color wheel and picker

This commit is contained in:
2017-12-05 22:25:38 +00:00
parent 8a21f3f78a
commit 9978709645
12 changed files with 226 additions and 42 deletions

View File

@@ -251,11 +251,16 @@
<node grow="1" width="10" align="center">
<text id="title" text="Color Picker" font-face="arial" font-size="11"/>
</node>
<combobox justify="flex-end" pad="5" margin="0 5 0 0" text="Triangle" combo-list="Triangle,Square" default="0"/>
<!--<combobox justify="flex-end" pad="5" margin="0 5 0 0" text="Triangle" combo-list="Triangle,Square" default="0"/>-->
</border>
<border width="300" color=".5 .5 .5 .9" pad="10" dir="col">
<colorwheel id="wheel" width="100%" aspect-ratio="1"/>
<border color="1" pad="5" dir="row" margin="10 0 0 0">
<border border-color="0 0 0 1" thickness="1" id="color-cur" height="30" grow="1" color="1"/>
<border border-color="0 0 0 1" thickness="1" id="color-old" height="30" grow="1" color="0"/>
<border border-color="0 0 0 1" thickness="1" id="color-old1" height="30" grow="1" color="0"/>
<border border-color="0 0 0 1" thickness="1" id="color-old2" height="30" grow="1" color="0"/>
</border>
<node width="100%" pad="2" height="20" dir="row" align="center" margin="10 0 0 0">
<node width="20"><text text="H" font-face="arial" font-size="11"/></node>
<slider-h id="hsv-h" width="10" grow="1" value="1"/>
@@ -280,7 +285,7 @@
</border>
<node height="33" dir="row" align="flex-end" justify="flex-end">
<button id="btn-ok" text="Reset" width="60" height="30" margin="0 10 0 0"/>
<button id="btn-cancel" text="Select color" width="100" height="30"/>
<button id="btn-select" text="Select color" width="100" height="30"/>
</node>
</border>
</border>
@@ -730,6 +735,6 @@
<text text="#opengl #fromscratch #c++" font-face="arial" font-size="11" margin="0 0 0 10" color=".2 .5 1 1"/>
</border>-->
</node>
<color-picker/>
<!--<color-picker/>-->
</layout>
</root>

View File

@@ -259,8 +259,8 @@ void App::update(float dt)
stroke->update_controls();
auto pix = ui::Canvas::I->m_current_brush.m_tip_color;
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
color->m_hue->set_value(hsv.x);
color->m_quad->set_value(hsv.y, 1.f - hsv.z);
color->m_hue->m_value.y = hsv.x;
color->m_quad->m_value = glm::vec2(hsv.y, 1.f - hsv.z);
auto observer = [this](Node* n)
{

View File

@@ -177,7 +177,7 @@ void App::initShaders()
"}";
static const char* shader_color_quad_f =
SHADER_VERSION
"uniform mediump vec4 col;"
"uniform mediump vec4 col; // HSV\n"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"mediump vec3 rgb2hsv(mediump vec3 c) {"
@@ -194,8 +194,7 @@ void App::initShaders()
" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
"}"
"void main() {"
" mediump float hue = rgb2hsv(col.rgb).x;"
" frag = vec4(hsv2rgb(vec3(hue, uv.x, 1.0 - uv.y)), 1.0);"
" frag = vec4(hsv2rgb(vec3(col.x, uv.x, 1.0 - uv.y)), 1.0);"
"}";
// COLOR TRI
static const char* shader_color_tri_f =

View File

@@ -29,7 +29,7 @@ void NodeColorQuad::set_value(float x, float y)
{
auto sz = m_size;
auto pos = glm::clamp(glm::vec2(x, y) * sz, { 0, 0 }, sz);
m_picker->SetPosition(pos - m_picker->GetSize() * .5f);
//m_picker->SetPosition(pos - m_picker->GetSize() * .5f);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0
if (on_value_changed)
on_value_changed(this, m_value);
@@ -86,6 +86,11 @@ kEventResult NodeColorQuad::handle_event(Event* e)
void NodeColorQuad::draw()
{
m_picker->m_border_color = m_value.y > .5f ? glm::vec4(1) : glm::vec4(0, 0, 0, 1);
auto sz = m_size;
auto pos = glm::clamp(m_value * sz, { 0, 0 }, sz);
m_picker->SetPosition(pos - m_picker->GetSize() * .5f);
using namespace ui;
ui::ShaderManager::use(kShader::ColorQuad);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include "node_colorwheel.h"
#include "shader.h"
#include "log.h"
Node* NodeColorWheel::clone_instantiate() const
{
@@ -11,10 +12,12 @@ void NodeColorWheel::clone_finalize(Node* dest) const
{
NodeColorWheel* n = (NodeColorWheel*)dest;
n->init_controls();
n->m_mouse_ignore = false;
}
void NodeColorWheel::init()
{
m_mouse_ignore = false;
//init_template("color-picker");
init_controls();
}
@@ -26,7 +29,11 @@ void NodeColorWheel::init_controls()
void NodeColorWheel::loaded()
{
m_circle.create<64>(.5, .4, ui::Circle::kUVMapping::Tube);
m_cur_hue.create<16>(.05);
m_cur_hue.create<16>(.05, 0.04);
m_cur_quad.create<16>(.04, 0.03, ui::Circle::kUVMapping::Tube);
float quad_scale = glm::sin(glm::radians(45.f)) * 0.8f;
m_quad.create<1>(quad_scale, quad_scale);
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; glm::vec4 col; };
std::vector<vertex_t> vertices;
@@ -58,20 +65,125 @@ void NodeColorWheel::draw()
glDisable(GL_BLEND);
ShaderManager::use(kShader::ColorHue);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::eulerAngleZ(glm::radians(-90.f)));
ShaderManager::u_int(kShaderUniform::Direction, 0); // set horizontal
m_circle.draw_fill();
ShaderManager::use(kShader::ColorTri);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ShaderManager::u_vec4(kShaderUniform::Col, {1, 0, 0, 1});
GLenum type = GL_TRIANGLES;
glBindVertexArray(arrays);
glDrawArrays(type, 0, 3);
glBindVertexArray(0);
// ShaderManager::use(kShader::ColorTri);
// ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
// ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(m_hsv, 0.f));
// GLenum type = GL_TRIANGLES;
// glBindVertexArray(arrays);
// glDrawArrays(type, 0, 3);
// glBindVertexArray(0);
ShaderManager::use(kShader::Color);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::eulerAngleZ(glm::radians(360.f * m_hsv.x)) * glm::translate(glm::vec3(.45,0,0)));
ShaderManager::u_vec4(kShaderUniform::Col, {1, 1, 1, 1});
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::eulerAngleZ(glm::radians(-360.f * m_hsv.x)) * glm::translate(glm::vec3(.45f,0.f,0.f)));
ShaderManager::u_vec4(kShaderUniform::Col, {convert_hsv2rgb({glm::fract(m_hsv.x + 0.5f), 1.f, 1.f}), 1.f});
m_cur_hue.draw_stroke();
ShaderManager::use(kShader::ColorQuad);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(m_hsv, 0.f));
m_quad.draw_fill();
float quad_scale = glm::sin(glm::radians(45.f)) * 0.8f;
glm::vec3 pos = glm::vec3(glm::vec2(m_hsv.y, 1.f - m_hsv.z) - 0.5f, 0);
ShaderManager::use(kShader::Color);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::translate(pos * quad_scale));
ShaderManager::u_vec4(kShaderUniform::Col, {convert_hsv2rgb({glm::fract(m_hsv.x + 0.5f), 1.f, 1.f}), 1.f});
m_cur_quad.draw_fill();
}
glm::vec4 NodeColorWheel::get_quad_rect() const
{
float quad_scale = glm::sin(glm::radians(45.f)) * 0.8f;
glm::vec2 size = m_size * quad_scale;
glm::vec2 pos = (m_size - size) * 0.5f;
return glm::vec4(pos, size);
}
bool NodeColorWheel::inside_quad(glm::vec2 pos, glm::vec2& out_coord) const
{
auto r = get_quad_rect();
out_coord = (pos - xy(r)) / zw(r);
return point_in_rect(pos, r);
}
void NodeColorWheel::handle_color_change()
{
if (on_value_changed)
on_value_changed(this, m_hsv);
}
kEventResult NodeColorWheel::handle_event(Event* e)
{
Node::handle_event(e);
auto* me = static_cast<MouseEvent*>(e);
switch (e->m_type)
{
case kEventType::MouseDownL:
{
m_old_value = m_hsv;
dragging = true;
mouse_capture();
auto pos = (me->m_pos - m_pos - GetSize() * 0.5f) / GetSize();
float l = glm::length(pos);
glm::vec2 quad_pos(0);
if (inside_quad(me->m_pos - m_pos, quad_pos))
{
mode = 2;
m_hsv.y = glm::clamp(quad_pos.x, 0.f, 1.f);
m_hsv.z = 1.f - glm::clamp(quad_pos.y, 0.f, 1.f);
handle_color_change();
}
else if (l >= 0.4f && l <= 0.5f)
{
mode = 1;
auto pos = glm::normalize(me->m_pos - m_pos - GetSize() * 0.5f);
m_hsv.x = (glm::atan(pos.y, -pos.x) + glm::pi<float>()) / glm::two_pi<float>();
handle_color_change();
}
else
{
mode = 0;
}
}
break;
case kEventType::MouseUpL:
mouse_release();
dragging = false;
break;
case kEventType::MouseMove:
if (dragging)
{
if (mode == 1)
{
auto pos = glm::normalize(me->m_pos - m_pos - GetSize() * 0.5f);
m_hsv.x = (glm::atan(pos.y, -pos.x) + glm::pi<float>()) / glm::two_pi<float>();
handle_color_change();
}
else if (mode == 2)
{
glm::vec2 quad_pos(0);
inside_quad(me->m_pos - m_pos, quad_pos);
m_hsv.y = glm::clamp(quad_pos.x, 0.f, 1.f);
m_hsv.z = 1.f - glm::clamp(quad_pos.y, 0.f, 1.f);
handle_color_change();
}
}
break;
case kEventType::MouseCancel:
mouse_release();
dragging = false;
m_hsv = m_old_value;
handle_color_change();
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}

View File

@@ -3,21 +3,33 @@
#include "node.h"
#include "shape.h"
#include "node_slider.h"
#include "node_border.h"
class NodeColorWheel : public Node
{
public:
ui::Circle m_circle;
ui::Circle m_cur_hue;
ui::Plane m_cur_hue;
ui::Circle m_cur_quad;
ui::Plane m_quad;
NodeBorder* m_color_cur;
glm::vec3 m_hsv;
GLuint m_tri_vbo;
GLuint m_tri_vao;
GLuint buffers;
GLuint arrays;
std::function<void(Node* target, glm::vec3 hsv)> on_value_changed;
int mode; // 1:hue 2:quad
bool dragging = false;
glm::vec3 m_old_value{0.f};
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
virtual void loaded() override;
virtual void draw() override;
virtual kEventResult handle_event(Event* e) override;
void init_controls();
glm::vec4 get_quad_rect() const;
bool inside_quad(glm::vec2 pos, glm::vec2& out_coord) const;
void handle_color_change();
};

View File

@@ -25,15 +25,20 @@ void NodeColorPicker::init()
void NodeColorPicker::draw()
{
NodeBorder::draw();
glm::vec3 rgb = glm::vec3(ui::Canvas::I->m_current_brush.m_tip_color);
glm::vec3 hsv = convert_rgb2hsv(rgb);
m_slider_h->set_value(hsv.x);
m_slider_s->set_value(hsv.y);
m_slider_v->set_value(hsv.z);
m_slider_r->set_value(rgb.x);
m_slider_g->set_value(rgb.y);
m_slider_b->set_value(rgb.z);
m_wheel->m_hsv = hsv;
// glm::vec3 rgb = glm::vec3(ui::Canvas::I->m_current_brush.m_tip_color);
// glm::vec3 hsv = convert_rgb2hsv(rgb);
// m_slider_h->m_value.x = hsv.x;
// m_slider_s->m_value.x = hsv.y;
// m_slider_v->m_value.x = hsv.z;
// m_slider_r->m_value.x = rgb.x;
// m_slider_g->m_value.x = rgb.y;
// m_slider_b->m_value.x = rgb.z;
// m_wheel->m_hsv = hsv;
}
void NodeColorPicker::handle_value_changed()
{
}
void NodeColorPicker::init_controls()
@@ -45,12 +50,44 @@ void NodeColorPicker::init_controls()
m_slider_g = find<NodeSliderH>("rgb-g");
m_slider_b = find<NodeSliderH>("rgb-b");
m_wheel = find<NodeColorWheel>("wheel");
m_color_cur = find<NodeBorder>("color-cur");
m_color_old = find<NodeBorder>("color-old");
m_color_old1 = find<NodeBorder>("color-old1");
m_color_old2 = find<NodeBorder>("color-old2");
m_button_select = find<NodeButton>("btn-select");
m_button_select->on_click = [this](Node*)
{
m_color_old2->m_color = m_color_old1->m_color;
m_color_old1->m_color = m_color_old->m_color;
m_color_old->m_color = m_color_cur->m_color;
};
m_wheel->on_value_changed = [this](Node*, glm::vec3 hsv)
{
m_slider_h->m_value.x = hsv.x;
m_slider_s->m_value.x = hsv.y;
m_slider_v->m_value.x = hsv.z;
glm::vec3 rgb = convert_hsv2rgb(hsv);
m_slider_r->m_value.x = rgb.x;
m_slider_g->m_value.x = rgb.y;
m_slider_b->m_value.x = rgb.z;
m_color_cur->m_color = {rgb,1};
};
auto hsv_setter = [this](Node* target, float v)
{
m_wheel->m_hsv = get_hsv();
glm::vec3 rgb = convert_hsv2rgb(get_hsv());
m_color_cur->m_color = {rgb,1};
};
m_slider_h->on_value_changed = hsv_setter;
m_slider_s->on_value_changed = hsv_setter;
m_slider_v->on_value_changed = hsv_setter;
}
glm::vec4 NodeColorPicker::get_hsv() const
glm::vec3 NodeColorPicker::get_hsv() const
{
float h = m_slider_h->get_value();
float s = m_slider_s->get_value();
float v = m_slider_v->get_value();
return glm::vec4(h, s, v, 1.f);
return glm::vec3(h, s, v);
}

View File

@@ -2,6 +2,7 @@
#include "node_border.h"
#include "node_slider.h"
#include "node_colorwheel.h"
#include "node_button.h"
class NodeColorPicker : public NodeBorder
{
@@ -13,8 +14,13 @@ public:
NodeSliderH* m_slider_g;
NodeSliderH* m_slider_b;
NodeColorWheel* m_wheel;
glm::vec4 m_rgb;
glm::vec4 m_hsv;
NodeBorder* m_color_cur;
NodeBorder* m_color_old;
NodeBorder* m_color_old1;
NodeBorder* m_color_old2;
NodeButton* m_button_select;
glm::vec3 m_rgb;
glm::vec3 m_hsv;
virtual Node* clone_instantiate() const override;
//virtual void clone_copy(Node* dest) const override;
@@ -22,5 +28,6 @@ public:
virtual void init() override;
virtual void draw() override;
void init_controls();
glm::vec4 get_hsv() const;
glm::vec3 get_hsv() const;
void handle_value_changed();
};

View File

@@ -49,7 +49,7 @@ void NodeSliderH::set_value(float value)
float NodeSliderH::get_value()
{
return glm::length(m_value);
return glm::length(m_value * m_mask);
}
void NodeSliderH::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)

View File

@@ -6,7 +6,7 @@ class NodeSliderH : public NodeBorder
bool dragging = false;
public:
glm::vec2 m_mask{ 1, 0 };
glm::vec2 m_value;
glm::vec2 m_value{0};
glm::vec2 m_old_value;
std::function<void(Node* target, float value)> on_value_changed;
virtual Node* clone_instantiate() const override;

View File

@@ -102,6 +102,7 @@
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/vector_angle.hpp>
#include <glm/gtx/intersect.hpp>
#include <tinyxml2.h>
#include <jpge.h>

View File

@@ -64,9 +64,15 @@ bool Shader::create(const char* vertex, const char* fragment)
glDeleteShader(vs);
glDeleteShader(fs);
glBindAttribLocation(ps, 0, "pos");
glBindAttribLocation(ps, 1, "uvs");
glBindAttribLocation(ps, 2, "col");
glLinkProgram(ps);
if (glGetAttribLocation(ps, "pos") != -1)
glBindAttribLocation(ps, 0, "pos");
if (glGetAttribLocation(ps, "uvs") != -1)
glBindAttribLocation(ps, 1, "uvs");
if (glGetAttribLocation(ps, "col") != -1)
glBindAttribLocation(ps, 2, "col");
glLinkProgram(ps);
glGetProgramiv(ps, GL_LINK_STATUS, &status);