00001
00002
00003
00004
00005
00006
00007 #ifdef WIN32
00008 #include "WindowsIncludes.h"
00009 #else
00010 #define HWND void*
00011 #endif
00012
00013
00014 #include "OgreTextAreaOverlayElement.h"
00015 #include "Ogre.h"
00016 #include <OIS/OIS.h>
00017
00018
00019 #include "OverlayHelper.h"
00020 #include "App3D.h"
00021
00022
00023 #include "GetTime.h"
00024 #include "RakSleep.h"
00025 #include "RakAssert.h"
00026 #include "StringTable.h"
00027 #include "RakPeerInterface.h"
00028 #include "RakNetworkFactory.h"
00029 #include "BitStream.h"
00030 #include "MessageIdentifiers.h"
00031 #include "ReplicaManager3.h"
00032 #include "NetworkIDManager.h"
00033 #include "RakSleep.h"
00034 #include "FormatString.h"
00035 #include "StringCompressor.h"
00036 #include "Rand.h"
00037 #include "TransformationHistory.h"
00038
00039 using namespace Ogre;
00040 using namespace DataStructures;
00041 using namespace OIS;
00042 using namespace RakNet;
00043
00044 class Popcorn;
00045
00046
00047 static const char *SERVER_IP_ADDRESS="127.0.0.1";
00048 static const unsigned short SERVER_PORT=12345;
00049
00050 static const int DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES=250;
00051
00052
00053 static const int MIN_KERNELS=100;
00054 static const int KERNELS_VARIANCE=60;
00055 static const RakNetTime POP_COUNTDOWN_MIN_DELAY_MS=1000;
00056 static const RakNetTime POP_COUNTDOWN_VARIANCE_MS=5000;
00057 static const RakNetTime RESTART_TIMER_MS=14000;
00058 static const float POSITION_VARIANCE=100.0f;
00059 static const float PLANE_VELOCITY_VARIANCE=30.0f;
00060 static const float UPWARD_VELOCITY_MINIMUM=35.0f;
00061 static const float UPWARD_VELOCITY_VARIANCE=25.0f;
00062 static const float DOWNWARD_ACCELERATION = -15.0f;
00063
00064 bool isServer;
00065 Ogre::Entity *popcornKernel, *popcornPopped;
00066 RakPeerInterface *rakPeer;
00067 DataStructures::List<Popcorn*> popcornList;
00068 bool enableInterpolation;
00069
00070 App3D *app;
00071
00072
00073
00074
00075
00076 class Popcorn : public Replica3
00077 {
00078 public:
00079 Popcorn() {
00080
00081 transformationHistory.Init(30,3000);
00082
00083 position=Ogre::Vector3::ZERO;
00084 orientation=Ogre::Quaternion::IDENTITY;
00085
00086 visiblePosition=Ogre::Vector3::ZERO;
00087 visibleOrientation=Ogre::Quaternion::IDENTITY;
00088 isKernel=true;
00089 }
00090 virtual ~Popcorn()
00091 {
00092 if (isServer)
00093 BroadcastDestruction();
00094
00095 app->GetSceneManager()->destroyEntity(sceneNode->getAttachedObject(0)->getName());
00096 app->GetSceneManager()->getRootSceneNode()->removeAndDestroyChild(sceneNode->getName());
00097 popcornList.RemoveAtIndex(popcornList.GetIndexOf(this));
00098 }
00099
00100 bool isKernel;
00101 Ogre::Vector3 position;
00102 Ogre::Quaternion orientation;
00103 Ogre::Quaternion rotationalVelocity;
00104 Ogre::Vector3 velocity;
00105 Ogre::SceneNode *sceneNode;
00106 RakNetTime popCountdown;
00107 Ogre::Vector3 visiblePosition;
00108 Ogre::Quaternion visibleOrientation;
00109 TransformationHistory transformationHistory;
00110
00111 virtual void WriteAllocationID(RakNet::BitStream *allocationIdBitstream) const
00112 {
00113 StringTable::Instance()->EncodeString("Popcorn", 128, allocationIdBitstream);
00114 }
00115 virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3)
00116 {
00117 if (isServer)
00118 return QueryConstruction_ServerConstruction(destinationConnection);
00119 else
00120 return QueryConstruction_ClientConstruction(destinationConnection);
00121 }
00122 virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection){
00123 if (isServer)
00124 return QueryRemoteConstruction_ServerConstruction(sourceConnection);
00125 else
00126 return QueryRemoteConstruction_ClientConstruction(sourceConnection);
00127 }
00128 virtual void SerializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection){}
00129 virtual bool DeserializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection){return true;}
00130 virtual void SerializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *destinationConnection){}
00131 virtual bool DeserializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *sourceConnection){return true;}
00132 virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const
00133 {
00134 if (isServer)
00135 return QueryActionOnPopConnection_Server(droppedConnection);
00136 else
00137 return QueryActionOnPopConnection_Client(droppedConnection);
00138 }
00139 virtual void DeallocReplica(RakNet::Connection_RM3 *sourceConnection) {delete this;}
00140 virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection)
00141 {
00142 if (isServer)
00143 return QuerySerialization_ServerSerializable(destinationConnection);
00144 else
00145 return QuerySerialization_ClientSerializable(destinationConnection);
00146 }
00147 virtual RM3SerializationResult Serialize(RakNet::SerializeParameters *serializeParameters)
00148 {
00149
00150 RakAssert(isServer==true);
00151 serializeParameters->outputBitstream[0].Write(isKernel);
00152 serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&position,sizeof(position));
00153 serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&velocity,sizeof(velocity));
00154 serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&orientation,sizeof(orientation));
00155 return RM3SR_BROADCAST_IDENTICALLY;
00156 }
00157 virtual void Deserialize(RakNet::DeserializeParameters *deserializeParameters)
00158 {
00159 bool lastIsKernel = isKernel;
00160
00161
00162
00163 deserializeParameters->serializationBitstream[0].Read(isKernel);
00164 if (isKernel==false && lastIsKernel==true)
00165 popCountdown=DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES;
00166
00167 deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&position,sizeof(position));
00168 deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&velocity,sizeof(velocity));
00169 deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&orientation,sizeof(orientation));
00170
00171
00172
00173 sceneNode->setVisible(true,true);
00174
00175
00176
00177 transformationHistory.Write(position,velocity,orientation,RakNet::GetTime());
00178 }
00179
00180 virtual void SetToPopped(void)
00181 {
00182
00183 isKernel=false;
00184 if (sceneNode->getAttachedObject(0))
00185 app->GetSceneManager()->destroyEntity(sceneNode->getAttachedObject(0)->getName());
00186 sceneNode->detachAllObjects();
00187 sceneNode->attachObject(popcornPopped->clone(FormatString("%p",this)));
00188 if (isServer)
00189 {
00190 velocity.x=-PLANE_VELOCITY_VARIANCE/2.0f+frandomMT()*PLANE_VELOCITY_VARIANCE;
00191 velocity.y=UPWARD_VELOCITY_MINIMUM+frandomMT()*UPWARD_VELOCITY_VARIANCE;
00192 velocity.z=-PLANE_VELOCITY_VARIANCE/2.0f+frandomMT()*PLANE_VELOCITY_VARIANCE;
00193 }
00194 }
00195
00196 virtual void Update(RakNetTime timeElapsedMs)
00197 {
00198 visiblePosition=position;
00199 visibleOrientation=orientation;
00200
00201 if (isKernel==false)
00202 {
00203 if (isServer)
00204 {
00205
00206 float timeElapsedSec = timeElapsedMs * .001f;
00207 position += velocity * timeElapsedSec + .5f * Ogre::Vector3(0.0f, DOWNWARD_ACCELERATION, 0.0f) * timeElapsedSec*timeElapsedSec;;
00208 velocity += Ogre::Vector3(0.0f, DOWNWARD_ACCELERATION, 0.0f) * timeElapsedSec;
00209 orientation = Quaternion::Slerp(timeElapsedSec, orientation, orientation * rotationalVelocity, true);
00210 }
00211 else
00212 {
00213
00214 if (popCountdown <= timeElapsedMs)
00215 {
00216 SetToPopped();
00217 popCountdown=-1;
00218 }
00219 else
00220 popCountdown-=timeElapsedMs;
00221
00222
00223 if (enableInterpolation)
00224 {
00225
00226
00227
00228 transformationHistory.Read(&visiblePosition, 0, &visibleOrientation, RakNet::GetTime()-DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES,RakNet::GetTime());
00229 }
00230 }
00231 }
00232 else
00233 {
00234 if (isServer)
00235 {
00236 if (popCountdown <= timeElapsedMs)
00237 {
00238
00239 SetToPopped();
00240 }
00241 else
00242 popCountdown-=timeElapsedMs;
00243
00244 }
00245
00246 }
00247
00248 sceneNode->setPosition(visiblePosition);
00249 sceneNode->setOrientation(visibleOrientation);
00250 }
00251
00252
00253 static void ClearPopcorn()
00254 {
00255
00256 while (popcornList.Size())
00257 delete popcornList[popcornList.Size()-1];
00258 }
00259 static Popcorn * CreateKernel(ReplicaManager3 *replicaManager3)
00260 {
00261 Popcorn *p = new Popcorn;
00262
00263 replicaManager3->Reference(p);
00264 static int count=0;
00265 count++;
00266 popcornList.Insert(p, __FILE__, __LINE__ );
00267 p->sceneNode = app->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
00268 p->sceneNode->attachObject(popcornKernel->clone(FormatString("%p",p)));
00269
00270
00271 if (isServer)
00272 {
00273 p->position.x=-POSITION_VARIANCE/2.0f+frandomMT()*POSITION_VARIANCE;
00274 p->position.y=0.0f;
00275 p->position.z=-POSITION_VARIANCE/2.0f+frandomMT()*POSITION_VARIANCE;
00276 p->velocity=Ogre::Vector3::ZERO;
00277 p->popCountdown=POP_COUNTDOWN_MIN_DELAY_MS + randomMT() % POP_COUNTDOWN_VARIANCE_MS;
00278 p->orientation.FromAngleAxis(Ogre::Radian(frandomMT()*6.28f), Ogre::Vector3(-1.0f+frandomMT()*2.0f,-1.0f+frandomMT()*2.0f,-1.0f+frandomMT()*2.0f).normalisedCopy());
00279 p->rotationalVelocity.FromAngleAxis(Ogre::Radian(frandomMT()*6.28f), Ogre::Vector3(-1.0f+frandomMT()*2.0f,-1.0f+frandomMT()*2.0f,-1.0f+frandomMT()*2.0f).normalisedCopy());
00280 p->visiblePosition=p->position;
00281 p->visibleOrientation=p->orientation;
00282 }
00283 else
00284 p->sceneNode->setVisible(false,true);
00285
00286
00287 return p;
00288 }
00289 };
00290
00291
00292
00293 class PopcornSampleConnection : public Connection_RM3
00294 {
00295 public:
00296 PopcornSampleConnection(SystemAddress _systemAddress, RakNetGUID _guid) : Connection_RM3(_systemAddress,_guid) {}
00297 virtual ~PopcornSampleConnection() {}
00298
00299
00300
00301 virtual Replica3 *AllocReplica(RakNet::BitStream *allocationIdBitstream, ReplicaManager3 *replicaManager3)
00302 {
00303 char objectName[128];
00304 StringTable::Instance()->DecodeString(objectName,128,allocationIdBitstream);
00305 if (strcmp(objectName,"Popcorn")==0)
00306 {
00307 return Popcorn::CreateKernel(replicaManager3);
00308 }
00309 return 0;
00310 }
00311 };
00312 class PopcornDemoRM3 : public ReplicaManager3
00313 {
00314 virtual Connection_RM3* AllocConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID) const {return new PopcornSampleConnection(systemAddress,rakNetGUID);}
00315 virtual void DeallocConnection(Connection_RM3 *connection) const {delete connection;}
00316 };
00317 PopcornDemoRM3 replicaManager3;
00318 class ExampleApp : public App3D
00319 {
00320 public:
00321 ExampleApp()
00322 {
00323 quit=false;
00324 }
00325
00326 ~ExampleApp()
00327 {
00328 }
00329
00330 void OnAppShutdown( void )
00331 {
00332 Popcorn::ClearPopcorn();
00333
00334 App3D::OnAppShutdown();
00335
00336 if( mInputManager )
00337 {
00338 mInputManager->destroyInputObject( mKeyboard );
00339 OIS::InputManager::destroyInputSystem(mInputManager);
00340 mInputManager = 0;
00341 }
00342
00343 RakNetworkFactory::DestroyRakPeerInterface(rakPeer);
00344
00345 }
00346
00347 void Render(AppTime curTimeMS)
00348 {
00349 App3D::Render(curTimeMS);
00350 }
00351
00352 bool ShouldQuit(void) const {return quit || window->isClosed();}
00353
00354 void Update(AppTime curTimeMS, AppTime elapsedTimeMS)
00355 {
00356 #ifndef WIN32
00357 WindowEventUtilities::messagePump();
00358 #endif
00359
00360
00361 App3D::Update(curTimeMS, elapsedTimeMS);
00362 overlayHelper.Update(elapsedTimeMS);
00363
00364 mKeyboard->capture();
00365
00366 Ogre::Vector3 mTranslateVector = Ogre::Vector3::ZERO;
00367
00368 float mMoveSpeed=50.0f;
00369 float mRotateSpeed=1.0f;
00370 float mMoveScale = mMoveSpeed * elapsedTimeMS * .001f;
00371
00372 Ogre::Radian mRotScale(mRotateSpeed * elapsedTimeMS * .001f);
00373
00374 if(mKeyboard->isKeyDown(KC_A))
00375 mTranslateVector.x = -mMoveScale;
00376
00377 if(mKeyboard->isKeyDown(KC_D))
00378 mTranslateVector.x = mMoveScale;
00379
00380 if(mKeyboard->isKeyDown(KC_UP) || mKeyboard->isKeyDown(KC_W) )
00381 mTranslateVector.z = -mMoveScale;
00382
00383 if(mKeyboard->isKeyDown(KC_DOWN) || mKeyboard->isKeyDown(KC_S) )
00384 mTranslateVector.z = mMoveScale;
00385
00386 if(mKeyboard->isKeyDown(KC_PGUP))
00387 mTranslateVector.y = mMoveScale;
00388
00389 if(mKeyboard->isKeyDown(KC_PGDOWN))
00390 mTranslateVector.y = -mMoveScale;
00391
00392 if(mKeyboard->isKeyDown(KC_RIGHT))
00393 camera->yaw(-mRotScale);
00394
00395 if(mKeyboard->isKeyDown(KC_LEFT))
00396 camera->yaw(mRotScale);
00397
00398
00399 if(mKeyboard->isKeyDown(KC_SPACE))
00400 enableInterpolation=false;
00401 else
00402 enableInterpolation=true;
00403
00404 static bool didUpdateDelayLastTick=false;
00405 bool didUpdateDelayThisTick=false;
00406
00407 if (isStarted==false)
00408 {
00409 SocketDescriptor sd;
00410
00411 if(mKeyboard->isKeyDown(KC_S))
00412 {
00413
00414 isStarted=true;
00415 isServer=true;
00416 ShowMessage("Server started");
00417 sd.port=SERVER_PORT;
00418
00419 }
00420
00421 if(mKeyboard->isKeyDown(KC_C))
00422 {
00423 isStarted=true;
00424 ShowMessage(FormatString("Client started, connecting to %s", SERVER_IP_ADDRESS));
00425
00426 isStarted=true;
00427 isServer=false;
00428 sd.port=0;
00429 }
00430
00431 if (isStarted)
00432 {
00433 networkIdManager.SetIsNetworkIDAuthority(isServer);
00434
00435 rakPeer = RakNetworkFactory::GetRakPeerInterface();
00436 rakPeer->Startup(isServer ? 32 : 1,100,&sd,1);
00437 rakPeer->AttachPlugin(&replicaManager3);
00438 rakPeer->SetNetworkIDManager(&networkIdManager);
00439
00440 if (isServer)
00441 rakPeer->SetMaximumIncomingConnections(32);
00442 else
00443 rakPeer->Connect(SERVER_IP_ADDRESS,SERVER_PORT,0,0);
00444
00445
00446 StringTable::Instance()->AddString("Popcorn",false);
00447 }
00448 }
00449
00450 if (isStarted)
00451 {
00452 Packet *packet;
00453 for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
00454 {
00455 switch (packet->data[0])
00456 {
00457 case ID_CONNECTION_ATTEMPT_FAILED:
00458 ShowMessage("ID_CONNECTION_ATTEMPT_FAILED\n");
00459 break;
00460 case ID_NO_FREE_INCOMING_CONNECTIONS:
00461 ShowMessage("ID_NO_FREE_INCOMING_CONNECTIONS\n");
00462 break;
00463 case ID_CONNECTION_REQUEST_ACCEPTED:
00464 ShowMessage("ID_CONNECTION_REQUEST_ACCEPTED\n");
00465 break;
00466 case ID_NEW_INCOMING_CONNECTION:
00467 ShowMessage(FormatString("ID_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString()));
00468 break;
00469 case ID_DISCONNECTION_NOTIFICATION:
00470 ShowMessage("ID_DISCONNECTION_NOTIFICATION\n");
00471 break;
00472 case ID_CONNECTION_LOST:
00473 ShowMessage("ID_CONNECTION_LOST\n");
00474 break;
00475 }
00476 }
00477
00478 if (isServer)
00479 {
00480
00481 if (popcornLifetimeCountdown<=elapsedTimeMS)
00482 {
00483 Popcorn::ClearPopcorn();
00484 CreateKernels(&replicaManager3);
00485 popcornLifetimeCountdown=RESTART_TIMER_MS;
00486 }
00487 popcornLifetimeCountdown-=elapsedTimeMS;
00488 }
00489
00490
00491 unsigned i;
00492 for (i=0; i < popcornList.Size(); i++)
00493 {
00494 popcornList[i]->Update(elapsedTimeMS);
00495 }
00496 }
00497
00498 camera->moveRelative(mTranslateVector);
00499
00500 if( mKeyboard->isKeyDown(KC_ESCAPE) || mKeyboard->isKeyDown(KC_Q) )
00501 quit=true;
00502 }
00503
00504
00505 virtual void PostConfigure(const char *defaultResourceConfigurationPath, bool recursive)
00506 {
00507 App3D::PostConfigure(defaultResourceConfigurationPath, false);
00508 App3D::InitSceneManager(0);
00509 App3D::InitGUIManager();
00510 App3D::InitCamera(0);
00511 App3D::InitViewport(0);
00512
00513 ParamList pl;
00514 size_t windowHnd = 0;
00515 std::ostringstream windowHndStr;
00516
00517 window->getCustomAttribute("WINDOW", &windowHnd);
00518 windowHndStr << windowHnd;
00519 pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
00520
00521 mInputManager = InputManager::createInputSystem( pl );
00522
00523 mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject( OISKeyboard, false ));
00524
00525
00526 overlayHelper.Startup();
00527
00528 sceneManager->setAmbientLight( ColourValue( .5, .5, .5 ) );
00529
00530 ShowMessage("'S'erver. 'C'lient. Hold ' ' to disable interp.");
00531
00532 mainLight = sceneManager->createLight("MainLight");
00533 mainLightNode = sceneManager->getRootSceneNode()->createChildSceneNode( "MainLightNode" );
00534 mainLightNode->attachObject(mainLight);
00535 mainLight->setType(Light::LT_POINT);
00536 mainLight->setPosition(200.0f, 200.0f, 200.0f);
00537
00538 camera->setPosition(150.0f, 150.0f, 70.0f);
00539 camera->lookAt(0.0f,50.0f,0.0f);
00540 camera->setNearClipDistance(1.0f);
00541
00542 popcornKernel = sceneManager->createEntity("PopcornKernel", "PopcornKernel.mesh");
00543 popcornPopped = sceneManager->createEntity("PopcornPopped", "PopcornPopped.mesh");
00544 popcornLifetimeCountdown=0;
00545
00546 sceneManager->setSkyBox(true, "Examples/SteveCubeSkyBox");
00547 isStarted=false;
00548 enableInterpolation=true;
00549 }
00550
00551 virtual void CreateKernels(ReplicaManager3 *replicaManager3)
00552 {
00553 RakAssert(isServer);
00554 unsigned int kernelCount;
00555 if (KERNELS_VARIANCE!=0)
00556 kernelCount = MIN_KERNELS + randomMT() % KERNELS_VARIANCE;
00557 else
00558 kernelCount = MIN_KERNELS;
00559 for (unsigned int i=0; i < kernelCount; i++)
00560 Popcorn::CreateKernel(replicaManager3);
00561
00562 }
00563
00564 protected:
00565 virtual char * GetWindowTitle(void) const {return "Popcorn popper";}
00566 void ShowMessage(const char *msg, float timescale=1.0f)
00567 {
00568
00569 static int count=0;
00570 OverlayContainer* panel =overlayHelper.CreatePanel(FormatString("%i",count++));
00571 panel->setMetricsMode(Ogre::GMM_PIXELS);
00572 panel->setPosition(10, 10);
00573 panel->setDimensions(100, 100);
00574
00575
00576
00577 TextAreaOverlayElement *textArea = overlayHelper.CreateTextArea(FormatString("%i",count++), "BlueHighway", panel);
00578 textArea->setMetricsMode(Ogre::GMM_PIXELS);
00579 textArea->setPosition(10, 10);
00580 textArea->setDimensions(200, 200);
00581 textArea->setCaption(msg);
00582 textArea->setCharHeight(32);
00583 textArea->setColourBottom(ColourValue(0.3, 0.5, 0.3));
00584 textArea->setColourTop(ColourValue(0.5, 0.7, 0.5));
00585
00586
00587 overlayHelper.FadeOverlayElement(textArea, 3000*timescale, 1000*timescale, 0.0f, true);
00588 overlayHelper.FadeOverlayElement(panel, 3000*timescale, 1000*timescale, 0.0f, true);
00589 }
00590
00591
00592 OverlayHelper overlayHelper;
00593 bool quit;
00594
00595 SceneNode *mainLightNode;
00596 Light *mainLight;
00597
00598 OIS::InputManager* mInputManager;
00599 OIS::Keyboard* mKeyboard;
00600
00601 NetworkIDManager networkIdManager;
00602 bool isStarted;
00603 RakNetTime popcornLifetimeCountdown;
00604 };
00605
00606
00607 #ifdef WIN32
00608 int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
00609 #else
00610 int main (int argc, char** argv)
00611 #endif
00612 {
00613
00614 HWND hWnd;
00615 RakNetTime curTime, lastTime, elapsed;
00616 app = new ExampleApp;
00617 app->PreConfigure();
00618 if (app->Configure()==false)
00619 {
00620 delete app;
00621 return 0;
00622 }
00623 #ifdef WIN32
00624 app->window->getCustomAttribute("HWND", &hWnd);
00625 MSG msg;
00626 #else
00627 app->window->getCustomAttribute("GLXWINDOW", &hWnd);
00628 #endif
00629
00630 app->PostConfigure("resources.cfg",false);
00631 lastTime=RakNet::GetTime();
00632
00633 while (app->ShouldQuit()==false)
00634 {
00635 curTime=RakNet::GetTime();
00636 elapsed = curTime-lastTime;
00637 if (elapsed > 100)
00638 elapsed=100;
00639 app->Update(curTime, elapsed);
00640 lastTime=curTime;
00641 app->Render(curTime);
00642 #ifdef WIN32
00643 if (PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE )>0)
00644 {
00645 TranslateMessage( &msg );
00646 DispatchMessage( &msg );
00647 }
00648 #endif
00649
00650 RakSleep(0);
00651 }
00652
00653 app->OnAppShutdown();
00654
00655 delete app;
00656
00657 return 0;
00658 }