Own brush workers and thin preview/platform seams
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
#include "app_core/document_platform_io.h"
|
||||
#include "app_core/document_sharing.h"
|
||||
#include "platform_api/platform_services.h"
|
||||
#ifdef __LINUX__
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "platform_linux/linux_platform_services.h"
|
||||
#endif
|
||||
#include "platform_legacy/legacy_platform_services.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
|
||||
@@ -51,6 +55,21 @@ namespace {
|
||||
void App::set_platform_services(pp::platform::PlatformServices* services) noexcept
|
||||
{
|
||||
platform_services_ = services;
|
||||
#ifdef __LINUX__
|
||||
if (services)
|
||||
{
|
||||
pp::platform::linux::set_fps_title_callback([this](std::string title) {
|
||||
if (!glfw_window)
|
||||
return;
|
||||
|
||||
glfwSetWindowTitle(glfw_window, title.c_str());
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
pp::platform::linux::set_fps_title_callback({});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
pp::platform::PlatformServices* App::platform_services() const noexcept
|
||||
|
||||
@@ -7,12 +7,90 @@
|
||||
#include "node_dialog_export_ppbr.h"
|
||||
#include "node_panel_brush.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
class LegacyBrushPackageWorker final {
|
||||
public:
|
||||
LegacyBrushPackageWorker()
|
||||
: worker_([this](std::stop_token stop_token) {
|
||||
run(stop_token);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
~LegacyBrushPackageWorker()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void post(std::function<void()> task)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (stopping_)
|
||||
return;
|
||||
tasks_.push_back(std::move(task));
|
||||
}
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
void shutdown()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
stopping_ = true;
|
||||
}
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void run(std::stop_token stop_token)
|
||||
{
|
||||
for (;;) {
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [&] {
|
||||
return stopping_ || stop_token.stop_requested() || !tasks_.empty();
|
||||
});
|
||||
if ((stopping_ || stop_token.stop_requested()) && tasks_.empty())
|
||||
break;
|
||||
task = std::move(tasks_.front());
|
||||
tasks_.pop_front();
|
||||
}
|
||||
|
||||
if (task) {
|
||||
try {
|
||||
task();
|
||||
} catch (...) {
|
||||
LOG("brush package export worker task failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
std::deque<std::function<void()>> tasks_;
|
||||
bool stopping_ = false;
|
||||
std::jthread worker_;
|
||||
};
|
||||
|
||||
LegacyBrushPackageWorker& brush_package_worker()
|
||||
{
|
||||
static LegacyBrushPackageWorker worker;
|
||||
return worker;
|
||||
}
|
||||
|
||||
NodePanelBrushPreset::PPBRInfo to_legacy_ppbr_info(
|
||||
const pp::app::BrushPackageExportRequest& request,
|
||||
const NodeDialogExportPPBR& dialog)
|
||||
@@ -44,20 +122,29 @@ public:
|
||||
{
|
||||
const auto path_string = std::string(path);
|
||||
const auto info = to_legacy_ppbr_info(request, dialog_);
|
||||
auto presets = app_.presets;
|
||||
if (mode_ == LegacyBrushPackageExportMode::desktop_async_close_and_message) {
|
||||
auto* app = &app_;
|
||||
auto* dialog = &dialog_;
|
||||
std::thread([app, dialog, path_string, info] {
|
||||
auto dialog = std::static_pointer_cast<NodeDialogExportPPBR>(dialog_.shared_from_this());
|
||||
brush_package_worker().post([app, presets, dialog, path_string, info] {
|
||||
BT_SetTerminate();
|
||||
app->presets->export_ppbr(path_string, info);
|
||||
pp::panopainter::close_legacy_dialog_node(*dialog);
|
||||
if (presets) {
|
||||
presets->export_ppbr(path_string, info);
|
||||
}
|
||||
const auto plan = pp::app::plan_brush_package_export_success_dialog(path_string);
|
||||
app->message_box(plan.title, plan.message, plan.show_cancel);
|
||||
}).detach();
|
||||
app->ui_task([dialog, plan] {
|
||||
if (dialog) {
|
||||
pp::panopainter::close_legacy_dialog_node(*dialog);
|
||||
}
|
||||
App::I->message_box(plan.title, plan.message, plan.show_cancel);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
app_.presets->export_ppbr(path_string, info);
|
||||
if (presets) {
|
||||
presets->export_ppbr(path_string, info);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -5,12 +5,90 @@
|
||||
#include "app.h"
|
||||
#include "node_panel_brush.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <thread>
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
class LegacyBrushPackageWorker final {
|
||||
public:
|
||||
LegacyBrushPackageWorker()
|
||||
: worker_([this](std::stop_token stop_token) {
|
||||
run(stop_token);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
~LegacyBrushPackageWorker()
|
||||
{
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void post(std::function<void()> task)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (stopping_)
|
||||
return;
|
||||
tasks_.push_back(std::move(task));
|
||||
}
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
void shutdown()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
stopping_ = true;
|
||||
}
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void run(std::stop_token stop_token)
|
||||
{
|
||||
for (;;) {
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [&] {
|
||||
return stopping_ || stop_token.stop_requested() || !tasks_.empty();
|
||||
});
|
||||
if ((stopping_ || stop_token.stop_requested()) && tasks_.empty())
|
||||
break;
|
||||
task = std::move(tasks_.front());
|
||||
tasks_.pop_front();
|
||||
}
|
||||
|
||||
if (task) {
|
||||
try {
|
||||
task();
|
||||
} catch (...) {
|
||||
LOG("brush package import worker task failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
std::deque<std::function<void()>> tasks_;
|
||||
bool stopping_ = false;
|
||||
std::jthread worker_;
|
||||
};
|
||||
|
||||
LegacyBrushPackageWorker& brush_package_worker()
|
||||
{
|
||||
static LegacyBrushPackageWorker worker;
|
||||
return worker;
|
||||
}
|
||||
|
||||
class LegacyBrushPackageImportServices final : public pp::app::BrushPackageImportServices {
|
||||
public:
|
||||
explicit LegacyBrushPackageImportServices(App& app) noexcept
|
||||
@@ -22,12 +100,18 @@ public:
|
||||
{
|
||||
auto presets = app_.presets;
|
||||
const auto path_string = std::string(path);
|
||||
if (kind == pp::app::BrushPackageImportKind::abr) {
|
||||
std::thread(&NodePanelBrushPreset::import_abr, presets, path_string).detach();
|
||||
return;
|
||||
}
|
||||
brush_package_worker().post([presets, kind, path_string] {
|
||||
BT_SetTerminate();
|
||||
if (!presets) {
|
||||
return;
|
||||
}
|
||||
if (kind == pp::app::BrushPackageImportKind::abr) {
|
||||
presets->import_abr(path_string);
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread(&NodePanelBrushPreset::import_ppbr, presets, path_string).detach();
|
||||
presets->import_ppbr(path_string);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
#include "../libs/glm/glm/ext/matrix_clip_space.hpp"
|
||||
|
||||
#include "legacy_canvas_stroke_shader_services.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_canvas_stroke_preview_services.h"
|
||||
#include "legacy_canvas_stroke_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "paint_renderer/compositor.h"
|
||||
#include "texture.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace pp::panopainter {
|
||||
@@ -241,6 +245,91 @@ template <typename Frame>
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool execute_legacy_node_stroke_preview_final_composite(
|
||||
glm::vec2 size,
|
||||
glm::vec2 pattern_scale,
|
||||
const Brush& brush,
|
||||
const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass,
|
||||
Texture2D& background_texture,
|
||||
Texture2D& stroke_texture,
|
||||
Texture2D& dual_texture,
|
||||
Texture2D& preview_texture,
|
||||
Sampler& linear_sampler,
|
||||
Sampler& repeat_sampler,
|
||||
std::function<void()> bind_pattern_texture,
|
||||
std::function<void()> draw_composite)
|
||||
{
|
||||
if (!bind_pattern_texture || !draw_composite) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pp::panopainter::execute_legacy_stroke_preview_final_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = size,
|
||||
.pattern = {
|
||||
.scale = pattern_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 = composite_pass.pattern_blend_mode,
|
||||
.offset = glm::vec2(brush.m_pattern_rand_offset ? 0.5f : 0.0f),
|
||||
},
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = brush.m_blend_mode,
|
||||
.use_dual = composite_pass.use_dual,
|
||||
.dual_blend_mode = composite_pass.dual_blend_mode,
|
||||
.dual_alpha = composite_pass.dual_alpha,
|
||||
.use_pattern = composite_pass.use_pattern,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
linear_sampler.bind(0U);
|
||||
linear_sampler.bind(1U);
|
||||
linear_sampler.bind(2U);
|
||||
linear_sampler.bind(3U);
|
||||
repeat_sampler.bind(4U);
|
||||
},
|
||||
[&] {
|
||||
pp::legacy::ui_gl::activate_texture_unit(0U, "NodeStrokePreview");
|
||||
background_texture.bind();
|
||||
pp::legacy::ui_gl::activate_texture_unit(1U, "NodeStrokePreview");
|
||||
stroke_texture.bind();
|
||||
pp::legacy::ui_gl::activate_texture_unit(3U, "NodeStrokePreview");
|
||||
dual_texture.bind();
|
||||
pp::legacy::ui_gl::activate_texture_unit(4U, "NodeStrokePreview");
|
||||
bind_pattern_texture();
|
||||
},
|
||||
[&] {
|
||||
draw_composite();
|
||||
});
|
||||
|
||||
const auto copy_status = pp::paint_renderer::copy_stroke_preview_result_to_texture(
|
||||
[&] {
|
||||
preview_texture.bind();
|
||||
},
|
||||
[](
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height) {
|
||||
copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height);
|
||||
},
|
||||
pp::paint_renderer::StrokePreviewCopySize {
|
||||
.width = static_cast<int>(size.x),
|
||||
.height = static_cast<int>(size.y),
|
||||
});
|
||||
return copy_status.ok();
|
||||
}
|
||||
|
||||
struct LegacyNodeStrokePreviewPassOrchestrationRequest {
|
||||
pp::renderer::RenderDeviceFeatures features {};
|
||||
glm::vec2 preview_size {};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "assets/brush_package.h"
|
||||
#include "app_core/brush_ui.h"
|
||||
#include "legacy_brush_ui_services.h"
|
||||
#include "legacy_brush_package_import_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "asset.h"
|
||||
#include "texture.h"
|
||||
@@ -600,13 +601,8 @@ void NodePanelBrushPreset::init()
|
||||
switch (index)
|
||||
{
|
||||
case 0: // import file
|
||||
App::I->pick_file({"abr", "ppbr"}, [this] (std::string path) {
|
||||
std::thread([this, path] {
|
||||
BT_SetTerminate();
|
||||
import_brush(path);
|
||||
for (auto p : s_panels)
|
||||
p->m_notification->SetVisibility(p->m_container->m_children.size() == 0);
|
||||
}).detach();
|
||||
App::I->pick_file({"abr", "ppbr"}, [presets = std::static_pointer_cast<NodePanelBrushPreset>(shared_from_this())] (std::string path) {
|
||||
presets->import_brush(path);
|
||||
});
|
||||
break;
|
||||
case 1: // export file
|
||||
@@ -637,13 +633,8 @@ void NodePanelBrushPreset::init()
|
||||
};
|
||||
m_btn_import = find<NodeButton>("import");
|
||||
m_btn_import->on_click = [this] (Node*) {
|
||||
App::I->pick_file({ "abr", "ppbr" }, [this](std::string path) {
|
||||
std::thread([this, path] {
|
||||
BT_SetTerminate();
|
||||
import_brush(path);
|
||||
for (auto p : s_panels)
|
||||
p->m_notification->SetVisibility(p->m_container->m_children.size() == 0);
|
||||
}).detach();
|
||||
App::I->pick_file({ "abr", "ppbr" }, [presets = std::static_pointer_cast<NodePanelBrushPreset>(shared_from_this())](std::string path) {
|
||||
presets->import_brush(path);
|
||||
});
|
||||
};
|
||||
m_btn_download = find<NodeButton>("download");
|
||||
@@ -1050,6 +1041,10 @@ bool NodePanelBrushPreset::import_ppbr(const std::string& path)
|
||||
|
||||
// brush settings
|
||||
auto brushes_count = sr.ru32();
|
||||
std::vector<std::shared_ptr<Brush>> brushes_to_add;
|
||||
if (brushes_count > 0) {
|
||||
brushes_to_add.reserve(static_cast<std::size_t>(brushes_count));
|
||||
}
|
||||
for (int i = 0; i < brushes_count; i++)
|
||||
{
|
||||
auto b = std::make_shared<Brush>();
|
||||
@@ -1058,16 +1053,23 @@ bool NodePanelBrushPreset::import_ppbr(const std::string& path)
|
||||
LOG("import_ppbr brush name %s", b->m_name.c_str());
|
||||
if (b->valid())
|
||||
{
|
||||
for (auto p : s_panels)
|
||||
p->add_brush(b);
|
||||
brushes_to_add.push_back(b);
|
||||
}
|
||||
pb->increment();
|
||||
}
|
||||
|
||||
save();
|
||||
App::I->stroke->m_brush_popup->reload();
|
||||
auto owner = std::static_pointer_cast<NodePanelBrushPreset>(shared_from_this());
|
||||
App::I->ui_task([owner, brushes_to_add = std::move(brushes_to_add), pb]() mutable {
|
||||
for (const auto& b : brushes_to_add)
|
||||
{
|
||||
for (auto p : s_panels)
|
||||
p->add_brush(b);
|
||||
}
|
||||
|
||||
pp::panopainter::close_legacy_dialog_node(*pb);
|
||||
owner->save();
|
||||
App::I->stroke->m_brush_popup->reload();
|
||||
pp::panopainter::close_legacy_dialog_node(*pb);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1148,7 +1150,8 @@ bool NodePanelBrushPreset::import_abr(const std::string& path)
|
||||
});
|
||||
|
||||
auto brushes = abr.compute_brushes(App::I->data_path);
|
||||
App::I->ui_task([&]{
|
||||
auto owner = std::static_pointer_cast<NodePanelBrushPreset>(shared_from_this());
|
||||
App::I->ui_task([owner, brushes = std::move(brushes), pb]() mutable {
|
||||
for (const auto& b : brushes)
|
||||
{
|
||||
if (b->valid())
|
||||
@@ -1159,12 +1162,11 @@ bool NodePanelBrushPreset::import_abr(const std::string& path)
|
||||
}
|
||||
pb->increment();
|
||||
}
|
||||
owner->save();
|
||||
App::I->stroke->m_brush_popup->reload();
|
||||
pp::panopainter::close_legacy_dialog_node(*pb);
|
||||
});
|
||||
|
||||
save();
|
||||
App::I->stroke->m_brush_popup->reload();
|
||||
pp::panopainter::close_legacy_dialog_node(*pb);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1178,7 +1180,15 @@ bool NodePanelBrushPreset::import_brush(const std::string& path)
|
||||
std::string name = m[2].str();
|
||||
std::string ext = m[3].str();
|
||||
|
||||
return ext == "ppbr" ? import_ppbr(path) : import_abr(path);
|
||||
const auto kind = ext == "ppbr"
|
||||
? pp::app::BrushPackageImportKind::ppbr
|
||||
: pp::app::BrushPackageImportKind::abr;
|
||||
const auto status = pp::panopainter::execute_legacy_brush_package_import(*App::I, kind, path);
|
||||
if (!status.ok()) {
|
||||
LOG("Brush package import request failed: %s", status.message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NodePanelBrushPreset::clear_brushes()
|
||||
|
||||
@@ -82,43 +82,6 @@ constexpr std::uint32_t kMixer = 3U;
|
||||
constexpr std::uint32_t kReservedLinear = 4U;
|
||||
}
|
||||
|
||||
struct StrokePreviewCompositePassInputs {
|
||||
glm::vec2 resolution;
|
||||
glm::vec2 pattern_scale;
|
||||
const Brush& brush;
|
||||
const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass;
|
||||
Texture2D& background_texture;
|
||||
Texture2D& stroke_texture;
|
||||
Texture2D& dual_texture;
|
||||
Sampler& linear_sampler;
|
||||
Sampler& repeat_sampler;
|
||||
std::function<void()> draw_composite;
|
||||
|
||||
StrokePreviewCompositePassInputs(
|
||||
glm::vec2 resolution_in,
|
||||
glm::vec2 pattern_scale_in,
|
||||
const Brush& brush_in,
|
||||
const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass_in,
|
||||
Texture2D& background_texture_in,
|
||||
Texture2D& stroke_texture_in,
|
||||
Texture2D& dual_texture_in,
|
||||
Sampler& linear_sampler_in,
|
||||
Sampler& repeat_sampler_in,
|
||||
std::function<void()> draw_composite_in)
|
||||
: resolution(resolution_in)
|
||||
, pattern_scale(pattern_scale_in)
|
||||
, brush(brush_in)
|
||||
, composite_pass(composite_pass_in)
|
||||
, background_texture(background_texture_in)
|
||||
, stroke_texture(stroke_texture_in)
|
||||
, dual_texture(dual_texture_in)
|
||||
, linear_sampler(linear_sampler_in)
|
||||
, repeat_sampler(repeat_sampler_in)
|
||||
, draw_composite(std::move(draw_composite_in))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
pp::panopainter::LegacyNodeStrokePreviewMixPassRequest make_stroke_preview_mix_pass_request(
|
||||
const Brush& brush,
|
||||
glm::vec2 resolution) noexcept
|
||||
@@ -232,65 +195,7 @@ pp::panopainter::LegacyCanvasStrokeMixPassRequest make_stroke_preview_mix_pass_e
|
||||
[&](int) {
|
||||
set_active_texture_unit(stroke_preview_composite_slots::kBackground);
|
||||
background_texture.unbind();
|
||||
});
|
||||
}
|
||||
|
||||
void copy_stroke_preview_result_to_texture(Texture2D& texture, glm::vec2 size);
|
||||
|
||||
void execute_stroke_preview_final_composite_and_copy(
|
||||
const StrokePreviewCompositePassInputs& inputs,
|
||||
Texture2D& preview_texture,
|
||||
glm::vec2 size)
|
||||
{
|
||||
pp::panopainter::execute_legacy_stroke_preview_final_composite(
|
||||
[&] {
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = inputs.resolution,
|
||||
.pattern = {
|
||||
.scale = inputs.pattern_scale,
|
||||
.invert = static_cast<float>(inputs.brush.m_pattern_invert),
|
||||
.brightness = inputs.brush.m_pattern_brightness,
|
||||
.contrast = inputs.brush.m_pattern_contrast,
|
||||
.depth = inputs.brush.m_pattern_depth,
|
||||
.blend_mode = inputs.composite_pass.pattern_blend_mode,
|
||||
.offset = glm::vec2(inputs.brush.m_pattern_rand_offset ? 0.5f : 0.0f),
|
||||
},
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = inputs.brush.m_blend_mode,
|
||||
.use_dual = inputs.composite_pass.use_dual,
|
||||
.dual_blend_mode = inputs.composite_pass.dual_blend_mode,
|
||||
.dual_alpha = inputs.composite_pass.dual_alpha,
|
||||
.use_pattern = inputs.composite_pass.use_pattern,
|
||||
});
|
||||
},
|
||||
[&] {
|
||||
inputs.linear_sampler.bind(stroke_preview_composite_slots::kBackground);
|
||||
inputs.linear_sampler.bind(stroke_preview_composite_slots::kStroke);
|
||||
inputs.linear_sampler.bind(2U);
|
||||
inputs.linear_sampler.bind(stroke_preview_composite_slots::kDual);
|
||||
inputs.repeat_sampler.bind(stroke_preview_composite_slots::kPattern);
|
||||
},
|
||||
[&] {
|
||||
set_active_texture_unit(stroke_preview_composite_slots::kBackground);
|
||||
inputs.background_texture.bind();
|
||||
set_active_texture_unit(stroke_preview_composite_slots::kStroke);
|
||||
inputs.stroke_texture.bind();
|
||||
set_active_texture_unit(stroke_preview_composite_slots::kDual);
|
||||
inputs.dual_texture.bind();
|
||||
set_active_texture_unit(stroke_preview_composite_slots::kPattern);
|
||||
inputs.brush.m_pattern_texture ?
|
||||
inputs.brush.m_pattern_texture->bind() :
|
||||
unbind_texture_2d();
|
||||
},
|
||||
[&] {
|
||||
inputs.draw_composite();
|
||||
});
|
||||
copy_stroke_preview_result_to_texture(preview_texture, size);
|
||||
});
|
||||
}
|
||||
|
||||
void copy_stroke_preview_framebuffer_to_texture(
|
||||
@@ -500,22 +405,6 @@ void execute_stroke_preview_background_capture_pass(
|
||||
assert(copy_status.ok());
|
||||
}
|
||||
|
||||
void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2 size)
|
||||
{
|
||||
const auto result = pp::paint_renderer::copy_stroke_preview_result_to_texture(
|
||||
[&] {
|
||||
preview_texture.bind();
|
||||
},
|
||||
[](int src_x, int src_y, int dst_x, int dst_y, int width, int height) {
|
||||
copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height);
|
||||
},
|
||||
pp::paint_renderer::StrokePreviewCopySize {
|
||||
.width = static_cast<int>(size.x),
|
||||
.height = static_cast<int>(size.y),
|
||||
});
|
||||
assert(result.ok());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
||||
@@ -841,22 +730,26 @@ void NodeStrokePreview::draw_stroke_immediate()
|
||||
return false;
|
||||
}
|
||||
|
||||
execute_stroke_preview_final_composite_and_copy(
|
||||
StrokePreviewCompositePassInputs(
|
||||
size,
|
||||
glm::vec2(b->m_pattern_scale),
|
||||
*b,
|
||||
material.composite_pass,
|
||||
m_tex_background,
|
||||
m_tex,
|
||||
m_tex_dual,
|
||||
m_sampler_linear,
|
||||
m_sampler_linear_repeat,
|
||||
[&] {
|
||||
m_plane.draw_fill();
|
||||
}),
|
||||
const bool final_composite_ok = pp::panopainter::execute_legacy_node_stroke_preview_final_composite(
|
||||
size,
|
||||
glm::vec2(b->m_pattern_scale),
|
||||
*b,
|
||||
material.composite_pass,
|
||||
m_tex_background,
|
||||
m_tex,
|
||||
m_tex_dual,
|
||||
m_tex_preview,
|
||||
size);
|
||||
m_sampler_linear,
|
||||
m_sampler_linear_repeat,
|
||||
[&] {
|
||||
b->m_pattern_texture ? b->m_pattern_texture->bind() : unbind_texture_2d();
|
||||
},
|
||||
[&] {
|
||||
m_plane.draw_fill();
|
||||
});
|
||||
if (!final_composite_ok) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
assert(sequence_ok);
|
||||
|
||||
@@ -2,21 +2,28 @@
|
||||
|
||||
#ifdef __LINUX__
|
||||
#include <string>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "app.h"
|
||||
#include <utility>
|
||||
|
||||
namespace pp::platform::linux {
|
||||
namespace {
|
||||
|
||||
std::function<void(std::string)> g_fps_title_callback;
|
||||
|
||||
void linux_update_fps(int frames)
|
||||
{
|
||||
App::I->title("PanoPainter - " + std::to_string(frames) + " FPS");
|
||||
if (!g_fps_title_callback)
|
||||
return;
|
||||
|
||||
g_fps_title_callback("PanoPainter - " + std::to_string(frames) + " FPS");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void set_fps_title_callback(std::function<void(std::string)> callback)
|
||||
{
|
||||
g_fps_title_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void report_rendered_frames(int frames)
|
||||
{
|
||||
linux_update_fps(frames);
|
||||
@@ -26,6 +33,11 @@ void report_rendered_frames(int frames)
|
||||
#else
|
||||
namespace pp::platform::linux {
|
||||
|
||||
void set_fps_title_callback(std::function<void(std::string)> callback)
|
||||
{
|
||||
(void)callback;
|
||||
}
|
||||
|
||||
void report_rendered_frames(int frames)
|
||||
{
|
||||
(void)frames;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace pp::platform::linux {
|
||||
|
||||
void set_fps_title_callback(std::function<void(std::string)> callback);
|
||||
void report_rendered_frames(int frames);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user