PeriDyno 1.0.0
Loading...
Searching...
No Matches
imGuIZMOquat.cpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2018-2020 Michele Morrone
3// All rights reserved.
4//
5// https://michelemorrone.eu - https://BrutPitt.com
6//
7// twitter: https://twitter.com/BrutPitt - github: https://github.com/BrutPitt
8//
9// mailto:brutpitt@gmail.com - mailto:me@michelemorrone.eu
10//
11// This software is distributed under the terms of the BSD 2-Clause license
12//------------------------------------------------------------------------------
13#include "imGuIZMOquat.h"
14
15ImVector<vec3> imguiGizmo::sphereVtx;
16ImVector<int> imguiGizmo::sphereTess;
17ImVector<vec3> imguiGizmo::arrowVtx[4];
18ImVector<vec3> imguiGizmo::arrowNorm[4];
19ImVector<vec3> imguiGizmo::cubeVtx;
20ImVector<vec3> imguiGizmo::cubeNorm;
21ImVector<vec3> imguiGizmo::planeVtx;
22ImVector<vec3> imguiGizmo::planeNorm;
24bool imguiGizmo::dragActivate = false;
25//
26// Settings
27//
28// axes/arrow are composed of cone (or pyramid) and cylinder
29// (or parallelepiped): this solid are builded at first instance
30// and will have same slices/radius/length for all controls in your
31// applications but can be resized proportionally with a reductin
32// factor: solidResizeFactor and axesResizeFactor.
33// Same thing for the colors of sphere tessellation, while color
34// of axes and cube are fixed
35//
36// Solid/axes settings can be set one only one time before your widget
37// while solidResizeFactor and axesResizeFactor settings must
38// be call before and always of your widget, every redraw... and
39// restored after use... like push/pop
40// ... I avoided creating a push/pop mechanism
42
43// arrow/axes components
46float imguiGizmo::coneRadius = 0.07f;
47float imguiGizmo::coneLength = 0.37f;
48
49
51float imguiGizmo::cylRadius = 0.02f; // sizeCylLength = defined in base to control size
52
53
54// Sphere components
56float imguiGizmo::sphereRadius = .27f;
58
59// Cube components
61float imguiGizmo::cubeSize = .05f;
62
63// Plane components
65float imguiGizmo::planeSize = .33f;
66float imguiGizmo::planeThickness = .015f;
67
68// Axes resize
70vec3 imguiGizmo::axesResizeFactor(.95f, 1.0f, 1.0f);
72
73// Solid resize
77
78// Direction arrow color
80ImVec4 imguiGizmo::directionColor(1.0f, 1.0f, 0.0f, 1.0f);
82
83// Plane color
85ImVec4 imguiGizmo::planeColor(0.0f, 0.5f, 1.0f, STARTING_ALPHA_PLANE);
87
88// Sphere Colors
90ImU32 imguiGizmo::sphereColors[2] = { 0xff401010, 0xffc0a0a0 }; // Tessellation colors
91ImU32 imguiGizmo::savedSphereColors[2] = { 0xff401010, 0xffc0a0a0 };
92//ImU32 spherecolorA=0xff005cc0, spherecolorB=0xffc05c00;
93
94// Gizmo mouse settings
96float imguiGizmo::gizmoFeelingRot = 1.f; // >1 more mouse sensibility, <1 less mouse sensibility
97
98#ifndef IMGUIZMO_USE_ONLY_ROT
101#endif
102
103//
104// for all gizmo3D
105//
106// input:
107// size: dimension of the control
108// mode: visualization mode: axis starting from origin, fullAxis
109// (whit or w/o solid at 0,0,0) or only one arrow for direction
110//
111// other settings (to call before and always of your control):
112// dimesion solid, axes, and arrow, slice of poligons end over: view
113// section "settings of class declaration", these these values are valid for
114// ALL controls in your application, because the lists of triangles/quads,
115// which compose the solids, are builded one time with the first
116// instance ... and NOT every redraw
117//
118// solidResizeFactor - axesResizeFactor
119// can resize axes or solid, respectively (helper func)
121namespace ImGui
122{
123// Quaternion control
124// in/out:
125// - quat (quaternion) rotation
127bool gizmo3D(const char* label, quat& q, float size, const int mode)
128{
129 imguiGizmo g;
130 g.modeSettings(mode & ~g.modeDual);
131
132 g.qtV = q;
133
134 bool ret = g.drawFunc(label, size);
135 if(ret) q = g.qtV;
136
137 return ret;
138}
139// Angle/Axes control
140// in/out:
141// - vec4 - X Y Z vector/axes components - W angle of rotation
143bool gizmo3D(const char* label, vec4& axis_angle, float size, const int mode)
144{
145 imguiGizmo g;
146 g.modeSettings(mode & ~g.modeDual);
147
148 return g.getTransforms(g.qtV, label, axis_angle, size);
149}
150// Direction control
151// in/out:
152// - vec3 - X Y Z vector/axes components
154bool gizmo3D(const char* label, vec3& dir, float size, const int mode)
155{
156 imguiGizmo g;
158
159 return g.getTransforms(g.qtV, label, dir, size);
160}
161// 2 Manipulators -> 2 Quaternions
162// in/out:
163// - axes (quaternion) for full control - LeftClick
164// - spot (quaternion) for full control - RightClick
165//
166// both pressed buttons... rotate together
167// ctrl-Shift-Alt mods, for X-Y-Z rotations (respectivally)
168// are abilitated on both ... also together!
170bool gizmo3D(const char* label, quat& axes, quat& spot, float size, const int mode)
171{
172 imguiGizmo g;
173 g.setDualMode(mode);
174
175 g.qtV = axes; g.qtV2 = spot;
176
177 bool ret = g.drawFunc(label, size);
178 if(ret) { axes = g.qtV; spot = g.qtV2; }
179
180 return ret;
181}
182// 2 Manipulators -> Quaternion and vec3
183// in/out:
184// - axes (quaternion) for full control - LeftClick
185// - spot (vec3) for full control - RightClick
187bool gizmo3D(const char* label, quat& axes, vec3& spotDir, float size, const int mode)
188{
189 imguiGizmo g;
190 g.setDualMode(mode);
191
192 g.qtV = axes;
193
194 bool ret = g.getTransforms(g.qtV2, label, spotDir, size);
195 if(ret) axes = g.qtV;
196 return ret;
197}
198// 2 Manipulators -> Quaternion and vec4
199// in/out:
200// - axes (quaternion) for full control - LeftClick
201// - spot (vec4) for full control - RightClick
203bool gizmo3D(const char* label, quat& axes, vec4& axesAngle, float size, const int mode)
204{
205 imguiGizmo g;
206 g.setDualMode(mode);
207
208 g.qtV = axes;
209
210 bool ret = g.getTransforms(g.qtV2, label, axesAngle, size);
211 if(ret) axes = g.qtV;
212 return ret;
213
214}
215#ifndef IMGUIZMO_USE_ONLY_ROT
216// Quaternion control + Pan & Dolly
217// in/out:
218// - vec3 Pan(x,y) Dolly(z)
219// - quat (quaternion) rotation
221bool gizmo3D(const char* label, vec3& vPanDolly, quat& q, float size, const int mode)
222{
223 imguiGizmo g;
224 g.modeSettings((mode | g.modePanDolly) & ~g.modeDual );
225
226 g.qtV = q;
227 g.posPanDolly = vPanDolly;
228
229 bool ret = g.drawFunc(label, size);
230 if(ret) {
231 q = g.qtV;
232 vPanDolly = g.posPanDolly;
233 }
234
235 return ret;
236}
237// Angle/Axes control + Pan & Dolly
238// in/out:
239// - vec3 Pan(x,y) Dolly(z)
240// - vec4 - X Y Z vector/axes components - W angle of rotation
242bool gizmo3D(const char* label, vec3& vPanDolly, vec4& axis_angle, float size, const int mode)
243{
244 imguiGizmo g;
245 g.modeSettings(mode & ~g.modeDual | g.modePanDolly);
246 g.posPanDolly = vPanDolly;
247
248 bool ret = g.getTransforms(g.qtV, label, axis_angle, size);
249
250 if(ret) vPanDolly = g.posPanDolly;
251 return ret;
252}
253// Direction control + Pan & Dolly
254// in/out:
255// - vec3 Pan(x,y) Dolly(z)
256// - vec3 - X Y Z vector/axes components
258bool gizmo3D(const char* label, vec3& vPanDolly, vec3& dir, float size, const int mode)
259{
260 imguiGizmo g;
262 g.posPanDolly = vPanDolly;
263
264 bool ret = g.getTransforms(g.qtV, label, dir, size);
265
266 if(ret) vPanDolly = g.posPanDolly;
267 return ret;
268
269}
270// 2 Manipulators -> 2 Quaternions + Pan & Dolly
271// in/out:
272// - vec3 Pan(x,y) Dolly(z) - default: Ctrl /Shift
273// - axes (quaternion) for full control - LeftClick
274// - spot (quaternion) for full control - RightClick
275//
276// both pressed buttons... rotate together
277// ctrl-Shift-Alt mods, for X-Y-Z rotations (respectivally)
278// are abilitated on both ... also together!
280bool gizmo3D(const char* label, vec3& vPanDolly, quat& axes, quat& spot, float size, const int mode)
281{
282 imguiGizmo g;
283 g.setDualMode(mode);
284 g.posPanDolly = vPanDolly;
285
286 g.qtV = axes; g.qtV2 = spot;
287
288 bool ret = g.drawFunc(label, size);
289 if(ret) { vPanDolly = g.posPanDolly; axes = g.qtV; spot = g.qtV2; }
290
291 return ret;
292}
293// 2 Manipulators -> Quaternion and vec3 + Pan & Dolly
294// in/out:
295// - vec3 Pan(x,y) Dolly(z) - default: Ctrl /Shift
296// - axes (quaternion) for full control - LeftClick
297// - spot (vec3) for full control - RightClick
299bool gizmo3D(const char* label, vec3& vPanDolly, quat& axes, vec3& spotDir, float size, const int mode)
300{
301 imguiGizmo g;
302 g.setDualMode(mode);
303 g.posPanDolly = vPanDolly;
304
305 g.qtV = axes;
306
307 bool ret = g.getTransforms(g.qtV2, label, spotDir, size);
308 if(ret) { vPanDolly = g.posPanDolly; axes = g.qtV; }
309 return ret;
310}
311// 2 Manipulators -> Quaternion and vec4 + Pan & Dolly
312// in/out:
313// - vec3 Pan(x,y) Dolly(z) - default: Ctrl /Shift
314// - axes (quaternion) for full control - LeftClick
315// - spot (vec4) for full control - RightClick
317bool gizmo3D(const char* label, vec3& vPanDolly, quat& axes, vec4& axesAngle, float size, const int mode)
318{
319 imguiGizmo g;
320 g.setDualMode(mode);
321 g.posPanDolly = vPanDolly;
322
323 g.qtV = axes;
324
325 bool ret = g.getTransforms(g.qtV2, label, axesAngle, size);
326 if(ret) { vPanDolly = g.posPanDolly; axes = g.qtV; }
327 return ret;
328
329}
330#endif
331
332} // namespace ImGui
333
334static inline int clamp(int v, int mn, int mx)
335{
336 return (v < mn) ? mn : (v > mx) ? mx : v;
337}
338
339//
340// LightEffect
341// faster but minus cute/precise.. ok for sphere
343inline ImU32 addLightEffect(ImU32 color, float light)
344{
345 float l = ((light<.6f) ? .6f : light) * .8f;
346 float lc = light * 80.0f; // ambient component
347 return clamp(ImU32((( color & 0xff)*l + lc)),0,255) |
348 (clamp(ImU32((((color>>8) & 0xff)*l + lc)),0,255) << 8) |
349 (clamp(ImU32((((color>>16) & 0xff)*l + lc)),0,255) << 16) |
350 (ImU32(ImGui::GetStyle().Alpha * (color>>24)) << 24);
351}
352//
353// LightEffect
354// with distance attenuatin
356inline ImU32 addLightEffect(const vec4 &color, float light, float atten)
357{
358 vec3 l((light<.5) ? .5f : light);
359 vec3 a(atten>.25 ? .25f : atten);
360 vec3 c(((vec3(color) + l*.5f) * l) *.75f + a*vec3(color)*.45f +a*.25f);
361
362 const float alpha = color.a * ImGui::GetStyle().Alpha; //ImGui::GetCo(ImGuiCol_FrameBg).w;
363 return ImGui::ColorConvertFloat4ToU32(ImVec4(c.x, c.y, c.z, alpha));
364}
365
366inline ImU32 addLightEffect(ImU32 color, float light, float atten)
367{
368 vec4 c(float(color & 0xff)/255.f,float((color>>8) & 0xff)/255.f,float((color>>16) & 0xff)/255.f, 1.0f);
369 return addLightEffect(c, light, atten);
370}
371
372// inline helper drawing functions
374typedef vec3 & (*ptrFunc)(vec3 &);
375
376
377inline vec3 &adjustPlane(vec3 &coord)
378{
379 coord.x = (coord.x > 0.0f) ? ( 2.5f * coord.x - 1.6f) : coord.x ;
381 coord *= vec3(1.0f, 2.0f, 2.0f);
382 return coord;
383}
384
385inline vec3 &adjustDir(vec3 &coord)
386{
387 coord.x = (coord.x > 0.0f) ? ( 2.5f * coord.x - 1.6f) : coord.x + 0.1f;
388 coord *= vec3(1.0f, 3.0f, 3.0f);
389 return coord;
390}
391
392inline vec3 &adjustSpotCyl(vec3 &coord)
393{
394 const float halfCylMinusCone = 1.0f - imguiGizmo::coneLength;
395 coord.x = (coord.x*.075f - 2.0f +( halfCylMinusCone - halfCylMinusCone*.075f)); //cyl begin where cone end
396 return coord;
397
398}
399inline vec3 &adjustSpotCone(vec3 &coord)
400{
401 coord.x-= 2.00f;
402 return coord;
403}
404
405inline vec3 fastRotate (int axis, vec3 &v)
406{
407 return ((axis == imguiGizmo::axisIsY) ? vec3(-v.y, v.x, v.z) : // rotation Z 90'
408 ((axis == imguiGizmo::axisIsZ) ? vec3(-v.z, v.y, v.x) : // rotation Y 90'
409 v));
410}
411
412//
413// Draw imguiGizmo
414//
416bool imguiGizmo::drawFunc(const char* label, float size)
417{
418
419 ImGuiIO& io = ImGui::GetIO();
420 ImGuiStyle& style = ImGui::GetStyle();
421 ImDrawList* draw_list = ImGui::GetWindowDrawList();
422
423 const float arrowStartingPoint = (axesOriginType & imguiGizmo::sphereAtOrigin) ? sphereRadius * solidResizeFactor:
425 cylRadius * .5);
426 // if modeDual... leave space for draw light arrow
428
429 // build solids... once!
431 if (!solidAreBuilded) {
432 const float arrowBgn = -1.0f, arrowEnd = 1.0f;
433
434 buildCone (arrowEnd - coneLength, arrowEnd, coneRadius, coneSlices);
435 buildCylinder(arrowBgn, arrowEnd - coneLength, cylRadius , cylSlices );
439 solidAreBuilded = true;
440 }
441
442 ImGui::PushID(label);
443 ImGui::BeginGroup();
444
445 bool value_changed = false;
446
447 ImVec2 controlPos(ImGui::GetCursorScreenPos());
448
449 const float squareSize = size; //std::min(ImGui::CalcItemWidth(), size);
450 const float halfSquareSize = squareSize*.5;
451 const ImVec2 innerSize(squareSize,squareSize);
452
453 bool highlighted = false;
454 ImGui::InvisibleButton("imguiGizmo", innerSize);
455
456 bool vgModsActive = false;
458
459 if(io.KeyCtrl) { vgMods |= vg::evControlModifier; vgModsActive = true; }
460 if(io.KeyAlt) { vgMods |= vg::evAltModifier; vgModsActive = true; }
461 if(io.KeyShift) { vgMods |= vg::evShiftModifier; vgModsActive = true; }
462 if(io.KeySuper) { vgMods |= vg::evSuperModifier; vgModsActive = true; }
463
464 vg::vImGuIZMO track;
465 // getTrackball
466 // in : q -> quaternion to which applay rotations
467 // out: q -> quaternion with rotations
469 auto getTrackball = [&] (quat &q) {
470 ImVec2 mouse = ImGui::GetMousePos() - controlPos;
471
472 track.viewportSize(innerSize.x, innerSize.y);
473 track.setRotation(q);
474 track.setGizmoFeeling(gizmoFeelingRot);
475#ifndef IMGUIZMO_USE_ONLY_ROT
476 if(drawMode&modePanDolly || io.MouseWheel!=0) {
477 float screenFactor = 1.f/(io.DisplaySize.x<io.DisplaySize.y ? io.DisplaySize.x : io.DisplaySize.y);
481 track.setPanScale(screenFactor*panScale);
482 track.setDollyScale(screenFactor*dollyScale);
483 track.wheel(0.f, io.MouseWheel);
484 track.motionImmediateMode(mouse.x, mouse.y, io.MouseDelta.x, io.MouseDelta.y, vgMods);
485 // get new rotation only if !Pan && ! Dolly
486 if((!track.isDollyActive() && !track.isPanActive() && io.MouseWheel==0)) q = track.getRotation();
487 else posPanDolly = track.getPosition();
488 } else {
489 track.imGuIZMO_BASE_CLASS::motionImmediateMode(mouse.x, mouse.y, io.MouseDelta.x, io.MouseDelta.y, vgMods);
490 q = track.getRotation();
491 }
492#else
493 track.motionImmediateMode(mouse.x, mouse.y, io.MouseDelta.x, io.MouseDelta.y, vgMods);
494 q = track.getRotation();
495#endif
496 value_changed = true; // if getTrackball() called, value is changed
497 };
498
499 // LeftClick
500 if (ImGui::IsItemActive()) {
501 highlighted = true;
502 if(ImGui::IsMouseDragging(0)) getTrackball(qtV);
503 if((drawMode&modeDual) && ImGui::IsMouseDragging(1)) getTrackball(qtV2); // if dual mode... move together
504 //if((drawMode&modeDual) && ImGui::IsMouseDragging(2)) { getTrackball(qtV); getTrackball(qtV2); } // middle if dual mode... move together
505
506 ImColor col(style.Colors[ImGuiCol_FrameBgActive]);
507 col.Value.w*=ImGui::GetStyle().Alpha;
508 draw_list->AddRectFilled(controlPos, controlPos + innerSize, col, style.FrameRounding);
509 } else { // eventual right click... only dualmode
510 highlighted = ImGui::IsItemHovered();
511 if(highlighted && (drawMode&modeDual) && ImGui::IsMouseDragging(1)) getTrackball(qtV2);
512 else if(highlighted && (drawMode&modeDual) && ImGui::IsMouseDragging(2)) { getTrackball(qtV); getTrackball(qtV2); }
513#ifndef IMGUIZMO_USE_ONLY_ROT
514 else if(highlighted && io.MouseWheel!=0) getTrackball(qtV);
515#endif
516
517 ImColor col(highlighted ? style.Colors[ImGuiCol_FrameBgHovered]: style.Colors[ImGuiCol_FrameBg]);
518 col.Value.w*=ImGui::GetStyle().Alpha;
519 draw_list->AddRectFilled(controlPos, controlPos + innerSize, col, style.FrameRounding);
520 }
521
522
523 draw_list->PushClipRect(controlPos, controlPos + innerSize, true);
524
525 const ImVec2 wpUV = ImGui::GetFontTexUvWhitePixel(); //culling versus
526 ImVec2 uv[4]; ImU32 col[4]; //buffers to storetransformed vtx & col for PrimVtx & PrimQuadUV
527
528 quat _q(normalize(qtV));
529
530 // Just a "few" lambdas...
532 auto normalizeToControlSize = [&] (float x, float y) {
533 return controlPos + ImVec2(x,-y) * halfSquareSize + ImVec2(halfSquareSize,halfSquareSize); //drawing from 0,0 .. no borders
534 };
535
536 auto returnSizeFromRatio = [&] (float ratio) { return squareSize * ratio; };
537
539 auto addTriangle = [&] ()
540 { // test cull dir
541 if(cross(vec2(uv[1].x-uv[0].x, uv[1].y-uv[0].y),
542 vec2(uv[2].x-uv[0].x, uv[2].y-uv[0].y)) > 0) { uv[1] = uv[2] = uv[0]; }
543
544 for(int i=0; i<3; i++) draw_list->PrimVtx(uv[i], wpUV, col[i]);
545 };
546
548 auto addQuad = [&] (ImU32 colLight)
549 { // test cull dir
550 if(cross(vec2(uv[1].x-uv[0].x, uv[1].y-uv[0].y),
551 vec2(uv[3].x-uv[0].x, uv[3].y-uv[0].y)) > 0) { uv[3] = uv[1] = uv[2] = uv[0]; }
552
553 draw_list->PrimQuadUV(uv[0],uv[1],uv[2],uv[3], wpUV, wpUV, wpUV, wpUV, colLight);
554 };
555
557 auto drawSphere = [&] ()
558 {
559 draw_list->PrimReserve(sphereVtx.size(), sphereVtx.size()); // num vert/indices
560 auto itTess = sphereTess.begin();
561 for(auto itVtx = sphereVtx.begin(); itVtx != sphereVtx.end(); ) {
562 for(int h=0; h<3; h++, itTess++) {
563 vec3 coord = _q * (*itVtx++ * solidResizeFactor); //Rotate
564
565 uv[h] = normalizeToControlSize(coord.x,coord.y);
566 const float drawSize = sphereRadius * solidResizeFactor;
567 col[h] = addLightEffect(sphereColors[*itTess], (-drawSize*.5f + (coord.z*coord.z) / (drawSize*drawSize)));
568 //col[h] = colorLightedY(sphereCol[i++], (-sizeSphereRadius.5f + (coord.z*coord.z) / (sizeSphereRadius*sizeSphereRadius)), coord.z);
569 }
570 addTriangle();
571 }
572 };
573
575 auto drawCube = [&] ()
576 {
577 draw_list->PrimReserve(cubeNorm.size()*6, cubeNorm.size()*4); // num vert/indices
578 for(vec3* itNorm = cubeNorm.begin(), *itVtx = cubeVtx.begin() ; itNorm != cubeNorm.end();) {
579 vec3 coord;
580 vec3 norm = _q * *itNorm;
581 for(int i = 0; i<4; ) {
582 coord = _q * (*itVtx++ * solidResizeFactor);
583 uv[i++] = normalizeToControlSize(coord.x,coord.y);
584 }
585 addQuad(addLightEffect(vec4(abs(*itNorm++),1.0f), norm.z, coord.z));
586 }
587 };
588
590 auto drawPlane = [&] ()
591 {
592 draw_list->PrimReserve(planeNorm.size()*6, planeNorm.size()*4); // num vert/indices
593 for(auto itNorm = planeNorm.begin(), itVtx = planeVtx.begin() ; itNorm != planeNorm.end();) {
594 vec3 coord;
595 vec3 norm = _q * *itNorm;
596 for(int i = 0; i<4; ) {
597 coord = _q * (*itVtx++ * solidResizeFactor);
598 uv[i++] = normalizeToControlSize(coord.x,coord.y);
599 }
600 itNorm++;
601 addQuad(addLightEffect(vec4(planeColor.x, planeColor.y, planeColor.z, planeColor.w), norm.z, coord.z));
602 }
603 };
604
606 auto drawAxes = [&] (int side)
607 {
608 for(int n = 0; n < 4; n++) { //Arrow: 2 Cone -> (Surface + cap) + 2 Cyl -> (Surface + cap)
609 for(int arrowAxis = 0; arrowAxis < 3; arrowAxis++) { // draw 3 axes
610 vec3 arrowCoord(0.0f, 0.0f, 0.0f); arrowCoord[arrowAxis] = 1.0f; // rotate on 3 axis (arrow -> X, Y, Z ) in base to current arrowAxis
611 const float arrowCoordZ = vec3(_q*arrowCoord).z; //.Rotate
612
613 const int i = (arrowCoordZ > 0) ? 3 - n : n; //painter algorithm: before farthest
614
615 bool skipCone =true;
616
617 if((side == backSide && arrowCoordZ > 0) || (side == frontSide && arrowCoordZ <= 0)) {
618 if (!showFullAxes && (i == CYL_CAP)) continue; // skip if cylCap is hidden
619 if (i <= CONE_CAP) continue; // do not draw cone
620 else skipCone = false;
621 }
622
623 auto *ptrVtx = arrowVtx+i;
624 draw_list->PrimReserve(ptrVtx->size(), ptrVtx->size()); // // reserve vtx
625
626 for(auto itVtx = ptrVtx->begin(), itNorm = (arrowNorm+i)->begin(); itVtx != ptrVtx->end(); ) { //for all Vtx
627#if !defined(imguiGizmo_INTERPOLATE_NORMALS)
628 vec3 norm( _q * fastRotate(arrowAxis, *itNorm++));
629#endif
630 for(int h=0; h<3; h++) {
631 vec3 coord(*itVtx++ * resizeAxes); // reduction
632
633 // reposition starting point...
634 if(!skipCone && coord.x > 0) coord.x = -arrowStartingPoint;
635 if((skipCone && coord.x <= 0) ||
636 (!showFullAxes && (coord.x < arrowStartingPoint)) ) coord.x = arrowStartingPoint;
637 //transform
638 coord = _q * fastRotate(arrowAxis, coord);
639 uv[h] = normalizeToControlSize(coord.x,coord.y);
640#ifdef imguiGizmo_INTERPOLATE_NORMALS
641 vec3 norm( _q * fastRotate(arrowAxis, *itNorm++));
642#endif
643 //col[h] = addLightEffect(ImU32(0xFF) << arrowAxis*8, float(0xa0)*norm.z+.5f);
644 col[h] = addLightEffect(vec4(float(arrowAxis==axisIsX),float(arrowAxis==axisIsY),float(arrowAxis==axisIsZ), 1.0), norm.z, coord.z);
645 }
646 addTriangle();
647 }
648 }
649 }
650 };
651
653 auto drawComponent = [&] (const int idx, const quat &q, ptrFunc func)
654 {
655 auto *ptrVtx = arrowVtx+idx;
656 draw_list->PrimReserve(ptrVtx->size(), ptrVtx->size()); // reserve vtx
657 for(auto itVtx = ptrVtx->begin(), itNorm = (arrowNorm+idx)->begin(); itVtx != ptrVtx->end(); ) {
658#if !defined(imguiGizmo_INTERPOLATE_NORMALS)
659 vec3 norm = (_q * *itNorm++);
660#endif
661 for(int h=0; h<3; h++) {
662 vec3 coord = *itVtx++;
663#ifdef imguiGizmo_INTERPOLATE_NORMALS
664 vec3 norm = (q * *itNorm++);
665#endif
666 coord = q * (func(coord) * resizeAxes); // remodelling Directional Arrow (func) and transforms;
667
668 uv[h] = normalizeToControlSize(coord.x,coord.y);
669 //col[h] = addLightEffect(color, float(0xa0)*norm.z+.5f);
670 col[h] = addLightEffect(vec4(directionColor.x, directionColor.y, directionColor.z, 1.0), norm.z, coord.z>0 ? coord.z : coord.z*.5);
671 }
672 addTriangle();
673 }
674
675 };
676
678 auto dirArrow = [&] (const quat &q, int mode)
679 {
680 vec3 arrowCoord(_q * vec3(1.0f, 0.0f, 0.0f));
681
682 ptrFunc func = (mode & modeDirPlane) ? adjustPlane : adjustDir;
683
684 if(arrowCoord.z <= 0) { for(int i = 0; i < 4; i++) drawComponent(i, q, func); if(mode & modeDirPlane) drawPlane(); }
685 else { if(mode & modeDirPlane) drawPlane(); for(int i = 3; i >= 0; i--) drawComponent(i, q, func); }
686
687 };
688
690 auto spotArrow = [&] (const quat &q, const float arrowCoordZ)
691 {
692 if(arrowCoordZ > 0) {
693 drawComponent(CONE_SURF, q, adjustSpotCone); drawComponent(CONE_CAP , q, adjustSpotCone);
694 drawComponent(CYL_SURF , q, adjustSpotCyl ); drawComponent(CYL_CAP , q, adjustSpotCyl );
695 } else {
696 drawComponent(CYL_CAP , q, adjustSpotCyl ); drawComponent(CYL_SURF , q, adjustSpotCyl );
697 drawComponent(CONE_CAP , q, adjustSpotCone); drawComponent(CONE_SURF, q, adjustSpotCone);
698 }
699
700 };
701
703 auto draw3DSystem = [&] ()
704 {
705 drawAxes(backSide);
706 if (axesOriginType & sphereAtOrigin) drawSphere();
707 else if(axesOriginType & cubeAtOrigin) drawCube();
708 drawAxes(frontSide);
709 };
710
711#define CENTER_HELPER_X -.85f
712#define CENTER_HELPER_Y -.85f
714 auto drawRotationHelper = [&] () {
715 const ImVec2 center(normalizeToControlSize(CENTER_HELPER_X, CENTER_HELPER_Y));
716 const float radius = returnSizeFromRatio(.05);
717 const int nSegments = 12;
718 const ImU32 color = (vgMods & vg::evShiftModifier) ? 0xff0000ff :
719 (vgMods & vg::evControlModifier) ? 0xff00ff00 : 0xffff0000;
720
721 if(squareSize<100) { // if too small filled circle
722 draw_list->AddCircleFilled(center, radius, color, nSegments);
723 } else { // draw arc
724 const float thickness = squareSize/100.f;
725 const float a_max = (IM_PI * 1.5f) * ((float)nSegments) / (float)nSegments;
726 draw_list->PathClear();
727 draw_list->PathArcTo(center, radius - 0.5f, 0.0f, a_max, nSegments);
728 draw_list->PathStroke(color, false, thickness);
729 if(squareSize>150) { // if big enough draw also arrowhead
730 const float lenLine = radius*.33f;
731 const float thickRadius = radius - thickness*.5;
732 draw_list->AddTriangleFilled(ImVec2(center.x-lenLine, center.y-(thickRadius+lenLine)),
733 ImVec2(center.x+lenLine, center.y- thickRadius),
734 ImVec2(center.x-lenLine, center.y-(thickRadius-lenLine)),
735 color);
736
737 draw_list->AddTriangleFilled(ImVec2(center.x+(thickRadius-lenLine), center.y+lenLine),
738 ImVec2(center.x+ thickRadius , center.y-lenLine),
739 ImVec2(center.x+(thickRadius+lenLine), center.y+lenLine),
740 color);
741 }
742
743 }
744 };
745
747 auto drawPanHelper = [&] () {
748 const ImVec2 center(normalizeToControlSize(CENTER_HELPER_X, CENTER_HELPER_Y));
749 const float lenLine = returnSizeFromRatio(.05f);
750 const float halfLen = lenLine * .5f;
751 const float hhLen = halfLen * .5f;
752 const ImU32 color = 0xffffff00;
753 draw_list->AddTriangleFilled(ImVec2(center.x , center.y+lenLine+halfLen),
754 ImVec2(center.x-halfLen, center.y+lenLine-hhLen ),
755 ImVec2(center.x+halfLen, center.y+lenLine-hhLen ),
756 color);
757 draw_list->AddTriangleFilled(ImVec2(center.x , center.y-lenLine-halfLen),
758 ImVec2(center.x-halfLen, center.y-lenLine+hhLen ),
759 ImVec2(center.x+halfLen, center.y-lenLine+hhLen ),
760 color);
761 draw_list->AddTriangleFilled(ImVec2(center.x+lenLine+halfLen, center.y ),
762 ImVec2(center.x+lenLine-hhLen , center.y-halfLen),
763 ImVec2(center.x+lenLine-hhLen , center.y+halfLen),
764 color);
765 draw_list->AddTriangleFilled(ImVec2(center.x-lenLine-halfLen, center.y ),
766 ImVec2(center.x-lenLine+hhLen , center.y-halfLen),
767 ImVec2(center.x-lenLine+hhLen , center.y+halfLen),
768 color);
769 };
770
772 auto drawDollyHelper = [&] () {
773 const ImVec2 center(normalizeToControlSize(CENTER_HELPER_X, CENTER_HELPER_Y));
774 const float lenLine = returnSizeFromRatio(.05f);
775 const float halfLen = lenLine * .5f;
776 const ImU32 color = 0xff00ffff;
777 draw_list->AddTriangleFilled(ImVec2(center.x , center.y+lenLine+halfLen),
778 ImVec2(center.x-lenLine, center.y+halfLen ),
779 ImVec2(center.x+lenLine, center.y+halfLen ),
780 color);
781 draw_list->AddTriangleFilled(ImVec2(center.x , center.y-lenLine ),
782 ImVec2(center.x-halfLen, center.y-halfLen ),
783 ImVec2(center.x+halfLen, center.y-halfLen ),
784 color);
785 };
786
787 // ... and now.. draw the widget!!!
789 //if((drawMode & modePanDolly) && (ImGui::IsItemHovered() || ImGui::IsMouseDragging(0))) {
790
791 if(drawMode & (modeDirection | modeDirPlane)) dirArrow(_q, drawMode);
792 else { // draw arrows & solid
793 if(drawMode & modeDual) {
794 vec3 spot(qtV2 * vec3(-1.0f, 0.0f, .0f)); // versus opposite
795 if(spot.z>0) { draw3DSystem(); spotArrow(normalize(qtV2),spot.z); }
796 else { spotArrow(normalize(qtV2),spot.z); draw3DSystem(); }
797 } else draw3DSystem();
798 }
799
800 // Helper on vgModifier active
801 if(vgModsActive && (ImGui::IsItemHovered() && (!ImGui::IsMouseDown(0) && !ImGui::IsMouseDown(1)) )) {
802#ifndef IMGUIZMO_USE_ONLY_ROT
803 if(drawMode & modePanDolly) {
804 if(panMod & vgMods) drawPanHelper();
805 else if(dollyMod & vgMods) drawDollyHelper();
806 } else {
807 drawRotationHelper();
808 }
809#else
810 drawRotationHelper();
811#endif
812 }
813
814 // Draw text from top left corner
815 ImGui::SetCursorScreenPos(controlPos);
816 if(label[0]!='#' && label[1]!='#') ImGui::Text("%s", label);
817
818 draw_list->PopClipRect();
819
820 ImGui::EndGroup();
821 ImGui::PopID();
822
823 return value_changed;
824}
825
826// Polygon
828void imguiGizmo::buildPolygon(const vec3 &size, ImVector<vec3> &vtx, ImVector<vec3> &norm)
829{
830
831 vtx .clear();
832 norm.clear();
833
834#define V(a,b,c) vtx.push_back(vec3(a size.x, b size.y, c size.z))
835#define N(x,y,z) norm.push_back(vec3(x, y, z))
836
837 N( 1.0f, 0.0f, 0.0f); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+);
838 N( 0.0f, 1.0f, 0.0f); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+);
839 N( 0.0f, 0.0f, 1.0f); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+);
840 N(-1.0f, 0.0f, 0.0f); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-);
841 N( 0.0f,-1.0f, 0.0f); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+);
842 N( 0.0f, 0.0f,-1.0f); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-);
843
844#undef V
845#undef N
846}
847// Sphere
849void imguiGizmo::buildSphere(const float radius, const int tessFactor)
850{
851 const int div = tessFactor; //tessellation colors: meridians/div x paralles/div
852 const int meridians = 32; //64/2;
853 const int parallels = meridians/2;
854
855 sphereVtx .clear();
856 sphereTess.clear();
857
858# define V(x,y,z) sphereVtx.push_back(vec3(x, y, z))
859# define T(t) sphereTess.push_back(t)
860
861 const float incAngle = 2.0f*T_PI/(float)( meridians );
862 float angle = incAngle;
863
864 // Adjust z and radius as stacks are drawn.
865 float z0, z1 = cosf(angle)*radius;
866 float r0, r1 = sinf(angle)*radius;
867 float x1 = -1.0f;
868 float y1 = 0.0f;
869
870 // The first pole==>parallel is covered with triangles
871 for(int j=0; j<meridians; j++, angle+=incAngle) {
872 const float x0 = x1; x1 = cosf(T_PI-angle);
873 const float y0 = y1; y1 = sinf(T_PI-angle);
874
875 const int tType = ((j>>div)&1);
876
877 V(0.0f, 0.0f, radius); T(tType);
878 V(x0*r1,-y0*r1, z1); T(tType);
879 V(x1*r1,-y1*r1, z1); T(tType);
880 }
881
882 // Cover each stack with a quad divided in 2 triangles, except the top and bottom stacks
883 angle = incAngle+incAngle;
884 x1 = 1.f; y1 = 0.f;
885
886 for(int i=1; i<parallels-1; i++, angle+=incAngle) {
887 //int div =8;
888 z0 = z1; z1 = cosf(angle)*radius;
889 r0 = r1; r1 = sinf(angle)*radius;
890 float angleJ = incAngle;
891
892 for(int j=0; j<meridians; j++, angleJ+=incAngle) {
893 const float x0 = x1; x1 = cosf(angleJ);
894 const float y0 = y1; y1 = sinf(angleJ);
895
896 const int tType = ((i>>div)&1) ? ((j>>div)&1) : !((j>>div)&1);
897
898 V(x0*r1, -y0*r1, z1); T(tType);
899 V(x0*r0, -y0*r0, z0); T(tType);
900 V(x1*r0, -y1*r0, z0); T(tType);
901 V(x0*r1, -y0*r1, z1); T(tType);
902 V(x1*r0, -y1*r0, z0); T(tType);
903 V(x1*r1, -y1*r1, z1); T(tType);
904 }
905 }
906
907 // The last parallel==>pole is covered with triangls
908 z0 = z1;
909 r0 = r1;
910 x1 = -1.0f; y1 = 0.f;
911
912 angle = incAngle;
913 for(int j=0; j<meridians; j++,angle+=incAngle) {
914 const float x0 = x1; x1 = cosf(angle+T_PI);
915 const float y0 = y1; y1 = sinf(angle+T_PI);
916
917 const int tType = ((parallels-1)>>div)&1 ? ((j>>div)&1) : !((j>>div)&1);
918
919 V( 0.0f, 0.0f,-radius); T(tType);
920 V(x0*r0, -y0*r0, z0); T(tType);
921 V(x1*r0, -y1*r0, z0); T(tType);
922 }
923# undef V
924# undef C
925}
926// Cone / Pyramid
928void imguiGizmo::buildCone(const float x0, const float x1, const float radius, const int slices)
929{
930 const float height = x1-x0 ;
931
932 // Scaling factors for vertex normals
933 const float sq = sqrtf( height * height + radius * radius );
934 const float cosn = height / sq;
935 const float sinn = radius / sq;
936
937 const float incAngle = 2.0f*T_PI/(float)( slices );
938 float angle = incAngle;
939
940 float yt1 = sinn, y1 = radius;// ==> yt1 = cos(0) * sinn, y1 = cos(0) * radius
941 float zt1 = 0.0f, z1 = 0.0f; // ==> zt1 = sin(0) * sinn, z1 = sin(0) * radius
942
943 const float xt0 = x0 * cosn, xt1 = x1 * cosn;
944
945 arrowVtx[CONE_CAP ].clear(); arrowNorm[CONE_CAP ].clear();
946 arrowVtx[CONE_SURF].clear(); arrowNorm[CONE_SURF].clear();
947
948# define V(i,x,y,z) arrowVtx [i].push_back(vec3(x, y, z))
949# define N(i,x,y,z) arrowNorm[i].push_back(vec3(x, y, z))
950
951 for(int j=0; j<slices; j++, angle+=incAngle) {
952 const float yt0 = yt1; yt1 = cosf(angle);
953 const float y0 = y1; y1 = yt1*radius; yt1*=sinn;
954 const float zt0 = zt1; zt1 = sinf(angle);
955 const float z0 = z1; z1 = zt1*radius; zt1*=sinn;
956
957 // Cover the circular base with a triangle fan...
958 V(CONE_CAP, x0, 0.f, 0.f);
959 V(CONE_CAP, x0, y0, -z0);
960 V(CONE_CAP, x0, y1, -z1);
961
962 N(CONE_CAP,-1.f, 0.f, 0.f);
963# ifdef imguiGizmo_INTERPOLATE_NORMALS
964 N(CONE_CAP,-1.f, 0.f, 0.f);
965 N(CONE_CAP,-1.f, 0.f, 0.f);
966#endif
967 V(CONE_SURF, x1, 0.f, 0.f);
968 V(CONE_SURF, x0, y0, z0);
969 V(CONE_SURF, x0, y1, z1);
970# ifdef imguiGizmo_INTERPOLATE_NORMALS
971 N(CONE_SURF,xt1, 0.f, 0.f);
972 N(CONE_SURF,xt0, yt0, zt0);
973 N(CONE_SURF,xt0, yt1, zt1);
974#else
975 N(CONE_SURF, xt0, yt0, zt0);
976#endif
977 }
978#undef V
979#undef N
980}
981// Cylinder
983void imguiGizmo::buildCylinder(const float x0, const float x1, const float radius, const int slices)
984{
985
986 float y1 = 1.0f, yr1 = radius;
987 float z1 = 0.0f, zr1 = 0.0f; // * radius
988
989 const float incAngle = 2.0f*T_PI/(float)( slices );
990 float angle = incAngle;
991
992 arrowVtx[CYL_CAP ].clear(); arrowNorm[CYL_CAP ].clear();
993 arrowVtx[CYL_SURF].clear(); arrowNorm[CYL_SURF].clear();
994
995# define V(i,x,y,z) arrowVtx [i].push_back(vec3(x, y, z))
996# define N(i,x,y,z) arrowNorm[i].push_back(vec3(x, y, z))
997
998 for(int j=0; j<slices; j++, angle+=incAngle) {
999 const float y0 = y1; y1 = cosf(angle);
1000 const float z0 = z1; z1 = sinf(angle);
1001 const float yr0 = yr1; yr1 = y1 * radius;
1002 const float zr0 = zr1; zr1 = z1 * radius;
1003
1004 // Cover the base
1005 V(CYL_CAP, x0, 0.f, 0.f);
1006 V(CYL_CAP, x0, yr0,-zr0);
1007 V(CYL_CAP, x0, yr1,-zr1);
1008
1009 N(CYL_CAP, -1.f, 0.f, 0.f);
1010# ifdef imguiGizmo_INTERPOLATE_NORMALS
1011 N(CYL_CAP, -1.f, 0.f, 0.f);
1012 N(CYL_CAP, -1.f, 0.f, 0.f);
1013#endif
1014 // Cover surface
1015 N(CYL_SURF, 0.f, y0, z0);
1016 N(CYL_SURF, 0.f, y0, z0);
1017# ifdef imguiGizmo_INTERPOLATE_NORMALS
1018 N(CYL_SURF, 0.f, y1, z1);
1019 N(CYL_SURF, 0.f, y0, z0);
1020 N(CYL_SURF, 0.f, y1, z1);
1021 N(CYL_SURF, 0.f, y1, z1);
1022#endif
1023 V(CYL_SURF, x1, yr0, zr0);
1024 V(CYL_SURF, x0, yr0, zr0);
1025 V(CYL_SURF, x0, yr1, zr1);
1026 V(CYL_SURF, x1, yr0, zr0);
1027 V(CYL_SURF, x0, yr1, zr1);
1028 V(CYL_SURF, x1, yr1, zr1);
1029#ifdef SHOW_FULL_CYLINDER
1030 // Cover the top ..in the arrow this cap is covered from cone/pyramid
1031 V(CYL_CAP , x1, 0.f, 0.f);
1032 V(CYL_CAP , x1, yr0, zr0);
1033 V(CYL_CAP , x1, yr1, zr1);
1034 N(CYL_CAP , 1.f, 0.f, 0.f);
1035 # ifdef imguiGizmo_INTERPOLATE_NORMALS
1036 N(CYL_CAP , 1.f, 0.f, 0.f);
1037 N(CYL_CAP , 1.f, 0.f, 0.f);
1038 #endif
1039#endif
1040 }
1041#undef V
1042#undef N
1043}
1044
1045
1046
1047
1048
void setPosition(const tVec3 &p)
Definition vGizmo.h:481
void setDollyControl(vgButtons b, vgModifiers m=evNoModifier)
Definition vGizmo.h:435
void motionImmediateMode(T x, T y, T dx, T dy, vgModifiers mod)
Definition vGizmo.h:486
void setPanScale(T scale)
Definition vGizmo.h:458
void setPanControl(vgButtons b, vgModifiers m=evNoModifier)
Definition vGizmo.h:441
void setDollyScale(T scale)
Definition vGizmo.h:454
void wheel(T x, T y)
Definition vGizmo.h:375
tVec3 getPosition() const
Definition vGizmo.h:480
#define V(a, b, c)
vec3 fastRotate(int axis, vec3 &v)
#define CENTER_HELPER_X
vec3 &(* ptrFunc)(vec3 &)
vec3 & adjustPlane(vec3 &coord)
static int clamp(int v, int mn, int mx)
vec3 & adjustSpotCone(vec3 &coord)
vec3 & adjustDir(vec3 &coord)
#define T(t)
ImU32 addLightEffect(ImU32 color, float light)
vec3 & adjustSpotCyl(vec3 &coord)
#define N(x, y, z)
#define CENTER_HELPER_Y
#define STARTING_ALPHA_PLANE
bool gizmo3D(const char *label, quat &q, float size, const int mode)
virtualGizmo3DClass vImGuIZMO
Definition vGizmo.h:527
@ evSuperModifier
Definition vGizmo.h:48
@ evNoModifier
Definition vGizmo.h:44
@ evShiftModifier
Definition vGizmo.h:45
@ evAltModifier
Definition vGizmo.h:47
@ evControlModifier
Definition vGizmo.h:46
static ImVector< vec3 > planeNorm
static ImVector< vec3 > cubeNorm
static vgModifiers dollyMod
void setDualMode(const int mode)
static ImU32 sphereColors[2]
static vec3 axesResizeFactor
bool getTransforms(quat &q, const char *label, vec3 &dir, float size)
bool drawFunc(const char *label, float size)
static ImVector< vec3 > planeVtx
static ImVector< int > sphereTess
vgButtons buttonPanDolly
static ImVector< vec3 > cubeVtx
static ImVec4 planeColor
static ImVec4 savedPlaneColor
static float gizmoFeelingRot
static int cylSlices
static float panScale
static ImVector< vec3 > arrowNorm[4]
static ImVec4 directionColor
static ImVector< vec3 > arrowVtx[4]
static float cubeSize
static float sphereRadius
static float solidResizeFactor
static vec3 savedAxesResizeFactor
bool showFullAxes
static ImVector< vec3 > sphereVtx
static ImVec4 savedDirectionColor
static float coneLength
static float planeThickness
static bool dragActivate
static float savedSolidResizeFactor
static void buildCone(const float x0, const float x1, const float radius, const int slices)
static void buildCylinder(const float x0, const float x1, const float radius, const int slices)
static void buildCube(const float size)
static ImU32 savedSphereColors[2]
static void buildSphere(const float radius, const int tessFactor)
static void buildPlane(const float size, const float thickness=planeThickness)
vec3 posPanDolly
static float cylRadius
static bool solidAreBuilded
static int coneSlices
void modeSettings(int mode)
static float coneRadius
static vgModifiers panMod
static float dollyScale
static void buildPolygon(const vec3 &size, ImVector< vec3 > &vtx, ImVector< vec3 > &norm)
static float planeSize
static int sphereTessFactor
int vgModifiers
Definition vGizmo.h:28
vgm::Quat quat
Definition vgMath.h:633
vgm::Vec3 vec3
Definition vgMath.h:631
vgm::Vec2 vec2
Definition vgMath.h:630
#define T_PI
Definition vgMath.h:95
vgm::Vec4 vec4
Definition vgMath.h:632