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