diff --git a/data/layout.xml b/data/layout.xml index 752776f..da3c70e 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -106,7 +106,7 @@ - + @@ -394,7 +394,7 @@ - + diff --git a/engine.vcxproj b/engine.vcxproj index 89993c9..be2ed74 100644 --- a/engine.vcxproj +++ b/engine.vcxproj @@ -153,6 +153,7 @@ + @@ -191,6 +192,7 @@ + @@ -203,6 +205,7 @@ + diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters index 20f7b40..8464ef6 100644 --- a/engine.vcxproj.filters +++ b/engine.vcxproj.filters @@ -63,6 +63,9 @@ Source Files + + Source Files + @@ -101,8 +104,12 @@ Header Files + + Header Files + + \ No newline at end of file diff --git a/engine/canvas.cpp b/engine/canvas.cpp new file mode 100644 index 0000000..8f50fbd --- /dev/null +++ b/engine/canvas.cpp @@ -0,0 +1,5 @@ +#include "pch.h" +#include "canvas.h" + + + diff --git a/engine/canvas.h b/engine/canvas.h new file mode 100644 index 0000000..89d3f8a --- /dev/null +++ b/engine/canvas.h @@ -0,0 +1,147 @@ +#pragma once +#include "rtt.h" +#include "texture.h" +#include "shader.h" +#include "shape.h" + +NS_START + +class Brush +{ +public: + std::string m_name; + int id; + uint16_t m_texture_id; +}; + +class Stroke +{ +public: + struct Keypoint + { + glm::vec2 pos; + float pressure; + }; + int m_layer; + float m_dist; + std::shared_ptr m_brush; + std::vector m_keypoints; + void add_point(glm::vec2 pos, float pressure) + { + m_keypoints.emplace_back(); + m_keypoints.back().pos = pos; + m_keypoints.back().pressure = pressure; + } +}; + +class Layer +{ +public: + RTT m_rtt; + bool m_visible = true; + bool m_locked = false; + float m_alpha = 1.f; + std::string m_name; + bool create(int width, int height, std::string name) + { + m_rtt.create(width, height); + return true; + } +}; + +class Canvas +{ +public: + int m_width; + int m_height; + std::vector m_layers; + std::vector m_strokes; + std::unique_ptr m_tmp; + Stroke* m_current_stroke = nullptr; + int m_current_layer_idx = 0; + RTT m_fb; + Sampler m_sampler; + Plane m_plane; + bool create(int width, int height) + { + m_width = width; + m_height = height; + m_tmp = std::make_unique(); + m_tmp->create(width, height, "tmp"); + m_fb.create(width, height); + m_sampler.create(); + m_plane.create<1>(1, 1); + return true; + } + void layer_add(std::string name) + { + m_layers.emplace_back(); + m_layers.back().create(m_width, m_height, name); + } + void stroke_start(glm::vec2 point, float pressure, std::shared_ptr brush) + { + m_strokes.emplace_back(); + m_strokes.back().m_brush = brush; + m_strokes.back().add_point(point, pressure); + m_current_stroke = &m_strokes.back(); + } + void stroke_update(glm::vec2 point, float pressure) + { + m_current_stroke->add_point(point, pressure); + + m_fb.bindFramebuffer(); + + GLint vp[4]; + GLfloat cc[4]; + glGetIntegerv(GL_VIEWPORT, vp); + glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + + glViewport(0, 0, m_width, m_height); + + auto mvp = glm::ortho(0.f, (float)m_width, (float)m_height, 0.f, -1.f, 1.f) * + glm::translate(glm::vec3(point, 0)) * + glm::scale(glm::vec3(30, 30, 1)); + + auto& tex = TextureManager::get(m_current_stroke->m_brush->m_texture_id); + tex.bind(); + m_sampler.bind(0); + ui::ShaderManager::use(kShader::Texture); + ui::ShaderManager::u_int(kShaderUniform::Tex, 0); + ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp); + m_plane.draw_fill(); + m_sampler.unbind(); + tex.unbind(); + + + glViewport(vp[0], vp[1], vp[2], vp[3]); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + + m_fb.unbindFramebuffer(); + } + void stroke_end() + { + m_current_stroke = nullptr; + } + void clear() + { + m_fb.bindFramebuffer(); + + GLint vp[4]; + GLfloat cc[4]; + glGetIntegerv(GL_VIEWPORT, vp); + glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, m_width, m_height); + + // + + glViewport(vp[0], vp[1], vp[2], vp[3]); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + + m_fb.unbindFramebuffer(); + } +}; + +NS_END diff --git a/engine/layout.cpp b/engine/layout.cpp index 5ba5236..5b80eff 100644 --- a/engine/layout.cpp +++ b/engine/layout.cpp @@ -463,7 +463,8 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) CASE(kWidget::PanelColor, NodePanelColor); CASE(kWidget::PanelStroke, NodePanelStroke); CASE(kWidget::ColorQuad, NodeColorQuad); - CASE(kWidget::Canvas2D, NodeStrokePreview); + CASE(kWidget::StrokePreview, NodeStrokePreview); + CASE(kWidget::Canvas, NodeCanvas); #undef CASE case kWidget::Ref: { diff --git a/engine/layout.h b/engine/layout.h index 435c587..f362263 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -6,6 +6,7 @@ #include "asset.h" #include "rtt.h" #include "bezier.h" +#include "canvas.h" #include #include @@ -72,7 +73,8 @@ enum class kWidget : uint16_t PanelColor = const_hash("panel-color"), PanelStroke = const_hash("panel-stroke"), ColorQuad = const_hash("color-quad"), - Canvas2D = const_hash("canvas2D"), + StrokePreview = const_hash("stroke-preview"), + Canvas = const_hash("canvas"), }; enum class kShapeType : uint16_t @@ -733,15 +735,15 @@ public: key_capture(); break; case kEventType::KeyDown: - switch (ke->m_key) - { +// switch (ke->m_key) +// { // case VK_BACK: // m_string.erase(m_string.end() - 1); // m_text->set_text(m_string.c_str()); // break; - default: - break; - } +// default: +// break; +// } break; case kEventType::KeyChar: if (ke->m_key >= 32 && ke->m_key < 32+96) @@ -1852,4 +1854,83 @@ public: } }; +class NodeCanvas : public Node +{ + bool m_dragging = false; +public: + std::unique_ptr m_canvas; + virtual Node* clone_instantiate() const override { return new NodeCanvas(); } + virtual void init() override + { + m_mouse_ignore = false; + m_canvas = std::make_unique(); + m_canvas->create(512, 512); + m_canvas->clear(); + } + virtual void draw() override + { + using namespace ui; + //glm::mat4 cam = glm::lookAt(glm::vec3(sinf(angle) * 10, 0, -10), glm::vec3(0, 0, 0), glm::vec3(0, -1, 0)); + //glm::mat4 proj = glm::perspective(glm::radians(45.f), m_clip.z / m_clip.w, .1f, 100); + GLint vp[4]; + GLfloat cc[4]; + glGetIntegerv(GL_VIEWPORT, vp); + glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); + + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + auto box = m_clip * root()->m_zoom; + glm::ivec4 c = (glm::ivec4)glm::vec4(box.x, (int)(vp[3] - box.y - box.w), box.z, box.w); + glViewport(c.x, c.y, c.z, c.w); + + glm::vec2 sz = { m_canvas->m_width, m_canvas->m_height }; + auto mvp = glm::ortho(0.f, box.z, box.w, 0.f, -1.f, 1.f) * + glm::translate(glm::vec3((m_size - sz) * 0.5f, 0)) * + glm::scale(glm::vec3(sz, 1)) * + glm::translate(glm::vec3(.5f, .5f, 0.f)); // pivot + + m_canvas->m_fb.bindTexture(); + m_canvas->m_sampler.bind(0); + ui::ShaderManager::use(kShader::Texture); + ui::ShaderManager::u_int(kShaderUniform::Tex, 0); + ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp); + NodeBorder::m_plane.draw_fill(); + m_canvas->m_sampler.unbind(); + m_canvas->m_fb.unbindTexture(); + + + glViewport(vp[0], vp[1], vp[2], vp[3]); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + } + virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override + { + } + virtual kEventResult handle_event(Event* e) override + { + MouseEvent* me = static_cast(e); + Node::handle_event(e); + switch (e->m_type) + { + case kEventType::MouseDownL: + { + auto b = std::make_shared(); + b->m_texture_id = const_hash("data/Icons/Round-Brush.png"); + m_canvas->stroke_start(me->m_pos, 1.f, b); + m_dragging = true; + break; + } + case kEventType::MouseUpL: + m_canvas->stroke_end(); + m_dragging = false; + break; + case kEventType::MouseMove: + if (m_dragging) + m_canvas->stroke_update(me->m_pos, 1.f); + break; + default: + break; + } + return kEventResult::Consumed; + } +}; diff --git a/engine/pch.h b/engine/pch.h index 5aa7235..34ff803 100644 --- a/engine/pch.h +++ b/engine/pch.h @@ -33,6 +33,9 @@ #define SHADER_VERSION "#version 150\n" #endif +#define NS_START namespace ui { +#define NS_END } + #ifdef __cplusplus #include #include