载入中...
搜索中...
未找到
TransformGizmo.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5#include <glm/gtc/matrix_transform.hpp>
6#include <glm/gtc/type_ptr.hpp>
7
8#include <algorithm>
9#include <cmath>
10#include <cstring>
11
12namespace eve::editor {
13namespace {
14
15constexpr float kPi = 3.14159265358979323846f;
16constexpr float kAxisHitRadius = 0.12f;
17constexpr float kPlaneHitSize = 0.25f;
18constexpr float kRingThickness = 0.08f;
19
20float snapValue(float v, float step) {
21 if (step <= 0.f) return v;
22 return std::round(v / step) * step;
23}
24
25glm::vec3 safeNormalize(const glm::vec3 &v, const glm::vec3 &fallback) {
26 float len = glm::length(v);
27 if (len < 1e-6f) return fallback;
28 return v / len;
29}
30
31} // namespace
32
34
35void TransformGizmo::setMode(const std::string &mode) {
36 if (mode != "translate" && mode != "rotate" && mode != "scale" && mode != "bound") {
37 throw Exception("TransformGizmo::setMode: expected translate|rotate|scale|bound");
38 }
39 mode_ = mode;
41}
42
43void TransformGizmo::setSpace(const std::string &space) {
44 if (space != "local" && space != "world") {
45 throw Exception("TransformGizmo::setSpace: expected local|world");
46 }
47 space_ = space;
49}
50
51void TransformGizmo::setSize(float size) {
52 if (size <= 0.f) throw Exception("TransformGizmo::setSize: size must be > 0");
53 size_ = size;
55}
56
57void TransformGizmo::setPosition(float x, float y, float z) {
58 position_ = {x, y, z};
60}
61
62void TransformGizmo::setRotationEuler(float x, float y, float z) {
63 rotation_ = {x, y, z};
65}
66
67void TransformGizmo::setScale(float x, float y, float z) {
68 scale_ = {x, y, z};
70}
71
72void TransformGizmo::setBounds(float minX, float minY, float minZ, float maxX, float maxY,
73 float maxZ) {
74 boundsMin_ = {std::min(minX, maxX), std::min(minY, maxY), std::min(minZ, maxZ)};
75 boundsMax_ = {std::max(minX, maxX), std::max(minY, maxY), std::max(minZ, maxZ)};
77}
78
79void TransformGizmo::setSnapTranslate(float x, float y, float z) { snapTranslate_ = {x, y, z}; }
80
81void TransformGizmo::setSnapRotate(float degrees) { snapRotateDeg_ = degrees; }
82
83void TransformGizmo::setSnapScale(float s) { snapScale_ = s; }
84
85float TransformGizmo::getMatrix(int index) const {
86 if (index < 0 || index > 15) throw Exception("TransformGizmo::getMatrix: index 0..15");
87 glm::mat4 m = worldMatrix();
88 const float *p = glm::value_ptr(m);
89 return p[index];
90}
91
92glm::mat4 TransformGizmo::localRotationMatrix() const {
93 glm::mat4 m(1.f);
94 m = glm::rotate(m, rotation_.z, glm::vec3(0.f, 0.f, 1.f));
95 m = glm::rotate(m, rotation_.y, glm::vec3(0.f, 1.f, 0.f));
96 m = glm::rotate(m, rotation_.x, glm::vec3(1.f, 0.f, 0.f));
97 return m;
98}
99
100glm::mat4 TransformGizmo::worldMatrix() const {
101 glm::mat4 m(1.f);
102 m = glm::translate(m, position_);
103 m *= localRotationMatrix();
104 m = glm::scale(m, scale_);
105 return m;
106}
107
108glm::vec3 TransformGizmo::axisWorld(int axis) const {
109 glm::vec3 local(0.f);
110 local[axis] = 1.f;
111 if (space_ == "world" && mode_ != "bound") return local;
112 glm::mat3 R(localRotationMatrix());
113 return safeNormalize(R * local, local);
114}
115
116void TransformGizmo::colorForAxis(const std::string &axis, glm::vec4 &out) const {
117 bool active = (axis == activeAxis_ || axis == hoverAxis_);
118 float boost = active ? 1.f : 0.75f;
119 if (axis == "x")
120 out = {1.f * boost, 0.2f, 0.2f, 1.f};
121 else if (axis == "y")
122 out = {0.2f, 1.f * boost, 0.2f, 1.f};
123 else if (axis == "z")
124 out = {0.25f, 0.45f, 1.f * boost, 1.f};
125 else if (axis == "xy")
126 out = {1.f * boost, 1.f * boost, 0.2f, 0.85f};
127 else if (axis == "yz")
128 out = {0.2f, 1.f * boost, 1.f * boost, 0.85f};
129 else if (axis == "xz")
130 out = {1.f * boost, 0.2f, 1.f * boost, 0.85f};
131 else if (axis == "xyz")
132 out = {0.9f * boost, 0.9f * boost, 0.9f * boost, 1.f};
133 else
134 out = {0.8f * boost, 0.8f * boost, 0.2f, 1.f};
135}
136
138 parts_.clear();
139 const glm::vec3 origin = position_;
140
141 auto addAxis = [&](const char *axisName, int ai, const char *kind) {
142 Part p;
143 p.kind = kind;
144 p.axis = axisName;
145 p.origin = origin;
146 p.dir = axisWorld(ai);
147 p.length = size_;
148 p.radius = size_ * 0.04f;
149 colorForAxis(p.axis, p.color);
150 parts_.push_back(p);
151 };
152
153 if (mode_ == "translate") {
154 addAxis("x", 0, "axis");
155 addAxis("y", 1, "axis");
156 addAxis("z", 2, "axis");
157 // plane handles
158 for (const char *plane : {"xy", "yz", "xz"}) {
159 Part p;
160 p.kind = "plane";
161 p.axis = plane;
162 p.origin = origin;
163 if (std::strcmp(plane, "xy") == 0)
164 p.dir = glm::normalize(axisWorld(0) + axisWorld(1));
165 else if (std::strcmp(plane, "yz") == 0)
166 p.dir = glm::normalize(axisWorld(1) + axisWorld(2));
167 else
168 p.dir = glm::normalize(axisWorld(0) + axisWorld(2));
169 p.length = size_ * kPlaneHitSize;
170 p.radius = size_ * kPlaneHitSize;
171 colorForAxis(p.axis, p.color);
172 parts_.push_back(p);
173 }
174 Part c;
175 c.kind = "center";
176 c.axis = "xyz";
177 c.origin = origin;
178 c.dir = {0.f, 1.f, 0.f};
179 c.length = 0.f;
180 c.radius = size_ * 0.06f;
181 colorForAxis(c.axis, c.color);
182 parts_.push_back(c);
183 } else if (mode_ == "rotate") {
184 addAxis("x", 0, "ring");
185 addAxis("y", 1, "ring");
186 addAxis("z", 2, "ring");
187 for (auto &p : parts_) {
188 p.length = 0.f;
189 p.radius = size_;
190 }
191 } else if (mode_ == "scale") {
192 addAxis("x", 0, "axis");
193 addAxis("y", 1, "axis");
194 addAxis("z", 2, "axis");
195 Part u;
196 u.kind = "center";
197 u.axis = "xyz";
198 u.origin = origin;
199 u.dir = {0.f, 1.f, 0.f};
200 u.radius = size_ * 0.08f;
201 colorForAxis(u.axis, u.color);
202 parts_.push_back(u);
203 } else { // bound
204 const char *names[] = {"bx", "by", "bz", "bnx", "bny", "bnz"};
205 glm::vec3 centers[6] = {
206 {boundsMax_.x, 0.f, 0.f}, {0.f, boundsMax_.y, 0.f}, {0.f, 0.f, boundsMax_.z},
207 {boundsMin_.x, 0.f, 0.f}, {0.f, boundsMin_.y, 0.f}, {0.f, 0.f, boundsMin_.z},
208 };
209 glm::mat3 R(localRotationMatrix());
210 for (int i = 0; i < 6; ++i) {
211 Part p;
212 p.kind = "handle";
213 p.axis = names[i];
214 glm::vec3 local = centers[i];
215 // scale local handle offset by object scale
216 local *= scale_;
217 p.origin = position_ + R * local;
218 p.dir = axisWorld(i % 3);
219 p.radius = size_ * 0.07f;
220 colorForAxis((i % 3 == 0) ? "x" : (i % 3 == 1) ? "y" : "z", p.color);
221 parts_.push_back(p);
222 }
223 Part box;
224 box.kind = "box";
225 box.axis = "bound";
226 box.origin = position_;
227 box.dir = {0.f, 1.f, 0.f};
228 box.length = glm::length(boundsMax_ - boundsMin_) * 0.5f;
229 box.radius = box.length;
230 colorForAxis("xyz", box.color);
231 parts_.push_back(box);
232 }
233}
234
235float TransformGizmo::hitAxis(const glm::vec3 &ro, const glm::vec3 &rd, int axisIndex,
236 float &outT) const {
237 glm::vec3 a = axisWorld(axisIndex);
238 glm::vec3 p0 = position_;
239 glm::vec3 p1 = position_ + a * size_;
240 // Closest approach ray-segment
241 glm::vec3 u = p1 - p0;
242 glm::vec3 v = rd;
243 glm::vec3 w = p0 - ro;
244 float aa = glm::dot(u, u);
245 float bb = glm::dot(v, v);
246 float cc = glm::dot(u, v);
247 float dd = glm::dot(u, w);
248 float ee = glm::dot(v, w);
249 float denom = aa * bb - cc * cc;
250 float sn = 0.f, tn = 0.f;
251 if (std::fabs(denom) > 1e-8f) {
252 sn = (cc * ee - bb * dd) / denom;
253 tn = (aa * ee - cc * dd) / denom;
254 }
255 sn = std::clamp(sn, 0.f, 1.f);
256 if (tn < 0.f) return -1.f;
257 glm::vec3 closestU = p0 + u * sn;
258 glm::vec3 closestV = ro + v * tn;
259 float dist = glm::length(closestU - closestV);
260 float thresh = size_ * kAxisHitRadius;
261 if (dist > thresh) return -1.f;
262 outT = tn;
263 return dist;
264}
265
266float TransformGizmo::hitPlane(const glm::vec3 &ro, const glm::vec3 &rd, int planeMask,
267 float &outT) const {
268 // planeMask: bit0=x, bit1=y, bit2=z included in plane (two bits set)
269 glm::vec3 n(0.f);
270 if ((planeMask & 1) == 0) n = axisWorld(0);
271 else if ((planeMask & 2) == 0) n = axisWorld(1);
272 else n = axisWorld(2);
273 float denom = glm::dot(n, rd);
274 if (std::fabs(denom) < 1e-6f) return -1.f;
275 float t = glm::dot(position_ - ro, n) / denom;
276 if (t < 0.f) return -1.f;
277 glm::vec3 hit = ro + rd * t;
278 glm::vec3 d = hit - position_;
279 // project onto the two axes
280 int a0 = (planeMask & 1) ? 0 : ((planeMask & 2) ? 1 : 2);
281 int a1 = (planeMask & 4) ? 2 : ((planeMask & 2) && a0 != 1 ? 1 : (a0 == 0 ? 1 : 0));
282 if (planeMask == 3) {
283 a0 = 0;
284 a1 = 1;
285 } else if (planeMask == 6) {
286 a0 = 1;
287 a1 = 2;
288 } else if (planeMask == 5) {
289 a0 = 0;
290 a1 = 2;
291 }
292 float u = glm::dot(d, axisWorld(a0));
293 float v = glm::dot(d, axisWorld(a1));
294 float lim = size_ * kPlaneHitSize;
295 float lo = size_ * 0.05f;
296 if (u < lo || v < lo || u > lim || v > lim) return -1.f;
297 outT = t;
298 return 0.f;
299}
300
301float TransformGizmo::hitRing(const glm::vec3 &ro, const glm::vec3 &rd, int axisIndex,
302 float &outT) const {
303 glm::vec3 n = axisWorld(axisIndex);
304 float denom = glm::dot(n, rd);
305 if (std::fabs(denom) < 1e-6f) return -1.f;
306 float t = glm::dot(position_ - ro, n) / denom;
307 if (t < 0.f) return -1.f;
308 glm::vec3 hit = ro + rd * t;
309 float dist = glm::length(hit - position_);
310 float target = size_;
311 float thick = size_ * kRingThickness;
312 if (std::fabs(dist - target) > thick) return -1.f;
313 outT = t;
314 return std::fabs(dist - target);
315}
316
317float TransformGizmo::hitBoundHandle(const glm::vec3 &ro, const glm::vec3 &rd, int handle,
318 float &outT) const {
319 if (handle < 0 || handle >= static_cast<int>(parts_.size())) return -1.f;
320 const Part &p = parts_[handle];
321 if (p.kind != "handle") return -1.f;
322 // sphere hit
323 glm::vec3 oc = ro - p.origin;
324 float b = glm::dot(oc, rd);
325 float c = glm::dot(oc, oc) - p.radius * p.radius;
326 float disc = b * b - c;
327 if (disc < 0.f) return -1.f;
328 float t = -b - std::sqrt(disc);
329 if (t < 0.f) t = -b + std::sqrt(disc);
330 if (t < 0.f) return -1.f;
331 outT = t;
332 return 0.f;
333}
334
335std::string TransformGizmo::pick(float ox, float oy, float oz, float dx, float dy, float dz) {
336 glm::vec3 ro(ox, oy, oz);
337 glm::vec3 rd = safeNormalize(glm::vec3(dx, dy, dz), glm::vec3(0.f, 0.f, -1.f));
338 hoverAxis_.clear();
339 float bestT = 1e30f;
340 std::string best;
341
342 auto consider = [&](const std::string &axis, float score, float t) {
343 if (score < 0.f) return;
344 if (t < bestT) {
345 bestT = t;
346 best = axis;
347 }
348 };
349
350 if (mode_ == "translate") {
351 float t;
352 for (int i = 0; i < 3; ++i) {
353 float s = hitAxis(ro, rd, i, t);
354 consider(i == 0 ? "x" : i == 1 ? "y" : "z", s, t);
355 }
356 float tp;
357 if (hitPlane(ro, rd, 3, tp) >= 0.f) consider("xy", 0.f, tp);
358 if (hitPlane(ro, rd, 6, tp) >= 0.f) consider("yz", 0.f, tp);
359 if (hitPlane(ro, rd, 5, tp) >= 0.f) consider("xz", 0.f, tp);
360 // center sphere
361 glm::vec3 oc = ro - position_;
362 float b = glm::dot(oc, rd);
363 float c = glm::dot(oc, oc) - (size_ * 0.06f) * (size_ * 0.06f);
364 float disc = b * b - c;
365 if (disc >= 0.f) {
366 float t = -b - std::sqrt(disc);
367 if (t >= 0.f) consider("xyz", 0.f, t);
368 }
369 } else if (mode_ == "rotate") {
370 float t;
371 for (int i = 0; i < 3; ++i) {
372 float s = hitRing(ro, rd, i, t);
373 consider(i == 0 ? "x" : i == 1 ? "y" : "z", s, t);
374 }
375 } else if (mode_ == "scale") {
376 float t;
377 for (int i = 0; i < 3; ++i) {
378 float s = hitAxis(ro, rd, i, t);
379 consider(i == 0 ? "x" : i == 1 ? "y" : "z", s, t);
380 }
381 glm::vec3 oc = ro - position_;
382 float rad = size_ * 0.08f;
383 float b = glm::dot(oc, rd);
384 float c = glm::dot(oc, oc) - rad * rad;
385 float disc = b * b - c;
386 if (disc >= 0.f) {
387 float t = -b - std::sqrt(disc);
388 if (t >= 0.f) consider("xyz", 0.f, t);
389 }
390 } else {
391 for (int i = 0; i < static_cast<int>(parts_.size()); ++i) {
392 float t;
393 float s = hitBoundHandle(ro, rd, i, t);
394 if (s >= 0.f) consider(parts_[i].axis, s, t);
395 }
396 }
397
398 hoverAxis_ = best;
399 rebuildParts();
400 return best;
401}
402
403glm::vec3 TransformGizmo::projectToDragPlane(const glm::vec3 &ro, const glm::vec3 &rd) const {
404 float denom = glm::dot(dragPlaneNormal_, rd);
405 if (std::fabs(denom) < 1e-8f) {
406 // fallback: project along axis using perpendicular plane from camera-ish guess
407 return dragStartHit_;
408 }
409 float t = glm::dot(dragStartHit_ - ro, dragPlaneNormal_) / denom;
410 return ro + rd * t;
411}
412
413void TransformGizmo::applySnapTranslate(glm::vec3 &v) const {
414 if (snapTranslate_.x > 0.f) v.x = snapValue(v.x, snapTranslate_.x);
415 if (snapTranslate_.y > 0.f) v.y = snapValue(v.y, snapTranslate_.y);
416 if (snapTranslate_.z > 0.f) v.z = snapValue(v.z, snapTranslate_.z);
417}
418
419float TransformGizmo::applySnapRotate(float radians) const {
420 if (snapRotateDeg_ <= 0.f) return radians;
421 float deg = radians * (180.f / kPi);
422 deg = snapValue(deg, snapRotateDeg_);
423 return deg * (kPi / 180.f);
424}
425
426float TransformGizmo::applySnapScale(float s) const {
427 if (snapScale_ <= 0.f) return s;
428 return snapValue(s, snapScale_);
429}
430
431bool TransformGizmo::beginDrag(const std::string &axis, float ox, float oy, float oz, float dx,
432 float dy, float dz) {
433 if (axis.empty()) return false;
434 activeAxis_ = axis;
435 hoverAxis_ = axis;
436 dragging_ = true;
437 dragStartPos_ = position_;
438 dragStartRot_ = rotation_;
439 dragStartScale_ = scale_;
440
441 glm::vec3 ro(ox, oy, oz);
442 glm::vec3 rd = safeNormalize(glm::vec3(dx, dy, dz), glm::vec3(0.f, 0.f, -1.f));
443
444 if (mode_ == "translate" || mode_ == "scale" || mode_ == "bound") {
445 if (axis == "x" || axis == "bx" || axis == "bnx")
446 dragAxisDir_ = axisWorld(0);
447 else if (axis == "y" || axis == "by" || axis == "bny")
448 dragAxisDir_ = axisWorld(1);
449 else if (axis == "z" || axis == "bz" || axis == "bnz")
450 dragAxisDir_ = axisWorld(2);
451 else if (axis == "xy")
452 dragPlaneNormal_ = axisWorld(2);
453 else if (axis == "yz")
454 dragPlaneNormal_ = axisWorld(0);
455 else if (axis == "xz")
456 dragPlaneNormal_ = axisWorld(1);
457 else
458 dragPlaneNormal_ = safeNormalize(glm::cross(rd, glm::vec3(0.f, 1.f, 0.f)),
459 glm::vec3(0.f, 0.f, 1.f));
460
461 if (axis == "x" || axis == "y" || axis == "z" || axis == "bx" || axis == "by" ||
462 axis == "bz" || axis == "bnx" || axis == "bny" || axis == "bnz") {
463 // plane facing camera containing axis
464 glm::vec3 side = glm::cross(dragAxisDir_, rd);
465 if (glm::length(side) < 1e-5f) side = glm::cross(dragAxisDir_, glm::vec3(0.f, 1.f, 0.f));
466 dragPlaneNormal_ = safeNormalize(glm::cross(side, dragAxisDir_), glm::vec3(0.f, 1.f, 0.f));
467 }
468 if (axis == "xyz") {
469 dragPlaneNormal_ = -rd;
470 }
471 } else { // rotate
472 int ai = axis == "x" ? 0 : axis == "y" ? 1 : 2;
473 dragAxisDir_ = axisWorld(ai);
474 dragPlaneNormal_ = dragAxisDir_;
475 }
476
477 float denom = glm::dot(dragPlaneNormal_, rd);
478 if (std::fabs(denom) > 1e-8f) {
479 float t = glm::dot(position_ - ro, dragPlaneNormal_) / denom;
480 dragStartHit_ = ro + rd * t;
481 } else {
482 dragStartHit_ = position_;
483 }
484 rebuildParts();
485 return true;
486}
487
488bool TransformGizmo::updateDrag(float ox, float oy, float oz, float dx, float dy, float dz) {
489 if (!dragging_) return false;
490 glm::vec3 ro(ox, oy, oz);
491 glm::vec3 rd = safeNormalize(glm::vec3(dx, dy, dz), glm::vec3(0.f, 0.f, -1.f));
492 glm::vec3 hit = projectToDragPlane(ro, rd);
493 glm::vec3 delta = hit - dragStartHit_;
494
495 if (mode_ == "translate") {
496 glm::vec3 move(0.f);
497 if (activeAxis_ == "x" || activeAxis_ == "y" || activeAxis_ == "z") {
498 float dist = glm::dot(delta, dragAxisDir_);
499 move = dragAxisDir_ * dist;
500 } else if (activeAxis_ == "xy") {
501 move = axisWorld(0) * glm::dot(delta, axisWorld(0)) +
502 axisWorld(1) * glm::dot(delta, axisWorld(1));
503 } else if (activeAxis_ == "yz") {
504 move = axisWorld(1) * glm::dot(delta, axisWorld(1)) +
505 axisWorld(2) * glm::dot(delta, axisWorld(2));
506 } else if (activeAxis_ == "xz") {
507 move = axisWorld(0) * glm::dot(delta, axisWorld(0)) +
508 axisWorld(2) * glm::dot(delta, axisWorld(2));
509 } else if (activeAxis_ == "xyz") {
510 move = delta;
511 }
512 position_ = dragStartPos_ + move;
513 applySnapTranslate(position_);
514 } else if (mode_ == "rotate") {
515 glm::vec3 from = safeNormalize(dragStartHit_ - position_, dragAxisDir_);
516 glm::vec3 to = safeNormalize(hit - position_, from);
517 // angle around dragAxisDir_
518 glm::vec3 c = glm::cross(from, to);
519 float sinA = glm::dot(c, dragAxisDir_);
520 float cosA = glm::clamp(glm::dot(from, to), -1.f, 1.f);
521 float ang = std::atan2(sinA, cosA);
522 ang = applySnapRotate(ang);
523 rotation_ = dragStartRot_;
524 if (activeAxis_ == "x")
525 rotation_.x = dragStartRot_.x + ang;
526 else if (activeAxis_ == "y")
527 rotation_.y = dragStartRot_.y + ang;
528 else
529 rotation_.z = dragStartRot_.z + ang;
530 } else if (mode_ == "scale") {
531 float dist = glm::dot(delta, dragAxisDir_);
532 float factor = 1.f + dist / std::max(size_, 1e-3f);
533 if (activeAxis_ == "xyz") {
534 float s = applySnapScale(std::max(0.01f, dragStartScale_.x * factor));
535 scale_ = {s, s, s};
536 } else {
537 scale_ = dragStartScale_;
538 float s = applySnapScale(std::max(0.01f, (activeAxis_ == "x" ? dragStartScale_.x
539 : activeAxis_ == "y" ? dragStartScale_.y
540 : dragStartScale_.z) *
541 factor));
542 if (activeAxis_ == "x")
543 scale_.x = s;
544 else if (activeAxis_ == "y")
545 scale_.y = s;
546 else
547 scale_.z = s;
548 }
549 } else { // bound — move corresponding face by translating position / expanding bounds
550 float dist = glm::dot(delta, dragAxisDir_);
551 if (activeAxis_ == "bx")
552 boundsMax_.x = std::max(boundsMin_.x + 0.01f, boundsMax_.x + dist / std::max(scale_.x, 1e-3f));
553 else if (activeAxis_ == "by")
554 boundsMax_.y = std::max(boundsMin_.y + 0.01f, boundsMax_.y + dist / std::max(scale_.y, 1e-3f));
555 else if (activeAxis_ == "bz")
556 boundsMax_.z = std::max(boundsMin_.z + 0.01f, boundsMax_.z + dist / std::max(scale_.z, 1e-3f));
557 else if (activeAxis_ == "bnx")
558 boundsMin_.x = std::min(boundsMax_.x - 0.01f, boundsMin_.x + dist / std::max(scale_.x, 1e-3f));
559 else if (activeAxis_ == "bny")
560 boundsMin_.y = std::min(boundsMax_.y - 0.01f, boundsMin_.y + dist / std::max(scale_.y, 1e-3f));
561 else if (activeAxis_ == "bnz")
562 boundsMin_.z = std::min(boundsMax_.z - 0.01f, boundsMin_.z + dist / std::max(scale_.z, 1e-3f));
563 // reset start so incremental face edits accumulate smoothly
564 dragStartHit_ = hit;
565 }
566
567 rebuildParts();
568 return true;
569}
570
572 dragging_ = false;
573 activeAxis_.clear();
574 rebuildParts();
575}
576
577bool TransformGizmo::validPart(int index) const {
578 return index >= 0 && index < static_cast<int>(parts_.size());
579}
580
581std::string TransformGizmo::getPartKind(int index) const {
582 if (!validPart(index)) throw Exception("TransformGizmo::getPartKind: bad index");
583 return parts_[index].kind;
584}
585std::string TransformGizmo::getPartAxis(int index) const {
586 if (!validPart(index)) throw Exception("TransformGizmo::getPartAxis: bad index");
587 return parts_[index].axis;
588}
589float TransformGizmo::getPartColorR(int index) const {
590 if (!validPart(index)) throw Exception("TransformGizmo::getPartColorR: bad index");
591 return parts_[index].color.r;
592}
593float TransformGizmo::getPartColorG(int index) const {
594 if (!validPart(index)) throw Exception("TransformGizmo::getPartColorG: bad index");
595 return parts_[index].color.g;
596}
597float TransformGizmo::getPartColorB(int index) const {
598 if (!validPart(index)) throw Exception("TransformGizmo::getPartColorB: bad index");
599 return parts_[index].color.b;
600}
601float TransformGizmo::getPartColorA(int index) const {
602 if (!validPart(index)) throw Exception("TransformGizmo::getPartColorA: bad index");
603 return parts_[index].color.a;
604}
605float TransformGizmo::getPartOriginX(int index) const {
606 if (!validPart(index)) throw Exception("TransformGizmo::getPartOriginX: bad index");
607 return parts_[index].origin.x;
608}
609float TransformGizmo::getPartOriginY(int index) const {
610 if (!validPart(index)) throw Exception("TransformGizmo::getPartOriginY: bad index");
611 return parts_[index].origin.y;
612}
613float TransformGizmo::getPartOriginZ(int index) const {
614 if (!validPart(index)) throw Exception("TransformGizmo::getPartOriginZ: bad index");
615 return parts_[index].origin.z;
616}
617float TransformGizmo::getPartDirX(int index) const {
618 if (!validPart(index)) throw Exception("TransformGizmo::getPartDirX: bad index");
619 return parts_[index].dir.x;
620}
621float TransformGizmo::getPartDirY(int index) const {
622 if (!validPart(index)) throw Exception("TransformGizmo::getPartDirY: bad index");
623 return parts_[index].dir.y;
624}
625float TransformGizmo::getPartDirZ(int index) const {
626 if (!validPart(index)) throw Exception("TransformGizmo::getPartDirZ: bad index");
627 return parts_[index].dir.z;
628}
629float TransformGizmo::getPartLength(int index) const {
630 if (!validPart(index)) throw Exception("TransformGizmo::getPartLength: bad index");
631 return parts_[index].length;
632}
633float TransformGizmo::getPartRadius(int index) const {
634 if (!validPart(index)) throw Exception("TransformGizmo::getPartRadius: bad index");
635 return parts_[index].radius;
636}
637
638} // namespace eve::editor
bool active
Definition CardTypes.cpp:34
float degrees
Definition CardTypes.cpp:33
Tok kind
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int w
uint32_t a
uint32_t b
uint32_t c
glm::vec4 p[6]
int d
int v
float step
Definition TreeMesh.cpp:196
float m[16]
uint32_t s
Definition Weather.cpp:28
float getPartDirY(int index) const
void setSnapRotate(float degrees)
float getPartColorR(int index) const
void rebuildParts()
Rebuild draw parts for current mode/space (call after TRS/mode change).
float getPartDirX(int index) const
std::string pick(float ox, float oy, float oz, float dx, float dy, float dz)
Ray pick against active mode handles. Returns axis id: "x"|"y"|"z"|"xy"|"yz"|"xz"|"xyz"|"bx"|…|"bz"|"...
float getPartDirZ(int index) const
std::string getPartKind(int index) const
float getPartRadius(int index) const
float getMatrix(int index) const
Column-major matrix element 0..15 of current TRS.
float getPartColorG(int index) const
void setBounds(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Local AABB extents for bound mode (relative to object origin).
float getPartColorB(int index) const
bool beginDrag(const std::string &axis, float ox, float oy, float oz, float dx, float dy, float dz)
float getPartOriginY(int index) const
void setSnapTranslate(float x, float y, float z)
float getPartLength(int index) const
void setPosition(float x, float y, float z)
float getPartColorA(int index) const
bool updateDrag(float ox, float oy, float oz, float dx, float dy, float dz)
float getPartOriginX(int index) const
void setRotationEuler(float x, float y, float z)
Euler radians, XYZ order.
void setMode(const std::string &mode)
void setScale(float x, float y, float z)
std::string getPartAxis(int index) const
float getPartOriginZ(int index) const
void setSpace(const std::string &space)