HSV colour transitions

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
luminosity
Prole
Posts: 34
Joined: Fri Sep 24, 2010 5:46 am

HSV colour transitions

Post by luminosity » Mon Jan 24, 2011 12:46 am

Something I did for my game recently was a small colour module to allow me to calculate transitions between two colours using the hsv colour space. This means I can make a gradient from one colour to another, without getting muddy-looking colours in the middle, which transitioning through RGB gets you. For instance, I use it to calculate what colour to draw a hit point bar, from red at 20% or below, to green at 80% or above.

The code is fairly game neutral so I thought people here might potentially find it useful, and it's nice to give back. Consider it public domain.

Code: Select all

local function smallColorRange(largeColor)
	return largeColor / 255
end

local function largeColorRange(smallColor)
	return math.floor(smallColor * 255 + 0.5)
end

local function pack(...)
	return arg
end

local function rgbToHsv(r, g, b)
	-- convert rgb from 0-255, to 0-1
	r = smallColorRange(r)
	g = smallColorRange(g)
	b = smallColorRange(b)
	local h, s, v
	local min = math.min(r, g, b)
	local max  = math.max(r, g, b)
	local delta = max - min
	-- value
	v = max
	-- saturation
	if delta ~= 0 then -- we know max won't be zero, as min can't be less than zero and the difference is not 0
		s = delta / max
	else
		h = -1
		s = 0
		return h, s, v
	end
	-- hue
	if r == max then -- yellow <-> magenta
		h = (g - b) / delta
	elseif g == max then -- cyan <-> yellow
		h = 2 + (b - r) / delta
	else -- magenta <-> cyan
		h = 4 + (r - g) / delta
	end
	h = h * 60 -- 60 degrees
	if h < 0 then
		h = h + 360
	end
	return h, s, v
end

local function hsvToRgb(h, s, v)
	local r, g, b
	if s == 0 then -- monochromatic
		-- restore colors from 0-1, to 0-255
		r = largeColorRange(v)
		g = largeColorRange(v)
		b = largeColorRange(v)
		return r, g, b
	end
	
	h = h / 60 -- sector of wheel
	local i = math.floor(h)
	local f = h - i -- factorial part of h
	local p = v * (1 - s)
	local q = v * (1 - s * f)
	local t = v * (1 - s * (1 - f))
	
	if i == 0 then
		r = v
		g = t
		b = p
	elseif i == 1 then
		r = q
		g = v
		b = p
	elseif i == 2 then
		r = p
		g = v
		b = t
	elseif i == 3 then
		r = p
		g = q
		b = v
	elseif i == 4 then
		r = t
		g = p
		b = v
	else
		r = v
		g = p
		b = q
	end
	
	r = largeColorRange(r)
	g = largeColorRange(g)
	b = largeColorRange(b)
	
	return r, g, b
end

local function gradientColor(color1, color2, proportion)
	if proportion < 0 or proportion > 1 then 
		error("Gradient proportion must be between 0 and 1.") 
	end
	
	local h1, s1, v1 = rgbToHsv(unpack(color1))
	local h2, s2, v2 = rgbToHsv(unpack(color2))
	-- find difference between two values, and advance proportion of that difference from value 1
	local hDiff = (h2 - h1) * proportion
	local sDiff = (s2 - s1) * proportion
	local vDiff = (v2 - v1) * proportion
	
	local gradH = hDiff + h1
	local gradS = sDiff + s1
	local gradV = vDiff + v1
	
	return pack(hsvToRgb(gradH, gradS, gradV))
end

return {
	rgbToHsv=rgbToHsv,
	hsvToRgb=hsvToRgb,
	gradientColor=gradientColor,
}
So to use it I'd say

Code: Select all

local Color = require('color')

-- randomly picked probably ugly colours
local red = {200, 20, 20}
local green = {30, 200, 10}
local hpBarColor = Color.gradientColor(red, green, curHP / totalHP)

User avatar
TechnoCat
Inner party member
Posts: 1611
Joined: Thu Jul 30, 2009 12:31 am
Location: Denver, CO
Contact:

Re: HSV colour transitions

Post by TechnoCat » Mon Jan 24, 2011 3:50 am

Oh my, HSV is very yummy.
800px-HSV_color_solid_cylinder_alpha_lowgamma.png
Colorful Cake.
800px-HSV_color_solid_cylinder_alpha_lowgamma.png (253.63 KiB) Viewed 771 times
The hue saturation approach to color is very useful indeed. Thank you for the contribution.

User avatar
Taehl
Dreaming in associative arrays
Posts: 1024
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

Re: HSV colour transitions

Post by Taehl » Tue Jan 25, 2011 11:29 pm

I, personally, prefer HSL, Photoshop be damned. I've put my conversion function on the wiki, in case anyone wants it.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.

Post Reply

Who is online

Users browsing this forum: No registered users and 23 guests