#pragma once #include "rtt.h" #include "texture.h" #include "shader.h" #include "shape.h" #include "brush.h" #include "action.h" NS_START class Layer { public: RTT m_rtt[6]; bool m_visible = true; bool m_locked = false; float m_opacity = 1.f; std::string m_name; struct Snapshot { std::unique_ptr image[6]; }; bool create(int width, int height, std::string name) { for (int i = 0; i < 6; i++) { m_rtt[i].create(width, height); m_rtt[i].bindFramebuffer(); m_rtt[i].clear(); m_rtt[i].unbindFramebuffer(); } return true; } void clear(const glm::vec4& c) { // push clear color state GLfloat cc[4]; glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glClearColor(c.r, c.g, c.b, c.a); for (int i = 0; i < 6; i++) { m_rtt[i].bindFramebuffer(); glClear(GL_COLOR_BUFFER_BIT); m_rtt[i].unbindFramebuffer(); } // restore clear color state glClearColor(cc[0], cc[1], cc[2], cc[3]); } Snapshot snapshot() { Snapshot snap; for (int i = 0; i < 6; i++) { snap.image[i] = std::make_unique(m_rtt[i].bytes()); m_rtt[i].readTextureData(snap.image[i].get()); } return snap; } }; class Canvas { Plane m_plane; Plane m_plane_brush; BrushMesh m_mesh; bool m_dirty = false; public: bool m_erase = false; glm::mat4 m_mv; glm::mat4 m_proj; glm::vec4 m_box; int m_width; int m_height; bool m_use_instanced = false; int m_current_layer_idx = 0; std::unique_ptr m_current_stroke; bool m_show_tmp = false; std::vector m_layers; std::vector m_order; glm::vec4 m_dirty_box[6]; bool m_dirty_face[6]; RTT m_tmp[6]; Texture2D m_tex[6]; Texture2D m_tex2[6]; static glm::vec3 m_plane_origin[6]; static glm::vec3 m_plane_normal[6]; static glm::vec3 m_plane_tangent[6]; static glm::mat4 m_plane_transform[6]; Sampler m_sampler; Sampler m_sampler_bg; glm::vec2 m_cam_rot; float m_cam_fov = 85; std::vector m_layers_snapshot; bool create(int width, int height); void resize(int width, int height); void layer_add(std::string name); void layer_order(int idx, int pos); void stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush); void stroke_update(glm::vec2 point, float pressure); void stroke_draw(); void stroke_end(); void stroke_commit(); void clear(const glm::vec4& color = { 1, 1, 1, 1 }); void snapshot_save(); void snapshot_restore(); }; class ActionStroke : public Action { public: std::unique_ptr m_stroke; std::unique_ptr m_image[6]; glm::ivec4 m_box[6]; bool m_dirty[6]; int m_layer_idx; Canvas* m_canvas; virtual void run() override { } virtual void undo() override { for (int i = 0; i < 6; i++) { // empty data if (!m_image[i]) continue; m_canvas->m_layers[m_layer_idx].m_rtt[i].bindTexture(); glm::vec2 box_sz = m_box[i].zw() - m_box[i].xy(); glTexSubImage2D(GL_TEXTURE_2D, 0, m_box[i].x, m_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get()); m_canvas->m_layers[m_layer_idx].m_rtt[i].unbindTexture(); } } }; NS_END