NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
TextureAdjustable.cpp
Go to the documentation of this file.
00001 
00010 #pragma once
00011 
00012 #include "TextureAdjustable.h"
00013 
00014 // Standard Includes
00015 #include <string>
00016 
00017 // Library Includes
00018 #include <d3dx9.h>
00019 
00020 // Local Includes
00021 #include "../../sharedbase/MessageRouter.h"
00022 #include "../../sharedbase/Envelope.h"
00023 #include "../RenderModule.h"
00024 #include "../Textures.h"
00025 #include "TexturesSystemInterface.h"
00026 
00027 // Forward Declarations
00028 
00029 // Typedefs
00030 namespace GraphicsCore {
00031   #define SUBSCRIBE_BASIC(msgid, handler)   {std::shared_ptr<Subscriber> handler_sptr(new Subscriber(boost::bind((&handler), this, _1))); this->messageRouter->Subscribe((msgid), handler_sptr);}
00032   #define UNSUBSCRIBE_BASIC(msgid, handler) {std::shared_ptr<Subscriber> handler_sptr(new Subscriber(boost::bind((&handler), this, _1))); this->messageRouter->Unsubscribe((msgid), handler_sptr);}
00033   #define SUBSCRIBE_DIRECTED(msgid, handler)   {std::shared_ptr<DirectedSubscriber> handler_sptr(new DirectedSubscriber(boost::bind((&handler), this, _1))); this->messageRouter->SubscribeDirected((msgid), handler_sptr);}
00034   #define UNSUBSCRIBE_DIRECTED(msgid, handler) {std::shared_ptr<DirectedSubscriber> handler_sptr(new DirectedSubscriber(boost::bind((&handler), this, _1))); this->messageRouter->UnsubscribeDirected((msgid), handler_sptr);}
00035 }
00036 
00037 // Local Constants
00038 namespace GraphicsCore {
00039   // 0 is left for an undefined entry.
00040   static const unsigned int TEXTURE_OFFSET = 1; // Followed by: float, float
00041   static const unsigned int TEXTURE_SCALE = 2; // non-uniform scaling.  Followed by: float, float
00042   static const unsigned int TEXTURE_SCALE_UNIFORM = 3; // Followed by: float
00043   static const unsigned int TEXTURE_ROTATION = 4; // Followed by: float
00044   static const unsigned int TEXTURE_FILE = 5; // Followed by: string
00045 }
00046 
00047 
00048 namespace GraphicsCore {
00049   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00050   TextureAdjustable::TextureAdjustable(TextureInterface* texture, MessageRouter* messageRouter, RenderModule* renderModule) :
00051     primaryBuffer(TextureAdjustableDataPointer(new TextureAdjustableData())),
00052     secondaryBuffer(TextureAdjustableDataPointer(new TextureAdjustableData())),
00053     messageRouter(messageRouter),
00054     renderModule(renderModule),
00055     messageTypeId(0)
00056   {
00057     
00058     this->primaryBuffer->scale.x = this->primaryBuffer->scale.y = 1.0f;
00059     this->primaryBuffer->translation.x = this->primaryBuffer->translation.y = 0.0f;
00060     this->primaryBuffer->sinRotation = 0.0f;
00061     this->primaryBuffer->cosRotation = 1.0f;
00062     this->primaryBuffer->texture = texture;
00063     
00064     this->secondaryBuffer->scale.x = this->secondaryBuffer->scale.y = 1.0f;
00065     this->secondaryBuffer->translation.x = this->secondaryBuffer->translation.y = 0.0f;
00066     this->secondaryBuffer->sinRotation = 0.0f;
00067     this->secondaryBuffer->cosRotation = 1.0f;
00068     this->secondaryBuffer->texture = nullptr;
00069     
00070     this->swap.needed = false;
00071     
00072     D3DXMatrixIdentity(&this->currentMatrix);
00073   }
00074   
00075   TextureAdjustable::~TextureAdjustable() {
00076     UNSUBSCRIBE_BASIC(this->messageTypeId, TextureAdjustable::MessageHandler);
00077     
00078     if (this->secondaryBuffer->texture != nullptr && this->secondaryBuffer->texture != this->primaryBuffer->texture) {
00079       TexturesSystemInterface::DestroyTexture(this->secondaryBuffer->texture);
00080     }
00081     
00082     if (this->primaryBuffer->texture != nullptr) {
00083       TexturesSystemInterface::DestroyTexture(this->primaryBuffer->texture);
00084     }
00085   }
00086   
00087   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00088   bool TextureAdjustable::SetMessageId(unsigned int message_type_id) {
00089     UNSUBSCRIBE_BASIC(this->messageTypeId, TextureAdjustable::MessageHandler);
00090     SUBSCRIBE_BASIC(message_type_id, TextureAdjustable::MessageHandler);
00091     
00092     this->messageTypeId = message_type_id;
00093     
00094     return true;
00095   }
00096   
00097   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00098   void TextureAdjustable::Apply(LPDIRECT3DDEVICE9 d3d_device) {
00099     // Attempt buffer swap here if needed.
00100     {
00101       Threading::UpgradeLock swap_lock(this->swap.mutex);
00102       if (this->swap.needed) {
00103         {
00104           Threading::UpgradeToUniqueLock unique_lock(swap_lock);
00105           this->swap.needed = false;
00106         }
00107         
00108         {
00109           Threading::WriteLock w1_lock(this->secondaryBuffer->mutex);
00110           Threading::WriteLock w2_lock(this->primaryBuffer->mutex);
00111           Threading::Swap<TextureAdjustableDataPointer>(this->primaryBuffer, this->secondaryBuffer);
00112         }
00113         
00114         // Recompute matrix.  Not all positions need changing as they never are modified from when set by the Identity operation in the constructor.
00115         this->currentMatrix(0, 0) = this->primaryBuffer->scale.x * this->primaryBuffer->cosRotation;
00116         this->currentMatrix(0, 1) = this->primaryBuffer->scale.x * this->primaryBuffer->sinRotation;
00117         
00118         this->currentMatrix(1, 0) = this->primaryBuffer->scale.y * -this->primaryBuffer->sinRotation;
00119         this->currentMatrix(1, 1) = this->primaryBuffer->scale.y * this->primaryBuffer->cosRotation;
00120         
00121         this->currentMatrix(2, 0) = this->primaryBuffer->translation.x;
00122         this->currentMatrix(2, 1) = this->primaryBuffer->translation.y;
00123       }
00124     }
00125     
00126     Threading::ReadLock r_lock(this->primaryBuffer->mutex);
00127     if (this->primaryBuffer->texture != nullptr) {
00128       d3d_device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
00129       d3d_device->SetTransform(D3DTS_TEXTURE0, &this->currentMatrix);
00130       
00131       this->primaryBuffer->texture->Apply(d3d_device);
00132     }
00133   }
00134   
00135   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00136   void TextureAdjustable::MessageHandler(EnvelopeSPTR envelope) {
00137     if (envelope->GetCount()) {
00138       bool safe = true; // if the parsing or lexing fails, this will be set false and the changes will not be committed.
00139       
00140       {
00141         Threading::WriteLock w_lock(this->secondaryBuffer->mutex);
00142         
00143         // Copy the primary buffer
00144         {
00145           Threading::ReadLock r_lock(this->primaryBuffer->mutex);
00146           this->secondaryBuffer->scale = this->primaryBuffer->scale;
00147           this->secondaryBuffer->translation = this->primaryBuffer->translation;
00148           this->secondaryBuffer->sinRotation = this->primaryBuffer->sinRotation;
00149           this->secondaryBuffer->cosRotation = this->primaryBuffer->cosRotation;
00150           
00151           if (this->secondaryBuffer->texture != nullptr && this->secondaryBuffer->texture != this->primaryBuffer->texture) {
00152             TexturesSystemInterface::DestroyTexture(this->secondaryBuffer->texture);
00153           }
00154           
00155           this->secondaryBuffer->texture = this->primaryBuffer->texture;
00156         }
00157         
00158         // Parse the envelope
00159         {
00160           // Syntax: {uint code, properties in a fixed amount per code...}, ...
00161           unsigned int param_type;
00162           unsigned int count = envelope->GetCount();
00163           for (unsigned int index = 0; index < count && safe; ++index) {
00164             param_type = envelope->GetDataUInt(index);
00165             switch (param_type) {
00166               case TEXTURE_OFFSET: {
00167                 // Get the values
00168                 this->secondaryBuffer->translation.x = envelope->GetDataFloat(index + 1);
00169                 this->secondaryBuffer->translation.y = envelope->GetDataFloat(index + 2);
00170                 
00171                 // Consume the positions used.
00172                 index += 2;
00173               }
00174               break;
00175               case TEXTURE_SCALE: {
00176                 // Get the values
00177                 this->secondaryBuffer->scale.x = envelope->GetDataFloat(index + 1);
00178                 this->secondaryBuffer->scale.y = envelope->GetDataFloat(index + 2);
00179                 
00180                 // Consume the positions used.
00181                 index += 2;
00182               }
00183               break;
00184               case TEXTURE_SCALE_UNIFORM: {
00185                 // Get the values
00186                 this->secondaryBuffer->scale.x = this->secondaryBuffer->scale.y = envelope->GetDataFloat(index + 1);
00187                 
00188                 // Consume the positions used.
00189                 index += 1;
00190               }
00191               break;
00192               case TEXTURE_ROTATION: {
00193                 // Get the values
00194                 float angle = envelope->GetDataFloat(index + 1);
00195                 
00196                 this->secondaryBuffer->sinRotation = sin(angle);
00197                 this->secondaryBuffer->cosRotation = cos(angle);
00198                 
00199                 // Consume the positions used.
00200                 index += 1;
00201               }
00202               break;
00203               case TEXTURE_FILE: {
00204                 // Get the values
00205                 std::string file = envelope->GetDataString(index + 1);
00206                 
00207                 EnvelopeSPTR envelope(new Envelope());
00208                 envelope->msgid = ID_TEXTURE_BASIC;
00209                 envelope->AddData(ID_TEXTURE_PARAM_FILE);
00210                 envelope->AddData(file);
00211                 
00212                 // At this point the texture in the secondary buffer is either a nullptr, or a pointer to the same texture that is in the primary buffer.
00213                 // Either way, we can just override it.
00214                 this->secondaryBuffer->texture = TexturesSystemInterface::CreateTexture(envelope, renderModule);
00215                 
00216                 // Consume the positions used.
00217                 index += 1;
00218               }
00219               break;
00220               default: {
00221                 LOG(LOG_PRIORITY::INFO, "Unknown texture parameter type sent: " + boost::lexical_cast < std::string > (param_type));
00222                 safe = false; // Stop processing the loop: to proceed would be just garbage due to unknown types.
00223               }
00224             }
00225           }
00226         }
00227       }
00228       
00229       if (safe) {
00230         // Mark the buffers for swapping.
00231         Threading::WriteLock w_lock(this->swap.mutex);
00232         this->swap.needed = true;
00233       }
00234     }
00235   }
00236 }