QB64.org Forum
Active Forums => QB64 Discussion => Topic started by: johannhowitzer on August 11, 2020, 12:14:37 am
-
Having a little issue with _clearcolor as related to a routine I'm using in my game project to overlay a semitransparent color over a masked sprite.
h~& is the overlay color, which has an alpha component, d& is the image handle, here I'm passing in an image surface I use for assembling graphics before putting them on the screen. Here's how my program is using it during the sprite drawing:
call clear_image
(assembly
, hue
(hue_transparent
)) _putimage(0, 0)-step(w
, h
), sprite_image
, assembly
, (x2
, y2
)-step(sprite
(s
).size.x
, sprite
(s
).size.y
)
' Overlays
if blink_cd
> 1 then call overlay
(assembly
, _rgba(255, 0, 0, 63)) ' Engine burnout call overlay
(assembly
, _rgba(255, 255, 255, int(entity
(player
).hit_flash
* 224))) ' Hit flash
So first I clear the assembly image to transparent (_rgba(0, 0, 0, 0)), then put the sprite there from a sprite sheet that's got a color keyed out with _clearcolor. Then I apply the red engine burnout overlay, which works fine. The overlay() routine should leave the background still fully transparent, using its own _clearcolor that matches the overlay color. Then the hit flash value - which ranges from 0 to 1 and decays each frame - is used to apply a white overlay that fades down to the ship's normal colors. The overlay works, the fade works.
The problem is that only for the white overlay, the white is bleeding off the sprite and causing a rectangle around the ship while the flash happens. Only for the white, not the red burnout overlay. I've made some attempts at debugging this, tried a few different things like resetting the _clearcolor to _none at the start of overlay(), adding a second assembly surface and copying the sprite over before the white overlay. Also, the white bleed is happening whether the red overlay is used or not.
Tried to post an image of it here, but I guess this forum doesn't allow images. Looking closely, some pixels in the ship sprite are being keyed out when they shouldn't be - they're appearing black.
-
Okay, I was wrong, it's happening for the red overlay too, it was just too dim to tell. Apparently this is not a good method for overlaying a color on a non-rectangular image. It does work correctly if I use point(0, 0) as the _clearcolor, this just means that every sprite has to have a transparent pixel in the top-left.
-
Are you using 32 bit color? There is supposedly a difference between _RGBA() and _RGBA32() and I see you are using _RGBA.
Something to try _RGBA32().
-
I'm in 32-bit, but switching all uses of _rgba to _rgba32 didn't fix this. Sticking to point(0, 0) for now, probably some weirdness with color addition, and even for the odd rectangular sprite needing an overlay, I can just add a row above and below of transparency. point(0, 0) should be 100% reliable.
-
h~& is being blended with black when you draw the box, so you end up with a different color. You'd have to calculate what the new color is in order to clear it properly, and POINT is perfectly up to the job.
-
Yeah, I had assumed adding a color to _rgba(0, 0, 0, 0) would just result in the color I added, that seems to be incorrect. Intuitively it seems like it should be correct, but it isn't.
-
h~& is being blended with black when you draw the box, so you end up with a different color. You'd have to calculate what the new color is in order to clear it properly, and POINT is perfectly up to the job.
Or add_DONTBLEND to your sub overlay.
SUB overlay(d&, h~&)
preserve& = _DEST
_DEST d&
_DONTBLEND
LINE(0, 0)-(_WIDTH, _HEIGHT), h~&, bf
_BLEND
_CLEARCOLOR h~&, d&
_DEST preserve&
END SUB
-
Thanks, but that defeats the purpose of overlay() entirely. The result of not blending the color overlay on the sprite at all is an image full of only the one color and no sprite, and then _clearcolor wipes it to nothing, as test confirmed. This makes overlay() into don't display the sprite ever.
Oh, and I just realized I don't even need to worry about the top left of the sprite being transparent in the first place, silly me. Just start the sprite at (0, 1) and the top left of the assembly surface will always work. Or, better yet (can you tell I'm thinking out loud), use point(_width - 1, _height - 1) within the routine so you can work from (0, 0) outside it. So here's the final routine if anyone wants to use it in something:
-
Yeah, I had assumed adding a color to _rgba(0, 0, 0, 0) would just result in the color I added, that seems to be incorrect. Intuitively it seems like it should be correct, but it isn't.
Seems like you can place the color directly with MEM commands when you really need to; PSET didn’t work when I tested it right now...which I’m glad I just realized because I’ve been using PSET to create a gradient map to use with Hardware images