TerraForge3D  2.3.1
3D Terrain And Landscape Generator
ImGuiCurveEditor.cpp
1// [src] https://github.com/ocornut/imgui/issues/123
2// [src] https://github.com/ocornut/imgui/issues/55
3
4// v1.22 - flip button; cosmetic fixes
5// v1.21 - oops :)
6// v1.20 - add iq's interpolation code
7// v1.10 - easing and colors
8// v1.00 - jari komppa's original
9
10#include "ImGuiCurveEditor.h"
11
12#include "imgui.h"
13
14#define IMGUI_DEFINE_MATH_OPERATORS
15#include "imgui_internal.h"
16
17#include <cmath>
18
19/* To use, add this prototype somewhere..
20
21namespace ImGui
22{
23 int Curve(const char *label, const ImVec2& size, int maxpoints, ImVec2 *points);
24 float CurveValue(float p, int maxpoints, const ImVec2 *points);
25 float CurveValueSmooth(float p, int maxpoints, const ImVec2 *points);
26};
27
28*/
29/*
30 Example of use:
31
32 ImVec2 foo[10];
33 ...
34 foo[0].x = -1; // init data so editor knows to take it from here
35 ...
36 if (ImGui::Curve("Das editor", ImVec2(600, 200), 10, foo))
37 {
38 // curve changed
39 }
40 ...
41 float value_you_care_about = ImGui::CurveValue(0.7f, 10, foo); // calculate value at position 0.7
42*/
43
44namespace ImGui
45{
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);
49}; // namespace ImGui
50
51namespace tween
52{
53enum TYPE
54{
55 LINEAR,
56
57 QUADIN, // t^2
58 QUADOUT,
59 QUADINOUT,
60 CUBICIN, // t^3
61 CUBICOUT,
62 CUBICINOUT,
63 QUARTIN, // t^4
64 QUARTOUT,
65 QUARTINOUT,
66 QUINTIN, // t^5
67 QUINTOUT,
68 QUINTINOUT,
69 SINEIN, // sin(t)
70 SINEOUT,
71 SINEINOUT,
72 EXPOIN, // 2^t
73 EXPOOUT,
74 EXPOINOUT,
75 CIRCIN, // sqrt(1-t^2)
76 CIRCOUT,
77 CIRCINOUT,
78 ELASTICIN, // exponentially decaying sine wave
79 ELASTICOUT,
80 ELASTICINOUT,
81 BACKIN, // overshooting cubic easing: (s+1)*t^3 - s*t^2
82 BACKOUT,
83 BACKINOUT,
84 BOUNCEIN, // exponentially decaying parabolic bounce
85 BOUNCEOUT,
86 BOUNCEINOUT,
87
88 SINESQUARE, // gapjumper's
89 EXPONENTIAL, // gapjumper's
90 SCHUBRING1, // terry schubring's formula 1
91 SCHUBRING2, // terry schubring's formula 2
92 SCHUBRING3, // terry schubring's formula 3
93
94 SINPI2, // tomas cepeda's
95 SWING, // tomas cepeda's & lquery's
96};
97
98// }
99
100// implementation
101
102static inline double ease(int easetype, double t)
103{
104 using namespace std;
105 const double d = 1.f;
106 const double pi = 3.1415926535897932384626433832795;
107 const double pi2 = 3.1415926535897932384626433832795 / 2;
108 double p = t / d;
109
110 switch (easetype)
111 {
112 // Modeled after the line y = x
113 default:
114 case TYPE::LINEAR:
115 {
116 return p;
117 }
118
119 // Modeled after the parabola y = x^2
120 case TYPE::QUADIN:
121 {
122 return p * p;
123 }
124
125 // Modeled after the parabola y = -x^2 + 2x
126 case TYPE::QUADOUT:
127 {
128 return -(p * (p - 2));
129 }
130
131 // Modeled after the piecewise quadratic
132 // y = (1/2)((2x)^2) ; [0, 0.5)
133 // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
134 case TYPE::QUADINOUT:
135 {
136 if (p < 0.5)
137 {
138 return 2 * p * p;
139 }
140
141 else
142 {
143 return (-2 * p * p) + (4 * p) - 1;
144 }
145 }
146
147 // Modeled after the cubic y = x^3
148 case TYPE::CUBICIN:
149 {
150 return p * p * p;
151 }
152
153 // Modeled after the cubic y = (x - 1)^3 + 1
154 case TYPE::CUBICOUT:
155 {
156 double f = (p - 1);
157 return f * f * f + 1;
158 }
159
160 // Modeled after the piecewise cubic
161 // y = (1/2)((2x)^3) ; [0, 0.5)
162 // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
163 case TYPE::CUBICINOUT:
164 {
165 if (p < 0.5)
166 {
167 return 4 * p * p * p;
168 }
169
170 else
171 {
172 double f = ((2 * p) - 2);
173 return 0.5 * f * f * f + 1;
174 }
175 }
176
177 // Modeled after the quartic x^4
178 case TYPE::QUARTIN:
179 {
180 return p * p * p * p;
181 }
182
183 // Modeled after the quartic y = 1 - (x - 1)^4
184 case TYPE::QUARTOUT:
185 {
186 double f = (p - 1);
187 return f * f * f * (1 - p) + 1;
188 }
189
190 // Modeled after the piecewise quartic
191 // y = (1/2)((2x)^4) ; [0, 0.5)
192 // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
193 case TYPE::QUARTINOUT:
194 {
195 if (p < 0.5)
196 {
197 return 8 * p * p * p * p;
198 }
199
200 else
201 {
202 double f = (p - 1);
203 return -8 * f * f * f * f + 1;
204 }
205 }
206
207 // Modeled after the quintic y = x^5
208 case TYPE::QUINTIN:
209 {
210 return p * p * p * p * p;
211 }
212
213 // Modeled after the quintic y = (x - 1)^5 + 1
214 case TYPE::QUINTOUT:
215 {
216 double f = (p - 1);
217 return f * f * f * f * f + 1;
218 }
219
220 // Modeled after the piecewise quintic
221 // y = (1/2)((2x)^5) ; [0, 0.5)
222 // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
223 case TYPE::QUINTINOUT:
224 {
225 if (p < 0.5)
226 {
227 return 16 * p * p * p * p * p;
228 }
229
230 else
231 {
232 double f = ((2 * p) - 2);
233 return 0.5 * f * f * f * f * f + 1;
234 }
235 }
236
237 // Modeled after quarter-cycle of sine wave
238 case TYPE::SINEIN:
239 {
240 return sin((p - 1) * pi2) + 1;
241 }
242
243 // Modeled after quarter-cycle of sine wave (different phase)
244 case TYPE::SINEOUT:
245 {
246 return sin(p * pi2);
247 }
248
249 // Modeled after half sine wave
250 case TYPE::SINEINOUT:
251 {
252 return 0.5 * (1 - cos(p * pi));
253 }
254
255 // Modeled after shifted quadrant IV of unit circle
256 case TYPE::CIRCIN:
257 {
258 return 1 - sqrt(1 - (p * p));
259 }
260
261 // Modeled after shifted quadrant II of unit circle
262 case TYPE::CIRCOUT:
263 {
264 return sqrt((2 - p) * p);
265 }
266
267 // Modeled after the piecewise circular function
268 // y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
269 // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
270 case TYPE::CIRCINOUT:
271 {
272 if (p < 0.5)
273 {
274 return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
275 }
276
277 else
278 {
279 return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
280 }
281 }
282
283 // Modeled after the exponential function y = 2^(10(x - 1))
284 case TYPE::EXPOIN:
285 {
286 return (p == 0.0) ? p : pow(2, 10 * (p - 1));
287 }
288
289 // Modeled after the exponential function y = -2^(-10x) + 1
290 case TYPE::EXPOOUT:
291 {
292 return (p == 1.0) ? p : 1 - pow(2, -10 * p);
293 }
294
295 // Modeled after the piecewise exponential
296 // y = (1/2)2^(10(2x - 1)) ; [0,0.5)
297 // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
298 case TYPE::EXPOINOUT:
299 {
300 if (p == 0.0 || p == 1.0)
301 {
302 return p;
303 }
304
305 if (p < 0.5)
306 {
307 return 0.5 * pow(2, (20 * p) - 10);
308 }
309
310 else
311 {
312 return -0.5 * pow(2, (-20 * p) + 10) + 1;
313 }
314 }
315
316 // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
317 case TYPE::ELASTICIN:
318 {
319 return sin(13 * pi2 * p) * pow(2, 10 * (p - 1));
320 }
321
322 // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
323 case TYPE::ELASTICOUT:
324 {
325 return sin(-13 * pi2 * (p + 1)) * pow(2, -10 * p) + 1;
326 }
327
328 // Modeled after the piecewise exponentially-damped sine wave:
329 // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
330 // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
331 case TYPE::ELASTICINOUT:
332 {
333 if (p < 0.5)
334 {
335 return 0.5 * sin(13 * pi2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1));
336 }
337
338 else
339 {
340 return 0.5 * (sin(-13 * pi2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2);
341 }
342 }
343
344 // Modeled (originally) after the overshooting cubic y = x^3-x*sin(x*pi)
345 case TYPE::BACKIN:
346 {
347 /*
348 return p * p * p - p * sin(p * pi); */
349 double s = 1.70158f;
350 return p * p * ((s + 1) * p - s);
351 }
352
353 // Modeled (originally) after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
354 case TYPE::BACKOUT:
355 {
356 /*
357 double f = (1 - p);
358 return 1 - (f * f * f - f * sin(f * pi)); */
359 double s = 1.70158f;
360 return --p, 1.f * (p * p * ((s + 1) * p + s) + 1);
361 }
362
363 // Modeled (originally) after the piecewise overshooting cubic function:
364 // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
365 // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
366 case TYPE::BACKINOUT:
367 {
368 /*
369 if(p < 0.5) {
370 double f = 2 * p;
371 return 0.5 * (f * f * f - f * sin(f * pi));
372 }
373 else {
374 double f = (1 - (2*p - 1));
375 return 0.5 * (1 - (f * f * f - f * sin(f * pi))) + 0.5;
376 } */
377 double s = 1.70158f * 1.525f;
378
379 if (p < 0.5)
380 {
381 return p *= 2, 0.5 * p * p * (p * s + p - s);
382 }
383
384 else
385 {
386 return p = p * 2 - 2, 0.5 * (2 + p * p * (p * s + p + s));
387 }
388 }
389
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)
395
396 case TYPE::BOUNCEIN:
397 {
398 return 1 - tween$bounceout(1 - p);
399 }
400
401 case TYPE::BOUNCEOUT:
402 {
403 return tween$bounceout(p);
404 }
405
406 case TYPE::BOUNCEINOUT:
407 {
408 if (p < 0.5)
409 {
410 return 0.5 * (1 - tween$bounceout(1 - p * 2));
411 }
412
413 else
414 {
415 return 0.5 * tween$bounceout((p * 2 - 1)) + 0.5;
416 }
417 }
418
419#undef tween$bounceout
420
421 case TYPE::SINESQUARE:
422 {
423 double A = sin((p)*pi2);
424 return A * A;
425 }
426
427 case TYPE::EXPONENTIAL:
428 {
429 return 1 / (1 + exp(6 - 12 * (p)));
430 }
431
432 case TYPE::SCHUBRING1:
433 {
434 return 2 * (p + (0.5f - p) * abs(0.5f - p)) - 0.5f;
435 }
436
437 case TYPE::SCHUBRING2:
438 {
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;
442 return pAvg;
443 }
444
445 case TYPE::SCHUBRING3:
446 {
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;
449 return p2pass;
450 }
451
452 case TYPE::SWING:
453 {
454 return ((-cos(pi * p) * 0.5) + 0.5);
455 }
456
457 case TYPE::SINPI2:
458 {
459 return sin(p * pi2);
460 }
461 }
462}
463} // namespace tween
464
465namespace ImGui
466{
467// [src] http://iquilezles.org/www/articles/minispline/minispline.htm
468// key format (for dim == 1) is (t0,x0,t1,x1 ...)
469// key format (for dim == 2) is (t0,x0,y0,t1,x1,y1 ...)
470// key format (for dim == 3) is (t0,x0,y0,z0,t1,x1,y1,z1 ...)
471void spline(const float *key, int num, int dim, float t, float *v)
472{
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;
475 // find key
476 int k = 0;
477
478 while (key[k * size] < t)
479 {
480 k++;
481 }
482
483 // interpolant
484 const float h = (t - key[(k - 1) * size]) / (key[k * size] - key[(k - 1) * size]);
485
486 // init result
487 for (int i = 0; i < dim; i++)
488 {
489 v[i] = 0.0f;
490 }
491
492 // add basis functions
493 for (int i = 0; i < 4; i++)
494 {
495 int kn = k + i - 2;
496
497 if (kn < 0)
498 {
499 kn = 0;
500 }
501
502 else if (kn > (num - 1))
503 {
504 kn = num - 1;
505 }
506
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]);
509
510 for (int j = 0; j < dim; j++)
511 {
512 v[j] += b * key[kn * size + j + 1];
513 }
514 }
515}
516
517float CurveValueSmooth(float p, int maxpoints, const ImVec2 *points)
518{
519 if (maxpoints < 2 || points == 0)
520 {
521 return 0;
522 }
523
524 if (p < 0)
525 {
526 return points[0].y;
527 }
528
529 float *input = new float[maxpoints * 2];
530 float output[4];
531
532 for (int i = 0; i < maxpoints; ++i)
533 {
534 input[i * 2 + 0] = points[i].x;
535 input[i * 2 + 1] = points[i].y;
536 }
537
538 spline(input, maxpoints, 1, p, output);
539 delete[] input;
540 return output[0];
541}
542
543float CurveValue(float p, int maxpoints, const ImVec2 *points)
544{
545 if (maxpoints < 2 || points == 0)
546 {
547 return 0;
548 }
549
550 if (p < 0)
551 {
552 return points[0].y;
553 }
554
555 int left = 0;
556
557 while (left < maxpoints && points[left].x < p && points[left].x != -1)
558 {
559 left++;
560 }
561
562 if (left)
563 {
564 left--;
565 }
566
567 if (left == maxpoints - 1)
568 {
569 return points[maxpoints - 1].y;
570 }
571
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;
574}
575
576int Curve(const char *label, const ImVec2 &size, const int maxpoints, ImVec2 *points)
577{
578 int modified = 0;
579 int i;
580
581 if (maxpoints < 2 || points == 0)
582 {
583 return 0;
584 }
585
586 if (points[0].x < 0)
587 {
588 points[0].x = 0;
589 points[0].y = 0;
590 points[1].x = 1;
591 points[1].y = 1;
592 points[2].x = -1;
593 }
594
595 ImGuiWindow *window = GetCurrentWindow();
596 ImGuiContext &g = *GImGui;
597 const ImGuiStyle &style = g.Style;
598 const ImGuiID id = window->GetID(label);
599
600 if (window->SkipItems)
601 {
602 return 0;
603 }
604
605 ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
606 ItemSize(bb);
607
608 if (!ItemAdd(bb, NULL))
609 {
610 return 0;
611 }
612
613 const bool hovered = ImGui::ItemHoverable(bb, id);
614 int max = 0;
615
616 while (max < maxpoints && points[max].x >= 0)
617 {
618 max++;
619 }
620
621 int kill = 0;
622
623 do
624 {
625 if (kill)
626 {
627 modified = 1;
628
629 for (i = kill + 1; i < max; i++)
630 {
631 points[i - 1] = points[i];
632 }
633
634 max--;
635 points[max].x = -1;
636 kill = 0;
637 }
638
639 for (i = 1; i < max - 1; i++)
640 {
641 if (abs(points[i].x - points[i - 1].x) < 1 / 128.0)
642 {
643 kill = i;
644 }
645 }
646 }
647 while (kill);
648
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;
652
653 if (hovered)
654 {
655 SetHoveredID(id);
656
657 if (g.IO.MouseDown[0])
658 {
659 modified = 1;
660 ImVec2 pos = (g.IO.MousePos - bb.Min) / (bb.Max - bb.Min);
661 pos.y = 1 - pos.y;
662 int left = 0;
663
664 while (left < max && points[left].x < pos.x)
665 {
666 left++;
667 }
668
669 if (left)
670 {
671 left--;
672 }
673
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);
678 int sel = -1;
679
680 if (p1d < (1 / 16.0))
681 {
682 sel = left;
683 }
684
685 if (p2d < (1 / 16.0))
686 {
687 sel = left + 1;
688 }
689
690 if (sel != -1)
691 {
692 points[sel] = pos;
693 }
694
695 else
696 {
697 if (max < maxpoints)
698 {
699 max++;
700
701 for (i = max; i > left; i--)
702 {
703 points[i] = points[i - 1];
704 }
705
706 points[left + 1] = pos;
707 }
708
709 if (max < maxpoints)
710 {
711 points[max].x = -1;
712 }
713 }
714
715 // snap first/last to min/max
716 if (points[0].x < points[max - 1].x)
717 {
718 points[0].x = 0;
719 points[max - 1].x = 1;
720 }
721
722 else
723 {
724 points[0].x = 1;
725 points[max - 1].x = 0;
726 }
727 }
728 }
729
730 // bg grid
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));
737
738 for (i = 0; i < 9; i++)
739 {
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));
742 }
743
744 // smooth curve
745 enum
746 {
747 smoothness = 256
748 }; // the higher the smoother
749
750 for (i = 0; i <= (smoothness - 1); ++i)
751 {
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));
759 }
760
761 // lines
762 for (i = 1; i < max; i++)
763 {
764 ImVec2 a = points[i - 1];
765 ImVec2 b = points[i];
766 a.y = 1 - a.y;
767 b.y = 1 - b.y;
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));
771 }
772
773 if (hovered)
774 {
775 // control points
776 for (i = 0; i < max; i++)
777 {
778 ImVec2 p = points[i];
779 p.y = 1 - p.y;
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));
784 }
785 }
786
787 // buttons; @todo: mirror, smooth, tessellate
788 if (ImGui::Button("Flip"))
789 {
790 for (i = 0; i < max; ++i)
791 {
792 points[i].y = 1 - points[i].y;
793 }
794 }
795
796 ImGui::SameLine();
797 // curve selector
798 const char *items[] = { "Custom",
799
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",
805 "Bounce in out",
806
807 "Sine square", "Exponential",
808
809 "Schubring1", "Schubring2", "Schubring3",
810
811 "SinPi2", "Swing"
812 };
813 static int item = 0;
814
815 if (modified)
816 {
817 item = 0;
818 }
819
820 /*
821 if (ImGui::Combo("Ease type", &item, items, IM_ARRAYSIZE(items)))
822 {
823 max = maxpoints;
824 if (item > 0)
825 {
826 for (i = 0; i < max; ++i)
827 {
828 points[i].x = i / float(max - 1);
829 points[i].y = float(tween::ease(item - 1, points[i].x));
830 }
831 }
832 }
833 */
834 char buf[128];
835 const char *str = label;
836
837 if (hovered)
838 {
839 ImVec2 pos = (g.IO.MousePos - bb.Min) / (bb.Max - bb.Min);
840 pos.y = 1 - pos.y;
841 sprintf(buf, "%s (%f,%f)", label, pos.x, pos.y);
842 str = buf;
843 }
844
845 RenderTextClipped(ImVec2(bb.Min.x, bb.Min.y + style.FramePadding.y), bb.Max, str, NULL, NULL, ImVec2(0.5f, 0.5f));
846 return modified;
847}
848
849}; // namespace ImGui
@ key
the parser read a key of a value in an object
STL namespace.