10#include "ImGuiCurveEditor.h"
14#define IMGUI_DEFINE_MATH_OPERATORS
15#include "imgui_internal.h"
46int Curve(
const char *label,
const ImVec2 &size,
int maxpoints, ImVec2 *points);
47float CurveValue(
float p,
int maxpoints,
const ImVec2 *points);
48float CurveValueSmooth(
float p,
int maxpoints,
const ImVec2 *points);
102static inline double ease(
int easetype,
double t)
105 const double d = 1.f;
106 const double pi = 3.1415926535897932384626433832795;
107 const double pi2 = 3.1415926535897932384626433832795 / 2;
128 return -(p * (p - 2));
134 case TYPE::QUADINOUT:
143 return (-2 * p * p) + (4 * p) - 1;
157 return f * f * f + 1;
163 case TYPE::CUBICINOUT:
167 return 4 * p * p * p;
172 double f = ((2 * p) - 2);
173 return 0.5 * f * f * f + 1;
180 return p * p * p * p;
187 return f * f * f * (1 - p) + 1;
193 case TYPE::QUARTINOUT:
197 return 8 * p * p * p * p;
203 return -8 * f * f * f * f + 1;
210 return p * p * p * p * p;
217 return f * f * f * f * f + 1;
223 case TYPE::QUINTINOUT:
227 return 16 * p * p * p * p * p;
232 double f = ((2 * p) - 2);
233 return 0.5 * f * f * f * f * f + 1;
240 return sin((p - 1) * pi2) + 1;
250 case TYPE::SINEINOUT:
252 return 0.5 * (1 - cos(p * pi));
258 return 1 - sqrt(1 - (p * p));
264 return sqrt((2 - p) * p);
270 case TYPE::CIRCINOUT:
274 return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
279 return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
286 return (p == 0.0) ? p : pow(2, 10 * (p - 1));
292 return (p == 1.0) ? p : 1 - pow(2, -10 * p);
298 case TYPE::EXPOINOUT:
300 if (p == 0.0 || p == 1.0)
307 return 0.5 * pow(2, (20 * p) - 10);
312 return -0.5 * pow(2, (-20 * p) + 10) + 1;
317 case TYPE::ELASTICIN:
319 return sin(13 * pi2 * p) * pow(2, 10 * (p - 1));
323 case TYPE::ELASTICOUT:
325 return sin(-13 * pi2 * (p + 1)) * pow(2, -10 * p) + 1;
331 case TYPE::ELASTICINOUT:
335 return 0.5 * sin(13 * pi2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1));
340 return 0.5 * (sin(-13 * pi2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2);
350 return p * p * ((s + 1) * p - s);
360 return --p, 1.f * (p * p * ((s + 1) * p + s) + 1);
366 case TYPE::BACKINOUT:
377 double s = 1.70158f * 1.525f;
381 return p *= 2, 0.5 * p * p * (p * s + p - s);
386 return p = p * 2 - 2, 0.5 * (2 + p * p * (p * s + p + s));
390#define tween$bounceout(p) \
391((p) < 4 / 11.0 ? (121 * (p) * (p)) / 16.0 \
392: (p) < 8 / 11.0 ? (363 / 40.0 * (p) * (p)) - (99 / 10.0 * (p)) + 17 / 5.0 \
393: (p) < 9 / 10.0 ? (4356 / 361.0 * (p) * (p)) - (35442 / 1805.0 * (p)) + 16061 / 1805.0 \
394 : (54 / 5.0 * (p) * (p)) - (513 / 25.0 * (p)) + 268 / 25.0)
398 return 1 - tween$bounceout(1 - p);
401 case TYPE::BOUNCEOUT:
403 return tween$bounceout(p);
406 case TYPE::BOUNCEINOUT:
410 return 0.5 * (1 - tween$bounceout(1 - p * 2));
415 return 0.5 * tween$bounceout((p * 2 - 1)) + 0.5;
419#undef tween$bounceout
421 case TYPE::SINESQUARE:
423 double A = sin((p)*pi2);
427 case TYPE::EXPONENTIAL:
429 return 1 / (1 + exp(6 - 12 * (p)));
432 case TYPE::SCHUBRING1:
434 return 2 * (p + (0.5f - p) * abs(0.5f - p)) - 0.5f;
437 case TYPE::SCHUBRING2:
439 double p1pass = 2 * (p + (0.5f - p) * abs(0.5f - p)) - 0.5f;
440 double p2pass = 2 * (p1pass + (0.5f - p1pass) * abs(0.5f - p1pass)) - 0.5f;
441 double pAvg = (p1pass + p2pass) / 2;
445 case TYPE::SCHUBRING3:
447 double p1pass = 2 * (p + (0.5f - p) * abs(0.5f - p)) - 0.5f;
448 double p2pass = 2 * (p1pass + (0.5f - p1pass) * abs(0.5f - p1pass)) - 0.5f;
454 return ((-cos(pi * p) * 0.5) + 0.5);
471void spline(
const float *key,
int num,
int dim,
float t,
float *v)
473 static signed char coefs[16] = { -1, 2, -1, 0, 3, -5, 0, 2, -3, 4, 1, 0, 1, -1, 0, 0 };
474 const int size = dim + 1;
478 while (key[k * size] < t)
484 const float h = (t -
key[(k - 1) * size]) / (
key[k * size] -
key[(k - 1) * size]);
487 for (
int i = 0; i < dim; i++)
493 for (
int i = 0; i < 4; i++)
502 else if (kn > (num - 1))
507 const signed char *co = coefs + 4 * i;
508 const float b = 0.5f * (((co[0] * h + co[1]) * h + co[2]) * h + co[3]);
510 for (
int j = 0; j < dim; j++)
512 v[j] += b *
key[kn * size + j + 1];
517float CurveValueSmooth(
float p,
int maxpoints,
const ImVec2 *points)
519 if (maxpoints < 2 || points == 0)
529 float *input =
new float[maxpoints * 2];
532 for (
int i = 0; i < maxpoints; ++i)
534 input[i * 2 + 0] = points[i].x;
535 input[i * 2 + 1] = points[i].y;
538 spline(input, maxpoints, 1, p, output);
543float CurveValue(
float p,
int maxpoints,
const ImVec2 *points)
545 if (maxpoints < 2 || points == 0)
557 while (left < maxpoints && points[left].x < p && points[left].x != -1)
567 if (left == maxpoints - 1)
569 return points[maxpoints - 1].y;
572 float d = (p - points[left].x) / (points[left + 1].x - points[left].x);
573 return points[left].y + (points[left + 1].y - points[left].y) * d;
576int Curve(
const char *label,
const ImVec2 &size,
const int maxpoints, ImVec2 *points)
581 if (maxpoints < 2 || points == 0)
595 ImGuiWindow *window = GetCurrentWindow();
596 ImGuiContext &g = *GImGui;
597 const ImGuiStyle &style = g.Style;
598 const ImGuiID
id = window->GetID(label);
600 if (window->SkipItems)
605 ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
608 if (!ItemAdd(bb, NULL))
613 const bool hovered = ImGui::ItemHoverable(bb,
id);
616 while (max < maxpoints && points[max].x >= 0)
629 for (i = kill + 1; i < max; i++)
631 points[i - 1] = points[i];
639 for (i = 1; i < max - 1; i++)
641 if (abs(points[i].x - points[i - 1].x) < 1 / 128.0)
649 RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg, 1),
true, style.FrameRounding);
650 float ht = bb.Max.y - bb.Min.y;
651 float wd = bb.Max.x - bb.Min.x;
657 if (g.IO.MouseDown[0])
660 ImVec2 pos = (g.IO.MousePos - bb.Min) / (bb.Max - bb.Min);
664 while (left < max && points[left].x < pos.x)
674 ImVec2 p = points[left] - pos;
675 float p1d = sqrt(p.x * p.x + p.y * p.y);
676 p = points[left + 1] - pos;
677 float p2d = sqrt(p.x * p.x + p.y * p.y);
680 if (p1d < (1 / 16.0))
685 if (p2d < (1 / 16.0))
701 for (i = max; i > left; i--)
703 points[i] = points[i - 1];
706 points[left + 1] = pos;
716 if (points[0].x < points[max - 1].x)
719 points[max - 1].x = 1;
725 points[max - 1].x = 0;
731 window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ht / 2), ImVec2(bb.Max.x, bb.Min.y + ht / 2),
732 GetColorU32(ImGuiCol_TextDisabled), 3);
733 window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ht / 4), ImVec2(bb.Max.x, bb.Min.y + ht / 4),
734 GetColorU32(ImGuiCol_TextDisabled));
735 window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y + ht / 4 * 3), ImVec2(bb.Max.x, bb.Min.y + ht / 4 * 3),
736 GetColorU32(ImGuiCol_TextDisabled));
738 for (i = 0; i < 9; i++)
740 window->DrawList->AddLine(ImVec2(bb.Min.x + (wd / 10) * (i + 1), bb.Min.y),
741 ImVec2(bb.Min.x + (wd / 10) * (i + 1), bb.Max.y), GetColorU32(ImGuiCol_TextDisabled));
750 for (i = 0; i <= (smoothness - 1); ++i)
752 float px = (i + 0) /
float(smoothness);
753 float qx = (i + 1) /
float(smoothness);
754 float py = 1 - CurveValueSmooth(px, maxpoints, points);
755 float qy = 1 - CurveValueSmooth(qx, maxpoints, points);
756 ImVec2 p(px * (bb.Max.x - bb.Min.x) + bb.Min.x, py * (bb.Max.y - bb.Min.y) + bb.Min.y);
757 ImVec2 q(qx * (bb.Max.x - bb.Min.x) + bb.Min.x, qy * (bb.Max.y - bb.Min.y) + bb.Min.y);
758 window->DrawList->AddLine(p, q, GetColorU32(ImGuiCol_PlotLines));
762 for (i = 1; i < max; i++)
764 ImVec2 a = points[i - 1];
765 ImVec2 b = points[i];
768 a = a * (bb.Max - bb.Min) + bb.Min;
769 b = b * (bb.Max - bb.Min) + bb.Min;
770 window->DrawList->AddLine(a, b, GetColorU32(ImGuiCol_PlotLinesHovered));
776 for (i = 0; i < max; i++)
778 ImVec2 p = points[i];
780 p = p * (bb.Max - bb.Min) + bb.Min;
781 ImVec2 a = p - ImVec2(2, 2);
782 ImVec2 b = p + ImVec2(2, 2);
783 window->DrawList->AddRect(a, b, GetColorU32(ImGuiCol_PlotLinesHovered));
788 if (ImGui::Button(
"Flip"))
790 for (i = 0; i < max; ++i)
792 points[i].y = 1 - points[i].y;
798 const char *items[] = {
"Custom",
800 "Linear",
"Quad in",
"Quad out",
"Quad in out",
"Cubic in",
"Cubic out",
801 "Cubic in out",
"Quart in",
"Quart out",
"Quart in out",
"Quint in",
"Quint out",
802 "Quint in out",
"Sine in",
"Sine out",
"Sine in out",
"Expo in",
"Expo out",
803 "Expo in out",
"Circ in",
"Circ out",
"Circ in out",
"Elastic in",
"Elastic out",
804 "Elastic in out",
"Back in",
"Back out",
"Back in out",
"Bounce in",
"Bounce out",
807 "Sine square",
"Exponential",
809 "Schubring1",
"Schubring2",
"Schubring3",
835 const char *str = label;
839 ImVec2 pos = (g.IO.MousePos - bb.Min) / (bb.Max - bb.Min);
841 sprintf(buf,
"%s (%f,%f)", label, pos.x, pos.y);
845 RenderTextClipped(ImVec2(bb.Min.x, bb.Min.y + style.FramePadding.y), bb.Max, str, NULL, NULL, ImVec2(0.5f, 0.5f));
@ key
the parser read a key of a value in an object