Overte C++ Documentation
EntityItemPropertiesMacros.h
1 //
2 // EntityItemPropertiesMacros.h
3 // libraries/entities/src
4 //
5 // Created by Brad Hefta-Gaub on 9/10/14.
6 // Copyright 2014 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 
15 #ifndef hifi_EntityItemPropertiesMacros_h
16 #define hifi_EntityItemPropertiesMacros_h
17 
18 #include <EntityItemID.h>
19 #include <EntityPropertyFlags.h>
20 #include <RegisteredMetaTypes.h>
21 #include <ScriptEngine.h>
22 #include <ScriptValue.h>
23 #include <ScriptValueUtils.h>
24 #include "Sampler.h"
25 
26 const quint64 UNKNOWN_CREATED_TIME = 0;
27 
28 using vec3Color = glm::vec3;
29 using u8vec3Color = glm::u8vec3;
30 
31 struct EntityPropertyInfo {
32  EntityPropertyInfo(EntityPropertyList propEnum) :
33  propertyEnums(propEnum) {}
34  EntityPropertyInfo(EntityPropertyList propEnum, QVariant min, QVariant max) :
35  propertyEnums(propEnum), minimum(min), maximum(max) {}
36  EntityPropertyInfo() = default;
37  EntityPropertyFlags propertyEnums;
38  QVariant minimum;
39  QVariant maximum;
40 };
41 
42 template <typename T>
43 EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if<!std::is_integral<T>::value>::type* = 0) {
44  return EntityPropertyInfo(p);
45 }
46 
47 template <typename T>
48 EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
49  return EntityPropertyInfo(p, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
50 }
51 
52 #define APPEND_ENTITY_PROPERTY(P,V) \
53  if (requestedProperties.getHasProperty(P)) { \
54  LevelDetails propertyLevel = packetData->startLevel(); \
55  successPropertyFits = packetData->appendValue(V); \
56  if (successPropertyFits) { \
57  propertyFlags |= P; \
58  propertiesDidntFit -= P; \
59  propertyCount++; \
60  packetData->endLevel(propertyLevel); \
61  } else { \
62  packetData->discardLevel(propertyLevel); \
63  appendState = OctreeElement::PARTIAL; \
64  } \
65  } else { \
66  propertiesDidntFit -= P; \
67  }
68 
69 #define READ_ENTITY_PROPERTY(P,T,S) \
70  if (propertyFlags.getHasProperty(P)) { \
71  T fromBuffer; \
72  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
73  dataAt += bytes; \
74  bytesRead += bytes; \
75  if (overwriteLocalData) { \
76  S(fromBuffer); \
77  } \
78  somethingChanged = true; \
79  }
80 
81 #define SKIP_ENTITY_PROPERTY(P,T) \
82  if (propertyFlags.getHasProperty(P)) { \
83  T fromBuffer; \
84  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
85  dataAt += bytes; \
86  bytesRead += bytes; \
87  }
88 
89 #define DECODE_GROUP_PROPERTY_HAS_CHANGED(P,N) \
90  if (propertyFlags.getHasProperty(P)) { \
91  set##N##Changed(true); \
92  }
93 
94 
95 #define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
96  if (propertyFlags.getHasProperty(P)) { \
97  T fromBuffer; \
98  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
99  dataAt += bytes; \
100  processedBytes += bytes; \
101  properties.O(fromBuffer); \
102  }
103 
104 #define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \
105  if (properties._##P##Changed) { \
106  M(properties._##P); \
107  somethingChanged = true; \
108  }
109 
110 #define SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(G,P,p,M) \
111  if (properties.get##G().p##Changed()) { \
112  M(properties.get##G().get##P()); \
113  somethingChanged = true; \
114  }
115 
116 #define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \
117  if (properties.C()) { \
118  S(properties.G()); \
119  somethingChanged = true; \
120  }
121 
122 #define COPY_ENTITY_PROPERTY_TO_PROPERTIES(P,M) \
123  properties._##P = M(); \
124  properties._##P##Changed = false;
125 
126 #define COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(G,P,M) \
127  properties.get##G().set##P(M()); \
128  properties.get##G().set##P##Changed(false);
129 
130 #define CHECK_PROPERTY_CHANGE(P,M) \
131  if (_##M##Changed) { \
132  changedProperties += P; \
133  }
134 
135 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); }
136 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); }
137 inline ScriptValue vec3Color_convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); }
138 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); }
139 inline ScriptValue u8vec3Color_convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); }
140 inline ScriptValue convertScriptValue(ScriptEngine* e, float v) { return e->newValue(v); }
141 inline ScriptValue convertScriptValue(ScriptEngine* e, int v) { return e->newValue(v); }
142 inline ScriptValue convertScriptValue(ScriptEngine* e, bool v) { return e->newValue(v); }
143 inline ScriptValue convertScriptValue(ScriptEngine* e, quint16 v) { return e->newValue(v); }
144 inline ScriptValue convertScriptValue(ScriptEngine* e, quint32 v) { return e->newValue(v); }
145 inline ScriptValue convertScriptValue(ScriptEngine* e, quint64 v) { return e->newValue((double)v); }
146 inline ScriptValue convertScriptValue(ScriptEngine* e, const QString& v) { return e->newValue(v); }
147 
148 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
149 inline ScriptValue convertScriptValue(ScriptEngine* e, const ScriptValue& v) { return v; }
150 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ToScriptValue(e, v); }
151 inline ScriptValue qVectorVec3Color_convertScriptValue(ScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ColorToScriptValue(e, v); }
152 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<glm::quat>& v) {return qVectorQuatToScriptValue(e, v); }
153 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<bool>& v) {return qVectorBoolToScriptValue(e, v); }
154 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<float>& v) { return qVectorFloatToScriptValue(e, v); }
155 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QUuid>& v) { return qVectorQUuidToScriptValue(e, v); }
156 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QString>& v) { return qVectorQStringToScriptValue(e, v); }
157 
158 inline ScriptValue convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); }
159 
160 inline ScriptValue convertScriptValue(ScriptEngine* e, const QByteArray& v) {
161  QByteArray b64 = v.toBase64();
162  return e->newValue(QString(b64));
163 }
164 
165 inline ScriptValue convertScriptValue(ScriptEngine* e, const EntityItemID& v) { return e->newValue(QUuid(v).toString()); }
166 
167 inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); }
168 
169 inline ScriptValue convertScriptValue(ScriptEngine* e, const Sampler& v) { return samplerToScriptValue(e, v); }
170 
171 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \
172  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
173  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
174  ScriptValue groupProperties = properties.property(#g); \
175  if (!groupProperties.isValid()) { \
176  groupProperties = engine->newObject(); \
177  } \
178  ScriptValue V = convertScriptValue(engine, get##P()); \
179  groupProperties.setProperty(#p, V); \
180  properties.setProperty(#g, groupProperties); \
181  }
182 
183 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(X,G,g,P,p,T) \
184  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
185  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
186  ScriptValue groupProperties = properties.property(#g); \
187  if (!groupProperties.isValid()) { \
188  groupProperties = engine->newObject(); \
189  } \
190  ScriptValue V = T##_convertScriptValue(engine, get##P()); \
191  groupProperties.setProperty(#p, V); \
192  properties.setProperty(#g, groupProperties); \
193  }
194 
195 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(X,G,g,P,p,M) \
196  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
197  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
198  ScriptValue groupProperties = properties.property(#g); \
199  if (!groupProperties.isValid()) { \
200  groupProperties = engine->newObject(); \
201  } \
202  ScriptValue V = convertScriptValue(engine, M()); \
203  groupProperties.setProperty(#p, V); \
204  properties.setProperty(#g, groupProperties); \
205  }
206 
207 #define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \
208  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
209  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
210  ScriptValue V = convertScriptValue(engine, _##P); \
211  properties.setProperty(#P, V); \
212  }
213 
214 #define COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(p,P,T) \
215  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
216  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
217  ScriptValue V = T##_convertScriptValue(engine, _##P); \
218  properties.setProperty(#P, V); \
219  }
220 
221 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \
222  properties.setProperty(#P, G);
223 
224 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \
225  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
226  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
227  ScriptValue V = convertScriptValue(engine, G); \
228  properties.setProperty(#P, V); \
229  }
230 
231 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(p, P, G, T) \
232  if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
233  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
234  ScriptValue V = T##_convertScriptValue(engine, G()); \
235  properties.setProperty(#P, V); \
236  }
237 
238 // same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step
239 #define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \
240  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
241  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
242  ScriptValue V = convertScriptValue(engine, G()); \
243  properties.setProperty(#X, V); \
244  }
245 
246 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \
247  if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
248  ScriptValue V = convertScriptValue(engine, G); \
249  properties.setProperty(#P, V); \
250  }
251 
252 #define COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(p, P) \
253  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
254  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
255  if (isMyOwnAvatarEntity || nodeList->getThisNodeCanViewAssetURLs()) { \
256  ScriptValue V = convertScriptValue(engine, _##P); \
257  properties.setProperty(#P, V); \
258  } else { \
259  const QString emptyURL = ""; \
260  ScriptValue V = convertScriptValue(engine, emptyURL); \
261  properties.setProperty(#P, V); \
262  } \
263  }
264 
265 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(X, G, g, P, p) \
266  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
267  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
268  if (isMyOwnAvatarEntity || nodeList->getThisNodeCanViewAssetURLs()) { \
269  ScriptValue groupProperties = properties.property(#g); \
270  if (!groupProperties.isValid()) { \
271  groupProperties = engine->newObject(); \
272  } \
273  ScriptValue V = convertScriptValue(engine, get##P()); \
274  groupProperties.setProperty(#p, V); \
275  properties.setProperty(#g, groupProperties); \
276  } else { \
277  const QString emptyURL = ""; \
278  ScriptValue V = convertScriptValue(engine, emptyURL); \
279  properties.setProperty(#P, V); \
280  } \
281  }
282 
283 typedef QVector<glm::vec3> qVectorVec3;
284 typedef QVector<glm::quat> qVectorQuat;
285 typedef QVector<bool> qVectorBool;
286 typedef QVector<float> qVectorFloat;
287 typedef QVector<QUuid> qVectorQUuid;
288 typedef QVector<QString> qVectorQString;
289 typedef QSet<QString> qSetQString;
290 inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
291 inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
292 inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
293  // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range.
294  return v.toString().toUInt(&isValid);
295 }
296 inline quint16 quint16_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
297 inline uint16_t uint16_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
298 inline uint32_t uint32_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
299 inline int int_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
300 inline bool bool_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
301 inline uint8_t uint8_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); }
302 inline QString QString_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
303 inline QUuid QUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
304 inline EntityItemID EntityItemID_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
305 
306 inline QByteArray QByteArray_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
307  isValid = true;
308  QString b64 = v.toVariant().toString().trimmed();
309  return QByteArray::fromBase64(b64.toUtf8());
310 }
311 
312 inline glm::vec2 vec2_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
313  isValid = true;
314  glm::vec2 vec2;
315  vec2FromScriptValue(v, vec2);
316  return vec2;
317 }
318 
319 inline glm::vec3 vec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
320  isValid = true;
321  glm::vec3 vec3;
322  vec3FromScriptValue(v, vec3);
323  return vec3;
324 }
325 
326 inline glm::vec3 vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
327  isValid = true;
328  glm::vec3 vec3;
329  vec3FromScriptValue(v, vec3);
330  return vec3;
331 }
332 
333 inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
334  isValid = true;
335  glm::u8vec3 vec3;
336  u8vec3FromScriptValue(v, vec3);
337  return vec3;
338 }
339 
340 inline AACube AACube_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
341  isValid = true;
342  AACube result;
343  aaCubeFromScriptValue(v, result);
344  return result;
345 }
346 
347 inline qVectorFloat qVectorFloat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
348  isValid = true;
349  return qVectorFloatFromScriptValue(v);
350 }
351 
352 inline qVectorVec3 qVectorVec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
353  isValid = true;
354  return qVectorVec3FromScriptValue(v);
355 }
356 
357 inline qVectorQuat qVectorQuat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
358  isValid = true;
359  return qVectorQuatFromScriptValue(v);
360 }
361 
362 inline qVectorBool qVectorBool_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
363  isValid = true;
364  return qVectorBoolFromScriptValue(v);
365 }
366 
367 inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
368  isValid = true;
369  return qVectorQUuidFromScriptValue(v);
370 }
371 
372 inline qVectorQString qVectorQString_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
373  isValid = true;
374  return qVectorQStringFromScriptValue(v);
375 }
376 
377 inline glm::quat quat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
378  isValid = false;
379  ScriptValue x = v.property("x");
380  ScriptValue y = v.property("y");
381  ScriptValue z = v.property("z");
382  ScriptValue w = v.property("w");
383  if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
384  glm::quat newValue;
385  newValue.x = x.toVariant().toFloat();
386  newValue.y = y.toVariant().toFloat();
387  newValue.z = z.toVariant().toFloat();
388  newValue.w = w.toVariant().toFloat();
389  isValid = !glm::isnan(newValue.x) &&
390  !glm::isnan(newValue.y) &&
391  !glm::isnan(newValue.z) &&
392  !glm::isnan(newValue.w);
393  if (isValid) {
394  return newValue;
395  }
396  }
397  return glm::quat();
398 }
399 
400 inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
401  isValid = true;
402  QRect rect;
403  qRectFromScriptValue(v, rect);
404  return rect;
405 }
406 
407 inline Sampler Sampler_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
408  isValid = true;
409  Sampler sampler;
410  samplerFromScriptValue(v, sampler);
411  return sampler;
412 }
413 
414 #define COPY_PROPERTY_IF_CHANGED(P) \
415 { \
416  if (other._##P##Changed) { \
417  _##P = other._##P; \
418  } \
419 }
420 
421 #define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \
422  { \
423  if (namesSet.contains(#P)) { \
424  ScriptValue V = object.property(#P); \
425  if (V.isValid()) { \
426  bool isValid = false; \
427  T newValue = T##_convertFromScriptValue(V, isValid); \
428  if (isValid && (_defaultSettings || newValue != _##P)) { \
429  S(newValue); \
430  } \
431  } \
432  } \
433  }
434 
435 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(P, T, S, G) \
436 { \
437  if (namesSet.contains(#P)) { \
438  ScriptValue V = object.property(#P); \
439  if (V.isValid()) { \
440  bool isValid = false; \
441  T newValue = T##_convertFromScriptValue(V, isValid); \
442  if (isValid && (_defaultSettings || newValue != G())) { \
443  S(newValue); \
444  } \
445  } \
446  } \
447 }
448 
449 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(P, T, S) \
450 { \
451  if (namesSet.contains(#P)) { \
452  ScriptValue V = object.property(#P); \
453  if (V.isValid()) { \
454  bool isValid = false; \
455  T newValue = T##_convertFromScriptValue(V, isValid); \
456  if (isValid && (_defaultSettings)) { \
457  S(newValue); \
458  } \
459  } \
460  } \
461 }
462 
463 #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(G, P, T, S) \
464  { \
465  if (namesSet.contains(#G)) { \
466  ScriptValue G = object.property(#G); \
467  if (G.isValid()) { \
468  ScriptValue V = G.property(#P); \
469  if (V.isValid()) { \
470  bool isValid = false; \
471  T newValue = T##_convertFromScriptValue(V, isValid); \
472  if (isValid && (_defaultSettings || newValue != _##P)) { \
473  S(newValue); \
474  } \
475  } \
476  } \
477  } \
478  }
479 
480 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \
481  { \
482  if (namesSet.contains(#P)) { \
483  ScriptValue P = object.property(#P); \
484  if (P.isValid()) { \
485  QString newValue = P.toVariant().toString(); \
486  if (_defaultSettings || newValue != get##S##AsString()) { \
487  set##S##FromString(newValue); \
488  } \
489  } \
490  } \
491  }
492 
493 #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(G, P, S) \
494  { \
495  if (namesSet.contains(#G)) { \
496  ScriptValue G = object.property(#G); \
497  if (G.isValid()) { \
498  ScriptValue P = G.property(#P); \
499  if (P.isValid()) { \
500  QString newValue = P.toVariant().toString(); \
501  if (_defaultSettings || newValue != get##S##AsString()) { \
502  set##S##FromString(newValue); \
503  } \
504  } \
505  } \
506  } \
507  }
508 
509 #define DEFINE_PROPERTY_GROUP(N, n, T) \
510  public: \
511  const T& get##N() const { return _##n; } \
512  T& get##N() { return _##n; } \
513  private: \
514  T _##n; \
515  static T _static##N;
516 
517 
518 #define ADD_PROPERTY_TO_MAP(P, n, T) \
519  { \
520  EntityPropertyInfo propertyInfo { makePropertyInfo<T>(P) }; \
521  _propertyInfos[#n] = propertyInfo; \
522  _enumsToPropertyStrings[P] = #n; \
523  }
524 
525 #define ADD_PROPERTY_TO_MAP_WITH_RANGE(P, n, M, X) \
526  { \
527  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \
528  _propertyInfos[#n] = propertyInfo; \
529  _enumsToPropertyStrings[P] = #n; \
530  }
531 
532 #define ADD_GROUP_PROPERTY_TO_MAP(P, g, n) \
533  { \
534  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P); \
535  _propertyInfos[#g "." #n] = propertyInfo; \
536  _propertyInfos[#g].propertyEnums << P; \
537  _enumsToPropertyStrings[P] = #g "." #n; \
538  }
539 
540 #define ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(P, g, n, M, X) \
541  { \
542  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \
543  _propertyInfos[#g "." #n] = propertyInfo; \
544  _propertyInfos[#g].propertyEnums << P; \
545  _enumsToPropertyStrings[P] = #g "." #n; \
546  }
547 
548 #define DEFINE_CORE(N, n, T, V) \
549  public: \
550  bool n##Changed() const { return _##n##Changed; } \
551  void set##N##Changed(bool value) { _##n##Changed = value; } \
552  private: \
553  T _##n = V; \
554  bool _##n##Changed { false };
555 
556 #define DEFINE_PROPERTY(N, n, T, V) \
557  public: \
558  T get##N() const { return _##n; } \
559  void set##N(T value) { _##n = value; _##n##Changed = true; } \
560  DEFINE_CORE(N, n, T, V)
561 
562 #define DEFINE_PROPERTY_REF(N, n, T, V) \
563  public: \
564  const T& get##N() const { return _##n; } \
565  void set##N(const T& value) { _##n = value; _##n##Changed = true; } \
566  DEFINE_CORE(N, n, T, V)
567 
568 #define DEFINE_PROPERTY_REF_WITH_SETTER(N, n, T, V) \
569  public: \
570  const T& get##N() const { return _##n; } \
571  void set##N(const T& value); \
572  DEFINE_CORE(N, n, T, V)
573 
574 #define DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(N, n, T, V) \
575  public: \
576  T get##N() const; \
577  void set##N(const T& value); \
578  DEFINE_CORE(N, n, T, V)
579 
580 #define DEFINE_PROPERTY_REF_ENUM(N, n, T, V) \
581  public: \
582  const T& get##N() const { return _##n; } \
583  void set##N(const T& value) { _##n = value; _##n##Changed = true; } \
584  QString get##N##AsString() const; \
585  void set##N##FromString(const QString& name); \
586  DEFINE_CORE(N, n, T, V)
587 
588 #define DEBUG_PROPERTY(D, P, N, n, x) \
589  D << " " << #n << ":" << P.get##N() << x << "[changed:" << P.n##Changed() << "]\n";
590 
591 #define DEBUG_PROPERTY_IF_CHANGED(D, P, N, n, x) \
592  if (P.n##Changed()) { \
593  D << " " << #n << ":" << P.get##N() << x << "\n"; \
594  }
595 
596 // EntityItem helpers
597 #define DEFINE_VARIABLE_NO_GETTER_SETTER(N, n, T, V) \
598  protected: \
599  T _##n = V;
600 
601 #define DEFINE_VARIABLE(N, n, T, V) \
602  public: \
603  T get##N() const; \
604  void set##N(T value); \
605  protected: \
606  T _##n = V;
607 
608 #define DEFINE_VARIABLE_REF(N, n, T, V) \
609  public: \
610  T get##N() const; \
611  void set##N(const T& value); \
612  protected: \
613  T _##n = V;
614 
615 #define DEFINE_VARIABLE_BASIC(N, n, T, V) \
616  public: \
617  T get##N() const { \
618  return resultWithReadLock<T>([&] { \
619  return _##n; \
620  }); \
621  } \
622  void set##N(T value) { \
623  withWriteLock([&] { \
624  _##n = value; \
625  }); \
626  } \
627  protected: \
628  T _##n = V;
629 
630 #define DEFINE_VARIABLE_BASIC_REF(N, n, T, V) \
631  public: \
632  T get##N() const { \
633  return resultWithReadLock<T>([&] { \
634  return _##n; \
635  }); \
636  } \
637  void set##N(const T& value) { \
638  withWriteLock([&] { \
639  _##n = value; \
640  }); \
641  } \
642  protected: \
643  T _##n = V;
644 
645 #define DEFINE_VARIABLE_RENDER(N, n, T, V) \
646  public: \
647  T get##N() const { \
648  return resultWithReadLock<T>([&] { \
649  return _##n; \
650  }); \
651  } \
652  void set##N(T value) { \
653  withWriteLock([&] { \
654  _needsRenderUpdate |= _##n != value; \
655  _##n = value; \
656  }); \
657  } \
658  protected: \
659  T _##n = V;
660 
661 #define DEFINE_VARIABLE_RENDER_REF(N, n, T, V) \
662  public: \
663  T get##N() const { \
664  return resultWithReadLock<T>([&] { \
665  return _##n; \
666  }); \
667  } \
668  void set##N(const T& value) { \
669  withWriteLock([&] { \
670  _needsRenderUpdate |= _##n != value; \
671  _##n = value; \
672  }); \
673  } \
674  protected: \
675  T _##n = V;
676 
677 #define ENTITY_PROPERTY_SUBCLASS_METHODS \
678  EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, \
679  bool allowEmptyDesiredProperties) const override; \
680  bool setSubClassProperties(const EntityItemProperties& properties) override; \
681  EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \
682  void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, \
683  EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, \
684  EntityPropertyFlags& requestedProperties, \
685  EntityPropertyFlags& propertyFlags, \
686  EntityPropertyFlags& propertiesDidntFit, \
687  int& propertyCount, \
688  OctreeElement::AppendState& appendState) const override; \
689  int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \
690  ReadBitstreamToTreeParams& args, \
691  EntityPropertyFlags& propertyFlags, bool overwriteLocalData, \
692  bool& somethingChanged) override; \
693  virtual void debugDump() const override;
694 
695 #define ENTITY_PROPERTY_GROUP_METHODS(P) \
696  virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, \
697  ScriptEngine* engine, bool skipDefaults, \
698  EntityItemProperties& defaultEntityProperties, \
699  bool returnNothingOnEmptyPropertyFlags, \
700  bool isMyOwnAvatarEntity) const override; \
701  virtual void copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, \
702  bool& _defaultSettings) override; \
703  void merge(const P& other); \
704  virtual void debugDump() const override; \
705  virtual void listChangedProperties(QList<QString>& out) override; \
706  virtual bool appendToEditPacket(OctreePacketData* packetData, \
707  EntityPropertyFlags& requestedProperties, \
708  EntityPropertyFlags& propertyFlags, \
709  EntityPropertyFlags& propertiesDidntFit, \
710  int& propertyCount, \
711  OctreeElement::AppendState& appendState) const override; \
712  virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, \
713  const unsigned char*& dataAt, int& processedBytes) override; \
714  virtual void markAllChanged() override; \
715  virtual EntityPropertyFlags getChangedProperties() const override; \
716  virtual void getProperties(EntityItemProperties& propertiesOut) const override; \
717  virtual bool setProperties(const EntityItemProperties& properties) override; \
718  virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \
719  virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \
720  ReadBitstreamToTreeParams& args, \
721  EntityPropertyFlags& propertyFlags, \
722  bool overwriteLocalData, bool& somethingChanged) override; \
723  static void addPropertyMap(QHash<QString, EntityPropertyInfo>& _propertyInfos, \
724  QHash<EntityPropertyList, QString>& _enumsToPropertyStrings);
725 
726 #endif // hifi_EntityItemPropertiesMacros_h
Abstract ID for editing model items. Used in EntityItem JS API.
Definition: EntityItemID.h:28
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