Overte C++ Documentation
AnimVariant.h
1 //
2 // AnimVariant.h
3 //
4 // Created by Anthony J. Thibault on 9/2/15.
5 // Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
6 // Copyright 2023 Overte e.V.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 // SPDX-License-Identifier: Apache-2.0
11 //
12 
13 #ifndef hifi_AnimVariant_h
14 #define hifi_AnimVariant_h
15 
16 #include <cassert>
17 #include <functional>
18 #include <glm/glm.hpp>
19 #include <glm/gtx/quaternion.hpp>
20 #include <map>
21 #include <set>
22 #include <StreamUtils.h>
23 #include <GLMHelpers.h>
24 #include "AnimationLogging.h"
25 #include <ScriptValue.h>
26 
27 class ScriptEngine;
28 
29 class AnimVariant {
30 public:
31  enum class Type {
32  Bool = 0,
33  Int,
34  Float,
35  Vec3,
36  Quat,
37  String,
38  NumTypes
39  };
40 
41  static const AnimVariant False;
42 
43  AnimVariant() : _type(Type::Bool) { memset(&_val, 0, sizeof(_val)); }
44  explicit AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; }
45  explicit AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; }
46  explicit AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; }
47  explicit AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast<glm::vec3*>(&_val) = value; }
48  explicit AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast<glm::quat*>(&_val) = value; }
49  explicit AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; }
50 
51  bool isBool() const { return _type == Type::Bool; }
52  bool isInt() const { return _type == Type::Int; }
53  bool isFloat() const { return _type == Type::Float; }
54  bool isVec3() const { return _type == Type::Vec3; }
55  bool isQuat() const { return _type == Type::Quat; }
56  bool isString() const { return _type == Type::String; }
57  Type getType() const { return _type; }
58 
59  void setBool(bool value) { assert(_type == Type::Bool); _val.boolVal = value; }
60  void setInt(int value) { assert(_type == Type::Int); _val.intVal = value; }
61  void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; }
62  void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast<glm::vec3*>(&_val) = value; }
63  void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast<glm::quat*>(&_val) = value; }
64  void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; }
65 
66  bool getBool() const {
67  if (_type == Type::Bool) {
68  return _val.boolVal;
69  } else if (_type == Type::Int) {
70  return _val.intVal != 0;
71  } else {
72  return false;
73  }
74  }
75  int getInt() const {
76  if (_type == Type::Int) {
77  return _val.intVal;
78  } else if (_type == Type::Float) {
79  return (int)_val.floats[0];
80  } else {
81  return 0;
82  }
83  }
84  float getFloat() const {
85  if (_type == Type::Float) {
86  return _val.floats[0];
87  } else if (_type == Type::Int) {
88  return (float)_val.intVal;
89  } else {
90  return 0.0f;
91  }
92  }
93  const glm::vec3& getVec3() const {
94  if (_type == Type::Vec3) {
95  return *reinterpret_cast<const glm::vec3*>(&_val);
96  } else {
97  return Vectors::ZERO;
98  }
99  }
100  const glm::quat& getQuat() const {
101  if (_type == Type::Quat) {
102  return *reinterpret_cast<const glm::quat*>(&_val);
103  } else {
104  return Quaternions::IDENTITY;
105  }
106  }
107  const QString& getString() const {
108  return _stringVal;
109  }
110 
111 protected:
112  Type _type;
113  QString _stringVal;
114  union {
115  bool boolVal;
116  int intVal;
117  float floats[4];
118  } _val;
119 };
120 
121 class AnimVariantMap {
122 public:
123 
124  bool lookup(const QString& key, bool defaultValue) const {
125  // check triggers first, then map
126  if (key.isEmpty()) {
127  return defaultValue;
128  } else if (_triggers.find(key) != _triggers.end()) {
129  return true;
130  } else {
131  auto iter = _map.find(key);
132  return iter != _map.end() ? iter->second.getBool() : defaultValue;
133  }
134  }
135 
136  int lookup(const QString& key, int defaultValue) const {
137  if (key.isEmpty()) {
138  return defaultValue;
139  } else {
140  auto iter = _map.find(key);
141  return iter != _map.end() ? iter->second.getInt() : defaultValue;
142  }
143  }
144 
145  float lookup(const QString& key, float defaultValue) const {
146  if (key.isEmpty()) {
147  return defaultValue;
148  } else {
149  auto iter = _map.find(key);
150  return iter != _map.end() ? iter->second.getFloat() : defaultValue;
151  }
152  }
153 
154  const glm::vec3& lookupRaw(const QString& key, const glm::vec3& defaultValue) const {
155  if (key.isEmpty()) {
156  return defaultValue;
157  } else {
158  auto iter = _map.find(key);
159  return iter != _map.end() ? iter->second.getVec3() : defaultValue;
160  }
161  }
162 
163  glm::vec3 lookupRigToGeometry(const QString& key, const glm::vec3& defaultValue) const {
164  if (key.isEmpty()) {
165  return defaultValue;
166  } else {
167  auto iter = _map.find(key);
168  return iter != _map.end() ? transformPoint(_rigToGeometryMat, iter->second.getVec3()) : defaultValue;
169  }
170  }
171 
172  glm::vec3 lookupRigToGeometryVector(const QString& key, const glm::vec3& defaultValue) const {
173  if (key.isEmpty()) {
174  return defaultValue;
175  } else {
176  auto iter = _map.find(key);
177  return iter != _map.end() ? transformVectorFast(_rigToGeometryMat, iter->second.getVec3()) : defaultValue;
178  }
179  }
180 
181  const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const {
182  if (key.isEmpty()) {
183  return defaultValue;
184  } else {
185  auto iter = _map.find(key);
186  return iter != _map.end() ? iter->second.getQuat() : defaultValue;
187  }
188  }
189 
190  glm::quat lookupRigToGeometry(const QString& key, const glm::quat& defaultValue) const {
191  if (key.isEmpty()) {
192  return defaultValue;
193  } else {
194  auto iter = _map.find(key);
195  return iter != _map.end() ? _rigToGeometryRot * iter->second.getQuat() : defaultValue;
196  }
197  }
198 
199  const QString& lookup(const QString& key, const QString& defaultValue) const {
200  if (key.isEmpty()) {
201  return defaultValue;
202  } else {
203  auto iter = _map.find(key);
204  return iter != _map.end() ? iter->second.getString() : defaultValue;
205  }
206  }
207 
208  void set(const QString& key, bool value) { _map[key] = AnimVariant(value); }
209  void set(const QString& key, int value) { _map[key] = AnimVariant(value); }
210  void set(const QString& key, float value) { _map[key] = AnimVariant(value); }
211  void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); }
212  void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); }
213  void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); }
214  void unset(const QString& key) { _map.erase(key); }
215 
216  void setTrigger(const QString& key) { _map[key] = AnimVariant(true); }
217 
218  void setRigToGeometryTransform(const glm::mat4& rigToGeometry) {
219  _rigToGeometryMat = rigToGeometry;
220  _rigToGeometryRot = glmExtractRotation(rigToGeometry);
221  }
222 
223  void clearMap() { _map.clear(); _triggers.clear(); }
224  bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
225 
226  const AnimVariant& get(const QString& key) const {
227  auto iter = _map.find(key);
228  if (iter != _map.end()) {
229  return iter->second;
230  } else {
231  return AnimVariant::False;
232  }
233  }
234 
235  // Answer a Plain Old Javascript Object (for the given engine) all of our values set as properties.
236  ScriptValue animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const;
237  // Side-effect us with the value of object's own properties. (No inherited properties.)
238  void animVariantMapFromScriptValue(const ScriptValue& object);
239  void copyVariantsFrom(const AnimVariantMap& other);
240 
241  // For stat debugging.
242  std::map<QString, QString> toDebugMap() const;
243 
244 #ifndef NDEBUG
245  void dump() const {
246  qCDebug(animation) << "AnimVariantMap =";
247  for (auto& pair : _map) {
248  switch (pair.second.getType()) {
249  case AnimVariant::Type::Bool:
250  qCDebug(animation) << " " << pair.first << "=" << pair.second.getBool();
251  break;
252  case AnimVariant::Type::Int:
253  qCDebug(animation) << " " << pair.first << "=" << pair.second.getInt();
254  break;
255  case AnimVariant::Type::Float:
256  qCDebug(animation) << " " << pair.first << "=" << pair.second.getFloat();
257  break;
258  case AnimVariant::Type::Vec3:
259  qCDebug(animation) << " " << pair.first << "=" << pair.second.getVec3();
260  break;
261  case AnimVariant::Type::Quat:
262  qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat();
263  break;
264  case AnimVariant::Type::String:
265  qCDebug(animation) << " " << pair.first << "=" << pair.second.getString();
266  break;
267  default:
268  assert(false);
269  }
270  }
271  }
272 #endif
273 
274 protected:
275  std::map<QString, AnimVariant> _map;
276  std::set<QString> _triggers;
277  glm::mat4 _rigToGeometryMat;
278  glm::quat _rigToGeometryRot;
279 };
280 
281 typedef std::function<void(ScriptValue)> AnimVariantResultHandler;
282 Q_DECLARE_METATYPE(AnimVariantResultHandler);
283 Q_DECLARE_METATYPE(AnimVariantMap)
284 
285 #endif // hifi_AnimVariant_h
Provides the Quat scripting interface.
Definition: Quat.h:61
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40
Provides the Vec3 scripting interface.
Definition: Vec3.h:80