Extract app runtime shell, canvas render shell, and node tree services
This commit is contained in:
@@ -20,6 +20,8 @@ set(PP_LEGACY_PAINT_DOCUMENT_SOURCES
|
||||
src/bezier.cpp
|
||||
src/brush.cpp
|
||||
src/canvas.cpp
|
||||
src/legacy_canvas_render_shell_services.cpp
|
||||
src/legacy_canvas_render_shell_services.h
|
||||
src/canvas_actions.cpp
|
||||
src/canvas_layer.cpp
|
||||
src/legacy_canvas_layer_services.cpp
|
||||
@@ -52,6 +54,7 @@ set(PP_LEGACY_UI_CORE_SOURCES
|
||||
src/legacy_ui_node_event.cpp
|
||||
src/legacy_ui_node_event.h
|
||||
src/legacy_ui_node_execution.cpp
|
||||
src/legacy_ui_node_tree_services.cpp
|
||||
src/layout.cpp
|
||||
src/node.cpp
|
||||
src/node_border.cpp
|
||||
@@ -129,6 +132,7 @@ set(PP_PANOPAINTER_APP_SOURCES
|
||||
src/app_layout_tools_menu.cpp
|
||||
src/app_shaders.cpp
|
||||
src/app_vr.cpp
|
||||
src/legacy_app_runtime_shell_services.cpp
|
||||
src/legacy_app_frame_services.cpp
|
||||
src/legacy_app_dialog_services.cpp
|
||||
src/legacy_app_dialog_services.h
|
||||
|
||||
@@ -79,15 +79,15 @@ What is still carrying too much live ownership:
|
||||
|
||||
Current hotspot files:
|
||||
|
||||
- `src/canvas.cpp`: 1010 lines
|
||||
- `src/canvas.cpp`: 429 lines
|
||||
- `src/app_layout.cpp`: 125 lines
|
||||
- `src/canvas_modes.cpp`: 720 lines
|
||||
- `src/node.cpp`: 803 lines
|
||||
- `src/node.cpp`: 465 lines
|
||||
- `src/main.cpp`: 271 lines
|
||||
- `src/node_panel_brush.cpp`: 435 lines
|
||||
- `src/node_stroke_preview.cpp`: 607 lines
|
||||
- `src/node_canvas.cpp`: 219 lines
|
||||
- `src/app.cpp`: 502 lines
|
||||
- `src/app.cpp`: 292 lines
|
||||
- `src/app_dialogs.cpp`: 168 lines
|
||||
|
||||
Current architecture mismatches that must be treated as real blockers:
|
||||
@@ -332,7 +332,22 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
while `Canvas` point-trace/unproject/project/camera push-pop-get-set and
|
||||
face-to-shape helpers now also route through
|
||||
`src/legacy_canvas_projection_services.*` instead of staying inline in
|
||||
`src/canvas.cpp`.
|
||||
`src/canvas.cpp`, while `App::draw(...)`, `App::update(...)`,
|
||||
`App::terminate(...)`, `App::update_memory_usage(...)`,
|
||||
`App::update_rec_frames(...)`, `App::res_from_index(...)`,
|
||||
`App::res_to_index(...)`, `App::res_to_string(...)`, `App::rec_clear(...)`,
|
||||
`App::rec_start(...)`, `App::rec_stop(...)`, `App::rec_export(...)`,
|
||||
`App::rec_loop(...)`, and `App::render_thread_tick(...)` now also route
|
||||
through `src/legacy_app_runtime_shell_services.cpp` instead of staying
|
||||
inline in `src/app.cpp`, while `Canvas::draw_merge(...)`, the temporary
|
||||
paint/branch orchestration helpers, final-plane composite, timelapse commit,
|
||||
create/destroy, clear-context, and camera accessors now also route through
|
||||
`src/legacy_canvas_render_shell_services.*` instead of staying inline in
|
||||
`src/canvas.cpp`, while `Node::destroy()`, `root()`, `set_manager(...)`,
|
||||
`added_to_root()`, `handle_on_screen(...)`, template loading helpers, child
|
||||
add/remove/move helpers, and child query helpers now also route through
|
||||
`src/legacy_ui_node_tree_services.cpp` instead of staying inline in
|
||||
`src/node.cpp`.
|
||||
- Modern C++23 usage exists in extracted components, especially `std::span`,
|
||||
explicit result/status objects, and a few concepts, but the live app still
|
||||
does not consistently express ownership, thread affinity, or renderer
|
||||
|
||||
@@ -91,7 +91,7 @@ Status: In Progress
|
||||
|
||||
Why now:
|
||||
`src/canvas.cpp` is still the biggest single architectural blocker at about
|
||||
1010 lines, with `src/canvas_modes.cpp` now materially thinner and the next
|
||||
429 lines, with `src/canvas_modes.cpp` now materially thinner and the next
|
||||
remaining render-shell pressure shifting toward preview/canvas nodes.
|
||||
|
||||
Current slice:
|
||||
@@ -142,6 +142,12 @@ Current slice:
|
||||
in `src/legacy_canvas_stroke_runtime_services.*` instead of staying inline in
|
||||
`src/canvas.cpp`, which trims another large retained live stroke/runtime
|
||||
pocket from the canvas shell.
|
||||
- `Canvas::draw_merge(...)`, the temporary-paint and merge-branch
|
||||
orchestration helpers, final-plane composite, timelapse commit, create,
|
||||
destroy, clear-context, and camera accessors now also live in
|
||||
`src/legacy_canvas_render_shell_services.*` instead of staying inline in
|
||||
`src/canvas.cpp`, which trims another large retained render/context shell
|
||||
from the live canvas owner.
|
||||
- The `CanvasModePen` and `CanvasModeLine` interaction families now also live
|
||||
in `src/legacy_canvas_mode_pen_line.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which materially thins another retained pen/line
|
||||
@@ -521,7 +527,7 @@ Status: In Progress
|
||||
|
||||
Why now:
|
||||
`src/app.cpp` still carries startup, frame flow, queue draining, recording,
|
||||
and composition logic in one 575-line file.
|
||||
and composition logic in one 292-line file.
|
||||
|
||||
Current slice:
|
||||
- UI observer math now routes through `src/legacy_app_frame_services.cpp`
|
||||
@@ -530,6 +536,14 @@ Current slice:
|
||||
retained helper.
|
||||
- Canvas toolbar refresh in `App::update()` now also routes through that helper
|
||||
file, materially shrinking `src/app.cpp`.
|
||||
- `App::draw(...)`, `App::update(...)`, `App::terminate(...)`,
|
||||
`App::update_memory_usage(...)`, `App::update_rec_frames(...)`,
|
||||
`App::res_from_index(...)`, `App::res_to_index(...)`,
|
||||
`App::res_to_string(...)`, `App::rec_clear(...)`, `App::rec_start(...)`,
|
||||
`App::rec_stop(...)`, `App::rec_export(...)`, `App::rec_loop(...)`, and
|
||||
`App::render_thread_tick(...)` now also live in
|
||||
`src/legacy_app_runtime_shell_services.cpp` instead of staying inline in
|
||||
`src/app.cpp`, which materially thins the remaining frame/runtime shell.
|
||||
|
||||
Write scope:
|
||||
- `src/app.cpp`
|
||||
@@ -758,6 +772,12 @@ Current slice:
|
||||
`src/legacy_ui_node_attributes.*` instead of staying inline in `src/node.cpp`,
|
||||
which trims another coherent XML/Yoga attribute decoding pocket from the base
|
||||
scene-graph shell without changing its public surface.
|
||||
- `Node::destroy()`, `root()`, `set_manager(...)`, `added_to_root()`,
|
||||
`handle_on_screen(...)`, template loading helpers, child add/remove/move
|
||||
helpers, and child query helpers now also live in
|
||||
`src/legacy_ui_node_tree_services.cpp` instead of staying inline in
|
||||
`src/node.cpp`, which materially thins the remaining generic scene-graph
|
||||
lifecycle/tree shell without changing the public surface.
|
||||
|
||||
Write scope:
|
||||
- `src/node.cpp`
|
||||
|
||||
237
src/app.cpp
237
src/app.cpp
@@ -32,43 +32,6 @@
|
||||
|
||||
App* App::I = nullptr; // singleton
|
||||
|
||||
namespace {
|
||||
void apply_app_viewport(pp::renderer::gl::OpenGlViewportRect viewport)
|
||||
{
|
||||
const auto status = pp::renderer::gl::apply_opengl_viewport(
|
||||
viewport,
|
||||
pp::renderer::gl::OpenGlViewportDispatch {
|
||||
.viewport = pp::legacy::ui_gl::set_opengl_viewport,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("OpenGL viewport failed: %s", status.message);
|
||||
}
|
||||
|
||||
void apply_app_scissor(pp::renderer::gl::OpenGlScissorRect scissor)
|
||||
{
|
||||
const auto status = pp::renderer::gl::apply_opengl_scissor_rect(
|
||||
scissor,
|
||||
pp::renderer::gl::OpenGlScissorDispatch {
|
||||
.enable = pp::legacy::ui_gl::enable_opengl_state,
|
||||
.disable = pp::legacy::ui_gl::disable_opengl_state,
|
||||
.scissor = pp::legacy::ui_gl::set_opengl_scissor,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("OpenGL scissor failed: %s", status.message);
|
||||
}
|
||||
|
||||
void apply_app_scissor_test(bool enabled)
|
||||
{
|
||||
const auto status = pp::renderer::gl::apply_opengl_scissor_test(
|
||||
enabled,
|
||||
pp::renderer::gl::OpenGlScissorTestDispatch {
|
||||
.enable = pp::legacy::ui_gl::enable_opengl_state,
|
||||
.disable = pp::legacy::ui_gl::disable_opengl_state,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("OpenGL scissor test failed: %s", status.message);
|
||||
}
|
||||
|
||||
[[nodiscard]] GLenum linear_texture_filter() noexcept
|
||||
{
|
||||
return static_cast<GLenum>(pp::renderer::gl::linear_texture_filter());
|
||||
@@ -94,7 +57,6 @@ void apply_app_scissor_test(bool enabled)
|
||||
return static_cast<GLuint>(pp::renderer::gl::default_framebuffer_id());
|
||||
}
|
||||
|
||||
}
|
||||
void App::create()
|
||||
{
|
||||
const auto initial_surface = pp::app::plan_app_initial_surface();
|
||||
@@ -182,11 +144,7 @@ void App::initLog()
|
||||
|
||||
namespace pp::panopainter
|
||||
{
|
||||
bool process_legacy_recording_worker_iteration(App& app);
|
||||
void update_legacy_recording_frame_label(App& app);
|
||||
bool update_legacy_app_ui_observer(App& app, Node* n);
|
||||
void watch_legacy_app_ui_children(App& app, const std::function<bool(Node*)>& observer, bool skip_first_main_child);
|
||||
void update_legacy_canvas_toolbar(App& app);
|
||||
}
|
||||
|
||||
bool App::check_license()
|
||||
@@ -334,143 +292,6 @@ bool App::update_ui_observer(Node *n)
|
||||
return pp::panopainter::update_legacy_app_ui_observer(*this, n);
|
||||
}
|
||||
|
||||
void App::draw(float dt)
|
||||
{
|
||||
const auto draw_plan = pp::app::plan_app_frame_draw(
|
||||
canvas != nullptr,
|
||||
canvas && canvas->m_canvas,
|
||||
vr_active,
|
||||
ui_visible,
|
||||
vr_only);
|
||||
|
||||
// update offscreen stuff
|
||||
if (draw_plan.draw_canvas_stroke)
|
||||
canvas->m_canvas->stroke_draw();
|
||||
|
||||
auto observer = std::bind(&App::update_ui_observer, this, std::placeholders::_1);
|
||||
|
||||
if (draw_plan.draw_vr_ui)
|
||||
{
|
||||
uirtt.bindFramebuffer();
|
||||
uirtt.clear();
|
||||
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
|
||||
.width = static_cast<std::int32_t>(uirtt.getWidth()),
|
||||
.height = static_cast<std::int32_t>(uirtt.getHeight()),
|
||||
});
|
||||
apply_app_scissor_test(true);
|
||||
pp::panopainter::watch_legacy_app_ui_children(*this, observer, true);
|
||||
apply_app_scissor_test(false);
|
||||
uirtt.unbindFramebuffer();
|
||||
}
|
||||
|
||||
if (draw_plan.draw_main_ui)
|
||||
{
|
||||
bind_main_render_target();
|
||||
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
|
||||
.x = static_cast<std::int32_t>(off_x),
|
||||
.y = static_cast<std::int32_t>(off_y),
|
||||
.width = static_cast<std::int32_t>(width),
|
||||
.height = static_cast<std::int32_t>(height),
|
||||
});
|
||||
apply_app_scissor_test(true);
|
||||
pp::panopainter::watch_legacy_app_ui_children(*this, observer, false);
|
||||
apply_app_scissor_test(false);
|
||||
}
|
||||
|
||||
if (draw_plan.reset_redraw)
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
void App::update(float dt)
|
||||
{
|
||||
const auto update_plan = pp::app::plan_app_frame_update(redraw, animate);
|
||||
if (!update_plan.update_frame)
|
||||
return;
|
||||
|
||||
if (auto* main = layout[main_id]; update_plan.update_layouts && main)
|
||||
main->update(width, height, zoom);
|
||||
|
||||
if (auto* main = layout_designer[main_id]; update_plan.update_layouts && main)
|
||||
main->update(width, height, zoom);
|
||||
|
||||
if (!update_plan.refresh_canvas_toolbar)
|
||||
return;
|
||||
|
||||
pp::panopainter::update_legacy_canvas_toolbar(*this);
|
||||
}
|
||||
|
||||
void App::terminate()
|
||||
{
|
||||
LOG("App::terminate");
|
||||
const auto shutdown_plan = pp::app::plan_app_shutdown();
|
||||
|
||||
if (shutdown_plan.save_ui_state)
|
||||
ui_save();
|
||||
|
||||
if (shutdown_plan.terminate_stroke_preview_renderer)
|
||||
NodeStrokePreview::terminate_renderer();
|
||||
if (shutdown_plan.stop_recording)
|
||||
rec_stop();
|
||||
|
||||
if (shutdown_plan.invalidate_textures)
|
||||
TextureManager::invalidate();
|
||||
if (shutdown_plan.invalidate_shaders)
|
||||
ShaderManager::invalidate();
|
||||
if (shutdown_plan.unload_layouts) {
|
||||
layout.unload();
|
||||
layout_designer.unload();
|
||||
}
|
||||
if (shutdown_plan.destroy_ui_render_target)
|
||||
uirtt.destroy();
|
||||
if (shutdown_plan.destroy_face_plane)
|
||||
m_face_plane.destroy();
|
||||
if (shutdown_plan.release_panel_nodes) {
|
||||
layers.reset();
|
||||
color.reset();
|
||||
stroke.reset();
|
||||
grid.reset();
|
||||
presets.reset();
|
||||
floating_presets.reset();
|
||||
floating_color.reset();
|
||||
floating_layers.reset();
|
||||
floating_picker.reset();
|
||||
}
|
||||
if (shutdown_plan.clear_quick_mode_state)
|
||||
quick_mode_state.clear();
|
||||
}
|
||||
|
||||
void App::update_memory_usage(size_t bytes)
|
||||
{
|
||||
if (auto txt = layout[main_id]->find<NodeText>("txt-memory"))
|
||||
{
|
||||
const auto label = pp::app::make_history_memory_label(bytes);
|
||||
txt->set_text(label.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void App::update_rec_frames()
|
||||
{
|
||||
pp::panopainter::update_legacy_recording_frame_label(*this);
|
||||
}
|
||||
|
||||
int App::res_from_index(int i)
|
||||
{
|
||||
const auto resolution = pp::app::display_resolution_from_index(i);
|
||||
return resolution ? resolution.value() : pp::app::document_resolution_values.front();
|
||||
}
|
||||
|
||||
int App::res_to_index(int res)
|
||||
{
|
||||
const auto index = pp::app::document_resolution_to_index(res);
|
||||
return index ? static_cast<int>(index.value()) : static_cast<int>(pp::app::document_resolution_values.size());
|
||||
}
|
||||
|
||||
std::string App::res_to_string(int res)
|
||||
{
|
||||
const auto label = pp::app::document_resolution_label(res);
|
||||
return label ? std::string(label.value()) : std::string("unknown");
|
||||
}
|
||||
|
||||
void App::renderdoc_frame_start()
|
||||
{
|
||||
begin_render_capture_frame();
|
||||
@@ -481,64 +302,6 @@ void App::renderdoc_frame_end()
|
||||
end_render_capture_frame();
|
||||
}
|
||||
|
||||
void App::rec_clear()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_clear(
|
||||
rec_running,
|
||||
platform_deletes_recorded_files_on_clear()
|
||||
);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_clear_plan(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording clear action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_start()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_start(rec_running);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_start_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording start action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_stop()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_stop(rec_running);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_stop_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording stop action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_export(std::string path)
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_export(static_cast<std::size_t>(rec_count));
|
||||
/*
|
||||
#if defined(__IOS__) || defined(__OSX__)
|
||||
export_mp4(rec_path, width, height, rec_count, ^(float) {
|
||||
pb->increment();
|
||||
});
|
||||
#endif
|
||||
*/
|
||||
const auto status = pp::panopainter::execute_legacy_recording_export_plan(*this, plan, path);
|
||||
if (!status.ok())
|
||||
LOG("Recording export action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_loop()
|
||||
{
|
||||
BT_SetTerminate();
|
||||
rec_running = true;
|
||||
while (rec_running)
|
||||
{
|
||||
if (!pp::panopainter::process_legacy_recording_worker_iteration(*this))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void App::render_thread_tick()
|
||||
{
|
||||
runtime_.render_thread_tick(*this);
|
||||
}
|
||||
|
||||
void App::render_thread_main()
|
||||
{
|
||||
runtime_.render_thread_main(*this, {});
|
||||
|
||||
657
src/canvas.cpp
657
src/canvas.cpp
@@ -1,8 +1,8 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#include "canvas.h"
|
||||
#include "app.h"
|
||||
#include "legacy_canvas_draw_merge_services.h"
|
||||
#include "legacy_canvas_render_shell_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "legacy_canvas_stroke_erase_services.h"
|
||||
#include "legacy_gl_renderbuffer_dispatch.h"
|
||||
#include "legacy_canvas_stroke_commit_services.h"
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "legacy_canvas_object_draw_services.h"
|
||||
#include "legacy_canvas_projection_services.h"
|
||||
#include "legacy_canvas_stroke_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "app_core/document_canvas.h"
|
||||
#include "texture.h"
|
||||
@@ -314,507 +313,6 @@ std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vert
|
||||
return pp::panopainter::legacy_canvas_stroke_draw_project(*this, B, project_3d, mv);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_layer_composite(
|
||||
bool is_temporary_erase,
|
||||
bool is_temporary_paint,
|
||||
bool use_blend,
|
||||
const pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution& execution)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_composite(
|
||||
is_temporary_erase,
|
||||
is_temporary_paint,
|
||||
use_blend,
|
||||
execution);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_layer_texture(
|
||||
const pp::panopainter::LegacyCanvasDrawMergeTextureAlphaUniforms& uniforms,
|
||||
const pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution& execution)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_texture(uniforms, execution);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_layer_blend(
|
||||
const pp::panopainter::LegacyCanvasDrawMergeLayerBlendUniforms& uniforms,
|
||||
const pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution& execution)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_blend(uniforms, execution);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_final_plane_composite(
|
||||
const pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms& uniforms,
|
||||
const pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeExecution& execution)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_final_plane_composite(uniforms, execution);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const glm::mat4& ortho);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution
|
||||
make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeExecution
|
||||
make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas)
|
||||
{
|
||||
return {
|
||||
.bind_merged_texture_copy_target = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.copy_merged_framebuffer = [&] {
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height);
|
||||
},
|
||||
.enable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), true);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.bind_sampler = [&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
},
|
||||
.bind_merged_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.unbind_merged_texture = [&] {
|
||||
canvas.m_merge_tex.unbind();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_final_composite(
|
||||
Canvas& canvas,
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard,
|
||||
bool use_blend);
|
||||
|
||||
static void execute_canvas_draw_merge_plane_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination,
|
||||
bool draw_checkerboard);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution make_canvas_draw_merge_branch_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool copy_blend_destination);
|
||||
|
||||
static void execute_canvas_draw_merge_branch_body(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination)
|
||||
{
|
||||
if (use_blend)
|
||||
{
|
||||
canvas.m_merge_rtt.bindFramebuffer();
|
||||
canvas.m_merge_rtt.clear();
|
||||
}
|
||||
|
||||
execute_canvas_draw_merge_layer_composite(
|
||||
canvas.m_current_stroke && canvas.m_current_mode == kCanvasMode::Erase && canvas.m_show_tmp && canvas.m_current_layer_idx == layer_index,
|
||||
canvas.m_current_stroke && canvas.m_show_tmp && canvas.m_current_layer_idx == layer_index,
|
||||
use_blend,
|
||||
make_canvas_draw_merge_branch_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho,
|
||||
copy_blend_destination));
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution make_canvas_draw_merge_branch_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool copy_blend_destination)
|
||||
{
|
||||
return pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution {
|
||||
.execute_temporary_erase = [&] {
|
||||
execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layer,
|
||||
ortho);
|
||||
},
|
||||
.execute_temporary_paint = [&] {
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
canvas,
|
||||
layer_index,
|
||||
plane_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho));
|
||||
},
|
||||
.execute_layer_texture = [&] {
|
||||
execute_canvas_draw_merge_layer_texture(
|
||||
pp::panopainter::LegacyCanvasDrawMergeTextureAlphaUniforms {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.alpha = layer->m_opacity,
|
||||
.highlight = layer->m_hightlight,
|
||||
},
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index));
|
||||
},
|
||||
.execute_layer_blend = [&] {
|
||||
execute_canvas_draw_merge_layer_blend(
|
||||
pp::panopainter::LegacyCanvasDrawMergeLayerBlendUniforms {
|
||||
.shader = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.destination_texture_slot = 2,
|
||||
.use_destination_texture = copy_blend_destination,
|
||||
.blend_mode = layer->m_blend_mode,
|
||||
.alpha = 1.f,
|
||||
},
|
||||
.copy_destination = copy_blend_destination,
|
||||
},
|
||||
make_canvas_draw_merge_layer_blend_dispatch(
|
||||
canvas));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static auto make_canvas_draw_merge_temporary_erase_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
return pp::panopainter::make_legacy_canvas_draw_merge_temporary_erase_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_erase_shader(
|
||||
pp::panopainter::LegacyStrokeEraseUniforms {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.stroke_texture_slot = 1,
|
||||
.mask_texture_slot = 2,
|
||||
.alpha = layer->m_opacity,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(1);
|
||||
canvas.m_sampler.bind(2);
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].bindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).bindTexture();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_smask.rtt(plane_index).unbindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
});
|
||||
}
|
||||
static void execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
make_canvas_draw_merge_temporary_erase_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layer,
|
||||
ortho));
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index)
|
||||
{
|
||||
return pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution {
|
||||
.bind_sampler = [&] {
|
||||
canvas.m_cam_fov < 20.f ? canvas.m_sampler_nearest.bind(0) : canvas.m_sampler.bind(0);
|
||||
},
|
||||
.bind_layer_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.unbind_layer_texture = [&] {
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution
|
||||
make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas)
|
||||
{
|
||||
return pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution {
|
||||
.unbind_merge_framebuffer = [&] {
|
||||
canvas.m_merge_rtt.unbindFramebuffer();
|
||||
},
|
||||
.bind_samplers = [&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(2);
|
||||
},
|
||||
.bind_merge_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_rtt.bindTexture();
|
||||
},
|
||||
.bind_destination_texture = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.copy_destination_framebuffer = [&] {
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.unbind_destination_texture = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.unbind();
|
||||
},
|
||||
.unbind_merge_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_rtt.unbindTexture();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_iteration(
|
||||
Canvas& canvas,
|
||||
const std::array<bool, 6>& faces,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
if (!faces[plane_index])
|
||||
continue;
|
||||
|
||||
execute_canvas_draw_merge_plane_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layers,
|
||||
brush,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination,
|
||||
draw_checkerboard);
|
||||
}
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
canvas.m_layers_merge.rtt(plane_index).bindFramebuffer();
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_plane_setup(
|
||||
pp::panopainter::LegacyCanvasDrawMergePlaneSetupUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.use_blend = use_blend,
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
pp::panopainter::LegacyCanvasDrawMergePlaneSetupExecution {
|
||||
.clear_plane = [&] {
|
||||
canvas.m_layers_merge.rtt(plane_index).clear({ 1, 1, 1, 0 });
|
||||
},
|
||||
.disable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
},
|
||||
.enable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), true);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
});
|
||||
|
||||
for (int layer_index = 0; layer_index < layers.size(); layer_index++)
|
||||
{
|
||||
execute_canvas_draw_merge_branch_body(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layers[layer_index],
|
||||
brush,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination);
|
||||
}
|
||||
|
||||
execute_canvas_draw_merge_plane_final_composite(canvas, ortho, draw_checkerboard, use_blend);
|
||||
canvas.m_layers_merge.rtt(plane_index).unbindFramebuffer();
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_final_composite(
|
||||
Canvas& canvas,
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard,
|
||||
bool use_blend)
|
||||
{
|
||||
if (use_blend)
|
||||
{
|
||||
execute_canvas_draw_merge_final_plane_composite(
|
||||
pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.texture = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
},
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
make_canvas_draw_merge_final_plane_composite_execution(canvas));
|
||||
}
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
const auto stroke_material = canvas_stroke_material_plan(brush, false);
|
||||
glm::vec2 patt_scale = glm::vec2(brush.m_pattern_scale);
|
||||
if (brush.m_pattern_flipx) patt_scale.x *= -1.f;
|
||||
if (brush.m_pattern_flipy) patt_scale.y *= -1.f;
|
||||
|
||||
return pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = Canvas::I->m_size,
|
||||
.pattern = {
|
||||
.scale = patt_scale,
|
||||
.invert = static_cast<float>(brush.m_pattern_invert),
|
||||
.brightness = brush.m_pattern_brightness,
|
||||
.contrast = brush.m_pattern_contrast,
|
||||
.depth = brush.m_pattern_depth,
|
||||
.blend_mode = brush.m_pattern_blend_mode,
|
||||
.offset = Canvas::I->m_pattern_offset,
|
||||
},
|
||||
.mvp = ortho,
|
||||
.layer_alpha = layer->m_opacity,
|
||||
.alpha_lock = layer->m_alpha_locked,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = brush.m_blend_mode,
|
||||
.use_dual = stroke_material.composite_pass.use_dual,
|
||||
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
|
||||
.dual_alpha = stroke_material.composite_pass.dual_alpha,
|
||||
.use_pattern = stroke_material.composite_pass.use_pattern,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(1);
|
||||
canvas.m_sampler.bind(2);
|
||||
canvas.m_sampler.bind(3);
|
||||
canvas.m_sampler_stencil.bind(4);
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].bindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(3);
|
||||
if (stroke_material.composite_pass.use_dual)
|
||||
canvas.m_tmp_dual[plane_index].bindTexture();
|
||||
set_active_texture_unit(4);
|
||||
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(3);
|
||||
if (stroke_material.composite_pass.use_dual)
|
||||
canvas.m_tmp_dual[plane_index].unbindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).unbindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
});
|
||||
}
|
||||
|
||||
void Canvas::draw_merge_temporary_paint_branch(
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
@@ -822,14 +320,13 @@ void Canvas::draw_merge_temporary_paint_branch(
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
*this,
|
||||
layer_index,
|
||||
plane_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho));
|
||||
pp::panopainter::legacy_canvas_draw_merge_temporary_paint_branch(
|
||||
*this,
|
||||
layer_index,
|
||||
plane_index,
|
||||
std::move(layer),
|
||||
brush,
|
||||
ortho);
|
||||
}
|
||||
|
||||
void Canvas::draw_merge_branch_orchestration(
|
||||
@@ -841,12 +338,7 @@ void Canvas::draw_merge_branch_orchestration(
|
||||
bool use_blend,
|
||||
bool copy_blend_destination)
|
||||
{
|
||||
if (!(m_show_tmp && m_current_layer_idx == layer_index) &&
|
||||
(!layer->m_visible ||
|
||||
layer->m_opacity == .0f ||
|
||||
!layer->face(plane_index)))
|
||||
return;
|
||||
execute_canvas_draw_merge_branch_body(
|
||||
pp::panopainter::legacy_canvas_draw_merge_branch_orchestration(
|
||||
*this,
|
||||
plane_index,
|
||||
layer_index,
|
||||
@@ -861,19 +353,10 @@ void Canvas::draw_merge_final_plane_composite(
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
execute_canvas_draw_merge_final_plane_composite(
|
||||
pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.texture = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
},
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
make_canvas_draw_merge_final_plane_composite_execution(*this));
|
||||
pp::panopainter::legacy_canvas_draw_merge_final_plane_composite(
|
||||
*this,
|
||||
ortho,
|
||||
draw_checkerboard);
|
||||
}
|
||||
|
||||
void Canvas::stroke_draw()
|
||||
@@ -918,126 +401,30 @@ glm::vec3 Canvas::point_trace(glm::vec2 loc)
|
||||
}
|
||||
void Canvas::stroke_commit_timelapse()
|
||||
{
|
||||
if (m_encoder && App::I->rec_running)
|
||||
{
|
||||
auto t_now = std::chrono::high_resolution_clock::now();
|
||||
float dt = std::chrono::duration<float>(t_now - m_disrty_stroke_time).count();
|
||||
if (dt > 2.f && m_dirty_stroke && App::I->rec_mutex.try_lock())
|
||||
{
|
||||
draw_merge(true);
|
||||
App::I->rec_mutex.unlock();
|
||||
App::I->rec_cv.notify_one();
|
||||
LOG("rec frame generated");
|
||||
m_dirty_stroke = false;
|
||||
m_disrty_stroke_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
pp::panopainter::legacy_canvas_stroke_commit_timelapse(*this);
|
||||
}
|
||||
|
||||
void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SIXPLETTE(true)*/)
|
||||
{
|
||||
assert(App::I->is_render_thread());
|
||||
|
||||
apply_canvas_viewport(0, 0, m_width, m_height);
|
||||
auto ortho = glm::ortho<float>(-0.5f, 0.5f, -0.5f, 0.5f, -1.f, 1.f);
|
||||
const auto& b = m_current_stroke->m_brush;
|
||||
|
||||
const auto blend_gate = draw_merge_blend_gate_plan(
|
||||
m_width,
|
||||
m_height,
|
||||
m_layers,
|
||||
m_current_stroke ? m_current_stroke->m_brush.get() : nullptr);
|
||||
const bool use_blend = blend_gate.shader_blend;
|
||||
const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color;
|
||||
|
||||
// if not using shader blend, use gl rasterizer blend
|
||||
apply_canvas_capability(depth_test_state(), false);
|
||||
|
||||
execute_canvas_draw_merge_plane_iteration(
|
||||
*this,
|
||||
faces,
|
||||
m_layers,
|
||||
*b,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination,
|
||||
draw_checkerboard);
|
||||
pp::panopainter::legacy_canvas_draw_merge(*this, draw_checkerboard, faces);
|
||||
}
|
||||
|
||||
void Canvas::stroke_update(glm::vec3 point, float pressure) { pp::panopainter::legacy_canvas_stroke_update(*this, point, pressure); }
|
||||
void Canvas::stroke_start(glm::vec3 point, float pressure) { pp::panopainter::legacy_canvas_stroke_start(*this, point, pressure); }
|
||||
void Canvas::destroy()
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_tmp[i].destroy();
|
||||
m_tmp_dual[i].destroy();
|
||||
m_tex[i].destroy();
|
||||
m_tex2[i].destroy();
|
||||
}
|
||||
for (auto& l : m_layers)
|
||||
l->destroy();
|
||||
m_smask.destroy();
|
||||
m_mixer.destroy();
|
||||
m_layers_merge.destroy();
|
||||
m_merge_rtt.destroy();
|
||||
m_merge_tex.destroy();
|
||||
pp::panopainter::legacy_canvas_destroy(*this);
|
||||
}
|
||||
|
||||
bool Canvas::create(int width, int height)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_size = { width, height };
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
const auto stroke_format = current_canvas_stroke_internal_format();
|
||||
m_tmp[i].create(width, height, -1, stroke_format);
|
||||
m_tmp_dual[i].create(width, height, -1, stroke_format);
|
||||
m_tex[i].create(width, height, rgba8_internal_format());
|
||||
m_tex2[i].create(width, height, rgba8_internal_format());
|
||||
}
|
||||
#if defined(__GLES__)
|
||||
m_sampler_brush.create();
|
||||
#else
|
||||
m_sampler_brush.create(texture_filter_linear(), texture_wrap_clamp_to_border());
|
||||
#endif
|
||||
m_sampler.create(texture_filter_linear());
|
||||
m_sampler_nearest.create(texture_filter_nearest());
|
||||
m_sampler_brush.set_filter(texture_filter_linear_mipmap_linear(), texture_filter_linear());
|
||||
m_sampler_brush.set_border({ 1, 1, 1, 1 });
|
||||
m_sampler_stencil.create(texture_filter_linear(), texture_wrap_repeat());
|
||||
m_sampler_mix.create(texture_filter_nearest(), texture_wrap_repeat());
|
||||
m_sampler_linear.create();
|
||||
m_plane.create<1>(1, 1);
|
||||
m_plane_brush.create<1>(1, 1);
|
||||
m_brush_shape.create();
|
||||
for (auto& l : m_layers)
|
||||
l->create(width, height, "");
|
||||
m_smask.create(width, height, "mask");
|
||||
//m_smask.clear({1, 1, 1, 1});
|
||||
m_layers_merge.create(width, height, "merge");
|
||||
m_merge_rtt.create(width, height);
|
||||
m_merge_tex.create(width, height);
|
||||
m_unsaved = true;
|
||||
|
||||
timelapse_reset_encoder();
|
||||
|
||||
return true;
|
||||
return pp::panopainter::legacy_canvas_create(*this, width, height);
|
||||
}
|
||||
|
||||
void Canvas::clear_context()
|
||||
{
|
||||
LOG("Canvas CLEAR CONTEXT");
|
||||
for (auto& layer : m_layers)
|
||||
layer->destroy();
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_tmp[i].destroy();
|
||||
m_tex[i].destroy();
|
||||
m_tex2[i].destroy();
|
||||
}
|
||||
};
|
||||
pp::panopainter::legacy_canvas_clear_context(*this);
|
||||
}
|
||||
|
||||
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame)
|
||||
{
|
||||
@@ -1085,12 +472,12 @@ void Canvas::pop_camera()
|
||||
|
||||
CameraData Canvas::get_camera()
|
||||
{
|
||||
return pp::panopainter::legacy_canvas_get_camera(*this);
|
||||
return pp::panopainter::legacy_canvas_render_shell_get_camera(*this);
|
||||
}
|
||||
|
||||
void Canvas::set_camera(const CameraData& c)
|
||||
{
|
||||
pp::panopainter::legacy_canvas_set_camera(*this, c);
|
||||
pp::panopainter::legacy_canvas_render_shell_set_camera(*this, c);
|
||||
}
|
||||
|
||||
void Canvas::timelapse_reset_encoder() noexcept
|
||||
|
||||
239
src/legacy_app_runtime_shell_services.cpp
Normal file
239
src/legacy_app_runtime_shell_services.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "app_core/app_frame.h"
|
||||
#include "app_core/app_shutdown.h"
|
||||
#include "app_core/app_status.h"
|
||||
#include "legacy_recording_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void apply_app_viewport(pp::renderer::gl::OpenGlViewportRect viewport)
|
||||
{
|
||||
const auto status = pp::renderer::gl::apply_opengl_viewport(
|
||||
viewport,
|
||||
pp::renderer::gl::OpenGlViewportDispatch {
|
||||
.viewport = pp::legacy::ui_gl::set_opengl_viewport,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("OpenGL viewport failed: %s", status.message);
|
||||
}
|
||||
|
||||
void apply_app_scissor_test(bool enabled)
|
||||
{
|
||||
const auto status = pp::renderer::gl::apply_opengl_scissor_test(
|
||||
enabled,
|
||||
pp::renderer::gl::OpenGlScissorTestDispatch {
|
||||
.enable = pp::legacy::ui_gl::enable_opengl_state,
|
||||
.disable = pp::legacy::ui_gl::disable_opengl_state,
|
||||
});
|
||||
if (!status.ok())
|
||||
LOG("OpenGL scissor test failed: %s", status.message);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace pp::panopainter {
|
||||
bool process_legacy_recording_worker_iteration(App& app);
|
||||
void update_legacy_recording_frame_label(App& app);
|
||||
bool update_legacy_app_ui_observer(App& app, Node* n);
|
||||
void watch_legacy_app_ui_children(App& app, const std::function<bool(Node*)>& observer, bool skip_first_main_child);
|
||||
void update_legacy_canvas_toolbar(App& app);
|
||||
} // namespace pp::panopainter
|
||||
|
||||
void App::draw(float dt)
|
||||
{
|
||||
const auto draw_plan = pp::app::plan_app_frame_draw(
|
||||
canvas != nullptr,
|
||||
canvas && canvas->m_canvas,
|
||||
vr_active,
|
||||
ui_visible,
|
||||
vr_only);
|
||||
|
||||
// update offscreen stuff
|
||||
if (draw_plan.draw_canvas_stroke)
|
||||
canvas->m_canvas->stroke_draw();
|
||||
|
||||
auto observer = std::bind(&App::update_ui_observer, this, std::placeholders::_1);
|
||||
|
||||
if (draw_plan.draw_vr_ui)
|
||||
{
|
||||
uirtt.bindFramebuffer();
|
||||
uirtt.clear();
|
||||
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
|
||||
.width = static_cast<std::int32_t>(uirtt.getWidth()),
|
||||
.height = static_cast<std::int32_t>(uirtt.getHeight()),
|
||||
});
|
||||
apply_app_scissor_test(true);
|
||||
pp::panopainter::watch_legacy_app_ui_children(*this, observer, true);
|
||||
apply_app_scissor_test(false);
|
||||
uirtt.unbindFramebuffer();
|
||||
}
|
||||
|
||||
if (draw_plan.draw_main_ui)
|
||||
{
|
||||
bind_main_render_target();
|
||||
apply_app_viewport(pp::renderer::gl::OpenGlViewportRect {
|
||||
.x = static_cast<std::int32_t>(off_x),
|
||||
.y = static_cast<std::int32_t>(off_y),
|
||||
.width = static_cast<std::int32_t>(width),
|
||||
.height = static_cast<std::int32_t>(height),
|
||||
});
|
||||
apply_app_scissor_test(true);
|
||||
pp::panopainter::watch_legacy_app_ui_children(*this, observer, false);
|
||||
apply_app_scissor_test(false);
|
||||
}
|
||||
|
||||
if (draw_plan.reset_redraw)
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
void App::update(float dt)
|
||||
{
|
||||
const auto update_plan = pp::app::plan_app_frame_update(redraw, animate);
|
||||
if (!update_plan.update_frame)
|
||||
return;
|
||||
|
||||
if (auto* main = layout[main_id]; update_plan.update_layouts && main)
|
||||
main->update(width, height, zoom);
|
||||
|
||||
if (auto* main = layout_designer[main_id]; update_plan.update_layouts && main)
|
||||
main->update(width, height, zoom);
|
||||
|
||||
if (!update_plan.refresh_canvas_toolbar)
|
||||
return;
|
||||
|
||||
pp::panopainter::update_legacy_canvas_toolbar(*this);
|
||||
}
|
||||
|
||||
void App::terminate()
|
||||
{
|
||||
LOG("App::terminate");
|
||||
const auto shutdown_plan = pp::app::plan_app_shutdown();
|
||||
|
||||
if (shutdown_plan.save_ui_state)
|
||||
ui_save();
|
||||
|
||||
if (shutdown_plan.terminate_stroke_preview_renderer)
|
||||
NodeStrokePreview::terminate_renderer();
|
||||
if (shutdown_plan.stop_recording)
|
||||
rec_stop();
|
||||
|
||||
if (shutdown_plan.invalidate_textures)
|
||||
TextureManager::invalidate();
|
||||
if (shutdown_plan.invalidate_shaders)
|
||||
ShaderManager::invalidate();
|
||||
if (shutdown_plan.unload_layouts) {
|
||||
layout.unload();
|
||||
layout_designer.unload();
|
||||
}
|
||||
if (shutdown_plan.destroy_ui_render_target)
|
||||
uirtt.destroy();
|
||||
if (shutdown_plan.destroy_face_plane)
|
||||
m_face_plane.destroy();
|
||||
if (shutdown_plan.release_panel_nodes) {
|
||||
layers.reset();
|
||||
color.reset();
|
||||
stroke.reset();
|
||||
grid.reset();
|
||||
presets.reset();
|
||||
floating_presets.reset();
|
||||
floating_color.reset();
|
||||
floating_layers.reset();
|
||||
floating_picker.reset();
|
||||
}
|
||||
if (shutdown_plan.clear_quick_mode_state)
|
||||
quick_mode_state.clear();
|
||||
}
|
||||
|
||||
void App::update_memory_usage(size_t bytes)
|
||||
{
|
||||
if (auto txt = layout[main_id]->find<NodeText>("txt-memory"))
|
||||
{
|
||||
const auto label = pp::app::make_history_memory_label(bytes);
|
||||
txt->set_text(label.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void App::update_rec_frames()
|
||||
{
|
||||
pp::panopainter::update_legacy_recording_frame_label(*this);
|
||||
}
|
||||
|
||||
int App::res_from_index(int i)
|
||||
{
|
||||
const auto resolution = pp::app::display_resolution_from_index(i);
|
||||
return resolution ? resolution.value() : pp::app::document_resolution_values.front();
|
||||
}
|
||||
|
||||
int App::res_to_index(int res)
|
||||
{
|
||||
const auto index = pp::app::document_resolution_to_index(res);
|
||||
return index ? static_cast<int>(index.value()) : static_cast<int>(pp::app::document_resolution_values.size());
|
||||
}
|
||||
|
||||
std::string App::res_to_string(int res)
|
||||
{
|
||||
const auto label = pp::app::document_resolution_label(res);
|
||||
return label ? std::string(label.value()) : std::string("unknown");
|
||||
}
|
||||
|
||||
void App::rec_clear()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_clear(
|
||||
rec_running,
|
||||
platform_deletes_recorded_files_on_clear()
|
||||
);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_clear_plan(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording clear action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_start()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_start(rec_running);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_start_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording start action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_stop()
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_stop(rec_running);
|
||||
const auto status = pp::panopainter::execute_legacy_recording_stop_action(*this, plan);
|
||||
if (!status.ok())
|
||||
LOG("Recording stop action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_export(std::string path)
|
||||
{
|
||||
const auto plan = pp::app::plan_recording_export(static_cast<std::size_t>(rec_count));
|
||||
/*
|
||||
#if defined(__IOS__) || defined(__OSX__)
|
||||
export_mp4(rec_path, width, height, rec_count, ^(float) {
|
||||
pb->increment();
|
||||
});
|
||||
#endif
|
||||
*/
|
||||
const auto status = pp::panopainter::execute_legacy_recording_export_plan(*this, plan, path);
|
||||
if (!status.ok())
|
||||
LOG("Recording export action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void App::rec_loop()
|
||||
{
|
||||
BT_SetTerminate();
|
||||
rec_running = true;
|
||||
while (rec_running)
|
||||
{
|
||||
if (!pp::panopainter::process_legacy_recording_worker_iteration(*this))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void App::render_thread_tick()
|
||||
{
|
||||
runtime_.render_thread_tick(*this);
|
||||
}
|
||||
727
src/legacy_canvas_render_shell_services.cpp
Normal file
727
src/legacy_canvas_render_shell_services.cpp
Normal file
@@ -0,0 +1,727 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "legacy_canvas_render_shell_services.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "legacy_canvas_draw_merge_services.h"
|
||||
#include "legacy_canvas_stroke_commit_services.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_canvas_stroke_erase_services.h"
|
||||
#include "legacy_canvas_stroke_execution_services.h"
|
||||
#include "legacy_canvas_stroke_runtime_services.h"
|
||||
#include "legacy_canvas_stroke_shader_services.h"
|
||||
#include "legacy_canvas_projection_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace pp::panopainter;
|
||||
|
||||
GLint current_canvas_stroke_internal_format()
|
||||
{
|
||||
const auto renderer_features = ShaderManager::render_device_features();
|
||||
if (renderer_features.float32_linear_filtering)
|
||||
return static_cast<GLint>(pp::renderer::gl::rgba32f_internal_format());
|
||||
if (renderer_features.float16_render_targets)
|
||||
return static_cast<GLint>(pp::renderer::gl::rgba16f_internal_format());
|
||||
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
|
||||
}
|
||||
|
||||
GLint rgba8_internal_format()
|
||||
{
|
||||
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
|
||||
}
|
||||
|
||||
GLenum depth_test_state()
|
||||
{
|
||||
return static_cast<GLenum>(pp::renderer::gl::depth_test_state());
|
||||
}
|
||||
|
||||
GLenum blend_state()
|
||||
{
|
||||
return static_cast<GLenum>(pp::renderer::gl::blend_state());
|
||||
}
|
||||
|
||||
void set_active_texture_unit(std::uint32_t unit_index)
|
||||
{
|
||||
pp::legacy::ui_gl::activate_texture_unit(unit_index, "Canvas");
|
||||
}
|
||||
|
||||
void unbind_texture_2d()
|
||||
{
|
||||
pp::legacy::ui_gl::unbind_texture_2d("Canvas");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void apply_canvas_capability(std::uint32_t state, bool enabled)
|
||||
{
|
||||
pp::legacy::ui_gl::set_capability(state, enabled, "Canvas");
|
||||
}
|
||||
|
||||
pp::paint_renderer::CanvasBlendGatePlan draw_merge_blend_gate_plan(
|
||||
int width,
|
||||
int height,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush* brush) noexcept
|
||||
{
|
||||
std::vector<int> layer_blend_modes;
|
||||
layer_blend_modes.reserve(layers.size());
|
||||
for (const auto& layer : layers) {
|
||||
if (!layer) {
|
||||
continue;
|
||||
}
|
||||
layer_blend_modes.push_back(layer->m_blend_mode);
|
||||
}
|
||||
|
||||
const auto plan = pp::paint_renderer::plan_canvas_blend_gate(
|
||||
ShaderManager::render_device_features(),
|
||||
pp::paint_renderer::CanvasBlendGateRequest {
|
||||
.extent = pp::renderer::Extent2D {
|
||||
.width = static_cast<std::uint32_t>(std::max(width, 0)),
|
||||
.height = static_cast<std::uint32_t>(std::max(height, 0)),
|
||||
},
|
||||
.layer_blend_modes = layer_blend_modes,
|
||||
.has_stroke_blend_mode = brush != nullptr,
|
||||
.stroke_blend_mode = brush ? brush->m_blend_mode : 0,
|
||||
});
|
||||
if (plan) {
|
||||
return plan.value();
|
||||
}
|
||||
|
||||
pp::paint_renderer::CanvasBlendGatePlan fallback;
|
||||
fallback.shader_blend = true;
|
||||
fallback.complex_blend = true;
|
||||
fallback.compatibility_fallback = true;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeExecution
|
||||
make_canvas_draw_merge_final_plane_composite_execution(Canvas& canvas)
|
||||
{
|
||||
return {
|
||||
.bind_merged_texture_copy_target = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.copy_merged_framebuffer = [&] {
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height);
|
||||
},
|
||||
.enable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), true);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.bind_sampler = [&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
},
|
||||
.bind_merged_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.unbind_merged_texture = [&] {
|
||||
canvas.m_merge_tex.unbind();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const glm::mat4& ortho);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index);
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution
|
||||
make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas);
|
||||
|
||||
static void execute_canvas_draw_merge_branch_body(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination)
|
||||
{
|
||||
if (use_blend)
|
||||
{
|
||||
canvas.m_merge_rtt.bindFramebuffer();
|
||||
canvas.m_merge_rtt.clear();
|
||||
}
|
||||
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_composite(
|
||||
canvas.m_current_stroke && canvas.m_current_mode == kCanvasMode::Erase && canvas.m_show_tmp && canvas.m_current_layer_idx == layer_index,
|
||||
canvas.m_current_stroke && canvas.m_show_tmp && canvas.m_current_layer_idx == layer_index,
|
||||
use_blend,
|
||||
pp::panopainter::LegacyCanvasDrawMergeLayerCompositeExecution {
|
||||
.execute_temporary_erase = [&] {
|
||||
execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layer,
|
||||
ortho);
|
||||
},
|
||||
.execute_temporary_paint = [&] {
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
canvas,
|
||||
layer_index,
|
||||
plane_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho));
|
||||
},
|
||||
.execute_layer_texture = [&] {
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_texture(
|
||||
pp::panopainter::LegacyCanvasDrawMergeTextureAlphaUniforms {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.alpha = layer->m_opacity,
|
||||
.highlight = layer->m_hightlight,
|
||||
},
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index));
|
||||
},
|
||||
.execute_layer_blend = [&] {
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_layer_blend(
|
||||
pp::panopainter::LegacyCanvasDrawMergeLayerBlendUniforms {
|
||||
.shader = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.destination_texture_slot = 2,
|
||||
.use_destination_texture = copy_blend_destination,
|
||||
.blend_mode = layer->m_blend_mode,
|
||||
.alpha = 1.f,
|
||||
},
|
||||
.copy_destination = copy_blend_destination,
|
||||
},
|
||||
make_canvas_draw_merge_layer_blend_dispatch(
|
||||
canvas));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_final_composite(
|
||||
Canvas& canvas,
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard,
|
||||
bool use_blend)
|
||||
{
|
||||
if (use_blend)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_final_plane_composite(
|
||||
pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.texture = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
},
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
make_canvas_draw_merge_final_plane_composite_execution(canvas));
|
||||
}
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
canvas.m_layers_merge.rtt(plane_index).bindFramebuffer();
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_plane_setup(
|
||||
pp::panopainter::LegacyCanvasDrawMergePlaneSetupUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.use_blend = use_blend,
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
pp::panopainter::LegacyCanvasDrawMergePlaneSetupExecution {
|
||||
.clear_plane = [&] {
|
||||
canvas.m_layers_merge.rtt(plane_index).clear({ 1, 1, 1, 0 });
|
||||
},
|
||||
.disable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
},
|
||||
.enable_blend = [&] {
|
||||
apply_canvas_capability(blend_state(), true);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
});
|
||||
|
||||
for (int layer_index = 0; layer_index < layers.size(); layer_index++)
|
||||
{
|
||||
execute_canvas_draw_merge_branch_body(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layers[layer_index],
|
||||
brush,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination);
|
||||
}
|
||||
|
||||
execute_canvas_draw_merge_plane_final_composite(canvas, ortho, draw_checkerboard, use_blend);
|
||||
canvas.m_layers_merge.rtt(plane_index).unbindFramebuffer();
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_plane_iteration(
|
||||
Canvas& canvas,
|
||||
const std::array<bool, 6>& faces,
|
||||
const std::vector<std::shared_ptr<Layer>>& layers,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
for (int plane_index = 0; plane_index < 6; plane_index++)
|
||||
{
|
||||
if (!faces[plane_index])
|
||||
continue;
|
||||
|
||||
execute_canvas_draw_merge_plane_dispatch(
|
||||
canvas,
|
||||
plane_index,
|
||||
layers,
|
||||
brush,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination,
|
||||
draw_checkerboard);
|
||||
}
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_temporary_erase_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
pp::panopainter::make_legacy_canvas_draw_merge_temporary_erase_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_erase_shader(
|
||||
pp::panopainter::LegacyStrokeEraseUniforms {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
.stroke_texture_slot = 1,
|
||||
.mask_texture_slot = 2,
|
||||
.alpha = layer->m_opacity,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(1);
|
||||
canvas.m_sampler.bind(2);
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].bindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).bindTexture();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_smask.rtt(plane_index).unbindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
}));
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
const auto stroke_material = pp::panopainter::plan_legacy_canvas_stroke_material(
|
||||
pp::paint_renderer::CanvasStrokeMaterialRequest {
|
||||
.destination_feedback_needed = false,
|
||||
.pattern_enabled = brush.m_pattern_enabled,
|
||||
.pattern_eachsample = brush.m_pattern_eachsample,
|
||||
.wet_blend = brush.m_tip_wet > 0.F,
|
||||
.mix_blend = brush.m_tip_mix > 0.F,
|
||||
.noise_enabled = brush.m_tip_noise > 0.F,
|
||||
.dual_brush_enabled = brush.m_dual_enabled,
|
||||
.dual_blend_mode = brush.m_dual_blend_mode,
|
||||
.pattern_blend_mode = brush.m_pattern_blend_mode,
|
||||
.dual_alpha = brush.m_dual_opacity,
|
||||
});
|
||||
glm::vec2 patt_scale = glm::vec2(brush.m_pattern_scale);
|
||||
if (brush.m_pattern_flipx) patt_scale.x *= -1.f;
|
||||
if (brush.m_pattern_flipy) patt_scale.y *= -1.f;
|
||||
|
||||
return pp::panopainter::make_legacy_canvas_draw_merge_temporary_paint_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = Canvas::I->m_size,
|
||||
.pattern = {
|
||||
.scale = patt_scale,
|
||||
.invert = static_cast<float>(brush.m_pattern_invert),
|
||||
.brightness = brush.m_pattern_brightness,
|
||||
.contrast = brush.m_pattern_contrast,
|
||||
.depth = brush.m_pattern_depth,
|
||||
.blend_mode = brush.m_pattern_blend_mode,
|
||||
.offset = Canvas::I->m_pattern_offset,
|
||||
},
|
||||
.mvp = ortho,
|
||||
.layer_alpha = layer->m_opacity,
|
||||
.alpha_lock = layer->m_alpha_locked,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = brush.m_blend_mode,
|
||||
.use_dual = stroke_material.composite_pass.use_dual,
|
||||
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
|
||||
.dual_alpha = stroke_material.composite_pass.dual_alpha,
|
||||
.use_pattern = stroke_material.composite_pass.use_pattern,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(1);
|
||||
canvas.m_sampler.bind(2);
|
||||
canvas.m_sampler.bind(3);
|
||||
canvas.m_sampler_stencil.bind(4);
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].bindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).bindTexture();
|
||||
set_active_texture_unit(3);
|
||||
if (stroke_material.composite_pass.use_dual)
|
||||
canvas.m_tmp_dual[plane_index].bindTexture();
|
||||
set_active_texture_unit(4);
|
||||
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(3);
|
||||
if (stroke_material.composite_pass.use_dual)
|
||||
canvas.m_tmp_dual[plane_index].unbindTexture();
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).unbindTexture();
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].unbindTexture();
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
});
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerTextureExecution
|
||||
make_canvas_draw_merge_layer_texture_dispatch(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index)
|
||||
{
|
||||
return {
|
||||
.bind_sampler = [&] {
|
||||
canvas.m_cam_fov < 20.f ? canvas.m_sampler_nearest.bind(0) : canvas.m_sampler.bind(0);
|
||||
},
|
||||
.bind_layer_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).bindTexture();
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.unbind_layer_texture = [&] {
|
||||
canvas.m_layers[layer_index]->rtt(plane_index).unbindTexture();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeLayerBlendExecution
|
||||
make_canvas_draw_merge_layer_blend_dispatch(Canvas& canvas)
|
||||
{
|
||||
return {
|
||||
.unbind_merge_framebuffer = [&] {
|
||||
canvas.m_merge_rtt.unbindFramebuffer();
|
||||
},
|
||||
.bind_samplers = [&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(2);
|
||||
},
|
||||
.bind_merge_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_rtt.bindTexture();
|
||||
},
|
||||
.bind_destination_texture = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.bind();
|
||||
},
|
||||
.copy_destination_framebuffer = [&] {
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height);
|
||||
},
|
||||
.draw = [&] {
|
||||
canvas.m_plane.draw_fill();
|
||||
},
|
||||
.unbind_destination_texture = [&] {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_merge_tex.unbind();
|
||||
},
|
||||
.unbind_merge_texture = [&] {
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_merge_rtt.unbindTexture();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void legacy_canvas_draw_merge_temporary_paint_branch(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
std::shared_ptr<Layer> layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_temporary_composite(
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
canvas,
|
||||
layer_index,
|
||||
plane_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho));
|
||||
}
|
||||
|
||||
void legacy_canvas_draw_merge_branch_orchestration(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination)
|
||||
{
|
||||
if (!(canvas.m_show_tmp && canvas.m_current_layer_idx == layer_index) &&
|
||||
(!layer->m_visible ||
|
||||
layer->m_opacity == .0f ||
|
||||
!layer->face(plane_index)))
|
||||
return;
|
||||
execute_canvas_draw_merge_branch_body(
|
||||
canvas,
|
||||
plane_index,
|
||||
layer_index,
|
||||
layer,
|
||||
brush,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination);
|
||||
}
|
||||
|
||||
void legacy_canvas_draw_merge_final_plane_composite(
|
||||
Canvas& canvas,
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard)
|
||||
{
|
||||
pp::panopainter::execute_legacy_canvas_draw_merge_final_plane_composite(
|
||||
pp::panopainter::LegacyCanvasDrawMergeFinalPlaneCompositeUniforms {
|
||||
.checkerboard = {
|
||||
.mvp = ortho,
|
||||
.colorize = false,
|
||||
},
|
||||
.texture = {
|
||||
.mvp = ortho,
|
||||
.texture_slot = 0,
|
||||
},
|
||||
.draw_checkerboard = draw_checkerboard,
|
||||
},
|
||||
make_canvas_draw_merge_final_plane_composite_execution(canvas));
|
||||
}
|
||||
|
||||
void legacy_canvas_stroke_commit_timelapse(Canvas& canvas)
|
||||
{
|
||||
if (canvas.m_encoder && App::I->rec_running)
|
||||
{
|
||||
auto t_now = std::chrono::high_resolution_clock::now();
|
||||
float dt = std::chrono::duration<float>(t_now - canvas.m_disrty_stroke_time).count();
|
||||
if (dt > 2.f && canvas.m_dirty_stroke && App::I->rec_mutex.try_lock())
|
||||
{
|
||||
legacy_canvas_draw_merge(canvas, true);
|
||||
App::I->rec_mutex.unlock();
|
||||
App::I->rec_cv.notify_one();
|
||||
LOG("rec frame generated");
|
||||
canvas.m_dirty_stroke = false;
|
||||
canvas.m_disrty_stroke_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void legacy_canvas_draw_merge(Canvas& canvas, bool draw_checkerboard, std::array<bool, 6> faces)
|
||||
{
|
||||
assert(App::I->is_render_thread());
|
||||
|
||||
apply_canvas_viewport(0, 0, canvas.m_width, canvas.m_height);
|
||||
auto ortho = glm::ortho<float>(-0.5f, 0.5f, -0.5f, 0.5f, -1.f, 1.f);
|
||||
const auto& b = canvas.m_current_stroke->m_brush;
|
||||
|
||||
const auto blend_gate = draw_merge_blend_gate_plan(
|
||||
canvas.m_width,
|
||||
canvas.m_height,
|
||||
canvas.m_layers,
|
||||
canvas.m_current_stroke ? canvas.m_current_stroke->m_brush.get() : nullptr);
|
||||
const bool use_blend = blend_gate.shader_blend;
|
||||
const bool copy_blend_destination = use_blend && !blend_gate.reads_destination_color;
|
||||
|
||||
apply_canvas_capability(depth_test_state(), false);
|
||||
|
||||
execute_canvas_draw_merge_plane_iteration(
|
||||
canvas,
|
||||
faces,
|
||||
canvas.m_layers,
|
||||
*b,
|
||||
ortho,
|
||||
use_blend,
|
||||
copy_blend_destination,
|
||||
draw_checkerboard);
|
||||
}
|
||||
|
||||
void legacy_canvas_destroy(Canvas& canvas)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
canvas.m_tmp[i].destroy();
|
||||
canvas.m_tmp_dual[i].destroy();
|
||||
canvas.m_tex[i].destroy();
|
||||
canvas.m_tex2[i].destroy();
|
||||
}
|
||||
for (auto& l : canvas.m_layers)
|
||||
l->destroy();
|
||||
canvas.m_smask.destroy();
|
||||
canvas.m_mixer.destroy();
|
||||
canvas.m_layers_merge.destroy();
|
||||
canvas.m_merge_rtt.destroy();
|
||||
canvas.m_merge_tex.destroy();
|
||||
}
|
||||
|
||||
bool legacy_canvas_create(Canvas& canvas, int width, int height)
|
||||
{
|
||||
canvas.m_width = width;
|
||||
canvas.m_height = height;
|
||||
canvas.m_size = { width, height };
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
const auto stroke_format = current_canvas_stroke_internal_format();
|
||||
canvas.m_tmp[i].create(width, height, -1, stroke_format);
|
||||
canvas.m_tmp_dual[i].create(width, height, -1, stroke_format);
|
||||
canvas.m_tex[i].create(width, height, rgba8_internal_format());
|
||||
canvas.m_tex2[i].create(width, height, rgba8_internal_format());
|
||||
}
|
||||
#if defined(__GLES__)
|
||||
canvas.m_sampler_brush.create();
|
||||
#else
|
||||
canvas.m_sampler_brush.create(pp::renderer::gl::linear_texture_filter(), pp::renderer::gl::clamp_to_border_texture_wrap());
|
||||
#endif
|
||||
canvas.m_sampler.create(pp::renderer::gl::linear_texture_filter());
|
||||
canvas.m_sampler_nearest.create(pp::renderer::gl::nearest_texture_filter());
|
||||
canvas.m_sampler_brush.set_filter(pp::renderer::gl::linear_mipmap_linear_texture_filter(), pp::renderer::gl::linear_texture_filter());
|
||||
canvas.m_sampler_brush.set_border({ 1, 1, 1, 1 });
|
||||
canvas.m_sampler_stencil.create(pp::renderer::gl::linear_texture_filter(), pp::renderer::gl::repeat_texture_wrap());
|
||||
canvas.m_sampler_mix.create(pp::renderer::gl::nearest_texture_filter(), pp::renderer::gl::repeat_texture_wrap());
|
||||
canvas.m_sampler_linear.create();
|
||||
canvas.m_plane.create<1>(1, 1);
|
||||
canvas.m_plane_brush.create<1>(1, 1);
|
||||
canvas.m_brush_shape.create();
|
||||
for (auto& l : canvas.m_layers)
|
||||
l->create(width, height, "");
|
||||
canvas.m_smask.create(width, height, "mask");
|
||||
canvas.m_layers_merge.create(width, height, "merge");
|
||||
canvas.m_merge_rtt.create(width, height);
|
||||
canvas.m_merge_tex.create(width, height);
|
||||
canvas.m_unsaved = true;
|
||||
|
||||
canvas.timelapse_reset_encoder();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void legacy_canvas_clear_context(Canvas& canvas)
|
||||
{
|
||||
LOG("Canvas CLEAR CONTEXT");
|
||||
for (auto& layer : canvas.m_layers)
|
||||
layer->destroy();
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
canvas.m_tmp[i].destroy();
|
||||
canvas.m_tex[i].destroy();
|
||||
canvas.m_tex2[i].destroy();
|
||||
}
|
||||
}
|
||||
|
||||
CameraData legacy_canvas_render_shell_get_camera(const Canvas& canvas)
|
||||
{
|
||||
return legacy_canvas_get_camera(canvas);
|
||||
}
|
||||
|
||||
void legacy_canvas_render_shell_set_camera(Canvas& canvas, const CameraData& camera)
|
||||
{
|
||||
legacy_canvas_set_camera(canvas, camera);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
40
src/legacy_canvas_render_shell_services.h
Normal file
40
src/legacy_canvas_render_shell_services.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "canvas.h"
|
||||
|
||||
class Canvas;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
void legacy_canvas_draw_merge_temporary_paint_branch(
|
||||
Canvas& canvas,
|
||||
int layer_index,
|
||||
int plane_index,
|
||||
std::shared_ptr<Layer> layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho);
|
||||
void legacy_canvas_draw_merge_branch_orchestration(
|
||||
Canvas& canvas,
|
||||
int plane_index,
|
||||
int layer_index,
|
||||
const std::shared_ptr<Layer>& layer,
|
||||
const Brush& brush,
|
||||
const glm::mat4& ortho,
|
||||
bool use_blend,
|
||||
bool copy_blend_destination);
|
||||
void legacy_canvas_draw_merge_final_plane_composite(
|
||||
Canvas& canvas,
|
||||
const glm::mat4& ortho,
|
||||
bool draw_checkerboard);
|
||||
void legacy_canvas_stroke_commit_timelapse(Canvas& canvas);
|
||||
void legacy_canvas_draw_merge(
|
||||
Canvas& canvas,
|
||||
bool draw_checkerboard,
|
||||
std::array<bool, 6> faces = SIXPLETTE(true));
|
||||
void legacy_canvas_destroy(Canvas& canvas);
|
||||
bool legacy_canvas_create(Canvas& canvas, int width, int height);
|
||||
void legacy_canvas_clear_context(Canvas& canvas);
|
||||
CameraData legacy_canvas_render_shell_get_camera(const Canvas& canvas);
|
||||
void legacy_canvas_render_shell_set_camera(Canvas& canvas, const CameraData& camera);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
377
src/legacy_ui_node_tree_services.cpp
Normal file
377
src/legacy_ui_node_tree_services.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "layout.h"
|
||||
#include "node.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using NodeChildren = std::vector<std::shared_ptr<Node>>;
|
||||
using NodeChildIterator = NodeChildren::iterator;
|
||||
|
||||
NodeChildIterator find_child_iterator(Node& parent, Node* child)
|
||||
{
|
||||
return std::find_if(parent.m_children.begin(), parent.m_children.end(),
|
||||
[child](const std::shared_ptr<Node>& candidate) { return candidate.get() == child; });
|
||||
}
|
||||
|
||||
template <typename AttachChildrenFn>
|
||||
void attach_child(Node& parent, Node* child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||
{
|
||||
if (child->m_parent)
|
||||
child->m_parent->remove_child(child);
|
||||
|
||||
attach_children(child);
|
||||
child->m_parent = &parent;
|
||||
child->set_manager(parent.m_manager);
|
||||
child->m_destroyed = false;
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||
child->added(&parent);
|
||||
parent.on_child_added(child);
|
||||
}
|
||||
|
||||
template <typename AttachChildrenFn>
|
||||
void attach_child(Node& parent, const std::shared_ptr<Node>& child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||
{
|
||||
if (child->m_parent)
|
||||
child->m_parent->remove_child(child.get());
|
||||
|
||||
attach_children(child);
|
||||
child->m_parent = &parent;
|
||||
child->set_manager(parent.m_manager);
|
||||
child->m_destroyed = false;
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||
child->added(&parent);
|
||||
parent.on_child_added(child.get());
|
||||
}
|
||||
|
||||
void detach_child(Node& parent, NodeChildIterator child_it)
|
||||
{
|
||||
Node* child = child_it->get();
|
||||
child->removed(&parent);
|
||||
child->m_parent = nullptr;
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
parent.on_child_removed(child);
|
||||
parent.m_children.erase(child_it);
|
||||
if (parent.child_mouse_focus.get() == child)
|
||||
parent.child_mouse_focus = nullptr;
|
||||
}
|
||||
|
||||
void detach_all_children(Node& parent)
|
||||
{
|
||||
for (auto& child : parent.m_children)
|
||||
{
|
||||
child->removed(&parent);
|
||||
child->m_parent = nullptr;
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
parent.on_child_removed(child.get());
|
||||
}
|
||||
parent.m_children.clear();
|
||||
parent.child_mouse_focus = nullptr;
|
||||
}
|
||||
|
||||
void reorder_child(Node& parent, Node* child, int index)
|
||||
{
|
||||
int count = YGNodeGetChildCount(parent.y_node);
|
||||
index = glm::clamp<int>(index, 0, count - 1);
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, index);
|
||||
|
||||
auto child_it = find_child_iterator(parent, child);
|
||||
auto moved_child = *child_it;
|
||||
parent.m_children.erase(child_it);
|
||||
parent.m_children.insert(parent.m_children.begin() + index, moved_child);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::destroy()
|
||||
{
|
||||
//m_destroyed = true;
|
||||
//mouse_release();
|
||||
//key_release();
|
||||
//for (auto& c : m_children)
|
||||
// c->destroy();
|
||||
//for (auto p = m_parent; p; p = p->m_parent)
|
||||
// if (p->child_mouse_focus.get() == this)
|
||||
// p->child_mouse_focus = nullptr;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
mouse_release();
|
||||
key_release();
|
||||
auto cp = m_children;
|
||||
for (auto& c : cp)
|
||||
c->destroy();
|
||||
for (auto p = m_parent; p; p = p->m_parent)
|
||||
if (p->child_mouse_focus.get() == this)
|
||||
p->child_mouse_focus = nullptr;
|
||||
remove_all_children();
|
||||
remove_from_parent();
|
||||
});
|
||||
}
|
||||
|
||||
Node* Node::root()
|
||||
{
|
||||
Node* ret = this;
|
||||
while (ret->m_parent)
|
||||
ret = ret->m_parent;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Node::set_manager(LayoutManager* manager)
|
||||
{
|
||||
m_manager = manager;
|
||||
for (auto& c : m_children)
|
||||
c->set_manager(manager);
|
||||
}
|
||||
|
||||
bool Node::added_to_root()
|
||||
{
|
||||
auto r = root();
|
||||
return r == m_manager->get(App::I->main_id);
|
||||
}
|
||||
|
||||
void Node::handle_on_screen(bool old_visibility, bool new_visibility)
|
||||
{
|
||||
if (new_visibility == false)
|
||||
{
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->m_on_screen)
|
||||
{
|
||||
c->handle_on_screen(true, false);
|
||||
c->m_on_screen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Node* Node::init_template(const char* id)
|
||||
{
|
||||
Node* t = nullptr;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
auto hid = const_hash(id);
|
||||
Node* top = m_manager->get(hid);
|
||||
t = static_cast<Node*>(top->m_children[0].get());
|
||||
t->set_manager(m_manager);
|
||||
for (auto& c : t->m_children)
|
||||
{
|
||||
auto node = c->clone();
|
||||
add_child(node);
|
||||
}
|
||||
YGNodeCopyStyle(y_node, t->y_node);
|
||||
t->clone_copy(this);
|
||||
});
|
||||
return t;
|
||||
}
|
||||
|
||||
bool Node::init_template_file(const std::string& path, const std::string& id)
|
||||
{
|
||||
bool ret = false;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
LayoutManager m;
|
||||
if (m.load(path.c_str()))
|
||||
{
|
||||
auto t = m.get_ref(id.c_str())->m_children[0];
|
||||
t->set_manager(m_manager);
|
||||
for (auto& c : t->m_children)
|
||||
add_child(c->clone());
|
||||
YGNodeCopyStyle(y_node, t->y_node);
|
||||
t->clone_copy(this);
|
||||
ret = true;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Node::load_template(const std::string& filename, const std::string& name) const
|
||||
{
|
||||
LayoutManager m;
|
||||
std::shared_ptr<Node> ret;
|
||||
if (m.load(filename.c_str()))
|
||||
ret = m.get_ref(name.c_str())->m_children[0]->clone();
|
||||
m.unload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Node::parse_template(const std::string& xml_string, const std::string& name) const
|
||||
{
|
||||
LayoutManager m;
|
||||
std::shared_ptr<Node> ret;
|
||||
if (m.parse(xml_string))
|
||||
ret = m.get_ref(name.c_str())->m_children[0]->clone();
|
||||
m.unload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||
[this](Node* child)
|
||||
{
|
||||
m_children.emplace_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, index,
|
||||
[this](Node* child)
|
||||
{
|
||||
// Preserve the current backing-vector behavior for raw-pointer inserts.
|
||||
m_children.emplace_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(std::shared_ptr<Node> n)
|
||||
{
|
||||
App::I->ui_task([this, n]
|
||||
{
|
||||
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||
[this](const std::shared_ptr<Node>& child)
|
||||
{
|
||||
m_children.push_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(std::shared_ptr<Node> n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, index,
|
||||
[this, index](const std::shared_ptr<Node>& child)
|
||||
{
|
||||
m_children.insert(m_children.begin() + index, child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::remove_from_parent()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->remove_child(this);
|
||||
}
|
||||
|
||||
void Node::remove_child(Node* n)
|
||||
{
|
||||
auto i = find_child_iterator(*this, n);
|
||||
if (i != m_children.end())
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
detach_child(*this, i);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Node::remove_all_children()
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
detach_all_children(*this);
|
||||
});
|
||||
}
|
||||
|
||||
void Node::move_child(Node* n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
reorder_child(*this, n, index);
|
||||
});
|
||||
}
|
||||
|
||||
void Node::move_child_front(Node* n)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
move_child(n, count - 1);
|
||||
}
|
||||
|
||||
void Node::move_child_offset(Node* n, int offset)
|
||||
{
|
||||
int idx = get_child_index(n);
|
||||
move_child(n, idx + offset);
|
||||
}
|
||||
|
||||
int Node::get_child_index(Node* n)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (YGNodeGetChild(y_node, i) == n->y_node)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Node* Node::get_child_at(int index)
|
||||
{
|
||||
auto n = YGNodeGetChild(y_node, index);
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->y_node == n)
|
||||
return c.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glm::vec4 Node::get_children_rect() const
|
||||
{
|
||||
if (m_children.empty())
|
||||
return glm::vec4(0);
|
||||
glm::vec4 ret = m_children[0]->m_clip_uncut;
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->m_display)
|
||||
{
|
||||
ret = rect_union(ret, c->m_clip_uncut);
|
||||
auto r = c->get_children_rect();
|
||||
if (r.w > 0 && r.z > 0)
|
||||
ret = rect_union(ret, r);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Node>> Node::get_children_at_point(glm::vec2 point) const
|
||||
{
|
||||
std::vector<std::shared_ptr<Node>> ret;
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (point_in_rect(point, c->m_clip))
|
||||
{
|
||||
ret.push_back(c);
|
||||
auto c_ret = c->get_children_at_point(point);
|
||||
ret.insert(ret.end(), c_ret.begin(), c_ret.end());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Node::is_child_recursive(Node* o) const
|
||||
{
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (c.get() == o || c->is_child_recursive(o))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::is_child(Node* o) const
|
||||
{
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (c.get() == o)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
373
src/node.cpp
373
src/node.cpp
@@ -9,86 +9,6 @@
|
||||
#include "util.h"
|
||||
#include "asset.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
using NodeChildren = std::vector<std::shared_ptr<Node>>;
|
||||
using NodeChildIterator = NodeChildren::iterator;
|
||||
|
||||
NodeChildIterator find_child_iterator(Node& parent, Node* child)
|
||||
{
|
||||
return std::find_if(parent.m_children.begin(), parent.m_children.end(),
|
||||
[child](const std::shared_ptr<Node>& candidate) { return candidate.get() == child; });
|
||||
}
|
||||
|
||||
template <typename AttachChildrenFn>
|
||||
void attach_child(Node& parent, Node* child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||
{
|
||||
if (child->m_parent)
|
||||
child->m_parent->remove_child(child);
|
||||
|
||||
attach_children(child);
|
||||
child->m_parent = &parent;
|
||||
child->set_manager(parent.m_manager);
|
||||
child->m_destroyed = false;
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||
child->added(&parent);
|
||||
parent.on_child_added(child);
|
||||
}
|
||||
|
||||
template <typename AttachChildrenFn>
|
||||
void attach_child(Node& parent, const std::shared_ptr<Node>& child, int yoga_index, AttachChildrenFn&& attach_children)
|
||||
{
|
||||
if (child->m_parent)
|
||||
child->m_parent->remove_child(child.get());
|
||||
|
||||
attach_children(child);
|
||||
child->m_parent = &parent;
|
||||
child->set_manager(parent.m_manager);
|
||||
child->m_destroyed = false;
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, yoga_index);
|
||||
child->added(&parent);
|
||||
parent.on_child_added(child.get());
|
||||
}
|
||||
|
||||
void detach_child(Node& parent, NodeChildIterator child_it)
|
||||
{
|
||||
Node* child = child_it->get();
|
||||
child->removed(&parent);
|
||||
child->m_parent = nullptr;
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
parent.on_child_removed(child);
|
||||
parent.m_children.erase(child_it);
|
||||
if (parent.child_mouse_focus.get() == child)
|
||||
parent.child_mouse_focus = nullptr;
|
||||
}
|
||||
|
||||
void detach_all_children(Node& parent)
|
||||
{
|
||||
for (auto& child : parent.m_children)
|
||||
{
|
||||
child->removed(&parent);
|
||||
child->m_parent = nullptr;
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
parent.on_child_removed(child.get());
|
||||
}
|
||||
parent.m_children.clear();
|
||||
parent.child_mouse_focus = nullptr;
|
||||
}
|
||||
|
||||
void reorder_child(Node& parent, Node* child, int index)
|
||||
{
|
||||
int count = YGNodeGetChildCount(parent.y_node);
|
||||
index = glm::clamp<int>(index, 0, count - 1);
|
||||
YGNodeRemoveChild(parent.y_node, child->y_node);
|
||||
YGNodeInsertChild(parent.y_node, child->y_node, index);
|
||||
|
||||
auto child_it = find_child_iterator(parent, child);
|
||||
auto moved_child = *child_it;
|
||||
parent.m_children.erase(child_it);
|
||||
parent.m_children.insert(parent.m_children.begin() + index, moved_child);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::app_redraw()
|
||||
{
|
||||
App::I->redraw = true;
|
||||
@@ -108,52 +28,6 @@ void Node::watch(std::function<bool(Node*)> observer)
|
||||
}
|
||||
}
|
||||
|
||||
void Node::destroy()
|
||||
{
|
||||
//m_destroyed = true;
|
||||
//mouse_release();
|
||||
//key_release();
|
||||
//for (auto& c : m_children)
|
||||
// c->destroy();
|
||||
//for (auto p = m_parent; p; p = p->m_parent)
|
||||
// if (p->child_mouse_focus.get() == this)
|
||||
// p->child_mouse_focus = nullptr;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
mouse_release();
|
||||
key_release();
|
||||
auto cp = m_children;
|
||||
for (auto& c : cp)
|
||||
c->destroy();
|
||||
for (auto p = m_parent; p; p = p->m_parent)
|
||||
if (p->child_mouse_focus.get() == this)
|
||||
p->child_mouse_focus = nullptr;
|
||||
remove_all_children();
|
||||
remove_from_parent();
|
||||
});
|
||||
}
|
||||
|
||||
Node* Node::root()
|
||||
{
|
||||
Node* ret = this;
|
||||
while (ret->m_parent)
|
||||
ret = ret->m_parent;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Node::set_manager(LayoutManager* manager)
|
||||
{
|
||||
m_manager = manager;
|
||||
for (auto& c : m_children)
|
||||
c->set_manager(manager);
|
||||
}
|
||||
|
||||
bool Node::added_to_root()
|
||||
{
|
||||
auto r = root();
|
||||
return r == m_manager->get(App::I->main_id);
|
||||
}
|
||||
|
||||
kEventResult Node::on_event(Event* e)
|
||||
{
|
||||
return pp::panopainter::handle_legacy_ui_node_event(*this, e);
|
||||
@@ -169,21 +43,6 @@ void Node::handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom)
|
||||
|
||||
}
|
||||
|
||||
void Node::handle_on_screen(bool old_visibility, bool new_visibility)
|
||||
{
|
||||
if (new_visibility == false)
|
||||
{
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->m_on_screen)
|
||||
{
|
||||
c->handle_on_screen(true, false);
|
||||
c->m_on_screen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Node::handle_parent_resize(glm::vec2 old_size, glm::vec2 new_size)
|
||||
{
|
||||
|
||||
@@ -217,238 +76,6 @@ void Node::removed(Node* parent)
|
||||
p->child_mouse_focus = nullptr;
|
||||
}
|
||||
|
||||
const Node* Node::init_template(const char* id)
|
||||
{
|
||||
Node* t = nullptr;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
auto hid = const_hash(id);
|
||||
Node* top = m_manager->get(hid);
|
||||
t = static_cast<Node*>(top->m_children[0].get());
|
||||
t->set_manager(m_manager);
|
||||
for (auto& c : t->m_children)
|
||||
{
|
||||
auto node = c->clone();
|
||||
add_child(node);
|
||||
}
|
||||
YGNodeCopyStyle(y_node, t->y_node);
|
||||
t->clone_copy(this);
|
||||
});
|
||||
return t;
|
||||
}
|
||||
|
||||
bool Node::init_template_file(const std::string& path, const std::string& id)
|
||||
{
|
||||
bool ret = false;
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
LayoutManager m;
|
||||
if (m.load(path.c_str()))
|
||||
{
|
||||
auto t = m.get_ref(id.c_str())->m_children[0];
|
||||
t->set_manager(m_manager);
|
||||
for (auto& c : t->m_children)
|
||||
add_child(c->clone());
|
||||
YGNodeCopyStyle(y_node, t->y_node);
|
||||
t->clone_copy(this);
|
||||
ret = true;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Node::load_template(const std::string& filename, const std::string& name) const
|
||||
{
|
||||
LayoutManager m;
|
||||
std::shared_ptr<Node> ret;
|
||||
if (m.load(filename.c_str()))
|
||||
ret = m.get_ref(name.c_str())->m_children[0]->clone();
|
||||
m.unload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Node::parse_template(const std::string& xml_string, const std::string& name) const
|
||||
{
|
||||
LayoutManager m;
|
||||
std::shared_ptr<Node> ret;
|
||||
if (m.parse(xml_string))
|
||||
ret = m.get_ref(name.c_str())->m_children[0]->clone();
|
||||
m.unload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||
[this](Node* child)
|
||||
{
|
||||
m_children.emplace_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(Node* n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, index,
|
||||
[this](Node* child)
|
||||
{
|
||||
// Preserve the current backing-vector behavior for raw-pointer inserts.
|
||||
m_children.emplace_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(std::shared_ptr<Node> n)
|
||||
{
|
||||
App::I->ui_task([this,n]
|
||||
{
|
||||
attach_child(*this, n, YGNodeGetChildCount(y_node),
|
||||
[this](const std::shared_ptr<Node>& child)
|
||||
{
|
||||
m_children.push_back(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::add_child(std::shared_ptr<Node> n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
attach_child(*this, n, index,
|
||||
[this, index](const std::shared_ptr<Node>& child)
|
||||
{
|
||||
m_children.insert(m_children.begin() + index, child);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Node::remove_from_parent()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->remove_child(this);
|
||||
}
|
||||
|
||||
void Node::remove_child(Node* n)
|
||||
{
|
||||
auto i = find_child_iterator(*this, n);
|
||||
if (i != m_children.end())
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
detach_child(*this, i);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Node::remove_all_children()
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
detach_all_children(*this);
|
||||
});
|
||||
}
|
||||
|
||||
void Node::move_child(Node* n, int index)
|
||||
{
|
||||
App::I->ui_task([&]
|
||||
{
|
||||
reorder_child(*this, n, index);
|
||||
});
|
||||
}
|
||||
|
||||
void Node::move_child_front(Node* n)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
move_child(n, count - 1);
|
||||
}
|
||||
|
||||
void Node::move_child_offset(Node* n, int offset)
|
||||
{
|
||||
int idx = get_child_index(n);
|
||||
move_child(n, idx + offset);
|
||||
}
|
||||
|
||||
int Node::get_child_index(Node* n)
|
||||
{
|
||||
int count = YGNodeGetChildCount(y_node);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (YGNodeGetChild(y_node, i) == n->y_node)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Node* Node::get_child_at(int index)
|
||||
{
|
||||
auto n = YGNodeGetChild(y_node, index);
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->y_node == n)
|
||||
return c.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glm::vec4 Node::get_children_rect() const
|
||||
{
|
||||
if (m_children.empty())
|
||||
return glm::vec4(0);
|
||||
glm::vec4 ret = m_children[0]->m_clip_uncut;
|
||||
for (auto& c : m_children)
|
||||
{
|
||||
if (c->m_display)
|
||||
{
|
||||
ret = rect_union(ret, c->m_clip_uncut);
|
||||
auto r = c->get_children_rect();
|
||||
if (r.w > 0 && r.z > 0)
|
||||
ret = rect_union(ret, r);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Node>> Node::get_children_at_point(glm::vec2 point) const
|
||||
{
|
||||
std::vector<std::shared_ptr<Node>> ret;
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (point_in_rect(point, c->m_clip))
|
||||
{
|
||||
ret.push_back(c);
|
||||
auto c_ret = c->get_children_at_point(point);
|
||||
ret.insert(ret.end(), c_ret.begin(), c_ret.end());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Node::is_child_recursive(Node* o) const
|
||||
{
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (c.get() == o || c->is_child_recursive(o))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Node::is_child(Node* o) const
|
||||
{
|
||||
for (const auto& c : m_children)
|
||||
{
|
||||
if (c.get() == o)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Node::mouse_capture()
|
||||
{
|
||||
pp::panopainter::legacy_ui_node_mouse_capture(*this);
|
||||
|
||||
Reference in New Issue
Block a user