Cannot edit Masked Textures
Blitz3D Forums/Blitz3D Programming/Cannot edit Masked Textures
| ||
| 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. |
| ||
| 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? |
| ||
| 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? |
| ||
| 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? |
| ||
| 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. |
| ||
| 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. |
| ||
| 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. |
| ||
| Hmm. No such luck on anything. |
| ||
| 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. |
| ||
| 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 |
| ||
| 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 |
| ||
| 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... |
| ||
| 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... |
| ||
| >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 |
| ||
| 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... |
| ||
| 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. |
| ||
| 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 |
| ||
| 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. |
| ||
| >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 |
| ||
| Text seems to be the main problem, rects, line and cls seem to work fine. |
| ||
| 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 |
| ||
| I don't see any mention of it in 1.88, so will this ever be fixed? Andy |
| ||
| Was this ever fixed? Andy |