surface.DrawGradientBox

Hey dudes :smiley:

This function creates rectangles with gradient effect (Alpha supported).

Usage: draw.GradientBox(PosX, PosY, Width, Height, Alignment, Color()…)
Valid arguments for Alignment: 0 - Vertical
1 - Horizontal

Outputs something like this:

http://s4.postimage.org/8m5l598mv/drawgradientbox001_03.jpg



local g_grds, g_wgrd, g_sz
function draw.GradientBox(x, y, w, h, al, ...)
	g_grds = {...}
	al = math.Clamp(math.floor(al), 0, 1)
	if(al == 1) then
		local t = w
		w, h = h, t
	end
	g_wgrd = w / (#g_grds - 1)
	local n
	for i = 1, w do
		for c = 1, #g_grds do
			n = c
			if(i <= g_wgrd * c) then break end
		end
		g_sz = i - (g_wgrd * (n - 1))
		surface.SetDrawColor(
			Lerp(g_sz/g_wgrd, g_grds[n].r, g_grds[n + 1].r),
			Lerp(g_sz/g_wgrd, g_grds[n].g, g_grds[n + 1].g),
			Lerp(g_sz/g_wgrd, g_grds[n].b, g_grds[n + 1].b),
			Lerp(g_sz/g_wgrd, g_grds[n].a, g_grds[n + 1].a))
		if(al == 1) then surface.DrawRect(x, y + i, h, 1)
		else surface.DrawRect(x + i, y, 1, h) end
	end
end


I’d like to know framerate before and after, please. Doing things like this have to have some pull on FPS, right?

[editline]21st January 2011[/editline]

Last gradient reminds me of dont_buff_my_pylon.

[editline]21st January 2011[/editline]

You also may want to optimize your function, considering this is done per-frame.

This is crazy awesome! But like Andrew said, it would probably be best to make sure the calculation is only run once, or maybe on a timer, but its very impressive either way!

In my AMD Athlon 2.0Ghz 3000+ (2006 processor) with nVidia Geforce FX 5200, the four gradient boxes used in screenshot my FPS dropped by 6 at 1024x768 (in clean gm_flatgrass)

I don’t think there’s a way to optimize it, a gradient is made by multiple lines with slightly different colors…

Create the locals outside of the function, this should save you two frames at most.

[editline]21st January 2011[/editline]

Also don’t bother clamping the values.

Code optimized! thanks amcwatters for the tips…

You should try to add stops, so you can have eg. 20 stops from the one color to the other…

Is this what you mean ?

First post updated, only one stop can be used…

I think he meant steps.

Very nice. Support for a curved one would be nice too

Fantastic. Mind if I throw this into Exsto? You’ll receive credit, of course.

Of course you can, Im sharing with everybody in hopes that might be usefull :smiley:

Holy canoli! That’s a lot of code. I would consider using a Color object instead of having all the different arguments. It’s a bit of a bitch to have to put in 8 different arguments instead of 2.

This is the code I used for gradients:

[lua]GRADIENT_HORIZONTAL = 0;
GRADIENT_VERTICAL = 1;
function draw.LinearGradient(x,y,w,h,from,to,dir,res)
dir = dir or GRADIENT_HORIZONTAL;
if dir == GRADIENT_HORIZONTAL then res = (res and res <= w) and res or w;
elseif dir == GRADIENT_VERTICAL then res = (res and res <= h) and res or h; end
for i=1,res do
surface.SetDrawColor(
Lerp(i/res,from.r,to.r),
Lerp(i/res,from.g,to.g),
Lerp(i/res,from.b,to.b),
Lerp(i/res,from.a,to.a)
);
if dir == GRADIENT_HORIZONTAL then surface.DrawRect(x + w * (i/res), y, w/res, h );
elseif dir == GRADIENT_VERTICAL then surface.DrawRect(x, y + h * (i/res), w, h/res ); end
end
end

– Example use
function panel:Paint()
draw.LinearGradient( 0, 0, self:GetWide(), self:GetTall(), color_white, color_black, GRADIENT_VERTICAL );
end
[/lua]

Which I used to make stuff like this:

[img_thumb]http://i182.photobucket.com/albums/x305/Entoros/dml3.png[/img_thumb]

It also allows you to specify the resolution of the texture for lower-quality if you need it. It doesn’t include stops, though.

Lol, I was wondering where the Lerp is.
Lerp makes everyone’s life so much easier :3

Here’s what I’ve been doing in Luapad. Only vertical though, because I didn’t need horizontal gradients.

[lua]local StartColor, EndColor = color_white, color_black;

local gx, gy, gw, gh = 0, 0, 128, 64;

local f;

for i=0, gh do
f = i / gh;

surface.SetDrawColor(
	math.min(Lerp(f, StartColor.r, EndColor.r), 255),
	math.min(Lerp(f, StartColor.g, EndColor.g), 255),
	math.min(Lerp(f, StartColor.b, EndColor.b), 255),
	255
);
surface.DrawLine(gx, gy + i, gx + gw, gy + i);

end[/lua]

Try to use surface.DrawRect only for now, it usually takes less performence then surface.DrawLine.

Also this should rather go into the draw library since surface is for C functions only…

[editline]22nd January 2011[/editline]

And overv should add this to gmod by default, doesn’t harm anyone.

[editline]22nd January 2011[/editline]

Oh and [lua]if(!w || !h || !x || !y || !r || !g || !b || !a || !r2 || !g2 || !b2 || !a2) then return end[/lua]

A coder should take care about the arguments himself, too many failsafe checks are bad.

If he doesn’t provide arguments. It’s his own fault :frowning:

I thought there were materials provided by gmod that did gradients. You draw the base colour (or nothing for transparent), then draw the gradient material over the top. The gradient material is just white fading to transparent, so you can colour the material to get the gradient between two colours. Much faster than drawing lines, although you might lose quality unless texture quality is set to high.

Those are limited by their resolution.

And the stop thing is not possible with this methode.

Update! :smiley:
Function name changed, as suggested by Wizard of Ass.
Using now the Lerp() function, thanks Entoros :smiley:

Now you can create rectangles with many gradient colors!

http://s4.postimage.org/8m5l598mv/drawgradientbox001_03.jpg