Texture woes - I am about to go MAL over this!!!

Blitz3D Forums/Blitz3D Programming/Texture woes - I am about to go MAL over this!!!

Adam Novagen(Posted 2009) [#1]
Hey all,

Okay, I'm trying to get Blitz to do something. It's really not all that complicated. I have a "ship" representing the player. Underneath the ship, there's a quad which has to display two bars, one for health and one for energy. The quad was created the way I always do 'em: CreateMesh(), CreateSurface(), AddVertex() (UV mapping included) and AddTriangle().

There are three images that have to be drawn on the texture for this quad, which we may as well call a sprite because that's how I'm using it. First, there's a background, which is basically like a piece of metal or something with two grooves, then the two bars get drawn in those grooves. The texture itself is 128x128 to ensure maximum compatibility, while the bar background is only 104x26. This leaves a black area around it, which is where the problem comes in.

For the first attempt, I tried using the Mask (4) flag along with the Color (1) and VRAM (256) flags. The Mask flag is supposed to make all black (0,0,0) areas transparent, right? Wrong. The texture showed up as a solid black rectangle, with no sign of the bars. As soon as I removed the Mask flag, the bars showed up again, but still in the middle of a black square. What the *&^@.

Next, I tried the Alpha (2) flag instead of the Mask flag, then filled in the texture using WritePixelFast with ARGB 0,0,0,0. As expected, the black area disappeared. When I started drawing the bars again, though, they appeared semi-transparent. Blitz was reading the Alpha value all the way AROUND them, but when it got to the bars themselves, it was reading the brightness.

Okay, new plan. Instead of using DrawBlock() and DrawBlockRect() to draw the bars, I'll use WritePixelFast() with an Alpha value of 255, and the RGB value of the bars' pixels. Copy them over one pixel at a time, with full opacity. But NOOO, they still appeared as semi-transparent!

Okay, FINE. I'll save them as PNGs instead of BMPs, then load them as textures with the Alpha flag, then use CopyRect(). Proper Alpha values all around. WRONG-O!!! They STILL showed up semi-transparent, and this time some of the last pixels were missing.

BACK TO THE DRAWING BOARD, THEN. I'll just have to throw compatibility to the wind, and make the initial texture 104x26, so that there's no black around the bars or their background. Okay, fine. BUT HEY, THAT'D BE TOO EASY!!! There was still some black to the right and bottom of the bar background. Not as much as before, but there shouldn't be ANY, since it's now the exact same size as the texture!!!

So, I'm pretty much at my wit's end. Why in the world would the Mask flag... Well, not Mask?? Why all the Alpha foul-ups?? And how in the world am I going to get these bars in place??? @_@ My sanity greatly appreciates your help.


skidracer(Posted 2009) [#2]
As you have found DrawBlock, CopyRect, DrawText etc. have no respect for alpha channels (they use GDI commands) and cannot be used on 32 bit textures unless you fix the alpha in a second pass.

So either draw the ENTIRE shape with WritePixelFast, process the alpha bits in a second pass or take the optimal route and build all the bars using geometry (runtime texture modification is always going to be a huge hit on your pipeline).


Gabriel(Posted 2009) [#3]
Textures have to be powers of two. You cannot create a 104x26 texture, it will be resized to the nest largest power of two in each dimension, which is 128x32. That would explain the black on the right and bottom. You should always check texture dimensions with TextureWidth and TextureHeight, not just assume that they are the size you hope.

CopyRect, IIRC, always ignores alpha, so it doesn't matter whether you use BMP or PNG.

Copying with WritePixelFast should work, but you might need to use PNG. BMP *does* have an alpha channel, but I think DirectX doesn't load the alpha channel.


Adam Novagen(Posted 2009) [#4]
... or take the optimal route and build all the bars using geometry (runtime texture modification is always going to be a huge hit on your pipeline).


Well, in this case it doesn't have much of an impact since the images are so tiny. However, building them with geometry makes sense... I might make the bars and their background three individual sprites, that could work...

Textures have to be powers of two.


O-Kay, that makes sense; I knew there was some limitation involved, but I couldn't find the mention of it in the BlitzDocs. And yeah, that's got to be why the black areas still appeared. Hey, while I think of it, what exactly does IIRC stand for?

Okay, thanks guys; I'll take these ideas on board & see what I can do. Still, I can't figure out why the Mask flag didn't just solve the whole thing in the first place...


Yasha(Posted 2009) [#5]
"If I Recall Correctly".

Two more ideas come to mind:

1) Create your 104x26 image in your editor, and stretch it to 128x32, then resize the quad itself so the image proportions are correct (having each corner have UV of 1 or 0).

2) Create your 104x26 image, add borders so that it's 128x32, and work out the correct UV coords for the corners so that the extra texture space simply never gets put on the quad (ie.: 0,0 ; 0.8125,0 ; 0,0.8125 ; 0.8125,0.8125).

The second one would likely be easier, as you could then just forget about the black corner. However, geometry is still better in any case.


Kryzon(Posted 2009) [#6]
I'd say, forget about pixel manipulation routines. Just forget about them.
If the thing doesn't work properly in the first place, then there's something so wrong about it that giving your program crutches for it just won't cut it.

Stick to geometry. Simple quad rectangle, 2 triangles, that's it. Do that for the health bar's framing and the health "content" themselves (meaning, total of 3 quads).
If you use a pixel perfect lib like the free Sprite Control, you can place the health bar content sprites exactly at the pixels you want them to be aligned with the framing, with a mathematical precision.
Most likely you'll want to change the size\value of the health bar's content, and for that you will have to find the index of the two vertices in the quad's right side. Then move them about using VertexCoords.

If your health bar content sprites are painted with a single-colored brush (and no texture), then you can just do that without a problem. If they have a certain texture to them, then moving their vertices will cause that texture to compress\expand, and that doesn't look to good. You'll have to painfully adjust these vertices UV coordinates when you move them so that the texture stays in place.
That's why I recommend using single colored brushes for the content quads, without textures (like green or red for HP, and blue or purple for MANA, for instance). It doesn't look as bad as you might think, especially if you use a black and white overlay quad just on top of these content sprites, specially textured with an alpha map to give these quads a beveled look.

This health bar, for instance, I used a total of 4 quads to build it:

not only there's the main texture quads but also stuff like a "glare" overlay, to give that white shine, like glass.

PS: Whenever in doubt about a TXT-Talk slang or general shortenings, go to Google and write "define: IIRC" for instance. Google will look up quick and list you various possible definitions for the term you specified.


Adam Novagen(Posted 2009) [#7]
Thanks for the Define: tip, Kryzon!

Anyway, problem solved. I used the GIMP to center the health bar background in a 128x128 PNG, so no more black outline. As far as the health & energy bars themselves, they're only simple bars filled with color gradients, so I got creative with vertex coloring & custom meshes, and everything works perfectly now, plus there's no more realtime Texture alterations! :D


Ross C(Posted 2009) [#8]
The fast Libs have a copyrect that copies alpha, if that helps.