NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
RenderModule.cpp
Go to the documentation of this file.
00001 
00012 #include <cassert>
00013 
00014 #include <windows.h>
00015 #include <d3d9.h>
00016 #include <boost/foreach.hpp>
00017 
00018 #include "RenderModule.h"
00019 #include "../sharedbase/EventLogger.h"
00020 #include "../sharedbase/PropertyMap.h"
00021 #include "../sharedbase/Entity.h"
00022 #include "../sharedbase/MessageRouter.h"
00023 #include "../sharedbase/Envelope.h"
00024 
00025 #include "component/RenderableComponent.h"
00026 #include "component/CameraComponent.h"
00027 
00028 #include "InterfaceUpdateable.h"
00029 
00030 #include "GlobalPropertyNames.h"
00031 #include "Messages.h"
00032 #include "Types.h"
00033 
00034 #ifndef _WIN32
00035 #define sprintf_s sprintf
00036 #endif
00037 
00038 namespace GraphicsCore {
00039   /* * * * * * * * * * * * * * * * * * * * * */
00040   // Create the static data
00041   /* * * * * * * * * * * * * * * * * * * * * */
00042   RenderModule* RenderModule::currentRenderModule;
00043   
00044   /* * * * * * * * * * * * * * * * * * * * * */
00045   // Create the local consts and globals
00046   /* * * * * * * * * * * * * * * * * * * * * */
00047   const D3DXVECTOR3 UP_DIRECTION = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
00048   
00049   const D3DFILLMODE DEFAULT_FILLMODE = D3DFILL_SOLID;
00050   const float DEFAULT_RENDER_DELAY = 1.0f / 30.0f;
00051   
00052   const Color BLACK = Color(0.0f, 0.0f, 0.0f, 1.0f);
00053   const Color WHITE = Color(1.0f, 1.0f, 1.0f, 1.0f);
00054   
00055   float AspectRatio, AspectRatioInv;
00056 
00057   RenderModule::RenderModule(PropertyMap* gprops, MessageRouter* msgrouter) :
00058       ModuleInterface(gprops, msgrouter) {
00059     assert(this->gprops != nullptr);
00060     assert(this->msgrouter != nullptr);
00061     
00062     assert(RenderModule::GetRenderModule() == nullptr); // Enforce the one-instance-only rule of a singleton, but leave the class publicly initializable.
00063     RenderModule::SetRenderModule(this);
00064     
00065     /* * * * * * * * * * * * * * * * * * * * * */
00066     // Create the global properties
00067     /* * * * * * * * * * * * * * * * * * * * * */
00068     // Screen size
00069     this->gprops->SetProperty(GP_WINDOW_WIDTH, GP_WINDOW_WIDTH_DEF);
00070     this->gprops->SetProperty(GP_WINDOW_HEIGHT, GP_WINDOW_HEIGHT_DEF);
00071     
00072     this->gprops->SetProperty(GP_CLIENT_WIDTH, GP_CLIENT_WIDTH_DEF);
00073     this->gprops->SetProperty(GP_CLIENT_HEIGHT, GP_CLIENT_HEIGHT_DEF);
00074     this->gprops->SetProperty(GP_CLIENT_ASPECT, GP_CLIENT_ASPECT_DEF);
00075     this->gprops->SetProperty(GP_CLIENT_ASPECT_INV, 1.0f / this->gprops->GetPropertyValue<float>(GP_CLIENT_ASPECT));
00076     
00077     // Clear color
00078     this->gprops->SetProperty(GP_GRAPHICS_PAUSE, GP_GRAPHICS_PAUSE_DEF);
00079     
00080     // Clear color
00081     this->gprops->SetProperty(GP_CLEAR_COLOR, GP_CLEAR_COLOR_DEF);
00082     
00083     // Anisotropic filtering
00084     this->gprops->SetProperty(GP_ANISOTROPIC_FILTERING, GP_ANISOTROPIC_FILTERING_DEF);
00085     
00086     // Fog
00087     this->gprops->SetProperty(GP_FOG_ENABLED, GP_FOG_ENABLED_DEF);
00088     this->gprops->SetProperty(GP_FOG_COLOR, GP_FOG_COLOR_DEF);
00089     this->gprops->SetProperty(GP_FOG_MODE, GP_FOG_MODE_DEF);
00090     this->gprops->SetProperty(GP_FOG_RANGE_NEAR, GP_FOG_RANGE_NEAR_DEF);
00091     this->gprops->SetProperty(GP_FOG_RANGE_FAR, GP_FOG_RANGE_FAR_DEF);
00092     this->gprops->SetProperty(GP_FOG_RANGE_DENSITY, GP_FOG_RANGE_DENSITY_DEF);
00093     
00094     /* * * * * * * * * * * * * * * * * * * * * */
00095     // Define the local globals
00096     /* * * * * * * * * * * * * * * * * * * * * */
00097     AspectRatio = this->gprops->GetPropertyValue<float>(GP_CLIENT_ASPECT);
00098     AspectRatioInv = this->gprops->GetPropertyValue<float>(GP_CLIENT_ASPECT_INV);
00099     
00100     /* * * * * * * * * * * * * * * * * * * * * */
00101     // Define the instance properties
00102     /* * * * * * * * * * * * * * * * * * * * * */
00103     // DX
00104     this->pD3D = nullptr;
00105     this->pd3dDevice = nullptr;
00106     
00107     // Camera
00108     this->currentCamera = nullptr;
00109     this->currentCameraName.assign("");
00110     
00111     // Render
00112     this->fillMode = DEFAULT_FILLMODE;
00113     this->renderDelay = DEFAULT_RENDER_DELAY;
00114     
00115     /* * * * * * * * * * * * * * * * * * * * * */
00116     // Register the event handlers
00117     /* * * * * * * * * * * * * * * * * * * * * */
00118     this->RegisterListeners();
00119     
00120     
00121     /* * * * * * * * * * * * * * * * * * * * * */
00122     // Notify loading success
00123     /* * * * * * * * * * * * * * * * * * * * * */
00124     {
00125       EnvelopeSPTR e(new Envelope);
00126       e->msgid = ACK_LOAD_GRAPHICS;
00127       this->msgrouter->SendSP(e);
00128     }
00129   }
00130 
00131   RenderModule::~RenderModule(void) {
00132     assert(this->myRenderableComponents.empty());
00133     assert(this->cameraComponents.empty());
00134     assert(this->renderableComponents.empty()); // At this stage, all renderable components should have been cleared via their destructors.
00135     // If this last assert fired, then some other core did not destroy the RenderableComponents it instantiated before this destructor was called.
00136     
00137     // The below should be null if this object is being destroyed, via the Shutdown method.
00138     assert(this->pD3D == nullptr);
00139     assert(this->pd3dDevice == nullptr);
00140   }
00141 
00142   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00143   bool RenderModule::RegisterComponent(RenderableComponent* renderableComponent) {
00144     std::pair<std::set<RenderableComponent*>::iterator, bool> result;
00145     
00146     assert(renderableComponent != nullptr);
00147     
00148     Threading::WriteLock w_lock(this->renderableComponentsMutex);
00149     
00150     result = this->renderableComponents.insert(renderableComponent);
00151 
00152     return result.second; // the second value is true if, and only if, the element was inserted.
00153   }
00154 
00155   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00156   bool RenderModule::UnregisterComponent(RenderableComponent* renderableComponent) {
00157     int num_removed;
00158 
00159     assert(renderableComponent != nullptr);
00160     
00161     Threading::WriteLock w_lock(this->renderableComponentsMutex);
00162     
00163     num_removed = this->renderableComponents.erase(renderableComponent); // This will fail on RenderModule shutdown, but by then it doesn't make a difference.
00164 
00165     return (num_removed > 0);
00166   }
00167 
00168   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00169   bool RenderModule::RegisterUpdateable(InterfaceUpdateable* updateableObject) {
00170     std::pair<std::set<InterfaceUpdateable*>::iterator, bool> result;
00171     
00172     assert(updateableObject != nullptr);
00173     
00174     Threading::WriteLock w_lock(this->updateableObjectsMutex);
00175     
00176     result = this->updateableObjects.insert(updateableObject);
00177     
00178     return result.second; // the second value is true if, and only if, the element was inserted.
00179   }
00180 
00181   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00182   bool RenderModule::UnregisterUpdateable(InterfaceUpdateable* updateableObject) {
00183     int num_removed;
00184     
00185     assert(updateableObject != nullptr);
00186     
00187     Threading::WriteLock w_lock(this->updateableObjectsMutex);
00188     
00189     num_removed = this->updateableObjects.erase(updateableObject); // This will fail on RenderModule shutdown, but by then it doesn't make a difference.
00190     
00191     return (num_removed > 0);
00192   }
00193 
00194   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00195   void RenderModule::Render() {
00196     static D3DXMATRIX matrixProj, matrixView, matrixOrtho, matrix;
00197     static D3DXVECTOR3 cameraLookAt, cameraPosition;
00198     
00199     if (this->pd3dDevice == nullptr) { // Did you make sure Startup was called?
00200       return;
00201     }
00202 
00203     // Set fill mode
00204     this->pd3dDevice->SetRenderState(D3DRS_FILLMODE, this->fillMode);
00205     
00206     // Enable lighting
00207     this->pd3dDevice->SetRenderState(D3DRS_LIGHTING, true);
00208     this->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
00209     
00210     // Activate depth buffer
00211     this->pd3dDevice->SetRenderState(D3DRS_ZENABLE, true);
00212     this->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
00213     
00214     // Activate texture filtering on texture 0
00215     // *TODO: Make the texture levels configurable via script - probably via some form of advanced script-controllable shader system.
00216     {
00217       unsigned int aniso_level = this->gprops->GetPropertyValue<unsigned int>(GP_ANISOTROPIC_FILTERING);
00218       if (aniso_level <= 0) {
00219         aniso_level = 1; // 1 means disabled, 0 is invalid.
00220       }
00221       
00222       this->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
00223       this->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
00224       this->pd3dDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, aniso_level);
00225     }
00226     
00227     // Activate alpha-blending
00228     {
00229       this->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
00230       //D3DTSS_COLORARG1 is set to D3DTA_TEXTURE which means that colour1 is
00231       //entirely taken from the texture and nothing else.
00232       this->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
00233       
00234       //The next 2 RenderStates determine how the blending is done.
00235       //The source is our object, destination is the drawing surface.
00236       //SRCBLEND specifies that the final color should be 50% (because
00237       //that's what we set our source alpha to) from our source and 50%
00238       //(INVSRCALPHA, 100%-SRCALPHA(50% in this case))
00239       this->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
00240       this->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
00241 
00242       //This enables Alpha Blending
00243       this->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
00244     }
00245     
00246     // Set up fog
00247     {
00248       bool fog_enabled = this->gprops->GetPropertyValue<bool>(GP_FOG_ENABLED);
00249       
00250       if (fog_enabled) {
00251         unsigned long fog_color = (unsigned long) this->gprops->GetPropertyValue<Color>(GP_FOG_COLOR);
00252         unsigned int fog_mode = this->gprops->GetPropertyValue<unsigned int>(GP_FOG_MODE);
00253         float fog_range_near = this->gprops->GetPropertyValue<float>(GP_FOG_RANGE_NEAR);
00254         float fog_range_far = this->gprops->GetPropertyValue<float>(GP_FOG_RANGE_FAR);
00255         float fog_range_density = this->gprops->GetPropertyValue<float>(GP_FOG_RANGE_DENSITY);
00256         
00257         // Enable fog blending.
00258         this->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, true);
00259      
00260         // Set the fog color.
00261         this->pd3dDevice->SetRenderState(D3DRS_FOGCOLOR, fog_color);
00262         
00263         // Set fog parameters.
00264         this->pd3dDevice->SetRenderState(D3DRS_FOGTABLEMODE, fog_mode);
00265         
00266         if (fog_mode == D3DFOG_LINEAR) {
00267           this->pd3dDevice->SetRenderState(D3DRS_FOGSTART, *(unsigned long *)(&fog_range_near));
00268           this->pd3dDevice->SetRenderState(D3DRS_FOGEND,   *(unsigned long *)(&fog_range_far));
00269         }
00270         else {
00271           this->pd3dDevice->SetRenderState(D3DRS_FOGDENSITY, *(unsigned long *)(&fog_range_density));
00272         }
00273       }
00274     }
00275     
00276     { // Clear the backbuffer to the specified color
00277       Color clear_color = this->gprops->GetPropertyValue<Color>(GP_CLEAR_COLOR);
00278       
00279       this->pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_color, 1.0f, 0);
00280     }
00281     
00282     // Open a scene for rendering
00283     if (SUCCEEDED(this->pd3dDevice->BeginScene())) {
00284       Threading::ReadLock r_lock(this->currentCameraMutex);
00285       
00286       // Verify active camera, no rendering perspective-space objects otherwise.
00287       if (this->currentCamera) {
00288         /* * * * * * * * * * * * * * * * * */
00289         // Set the perspective camera in the 3D world
00290         /* * * * * * * * * * * * * * * * * */
00291 
00292         // Clear any ambient light left-overs.
00293         this->pd3dDevice->SetRenderState(D3DRS_AMBIENT, BLACK);
00294         
00295         float fovy = this->currentCamera->GetFov() * AspectRatioInv; // calculate the vertical FOV from the horizontal FOV stored in the camera.
00296 
00297         // Set the projection transformation
00298         D3DXMatrixIdentity(&matrixProj);
00299         D3DXMatrixPerspectiveFovLH(&matrixProj, fovy, AspectRatio, this->currentCamera->GetNearClipRange(), this->currentCamera->GetFarClipRange());
00300         this->pd3dDevice->SetTransform(D3DTS_PROJECTION, &matrixProj);
00301         
00302         // Set the view transformation
00303         D3DXMatrixIdentity(&matrixView);
00304         
00305         // Calculate the camera's world position
00306         cameraPosition = this->currentCamera->GetOffset(); // Get and rotate the offset
00307         RotateVectorByQuaternion(&cameraPosition, &cameraPosition, &(this->currentCamera->GetOwner()->GetWorldRotation()));
00308         cameraPosition += this->currentCamera->GetOwner()->GetWorldPosition();
00309         
00310         // Calculate a lookat based on rotation of camera and a unit vector
00311         cameraLookAt = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
00312         RotateVectorByQuaternion(&cameraLookAt, &cameraLookAt, &(this->currentCamera->GetRotation() * this->currentCamera->GetOwner()->GetWorldRotation()));
00313         cameraLookAt += cameraPosition; // the look at position is naturally relative to the camera, so add the camera's position to adjust to world coordinates.
00314 
00315         D3DXMatrixLookAtLH(
00316           &matrixView,
00317           &cameraPosition, // Camera Position
00318           &cameraLookAt, // Look At Position
00319           &UP_DIRECTION // Up Direction
00320         );
00321         this->pd3dDevice->SetTransform(D3DTS_VIEW, &matrixView);
00322         
00323         // Render the 3D world space
00324         
00325         // Clear the matrices
00326         D3DXMatrixIdentity(&matrix);
00327         
00328         // Set the world transformation
00329         this->pd3dDevice->SetTransform(D3DTS_WORLD, &matrix);
00330         
00331         this->RenderObjectInSpace(CS_WORLD);
00332       }
00333 
00334       {
00335         /* * * * * * * * * * * * * * * * * */
00336         // Set the orthographic camera for the 2D world of the HUD
00337         /* * * * * * * * * * * * * * * * * */
00338         
00339         // Set up the ambient light for the HUD that makes everything visible without having to resort to emissive surfaces.
00340         this->pd3dDevice->SetRenderState(D3DRS_AMBIENT, WHITE);
00341         
00342         // Clear the fog
00343         this->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
00344         
00345         // Clear the Z Buffer so that world objects don't clip through screen objects.
00346         this->pd3dDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
00347         
00348         // Clear the matrices
00349         D3DXMatrixIdentity(&matrixOrtho);
00350         D3DXMatrixIdentity(&matrixView);
00351         D3DXMatrixIdentity(&matrix);
00352         
00353         // Camera is facing the X-Y plane, such that 
00354         //  <0,0,0> is in the upper left of the window and
00355         //  X=1 is at the right-most position of the screen.
00356         D3DXMatrixOrthoOffCenterLH(&matrixOrtho, 0.0f, 1.0f, -AspectRatioInv, 0.0f, -100.0f, 100.0f);
00357         this->pd3dDevice->SetTransform(D3DTS_PROJECTION, &matrixOrtho);
00358         
00359         // Clear the view matrix
00360         this->pd3dDevice->SetTransform(D3DTS_VIEW, &matrixView);
00361         
00362         // Set the world transformation
00363         this->pd3dDevice->SetTransform(D3DTS_WORLD, &matrix);
00364         
00365         // Render the 2D HUD space
00366         this->RenderObjectInSpace(CS_SCREEN);
00367       }
00368       
00369       this->pd3dDevice->EndScene();
00370     }
00371     
00372     // Present the backbuffer contents to the display
00373     this->pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr);
00374   }
00375 
00376   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00377   void RenderModule::RenderObjectInSpace(ECoordinateSpace space) {
00378     static D3DXMATRIX matrix;
00379     static const D3DMATRIX UNIT_MATRIX = {
00380       1.0f, 0.0f, 0.0f, 0.0f,
00381       0.0f, 1.0f, 0.0f, 0.0f,
00382       0.0f, 0.0f, 1.0f, 0.0f,
00383       0.0f, 0.0f, 0.0f, 1.0f
00384     };
00385 
00386     float scale;
00387     
00388     Threading::ReadLock r_lock(this->renderableComponentsMutex);
00389     
00390     BOOST_FOREACH(RenderableComponent * component, this->renderableComponents) {
00391       if (component->GetCoordSpace() == space) {
00392         EntitySPTR owner(component->GetOwner());
00393         assert(owner.get() != nullptr); // There MUST be an owning entity for any component.
00394         
00395         scale = owner->GetWorldScale();
00396         if (fabs(scale) <= 0.000001f) { // 0 (or way too close to it) is not a valid scale.  Negative is fine though!
00397           char temp[57]; // 57 is the count of numerals in the number computed from pow(2, 64) + 1 (The +1 is for the null terminator.)
00398           sprintf_s(temp, "%u", owner->GetId());
00399           LOG(LOG_PRIORITY::ERR, "Entity '" + std::string(temp) + "' has an invalid calculated 'world' scale: scale must be non-zero and positive!");
00400           continue;
00401         }
00402         
00403         D3DXMatrixTransformation(&matrix, nullptr, nullptr, &D3DXVECTOR3(scale, scale, scale), nullptr, &(owner->GetWorldRotation()), &(owner->GetWorldPosition()));
00404         
00405         this->pd3dDevice->SetTransform(D3DTS_WORLD, &matrix);
00406         
00407         this->pd3dDevice->SetMaterial(&BLANK_MATERIAL);
00408         this->pd3dDevice->SetTexture(0, nullptr);
00409         this->pd3dDevice->SetTransform(D3DTS_TEXTURE0, &UNIT_MATRIX);
00410         
00411         component->Render(this->pd3dDevice);
00412       }
00413     }
00414   }
00415 
00416   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00417   // Update is treated as a render call in this class
00418   // Called each game update with change in time (dt) in seconds since last update
00419   void RenderModule::Update(double dt) {
00420     this->deltaAccumulator += dt;
00421     
00422     if (this->deltaAccumulator >= this->renderDelay) {
00423       if (!this->gprops->GetPropertyValue<bool>(GP_GRAPHICS_PAUSE)) {
00424         Threading::WriteLock w_lock(this->updateableObjectsMutex);
00425         
00426         BOOST_FOREACH(InterfaceUpdateable* updateable, this->updateableObjects) {
00427           updateable->Update(this->deltaAccumulator);
00428         }
00429       }
00430 
00431       this->Render();
00432       this->deltaAccumulator = 0.0;
00433     }
00434   }
00435 
00436   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00437   bool RenderModule::Resize() {
00438     // Function contents in part copied from provided code from previous coursework.
00439     
00440     unsigned int clientWidth, clientHeight;
00441     HWND hwnd;
00442     
00443     // Get hwnd
00444     if (!this->gprops->PropertyExists(GP_HWND)) {
00445       LOG(LOG_PRIORITY::ERR, "No hwnd global property found!");
00446       return false;
00447     }
00448     try {
00449       hwnd = boost::any_cast < HWND > (this->gprops->GetProperty(GP_HWND));
00450     }
00451     catch (const boost::bad_any_cast & e) {
00452       e; // ignore the "unreferenced local variable" warning by faking its use here.
00453       LOG(LOG_PRIORITY::CONFIG, "hwnd global property found, but of wrong type!");
00454       return false;
00455     }
00456 
00457     // Get screen width and height from the hwnd, and store in gprops
00458     RECT clientArea;
00459     GetClientRect(hwnd, &clientArea);
00460     
00461     clientWidth = clientArea.right - clientArea.left;
00462     clientHeight = clientArea.bottom - clientArea.top;
00463     
00464     this->gprops->SetProperty(GP_CLIENT_WIDTH, clientWidth);
00465     this->gprops->SetProperty(GP_CLIENT_HEIGHT, clientHeight);
00466     
00467     // Set the presentation parameters
00468     ZeroMemory(&this->d3dpp, sizeof(this->d3dpp));
00469     this->d3dpp.Windowed = TRUE;
00470     this->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
00471     this->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
00472     this->d3dpp.BackBufferCount = 1;
00473     this->d3dpp.BackBufferHeight = clientHeight;
00474     this->d3dpp.BackBufferWidth = clientWidth;
00475     this->d3dpp.hDeviceWindow = hwnd;
00476     this->d3dpp.EnableAutoDepthStencil = TRUE;
00477     this->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
00478     
00479     // Initialize the D3D device
00480     if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &this->d3dpp, &pd3dDevice))) {
00481       LOG(LOG_PRIORITY::SYSERR, "Unable to create the Direct3D device!");
00482       return false;
00483     }
00484 
00485     // Disable lighting
00486     pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
00487     
00488     return true;
00489   }
00490 
00491   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00492   // Called to initialize the core
00493   void RenderModule::Startup(EnvelopeSPTR envelope) {
00494     bool status = false;
00495     
00496     // Init DX
00497     if (nullptr == (pD3D = Direct3DCreate9(D3D_SDK_VERSION))) {
00498       LOG(LOG_PRIORITY::SYSERR, "Unable to create Direct3D object!");
00499       return;
00500     }
00501 
00502     // Set the buffer size
00503     status = this->Resize();
00504     
00505     // Zero the accumulator
00506     this->deltaAccumulator = 0.0f;
00507     
00508     // Un-register from the startup message, as there's no need to start again.
00509     {
00510       std::shared_ptr<Subscriber> handler(new Subscriber(boost::bind(&RenderModule::Startup, this, _1)));
00511       this->msgrouter->Unsubscribe(MSG_START_GRAPHICS, handler);
00512     }
00513     
00514     // Send notification that the module is started.
00515     {
00516       EnvelopeSPTR e(new Envelope);
00517       e->msgid = ACK_START_GRAPHICS;
00518       e->AddData(status);
00519       this->msgrouter->SendSP(e);
00520     }
00521     
00522     LOG(LOG_PRIORITY::INFO, "GraphicsDX9 started.");
00523     
00524     return;
00525   }
00526 
00527   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00528   // Called to shutdown the core
00529   void RenderModule::Shutdown(EnvelopeSPTR envelope) {
00530     {
00531       // Delete the cameras
00532       Threading::WriteLock w_lock(this->cameraComponentsMutex);
00533       
00534       for (
00535       cameramap::left_const_iterator it = this->cameraComponents.left.begin();
00536           it != this->cameraComponents.left.end();
00537           ++it
00538           ) {
00539         CameraComponent* cam = (*it).second;
00540         delete cam;
00541       }
00542       this->cameraComponents.clear(); // note that this doesn't delete pointer-based objects on its own, so the above does the job.
00543     }
00544     
00545     {
00546       // Delete the renderable components that were instantiated locally.
00547       // After all, if I didn't instantiate it, then deleting it would be a violation of RAII.
00548       Threading::WriteLock w_lock(this->myRenderableComponentsMutex);
00549       
00550       BOOST_FOREACH(RenderableComponent * comp, this->myRenderableComponents) {
00551         delete comp;
00552       }
00553       this->myRenderableComponents.clear();
00554     }
00555     
00556     //this->renderableComponents // now contains only pointers to objects owned by other people. (Mine were cleared via their destructors by the above)
00557     
00558     {
00559       // Invalidate the pointer to the active camera
00560       Threading::WriteLock w_lock(this->currentCameraMutex);
00561       
00562       this->currentCamera = nullptr;
00563     }
00564     
00565     if (pd3dDevice != nullptr) {
00566       pd3dDevice->Release();
00567       pd3dDevice = nullptr;
00568     }
00569     
00570     if (pD3D != nullptr) {
00571       pD3D->Release();
00572       pD3D = nullptr;
00573     }
00574   }
00575 }