Alpha Buffer with MaxGUI Canvas

BlitzMax Forums/BlitzMax Programming/Alpha Buffer with MaxGUI Canvas

Can't seem to get the alhpabuffer working on canvases. Here's an example of it working with normal graphics whereby it simply draws circles with alphablend then saves to a png file (with alpha):

SuperStrict


Import maxgui.maxgui 'import maxgui core
Import MaxGUI.Win32MaxGUI 'import win32 version maxgui core

SetGraphicsDriver GLMax2DDriver()

Graphics 1000, 500,,, GRAPHICS_ALPHABUFFER

'Global previewwindow:TGadget = CreateWindow("Preview", 0, 0, 1000, 500, Null, WINDOW_TITLEBAR | WINDOW_RESIZABLE | WINDOW_STATUS | WINDOW_MENU)
'Global previewpanel:TGadget = CreatePanel(0, 0, ClientWidth(previewwindow), ClientHeight(previewwindow), previewwindow)
'Global previewcanvas:TGadget = CreateCanvas(0, 0, ClientWidth(previewpanel), ClientHeight(previewpanel) , previewpanel)

'previewcanvas.AttachGraphics GRAPHICS_ALPHABUFFER

'Local w:Int, h:Int, depth:Int, hrtz:Int, flags:Int
'
'CanvasGraphics(previewcanvas).GetSettings(w, h, depth, hrtz, flags)

'drawtocanvas previewcanvas, 0, 0, 0, 0
SetClsColor2 0, 0, 0, 0
Cls
SeedRnd 0

For Local c:Int = 1 To 50

	Local size:Int = Rnd(50, 125) 
	Local x:Int = Rnd(100, 300) 
	Local y:Int = Rnd(100, 300) 
	
	SetColor Rnd(255), Rnd(255), Rnd(255) 
	
	ColorMaskColor
	
	SetBlend ALPHABLEND
	
	SetAlpha.5
	
	DrawOval x, y, size, size
	
	SetColor 150, 150, 150
	
	ResetColorMask
	
	SetBlend LIGHTBLEND
	
	SetAlpha.5
	
	x = Rnd(100, 300) 
	y = Rnd(100, 300) 
	
	DrawOval x, y, size, size
	
Next

SeedRnd 0

ColorMaskAlpha

For Local c:Int = 1 To 50

	Local size:Int = Rnd(50, 125) 
	Local x:Int = Rnd(100, 300) 
	Local y:Int = Rnd(100, 300) 
	
	SetColor Rnd(255), Rnd(255), Rnd(255) 
	
	SetBlendAlphaONE
	        
	SetAlpha.5
	DrawOval x, y, size, size
	
	glEnable GL_BLEND
	glBlendFunc GL_SRC_ALPHA, GL_ONE
	
	SetColor 150, 150, 150
	
	SetAlpha.5
	
	x = Rnd(100, 300) 
	y = Rnd(100, 300) 
	
	DrawOval x, y, size, size

        
Next

glColorMask(True, True, True, True) 
Local pixmapalpha:TPixmap = GrabPixmapAlpha(0, 0, 500, 500) 
Local pixmapcolor:TPixmap = GrabPixmapColor(0, 0, 500, 500) 
Local pixmapfinal:TPixmap = mergepixmaps(pixmapalpha, pixmapcolor) 

SavePixmapPNG(pixmapfinal, "test.png")
SetAlpha 1
SetColor 255, 255, 255
SetBlend ALPHABLEND
Local testimg:TImage = LoadImage("test.png") 
DrawImage testimg, 500, 0

Flip
WaitKey

Function SetClsColor2(red:Float, green:Float, blue:Float, alpha:Float = 255) 
	glClearColor red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0
End Function

Function GrabPixmapAlpha:TPixmap(x:Float, y:Float, w:Float, h:Float) 

	Local p:TPixmap = CreatePixmap(w, h, PF_A8) 
	glReadPixels x, GraphicsHeight() - h - y, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, p.pixels
	p = YFlipPixmap(p) 
	
	Return ConvertPixmap(p, PF_RGBA8888) 
        
End Function

Function GrabPixmapColor:TPixmap(x:Float, y:Float, w:Float, h:Float) 

	Local p:TPixmap = CreatePixmap(w, h, PF_RGB888) 
	glReadPixels x, GraphicsHeight() - h - y, w, h, GL_RGB, GL_UNSIGNED_BYTE, p.pixels
	p = YFlipPixmap(p) 
	
	Return ConvertPixmap(p, PF_RGBA8888) 
        
End Function

Function SetBlendAlphaSRC() 
	glEnable GL_BLEND
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 
	glDisable GL_ALPHA_TEST
End Function

Function SetBlendAlphaONE() 
	glEnable GL_BLEND
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) 
	glDisable GL_ALPHA_TEST
End Function

Function ColorMaskColor() 
	glColorMask(True, True, True, False) 
End Function

Function ColorMaskAlpha() 
	glColorMask(False, False, False, True) 
End Function

Function ResetColorMask() 
	glColorMask(True, True, True, True) 
End Function

Function mergepixmaps:TPixmap(alpha:TPixmap, color:TPixmap) 
	Local p:TPixmap = CreatePixmap(alpha.width, alpha.height, PF_RGBA8888) 
	ClearPixels(p, 0) 
	Local c:Int
	Local a:Int
	Local r:Int
	Local g:Int
	Local b:Int
	Local t1:Int
	For Local x:Int = 0 To alpha.width - 1
		For Local y:Int = 0 To alpha.height - 1
			a = ReadPixel(alpha, x, y) 
			c = ReadPixel(color, x, y) 
			b = c & $000000FF
			g = (c & $0000FF00) Shr 8
			r = (c & $00FF0000) Shr 16
			t1 = (a & $FF000000) Shr 24
			If r Then r = Float(r) / (Float(t1) / 255.0) 
			If g Then g = Float(g) / (Float(t1) / 255.0) 
			If b Then b = Float(b) / (Float(t1) / 255.0) 
			WritePixel(p, x, y, b + (g Shl 8) + (r Shl 16) + (t1 Shl 24)) 
		Next
	Next
	Return p
End Function

Function drawtocanvas(can:TGadget, r:Int = 0, g:Int = 0, b:Int = 0, clear:Byte = True)
	If can
		SetGraphics CanvasGraphics(can) 
		SetViewport 0, 0, GadgetWidth(can), GadgetHeight(can) 
		SetClsColor2 r, g, b, 0
		Cls
	End If
End Function


and here's the same hing on a canvas:
SuperStrict


Import maxgui.maxgui 'import maxgui core
Import MaxGUI.Win32MaxGUI 'import win32 version maxgui core

SetGraphicsDriver GLMax2DDriver()

'Graphics 1000, 500,,, GRAPHICS_ALPHABUFFER

Global previewwindow:TGadget = CreateWindow("Preview", 0, 0, 1000, 500, Null, WINDOW_TITLEBAR | WINDOW_RESIZABLE | WINDOW_STATUS | WINDOW_MENU)
Global previewpanel:TGadget = CreatePanel(0, 0, ClientWidth(previewwindow), ClientHeight(previewwindow), previewwindow)
Global previewcanvas:TGadget = CreateCanvas(0, 0, ClientWidth(previewpanel), ClientHeight(previewpanel) , previewpanel)

previewcanvas.AttachGraphics GRAPHICS_ALPHABUFFER

drawtocanvas previewcanvas, 0, 0, 0
'SetClsColor2 0, 0, 0, 0
'Cls
SeedRnd 0

For Local c:Int = 1 To 50

	Local size:Int = Rnd(50, 125) 
	Local x:Int = Rnd(100, 300) 
	Local y:Int = Rnd(100, 300) 
	
	SetColor Rnd(255), Rnd(255), Rnd(255) 
	
	ColorMaskColor
	
	SetBlend ALPHABLEND
	
	SetAlpha.5
	
	DrawOval x, y, size, size
	
	SetColor 150, 150, 150
	
	ResetColorMask
	
	SetBlend LIGHTBLEND
	
	SetAlpha.5
	
	x = Rnd(100, 300) 
	y = Rnd(100, 300) 
	
	DrawOval x, y, size, size
	
Next

SeedRnd 0

ColorMaskAlpha

For Local c:Int = 1 To 50

	Local size:Int = Rnd(50, 125) 
	Local x:Int = Rnd(100, 300) 
	Local y:Int = Rnd(100, 300) 
	
	SetColor Rnd(255), Rnd(255), Rnd(255) 
	
	SetBlendAlphaONE
	        
	SetAlpha.5
	DrawOval x, y, size, size
	
	glEnable GL_BLEND
	glBlendFunc GL_SRC_ALPHA, GL_ONE
	
	SetColor 150, 150, 150
	
	SetAlpha.5
	
	x = Rnd(100, 300) 
	y = Rnd(100, 300) 
	
	DrawOval x, y, size, size

        
Next

glColorMask(True, True, True, True) 
Local pixmapalpha:TPixmap = GrabPixmapAlpha(0, 0, 500, 500) 
Local pixmapcolor:TPixmap = GrabPixmapColor(0, 0, 500, 500) 
Local pixmapfinal:TPixmap = mergepixmaps(pixmapalpha, pixmapcolor) 

SavePixmapPNG(pixmapfinal, "test.png")
SetAlpha 1
SetColor 255, 255, 255
SetBlend ALPHABLEND
Local testimg:TImage = LoadImage("test.png") 
DrawImage testimg, 500, 0

Flip
WaitKey

Function SetClsColor2(red:Float, green:Float, blue:Float, alpha:Float = 255) 
	glClearColor red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0
End Function

Function GrabPixmapAlpha:TPixmap(x:Float, y:Float, w:Float, h:Float) 

	Local p:TPixmap = CreatePixmap(w, h, PF_A8) 
	glReadPixels x, GraphicsHeight() - h - y, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, p.pixels
	p = YFlipPixmap(p) 
	
	Return ConvertPixmap(p, PF_RGBA8888) 
        
End Function

Function GrabPixmapColor:TPixmap(x:Float, y:Float, w:Float, h:Float) 

	Local p:TPixmap = CreatePixmap(w, h, PF_RGB888) 
	glReadPixels x, GraphicsHeight() - h - y, w, h, GL_RGB, GL_UNSIGNED_BYTE, p.pixels
	p = YFlipPixmap(p) 
	
	Return ConvertPixmap(p, PF_RGBA8888) 
        
End Function

Function SetBlendAlphaSRC() 
	glEnable GL_BLEND
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 
	glDisable GL_ALPHA_TEST
End Function

Function SetBlendAlphaONE() 
	glEnable GL_BLEND
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) 
	glDisable GL_ALPHA_TEST
End Function

Function ColorMaskColor() 
	glColorMask(True, True, True, False) 
End Function

Function ColorMaskAlpha() 
	glColorMask(False, False, False, True) 
End Function

Function ResetColorMask() 
	glColorMask(True, True, True, True) 
End Function

Function mergepixmaps:TPixmap(alpha:TPixmap, color:TPixmap) 
	Local p:TPixmap = CreatePixmap(alpha.width, alpha.height, PF_RGBA8888) 
	ClearPixels(p, 0) 
	Local c:Int
	Local a:Int
	Local r:Int
	Local g:Int
	Local b:Int
	Local t1:Int
	For Local x:Int = 0 To alpha.width - 1
		For Local y:Int = 0 To alpha.height - 1
			a = ReadPixel(alpha, x, y) 
			c = ReadPixel(color, x, y) 
			b = c & $000000FF
			g = (c & $0000FF00) Shr 8
			r = (c & $00FF0000) Shr 16
			t1 = (a & $FF000000) Shr 24
			If r Then r = Float(r) / (Float(t1) / 255.0) 
			If g Then g = Float(g) / (Float(t1) / 255.0) 
			If b Then b = Float(b) / (Float(t1) / 255.0) 
			WritePixel(p, x, y, b + (g Shl 8) + (r Shl 16) + (t1 Shl 24)) 
		Next
	Next
	Return p
End Function

Function drawtocanvas(can:TGadget, r:Int = 0, g:Int = 0, b:Int = 0)
	If can
		SetGraphics CanvasGraphics(can) 
		SetViewport 0, 0, GadgetWidth(can), GadgetHeight(can) 
		SetClsColor2 r, g, b, 0
		Cls
	End If
End Function


Anyone any ideas why?

If I understand it correctly, when you create a canvas you actually are creating a graphics context ie a screen within a window, which will allocate buffers based on what the default buffers are for the driver you've selected. You can set which buffers are the default buffers for the driver, and then when you create your canvas it will be created with those buffers. You can't just say `add on an alpha buffer` after the fact, and you shouldn't need to. You can get rid of the `attach graphics` call if you set the buffers you want in the driver default.

Note that your desktop will have to be in 32-bit color mode and it must support an alpha channel in the screen in order for it to have a chance of being provided when you create your canvas. And note that just because you ask for it does not mean that your drive will give it to you, so after you create the canvas and do setgraphics canvasgraphics, or whatever it is, you may want to write a value to the alpha channel of the screen and then read off a pixel from the backbuffer with like grabpixmap and test it to see if the value you wrote is present in the pixel you read back. Note that although OpenGL for example can tell you supposedly how many bits are present in the alpha channel, it can be broken and report falsely if you requested something that was not available.

Once you do have an alpha channel as part of the display, you need a way to write alpha data to it. Drawing objects with alphablending will not achieve that, as the source alpha of the sprite is used to scale the colors in the sprite against the existing colors in the screen, but pays no attention to the screen's alpha channel at all. You have to draw into the screen's alpha channel if you hope to read values from it, and Max2D does not have any native commands to do that. You'd have to dip into DX or GL commands. Not sure if DrawPixmap works tho.

ahh I see, thanks. I never noticed the extra parameters for setgraphicsdriver.

SetGraphicsDriver GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_ALPHABUFFER