PageRenderTime 24ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Core/Dependencies/Engine/GameObjectManager.cpp

https://bitbucket.org/barakianc/nvidia-physx-and-apex-in-gge
C++ | 1048 lines | 674 code | 162 blank | 212 comment | 97 complexity | 60a27d2cac4c7c93457df17e6bca82bf MD5 | raw file
  1. #include "StdAfx.h"
  2. #include "GameObjectManager.h"
  3. #include "GameObject.h"
  4. #ifdef HAVOK
  5. #include "HavokObject.h"
  6. #endif
  7. #ifdef PHYSX
  8. #include "PhysXObject.h"
  9. #include "PxTask.h"
  10. #ifdef PHYSX_APEX
  11. #include "NxApex.h"
  12. #include "GGEApexRenderResourceManager.h"
  13. #include "destructible/public/NxModuleDestructible.h"
  14. #include "clothing/public/NxModuleClothing.h"
  15. #include "clothing/public/NxClothingActor.h"
  16. #include <NxParamUtils.h>
  17. #endif
  18. #endif
  19. #include "AnimationManager.h"
  20. ///AI Agent Manager
  21. #include "..\AI\AIAgentManager.h"
  22. #include "AIWorldManager.h"
  23. using namespace std;
  24. ///This function is needed for memory initialization
  25. ///If you do not have it you can not initialize the Havok Memory system
  26. ///This function is called whenever an HK_ASSERT2() function finds a problem
  27. ///Look at GameObjectManager constructor for detailed information
  28. static void HK_CALL errorReport(const char* msg, void* userArgGivenToInit){
  29. GGETRACELOG("Havok Assertion Info = %s\n",msg);
  30. }
  31. /**********************************************GameObjectManagerDefinitionsSTART*********************************************/
  32. ///Destructor of the GameObjectManager
  33. GameObjectManager::~GameObjectManager()
  34. {
  35. //RDS_LOOK our game engine creates a game object manager even if it doesnt have havok in it
  36. //so this one is not called by the first screen but when we switch to different scene in the game
  37. //this function is called by the programmer in the GameScreen's Destroy() function
  38. //clear the memory y calling all the destructors of the gameObjects created
  39. int f_iActiveGameObjectCount = m_pGameObjectList.size();
  40. if (f_iActiveGameObjectCount>0) {//this check needs to be done
  41. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end();i++)
  42. {
  43. GameObject* f_pTempGameObject = *i;
  44. delete(f_pTempGameObject);
  45. }
  46. }
  47. #ifdef HAVOK
  48. if (m_pPhysicsWorld) {
  49. m_pPhysicsWorld->markForWrite();
  50. m_pPhysicsWorld->removeReference();
  51. }
  52. if (m_bVisualDebuggerActive) {
  53. if (m_pVisualDebugger)
  54. m_pVisualDebugger->removeReference();
  55. if (m_pPhysicsContext)
  56. m_pPhysicsContext->removeReference();
  57. }
  58. if (m_pJobQueue)
  59. m_pJobQueue->~hkJobQueue();
  60. if (m_pThreadPool)
  61. m_pThreadPool->removeReference();
  62. m_pThreadPool = NULL;
  63. m_pJobQueue = NULL;
  64. m_pPhysicsWorld = NULL;
  65. m_pVisualDebugger = NULL;
  66. m_pPhysicsContext = NULL;
  67. #endif
  68. }
  69. ///GameObjectManager constructor.
  70. ///This function only initializes the memory needed by HavokPhysicsEngine
  71. GameObjectManager::GameObjectManager(){
  72. #ifdef PHYSX
  73. m_PhysXSDK = NULL;
  74. m_PhysXCooking = NULL;
  75. m_CpuDispatcher = NULL;
  76. recordMemoryAllocations = true;
  77. m_NbThreads = 1;
  78. #ifdef PHYSX_APEX
  79. m_GGEApexRender = new GGEApexRenderer();
  80. m_rewriteBuffers = false;
  81. #endif
  82. //this->CreateWorld(false);
  83. #endif
  84. #ifdef HAVOK
  85. //RDS_LOOK --> how much memory to allocate is needed to be asked to Havok Prof guys
  86. m_pMemoryRouter = hkMemoryInitUtil::initDefault(hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo(500000));// Allocates 0.5MB of physics solver buffer.
  87. hkBaseSystem::init( m_pMemoryRouter, errorReport );//HAVOK_MEMORY_INITIALIZATION_LINE
  88. //Now set every member of the GameObjectManager instance to NULL. So that we can see if they have been initialized or not by checking "==NULL"
  89. m_pThreadPool = NULL;
  90. m_pJobQueue = NULL;
  91. m_pPhysicsWorld = NULL;
  92. m_pVisualDebugger = NULL;
  93. m_pPhysicsContext = NULL;
  94. m_bVisualDebuggerActive = false;
  95. this->CreateWorld(false);
  96. #endif
  97. m_bInitializationPeriod = true;
  98. m_aiAgentManager = new GamePipe::AIAgentManager();
  99. m_aiAgentManager->initialize();
  100. m_recastManager = new AIWorldManager();
  101. m_recastManager->initialize();
  102. }
  103. #ifdef PHYSX
  104. /*void ContactCallback::onContact(physx::PxContactPair & pair, physx::PxU32 events) {
  105. printf("COLLISSSSSSSSSSSSSSSSSSSSS");
  106. //if(events & physx::PxPairFlag::eNOTIFY_TOUCH_FOUND == 0) {
  107. // return;
  108. //}
  109. if(pair.actors[0]->userData == (void*)4 || pair.actors[1]->userData == (void*)4) {
  110. std::cout << "Hit with hoop detected" << std::endl;
  111. }
  112. if(pair.actors[0]->userData == (void*)6 || pair.actors[1]->userData == (void*)6) {
  113. std::cout << "Hit with ground detected" << std::endl;
  114. }
  115. }*/
  116. physx::PxFilterFlags PhysXFilterShader(
  117. physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0,
  118. physx::PxFilterObjectAttributes attributes1, physx::PxFilterData filterData1,
  119. physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize)
  120. {
  121. //printf("COLLISIONNNN");
  122. // let triggers through
  123. if(physx::PxFilterObjectIsTrigger(attributes0) || physx::PxFilterObjectIsTrigger(attributes1))
  124. {
  125. //printf("12345");
  126. pairFlags = physx::PxPairFlag::eTRIGGER_DEFAULT | physx::PxPairFlag::eNOTIFY_TOUCH_PERSISTS;
  127. return physx::PxFilterFlag::eDEFAULT;
  128. }
  129. // generate contacts for all that were not filtered above
  130. pairFlags = physx::PxPairFlag::eSWEPT_INTEGRATION_LINEAR;
  131. pairFlags |= physx::PxPairFlag::eCONTACT_DEFAULT | physx::PxPairFlag::eNOTIFY_TOUCH_FOUND;
  132. // trigger the contact callback for pairs (A,B) where
  133. // the filtermask of A contains the ID of B and vice versa.
  134. //if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
  135. // pairFlags |= physx::PxPairFlag::eNOTIFY_TOUCH_FOUND;
  136. return physx::PxFilterFlag::eDEFAULT;
  137. }
  138. void GameObjectManager::onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count){
  139. }
  140. void GameObjectManager::onWake(physx::PxActor** actors, physx::PxU32 count){
  141. }
  142. void GameObjectManager::onSleep(physx::PxActor** actors, physx::PxU32 count){
  143. }
  144. void GameObjectManager::onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs)
  145. {
  146. }
  147. void GameObjectManager::onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count)
  148. {
  149. printf("onTrigger");
  150. bTrigger = true;
  151. for(physx::PxU32 i=0; i < count; i++)
  152. {
  153. if((&pairs[i].otherShape->getActor() == 0) && (&pairs[i].triggerShape->getActor() == 0))
  154. {
  155. //gTreasureFound = true;
  156. }
  157. }
  158. }
  159. void GameObjectManager::setTrigger(bool bt)
  160. {
  161. bTrigger = bt;
  162. }
  163. bool GameObjectManager::getTrigger()
  164. {
  165. return bTrigger;
  166. }
  167. void GameObjectManager::CreateWorld(bool f_bVisualDebuggerActive) {
  168. if(EnginePtr->GetPVDConnection() != NULL && EnginePtr->GetPVDConnection()->isConnected()){
  169. EnginePtr->GetPVDConnection()->disconnect();
  170. EnginePtr->GetPVDConnection()->release();
  171. }
  172. m_PhysXZoneManager = &physx::PxProfileZoneManager::createProfileZoneManager(EnginePtr->GetPhysXFoundation());
  173. if(!m_PhysXZoneManager){
  174. printf("createProfileZoneManager failed!");
  175. }
  176. m_PhysXSDK = PxCreatePhysics(PX_PHYSICS_VERSION, *EnginePtr->GetPhysXFoundation(), physx::PxTolerancesScale(), recordMemoryAllocations, m_PhysXZoneManager );
  177. //PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, physx::PxTolerancesScale(), recordMemoryAllocations);
  178. if(!m_PhysXSDK) {
  179. printf("PxCreatePhysics failed!");
  180. }
  181. if (!PxInitExtensions(*m_PhysXSDK)) {
  182. printf("PxInitExtensions failed!");
  183. }
  184. physx::PxCooking* m_PhysXCooking = PxCreateCooking(PX_PHYSICS_VERSION, *(EnginePtr->GetPhysXFoundation()), physx::PxCookingParams());
  185. if(!m_PhysXCooking) {
  186. printf("PxCreateCooking failed!");
  187. }
  188. physx::PxSimulationFilterShader gDefaultFilterShader = physx::PxDefaultSimulationFilterShader;
  189. physx::PxSceneDesc sceneDescC = m_PhysXSDK->getTolerancesScale();
  190. sceneDesc = &sceneDescC;
  191. sceneDesc->gravity = physx::PxVec3(0.0f, -9.81f, 0.0f);
  192. if(!sceneDesc->cpuDispatcher) {
  193. m_CpuDispatcher = physx::PxDefaultCpuDispatcherCreate(m_NbThreads);
  194. if(!m_CpuDispatcher)
  195. printf("PxDefaultCpuDispatcherCreate failed!");
  196. sceneDesc->cpuDispatcher = m_CpuDispatcher;
  197. }
  198. /*physx::pxtask::CudaContextManager *mCudaContextManager;
  199. physx::pxtask::CudaContextManagerDesc cudaContextManagerDesc;
  200. mCudaContextManager = physx::pxtask::createCudaContextManager(cudaContextManagerDesc, &m_PhysXSDK->getProfileZoneManager());
  201. if(!sceneDesc->gpuDispatcher && mCudaContextManager)
  202. {
  203. sceneDesc->gpuDispatcher = mCudaContextManager->getGpuDispatcher();
  204. }*/
  205. //ContactCallback contactCallback;
  206. //if(!sceneDesc.filterShader)
  207. //sceneDesc.filterShader = *gDefaultFilterShader;
  208. sceneDesc->filterShader = PhysXFilterShader;
  209. //sceneDesc->flags = physx::PxSceneFlag::eENABLE_SWEPT_INTEGRATION;
  210. //sceneDesc->sweepEpsilonDistance = 0.00001f;
  211. sceneDesc->simulationEventCallback = this;
  212. m_PhysXMaterial = m_PhysXSDK->createMaterial(0.5f, 0.5f, 0.4f); //static friction, dynamic friction, restitution
  213. if(!m_PhysXMaterial) {
  214. printf("createMaterial failed!");
  215. }
  216. m_PhysXScene = m_PhysXSDK->createScene(*sceneDesc);
  217. if (!m_PhysXScene)
  218. printf("createScene failed!");
  219. if (m_PhysXSDK->getPvdConnectionManager()) {
  220. physx::PxVisualDebuggerConnectionFlags connectionFlags = physx::PxVisualDebuggerExt::getAllConnectionFlags();
  221. EnginePtr->SetPVDConnection(m_PhysXSDK,connectionFlags);
  222. }
  223. #ifdef PHYSX_APEX
  224. static physx::PxDefaultErrorCallback gDefaultErrorCallback;
  225. m_ApexSDKDesc = new physx::apex::NxApexSDKDesc();
  226. m_ApexSDKDesc->physXSDK = m_PhysXSDK;
  227. m_ApexSDKDesc->cooking = m_PhysXCooking;
  228. m_ApexSDKDesc->outputStream = &gDefaultErrorCallback;
  229. //m_ApexSDKDesc->allocator = 0;
  230. //physx::apex::NxResourceCallback
  231. m_ApexSDKDesc->renderResourceManager = new GGEApexResourceManager();
  232. PX_ASSERT(m_ApexSDKDesc);
  233. m_ApexSDK = NxCreateApexSDK(*m_ApexSDKDesc);
  234. PX_ASSERT(m_ApexSDK);
  235. physx::apex::NxApexRenderDebug* apex_RenderDebug = m_ApexSDK->createApexRenderDebug(false,true);
  236. /*physx::PxMat44 pose;
  237. pose = physx::PxMat44::createIdentity();
  238. if(apex_RenderDebug){
  239. apex_RenderDebug->beginDrawGroup(pose);
  240. apex_RenderDebug->drawGrid(false,40);
  241. apex_RenderDebug->endDrawGroup();
  242. }*/
  243. m_ApexSceneDesc = new physx::apex::NxApexSceneDesc();
  244. m_ApexSceneDesc->scene = m_PhysXScene;
  245. m_ApexScene = m_ApexSDK->createScene(*m_ApexSceneDesc);
  246. //create destruction module
  247. m_apexDestructibleModule = static_cast<physx::apex::NxModuleDestructible*>(m_ApexSDK->createModule("Destructible"));
  248. NxParameterized::Interface* params = m_apexDestructibleModule->getDefaultModuleDesc();
  249. m_apexDestructibleModule->init(*params);
  250. //create cloth module
  251. m_apexClothModule = static_cast<physx::apex::NxModuleClothing*>(m_ApexSDK->createModule("Clothing"));
  252. if(m_apexClothModule != NULL){
  253. NxParameterized::Interface* clothDesc = m_apexClothModule->getDefaultModuleDesc();
  254. NxParameterized::setParamU32(*clothDesc,"maxNumCompartments",3);
  255. NxParameterized::setParamU32(*clothDesc,"maxUnusedPhysXResources",5);
  256. m_apexClothModule->init(*clothDesc);
  257. }
  258. //set up view and proj matricies
  259. Ogre::Camera* oCamera = EnginePtr->GetForemostGameScreen()->GetActiveCamera();
  260. physx::PxMat44 projMatrix;
  261. physx::PxMat44 viewMat;
  262. Ogre::Matrix4 ogProj = oCamera->getProjectionMatrix();
  263. Ogre::Matrix4 ogView = oCamera->getViewMatrix();
  264. for(int i = 0; i < 4; i++){
  265. for(int j = 0; j < 4; j++){
  266. projMatrix[i][j] = ogProj[i][j];
  267. viewMat[i][j] = ogView[i][j];
  268. }
  269. }
  270. int numproj = m_ApexScene->getNumProjMatrices();
  271. const physx::PxU32 viewIDlookAtRightHand = m_ApexScene->allocViewMatrix(physx::apex::ViewMatrixType::LOOK_AT_RH);
  272. const physx::PxU32 projIDperspectiveCubicRightHand = m_ApexScene->allocProjMatrix(physx::apex::ProjMatrixType::USER_CUSTOMIZED);
  273. m_ApexScene->setProjMatrix(projMatrix,projIDperspectiveCubicRightHand);
  274. m_ApexScene->setProjParams(0.1f, 10000.0f, 45.0f,EnginePtr->GetRenderWindow()->getWidth(),EnginePtr->GetRenderWindow()->getHeight(),projIDperspectiveCubicRightHand);
  275. m_ApexScene->setViewMatrix(viewMat,viewIDlookAtRightHand);
  276. m_ApexScene->setUseViewProjMatrix(viewIDlookAtRightHand,projIDperspectiveCubicRightHand);
  277. //Get APEX framework debug rendering parameters
  278. NxParameterized::Interface &dbgRenderParams = *m_ApexScene->getDebugRenderParams();
  279. //Get clothing debug rendering parameters
  280. NxParameterized::Interface &dbgRenderParamsClothing = *m_ApexScene->getModuleDebugRenderParams("Clothing");
  281. //Get Destruction debug rendering parameters
  282. NxParameterized::Interface &dbgRenderParamsDestruction = *m_ApexScene->getModuleDebugRenderParams("Destructible");
  283. /*NxParameterized::setParamBool(dbgRenderParams, "VISUALIZATION_ENABLE", true);
  284. NxParameterized::setParamF32(dbgRenderParams, "VISUALIZATION_SCALE", 1.0f);
  285. NxParameterized::setParamBool(dbgRenderParamsClothing,"VISUALIZE_CLOTHING_ACTOR",true);
  286. NxParameterized::setParamF32(dbgRenderParamsClothing, "VISUALIZE_CLOTHING_PHYSICS_MESH_WIRE", 0.9f);
  287. NxParameterized::setParamBool(dbgRenderParamsDestruction,"VISUALIZE_DESTRUCTIBLE_ACTOR",true);*/
  288. m_ApexActors = new m_apexActorStruct[25];
  289. m_ApexActorCount = 0;
  290. #endif
  291. }
  292. #endif
  293. void GameObjectManager::DeleteGameObjects()
  294. {
  295. int f_iActiveGameObjectCount = m_pGameObjectList.size();
  296. if (f_iActiveGameObjectCount>0) {//this check needs to be done
  297. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end();i++)
  298. {
  299. GameObject* f_pTempGameObject = *i;
  300. /*GraphicsObject* graphicsObject = f_pTempGameObject->m_pGraphicsObject;
  301. if (graphicsObject)
  302. {
  303. Ogre::SceneNode* sceneNode = graphicsObject->m_pOgreSceneNode;
  304. Ogre::String entityNodeName = sceneNode->getName();;
  305. //sceneNode = sceneNode->getParentSceneNode();
  306. //sceneNode->detachObject(entityNodeName);
  307. //EnginePtr->GetForemostGameScreen()->GetDefaultSceneManager()->destroySceneNode(sceneNode);
  308. }*/
  309. delete(f_pTempGameObject);
  310. }
  311. }
  312. }
  313. #ifdef HAVOK
  314. ///This creates the Physics world for the user according to the values in the hkpWorldinfo
  315. ///The boolean parameter(f_bVisualDebuggerActive) is set to false as default
  316. void GameObjectManager::CreateWorld(bool f_bVisualDebuggerActive)
  317. {
  318. // Most of the comments are copied and pasted from ConsoleExampleMt.cpp of HavokDemos folder (2010 version)
  319. //RDS_HARDCODED
  320. ///This variable is set for being able to change the game running speed.
  321. m_fWorldStep = 1/60.0f;
  322. //a sanity check.if the world is already created do not create it again and again
  323. if (m_pPhysicsWorld==NULL)
  324. {// Initialize the multi-threading classes, hkJobQueue, and hkJobThreadPool
  325. // Most of the comments are copied and pasted from ConsoleExampleMt.cpp of HavokDemos folder (2010 version)
  326. // They can be used for all Havok multithreading tasks. In this exmaple we only show how to use
  327. // them for physics, but you can reference other multithreading demos in the demo framework
  328. // to see how to multithread other products. The model of usage is the same as for physics.
  329. // The hkThreadpool has a specified number of threads that can run Havok jobs. These can work
  330. // alongside the main thread to perform any Havok multi-threadable computations.
  331. // The model for running Havok tasks in Spus and in auxilary threads is identical. It is encapsulated in the
  332. // class hkJobThreadPool. On PlayStation(R)3 we initialize the SPU version of this class, which is simply a SPURS taskset.
  333. // On other multi-threaded platforms we initialize the CPU version of this class, hkCpuJobThreadPool, which creates a pool of threads
  334. // that run in exactly the same way. On the PlayStation(R)3 we could also create a hkCpuJobThreadPool. However, it is only
  335. // necessary (and advisable) to use one Havok PPU thread for maximum efficiency. In this case we simply use this main thread
  336. // for this purpose, and so do not create a hkCpuJobThreadPool.
  337. // Get the number of physical threads available on the system
  338. hkGetHardwareInfo(m_hardwareInfo);
  339. m_iTotalNumThreadsUsed = m_hardwareInfo.m_numThreads;
  340. m_threadPoolCinfo.m_numThreads = m_iTotalNumThreadsUsed - 1;// We use one less than this for our thread pool, because we must also use this thread for our simulation
  341. m_threadPoolCinfo.m_timerBufferPerThreadAllocation = 200000;// This line enables timers collection, by allocating 200 Kb per thread. If you leave this at its default (0) timer collection will not be enabled.
  342. m_pThreadPool = new hkCpuJobThreadPool( m_threadPoolCinfo );
  343. // We also need to create a Job queue. This job queue will be used by all Havok modules to run multithreaded work.
  344. // Here we only use it for physics.
  345. m_jobQueuInfo.m_jobQueueHwSetup.m_numCpuThreads = m_iTotalNumThreadsUsed;
  346. m_pJobQueue = new hkJobQueue(m_jobQueuInfo);
  347. // Enable monitors for this thread.-->I am not really sure what this means now RDS_LOOK
  348. hkMonitorStream::getInstance().resize(200000);// Monitors have been enabled for thread pool threads already (see above comment).
  349. // <PHYSICS-ONLY>: Create the physics world.
  350. // At this point you would initialize any other Havok modules you are using.
  351. // The world cinfo contains global simulation parameters, including gravity, solver settings etc.
  352. m_worldInfo.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_MULTITHREADED;// Set the simulation type of the world to multi-threaded.
  353. // Flag objects that fall "out of the world" to be automatically removed - just necessary for this physics scene
  354. // In other words, objects that fall "out of the world" will be automatically removed
  355. m_worldInfo.m_broadPhaseBorderBehaviour = hkpWorldCinfo::BROADPHASE_BORDER_REMOVE_ENTITY;
  356. //RDS_HARDCODED values here --> just for me to see if I can make this part better
  357. //standard gravity settings, collision tolerance and world size
  358. m_worldInfo.m_gravity.set(0,-9.8f,0);
  359. //I do not know what the next line does. For this demo it doesnt change anything if/if not having this line enabled
  360. //m_worldInfo.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_8ITERS_MEDIUM);
  361. m_worldInfo.m_collisionTolerance = 0.1f;
  362. //This will effect the removal of objects when they fall out of the world.
  363. //If you have BROADPHASE_BORDER_REMOVE_ENTITY then your entities will be removed from Havok according to this number you set
  364. m_worldInfo.setBroadPhaseWorldSize(5000.0f);
  365. m_pPhysicsWorld = new hkpWorld(m_worldInfo);//initialize world with created info
  366. // RDS_PREVDEFINITIONS this line is from another HavokWrapper. Helps when using VisualDebugger
  367. // Disable deactivation, so that you can view timers in the VDB. This should not be done in your game.
  368. m_pPhysicsWorld->m_wantDeactivation = false;
  369. // When the simulation type is SIMULATION_TYPE_MULTITHREADED, in the debug build, the sdk performs checks
  370. // to make sure only one thread is modifying the world at once to prevent multithreaded bugs. Each thread
  371. // must call markForRead / markForWrite before it modifies the world to enable these checks.
  372. m_pPhysicsWorld->markForWrite();
  373. // Register all collision agents, even though only box - box will be used in this particular example.
  374. // It's important to register collision agents before adding any entities to the world.
  375. hkpAgentRegisterUtil::registerAllAgents( m_pPhysicsWorld->getCollisionDispatcher() );
  376. m_pPhysicsWorld->registerWithJobQueue( m_pJobQueue );// We need to register all modules we will be running multi-threaded with the job queue
  377. m_pPhysicsWorld->unmarkForWrite();// Now we have finished modifying the world, release our write marker.
  378. }
  379. if ((m_bVisualDebuggerActive==false)&&(f_bVisualDebuggerActive==true)&&(m_pVisualDebugger==NULL))
  380. {// Initialize the VDB
  381. m_bVisualDebuggerActive = true;
  382. // <PHYSICS-ONLY>: Register physics specific visual debugger processes
  383. // By default the VDB will show debug points and lines, however some products such as physics and cloth have additional viewers
  384. // that can show geometries etc and can be enabled and disabled by the VDB app.
  385. {
  386. // The visual debugger so we can connect remotely to the simulation
  387. // The context must exist beyond the use of the VDB instance, and you can make
  388. // whatever contexts you like for your own viewer types.
  389. m_pPhysicsContext = new hkpPhysicsContext();// Create context for Visual Debugger
  390. hkpPhysicsContext::registerAllPhysicsProcesses(); //Reigster all the physics viewers
  391. m_pPhysicsWorld->markForWrite();//RDS for the following line to be able to have effect on m_pPhysicsWorld
  392. m_pPhysicsContext->addWorld(m_pPhysicsWorld); // add the physics world so the viewers can see it
  393. m_arrayPhysicsContext.pushBack(m_pPhysicsContext);
  394. m_pPhysicsWorld->unmarkForWrite();// Now we have finished modifying the world, release our write marker.
  395. }
  396. m_pVisualDebugger = new hkVisualDebugger(m_arrayPhysicsContext);//Create VDB instance
  397. m_pVisualDebugger->serve();
  398. }
  399. }
  400. #endif
  401. #ifdef PHYSX
  402. void GameObjectManager::SetVisualDebugger(bool f_bVisualDebuggerActive) {
  403. }
  404. #endif
  405. #ifdef HAVOK
  406. void GameObjectManager::SetVisualDebugger(bool f_bVisualDebuggerActive)
  407. {
  408. //if the VisualDebugger has not been initialized first initialise it
  409. if ((m_bVisualDebuggerActive==false)&&(f_bVisualDebuggerActive==true)&&(m_pVisualDebugger==NULL))
  410. {// Initialize the VDB
  411. m_bVisualDebuggerActive = true;
  412. // <PHYSICS-ONLY>: Register physics specific visual debugger processes
  413. // By default the VDB will show debug points and lines, however some products such as physics and cloth have additional viewers
  414. // that can show geometries etc and can be enabled and disabled by the VDB app.
  415. {
  416. // The visual debugger so we can connect remotely to the simulation
  417. // The context must exist beyond the use of the VDB instance, and you can make
  418. // whatever contexts you like for your own viewer types.
  419. m_pPhysicsContext = new hkpPhysicsContext();// Create context for Visual Debugger
  420. hkpPhysicsContext::registerAllPhysicsProcesses(); //Reigster all the physics viewers
  421. m_pPhysicsWorld->markForWrite();//RDS for the following line to be able to have effect on m_pPhysicsWorld
  422. m_pPhysicsContext->addWorld(m_pPhysicsWorld); // add the physics world so the viewers can see it
  423. m_arrayPhysicsContext.pushBack(m_pPhysicsContext);
  424. m_pPhysicsWorld->unmarkForWrite();// Now we have finished modifying the world, release our write marker.
  425. }
  426. m_pVisualDebugger = new hkVisualDebugger(m_arrayPhysicsContext);//Create VDB instance
  427. m_pVisualDebugger->serve();
  428. }
  429. //if the visual debugger was already running and user wanted to just close the connection for some time
  430. //instead of clearing the content and deleting pointers just shutdown the connection
  431. if ((m_bVisualDebuggerActive)&&(f_bVisualDebuggerActive==false)) {
  432. if (m_pVisualDebugger)//just a sanity check
  433. m_pVisualDebugger->shutdown();
  434. }
  435. //if the user initialized the visualdebugger before and wants to reactivate the visual debugger for some purpose
  436. //this will be enough
  437. if ((m_bVisualDebuggerActive==false)&&(m_pVisualDebugger!=NULL)&&(f_bVisualDebuggerActive==true))
  438. {// Initialize the VDB back again if it was set to true
  439. m_bVisualDebuggerActive=true;
  440. m_pVisualDebugger->serve();
  441. }
  442. }
  443. #endif
  444. void GameObjectManager::RefreshGameObjectsList(bool fromGameEngine)
  445. {
  446. //delete the ones to be deleted
  447. int f_iToBeDeletedGameObjectCount = m_pGameObjectsToDeleteList.size();
  448. if (f_iToBeDeletedGameObjectCount>0)
  449. {
  450. if (m_bReachDeleteList || !fromGameEngine)
  451. {
  452. m_bReachDeleteList = false;
  453. for (list<GameObject*>::iterator i = m_pGameObjectsToDeleteList.begin(); i != m_pGameObjectsToDeleteList.end();i++)
  454. {
  455. GameObject* f_pTempGameObject = *i;
  456. m_pGameObjectList.remove(f_pTempGameObject);
  457. delete(f_pTempGameObject);
  458. }
  459. m_pGameObjectsToDeleteList.clear();
  460. m_bReachDeleteList = true;
  461. }
  462. }
  463. //add the ones to be added
  464. int f_iToBeAddedGameObjectCount = m_pGameObjectsToAddList.size();
  465. if (f_iToBeAddedGameObjectCount>0)
  466. {
  467. if (m_bReachAddList || !fromGameEngine)
  468. {
  469. m_bReachAddList=false;
  470. for (list<GameObject*>::iterator i = m_pGameObjectsToAddList.begin(); i != m_pGameObjectsToAddList.end();i++)
  471. {
  472. GameObject* f_pTempGameObject = *i;
  473. m_pGameObjectList.push_back(f_pTempGameObject);
  474. }
  475. m_pGameObjectsToAddList.clear();
  476. m_bReachAddList=true;
  477. }
  478. }
  479. }
  480. #ifdef PHYSX
  481. void GameObjectManager::UpdateWorld() {
  482. if (m_pPhysicsWorld==NULL)//if physics world is not created just return
  483. return;
  484. RefreshGameObjectsList();
  485. #ifdef PHYSX_APEX
  486. m_ApexScene->simulate(EnginePtr->GetDeltaTime());
  487. #else
  488. m_PhysXScene->simulate(EnginePtr->GetDeltaTime());
  489. m_PhysXScene->fetchResults(true);
  490. #endif
  491. if (m_pGameObjectList.begin() != m_pGameObjectList.end())
  492. {
  493. //update all the gameobjects
  494. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end();i++)
  495. {
  496. GameObject* f_pTempGameObject = *i;
  497. if (!f_pTempGameObject->update()||!f_pTempGameObject->isActive())
  498. {
  499. if (m_bReachDeleteList)
  500. {
  501. m_pGameObjectsToDeleteList.push_back(f_pTempGameObject);
  502. }
  503. }
  504. }
  505. }
  506. #ifdef PHYSX_APEX
  507. //update the projection and view matricies this frame
  508. Ogre::Camera* oCamera = EnginePtr->GetForemostGameScreen()->GetActiveCamera();
  509. physx::PxMat44 projMatrix;
  510. physx::PxMat44 viewMat;
  511. Ogre::Matrix4 ogProj = oCamera->getProjectionMatrix();
  512. Ogre::Matrix4 ogView = oCamera->getViewMatrix();
  513. for(int i = 0; i < 4; i++){
  514. for(int j = 0; j < 4; j++){
  515. projMatrix[i][j] = ogProj[i][j];
  516. viewMat[i][j] = ogView[i][j];
  517. }
  518. }
  519. //static const physx::PxU32 viewIDlookAtRightHand = m_ApexScene->allocViewMatrix(physx::apex::ViewMatrixType::LOOK_AT_RH);
  520. //static const physx::PxU32 projIDperspectiveCubicRightHand = m_ApexScene->allocProjMatrix(physx::apex::ProjMatrixType::USER_CUSTOMIZED);
  521. m_ApexScene->setProjMatrix(projMatrix,0);
  522. m_ApexScene->setProjParams(0.1f, 10000.0f, 45.0f,EnginePtr->GetRenderWindow()->getWidth(),EnginePtr->GetRenderWindow()->getHeight(),0);
  523. m_ApexScene->setViewMatrix(viewMat,0);
  524. m_ApexScene->setUseViewProjMatrix(0,0);
  525. /*physx::apex::NxApexRenderableIterator* iter = m_ApexScene->createRenderableIterator();
  526. for( physx::apex::NxApexRenderable *r = iter->getFirst() ; r ; r = iter->getNext() ){
  527. GGEApexRenderer apexRenderer;
  528. apexRenderer.m_materialName = "lambert2";
  529. r->lockRenderResources();
  530. r->updateRenderResources(m_rewriteBuffers);
  531. r->dispatchRenderResources(apexRenderer);
  532. r->unlockRenderResources();
  533. }
  534. iter->release();*/
  535. //update all the apex actors in the array
  536. for(int i = 0; i < m_ApexActorCount; i++){
  537. GGEApexRenderer apexRenderer;
  538. apexRenderer.m_materialName = m_ApexActors[i].m_matName;
  539. switch(m_ApexActors[i].m_actortype)
  540. {
  541. //destructible object
  542. case(0):
  543. {
  544. physx::apex::NxDestructibleActor* destrcActor = (physx::apex::NxDestructibleActor*)(m_ApexActors[i].m_apexActor);
  545. destrcActor->lockRenderResources();
  546. destrcActor->updateRenderResources();
  547. destrcActor->dispatchRenderResources(apexRenderer);
  548. destrcActor->unlockRenderResources();
  549. break;
  550. }
  551. //cloth object
  552. case (1):
  553. {
  554. physx::apex::NxClothingActor* clothActor = (physx::apex::NxClothingActor*)(m_ApexActors[i].m_apexActor);
  555. clothActor->lockRenderResources();
  556. clothActor->updateRenderResources();
  557. clothActor->dispatchRenderResources(apexRenderer);
  558. clothActor->unlockRenderResources();
  559. break;
  560. }
  561. default:
  562. break;
  563. }
  564. }
  565. //update the apex scene
  566. GGEApexRenderer apexRenderer;
  567. apexRenderer.m_materialName = "lambert2";
  568. m_ApexScene->prepareRenderResourceContexts();
  569. m_ApexScene->lockRenderResources();
  570. m_ApexScene->updateRenderResources();
  571. m_ApexScene->dispatchRenderResources(apexRenderer);
  572. m_ApexScene->unlockRenderResources();
  573. physx::PxU32 errorState = 0;
  574. //call fetch results to finish the simulation for this frame
  575. m_ApexScene->fetchResults(true,&errorState);
  576. #endif
  577. }
  578. #endif
  579. #ifdef HAVOK
  580. ///This function should be called in the update loop of the gameScreen to update every object in the GameObjectList
  581. ///This function takes action according to the GameObjectType specified in each GameObject instance
  582. void GameObjectManager::UpdateWorld()
  583. {
  584. if (m_pPhysicsWorld==NULL)//if physics world is not created just return
  585. return;
  586. if (m_bInitializationPeriod)
  587. m_bInitializationPeriod=false;
  588. #ifdef GGE_PROFILER2
  589. float starttime;
  590. starttime= (float)GGE_Profiler2Ptr->m_pTimer2->getMicroseconds();
  591. GGE_Profiler2Ptr->SetPhysicsStartTime(starttime);
  592. #endif
  593. RefreshGameObjectsList();
  594. //if the frame per second gets less than 5 fps just iterate the havok world as if it is 5fps
  595. //this helps a lot in the initialization of the screen
  596. //EnginePtr->GetDeltaTime() can reach up to 18 which will iterate havok world 18 seconds for 1 frame
  597. m_fWorldStep = EnginePtr->GetDeltaTime();
  598. if (m_fWorldStep>1.0f/5.0f)
  599. m_fWorldStep=1.0f/5.0f;
  600. //unsigned long long f_iActiveGameObjectCount = m_pGameObjectList.size();
  601. if (m_pGameObjectList.begin() != m_pGameObjectList.end())
  602. {
  603. //update all the gameobjects
  604. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end();i++)
  605. {
  606. GameObject* f_pTempGameObject = *i;
  607. if (!f_pTempGameObject->isActive()||!f_pTempGameObject->update())
  608. {
  609. if (m_bReachDeleteList)
  610. {
  611. m_pGameObjectsToDeleteList.push_back(f_pTempGameObject);
  612. }
  613. }
  614. }
  615. //RDS_LOOK I do not know why these are here for any question dogasiyli@hotmail.com
  616. // Updating visual debugger should happen after all the updates in the world have occured
  617. if (m_bVisualDebuggerActive) {
  618. if (m_pPhysicsContext!=NULL)//NULL check is just a sanity check
  619. m_pPhysicsContext->syncTimers(m_pThreadPool);
  620. if (m_pVisualDebugger!=NULL)//NULL check is just a sanity check
  621. m_pVisualDebugger->step();
  622. }
  623. hkMonitorStream::getInstance().reset();
  624. m_pThreadPool->clearTimerData();
  625. }
  626. m_aiAgentManager->update(EnginePtr->GetDeltaTime());
  627. #ifdef GGE_PROFILER2
  628. float endtime;
  629. endtime = (float)GGE_Profiler2Ptr->m_pTimer2->getMicroseconds();
  630. GGE_Profiler2Ptr->SetPhysicsEndTime(endtime);
  631. #endif
  632. // XXX UPDATE THE PHYSICS WORLD LAST!
  633. // Random crashes can occur if you are dealing with many many havok objects otherwise.
  634. // Crashes still occur if too many TOI events happen between havok objects
  635. // YOU HAVE BEEN WARNED
  636. if (m_pPhysicsWorld!=NULL)
  637. m_pPhysicsWorld->stepMultithreaded(m_pJobQueue,m_pThreadPool,m_fWorldStep);
  638. }
  639. #endif
  640. #ifdef PHYSX
  641. void GameObjectManager::PushBackManager()
  642. {
  643. return;
  644. }
  645. void GameObjectManager::PopBackManager()
  646. {
  647. return;
  648. }
  649. #endif
  650. #ifdef HAVOK
  651. void GameObjectManager::PushBackManager()
  652. {
  653. if (m_bVisualDebuggerActive) {
  654. if (m_pVisualDebugger)
  655. m_pVisualDebugger->shutdown();
  656. }
  657. }
  658. void GameObjectManager::PopBackManager()
  659. {
  660. if ((m_bVisualDebuggerActive)&&(m_pVisualDebugger!=NULL))//NULL check is just a sanity check
  661. {// Initialize the VDB back again if it was set to true
  662. m_pVisualDebugger->serve();
  663. }
  664. }
  665. #endif
  666. ///Adds a GameObject to GameObjectManager list
  667. void GameObjectManager::AddGameObject(GameObject* f_pNewGameObject)
  668. {
  669. if (f_pNewGameObject==NULL)
  670. return;
  671. if (m_bInitializationPeriod)
  672. {
  673. m_pGameObjectList.push_back(f_pNewGameObject);
  674. if(f_pNewGameObject->m_eObjectType)
  675. {
  676. GGETRACELOG("Added ObjectType"); //1st check if Object type exists cuz of compatibility with old .scene file
  677. char str[10];
  678. _itoa_s(f_pNewGameObject->m_eObjectType,str,10);
  679. GGETRACELOG(str);
  680. }
  681. else
  682. {
  683. GGETRACELOG("Added Old Object");
  684. }
  685. if(f_pNewGameObject->m_eCollisionShapeType)
  686. {
  687. GGETRACELOG("Added CollisionShapeType");
  688. char str2[10];
  689. _itoa_s(f_pNewGameObject->m_eCollisionShapeType,str2,10);
  690. GGETRACELOG(str2);
  691. }
  692. else
  693. {
  694. GGETRACELOG("Added Old Object without collision shape type");
  695. }
  696. }
  697. else
  698. {
  699. //while (!m_bReachAddList);
  700. GGETRACELOG("Initialization Period false block");
  701. m_bReachAddList = false;
  702. m_pGameObjectsToAddList.push_back(f_pNewGameObject);
  703. m_bReachAddList = true;
  704. }
  705. }
  706. ///Deletes a GameObject from GameObjectManager list
  707. void GameObjectManager::RemoveGameObject(GameObject* f_pNewGameObject)
  708. {
  709. if ((m_pGameObjectList.size()<1)&&(f_pNewGameObject==NULL))
  710. return;
  711. if (this->HasGameObject(f_pNewGameObject->m_pGraphicsObject->m_sOgreUniqueName))
  712. {
  713. //while (!m_bReachDeleteList);
  714. m_bReachDeleteList = false;
  715. m_pGameObjectsToDeleteList.push_back(f_pNewGameObject);
  716. m_bReachDeleteList = true;
  717. }
  718. }
  719. int GameObjectManager::GetNumOfGameObjects()
  720. {
  721. if (m_pGameObjectList.size()<1)
  722. return 0;
  723. return m_pGameObjectList.size();
  724. }
  725. ///This function returns true if there is a GameObject with an entity that has the given name
  726. bool GameObjectManager::HasGameObject(Ogre::String f_sOgreUniqueName)
  727. {
  728. //RDS_IMPROVE Needs checking if it is doing sth incorrect
  729. //I think we should pass the OgreSceneManager and make sth like
  730. //return OgreSceneManager->hasEntity(f_sTempUniqueName);
  731. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end(); i++)
  732. {
  733. GameObject* f_pTempGameObject = *i;
  734. if(f_pTempGameObject->m_pGraphicsObject != NULL)
  735. {
  736. if (f_pTempGameObject->m_pGraphicsObject->m_sOgreUniqueName.compare(f_sOgreUniqueName)==0)
  737. {
  738. return true;
  739. }
  740. }
  741. }
  742. return false;
  743. }
  744. ///This function returns the GameObject with an entity that has the given name, if no such GameObject exist it returns NULL
  745. GameObject* GameObjectManager::GetGameObject(Ogre::String f_sOgreUniqueName)
  746. {
  747. //RDS_IMPROVE Needs checking if it is doing sth incorrect
  748. //I think we should pass the OgreSceneManager and make sth like
  749. //if (OgreSceneManager->hasEntity(f_sTempUniqueName))
  750. // return OgreSceneManager->getEntity(f_sTempUniqueName);
  751. //return NULL;
  752. for (list<GameObject*>::iterator i = m_pGameObjectList.begin(); i != m_pGameObjectList.end(); i++)
  753. {
  754. GameObject* f_pTempGameObject = *i;
  755. if(f_pTempGameObject->m_pGraphicsObject != NULL)
  756. {
  757. if (f_pTempGameObject->m_pGraphicsObject->m_sOgreUniqueName.compare(f_sOgreUniqueName)==0)
  758. {
  759. return f_pTempGameObject;
  760. }
  761. }
  762. }
  763. return NULL;
  764. }
  765. #ifdef HAVOK
  766. ///This Function returns the created hkpWorld
  767. hkpWorld* GameObjectManager::GetWorld(){return m_pPhysicsWorld;}
  768. #endif
  769. #ifdef PHYSX
  770. physx::PxPhysics* GameObjectManager::GetPhysXWorld(){
  771. return m_PhysXSDK;
  772. }
  773. physx::PxScene* GameObjectManager::GetPhysXScene() {
  774. return m_PhysXScene;
  775. }
  776. physx::PxCooking* GameObjectManager::GetPhysXCooking() {
  777. return m_PhysXCooking;
  778. }
  779. physx::PxSceneDesc* GameObjectManager::GetPhysXDesc()
  780. {
  781. return sceneDesc;
  782. }
  783. physx::PxProfileZoneManager* GameObjectManager::GetPhysXZoneManager(){
  784. return m_PhysXZoneManager;
  785. }
  786. #ifdef PHYSX_APEX
  787. physx::apex::NxApexSDK* GameObjectManager::GetApexSDK(){
  788. return m_ApexSDK;
  789. }
  790. physx::apex::NxApexSDKDesc* GameObjectManager::GetApexSDKDesc(){
  791. return m_ApexSDKDesc;
  792. }
  793. physx::apex::NxApexScene* GameObjectManager::GetApexScene(){
  794. return m_ApexScene;
  795. }
  796. physx::apex::NxApexSceneDesc* GameObjectManager::GetApexSceneDesc(){
  797. return m_ApexSceneDesc;
  798. }
  799. physx::apex::NxModuleDestructible* GameObjectManager::GetDestructibleModule(){
  800. return m_apexDestructibleModule;
  801. }
  802. GGEApexRenderer* GameObjectManager::GetApexRender(){
  803. return m_GGEApexRender;
  804. }
  805. void GameObjectManager::AddApexActor(physx::apex::NxApexActor* actor,std::string mat,int actortype){
  806. if(m_ApexActorCount < 25){
  807. m_ApexActors[m_ApexActorCount].m_apexActor = actor;
  808. m_ApexActors[m_ApexActorCount].m_matName = mat;
  809. m_ApexActors[m_ApexActorCount].m_actortype = actortype;
  810. m_ApexActorCount++;
  811. }
  812. }
  813. #endif
  814. #endif
  815. GamePipe::AIAgentManager* GameObjectManager::getAIAgentManager()
  816. {
  817. return m_aiAgentManager;
  818. };
  819. AIWorldManager* GameObjectManager::getAIWorldManager()
  820. {
  821. return m_recastManager;
  822. };
  823. #ifdef HAVOK
  824. ///This function casts a ray from a point to the other and sets the pointer variables according to the closest hit
  825. bool GameObjectManager::castRay( Ogre::Vector3 f_vCastFrom,
  826. Ogre::Vector3 f_vCastTo,
  827. hkpRigidBody** f_pFirstCollidedRigidBody,
  828. GameObject** f_pCollidedGameObject,
  829. Ogre::Vector3* f_vReturnCollisionPoint
  830. )
  831. {
  832. hkpWorldRayCastInput input;
  833. input.m_from.set(f_vCastFrom.x, f_vCastFrom.y, f_vCastFrom.z);
  834. input.m_to.set( f_vCastTo.x, f_vCastTo.y, f_vCastTo.z);
  835. hkpClosestRayHitCollector output;
  836. m_pPhysicsWorld->castRay(input, output );
  837. // These comments are from HavokDemos_2010
  838. // To visualise the raycast we make use of a macro defined in "hkDebugDisplay.h" called HK_DISPLAY_LINE.
  839. // The macro takes three parameters: a start point, an end point and the line color.
  840. // If a hit is found we display a RED line from the raycast start point to the point of intersection and mark that
  841. // point with a small RED cross. The intersection point is calculated using: startWorld + (result.m_mindist * endWorld).
  842. //
  843. // If no hit is found we simply display a GREY line between the raycast start and end points.
  844. if( output.hasHit() )
  845. {
  846. hkVector4 intersectionPointWorld;
  847. intersectionPointWorld.setInterpolate4( input.m_from, input.m_to, output.getHit().m_hitFraction );
  848. //now lets store the collision point to send back to who ever called the function
  849. hkReal f_fIntersectionPoint[3];
  850. intersectionPointWorld.store3(f_fIntersectionPoint);
  851. *f_vReturnCollisionPoint = Ogre::Vector3(f_fIntersectionPoint[0],f_fIntersectionPoint[1],f_fIntersectionPoint[2]);
  852. //some helper lines for visual debugger
  853. HK_DISPLAY_LINE( input.m_from, intersectionPointWorld, hkColor::RED);
  854. HK_DISPLAY_ARROW( intersectionPointWorld, output.getHit().m_normal, hkColor::CYAN);
  855. //get the rigidBody pointer of the collidable (in other words owner of the root collidable)
  856. //by this line we will also send the collided rigidBody pointer to the function caller
  857. (*f_pFirstCollidedRigidBody) = (hkpRigidBody *)(output.getHit().m_rootCollidable->getOwner());
  858. //Now check if the rigidBody has a collision listener.
  859. //If it has a collisionlistener we can also send the GameObject pointer back to the function caller too
  860. if ((*f_pFirstCollidedRigidBody)->getContactListeners().getSize()>0)
  861. {
  862. //if we are here it means the rigidbody has a collision listener
  863. //so we are gonna grab it, but we will just grab the first one because normally 1 gameObject should have 1 collision listener
  864. //this assumption should be correct because I create collision listeners for gameObjects and I only have 1 to 1 attachment
  865. CollisionListener* f_pOtherGameObjectListener = (CollisionListener*)((*f_pFirstCollidedRigidBody)->getContactListeners()[0]);
  866. //Now get the pointer and set it to the passed parameter so that we are sending back the pointer of the collided gameObject
  867. *f_pCollidedGameObject = f_pOtherGameObjectListener->m_pGameObject;
  868. }
  869. return true;
  870. }
  871. else
  872. {
  873. // Otherwise draw as GREY
  874. HK_DISPLAY_LINE(input.m_from, input.m_to, hkColor::rgbFromChars(200, 200, 200));
  875. }
  876. return false;
  877. };
  878. #endif
  879. /***********************************************GameObjectManagerDefinitionsEND**********************************************/