color wheel and picker
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user