Sprite Masking problem

Blitz3D Forums/Blitz3D Programming/Sprite Masking problem

Nesbitt(Posted 2004) [#1]
I'm creating a basic solar system simulator. I want to have spheres for planets, with floating text labels under them. The logical thing seemed to use sprites, so I wrote code to create a texture, draw the text on the screen, and copy the text to the texture using copyrect. Then I created a sprite and told it to use that texture.

Everything was going fine until I tried to make the sprite transparent. You see, I just want the words to float in space with no annoying black box around them. I had already set the "flags" value in the createtexture command to 48 in order to use the ClampU and ClampV modes and prevent the text from wrapping, and it worked just fine... so I added 4 to turn on masking as well, and then things went goofy.
The words became transparent, but got squished into the left half of the sprite, while the right half became a non-transparent black box. I'm a newcomer to B3d and have no idea why this is happening. Any tips?


Nesbitt(Posted 2004) [#2]
Me again. Here's a sample program to illustrate the problem. Set the constant at the top to 48, run it, and use the arrow keys to rotate, and the label looks good but has a black box around it. Change the constant to 52, and you should see the weird behavior I described above, rather than the black box just being transparent.

---

; This value is the oddball... I need Clamp U and Clamp V flags turned on, so it should be 16+32=48.
; When I turn on masking (4) and use a value of 52, it halves my text and adds a black box.

Global mode = 48 ; switch this between 48 and 52

Global camera_obj
Global light_obj
Global sphere_obj
Global sprite_obj
Global sphere2_obj

Global rot

Global scrap



; initialize graphics modes

Graphics3D maxx, maxy, 16, 1
SetBuffer BackBuffer()



; define camera and light

camera_obj = CreateCamera()
PositionEntity camera_obj, 0, 0, -10

light = CreateLight()
RotateEntity light, 45, 45, 0


; define spheres

sphere_obj = CreateSphere()

sphere2_obj = CreateSphere()
PositionEntity sphere2_obj, -1, -1.5, 5


; draw sphere's label on screen and copy it into texture
; define the label as being 256 pixels across and 32 down

scrap = CreateTexture (256, 32, mode)


; draw the text on this label, then use copyrect to put it in the texture buffer

Cls
Text 128, 0, "This is a sphere", 1
CopyRect 0, 0, 256, 32, 0, 0, BackBuffer(), TextureBuffer(scrap)


; create label sprite and texture it with "scrap"

label_obj = CreateSprite()
PositionEntity label_obj, 0, -1.5, 0
ScaleSprite label_obj, 4, 0.5
EntityTexture label_obj, scrap


; we don't need scrap anymore - clear it out

FreeImage scrap


; draw the world

While Not KeyHit(1)

PositionEntity camera_obj, 0, 0, 0
RotateEntity camera_obj, 0, rot, 0
MoveEntity camera_obj, 0, 0, -10

RenderWorld()
Flip

If KeyDown(203) Then
rot = (rot-2) Mod 360
End If
If KeyDown(205) Then
rot = (rot+2) Mod 360
End If

Wend


sswift(Posted 2004) [#3]
An image on the backbuffer has no alpha information. When you load an image with masking, Blitz calculates the alpha from the image color. But when you copy an image into an image with masking enabled, the alpha is not calculated.

Search the code archives for code which allows you to "set any masking color". It will probably calculate the alpha for you.

Alternatively, you can just set your sprite to add blend. That will make black transparent, and may make your text look cooler as it will appear to be transparent when in front of a planet or stars.


Ross C(Posted 2004) [#4]
Hey, go here :)

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


Nesbitt(Posted 2004) [#5]
Thanks for the tips, guys! What great service - I post last thing before I go to bed, and I have the explanation and a solution when I get up. Very convenient!

Regards,
Pete


Nesbitt(Posted 2004) [#6]
To Ross C (or anybody else who can help):

I tried implementing your algorithms from the link above, and they work, though I have a couple of questions:

1. Is it necessary to call prepare_texture() in this case, or is it unneccessary since no alpha information exists anyway?

2. Although the label is now properly transparent (woo hoo!) it's still shrunk to half its required size... This is odd, because it's the correct size when the texture mode is 48, and it shrinks when I use mode 52 to get masking. Any ideas what might be causing this?

Here's the new code, with your functions in place:

---

; This value is the oddball... I need Clamp U and Clamp V flags turned on, so it should be 16+32=48.
; When I turn on masking (4) and use a value of 52, it halves my text and adds a black box.

Global mode = 52 ; switch this between 48 and 52

Global camera_obj
Global light_obj
Global sphere_obj
Global sprite_obj
Global sphere2_obj

Global rot

Global scrap



; initialize graphics modes

Graphics3D maxx, maxy, 16, 1
SetBuffer BackBuffer()



; define camera and light

camera_obj = CreateCamera()
PositionEntity camera_obj, 0, 0, -10

light = CreateLight()
RotateEntity light, 45, 45, 0


; define spheres

sphere_obj = CreateSphere()

sphere2_obj = CreateSphere()
PositionEntity sphere2_obj, -1, -1.5, 5


; draw sphere's label on screen and copy it into texture
; define the label as being 256 pixels across and 32 down

scrap = CreateTexture (256, 32, mode)


; draw the text on this label, then use copyrect to put it in the texture buffer

Cls
Text 128, 0, "This is a sphere", 1
CopyRect 0, 0, 256, 32, 0, 0, BackBuffer(), TextureBuffer(scrap)


; create label sprite and texture it with "scrap"

label_obj = CreateSprite()
PositionEntity label_obj, 0, -1.5, 0
ScaleSprite label_obj, 4, 0.5
EntityTexture label_obj, scrap

; apply Ross C's function
prepare_texture(scrap)
texture_mask_colour(scrap, 0, 0, 0)


; draw the world

While Not KeyHit(1)

PositionEntity camera_obj, 0, 0, 0
RotateEntity camera_obj, 0, rot, 0
MoveEntity camera_obj, 0, 0, -10

RenderWorld()
Flip

If KeyDown(203) Then
rot = (rot-2) Mod 360
End If
If KeyDown(205) Then
rot = (rot+2) Mod 360
End If

Wend

;--------------------------------------------------------------------
; PREPARE_TEXTURE() created by Ross C |
; This function will clear a texture of all it's alpha information |
;--------------------------------------------------------------------
;parameters = texture : the texture you wish to clear alpha information from

Function prepare_texture(texture)

LockBuffer TextureBuffer(texture)

For loop=0 To TextureWidth(texture)
For loop1=0 To TextureHeight(texture)

RGB1=ReadPixelFast(loop,loop1,TextureBuffer(texture))
r=(RGB1 And $FF0000)Shr 16;separate out the red
g=(RGB1 And $FF00) Shr 8;green
b=RGB1 And $FF;and blue parts of the color
a=(RGB1 And $FF000000)Shr 24

a=255; remove any alpha information currently in the texture.

newrgb= (a Shl 24) Or (r Shl 16) Or (g Shl 8) Or b; combine the ARGB back into a number

WritePixelFast(loop,loop1,newrgb,TextureBuffer(texture)); write the info back to the texture
Next
Next

UnlockBuffer TextureBuffer(texture)

End Function


;---------------------------------------------------------------------
; TEXTURE_MASK_COLOUR created by Ross C |
; This function will mask the passed across RGB of the texture also |
; passed across. Do NOT pass across a value for flag if you only |
; want to mask an exact colour. |
;---------------------------------------------------------------------
;parameters = texture : the texture you wish to clear alpha information from
; = r1 : the red value to mask
; = g1 : the green value to mask
; = b1 : the blue value to mask
; = tolerance : the tolerance value. If set to 0, then the function will only mask the
; EXACT colours passed across. Higher value will mask values close to the colour.

Function texture_mask_colour(texture,r1,g1,b1,tolerance=0)


LockBuffer TextureBuffer(texture)

For loop=0 To TextureWidth(texture)
For loop1=0 To TextureHeight(texture)
RGB1=ReadPixelFast(loop,loop1,TextureBuffer(texture)) ; read the RGB value from the texture
r=(RGB1 And $FF0000)Shr 16;separate out the red
g=(RGB1 And $FF00) Shr 8;green
b=RGB1 And $FF;and blue parts of the color
a=(RGB1 And $FF000000)Shr 24 ; extract the alpha

If r>=r1-tolerance And r=<r1+tolerance And g=>g1-tolerance And g=<g1+tolerance And b=>b1-tolerance And b=<b1+tolerance Then; check RGB lies with the tolerance
;temp=((Abs(r-r1)+Abs(g-g1)+Abs(b-b1))/3.0)*4.0 ; alpha the values based on the tolerance value
a=0;temp

End If

newrgb= (a Shl 24) Or (r Shl 16) Or (g Shl 8) Or b ; combine the ARGB back into one value

WritePixelFast(loop,loop1,newrgb,TextureBuffer(texture)); write back to the texture
Next
Next
UnlockBuffer TextureBuffer(texture)

End Function