WinMain.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. // Demonstrates how to lag a client in the past using the interpolation history class,
  11. // in order to get smooth visuals despite choppy input.
  12. // Start two instances on the same computer, press 's' on one instance, 'c' on the other.
  13. // Hold down space to see the actual networking.
  14. // Change SERVER_IP_ADDRESS to connect over the internet
  15. #ifdef WIN32
  16. #include "WindowsIncludes.h"
  17. #else
  18. #define HWND void*
  19. #endif
  20. // Ogre includes
  21. #include "OgreTextAreaOverlayElement.h"
  22. #include "Ogre.h"
  23. #include <OIS.h>
  24. // Stuff to help run ogre
  25. #include "OverlayHelper.h"
  26. #include "App3D.h"
  27. // RakNet includes
  28. #include "GetTime.h"
  29. #include "RakSleep.h"
  30. #include "RakAssert.h"
  31. #include "StringTable.h"
  32. #include "RakPeerInterface.h"
  33. #include "BitStream.h"
  34. #include "MessageIdentifiers.h"
  35. #include "ReplicaManager3.h"
  36. #include "NetworkIDManager.h"
  37. #include "RakSleep.h"
  38. #include "FormatString.h"
  39. #include "StringCompressor.h"
  40. #include "Rand.h"
  41. #include "TransformationHistory.h"
  42. using namespace Ogre;
  43. using namespace DataStructures;
  44. using namespace OIS;
  45. using namespace RakNet;
  46. class Popcorn;
  47. // Network variables
  48. static const char *SERVER_IP_ADDRESS="127.0.0.1";
  49. static const unsigned short SERVER_PORT=12345;
  50. // How often the server sends position updates to the client
  51. static const int DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES=250;
  52. // Demo variables
  53. static const int MIN_KERNELS=100;
  54. static const int KERNELS_VARIANCE=60;
  55. static const RakNet::TimeMS POP_COUNTDOWN_MIN_DELAY_MS=1000;
  56. static const RakNet::TimeMS POP_COUNTDOWN_VARIANCE_MS=5000;
  57. static const RakNet::TimeMS RESTART_TIMER_MS=14000;
  58. static const float POSITION_VARIANCE=100.0f;
  59. static const float PLANE_VELOCITY_VARIANCE=30.0f;
  60. static const float UPWARD_VELOCITY_MINIMUM=35.0f;
  61. static const float UPWARD_VELOCITY_VARIANCE=25.0f;
  62. static const float DOWNWARD_ACCELERATION = -15.0f;
  63. bool isServer;
  64. Ogre::Entity *popcornKernel, *popcornPopped;
  65. RakNet::RakPeerInterface *rakPeer;
  66. DataStructures::List<Popcorn*> popcornList;
  67. bool enableInterpolation;
  68. App3D *app;
  69. // This class represents a kernel of popcorn, which pops after a short delay
  70. // When to pop, and the physics the popcorn takes is entirely controlled by the server
  71. // Every DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES the server will send an update
  72. // The client intentionally lags this far behind, so it always has a recent position to interpolate to
  73. class Popcorn : public Replica3
  74. {
  75. public:
  76. Popcorn() {
  77. // Buffer up for 3 seconds if we were to get 30 updates per second
  78. transformationHistory.Init(30,3000);
  79. position=Ogre::Vector3::ZERO;
  80. orientation=Ogre::Quaternion::IDENTITY;
  81. // Visible position is where we are interpolating at, which is behind the real position
  82. visiblePosition=Ogre::Vector3::ZERO;
  83. visibleOrientation=Ogre::Quaternion::IDENTITY;
  84. isKernel=true;
  85. }
  86. virtual ~Popcorn()
  87. {
  88. if (isServer)
  89. BroadcastDestruction();
  90. app->GetSceneManager()->destroyEntity(sceneNode->getAttachedObject(0)->getName());
  91. app->GetSceneManager()->getRootSceneNode()->removeAndDestroyChild(sceneNode->getName());
  92. popcornList.RemoveAtIndex(popcornList.GetIndexOf(this));
  93. }
  94. bool isKernel;
  95. Ogre::Vector3 position;
  96. Ogre::Quaternion orientation;
  97. Ogre::Quaternion rotationalVelocity;
  98. Ogre::Vector3 velocity;
  99. Ogre::SceneNode *sceneNode;
  100. RakNet::TimeMS popCountdown;
  101. Ogre::Vector3 visiblePosition;
  102. Ogre::Quaternion visibleOrientation;
  103. TransformationHistory transformationHistory;
  104. virtual void WriteAllocationID(RakNet::Connection_RM3 *destinationConnection, RakNet::BitStream *allocationIdBitstream) const
  105. {
  106. StringTable::Instance()->EncodeString("Popcorn", 128, allocationIdBitstream);
  107. }
  108. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3)
  109. {
  110. if (isServer)
  111. return QueryConstruction_ServerConstruction(destinationConnection, isServer);
  112. else
  113. return QueryConstruction_ClientConstruction(destinationConnection, isServer);
  114. }
  115. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection){
  116. if (isServer)
  117. return QueryRemoteConstruction_ServerConstruction(sourceConnection, isServer);
  118. else
  119. return QueryRemoteConstruction_ClientConstruction(sourceConnection, isServer);
  120. }
  121. virtual void SerializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection){}
  122. virtual bool DeserializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection){return true;}
  123. virtual void SerializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *destinationConnection){}
  124. virtual bool DeserializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *sourceConnection){return true;}
  125. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const
  126. {
  127. if (isServer)
  128. return QueryActionOnPopConnection_Server(droppedConnection);
  129. else
  130. return QueryActionOnPopConnection_Client(droppedConnection);
  131. }
  132. virtual void DeallocReplica(RakNet::Connection_RM3 *sourceConnection) {delete this;}
  133. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection)
  134. {
  135. if (isServer)
  136. return QuerySerialization_ServerSerializable(destinationConnection, isServer);
  137. else
  138. return QuerySerialization_ClientSerializable(destinationConnection, isServer);
  139. }
  140. virtual RM3SerializationResult Serialize(RakNet::SerializeParameters *serializeParameters)
  141. {
  142. // Autoserialize causes a network packet to go out when any of these member variables change.
  143. RakAssert(isServer==true);
  144. serializeParameters->outputBitstream[0].Write(isKernel);
  145. serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&position,sizeof(position));
  146. serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&velocity,sizeof(velocity));
  147. serializeParameters->outputBitstream[0].WriteAlignedBytes((const unsigned char*)&orientation,sizeof(orientation));
  148. return RM3SR_BROADCAST_IDENTICALLY;
  149. }
  150. virtual void Deserialize(RakNet::DeserializeParameters *deserializeParameters)
  151. {
  152. bool lastIsKernel = isKernel;
  153. // Doing this because we are also lagging position and orientation behind by DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES
  154. // Without it, the kernel would pop immediately but would not start moving
  155. deserializeParameters->serializationBitstream[0].Read(isKernel);
  156. if (isKernel==false && lastIsKernel==true)
  157. popCountdown=DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES;
  158. deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&position,sizeof(position));
  159. deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&velocity,sizeof(velocity));
  160. deserializeParameters->serializationBitstream[0].ReadAlignedBytes((unsigned char*)&orientation,sizeof(orientation));
  161. // Scene node starts invisible until we deserialize the intial startup data
  162. // This data could also have been passed in SerializeConstruction()
  163. sceneNode->setVisible(true,true);
  164. // Every time we get a network packet, we write it to the transformation history class.
  165. // This class, given a time in the past, can then return to us an interpolated position of where we should be in at that time
  166. transformationHistory.Write(position,velocity,orientation,RakNet::GetTimeMS());
  167. }
  168. virtual void SetToPopped(void)
  169. {
  170. // Change the mesh, and add some velocity.
  171. isKernel=false;
  172. if (sceneNode->getAttachedObject(0))
  173. app->GetSceneManager()->destroyEntity(sceneNode->getAttachedObject(0)->getName());
  174. sceneNode->detachAllObjects();
  175. sceneNode->attachObject(popcornPopped->clone(FormatString("%p",this)));
  176. if (isServer)
  177. {
  178. velocity.x=-PLANE_VELOCITY_VARIANCE/2.0f+frandomMT()*PLANE_VELOCITY_VARIANCE;
  179. velocity.y=UPWARD_VELOCITY_MINIMUM+frandomMT()*UPWARD_VELOCITY_VARIANCE;
  180. velocity.z=-PLANE_VELOCITY_VARIANCE/2.0f+frandomMT()*PLANE_VELOCITY_VARIANCE;
  181. }
  182. }
  183. virtual void Update(RakNet::TimeMS timeElapsedMs)
  184. {
  185. visiblePosition=position;
  186. visibleOrientation=orientation;
  187. if (isKernel==false)
  188. {
  189. if (isServer)
  190. {
  191. // Only the server is doing physics
  192. float timeElapsedSec = timeElapsedMs * .001f;
  193. position += velocity * timeElapsedSec + .5f * Ogre::Vector3(0.0f, DOWNWARD_ACCELERATION, 0.0f) * timeElapsedSec*timeElapsedSec;;
  194. velocity += Ogre::Vector3(0.0f, DOWNWARD_ACCELERATION, 0.0f) * timeElapsedSec;
  195. orientation = Quaternion::Slerp(timeElapsedSec, orientation, orientation * rotationalVelocity, true);
  196. }
  197. else
  198. {
  199. // See above - delay the pop until we start moving
  200. if (popCountdown <= timeElapsedMs)
  201. {
  202. SetToPopped();
  203. popCountdown=-1;
  204. }
  205. else
  206. popCountdown-=timeElapsedMs;
  207. // interpolate visible position, lagging behind by a small amount so where know where to update to
  208. if (enableInterpolation)
  209. {
  210. // Important: the first 3 parameters are in/out parameters, so set their values to the known current values before calling Read()
  211. // We are subtracting DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES from the current time to get an interpolated position in the past
  212. // Without this we wouldn't have a node to interpolate to, and wouldn't know where to go
  213. transformationHistory.Read(&visiblePosition, 0, &visibleOrientation, RakNet::GetTimeMS()-DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES,RakNet::GetTimeMS());
  214. }
  215. }
  216. }
  217. else
  218. {
  219. if (isServer)
  220. {
  221. if (popCountdown <= timeElapsedMs)
  222. {
  223. // Only the server controls when to pop
  224. SetToPopped();
  225. }
  226. else
  227. popCountdown-=timeElapsedMs;
  228. }
  229. }
  230. sceneNode->setPosition(visiblePosition);
  231. sceneNode->setOrientation(visibleOrientation);
  232. }
  233. static void ClearPopcorn()
  234. {
  235. // Destructor removes itself from this list
  236. while (popcornList.Size())
  237. delete popcornList[popcornList.Size()-1];
  238. }
  239. static Popcorn * CreateKernel(ReplicaManager3 *replicaManager3)
  240. {
  241. Popcorn *p = new Popcorn;
  242. // Tell the replication system about this new Replica instance.
  243. replicaManager3->Reference(p);
  244. static int count=0;
  245. count++;
  246. popcornList.Insert(p, _FILE_AND_LINE_ );
  247. p->sceneNode = app->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
  248. p->sceneNode->attachObject(popcornKernel->clone(FormatString("%p",p)));
  249. // Only server sets up initial positions, etc.
  250. if (isServer)
  251. {
  252. p->position.x=-POSITION_VARIANCE/2.0f+frandomMT()*POSITION_VARIANCE;
  253. p->position.y=0.0f;
  254. p->position.z=-POSITION_VARIANCE/2.0f+frandomMT()*POSITION_VARIANCE;
  255. p->velocity=Ogre::Vector3::ZERO;
  256. p->popCountdown=POP_COUNTDOWN_MIN_DELAY_MS + randomMT() % POP_COUNTDOWN_VARIANCE_MS;
  257. 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());
  258. 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());
  259. p->visiblePosition=p->position;
  260. p->visibleOrientation=p->orientation;
  261. }
  262. else
  263. p->sceneNode->setVisible(false,true);
  264. return p;
  265. }
  266. };
  267. // One instance of Connection_RM2 is implicitly created per connection that uses ReplicaManager2. The most important function to implement is Construct() as this creates your game objects.
  268. // It is designed this way so you can override per-connection behavior in your own game classes
  269. class PopcornSampleConnection : public Connection_RM3
  270. {
  271. public:
  272. PopcornSampleConnection(const SystemAddress &_systemAddress, RakNetGUID _guid) : Connection_RM3(_systemAddress,_guid) {}
  273. virtual ~PopcornSampleConnection() {}
  274. // Callback used to create objects
  275. // See Connection_RM2::Construct in ReplicaManager2.h for a full explanation of each parameter
  276. virtual Replica3 *AllocReplica(RakNet::BitStream *allocationIdBitstream, ReplicaManager3 *replicaManager3)
  277. {
  278. char objectName[128];
  279. StringTable::Instance()->DecodeString(objectName,128,allocationIdBitstream);
  280. if (strcmp(objectName,"Popcorn")==0)
  281. {
  282. return Popcorn::CreateKernel(replicaManager3);
  283. }
  284. return 0;
  285. }
  286. };
  287. class PopcornDemoRM3 : public ReplicaManager3
  288. {
  289. virtual Connection_RM3* AllocConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID) const {return new PopcornSampleConnection(systemAddress,rakNetGUID);}
  290. virtual void DeallocConnection(Connection_RM3 *connection) const {delete connection;}
  291. };
  292. PopcornDemoRM3 replicaManager3;
  293. class ExampleApp : public App3D
  294. {
  295. public:
  296. ExampleApp()
  297. {
  298. quit=false;
  299. }
  300. ~ExampleApp()
  301. {
  302. }
  303. void OnAppShutdown( void )
  304. {
  305. Popcorn::ClearPopcorn();
  306. App3D::OnAppShutdown();
  307. if( mInputManager )
  308. {
  309. mInputManager->destroyInputObject( mKeyboard );
  310. OIS::InputManager::destroyInputSystem(mInputManager);
  311. mInputManager = 0;
  312. }
  313. RakNet::RakPeerInterface::DestroyInstance(rakPeer);
  314. }
  315. void Render(AppTime curTimeMS)
  316. {
  317. App3D::Render(curTimeMS);
  318. }
  319. bool ShouldQuit(void) const {return quit || window->isClosed();}
  320. void Update(AppTime curTimeMS, AppTime elapsedTimeMS)
  321. {
  322. #ifndef WIN32
  323. WindowEventUtilities::messagePump();
  324. #endif
  325. // Update all subsystems
  326. App3D::Update(curTimeMS, elapsedTimeMS);
  327. overlayHelper.Update(elapsedTimeMS);
  328. mKeyboard->capture();
  329. Ogre::Vector3 mTranslateVector = Ogre::Vector3::ZERO;
  330. float mMoveSpeed=50.0f;
  331. float mRotateSpeed=1.0f;
  332. float mMoveScale = mMoveSpeed * elapsedTimeMS * .001f;
  333. // Take about 10 seconds for full rotation
  334. Ogre::Radian mRotScale(mRotateSpeed * elapsedTimeMS * .001f);
  335. if(mKeyboard->isKeyDown(KC_A))
  336. mTranslateVector.x = -mMoveScale; // Move camera left
  337. if(mKeyboard->isKeyDown(KC_D))
  338. mTranslateVector.x = mMoveScale; // Move camera RIGHT
  339. if(mKeyboard->isKeyDown(KC_UP) || mKeyboard->isKeyDown(KC_W) )
  340. mTranslateVector.z = -mMoveScale; // Move camera forward
  341. if(mKeyboard->isKeyDown(KC_DOWN) || mKeyboard->isKeyDown(KC_S) )
  342. mTranslateVector.z = mMoveScale; // Move camera backward
  343. if(mKeyboard->isKeyDown(KC_PGUP))
  344. mTranslateVector.y = mMoveScale; // Move camera up
  345. if(mKeyboard->isKeyDown(KC_PGDOWN))
  346. mTranslateVector.y = -mMoveScale; // Move camera down
  347. if(mKeyboard->isKeyDown(KC_RIGHT))
  348. camera->yaw(-mRotScale);
  349. if(mKeyboard->isKeyDown(KC_LEFT))
  350. camera->yaw(mRotScale);
  351. // Hold down space to see what it looks like without interpolation
  352. if(mKeyboard->isKeyDown(KC_SPACE))
  353. enableInterpolation=false;
  354. else
  355. enableInterpolation=true;
  356. static bool didUpdateDelayLastTick=false;
  357. bool didUpdateDelayThisTick=false;
  358. if (isStarted==false)
  359. {
  360. RakNet::SocketDescriptor sd;
  361. if(mKeyboard->isKeyDown(KC_S))
  362. {
  363. // Start server
  364. isStarted=true;
  365. isServer=true;
  366. ShowMessage("Server started");
  367. sd.port=SERVER_PORT;
  368. }
  369. if(mKeyboard->isKeyDown(KC_C))
  370. {
  371. isStarted=true;
  372. ShowMessage(FormatString("Client started, connecting to %s", SERVER_IP_ADDRESS));
  373. // Start server
  374. isStarted=true;
  375. isServer=false;
  376. sd.port=0;
  377. }
  378. if (isStarted)
  379. {
  380. // Start RakNet, up to 32 connections if the server
  381. rakPeer = RakNet::RakPeerInterface::GetInstance();
  382. StartupResult sr = rakPeer->Startup(isServer ? 32 : 1,&sd,1);
  383. RakAssert(sr==RAKNET_STARTED);
  384. rakPeer->AttachPlugin(&replicaManager3);
  385. replicaManager3.SetNetworkIDManager(&networkIdManager);
  386. //rakPeer->SetNetworkIDManager(&networkIdManager);
  387. // The server should allow systems to connect. Clients do not need to unless you want to use RakVoice or for some other reason want to transmit directly between systems.
  388. if (isServer)
  389. {
  390. rakPeer->SetMaximumIncomingConnections(32);
  391. }
  392. else
  393. {
  394. ConnectionAttemptResult car = rakPeer->Connect(SERVER_IP_ADDRESS,SERVER_PORT,0,0);
  395. RakAssert(car==CONNECTION_ATTEMPT_STARTED);
  396. }
  397. replicaManager3.SetAutoSerializeInterval(DEFAULT_SERVER_MILLISECONDS_BETWEEN_UPDATES);
  398. // StringTable has to be called after RakPeer started, or else first call StringTable::AddRef() yourself
  399. StringTable::Instance()->AddString("Popcorn",false);
  400. }
  401. }
  402. if (isStarted)
  403. {
  404. RakNet::Packet *packet;
  405. for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
  406. {
  407. switch (packet->data[0])
  408. {
  409. case ID_CONNECTION_ATTEMPT_FAILED:
  410. ShowMessage("ID_CONNECTION_ATTEMPT_FAILED\n");
  411. break;
  412. case ID_NO_FREE_INCOMING_CONNECTIONS:
  413. ShowMessage("ID_NO_FREE_INCOMING_CONNECTIONS\n");
  414. break;
  415. case ID_CONNECTION_REQUEST_ACCEPTED:
  416. ShowMessage("ID_CONNECTION_REQUEST_ACCEPTED\n");
  417. break;
  418. case ID_NEW_INCOMING_CONNECTION:
  419. ShowMessage(FormatString("ID_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString()));
  420. break;
  421. case ID_DISCONNECTION_NOTIFICATION:
  422. ShowMessage("ID_DISCONNECTION_NOTIFICATION\n");
  423. break;
  424. case ID_CONNECTION_LOST:
  425. ShowMessage("ID_CONNECTION_LOST\n");
  426. break;
  427. }
  428. }
  429. if (isServer)
  430. {
  431. // Restart the demo every RESTART_TIMER_MS milliseconds
  432. if (popcornLifetimeCountdown<=elapsedTimeMS)
  433. {
  434. Popcorn::ClearPopcorn();
  435. CreateKernels(&replicaManager3);
  436. popcornLifetimeCountdown=RESTART_TIMER_MS;
  437. }
  438. popcornLifetimeCountdown-=elapsedTimeMS;
  439. }
  440. unsigned i;
  441. for (i=0; i < popcornList.Size(); i++)
  442. {
  443. popcornList[i]->Update(elapsedTimeMS);
  444. }
  445. }
  446. camera->moveRelative(mTranslateVector);
  447. if( mKeyboard->isKeyDown(KC_ESCAPE) || mKeyboard->isKeyDown(KC_Q) )
  448. quit=true;
  449. }
  450. // Just Ogre startup stuff
  451. virtual void PostConfigure(const char *defaultResourceConfigurationPath, bool recursive)
  452. {
  453. App3D::PostConfigure(defaultResourceConfigurationPath, false);
  454. App3D::InitSceneManager(0);
  455. App3D::InitGUIManager();
  456. App3D::InitCamera(0);
  457. App3D::InitViewport(0);
  458. ParamList pl;
  459. size_t windowHnd = 0;
  460. std::ostringstream windowHndStr;
  461. window->getCustomAttribute("WINDOW", &windowHnd);
  462. windowHndStr << windowHnd;
  463. pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
  464. mInputManager = InputManager::createInputSystem( pl );
  465. //Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
  466. mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject( OISKeyboard, false ));
  467. // Start the overlay helper class, which handles fading of overlays and other stuff
  468. overlayHelper.Startup();
  469. sceneManager->setAmbientLight( ColourValue( .5, .5, .5 ) );
  470. mainLight = sceneManager->createLight("MainLight");
  471. mainLightNode = sceneManager->getRootSceneNode()->createChildSceneNode( "MainLightNode" );
  472. mainLightNode->attachObject(mainLight);
  473. mainLight->setType(Light::LT_POINT);
  474. mainLight->setPosition(200.0f, 200.0f, 200.0f);
  475. camera->setPosition(150.0f, 150.0f, 70.0f);
  476. camera->lookAt(0.0f,50.0f,0.0f);
  477. camera->setNearClipDistance(1.0f);
  478. popcornKernel = sceneManager->createEntity("PopcornKernel", "PopcornKernel.mesh");
  479. popcornPopped = sceneManager->createEntity("PopcornPopped", "PopcornPopped.mesh");
  480. popcornLifetimeCountdown=0;
  481. sceneManager->setSkyBox(true, "Examples/SteveCubeSkyBox");
  482. isStarted=false;
  483. enableInterpolation=true;
  484. // Bug: Since updating to ogre OgreSDK_vc8_v1-7-1 from Ogre 3D 1.6.2, the first call to ShowMessage doesn't show up anymore
  485. ShowMessage("'S'erver. 'C'lient. Hold ' ' to disable interp.");
  486. ShowMessage("'S'erver. 'C'lient. Hold ' ' to disable interp.");
  487. }
  488. virtual void CreateKernels(ReplicaManager3 *replicaManager3)
  489. {
  490. RakAssert(isServer);
  491. unsigned int kernelCount;
  492. if (KERNELS_VARIANCE!=0)
  493. kernelCount = MIN_KERNELS + randomMT() % KERNELS_VARIANCE;
  494. else
  495. kernelCount = MIN_KERNELS;
  496. for (unsigned int i=0; i < kernelCount; i++)
  497. Popcorn::CreateKernel(replicaManager3);
  498. }
  499. protected:
  500. virtual char * GetWindowTitle(void) const {return (char *)"Popcorn popper";}
  501. void ShowMessage(const char *msg, float timescale=1.0f)
  502. {
  503. // Create a panel
  504. static int count=0;
  505. OverlayContainer* panel =overlayHelper.CreatePanel(FormatString("%i",count++));
  506. panel->setMetricsMode(Ogre::GMM_PIXELS);
  507. panel->setPosition(10, 10);
  508. panel->setDimensions(100, 100);
  509. //panel->setMaterialName("MaterialName"); // Optional background material
  510. // Create a text area
  511. TextAreaOverlayElement *textArea = overlayHelper.CreateTextArea(FormatString("%i",count++), "BlueHighway", panel);
  512. textArea->setMetricsMode(Ogre::GMM_PIXELS);
  513. textArea->setPosition(10, 10);
  514. textArea->setDimensions(200, 200);
  515. textArea->setCaption(msg);
  516. textArea->setCharHeight(32);
  517. textArea->setColourBottom(ColourValue(0.3, 0.5, 0.3));
  518. textArea->setColourTop(ColourValue(0.5, 0.7, 0.5));
  519. // Destroy the children (the text area) before destroying the parents.
  520. overlayHelper.FadeOverlayElement(textArea, 3000*timescale, 1000*timescale, 0.0f, true);
  521. overlayHelper.FadeOverlayElement(panel, 3000*timescale, 1000*timescale, 0.0f, true);
  522. }
  523. // Our major systems. Note the base class ExampleApplication has all the Ogre 3D systems
  524. OverlayHelper overlayHelper;
  525. bool quit;
  526. SceneNode *mainLightNode;
  527. Light *mainLight;
  528. OIS::InputManager* mInputManager;
  529. OIS::Keyboard* mKeyboard;
  530. NetworkIDManager networkIdManager;
  531. bool isStarted;
  532. RakNet::TimeMS popcornLifetimeCountdown;
  533. };
  534. #ifdef WIN32
  535. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  536. #else
  537. int main (int argc, char** argv)
  538. #endif
  539. {
  540. HWND hWnd;
  541. RakNet::TimeMS curTime, lastTime, elapsed;
  542. app = new ExampleApp;
  543. app->PreConfigure();
  544. if (app->Configure()==false)
  545. {
  546. delete app;
  547. return 0;
  548. }
  549. #ifdef WIN32
  550. app->window->getCustomAttribute("HWND", &hWnd);
  551. MSG msg;
  552. #else
  553. app->window->getCustomAttribute("GLXWINDOW", &hWnd);
  554. #endif
  555. app->PostConfigure("resources.cfg",false);
  556. lastTime=RakNet::GetTimeMS();
  557. while (app->ShouldQuit()==false)
  558. {
  559. curTime=RakNet::GetTimeMS();
  560. elapsed = curTime-lastTime;
  561. if (elapsed > 100)
  562. elapsed=100; // Spike limiter
  563. app->Update(curTime, elapsed);
  564. lastTime=curTime;
  565. app->Render(curTime);
  566. #ifdef WIN32
  567. if (PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE )>0)
  568. {
  569. TranslateMessage( &msg );
  570. DispatchMessage( &msg );
  571. }
  572. #endif
  573. // Make sure the RakNet thread runs
  574. RakSleep(0);
  575. }
  576. app->OnAppShutdown();
  577. delete app;
  578. return 0;
  579. }
粤ICP备19079148号