Extract fill modes, preview runtime pockets, and brush item UI

This commit is contained in:
2026-06-16 23:17:29 +02:00
parent a8e4e02e94
commit dde6123598
11 changed files with 497 additions and 377 deletions

View File

@@ -0,0 +1,245 @@
#include "pch.h"
#include "canvas_modes.h"
#include "app.h"
#include "canvas.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_ui_overlay_services.h"
#include "node_tool_bucket.h"
#include "texture.h"
void CanvasModeFill::init()
{
m_shape.create();
}
void CanvasModeFill::leave(kCanvasMode next)
{
if (m_points.size() > 2)
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 1, 1, 1, 1 },
.mvp = proj * camera,
});
m_shape.draw_fill();
};
Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0);
m_points.clear();
Canvas::I->m_smask_active = true;
}
else
{
Canvas::I->m_smask_active = false;
}
}
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 hit_fb;
int plane_id;
if (Canvas::I->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0))
{
m_dirty_planes[plane_id]++;
vertex_t v;
v.pos = glm::vec4(hit_o, 1);
v.uvs = glm::vec2(0);
if (m_points.size() < 3)
{
m_points.push_back(v);
}
else
{
auto last = m_points.back();
m_points.push_back(m_points[0]);
m_points.push_back(last);
m_points.push_back(v);
}
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
Canvas::I->m_smask.clear({0, 0, 0, 0});
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
break;
case kEventType::MouseMove:
{
glm::vec3 ro, rd, hit_o, hit_d;
glm::vec2 fb_pos;
int plane_id;
if (m_dragging && Canvas::I->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, plane_id))
{
vertex_t v;
v.pos = glm::vec4(hit_o, 1);
v.uvs = glm::vec2(0);
m_points.back() = v;
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (!m_points.empty())
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, .25 },
.mvp = proj * camera,
});
m_dragging ? m_shape.draw_fill() : m_shape.draw_stroke();
}
}
void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type);
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
struct ActionFloodFill : public Action
{
std::shared_ptr<Layer> m_layer;
std::shared_ptr<LayerFrame::Snapshot> m_snap;
std::array<bool, 6> m_dirty_face = SIXPLETTE(false);
std::array<glm::vec4, 6> m_dirty_box = SIXPLETTE(glm::vec4(0));
glm::ivec2 m_pos;
glm::vec4 m_color;
float m_threshold;
int m_layer_index;
int m_plane;
virtual void run() override { }
virtual size_t memory() override { return m_snap->memsize(); }
virtual Action* get_redo() override
{
auto a = new ActionFloodFill;
a->m_direction = reverse_direction();
a->m_layer = m_layer;
a->m_snap = m_snap;
a->m_pos = m_pos;
a->m_color = m_color;
a->m_layer_index = m_layer_index;
a->m_threshold = m_threshold;
a->m_plane = m_plane;
a->m_dirty_box = m_dirty_box;
a->m_dirty_face = m_dirty_face;
return a;
}
virtual void undo() override
{
if (m_direction == Direction::Undo)
{
m_layer->restore(*m_snap);
}
else
{
Canvas::FloodData plane_data;
std::unique_ptr<glm::vec4> color;
Canvas::I->flood_fill(m_layer_index, m_plane, { m_pos },
plane_data, m_threshold, m_color, color);
plane_data.apply();
}
}
};
switch (me->m_type)
{
case kEventType::MouseUpL:
glm::vec3 ro, rd, hit, n;
glm::vec2 pos;
int plane;
if (Canvas::I->point_trace(loc, ro, rd, hit, pos, n, plane))
{
Canvas::FloodData plane_data;
std::unique_ptr<glm::vec4> color;
Canvas::I->flood_fill(Canvas::I->m_current_layer_idx, plane, { (glm::ivec2)pos },
plane_data, m_tool->get_threshold(), Canvas::I->m_current_brush->m_tip_color, color);
auto a = new ActionFloodFill;
a->m_direction = Action::Direction::Undo;
a->m_layer = plane_data.layer;
a->m_snap = std::make_shared<LayerFrame::Snapshot>(plane_data.layer->snapshot());
a->m_pos = (glm::ivec2)pos;
a->m_color = Canvas::I->m_current_brush->m_tip_color;
a->m_layer_index = Canvas::I->m_current_layer_idx;
a->m_threshold = m_tool->get_threshold();
a->m_plane = plane;
a->m_dirty_box = plane_data.layer->frame().m_dirty_box;
a->m_dirty_face = plane_data.layer->frame().m_dirty_face;
ActionManager::add(a);
plane_data.apply();
}
break;
default:
break;
}
}
void CanvasModeFloodFill::init()
{
TextureManager::load(m_cursor_path.c_str());
}
void CanvasModeFloodFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_draw_tip)
{
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader({
.mvp = glm::scale(glm::vec3(1, -1, 1))
* ortho
* glm::translate(glm::vec3(Canvas::I->m_cur_pos, 0.f))
* glm::scale(glm::vec3(32, 32, 1))
* glm::translate(glm::vec3(0.5f, -0.5f, 0)),
.texture_slot = 0,
});
auto& t = TextureManager::get(m_cursor_id);
Canvas::I->m_sampler_linear.bind(0);
t.bind();
Canvas::I->m_plane.draw_fill();
t.unbind();
}
}
void CanvasModeFloodFill::enter(kCanvasMode prev)
{
auto tools = App::I->layout[App::I->main_id]->find("tools-container");
m_tool = tools->add_child<NodeToolBucket>();
}
void CanvasModeFloodFill::leave(kCanvasMode next)
{
pp::panopainter::destroy_legacy_node(*m_tool);
m_tool = nullptr;
}