Add curve visualization back, guard eval
Editing curves is still cumbersome, but that's fine. Visualization is just for feedback (and imgui's path renderer is a little wonky), but this helps a bit. Bug: skia: Change-Id: I3dace6d822d472314513bb1ad72bcea1e8991b77 Reviewed-on: https://skia-review.googlesource.com/c/192828 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
5f5a016b1b
commit
112aa2d22e
@ -39,6 +39,7 @@ struct SkCurve {
|
||||
|
||||
SkScalar eval(SkScalar x, SkRandom& random) const;
|
||||
void visitFields(SkFieldVisitor* v);
|
||||
void getExtents(SkScalar extents[2]) const;
|
||||
|
||||
SkTArray<SkScalar, true> fXValues;
|
||||
SkTArray<SkCurveSegment, true> fSegments;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define SkReflected_DEFINED
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkCurve.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkString.h"
|
||||
#include "SkTArray.h"
|
||||
@ -118,6 +119,12 @@ public:
|
||||
virtual void visit(const char*, SkPoint&, SkField = SkField()) = 0;
|
||||
virtual void visit(const char*, SkColor4f&, SkField = SkField()) = 0;
|
||||
|
||||
virtual void visit(const char* name, SkCurve& c, SkField = SkField()) {
|
||||
this->enterObject(name);
|
||||
c.visitFields(this);
|
||||
this->exitObject();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void visit(const char* name, T& value) {
|
||||
this->enterObject(name);
|
||||
|
@ -53,6 +53,9 @@ SkScalar SkCurve::eval(SkScalar x, SkRandom& random) const {
|
||||
SkScalar rangeMin = (i == 0) ? 0.0f : fXValues[i - 1];
|
||||
SkScalar rangeMax = (i == fXValues.count()) ? 1.0f : fXValues[i];
|
||||
SkScalar segmentX = (x - rangeMin) / (rangeMax - rangeMin);
|
||||
if (!SkScalarIsFinite(segmentX)) {
|
||||
segmentX = rangeMin;
|
||||
}
|
||||
SkASSERT(0.0f <= segmentX && segmentX <= 1.0f);
|
||||
return fSegments[i].eval(segmentX, random);
|
||||
}
|
||||
@ -70,3 +73,20 @@ void SkCurve::visitFields(SkFieldVisitor* v) {
|
||||
fXValues[i] = SkTPin(fXValues[i], i > 0 ? fXValues[i - 1] : 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SkCurve::getExtents(SkScalar extents[2]) const {
|
||||
extents[0] = INFINITY;
|
||||
extents[1] = -INFINITY;
|
||||
auto extend = [=](SkScalar y) {
|
||||
extents[0] = SkTMin(extents[0], y);
|
||||
extents[1] = SkTMax(extents[1], y);
|
||||
};
|
||||
for (const auto& segment : fSegments) {
|
||||
for (int i = 0; i < (segment.fConstant ? 1 : 4); ++i) {
|
||||
extend(segment.fMin[i]);
|
||||
if (segment.fRanged) {
|
||||
extend(segment.fMax[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "ParticlesSlide.h"
|
||||
|
||||
#include "ImGuiLayer.h"
|
||||
#include "SkParticleAffector.h"
|
||||
#include "SkParticleEffect.h"
|
||||
#include "SkParticleEmitter.h"
|
||||
@ -38,55 +39,6 @@ static int InputTextCallback(ImGuiInputTextCallbackData* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static ImVec2 map_point(float x, float y, ImVec2 pos, ImVec2 size, float yMin, float yMax) {
|
||||
// Turn y into 0 - 1 value
|
||||
float yNorm = 1.0f - ((y - yMin) / (yMax - yMin));
|
||||
return ImVec2(pos.x + size.x * x, pos.y + size.y * yNorm);
|
||||
}
|
||||
|
||||
static void ImGui_DrawCurve(SkScalar* pts) {
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
// Fit our image/canvas to the available width, and scale the height to maintain aspect ratio.
|
||||
float canvasWidth = SkTMax(ImGui::GetContentRegionAvailWidth(), 50.0f);
|
||||
ImVec2 size = ImVec2(canvasWidth, canvasWidth);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
// Background rectangle
|
||||
drawList->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(0, 0, 0, 128));
|
||||
|
||||
// Determine min/max extents
|
||||
float yMin = pts[0], yMax = pts[0];
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
yMin = SkTMin(yMin, pts[i]);
|
||||
yMax = SkTMax(yMax, pts[i]);
|
||||
}
|
||||
|
||||
// Grow the extents by 10%, at least 1.0f
|
||||
float grow = SkTMax((yMax - yMin) * 0.1f, 1.0f);
|
||||
|
||||
yMin -= grow;
|
||||
yMax += grow;
|
||||
|
||||
ImVec2 a = map_point(0.0f , pts[0], pos, size, yMin, yMax),
|
||||
b = map_point(1 / 3.0f, pts[1], pos, size, yMin, yMax),
|
||||
c = map_point(2 / 3.0f, pts[2], pos, size, yMin, yMax),
|
||||
d = map_point(1.0f , pts[3], pos, size, yMin, yMax);
|
||||
|
||||
drawList->AddBezierCurve(a, b, c, d, IM_COL32(255, 255, 255, 255), 1.0f);
|
||||
|
||||
// Draw markers
|
||||
drawList->AddCircle(a, 5.0f, 0xFFFFFFFF);
|
||||
drawList->AddCircle(b, 5.0f, 0xFFFFFFFF);
|
||||
drawList->AddCircle(c, 5.0f, 0xFFFFFFFF);
|
||||
drawList->AddCircle(d, 5.0f, 0xFFFFFFFF);
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(pos.x, pos.y + size.y));
|
||||
ImGui::Spacing();
|
||||
}
|
||||
#endif
|
||||
|
||||
class SkGuiVisitor : public SkFieldVisitor {
|
||||
public:
|
||||
SkGuiVisitor() {
|
||||
@ -130,22 +82,58 @@ public:
|
||||
|
||||
#undef IF_OPEN
|
||||
|
||||
/*
|
||||
void visit(const char* name, SkCurve& c, SkField) override {
|
||||
this->enterObject(item(name));
|
||||
if (fTreeStack.back()) {
|
||||
ImGui::Checkbox("Ranged", &c.fRanged);
|
||||
ImGui::DragFloat4("Min", c.fMin);
|
||||
ImGui_DrawCurve(c.fMin);
|
||||
if (c.fRanged) {
|
||||
ImGui::DragFloat4("Max", c.fMax);
|
||||
ImGui_DrawCurve(c.fMax);
|
||||
}
|
||||
// Get vertical extents of the curve
|
||||
SkScalar extents[2];
|
||||
c.getExtents(extents);
|
||||
|
||||
// Grow the extents by 10%, at least 1.0f
|
||||
SkScalar grow = SkTMax((extents[1] - extents[0]) * 0.1f, 1.0f);
|
||||
extents[0] -= grow;
|
||||
extents[1] += grow;
|
||||
|
||||
{
|
||||
ImGui::DragCanvas dc(&c, { 0.0f, extents[1] }, { 1.0f, extents[0] }, 0.5f);
|
||||
dc.fillColor(IM_COL32(0, 0, 0, 128));
|
||||
|
||||
for (int i = 0; i < c.fSegments.count(); ++i) {
|
||||
SkSTArray<8, ImVec2, true> pts;
|
||||
SkScalar rangeMin = (i == 0) ? 0.0f : c.fXValues[i - 1];
|
||||
SkScalar rangeMax = (i == c.fXValues.count()) ? 1.0f : c.fXValues[i];
|
||||
auto screenPoint = [&](int idx, bool useMax) {
|
||||
SkScalar xVal = rangeMin + (idx / 3.0f) * (rangeMax - rangeMin);
|
||||
SkScalar* yVals = useMax ? c.fSegments[i].fMax : c.fSegments[i].fMin;
|
||||
SkScalar yVal = yVals[c.fSegments[i].fConstant ? 0 : idx];
|
||||
SkPoint pt = dc.fLocalToScreen.mapXY(xVal, yVal);
|
||||
return ImVec2(pt.fX, pt.fY);
|
||||
};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
pts.push_back(screenPoint(i, false));
|
||||
}
|
||||
if (c.fSegments[i].fRanged) {
|
||||
for (int i = 3; i >= 0; --i) {
|
||||
pts.push_back(screenPoint(i, true));
|
||||
}
|
||||
}
|
||||
|
||||
if (c.fSegments[i].fRanged) {
|
||||
dc.fDrawList->PathLineTo(pts[0]);
|
||||
dc.fDrawList->PathBezierCurveTo(pts[1], pts[2], pts[3]);
|
||||
dc.fDrawList->PathLineTo(pts[4]);
|
||||
dc.fDrawList->PathBezierCurveTo(pts[5], pts[6], pts[7]);
|
||||
dc.fDrawList->PathFillConvex(IM_COL32(255, 255, 255, 128));
|
||||
} else {
|
||||
dc.fDrawList->AddBezierCurve(pts[0], pts[1], pts[2], pts[3],
|
||||
IM_COL32(255, 255, 255, 255), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
c.visitFields(this);
|
||||
}
|
||||
this->exitObject();
|
||||
}
|
||||
*/
|
||||
|
||||
void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
|
||||
if (fTreeStack.back()) {
|
||||
|
Loading…
Reference in New Issue
Block a user