diff --git a/doxygen/_e_c_s_8h_source.html b/doxygen/_e_c_s_8h_source.html index bc7e3db0..f089728f 100644 --- a/doxygen/_e_c_s_8h_source.html +++ b/doxygen/_e_c_s_8h_source.html @@ -132,543 +132,535 @@
74 
78  struct Visibility : public ecs::PerView<bool, 4, true>
79  {
-
80  Visibility* parent = nullptr;
-
81  };
-
82 
-
83  namespace ecs
-
84  {
-
89  class ROCKY_EXPORT System
-
90  {
-
91  public:
-
93  entt::registry& registry;
-
94 
-
96  Status status;
-
97 
-
99  virtual void initializeSystem(Runtime& runtime)
-
100  {
-
101  //nop
-
102  }
-
103 
-
105  virtual void update(Runtime& runtime)
-
106  {
-
107  //nop
-
108  }
-
109 
-
110  protected:
-
111  System(entt::registry& in_registry) :
-
112  registry(in_registry) { }
-
113  };
-
114 
-
124  class SystemNodeBase : public vsg::Inherit<vsg::Compilable, SystemNodeBase>
-
125  {
-
126  public:
-
127  class SystemsManagerGroup* manager = nullptr;
-
128 
-
129  struct CreateOrUpdateData
-
130  {
-
131  vsg::ref_ptr<vsg::Node> existing_node;
-
132  vsg::ref_ptr<vsg::Node> new_node;
-
133  bool new_node_needs_compilation = true;
-
134  };
-
135 
-
136  struct EntityCompileBatch
-
137  {
-
138  std::vector<entt::entity> entities;
-
139  SystemNodeBase* system;
-
140  Runtime* runtime;
-
141  };
-
142 
-
143  virtual void create_or_update(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const = 0;
-
144  virtual void finish_update(entt::entity entity, CreateOrUpdateData& data) const = 0;
-
145  };
-
146 
-
147  template<class T>
-
148  class SystemNode : public vsg::Inherit<SystemNodeBase, SystemNode<T>>, public System
-
149  {
-
150  using super = SystemNodeBase;
-
151 
-
152  public:
-
154  virtual ~SystemNode<T>();
-
155 
-
156  // looks for any new components that need VSG initialization
-
157  void update(Runtime&) override;
-
158 
-
159  protected:
-
161  SystemNode<T>(entt::registry& in_registry);
-
162 
-
164  virtual int featureMask(const T& t) const { return 0; }
-
165 
-
166  // The configuration and command list for a graphics pipeline
-
167  // configured for a specific set of features. This setup
-
168  // supports the creation of a unique pipeline for a feature set
-
169  // that's stored in an integer mask.
-
170  struct Pipeline
-
171  {
-
172  vsg::ref_ptr<vsg::GraphicsPipelineConfigurator> config;
-
173  vsg::ref_ptr<vsg::Commands> commands;
-
174  };
-
175  std::vector<Pipeline> pipelines;
-
176 
-
177  // Hooks to expose systems and components to VSG visitors.
-
178  void compile(vsg::Context&) override;
-
179  void traverse(vsg::Visitor& v) override;
-
180  void traverse(vsg::ConstVisitor& v) const override;
-
181  void traverse(vsg::RecordTraversal&) const override;
-
182 
-
189  bool setReferencePoint(const GeoPoint& point, SRSOperation& out_xform, vsg::dvec3& out_offset) const;
-
190 
-
192  vsg::ref_ptr<vsg::PipelineLayout> getPipelineLayout(const T&) const;
-
193 
+
80  // setting this ties this component to another, ignoring the internal settings
+
81  Visibility* parent = nullptr;
+
82  };
+
83 
+
84  namespace ecs
+
85  {
+
90  class ROCKY_EXPORT System
+
91  {
+
92  public:
+
94  entt::registry& registry;
+
95 
+
97  Status status;
+
98 
+
100  virtual void initializeSystem(Runtime& runtime)
+
101  {
+
102  //nop
+
103  }
+
104 
+
106  virtual void update(Runtime& runtime)
+
107  {
+
108  //nop
+
109  }
+
110 
+
111  protected:
+
112  System(entt::registry& in_registry) :
+
113  registry(in_registry) { }
+
114  };
+
115 
+
125  class SystemNodeBase : public vsg::Inherit<vsg::Compilable, SystemNodeBase>
+
126  {
+
127  public:
+
128  class SystemsManagerGroup* manager = nullptr;
+
129 
+
130  struct CreateOrUpdateData
+
131  {
+
132  vsg::ref_ptr<vsg::Node> existing_node;
+
133  vsg::ref_ptr<vsg::Node> new_node;
+
134  bool new_node_needs_compilation = true;
+
135  };
+
136 
+
137  struct EntityCompileBatch
+
138  {
+
139  std::vector<entt::entity> entities;
+
140  SystemNodeBase* system;
+
141  Runtime* runtime;
+
142  };
+
143 
+
144  virtual void create_or_update(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const = 0;
+
145  virtual void finish_update(entt::entity entity, CreateOrUpdateData& data) const = 0;
+
146  };
+
147 
+
148  template<class T>
+
149  class SystemNode : public vsg::Inherit<SystemNodeBase, SystemNode<T>>, public System
+
150  {
+
151  using super = SystemNodeBase;
+
152 
+
153  public:
+
155  virtual ~SystemNode<T>();
+
156 
+
157  // looks for any new components that need VSG initialization
+
158  void update(Runtime&) override;
+
159 
+
160  protected:
+
162  SystemNode<T>(entt::registry& in_registry);
+
163 
+
165  virtual int featureMask(const T& t) const { return 0; }
+
166 
+
167  // The configuration and command list for a graphics pipeline
+
168  // configured for a specific set of features. This setup
+
169  // supports the creation of a unique pipeline for a feature set
+
170  // that's stored in an integer mask.
+
171  struct Pipeline
+
172  {
+
173  vsg::ref_ptr<vsg::GraphicsPipelineConfigurator> config;
+
174  vsg::ref_ptr<vsg::Commands> commands;
+
175  };
+
176  std::vector<Pipeline> pipelines;
+
177 
+
178  // Hooks to expose systems and components to VSG visitors.
+
179  void compile(vsg::Context&) override;
+
180  void traverse(vsg::Visitor& v) override;
+
181  void traverse(vsg::ConstVisitor& v) const override;
+
182  void traverse(vsg::RecordTraversal&) const override;
+
183 
+
190  bool setReferencePoint(const GeoPoint& point, SRSOperation& out_xform, vsg::dvec3& out_offset) const;
+
191 
+
193  vsg::ref_ptr<vsg::PipelineLayout> getPipelineLayout(const T&) const;
194 
-
195  // temporary? replace with createOrUpdateNode?
-
196  virtual vsg::ref_ptr<vsg::Node> createNode(entt::entity, Runtime&) const {
-
197  return {};
-
198  }
-
199 
-
200  virtual void createOrUpdateNode(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const {
-
201  data.new_node = createNode(entity, runtime); // polyfill
-
202  }
-
203 
-
204 
-
205  void create_or_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const override;
-
206  void finish_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data) const override;
-
207 
-
208  private:
-
209 
-
210  // list of entities whose components are out of date and need updating
-
211  mutable std::vector<entt::entity> entities_to_update;
+
196  virtual void createOrUpdateNode(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const = 0;
+
197 
+
198  void create_or_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const override;
+
199  void finish_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data) const override;
+
200 
+
201  private:
+
202 
+
203  // list of entities whose components are out of date and need updating
+
204  mutable std::vector<entt::entity> entities_to_update;
+
205 
+
206  // internal structure used when sorting components (by pipeline) for rendering
+
207  struct RenderLeaf
+
208  {
+
209  Renderable& renderable;
+
210  Transform* transform;
+
211  };
212 
-
213  // internal structure used when sorting components (by pipeline) for rendering
-
214  struct RenderLeaf
-
215  {
-
216  Renderable& renderable;
-
217  Transform* transform;
-
218  };
-
219 
-
220  // re-usable collection to minimize re-allocation
-
221  mutable std::vector<std::vector<RenderLeaf>> pipelineRenderLeaves;
-
222  };
-
223 
-
228  class ROCKY_EXPORT SystemsManagerGroup : public vsg::Inherit<vsg::Group, SystemsManagerGroup>
-
229  {
-
230  public:
-
231  SystemsManagerGroup(BackgroundServices& bg);
-
232 
-
235  template<class T>
-
236  void add(vsg::ref_ptr<SystemNode<T>> system)
-
237  {
-
238  addChild(system);
-
239  systems.emplace_back(system.get());
-
240  }
-
241 
-
245  template<class T>
-
246  vsg::ref_ptr<T> add(entt::registry& entities)
-
247  {
-
248  auto system = T::create(entities);
-
249  if (system)
-
250  {
-
251  addChild(system);
-
252  systems.emplace_back(system);
-
253  }
-
254  return system;
-
255  }
-
256 
-
260  void add(std::shared_ptr<System> system)
-
261  {
-
262  non_node_systems.emplace_back(system);
-
263  systems.emplace_back(system.get());
-
264  }
-
265 
-
269  void initialize(Runtime& runtime)
-
270  {
-
271  for (auto& child : children)
-
272  {
-
273  auto systemNode = child->cast<SystemNodeBase>();
-
274  if (systemNode)
-
275  {
-
276  systemNode->manager = this;
-
277  }
-
278  }
-
279 
-
280  for (auto& system : systems)
-
281  {
-
282  system->initializeSystem(runtime);
-
283  }
-
284  }
-
285 
-
288  void update(Runtime& runtime)
-
289  {
-
290  for (auto& system : systems)
-
291  {
-
292  system->update(runtime);
-
293  }
-
294  }
-
295 
-
296  void traverse(vsg::RecordTraversal& rt) const override
-
297  {
-
298  vsg::Group::traverse(rt);
-
299  }
-
300 
-
301  public:
-
302  // the data structure holding the queued jobs. 16 might be overkill :)
-
303  util::RingBuffer<SystemNodeBase::EntityCompileBatch> entityCompileJobs{ 16 };
-
304 
-
305  private:
-
306  std::vector<System*> systems;
-
307  std::vector<std::shared_ptr<System>> non_node_systems;
-
308  // NB: SystmeNode instances are group children
-
309  };
-
310 
-
315  inline bool visible(Visibility& vis, int view_index)
-
316  {
-
317  return vis.parent != nullptr ? visible(*vis.parent, view_index) : vis[view_index];
-
318  }
-
319 
-
325  inline void setVisible(entt::registry& r, entt::entity e, bool value, int view_index = -1)
-
326  {
-
327  auto& visibility = r.get<Visibility>(e);
-
328  if (visibility.parent == nullptr)
-
329  {
-
330  if (view_index > 0)
-
331  visibility[view_index] = value;
-
332  else
-
333  visibility.setAll(value);
-
334  }
-
335  }
-
336 
-
342  inline bool visible(entt::registry& r, entt::entity e, int view_index = 0)
-
343  {
-
344  return visible(r.get<Visibility>(e), view_index);
-
345  }
-
346  }
-
347 
-
348 
-
349  //........................................................................
-
350 
-
351 
-
352  namespace ecs
-
353  {
-
354  namespace detail
-
355  {
-
356  // called by registry.emplace<T>()
-
357  template<typename T>
-
358  inline void SystemNode_on_construct(entt::registry& r, entt::entity e)
-
359  {
-
360  T& new_component = r.get<T>(e);
+
213  // re-usable collection to minimize re-allocation
+
214  mutable std::vector<std::vector<RenderLeaf>> pipelineRenderLeaves;
+
215  };
+
216 
+
221  class ROCKY_EXPORT SystemsManagerGroup : public vsg::Inherit<vsg::Group, SystemsManagerGroup>
+
222  {
+
223  public:
+
224  SystemsManagerGroup(BackgroundServices& bg);
+
225 
+
228  template<class T>
+
229  void add(vsg::ref_ptr<SystemNode<T>> system)
+
230  {
+
231  addChild(system);
+
232  systems.emplace_back(system.get());
+
233  }
+
234 
+
238  template<class T>
+
239  vsg::ref_ptr<T> add(entt::registry& entities)
+
240  {
+
241  auto system = T::create(entities);
+
242  if (system)
+
243  {
+
244  addChild(system);
+
245  systems.emplace_back(system);
+
246  }
+
247  return system;
+
248  }
+
249 
+
253  void add(std::shared_ptr<System> system)
+
254  {
+
255  non_node_systems.emplace_back(system);
+
256  systems.emplace_back(system.get());
+
257  }
+
258 
+
262  void initialize(Runtime& runtime)
+
263  {
+
264  for (auto& child : children)
+
265  {
+
266  auto systemNode = child->cast<SystemNodeBase>();
+
267  if (systemNode)
+
268  {
+
269  systemNode->manager = this;
+
270  }
+
271  }
+
272 
+
273  for (auto& system : systems)
+
274  {
+
275  system->initializeSystem(runtime);
+
276  }
+
277  }
+
278 
+
281  void update(Runtime& runtime)
+
282  {
+
283  for (auto& system : systems)
+
284  {
+
285  system->update(runtime);
+
286  }
+
287  }
+
288 
+
289  void traverse(vsg::RecordTraversal& rt) const override
+
290  {
+
291  vsg::Group::traverse(rt);
+
292  }
+
293 
+
294  public:
+
295  // the data structure holding the queued jobs. 16 might be overkill :)
+
296  util::RingBuffer<SystemNodeBase::EntityCompileBatch> entityCompileJobs{ 16 };
+
297 
+
298  private:
+
299  std::vector<System*> systems;
+
300  std::vector<std::shared_ptr<System>> non_node_systems;
+
301  // NB: SystmeNode instances are group children
+
302  };
+
303 
+
308  inline bool visible(Visibility& vis, int view_index)
+
309  {
+
310  return vis.parent != nullptr ? visible(*vis.parent, view_index) : vis[view_index];
+
311  }
+
312 
+
318  inline void setVisible(entt::registry& r, entt::entity e, bool value, int view_index = -1)
+
319  {
+
320  auto& visibility = r.get<Visibility>(e);
+
321  if (visibility.parent == nullptr)
+
322  {
+
323  if (view_index > 0)
+
324  visibility[view_index] = value;
+
325  else
+
326  visibility.setAll(value);
+
327  }
+
328  }
+
329 
+
335  inline bool visible(entt::registry& r, entt::entity e, int view_index = 0)
+
336  {
+
337  return visible(r.get<Visibility>(e), view_index);
+
338  }
+
339  }
+
340 
+
341 
+
342  //........................................................................
+
343 
+
344 
+
345  namespace ecs
+
346  {
+
347  namespace detail
+
348  {
+
349  // called by registry.emplace<T>()
+
350  template<typename T>
+
351  inline void SystemNode_on_construct(entt::registry& r, entt::entity e)
+
352  {
+
353  T& new_component = r.get<T>(e);
+
354 
+
355  // Add a visibility tag (if first time dealing with this component)
+
356  // I am not sure yet how to remove this in the end.
+
357  if (!r.try_get<Visibility>(e))
+
358  {
+
359  r.emplace<Visibility>(e);
+
360  }
361 
-
362  // Add a visibility tag (if first time dealing with this component)
-
363  // I am not sure yet how to remove this in the end.
-
364  if (!r.try_get<Visibility>(e))
-
365  {
-
366  r.emplace<Visibility>(e);
-
367  }
+
362  // Create a Renderable component and attach it to the new component.
+
363  new_component.attach_point = r.create();
+
364  r.emplace<ecs::Renderable>(new_component.attach_point);
+
365 
+
366  new_component.revision++;
+
367  }
368 
-
369  // Create a Renderable component and attach it to the new component.
-
370  new_component.attach_point = r.create();
-
371  r.emplace<ecs::Renderable>(new_component.attach_point);
-
372 
-
373  new_component.revision++;
-
374  }
-
375 
-
376  // invoked by registry.replace<T>(), emplace_or_replace<T>(), or patch<T>()
-
377  template<typename T>
-
378  inline void SystemNode_on_update(entt::registry& r, entt::entity e)
-
379  {
-
380  T& updated_component = r.get<T>(e);
-
381 
-
382  if (updated_component.attach_point == entt::null)
-
383  {
-
384  updated_component.attach_point = r.create();
-
385  r.emplace<ecs::Renderable>(updated_component.attach_point);
-
386  }
-
387 
-
388  updated_component.revision++;
-
389  }
-
390 
-
391  // invoked by registry.erase<T>(), remove<T>(), or registry.destroy(e)
-
392  template<typename T>
-
393  inline void SystemNode_on_destroy(entt::registry& r, entt::entity e)
-
394  {
-
395  T& component_being_destroyed = r.get<T>(e);
-
396  r.destroy(component_being_destroyed.attach_point);
-
397  }
-
398  }
-
399  }
-
400 
-
401  template<class T>
-
402  ecs::SystemNode<T>::SystemNode(entt::registry& in_registry) :
-
403  System(in_registry)
-
404  {
-
405  registry.on_construct<T>().template connect<&detail::SystemNode_on_construct<T>>();
-
406  registry.on_update<T>().template connect<&detail::SystemNode_on_update<T>>();
-
407  registry.on_destroy<T>().template connect<&detail::SystemNode_on_destroy<T>>();
-
408  }
-
409 
-
410  template<class T>
-
411  ecs::SystemNode<T>::~SystemNode()
-
412  {
-
413  registry.on_construct<T>().template disconnect<&detail::SystemNode_on_construct<T>>();
-
414  registry.on_update<T>().template disconnect<&detail::SystemNode_on_update<T>>();
-
415  registry.on_destroy<T>().template disconnect<&detail::SystemNode_on_destroy<T>>();
-
416  }
-
417 
-
418  template<class T>
-
419  inline void ecs::SystemNode<T>::traverse(vsg::Visitor& v)
-
420  {
-
421  for (auto& pipeline : pipelines)
-
422  {
-
423  pipeline.commands->accept(v);
-
424  }
+
369  // invoked by registry.replace<T>(), emplace_or_replace<T>(), or patch<T>()
+
370  template<typename T>
+
371  inline void SystemNode_on_update(entt::registry& r, entt::entity e)
+
372  {
+
373  T& updated_component = r.get<T>(e);
+
374 
+
375  if (updated_component.attach_point == entt::null)
+
376  {
+
377  updated_component.attach_point = r.create();
+
378  r.emplace<ecs::Renderable>(updated_component.attach_point);
+
379  }
+
380 
+
381  updated_component.revision++;
+
382  }
+
383 
+
384  // invoked by registry.erase<T>(), remove<T>(), or registry.destroy(e)
+
385  template<typename T>
+
386  inline void SystemNode_on_destroy(entt::registry& r, entt::entity e)
+
387  {
+
388  T& component_being_destroyed = r.get<T>(e);
+
389  r.destroy(component_being_destroyed.attach_point);
+
390  }
+
391  }
+
392  }
+
393 
+
394  template<class T>
+
395  ecs::SystemNode<T>::SystemNode(entt::registry& in_registry) :
+
396  System(in_registry)
+
397  {
+
398  registry.on_construct<T>().template connect<&detail::SystemNode_on_construct<T>>();
+
399  registry.on_update<T>().template connect<&detail::SystemNode_on_update<T>>();
+
400  registry.on_destroy<T>().template connect<&detail::SystemNode_on_destroy<T>>();
+
401  }
+
402 
+
403  template<class T>
+
404  ecs::SystemNode<T>::~SystemNode()
+
405  {
+
406  registry.on_construct<T>().template disconnect<&detail::SystemNode_on_construct<T>>();
+
407  registry.on_update<T>().template disconnect<&detail::SystemNode_on_update<T>>();
+
408  registry.on_destroy<T>().template disconnect<&detail::SystemNode_on_destroy<T>>();
+
409  }
+
410 
+
411  template<class T>
+
412  inline void ecs::SystemNode<T>::traverse(vsg::Visitor& v)
+
413  {
+
414  for (auto& pipeline : pipelines)
+
415  {
+
416  pipeline.commands->accept(v);
+
417  }
+
418 
+
419  registry.view<T>().each([&](auto& c)
+
420  {
+
421  auto& renderable = registry.get<Renderable>(c.attach_point);
+
422  if (renderable.node)
+
423  renderable.node->accept(v);
+
424  });
425 
-
426  registry.view<T>().each([&](auto& c)
-
427  {
-
428  auto& renderable = registry.get<Renderable>(c.attach_point);
-
429  if (renderable.node)
-
430  renderable.node->accept(v);
-
431  });
-
432 
-
433  super::traverse(v);
-
434  }
-
435 
-
437  template<class T>
-
438  inline void ecs::SystemNode<T>::traverse(vsg::ConstVisitor& v) const
-
439  {
-
440  for (auto& pipeline : pipelines)
-
441  {
-
442  pipeline.commands->accept(v);
-
443  }
+
426  super::traverse(v);
+
427  }
+
428 
+
430  template<class T>
+
431  inline void ecs::SystemNode<T>::traverse(vsg::ConstVisitor& v) const
+
432  {
+
433  for (auto& pipeline : pipelines)
+
434  {
+
435  pipeline.commands->accept(v);
+
436  }
+
437 
+
438  registry.view<T>().each([&](auto& c)
+
439  {
+
440  auto& renderable = registry.get<Renderable>(c.attach_point);
+
441  if (renderable.node)
+
442  renderable.node->accept(v);
+
443  });
444 
-
445  registry.view<T>().each([&](auto& c)
-
446  {
-
447  auto& renderable = registry.get<Renderable>(c.attach_point);
-
448  if (renderable.node)
-
449  renderable.node->accept(v);
-
450  });
-
451 
-
452  super::traverse(v);
-
453  }
-
454 
-
455  template<class T>
-
456  inline void ecs::SystemNode<T>::compile(vsg::Context& context)
-
457  {
-
458  // Compile the pipelines
-
459  for (auto& pipeline : pipelines)
-
460  {
-
461  pipeline.commands->compile(context);
-
462  }
-
463 
-
464  // Compile the components
-
465  util::SimpleCompiler compiler(context);
-
466 
-
467  registry.view<T>().each([&](auto& c)
-
468  {
-
469  auto& renderable = registry.get<Renderable>(c.attach_point);
-
470  if (renderable.node)
-
471  renderable.node->accept(compiler);
-
472  });
-
473  }
-
474 
-
475  template<class T>
-
476  inline void ecs::SystemNode<T>::traverse(vsg::RecordTraversal& rt) const
-
477  {
-
478  const vsg::dmat4 identity_matrix = vsg::dmat4(1.0);
-
479  auto viewID = rt.getState()->_commandBuffer->viewID;
+
445  super::traverse(v);
+
446  }
+
447 
+
448  template<class T>
+
449  inline void ecs::SystemNode<T>::compile(vsg::Context& context)
+
450  {
+
451  // Compile the pipelines
+
452  for (auto& pipeline : pipelines)
+
453  {
+
454  pipeline.commands->compile(context);
+
455  }
+
456 
+
457  // Compile the components
+
458  util::SimpleCompiler compiler(context);
+
459 
+
460  registry.view<T>().each([&](auto& c)
+
461  {
+
462  auto& renderable = registry.get<Renderable>(c.attach_point);
+
463  if (renderable.node)
+
464  renderable.node->accept(compiler);
+
465  });
+
466  }
+
467 
+
468  template<class T>
+
469  inline void ecs::SystemNode<T>::traverse(vsg::RecordTraversal& rt) const
+
470  {
+
471  const vsg::dmat4 identity_matrix = vsg::dmat4(1.0);
+
472  auto viewID = rt.getState()->_commandBuffer->viewID;
+
473 
+
474  // Sort components into render sets by pipeline. If this system doesn't support
+
475  // multiple pipelines, just store them all together in renderSet[0].
+
476  if (pipelineRenderLeaves.empty())
+
477  {
+
478  pipelineRenderLeaves.resize(!pipelines.empty() ? pipelines.size() : 1);
+
479  }
480 
-
481  // Sort components into render sets by pipeline. If this system doesn't support
-
482  // multiple pipelines, just store them all together in renderSet[0].
-
483  if (pipelineRenderLeaves.empty())
-
484  {
-
485  pipelineRenderLeaves.resize(!pipelines.empty() ? pipelines.size() : 1);
-
486  }
-
487 
-
488  // Get an optimized view of all this system's components:
-
489  registry.view<T, Visibility>().each([&](const entt::entity entity, const T& component, auto& visibility)
-
490  {
-
491  auto& renderable = registry.get<Renderable>(component.attach_point);
-
492  if (renderable.node)
-
493  {
-
494  auto& leaves = !pipelines.empty() ? pipelineRenderLeaves[featureMask(component)] : pipelineRenderLeaves[0];
-
495  auto* transform = registry.try_get<Transform>(entity);
-
496 
-
497  // if it's visible, queue it up for rendering
-
498  if (visible(visibility, viewID))
-
499  {
-
500  leaves.emplace_back(RenderLeaf{ renderable, transform });
-
501  }
-
502 
-
503  // otherwise if it's invisible but still has a transform, process that transform
-
504  // so it can calculate its screen-space information (for things like decluttering
-
505  // and intersection)
-
506  else if (transform)
-
507  {
-
508  transform->push(rt, identity_matrix, false);
-
509  }
-
510  }
-
511 
-
512  // If our renderable has a new node waiting to be merged, queue it up
-
513  if (renderable.staged->has_value())
-
514  {
-
515  entities_to_update.emplace_back(entity);
+
481  // Get an optimized view of all this system's components:
+
482  registry.view<T, Visibility>().each([&](const entt::entity entity, const T& component, auto& visibility)
+
483  {
+
484  auto& renderable = registry.get<Renderable>(component.attach_point);
+
485  if (renderable.node)
+
486  {
+
487  auto& leaves = !pipelines.empty() ? pipelineRenderLeaves[featureMask(component)] : pipelineRenderLeaves[0];
+
488  auto* transform = registry.try_get<Transform>(entity);
+
489 
+
490  // if it's visible, queue it up for rendering
+
491  if (visible(visibility, viewID))
+
492  {
+
493  leaves.emplace_back(RenderLeaf{ renderable, transform });
+
494  }
+
495 
+
496  // otherwise if it's invisible but still has a transform, process that transform
+
497  // so it can calculate its screen-space information (for things like decluttering
+
498  // and intersection)
+
499  else if (transform)
+
500  {
+
501  transform->push(rt, identity_matrix, false);
+
502  }
+
503  }
+
504 
+
505  // If our renderable has a new node waiting to be merged, queue it up
+
506  if (renderable.staged->has_value())
+
507  {
+
508  entities_to_update.emplace_back(entity);
+
509  }
+
510 
+
511  // Or if out renderabe is stale, queue it up for regeneration
+
512  else if (renderable.revision != component.revision)
+
513  {
+
514  entities_to_update.emplace_back(entity);
+
515  renderable.revision = component.revision;
516  }
-
517 
-
518  // Or if out renderabe is stale, queue it up for regeneration
-
519  else if (renderable.revision != component.revision)
-
520  {
-
521  entities_to_update.emplace_back(entity);
-
522  renderable.revision = component.revision;
-
523  }
-
524  });
-
525 
-
526  // Time to record all visible components. For each pipeline:
-
527  for (int p = 0; p < pipelineRenderLeaves.size(); ++p)
-
528  {
-
529  if (!pipelineRenderLeaves[p].empty())
-
530  {
-
531  // Bind the Graphics Pipeline for this render set, if there is one:
-
532  if (!pipelines.empty())
-
533  {
-
534  pipelines[p].commands->accept(rt);
-
535  }
-
536 
-
537  // Them record each component. If the component has a transform apply it too.
-
538  for (auto& leaf : pipelineRenderLeaves[p])
-
539  {
-
540  if (leaf.transform)
-
541  {
-
542  if (leaf.transform->push(rt, identity_matrix, true))
-
543  {
-
544  leaf.renderable.node->accept(rt);
-
545  leaf.transform->pop(rt);
-
546  }
-
547  }
-
548  else
-
549  {
-
550  leaf.renderable.node->accept(rt);
-
551  }
-
552  }
+
517  });
+
518 
+
519  // Time to record all visible components. For each pipeline:
+
520  for (int p = 0; p < pipelineRenderLeaves.size(); ++p)
+
521  {
+
522  if (!pipelineRenderLeaves[p].empty())
+
523  {
+
524  // Bind the Graphics Pipeline for this render set, if there is one:
+
525  if (!pipelines.empty())
+
526  {
+
527  pipelines[p].commands->accept(rt);
+
528  }
+
529 
+
530  // Them record each component. If the component has a transform apply it too.
+
531  for (auto& leaf : pipelineRenderLeaves[p])
+
532  {
+
533  if (leaf.transform)
+
534  {
+
535  if (leaf.transform->push(rt, identity_matrix, true))
+
536  {
+
537  leaf.renderable.node->accept(rt);
+
538  leaf.transform->pop(rt);
+
539  }
+
540  }
+
541  else
+
542  {
+
543  leaf.renderable.node->accept(rt);
+
544  }
+
545  }
+
546 
+
547  // clear out for next time around.
+
548  pipelineRenderLeaves[p].clear();
+
549  }
+
550  }
+
551  }
+
552 
553 
-
554  // clear out for next time around.
-
555  pipelineRenderLeaves[p].clear();
-
556  }
-
557  }
-
558  }
-
559 
-
560 
-
561  template<class T>
-
562  inline void ecs::SystemNode<T>::update(Runtime& runtime)
-
563  {
-
564  std::vector<entt::entity> entities_to_create;
-
565 
-
566  for (auto& entity : entities_to_update)
-
567  {
-
568  T& component = registry.get<T>(entity);
-
569  Renderable& renderable = registry.get<Renderable>(component.attach_point);
+
554  template<class T>
+
555  inline void ecs::SystemNode<T>::update(Runtime& runtime)
+
556  {
+
557  std::vector<entt::entity> entities_to_create;
+
558 
+
559  for (auto& entity : entities_to_update)
+
560  {
+
561  T& component = registry.get<T>(entity);
+
562  Renderable& renderable = registry.get<Renderable>(component.attach_point);
+
563 
+
564  // if a staged node exists, swap it in.
+
565  vsg::ref_ptr<vsg::Node> new_node;
+
566  if (renderable.staged->get_and_clear(new_node))
+
567  {
+
568  if (renderable.node)
+
569  runtime.dispose(renderable.node);
570 
-
571  // if a staged node exists, swap it in.
-
572  vsg::ref_ptr<vsg::Node> new_node;
-
573  if (renderable.staged->get_and_clear(new_node))
+
571  renderable.node = new_node;
+
572  }
+
573  else
574  {
-
575  if (renderable.node)
-
576  runtime.dispose(renderable.node);
-
577 
-
578  renderable.node = new_node;
-
579  }
-
580  else
-
581  {
-
582  // either the node doesn't exist yet, or the revision changed.
-
583  // Queue it up for creation.
-
584  entities_to_create.emplace_back(entity);
-
585  }
-
586  }
-
587 
-
588  // If we detected any entities that need new nodes, create them now.
-
589  if (!entities_to_create.empty())
-
590  {
-
591  if (manager)
-
592  {
-
593  bool ok = manager->entityCompileJobs.emplace(EntityCompileBatch{
-
594  std::move(entities_to_create),
-
595  this,
-
596  &runtime });
+
575  // either the node doesn't exist yet, or the revision changed.
+
576  // Queue it up for creation.
+
577  entities_to_create.emplace_back(entity);
+
578  }
+
579  }
+
580 
+
581  // If we detected any entities that need new nodes, create them now.
+
582  if (!entities_to_create.empty())
+
583  {
+
584  if (manager)
+
585  {
+
586  bool ok = manager->entityCompileJobs.emplace(EntityCompileBatch{
+
587  std::move(entities_to_create),
+
588  this,
+
589  &runtime });
+
590 
+
591  if (!ok)
+
592  {
+
593  Log()->warn("Failed to enqueue entity compile job - queue overflow");
+
594  }
+
595  }
+
596  }
597 
-
598  if (!ok)
-
599  {
-
600  Log()->warn("Failed to enqueue entity compile job - queue overflow");
-
601  }
-
602  }
-
603  }
-
604 
-
605  entities_to_update.clear();
-
606  }
-
607 
-
608  template<class T>
-
609  void ecs::SystemNode<T>::create_or_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const
-
610  {
-
611  T& component = registry.get<T>(entity);
-
612  auto& renderable = registry.get<Renderable>(component.attach_point);
-
613  data.existing_node = renderable.node;
-
614  createOrUpdateNode(entity, data, runtime);
-
615  }
-
616 
-
617  template<class T>
-
618  void ecs::SystemNode<T>::finish_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data) const
-
619  {
-
620  T& component = registry.get<T>(entity);
-
621  auto& renderable = registry.get<Renderable>(component.attach_point);
-
622  if (data.new_node)
-
623  {
-
624  renderable.staged->set(data.new_node);
-
625  }
-
626  }
+
598  entities_to_update.clear();
+
599  }
+
600 
+
601  template<class T>
+
602  void ecs::SystemNode<T>::create_or_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data, Runtime& runtime) const
+
603  {
+
604  T& component = registry.get<T>(entity);
+
605  auto& renderable = registry.get<Renderable>(component.attach_point);
+
606  data.existing_node = renderable.node;
+
607  createOrUpdateNode(entity, data, runtime);
+
608  }
+
609 
+
610  template<class T>
+
611  void ecs::SystemNode<T>::finish_update(entt::entity entity, SystemNodeBase::CreateOrUpdateData& data) const
+
612  {
+
613  T& component = registry.get<T>(entity);
+
614  auto& renderable = registry.get<Renderable>(component.attach_point);
+
615  if (data.new_node)
+
616  {
+
617  renderable.staged->set(data.new_node);
+
618  }
+
619  }
+
620 
+
621  template<class T>
+
622  bool ecs::SystemNode<T>::setReferencePoint(const GeoPoint& point, SRSOperation& out_xform, vsg::dvec3& out_offset) const
+
623  {
+
624  if (point.srs.valid())
+
625  {
+
626  SRS worldSRS = point.srs;
627 
-
628  template<class T>
-
629  bool ecs::SystemNode<T>::setReferencePoint(const GeoPoint& point, SRSOperation& out_xform, vsg::dvec3& out_offset) const
-
630  {
-
631  if (point.srs.valid())
-
632  {
-
633  SRS worldSRS = point.srs;
-
634 
-
635  if (point.srs.isGeodetic())
-
636  {
-
637  worldSRS = point.srs.geocentricSRS();
-
638  GeoPoint world = point.transform(worldSRS);
-
639  if (world.valid())
-
640  {
-
641  out_offset = vsg::dvec3{ world.x, world.y, world.z };
-
642  }
-
643  }
-
644  else
-
645  {
-
646  out_offset = vsg::dvec3{ point.x, point.y, point.z };
-
647  }
-
648 
-
649  out_xform = SRSOperation(point.srs, worldSRS);
-
650  return true;
-
651  }
-
652  return false;
-
653  }
-
654 
-
655  template<class T>
-
656  vsg::ref_ptr<vsg::PipelineLayout> ecs::SystemNode<T>::getPipelineLayout(const T& t) const
-
657  {
-
658  return pipelines.empty() ? nullptr : pipelines[featureMask(t)].config->layout;
-
659  }
-
660 }
+
628  if (point.srs.isGeodetic())
+
629  {
+
630  worldSRS = point.srs.geocentricSRS();
+
631  GeoPoint world = point.transform(worldSRS);
+
632  if (world.valid())
+
633  {
+
634  out_offset = vsg::dvec3{ world.x, world.y, world.z };
+
635  }
+
636  }
+
637  else
+
638  {
+
639  out_offset = vsg::dvec3{ point.x, point.y, point.z };
+
640  }
+
641 
+
642  out_xform = SRSOperation(point.srs, worldSRS);
+
643  return true;
+
644  }
+
645  return false;
+
646  }
+
647 
+
648  template<class T>
+
649  vsg::ref_ptr<vsg::PipelineLayout> ecs::SystemNode<T>::getPipelineLayout(const T& t) const
+
650  {
+
651  return pipelines.empty() ? nullptr : pipelines[featureMask(t)].config->layout;
+
652  }
+
653 }
ROCKY_NAMESPACE::Runtime
Definition: Runtime.h:39
-
ROCKY_NAMESPACE::ecs::System
Definition: ECS.h:90
-
ROCKY_NAMESPACE::ecs::System::update
virtual void update(Runtime &runtime)
Update the ECS system (once per frame)
Definition: ECS.h:105
-
ROCKY_NAMESPACE::ecs::System::registry
entt::registry & registry
ECS entity registry.
Definition: ECS.h:93
-
ROCKY_NAMESPACE::ecs::System::status
Status status
Status.
Definition: ECS.h:96
-
ROCKY_NAMESPACE::ecs::System::initializeSystem
virtual void initializeSystem(Runtime &runtime)
Initialize the ECS system (once at startup)
Definition: ECS.h:99
-
ROCKY_NAMESPACE::ecs::SystemNodeBase
Definition: ECS.h:125
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup
Definition: ECS.h:229
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
vsg::ref_ptr< T > add(entt::registry &entities)
Definition: ECS.h:246
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
void add(std::shared_ptr< System > system)
Definition: ECS.h:260
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::update
void update(Runtime &runtime)
Definition: ECS.h:288
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
void add(vsg::ref_ptr< SystemNode< T >> system)
Definition: ECS.h:236
-
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::initialize
void initialize(Runtime &runtime)
Definition: ECS.h:269
-
ROCKY_NAMESPACE::ecs::setVisible
void setVisible(entt::registry &r, entt::entity e, bool value, int view_index=-1)
Definition: ECS.h:325
-
ROCKY_NAMESPACE::ecs::visible
bool visible(Visibility &vis, int view_index)
Definition: ECS.h:315
+
ROCKY_NAMESPACE::ecs::System
Definition: ECS.h:91
+
ROCKY_NAMESPACE::ecs::System::update
virtual void update(Runtime &runtime)
Update the ECS system (once per frame)
Definition: ECS.h:106
+
ROCKY_NAMESPACE::ecs::System::registry
entt::registry & registry
ECS entity registry.
Definition: ECS.h:94
+
ROCKY_NAMESPACE::ecs::System::status
Status status
Status.
Definition: ECS.h:97
+
ROCKY_NAMESPACE::ecs::System::initializeSystem
virtual void initializeSystem(Runtime &runtime)
Initialize the ECS system (once at startup)
Definition: ECS.h:100
+
ROCKY_NAMESPACE::ecs::SystemNodeBase
Definition: ECS.h:126
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup
Definition: ECS.h:222
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
vsg::ref_ptr< T > add(entt::registry &entities)
Definition: ECS.h:239
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
void add(std::shared_ptr< System > system)
Definition: ECS.h:253
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::update
void update(Runtime &runtime)
Definition: ECS.h:281
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::add
void add(vsg::ref_ptr< SystemNode< T >> system)
Definition: ECS.h:229
+
ROCKY_NAMESPACE::ecs::SystemsManagerGroup::initialize
void initialize(Runtime &runtime)
Definition: ECS.h:262
+
ROCKY_NAMESPACE::ecs::setVisible
void setVisible(entt::registry &r, entt::entity e, bool value, int view_index=-1)
Definition: ECS.h:318
+
ROCKY_NAMESPACE::ecs::visible
bool visible(Visibility &vis, int view_index)
Definition: ECS.h:308
ROCKY_NAMESPACE
Definition: Callbacks.h:16
ROCKY_NAMESPACE::Status
Definition: Status.h:24
ROCKY_NAMESPACE::Visibility
Definition: ECS.h:79
diff --git a/doxygen/_icon_system_8h_source.html b/doxygen/_icon_system_8h_source.html index 7df54b8f..afe33d74 100644 --- a/doxygen/_icon_system_8h_source.html +++ b/doxygen/_icon_system_8h_source.html @@ -118,7 +118,7 @@
67 
68  private:
69 
-
71  vsg::ref_ptr<vsg::Node> createNode(entt::entity entity, Runtime& runtime) const override;
+
71  void createOrUpdateNode(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const override;
72 
73  // cache of image descriptors so we can re-use textures & samplers
74  mutable std::unordered_map<std::shared_ptr<Image>, vsg::ref_ptr<vsg::DescriptorImage>> descriptorImage_cache;
diff --git a/doxygen/_label_system_8h_source.html b/doxygen/_label_system_8h_source.html index 84fa9e74..3ebef615 100644 --- a/doxygen/_label_system_8h_source.html +++ b/doxygen/_label_system_8h_source.html @@ -92,12 +92,10 @@
27 
29  void initializeSystem(Runtime&) override;
30 
-
31  vsg::ref_ptr<vsg::Node> createNode(entt::entity, Runtime&) const override;
+
31  void createOrUpdateNode(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const override;
32 
-
33  private:
-
34  //bool update(entt::entity, Runtime& runtime) override;
-
35  };
-
36 }
+
33  };
+
34 }
ROCKY_NAMESPACE::LabelSystemNode
Definition: LabelSystem.h:17
ROCKY_NAMESPACE::Runtime
Definition: Runtime.h:39
ROCKY_NAMESPACE
Definition: Callbacks.h:16
diff --git a/doxygen/_math_8h_source.html b/doxygen/_math_8h_source.html index 737997c4..9a554c60 100644 --- a/doxygen/_math_8h_source.html +++ b/doxygen/_math_8h_source.html @@ -79,540 +79,568 @@
10 #include <iterator>
11 #include <algorithm>
12 #include <cstdarg>
-
13 
-
14 #ifndef M_PI
-
15 #define M_PI 3.14159265358979323846
-
16 #endif
-
17 
-
18 namespace ROCKY_NAMESPACE
-
19 {
-
20  // mult a vec3 x mat4
-
21  inline glm::dvec3 operator * (const glm::dvec3& a, const glm::dmat4& b)
-
22  {
-
23  return glm::dvec3(glm::dvec4(a, 1) * b);
-
24  }
-
25  inline glm::fvec3 operator * (const glm::fvec3& a, const glm::fmat4& b)
-
26  {
-
27  return glm::fvec3(glm::fvec4(a, 1) * b);
-
28  }
-
29 
-
31  inline glm::fvec3 operator * (const glm::fmat4& mat, const glm::fvec3& v) {
-
32  return glm::fvec3(mat * glm::fvec4(v, 1));
-
33  }
-
34 
-
36  inline glm::dvec3 operator * (const glm::dmat4& mat, const glm::dvec3& v) {
-
37  return glm::dvec3(mat * glm::dvec4(v, 1));
-
38  }
-
39 
-
40 #if 1
-
41  class ROCKY_EXPORT Sphere
-
42  {
-
43  public:
-
44  glm::dvec3 center;
-
45  double radius;
-
46 
-
47  Sphere() : center(0, 0, 0), radius(-1) { }
-
48 
-
49  Sphere(const glm::dvec3& a, double b) :
-
50  center(a), radius(b) { }
-
51 
-
52  void expandBy(const glm::dvec3& v) {
-
53  if (valid()) {
-
54  auto dv = v - center;
-
55  double r = glm::length(dv);
-
56  if (r > radius) {
-
57  double dr = 0.5*(r - radius);
-
58  center += dv * (dr / r);
-
59  radius += dr;
-
60  }
-
61  }
-
62  else {
-
63  center = v;
-
64  radius = 0.0;
-
65  }
-
66  }
-
67 
-
68  bool valid() const {
-
69  return radius >= 0.0;
-
70  }
-
71  };
-
72 #endif
-
73 
-
74  struct ROCKY_EXPORT Box
-
75  {
-
76  double xmin, ymin, zmin;
-
77  double xmax, ymax, zmax;
-
78 
-
79  inline double width() const {
-
80  return xmax - xmin;
-
81  }
-
82  inline double height() const {
-
83  return ymax - ymin;
-
84  }
-
85  inline double area2d() const {
-
86  return width()*height();
-
87  }
-
88  inline glm::dvec3 center() const {
-
89  return glm::dvec3(
-
90  xmin + 0.5*(xmax - xmin),
-
91  ymin + 0.5*(ymax - ymin),
-
92  zmin + 0.5*(zmax - zmin));
-
93  }
-
94  bool intersects(const Box& rhs) const {
-
95  bool exclusive =
-
96  xmin > rhs.xmax || xmax < rhs.xmin ||
-
97  ymin > rhs.ymax || ymax < rhs.ymin ||
-
98  zmin > rhs.zmax || zmax < rhs.zmin;
-
99  return !exclusive;
-
100  }
-
101  Box intersection_with(const Box&) const;
-
102 
-
103  Box union_with(const Box&) const;
-
104 
-
105  bool contains(const Box&) const;
-
106 
-
107  void expandBy(const glm::dvec3& p) {
-
108  xmin = std::min(xmin, p.x);
-
109  xmax = std::max(xmax, p.x);
-
110  ymin = std::min(ymin, p.y);
-
111  ymax = std::max(ymax, p.y);
-
112  zmin = std::min(zmin, p.z);
-
113  zmax = std::max(zmax, p.z);
-
114  }
-
115 
-
116  void expandBy(const Box& rhs) {
-
117  xmin = std::min(xmin, rhs.xmin);
-
118  xmax = std::max(xmax, rhs.xmax);
-
119  ymin = std::min(ymin, rhs.ymin);
-
120  ymax = std::max(ymax, rhs.ymax);
-
121  zmin = std::min(zmin, rhs.zmin);
-
122  zmax = std::max(zmax, rhs.zmax);
-
123  }
-
124 
-
125  inline bool clamp(double& x, double& y, double& z) const {
-
126  bool clamped = false;
-
127  if (x < xmin) { x = xmin; clamped = true; }
-
128  else if (x > xmax) { x = xmax; clamped = true; }
-
129  if (y < ymin) { y = ymin; clamped = true; }
-
130  else if (y > ymax) { y = ymax; clamped = true; }
-
131  if (z < zmin) { z = zmin; clamped = true; }
-
132  else if (z > zmax) { z = zmax; clamped = true; }
-
133  return clamped;
-
134  }
-
135 
-
136  template<class ITER>
-
137  void expandBy(ITER begin, ITER end) {
-
138  for (ITER i = begin; i != end; ++i)
-
139  expandBy({ i->x, i->y, i->z });
-
140  }
-
141 
-
142  glm::dvec3 corner(unsigned i) const {
-
143  return glm::dvec3(
-
144  (i & 0x1) ? xmax : xmin,
-
145  (i & 0x2) ? ymax : ymin,
-
146  (i & 0x4) ? zmax : zmin);
-
147  }
-
148 
-
149 #if 1
-
150  void expandBy(const Sphere& rhs) {
-
151  expandBy(Box(
-
152  rhs.center.x - rhs.radius, rhs.center.x + rhs.radius,
-
153  rhs.center.y - rhs.radius, rhs.center.y + rhs.radius,
-
154  rhs.center.z - rhs.radius, rhs.center.z + rhs.radius));
-
155  }
-
156 #endif
-
157 
-
158  bool valid() const {
-
159  return
-
160  xmin <= xmax &&
-
161  ymin <= ymax &&
-
162  zmin <= zmax;
-
163  }
-
164 
-
165  bool operator == (const Box& rhs) const {
-
166  return
-
167  xmin == rhs.xmin &&
-
168  ymin == rhs.ymin &&
-
169  zmin == rhs.zmin &&
-
170  xmax == rhs.xmax &&
-
171  ymax == rhs.ymax &&
-
172  zmax == rhs.zmax;
-
173  }
-
174 
-
175  bool operator != (const Box& rhs) const {
-
176  return
-
177  xmin != rhs.xmin ||
-
178  ymin != rhs.ymin ||
-
179  zmin != rhs.zmin ||
-
180  xmax != rhs.xmax ||
-
181  ymax != rhs.ymax ||
-
182  zmax != rhs.zmax;
-
183  }
-
184 
-
185  Box() :
-
186  xmin(DBL_MAX), ymin(DBL_MAX), zmin(DBL_MAX),
-
187  xmax(-DBL_MAX), ymax(-DBL_MAX), zmax(-DBL_MAX) { }
-
188 
-
189  Box(double x0, double y0, double z0, double x1, double y1, double z1) :
-
190  xmin(x0), ymin(y0), zmin(z0),
-
191  xmax(x1), ymax(y1), zmax(z1) { }
-
192 
-
193  Box(double x0, double y0, double x1, double y1) :
-
194  xmin(x0), ymin(y0), zmin(0.0),
-
195  xmax(x1), ymax(y1), zmax(0.0) { }
-
196  };
-
197 
-
198  namespace util
-
199  {
-
200  template<typename T>
-
201  inline double lengthSquared(const T& v) {
-
202  return glm::dot(v, v);
-
203  }
-
204 
-
205  template<typename T>
-
206  inline T deg2rad(T v) {
-
207  return v * static_cast<T>(M_PI) / static_cast<T>(180.0);
-
208  }
-
209 
-
210  template<typename T>
-
211  inline T rad2deg(T v) {
-
212  return v * static_cast<T>(180.0) / static_cast<T>(M_PI);
-
213  }
-
214 
-
215  template<typename T>
-
216  inline T step(const T& edge, const T& x)
-
217  {
-
218  return x < edge ? static_cast<T>(0.0) : static_cast<T>(1.0);
-
219  }
-
220 
-
221  template<typename T>
-
222  inline T clamp(const T& x, const T& lo, const T& hi)
-
223  {
-
224  return x<lo ? lo : x>hi ? hi : x;
-
225  }
-
226 
-
227  template<typename T>
-
228  inline T lerpstep(T lo, T hi, T x)
-
229  {
-
230  if (x <= lo) return static_cast<T>(0.0);
-
231  else if (x >= hi) return static_cast<T>(1.0);
-
232  else return (x - lo) / (hi - lo);
-
233  }
-
234 
-
235  template<typename T>
-
236  inline T smoothstep(T lo, T hi, T x)
-
237  {
-
238  T t = clamp((x - lo) / (hi - lo), static_cast<T>(0.0), static_cast<T>(1.0));
-
239  return t * t * (static_cast<T>(3.0) - static_cast<T>(2.0) * t);
-
240  }
-
241 
-
242  // move closer to one
-
243  template<typename T>
-
244  inline T decel(T x)
-
245  {
-
246  return static_cast<T>(1.0) - (static_cast<T>(1.0) - x) * (static_cast<T>(1.0) - x);
-
247  }
-
248 
-
249  // move closer to zero
-
250  template<typename T>
-
251  inline T accel(T x)
-
252  {
-
253  return soften(x * x);
-
254  }
-
255 
-
256  template<typename T>
-
257  inline T threshold(T x, T thresh, T buf)
-
258  {
-
259  if (x < thresh - buf) return static_cast<T>(0.0);
-
260  else if (x > thresh + buf) return static_cast<T>(1.0);
-
261  else return clamp((x - (thresh - buf)) / (buf * static_cast<T>(2.0)), static_cast<T>(0.0), static_cast<T>(1.0));
-
262  }
-
263 
-
264  template<typename T>
-
265  inline T fract(T x)
-
266  {
-
267  return x - floor(x);
-
268  }
-
269 
-
270  template<typename T>
-
271  inline double unitremap(T a, T lo, T hi)
-
272  {
-
273  return clamp((a - lo) / (hi - lo), static_cast<T>(0.0), static_cast<T>(1.0));
-
274  }
-
275 
-
276  template<typename T>
-
277  inline T mix(const T& a, const T& b, float c)
-
278  {
-
279  return a * (1.0 - c) + b * c;
-
280  }
-
281 
-
282  template<typename T>
-
283  inline double dot2D(const T& a, const T& b)
-
284  {
-
285  return a.x() * b.x() + a.y() * b.y();
-
286  }
-
287 
-
288  template<typename T>
-
289  inline double dot3D(const T& a, const T& b)
-
290  {
-
291  return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
-
292  }
-
293 
-
294  template<typename T>
-
295  inline double distanceSquared2D(const T& a, const T& b)
-
296  {
-
297  return
-
298  (b.x() - a.x()) * (b.x() - a.x()) +
-
299  (b.y() - a.y()) * (b.y() - a.y());
-
300  }
-
301 
-
302  template<typename T>
-
303  inline double distanceSquared3D(const T& a, const T& b)
-
304  {
-
305  return
-
306  (b.x() - a.x()) * (b.x() - a.x()) +
-
307  (b.y() - a.y()) * (b.y() - a.y()) +
-
308  (b.z() - a.z()) * (b.z() - a.z());
-
309  }
-
310 
-
311  template<typename T>
-
312  inline double distance2D(const T& a, const T& b)
-
313  {
-
314  return sqrt(distanceSquared2D(a, b));
-
315  }
-
316 
-
317  template<typename T>
-
318  inline double distance3D(const T& a, const T& b)
-
319  {
-
320  return sqrt(distanceSquared3D(a, b));
-
321  }
-
322 
-
323  template<typename T>
-
324  inline T square(const T& a)
-
325  {
-
326  return (a) * (a);
-
327  }
-
328 
-
329  template<typename T>
-
330  inline T normalize(const T& a)
-
331  {
-
332  T temp = a;
-
333  temp.normalize();
-
334  return temp;
-
335  }
-
336 
-
337  // Round integral x to the nearest multiple of "multiple" greater than or equal to x
-
338  template<typename T>
-
339  inline T align(T x, T multiple)
-
340  {
-
341  T isPositive = (T)(x >= 0);
-
342  return ((x + isPositive * (multiple - 1)) / multiple) * multiple;
-
343  }
-
344 
-
345  // equal within a threshold
-
346  template<typename A, typename B>
-
347  inline bool equiv(A x, B y, double epsilon)
-
348  {
-
349  double delta = x - y;
-
350  return delta < 0.0 ? delta >= -epsilon : delta <= epsilon;
-
351  }
-
352 
-
353  // equal within a default threshold
-
354  template<typename A, typename B>
-
355  inline bool equiv(A x, B y)
-
356  {
-
357  return equiv(x, y, 1e-6);
-
358  }
-
359 
-
360  // equal within a default threshold
-
361  template<>
-
362  inline bool equiv<glm::dvec3>(glm::dvec3 a, glm::dvec3 b, double E)
-
363  {
-
364  return equiv(a.x, b.x, E) && equiv(a.y, b.y, E) && equiv(a.z, b.z, E);
-
365  }
-
366 
-
367  // equal within a default threshold
-
368  template<>
-
369  inline bool equiv<glm::dvec3>(glm::dvec3 a, glm::dvec3 b)
-
370  {
-
371  return equiv(a.x, b.x) && equiv(a.y, b.y) && equiv(a.z, b.z);
-
372  }
-
373 
-
374  inline int nextPowerOf2(int x)
-
375  {
-
376  --x;
-
377  x |= x >> 1;
-
378  x |= x >> 2;
-
379  x |= x >> 4;
-
380  x |= x >> 8;
-
381  x |= x >> 16;
-
382  return x + 1;
-
383  }
-
384 
-
385  template<typename... Args>
-
386  inline double smallest(Args... a) {
-
387  double r = DBL_MAX;
-
388  for (auto v : std::initializer_list<double>({ a... })) {
-
389  r = std::min(r, v);
-
390  }
-
391  return r;
-
392  }
-
393 
-
394  template<typename... Args>
-
395  inline double largest(Args... a) {
-
396  double r = -DBL_MAX;
-
397  for (auto v : std::initializer_list<double>({ a... })) {
-
398  r = std::max(r, v);
-
399  }
-
400  return r;
-
401  }
-
402 
-
403  // Adapted from Boost - see boost license
-
404  // https://www.boost.org/users/license.html
-
405  template <typename T>
-
406  inline std::size_t hash_value_unsigned_one(T val)
-
407  {
-
408  const int size_t_bits = std::numeric_limits<std::size_t>::digits;
-
409  const int length = (std::numeric_limits<T>::digits - 1) / size_t_bits;
-
410  std::size_t seed = 0;
-
411  for (int i = length * size_t_bits; i > 0; i -= size_t_bits)
-
412  seed ^= (std::size_t)(val >> i) + (seed << 6) + (seed >> 2);
-
413  seed ^= (std::size_t)val + (seed << 6) + (seed >> 2);
-
414  return seed;
-
415  }
-
416 
-
417  template<typename ...Args>
-
418  inline std::size_t hash_value_unsigned(Args... args) {
-
419  std::size_t seed = 0;
-
420  for(auto v : std::initializer_list<std::size_t>({ args... })) {
-
421  seed = (seed == 0) ? hash_value_unsigned_one(v) :
-
422  seed ^ (hash_value_unsigned_one(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
-
423  }
-
424  return seed;
-
425  }
-
426 
-
427  template<int C, int R, typename T, glm::qualifier Q>
-
428  bool is_identity(const glm::mat<C, R, T, Q>& m) {
-
429  for (int c = 0; c < C; ++c)
-
430  for (int r = 0; r < R; ++r)
-
431  if ((c == r && !equiv(m[c][r], static_cast<T>(1))) ||
-
432  (c != r && !equiv(m[c][r], static_cast<T>(0))))
-
433  return false;
-
434  return true;
-
435  }
-
436 
-
437  template<typename M>
-
438  M pre_mult(const M& a, const M& b) {
-
439  return a * b;
-
440  }
-
441 
-
444  template<typename Q>
-
445  inline void euler_radians_to_quaternion(double xaxis, double yaxis, double zaxis, Q& q)
-
446  {
-
447  // x-axis rotation:
-
448  double cx = cos(xaxis * 0.5);
-
449  double sx = sin(xaxis * 0.5);
-
450  // y-axis rotation:
-
451  double cy = cos(yaxis * 0.5);
-
452  double sy = sin(yaxis * 0.5);
-
453  // z-axis rotation:
-
454  double cz = cos(zaxis * 0.5);
-
455  double sz = sin(zaxis * 0.5);
-
456 
-
457  q.w = cx * cy * cz + sx * sy * sz;
-
458  q.x = sx * cy * cz - cx * sy * sz;
-
459  q.y = cx * sy * cz + sx * cy * sz;
-
460  q.z = cx * cy * sz - sx * sy * cz;
-
461  }
-
462 
-
464  template<typename Q>
-
465  inline void euler_degrees_to_quaternion(double xaxis, double yaxis, double zaxis, Q& q)
-
466  {
-
467  euler_radians_to_quaternion(deg2rad(xaxis), deg2rad(yaxis), deg2rad(zaxis), q);
-
468  }
-
469 
-
472  template<typename Q>
-
473  inline void quaternion_to_euler_radians(const Q& q, double& xaxis, double& yaxis, double& zaxis)
-
474  {
-
475  // x-axis rotation
-
476  double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
-
477  double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
-
478  xaxis = std::atan2(sinr_cosp, cosr_cosp);
-
479  // y-axis rotation
-
480  double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.x * q.z));
-
481  double cosp = std::sqrt(1 - 2 * (q.w * q.y - q.x * q.z));
-
482  yaxis = (2 * std::atan2(sinp, cosp) - M_PI / 2);
-
483  // z-axis rotation
-
484  double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
-
485  double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
-
486  zaxis = std::atan2(siny_cosp, cosy_cosp);
-
487  }
-
488 
-
490  template<typename Q>
-
491  inline void quaternion_to_euler_degrees(const Q& q, double& xaxis, double& yaxis, double& zaxis)
-
492  {
-
493  quaternion_to_euler_radians(q, xaxis, yaxis, zaxis);
-
494  xaxis = rad2deg(xaxis), yaxis = rad2deg(yaxis), zaxis = rad2deg(zaxis);
-
495  }
-
496 
-
497 
-
498  // from OpenSceneGraph
-
499  template<typename M, typename Q>
-
500  inline void get_rotation_from_matrix(const M& _mat, Q& q)
-
501  {
-
502  double s;
-
503  double tq[4];
-
504  int i, j;
-
505 
-
506  // Use tq to store the largest trace
-
507  tq[0] = 1 + _mat[0][0] + _mat[1][1] + _mat[2][2];
-
508  tq[1] = 1 + _mat[0][0] - _mat[1][1] - _mat[2][2];
-
509  tq[2] = 1 - _mat[0][0] + _mat[1][1] - _mat[2][2];
-
510  tq[3] = 1 - _mat[0][0] - _mat[1][1] + _mat[2][2];
-
511 
-
512  // Find the maximum (could also use stacked if's later)
-
513  j = 0;
-
514  for (i = 1; i < 4; i++) j = (tq[i] > tq[j]) ? i : j;
-
515 
-
516  // check the diagonal
-
517  if (j == 0)
-
518  {
-
519  /* perform instant calculation */
-
520  q.w = tq[0];
-
521  q.x = _mat[1][2] - _mat[2][1];
-
522  q.y = _mat[2][0] - _mat[0][2];
-
523  q.z = _mat[0][1] - _mat[1][0];
-
524  }
-
525  else if (j == 1)
-
526  {
-
527  q.w = _mat[1][2] - _mat[2][1];
-
528  q.x = tq[1];
-
529  q.y = _mat[0][1] + _mat[1][0];
-
530  q.z = _mat[2][0] + _mat[0][2];
-
531  }
-
532  else if (j == 2)
-
533  {
-
534  q.w = _mat[2][0] - _mat[0][2];
-
535  q.x = _mat[0][1] + _mat[1][0];
-
536  q.y = tq[2];
-
537  q.z = _mat[1][2] + _mat[2][1];
+
13 #include <tuple>
+
14 
+
15 #ifndef M_PI
+
16 #define M_PI 3.14159265358979323846
+
17 #endif
+
18 
+
19 namespace ROCKY_NAMESPACE
+
20 {
+
21  // mult a vec3 x mat4
+
22  inline glm::dvec3 operator * (const glm::dvec3& a, const glm::dmat4& b)
+
23  {
+
24  return glm::dvec3(glm::dvec4(a, 1) * b);
+
25  }
+
26  inline glm::fvec3 operator * (const glm::fvec3& a, const glm::fmat4& b)
+
27  {
+
28  return glm::fvec3(glm::fvec4(a, 1) * b);
+
29  }
+
30 
+
32  inline glm::fvec3 operator * (const glm::fmat4& mat, const glm::fvec3& v) {
+
33  return glm::fvec3(mat * glm::fvec4(v, 1));
+
34  }
+
35 
+
37  inline glm::dvec3 operator * (const glm::dmat4& mat, const glm::dvec3& v) {
+
38  return glm::dvec3(mat * glm::dvec4(v, 1));
+
39  }
+
40 
+
41 #if 1
+
42  class ROCKY_EXPORT Sphere
+
43  {
+
44  public:
+
45  glm::dvec3 center;
+
46  double radius;
+
47 
+
48  Sphere() : center(0, 0, 0), radius(-1) { }
+
49 
+
50  Sphere(const glm::dvec3& a, double b) :
+
51  center(a), radius(b) { }
+
52 
+
53  void expandBy(const glm::dvec3& v) {
+
54  if (valid()) {
+
55  auto dv = v - center;
+
56  double r = glm::length(dv);
+
57  if (r > radius) {
+
58  double dr = 0.5*(r - radius);
+
59  center += dv * (dr / r);
+
60  radius += dr;
+
61  }
+
62  }
+
63  else {
+
64  center = v;
+
65  radius = 0.0;
+
66  }
+
67  }
+
68 
+
69  bool valid() const {
+
70  return radius >= 0.0;
+
71  }
+
72  };
+
73 #endif
+
74 
+
75  struct ROCKY_EXPORT Box
+
76  {
+
77  double xmin, ymin, zmin;
+
78  double xmax, ymax, zmax;
+
79 
+
80  inline double width() const {
+
81  return xmax - xmin;
+
82  }
+
83  inline double height() const {
+
84  return ymax - ymin;
+
85  }
+
86  inline double area2d() const {
+
87  return width()*height();
+
88  }
+
89  inline glm::dvec3 center() const {
+
90  return glm::dvec3(
+
91  xmin + 0.5*(xmax - xmin),
+
92  ymin + 0.5*(ymax - ymin),
+
93  zmin + 0.5*(zmax - zmin));
+
94  }
+
95  bool intersects(const Box& rhs) const {
+
96  bool exclusive =
+
97  xmin > rhs.xmax || xmax < rhs.xmin ||
+
98  ymin > rhs.ymax || ymax < rhs.ymin ||
+
99  zmin > rhs.zmax || zmax < rhs.zmin;
+
100  return !exclusive;
+
101  }
+
102  Box intersection_with(const Box&) const;
+
103 
+
104  Box union_with(const Box&) const;
+
105 
+
106  bool contains(const Box&) const;
+
107 
+
108  void expandBy(const glm::dvec3& p) {
+
109  xmin = std::min(xmin, p.x);
+
110  xmax = std::max(xmax, p.x);
+
111  ymin = std::min(ymin, p.y);
+
112  ymax = std::max(ymax, p.y);
+
113  zmin = std::min(zmin, p.z);
+
114  zmax = std::max(zmax, p.z);
+
115  }
+
116 
+
117  void expandBy(const Box& rhs) {
+
118  xmin = std::min(xmin, rhs.xmin);
+
119  xmax = std::max(xmax, rhs.xmax);
+
120  ymin = std::min(ymin, rhs.ymin);
+
121  ymax = std::max(ymax, rhs.ymax);
+
122  zmin = std::min(zmin, rhs.zmin);
+
123  zmax = std::max(zmax, rhs.zmax);
+
124  }
+
125 
+
126  inline bool clamp(double& x, double& y, double& z) const {
+
127  bool clamped = false;
+
128  if (x < xmin) { x = xmin; clamped = true; }
+
129  else if (x > xmax) { x = xmax; clamped = true; }
+
130  if (y < ymin) { y = ymin; clamped = true; }
+
131  else if (y > ymax) { y = ymax; clamped = true; }
+
132  if (z < zmin) { z = zmin; clamped = true; }
+
133  else if (z > zmax) { z = zmax; clamped = true; }
+
134  return clamped;
+
135  }
+
136 
+
137  template<class ITER>
+
138  void expandBy(ITER begin, ITER end) {
+
139  for (ITER i = begin; i != end; ++i)
+
140  expandBy({ i->x, i->y, i->z });
+
141  }
+
142 
+
143  glm::dvec3 corner(unsigned i) const {
+
144  return glm::dvec3(
+
145  (i & 0x1) ? xmax : xmin,
+
146  (i & 0x2) ? ymax : ymin,
+
147  (i & 0x4) ? zmax : zmin);
+
148  }
+
149 
+
150 #if 1
+
151  void expandBy(const Sphere& rhs) {
+
152  expandBy(Box(
+
153  rhs.center.x - rhs.radius, rhs.center.x + rhs.radius,
+
154  rhs.center.y - rhs.radius, rhs.center.y + rhs.radius,
+
155  rhs.center.z - rhs.radius, rhs.center.z + rhs.radius));
+
156  }
+
157 #endif
+
158 
+
159  bool valid() const {
+
160  return
+
161  xmin <= xmax &&
+
162  ymin <= ymax &&
+
163  zmin <= zmax;
+
164  }
+
165 
+
166  bool operator == (const Box& rhs) const {
+
167  return
+
168  xmin == rhs.xmin &&
+
169  ymin == rhs.ymin &&
+
170  zmin == rhs.zmin &&
+
171  xmax == rhs.xmax &&
+
172  ymax == rhs.ymax &&
+
173  zmax == rhs.zmax;
+
174  }
+
175 
+
176  bool operator != (const Box& rhs) const {
+
177  return
+
178  xmin != rhs.xmin ||
+
179  ymin != rhs.ymin ||
+
180  zmin != rhs.zmin ||
+
181  xmax != rhs.xmax ||
+
182  ymax != rhs.ymax ||
+
183  zmax != rhs.zmax;
+
184  }
+
185 
+
186  Box() :
+
187  xmin(DBL_MAX), ymin(DBL_MAX), zmin(DBL_MAX),
+
188  xmax(-DBL_MAX), ymax(-DBL_MAX), zmax(-DBL_MAX) { }
+
189 
+
190  Box(double x0, double y0, double z0, double x1, double y1, double z1) :
+
191  xmin(x0), ymin(y0), zmin(z0),
+
192  xmax(x1), ymax(y1), zmax(z1) { }
+
193 
+
194  Box(double x0, double y0, double x1, double y1) :
+
195  xmin(x0), ymin(y0), zmin(0.0),
+
196  xmax(x1), ymax(y1), zmax(0.0) { }
+
197  };
+
198 
+
199  namespace util
+
200  {
+
201  template<typename T>
+
202  inline double lengthSquared(const T& v) {
+
203  return glm::dot(v, v);
+
204  }
+
205 
+
206  template<typename T>
+
207  inline T deg2rad(T v) {
+
208  return v * static_cast<T>(M_PI) / static_cast<T>(180.0);
+
209  }
+
210 
+
211  template<typename T>
+
212  inline T rad2deg(T v) {
+
213  return v * static_cast<T>(180.0) / static_cast<T>(M_PI);
+
214  }
+
215 
+
216  template<typename T>
+
217  inline T step(const T& edge, const T& x)
+
218  {
+
219  return x < edge ? static_cast<T>(0.0) : static_cast<T>(1.0);
+
220  }
+
221 
+
222  template<typename T>
+
223  inline T clamp(const T& x, const T& lo, const T& hi)
+
224  {
+
225  return x<lo ? lo : x>hi ? hi : x;
+
226  }
+
227 
+
228  template<typename T>
+
229  inline T lerpstep(T lo, T hi, T x)
+
230  {
+
231  if (x <= lo) return static_cast<T>(0.0);
+
232  else if (x >= hi) return static_cast<T>(1.0);
+
233  else return (x - lo) / (hi - lo);
+
234  }
+
235 
+
236  template<typename T>
+
237  inline T smoothstep(T lo, T hi, T x)
+
238  {
+
239  T t = clamp((x - lo) / (hi - lo), static_cast<T>(0.0), static_cast<T>(1.0));
+
240  return t * t * (static_cast<T>(3.0) - static_cast<T>(2.0) * t);
+
241  }
+
242 
+
243  // move closer to one
+
244  template<typename T>
+
245  inline T decel(T x)
+
246  {
+
247  return static_cast<T>(1.0) - (static_cast<T>(1.0) - x) * (static_cast<T>(1.0) - x);
+
248  }
+
249 
+
250  // move closer to zero
+
251  template<typename T>
+
252  inline T accel(T x)
+
253  {
+
254  return soften(x * x);
+
255  }
+
256 
+
257  template<typename T>
+
258  inline T threshold(T x, T thresh, T buf)
+
259  {
+
260  if (x < thresh - buf) return static_cast<T>(0.0);
+
261  else if (x > thresh + buf) return static_cast<T>(1.0);
+
262  else return clamp((x - (thresh - buf)) / (buf * static_cast<T>(2.0)), static_cast<T>(0.0), static_cast<T>(1.0));
+
263  }
+
264 
+
265  template<typename T>
+
266  inline T fract(T x)
+
267  {
+
268  return x - floor(x);
+
269  }
+
270 
+
271  template<typename T>
+
272  inline double unitremap(T a, T lo, T hi)
+
273  {
+
274  return clamp((a - lo) / (hi - lo), static_cast<T>(0.0), static_cast<T>(1.0));
+
275  }
+
276 
+
277  template<typename T>
+
278  inline T mix(const T& a, const T& b, float c)
+
279  {
+
280  return a * (1.0 - c) + b * c;
+
281  }
+
282 
+
283  template<typename T>
+
284  inline double dot2D(const T& a, const T& b)
+
285  {
+
286  return a.x() * b.x() + a.y() * b.y();
+
287  }
+
288 
+
289  template<typename T>
+
290  inline double dot3D(const T& a, const T& b)
+
291  {
+
292  return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
+
293  }
+
294 
+
295  template<typename T>
+
296  inline double distanceSquared2D(const T& a, const T& b)
+
297  {
+
298  return
+
299  (b.x() - a.x()) * (b.x() - a.x()) +
+
300  (b.y() - a.y()) * (b.y() - a.y());
+
301  }
+
302 
+
303  template<typename T>
+
304  inline double distanceSquared3D(const T& a, const T& b)
+
305  {
+
306  return
+
307  (b.x() - a.x()) * (b.x() - a.x()) +
+
308  (b.y() - a.y()) * (b.y() - a.y()) +
+
309  (b.z() - a.z()) * (b.z() - a.z());
+
310  }
+
311 
+
312  template<typename T>
+
313  inline double distance2D(const T& a, const T& b)
+
314  {
+
315  return sqrt(distanceSquared2D(a, b));
+
316  }
+
317 
+
318  template<typename T>
+
319  inline double distance3D(const T& a, const T& b)
+
320  {
+
321  return sqrt(distanceSquared3D(a, b));
+
322  }
+
323 
+
324  template<typename T>
+
325  inline T square(const T& a)
+
326  {
+
327  return (a) * (a);
+
328  }
+
329 
+
330  template<typename T>
+
331  inline T normalize(const T& a)
+
332  {
+
333  T temp = a;
+
334  temp.normalize();
+
335  return temp;
+
336  }
+
337 
+
338  // Round integral x to the nearest multiple of "multiple" greater than or equal to x
+
339  template<typename T>
+
340  inline T align(T x, T multiple)
+
341  {
+
342  T isPositive = (T)(x >= 0);
+
343  return ((x + isPositive * (multiple - 1)) / multiple) * multiple;
+
344  }
+
345 
+
346  // equal within a threshold
+
347  template<typename A, typename B>
+
348  inline bool equiv(A x, B y, double epsilon)
+
349  {
+
350  double delta = x - y;
+
351  return delta < 0.0 ? delta >= -epsilon : delta <= epsilon;
+
352  }
+
353 
+
354  // equal within a default threshold
+
355  template<typename A, typename B>
+
356  inline bool equiv(A x, B y)
+
357  {
+
358  return equiv(x, y, 1e-6);
+
359  }
+
360 
+
361  // equal within a default threshold
+
362  template<>
+
363  inline bool equiv<glm::dvec3>(glm::dvec3 a, glm::dvec3 b, double E)
+
364  {
+
365  return equiv(a.x, b.x, E) && equiv(a.y, b.y, E) && equiv(a.z, b.z, E);
+
366  }
+
367 
+
368  // equal within a default threshold
+
369  template<>
+
370  inline bool equiv<glm::dvec3>(glm::dvec3 a, glm::dvec3 b)
+
371  {
+
372  return equiv(a.x, b.x) && equiv(a.y, b.y) && equiv(a.z, b.z);
+
373  }
+
374 
+
375  inline int nextPowerOf2(int x)
+
376  {
+
377  --x;
+
378  x |= x >> 1;
+
379  x |= x >> 2;
+
380  x |= x >> 4;
+
381  x |= x >> 8;
+
382  x |= x >> 16;
+
383  return x + 1;
+
384  }
+
385 
+
386  template<typename... Args>
+
387  inline double smallest(Args... a) {
+
388  double r = DBL_MAX;
+
389  for (auto v : std::initializer_list<double>({ a... })) {
+
390  r = std::min(r, v);
+
391  }
+
392  return r;
+
393  }
+
394 
+
395  template<typename... Args>
+
396  inline double largest(Args... a) {
+
397  double r = -DBL_MAX;
+
398  for (auto v : std::initializer_list<double>({ a... })) {
+
399  r = std::max(r, v);
+
400  }
+
401  return r;
+
402  }
+
403 
+
404  // Adapted from Boost - see boost license
+
405  // https://www.boost.org/users/license.html
+
406  template <typename T>
+
407  inline std::size_t hash_value_unsigned_one(T val)
+
408  {
+
409  const int size_t_bits = std::numeric_limits<std::size_t>::digits;
+
410  const int length = (std::numeric_limits<T>::digits - 1) / size_t_bits;
+
411  std::size_t seed = 0;
+
412  for (int i = length * size_t_bits; i > 0; i -= size_t_bits)
+
413  seed ^= (std::size_t)(val >> i) + (seed << 6) + (seed >> 2);
+
414  seed ^= (std::size_t)val + (seed << 6) + (seed >> 2);
+
415  return seed;
+
416  }
+
417 
+
418  template<typename ...Args>
+
419  inline std::size_t hash_value_unsigned(Args... args) {
+
420  std::size_t seed = 0;
+
421  for(auto v : std::initializer_list<std::size_t>({ args... })) {
+
422  seed = (seed == 0) ? hash_value_unsigned_one(v) :
+
423  seed ^ (hash_value_unsigned_one(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
+
424  }
+
425  return seed;
+
426  }
+
427 
+
428  template<int C, int R, typename T, glm::qualifier Q>
+
429  bool is_identity(const glm::mat<C, R, T, Q>& m) {
+
430  for (int c = 0; c < C; ++c)
+
431  for (int r = 0; r < R; ++r)
+
432  if ((c == r && !equiv(m[c][r], static_cast<T>(1))) ||
+
433  (c != r && !equiv(m[c][r], static_cast<T>(0))))
+
434  return false;
+
435  return true;
+
436  }
+
437 
+
438  template<typename M>
+
439  M pre_mult(const M& a, const M& b) {
+
440  return a * b;
+
441  }
+
442 
+
445  template<typename Q>
+
446  inline Q quaternion_from_euler_radians(double xaxis, double yaxis, double zaxis)
+
447  {
+
448  Q q;
+
449 
+
450  // x-axis rotation:
+
451  double cx = cos(xaxis * 0.5);
+
452  double sx = sin(xaxis * 0.5);
+
453  // y-axis rotation:
+
454  double cy = cos(yaxis * 0.5);
+
455  double sy = sin(yaxis * 0.5);
+
456  // z-axis rotation:
+
457  double cz = cos(zaxis * 0.5);
+
458  double sz = sin(zaxis * 0.5);
+
459 
+
460  q.w = cx * cy * cz + sx * sy * sz;
+
461  q.x = sx * cy * cz - cx * sy * sz;
+
462  q.y = cx * sy * cz + sx * cy * sz;
+
463  q.z = cx * cy * sz - sx * sy * cz;
+
464 
+
465  return q;
+
466  }
+
467 
+
469  template<typename Q>
+
470  inline Q quaternion_from_euler_degrees(double xaxis, double yaxis, double zaxis)
+
471  {
+
472  return quaternion_from_euler_radians<Q>(deg2rad(xaxis), deg2rad(yaxis), deg2rad(zaxis));
+
473  }
+
474 
+
477  template<typename Q>
+
478  inline std::tuple<double, double, double> euler_radians_from_quaternion(const Q& q)
+
479  {
+
480  // x-axis rotation
+
481  double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
+
482  double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
+
483  double xaxis = std::atan2(sinr_cosp, cosr_cosp);
+
484  // y-axis rotation
+
485  double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.x * q.z));
+
486  double cosp = std::sqrt(1 - 2 * (q.w * q.y - q.x * q.z));
+
487  double yaxis = (2 * std::atan2(sinp, cosp) - M_PI / 2);
+
488  // z-axis rotation
+
489  double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
+
490  double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
+
491  double zaxis = std::atan2(siny_cosp, cosy_cosp);
+
492 
+
493  return std::make_tuple(xaxis, yaxis, zaxis);
+
494  }
+
495 
+
497  template<typename Q>
+
498  inline std::tuple<double, double, double> euler_degrees_from_quaternion(const Q& q)
+
499  {
+
500  auto a = euler_radians_from_quaternion(q);
+
501  return std::make_tuple(rad2deg(std::get<0>(a)), rad2deg(std::get<1>(a)), rad2deg(std::get<2>(a)));
+
502  }
+
503 
+
510  template<typename Q, typename M>
+
511  inline Q quaternion_from_unscaled_matrix(const M& _mat)
+
512  {
+
513  Q q;
+
514 
+
515  // from OpenSceneGraph:
+
516  double s;
+
517  double tq[4];
+
518  int i, j;
+
519 
+
520  // Use tq to store the largest trace
+
521  tq[0] = 1 + _mat[0][0] + _mat[1][1] + _mat[2][2];
+
522  tq[1] = 1 + _mat[0][0] - _mat[1][1] - _mat[2][2];
+
523  tq[2] = 1 - _mat[0][0] + _mat[1][1] - _mat[2][2];
+
524  tq[3] = 1 - _mat[0][0] - _mat[1][1] + _mat[2][2];
+
525 
+
526  // Find the maximum (could also use stacked if's later)
+
527  j = 0;
+
528  for (i = 1; i < 4; i++) j = (tq[i] > tq[j]) ? i : j;
+
529 
+
530  // check the diagonal
+
531  if (j == 0)
+
532  {
+
533  /* perform instant calculation */
+
534  q.w = tq[0];
+
535  q.x = _mat[1][2] - _mat[2][1];
+
536  q.y = _mat[2][0] - _mat[0][2];
+
537  q.z = _mat[0][1] - _mat[1][0];
538  }
-
539  else /* if (j==3) */
+
539  else if (j == 1)
540  {
-
541  q.w = _mat[0][1] - _mat[1][0];
-
542  q.x = _mat[2][0] + _mat[0][2];
-
543  q.y = _mat[1][2] + _mat[2][1];
-
544  q.z = tq[3];
+
541  q.w = _mat[1][2] - _mat[2][1];
+
542  q.x = tq[1];
+
543  q.y = _mat[0][1] + _mat[1][0];
+
544  q.z = _mat[2][0] + _mat[0][2];
545  }
-
546 
-
547  s = sqrt(0.25 / tq[j]);
-
548  q.w *= s;
-
549  q.x *= s;
-
550  q.y *= s;
-
551  q.z *= s;
-
552  }
-
553  }
-
554 }
+
546  else if (j == 2)
+
547  {
+
548  q.w = _mat[2][0] - _mat[0][2];
+
549  q.x = _mat[0][1] + _mat[1][0];
+
550  q.y = tq[2];
+
551  q.z = _mat[1][2] + _mat[2][1];
+
552  }
+
553  else /* if (j==3) */
+
554  {
+
555  q.w = _mat[0][1] - _mat[1][0];
+
556  q.x = _mat[2][0] + _mat[0][2];
+
557  q.y = _mat[1][2] + _mat[2][1];
+
558  q.z = tq[3];
+
559  }
+
560 
+
561  s = sqrt(0.25 / tq[j]);
+
562  q.w *= s;
+
563  q.x *= s;
+
564  q.y *= s;
+
565  q.z *= s;
+
566 
+
567  return q;
+
568  }
+
569 
+
575  template<typename Q, typename M>
+
576  inline Q quaternion_from_matrix(const M& mat)
+
577  {
+
578  Q q;
+
579  M _mat = mat;
+
580 
+
581  // Remove the scaling from the matrix by normalizing each axis
+
582  double scaleX = sqrt(_mat[0][0] * _mat[0][0] + _mat[0][1] * _mat[0][1] + _mat[0][2] * _mat[0][2]);
+
583  double scaleY = sqrt(_mat[1][0] * _mat[1][0] + _mat[1][1] * _mat[1][1] + _mat[1][2] * _mat[1][2]);
+
584  double scaleZ = sqrt(_mat[2][0] * _mat[2][0] + _mat[2][1] * _mat[2][1] + _mat[2][2] * _mat[2][2]);
+
585 
+
586  _mat[0][0] /= scaleX; _mat[0][1] /= scaleX; _mat[0][2] /= scaleX;
+
587  _mat[1][0] /= scaleY; _mat[1][1] /= scaleY; _mat[1][2] /= scaleY;
+
588  _mat[2][0] /= scaleZ; _mat[2][1] /= scaleZ; _mat[2][2] /= scaleZ;
+
589 
+
590  return quaternion_from_unscaled_matrix<Q>(_mat);
+
591  }
+
592  }
+
593 }
ROCKY_NAMESPACE
Definition: Callbacks.h:16
diff --git a/doxygen/_mesh_system_8h_source.html b/doxygen/_mesh_system_8h_source.html index 80e44f13..06ad1c62 100644 --- a/doxygen/_mesh_system_8h_source.html +++ b/doxygen/_mesh_system_8h_source.html @@ -154,7 +154,7 @@
103 
105  void initializeSystem(Runtime&) override;
106 
-
107  vsg::ref_ptr<vsg::Node> createNode(entt::entity, Runtime&) const override;
+
107  void createOrUpdateNode(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const override;
108  protected:
109 
110  //bool update(entt::entity, Runtime&) override;
@@ -171,7 +171,7 @@
124  public:
125  NodeSystemNode(entt::registry& registry);
126 
-
127  vsg::ref_ptr<vsg::Node> createNode(entt::entity, Runtime&) const override;
+
127  void createOrUpdateNode(entt::entity entity, CreateOrUpdateData& data, Runtime& runtime) const override;
128  };
129 
130 }
diff --git a/doxygen/_motion_8h_source.html b/doxygen/_motion_8h_source.html index e1339c2c..09247b7d 100644 --- a/doxygen/_motion_8h_source.html +++ b/doxygen/_motion_8h_source.html @@ -174,8 +174,8 @@
ROCKY_NAMESPACE::SRS::geocentricSRS
SRS geocentricSRS() const
Gets the corresponding geocentric SRS. Only applies to a geodetic SRS.
Definition: SRS.cpp:671
ROCKY_NAMESPACE::SRS::ellipsoid
const Ellipsoid & ellipsoid() const
Underlying reference ellipsoid.
Definition: SRS.cpp:647
ROCKY_NAMESPACE::SRS::to
SRSOperation to(const SRS &target) const
Definition: SRS.cpp:659
-
ROCKY_NAMESPACE::ecs::System
Definition: ECS.h:90
-
ROCKY_NAMESPACE::ecs::System::registry
entt::registry & registry
ECS entity registry.
Definition: ECS.h:93
+
ROCKY_NAMESPACE::ecs::System
Definition: ECS.h:91
+
ROCKY_NAMESPACE::ecs::System::registry
entt::registry & registry
ECS entity registry.
Definition: ECS.h:94
ROCKY_NAMESPACE
Definition: Callbacks.h:16
ROCKY_NAMESPACE::Motion
Definition: Motion.h:16
ROCKY_NAMESPACE::Transform
Definition: Transform.h:19
diff --git a/doxygen/_pixel_scale_transform_8h_source.html b/doxygen/_pixel_scale_transform_8h_source.html index 94c7093e..c2caeeb2 100644 --- a/doxygen/_pixel_scale_transform_8h_source.html +++ b/doxygen/_pixel_scale_transform_8h_source.html @@ -97,24 +97,23 @@
37 
38  if (unrotate)
39  {
-
40  vsg::dquat rotation;
-
41  auto& mv = state.modelviewMatrixStack.top();
-
42  get_rotation_from_matrix(mv, rotation);
-
43  matrix = matrix * vsg::rotate(vsg::inverse(rotation));
-
44  }
-
45  rt.apply(*this);
-
46  };
-
47 
-
48  vsg::dmat4 transform(const vsg::dmat4& mv) const override
-
49  {
-
50  return mv * matrix;
-
51  }
+
40  auto& mv = state.modelviewMatrixStack.top();
+
41  auto rotation = util::quaternion_from_unscaled_matrix<vsg::dquat>(mv);
+
42  matrix = matrix * vsg::rotate(vsg::inverse(rotation));
+
43  }
+
44  rt.apply(*this);
+
45  };
+
46 
+
47  vsg::dmat4 transform(const vsg::dmat4& mv) const override
+
48  {
+
49  return mv * matrix;
+
50  }
+
51 
52 
-
53 
-
54  private:
-
55  mutable vsg::dmat4 matrix;
-
56  };
-
57 }
+
53  private:
+
54  mutable vsg::dmat4 matrix;
+
55  };
+
56 }
ROCKY_NAMESPACE::PixelScaleTransform
Definition: PixelScaleTransform.h:24
ROCKY_NAMESPACE
Definition: Callbacks.h:16
diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node-members.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node-members.html index d847a60a..4a68f9b7 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node-members.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node-members.html @@ -74,7 +74,7 @@

This is the complete list of members for ROCKY_NAMESPACE::LabelSystemNode, including all inherited members.

- + diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node.html index df28e474..b1760ac2 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_label_system_node.html @@ -97,9 +97,9 @@ void  - - + +
createNode(entt::entity, Runtime &) const override (defined in ROCKY_NAMESPACE::LabelSystemNode)ROCKY_NAMESPACE::LabelSystemNode
createOrUpdateNode(entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override (defined in ROCKY_NAMESPACE::LabelSystemNode)ROCKY_NAMESPACE::LabelSystemNode
Features enum name (defined in ROCKY_NAMESPACE::LabelSystemNode)ROCKY_NAMESPACE::LabelSystemNode
initializeSystem(Runtime &) overrideROCKY_NAMESPACE::LabelSystemNode
LabelSystemNode(entt::registry &registry)ROCKY_NAMESPACE::LabelSystemNode
initializeSystem (Runtime &) override
 One time setup of the system.
 
-vsg::ref_ptr< vsg::Node > createNode (entt::entity, Runtime &) const override
 
+void createOrUpdateNode (entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override
 

Detailed Description

Creates commands for rendering icon primitives.

diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node-members.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node-members.html index b3d919e4..034ebe45 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node-members.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node-members.html @@ -74,7 +74,7 @@

This is the complete list of members for ROCKY_NAMESPACE::MeshSystemNode, including all inherited members.

- + diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node.html index 8248b7d8..522d3738 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_mesh_system_node.html @@ -110,9 +110,9 @@ - - + +
createNode(entt::entity, Runtime &) const override (defined in ROCKY_NAMESPACE::MeshSystemNode)ROCKY_NAMESPACE::MeshSystemNode
createOrUpdateNode(entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override (defined in ROCKY_NAMESPACE::MeshSystemNode)ROCKY_NAMESPACE::MeshSystemNode
CULL_BACKFACES enum value (defined in ROCKY_NAMESPACE::MeshSystemNode)ROCKY_NAMESPACE::MeshSystemNode
DYNAMIC_STYLE enum value (defined in ROCKY_NAMESPACE::MeshSystemNode)ROCKY_NAMESPACE::MeshSystemNode
featureMask(const Mesh &mesh) const overrideROCKY_NAMESPACE::MeshSystemNode
 One-time initialization of the system

 
-vsg::ref_ptr< vsg::Node > createNode (entt::entity, Runtime &) const override
 
+void createOrUpdateNode (entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override
 

Detailed Description

VSG node that renders Mesh components.

diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node-members.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node-members.html index 9635fe05..9b7bca1d 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node-members.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node-members.html @@ -74,7 +74,7 @@

This is the complete list of members for ROCKY_NAMESPACE::NodeSystemNode, including all inherited members.

- +
createNode(entt::entity, Runtime &) const override (defined in ROCKY_NAMESPACE::NodeSystemNode)ROCKY_NAMESPACE::NodeSystemNode
createOrUpdateNode(entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override (defined in ROCKY_NAMESPACE::NodeSystemNode)ROCKY_NAMESPACE::NodeSystemNode
NodeSystemNode(entt::registry &registry) (defined in ROCKY_NAMESPACE::NodeSystemNode)ROCKY_NAMESPACE::NodeSystemNode
diff --git a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node.html b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node.html index e2b60fe3..1943aea0 100644 --- a/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node.html +++ b/doxygen/class_r_o_c_k_y___n_a_m_e_s_p_a_c_e_1_1_node_system_node.html @@ -84,9 +84,9 @@  NodeSystemNode (entt::registry &registry)   - -vsg::ref_ptr< vsg::Node > createNode (entt::entity, Runtime &) const override -  + +void createOrUpdateNode (entt::entity entity, CreateOrUpdateData &data, Runtime &runtime) const override + 

Detailed Description

VSG node that renders Node components (just plain vsg nodes)

diff --git a/doxygen/functions_c.html b/doxygen/functions_c.html index 481be022..83bf24e2 100644 --- a/doxygen/functions_c.html +++ b/doxygen/functions_c.html @@ -137,7 +137,7 @@

- c -