HSV Color Picker and Sprite Creator

Hey everyone!
I’ve been working on the newest version of my drawing app, and I just finished a quick (actually not so quick) test for my color picker! I somehow managed to figure out the shader code, and I am quite happy with how it turned out! So far I haven’t found anything similar on the forum—using shaders at least—so I thought it might be useful to share!

--# Main
-- HSV Shader

function setup()
    m = mesh()
    m:addRect(WIDTH/2,HEIGHT/2,200,200)
    m.shader = shader(vertex,fragment)
    hue = 0
    
    ring = mesh()
    res = 180
    local v = {}
    local c = {}
    
    for i = 1,res do
        local v1 = vec2(0,200):rotate((i-1)*math.pi*2/-res)
        local v2 = vec2(0,200):rotate(i*math.pi*2/-res)
        local v3 = vec2(0,150):rotate(i*math.pi*2/-res)
        local v4 = vec2(0,150):rotate((i-1)*math.pi*2/-res)
        local r,g,b
        r,g,b = hsvToRgb((i-1)/res,1,1)
        local c1 = color(r,g,b,255)
        r,g,b = hsvToRgb(i/res,1,1)
        local c2 = color(r,g,b,255)
        for i,vv in pairs({v1,v2,v3,v3,v4,v1}) do table.insert(v,vv) end
        for i,cc in pairs({c1,c2,c2,c2,c1,c1}) do table.insert(c,cc) end
    end
    ring.vertices = v
    ring.colors = c
end

function draw()
    background(40, 40, 50)
    
    pushMatrix()
    translate(WIDTH/2,HEIGHT/2)
    -- scale(3)
    ring:draw()
    popMatrix()
    
    hue = hue + DeltaTime/5
    if hue > 1 then hue = hue - 1 end
    m.shader.h = hue
    m:draw()
end

function hsvToRgb(h,s,v)
  local r,g,b

  local i = math.floor(h * 6);
  local f = h * 6 - i;
  local p = v * (1 - s);
  local q = v * (1 - f * s);
  local t = v * (1 - (1 - f) * s);

  i = i % 6

  if i == 0 then r, g, b = v, t, p
  elseif i == 1 then r, g, b = q, v, p
  elseif i == 2 then r, g, b = p, v, t
  elseif i == 3 then r, g, b = p, q, v
  elseif i == 4 then r, g, b = t, p, v
  elseif i == 5 then r, g, b = v, p, q
  end

  return r * 255, g * 255, b * 255
end

vertex = [[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;
    
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
  ]]
fragment = [[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform float h;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    // float h = 0.7;
    float s = vTexCoord.x;
    float v = vTexCoord.y;
    float r,g,b;

    float i = h*6.0;
    i = floor(i);
    float f = h * 6. - i;
    float p = v * (1. - s);
    float q = v * (1. - f * s);
    float t = v * (1. - (1. - f) * s);
    
    if (i == 0.) r=v,g=t,b=p;
    if (i == 1.) r=q,g=v,b=p;
    if (i == 2.) r=p,g=v,b=t;
    if (i == 3.) r=p,g=q,b=v;
    if (i == 4.) r=t,g=p,b=v;
    if (i == 5.) r=v,g=p,b=q;
    
    highp vec4 col = vec4(r,g,b,1.0);

    gl_FragColor = col;
}
]]

EDIT: I added a fancy color wheel

Here’s another bit of code I wrote:
This is the conversion algorithm I used for switching between RGB and HSV. I also included sliders that will show the RGB and HSV values of your color


--# Main
-- RGBHSV

function setup()
    r,g,b = 0,0,0
    h,s,v = 0,0,0
    parameter.integer("h",0,255,0,hsv)
    parameter.integer("s",0,255,255,hsv)
    parameter.integer("v",0,255,255,hsv)
    parameter.integer("r",0,255,255,rgb)
    parameter.integer("g",0,255,255,rgb)
    parameter.integer("b",0,255,255,rgb)
    parameter.integer("a",0,255,255)
end

function draw()
    background(40,40,50)
    fill(r,g,b,a)
    ellipse(WIDTH/2,HEIGHT/2,200)
end

function rgb()
    h,s,v = rgbToHsv(r,g,b)
    h,s,v = math.floor(h*255),math.floor(s*255),math.floor(v*255)
end

function hsv()
    r,g,b = hsvToRgb(h/255,s/255,v/255)
    r,g,b = math.floor(r),math.floor(g),math.floor(b)
end

function rgbToHsv(r, g, b, a)
  r, g, b = r / 255, g / 255, b / 255
  local max, min = math.max(r, g, b), math.min(r, g, b)
  local h, s, v
  v = max

  local d = max - min
  if max == 0 then s = 0 else s = d / max end

  if max == min then
    h = 0 -- achromatic
  else
    if max == r then
    h = (g - b) / d
    if g < b then h = h + 6 end
    elseif max == g then h = (b - r) / d + 2
    elseif max == b then h = (r - g) / d + 4
    end
    h = h / 6
  end

  return h, s, v, a
end

function hsvToRgb(h, s, v)
  local r, g, b

  local i = math.floor(h * 6);
  local f = h * 6 - i;
  local p = v * (1 - s);
  local q = v * (1 - f * s);
  local t = v * (1 - (1 - f) * s);

  i = i % 6

  if i == 0 then r, g, b = v, t, p
  elseif i == 1 then r, g, b = q, v, p
  elseif i == 2 then r, g, b = p, v, t
  elseif i == 3 then r, g, b = p, q, v
  elseif i == 4 then r, g, b = t, p, v
  elseif i == 5 then r, g, b = v, p, q
  end

  return r * 255, g * 255, b * 255
end

Here’s a look at my updated color picker UI!
I’m still trying to decide on the main color wheel, though? Do you guys prefer it smaller or bigger? I kinda like it bigger for having more accuracy, but I don’t want it to totally get in the way…

The right side of the screen is currently empty. I’m probably going to add tools like tolerance, blend modes, saved colors and color history, but I’m open to suggestions for other color-related tools!

nice! B)

@yojimbo2000 thank you!

You know, while I’m at it, I should share the previous version of my app. This is version 2.0
https://gist.github.com/Dwiniflin/c59ec5bd50225f2239a89f53a72c0c0e
It works fairly well, but I ran into a lot of bugs I couldn’t figure out, and the code was messy and frustrating to work with. I’m currently working on version 3.0 (I won’t bother sharing version 1.0, it was awful) and I thought it might be helpful if you guys could test it out and give me feedback on what you like and what you hate from 2.0 so I’ll know what to work on in the new version. Thanks everyone!!!

Here’s a couple screenshots:

I love it :3

There’s however some glitches that you migth have noticed:
-Parts of drawing not dissapearing after pressing the trash can
-Upon selecting rotate tool and pressig the screen it will return an error something like this: :837: could not perform arithmetic on nil value, pos

The GUI has a nice feel to it with the exception of the undo and redo buttons being badly placed.

@Dwins I’m confused. Most of the icons, such as the magnifying glasses and the grid toggle, are clean and sharp and beautiful. Where are they coming from?

@UberGoober I guess I drew those somewhere else… probably lost somewhere in the Main tab… Like I said, this is kind of an old project, and I was a slightly less organized programmer back when I made it

What pops out to me is that almost all the icons are really nice except for the most important ones: the drawing tools. Are they supposed to look low-res in a nod to the big pixels in the sprites themselves? They are very hard to read in any case, I’d like to see you sharpen them up if you’re up for it.

My guess is that you’ve abandoned this project by now, but thought I’d give my two cents!

In general this is a really nice job with an attractive design and UI.

@UberGoober thanks!
For the icons, I thought it would be a pain to have a bunch of assets people would have to download for them to show up in the project, so I made a separate Icons tab that draws each of them. I’m currently working on a newer version that I’m trying to clean up and simplify, so I’ll definitely keep your suggestion in mind!