stevon8ter's color picker [FINISHED]

@Andrew_Stacey, how would the mesh shader vertices table need to be set? is there a specific order?

The quadrilateral is specified in the table v. Vertices 1 and 4 are opposite, as are vertices 2 and 3. So if it were a square, it would be:

3 --- 4
|         |
1 --- 2

The quadrilateral is triangulated into 1-2-4 and 1-3-4. We also pass in the table of vertices to the mesh, this is the line m.shader.vertices = v. The colours are passed in similarly: there is an obvious correspondence between the tables of vertices and colours.

The ordering of the vertices - in case you’re interested - in the quadrilateral is using a binary encoding (offset by one since Lua tables start at 1) then splitting into coordinates. In binary, and subtracting one, the above diagram is:

10 --- 11
 |          |
00 --- 01

so that’s x and y coordinates, except that I’ve put them the wrong way around (not that that matters).

(I haven’t done arbitrary texCoords, it puts the texture on the mesh fitting it in the corners. I intend to extend it.)

@Andrew_Stacey hmmm my head currently doesn’t get the hang of it xo


--# GradientFill
--Project: Gradient Fill
--Author: Andrew Stacey
--Version: 1.1
--Comments: Uploaded too many tabs!
--Options: 
--Tabs: GradientFill
--Dependencies:

if localise then localise("GradientFill") end

function setup()
    a = mesh()
    
    x = WIDTH/2
    y = HEIGHT/2
    
    vec = {vec2(x-100, y-100), vec2(x-100, y+100), vec2(x+100, y+100), vec2(x+100, y-100)}
    
    col = {color(255, 255, 255, 255), color(255, 0, 0, 255), color(127, 127, 127, 255), color(0, 0, 0, 255)}
    
    v = {}
    c = {}
    
    v[1] = vec[1]    c[1] = col[1]
    v[2] = vec[4]    c[2] = col[1]
    v[3] = vec[3]    c[3] = col[1]
    
    v[4] = vec[1]    c[4] = col[1]
    v[5] = vec[2]    c[5] = col[1]
    v[6] = vec[3]    c[6] = col[1]
    
    a.vertices = v
    a.colors = c

    a.shader = shaderGradientFill()
    a.shader.vertices = vec
    a.shader.colours = {
        color(0, 0, 0, 255),
        color(255, 0, 0, 255),
        color(0, 50, 255, 255),
        color(255, 255, 255, 255)
    }
end

function draw()
    background(40,40,50)
    a:draw()
end

function touched(t)
    
end


function shaderGradientFill ()
return shader([[
//
// 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;

//This is an output variable that will be passed to the fragment shader
varying highp vec3 vPosition;
void main()
{
    //Pass the mesh color to the fragment shader

    vPosition = position.xyz;
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],[[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform vec3 vertices[4];
uniform vec4 colours[4];

vec3 np = cross(vertices[0]-vertices[1],vertices[0]-vertices[2]);
vec3 nx = cross(np,vertices[0] - vertices[2]);
vec3 ny = cross(np,vertices[0] - vertices[1]);
vec3 ox = (dot(nx,vertices[0]-vertices[3])*vertices[1] - dot(nx,vertices[0]-vertices[1])*vertices[3]);
float dx = dot(nx,vertices[1] - vertices[3]);
vec3 oy = (dot(ny,vertices[0]-vertices[3])*vertices[2] - dot(ny,vertices[0]-vertices[2])*vertices[3]);
float dy = dot(ny,vertices[2] - vertices[3]);
vec3 vx = (vertices[1] - vertices[0])/dot(vertices[1] - vertices[0],vertices[1] - vertices[0]);
vec3 vy = (vertices[2] - vertices[0])/dot(vertices[2] - vertices[0],vertices[2] - vertices[0]);

varying highp vec3 vPosition;
void main()
{
    vec3 qx;
    vec3 qy;
    float x;
    float y;
    if (dx != 0.) {
        qx = (dot(ny,dx*vertices[0] - ox)*vPosition - dot(ny, vertices[0] - vPosition) * ox)/(dot(ny,dx*vPosition - ox));

    } else {
        qx = vPosition + dot(ny,vertices[0] - vPosition)*(vertices[2] - vertices[0])/dot(ny,vertices[2] - vertices[0]);
    }
    x = dot(qx - vertices[0],vx);
    if (dy != 0.) {
        qy = (dot(nx,dy*vertices[0] - oy)*vPosition - dot(nx, vertices[0] - vPosition) * oy)/(dot(nx,dy*vPosition - oy));
    } else {
        qy = vPosition + dot(nx,vertices[0] - vPosition)*(vertices[1] - vertices[0])/dot(nx,vertices[1] - vertices[0]);
    }
    y = dot(qy - vertices[0],vy);
    lowp vec4 tex = texture2D( texture, vec2(x,y) );
    lowp vec4 col = (1.-y)*(1.-x)*colours[0] + (1.-y)*x*colours[1] + y*(1.-x)*colours[2] + y*x*colours[3];
    //Set the output color to the texture color
    gl_FragColor = col*tex;
}
]])
end                

I could figure out the right positions :frowning:

The vertices should be

    vec = {vec2(x-100, y-100), vec2(x-100, y+100), vec2(x+100, y-100), vec2(x+100, y+100)}

and v[6] should be vec[4]

@Andrew_Stacey the vertices are now correct, howerver, I don’t assign a texture, and yet it displayez ‘Made With Codea’ inside the mesh, nothing else, just that, filled with a gradient

thanks so far already

If you dn’t want to assign a texture at all, remove the lowp vec4 tex = ... line and change the gl_FragColor to just col.

(There’s a bug whereby if you have a texture in the shader but don’t assign one then it uses one anyway.)

@Andrew_Stacey I did as you said and it now shows a blank screen


--# GradientFill
--Project: Gradient Fill
--Author: Andrew Stacey
--Version: 1.1
--Comments: Uploaded too many tabs!
--Options: 
--Tabs: GradientFill
--Dependencies:

if localise then localise("GradientFill") end

function setup()
    a = mesh()
    
    x = WIDTH/2
    y = HEIGHT/2
    
    vec = {vec2(x-100, y-100), vec2(x-100, y+100), vec2(x+100, y-100), vec2(x+100, y+100)}

    col = {color(255, 255, 255, 255), color(255, 0, 0, 255), color(127, 127, 127, 255), color(0, 0, 0, 255)}
    
    v = {}
    c = {}
    
    v[1] = vec[1]    c[1] = col[1]
    v[2] = vec[4]    c[2] = col[1]
    v[3] = vec[3]    c[3] = col[1]
    
    v[4] = vec[1]    c[4] = col[1]
    v[5] = vec[2]    c[5] = col[1]
    v[6] = vec[4]    c[6] = col[1]
    
    a.vertices = v
    a.colors = c

    a.shader = shaderGradientFill()
    a.shader.vertices = vec
    a.shader.colours = {
        color(0, 0, 0, 255),
        color(255, 0, 0, 255),
        color(0, 50, 255, 255),
        color(255, 255, 255, 255)
    }
end

function draw()
    background(40,40,50)
    a:draw()
end

function touched(t)
    
end


function shaderGradientFill ()
return shader([[
//
// 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;

//This is an output variable that will be passed to the fragment shader
varying highp vec3 vPosition;
void main()
{
    //Pass the mesh color to the fragment shader

    vPosition = position.xyz;
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],[[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform vec3 vertices[4];
uniform vec4 colours[4];

vec3 np = cross(vertices[0]-vertices[1],vertices[0]-vertices[2]);
vec3 nx = cross(np,vertices[0] - vertices[2]);
vec3 ny = cross(np,vertices[0] - vertices[1]);
vec3 ox = (dot(nx,vertices[0]-vertices[3])*vertices[1] - dot(nx,vertices[0]-vertices[1])*vertices[3]);
float dx = dot(nx,vertices[1] - vertices[3]);
vec3 oy = (dot(ny,vertices[0]-vertices[3])*vertices[2] - dot(ny,vertices[0]-vertices[2])*vertices[3]);
float dy = dot(ny,vertices[2] - vertices[3]);
vec3 vx = (vertices[1] - vertices[0])/dot(vertices[1] - vertices[0],vertices[1] - vertices[0]);
vec3 vy = (vertices[2] - vertices[0])/dot(vertices[2] - vertices[0],vertices[2] - vertices[0]);

varying highp vec3 vPosition;
void main()
{
    vec3 qx;
    vec3 qy;
    float x;
    float y;
    if (dx != 0.) {
        qx = (dot(ny,dx*vertices[0] - ox)*vPosition - dot(ny, vertices[0] - vPosition) * ox)/(dot(ny,dx*vPosition - ox));

    } else {
        qx = vPosition + dot(ny,vertices[0] - vPosition)*(vertices[2] - vertices[0])/dot(ny,vertices[2] - vertices[0]);
    }
    x = dot(qx - vertices[0],vx);
    if (dy != 0.) {
        qy = (dot(nx,dy*vertices[0] - oy)*vPosition - dot(nx, vertices[0] - vPosition) * oy)/(dot(nx,dy*vPosition - oy));
    } else {
        qy = vPosition + dot(nx,vertices[0] - vPosition)*(vertices[1] - vertices[0])/dot(nx,vertices[1] - vertices[0]);
    }
    y = dot(qy - vertices[0],vy);
    lowp vec4 col = (1.-y)*(1.-x)*colours[0] + (1.-y)*x*colours[1] + y*(1.-x)*colours[2] + y*x*colours[3];
    //Set the output color to the texture color
    //col = col*tex;
}
]])
end                

and yeah, you still gotta remove the comment of col = col*tex
I thought that what the problem because there not being a texture… commenting it out creates a funny effect tho :wink:

Sorry! I was typing late at night. I meant to change the col*tex to just col, not the whole line.

--The name of the project must match your Codea project name if dependencies are used. 
--Project: Place Project Name Here
--Author:
--Version: Alpha 1.0
--Comments:


if localise then localise("steven8trGradientFill") end

function setup()
    a = mesh()

    x = WIDTH/2
    y = HEIGHT/2

    vec = {vec2(x-100, y-100), vec2(x-100, y+100), vec2(x+100, y-100), vec2(x+100, y+100)}

    col = {color(255, 255, 255, 255), color(255, 0, 0, 255), color(127, 127, 127, 255), color(0, 0, 0, 255)}

    v = {}
    c = {}

    v[1] = vec[1]    c[1] = col[1]
    v[2] = vec[4]    c[2] = col[1]
    v[3] = vec[3]    c[3] = col[1]

    v[4] = vec[1]    c[4] = col[1]
    v[5] = vec[2]    c[5] = col[1]
    v[6] = vec[4]    c[6] = col[1]

    a.vertices = v
    a.colors = c

    a.shader = shaderGradientFill()
    a.shader.vertices = vec
    a.shader.colours = {
        color(0, 0, 0, 255),
        color(255, 0, 0, 255),
        color(0, 50, 255, 255),
        color(255, 255, 255, 255)
    }
end

function draw()
    background(40,40,50)
    a:draw()
end

function touched(t)

end


function shaderGradientFill ()
return shader([[
//
// 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;

//This is an output variable that will be passed to the fragment shader
varying highp vec3 vPosition;
void main()
{
    //Pass the mesh color to the fragment shader

    vPosition = position.xyz;
    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}
]],[[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
//uniform lowp sampler2D texture;
uniform vec3 vertices[4];
uniform vec4 colours[4];

vec3 np = cross(vertices[0]-vertices[1],vertices[0]-vertices[2]);
vec3 nx = cross(np,vertices[0] - vertices[2]);
vec3 ny = cross(np,vertices[0] - vertices[1]);
vec3 ox = (dot(nx,vertices[0]-vertices[3])*vertices[1] - dot(nx,vertices[0]-vertices[1])*vertices[3]);
float dx = dot(nx,vertices[1] - vertices[3]);
vec3 oy = (dot(ny,vertices[0]-vertices[3])*vertices[2] - dot(ny,vertices[0]-vertices[2])*vertices[3]);
float dy = dot(ny,vertices[2] - vertices[3]);
vec3 vx = (vertices[1] - vertices[0])/dot(vertices[1] - vertices[0],vertices[1] - vertices[0]);
vec3 vy = (vertices[2] - vertices[0])/dot(vertices[2] - vertices[0],vertices[2] - vertices[0]);

varying highp vec3 vPosition;
void main()
{
    vec3 qx;
    vec3 qy;
    float x;
    float y;
    if (dx != 0.) {
        qx = (dot(ny,dx*vertices[0] - ox)*vPosition - dot(ny, vertices[0] - vPosition) * ox)/(dot(ny,dx*vPosition - ox));

    } else {
        qx = vPosition + dot(ny,vertices[0] - vPosition)*(vertices[2] - vertices[0])/dot(ny,vertices[2] - vertices[0]);
    }
    x = dot(qx - vertices[0],vx);
    if (dy != 0.) {
        qy = (dot(nx,dy*vertices[0] - oy)*vPosition - dot(nx, vertices[0] - vPosition) * oy)/(dot(nx,dy*vPosition - oy));
    } else {
        qy = vPosition + dot(nx,vertices[0] - vPosition)*(vertices[1] - vertices[0])/dot(nx,vertices[1] - vertices[0]);
    }
    y = dot(qy - vertices[0],vy);
    //lowp vec4 tex = texture2D( texture, vec2(x,y) );
    lowp vec4 col = (1.-y)*(1.-x)*colours[0] + (1.-y)*x*colours[1] + y*(1.-x)*colours[2] + y*x*colours[3];
    //Set the output color to the texture color
    gl_FragColor = col; //*tex;
}
]])
end                

@Andrew_Stacey thank you so much, this look so much better + I can probably understand the calculations so thank you so much :slight_smile: I’ll work on this when I get home from school

New version on CC (will need same tweaks for non-textured meshes). Much simpler shader code.

@Andrew_Stacey thanks for all your effort in this, once I get some sleep and some time I’ll work on this class some more

I hope to get it running at 60fps for everyone :wink:
In my opinion it isn’t looking bad, but I know that noone would use this class, tho I need it for a project, so I thought I might as well share it :wink:

Edit: found it already, didn’t look it up before asking xo

Ok no more questions this time

Time for a major UPDATE

http://twolivesleft.com/Codea/CC/alpha/index.php?v=1353

It now has full power of a color picker, including alpha level selector, works with different sizes, tho I wouldn’t make it to small because of touch handling

Example included which shows 2 different-sized color pickers at work

I hope you enjoy this and that I get some critical feedback on this

any sugestions are welcome

Also, I wanna thank @Andrew_Stacey for his great help in the last major parts of color shading

Quite nice. 23Hz on ipad1: good!

@Jmv38 thx :slight_smile: I might try to speed it up some more, right now it’s all kinda messy xd

@Jmv38 could you tell me in what circumstances ylu get 23Hz? Like, how many colorpickers are drawn? and how many rings/squares are you touching?

Not much to say really. Just ran the program you posted. There are 2 color pickers showing, one big and one small, and your fps counter says 23. But what is the problem? I think 23 is very good already. You could make it 60hz by putting everything in a single image and sprite it, but is it really worth the effort?

@Jmv38 ok thanks, Idk, I just always want my classes to run as good as they ever could be, but for now I’ll leave it like this, gonna work on my sprite picker first :wink: