Thin retained app and render runtime seams
This commit is contained in:
@@ -88,6 +88,7 @@ set(PP_LEGACY_APP_SOURCES
|
|||||||
src/legacy_canvas_mode_fill.cpp
|
src/legacy_canvas_mode_fill.cpp
|
||||||
src/legacy_canvas_mode_pen_line.cpp
|
src/legacy_canvas_mode_pen_line.cpp
|
||||||
src/legacy_canvas_mode_helpers.cpp
|
src/legacy_canvas_mode_helpers.cpp
|
||||||
|
src/legacy_document_image_import_services.cpp
|
||||||
src/legacy_canvas_mode_helpers.h
|
src/legacy_canvas_mode_helpers.h
|
||||||
src/legacy_canvas_mode_mask.cpp
|
src/legacy_canvas_mode_mask.cpp
|
||||||
src/legacy_canvas_mode_transform.cpp
|
src/legacy_canvas_mode_transform.cpp
|
||||||
@@ -101,6 +102,7 @@ set(PP_LEGACY_APP_SOURCES
|
|||||||
src/legacy_preference_storage.h
|
src/legacy_preference_storage.h
|
||||||
src/legacy_document_canvas_services.cpp
|
src/legacy_document_canvas_services.cpp
|
||||||
src/legacy_document_canvas_services.h
|
src/legacy_document_canvas_services.h
|
||||||
|
src/legacy_document_image_import_services.h
|
||||||
src/legacy_document_layer_services.cpp
|
src/legacy_document_layer_services.cpp
|
||||||
src/legacy_document_layer_services.h
|
src/legacy_document_layer_services.h
|
||||||
src/legacy_history_services.cpp
|
src/legacy_history_services.cpp
|
||||||
|
|||||||
@@ -18,6 +18,24 @@ agent or engineer to remove them without reconstructing context from chat.
|
|||||||
|
|
||||||
## Reductions
|
## Reductions
|
||||||
|
|
||||||
|
- 2026-06-17: `DEBT-0036` was narrowed again. Retained `Shape`,
|
||||||
|
`src/shader.cpp`, and `src/font.cpp` now queue render-thread create/update/
|
||||||
|
destroy work through `src/renderer_gl/render_runtime_dispatch.h` instead of
|
||||||
|
calling `App::I` directly, and `Shader` render-thread entry points now assert
|
||||||
|
that explicit runtime contract while shader-program and mesh ownership remain
|
||||||
|
retained.
|
||||||
|
- 2026-06-17: `DEBT-0036` was narrowed again. `NodeStrokePreview` no longer
|
||||||
|
owns static worker-thread, queue, or render-mutex state directly;
|
||||||
|
`src/legacy_node_stroke_preview_runtime_services.*` now owns the retained
|
||||||
|
preview worker lifecycle and queue helpers, leaving the node as a thinner
|
||||||
|
adapter while the retained preview runtime still reaches app/render helpers
|
||||||
|
internally.
|
||||||
|
- 2026-06-17: `DEBT-0029` was narrowed again.
|
||||||
|
`LegacyFileMenuServices::pick_image_for_import()` in
|
||||||
|
`src/legacy_app_shell_services.cpp` now delegates retained import execution
|
||||||
|
to `src/legacy_document_image_import_services.*`, so the File-menu adapter no
|
||||||
|
longer defines the live `DocumentImageImportServices` implementation inline;
|
||||||
|
legacy `Image` loading and retained canvas/import-mode execution still remain.
|
||||||
- 2026-06-17: `DEBT-0003` was narrowed again. `src/app_runtime.cpp` and
|
- 2026-06-17: `DEBT-0003` was narrowed again. `src/app_runtime.cpp` and
|
||||||
`src/app_runtime.h` now synchronize render/UI worker running state, reject
|
`src/app_runtime.h` now synchronize render/UI worker running state, reject
|
||||||
cross-thread work once those workers stop, and drain queued work through
|
cross-thread work once those workers stop, and drain queued work through
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ Key facts:
|
|||||||
- `Canvas::I` still appears hundreds of times in retained canvas modes, panels,
|
- `Canvas::I` still appears hundreds of times in retained canvas modes, panels,
|
||||||
and workflow bridges.
|
and workflow bridges.
|
||||||
- Raw `Node*` and callback captures remain a dominant UI lifetime risk.
|
- Raw `Node*` and callback captures remain a dominant UI lifetime risk.
|
||||||
- `RTT`, `Texture2D`, `Shape`, `Shader`, `Font`, and `CanvasLayer` still route
|
- `CanvasLayer` and retained stroke-preview/runtime draw paths still depend on
|
||||||
render work through `App::I` queues.
|
legacy render/runtime helpers, but `RTT`, `Texture2D`, `Shape`, `Shader`,
|
||||||
|
and `TextMesh` no longer call `App::I` directly for queueing.
|
||||||
- `AppRuntime` now owns synchronized running flags plus explicit post/reject,
|
- `AppRuntime` now owns synchronized running flags plus explicit post/reject,
|
||||||
same-thread execution, and queue-drain behavior, but broader singleton reach
|
same-thread execution, and queue-drain behavior, but broader singleton reach
|
||||||
and app-shell ownership remain.
|
and app-shell ownership remain.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "legacy_gl_mesh_dispatch.h"
|
#include "legacy_gl_mesh_dispatch.h"
|
||||||
#include "legacy_ui_gl_dispatch.h"
|
#include "legacy_ui_gl_dispatch.h"
|
||||||
|
#include "renderer_gl/render_runtime_dispatch.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -202,7 +203,7 @@ std::vector<TextMesh::Token> TextMesh::tokenize(const std::string& s, const Font
|
|||||||
|
|
||||||
bool TextMesh::create()
|
bool TextMesh::create()
|
||||||
{
|
{
|
||||||
App::I->render_task([this]
|
pp::renderer::gl::render_runtime_dispatch().render_task([this]
|
||||||
{
|
{
|
||||||
const auto mesh = pp::legacy::gl_mesh::create_mesh_objects(
|
const auto mesh = pp::legacy::gl_mesh::create_mesh_objects(
|
||||||
pp::renderer::gl::OpenGlMeshUpload {
|
pp::renderer::gl::OpenGlMeshUpload {
|
||||||
@@ -305,7 +306,7 @@ void TextMesh::update(const std::string& text, const std::string& font, int size
|
|||||||
cur_box -= glm::vec4(xy(f.bounds), 0, 0);
|
cur_box -= glm::vec4(xy(f.bounds), 0, 0);
|
||||||
bb = bbmax - bbmin;
|
bb = bbmax - bbmin;
|
||||||
font_array_count = (int)idx.size();
|
font_array_count = (int)idx.size();
|
||||||
App::I->render_task([&]
|
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||||
{
|
{
|
||||||
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
||||||
pp::renderer::gl::OpenGlBufferUpload {
|
pp::renderer::gl::OpenGlBufferUpload {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "app_core/document_import.h"
|
#include "app_core/document_import.h"
|
||||||
#include "legacy_app_dialog_services.h"
|
#include "legacy_app_dialog_services.h"
|
||||||
#include "legacy_canvas_view_services.h"
|
#include "legacy_canvas_view_services.h"
|
||||||
|
#include "legacy_document_image_import_services.h"
|
||||||
#include "legacy_document_canvas_services.h"
|
#include "legacy_document_canvas_services.h"
|
||||||
#include "legacy_history_services.h"
|
#include "legacy_history_services.h"
|
||||||
#include "legacy_ui_overlay_services.h"
|
#include "legacy_ui_overlay_services.h"
|
||||||
@@ -51,50 +52,23 @@ public:
|
|||||||
|
|
||||||
void pick_image_for_import() override
|
void pick_image_for_import() override
|
||||||
{
|
{
|
||||||
auto* app_ptr = &app_;
|
app_.pick_image([this](std::string path) {
|
||||||
app_.pick_image([app_ptr](std::string path) {
|
|
||||||
Image img;
|
Image img;
|
||||||
img.load_file(path);
|
img.load_file(path);
|
||||||
const auto import_plan = pp::app::plan_document_image_import(img.width, img.height);
|
const auto import_plan = pp::app::plan_document_image_import(img.width, img.height);
|
||||||
if (!import_plan)
|
if (!import_plan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
class LegacyDocumentImageImportServices final : public pp::app::DocumentImageImportServices {
|
auto* canvas = app_.canvas ? app_.canvas->m_canvas.get() : nullptr;
|
||||||
public:
|
auto* import_mode = canvas
|
||||||
LegacyDocumentImageImportServices(App& app, Image& image) noexcept
|
? static_cast<CanvasModeTransform*>(canvas->modes[(int)kCanvasMode::Import][0])
|
||||||
: app_(app)
|
: nullptr;
|
||||||
, image_(image)
|
const auto status = execute_legacy_document_image_import_plan(
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void import_equirectangular(std::string_view import_path) override
|
|
||||||
{
|
|
||||||
if (Canvas::I)
|
|
||||||
Canvas::I->import_equirectangular(std::string(import_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
void enter_transform_import(std::string_view) override
|
|
||||||
{
|
|
||||||
if (!app_.canvas || !app_.canvas->m_canvas)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* mode = static_cast<CanvasModeTransform*>(
|
|
||||||
app_.canvas->m_canvas->modes[(int)kCanvasMode::Import][0]);
|
|
||||||
mode->m_action = CanvasModeTransform::ActionType::Import;
|
|
||||||
mode->m_source_image = std::move(image_);
|
|
||||||
Canvas::set_mode(kCanvasMode::Import);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
App& app_;
|
|
||||||
Image& image_;
|
|
||||||
};
|
|
||||||
|
|
||||||
LegacyDocumentImageImportServices services(*app_ptr, img);
|
|
||||||
const auto status = pp::app::execute_document_image_import_plan(
|
|
||||||
import_plan.value(),
|
import_plan.value(),
|
||||||
path,
|
path,
|
||||||
services);
|
canvas,
|
||||||
|
import_mode,
|
||||||
|
std::move(img));
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Image import failed: %s", status.message);
|
LOG("Image import failed: %s", status.message);
|
||||||
});
|
});
|
||||||
|
|||||||
57
src/legacy_document_image_import_services.cpp
Normal file
57
src/legacy_document_image_import_services.cpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "legacy_document_image_import_services.h"
|
||||||
|
|
||||||
|
#include "canvas.h"
|
||||||
|
#include "canvas_modes.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class LegacyDocumentImageImportServices final : public pp::app::DocumentImageImportServices {
|
||||||
|
public:
|
||||||
|
LegacyDocumentImageImportServices(Canvas* canvas, CanvasModeTransform* import_mode, Image image) noexcept
|
||||||
|
: canvas_(canvas)
|
||||||
|
, import_mode_(import_mode)
|
||||||
|
, image_(std::move(image))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void import_equirectangular(std::string_view import_path) override
|
||||||
|
{
|
||||||
|
if (canvas_)
|
||||||
|
canvas_->import_equirectangular(std::string(import_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
void enter_transform_import(std::string_view) override
|
||||||
|
{
|
||||||
|
if (!canvas_ || !import_mode_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
import_mode_->m_action = CanvasModeTransform::ActionType::Import;
|
||||||
|
import_mode_->m_source_image = std::move(image_);
|
||||||
|
Canvas::set_mode(kCanvasMode::Import);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Canvas* canvas_ = nullptr;
|
||||||
|
CanvasModeTransform* import_mode_ = nullptr;
|
||||||
|
Image image_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
pp::foundation::Status execute_legacy_document_image_import_plan(
|
||||||
|
const pp::app::DocumentImageImportPlan& plan,
|
||||||
|
std::string_view path,
|
||||||
|
Canvas* canvas,
|
||||||
|
CanvasModeTransform* import_mode,
|
||||||
|
Image image)
|
||||||
|
{
|
||||||
|
LegacyDocumentImageImportServices services(canvas, import_mode, std::move(image));
|
||||||
|
return pp::app::execute_document_image_import_plan(plan, path, services);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
20
src/legacy_document_image_import_services.h
Normal file
20
src/legacy_document_image_import_services.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app_core/document_import.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
class Canvas;
|
||||||
|
class CanvasModeTransform;
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
|
||||||
|
[[nodiscard]] pp::foundation::Status execute_legacy_document_image_import_plan(
|
||||||
|
const pp::app::DocumentImageImportPlan& plan,
|
||||||
|
std::string_view path,
|
||||||
|
Canvas* canvas,
|
||||||
|
CanvasModeTransform* import_mode,
|
||||||
|
Image image);
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "paint_renderer/compositor.h"
|
#include "paint_renderer/compositor.h"
|
||||||
#include "renderer_gl/opengl_capabilities.h"
|
#include "renderer_gl/opengl_capabilities.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <stop_token>
|
#include <stop_token>
|
||||||
@@ -477,11 +478,141 @@ bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& previe
|
|||||||
|
|
||||||
} // namespace pp::panopainter
|
} // namespace pp::panopainter
|
||||||
|
|
||||||
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
namespace pp::panopainter {
|
||||||
std::atomic_bool NodeStrokePreview::s_running{ false };
|
|
||||||
std::mutex NodeStrokePreview::s_render_mutex;
|
|
||||||
BlockingQueue<std::shared_ptr<NodeStrokePreview>> NodeStrokePreview::s_queue;
|
|
||||||
|
|
||||||
|
class NodeStrokePreviewRuntime
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::mutex& render_mutex() noexcept
|
||||||
|
{
|
||||||
|
return render_mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(lifecycle_mutex_);
|
||||||
|
if (worker_.joinable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
worker_ = std::jthread([this](std::stop_token stop_token) {
|
||||||
|
run(stop_token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
std::jthread worker;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(lifecycle_mutex_);
|
||||||
|
if (!worker_.joinable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
worker = std::move(worker_);
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.request_stop();
|
||||||
|
queue_.UnlockGetters();
|
||||||
|
if (worker.joinable())
|
||||||
|
worker.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_queue()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(queue_.mutex);
|
||||||
|
queue_.q.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueue(const std::shared_ptr<NodeStrokePreview>& preview, bool draw_first)
|
||||||
|
{
|
||||||
|
if (!preview)
|
||||||
|
return;
|
||||||
|
|
||||||
|
start();
|
||||||
|
queue_.PostUnique(preview, draw_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(const std::shared_ptr<NodeStrokePreview>& preview)
|
||||||
|
{
|
||||||
|
if (!preview)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(queue_.mutex);
|
||||||
|
auto it = std::find_if(queue_.q.begin(), queue_.q.end(), [&preview](const auto& queued) {
|
||||||
|
return queued.first == preview;
|
||||||
|
});
|
||||||
|
if (it != queue_.q.end())
|
||||||
|
queue_.q.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run(std::stop_token stop_token)
|
||||||
|
{
|
||||||
|
BT_SetTerminate();
|
||||||
|
|
||||||
|
NodeStrokePreview::m_sampler_linear.create();
|
||||||
|
NodeStrokePreview::m_sampler_linear_repeat.create(
|
||||||
|
pp::renderer::gl::linear_texture_filter(),
|
||||||
|
pp::renderer::gl::repeat_texture_wrap());
|
||||||
|
NodeStrokePreview::m_sampler_mipmap.create();
|
||||||
|
NodeStrokePreview::m_sampler_mipmap.set_filter(
|
||||||
|
pp::renderer::gl::linear_mipmap_linear_texture_filter(),
|
||||||
|
pp::renderer::gl::linear_texture_filter());
|
||||||
|
NodeStrokePreview::m_brush_shape.create();
|
||||||
|
|
||||||
|
while (!stop_token.stop_requested())
|
||||||
|
{
|
||||||
|
auto node = queue_.Get();
|
||||||
|
if (!node) {
|
||||||
|
if (stop_token.stop_requested())
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> render_lock(render_mutex_);
|
||||||
|
|
||||||
|
// if the brush is not already loaded, load it and then destroy it
|
||||||
|
const bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
||||||
|
node->m_brush->preload();
|
||||||
|
|
||||||
|
pp::panopainter::execute_legacy_node_stroke_preview_render_task([node, to_unload] {
|
||||||
|
gl_state gl;
|
||||||
|
gl.save();
|
||||||
|
|
||||||
|
node->m_brush->load();
|
||||||
|
node->draw_stroke_immediate();
|
||||||
|
if (to_unload)
|
||||||
|
node->m_brush->unload();
|
||||||
|
|
||||||
|
gl.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
node->app_redraw();
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeStrokePreview::m_rtt.destroy();
|
||||||
|
NodeStrokePreview::m_rtt_mixer.destroy();
|
||||||
|
NodeStrokePreview::m_tex.destroy();
|
||||||
|
NodeStrokePreview::m_tex_dual.destroy();
|
||||||
|
NodeStrokePreview::m_tex_background.destroy();
|
||||||
|
NodeStrokePreview::m_brush_shape.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex lifecycle_mutex_;
|
||||||
|
std::mutex render_mutex_;
|
||||||
|
BlockingQueue<std::shared_ptr<NodeStrokePreview>> queue_;
|
||||||
|
std::jthread worker_;
|
||||||
|
};
|
||||||
|
|
||||||
|
NodeStrokePreviewRuntime& legacy_node_stroke_preview_runtime()
|
||||||
|
{
|
||||||
|
static NodeStrokePreviewRuntime runtime;
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
|
|
||||||
|
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
||||||
RTT NodeStrokePreview::m_rtt;
|
RTT NodeStrokePreview::m_rtt;
|
||||||
RTT NodeStrokePreview::m_rtt_mixer;
|
RTT NodeStrokePreview::m_rtt_mixer;
|
||||||
Texture2D NodeStrokePreview::m_tex; // blending tmp texture
|
Texture2D NodeStrokePreview::m_tex; // blending tmp texture
|
||||||
@@ -491,22 +622,60 @@ Sampler NodeStrokePreview::m_sampler_linear;
|
|||||||
Sampler NodeStrokePreview::m_sampler_linear_repeat;
|
Sampler NodeStrokePreview::m_sampler_linear_repeat;
|
||||||
Sampler NodeStrokePreview::m_sampler_mipmap;
|
Sampler NodeStrokePreview::m_sampler_mipmap;
|
||||||
DynamicShape NodeStrokePreview::m_brush_shape;
|
DynamicShape NodeStrokePreview::m_brush_shape;
|
||||||
std::jthread NodeStrokePreview::s_renderer;
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
|
||||||
|
std::mutex& legacy_node_stroke_preview_render_mutex()
|
||||||
|
{
|
||||||
|
return legacy_node_stroke_preview_runtime().render_mutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_legacy_node_stroke_preview_render_task(std::function<void()> task)
|
||||||
|
{
|
||||||
|
if (!task)
|
||||||
|
return;
|
||||||
|
|
||||||
|
App::I->render_task(std::move(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_legacy_node_stroke_preview_worker()
|
||||||
|
{
|
||||||
|
legacy_node_stroke_preview_runtime().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_legacy_node_stroke_preview_worker()
|
||||||
|
{
|
||||||
|
legacy_node_stroke_preview_runtime().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_legacy_node_stroke_preview_worker_queue()
|
||||||
|
{
|
||||||
|
legacy_node_stroke_preview_runtime().clear_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueue_legacy_node_stroke_preview_worker(
|
||||||
|
const std::shared_ptr<NodeStrokePreview>& preview,
|
||||||
|
bool draw_first)
|
||||||
|
{
|
||||||
|
legacy_node_stroke_preview_runtime().enqueue(preview, draw_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_legacy_node_stroke_preview_worker(
|
||||||
|
const std::shared_ptr<NodeStrokePreview>& preview)
|
||||||
|
{
|
||||||
|
legacy_node_stroke_preview_runtime().remove(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pp::panopainter
|
||||||
|
|
||||||
void NodeStrokePreview::terminate_renderer()
|
void NodeStrokePreview::terminate_renderer()
|
||||||
{
|
{
|
||||||
if (!s_renderer.joinable())
|
pp::panopainter::stop_legacy_node_stroke_preview_worker();
|
||||||
return;
|
|
||||||
|
|
||||||
s_running = false;
|
|
||||||
s_renderer.request_stop();
|
|
||||||
s_queue.UnlockGetters();
|
|
||||||
s_renderer.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeStrokePreview::empty_queue()
|
void NodeStrokePreview::empty_queue()
|
||||||
{
|
{
|
||||||
s_queue.q.clear();
|
pp::panopainter::clear_legacy_node_stroke_preview_worker_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeStrokePreview::restore_context()
|
void NodeStrokePreview::restore_context()
|
||||||
@@ -526,9 +695,9 @@ void NodeStrokePreview::clear_context()
|
|||||||
|
|
||||||
Image NodeStrokePreview::render_to_image()
|
Image NodeStrokePreview::render_to_image()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> _lock(s_render_mutex);
|
std::lock_guard<std::mutex> _lock(pp::panopainter::legacy_node_stroke_preview_render_mutex());
|
||||||
|
|
||||||
App::I->render_task([this] {
|
pp::panopainter::execute_legacy_node_stroke_preview_render_task([this] {
|
||||||
draw_stroke_immediate();
|
draw_stroke_immediate();
|
||||||
});
|
});
|
||||||
return m_tex_preview.get_image();
|
return m_tex_preview.get_image();
|
||||||
@@ -538,63 +707,9 @@ void NodeStrokePreview::draw_stroke()
|
|||||||
{
|
{
|
||||||
if (m_size.x == 0 || m_size.y == 0)
|
if (m_size.x == 0 || m_size.y == 0)
|
||||||
return;
|
return;
|
||||||
std::unique_lock<std::mutex> queue_lock(s_queue.mutex);
|
pp::panopainter::enqueue_legacy_node_stroke_preview_worker(
|
||||||
if (!s_renderer.joinable())
|
std::static_pointer_cast<NodeStrokePreview>(shared_from_this()),
|
||||||
{
|
m_draw_first);
|
||||||
s_running = true;
|
|
||||||
s_renderer = std::jthread([](std::stop_token stop_token) {
|
|
||||||
BT_SetTerminate();
|
|
||||||
|
|
||||||
m_sampler_linear.create();
|
|
||||||
m_sampler_linear_repeat.create(
|
|
||||||
pp::renderer::gl::linear_texture_filter(),
|
|
||||||
pp::renderer::gl::repeat_texture_wrap());
|
|
||||||
m_sampler_mipmap.create();
|
|
||||||
m_sampler_mipmap.set_filter(
|
|
||||||
pp::renderer::gl::linear_mipmap_linear_texture_filter(),
|
|
||||||
pp::renderer::gl::linear_texture_filter());
|
|
||||||
m_brush_shape.create();
|
|
||||||
while (s_running && !stop_token.stop_requested())
|
|
||||||
{
|
|
||||||
auto node = s_queue.Get();
|
|
||||||
if (node)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> _lock(s_render_mutex);
|
|
||||||
|
|
||||||
// if the brush is not already loaded, load it and then destroy it
|
|
||||||
bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
|
||||||
node->m_brush->preload();
|
|
||||||
|
|
||||||
App::I->render_task([node, to_unload]
|
|
||||||
{
|
|
||||||
gl_state gl;
|
|
||||||
gl.save();
|
|
||||||
|
|
||||||
node->m_brush->load();
|
|
||||||
node->draw_stroke_immediate();
|
|
||||||
if (to_unload)
|
|
||||||
node->m_brush->unload();
|
|
||||||
|
|
||||||
gl.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
node->app_redraw();
|
|
||||||
|
|
||||||
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_rtt.destroy();
|
|
||||||
m_rtt_mixer.destroy();
|
|
||||||
m_tex.destroy();
|
|
||||||
m_tex_dual.destroy();
|
|
||||||
m_tex_background.destroy();
|
|
||||||
m_brush_shape.destroy();
|
|
||||||
s_running = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
queue_lock.unlock();
|
|
||||||
s_queue.PostUnique(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()), m_draw_first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeStrokePreview::draw()
|
void NodeStrokePreview::draw()
|
||||||
@@ -637,7 +752,7 @@ void NodeStrokePreview::handle_on_screen(bool old_visibility, bool new_visibilit
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s_queue.Remove(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()));
|
pp::panopainter::remove_legacy_node_stroke_preview_worker(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()));
|
||||||
m_tex_preview.destroy();
|
m_tex_preview.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Node;
|
class Node;
|
||||||
@@ -136,6 +137,17 @@ struct LegacyNodeStrokePreviewImmediateDrawRequest {
|
|||||||
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_runtime(
|
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_runtime(
|
||||||
const LegacyNodeStrokePreviewImmediateRuntimeRequest& request);
|
const LegacyNodeStrokePreviewImmediateRuntimeRequest& request);
|
||||||
|
|
||||||
|
[[nodiscard]] std::mutex& legacy_node_stroke_preview_render_mutex();
|
||||||
|
void execute_legacy_node_stroke_preview_render_task(std::function<void()> task);
|
||||||
|
void start_legacy_node_stroke_preview_worker();
|
||||||
|
void stop_legacy_node_stroke_preview_worker();
|
||||||
|
void clear_legacy_node_stroke_preview_worker_queue();
|
||||||
|
void enqueue_legacy_node_stroke_preview_worker(
|
||||||
|
const std::shared_ptr<NodeStrokePreview>& preview,
|
||||||
|
bool draw_first);
|
||||||
|
void remove_legacy_node_stroke_preview_worker(
|
||||||
|
const std::shared_ptr<NodeStrokePreview>& preview);
|
||||||
|
|
||||||
void initialize_legacy_node_stroke_preview_clone(Node* dest);
|
void initialize_legacy_node_stroke_preview_clone(Node* dest);
|
||||||
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
|
||||||
#include "node_border.h"
|
#include "node_border.h"
|
||||||
#include "rtt.h"
|
#include "rtt.h"
|
||||||
#include "brush.h"
|
#include "brush.h"
|
||||||
@@ -9,10 +8,15 @@
|
|||||||
#include "legacy_node_stroke_preview_execution_services.h"
|
#include "legacy_node_stroke_preview_execution_services.h"
|
||||||
#include "legacy_node_stroke_preview_runtime_services.h"
|
#include "legacy_node_stroke_preview_runtime_services.h"
|
||||||
|
|
||||||
|
namespace pp::panopainter {
|
||||||
|
class NodeStrokePreviewRuntime;
|
||||||
|
}
|
||||||
|
|
||||||
class NodeStrokePreview : public NodeBorder
|
class NodeStrokePreview : public NodeBorder
|
||||||
{
|
{
|
||||||
using StrokeFrame = pp::panopainter::LegacyNodeStrokePreviewFrame;
|
using StrokeFrame = pp::panopainter::LegacyNodeStrokePreviewFrame;
|
||||||
|
|
||||||
|
friend class pp::panopainter::NodeStrokePreviewRuntime;
|
||||||
friend bool pp::panopainter::execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
friend bool pp::panopainter::execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
||||||
|
|
||||||
static RTT m_rtt;
|
static RTT m_rtt;
|
||||||
@@ -28,10 +32,6 @@ class NodeStrokePreview : public NodeBorder
|
|||||||
public:
|
public:
|
||||||
using parent = NodeBorder;
|
using parent = NodeBorder;
|
||||||
static std::atomic_int s_instances;
|
static std::atomic_int s_instances;
|
||||||
static std::atomic_bool s_running;
|
|
||||||
static std::mutex s_render_mutex;
|
|
||||||
static std::jthread s_renderer;
|
|
||||||
static BlockingQueue<std::shared_ptr<NodeStrokePreview>> s_queue;
|
|
||||||
static void terminate_renderer();
|
static void terminate_renderer();
|
||||||
static void empty_queue();
|
static void empty_queue();
|
||||||
std::shared_ptr<Brush> m_brush;
|
std::shared_ptr<Brush> m_brush;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
#include "app.h"
|
|
||||||
#include "legacy_gl_shader_dispatch.h"
|
#include "legacy_gl_shader_dispatch.h"
|
||||||
#include "renderer_gl/opengl_capabilities.h"
|
#include "renderer_gl/opengl_capabilities.h"
|
||||||
|
#include "renderer_gl/render_runtime_dispatch.h"
|
||||||
#include "renderer_gl/shader_bindings.h"
|
#include "renderer_gl/shader_bindings.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -165,7 +165,7 @@ bool Shader::reload()
|
|||||||
bool Shader::create(const std::string& vertex, const std::string& fragment)
|
bool Shader::create(const std::string& vertex, const std::string& fragment)
|
||||||
{
|
{
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
App::I->render_task([this, &ret, vertex, fragment]
|
pp::renderer::gl::render_runtime_dispatch().render_task([this, &ret, vertex, fragment]
|
||||||
{
|
{
|
||||||
static char infolog[4096];
|
static char infolog[4096];
|
||||||
const auto vertex_shader = pp::renderer::gl::compile_opengl_shader_source(
|
const auto vertex_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||||
@@ -337,7 +337,7 @@ void Shader::destroy()
|
|||||||
{
|
{
|
||||||
if (prog)
|
if (prog)
|
||||||
{
|
{
|
||||||
App::I->render_task_async([prog=prog]
|
pp::renderer::gl::render_runtime_dispatch().render_task_async([prog=prog]
|
||||||
{
|
{
|
||||||
const auto status = pp::renderer::gl::delete_opengl_program(
|
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||||
static_cast<std::uint32_t>(prog),
|
static_cast<std::uint32_t>(prog),
|
||||||
@@ -352,6 +352,7 @@ void Shader::destroy()
|
|||||||
|
|
||||||
void Shader::use()
|
void Shader::use()
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
const auto status = pp::renderer::gl::use_opengl_program(
|
const auto status = pp::renderer::gl::use_opengl_program(
|
||||||
static_cast<std::uint32_t>(prog),
|
static_cast<std::uint32_t>(prog),
|
||||||
pp::legacy::gl_shader::program_use_dispatch());
|
pp::legacy::gl_shader::program_use_dispatch());
|
||||||
@@ -360,6 +361,7 @@ void Shader::use()
|
|||||||
}
|
}
|
||||||
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -374,6 +376,7 @@ void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
|||||||
}
|
}
|
||||||
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -389,6 +392,7 @@ void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
|||||||
|
|
||||||
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -404,6 +408,7 @@ void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
|||||||
|
|
||||||
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -418,6 +423,7 @@ void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
|||||||
}
|
}
|
||||||
void Shader::u_int(kShaderUniform id, int i)
|
void Shader::u_int(kShaderUniform id, int i)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -432,6 +438,7 @@ void Shader::u_int(kShaderUniform id, int i)
|
|||||||
}
|
}
|
||||||
void Shader::u_int(const char* uniform_name, int i)
|
void Shader::u_int(const char* uniform_name, int i)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
||||||
static_cast<std::uint32_t>(prog),
|
static_cast<std::uint32_t>(prog),
|
||||||
uniform_name,
|
uniform_name,
|
||||||
@@ -450,6 +457,7 @@ void Shader::u_int(const char* uniform_name, int i)
|
|||||||
}
|
}
|
||||||
void Shader::u_float(kShaderUniform id, float f)
|
void Shader::u_float(kShaderUniform id, float f)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -464,6 +472,7 @@ void Shader::u_float(kShaderUniform id, float f)
|
|||||||
}
|
}
|
||||||
GLint Shader::GetAttribLocation(const char* attribute_name)
|
GLint Shader::GetAttribLocation(const char* attribute_name)
|
||||||
{
|
{
|
||||||
|
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||||
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
||||||
static_cast<std::uint32_t>(prog),
|
static_cast<std::uint32_t>(prog),
|
||||||
attribute_name,
|
attribute_name,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "legacy_gl_mesh_dispatch.h"
|
#include "legacy_gl_mesh_dispatch.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "app.h"
|
|
||||||
#include "renderer_gl/opengl_capabilities.h"
|
#include "renderer_gl/opengl_capabilities.h"
|
||||||
|
#include "renderer_gl/render_runtime_dispatch.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -71,7 +71,7 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
|
|||||||
use_idx = true;
|
use_idx = true;
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
App::I->render_task([&]
|
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ bool Shape::create_buffers(GLvoid* vertices, int vsize)
|
|||||||
use_idx = false;
|
use_idx = false;
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
App::I->render_task([&]
|
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||||
{
|
{
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ void Shape::draw_fill() const
|
|||||||
if (count[0] == 0) return;
|
if (count[0] == 0) return;
|
||||||
|
|
||||||
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_fill_count(count[0]));
|
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_fill_count(count[0]));
|
||||||
App::I->render_task([=]
|
pp::renderer::gl::render_runtime_dispatch().render_task([=]
|
||||||
{
|
{
|
||||||
(void)pp::legacy::gl_mesh::draw_mesh(
|
(void)pp::legacy::gl_mesh::draw_mesh(
|
||||||
pp::renderer::gl::OpenGlMeshDraw {
|
pp::renderer::gl::OpenGlMeshDraw {
|
||||||
@@ -148,7 +148,7 @@ void Shape::draw_stroke() const
|
|||||||
if (count[0] == 0) return;
|
if (count[0] == 0) return;
|
||||||
|
|
||||||
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_stroke_count(count[1]));
|
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_stroke_count(count[1]));
|
||||||
App::I->render_task([=]
|
pp::renderer::gl::render_runtime_dispatch().render_task([=]
|
||||||
{
|
{
|
||||||
(void)pp::legacy::gl_mesh::draw_mesh(
|
(void)pp::legacy::gl_mesh::draw_mesh(
|
||||||
pp::renderer::gl::OpenGlMeshDraw {
|
pp::renderer::gl::OpenGlMeshDraw {
|
||||||
@@ -165,10 +165,13 @@ void Shape::draw_stroke() const
|
|||||||
|
|
||||||
void Shape::destroy()
|
void Shape::destroy()
|
||||||
{
|
{
|
||||||
if (App::I) App::I->render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
|
if (buffers[0] || buffers[1] || arrays[0] || arrays[1])
|
||||||
{
|
{
|
||||||
(void)pp::legacy::gl_mesh::delete_mesh_objects({ b1, b2 }, { a1, a2 }, "Shape::destroy");
|
pp::renderer::gl::render_runtime_dispatch().render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
|
||||||
});
|
{
|
||||||
|
(void)pp::legacy::gl_mesh::delete_mesh_objects({ b1, b2 }, { a1, a2 }, "Shape::destroy");
|
||||||
|
});
|
||||||
|
}
|
||||||
buffers[0] = buffers[1] = 0;
|
buffers[0] = buffers[1] = 0;
|
||||||
arrays[0] = arrays[1] = 0;
|
arrays[0] = arrays[1] = 0;
|
||||||
}
|
}
|
||||||
@@ -451,7 +454,7 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
|
|||||||
vertices[i].pos.z = q;
|
vertices[i].pos.z = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
App::I->render_task([this]
|
pp::renderer::gl::render_runtime_dispatch().render_task([this]
|
||||||
{
|
{
|
||||||
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
||||||
pp::renderer::gl::OpenGlBufferUpload {
|
pp::renderer::gl::OpenGlBufferUpload {
|
||||||
@@ -732,7 +735,7 @@ void Sphere::create_impl(int rings, int sectors, float radius,
|
|||||||
}
|
}
|
||||||
void LineSegment::update_vertices(const glm::vec4 data[2])
|
void LineSegment::update_vertices(const glm::vec4 data[2])
|
||||||
{
|
{
|
||||||
App::I->render_task([&]
|
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||||
{
|
{
|
||||||
static vertex_t vertices[2];
|
static vertex_t vertices[2];
|
||||||
vertices[0] = { data[0], { 0, 0 } }; // A
|
vertices[0] = { data[0], { 0, 0 } }; // A
|
||||||
@@ -750,7 +753,7 @@ void LineSegment::update_vertices(const glm::vec4 data[2])
|
|||||||
}
|
}
|
||||||
void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
|
void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
|
||||||
{
|
{
|
||||||
App::I->render_task([&]
|
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||||
{
|
{
|
||||||
count[0] = vcount;
|
count[0] = vcount;
|
||||||
count[1] = vcount;
|
count[1] = vcount;
|
||||||
|
|||||||
Reference in New Issue
Block a user