Files
panopainter/engine/canvas.h
2018-07-30 23:35:27 +02:00

225 lines
7.5 KiB
C++

#pragma once
#include "rtt.h"
#include "texture.h"
#include "shader.h"
#include "shape.h"
#include "brush.h"
#include "action.h"
#include "canvas_modes.h"
NS_START
#define CANVAS_RES 512
class Layer
{
public:
RTT m_rtt[6];
glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0));
bool m_dirty_face[6] = SIXPLETTE(false);
bool m_visible = true;
bool m_alpha_locked = false;
float m_opacity = 1.f;
bool m_hightlight = false;
std::string m_name;
int w = 0;
int h = 0;
struct Snapshot
{
std::unique_ptr<uint8_t[]> image[6] = SIXPLETTE(0);
glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0));
bool m_dirty_face[6] = SIXPLETTE(false);
void create(int w, int h)
{
for (int i = 0; i < 6; i++)
image[i] = std::make_unique<uint8_t[]>(w*h*4);
}
};
bool create(int width, int height, std::string name);
void clear(const glm::vec4& c);
Snapshot snapshot(std::string data_path);
void restore(const Snapshot& snap);
void destroy();
};
class Canvas
{
public:
Plane m_plane;
Plane m_plane_brush;
BrushMesh m_mesh;
bool m_unsaved = false;
bool m_dirty = false;
bool m_commit_delayed = false;
bool m_dirty_stroke = false;
static Canvas* I;
bool m_alpha_lock = false;
bool m_touch_lock = true;
glm::mat4 m_mv{ 1 };
glm::mat4 m_proj{ 1 };
glm::vec4 m_box{ 0 };
glm::vec2 m_pan{ 0 };
int m_width = 0;
int m_height = 0;
bool m_use_instanced = false;
int m_current_layer_idx = 0;
std::unique_ptr<Stroke> m_current_stroke;
bool m_show_tmp = false;
std::vector<Layer> m_layers;
std::vector<int> m_order;
glm::vec4 m_dirty_box[6] = SIXPLETTE(glm::vec4(0));
bool m_dirty_face[6] = SIXPLETTE(false);
Layer m_smask; // selection mask
bool m_smask_active = false;
RTT m_tmp[6];
Texture2D m_brush_mix;
Texture2D m_tex[6];
Texture2D m_tex2[6];
bool m_pick_ready[6];
std::unique_ptr<glm::u8vec4[]> m_pick_data[6] = SIXPLETTE(nullptr);
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];
glm::vec2 stencil_offset;
Sampler m_sampler;
Sampler m_sampler_brush;
Sampler m_sampler_bg;
Sampler m_sampler_mask;
Sampler m_sampler_stencil;
glm::vec2 m_cam_rot{ 0 };
glm::vec3 m_cam_pos{ 0 };
float m_cam_fov = 85;
glm::vec2 m_cur_pos;
Brush m_current_brush;
enum class kCanvasMode { Draw, Erase, Line, Camera, Grid, Fill, MaskFree, MaskLine, COUNT };
kCanvasMode m_state{ kCanvasMode::Draw };
static std::vector<CanvasMode*> modes[];
std::vector<CanvasMode*>* m_mode = nullptr;
kCanvasMode m_current_mode = kCanvasMode::Draw;
static void set_mode(kCanvasMode mode)
{
if (I->m_mode)
for (auto& m : *I->m_mode)
m->leave();
I->m_mode = &modes[(int)mode];
I->m_state = mode;
I->m_current_mode = mode;
if (I->m_mode)
for (auto& m : *I->m_mode)
m->enter();
}
std::vector<Layer::Snapshot> m_layers_snapshot;
Canvas() { I = this; }
bool create(int width, int height);
void resize(int width, int height);
void layer_remove(int idx);
void layer_add(std::string name);
void layer_order(int idx, int pos);
void layer_merge(int source_idx, int dest_idx);
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_cancel();
void stroke_commit();
void clear(const glm::vec4& color = { 1, 1, 1, 0 });
void pick_start();
void pick_update(int plane);
glm::vec4 pick_get(glm::vec2 canvas_loc);
void pick_end();
void snapshot_save(std::string data_path);
void snapshot_restore();
void snap_history(const std::vector<int>& planes);
class ActionStroke* create_action(int layer);
void clear_context();
void import_equirectangular(std::string file_path);
void import_equirectangular_thread(std::string file_path);
void export_equirectangular(std::string file_path);
void export_equirectangular_thread(std::string file_path);
void export_anim(std::string data_path);
void export_cubes(std::string data_path);
void project_save(std::string file_path);
void project_save_thread(std::string file_path);
void project_open(std::string file_path, std::function<void()> on_complete = nullptr);
void project_open_thread(std::string file_path);
void inject_xmp(std::string jpg_path);
ui::Image thumbnail_generate(int w, int h);
ui::Image thumbnail_read(std::string data_path);
void preview_generate();
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>);
void draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>, Layer& layer);
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3 &out_hit);
void point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,
glm::vec3 &out_origin, glm::vec3 &out_dir);
bool point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec2& fb_pos, glm::vec3& hit_normal, int& out_plane_id);
bool point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id);
std::vector<ui::Shape::vertex_t> triangulate(const std::vector<std::shared_ptr<p2t::Point>>& points);
void project2Dpoints(std::vector<ui::Shape::vertex_t>& vertices);
};
class ActionStroke : public Action
{
public:
std::unique_ptr<Stroke> m_stroke;
std::unique_ptr<uint8_t[]> m_image[6] = SIXPLETTE(nullptr);
glm::ivec4 m_old_box[6] = SIXPLETTE(glm::ivec4(0));
bool m_old_dirty[6] = SIXPLETTE(false);
glm::ivec4 m_box[6] = SIXPLETTE(glm::ivec4(0));
bool m_dirty[6] = SIXPLETTE(false);
bool clear_layer = false;
int m_layer_idx;
Canvas* m_canvas;
virtual void run() override
{
}
virtual Action* get_redo()
{
auto redo = m_canvas->create_action(m_layer_idx);
return redo;
}
virtual void undo() override
{
if (clear_layer)
m_canvas->m_layers[m_layer_idx].clear({ 0, 0, 0, 0 });
for (int i = 0; i < 6; i++)
{
// empty data
if (!m_image[i])
continue;
m_canvas->m_layers[m_layer_idx].m_dirty_box[i] = m_old_box[i];
m_canvas->m_layers[m_layer_idx].m_dirty_face[i] = m_old_dirty[i];
m_canvas->m_layers[m_layer_idx].m_rtt[i].bindTexture();
glm::vec2 box_sz = zw(m_box[i]) - xy(m_box[i]);
glTexSubImage2D(GL_TEXTURE_2D, 0, (int)m_box[i].x, (int)m_box[i].y, (int)box_sz.x, (int)box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, m_image[i].get());
m_canvas->m_layers[m_layer_idx].m_rtt[i].unbindTexture();
}
}
virtual size_t memory() override
{
size_t mem = 0;
for (int i = 0; i < 6; i++)
{
glm::ivec2 sz = zw(m_box[i]) - xy(m_box[i]);
mem += sz.x * sz.y * 4 + sizeof(*this);
}
return mem;
}
virtual ~ActionStroke()
{
}
};
NS_END