Spinning Topp Logo BlackTopp Studios
inc
rayquerytool.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _rayquerytool_cpp
41 #define _rayquerytool_cpp
42 
43 using namespace std;
44 
45 #include "rayquerytool.h"
46 #include "actor.h"
47 #include "actormanager.h"
48 #include "areaeffect.h"
49 #include "areaeffectmanager.h"
50 #include "debris.h"
51 #include "debrismanager.h"
52 #include "eventmanager.h"
53 #include "worldobject.h"
54 #include "plane.h"
55 #include "ray.h"
56 #include "MathTools/mathtools.h"
57 #include "managedptr.h"
58 #include "serialization.h"
59 #include "entresol.h"
60 #include "world.h"
61 
62 #include "Graphics/graphicsmanager.h"
63 #include "Graphics/scenemanager.h"
64 #include "Graphics/cameraproxy.h"
65 #include "Graphics/gamewindow.h"
66 #include "Graphics/viewport.h"
68 
69 #include "Input/mouse.h"
70 #include "Input/inputmanager.h"
71 
72 #include "Internal/meshtools.h.cpp"
73 
74 #include <Ogre.h>
75 
76 #include <exception>
77 
78 #ifdef GetObject
79 #undef GetObject
80 #endif
81 
82 namespace Mezzanine
83 {
84 
85  namespace
86  {
87  /// @internal
88  /// @brief Ogre demands the use of special functions to delete a Ogre::RaySceneQuery, this handles that with RAII
89  class RayQueryHandle
90  {
91  public:
92  /// @brief This will work with a raw pointer to a Ogre::RaySceneQuery to manage a Ogre::RaySceneQuery.
93  typedef Ogre::RaySceneQuery* TargetPtrType;
94  /// @brief This will manage a Ogre::RaySceneQuery
95  typedef Ogre::RaySceneQuery TargetType;
96  /// @brief The actual ogre object we want to use.
97  Ogre::RaySceneQuery* RayQuery;
98  /// @brief The world in which to perform the ray query.
99  World* ParentWorld;
100 
101  /// @brief Class constructor.
102  /// @param QueryWorld The world in which to perform the ray query.
103  explicit RayQueryHandle(World* QueryWorld) :
104  ParentWorld(QueryWorld)
105  { }
106 
107  /// @brief Create the ogre specific handle and sort items for raycasting.
108  void Construct()
109  {
110  Graphics::SceneManager* SceneMan = static_cast<Graphics::SceneManager*>( this->ParentWorld->GetManager(ManagerBase::MT_SceneManager) );
111  this->RayQuery = SceneMan->_GetGraphicsWorldPointer()->createRayQuery(Ogre::Ray(), Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK);
112  this->RayQuery->setSortByDistance(true);
113  }
114 
115  /// @brief CAll the Ogre API to clean up this wierd handle thing
116  void Deconstruct()
117  {
118  if( this->GetPointer() )
119  { static_cast<Graphics::SceneManager*>( this->ParentWorld->GetManager(ManagerBase::MT_SceneManager) )->_GetGraphicsWorldPointer()->destroyQuery(this->RayQuery); }
120  }
121 
122  /// @brief This is what ManagedPtr will use in copy and assignment operations as well as invaliding handles.
123  /// @param Value The new value for the pointer. If NULL the only thing that the ManagedPtr will do to the handle is call its deconstruct method.
124  void SetPointer(TargetPtrType Value)
125  { this->RayQuery = Value; }
126 
127  /// @brief This is what the ManagedPtr with use for dereferencing.
128  /// @return The pointer to the managed data. This is expected to return a value that resolves to false when used as a condition when invalid.
129  TargetPtrType GetPointer()
130  { return this->RayQuery; }
131  };//RayQueryHandle
132 
133  typedef ManagedPtr<RayQueryHandle> ManagedRayQuery;
134 
135  /// @internal
136  /// @brief Exact an Ogre::RayQuery with some default parameters and see if we hit anything
137  /// @param RayQuery A ManagedRayQuery
138  /// @param Ooray The Ray to follow and see if it hits something
139  /// @return True if something is hit, false otherwise.
140  Boole ExecuteQuery(ManagedRayQuery& RayQuery, Ogre::Ray& Ooray)
141  {
142  if( RayQuery ) { //Double check that the Rayquery is valid
143  RayQuery->setRay(Ooray);
144  RayQuery->setQueryMask(-1); // GetFirstActorOnRayByAABB did not do this
145 
146  if( RayQuery->execute().size() <= 0 ) return false;//Did we hit anything
147  else return true;
148  }else{ // Something Failed
149  MEZZ_EXCEPTION(ExceptionBase::PARAMETERS_EXCEPTION,"Attempting to run a query on Null RaySceneQuery");
150  }
151  return false;
152  }
153  }
154 
155  ///////////////////////////////////////////////////////////////////////////////
156  // RayQueryTool Methods
157 
158  RayQueryTool::RayQueryTool() :
159  IntersectedObject(NULL),
160  ParentWorld(NULL),
161  ValidResult(false)
162  { this->ClearReturns(); }
163 
165  IntersectedObject(NULL),
166  ParentWorld(QueryWorld),
167  ValidResult(false)
168  { this->ClearReturns(); }
169 
170  ///////////////////////////////////////////////////////////////////////////////
171  // Utility
172 
173  void RayQueryTool::SetWorld(World* QueryWorld)
174  { this->ParentWorld = QueryWorld; }
175 
176  ///////////////////////////////////////////////////////////////////////////////
177  // World Ray Query Results
178 
180  {
181  this->ValidResult = false;
182  this->Offset = Vector3();
183  this->IntersectedObject = NULL;
184  return this->ValidResult;
185  }
186 
188  { return this->ValidResult; }
189 
191  { return this->Offset; }
192 
194  { return this->IntersectedObject; }
195 
196  ///////////////////////////////////////////////////////////////////////////////
197  // Ray Queries
198 
200  {
201  RayQueryHandle ray( this->ParentWorld );
202  ManagedRayQuery RayQuery( ray );
203  Ogre::Ray Ooray = ObjectRay.GetOgreRay();
204 
205  if(!ExecuteQuery(RayQuery, Ooray))
206  { return ClearReturns(); }
207 
208  // at this point we have raycast to a series of different objects bounding boxes.
209  // we need to test these different objects to see which is the first polygon hit.
210  // there are some minor optimizations (distance based) that mean we wont have to
211  // check all of the objects most of the time, but the worst case scenario is that
212  // we need to test every triangle of every object.
213  Ogre::Real closest_distance = -1.0f;
214  Vector3 closest_result;
215  IntersectedObject=NULL;
216  Ogre::RaySceneQueryResult &query_result = RayQuery->getLastResults();
217  for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++)
218  {
219  // stop checking if we have found a raycast hit that is closer than all remaining entities
220  if( (0.0f <= closest_distance) && (closest_distance < query_result[qr_idx].distance) )
221  { break; }
222 
223  // only check this result if its a hit against an entity
224  /// @todo Modify this so we can check for more movable types than just entities.
225  if( (NULL != query_result[qr_idx].movable) && (0 == query_result[qr_idx].movable->getMovableType().compare("Entity")) ) {
226  // get the entity to check
227  Ogre::Entity *pentity = static_cast<Ogre::Entity*>(query_result[qr_idx].movable);
228 
229  try
230  {
231  WorldObject* HitMetaInfo = Ogre::any_cast<Graphics::RenderableProxy*>(pentity->getUserAny())->GetParentObject();
232  if( HitMetaInfo && ( HitMetaInfo->GetType() & ObjectFlags ) ) {
233  // Data containers to be populated
234  Internal::MeshTools::Vector3Vec vertices;
235  Internal::MeshTools::IntVec indices;
236 
237  // get the mesh information
238  Internal::MeshTools::GetTransformedMeshData( pentity, vertices, indices );
239 
240  // test for hitting individual triangles on the mesh
241  Boole new_closest_found = false;
242  for( size_t i = 0 ; i < indices.size() ; i += 3 )
243  {
244  // check for a hit against this triangle
245  std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(Ooray, vertices[indices[i]], vertices[indices[i+1]], vertices[indices[i+2]], true, false);
246 
247  // if it was a hit check if its the closest
248  if( hit.first && ( (0.0f > closest_distance) || (hit.second < closest_distance) ) ) {
249  closest_distance = hit.second; // this is the closest so far, save it off
250  new_closest_found = true;
251  }
252  }
253 
254  // if we found a new closest raycast for this object, update the closest_result before moving on to the next object.
255  if( new_closest_found ) {
256  closest_result = Ooray.getPoint(closest_distance);
257  IntersectedObject = Ogre::any_cast<Graphics::RenderableProxy*>(pentity->getUserAny())->GetParentObject();
258  }
259 
260  } // \if WSO_ActorRigid
261  }catch(...){
262  ClearReturns();
263  MEZZ_EXCEPTION(ExceptionBase::INTERNAL_EXCEPTION,"Failed during cast in object raycast.");
264  }
265  } // \if entity
266  } // \if qr_idx
267 
268  // Change the closest point into a point relative to the Actor
269  if (IntersectedObject) {
270  Offset = IntersectedObject->GetOrientation() * ((closest_result - IntersectedObject->GetLocation()) * IntersectedObject->GetScale());
271  ValidResult=true;
272  return ValidResult;
273  }else{
274  return ClearReturns();
275  }
276  }
277 
279  {
280  RayQueryHandle ray( this->ParentWorld );
281  ManagedRayQuery RayQuery( ray );
282  Ogre::Ray Ooray = ObjectRay.GetOgreRay();
283  if(!ExecuteQuery(RayQuery, Ooray))
284  { return ClearReturns(); }
285 
286  Ogre::RaySceneQueryResult &query_result = RayQuery->getLastResults();
287 
288  if (0 < query_result.size())
289  {
290  Ogre::Entity *pentity = static_cast<Ogre::Entity*>(query_result[0].movable);
291  IntersectedObject = Ogre::any_cast<Graphics::RenderableProxy*>(pentity->getUserAny())->GetParentObject();
292  Offset = Vector3();
293  ValidResult = true;
294  /// @todo TODO: The function WorldQueryTool::GetFirstActorOnRayByAABB does not return an valid offset. This needs to be calculated somehow.
295  /// @todo TODO: The function WorldQueryTool::GetFirstActorOnRayByAABB has not been tested and needs to be tested
296  /// @todo TODO: The function WorldQueryTool::GetFirstActorOnRayByAABB does not take other obstructions into account
297  return ValidResult;
298  }else{
299  return ClearReturns();
300  }
301  }
302 
303  Boole RayQueryTool::RayPlaneIntersection(const Ray& QueryRay, const Plane& QueryPlane)
304  {
305  MathTools::Point3DTestResult Result = MathTools::Intersects(QueryPlane,QueryRay);
306  this->Offset = Result.second;
307  this->IntersectedObject = NULL;
308  return Result.first;
309  /*try{
310  Vector3 u = QueryRay.Destination - QueryRay.Origin;
311  Vector3 p0 = Vector3(0,0,0);
312 
313  if(QueryPlane.Normal.X == 0 && QueryPlane.Normal.Y == 0 && QueryPlane.Normal.Z == 0)
314  { return ClearReturns(); }
315  else
316  {
317  if(QueryPlane.Normal.X != 0)
318  { p0 = Vector3(QueryPlane.Distance,0,0); }
319  else if(QueryPlane.Normal.Y != 0)
320  { p0 = Vector3(0,QueryPlane.Distance,0); }
321  else
322  { p0 = Vector3(0,0,QueryPlane.Distance); }
323  }
324 
325  Vector3 w = QueryRay.Origin - p0;
326 
327  Real D = u.DotProduct(QueryPlane.Normal);
328  Real N = -1 * w.DotProduct(QueryPlane.Normal);
329 
330  Real SMALL_NUM = 0.00000001;
331 
332  if( (D<0? -D : D) < SMALL_NUM) // Checks if the Plane behind the RAy
333  {
334  if(N == 0)
335  {
336  Offset=QueryRay.Origin;
337  IntersectedObject=NULL;
338  ValidResult=true;
339  return ValidResult;
340  }
341  else
342  { return ClearReturns(); }
343  }
344 
345  Real sI = N/D;
346 
347  if(sI < 0 || sI > 1) // Checks if the ray is too long
348  { return ClearReturns(); }
349 
350  Vector3 return_vector(QueryRay.Origin + (u * sI));
351 
352  Real distance = return_vector.Distance(QueryRay.Origin);
353 
354  if(distance > QueryRay.Origin.Distance(QueryRay.Destination))
355  { return ClearReturns(); }
356 
357  Offset=return_vector;
358  IntersectedObject=NULL;
359  ValidResult=true;
360  return ValidResult;
361  } catch(exception e) {
362  //In case we divide b
363  Entresol::GetSingletonPtr()->Log("WorldQueryTool Error:Failed while calculating Ray/Plane Intersection, Assuming no valid intersection. Error follows:");
364  Entresol::GetSingletonPtr()->Log(e.what());
365  return ClearReturns();
366  }// */
367  }
368 
370  {
371  Graphics::Viewport* HoveredViewport = Input::InputManager::GetSingletonPtr()->GetSystemMouse()->GetHoveredViewport();
372  Vector2 MousePos = Input::InputManager::GetSingletonPtr()->GetSystemMouse()->GetViewportPosition();
373  Ray MouseRay;
374  if(HoveredViewport) {
375  MouseRay = Ray( HoveredViewport->GetCamera()->GetCameraToViewportRay(
376  MousePos.X / (Real)(HoveredViewport->GetActualWidth()),
377  MousePos.Y / (Real)(HoveredViewport->GetActualHeight()) ) );
378  }
379  return MouseRay;
380  }
381 
382  void RayQueryTool::ProtoSerialize(XML::Node& CurrentRoot) const
383  {
384  Mezzanine::XML::Node RayQueryToolNode = CurrentRoot.AppendChild(GetSerializableName());
385  RayQueryToolNode.SetName(GetSerializableName());
386 
387  Mezzanine::XML::Attribute VersionAttr = RayQueryToolNode.AppendAttribute("Version");
388  if( VersionAttr && VersionAttr.SetValue("1"))
389  {
390  Mezzanine::XML::Attribute ResultAttr = RayQueryToolNode.AppendAttribute("ValidResult");
391  if( ResultAttr && ResultAttr.SetValue(ValidResult))
392  {}
393  else
394  { SerializeError("Create XML Attribute for ValidResult", GetSerializableName(), true); }
395 
396  Mezzanine::XML::Node OffsetNode = RayQueryToolNode.AppendChild("Offset");
397  if( OffsetNode )
398  { Offset.ProtoSerialize(OffsetNode); }
399  else
400  { SerializeError("Create XML Node for Offset", GetSerializableName(), true); }
401 
402  Mezzanine::XML::Attribute WorldObjectAttr = RayQueryToolNode.AppendAttribute("WorldObject");
403  if( WorldObjectAttr )
404  {
405  if( IntersectedObject )
406  {
407  if(WorldObjectAttr.SetValue(IntersectedObject->GetName().c_str()))
408  {}
409  else
410  { SerializeError("Create XML Node for Offset", GetSerializableName(),true); }
411  }
412  }
413  else
414  { SerializeError("Create XML Attribute for Offset", GetSerializableName(),true); }
415  }else{
416  SerializeError("Create XML Version Attibute", GetSerializableName(),true);
417  }
418  }
419 
421  {
423  {
424  if(OneNode.GetAttribute("Version").AsInt() == 1)
425  {
426  ValidResult=OneNode.GetAttribute("ValidResult").AsBool();
427 
428  XML::Node VecNode = OneNode.GetChild("Offset");
429  if( !VecNode )
430  { DeSerializeError("Could not Deserialize Offset",GetSerializableName()); }
431  Offset.ProtoDeSerialize(VecNode);
432 
433  String WorldObjectName(OneNode.GetAttribute("WorldObject").AsString());
434  if( WorldObjectName.size() ) {
435  /// @todo This is temporary code that should be replaced with something more robust to find the proper world object.
436  IntersectedObject = static_cast<DebrisManager*>( this->ParentWorld->GetManager(ManagerBase::MT_DebrisManager) )->GetDebris(WorldObjectName);
437  if( IntersectedObject == NULL ) {
438  IntersectedObject = static_cast<ActorManager*>( this->ParentWorld->GetManager(ManagerBase::MT_ActorManager) )->GetActor(WorldObjectName);
439  }
440  if( IntersectedObject == NULL ) {
441  IntersectedObject = static_cast<AreaEffectManager*>( this->ParentWorld->GetManager(ManagerBase::MT_AreaEffectManager) )->GetAreaEffect(WorldObjectName);
442  }
443  }else{
444  IntersectedObject = NULL;
445  }
446  }else{
447  MEZZ_EXCEPTION(ExceptionBase::INVALID_VERSION_EXCEPTION,"Incompatible XML Version for " + GetSerializableName() + ": Not Version 1.");
448  }
449  }else{
450  MEZZ_EXCEPTION(ExceptionBase::II_IDENTITY_INVALID_EXCEPTION,"Attempting to deserialize a " + GetSerializableName() + ", found a " + String(OneNode.Name()) + ".");
451  }
452  }
453 
455  { return "RayQueryTool"; }
456 }
457 
458 #endif
Boole LastQueryResultsValid() const
Check to see if the last query found anything.
virtual Quaternion GetOrientation() const =0
Gets this objects current orientation.
Attribute AppendAttribute(const Char8 *Name)
Creates an Attribute and puts it at the end of this Nodes attributes.
A light-weight handle for manipulating attributes in DOM tree.
Definition: attribute.h:74
Thrown when an unknown internal error occurred.
Definition: exception.h:116
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
bool AsBool(bool def=false) const
Attempts to convert the value of the attribute to a float and returns the results.
virtual Ray GetCameraToViewportRay(const Real ScreenX, const Real ScreenY) const
Gets a Ray from the camera to the viewport.
A manager responsible for the storage and management of all areaeffects in use.
This file contains the declaration for the manager that manages debris objects in a world...
static Ray GetMouseRay()
Get a Ray from the current viewport, following the mouse.
This file contains the declaration for the base class from which graphics proxies inherit...
#define MEZZ_EXCEPTION(num, desc)
An easy way to throw exceptions with rich information.
Definition: exception.h:3048
STL namespace.
Thrown when a version is accessed/parsed/required and it cannot work correctly or is missing...
Definition: exception.h:112
const Char8 * AsString(const Char8 *def="") const
Attempts to convert the value of the attribute to a String and returns the results.
This is the base proxy class for world proxies wrapping functionality of the graphics subsystem...
Whole GetActualWidth() const
Gets the width of the viewport in pixels.
Definition: viewport.cpp:147
virtual const String & GetName() const
Gets the name of this object.
Definition: worldobject.cpp:67
This is used to represent a flat infinite slice of the game world.
Definition: plane.h:65
virtual Mezzanine::WorldObjectType GetType() const =0
Gets the type of the object instance.
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
The interface for serialization.
bool SetValue(const Char8 *rhs)
Set the value of this.
This is the base class from which classes that are insertable into the physical world.
Definition: worldobject.h:60
RayQueryTool()
Blank constructor.
bool SetName(const Char8 *rhs)
Set the name of .
static InputManager * GetSingletonPtr()
Fetches a pointer to the singleton.
Definition: singleton.h:97
This class is for creating and managing viewports within a game window.
Definition: viewport.h:65
virtual Vector3 GetLocation() const =0
Gets this objects current location.
Real Y
Coordinate on the Y vector.
Definition: vector2.h:69
This file contains the declaration for the World proxy wrapping camera functionality.
A manager responsible for the storage and management of all Debris that exist in a world...
Boole RayPlaneIntersection(const Ray &QueryRay, const Plane &QueryPlane)
Where does this Ray Meet this Plane?
A light-weight handle for manipulating nodes in DOM tree.
Definition: node.h:89
Real X
Coordinate on the X vector.
Definition: vector2.h:67
int AsInt(int def=0) const
Attempts to convert the value of the attribute to an int and returns the results. ...
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
void ProtoSerialize(XML::Node &CurrentRoot) const
Convert this class to an XML::Node ready for serialization.
This file contains the declaration for the debris class used to represent a small loose object in the...
WorldObject * LastQueryResultsObjectPtr() const
It is common to ray query for WorldObjects, if so the results can be retrieved with this...
Boole ClearReturns()
Clears an previously stored return values.
Whole GetActualHeight() const
Gets the height of the viewport in pixels.
Definition: viewport.cpp:150
The interface for a class useful for applying RAII when it should have been used but wasn't...
The base class for all Actors is defined here.
void DeSerializeError(const String &FailedTo, const String &ClassName, Boole SOrD)
Simply does some string concatenation, then throws an Exception.
void ProtoDeSerialize(const XML::Node &OneNode)
Take the data stored in an XML and overwrite this instance of this object with it.
Definition: vector3.cpp:614
void SetWorld(World *QueryWorld)
Sets the World in which the ray query is to be performed.
CameraProxy * GetCamera() const
Gets the CameraProxy associated with this viewport.
Definition: viewport.cpp:87
Thrown when the identity string wasn't valid at all.
Definition: exception.h:93
This is used to represent a point in space, or a vector through space.
Definition: vector3.h:77
Ogre::Ray GetOgreRay() const
Gets an Ogre::Ray that contains this Rays information.
Definition: ray.cpp:115
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
Boole GetFirstObjectOnRayByAABB(Ray ObjectRay, Whole ObjectFlags)
Partially implemented. This should find the first Object that is on or almost on the a given Ray...
This class represents a world for objects to interact within.
Definition: world.h:74
virtual Vector3 GetScale() const =0
Gets the scaling currently being applied to this object.
Vector3 LastQueryResultsOffset() const
Get an offset from the last query. Depending on the last query, this could be an Offset from a variet...
static String GetSerializableName()
Get the name of the the XML tag this class will leave behind as its instances are serialized...
const Char8 * Name() const
ptrdiff_tGet the name of this Node.
void SerializeError(const String &FailedTo, const String &ClassName, Boole SOrD)
Simply does some string concatenation, then throws an Exception.
Node AppendChild(NodeType Type=NodeElement)
Creates a Node and makes it a child of this one.
Boole GetFirstObjectOnRayByPolygon(Ray ObjectRay, Whole ObjectFlags)
This will find the first Object to intesect the Given ray.
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
void ProtoDeSerialize(const XML::Node &OneNode)
Take the data stored in an XML and overwrite this instance of this object with it.
Attribute GetAttribute(const Char8 *Name) const
Attempt to get an Attribute on this Node with a given name.
void ProtoSerialize(XML::Node &CurrentRoot) const
Convert this class to an XML::Node ready for serialization.
Definition: vector3.cpp:588
This represents a line placed in 3D space and is used with spacial queries.
Definition: ray.h:67
Node GetChild(const Char8 *Name) const
Attempt to get a child Node with a given name.
A manager responsible for the storage and management of all actors that exist in a world...
Definition: actormanager.h:94