Overte C++ Documentation
RegisteredMetaTypes.h
1 //
2 // RegisteredMetaTypes.h
3 // libraries/shared/src
4 //
5 // Created by Stephen Birarda on 10/3/13.
6 // Copyright 2013 High Fidelity, Inc.
7 // Copyright 2023 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 // SPDX-License-Identifier: Apache-2.0
12 //
13 
14 #ifndef hifi_RegisteredMetaTypes_h
15 #define hifi_RegisteredMetaTypes_h
16 
17 #include <QtCore/QUuid>
18 #include <QtCore/QUrl>
19 
20 #include <glm/glm.hpp>
21 #include <glm/gtc/quaternion.hpp>
22 
23 #include "AACube.h"
24 #include "ShapeInfo.h"
25 #include "SharedUtil.h"
26 #include "shared/Bilateral.h"
27 #include "Transform.h"
28 #include "PhysicsCollisionGroups.h"
29 #include "StencilMaskMode.h"
30 
31 class QColor;
32 class QUrl;
33 
34 Q_DECLARE_METATYPE(uint16_t)
35 Q_DECLARE_METATYPE(glm::vec2)
36 Q_DECLARE_METATYPE(glm::u8vec3)
37 Q_DECLARE_METATYPE(glm::vec3)
38 Q_DECLARE_METATYPE(glm::vec4)
39 Q_DECLARE_METATYPE(glm::quat)
40 Q_DECLARE_METATYPE(glm::mat4)
41 Q_DECLARE_METATYPE(QVector<float>)
42 Q_DECLARE_METATYPE(unsigned int)
43 Q_DECLARE_METATYPE(QVector<unsigned int>)
44 Q_DECLARE_METATYPE(AACube)
45 Q_DECLARE_METATYPE(std::function<void()>);
46 Q_DECLARE_METATYPE(std::function<QVariant()>);
47 
48 // Mat4
49 /*@jsdoc
50  * A 4 x 4 matrix, typically containing a scale, rotation, and translation transform. See also the {@link Mat4(0)|Mat4} object.
51  *
52  * @typedef {object} Mat4
53  * @property {number} r0c0 - Row 0, column 0 value.
54  * @property {number} r1c0 - Row 1, column 0 value.
55  * @property {number} r2c0 - Row 2, column 0 value.
56  * @property {number} r3c0 - Row 3, column 0 value.
57  * @property {number} r0c1 - Row 0, column 1 value.
58  * @property {number} r1c1 - Row 1, column 1 value.
59  * @property {number} r2c1 - Row 2, column 1 value.
60  * @property {number} r3c1 - Row 3, column 1 value.
61  * @property {number} r0c2 - Row 0, column 2 value.
62  * @property {number} r1c2 - Row 1, column 2 value.
63  * @property {number} r2c2 - Row 2, column 2 value.
64  * @property {number} r3c2 - Row 3, column 2 value.
65  * @property {number} r0c3 - Row 0, column 3 value.
66  * @property {number} r1c3 - Row 1, column 3 value.
67  * @property {number} r2c3 - Row 2, column 3 value.
68  * @property {number} r3c3 - Row 3, column 3 value.
69  */
70 QVariant mat4ToVariant(const glm::mat4& mat4);
71 glm::mat4 mat4FromVariant(const QVariant& object, bool& valid);
72 glm::mat4 mat4FromVariant(const QVariant& object);
73 
74 /*@jsdoc
75 * A 2-dimensional vector.
76 *
77 * @typedef {object} Vec2
78 * @property {number} x - X-coordinate of the vector. Synonyms: <code>u</code>.
79 * @property {number} y - Y-coordinate of the vector. Synonyms: <code>v</code>.
80 * @example <caption>Vec2s can be set in multiple ways and modified with their aliases, but still stringify in the same way</caption>
81 * Entities.editEntity(<id>, { materialMappingPos: { x: 0.1, y: 0.2 }}); // { x: 0.1, y: 0.2 }
82 * Entities.editEntity(<id>, { materialMappingPos: { u: 0.3, v: 0.4 }}); // { x: 0.3, y: 0.4 }
83 * Entities.editEntity(<id>, { materialMappingPos: [0.5, 0.6] }); // { x: 0.5, y: 0.6 }
84 * Entities.editEntity(<id>, { materialMappingPos: 0.7 }); // { x: 0.7, y: 0.7 }
85 * var color = Entities.getEntityProperties(<id>).materialMappingPos; // { x: 0.7, y: 0.7 }
86 * color.v = 0.8; // { x: 0.7, y: 0.8 }
87 */
88 QVariant vec2ToVariant(const glm::vec2& vec2);
89 glm::vec2 vec2FromVariant(const QVariant& object, bool& valid);
90 glm::vec2 vec2FromVariant(const QVariant& object);
91 
92 /*@jsdoc
93 * A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object.
94 *
95 * @typedef {object} Vec3
96 * @property {number} x - X-coordinate of the vector. Synonyms: <code>r</code>, <code>red</code>.
97 * @property {number} y - Y-coordinate of the vector. Synonyms: <code>g</code>, <code>green</code>.
98 * @property {number} z - Z-coordinate of the vector. Synonyms: <code>b</code>, <code>blue</code>.
99 * @example <caption>Vec3 values can be set in multiple ways and modified with their aliases, but still stringify in the same
100 * way.</caption>
101 * Entities.editEntity(<id>, { position: { x: 1, y: 2, z: 3 }}); // { x: 1, y: 2, z: 3 }
102 * Entities.editEntity(<id>, { position: { r: 4, g: 5, b: 6 }}); // { x: 4, y: 5, z: 6 }
103 * Entities.editEntity(<id>, { position: { red: 7, green: 8, blue: 9 }}); // { x: 7, y: 8, z: 9 }
104 * Entities.editEntity(<id>, { position: [10, 11, 12] }); // { x: 10, y: 11, z: 12 }
105 * Entities.editEntity(<id>, { position: 13 }); // { x: 13, y: 13, z: 13 }
106 * var position = Entities.getEntityProperties(<id>).position; // { x: 13, y: 13, z: 13 }
107 * position.g = 14; // { x: 13, y: 14, z: 13 }
108 * position.blue = 15; // { x: 13, y: 14, z: 15 }
109 * Entities.editEntity(<id>, { position: "red"}); // { x: 255, y: 0, z: 0 }
110 * Entities.editEntity(<id>, { position: "#00FF00"}); // { x: 0, y: 255, z: 0 }
111 */
112 QVariant vec3toVariant(const glm::vec3& vec3);
113 glm::vec3 vec3FromVariant(const QVariant &object, bool& valid);
114 glm::vec3 vec3FromVariant(const QVariant &object);
115 
116 /*@jsdoc
117  * A color vector. See also the {@link Vec3(0)|Vec3} object.
118  *
119  * @typedef {object} Color
120  * @property {number} red - Red component value. Integer in the range <code>0</code> - <code>255</code>. Synonyms: <code>r</code>, <code>x</code>.
121  * @property {number} green - Green component value. Integer in the range <code>0</code> - <code>255</code>. Synonyms: <code>g</code>, <code>y</code>.
122  * @property {number} blue - Blue component value. Integer in the range <code>0</code> - <code>255</code>. Synonyms: <code>b</code>, <code>z</code>.
123  * @example <caption>Colors can be set in multiple ways and modified with their aliases, but still stringify in the same way</caption>
124  * Entities.editEntity(<id>, { color: { x: 1, y: 2, z: 3 }}); // { red: 1, green: 2, blue: 3 }
125  * Entities.editEntity(<id>, { color: { r: 4, g: 5, b: 6 }}); // { red: 4, green: 5, blue: 6 }
126  * Entities.editEntity(<id>, { color: { red: 7, green: 8, blue: 9 }}); // { red: 7, green: 8, blue: 9 }
127  * Entities.editEntity(<id>, { color: [10, 11, 12] }); // { red: 10, green: 11, blue: 12 }
128  * Entities.editEntity(<id>, { color: 13 }); // { red: 13, green: 13, blue: 13 }
129  * var color = Entities.getEntityProperties(<id>).color; // { red: 13, green: 13, blue: 13 }
130  * color.g = 14; // { red: 13, green: 14, blue: 13 }
131  * color.blue = 15; // { red: 13, green: 14, blue: 15 }
132  * Entities.editEntity(<id>, { color: "red"}); // { red: 255, green: 0, blue: 0 }
133  * Entities.editEntity(<id>, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 }
134  */
135 /*@jsdoc
136  * A color vector with real values. Values may also be <code>null</code>. See also the {@link Vec3(0)|Vec3} object.
137  *
138  * @typedef {object} ColorFloat
139  * @property {number} red - Red component value. Real in the range <code>0</code> - <code>255</code>. Synonyms: <code>r</code>, <code>x</code>.
140  * @property {number} green - Green component value. Real in the range <code>0</code> - <code>255</code>. Synonyms: <code>g</code>, <code>y</code>.
141  * @property {number} blue - Blue component value. Real in the range <code>0</code> - <code>255</code>. Synonyms: <code>b</code>, <code>z</code>.
142  * @example <caption>ColorFloats can be set in multiple ways and modified with their aliases, but still stringify in the same way</caption>
143  * Entities.editEntity(<id>, { color: { x: 1, y: 2, z: 3 }}); // { red: 1, green: 2, blue: 3 }
144  * Entities.editEntity(<id>, { color: { r: 4, g: 5, b: 6 }}); // { red: 4, green: 5, blue: 6 }
145  * Entities.editEntity(<id>, { color: { red: 7, green: 8, blue: 9 }}); // { red: 7, green: 8, blue: 9 }
146  * Entities.editEntity(<id>, { color: [10, 11, 12] }); // { red: 10, green: 11, blue: 12 }
147  * Entities.editEntity(<id>, { color: 13 }); // { red: 13, green: 13, blue: 13 }
148  * var color = Entities.getEntityProperties(<id>).color; // { red: 13, green: 13, blue: 13 }
149  * color.g = 14; // { red: 13, green: 14, blue: 13 }
150  * color.blue = 15; // { red: 13, green: 14, blue: 15 }
151  * Entities.editEntity(<id>, { color: "red"}); // { red: 255, green: 0, blue: 0 }
152  * Entities.editEntity(<id>, { color: "#00FF00"}); // { red: 0, green: 255, blue: 0 }
153  */
154 QVariant u8vec3toVariant(const glm::u8vec3& vec3);
155 QVariant u8vec3ColortoVariant(const glm::u8vec3& vec3);
156 glm::u8vec3 u8vec3FromVariant(const QVariant &object, bool& valid);
157 glm::u8vec3 u8vec3FromVariant(const QVariant &object);
158 
159 /*@jsdoc
160  * A 4-dimensional vector.
161  *
162  * @typedef {object} Vec4
163  * @property {number} x - X-coordinate of the vector.
164  * @property {number} y - Y-coordinate of the vector.
165  * @property {number} z - Z-coordinate of the vector.
166  * @property {number} w - W-coordinate of the vector.
167  */
168 QVariant vec4toVariant(const glm::vec4& vec4);
169 glm::vec4 vec4FromVariant(const QVariant &object, bool& valid);
170 glm::vec4 vec4FromVariant(const QVariant &object);
171 
172 // Quaternions
173 QVariant quatToVariant(const glm::quat& quat);
174 glm::quat quatFromVariant(const QVariant &object, bool& isValid);
175 glm::quat quatFromVariant(const QVariant &object);
176 
177 /*@jsdoc
178  * Defines a rectangular portion of an image or screen, or similar.
179  * @typedef {object} Rect
180  * @property {number} x - Left, x-coordinate value.
181  * @property {number} y - Top, y-coordinate value.
182  * @property {number} width - Width of the rectangle.
183  * @property {number} height - Height of the rectangle.
184  */
185 QRect qRectFromVariant(const QVariant& object, bool& isValid);
186 QRect qRectFromVariant(const QVariant& object);
187 QVariant qRectToVariant(const QRect& rect);
188 
189 QRectF qRectFFromVariant(const QVariant& object, bool& isValid);
190 QRectF qRectFFromVariant(const QVariant& object);
191 QVariant qRectFToVariant(const QRectF& rect);
192 
193 // MathPicks also have to overide operator== for their type
194 class MathPick {
195 public:
196  virtual ~MathPick() {}
197  virtual operator bool() const = 0;
198  virtual QVariantMap toVariantMap() const = 0;
199 };
200 
201 /*@jsdoc
202  * A vector with a starting point. It is used, for example, when finding entities or avatars that lie under a mouse click or
203  * intersect a laser beam.
204  *
205  * @typedef {object} PickRay
206  * @property {Vec3} origin - The starting position of the ray.
207  * @property {Vec3} direction - The direction that the ray travels.
208  * @property {Vec3} unmodifiedDirection - The direction that the ray would travel, if not for applied effects like delays.
209  */
210 class PickRay : public MathPick {
211 public:
212  PickRay() : origin(NAN), direction(NAN), unmodifiedDirection(NAN) { }
213  PickRay(const QVariantMap& pickVariant) :
214  origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])),
215  unmodifiedDirection(vec3FromVariant(pickVariant["unmodifiedDirection"])) {}
216  PickRay(const glm::vec3& origin, const glm::vec3& direction) :
217  origin(origin), direction(direction), unmodifiedDirection(direction) {}
218  PickRay(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& unmodifiedDirection) :
219  origin(origin), direction(direction), unmodifiedDirection(unmodifiedDirection) {}
220  glm::vec3 origin;
221  glm::vec3 direction;
222  glm::vec3 unmodifiedDirection;
223 
224  operator bool() const override {
225  return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(direction)) || glm::any(glm::isnan(unmodifiedDirection)));
226  }
227  bool operator==(const PickRay& other) const {
228  return (origin == other.origin && direction == other.direction && unmodifiedDirection == other.unmodifiedDirection);
229  }
230  QVariantMap toVariantMap() const override {
231  QVariantMap pickRay;
232  pickRay["origin"] = vec3toVariant(origin);
233  pickRay["direction"] = vec3toVariant(direction);
234  pickRay["unmodifiedDirection"] = vec3toVariant(unmodifiedDirection);
235  return pickRay;
236  }
237 };
238 Q_DECLARE_METATYPE(PickRay)
239 
240 /*@jsdoc
241  * The tip of a stylus.
242  *
243  * @typedef {object} StylusTip
244  * @property {number} side - The hand that the stylus is attached to: <code>0</code> for left hand, <code>1</code> for the
245  * right hand, <code>-1</code> for invalid.
246  * @property {Vec3} tipOffset - The position of the stylus tip relative to the body of the stylus.
247  * @property {Vec3} position - The position of the stylus tip.
248  * @property {Quat} orientation - The orientation of the stylus.
249  * @property {Vec3} velocity - The velocity of the stylus tip.
250  */
251 class StylusTip : public MathPick {
252 public:
253  StylusTip() : position(NAN), velocity(NAN) {}
254  StylusTip(const bilateral::Side& side, const glm::vec3& tipOffset = Vectors::ZERO ,const glm::vec3& position = Vectors::ZERO,
255  const glm::quat& orientation = Quaternions::IDENTITY, const glm::vec3& velocity = Vectors::ZERO) :
256  side(side), tipOffset(tipOffset), position(position), orientation(orientation), velocity(velocity) {}
257  StylusTip(const QVariantMap& pickVariant) : side(bilateral::Side(pickVariant["side"].toInt())), tipOffset(vec3FromVariant(pickVariant["tipOffset"])),
258  position(vec3FromVariant(pickVariant["position"])), orientation(quatFromVariant(pickVariant["orientation"])), velocity(vec3FromVariant(pickVariant["velocity"])) {}
259 
260  bilateral::Side side { bilateral::Side::Invalid };
261  glm::vec3 tipOffset;
262  glm::vec3 position;
263  glm::quat orientation;
264  glm::vec3 velocity;
265 
266  operator bool() const override { return side != bilateral::Side::Invalid; }
267 
268  bool operator==(const StylusTip& other) const {
269  return (side == other.side && tipOffset == other.tipOffset && position == other.position && orientation == other.orientation && velocity == other.velocity);
270  }
271 
272  QVariantMap toVariantMap() const override {
273  QVariantMap stylusTip;
274  stylusTip["side"] = (int)side;
275  stylusTip["tipOffset"] = vec3toVariant(tipOffset);
276  stylusTip["position"] = vec3toVariant(position);
277  stylusTip["orientation"] = quatToVariant(orientation);
278  stylusTip["velocity"] = vec3toVariant(velocity);
279  return stylusTip;
280  }
281 };
282 
283 /*@jsdoc
284 * A parabola defined by a starting point, initial velocity, and acceleration. It is used, for example, when finding entities or
285 * avatars that intersect a parabolic beam.
286 *
287 * @typedef {object} PickParabola
288 * @property {Vec3} origin - The starting position of the parabola, i.e., the initial position of a virtual projectile whose
289 * trajectory defines the parabola.
290 * @property {Vec3} velocity - The starting velocity of the parabola in m/s, i.e., the initial speed of a virtual projectile
291 * whose trajectory defines the parabola.
292 * @property {Vec3} acceleration - The acceleration that the parabola experiences in m/s<sup>2</sup>, i.e., the acceleration of
293 * a virtual projectile whose trajectory defines the parabola, both magnitude and direction.
294 */
295 class PickParabola : public MathPick {
296 public:
297  PickParabola() : origin(NAN), velocity(NAN), acceleration(NAN) { }
298  PickParabola(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), velocity(vec3FromVariant(pickVariant["velocity"])), acceleration(vec3FromVariant(pickVariant["acceleration"])) {}
299  PickParabola(const glm::vec3& origin, const glm::vec3 velocity, const glm::vec3 acceleration) : origin(origin), velocity(velocity), acceleration(acceleration) {}
300  glm::vec3 origin;
301  glm::vec3 velocity;
302  glm::vec3 acceleration;
303 
304  operator bool() const override {
305  return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(velocity)) || glm::any(glm::isnan(acceleration)));
306  }
307  bool operator==(const PickParabola& other) const {
308  return (origin == other.origin && velocity == other.velocity && acceleration == other.acceleration);
309  }
310  QVariantMap toVariantMap() const override {
311  QVariantMap pickParabola;
312  pickParabola["origin"] = vec3toVariant(origin);
313  pickParabola["velocity"] = vec3toVariant(velocity);
314  pickParabola["acceleration"] = vec3toVariant(acceleration);
315  return pickParabola;
316  }
317 };
318 
319 class CollisionRegion : public MathPick {
320 public:
321  CollisionRegion() { }
322 
323  CollisionRegion(const CollisionRegion& collisionRegion) :
324  loaded(collisionRegion.loaded),
325  modelURL(collisionRegion.modelURL),
326  shapeInfo(std::make_shared<ShapeInfo>()),
327  transform(collisionRegion.transform),
328  threshold(collisionRegion.threshold),
329  collisionGroup(collisionRegion.collisionGroup)
330  {
331  shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString());
332  }
333 
334  CollisionRegion(const QVariantMap& pickVariant) {
335  // "loaded" is not deserialized here because there is no way to know if the shape is actually loaded
336  if (pickVariant["shape"].isValid()) {
337  auto shape = pickVariant["shape"].toMap();
338  if (!shape.empty()) {
339  ShapeType shapeType = SHAPE_TYPE_NONE;
340  if (shape["shapeType"].isValid()) {
341  shapeType = ShapeInfo::getShapeTypeForName(shape["shapeType"].toString());
342  }
343  if (shapeType >= SHAPE_TYPE_COMPOUND && shapeType <= SHAPE_TYPE_STATIC_MESH && shape["modelURL"].isValid()) {
344  QString newURL = shape["modelURL"].toString();
345  modelURL.setUrl(newURL);
346  } else {
347  modelURL.setUrl("");
348  }
349 
350  if (shape["dimensions"].isValid()) {
351  transform.setScale(vec3FromVariant(shape["dimensions"]));
352  }
353 
354  shapeInfo->setParams(shapeType, transform.getScale() / 2.0f, modelURL.toString());
355  }
356  }
357 
358  if (pickVariant["threshold"].isValid()) {
359  threshold = glm::max(0.0f, pickVariant["threshold"].toFloat());
360  }
361 
362  if (pickVariant["position"].isValid()) {
363  transform.setTranslation(vec3FromVariant(pickVariant["position"]));
364  }
365  if (pickVariant["orientation"].isValid()) {
366  transform.setRotation(quatFromVariant(pickVariant["orientation"]));
367  }
368  if (pickVariant["collisionGroup"].isValid()) {
369  collisionGroup = pickVariant["collisionGroup"].toUInt();
370  }
371  }
372 
373  /*@jsdoc
374  * A volume for checking collisions in the physics simulation.
375  * @typedef {object} CollisionRegion
376  * @property {Shape} shape - The collision region's shape and size. Dimensions are in world coordinates, but scale with the
377  * parent if defined.
378  * @property {boolean} loaded - <code>true</code> if the <code>shape</code> has no model, or has a model and it is loaded,
379  * <code>false</code> if otherwise.
380  * @property {Vec3} position - The position of the collision region, relative to the parent if defined.
381  * @property {Quat} orientation - The orientation of the collision region, relative to the parent if defined.
382  * @property {number} threshold - The approximate minimum penetration depth for a test object to be considered in contact with
383  * the collision region. The depth is in world coordinates but scales with the parent if defined.
384  * @property {CollisionMask} [collisionGroup=8] - The type of objects the collision region collides as. Objects whose collision
385  * masks overlap with the region's collision group are considered to be colliding with the region.
386  */
387 
388  /*@jsdoc
389  * A physical volume.
390  * @typedef {object} Shape
391  * @property {ShapeType} shapeType="none" - The type of shape.
392  * @property {string} [modelUrl=""] - The model to load to for the shape if <code>shapeType</code> is one of
393  * <code>"compound"</code>, <code>"simple-hull"</code>, <code>"simple-compound"</code>, or <code>"static-mesh"</code>.
394  * @property {Vec3} dimensions - The dimensions of the shape.
395  */
396 
397  QVariantMap toVariantMap() const override {
398  QVariantMap collisionRegion;
399 
400  QVariantMap shape;
401  shape["shapeType"] = ShapeInfo::getNameForShapeType(shapeInfo->getType());
402  shape["modelURL"] = modelURL.toString();
403  shape["dimensions"] = vec3toVariant(transform.getScale());
404 
405  collisionRegion["shape"] = shape;
406  collisionRegion["loaded"] = loaded;
407 
408  collisionRegion["threshold"] = threshold;
409  collisionRegion["collisionGroup"] = collisionGroup;
410 
411  collisionRegion["position"] = vec3toVariant(transform.getTranslation());
412  collisionRegion["orientation"] = quatToVariant(transform.getRotation());
413 
414  return collisionRegion;
415  }
416 
417  operator bool() const override {
418  return !std::isnan(threshold) &&
419  !(glm::any(glm::isnan(transform.getTranslation())) ||
420  glm::any(glm::isnan(transform.getRotation())) ||
421  shapeInfo->getType() == SHAPE_TYPE_NONE ||
422  collisionGroup == 0);
423  }
424 
425  bool operator==(const CollisionRegion& other) const {
426  return loaded == other.loaded &&
427  threshold == other.threshold &&
428  collisionGroup == other.collisionGroup &&
429  glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) &&
430  glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) &&
431  glm::all(glm::equal(transform.getScale(), other.transform.getScale())) &&
432  shapeInfo->getType() == other.shapeInfo->getType() &&
433  modelURL == other.modelURL;
434  }
435 
436  bool shouldComputeShapeInfo() const {
437  if (!(shapeInfo->getType() == SHAPE_TYPE_HULL ||
438  (shapeInfo->getType() >= SHAPE_TYPE_COMPOUND &&
439  shapeInfo->getType() <= SHAPE_TYPE_STATIC_MESH)
440  )) {
441  return false;
442  }
443 
444  if (collisionGroup == 0) {
445  return false;
446  }
447 
448  return !shapeInfo->getPointCollection().size();
449  }
450 
451  // We can't load the model here because it would create a circular dependency, so we delegate that responsibility to the owning CollisionPick
452  bool loaded { false };
453  QUrl modelURL;
454 
455  // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick
456  std::shared_ptr<ShapeInfo> shapeInfo = std::make_shared<ShapeInfo>();
457  Transform transform;
458  float threshold { 0.0f };
459  uint16_t collisionGroup { USER_COLLISION_GROUP_MY_AVATAR };
460 };
461 
462 namespace std {
463  inline void hash_combine(std::size_t& seed) { }
464 
465  template <typename T, typename... Rest>
466  inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
467  std::hash<T> hasher;
468  seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
469  hash_combine(seed, rest...);
470  }
471 
472  template <>
473  struct hash<bilateral::Side> {
474  size_t operator()(const bilateral::Side& a) const {
475  return std::hash<int>()((int)a);
476  }
477  };
478 
479  template <>
480  struct hash<glm::vec3> {
481  size_t operator()(const glm::vec3& a) const {
482  size_t result = 0;
483  hash_combine(result, a.x, a.y, a.z);
484  return result;
485  }
486  };
487 
488  template <>
489  struct hash<glm::quat> {
490  size_t operator()(const glm::quat& a) const {
491  size_t result = 0;
492  hash_combine(result, a.x, a.y, a.z, a.w);
493  return result;
494  }
495  };
496 
497  template <>
498  struct hash<Transform> {
499  size_t operator()(const Transform& a) const {
500  size_t result = 0;
501  hash_combine(result, a.getTranslation(), a.getRotation(), a.getScale());
502  return result;
503  }
504  };
505 
506  template <>
507  struct hash<PickRay> {
508  size_t operator()(const PickRay& a) const {
509  size_t result = 0;
510  hash_combine(result, a.origin, a.direction);
511  return result;
512  }
513  };
514 
515  template <>
516  struct hash<StylusTip> {
517  size_t operator()(const StylusTip& a) const {
518  size_t result = 0;
519  hash_combine(result, a.side, a.position, a.orientation, a.velocity);
520  return result;
521  }
522  };
523 
524  template <>
525  struct hash<PickParabola> {
526  size_t operator()(const PickParabola& a) const {
527  size_t result = 0;
528  hash_combine(result, a.origin, a.velocity, a.acceleration);
529  return result;
530  }
531  };
532 
533  template <>
534  struct hash<CollisionRegion> {
535  size_t operator()(const CollisionRegion& a) const {
536  size_t result = 0;
537  hash_combine(result, a.transform, (int)a.shapeInfo->getType(), qHash(a.modelURL));
538  return result;
539  }
540  };
541 
542 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
543  template <>
544  struct hash<QString> {
545  size_t operator()(const QString& a) const {
546  return qHash(a);
547  }
548  };
549 #endif
550 }
551 
552 /*@jsdoc
553  * <p>The type of a collision contact event.</p>
554  * <table>
555  * <thead>
556  * <tr><th>Value</th><th>Description</th></tr>
557  * </thead>
558  * <tbody>
559  * <tr><td><code>0</code></td><td>Start of the collision.</td></tr>
560  * <tr><td><code>1</code></td><td>Continuation of the collision.</td></tr>
561  * <tr><td><code>2</code></td><td>End of the collision.</td></tr>
562  * </tbody>
563  * </table>
564  * @typedef {number} ContactEventType
565  */
566 enum ContactEventType {
567  CONTACT_EVENT_TYPE_START,
568  CONTACT_EVENT_TYPE_CONTINUE,
569  CONTACT_EVENT_TYPE_END
570 };
571 
572 class Collision {
573 public:
574  Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f), velocityChange(0.0f) { }
575  Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint,
576  const glm::vec3& cPenetration, const glm::vec3& velocityChange)
577  : type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration), velocityChange(velocityChange) { }
578 
579  void invert(); // swap A and B
580 
581  ContactEventType type;
582  QUuid idA;
583  QUuid idB;
584  glm::vec3 contactPoint; // on B in world-frame
585  glm::vec3 penetration; // from B towards A in world-frame
586  glm::vec3 velocityChange;
587 };
588 Q_DECLARE_METATYPE(Collision)
589 
590 class AnimationDetails {
591 public:
592  AnimationDetails();
593  AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
594  bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation);
595 
596  QString role;
597  QUrl url;
598  float fps;
599  float priority;
600  bool loop;
601  bool hold;
602  bool startAutomatically;
603  float firstFrame;
604  float lastFrame;
605  bool running;
606  float currentFrame;
607  bool allowTranslation;
608 };
609 Q_DECLARE_METATYPE(AnimationDetails);
610 
611 namespace graphics {
612  class Mesh;
613 }
614 
615 using MeshPointer = std::shared_ptr<graphics::Mesh>;
616 
617 /*@jsdoc
618  * A mesh, such as returned by {@link Entities.getMeshes} or {@link Model} API functions.
619  *
620  * @class MeshProxy
621  * @hideconstructor
622  *
623  * @hifi-interface
624  * @hifi-client-entity
625  * @hifi-avatar
626  * @hifi-server-entity
627  * @hifi-assignment-client
628  *
629  * @deprecated Use the {@link Graphics} API instead.
630  */
631 class MeshProxy : public QObject {
632  Q_OBJECT
633 
634 public:
635  virtual MeshPointer getMeshPointer() const = 0;
636 
637  /*@jsdoc
638  * Gets the number of vertices in the mesh.
639  * @function MeshProxy#getNumVertices
640  * @returns {number} Integer number of vertices in the mesh.
641  */
642  Q_INVOKABLE virtual int getNumVertices() const = 0;
643 
644  /*@jsdoc
645  * Gets the position of a vertex in the mesh.
646  * @function MeshProxy#getPos
647  * @param {number} index - Integer index of the vertex.
648  * @returns {Vec3} Local position of the vertex relative to the mesh.
649  */
650  Q_INVOKABLE virtual glm::vec3 getPos(int index) const = 0;
651  Q_INVOKABLE virtual glm::vec3 getPos3(int index) const { return getPos(index); } // deprecated
652 };
653 
654 Q_DECLARE_METATYPE(MeshProxy*);
655 
656 class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
657 Q_DECLARE_METATYPE(MeshProxyList);
658 
659 
660 class MeshFace {
661 
662 public:
663  MeshFace() {}
664  ~MeshFace() {}
665 
666  QVector<uint32_t> vertexIndices;
667  // TODO -- material...
668 };
669 
670 Q_DECLARE_METATYPE(MeshFace)
671 Q_DECLARE_METATYPE(QVector<MeshFace>)
672 
673 QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures);
674 
675 Q_DECLARE_METATYPE(StencilMaskMode)
676 
677 #endif // hifi_RegisteredMetaTypes_h