NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
Quad.cpp
Go to the documentation of this file.
00001 
00012 #include "Quad.h"
00013 
00014 // System Library Includes
00015 
00016 // Application Library Includes
00017 #include <EngineConfig.h>
00018 
00019 // Local Includes
00020 #include "../../../sharedbase/EventLogger.h"
00021 #include "../../material/MaterialInterface.h"
00022 #include "../../texture/TextureInterface.h"
00023 
00024 // Forward Declarations
00025 
00026 // Typedefs and data structures
00027 namespace GraphicsCore {
00028   struct QuadVertex {
00029     D3DXVECTOR3 pos;
00030     D3DXVECTOR3 norm;
00031     D3DXVECTOR2 texcoord;
00032   };
00033 }
00034 
00035 // Constants
00036 namespace GraphicsCore {
00037   static const unsigned long QUAD_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
00038   static const D3DMATRIX UNIT_MATRIX = {
00039     1.0f, 0.0f, 0.0f, 0.0f,
00040     0.0f, 1.0f, 0.0f, 0.0f,
00041     0.0f, 0.0f, 1.0f, 0.0f,
00042     0.0f, 0.0f, 0.0f, 1.0f
00043   };
00044 }
00045 
00046 // Static members
00047 namespace GraphicsCore {
00048   LPD3DXMESH Quad::mesh;
00049 }
00050 
00051 // Class methods
00052 namespace GraphicsCore {
00053   Quad::Quad(EntitySPTR owner, ModuleInterface* render_module, LPDIRECT3DDEVICE9 d3d_device) :
00054     RenderableComponent(owner, render_module),
00055     width(1.0f),
00056     height(1.0f),
00057     originLocation(ORIGIN::CENTER),
00058     orientation(ORIENTATION::WORLD),
00059     material(nullptr),
00060     texture(nullptr),
00061     matrix(UNIT_MATRIX)
00062   {
00063     this->UpdateInstanceCache();
00064     
00065     if (Quad::mesh == nullptr) {
00066       std::vector<QuadVertex> vertices;
00067       std::vector<unsigned short> indices;
00068       
00069       // Create the vertices
00070       {
00071         QuadVertex vertex;
00072         
00073         vertex.pos      = D3DXVECTOR3( 0.0f,  0.0f,  0.0f);
00074         vertex.norm     = D3DXVECTOR3( 0.0f,  0.0f, -1.0f);
00075         vertex.texcoord = D3DXVECTOR2( 0.0f,  0.0f);
00076         vertices.push_back(vertex);
00077         
00078         vertex.pos      = D3DXVECTOR3( 1.0f,  0.0f,  0.0f);
00079         vertex.norm     = D3DXVECTOR3( 0.0f,  0.0f, -1.0f);
00080         vertex.texcoord = D3DXVECTOR2( 1.0f,  0.0f);
00081         vertices.push_back(vertex);
00082         
00083         vertex.pos      = D3DXVECTOR3( 1.0f, -1.0f,  0.0f);
00084         vertex.norm     = D3DXVECTOR3( 0.0f,  0.0f, -1.0f);
00085         vertex.texcoord = D3DXVECTOR2( 1.0f,  1.0f);
00086         vertices.push_back(vertex);
00087         
00088         vertex.pos      = D3DXVECTOR3( 0.0f, -1.0f,  0.0f);
00089         vertex.norm     = D3DXVECTOR3( 0.0f,  0.0f, -1.0f);
00090         vertex.texcoord = D3DXVECTOR2( 0.0f,  1.0f);
00091         vertices.push_back(vertex);
00092         
00093         if (vertices.size() < 3) {
00094           LOG(LOG_PRIORITY::ERR, "Parameters must be wrong because there are less than 3 vertices!");
00095           return;
00096         }
00097       }
00098       
00099       // Create the indices for the index buffer
00100       {
00101         indices.push_back(0);
00102         indices.push_back(1);
00103         indices.push_back(2);
00104         
00105         indices.push_back(2);
00106         indices.push_back(3);
00107         indices.push_back(0);
00108       }
00109       
00110       // Build the mesh
00111       {
00112         // Create the mesh itself
00113         {
00114           if (FAILED(D3DXCreateMeshFVF(
00115             indices.size() / 3, // Number of faces
00116             vertices.size(),    // Number of vertices
00117             D3DXMESH_MANAGED,   // Options
00118             QUAD_VERTEX_FVF,    // FVF
00119             d3d_device,
00120             &Quad::mesh
00121           ))) {
00122             std::string err = "Mesh could not be initialized! " + std::string((Quad::mesh == nullptr) ? "Mesh was null, not sure what happened..." : "Mesh wasn't null.  Possible issue with needing to delete mesh before recreating.");
00123             LOG(LOG_PRIORITY::INFO, err);
00124             return;
00125           }
00126           
00127         }
00128         
00129         // Fill the vertex buffer
00130         {
00131           void* vertexBuffer;
00132           if (FAILED(Quad::mesh->LockVertexBuffer(D3DLOCK_DISCARD, (void**)&vertexBuffer))) {
00133             LOG(LOG_PRIORITY::INFO, "Vertex buffer could not be locked!");
00134             return;
00135           }
00136           
00137           memcpy(vertexBuffer, &vertices.at(0), sizeof(QuadVertex) * vertices.size()); // *NOTE: This may not be the best technique, as memcpy with std::vector is a hazardous operation.
00138           
00139           Quad::mesh->UnlockVertexBuffer();
00140         }
00141         
00142         // Fill the index buffer
00143         {
00144           void* indexBuffer;
00145           if (FAILED(Quad::mesh->LockIndexBuffer(0, &indexBuffer))) {
00146             LOG(LOG_PRIORITY::INFO, "Index buffer could not be locked!");
00147             return;
00148           }
00149           
00150           memcpy(indexBuffer, &indices.at(0), sizeof(unsigned short) * indices.size()); // *NOTE: This may not be the best technique, as memcpy with std::vector is a hazardous operation.
00151           
00152           Quad::mesh->UnlockIndexBuffer();
00153         }
00154       }
00155       
00156       // Optimize the mesh
00157       // HACK: I'll write the mesh optimization line when I feel like it! ~Ricky
00158       // May also want to D3DXConvertMeshSubsetToSingleStrip
00159       
00160       
00161       // Send the mesh to disk for analysis - only when debugging the above algorithms
00162       //D3DXSaveMeshToX("../quad.x", Quad::mesh, NULL, NULL, NULL, 0, D3DXF_FILEFORMAT_TEXT);
00163     }
00164   }
00165   
00166   Quad::~Quad() {
00167     this->RemoveMaterial(0);
00168     
00169     this->RemoveTexture(0);
00170   }
00171   
00172   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00173   bool Quad::SetWidth(float size) {
00174     if (size > 0.0f && size < 2000000.0f) { // sanity check
00175       this->width = size;
00176       
00177       this->UpdateInstanceCache();
00178       
00179       return true;
00180     }
00181     
00182     return false;
00183   }
00184   
00185   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00186   bool Quad::SetHeight(float size) {
00187     if (size > 0.0f && size < 2000000.0f) { // sanity check
00188       this->height = size;
00189       
00190       this->UpdateInstanceCache();
00191       
00192       return true;
00193     }
00194     
00195     return false;
00196   }
00197   
00198   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00199   bool Quad::SetOrigin(ORIGIN::TYPE origin) {
00200     this->originLocation = origin;
00201     
00202     this->UpdateInstanceCache();
00203     
00204     return true;
00205   }
00206   
00207   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00208   bool Quad::SetOrientation(ORIENTATION::TYPE orientation) {
00209     this->orientation = orientation;
00210     
00211     return true;
00212   }
00213   
00214   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00215   void Quad::Render(LPDIRECT3DDEVICE9 d3d_device) {
00216     static D3DXMATRIX object_matrix;
00217     static D3DXMATRIX view_matrix;
00218     
00219     if (!(Quad::mesh == nullptr || (this->material == nullptr && this->texture == nullptr))) {
00220       if (this->material != nullptr) {
00221         this->material->Apply(d3d_device);
00222       }
00223       
00224       if (this->texture != nullptr) {
00225         this->texture->Apply(d3d_device);
00226       }
00227       
00228       // *NOTE: Currently assumes normal on -Z, might want to choose based on enum value at some point.
00229       if (this->orientation == ORIENTATION::CAMERA && this->GetCoordSpace() == CS_WORLD) {
00230         d3d_device->GetTransform(D3DTS_VIEW, &view_matrix);
00231         
00232         // Nullify the positional information so that the matrix can be used later to cancel the camera rotation
00233         view_matrix._41 = view_matrix._42 = view_matrix._43 = 0.0f;
00234         D3DXMatrixInverse(&view_matrix, nullptr, &view_matrix);
00235         
00236         // Get the current world transformation
00237         d3d_device->GetTransform(D3DTS_WORLD, &object_matrix);
00238         
00239         // Mix in the object transformation
00240         object_matrix *= this->matrix;
00241         
00242         // Take out the camera orientation
00243         object_matrix *= view_matrix;
00244         
00245         // Shove back into world transformation
00246         d3d_device->SetTransform(D3DTS_WORLD, &object_matrix);
00247       }
00248       else {
00249         d3d_device->MultiplyTransform(D3DTS_WORLD, &this->matrix);
00250       }
00251       
00252       Quad::mesh->DrawSubset(0);
00253     }
00254   }
00255   
00256   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00257   bool Quad::InsertMaterial(unsigned int index, EnvelopeSPTR envelope) {
00258     MaterialInterface* newMaterial = nullptr;
00259     
00260     // Quad only has one material.
00261     if (index == 0) {
00262       newMaterial = MaterialsSystemInterface::CreateMaterial(envelope);
00263       
00264       // Make sure a new material was created!
00265       if (newMaterial != nullptr) {
00266         // Remove any pre-existing material
00267         this->RemoveMaterial(index); // Return value doesn't need to be tested: if there was no material, we can continue.  If there was, this will remove it and we can continue.
00268         
00269         // Place the new material
00270         this->material = newMaterial;
00271         
00272         return true;
00273       }
00274       else {
00275         LOG(LOG_PRIORITY::INFO, "Material could not be created; not replacing existing material.");
00276       }
00277     }
00278     else {
00279       LOG(LOG_PRIORITY::INFO, "Material index out of bounds: Quad only supports 1 material at index 0." );
00280     }
00281     
00282     return false;
00283   }
00284   
00285   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00286   bool Quad::RemoveMaterial(unsigned int index) {
00287     // Quad only has one material.
00288     if (index == 0) {
00289       MaterialsSystemInterface::DestroyMaterial(this->material);
00290       
00291       this->material = nullptr;
00292       
00293       return true;
00294     }
00295     else {
00296       LOG(LOG_PRIORITY::INFO, "Material index out of bounds: Quad only supports 1 material at index 0." );
00297     }
00298     
00299     return false;
00300   }
00301   
00302   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00303   bool Quad::InsertTexture(unsigned int index, EnvelopeSPTR envelope) {
00304     TextureInterface* newTexture = nullptr;
00305     
00306     // Quad only has one texture.
00307     if (index == 0) {
00308       newTexture = TexturesSystemInterface::CreateTexture(envelope, this->GetRenderModule());
00309       
00310       // Make sure a new texture was created!
00311       if (newTexture != nullptr) {
00312         // Remove any pre-existing texture
00313         this->RemoveTexture(index); // Return value doesn't need to be tested: if there was no texture, we can continue.  If there was, this will remove it and we can continue.
00314         
00315         // Place the new texture
00316         this->texture = newTexture;
00317         
00318         return true;
00319       }
00320       else {
00321         LOG(LOG_PRIORITY::INFO, "Texture could not be created; not replacing existing texture.");
00322       }
00323     }
00324     else {
00325       LOG(LOG_PRIORITY::INFO, "Texture index out of bounds: Quad only supports 1 texture at index 0." );
00326     }
00327     
00328     return false;
00329   }
00330   
00331   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00332   bool Quad::RemoveTexture(unsigned int index) {
00333     // Quad only has one texture.
00334     if (index == 0) {
00335       TexturesSystemInterface::DestroyTexture(this->texture);
00336       
00337       this->texture = nullptr;
00338       
00339       return true;
00340     }
00341     else {
00342       LOG(LOG_PRIORITY::INFO, "Texture index out of bounds: Quad only supports 1 texture at index 0." );
00343     }
00344     
00345     return false;
00346   }
00347   
00348   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00349   void Quad::UpdateInstanceCache() {
00350     float offset_x = 0.0f;
00351     float offset_y = 0.0f;
00352     
00353     // Determine the needed offset
00354     switch (this->originLocation) {
00355       case ORIGIN::CENTER:
00356         offset_x = this->width / -2.0f;
00357         offset_y = this->height / 2.0f;
00358       break;
00359     }
00360     
00361     // Update the matrix cache
00362     this->matrix._11 = this->width;
00363     this->matrix._22 = this->height;
00364     this->matrix._41 = offset_x;
00365     this->matrix._42 = offset_y;
00366   }
00367 }