Blender  V3.3
GHOST_XrControllerModel.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <cassert>
8 
9 #include <Eigen/Core>
10 #include <Eigen/Geometry>
11 
12 #include "GHOST_Types.h"
13 #include "GHOST_XrException.h"
14 #include "GHOST_Xr_intern.h"
15 
17 
18 #define TINYGLTF_IMPLEMENTATION
19 #define TINYGLTF_NO_STB_IMAGE
20 #define TINYGLTF_NO_STB_IMAGE_WRITE
21 #define STBIWDEF static inline
22 #include "tiny_gltf.h"
23 
27  float local_transform[4][4];
28 };
29 
30 /* -------------------------------------------------------------------- */
38  std::vector<GHOST_XrControllerModelVertex> vertices;
39  std::vector<uint32_t> indices;
40 };
41 
46 static void validate_accessor(const tinygltf::Accessor &accessor,
47  const tinygltf::BufferView &buffer_view,
48  const tinygltf::Buffer &buffer,
49  size_t byte_stride,
50  size_t element_size)
51 {
52  /* Make sure the accessor does not go out of range of the buffer view. */
53  if (accessor.byteOffset + (accessor.count - 1) * byte_stride + element_size >
54  buffer_view.byteLength) {
55  throw GHOST_XrException("glTF: Accessor goes out of range of bufferview.");
56  }
57 
58  /* Make sure the buffer view does not go out of range of the buffer. */
59  if (buffer_view.byteOffset + buffer_view.byteLength > buffer.data.size()) {
60  throw GHOST_XrException("glTF: BufferView goes out of range of buffer.");
61  }
62 }
63 
64 template<float (GHOST_XrControllerModelVertex::*field)[3]>
65 static void read_vertices(const tinygltf::Accessor &accessor,
66  const tinygltf::BufferView &buffer_view,
67  const tinygltf::Buffer &buffer,
68  GHOST_XrPrimitive &primitive)
69 {
70  if (accessor.type != TINYGLTF_TYPE_VEC3) {
71  throw GHOST_XrException(
72  "glTF: Accessor for primitive attribute has incorrect type (VEC3 expected).");
73  }
74 
75  if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
76  throw GHOST_XrException(
77  "glTF: Accessor for primitive attribute has incorrect component type (FLOAT expected).");
78  }
79 
80  /* If stride is not specified, it is tightly packed. */
81  constexpr size_t packed_size = sizeof(float) * 3;
82  const size_t stride = buffer_view.byteStride == 0 ? packed_size : buffer_view.byteStride;
83  validate_accessor(accessor, buffer_view, buffer, stride, packed_size);
84 
85  /* Resize the vertices vector, if necessary, to include room for the attribute data.
86  * If there are multiple attributes for a primitive, the first one will resize, and the
87  * subsequent will not need to. */
88  primitive.vertices.resize(accessor.count);
89 
90  /* Copy the attribute value over from the glTF buffer into the appropriate vertex field. */
91  const uint8_t *buffer_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
92  for (size_t i = 0; i < accessor.count; i++, buffer_ptr += stride) {
93  memcpy(primitive.vertices[i].*field, buffer_ptr, stride);
94  }
95 }
96 
97 static void load_attribute_accessor(const tinygltf::Model &gltf_model,
98  const std::string &attribute_name,
99  int accessor_id,
100  GHOST_XrPrimitive &primitive)
101 {
102  const auto &accessor = gltf_model.accessors.at(accessor_id);
103 
104  if (accessor.bufferView == -1) {
105  throw GHOST_XrException("glTF: Accessor for primitive attribute specifies no bufferview.");
106  }
107 
108  const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
109  if (buffer_view.target != TINYGLTF_TARGET_ARRAY_BUFFER && buffer_view.target != 0) {
110  throw GHOST_XrException(
111  "glTF: Accessor for primitive attribute uses bufferview with invalid 'target' type.");
112  }
113 
114  const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
115 
116  if (attribute_name.compare("POSITION") == 0) {
117  read_vertices<&GHOST_XrControllerModelVertex::position>(
118  accessor, buffer_view, buffer, primitive);
119  }
120  else if (attribute_name.compare("NORMAL") == 0) {
121  read_vertices<&GHOST_XrControllerModelVertex::normal>(
122  accessor, buffer_view, buffer, primitive);
123  }
124 }
125 
130 template<typename TSrcIndex>
131 static void read_indices(const tinygltf::Accessor &accessor,
132  const tinygltf::BufferView &buffer_view,
133  const tinygltf::Buffer &buffer,
134  GHOST_XrPrimitive &primitive)
135 {
136 
137  /* Allow 0 (not specified) even though spec doesn't seem to allow this (BoomBox GLB fails). */
138  if (buffer_view.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER && buffer_view.target != 0) {
139  throw GHOST_XrException(
140  "glTF: Accessor for indices uses bufferview with invalid 'target' type.");
141  }
142 
143  constexpr size_t component_size_bytes = sizeof(TSrcIndex);
144  if (buffer_view.byteStride != 0 &&
145  buffer_view.byteStride !=
146  component_size_bytes) { /* Index buffer must be packed per glTF spec. */
147  throw GHOST_XrException(
148  "glTF: Accessor for indices uses bufferview with invalid 'byteStride'.");
149  }
150 
151  validate_accessor(accessor, buffer_view, buffer, component_size_bytes, component_size_bytes);
152 
153  /* Since only triangles are supported, enforce that the number of indices is divisible by 3. */
154  if ((accessor.count % 3) != 0) {
155  throw GHOST_XrException("glTF: Unexpected number of indices for triangle primitive");
156  }
157 
158  const TSrcIndex *index_buffer = reinterpret_cast<const TSrcIndex *>(
159  buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset);
160  for (uint32_t i = 0; i < accessor.count; i++) {
161  primitive.indices.push_back(*(index_buffer + i));
162  }
163 }
164 
168 static void load_index_accessor(const tinygltf::Model &gltf_model,
169  const tinygltf::Accessor &accessor,
170  GHOST_XrPrimitive &primitive)
171 {
172  if (accessor.type != TINYGLTF_TYPE_SCALAR) {
173  throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'type'.");
174  }
175 
176  if (accessor.bufferView == -1) {
177  throw GHOST_XrException("glTF: Index accessor without bufferView is currently not supported.");
178  }
179 
180  const tinygltf::BufferView &buffer_view = gltf_model.bufferViews.at(accessor.bufferView);
181  const tinygltf::Buffer &buffer = gltf_model.buffers.at(buffer_view.buffer);
182 
183  if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
184  read_indices<uint8_t>(accessor, buffer_view, buffer, primitive);
185  }
186  else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
187  read_indices<uint16_t>(accessor, buffer_view, buffer, primitive);
188  }
189  else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
190  read_indices<uint32_t>(accessor, buffer_view, buffer, primitive);
191  }
192  else {
193  throw GHOST_XrException("glTF: Accessor for indices specifies invalid 'componentType'.");
194  }
195 }
196 
197 static GHOST_XrPrimitive read_primitive(const tinygltf::Model &gltf_model,
198  const tinygltf::Primitive &gltf_primitive)
199 {
200  if (gltf_primitive.mode != TINYGLTF_MODE_TRIANGLES) {
201  throw GHOST_XrException(
202  "glTF: Unsupported primitive mode. Only TINYGLTF_MODE_TRIANGLES is supported.");
203  }
204 
205  GHOST_XrPrimitive primitive;
206 
207  /* glTF vertex data is stored in an attribute dictionary.Loop through each attribute and insert
208  * it into the GHOST_XrPrimitive. */
209  for (const auto &[attr_name, accessor_idx] : gltf_primitive.attributes) {
210  load_attribute_accessor(gltf_model, attr_name, accessor_idx, primitive);
211  }
212 
213  if (gltf_primitive.indices != -1) {
214  /* If indices are specified for the glTF primitive, read them into the GHOST_XrPrimitive. */
215  load_index_accessor(gltf_model, gltf_model.accessors.at(gltf_primitive.indices), primitive);
216  }
217 
218  return primitive;
219 }
220 
224 static void calc_node_transforms(const tinygltf::Node &gltf_node,
225  const float parent_transform[4][4],
226  float r_local_transform[4][4],
227  float r_world_transform[4][4])
228 {
229  /* A node may specify either a 4x4 matrix or TRS (Translation - Rotation - Scale) values, but not
230  * both. */
231  if (gltf_node.matrix.size() == 16) {
232  const std::vector<double> &dm = gltf_node.matrix;
233  float m[4][4] = {{(float)dm[0], (float)dm[1], (float)dm[2], (float)dm[3]},
234  {(float)dm[4], (float)dm[5], (float)dm[6], (float)dm[7]},
235  {(float)dm[8], (float)dm[9], (float)dm[10], (float)dm[11]},
236  {(float)dm[12], (float)dm[13], (float)dm[14], (float)dm[15]}};
237  memcpy(r_local_transform, m, sizeof(float[4][4]));
238  }
239  else {
240  /* No matrix is present, so construct a matrix from the TRS values (each one is optional). */
241  std::vector<double> translation = gltf_node.translation;
242  std::vector<double> rotation = gltf_node.rotation;
243  std::vector<double> scale = gltf_node.scale;
244  Eigen::Matrix4f &m = *(Eigen::Matrix4f *)r_local_transform;
245  Eigen::Quaternionf q;
246  Eigen::Matrix3f scalemat;
247 
248  if (translation.size() != 3) {
249  translation.resize(3);
250  translation[0] = translation[1] = translation[2] = 0.0;
251  }
252  if (rotation.size() != 4) {
253  rotation.resize(4);
254  rotation[0] = rotation[1] = rotation[2] = 0.0;
255  rotation[3] = 1.0;
256  }
257  if (scale.size() != 3) {
258  scale.resize(3);
259  scale[0] = scale[1] = scale[2] = 1.0;
260  }
261 
262  q.w() = (float)rotation[3];
263  q.x() = (float)rotation[0];
264  q.y() = (float)rotation[1];
265  q.z() = (float)rotation[2];
266  q.normalize();
267 
268  scalemat.setIdentity();
269  scalemat(0, 0) = (float)scale[0];
270  scalemat(1, 1) = (float)scale[1];
271  scalemat(2, 2) = (float)scale[2];
272 
273  m.setIdentity();
274  m.block<3, 3>(0, 0) = q.toRotationMatrix() * scalemat;
275  m.block<3, 1>(0, 3) = Eigen::Vector3f(
276  (float)translation[0], (float)translation[1], (float)translation[2]);
277  }
278 
279  *(Eigen::Matrix4f *)r_world_transform = *(Eigen::Matrix4f *)parent_transform *
280  *(Eigen::Matrix4f *)r_local_transform;
281 }
282 
283 static void load_node(const tinygltf::Model &gltf_model,
284  int gltf_node_id,
285  int32_t parent_idx,
286  const float parent_transform[4][4],
287  const std::string &parent_name,
288  const std::vector<XrControllerModelNodePropertiesMSFT> &node_properties,
289  std::vector<GHOST_XrControllerModelVertex> &vertices,
290  std::vector<uint32_t> &indices,
291  std::vector<GHOST_XrControllerModelComponent> &components,
292  std::vector<GHOST_XrControllerModelNode> &nodes,
293  std::vector<int32_t> &node_state_indices)
294 {
295  const tinygltf::Node &gltf_node = gltf_model.nodes.at(gltf_node_id);
296  float world_transform[4][4];
297 
298  GHOST_XrControllerModelNode &node = nodes.emplace_back();
299  const int32_t node_idx = (int32_t)(nodes.size() - 1);
300  node.parent_idx = parent_idx;
301  calc_node_transforms(gltf_node, parent_transform, node.local_transform, world_transform);
302 
303  for (size_t i = 0; i < node_properties.size(); ++i) {
304  if ((node_state_indices[i] < 0) && (parent_name == node_properties[i].parentNodeName) &&
305  (gltf_node.name == node_properties[i].nodeName)) {
306  node_state_indices[i] = node_idx;
307  break;
308  }
309  }
310 
311  if (gltf_node.mesh != -1) {
312  const tinygltf::Mesh &gltf_mesh = gltf_model.meshes.at(gltf_node.mesh);
313 
314  GHOST_XrControllerModelComponent &component = components.emplace_back();
315  node.component_idx = components.size() - 1;
316  memcpy(component.transform, world_transform, sizeof(component.transform));
317  component.vertex_offset = vertices.size();
318  component.index_offset = indices.size();
319 
320  for (const tinygltf::Primitive &gltf_primitive : gltf_mesh.primitives) {
321  /* Read the primitive data from the glTF buffers. */
322  const GHOST_XrPrimitive primitive = read_primitive(gltf_model, gltf_primitive);
323 
324  const size_t start_vertex = vertices.size();
325  size_t offset = start_vertex;
326  size_t count = primitive.vertices.size();
327  vertices.resize(offset + count);
328  memcpy(vertices.data() + offset,
329  primitive.vertices.data(),
330  count * sizeof(decltype(primitive.vertices)::value_type));
331 
332  offset = indices.size();
333  count = primitive.indices.size();
334  indices.resize(offset + count);
335  for (size_t i = 0; i < count; i += 3) {
336  indices[offset + i + 0] = start_vertex + primitive.indices[i + 0];
337  indices[offset + i + 1] = start_vertex + primitive.indices[i + 2];
338  indices[offset + i + 2] = start_vertex + primitive.indices[i + 1];
339  }
340  }
341 
342  component.vertex_count = vertices.size() - component.vertex_offset;
343  component.index_count = indices.size() - component.index_offset;
344  }
345 
346  /* Recursively load all children. */
347  for (const int child_node_id : gltf_node.children) {
348  load_node(gltf_model,
349  child_node_id,
350  node_idx,
351  world_transform,
352  gltf_node.name,
353  node_properties,
354  vertices,
355  indices,
356  components,
357  nodes,
358  node_state_indices);
359  }
360 }
361 
364 /* -------------------------------------------------------------------- */
369 static PFN_xrGetControllerModelKeyMSFT g_xrGetControllerModelKeyMSFT = nullptr;
370 static PFN_xrLoadControllerModelMSFT g_xrLoadControllerModelMSFT = nullptr;
371 static PFN_xrGetControllerModelPropertiesMSFT g_xrGetControllerModelPropertiesMSFT = nullptr;
372 static PFN_xrGetControllerModelStateMSFT g_xrGetControllerModelStateMSFT = nullptr;
373 static XrInstance g_instance = XR_NULL_HANDLE;
374 
375 #define INIT_EXTENSION_FUNCTION(name) \
376  CHECK_XR( \
377  xrGetInstanceProcAddr(instance, #name, reinterpret_cast<PFN_xrVoidFunction *>(&g_##name)), \
378  "Failed to get pointer to extension function: " #name);
379 
381 {
382  if (instance != g_instance) {
385  g_xrLoadControllerModelMSFT = nullptr;
388  }
389 
390  if (g_xrGetControllerModelKeyMSFT == nullptr) {
391  INIT_EXTENSION_FUNCTION(xrGetControllerModelKeyMSFT);
392  }
393  if (g_xrLoadControllerModelMSFT == nullptr) {
394  INIT_EXTENSION_FUNCTION(xrLoadControllerModelMSFT);
395  }
396  if (g_xrGetControllerModelPropertiesMSFT == nullptr) {
397  INIT_EXTENSION_FUNCTION(xrGetControllerModelPropertiesMSFT);
398  }
399  if (g_xrGetControllerModelStateMSFT == nullptr) {
400  INIT_EXTENSION_FUNCTION(xrGetControllerModelStateMSFT);
401  }
402 }
403 
406 /* -------------------------------------------------------------------- */
412  const char *subaction_path_str)
413 {
415 
416  CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_path),
417  (std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
418 }
419 
421 {
422  if (m_load_task.valid()) {
423  m_load_task.wait();
424  }
425 }
426 
427 void GHOST_XrControllerModel::load(XrSession session)
428 {
429  if (m_data_loaded || m_load_task.valid()) {
430  return;
431  }
432 
433  /* Get model key. */
434  XrControllerModelKeyStateMSFT key_state{XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT};
435  CHECK_XR(g_xrGetControllerModelKeyMSFT(session, m_subaction_path, &key_state),
436  "Failed to get controller model key state.");
437 
438  if (key_state.modelKey != XR_NULL_CONTROLLER_MODEL_KEY_MSFT) {
439  m_model_key = key_state.modelKey;
440  /* Load asynchronously. */
441  m_load_task = std::async(std::launch::async,
442  [&, session = session]() { return loadControllerModel(session); });
443  }
444 }
445 
446 void GHOST_XrControllerModel::loadControllerModel(XrSession session)
447 {
448  /* Load binary buffers. */
449  uint32_t buf_size = 0;
450  CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, 0, &buf_size, nullptr),
451  "Failed to get controller model buffer size.");
452 
453  std::vector<uint8_t> buf((size_t)buf_size);
454  CHECK_XR(g_xrLoadControllerModelMSFT(session, m_model_key, buf_size, &buf_size, buf.data()),
455  "Failed to load controller model binary buffers.");
456 
457  /* Convert to glTF model. */
458  tinygltf::TinyGLTF gltf_loader;
459  tinygltf::Model gltf_model;
460  std::string err_msg;
461  {
462  /* Workaround for TINYGLTF_NO_STB_IMAGE define. Set custom image loader to prevent failure when
463  * parsing image data. */
464  auto load_img_func = [](tinygltf::Image *img,
465  const int p0,
466  std::string *p1,
467  std::string *p2,
468  int p3,
469  int p4,
470  const unsigned char *p5,
471  int p6,
472  void *user_pointer) -> bool {
473  (void)img;
474  (void)p0;
475  (void)p1;
476  (void)p2;
477  (void)p3;
478  (void)p4;
479  (void)p5;
480  (void)p6;
481  (void)user_pointer;
482  return true;
483  };
484  gltf_loader.SetImageLoader(load_img_func, nullptr);
485  }
486 
487  if (!gltf_loader.LoadBinaryFromMemory(&gltf_model, &err_msg, nullptr, buf.data(), buf_size)) {
488  throw GHOST_XrException(("Failed to load glTF controller model: " + err_msg).c_str());
489  }
490 
491  /* Get node properties. */
492  XrControllerModelPropertiesMSFT model_properties{XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT};
493  model_properties.nodeCapacityInput = 0;
494  CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
495  "Failed to get controller model node properties count.");
496 
497  std::vector<XrControllerModelNodePropertiesMSFT> node_properties(
498  model_properties.nodeCountOutput, {XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT});
499  model_properties.nodeCapacityInput = (uint32_t)node_properties.size();
500  model_properties.nodeProperties = node_properties.data();
501  CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties),
502  "Failed to get controller model node properties.");
503 
504  m_node_state_indices.resize(node_properties.size(), -1);
505 
506  /* Get mesh vertex data. */
507  const tinygltf::Scene &default_scene = gltf_model.scenes.at(
508  (gltf_model.defaultScene == -1) ? 0 : gltf_model.defaultScene);
509  const int32_t root_idx = -1;
510  const std::string root_name = "";
511  float root_transform[4][4] = {{0}};
512  root_transform[0][0] = root_transform[1][1] = root_transform[2][2] = root_transform[3][3] = 1.0f;
513 
514  for (const int node_id : default_scene.nodes) {
515  load_node(gltf_model,
516  node_id,
517  root_idx,
518  root_transform,
519  root_name,
520  node_properties,
521  m_vertices,
522  m_indices,
523  m_components,
524  m_nodes,
525  m_node_state_indices);
526  }
527 
528  m_data_loaded = true;
529 }
530 
532 {
533  if (!m_data_loaded) {
534  return;
535  }
536 
537  /* Get node states. */
538  XrControllerModelStateMSFT model_state{XR_TYPE_CONTROLLER_MODEL_STATE_MSFT};
539  model_state.nodeCapacityInput = 0;
540  CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
541  "Failed to get controller model node state count.");
542 
543  const uint32_t count = model_state.nodeCountOutput;
544  std::vector<XrControllerModelNodeStateMSFT> node_states(
545  count, {XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT});
546  model_state.nodeCapacityInput = count;
547  model_state.nodeStates = node_states.data();
548  CHECK_XR(g_xrGetControllerModelStateMSFT(session, m_model_key, &model_state),
549  "Failed to get controller model node states.");
550 
551  /* Update node local transforms. */
552  assert(m_node_state_indices.size() == count);
553 
554  for (uint32_t state_idx = 0; state_idx < count; ++state_idx) {
555  const int32_t &node_idx = m_node_state_indices[state_idx];
556  if (node_idx >= 0) {
557  const XrPosef &pose = node_states[state_idx].nodePose;
558  Eigen::Matrix4f &m = *(Eigen::Matrix4f *)m_nodes[node_idx].local_transform;
559  Eigen::Quaternionf q(
560  pose.orientation.w, pose.orientation.x, pose.orientation.y, pose.orientation.z);
561  m.setIdentity();
562  m.block<3, 3>(0, 0) = q.toRotationMatrix();
563  m.block<3, 1>(0, 3) = Eigen::Vector3f(pose.position.x, pose.position.y, pose.position.z);
564  }
565  }
566 
567  /* Calculate component transforms (in world space). */
568  std::vector<Eigen::Matrix4f> world_transforms(m_nodes.size());
569  uint32_t i = 0;
570  for (const GHOST_XrControllerModelNode &node : m_nodes) {
571  world_transforms[i] = (node.parent_idx >= 0) ? world_transforms[node.parent_idx] *
572  *(Eigen::Matrix4f *)node.local_transform :
573  *(Eigen::Matrix4f *)node.local_transform;
574  if (node.component_idx >= 0) {
575  memcpy(m_components[node.component_idx].transform,
576  world_transforms[i].data(),
577  sizeof(m_components[node.component_idx].transform));
578  }
579  ++i;
580  }
581 }
582 
583 void GHOST_XrControllerModel::getData(GHOST_XrControllerModelData &r_data)
584 {
585  if (m_data_loaded) {
586  r_data.count_vertices = (uint32_t)m_vertices.size();
587  r_data.vertices = m_vertices.data();
588  r_data.count_indices = (uint32_t)m_indices.size();
589  r_data.indices = m_indices.data();
590  r_data.count_components = (uint32_t)m_components.size();
591  r_data.components = m_components.data();
592  }
593  else {
594  r_data.count_vertices = 0;
595  r_data.vertices = nullptr;
596  r_data.count_indices = 0;
597  r_data.indices = nullptr;
598  r_data.count_components = 0;
599  r_data.components = nullptr;
600  }
601 }
602 
typedef float(TangentPoint)[2]
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
struct Image Image
struct Mesh Mesh
struct Scene Scene
static void init_controller_model_extension_functions(XrInstance instance)
static void load_node(const tinygltf::Model &gltf_model, int gltf_node_id, int32_t parent_idx, const float parent_transform[4][4], const std::string &parent_name, const std::vector< XrControllerModelNodePropertiesMSFT > &node_properties, std::vector< GHOST_XrControllerModelVertex > &vertices, std::vector< uint32_t > &indices, std::vector< GHOST_XrControllerModelComponent > &components, std::vector< GHOST_XrControllerModelNode > &nodes, std::vector< int32_t > &node_state_indices)
static void read_vertices(const tinygltf::Accessor &accessor, const tinygltf::BufferView &buffer_view, const tinygltf::Buffer &buffer, GHOST_XrPrimitive &primitive)
static XrInstance g_instance
static void validate_accessor(const tinygltf::Accessor &accessor, const tinygltf::BufferView &buffer_view, const tinygltf::Buffer &buffer, size_t byte_stride, size_t element_size)
static PFN_xrLoadControllerModelMSFT g_xrLoadControllerModelMSFT
static void read_indices(const tinygltf::Accessor &accessor, const tinygltf::BufferView &buffer_view, const tinygltf::Buffer &buffer, GHOST_XrPrimitive &primitive)
#define INIT_EXTENSION_FUNCTION(name)
static PFN_xrGetControllerModelPropertiesMSFT g_xrGetControllerModelPropertiesMSFT
static void load_index_accessor(const tinygltf::Model &gltf_model, const tinygltf::Accessor &accessor, GHOST_XrPrimitive &primitive)
static PFN_xrGetControllerModelStateMSFT g_xrGetControllerModelStateMSFT
static PFN_xrGetControllerModelKeyMSFT g_xrGetControllerModelKeyMSFT
static GHOST_XrPrimitive read_primitive(const tinygltf::Model &gltf_model, const tinygltf::Primitive &gltf_primitive)
static void calc_node_transforms(const tinygltf::Node &gltf_node, const float parent_transform[4][4], float r_local_transform[4][4], float r_world_transform[4][4])
static void load_attribute_accessor(const tinygltf::Model &gltf_model, const std::string &attribute_name, int accessor_id, GHOST_XrPrimitive &primitive)
#define CHECK_XR(call, error_msg)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object instance
struct _Buffer Buffer
void updateComponents(XrSession session)
GHOST_XrControllerModel(XrInstance instance, const char *subaction_path)
void getData(GHOST_XrControllerModelData &r_data)
void load(XrSession session)
OperationNode * node
SyclQueue void void size_t num_bytes void
int count
ccl_global float * buffer
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
unsigned char uint8_t
Definition: stdint.h:78
std::vector< GHOST_XrControllerModelVertex > vertices
std::vector< uint32_t > indices