Extract retained stroke preview setup planner

This commit is contained in:
2026-06-13 11:27:30 +02:00
parent 499747173b
commit 3ec4f25889
6 changed files with 232 additions and 28 deletions

View File

@@ -7,7 +7,9 @@
#include "paint_renderer/compositor.h"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <vector>
namespace pp::panopainter {
@@ -222,4 +224,98 @@ struct LegacyNodeStrokePreviewPassSequenceRequest {
return true;
}
struct LegacyNodeStrokePreviewStrokePoint {
glm::vec3 position {};
float pressure = 0.0f;
};
struct LegacyNodeStrokePreviewStrokeSetupPlan {
float stroke_max_size = 0.0f;
float dual_stroke_max_size = 0.0f;
bool dual_enabled = false;
glm::vec2 pattern_scale {};
std::vector<LegacyNodeStrokePreviewStrokePoint> points;
};
struct LegacyNodeStrokePreviewStrokeSetupRequest {
glm::vec2 preview_size {};
float zoom = 1.0f;
float brush_tip_size = 0.0f;
float stroke_max_size_override = 0.0f;
float pad_override = NAN;
bool tip_size_pressure = false;
bool dual_enabled = false;
float dual_size = 1.0f;
float pattern_scale = 0.0f;
bool pattern_flipx = false;
bool pattern_flipy = false;
int preview_point_count = 100;
};
[[nodiscard]] inline glm::vec2 evaluate_legacy_node_stroke_preview_bezier(
std::vector<glm::vec2> control_points,
float t) noexcept
{
if (control_points.empty()) {
return {};
}
for (std::size_t remaining = control_points.size(); remaining > 1; --remaining) {
for (std::size_t i = 0; i + 1 < remaining; ++i) {
control_points[i] = glm::mix(control_points[i], control_points[i + 1], t);
}
}
return control_points.front();
}
[[nodiscard]] inline LegacyNodeStrokePreviewStrokeSetupPlan plan_legacy_node_stroke_preview_stroke_setup(
const LegacyNodeStrokePreviewStrokeSetupRequest& request) noexcept
{
LegacyNodeStrokePreviewStrokeSetupPlan plan;
plan.stroke_max_size = request.stroke_max_size_override > 0.0f ?
request.stroke_max_size_override :
request.preview_size.y * 0.75f;
plan.dual_enabled = request.dual_enabled;
plan.dual_stroke_max_size = plan.stroke_max_size * request.dual_size;
plan.pattern_scale = glm::vec2(request.pattern_scale);
if (request.pattern_flipx) {
plan.pattern_scale.x *= -1.0f;
}
if (request.pattern_flipy) {
plan.pattern_scale.y *= -1.0f;
}
const float min_pad = request.preview_size.x * 0.05f;
float pad = (5.0f + glm::max(glm::min(plan.stroke_max_size, request.brush_tip_size) / 2.0f, min_pad)) * request.zoom;
if (request.tip_size_pressure) {
pad = min_pad * request.zoom;
}
if (!std::isnan(request.pad_override)) {
pad = request.pad_override;
}
const float width = request.preview_size.x * request.zoom;
const float height = request.preview_size.y * request.zoom;
const std::vector<glm::vec2> keypoints {
{ pad, height / 2.0f },
{ width / 2.0f, 0.0f },
{ width / 2.0f, height },
{ width - pad, height / 2.0f },
};
const int point_count = std::max(request.preview_point_count, 0);
plan.points.reserve(static_cast<std::size_t>(point_count));
for (int i = 0; i < point_count; ++i) {
const float t = static_cast<float>(i) / static_cast<float>(point_count);
const float pressure = glm::clamp((1.0f - glm::abs(t * 2.0f - 1.0f)) * 1.1f, 0.0f, 1.0f);
plan.points.push_back(LegacyNodeStrokePreviewStrokePoint {
.position = glm::vec3(evaluate_legacy_node_stroke_preview_bezier(keypoints, t), 0.0f),
.pressure = pressure,
});
}
return plan;
}
} // namespace pp::panopainter