644 lines
23 KiB
C++
644 lines
23 KiB
C++
#include "pch.h"
|
|
#include "legacy_node_stroke_preview_runtime_services.h"
|
|
#include "log.h"
|
|
#include "node_stroke_preview.h"
|
|
#include "texture.h"
|
|
#include "shader.h"
|
|
#include "bezier.h"
|
|
#include "canvas.h"
|
|
#include "app.h"
|
|
#include "legacy_canvas_draw_merge_services.h"
|
|
#include "legacy_canvas_stroke_composite_services.h"
|
|
#include "legacy_canvas_stroke_execution_services.h"
|
|
#include "legacy_canvas_stroke_preview_services.h"
|
|
#include "legacy_canvas_stroke_shader_services.h"
|
|
#include "legacy_canvas_stroke_services.h"
|
|
#include "legacy_node_stroke_preview_execution_services.h"
|
|
#include "legacy_node_stroke_preview_sample_services.h"
|
|
#include "legacy_ui_gl_dispatch.h"
|
|
#include "paint_renderer/compositor.h"
|
|
#include "renderer_gl/opengl_capabilities.h"
|
|
#include "util.h"
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <stop_token>
|
|
|
|
namespace pp::panopainter {
|
|
|
|
pp::renderer::RenderDeviceFeatures stroke_preview_render_device_features() noexcept
|
|
{
|
|
return ShaderManager::render_device_features();
|
|
}
|
|
|
|
void apply_legacy_node_stroke_preview_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, "NodeStrokePreview");
|
|
}
|
|
|
|
pp::renderer::gl::OpenGlViewportRect query_legacy_node_stroke_preview_viewport()
|
|
{
|
|
return pp::legacy::ui_gl::query_viewport_rect("NodeStrokePreview");
|
|
}
|
|
|
|
std::array<float, 4> query_legacy_node_stroke_preview_clear_color()
|
|
{
|
|
return pp::legacy::ui_gl::query_clear_color("NodeStrokePreview");
|
|
}
|
|
|
|
void apply_legacy_node_stroke_preview_clear_color(std::array<float, 4> color)
|
|
{
|
|
pp::legacy::ui_gl::set_clear_color(color, "NodeStrokePreview");
|
|
}
|
|
|
|
void apply_legacy_node_stroke_preview_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
|
|
{
|
|
pp::legacy::ui_gl::apply_scissor_rect(x, y, width, height, "NodeStrokePreview");
|
|
}
|
|
|
|
void apply_legacy_node_stroke_preview_capability(std::uint32_t state, bool enabled)
|
|
{
|
|
pp::legacy::ui_gl::set_capability(state, enabled, "NodeStrokePreview");
|
|
}
|
|
|
|
namespace {
|
|
|
|
namespace stroke_preview_live_slots {
|
|
constexpr std::uint32_t kTip = 0U;
|
|
constexpr std::uint32_t kDestination = 1U;
|
|
constexpr std::uint32_t kPattern = 2U;
|
|
constexpr std::uint32_t kMixer = 3U;
|
|
constexpr std::uint32_t kReservedLinear = 4U;
|
|
}
|
|
|
|
void set_active_texture_unit(std::uint32_t unit_index)
|
|
{
|
|
pp::legacy::ui_gl::activate_texture_unit(unit_index, "NodeStrokePreview");
|
|
}
|
|
|
|
void unbind_texture_2d()
|
|
{
|
|
pp::legacy::ui_gl::unbind_texture_2d("NodeStrokePreview");
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void bind_legacy_node_stroke_preview_live_samplers(
|
|
Sampler& mipmap_sampler,
|
|
Sampler& linear_sampler,
|
|
Sampler& repeat_sampler)
|
|
{
|
|
mipmap_sampler.bind(stroke_preview_live_slots::kTip);
|
|
linear_sampler.bind(stroke_preview_live_slots::kDestination);
|
|
repeat_sampler.bind(stroke_preview_live_slots::kPattern);
|
|
linear_sampler.bind(stroke_preview_live_slots::kMixer);
|
|
linear_sampler.bind(stroke_preview_live_slots::kReservedLinear);
|
|
}
|
|
|
|
void bind_legacy_node_stroke_preview_dual_pass_textures(const Brush& dual_brush)
|
|
{
|
|
set_active_texture_unit(stroke_preview_live_slots::kTip);
|
|
dual_brush.m_tip_texture ?
|
|
dual_brush.m_tip_texture->bind() :
|
|
unbind_texture_2d();
|
|
}
|
|
|
|
void bind_legacy_node_stroke_preview_pattern_texture(const Brush& brush)
|
|
{
|
|
set_active_texture_unit(stroke_preview_live_slots::kPattern);
|
|
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d();
|
|
}
|
|
|
|
void bind_legacy_node_stroke_preview_destination_texture(Texture2D& texture)
|
|
{
|
|
set_active_texture_unit(stroke_preview_live_slots::kDestination);
|
|
texture.bind();
|
|
}
|
|
|
|
void unbind_legacy_node_stroke_preview_destination_texture(Texture2D& texture)
|
|
{
|
|
set_active_texture_unit(stroke_preview_live_slots::kDestination);
|
|
texture.unbind();
|
|
}
|
|
|
|
void unbind_legacy_node_stroke_preview_mixer_texture(RTT& mixer_rtt)
|
|
{
|
|
set_active_texture_unit(stroke_preview_live_slots::kMixer);
|
|
mixer_rtt.unbindTexture();
|
|
}
|
|
|
|
void copy_legacy_node_stroke_preview_destination_texture_region(
|
|
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);
|
|
}
|
|
|
|
bool execute_legacy_node_stroke_preview_immediate_draw(
|
|
const LegacyNodeStrokePreviewImmediateDrawRequest& request)
|
|
{
|
|
if (!request.brush ||
|
|
!request.prepare_render_target ||
|
|
!request.finish_render_target ||
|
|
!request.compute_frames ||
|
|
!request.draw_samples ||
|
|
!request.draw_mix ||
|
|
!request.draw_checkerboard ||
|
|
!request.draw_composite) {
|
|
return false;
|
|
}
|
|
|
|
if (!ensure_legacy_node_stroke_preview_render_targets(
|
|
LegacyNodeStrokePreviewRenderTargetSetup {
|
|
.preview_rtt = request.preview_rtt,
|
|
.preview_rtt_mixer = request.preview_rtt_mixer,
|
|
.preview_stroke_texture = request.preview_stroke_texture,
|
|
.preview_dual_texture = request.preview_dual_texture,
|
|
.preview_background_texture = request.preview_background_texture,
|
|
.preview_image_texture = request.preview_image_texture,
|
|
.size = request.preview_size,
|
|
})) {
|
|
return false;
|
|
}
|
|
|
|
const auto vp = query_legacy_node_stroke_preview_viewport();
|
|
const auto cc = query_legacy_node_stroke_preview_clear_color();
|
|
const glm::vec2 size = {
|
|
static_cast<float>(request.preview_rtt.getWidth()),
|
|
static_cast<float>(request.preview_rtt.getHeight()),
|
|
};
|
|
const bool sequence_ok = execute_legacy_node_stroke_preview_immediate_runtime(
|
|
LegacyNodeStrokePreviewImmediateRuntimeRequest {
|
|
.brush = request.brush,
|
|
.preview_size = request.preview_size,
|
|
.zoom = request.zoom,
|
|
.min_flow = request.min_flow,
|
|
.stroke_max_size_override = request.stroke_max_size_override,
|
|
.pad_override = request.pad_override,
|
|
.camera_fov = request.camera_fov,
|
|
.camera_rot = request.camera_rot,
|
|
.render_device_features = request.render_device_features,
|
|
.preview_rtt = request.preview_rtt,
|
|
.preview_rtt_mixer = request.preview_rtt_mixer,
|
|
.preview_stroke_texture = request.preview_stroke_texture,
|
|
.preview_dual_texture = request.preview_dual_texture,
|
|
.preview_background_texture = request.preview_background_texture,
|
|
.preview_image_texture = request.preview_image_texture,
|
|
.linear_sampler = request.linear_sampler,
|
|
.repeat_sampler = request.repeat_sampler,
|
|
.prepare_render_target = request.prepare_render_target,
|
|
.finish_render_target = request.finish_render_target,
|
|
.set_blend_enabled = [](bool enabled) {
|
|
apply_legacy_node_stroke_preview_capability(pp::renderer::gl::blend_state(), enabled);
|
|
},
|
|
.setup_stroke_shader = [](const LegacyStrokeShaderSetupUniforms& uniforms) {
|
|
setup_legacy_stroke_shader(uniforms);
|
|
},
|
|
.bind_dual_pass_textures = [](const Brush& dual_brush) {
|
|
bind_legacy_node_stroke_preview_dual_pass_textures(dual_brush);
|
|
},
|
|
.capture_background = [&](bool colorize) {
|
|
execute_legacy_node_stroke_preview_background_capture_pass(
|
|
LegacyNodeStrokePreviewBackgroundCaptureRequest {
|
|
.size = size,
|
|
.colorize = colorize,
|
|
.background_texture = request.preview_background_texture,
|
|
.draw_checkerboard = [&] {
|
|
request.draw_checkerboard();
|
|
},
|
|
});
|
|
},
|
|
.compute_frames = request.compute_frames,
|
|
.draw_samples = request.draw_samples,
|
|
.draw_mix = request.draw_mix,
|
|
.unbind_mixer_texture = [&] {
|
|
unbind_legacy_node_stroke_preview_mixer_texture(request.preview_rtt_mixer);
|
|
},
|
|
.bind_pattern_texture = [&] {
|
|
bind_legacy_node_stroke_preview_pattern_texture(*request.brush);
|
|
},
|
|
.draw_composite = request.draw_composite,
|
|
});
|
|
apply_legacy_node_stroke_preview_viewport(vp.x, vp.y, vp.width, vp.height);
|
|
apply_legacy_node_stroke_preview_clear_color(cc);
|
|
return sequence_ok;
|
|
}
|
|
|
|
void execute_legacy_node_stroke_preview_background_capture_pass(
|
|
const LegacyNodeStrokePreviewBackgroundCaptureRequest& request)
|
|
{
|
|
if (!request.draw_checkerboard) {
|
|
return;
|
|
}
|
|
|
|
const float aspect = request.size.x / request.size.y;
|
|
pp::panopainter::setup_legacy_canvas_draw_merge_checkerboard_shader(
|
|
pp::panopainter::LegacyCanvasDrawMergeCheckerboardUniforms {
|
|
.mvp = glm::ortho(-.5f, .5f, -.5f / aspect, .5f / aspect, -1.f, 1.f),
|
|
.colorize = request.colorize,
|
|
});
|
|
request.draw_checkerboard();
|
|
const auto copy_status = pp::paint_renderer::copy_stroke_preview_result_to_texture(
|
|
[&] {
|
|
request.background_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>(request.size.x),
|
|
.height = static_cast<int>(request.size.y),
|
|
});
|
|
assert(copy_status.ok());
|
|
}
|
|
|
|
std::vector<LegacyNodeStrokePreviewFrame> plan_legacy_node_stroke_preview_stroke_frames(
|
|
const LegacyNodeStrokePreviewStrokeComputeRequest& request)
|
|
{
|
|
auto samples = const_cast<Stroke&>(request.stroke).compute_samples();
|
|
StrokeSample previous_sample = request.stroke.m_prev_sample;
|
|
previous_sample.size *= request.zoom;
|
|
for (auto& sample : samples) {
|
|
sample.size *= request.zoom;
|
|
}
|
|
|
|
return pp::panopainter::plan_legacy_canvas_stroke_frames(
|
|
pp::panopainter::LegacyCanvasStrokeComputeRequest {
|
|
.previous_sample = previous_sample,
|
|
.samples = samples,
|
|
.zoom = 1.0f,
|
|
.mixer_size = request.mixer_size,
|
|
},
|
|
[](
|
|
std::array<vertex_t, 4>& brush_quad,
|
|
bool /*project_3d*/,
|
|
glm::mat4 /*model_view*/) {
|
|
return brush_quad;
|
|
},
|
|
[](
|
|
glm::vec4 mixer_rect,
|
|
glm::vec4 color,
|
|
float flow,
|
|
float opacity,
|
|
std::array<vertex_t, 4>&& shapes) -> LegacyNodeStrokePreviewFrame {
|
|
return LegacyNodeStrokePreviewFrame {
|
|
.col = color,
|
|
.flow = flow,
|
|
.opacity = opacity,
|
|
.shapes = std::move(shapes),
|
|
.mixer_rect = mixer_rect,
|
|
};
|
|
});
|
|
}
|
|
|
|
std::vector<LegacyNodeStrokePreviewFrame> plan_legacy_node_stroke_preview_stroke_frames(
|
|
const Stroke& stroke,
|
|
float zoom,
|
|
glm::vec2 mixer_size)
|
|
{
|
|
return plan_legacy_node_stroke_preview_stroke_frames(
|
|
LegacyNodeStrokePreviewStrokeComputeRequest {
|
|
.stroke = stroke,
|
|
.zoom = zoom,
|
|
.mixer_size = mixer_size,
|
|
});
|
|
}
|
|
|
|
bool execute_legacy_node_stroke_preview_immediate_runtime(
|
|
const LegacyNodeStrokePreviewImmediateRuntimeRequest& request)
|
|
{
|
|
if (!request.brush ||
|
|
!request.prepare_render_target ||
|
|
!request.finish_render_target ||
|
|
!request.set_blend_enabled ||
|
|
!request.setup_stroke_shader) {
|
|
return false;
|
|
}
|
|
|
|
const glm::vec2 render_target_size = {
|
|
static_cast<float>(request.preview_rtt.getWidth()),
|
|
static_cast<float>(request.preview_rtt.getHeight()),
|
|
};
|
|
const auto stroke_setup = plan_legacy_node_stroke_preview_stroke_setup(
|
|
LegacyNodeStrokePreviewStrokeSetupRequest {
|
|
.preview_size = request.preview_size,
|
|
.zoom = request.zoom,
|
|
.brush_tip_size = request.brush->m_tip_size,
|
|
.stroke_max_size_override = request.stroke_max_size_override,
|
|
.pad_override = request.pad_override,
|
|
.tip_size_pressure = request.brush->m_tip_size_pressure,
|
|
.dual_enabled = request.brush->m_dual_enabled,
|
|
.dual_size = request.brush->m_dual_size,
|
|
.pattern_scale = request.brush->m_pattern_scale,
|
|
.pattern_flipx = request.brush->m_pattern_flipx,
|
|
.pattern_flipy = request.brush->m_pattern_flipy,
|
|
});
|
|
const auto prepared_strokes = prepare_legacy_node_stroke_preview_strokes(
|
|
request.brush,
|
|
stroke_setup,
|
|
request.camera_fov,
|
|
request.camera_rot);
|
|
const glm::mat4 ortho_proj = glm::ortho<float>(0, render_target_size.x, 0, render_target_size.y, -1, 1);
|
|
|
|
request.prepare_render_target();
|
|
request.set_blend_enabled(false);
|
|
|
|
const auto pass_orchestration = plan_legacy_node_stroke_preview_pass_orchestration(
|
|
make_legacy_node_stroke_preview_pass_orchestration_request(
|
|
request.render_device_features,
|
|
render_target_size,
|
|
*request.brush,
|
|
ortho_proj));
|
|
request.setup_stroke_shader(pass_orchestration.stroke_shader);
|
|
const bool sequence_ok = execute_legacy_node_stroke_preview_live_render_passes(
|
|
LegacyNodeStrokePreviewLiveRenderRequest {
|
|
.brush = *request.brush,
|
|
.pass_orchestration = pass_orchestration,
|
|
.prepared_strokes = prepared_strokes,
|
|
.stroke_texture = request.preview_stroke_texture,
|
|
.mixer_rtt = request.preview_rtt_mixer,
|
|
.render_target = request.preview_rtt,
|
|
.background_texture = request.preview_background_texture,
|
|
.dual_texture = request.preview_dual_texture,
|
|
.preview_texture = request.preview_image_texture,
|
|
.linear_sampler = request.linear_sampler,
|
|
.repeat_sampler = request.repeat_sampler,
|
|
.zoom = request.zoom,
|
|
.min_flow = request.min_flow,
|
|
.copy_stroke_destination = pass_orchestration.copy_stroke_destination,
|
|
.size = render_target_size,
|
|
.bind_dual_pass_textures = request.bind_dual_pass_textures,
|
|
.capture_background = request.capture_background,
|
|
.compute_frames = request.compute_frames,
|
|
.draw_samples = request.draw_samples,
|
|
.draw_mix = request.draw_mix,
|
|
.unbind_mixer_texture = request.unbind_mixer_texture,
|
|
.bind_pattern_texture = request.bind_pattern_texture,
|
|
.draw_composite = request.draw_composite,
|
|
});
|
|
request.finish_render_target();
|
|
return sequence_ok;
|
|
}
|
|
|
|
void initialize_legacy_node_stroke_preview_clone(Node* dest)
|
|
{
|
|
static_cast<NodeStrokePreview*>(dest)->init_controls();
|
|
}
|
|
|
|
bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview)
|
|
{
|
|
if (preview.m_size.x == 0 || preview.m_size.y == 0) {
|
|
return false;
|
|
}
|
|
|
|
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_immediate_draw(
|
|
pp::panopainter::LegacyNodeStrokePreviewImmediateDrawRequest {
|
|
.brush = preview.m_brush,
|
|
.preview_size = preview.m_size,
|
|
.zoom = preview.root()->m_zoom,
|
|
.min_flow = preview.m_min_flow,
|
|
.stroke_max_size_override = preview.m_max_size,
|
|
.pad_override = preview.m_pad_override,
|
|
.camera_fov = Canvas::I->m_cam_fov,
|
|
.camera_rot = Canvas::I->m_cam_rot,
|
|
.render_device_features = pp::panopainter::stroke_preview_render_device_features(),
|
|
.preview_rtt = preview.m_rtt,
|
|
.preview_rtt_mixer = preview.m_rtt_mixer,
|
|
.preview_stroke_texture = preview.m_tex,
|
|
.preview_dual_texture = preview.m_tex_dual,
|
|
.preview_background_texture = preview.m_tex_background,
|
|
.preview_image_texture = preview.m_tex_preview,
|
|
.linear_sampler = preview.m_sampler_linear,
|
|
.repeat_sampler = preview.m_sampler_linear_repeat,
|
|
.prepare_render_target = [&] {
|
|
pp::panopainter::apply_legacy_node_stroke_preview_viewport(
|
|
0,
|
|
0,
|
|
preview.m_rtt.getWidth(),
|
|
preview.m_rtt.getHeight());
|
|
preview.m_rtt.bindFramebuffer();
|
|
preview.m_rtt.clear();
|
|
pp::panopainter::bind_legacy_node_stroke_preview_live_samplers(
|
|
preview.m_sampler_mipmap,
|
|
preview.m_sampler_linear,
|
|
preview.m_sampler_linear_repeat);
|
|
},
|
|
.finish_render_target = [&] {
|
|
preview.m_rtt.unbindFramebuffer();
|
|
},
|
|
.compute_frames = [&](const Stroke& stroke, float frame_zoom) {
|
|
return plan_legacy_node_stroke_preview_stroke_frames(
|
|
stroke,
|
|
frame_zoom,
|
|
glm::vec2(preview.m_rtt.getWidth(), preview.m_rtt.getHeight()));
|
|
},
|
|
.draw_samples = [&](std::array<vertex_t, 4>& shapes, Texture2D& texture, bool copy_stroke_destination) {
|
|
return pp::panopainter::execute_legacy_node_stroke_preview_sample_pass(
|
|
preview.m_rtt,
|
|
shapes,
|
|
preview.m_brush_shape,
|
|
texture,
|
|
copy_stroke_destination);
|
|
},
|
|
.draw_mix = [&](const glm::vec2& bb_min, const glm::vec2& bb_sz) {
|
|
pp::panopainter::execute_legacy_node_stroke_preview_mix_pass(
|
|
*preview.m_brush,
|
|
preview.m_size,
|
|
preview.m_rtt_mixer,
|
|
bb_min,
|
|
bb_sz,
|
|
preview.m_sampler_linear,
|
|
preview.m_tex_background,
|
|
preview.m_tex,
|
|
preview.m_tex_dual,
|
|
[&] {
|
|
preview.m_plane.draw_fill();
|
|
});
|
|
},
|
|
.draw_checkerboard = [&] {
|
|
preview.m_plane.draw_fill();
|
|
},
|
|
.draw_composite = [&] {
|
|
preview.m_plane.draw_fill();
|
|
},
|
|
});
|
|
assert(sequence_ok);
|
|
return sequence_ok;
|
|
}
|
|
|
|
} // namespace pp::panopainter
|
|
|
|
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
|
std::atomic_bool NodeStrokePreview::s_running{ false };
|
|
std::mutex NodeStrokePreview::s_render_mutex;
|
|
BlockingQueue<std::shared_ptr<NodeStrokePreview>> NodeStrokePreview::s_queue;
|
|
|
|
RTT NodeStrokePreview::m_rtt;
|
|
RTT NodeStrokePreview::m_rtt_mixer;
|
|
Texture2D NodeStrokePreview::m_tex; // blending tmp texture
|
|
Texture2D NodeStrokePreview::m_tex_dual;
|
|
Texture2D NodeStrokePreview::m_tex_background;
|
|
Sampler NodeStrokePreview::m_sampler_linear;
|
|
Sampler NodeStrokePreview::m_sampler_linear_repeat;
|
|
Sampler NodeStrokePreview::m_sampler_mipmap;
|
|
DynamicShape NodeStrokePreview::m_brush_shape;
|
|
std::jthread NodeStrokePreview::s_renderer;
|
|
|
|
void NodeStrokePreview::terminate_renderer()
|
|
{
|
|
if (!s_renderer.joinable())
|
|
return;
|
|
|
|
s_running = false;
|
|
s_renderer.request_stop();
|
|
s_queue.UnlockGetters();
|
|
s_renderer.join();
|
|
}
|
|
|
|
void NodeStrokePreview::empty_queue()
|
|
{
|
|
s_queue.q.clear();
|
|
}
|
|
|
|
void NodeStrokePreview::restore_context()
|
|
{
|
|
NodeBorder::restore_context();
|
|
init_controls();
|
|
if (m_size.x > 0 && m_size.y > 0)
|
|
m_tex_preview.create(static_cast<int>(m_size.x), static_cast<int>(m_size.y));
|
|
draw_stroke();
|
|
}
|
|
|
|
void NodeStrokePreview::clear_context()
|
|
{
|
|
NodeBorder::clear_context();
|
|
m_tex_preview.destroy();
|
|
}
|
|
|
|
Image NodeStrokePreview::render_to_image()
|
|
{
|
|
std::lock_guard<std::mutex> _lock(s_render_mutex);
|
|
|
|
App::I->render_task([this] {
|
|
draw_stroke_immediate();
|
|
});
|
|
return m_tex_preview.get_image();
|
|
}
|
|
|
|
void NodeStrokePreview::draw_stroke()
|
|
{
|
|
if (m_size.x == 0 || m_size.y == 0)
|
|
return;
|
|
std::unique_lock<std::mutex> queue_lock(s_queue.mutex);
|
|
if (!s_renderer.joinable())
|
|
{
|
|
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()
|
|
{
|
|
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader(
|
|
pp::panopainter::LegacyCanvasDrawMergeTextureUniforms {
|
|
.mvp = m_mvp,
|
|
.texture_slot = 0,
|
|
});
|
|
m_tex_preview.bind();
|
|
m_sampler_linear.bind(0);
|
|
m_plane.draw_fill();
|
|
m_sampler_linear.unbind();
|
|
m_tex_preview.unbind();
|
|
}
|
|
|
|
void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom)
|
|
{
|
|
if (m_preview_size == (new_size * root()->m_zoom) || !m_brush)
|
|
return;
|
|
|
|
m_preview_size = new_size * root()->m_zoom;
|
|
|
|
if (m_on_screen)
|
|
draw_stroke();
|
|
}
|
|
|
|
void NodeStrokePreview::destroy()
|
|
{
|
|
m_tex_preview.destroy();
|
|
Node::destroy();
|
|
}
|
|
|
|
void NodeStrokePreview::handle_on_screen(bool old_visibility, bool new_visibility)
|
|
{
|
|
parent::handle_on_screen(old_visibility, new_visibility);
|
|
if (new_visibility)
|
|
{
|
|
draw_stroke();
|
|
}
|
|
else
|
|
{
|
|
s_queue.Remove(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()));
|
|
m_tex_preview.destroy();
|
|
}
|
|
}
|