implementing color wheel and new color picker

This commit is contained in:
2017-11-23 20:26:57 +00:00
parent d44434a458
commit a90aa4a60e
23 changed files with 371 additions and 26 deletions

View File

@@ -242,7 +242,7 @@ void App::update(float dt)
//glViewport(0, 0, (GLsizei)width, (GLsizei)height);
//glClear(GL_COLOR_BUFFER_BIT);
#ifdef _WIN32
#if _WIN32 || __OSX__
layout.reload();
#endif
if (auto* main = layout[main_id])
@@ -260,7 +260,7 @@ void App::update(float dt)
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(1.f - hsv.y, 1.f - hsv.z);
color->m_quad->set_value(hsv.y, 1.f - hsv.z);
auto observer = [this](Node* n)
{

View File

@@ -180,11 +180,47 @@ void App::initShaders()
"uniform mediump vec4 col;"
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"void main(){"
" mediump vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);"
" frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);"
"mediump vec3 rgb2hsv(mediump vec3 c) {"
" mediump vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);"
" mediump vec4 p = mix(vec4(c.bg, k.wz), vec4(c.gb, k.xy), step(c.b, c.g));"
" mediump vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));"
" mediump float d = q.x - min(q.w, q.y);"
" mediump float e = 1.0e-10;"
" return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);"
"}"
"mediump vec3 hsv2rgb(mediump vec3 c) {"
" mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
" mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
" 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);"
"}";
// COLOR TRI
static const char* shader_color_tri_f =
SHADER_VERSION
"uniform mediump vec4 col;" // in HSV
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"mediump vec3 rgb2hsv(mediump vec3 c) {"
" mediump vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);"
" mediump vec4 p = mix(vec4(c.bg, k.wz), vec4(c.gb, k.xy), step(c.b, c.g));"
" mediump vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));"
" mediump float d = q.x - min(q.w, q.y);"
" mediump float e = 1.0e-10;"
" return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);"
"}"
"mediump vec3 hsv2rgb(mediump vec3 c) {"
" mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
" mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
"}"
"void main() {"
" mediump float sat = tan(atan(uv.y, uv.x)) *.5 + .5;"
" frag = vec4(hsv2rgb(vec3(col.r, sat, uv.x)), 1.0);"
"}";
// HUE
static const char* shader_color_hue_v =
SHADER_VERSION
@@ -199,15 +235,24 @@ void App::initShaders()
static const char* shader_color_hue_f =
SHADER_VERSION
"uniform mediump vec4 col;"
"uniform bool dir;" // 0:horizontal, 1:vertical
"in mediump vec3 uv;"
"out mediump vec4 frag;"
"mediump vec3 rgb2hsv(mediump vec3 c) {"
" mediump vec4 k = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);"
" mediump vec4 p = mix(vec4(c.bg, k.wz), vec4(c.gb, k.xy), step(c.b, c.g));"
" mediump vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));"
" mediump float d = q.x - min(q.w, q.y);"
" mediump float e = 1.0e-10;"
" return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);"
"}"
"mediump vec3 hsv2rgb(mediump vec3 c) {"
" mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
" mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
"}"
"void main(){"
" frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);"
" frag = vec4(hsv2rgb(vec3(dir?uv.y:uv.x, 1.0, 1.0)), 1.0);"
"}";
// FONT
@@ -373,6 +418,27 @@ void App::initShaders()
" frag = vec4(col.rgb, a);"
"}";
// VERTEX COLOR
static const char* shader_vertcol_v =
SHADER_VERSION
"uniform mat4 mvp;"
"in vec4 pos;"
"in vec4 col;"
"out vec4 c;"
"void main(){"
" c = col;"
" gl_Position = mvp * pos;"
" gl_PointSize = 5.0;"
"}";
static const char* shader_vertcol_f =
SHADER_VERSION
"in mediump vec4 c;"
"out mediump vec4 frag;"
"void main(){"
" frag = c;"
"}";
LOG("initializing shaders");
if (!ShaderManager::create(kShader::Texture, shader_v, shader_f))
LOG("Failed to create shader Texture");
@@ -388,6 +454,8 @@ void App::initShaders()
LOG("Failed to create shader Color");
if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f))
LOG("Failed to create shader ColorQuad");
if (!ShaderManager::create(kShader::ColorTri, shader_color_quad_v, shader_color_tri_f))
LOG("Failed to create shader ColorTri");
if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f))
LOG("Failed to create shader ColorHue");
if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f))
@@ -404,6 +472,8 @@ void App::initShaders()
LOG("Failed to create shader Equirect");
if (!ShaderManager::create(kShader::BrushStroke, shader_stroke_inst_v, shader_stroke_inst_f))
LOG("Failed to create shader BrushStroke");
if (!ShaderManager::create(kShader::VertexColor, shader_vertcol_v, shader_vertcol_f))
LOG("Failed to create shader VertexColor");
LOG("shaders initialized");
}

View File

@@ -117,6 +117,17 @@ std::vector<std::string> Asset::list_files(std::string folder, bool is_asset, co
return names;
}
std::string Asset::absolute(const std::string& path)
{
#ifdef __APPLE__
NSString* bundle_path = [[NSBundle mainBundle] resourcePath];
std::string base = [bundle_path cStringUsingEncoding:1];
return base + "/" + path;
#else
return path;
#endif
}
bool Asset::open(const char* path)
{
//LOG("Asset::open %s", path);

View File

@@ -10,6 +10,7 @@ public:
static std::vector<std::string> list_files(std::string folder, bool is_asset, const std::string& filter_regex);
static bool exist(std::string path, bool is_asset);
static bool delete_file(const std::string& path);
static std::string absolute(const std::string& path);
std::string m_current_path;
FILE* m_fp = nullptr;

View File

@@ -10,7 +10,7 @@ public:
int id = 0;
std::string m_name;
uint16_t m_tex_id = 0;
glm::vec4 m_tip_color;
glm::vec4 m_tip_color{1, 0, 0, 1};
float m_tip_size = 0;
float m_tip_spacing = 0;
float m_tip_flow = 0;

View File

@@ -1324,6 +1324,7 @@ void ui::Canvas::project_open_thread(std::string file_path)
l.destroy();
m_layers.clear();
m_order.clear();
resize(m_width, m_height);
App::I.async_end();
std::vector<int> tmp_order;

View File

@@ -8,10 +8,10 @@
bool LayoutManager::load(const char* path)
{
#if _WIN32
auto abs_path = Asset::absolute(path);
#if _WIN32 || __OSX__
struct stat tmp_info;
if (stat(path, &tmp_info) != 0)
if (stat(abs_path.c_str(), &tmp_info) != 0)
return false;
if (tmp_info.st_mtime <= m_file_info.st_mtime)
return false;

View File

@@ -28,6 +28,8 @@
#include "node_dialog_browse.h"
#include "node_dialog_cloud.h"
#include "node_combobox.h"
#include "node_colorwheel.h"
#include "node_dialog_picker.h"
void Node::async_start()
{
@@ -381,6 +383,7 @@ Node::~Node()
void Node::SetWidth(float value)
{
YGNodeStyleSetWidth(y_node, value);
m_size.x = value;
}
void Node::SetWidthP(float value)
@@ -391,6 +394,7 @@ void Node::SetWidthP(float value)
void Node::SetHeight(float value)
{
YGNodeStyleSetHeight(y_node, value);
m_size.y = value;
}
void Node::SetHeightP(float value)
@@ -401,11 +405,13 @@ void Node::SetHeightP(float value)
void Node::SetSize(float w, float h)
{
SetWidth(w); SetHeight(h);
m_size = {w, h};
}
void Node::SetSize(glm::vec2 value)
{
SetWidth(value.x); SetHeight(value.y);
m_size = value;
}
void Node::SetPadding(float t, float r, float b, float l)
@@ -428,12 +434,14 @@ glm::vec4 Node::GetPadding() const
void Node::SetPosition(const glm::vec2 pos)
{
SetPosition(pos.x, pos.y);
m_pos = pos;
}
void Node::SetPosition(float l, float t)
{
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
m_pos = {l, t};
}
void Node::SetPosition(float l, float t, float r, float b)
@@ -818,6 +826,8 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
CASE(kWidget::DialogBrowseItem, NodeDialogBrowseItem);
CASE(kWidget::DialogCloud, NodeDialogCloud);
CASE(kWidget::DialogCloudItem, NodeDialogCloudItem);
CASE(kWidget::ColorWheel, NodeColorWheel);
CASE(kWidget::ColorPicker, NodeColorPicker);
#undef CASE
case kWidget::Ref:
{

View File

@@ -76,6 +76,8 @@ enum class kWidget : uint16_t
DialogBrowseItem = const_hash("dialog-browse-item"),
DialogCloud = const_hash("dialog-cloud"),
DialogCloudItem = const_hash("dialog-cloud-item"),
ColorWheel = const_hash("colorwheel"),
ColorPicker = const_hash("color-picker"),
};
class Node

View File

@@ -143,7 +143,7 @@ void NodeCanvas::draw()
}
else if(m_canvas->m_show_tmp && m_canvas->m_current_layer_idx == layer_index)
{
m_sampler.bind(0);
m_sampler_linear.bind(0);
auto& paper = TextureManager::get(const_hash("data/paper.jpg"));
ui::ShaderManager::use(kShader::CompDraw);
ui::ShaderManager::u_int(kShaderUniform::Tex, 0);

View File

@@ -27,7 +27,7 @@ void NodeColorQuad::init()
void NodeColorQuad::set_value(float x, float y)
{
auto sz = GetSize();
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_value = pos / glm::max({ 1,1 }, sz); // avoid div0
@@ -45,7 +45,7 @@ kEventResult NodeColorQuad::handle_event(Event* e)
m_old_value = m_value;
dragging = true;
mouse_capture();
auto sz = GetSize();
auto sz = m_size;
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz);
m_picker->SetPosition(pos - m_picker->GetSize() * .5f);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0
@@ -60,7 +60,7 @@ kEventResult NodeColorQuad::handle_event(Event* e)
case kEventType::MouseMove:
if (dragging)
{
auto sz = GetSize();
auto sz = m_size;
auto pos = glm::clamp(((MouseEvent*)e)->m_pos - m_pos, { 0, 0 }, sz);
m_picker->SetPosition(pos - m_picker->GetSize() * .5f);
m_value = pos / glm::max({ 1,1 }, sz); // avoid div0

View File

@@ -3,11 +3,11 @@
class NodeColorQuad : public NodeBorder
{
NodeBorder* m_picker;
NodeBorder* m_picker{nullptr};
bool dragging = false;
public:
glm::vec2 m_value;
glm::vec2 m_old_value;
glm::vec2 m_value{0.f};
glm::vec2 m_old_value{0.f};
std::function<void(Node* target, glm::vec2 value)> on_value_changed;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const override;

View File

@@ -0,0 +1,77 @@
#include "pch.h"
#include "node_colorwheel.h"
#include "shader.h"
Node* NodeColorWheel::clone_instantiate() const
{
return new NodeColorWheel;
}
void NodeColorWheel::clone_finalize(Node* dest) const
{
NodeColorWheel* n = (NodeColorWheel*)dest;
n->init_controls();
}
void NodeColorWheel::init()
{
//init_template("color-picker");
init_controls();
}
void NodeColorWheel::init_controls()
{
}
void NodeColorWheel::loaded()
{
m_circle.create<64>(.5, .4, ui::Circle::kUVMapping::Tube);
m_cur_hue.create<16>(.05);
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; glm::vec4 col; };
std::vector<vertex_t> vertices;
float l = 0.4;
vertices.push_back({{glm::cos(4.f/3.f*glm::pi<float>())*l,glm::sin(4.f/3.f*glm::pi<float>())*l,0,1},{1,-1},{1,1,1,1}});
vertices.push_back({{glm::cos(2.f/3.f*glm::pi<float>())*l,glm::sin(2.f/3.f*glm::pi<float>())*l,0,1},{0,0},{0,0,0,1}});
vertices.push_back({{l,0,0,1},{1,1},{1,0,0,1}});
glGenBuffers(1, &buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &arrays);
glBindVertexArray(arrays);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, buffers);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
glBindVertexArray(0);
}
void NodeColorWheel::draw()
{
using namespace ui;
glDisable(GL_BLEND);
ShaderManager::use(kShader::ColorHue);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
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::Color);
ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp * glm::eulerAngleZ(glm::radians(45.f)) * glm::translate(glm::vec3(.45,0,0)));
ShaderManager::u_vec4(kShaderUniform::Col, {1, 1, 1, 1});
m_cur_hue.draw_stroke();
}

22
engine/node_colorwheel.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "util.h"
#include "node.h"
#include "shape.h"
#include "node_slider.h"
class NodeColorWheel : public Node
{
public:
ui::Circle m_circle;
ui::Circle m_cur_hue;
GLuint m_tri_vbo;
GLuint m_tri_vao;
GLuint buffers;
GLuint arrays;
virtual Node* clone_instantiate() const override;
virtual void clone_finalize(Node* dest) const;
virtual void init() override;
virtual void loaded() override;
virtual void draw() override;
void init_controls();
};

View File

@@ -57,8 +57,11 @@ void NodeComboBox::loaded()
float offset = 0;
for (int i = 0; i <= m_selected_child_index; i++)
offset += (m_data[i] == "-") ? 5.f : 30.f;
float height = m_items.size() * 30.f + (m_data.size() - m_items.size()) * 5.f; // add items and separators
glm::vec2 pos = m_pos + glm::vec2(0, m_size.y - offset);
auto screen = root()->m_size;
if ((pos.y + height) > screen.y) pos.y = screen.y - height;
if (pos.y < 0) pos.y = 0;
popup->SetPositioning(YGPositionTypeAbsolute);
popup->SetPosition(pos.x, pos.y);
popup->SetSize(m_size.x, YGUndefined);

View File

@@ -0,0 +1,55 @@
#include "pch.h"
#include "log.h"
#include "util.h"
#include "canvas.h"
#include "node_dialog_picker.h"
Node* NodeColorPicker::clone_instantiate() const
{
return new NodeColorPicker;
}
void NodeColorPicker::clone_finalize(Node* dest) const
{
auto n = static_cast<NodeColorPicker*>(dest);
n->init_controls();
}
void NodeColorPicker::init()
{
auto n = (NodeColorPicker*)init_template("color-picker");
n->clone_copy(this);
init_controls();
}
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);
}
void NodeColorPicker::init_controls()
{
m_slider_h = find<NodeSliderH>("hsv-h");
m_slider_s = find<NodeSliderH>("hsv-s");
m_slider_v = find<NodeSliderH>("hsv-v");
m_slider_r = find<NodeSliderH>("rgb-r");
m_slider_g = find<NodeSliderH>("rgb-g");
m_slider_b = find<NodeSliderH>("rgb-b");
m_wheel = find<NodeColorWheel>("wheel");
}
glm::vec4 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);
}

View File

@@ -0,0 +1,26 @@
#include "node.h"
#include "node_border.h"
#include "node_slider.h"
#include "node_colorwheel.h"
class NodeColorPicker : public NodeBorder
{
public:
NodeSliderH* m_slider_h;
NodeSliderH* m_slider_s;
NodeSliderH* m_slider_v;
NodeSliderH* m_slider_r;
NodeSliderH* m_slider_g;
NodeSliderH* m_slider_b;
NodeColorWheel* m_wheel;
glm::vec4 m_rgb;
glm::vec4 m_hsv;
virtual Node* clone_instantiate() const override;
//virtual void clone_copy(Node* dest) const override;
virtual void clone_finalize(Node* dest) const override;
virtual void init() override;
virtual void draw() override;
void init_controls();
glm::vec4 get_hsv() const;
};

View File

@@ -25,16 +25,16 @@ void NodePanelColor::init_controls()
m_hue = find<NodeSliderHue>("hue");
m_hue->on_hue_changed = [this](Node*, glm::vec4 hue_color) {
m_base_color = m_quad->m_color = hue_color;
auto x = glm::mix(m_base_color, glm::vec4(1, 1, 1, 1), m_cursor.x);
m_color = glm::mix(x, glm::vec4(0, 0, 0, 1), m_cursor.y);
float hue = convert_rgb2hsv(m_base_color).x;
m_color = glm::vec4(convert_hsv2rgb(glm::vec3(hue, m_cursor.x, 1.f-m_cursor.y)), 1.f);
if (on_color_changed)
on_color_changed(this, m_color);
};
m_quad->on_value_changed = [this](Node*, glm::vec2 pos)
{
auto x = glm::mix(m_base_color, glm::vec4(1, 1, 1, 1), pos.x);
m_color = glm::mix(x, glm::vec4(0, 0, 0, 1), pos.y);
m_cursor = pos;
float hue = convert_rgb2hsv(m_base_color).x;
m_color = glm::vec4(convert_hsv2rgb(glm::vec3(hue, m_cursor.x, 1.f-m_cursor.y)), 1.f);
if (on_color_changed)
on_color_changed(this, m_color);
};

View File

@@ -152,6 +152,7 @@ void NodeSliderHue::draw()
ui::ShaderManager::use(kShader::ColorHue);
ui::ShaderManager::u_mat4(kShaderUniform::MVP, m_mvp);
//ui::ShaderManager::u_vec4(kShaderUniform::Col, m_color);
ui::ShaderManager::u_int(kShaderUniform::Direction, 1); // set vertical
m_plane.draw_fill();
NodeBorder::m_color = glm::vec4(0);
NodeSliderH::draw();

View File

@@ -66,7 +66,8 @@ bool Shader::create(const char* vertex, const char* fragment)
glBindAttribLocation(ps, 0, "pos");
glBindAttribLocation(ps, 1, "uvs");
glBindAttribLocation(ps, 2, "col");
glLinkProgram(ps);
glGetProgramiv(ps, GL_LINK_STATUS, &status);
glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog);

View File

@@ -25,12 +25,14 @@ enum class kShaderUniform : uint16_t
Highlight = const_hash("highlight"),
BlendMode = const_hash("blend_mode"),
Noise = const_hash("noise"),
Direction = const_hash("dir"),
};
enum class kShader : uint16_t
{
Color = const_hash("color"),
ColorQuad = const_hash("color-quad"),
ColorTri = const_hash("color-tri"),
ColorHue = const_hash("color-hue"),
Texture = const_hash("texture"),
TextureAlpha= const_hash("texture-alpha"),
@@ -44,6 +46,7 @@ enum class kShader : uint16_t
Checkerboard= const_hash("checkerboard"),
Equirect = const_hash("equirect"),
BrushStroke = const_hash("brush-stroke"),
VertexColor = const_hash("vertex-color"),
};
class Shader