Cannot edit Masked Textures

Blitz3D Forums/Blitz3D Programming/Cannot edit Masked Textures

Fry Crayola(Posted 2004) [#1]
I'm having a problem in editing or copying to a texture that has been flagged as "Masked". Having set the buffer to TextureBuffer(mainTexture), no images drawn appear on the texture (I have a function to output the current texture to a file to debug). The Line function works, but draws lines twice the size that I desire. CopyRect also does not work.

I'm creating a 2D in 3D single surface system. One of the features of the system will be the ability to load up a square graphics tile, which is added to the main texture so that its contents may be displayed on the surface (the user must load in the necessary data for the sprites contained therein).

Another feature is the creation of fonts in a similar fashion. The fonts are loaded as standard, and the required characters are drawn to an image which is then copied onto the main texture. Each character has its own u,v values for top left and bottom right so that they may be drawn to the surface.

The main texture is a 1024*1024 texture (I plan to expand this to 2048*1024, which is supported, but for testing the smaller texture is more suitable), with the Colour and Masked flags activated (1+4). A rectangular block, measuring from 0,0 to 255,1024 is used for storing the fonts. The rest of the texture is given up for square tiles of equal size.

Obviously, without the ability to edit the texture properly, the system cannot work. It's proving to be quite irritable. Yet I recall Anthony Flack used a similar technique of adding tiles to a texture (indeed, his comments are what I based the system on), so I know it is possible in some respect.

The full code for the engine is here:

;********************************************************
;*														*
;*	2D in 3D engine										*
;*	Initialisation and Routines							*
;*														*
;********************************************************

;NOTES
;the pixel 0,0 on the texture must be coloured white, for rectangle drawing
;the rectangle covering 0,1 to 256,1024 is reserved for fonts only.
;loadBitmapFont loads a normal font into the custom font type
;you must create a custom font type before using loadBitmapFont

;constants
Const SYMBOL_TYPE = 0
Const NUMERAL_TYPE = 1
Const UC_TYPE = 2
Const LC_TYPE = 3
Const UCS_TYPE = 4
Const LCS_TYPE = 5

;type creation
Type sprite
Field width			;sprite width, pixels
Field height		;sprite height, pixels
Field u1#, v1#		;top left texture
Field u2#, v2#		;bottom right texture
Field tile			;tile number
End Type

Type font
Field ttFont		;the truetype font handle
Field flags			;character flags
Field height		;height of the font
Field stored[221]	;tells if character is used
Field x[221]		;x position
Field y[221]		;y position
Field u1#[221]		;uv coords for top left, and bottom right
Field u2#[221]
Field v1#[221]
Field v2#[221]
Field width[221]	;width in pixels
End Type

Global mainTexture, mainSurface, mainBrush, mainCamera, mainLight, mainMesh
Global screenWidth, screenHeight
Global totalTiles, tileSize, nextFreeTile
Global fontBottom

Dim tileInUse(111)  ;true if tile is in use. 112 tiles maximum.

;Initialisation
Function initialiseEngine(x,y,depth,size)
	Graphics3D x,y,depth
	ClearTextureFilters
	
	screenWidth = x
	screenHeight = y
	tilesAcross = 1792/size
	tilesDown = 1024/size
	totalTiles = tilesAcross * tilesDown
	tileSize = size
	
	For a = 0 To 111 : tileInUse(a) = False : Next
	nextFreeTile = 0
	
	mainMesh = CreateMesh()
	PositionMesh mainMesh, screenWidth*-0.5, screenHeight*-0.5, screenWidth*-0.5
	mainSurface = CreateSurface(mainMesh)
	mainCamera = CreateCamera()
	mainLight = CreateLight()
	LightColor mainLight,255,255,255
	mainBrush = CreateBrush()
	mainTexture = LoadTexture("engineTexture.png",5)
	BrushTexture mainBrush,mainTexture
	BrushFX mainBrush, 2
	PaintSurface mainSurface,mainBrush
	SetBuffer TextureBuffer(mainTexture)
	Color 255,255,255
	Line 0,0,127,0
	Print TextureWidth(mainTexture)
	Print TextureHeight(mainTexture)
	SetBuffer BackBuffer()
End Function

;drawing 3D image
Function draw3DImage(this.sprite, xpos#, ypos#, xscale#, yscale#, angle#)
	;this			:sprite to be drawn to screen
	;xpos, ypos		:coordinates of world to place sprite
	;xscale, yscale	:scaling
	;angle			:angle of rotation
	
	
	;first, get the x and y distances from centre
	angle = 360-angle
	xdist# = (((this\width)-1)/2.0)*xscale
	ydist# = (((this\height)-1)/2.0)*yscale
	
	;rotate each vertex in turn
	x1# = (xdist*-1) * Cos(angle) - ydist * Sin(angle)
	y1# = (xdist*-1) * Sin(angle) + ydist * Cos(angle)
	
	x2# = xdist * Cos(angle) - ydist * Sin(angle)
	y2# = xdist * Sin(angle) + ydist * Cos(angle)
	
	x3# = xdist * Cos(angle) + ydist * Sin(angle)
	y3# = xdist * Sin(angle) - ydist * Cos(angle)
	
	x4# = (xdist*-1) * Cos(angle) + ydist * Sin(angle)
	y4# = (xdist*-1) * Sin(angle) - ydist * Cos(angle)
	
	
	;create the four vertices as part of the quad.
	v1 = AddVertex(mainSurface, xpos+x1, ypos+y1, 0, this\u1, this\v1)
	v2 = AddVertex(mainSurface, xpos+x2, ypos+y2, 0, this\u2, this\v1)
	v3 = AddVertex(mainSurface, xpos+x3, ypos+y3, 0, this\u2, this\v2)
	v4 = AddVertex(mainSurface, xpos+x4, ypos+y4, 0, this\u1, this\v2)
	
	;add two triangles
	t1 = AddTriangle(mainSurface, v1, v2, v4)
	t2 = AddTriangle(mainSurface, v2, v3, v4)
End Function

;draw a solid coloured rectangle
Function rectangle(x, y, width, height, red, green, blue)
	
	v1 = AddVertex(mainSurface, x			, y			, 0, 0, 0)
	v2 = AddVertex(mainSurface, x+width-1	, y			, 0, 0, 0)
	v3 = AddVertex(mainSurface, x+width-1	, y-height+1, 0, 0, 0)
	v4 = AddVertex(mainSurface, x			, y-height+1, 0, 0, 0)
	
	VertexColor mainSurface, v1, red, green, blue
	VertexColor mainSurface, v2, red, green, blue
	VertexColor mainSurface, v3, red, green, blue
	VertexColor mainSurface, v4, red, green, blue
	
	t1 = AddTriangle(mainSurface, v1, v2, v3)
	t2 = AddTriangle(mainSurface, v1, v3, v4)
End Function

;update screen
Function updateScreen()
	UpdateNormals(mainMesh)
	RenderWorld
	Flip
End Function

;clear screen
Function clearScreen()
	ClearSurface(mainSurface)
End Function

;add a tile to the system
Function addTile(tilename$)
	If nextFreeTile < totalTiles Then
	
		image = LoadImage(tilename)
		x = (nextFreeTile Mod tilesAcross) * tileSize
		y = (nextFreeTile / tilesAcross) * tileSize
		CopyRect 0,0,tileSize,tileSize,x,y,ImageBuffer(image),TextureBuffer(mainTexture)
		Cls
		
		;update next free tile
		tileInUse(nextFreeTile) = True
		tileUsed = nextFreeTile
		While (nextFreeTile = True) Or (nextFreeTile = totalTiles)
			nextFreeTile = nextFreeTile + 1
		Wend
				
		Return tileUsed
	Else
		Return -1
	End If
End Function

;remove a tile from the system
Function removeTile(tileNumber)
	If tileNumber < totalTiles Then
	
		tileInUse(tileNumber) = False
		
		For this.sprite = Each sprite
			If this\tile = tileNumber : Delete this : End If
		Next
	
		Return True
	Else
		Return False
	End If
End Function

;load in a bitmap font - normal font must already be loaded, and type created
Function loadBitmapFont(fontname$, size, bold, italic, flags, this.font)

	;flags guide
	;1 : symbols
	;2 : numerals
	;4 : upper case
	;8 : lower case
	;16: upper case special
	;32: lower case special
	
	;0 is default
	If flags = 0 Then flags = 63

	;load in font from disc as normal
	theFont = LoadFont(fontname$, size, bold, italic)
	this\flags = flags
	SetFont theFont
	
	;set buffer, clear screen
	fontImage = CreateImage(256,1024)
	SetBuffer ImageBuffer(fontImage)
	ClsColor 0,0,0
	Cls
	Color 255,255,255
	
	;start at 0,0
	x = 0
	y = 0
	
	;get character height
	height = FontHeight()
	this\height = height
	
	;go through every character in order
	charType = SYMBOL_TYPE		;stores type of character
	For character = 33 To 254
	
		;skip the unnecessary
		If character = 48 Then charType = NUMERAL_TYPE
		If character = 58 Then charType = SYMBOL_TYPE
		If character = 65 Then charType = UC_TYPE
		If character = 91 Then charType = SYMBOL_TYPE
		If character = 97 Then charType = LC_TYPE
		If character = 123 Then 
			character = 128
			charType = SYMBOL_TYPE
		End If
		If character = 129 Then character = 163
		If character = 164 Then character = 169
		If character = 170 Then
			character = 192
			charType = UCS_TYPE
		End If
		If character = 198 Then character = 199
		If character = 215 Then character = 216
		If character = 221 Then character = 222
		If character = 224 Then charType = LCS_TYPE
		If character = 230 Then character = 231
		If character = 247 Then character = 248
		If character = 253 Then character = 254
		
		If Mid(Bin(flags), 32-chartype, 1) = "1" Then
			
			;check for horizontal fit
			this\width[character-33] = StringWidth(Chr$(character))
			If (x + this\width[character-33] -1 ) > 256 Then
				y = y + height
				x = 0
			End If
			
			;write character to image
			Text x,y, Chr$(character)
			
			;store x and y values
			this\x[character-33] = x
			this\y[character-33] = y
			this\stored[character-33] = True
			x = x + this\width[character-33]
		Else
			this\stored[character-33] = False
		End If
		
	Next
	
	;check for fit
	y = y + height
	If (fontBottom + y) < 1024 Then
		;success
		CopyRect 0,0,256,y,0,fontBottom-1,ImageBuffer(fontImage),TextureBuffer(mainTexture)
		
		;sort out u,v coors For letters
		For a = 0 To 221
			If this\stored[a] = True Then
				this\y[a] = this\y[a] + fontBottom + 1
				this\u1[a] = this\x[a] / 2048.0
				this\v1[a] = this\y[a] / 1024.0
				this\u2[a] = (this\x[a] + this\width[a] - 1) / 2048.0
				this\v2[a] = (this\y[a] + height - 1) / 1024.0
			End If
		Next			
		FreeImage fontImage
		this\ttFont = theFont
		Return True
	Else
		Delete this
		FreeImage fontImage
		Return False
	End If
	
End Function

;write in bitmap font
Function displayText(theText$, textx#, texty#, xcent, ycent, bitmapFont.font, red, green, blue)

	SetFont bitmapFont\ttFont
	
	;centre vertically
	If ycent Then
		texty = texty + (height * 0.5)
	End If
	
	;centre horizontally
	If xcent Then
		textx = textx - (StringWidth(thetext) * 0.5)
	End If
	
	;go through each character in turn, drawing to screen
	For a = 1 To Len(theText)
	
		char = Asc(Mid(theText, a, 1)) - 33
		
		;check if character in font
		If bitmapFont\stored[char] Then
			
			;create the four vertices as part of the quad.
			v1 = AddVertex(mainSurface, textx, texty, 0, bitmapFont\u1[char], bitmapFont\v1[char])
			v2 = AddVertex(mainSurface, textx+bitmapFont\width[char]-1, texty, 0, bitmapFont\u2[char], bitmapFont\v1[char])
			v3 = AddVertex(mainSurface, textx+bitmapFont\width[char]-1, texty-bitmapFont\height+1, 0, bitmapFont\u2[char], bitmapFont\v2[char])
			v4 = AddVertex(mainSurface, textx, texty-bitmapFont\height+1, 0, bitmapFont\u1[char], bitmapFont\v2[char])
		
			;color the vertices
			VertexColor mainSurface, v1, red, green, blue
			VertexColor mainSurface, v2, red, green, blue
			VertexColor mainSurface, v3, red, green, blue
			VertexColor mainSurface, v4, red, green, blue
	
			;add two triangles
			t1 = AddTriangle(mainSurface, v1, v2, v4)
			t2 = AddTriangle(mainSurface, v2, v3, v4)
			
			;move cursor
			textx = textx + bitmapFont\width[char]
		
		Else
			textx = textx + (bitmapFont\height * 0.5)
		End If
	Next
End Function

;function to save the texture to disc for debugging purposes
Function debugTexture()
	theImage = CreateImage(1024,1024)
	SetBuffer TextureBuffer(mainTexture)
	
	GrabImage theImage, 0, 0
	SaveImage (theImage, "debugTexture.bmp")
End Function


Any help will be greatly appreciated.


jfk EO-11110(Posted 2004) [#2]
Does this work whenthe texture doesn not use the Mask Flag?

BTW: you should notice that the Alpha Channel of a texture is erased as soon as you draw something to it.

Did you also try it with an additional 256 Flag?


Fry Crayola(Posted 2004) [#3]
I have tried it without the mask flag (flag 1 only) and it worked fine - but naturally I cannot use that as I need the masking.

I'll give it a go with an additional 256 flag now - but what does that do exactly? What signifigance does it have for my code?


Fry Crayola(Posted 2004) [#4]
Oh - 256 stores it in Vram. I can't see how it would affect it, but it's worth a try.

What about the Alpha Channel - does that mean if I edit a texture I cannot use transparency effects ever?


Fry Crayola(Posted 2004) [#5]
Hmm. Adding 256 to the flag allows me to edit the texture - but it doubles. I get the area I placed onto the texture twice - in the right place, and then directly to the right of this.

However, I don't see a reason for this and I'm thinking it could be down to my debugTexture routine not working properly. I'll have to give that a go.


jfk EO-11110(Posted 2004) [#6]
It means you need to update the alphachannel manually, using writepixelfast. I don't remember clearly if this happens with every operation, but with the draw primitive commands it erases the alpha channel.

The 256 Bit Check may be useful to see if it has something to do with mipmapping.

additionally I have to mention that blitz does rescale textures internally when their size is other than something that is power-of-2, eg. 256*256 or 128*512...

Then there is a problem with SaveBuffer, LoadImage etc. of Images that are bigger than the screen.

And I am not sure if it's true, but somebody said Textures bigger than 1024*1024 are scaled down to 1024*1024 internally.


Fry Crayola(Posted 2004) [#7]
Hmm. I'm using a 1024*1024 texture and getting the problem. The font uses a 256*1024 image for drawing - that's bigger than the screen. I'll try cropping that.

As for the internal scaling of textures - using TextureWidth and TextureHeight on a 2048*1024 texture returned those values rather than scaling, so I'm not sure what's going on there.

Thanks so far, I'll make some tweaks and see what I can discover.


Fry Crayola(Posted 2004) [#8]
Hmm. No such luck on anything.


Fry Crayola(Posted 2004) [#9]
Ok, I tried and I failed. I couldn't locate the problem, and other things weren't working as they should, so given that the code wasn't very long I decided the best option was to rewrite it, but be more thorough with my testing throughout.

So far I have got a system that allows me to draw rectangles to the screen of any colour (using the 2D-3D system) which I will be able to use. I can also draw sprites if they are pre-loaded as part of the texture - i.e. I don't edit the texture in any way.

I'm going to look at ways tomorrow (it's 6:45pm here and I've food to eat) of editing the texture. I am convinced it is possible going by what Mr Flack has said, and what I have seen from others. Regardless, I'm sure I will find workarounds.

Stay tuned for any further problems, but if anyone can help with editing textures, or knows a good routine, I'll be happy to hear from them.


Andy(Posted 2004) [#10]
I seem to be having the same problems. If masking is on when I draw images to the texture, then they don't show up even though rects work fine. Masking doesn't appear to work at all if the texture has been modified.

If you figure something out, let us know!

Andy


skidracer(Posted 2004) [#11]
This topic has sprouted wings:

http://www.blitzbasic.com/Community/posts.php?topic=37332

2D operations on masked textures leave the mask in an undefined state most commonly completely transparent (different depending on how the graphics driver interprets the DirectDraw/DirectX7 spec). You have to reset the mask after drawing to a masked texture using the following:

www.blitzbasic.com/codearcs/codearcs.php?code=1131


Fry Crayola(Posted 2004) [#12]
yeah... got kinda sidetracked on the other thread which was really just supposed to be about Blitz's actual limitations. Just too damned desperate for a solution I guess...


Fry Crayola(Posted 2004) [#13]
Problem solved, as mentioned on the other thread.

Using alpha-transparency instead of masking, and wrote a function to draw an image to it. Works perfectly. All seems so simple now...


Andy(Posted 2004) [#14]
>2D operations on masked textures leave the mask in an
>undefined state most commonly completely transparent
>(different depending on how the graphics driver interprets
>the DirectDraw/DirectX7 spec). You have to reset the mask
>after drawing to a masked texture using the following:

Very nice... How do you define the keycolor?

Edit... Trying to use it just gives me an 'expecting en-of-line'... Any chance of an example?

Andy


skidracer(Posted 2004) [#15]
Oops, fixed.

I just did a test and it seems 2D drawing is completely broken on masked and alpha textures, teach me to post code I haven;t throughly tested, sorry.

This didn't use to be the case so either something in Blitz3D has changed or my drivers are to blame. Will investigate...


Fry Crayola(Posted 2004) [#16]
What I did is write a routine that locks the relevant image and texture buffers, then used ReadPixelFast and WritePixelFast to copy the image over. CopyPixelFast is of no use unless your images also have alpha values, which is unlikely in my case.

Andy: The keycolor is whatever colour you want masked, I assume. It's defined as $xxxxxxxx, a 32-bit number containing (in order) alpha, red, blue, green. To check if a pixel is the required colour you want masked, you carry out logical operations on it.

e.g. to check if a pixel is black, I did:

If colour AND $00111111 = $00000000

This eliminates the alpha value getting in the way - as it will always end up $00 after the operation.


Andy(Posted 2004) [#17]
Thanks for the explanation, although I would have assumed the keycolor was in hex(The mention of $ff000000). This in itself is weird as everything else in Blitz uses decimal rgb.

What I don't understand is this... Why isn't there a 'resetmask()' command built-in if resetting the mask is required? Or better yet, do it automatically whenever drawing operations has been performed on the texture.

Andy


Fry Crayola(Posted 2004) [#18]
I have no idea why it's not done automatically. The reason the keycolor is in hex though is because it's not RGB, it's ARGB - it includes the alpha channel.

Split a 32 bit number up into 4 parts, which from most significant to least goes alpha, red, blue, green. It's easier to see this in Hex - two characters make up each channel, from 0 to 255.


Andy(Posted 2004) [#19]
>I just did a test and it seems 2D drawing is completely >broken on masked and alpha textures, teach me to post code >I haven;t throughly tested, sorry.
>
>This didn't use to be the case so either something in
>Blitz3D has changed or my drivers are to blame. Will
>investigate...

How did the investigation go? Drivers or Blitz?

Andy


skidracer(Posted 2004) [#20]
Text seems to be the main problem, rects, line and cls seem to work fine.


jfk EO-11110(Posted 2004) [#21]
BTW, I have jst seen this:

"
e.g. to check if a pixel is black, I did:

If colour AND $00111111 = $00000000

This eliminates the alpha value getting in the way - as it will always end up $00 after the operation.
"

But this not correct. A pixel could be of color $222222, and $222222 AND $111111 will also be $0, but nevertheless it is not black. So you need to use this instead:

if colour AND $00FFFFFF = $00000000


Andy(Posted 2004) [#22]
I don't see any mention of it in 1.88, so will this ever be fixed?

Andy


Andy(Posted 2005) [#23]
Was this ever fixed?

Andy