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  */
209 class PickRay : public MathPick {
210 public:
211  PickRay() : origin(NAN), direction(NAN) { }
212  PickRay(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])) {}
213  PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {}
214  glm::vec3 origin;
215  glm::vec3 direction;
216 
217  operator bool() const override {
218  return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(direction)));
219  }
220  bool operator==(const PickRay& other) const {
221  return (origin == other.origin && direction == other.direction);
222  }
223  QVariantMap toVariantMap() const override {
224  QVariantMap pickRay;
225  pickRay["origin"] = vec3toVariant(origin);
226  pickRay["direction"] = vec3toVariant(direction);
227  return pickRay;
228  }
229 };
230 Q_DECLARE_METATYPE(PickRay)
231 
232 /*@jsdoc
233  * The tip of a stylus.
234  *
235  * @typedef {object} StylusTip
236  * @property {number} side - The hand that the stylus is attached to: <code>0</code> for left hand, <code>1</code> for the
237  * right hand, <code>-1</code> for invalid.
238  * @property {Vec3} tipOffset - The position of the stylus tip relative to the body of the stylus.
239  * @property {Vec3} position - The position of the stylus tip.
240  * @property {Quat} orientation - The orientation of the stylus.
241  * @property {Vec3} velocity - The velocity of the stylus tip.
242  */
243 class StylusTip : public MathPick {
244 public:
245  StylusTip() : position(NAN), velocity(NAN) {}
246  StylusTip(const bilateral::Side& side, const glm::vec3& tipOffset = Vectors::ZERO ,const glm::vec3& position = Vectors::ZERO,
247  const glm::quat& orientation = Quaternions::IDENTITY, const glm::vec3& velocity = Vectors::ZERO) :
248  side(side), tipOffset(tipOffset), position(position), orientation(orientation), velocity(velocity) {}
249  StylusTip(const QVariantMap& pickVariant) : side(bilateral::Side(pickVariant["side"].toInt())), tipOffset(vec3FromVariant(pickVariant["tipOffset"])),
250  position(vec3FromVariant(pickVariant["position"])), orientation(quatFromVariant(pickVariant["orientation"])), velocity(vec3FromVariant(pickVariant["velocity"])) {}
251 
252  bilateral::Side side { bilateral::Side::Invalid };
253  glm::vec3 tipOffset;
254  glm::vec3 position;
255  glm::quat orientation;
256  glm::vec3 velocity;
257 
258  operator bool() const override { return side != bilateral::Side::Invalid; }
259 
260  bool operator==(const StylusTip& other) const {
261  return (side == other.side && tipOffset == other.tipOffset && position == other.position && orientation == other.orientation && velocity == other.velocity);
262  }
263 
264  QVariantMap toVariantMap() const override {
265  QVariantMap stylusTip;
266  stylusTip["side"] = (int)side;
267  stylusTip["tipOffset"] = vec3toVariant(tipOffset);
268  stylusTip["position"] = vec3toVariant(position);
269  stylusTip["orientation"] = quatToVariant(orientation);
270  stylusTip["velocity"] = vec3toVariant(velocity);
271  return stylusTip;
272  }
273 };
274 
275 /*@jsdoc
276 * A parabola defined by a starting point, initial velocity, and acceleration. It is used, for example, when finding entities or
277 * avatars that intersect a parabolic beam.
278 *
279 * @typedef {object} PickParabola
280 * @property {Vec3} origin - The starting position of the parabola, i.e., the initial position of a virtual projectile whose
281 * trajectory defines the parabola.
282 * @property {Vec3} velocity - The starting velocity of the parabola in m/s, i.e., the initial speed of a virtual projectile
283 * whose trajectory defines the parabola.
284 * @property {Vec3} acceleration - The acceleration that the parabola experiences in m/s<sup>2</sup>, i.e., the acceleration of
285 * a virtual projectile whose trajectory defines the parabola, both magnitude and direction.
286 */
287 class PickParabola : public MathPick {
288 public:
289  PickParabola() : origin(NAN), velocity(NAN), acceleration(NAN) { }
290  PickParabola(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), velocity(vec3FromVariant(pickVariant["velocity"])), acceleration(vec3FromVariant(pickVariant["acceleration"])) {}
291  PickParabola(const glm::vec3& origin, const glm::vec3 velocity, const glm::vec3 acceleration) : origin(origin), velocity(velocity), acceleration(acceleration) {}
292  glm::vec3 origin;
293  glm::vec3 velocity;
294  glm::vec3 acceleration;
295 
296  operator bool() const override {
297  return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(velocity)) || glm::any(glm::isnan(acceleration)));
298  }
299  bool operator==(const PickParabola& other) const {
300  return (origin == other.origin && velocity == other.velocity && acceleration == other.acceleration);
301  }
302  QVariantMap toVariantMap() const override {
303  QVariantMap pickParabola;
304  pickParabola["origin"] = vec3toVariant(origin);
305  pickParabola["velocity"] = vec3toVariant(velocity);
306  pickParabola["acceleration"] = vec3toVariant(acceleration);
307  return pickParabola;
308  }
309 };
310 
311 class CollisionRegion : public MathPick {
312 public:
313  CollisionRegion() { }
314 
315  CollisionRegion(const CollisionRegion& collisionRegion) :
316  loaded(collisionRegion.loaded),
317  modelURL(collisionRegion.modelURL),
318  shapeInfo(std::make_shared<ShapeInfo>()),
319  transform(collisionRegion.transform),
320  threshold(collisionRegion.threshold),
321  collisionGroup(collisionRegion.collisionGroup)
322  {
323  shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString());
324  }
325 
326  CollisionRegion(const QVariantMap& pickVariant) {
327  // "loaded" is not deserialized here because there is no way to know if the shape is actually loaded
328  if (pickVariant["shape"].isValid()) {
329  auto shape = pickVariant["shape"].toMap();
330  if (!shape.empty()) {
331  ShapeType shapeType = SHAPE_TYPE_NONE;
332  if (shape["shapeType"].isValid()) {
333  shapeType = ShapeInfo::getShapeTypeForName(shape["shapeType"].toString());
334  }
335  if (shapeType >= SHAPE_TYPE_COMPOUND && shapeType <= SHAPE_TYPE_STATIC_MESH && shape["modelURL"].isValid()) {
336  QString newURL = shape["modelURL"].toString();
337  modelURL.setUrl(newURL);
338  } else {
339  modelURL.setUrl("");
340  }
341 
342  if (shape["dimensions"].isValid()) {
343  transform.setScale(vec3FromVariant(shape["dimensions"]));
344  }
345 
346  shapeInfo->setParams(shapeType, transform.getScale() / 2.0f, modelURL.toString());
347  }
348  }
349 
350  if (pickVariant["threshold"].isValid()) {
351  threshold = glm::max(0.0f, pickVariant["threshold"].toFloat());
352  }
353 
354  if (pickVariant["position"].isValid()) {
355  transform.setTranslation(vec3FromVariant(pickVariant["position"]));
356  }
357  if (pickVariant["orientation"].isValid()) {
358  transform.setRotation(quatFromVariant(pickVariant["orientation"]));
359  }
360  if (pickVariant["collisionGroup"].isValid()) {
361  collisionGroup = pickVariant["collisionGroup"].toUInt();
362  }
363  }
364 
365  /*@jsdoc
366  * A volume for checking collisions in the physics simulation.
367  * @typedef {object} CollisionRegion
368  * @property {Shape} shape - The collision region's shape and size. Dimensions are in world coordinates, but scale with the
369  * parent if defined.
370  * @property {boolean} loaded - <code>true</code> if the <code>shape</code> has no model, or has a model and it is loaded,
371  * <code>false</code> if otherwise.
372  * @property {Vec3} position - The position of the collision region, relative to the parent if defined.
373  * @property {Quat} orientation - The orientation of the collision region, relative to the parent if defined.
374  * @property {number} threshold - The approximate minimum penetration depth for a test object to be considered in contact with
375  * the collision region. The depth is in world coordinates but scales with the parent if defined.
376  * @property {CollisionMask} [collisionGroup=8] - The type of objects the collision region collides as. Objects whose collision
377  * masks overlap with the region's collision group are considered to be colliding with the region.
378  */
379 
380  /*@jsdoc
381  * A physical volume.
382  * @typedef {object} Shape
383  * @property {ShapeType} shapeType="none" - The type of shape.
384  * @property {string} [modelUrl=""] - The model to load to for the shape if <code>shapeType</code> is one of
385  * <code>"compound"</code>, <code>"simple-hull"</code>, <code>"simple-compound"</code>, or <code>"static-mesh"</code>.
386  * @property {Vec3} dimensions - The dimensions of the shape.
387  */
388 
389  QVariantMap toVariantMap() const override {
390  QVariantMap collisionRegion;
391 
392  QVariantMap shape;
393  shape["shapeType"] = ShapeInfo::getNameForShapeType(shapeInfo->getType());
394  shape["modelURL"] = modelURL.toString();
395  shape["dimensions"] = vec3toVariant(transform.getScale());
396 
397  collisionRegion["shape"] = shape;
398  collisionRegion["loaded"] = loaded;
399 
400  collisionRegion["threshold"] = threshold;
401  collisionRegion["collisionGroup"] = collisionGroup;
402 
403  collisionRegion["position"] = vec3toVariant(transform.getTranslation());
404  collisionRegion["orientation"] = quatToVariant(transform.getRotation());
405 
406  return collisionRegion;
407  }
408 
409  operator bool() const override {
410  return !std::isnan(threshold) &&
411  !(glm::any(glm::isnan(transform.getTranslation())) ||
412  glm::any(glm::isnan(transform.getRotation())) ||
413  shapeInfo->getType() == SHAPE_TYPE_NONE ||
414  collisionGroup == 0);
415  }
416 
417  bool operator==(const CollisionRegion& other) const {
418  return loaded == other.loaded &&
419  threshold == other.threshold &&
420  collisionGroup == other.collisionGroup &&
421  glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) &&
422  glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) &&
423  glm::all(glm::equal(transform.getScale(), other.transform.getScale())) &&
424  shapeInfo->getType() == other.shapeInfo->getType() &&
425  modelURL == other.modelURL;
426  }
427 
428  bool shouldComputeShapeInfo() const {
429  if (!(shapeInfo->getType() == SHAPE_TYPE_HULL ||
430  (shapeInfo->getType() >= SHAPE_TYPE_COMPOUND &&
431  shapeInfo->getType() <= SHAPE_TYPE_STATIC_MESH)
432  )) {
433  return false;
434  }
435 
436  if (collisionGroup == 0) {
437  return false;
438  }
439 
440  return !shapeInfo->getPointCollection().size();
441  }
442 
443  // We can't load the model here because it would create a circular dependency, so we delegate that responsibility to the owning CollisionPick
444  bool loaded { false };
445  QUrl modelURL;
446 
447  // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick
448  std::shared_ptr<ShapeInfo> shapeInfo = std::make_shared<ShapeInfo>();
449  Transform transform;
450  float threshold { 0.0f };
451  uint16_t collisionGroup { USER_COLLISION_GROUP_MY_AVATAR };
452 };
453 
454 namespace std {
455  inline void hash_combine(std::size_t& seed) { }
456 
457  template <typename T, typename... Rest>
458  inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
459  std::hash<T> hasher;
460  seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
461  hash_combine(seed, rest...);
462  }
463 
464  template <>
465  struct hash<bilateral::Side> {
466  size_t operator()(const bilateral::Side& a) const {
467  return std::hash<int>()((int)a);
468  }
469  };
470 
471  template <>
472  struct hash<glm::vec3> {
473  size_t operator()(const glm::vec3& a) const {
474  size_t result = 0;
475  hash_combine(result, a.x, a.y, a.z);
476  return result;
477  }
478  };
479 
480  template <>
481  struct hash<glm::quat> {
482  size_t operator()(const glm::quat& a) const {
483  size_t result = 0;
484  hash_combine(result, a.x, a.y, a.z, a.w);
485  return result;
486  }
487  };
488 
489  template <>
490  struct hash<Transform> {
491  size_t operator()(const Transform& a) const {
492  size_t result = 0;
493  hash_combine(result, a.getTranslation(), a.getRotation(), a.getScale());
494  return result;
495  }
496  };
497 
498  template <>
499  struct hash<PickRay> {
500  size_t operator()(const PickRay& a) const {
501  size_t result = 0;
502  hash_combine(result, a.origin, a.direction);
503  return result;
504  }
505  };
506 
507  template <>
508  struct hash<StylusTip> {
509  size_t operator()(const StylusTip& a) const {
510  size_t result = 0;
511  hash_combine(result, a.side, a.position, a.orientation, a.velocity);
512  return result;
513  }
514  };
515 
516  template <>
517  struct hash<PickParabola> {
518  size_t operator()(const PickParabola& a) const {
519  size_t result = 0;
520  hash_combine(result, a.origin, a.velocity, a.acceleration);
521  return result;
522  }
523  };
524 
525  template <>
526  struct hash<CollisionRegion> {
527  size_t operator()(const CollisionRegion& a) const {
528  size_t result = 0;
529  hash_combine(result, a.transform, (int)a.shapeInfo->getType(), qHash(a.modelURL));
530  return result;
531  }
532  };
533 
534 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
535  template <>
536  struct hash<QString> {
537  size_t operator()(const QString& a) const {
538  return qHash(a);
539  }
540  };
541 #endif
542 }
543 
544 /*@jsdoc
545  * <p>The type of a collision contact event.</p>
546  * <table>
547  * <thead>
548  * <tr><th>Value</th><th>Description</th></tr>
549  * </thead>
550  * <tbody>
551  * <tr><td><code>0</code></td><td>Start of the collision.</td></tr>
552  * <tr><td><code>1</code></td><td>Continuation of the collision.</td></tr>
553  * <tr><td><code>2</code></td><td>End of the collision.</td></tr>
554  * </tbody>
555  * </table>
556  * @typedef {number} ContactEventType
557  */
558 enum ContactEventType {
559  CONTACT_EVENT_TYPE_START,
560  CONTACT_EVENT_TYPE_CONTINUE,
561  CONTACT_EVENT_TYPE_END
562 };
563 
564 class Collision {
565 public:
566  Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f), velocityChange(0.0f) { }
567  Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint,
568  const glm::vec3& cPenetration, const glm::vec3& velocityChange)
569  : type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration), velocityChange(velocityChange) { }
570 
571  void invert(); // swap A and B
572 
573  ContactEventType type;
574  QUuid idA;
575  QUuid idB;
576  glm::vec3 contactPoint; // on B in world-frame
577  glm::vec3 penetration; // from B towards A in world-frame
578  glm::vec3 velocityChange;
579 };
580 Q_DECLARE_METATYPE(Collision)
581 
582 class AnimationDetails {
583 public:
584  AnimationDetails();
585  AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
586  bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation);
587 
588  QString role;
589  QUrl url;
590  float fps;
591  float priority;
592  bool loop;
593  bool hold;
594  bool startAutomatically;
595  float firstFrame;
596  float lastFrame;
597  bool running;
598  float currentFrame;
599  bool allowTranslation;
600 };
601 Q_DECLARE_METATYPE(AnimationDetails);
602 
603 namespace graphics {
604  class Mesh;
605 }
606 
607 using MeshPointer = std::shared_ptr<graphics::Mesh>;
608 
609 /*@jsdoc
610  * A mesh, such as returned by {@link Entities.getMeshes} or {@link Model} API functions.
611  *
612  * @class MeshProxy
613  * @hideconstructor
614  *
615  * @hifi-interface
616  * @hifi-client-entity
617  * @hifi-avatar
618  * @hifi-server-entity
619  * @hifi-assignment-client
620  *
621  * @deprecated Use the {@link Graphics} API instead.
622  */
623 class MeshProxy : public QObject {
624  Q_OBJECT
625 
626 public:
627  virtual MeshPointer getMeshPointer() const = 0;
628 
629  /*@jsdoc
630  * Gets the number of vertices in the mesh.
631  * @function MeshProxy#getNumVertices
632  * @returns {number} Integer number of vertices in the mesh.
633  */
634  Q_INVOKABLE virtual int getNumVertices() const = 0;
635 
636  /*@jsdoc
637  * Gets the position of a vertex in the mesh.
638  * @function MeshProxy#getPos
639  * @param {number} index - Integer index of the vertex.
640  * @returns {Vec3} Local position of the vertex relative to the mesh.
641  */
642  Q_INVOKABLE virtual glm::vec3 getPos(int index) const = 0;
643  Q_INVOKABLE virtual glm::vec3 getPos3(int index) const { return getPos(index); } // deprecated
644 };
645 
646 Q_DECLARE_METATYPE(MeshProxy*);
647 
648 class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
649 Q_DECLARE_METATYPE(MeshProxyList);
650 
651 
652 class MeshFace {
653 
654 public:
655  MeshFace() {}
656  ~MeshFace() {}
657 
658  QVector<uint32_t> vertexIndices;
659  // TODO -- material...
660 };
661 
662 Q_DECLARE_METATYPE(MeshFace)
663 Q_DECLARE_METATYPE(QVector<MeshFace>)
664 
665 QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures);
666 
667 Q_DECLARE_METATYPE(StencilMaskMode)
668 
669 #endif // hifi_RegisteredMetaTypes_h