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 |