Draw HUD status bar element with shader and bounding box?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Draw HUD status bar element with shader and bounding box?

Post by argv »

I want to use ZScript to draw its HUD bars with a horizontal skew proportional to the height of the bar, regardless of how much of the bar is filled. I've put together this web-based demonstration (warning: doesn't show correctly in Microsoft IE/Edge) to show you what I have and what I want. The middle bar shows what I want; the bottom bar shows what I have.

Aetherius draws bars like I want on its HUD, by drawing each 1-pixel-wide sliver of the bar with a separate draw call. This is very slow. I'd like to help with that by skewing them with a shader instead, which should be much faster.

But I've got a problem. Currently, an ordinary texture can be drawn on the status bar, a shader can be attached to it via GLDEFS, and it can skew the texture just fine—but the horizontal skew is proportional to the scaled width of the texture, not the height! The result is like the bottom bar in the above demonstration.

This is my shader:

Code: Select all

const mat2 shearMatrix = mat2(1, 20./220., 0, 1);
const vec4 trans = vec4(0., 0., 0., 0.);

vec4 Process(vec4 color) {
	vec2 xy = gl_TexCoord[0].st;
	xy -= .5;
	xy.x *= 1. + (20. / 220.);
	xy *= shearMatrix;
	xy += .5;
	
	if (xy.x < 0. || xy.x > 1.)
		return trans * color;
	else
		return getTexel(xy) * color;
}
I have it attached to a 1×20 texture named “HPBFILNV” in GLDEFS. I'm drawing it from a ZScript BaseStatusBar implementation like so:

Code: Select all

SetSize(0, 1440, 1080);

int value = CPlayer.Health;
int MaxValue = CPlayer.mo.GetMaxHealth(true);
int MaxFillWidth = 200;
TextureID Fill = TexMan.CheckForTexture("HPBFILNV", TexMan.Type_Any);
Vector2 Pos = (250, -175);
int DrawFlags = DI_ITEM_LEFT_TOP | DI_SCREEN_LEFT_BOTTOM;

double scale = double(value) / double(MaxValue);
double underScale = min(scale, 1.0) * MaxFillWidth;

DrawTexture(Fill, Pos, DrawFlags, scale: (underScale, 1));
As you can see, the 1×20 texture is scaled horizontally to fill desired rectangular area. Then the shader is run over it to produce the (incorrectly) skewed bar.

Does anyone have any idea how to make it skew like I want? Is it possible, under the current constraints of GZDoom custom texture shaders?
User avatar
Gutawer
Posts: 469
Joined: Sat Apr 16, 2016 6:01 am
Preferred Pronouns: She/Her

Re: Draw HUD status bar element with shader and bounding box

Post by Gutawer »

I'd imagine your issue is because the shader's coordinates are between 0 and 1, so shearing the vector is going to be fucked up once the texture is scaled. Ideally you'd need to scale the texture coordinates by the scaled size of the texture (then scale back to get it in range 0-1), but I'm not entirely sure if that's possible.
However, if all you want to do is draw a sheared gradient, here's a different approach - in a for loop, create a vector which keeps track of the starting position of the current line of pixels, and for every loop, draw the line of pixels using the HUD Fill function, then subtract 1 from the x counter (to go back 1 x coordinate, for the shear effect), and subtract 1 from the y counter to go down one pixel. Then, draw the next line, and repeat until you've drawn the entire bar - the width of the lines of pixels will represent how much of the total bar is drawn. For the gradient effect, you can fairly easily interpolate between two colors. It wouldn't be as fast as a shear on the GPU, but it has another advantage of being software-compatible, and it shouldn't be that slow - for example, if you have an 8 pixel tall bar, you only need to call Fill 8 times.
argv
Posts: 184
Joined: Tue Aug 30, 2016 4:47 pm

Re: Draw HUD status bar element with shader and bounding box

Post by argv »

Brilliant! That'd be 20 draw calls! It's, yeah, not as fast as drawing the whole thing with a shader, but 20 draw calls is a lot better than 100+. Also, no texture, which I assume will improve performance a little. Thanks!

Return to “Scripting”