Hi. I had to catch some pneumonia to get time to use Codea again. I’m writing a color picker, and wondered if anyone has made a solution to find a cursor position for a given color in a color picker? The other way around is easier.
I want to call picker:setColor(c) and I want the UI to find a suitable place in the picker where the color c exists.
Here is the code for my Picker.
Edit: Updated with a solution
--# Main
-- Picker
function setup()
-- displayMode(FULLSCREEN)
p = Picker(200)
parameter.color("C", color(255,255,255), function (c)
p:setColor(c)
end)
end
function draw()
background(p.color)
translate(WIDTH/2,HEIGHT/2)
p:draw()
end
function touched(touch)
p:touched(touch)
end
--# Picker
Picker = class()
function Picker:init(size)
self.size = size or 200
self.m = matrix()
self:createHexagon()
self:createShadeSlider()
self:touched(vec2(0,0)) -- set start color white
end
function Picker:hexVector(i)
local a = i/6 * math.pi * 2 + math.pi/6
return vec2(math.cos(a), math.sin(a)) * self.size
end
function Picker:setColor(c)
local rv = self:hexVector(4) -- where red is 0
local gv = self:hexVector(6) -- where green is 0
local bv = self:hexVector(2) -- where blue is 0
local m = math.max(c.r, c.g, c.b)
self:setShade(m)
local p = (rv * (m - c.r) + gv * (m - c.g) + bv * (m - c.b))/255
self:touchedHexagon(p)
end
function Picker:createHexagon()
local vs, cs, colors = {}, {}, {
color(255, 255, 255, 255),
color(255, 0, 0, 255),
color(255, 255, 0, 255),
color(0, 255, 0, 255),
color(0, 255, 255, 255),
color(0, 0, 255, 255),
color(255, 0, 255, 255)
}
for i=1,6 do
table.insert(vs, vec2(0,0))
table.insert(cs, colors[1])
table.insert(vs, self:hexVector(i))
table.insert(cs, colors[i+1])
table.insert(vs, self:hexVector(i+1))
table.insert(cs, colors[i+2] or colors[2])
end
self.hexagon = mesh()
self.hexagon.vertices = vs
self.hexagon.colors = cs
self.colors = cs
self.hexagon.shader = self:circleShader()
end
function Picker:updateCenterColor(c)
local cs = self.colors
for i=1,6*3,3 do
cs[i] = c
end
self.hexagon.colors = cs
self:touchedHexagon(self.pos)
end
function Picker:createShadeSlider()
local x, y = self.size*(math.sqrt(3)/2)+10, self.size
local w, h = 44, y*2
self.sliderCenterX = x + w/2
local vs = {
vec2(x,y),vec2(x+w,y), vec2(x+w,y-h),
vec2(x,y),vec2(x+w,y-h),vec2(x,y-h)
}
local bc, wc = color(0,0,0,255), color(255,255,255,255)
self.slider = mesh()
self.slider.vertices = vs
self.slider.colors = {wc,wc,bc,wc,bc,bc}
self.slider.shader = self:circleShader()
self.bpos = vec2(x+w/2,y)
self.bcolor = wc
end
function Picker:setShade(v)
local p = vec2(self.sliderCenterX, -self.size + self.size*2*v/256)
self:touchedShadeSlider(p)
end
function Picker:draw()
self.m = modelMatrix()
self.hexagon.shader.p = self.pos
self.hexagon.shader.c = self.color
self.hexagon:draw()
self.slider.shader.p = self.bpos
self.slider.shader.c = self.bcolor
self.slider:draw()
end
function Picker:touched(touch)
local p = vec2(touch.x-self.m[13], touch.y-self.m[14])
if not self:touchedHexagon(p) then
self:touchedShadeSlider(p)
end
end
function Picker:touchedHexagon(p)
local c = self:touchedMesh(p, self.hexagon)
if c then
self.color, self.pos = c, p
return true
end
end
function Picker:touchedShadeSlider(p)
local c = self:touchedMesh(p, self.slider)
if c then
p.x = self.sliderCenterX
self.bcolor, self.bpos = c, p
self:updateCenterColor(c)
end
end
function Picker:touchedMesh(p, h)
for i=1,#h.vertices,3 do
local a, b, c = h.vertices[i], h.vertices[i+1], h.vertices[i+2]
local inside, u, v = insideTriangle(a,b,c,vec3(p.x,p.y,0))
if inside then
local d, e, f = h.colors[i]*255, h.colors[i+1]*255, h.colors[i+2]*255
return (1-u-v)*d + u*f + v*e -- color in triangle
end
end
end
function Picker:circleShader()
return shader([[
uniform mat4 modelViewProjection;
attribute vec4 position;
varying highp vec2 vTexCoord;
attribute vec4 color;
varying lowp vec4 vColor;
void main() {
vTexCoord = position.xy;
vColor = color;
gl_Position = modelViewProjection * position;
}
]],[[
precision highp float;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
uniform vec2 p;
uniform vec4 c;
void main() {
lowp vec4 col = vColor;
float l = length(vTexCoord - p);
if(l < 20.) {
col = c;
} else if(l < 22.) {
// complementary brightness for circle border
float y = 1. - (0.2126*col.x + 0.7152*col.y + 0.0722*col.z);
col = vec4(y, y, y, 1.);
}
gl_FragColor = col;
}
]])
end
--# Utils
-- texture coordinates for p in the triangle a,b,c
function uv(a, b, c, p)
local v0 = c - a
local v1 = b - a
local v2 = p - a
local dot00 = v0:dot(v0)
local dot01 = v0:dot(v1)
local dot02 = v0:dot(v2)
local dot11 = v1:dot(v1)
local dot12 = v1:dot(v2)
-- Compute barycentric coordinates
local invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
local u = (dot11 * dot02 - dot01 * dot12) * invDenom
local v = (dot00 * dot12 - dot01 * dot02) * invDenom
return u, v
end
function insideTriangle(a, b, c, p)
local u, v = uv(a,b,c,p)
return (u >= 0) and (v >= 0) and (u + v < 1), u, v
end