#pragma once #include "rtt.h" #include "shader.h" NS_START class Brush { public: int id; std::string m_name; uint16_t m_tex_id; glm::vec4 m_tip_color; float m_tip_size; float m_tip_spacing; float m_tip_flow; float m_tip_opacity; float m_tip_angle; float m_jitter_scale; float m_jitter_angle; float m_jitter_spread; float m_jitter_flow; }; struct StrokeSample { glm::vec2 pos; float size; float flow; float angle; }; class BrushMesh { public: ui::Shader shader; GLuint buffers[3]{ 0 }; GLuint vao{ 0 }; struct vertex_t { glm::vec4 pos; glm::vec2 uvs; }; struct instance_t { glm::mat4 mvp; float flow; }; int loc_flow; int loc_mvp; bool create(); void draw(const std::vector& samples, const glm::mat4& proj); }; class Stroke { public: struct Keypoint { glm::vec2 pos; float pressure; float dist; }; int m_layer; float m_dist; float m_step; ui::Brush m_brush; std::vector m_keypoints; std::vector m_samples; int m_last_kp; std::minstd_rand prng; void start(const ui::Brush& brush); void add_point(glm::vec2 pos, float pressure); void reset(bool clear_keypoints = false); bool has_sample(); std::vector compute_samples(); StrokeSample randomize_sample(const glm::vec2& pos, float pressure); }; class Layer { public: RTT m_rtt; bool m_visible = true; bool m_locked = false; float m_opacity = 1.f; std::string m_name; bool create(int width, int height, std::string name) { m_rtt.create(width, height); m_rtt.bindFramebuffer(); m_rtt.clear(); m_rtt.unbindFramebuffer(); return true; } }; NS_END