MercuryObject.cpp

Go to the documentation of this file.
00001 #include "global.h"
00002 #include "MercuryObject.h"
00003 #include "MercuryDisplay.h"
00004 #include "MercuryLog.h"
00005 
00006 MercuryObjectRegister   OBJECTREGISTER;
00007 
00008 MercuryObject::MercuryObject()
00009 :MercuryObjectBase()
00010 {
00011     m_bClone = false;
00012     m_initalized = false;
00013 }
00014 
00015 MercuryObject::MercuryObject( const MString & name )
00016 :MercuryObjectBase()
00017 {
00018     m_bClone = false;
00019     m_initalized = false;
00020     SetName(m_name);
00021 }
00022 
00023 void MercuryObject::Init()
00024 {
00025     MercuryObjectBase::Init();
00026 
00027     m_bMarkedForDestroy = false;
00028     m_hidden = false;
00029     m_pMaterial = NULL;
00030 
00031     m_modColor.m_alpha = m_modColor.m_shininess = 1.0f;
00032 
00033     m_halignment = LEFT;
00034     m_valignment = TOP;
00035     m_drawable = false;
00036     m_width = m_height = 0;
00037 
00038     m_state = LOADED;
00039 
00040     m_initalized = true;
00041 
00042     m_culled = false;
00043 
00044     m_glState.Enable(MGLS_ALL);
00045     m_inheretedGLState.Enable(MGLS_ALL);
00046 
00047     Tweening.AttachToObject( this );
00048     OBJECTREGISTER.Register( this, m_name );
00049 }
00050 
00051 MercuryObject::~MercuryObject()
00052 {
00053     OBJECTREGISTER.Unregister( m_name );
00054     /* Objects do not have to be removed when the parent is destroying
00055         because vector will do it for us */
00056 
00057     if( !m_bClone )
00058         FOREACH_Object(m_objects, i)
00059             if ( i->bAutoDelete )
00060                 SAFE_DELETE(i->pObject);
00061 
00062     m_pMaterial = NULL;
00063 }
00064 
00065 void MercuryObject::Update( const float dTime )
00066 {
00067     ASSERT_M(m_initalized,"Object '" + GetName() + "'not initialized.");
00068 
00069     if ((m_state == UNLOADED) || (dTime == 0))
00070         return;
00071 
00072     if ( m_bMarkedForDestroy )
00073     {
00074         ((MercuryObject*)m_parentObject)->RemoveObject( this );
00075         return;
00076     }
00077 
00078     WorldStack.Push();
00079 
00080     Tweening.Update( dTime );
00081 
00082     if ( !IsHidden() )
00083     {
00084         Prerender();
00085         ComputeInheritedGLState();
00086     }
00087 
00088     //We must always look for m_objects.end() because
00089     //objects can be destroyed during this call.
00090     //The post increment keeps the iterator from becoming invalid
00091     MDequeIterator<ParentHoldPair> child = m_objects.begin();
00092     while (child != m_objects.end())
00093         (child++)->pObject->Update(dTime);
00094 
00095     WorldStack.Pop();
00096 }
00097 
00098 void MercuryObject::Prerender()
00099 {
00100     //Alignment stuff
00101     switch(m_halignment)
00102     {
00103     case LEFT:
00104         SetAlignX(0);
00105         break;
00106     case CENTER:
00107         SetAlignX(-m_width / 2.0f);
00108         break;
00109     case RIGHT:
00110         SetAlignX(-(float)m_width);
00111         break;
00112     }
00113     switch(m_valignment)
00114     {
00115     case TOP:
00116         SetAlignY(0);
00117         break;
00118     case VCENTER:
00119         SetAlignY(-m_height / 2.0f);
00120         break;
00121     case BOTTOM:
00122         SetAlignY(-(float)m_height);
00123         break;
00124     }
00125 
00126     CalculateMatrices();
00127 }
00128 
00129 void MercuryObject::ComputeCull()
00130 {
00131     //This really needs to be a bottom up verses a top down approach
00132     //So we can take into account children bouning boxes.
00133     if (m_parentObject)
00134     {
00135         m_culled = ((MercuryObject*)m_parentObject)->IsCulled();
00136         if (m_culled)
00137             return;
00138     }
00139     m_culled = !DISPLAY->IsVisible( GetPosition(), GetScaledRadius(), m_finalMatrix );
00140 }
00141 
00142 void MercuryObject::ComputeInheritedGLState()
00143 {
00144     m_inheretedGLState = m_glState;
00145     if (m_parentObject)
00146         m_inheretedGLState &= ((MercuryObject*)m_parentObject)->GetInheritedGLState();
00147 }
00148 
00149 void MercuryObject::Render()
00150 {
00151     if ( IsHidden() || (m_state == UNLOADED))
00152         return;
00153 
00154     //XXX This needs to be moved to the stack unwind of update
00155     //once everything has a bounding volume.
00156     ComputeCull();
00157 
00158     if ( IsCulled() )
00159         return;
00160 
00161     if ( GetInheritedGLState().GetState(MGLS_OPAQUE) )
00162         CustomRender();
00163     else
00164         DISPLAY->AddTranslucentObject(this);
00165 
00166     MDequeIterator<ParentHoldPair> child = m_objects.begin();
00167     while (child != m_objects.end())
00168         (child++)->pObject->Render();
00169 }
00170 
00171 void MercuryObject::CustomRender()
00172 {
00173     if (m_fVisRadius > 0)
00174         DISPLAY->FindLights(m_finalMatrix, m_fVisRadius);
00175 
00176     //Skip expensive steps in things that don't have anything to draw
00177     //(pretty much any non mesh)
00178     if (m_drawable)
00179     {
00180         DISPLAY->SetStates( GetInheritedGLState() );
00181         DISPLAY->EnableShaders(m_pMaterial);
00182         DISPLAY->EnableTextures(m_pMaterial);
00183 
00184         DISPLAY->SetMaterial(&m_finalMaterial);
00185 
00186         Draw();
00187     }
00188 }
00189 
00190 void MercuryObject::AddObject(MercuryObject* object, bool bParentDelete)
00191 {
00192     ASSERT(object->m_initalized);
00193 
00194     ParentHoldPair c;
00195     c.bAutoDelete = bParentDelete;
00196     c.pObject = object;
00197 
00198     m_objects.push_back(c);
00199     object->SetParentObject(this);
00200 
00201     //I think we can do the sorting on insert in log(n)
00202     SortDrawOrder();
00203 
00204     //child needs to inheret colors from parent
00205     object->CalculateRealColor();
00206 }
00207 
00208 void MercuryObject::SetDrawOrder(int order)
00209 {
00210     MercuryObjectBase::SetDrawOrder(order);
00211 
00212     //I think we can also do this in log(n) vs linear
00213     if (m_parentObject)
00214         ((MercuryObject*)m_parentObject)->SortDrawOrder();
00215 }
00216 
00217 void MercuryObject::SortDrawOrder()
00218 {
00219     TSortDrawOrder(m_objects);
00220 }
00221 
00222 #include "MercuryObjectFactory.h"
00223 
00224 CLASS_FUNCTION_VOID_NOARGS( MercuryObject, Destroy );
00225 CLASS_FUNCTION_VOID_ONEARG( MercuryObject, SetName, TYPECASTMSTRING , const char * );
00226 CLASS_FUNCTION_VOID_TWOARGS( MercuryObject, AddObject, (MercuryObject*)(void*), void *, (bool), bool );
00227 CLASS_FUNCTION_TWOARGS( MercuryObject, RemoveObject, bool, (MercuryObject*)(void*), void *, (bool), bool );
00228 CLASS_FUNCTION_VOID_ONEARG( MercuryObject, SetMaterial, (MercuryMaterial*)(void*), MercuryMaterial* );
00229 CLASS_FUNCTION_VOID_FOURARGS( MercuryObject, SetDiffusef, (float), float, (float), float, (float), float, (float), float );
00230 CLASS_FUNCTION_VOID_FOURARGS( MercuryObject, SetSpecularf, (float), float, (float), float, (float), float, (float), float );
00231 CLASS_FUNCTION_VOID_FOURARGS( MercuryObject, SetEmissivef, (float), float, (float), float, (float), float, (float), float );
00232 CLASS_FUNCTION_VOID_FOURARGS( MercuryObject, SetAmbientf, (float), float, (float), float, (float), float, (float), float );
00233 CLASS_FUNCTION_NOARGS( MercuryObject, GetName, const char * );
00234 CLASS_FUNCTION_NOARGS( MercuryObject, GetMaterial, const MercuryMaterial * );
00235 //CLASS_FUNCTION_VOID_FOURARGS( MercuryObject, GetDiffusef, (float), float &, (float), float &, (float), float &, (float), float& );
00236 CLASS_FUNCTION_THREEARGS( MercuryObject, Spawn, MercuryObject*,TYPECASTMSTRING , const char *, TYPECASTMSTRING, const char *, (PROJECTIONTYPE)(int), int );
00237 CLASS_FUNCTION_NOARGS( MercuryObject, GetNumChildren, int );
00238 CLASS_FUNCTION_NOARGS( MercuryObject, GetHAlignment, int );
00239 CLASS_FUNCTION_VOID_ONEARG( MercuryObject, SetHAlignment, (MercuryObject::HALIGN)(int), int );
00240 CLASS_FUNCTION_NOARGS( MercuryObject, GetVAlignment, int );
00241 CLASS_FUNCTION_VOID_ONEARG( MercuryObject, SetVAlignment, (MercuryObject::VALIGN)(int), int );
00242 
00243 PSElement PS_MercuryObject_FinishTweening( MercuryCommandHandler * pThs, const PStack & pParameters )
00244 {
00245     ((MercuryObject*)pThs)->Tweening.FinishTweening();
00246     return PSElement();
00247 }
00248 RUN_STATEMENT_AT_BOOT( REGISTER_MercuryObject_FinishTweening, MercuryObjectFactory::GetInstance().RegisterFunction( &PS_MercuryObject_FinishTweening, "MercuryObject", "FinishTweening" ); )
00249 EXPORTPREFIX void HGEXPORT MercuryObject_FinishTweening( void * pThs )
00250 {
00251     ((MercuryObject*)pThs)->Tweening.FinishTweening(); 
00252 } EXPORTSUFFIX
00253 
00254 
00255 PSElement PS_MercuryObject_StopTweening( MercuryCommandHandler * pThs, const PStack & pParameters )
00256 {
00257     ((MercuryObject*)pThs)->Tweening.StopTweening();
00258     return PSElement();
00259 }
00260 RUN_STATEMENT_AT_BOOT( REGISTER_MercuryObject_StopTweening, MercuryObjectFactory::GetInstance().RegisterFunction( &PS_MercuryObject_StopTweening, "MercuryObject", "StopTweening" ); )
00261 EXPORTPREFIX void HGEXPORT MercuryObject_StopTweening( void * pThs )
00262 {
00263     ((MercuryObject*)pThs)->Tweening.StopTweening(); 
00264 } EXPORTSUFFIX
00265 
00266 
00267 PSElement PS_MercuryObject_AddCommand( MercuryCommandHandler * pThs, const PStack & pParameters )
00268 {
00269     ((MercuryObject*)pThs)->Tweening.AddCommand( pParameters.PeekItem(0), (MercuryTweenState::SPACE)(int)pParameters.PeekItem(1), pParameters.PeekItem(2) );
00270     return PSElement();
00271 }
00272 RUN_STATEMENT_AT_BOOT( REGISTER_MercuryObject_AddCommand, MercuryObjectFactory::GetInstance().RegisterFunction( &PS_MercuryObject_AddCommand, "MercuryObject", "AddCommand" ); )
00273 EXPORTPREFIX void HGEXPORT MercuryObject_AddCommand( void * pThs, const char * p1, int p2, const char * p3 )
00274 { 
00275     ((MercuryObject*)pThs)->Tweening.AddCommand( p1, (MercuryTweenState::SPACE) p2, p3 );
00276 } EXPORTSUFFIX
00277 
00278 
00279 void MercuryObject::SetName( const MString& name )
00280 {
00281     OBJECTREGISTER.Unregister( m_name );
00282     m_name=name;
00283     OBJECTREGISTER.Register( this, m_name );
00284 }
00285 
00286 bool MercuryObject::ReplaceObject(MercuryObject* object, MercuryObject* newobject)
00287 {
00288     ASSERT(object->m_initalized);
00289 
00290     FOREACH_Object(m_objects, i)
00291         if (i->pObject == object)
00292         {
00293             i->pObject->SetParentObject(NULL);
00294             i->pObject = newobject;
00295 
00296             i->pObject->SetParentObject(this);
00297             //I think we can do the sorting on insert in log(n)
00298             SortDrawOrder();
00299             //child needs to inheret colors from parent
00300             i->pObject->CalculateRealColor();
00301             return true;
00302         }
00303 
00304     return false;
00305 }
00306 
00307 bool MercuryObject::RemoveObject(MercuryObject* object, bool bAllowDelete )
00308 {
00309     FOREACH_Object(m_objects, i)
00310         if (i->pObject == object)
00311         {
00312             i->pObject->SetParentObject(NULL);
00313 
00314             if (i->bAutoDelete && bAllowDelete && !m_bClone )
00315                 SAFE_DELETE( i->pObject );
00316 
00317             i->pObject = NULL;
00318             m_objects.erase(i);
00319             return true;
00320         }
00321 
00322     return false;
00323 }
00324 
00325 void MercuryObject::CalculateRealColor()
00326 {
00327     m_realColor = m_modColor;
00328 
00329     if (m_parentObject != NULL)
00330         m_realColor *= ((MercuryObject*)m_parentObject)->m_realColor;
00331 
00332     m_finalMaterial = m_realColor;
00333 
00334     if (m_pMaterial != NULL)
00335         m_finalMaterial *= *m_pMaterial;
00336 
00337     //Calculate color recursively
00338     FOREACH_Object(m_objects, child)
00339         child->pObject->CalculateRealColor();
00340 }
00341 
00342 MercuryObject * MercuryObject::Spawn( const MString & sClass, const MString & sName, PROJECTIONTYPE projection )
00343 {
00344     MercuryObject * pObject = MercuryObjectFactory::GetInstance().GenerateObject( sClass, sName );
00345     if ( pObject == NULL )
00346         return false;
00347 
00348     pObject->Init();
00349     
00350     AddObject( pObject, true );
00351     return pObject;
00352 }
00353 
00354 MercuryObjectRegister::MercuryObjectRegister()
00355 :NOTFOUND(-5280) //Charles's magic number >:-(
00356 {
00357     if ( !MESSAGEMAN )
00358         MESSAGEMAN = new MercuryMessageManager;
00359     MESSAGEMAN->Subscribe( "ObjectStopTweening", MercuryCallback( SendCompiledMessage, (void*)1 ) );
00360     MESSAGEMAN->Subscribe( "ObjectFinishTweening", MercuryCallback( SendCompiledMessage, (void*)2 ) );
00361     MESSAGEMAN->Subscribe( "ObjectAddCommand", MercuryCallback( SendCompiledMessage, (void*)3 ) );
00362     MESSAGEMAN->Subscribe( "LogAllObjects", MercuryCallback( SendCompiledMessage, (void*)4 ) );
00363 }
00364 
00365 void MercuryObjectRegister::Register( MercuryObject * obj, const MString & name )
00366 {
00367     m_mObjects[name] = obj;
00368     if ( GetCountOfObject( name ) == NOTFOUND )
00369         m_mObjectCounts[name]=1;
00370     else
00371         ++m_mObjectCounts[name];
00372 }
00373 
00374 void MercuryObjectRegister::Unregister( const MString & name )
00375 {
00376     if ( --m_mObjectCounts[name] == 0 )
00377         m_mObjectCounts.remove( name );
00378     m_mObjects.remove( name );
00379 }
00380 
00381 MercuryObject * MercuryObjectRegister::GetObjectFromName( const MString & name )
00382 {
00383     MercuryObject ** ret = m_mObjects.get( name );
00384     if( ret )
00385         return *ret;
00386     else
00387         return NULL;
00388 }
00389 
00390 void MercuryObjectRegister::SendCompiledMessage( const MString &message, void * data, PStack & info )
00391 {
00392     switch ( (MVPtr)data )
00393     {
00394     case 4:
00395         {
00396             LOG.Info( "Logging all currently created objects." );
00397             LOG.Info( ssprintf( "Current noname allocations: %d", GetCountOfObject( "" ) ) );
00398             LOG.Info( "Memory Address:ObjectName Count" );
00399             MVector< MString > vNames;
00400             OBJECTREGISTER.m_mObjects.VectorIndicies( vNames );
00401             for( unsigned int i = 0; i < vNames.size(); i++ )
00402                 LOG.Info( ssprintf( "%X:%s  %d", OBJECTREGISTER.m_mObjects[vNames[i]], vNames[i].c_str(), GetCountOfObject( vNames[i] ) ) );
00403         }
00404         return;
00405     }
00406 
00407     MString sObjectName = info.PopItem().GetValueS();
00408     MercuryObject * res;
00409 
00410     res = OBJECTREGISTER.GetObjectFromName( sObjectName );
00411 
00412     if ( !res )
00413         return;
00414 
00415     switch ( (MVPtr)data )
00416     {
00417     case 1:
00418         res->Tweening.StopTweening();
00419         break;
00420     case 2:
00421         res->Tweening.FinishTweening();
00422         break;
00423     case 3:
00424         res->Tweening.AddCommand( info.PopItem().GetValueS() );
00425         break;
00426     }
00427 }
00428 
00429 int MercuryObjectRegister::GetCountOfObject( const MString & name )
00430 {
00431     if( m_mObjectCounts.get( name ) )
00432         return *(m_mObjectCounts.get( name ));
00433     else
00434         return 0;
00435 }
00436 
00437 void MercuryObjectRegister::ShutDown()
00438 {
00439     m_mObjects.clear();
00440     m_mObjectCounts.clear();
00441 }
00442 long HGEXPORT GetObjectByName( const char * sName )
00443 {
00444     return (long)OBJECTREGISTER.GetObjectFromName( sName );
00445 }
00446 
00447 REGISTER_OBJECT_TYPE( MercuryObject );
00448 
00449 MHash< MercuryObject * >    MercuryObjectRegister::m_mObjects;
00450 MHash< int >                MercuryObjectRegister::m_mObjectCounts;
00451 
00452 /* 
00453  * Copyright (c) 2005-2006, Joshua Allen, Charles Lohr
00454  * All rights reserved.
00455  *
00456  * Redistribution and use in source and binary forms, with or
00457  * without modification, are permitted provided that the following
00458  * conditions are met:
00459  *  -   Redistributions of source code must retain the above
00460  *      copyright notice, this list of conditions and the following disclaimer.
00461  *  -   Redistributions in binary form must reproduce the above copyright
00462  *      notice, this list of conditions and the following disclaimer in
00463  *      the documentation and/or other materials provided with the distribution.
00464  *  -   Neither the name of the Mercury Engine nor the names of its
00465  *      contributors may be used to endorse or promote products derived from
00466  *      this software without specific prior written permission.
00467  *
00468  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00469  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00470  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00471  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00472  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00473  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00474  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00475  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00476  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00477  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00478  */

Hosted by SourceForge.net Logo