text: // Geometric Tools, LLC
  // Copyright (c) 1998-2014
  // Distributed under the Boost Software License, Version 1.0.
  // http://www.boost.org/LICENSE_1_0.txt
  // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  //
  // File Version: 5.0.0 (2010/01/01)
  
  #include "Wm5GraphicsPCH.h"
  #include "Wm5BillboardNode.h"
  using namespace Wm5;
  
  WM5_IMPLEMENT_RTTI(Wm5, Node, BillboardNode);
  WM5_IMPLEMENT_STREAM(BillboardNode);
  WM5_IMPLEMENT_FACTORY(BillboardNode);
  
  //----------------------------------------------------------------------------
  BillboardNode::BillboardNode (Camera* camera)
      :
      mCamera(camera)
  {
  }
  //----------------------------------------------------------------------------
  BillboardNode::~BillboardNode ()
  {
  }
  //----------------------------------------------------------------------------
  void BillboardNode::UpdateWorldData (double applicationTime)
  {
      // Compute the billboard's world transforms based on its parent's world
      // transform and its local transforms.  Notice that you should not call
      // Node::UpdateWorldData since that function updates its children.  The
      // children of a BillboardNode cannot be updated until the billboard is
      // aligned with the camera.
      Spatial::UpdateWorldData(applicationTime);
  
      if (mCamera)
      {
          // Inverse-transform the camera to the model space of the billboard.
          APoint modelPos = WorldTransform.Inverse()*mCamera->GetPosition();
  
          // To align the billboard, the projection of the camera to the
          // xz-plane of the billboard's model space determines the angle of
          // rotation about the billboard's model y-axis.  If the projected
          // camera is on the model axis (x = 0 and z = 0), ATan2 returns zero
          // (rather than NaN), so there is no need to trap this degenerate
          // case and handle it separately.
          float angle = Mathf::ATan2(modelPos[0], modelPos[2]);
          HMatrix orient(AVector::UNIT_Y, angle);
          WorldTransform.SetRotate(WorldTransform.GetRotate()*orient);
      }
  
      // Update the children now that the billboard orientation is known.
      std::vector<SpatialPtr>::iterator iter = mChild.begin();
      std::vector<SpatialPtr>::iterator end = mChild.end();
      for (/**/; iter != end; ++iter)
      {
          Spatial* child = *iter;
          if (child)
          {
              child->Update(applicationTime, false);
          }
      }
  }
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  // Name support.
  //----------------------------------------------------------------------------
  Object* BillboardNode::GetObjectByName (const std::string& name)
  {
      Object* found = Object::GetObjectByName(name);
      if (found)
      {
          return found;
      }
  
      WM5_GET_OBJECT_BY_NAME(mCamera, name, found);
      return 0;
  }
  //----------------------------------------------------------------------------
  void BillboardNode::GetAllObjectsByName (const std::string& name,
      std::vector<Object*>& objects)
  {
      Node::GetAllObjectsByName(name, objects);
  
      WM5_GET_ALL_OBJECTS_BY_NAME(mCamera, name, objects);
  }
  //----------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------
  // Streaming support.
  //----------------------------------------------------------------------------
  BillboardNode::BillboardNode (LoadConstructor value)
      :
      Node(value),
      mCamera(0)
  {
  }
  //----------------------------------------------------------------------------
  void BillboardNode::Load (InStream& source)
  {
      WM5_BEGIN_DEBUG_STREAM_LOAD(source);
  
      Node::Load(source);
  
      source.ReadPointer(mCamera);
  
      WM5_END_DEBUG_STREAM_LOAD(BillboardNode, source);
  }
  //----------------------------------------------------------------------------
  void BillboardNode::Link (InStream& source)
  {
      Node::Link(source);
  
      source.ResolveLink(mCamera);
  }
  //----------------------------------------------------------------------------
  void BillboardNode::PostLink ()
  {
      Node::PostLink();
  }
  //----------------------------------------------------------------------------
  bool BillboardNode::Register (OutStream& target) const
  {
      if (Node::Register(target))
      {
          target.Register(mCamera);
          return true;
      }
      return false;
  }
  //----------------------------------------------------------------------------
  void BillboardNode::Save (OutStream& target) const
  {
      WM5_BEGIN_DEBUG_STREAM_SAVE(target);
  
      Node::Save(target);
  
      target.WritePointer(mCamera);
  
      WM5_END_DEBUG_STREAM_SAVE(BillboardNode, target);
  }
  //----------------------------------------------------------------------------
  int BillboardNode::GetStreamingSize () const
  {
      int size = Node::GetStreamingSize();
      size += WM5_POINTERSIZE(mCamera);
      return size;
  }
  //----------------------------------------------------------------------------
  