Extract canvas object draw and brush panel services

This commit is contained in:
2026-06-16 18:43:14 +02:00
parent b56a46a82c
commit a5002a4e3e
10 changed files with 504 additions and 279 deletions

View File

@@ -23,6 +23,8 @@ set(PP_LEGACY_PAINT_DOCUMENT_SOURCES
src/canvas_actions.cpp src/canvas_actions.cpp
src/canvas_layer.cpp src/canvas_layer.cpp
src/legacy_canvas_document_io_services.cpp src/legacy_canvas_document_io_services.cpp
src/legacy_canvas_object_draw_services.cpp
src/legacy_canvas_object_draw_services.h
src/legacy_canvas_projection_services.cpp src/legacy_canvas_projection_services.cpp
src/legacy_canvas_projection_services.h src/legacy_canvas_projection_services.h
src/legacy_canvas_state_services.cpp src/legacy_canvas_state_services.cpp
@@ -143,6 +145,8 @@ set(PP_PANOPAINTER_APP_SOURCES
set(PP_PANOPAINTER_UI_SOURCES set(PP_PANOPAINTER_UI_SOURCES
src/legacy_brush_ui_services.cpp src/legacy_brush_ui_services.cpp
src/legacy_brush_ui_services.h src/legacy_brush_ui_services.h
src/legacy_brush_panel_services.cpp
src/legacy_brush_panel_services.h
src/legacy_document_animation_services.cpp src/legacy_document_animation_services.cpp
src/legacy_document_animation_services.h src/legacy_document_animation_services.h
src/legacy_grid_ui_services.cpp src/legacy_grid_ui_services.cpp

View File

@@ -79,14 +79,14 @@ What is still carrying too much live ownership:
Current hotspot files: Current hotspot files:
- `src/canvas.cpp`: 2728 lines - `src/canvas.cpp`: 2592 lines
- `src/app_layout.cpp`: 125 lines - `src/app_layout.cpp`: 125 lines
- `src/canvas_modes.cpp`: 1710 lines - `src/canvas_modes.cpp`: 1626 lines
- `src/node.cpp`: 1368 lines - `src/node.cpp`: 1368 lines
- `src/main.cpp`: 271 lines - `src/main.cpp`: 271 lines
- `src/node_panel_brush.cpp`: 1207 lines - `src/node_panel_brush.cpp`: 1094 lines
- `src/node_stroke_preview.cpp`: 910 lines - `src/node_stroke_preview.cpp`: 910 lines
- `src/node_canvas.cpp`: 864 lines - `src/node_canvas.cpp`: 872 lines
- `src/app.cpp`: 575 lines - `src/app.cpp`: 575 lines
- `src/app_dialogs.cpp`: 168 lines - `src/app_dialogs.cpp`: 168 lines
@@ -244,6 +244,18 @@ Current architecture mismatches that must be treated as real blockers:
callback-assembly setup now also route through callback-assembly setup now also route through
`execute_node_canvas_draw_unmerged_pass(...)`, which trims another coherent `execute_node_canvas_draw_unmerged_pass(...)`, which trims another coherent
unmerged draw shell from the live node even though the file itself remains unmerged draw shell from the live node even though the file itself remains
large, while `NodeCanvas::draw()` merged-pass callback wiring and pass setup
now also route through `execute_node_canvas_draw_merged_pass(...)`, which
trims another coherent merged draw shell from the live node even though the
broader draw loop still remains inline,
while `Canvas::draw_objects_direct(...)` and `Canvas::draw_objects(...)` now
route through `src/legacy_canvas_object_draw_services.*` instead of staying
inline in `src/canvas.cpp`, which trims another coherent object-draw and
viewport-state execution family from the live canvas shell,
while `NodePanelBrush` save/restore/scan/reload/find/get-path ownership now
routes through `src/legacy_brush_panel_services.*` instead of staying inline
in `src/node_panel_brush.cpp`, which trims another retained brush-workflow
pocket from the live UI node even though the broader panel still remains
large, while shared canvas-mode GL wrappers plus the large, while shared canvas-mode GL wrappers plus the
`CanvasModeBasicCamera` and `CanvasModeCamera` input handlers now also route `CanvasModeBasicCamera` and `CanvasModeCamera` input handlers now also route
through `src/legacy_canvas_mode_helpers.*` instead of staying inline in through `src/legacy_canvas_mode_helpers.*` instead of staying inline in

View File

@@ -91,7 +91,7 @@ Status: In Progress
Why now: Why now:
`src/canvas.cpp` is still the biggest single architectural blocker at about `src/canvas.cpp` is still the biggest single architectural blocker at about
2728 lines. 2592 lines.
Current slice: Current slice:
- Canvas state-management helpers for picking, clear/clear-all, layer - Canvas state-management helpers for picking, clear/clear-all, layer
@@ -108,6 +108,10 @@ Current slice:
`src/legacy_canvas_projection_services.*` instead of staying inline in `src/legacy_canvas_projection_services.*` instead of staying inline in
`src/canvas.cpp`, which trims another coherent non-UI state/query pocket `src/canvas.cpp`, which trims another coherent non-UI state/query pocket
from the live canvas shell. from the live canvas shell.
- `Canvas::draw_objects_direct(...)` and `Canvas::draw_objects(...)` now also
live in `src/legacy_canvas_object_draw_services.*` instead of staying inline
in `src/canvas.cpp`, which trims another coherent object-draw and
viewport-state execution pocket from the live canvas shell.
- Shared canvas-mode GL wrappers plus the `CanvasModeBasicCamera` and - Shared canvas-mode GL wrappers plus the `CanvasModeBasicCamera` and
`CanvasModeCamera` input handlers now also live in `CanvasModeCamera` input handlers now also live in
`src/legacy_canvas_mode_helpers.*` instead of staying inline in `src/legacy_canvas_mode_helpers.*` instead of staying inline in
@@ -263,6 +267,10 @@ Current slice:
through `execute_node_canvas_draw_unmerged_pass(...)`, which trims another through `execute_node_canvas_draw_unmerged_pass(...)`, which trims another
coherent unmerged draw-orchestration block from the live node even though coherent unmerged draw-orchestration block from the live node even though
the file size remains roughly flat. the file size remains roughly flat.
- `NodeCanvas::draw()` merged-pass callback wiring and pass setup now also
route through `execute_node_canvas_draw_merged_pass(...)`, which trims
another coherent merged draw-orchestration block from the live node even
though the broader draw loop still remains inline.
Write scope: Write scope:
- `src/node_stroke_preview.cpp` - `src/node_stroke_preview.cpp`
@@ -970,6 +978,13 @@ Why now:
Cloud browse/download/upload and brush package import/export still close over Cloud browse/download/upload and brush package import/export still close over
retained nodes, worker threads, and direct UI ownership. retained nodes, worker threads, and direct UI ownership.
Current slice:
- `NodePanelBrush` save/restore/scan/reload/find/get-path ownership now routes
through `src/legacy_brush_panel_services.*` instead of staying inline in
`src/node_panel_brush.cpp`, which trims a coherent retained brush-workflow
pocket from the live UI node even though cloud and package-worker ownership
still remain separate follow-up work.
Write scope: Write scope:
- `src/legacy_cloud_services.*` - `src/legacy_cloud_services.*`
- `src/node_dialog_cloud.*` - `src/node_dialog_cloud.*`

View File

@@ -10,6 +10,7 @@
#include "legacy_canvas_stroke_edge_services.h" #include "legacy_canvas_stroke_edge_services.h"
#include "legacy_canvas_stroke_execution_services.h" #include "legacy_canvas_stroke_execution_services.h"
#include "legacy_canvas_stroke_shader_services.h" #include "legacy_canvas_stroke_shader_services.h"
#include "legacy_canvas_object_draw_services.h"
#include "legacy_canvas_projection_services.h" #include "legacy_canvas_projection_services.h"
#include "legacy_canvas_stroke_services.h" #include "legacy_canvas_stroke_services.h"
#include "legacy_ui_gl_dispatch.h" #include "legacy_ui_gl_dispatch.h"
@@ -2531,149 +2532,12 @@ void Canvas::clear_context()
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame) void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame)
{ {
App::I->render_task([&] pp::panopainter::legacy_canvas_draw_objects_direct(*this, std::move(observer), layer, frame);
{
// save viewport and clear color states
const auto vp = query_canvas_viewport();
const auto cc = query_canvas_clear_color();
auto blend = query_canvas_capability(blend_state());
// prepare common states
apply_canvas_viewport(0, 0, layer.w, layer.h);
apply_canvas_capability(blend_state(), false);
GLuint rboID = allocate_canvas_depth_renderbuffer(layer.w, layer.h);
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
for (int i = 0; i < 6; i++)
{
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
layer.rtt(i, frame).bindFramebuffer();
attach_canvas_depth_renderbuffer(rboID);
observer(plane_camera, proj, i);
attach_canvas_depth_renderbuffer(0);
layer.rtt(i, frame).unbindFramebuffer();
layer.face(i, frame) = true;
layer.box(i, frame) = { 0, 0, layer.w, layer.h };
}
delete_canvas_renderbuffer(rboID);
// restore viewport and clear color states
blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
apply_canvas_clear_color(cc);
set_active_texture_unit(0);
});
} }
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame, bool save_history) void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame, bool save_history)
{ {
App::I->render_task([&] pp::panopainter::legacy_canvas_draw_objects(*this, std::move(observer), layer, frame, save_history);
{
// save viewport and clear color states
const auto vp = query_canvas_viewport();
const auto cc = query_canvas_clear_color();
auto blend = query_canvas_capability(blend_state());
// prepare common states
apply_canvas_viewport(0, 0, layer.w, layer.h);
apply_canvas_capability(blend_state(), false);
GLuint rboID = allocate_canvas_depth_renderbuffer(layer.w, layer.h);
RTT rtt;
rtt.create(layer.w, layer.h);
rtt.bindFramebuffer();
attach_canvas_depth_renderbuffer(rboID);
rtt.unbindFramebuffer();
// allocate action to add to history
ActionStroke* action;
if (save_history)
{
action = new ActionStroke;
action->was_saved = !m_unsaved;
}
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
for (int i = 0; i < 6; i++)
{
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
rtt.bindFramebuffer();
rtt.clear({ 1, 1, 1, 0 });
observer(plane_camera, proj, i);
rtt.unbindFramebuffer();
glm::vec4 bounds = rtt.calc_bounds();
layer.rtt(i, frame).bindFramebuffer();
glm::vec2 box_sz = zw(bounds) - xy(bounds);
bool has_data = box_sz.x > 0 && box_sz.y > 0;
if (save_history)
{
// save image before commit
if (has_data)
{
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
layer.rtt(i, frame).readPixelsRgba8(
static_cast<int>(bounds.x),
static_cast<int>(bounds.y),
static_cast<int>(box_sz.x),
static_cast<int>(box_sz.y),
action->m_image[i].get());
action->m_box[i] = bounds;
}
action->m_old_box[i] = layer.box(i, frame);
action->m_old_dirty[i] = layer.face(i, frame);
}
// draw the tmp layer into the actual layer
if (has_data)
{
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader(
pp::panopainter::LegacyCanvasDrawMergeTextureUniforms {
.mvp = glm::ortho(-0.5f, 0.5f, -0.5f, 0.5f),
.texture_slot = 0,
});
set_active_texture_unit(0);
m_sampler_nearest.bind(0);
rtt.bindTexture();
m_plane.draw_fill();
rtt.unbindTexture();
layer.face(i, frame) = true;
layer.box(i, frame) = { glm::min(xy(layer.box(i, frame)), xy(bounds)), glm::max(zw(layer.box(i, frame)), zw(bounds)) };
}
layer.rtt(i, frame).unbindFramebuffer();
}
if (save_history)
{
// save history
action->m_layer_idx = m_current_layer_idx;
action->m_frame_idx = frame;
action->m_canvas = this;
//action->m_stroke = std::move(m_current_stroke);
ActionManager::add(action);
}
delete_canvas_renderbuffer(rboID);
rtt.destroy();
// restore viewport and clear color states
blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
apply_canvas_clear_color(cc);
set_active_texture_unit(0);
});
} }
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, int frame, bool save_history) void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, int frame, bool save_history)

View File

@@ -0,0 +1,166 @@
#include "pch.h"
#include "legacy_brush_panel_services.h"
#include "app.h"
#include "asset.h"
#include "node_panel_brush.h"
#include <fstream>
#include <functional>
#include <memory>
namespace pp::panopainter {
LegacyBrushPanelServices::LegacyBrushPanelServices(NodePanelBrush& panel) noexcept
: panel_(panel)
{
}
int LegacyBrushPanelServices::find_brush(const std::string& name) const
{
for (int i = 0; i < panel_.m_container->m_children.size(); i++) {
auto* b = static_cast<NodeButtonBrush*>(panel_.m_container->m_children[i].get());
if (b->brush_name.find(name) != std::string::npos) {
return i;
}
}
return -1;
}
std::string LegacyBrushPanelServices::get_texture_path(int index) const
{
if (index < 0 || index >= panel_.m_container->m_children.size()) {
return "";
}
return static_cast<NodeButtonBrush*>(panel_.m_container->m_children[index].get())->high_path;
}
std::string LegacyBrushPanelServices::get_thumb_path(int index) const
{
if (index < 0 || index >= panel_.m_container->m_children.size()) {
return "";
}
return static_cast<NodeButtonBrush*>(panel_.m_container->m_children[index].get())->thumb_path;
}
bool LegacyBrushPanelServices::save()
{
std::ofstream f(App::I->data_path + "/settings/" + panel_.m_dir_name + ".bin", std::ios::binary);
if (f.good()) {
BinaryStreamWriter sw;
sw.init();
sw.wstring_raw("PPVR"); // magic code
sw.wu16(0); // version major
sw.wu16(1); // minor
sw.wu32((int)panel_.m_container->m_children.size()); // number of items
for (const auto& child : panel_.m_container->m_children) {
auto b = std::static_pointer_cast<NodeButtonBrush>(child);
sw << *b;
}
f.write((char*)sw.m_data.data(), sw.m_data.size());
f.close();
App::I->flush_platform_storage();
return true;
}
return false;
}
bool LegacyBrushPanelServices::restore()
{
Asset f;
auto path = App::I->data_path + "/settings/" + panel_.m_dir_name + ".bin";
if (f.open(path.c_str())) {
f.read_all();
if (f.m_len == 0) {
return false;
}
BinaryStreamReader sr;
sr.init(f.m_data, f.m_len);
if (sr.rstring(4) != "PPVR") {
LOG("PPVR tag not found")
return false;
}
auto vmaj = sr.ru16();
auto vmin = sr.ru16();
if (vmaj != 0 && vmin != 1) {
LOG("unrecognised version %d.%d", vmaj, vmin);
return false;
}
auto count = sr.ru32();
for (int k = 0; k < count; k++) {
auto b = std::make_shared<NodeButtonBrush>();
if (!b->read(sr)) {
LOG("error deserializing the button brush");
return false;
}
if (Asset::exist(b->high_path)) {
panel_.m_container->add_child(b);
b->init();
b->create();
b->loaded();
b->set_icon(b->thumb_path.c_str());
b->on_click = std::bind(&NodePanelBrush::handle_click, &panel_, std::placeholders::_1);
}
}
return true;
}
return false;
}
void LegacyBrushPanelServices::clear()
{
panel_.m_container->remove_all_children();
}
void LegacyBrushPanelServices::scan()
{
auto icons = Asset::list_files("data/" + panel_.m_dir_name, ".*\\.png$");
for (auto& i : icons) {
std::string path = "data/" + panel_.m_dir_name + "/thumbs/" + i;
std::string path_hi = "data/" + panel_.m_dir_name + "/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
panel_.m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path.c_str());
brush->thumb_path = path;
brush->high_path = path_hi;
brush->brush_name = i;
brush->m_user_brush = false; // system brush, cannot be deleted from file
brush->on_click = std::bind(&NodePanelBrush::handle_click, &panel_, std::placeholders::_1);
}
auto custom_icons = Asset::list_files(App::I->data_path + "/" + panel_.m_dir_name, ".*\\.png$");
for (auto& i : custom_icons) {
std::string path_thumb = App::I->data_path + "/" + panel_.m_dir_name + "/thumbs/" + i;
std::string path_high = App::I->data_path + "/" + panel_.m_dir_name + "/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
panel_.m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path_thumb.c_str());
brush->thumb_path = path_thumb;
brush->high_path = path_high;
brush->brush_name = i;
brush->m_user_brush = true;
brush->on_click = std::bind(&NodePanelBrush::handle_click, &panel_, std::placeholders::_1);
}
}
void LegacyBrushPanelServices::reload()
{
clear();
scan();
save();
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
class NodePanelBrush;
namespace pp::panopainter {
class LegacyBrushPanelServices final {
public:
explicit LegacyBrushPanelServices(NodePanelBrush& panel) noexcept;
int find_brush(const std::string& name) const;
std::string get_texture_path(int index) const;
std::string get_thumb_path(int index) const;
bool save();
bool restore();
void clear();
void scan();
void reload();
private:
NodePanelBrush& panel_;
};
} // namespace pp::panopainter

View File

@@ -0,0 +1,221 @@
#include "pch.h"
#include "legacy_canvas_object_draw_services.h"
#include "app.h"
#include "canvas.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_gl_renderbuffer_dispatch.h"
#include "legacy_ui_gl_dispatch.h"
#include "renderer_gl/opengl_capabilities.h"
namespace pp::panopainter {
namespace {
GLenum blend_state()
{
return static_cast<GLenum>(pp::renderer::gl::blend_state());
}
void apply_canvas_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
pp::legacy::ui_gl::apply_viewport(x, y, width, height, "Canvas");
}
pp::renderer::gl::OpenGlViewportRect query_canvas_viewport()
{
return pp::legacy::ui_gl::query_viewport_rect("Canvas");
}
std::array<float, 4> query_canvas_clear_color()
{
return pp::legacy::ui_gl::query_clear_color("Canvas");
}
void apply_canvas_clear_color(std::array<float, 4> color)
{
pp::legacy::ui_gl::set_clear_color(color, "Canvas");
}
void apply_canvas_capability(std::uint32_t state, bool enabled)
{
pp::legacy::ui_gl::set_capability(state, enabled, "Canvas");
}
void set_active_texture_unit(std::uint32_t unit_index)
{
pp::legacy::ui_gl::activate_texture_unit(unit_index, "Canvas");
}
struct LegacyCanvasObjectDrawState {
pp::renderer::gl::OpenGlViewportRect viewport;
std::array<float, 4> clear_color;
bool blend = false;
};
LegacyCanvasObjectDrawState capture_legacy_canvas_object_draw_state()
{
return {
.viewport = query_canvas_viewport(),
.clear_color = query_canvas_clear_color(),
.blend = pp::legacy::ui_gl::query_capability(blend_state(), "Canvas"),
};
}
void restore_legacy_canvas_object_draw_state(const LegacyCanvasObjectDrawState& state)
{
state.blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
apply_canvas_viewport(state.viewport.x, state.viewport.y, state.viewport.width, state.viewport.height);
apply_canvas_clear_color(state.clear_color);
set_active_texture_unit(0);
}
template <typename Execute>
void execute_legacy_canvas_object_draw_task(Layer& layer, Execute&& execute)
{
const auto state = capture_legacy_canvas_object_draw_state();
apply_canvas_viewport(0, 0, layer.w, layer.h);
apply_canvas_capability(blend_state(), false);
GLuint rboID = pp::legacy::gl_renderbuffer::allocate_depth_renderbuffer(layer.w, layer.h, "Canvas");
execute(rboID);
pp::legacy::gl_renderbuffer::delete_renderbuffer(rboID, "Canvas");
restore_legacy_canvas_object_draw_state(state);
}
void execute_legacy_canvas_object_draw_face(
Canvas& canvas,
Layer& layer,
int frame,
int face_index,
RTT& rtt,
ActionStroke* action,
bool save_history,
const std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)>& observer)
{
rtt.bindFramebuffer();
rtt.clear({ 1, 1, 1, 0 });
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), canvas.m_plane_origin[face_index], canvas.m_plane_tangent[face_index]);
observer(plane_camera, proj, face_index);
rtt.unbindFramebuffer();
glm::vec4 bounds = rtt.calc_bounds();
layer.rtt(face_index, frame).bindFramebuffer();
glm::vec2 box_sz = zw(bounds) - xy(bounds);
bool has_data = box_sz.x > 0 && box_sz.y > 0;
if (save_history)
{
if (has_data)
{
action->m_image[face_index] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
layer.rtt(face_index, frame).readPixelsRgba8(
static_cast<int>(bounds.x),
static_cast<int>(bounds.y),
static_cast<int>(box_sz.x),
static_cast<int>(box_sz.y),
action->m_image[face_index].get());
action->m_box[face_index] = bounds;
}
action->m_old_box[face_index] = layer.box(face_index, frame);
action->m_old_dirty[face_index] = layer.face(face_index, frame);
}
if (has_data)
{
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader(
pp::panopainter::LegacyCanvasDrawMergeTextureUniforms {
.mvp = glm::ortho(-0.5f, 0.5f, -0.5f, 0.5f),
.texture_slot = 0,
});
set_active_texture_unit(0);
canvas.m_sampler_nearest.bind(0);
rtt.bindTexture();
canvas.m_plane.draw_fill();
rtt.unbindTexture();
layer.face(face_index, frame) = true;
layer.box(face_index, frame) = { glm::min(xy(layer.box(face_index, frame)), xy(bounds)), glm::max(zw(layer.box(face_index, frame)), zw(bounds)) };
}
layer.rtt(face_index, frame).unbindFramebuffer();
}
} // namespace
void legacy_canvas_draw_objects_direct(
Canvas& canvas,
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame)
{
App::I->render_task([&]
{
execute_legacy_canvas_object_draw_task(layer, [&](GLuint rboID)
{
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
for (int i = 0; i < 6; i++)
{
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), canvas.m_plane_origin[i], canvas.m_plane_tangent[i]);
layer.rtt(i, frame).bindFramebuffer();
pp::legacy::gl_renderbuffer::attach_depth_renderbuffer(rboID, "Canvas");
observer(plane_camera, proj, i);
pp::legacy::gl_renderbuffer::attach_depth_renderbuffer(0, "Canvas");
layer.rtt(i, frame).unbindFramebuffer();
layer.face(i, frame) = true;
layer.box(i, frame) = { 0, 0, layer.w, layer.h };
}
});
});
}
void legacy_canvas_draw_objects(
Canvas& canvas,
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame,
bool save_history)
{
App::I->render_task([&]
{
execute_legacy_canvas_object_draw_task(layer, [&](GLuint rboID)
{
RTT rtt;
rtt.create(layer.w, layer.h);
rtt.bindFramebuffer();
pp::legacy::gl_renderbuffer::attach_depth_renderbuffer(rboID, "Canvas");
rtt.unbindFramebuffer();
ActionStroke* action = nullptr;
if (save_history)
{
action = new ActionStroke;
action->was_saved = !canvas.m_unsaved;
}
for (int i = 0; i < 6; i++)
execute_legacy_canvas_object_draw_face(canvas, layer, frame, i, rtt, action, save_history, observer);
if (save_history)
{
action->m_layer_idx = canvas.m_current_layer_idx;
action->m_frame_idx = frame;
action->m_canvas = &canvas;
ActionManager::add(action);
}
rtt.destroy();
});
});
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,22 @@
#pragma once
#include "canvas.h"
#include <functional>
namespace pp::panopainter {
void legacy_canvas_draw_objects_direct(
Canvas& canvas,
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame);
void legacy_canvas_draw_objects(
Canvas& canvas,
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame,
bool save_history);
} // namespace pp::panopainter

View File

@@ -446,6 +446,26 @@ void execute_node_canvas_draw_unmerged_pass(
}); });
} }
void execute_node_canvas_draw_merged_pass(
NodeCanvas& node_canvas,
const glm::mat4& proj,
const glm::mat4& camera)
{
pp::panopainter::execute_legacy_canvas_draw_merged_pass(
node_canvas,
proj,
camera,
[&](auto state, bool enabled) {
apply_node_canvas_capability(state, enabled);
},
[](int unit) {
set_active_texture_unit(unit);
},
[&] {
node_canvas.m_face_plane.draw_fill();
});
}
void execute_node_canvas_draw_merge_tail( void execute_node_canvas_draw_merge_tail(
NodeCanvas& node_canvas, NodeCanvas& node_canvas,
const glm::mat4& ortho_proj, const glm::mat4& ortho_proj,
@@ -662,19 +682,7 @@ void NodeCanvas::draw()
apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w); apply_node_canvas_viewport(c.x + App::I->off_x, c.y + App::I->off_y, c.z, c.w);
}, },
[&] { [&] {
pp::panopainter::execute_legacy_canvas_draw_merged_pass( execute_node_canvas_draw_merged_pass(*this, proj, camera);
*this,
proj,
camera,
[&](auto state, bool enabled) {
apply_node_canvas_capability(state, enabled);
},
[](int unit) {
set_active_texture_unit(unit);
},
[&] {
m_face_plane.draw_fill();
});
}, },
[&] { [&] {
execute_node_canvas_draw_unmerged_pass(*this, proj, camera, c, yaw, pitch, roll); execute_node_canvas_draw_unmerged_pass(*this, proj, camera, c, yaw, pitch, roll);

View File

@@ -1,6 +1,7 @@
#include "pch.h" #include "pch.h"
#include "log.h" #include "log.h"
#include "node_panel_brush.h" #include "node_panel_brush.h"
#include "legacy_brush_panel_services.h"
#include "assets/brush_package.h" #include "assets/brush_package.h"
#include "app_core/brush_ui.h" #include "app_core/brush_ui.h"
#include "legacy_brush_ui_services.h" #include "legacy_brush_ui_services.h"
@@ -208,156 +209,42 @@ void NodePanelBrush::handle_click(Node* target)
int NodePanelBrush::find_brush(const std::string & name) const int NodePanelBrush::find_brush(const std::string & name) const
{ {
for (int i = 0; i < m_container->m_children.size(); i++) return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).find_brush(name);
{
NodeButtonBrush* b = (NodeButtonBrush*)m_container->m_children[i].get();
if (b->brush_name.find(name) != std::string::npos)
return i;
}
return -1;
} }
std::string NodePanelBrush::get_texture_path(int index) const std::string NodePanelBrush::get_texture_path(int index) const
{ {
if (index < 0 || index >= m_container->m_children.size()) return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).get_texture_path(index);
return "";
return ((NodeButtonBrush*)m_container->m_children[index].get())->high_path;
} }
std::string NodePanelBrush::get_thumb_path(int index) const std::string NodePanelBrush::get_thumb_path(int index) const
{ {
if (index < 0 || index >= m_container->m_children.size()) return pp::panopainter::LegacyBrushPanelServices(const_cast<NodePanelBrush&>(*this)).get_thumb_path(index);
return "";
return ((NodeButtonBrush*)m_container->m_children[index].get())->thumb_path;
} }
bool NodePanelBrush::save() bool NodePanelBrush::save()
{ {
std::ofstream f(App::I->data_path + "/settings/" + m_dir_name + ".bin", std::ios::binary); return pp::panopainter::LegacyBrushPanelServices(*this).save();
if (f.good())
{
BinaryStreamWriter sw;
sw.init();
sw.wstring_raw("PPVR"); // magic code
sw.wu16(0); // version major
sw.wu16(1); // minor
sw.wu32((int)m_container->m_children.size()); // number of items
for (const auto& child : m_container->m_children)
{
auto b = std::static_pointer_cast<NodeButtonBrush>(child);
sw << *b;
}
f.write((char*)sw.m_data.data(), sw.m_data.size());
f.close();
App::I->flush_platform_storage();
return true;
}
return false;
} }
bool NodePanelBrush::restore() bool NodePanelBrush::restore()
{ {
Asset f; return pp::panopainter::LegacyBrushPanelServices(*this).restore();
auto path = App::I->data_path + "/settings/" + m_dir_name + ".bin";
if (f.open(path.c_str()))
{
f.read_all();
if (f.m_len == 0)
return false;
BinaryStreamReader sr;
sr.init(f.m_data, f.m_len);
// sanity checks
if (sr.rstring(4) != "PPVR")
{
LOG("PPVR tag not found")
return false;
}
auto vmaj = sr.ru16();
auto vmin = sr.ru16();
if (vmaj != 0 && vmin != 1)
{
LOG("unrecognised version %d.%d", vmaj, vmin);
return false;
}
auto count = sr.ru32();
for (int k = 0; k < count; k++)
{
auto b = std::make_shared<NodeButtonBrush>();
if (!b->read(sr))
{
LOG("error deserializing the button brush");
return false;
}
if (Asset::exist(b->high_path))
{
m_container->add_child(b);
b->init();
b->create();
b->loaded();
b->set_icon(b->thumb_path.c_str());
b->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
}
return true;
}
return false;
} }
void NodePanelBrush::clear() void NodePanelBrush::clear()
{ {
m_container->remove_all_children(); pp::panopainter::LegacyBrushPanelServices(*this).clear();
} }
void NodePanelBrush::scan() void NodePanelBrush::scan()
{ {
auto icons = Asset::list_files("data/" + m_dir_name, ".*\\.png$"); pp::panopainter::LegacyBrushPanelServices(*this).scan();
for (auto& i : icons)
{
std::string path = "data/" + m_dir_name + "/thumbs/" + i;
std::string path_hi = "data/" + m_dir_name + "/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path.c_str());
brush->thumb_path = path;
brush->high_path = path_hi;
brush->brush_name = i;
brush->m_user_brush = false; // system brush, cannot be deleted from file
brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
auto custom_icons = Asset::list_files(App::I->data_path + "/" + m_dir_name, ".*\\.png$");
for (auto& i : custom_icons)
{
std::string path_thumb = App::I->data_path + "/" + m_dir_name + "/thumbs/" + i;
std::string path_high = App::I->data_path + "/" + m_dir_name + "/" + i;
NodeButtonBrush* brush = new NodeButtonBrush;
m_container->add_child(brush);
brush->init();
brush->create();
brush->loaded();
brush->set_icon(path_thumb.c_str());
brush->thumb_path = path_thumb;
brush->high_path = path_high;
brush->brush_name = i;
brush->m_user_brush = true;
brush->on_click = std::bind(&NodePanelBrush::handle_click, this, std::placeholders::_1);
}
} }
void NodePanelBrush::reload() void NodePanelBrush::reload()
{ {
clear(); pp::panopainter::LegacyBrushPanelServices(*this).reload();
scan();
save();
} }
void NodePanelBrush::added(Node* parent) void NodePanelBrush::added(Node* parent)