Color Constant Trick

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Color Constant Trick

Post by ejmr »

I recently posted a thread asking for some help, and got some great responses. So I wanted to give back by sharing a trick I learned while working on my current game project which others may find useful.

I found myself reading writing lots of calls like

Code: Select all

love.graphics.setColor(96, 85, 64)
Unless you are really familiar with your RGB values---and I am not---you may not know that creates a dark orange color. I wanted to create named color constants. So at first I created a table like so:

Code: Select all

Colors = {}
Colors.darkOrange = { 96, 85, 64 }
Colors.yellow = { 196, 196, 0 }
-- And so on.
The Lua function unpack() lets you take an array/table and expand its values as the parameters to a function call. So this let me go back and start writing

Code: Select all

love.graphics.setColor(unpack(Colors.yellow))
Except I felt calling unpack() every time was tedious on its own. Enter the usefulness of metatable functions. You can change the __index() function for a table to automatically unpack values. So I returned to my table of colors and added this:

Code: Select all

Colors.__index =
    function (table, key)
        local value = rawget(table, key)

        if value ~= nil then
            return unpack(value)
        else
            return nil
        end
    end
Now writing Colors.yellow is the same as unpack(Colors.yellow). This let me return to my original code and replace it with the more readable (in my opinion)

Code: Select all

love.graphics.setColor(Colors.darkOrange)
.

Just a simple trick I wanted to share that maybe some of you will find useful.
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
User avatar
Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

Re: Color Constant Trick

Post by Xgoff »

i'd be surprised if that would work because iirc __index always truncates to 1 return value

also, setColor can take a table directly so you don't need to unpack anyway
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Re: Color Constant Trick

Post by ejmr »

Xgoff wrote:i'd be surprised if that would work because iirc __index always truncates to 1 return value
It works without any errors or problems.
also, setColor can take a table directly so you don't need to unpack anyway
Looks like a change added in version 7.0.0. Thanks for pointing this out.
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
User avatar
Xgoff
Party member
Posts: 211
Joined: Fri Nov 19, 2010 4:20 am

Re: Color Constant Trick

Post by Xgoff »

ejmr wrote:
Xgoff wrote:i'd be surprised if that would work because iirc __index always truncates to 1 return value
It works without any errors or problems.
actually, it works because of setColor's table support; __index doesn't even get called since the fields already exist in the Colors table
User avatar
OmarShehata
Party member
Posts: 259
Joined: Tue May 29, 2012 6:46 pm
Location: Egypt
Contact:

Re: Color Constant Trick

Post by OmarShehata »

Neat trick though! Thanks for posting.
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Re: Color Constant Trick

Post by ejmr »

Thanks! Xgoff is correct, however, in that __index() is not even called in my specific example. But the trick could be useful in other situations where you want to unpack() something automatically or modify the behavior of normal table access.

Ah, I do love the power of metatables in Lua :)
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: Color Constant Trick

Post by coffee »

ejmr wrote:Just a simple trick I wanted to share that maybe some of you will find useful.
Thanks. As alternative method you wouldn't need to metatable or unpack nothing if you use a shortcut function to the long love.graphics.setColor. I did it here viewtopic.php?f=4&t=4854#p41738 for a shorter custom setColor(). As you see do basically the same constant color trick and as extra also use alpha naming/gradations. But your unpack method in vanilla command is also neat. :)
Miko did something close to yours here viewtopic.php?f=4&t=4854#p41760

BTW scirath's color management viewtopic.php?f=5&t=7378 is a very good advanced application of your naming concept.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Color Constant Trick

Post by kikito »

ejmr wrote:It works without any errors or problems.
I have not tried it, but I'm very sure trying to combine the Colors lib with an alpha value would fail:

Code: Select all

love.graphics.setColor(Colors.darkOrange, 128) -- I want to apply the color, and some alpha, too
To be fair, an explicit unpack would also fail.

Code: Select all

love.graphics.setColor(unpack(Colors.darkOrange), 128) -- same kind of fail
The only way I think this would work would be making darkOrange a function (or probably a callable table), so it can accept-and-pass an alpha value. In other words, to be used like this:

Code: Select all

love.graphics.setColor(Colors.darkOrange(128)) -- this could work, but requires more plumbing into the colors 
When I write def I mean function.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: Color Constant Trick

Post by coffee »

kikito wrote:
ejmr wrote:It works without any errors or problems.
I have not tried it, but I'm very sure trying to combine the Colors lib with an alpha value would fail:

Code: Select all

love.graphics.setColor(Colors.darkOrange, 128) -- I want to apply the color, and some alpha, too
To be fair, an explicit unpack would also fail.

Code: Select all

love.graphics.setColor(unpack(Colors.darkOrange), 128) -- same kind of fail
The only way I think this would work would be making darkOrange a function (or probably a callable table), so it can accept-and-pass an alpha value. In other words, to be used like this:

Code: Select all

love.graphics.setColor(Colors.darkOrange(128)) -- this could work, but requires more plumbing into the colors 
I pointed before miko method. Don't his way solve that problem?
viewtopic.php?f=4&t=4854#p41760

Code: Select all

ALPHAS={['half']=128, ['total']=0, ['opaque']=255}
COLORS={['black']={0,0,0}, ['white']={255,255,255}}
MT_Color={
  alpha=function(self, a)
    if not a then return end
    self[4]=ALPHAS[a] or tonumber(a)
  end,
  RGB=function(self, r, g, b)
    if not r then return end
    if type(r)=='string' then
      local c=COLORS[r]
      if c then
        for i=1,3 do
          self[i]=c[i]
        end
      else
        error('Unknown color: '..r)
      end
    else
      self[1], self[2], self[3]=r, g, b
    end
  end
}
MT_Color.__index=MT_Color

function newColor(r, g, b, a)
  local o=setmetatable({0,0,0,0}, MT_Color)
  o:RGB(r, g, b)
  o:alpha(a or 255)
  return o
end

green=newColor(0,255,0)
print('green 1', unpack(green))
green:alpha('half')
print('green 2', unpack(green))
green:RGB('white')
print('green 3', unpack(green))
love.graphics.setColor(green)
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Re: Color Constant Trick

Post by ejmr »

kikito wrote:
ejmr wrote:It works without any errors or problems.
I have not tried it, but I'm very sure trying to combine the Colors lib with an alpha value would fail:

Code: Select all

love.graphics.setColor(Colors.darkOrange, 128) -- I want to apply the color, and some alpha, too
This is true; it does fail in this circumstance. Thank you for pointing out this short-coming so I can rectify it in my own project.
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests