NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
Entity.cpp
Go to the documentation of this file.
00001 
00014 #include "Entity.h"
00015 
00016 // Standard Includes
00017 
00018 // Library Includes
00019 #include <d3dx9math.h>
00020 #include <boost/any.hpp>
00021 #include <boost/foreach.hpp>
00022 
00023 // Local Includes
00024 #include "QuatMath.h"
00025 #include "ComponentInterface.h"
00026 #include "ModuleInterface.h"
00027 
00028 // Forward Declarations
00029 
00030 // Typedefs
00031 
00032 // Methods
00033 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00034 EntitySPTR Entity::Factory(const std::string& name, const int& id) {
00035   EntitySPTR entity(new Entity(name, id));
00036   return entity;
00037 }
00038 
00039 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00041 void Entity::FactoryAtAddress(void* address) {
00042   Entity::FactoryAtAddress(address, "", -1);
00043 }
00044 
00045 void Entity::FactoryAtAddress(void* address, const std::string& name) {
00046   Entity::FactoryAtAddress(address, name, -1);
00047 }
00048 
00049 void Entity::FactoryAtAddress(void* address, const std::string& name, const int& id) {
00050   new (address) EntitySPTR(new Entity(name, id));
00051 }
00052 
00053 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00054 Entity::Entity(const std::string& name, const int& id) :
00055   location(D3DXVECTOR3(0.0f, 0.0f, 0.0f)),
00056   rotation(D3DXQUATERNION(0.0f, 0.0f, 0.0f, 1.0f)),
00057   scale(1.0f),
00058   id(id),
00059   priority(0),
00060   name(new std::string(name)),
00061   parent(nullptr)
00062   {
00063   LOG(LOG_PRIORITY::FLOW, "Entity '" + this->GetName() + "' created.");
00064 }
00065 
00066 Entity::~Entity() {
00067   LOG(LOG_PRIORITY::FLOW, "Entity '" + this->GetName() + "' destroyed.");
00068   
00069   this->ClearComponents();
00070   
00071   // Break from parent object.
00072   this->SetParent(nullptr);
00073 }
00074 
00075 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00076 void Entity::SetParent(EntitySPTR new_parent) {
00077   Threading::WriteLock w_lock(this->parentMutex);
00078   
00079   if (new_parent.get() != nullptr) {
00080     // Verify that a recursive relationship has not been established
00081     bool status = true;
00082     Entity* new_parent_p = new_parent.get();
00083     Entity* parent = this->parent.get();
00084     
00085     // Linearized recursive scan up the family tree.
00086     while (parent != nullptr && (status = (parent != new_parent_p))) {
00087       parent = parent->GetParent().get();
00088     }
00089     
00090     if (status) {
00091       this->parent = new_parent;
00092     }
00093     else {
00094       LOG(LOG_PRIORITY::CONFIG, "ERROR: Recursive parenting NOT allowed.  Attempted to parent '" + this->GetName() + "' to '" + new_parent->GetName() + "'.");
00095     }
00096   }
00097   else {
00098     this->parent.reset();
00099   }
00100 }
00101 
00102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00103 EntitySPTR Entity::GetParent(void) const {
00104   Threading::ReadLock r_lock(this->parentMutex);
00105   
00106   EntitySPTR ent(this->parent);
00107   
00108   return ent;
00109 }
00110 
00111 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00112 int Entity::GetId() const {
00113   return this->id;
00114 }
00115 
00116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00120 D3DXVECTOR3 Entity::GetWorldPosition(void) const {
00121   D3DXVECTOR3 result = this->location;
00122   Entity* entity = this->GetParent().get();
00123   D3DXVECTOR3 scaled, rotated;
00124   
00125   
00126   /* N=3
00127   push
00128     [n-2].translate
00129     [n-2].scale
00130     [n-2].rotate
00131     push
00132       [n-1].translate
00133       [n-1].scale
00134       [n-1].rotate
00135       push
00136         [n-0].translate
00137       pop
00138     pop
00139   pop
00140   
00141   (([n-0].translate) * [n-1].scale * [n-1].rotate + [n-1].translate) * [n-2].scale * [n-2].rotate + [n-2].translate
00142   */
00143   
00144   while (entity != nullptr) {
00145     //result = (result * entity->scale) * entity->rotation + entity->location;
00146     
00147     scaled = (result * entity->scale);
00148     
00149     RotateVectorByQuaternion(&rotated, &scaled, &(entity->rotation));
00150     
00151     result = rotated + entity->location;
00152     
00153     entity = entity->GetParent().get();
00154   }
00155   
00156   return result;
00157 }
00158 
00159 void Entity::SetWorldPosition(float x, float y, float z) {
00160   this->location = D3DXVECTOR3(x, y, z);
00161 }
00162 
00163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00167 D3DXQUATERNION Entity::GetWorldRotation(void) const {
00168   D3DXQUATERNION result = this->rotation;
00169   Entity* entity = this->GetParent().get();
00170   
00171   // Linearized recursive accumulation of rotations.
00172   while (entity != nullptr) {
00173     result = entity->rotation * result; // Remember, quat multiplication is NOT commutative!
00174     
00175     entity = entity->GetParent().get();
00176   }
00177   
00178   return result;
00179 }
00180 
00181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00185 float Entity::GetWorldScale(void) const {
00186   float result = this->scale;
00187   Entity* entity = this->GetParent().get();
00188   
00189   // Linearized recursive accumulation of scales.
00190   while (entity != nullptr) {
00191     result *= entity->scale;
00192     
00193     entity = entity->GetParent().get();
00194   }
00195   
00196   return result;
00197 }
00198 
00199 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00203 void Entity::SetRotation(D3DXQUATERNION rot) {
00204   D3DXQuaternionNormalize(&rot, &rot);
00205   this->rotation = rot;
00206   // *NOTE: If the normalize's sqrt call needs to be optimized away, there is a way (supposedly) to normalize quats without sqrt.
00207 }
00208 
00209 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00213 void Entity::SetRotation(float yaw, float pitch, float roll) {
00214   D3DXQUATERNION rot;
00215   D3DXQuaternionRotationYawPitchRoll(&rot, yaw, pitch, roll);
00216   this->SetRotation(rot);
00217 }
00218 
00219 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00223 void Entity::ChangePosition(D3DXVECTOR3 delta) {
00224   this->location += delta;
00225 }
00226 
00227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00231 void Entity::ChangeRotation(D3DXQUATERNION delta) {
00232   D3DXQuaternionNormalize(&delta, &delta);
00233   this->rotation *= delta;
00234   // *NOTE: If the normalize's sqrt call needs to be optimized away, there is a way (supposedly) to normalize quats without sqrt.
00235 }
00236 
00237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00241 void Entity::ChangeRotation(float deltaYaw, float deltaPitch, float deltaRoll) {
00242   D3DXQUATERNION delta;
00243   D3DXQuaternionRotationYawPitchRoll(&delta, deltaYaw, deltaPitch, deltaRoll);
00244   this->ChangeRotation(delta);
00245 }
00246 
00247 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00251 void Entity::ChangeScale(float delta) {
00252   this->scale *= delta;
00253 }
00254 
00255 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00256 void Entity::RegisterComponent(ComponentInterface* component) {
00257   Threading::WriteLock w_lock(this->componentsMutex);
00258   
00259   this->components.insert(component);
00260 }
00261 
00262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00263 void Entity::UnregisterComponent(ComponentInterface* component) {
00264   Threading::WriteLock w_lock(this->componentsMutex);
00265   
00266   this->components.erase(component);
00267 }
00268 
00269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00270 bool Entity::NotifyEntityRemoval(EntitySPTR entity) {
00271   if (entity == this->GetParent()) {
00272     this->SetParent(nullptr);
00273     
00274     return true;
00275   }
00276   
00277   return false;
00278 }
00279 
00280 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00281 void Entity::SetName(const std::string& name) {
00282   if (this->name.get() != nullptr) {
00283     LOG(LOG_PRIORITY::FLOW, "Entity '" + this->GetName() + "' renamed to '" + name + "'.");
00284     
00285     // Mutate the string to contain the new value
00286     this->name->erase(0, this->name->length());
00287     this->name->insert(0, name);
00288   }
00289   else {
00290     LOG(LOG_PRIORITY::FLOW, "Entity given name '" + name + "'. Pretty sure this is impossible because of the way the factories are set up.  Let me know if you see this in the log! ~Ricky");
00291     
00292     this->name.reset(new std::string(name));
00293   }
00294 }
00295 
00296 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00297 std::string Entity::GetName() {
00298   if (this->name != nullptr) {
00299     return *this->name;
00300   }
00301   
00302   return "";
00303 }
00304 
00305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00306 MutableStringSPTR Entity::GetNameSPTR() {
00307   return this->name;
00308 }
00309 
00310 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00311 void  Entity::ClearComponents() {
00312   static std::set<ComponentInterface*> components;
00313   static ModuleInterface* module;
00314   
00315   {
00316     Threading::ReadLock r_lock(this->componentsMutex);
00317     components = this->components;
00318   }
00319   
00320   // Remove the child components - each will unregister itself upon dtor.
00321   BOOST_FOREACH(ComponentInterface* component, components) {
00322     module = component->GetModule();
00323     if (module->RemoveComponent(component) == WHO_DELETES::CALLER) {
00324       delete component;
00325     }
00326   }
00327 }