pscene_collision.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWPhys *
  23. * *
  24. * $Archive:: /Commando/Code/wwphys/pscene_collision.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Greg_h $*
  29. * *
  30. * $Modtime:: 2/13/02 2:16p $*
  31. * *
  32. * $Revision:: 10 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "pscene.h"
  38. #include "physcoltest.h"
  39. #include "physinttest.h"
  40. #include "staticaabtreecull.h"
  41. #include "dynamicaabtreecull.h"
  42. #include "physgridcull.h"
  43. #include "lightcull.h"
  44. #include "staticphys.h"
  45. bool PhysicsSceneClass::Do_Groups_Collide(int group0,int group1)
  46. {
  47. int index = group0 | (group1 << COLLISION_FLAG_SHIFT);
  48. return AllowCollisionFlags[index];
  49. }
  50. void PhysicsSceneClass::Enable_Collision_Detection(int group0,int group1)
  51. {
  52. assert(group0 >= 0);
  53. assert(group1 >= 0);
  54. assert(group0 <= MAX_COLLISION_GROUP);
  55. assert(group1 <= MAX_COLLISION_GROUP);
  56. unsigned int index;
  57. index = group0 | (group1 << COLLISION_FLAG_SHIFT);
  58. AllowCollisionFlags[index] = 1;
  59. index = group1 | (group0 << COLLISION_FLAG_SHIFT);
  60. AllowCollisionFlags[index] = 1;
  61. }
  62. void PhysicsSceneClass::Disable_Collision_Detection(int group0,int group1)
  63. {
  64. assert(group0 >= 0);
  65. assert(group1 >= 0);
  66. assert(group0 <= MAX_COLLISION_GROUP);
  67. assert(group1 <= MAX_COLLISION_GROUP);
  68. unsigned int index;
  69. index = group0 | (group1 << COLLISION_FLAG_SHIFT);
  70. AllowCollisionFlags[index] = 0;
  71. index = group1 | (group0 << COLLISION_FLAG_SHIFT);
  72. AllowCollisionFlags[index] = 0;
  73. }
  74. void PhysicsSceneClass::Enable_All_Collision_Detections(int group)
  75. {
  76. assert(group >= 0);
  77. assert(group <= MAX_COLLISION_GROUP);
  78. for (int i=0; i <= MAX_COLLISION_GROUP; i++) {
  79. unsigned int index;
  80. index = group | (i << COLLISION_FLAG_SHIFT);
  81. AllowCollisionFlags[index] = 1;
  82. index = i | (group << COLLISION_FLAG_SHIFT);
  83. AllowCollisionFlags[index] = 1;
  84. }
  85. }
  86. void PhysicsSceneClass::Disable_All_Collision_Detections(int group)
  87. {
  88. assert(group >= 0);
  89. assert(group <= MAX_COLLISION_GROUP);
  90. for (int i=0; i <= MAX_COLLISION_GROUP; i++) {
  91. unsigned int index;
  92. index = group | (i << COLLISION_FLAG_SHIFT);
  93. AllowCollisionFlags[index] = 0;
  94. index = i | (group << COLLISION_FLAG_SHIFT);
  95. AllowCollisionFlags[index] = 0;
  96. }
  97. }
  98. void PhysicsSceneClass::Set_Collision_Region(const AABoxClass & bounds,int colgroup)
  99. {
  100. Collect_Collideable_Objects(bounds,colgroup,true,true,&CollisionRegionList);
  101. }
  102. void PhysicsSceneClass::Release_Collision_Region(void)
  103. {
  104. CollisionRegionList.Reset_List();
  105. }
  106. bool PhysicsSceneClass::Cast_Ray(PhysRayCollisionTestClass & raytest,bool use_collision_region)
  107. {
  108. /*
  109. ** Assert that the result structure has been initialized with the
  110. ** optimistic result that the entire move will be taken. Each call
  111. ** should whittle down the Fraction variable so that we are left
  112. ** with the fraction that the closest object allowed. If StartBad
  113. ** is ever set to true, we can bail out.
  114. */
  115. assert(raytest.Result->Fraction == 1.0f);
  116. assert(raytest.Result->StartBad == false);
  117. raytest.CollidedPhysObj = NULL;
  118. /*
  119. ** Check against physical objects in our vicinity
  120. */
  121. bool res = false;
  122. if (use_collision_region) {
  123. /*
  124. ** Use the cached collision region list
  125. */
  126. NonRefPhysListIterator it(&CollisionRegionList);
  127. for ( ; !it.Is_Done(); it.Next()) {
  128. PhysClass * obj = it.Peek_Obj();
  129. if ( Do_Groups_Collide(obj->Get_Collision_Group(),raytest.CollisionGroup) &&
  130. !obj->Is_Ignore_Me() )
  131. {
  132. res |= obj->Cast_Ray(raytest);
  133. }
  134. }
  135. } else {
  136. /*
  137. ** Cull the collision check using the culling systems
  138. */
  139. if (raytest.CheckStaticObjs) {
  140. res |= StaticCullingSystem->Cast_Ray(raytest);
  141. if (raytest.Result->StartBad) return true;
  142. }
  143. if (raytest.CheckDynamicObjs) {
  144. res |= DynamicCullingSystem->Cast_Ray(raytest);
  145. if (raytest.Result->StartBad) return true;
  146. }
  147. }
  148. return res;
  149. }
  150. bool PhysicsSceneClass::Cast_AABox(PhysAABoxCollisionTestClass & boxtest,bool use_collision_region)
  151. {
  152. /*
  153. ** Assert that the result structure has been initialized with the
  154. ** optimistic result that the entire move will be taken. Each call
  155. ** should whittle down the Fraction variable so that we are left
  156. ** with the fraction that the closest object allowed. If StartBad
  157. ** is ever set to true, we can bail out.
  158. */
  159. WWASSERT(boxtest.Result->Fraction == 1.0f);
  160. WWASSERT(boxtest.Result->StartBad == false);
  161. boxtest.CollidedPhysObj = NULL;
  162. /*
  163. ** Check against physical objects in our vicinity
  164. */
  165. bool res = false;
  166. if (use_collision_region) {
  167. /*
  168. ** Use the cached collision region list
  169. */
  170. NonRefPhysListIterator it(&CollisionRegionList);
  171. for ( ; !it.Is_Done(); it.Next()) {
  172. PhysClass * obj = it.Peek_Obj();
  173. if ( Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  174. !obj->Is_Ignore_Me() )
  175. {
  176. res |= obj->Cast_AABox(boxtest);
  177. }
  178. }
  179. } else {
  180. /*
  181. ** Cull the collision check using the culling systems
  182. */
  183. if (boxtest.CheckStaticObjs) {
  184. res |= StaticCullingSystem->Cast_AABox(boxtest);
  185. if (boxtest.Result->StartBad) return true;
  186. }
  187. if (boxtest.CheckDynamicObjs) {
  188. res |= DynamicCullingSystem->Cast_AABox(boxtest);
  189. if (boxtest.Result->StartBad) return true;
  190. }
  191. }
  192. return res;
  193. }
  194. bool PhysicsSceneClass::Cast_OBBox(PhysOBBoxCollisionTestClass & boxtest,bool use_collision_region)
  195. {
  196. /*
  197. ** Assert that the result structure has been initialized with the
  198. ** optimistic result that the entire move will be taken. Each call
  199. ** should whittle down the Fraction variable so that we are left
  200. ** with the fraction that the closest object allowed. If StartBad
  201. ** is ever set to true, we can bail out.
  202. */
  203. assert(boxtest.Result->Fraction == 1.0f);
  204. assert(boxtest.Result->StartBad == false);
  205. boxtest.CollidedPhysObj = NULL;
  206. /*
  207. ** Check against physical objects in our vicinity
  208. */
  209. bool res = false;
  210. if (use_collision_region) {
  211. /*
  212. ** Use the cached collision region list
  213. */
  214. NonRefPhysListIterator it(&CollisionRegionList);
  215. for ( ; !it.Is_Done(); it.Next()) {
  216. PhysClass * obj = it.Peek_Obj();
  217. if ( Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  218. !obj->Is_Ignore_Me() )
  219. {
  220. res |= obj->Cast_OBBox(boxtest);
  221. }
  222. }
  223. } else {
  224. /*
  225. ** Cull the collision check using the culling systems
  226. */
  227. if (boxtest.CheckStaticObjs) {
  228. res |= StaticCullingSystem->Cast_OBBox(boxtest);
  229. if (boxtest.Result->StartBad) return true;
  230. }
  231. if (boxtest.CheckDynamicObjs) {
  232. res |= DynamicCullingSystem->Cast_OBBox(boxtest);
  233. if (boxtest.Result->StartBad) return true;
  234. }
  235. }
  236. return res;
  237. }
  238. bool PhysicsSceneClass::Intersection_Test(PhysAABoxIntersectionTestClass & boxtest,bool use_collision_region)
  239. {
  240. if (use_collision_region) {
  241. /*
  242. ** Test for intersection with objects in the cached collision region
  243. */
  244. NonRefPhysListIterator it(&CollisionRegionList);
  245. for ( ; !it.Is_Done(); it.Next()) {
  246. PhysClass * obj = it.Peek_Obj();
  247. if ( Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  248. !obj->Is_Ignore_Me() )
  249. {
  250. if (obj->Intersection_Test(boxtest)) {
  251. return true;
  252. }
  253. }
  254. }
  255. } else {
  256. /*
  257. ** Test for intersection with objects in the static and dynamic culling systems
  258. */
  259. if (boxtest.CheckStaticObjs) {
  260. if (StaticCullingSystem->Intersection_Test(boxtest)) {
  261. return true;
  262. }
  263. }
  264. if (boxtest.CheckDynamicObjs) {
  265. if (DynamicCullingSystem->Intersection_Test(boxtest)) {
  266. return true;
  267. }
  268. }
  269. }
  270. return false;
  271. }
  272. bool PhysicsSceneClass::Intersection_Test(PhysOBBoxIntersectionTestClass & boxtest,bool use_collision_region)
  273. {
  274. if (use_collision_region) {
  275. /*
  276. ** Test for intersection with objects in the cached collision region
  277. */
  278. NonRefPhysListIterator it(&CollisionRegionList);
  279. for ( ; !it.Is_Done(); it.Next()) {
  280. PhysClass * obj = it.Peek_Obj();
  281. if ( Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  282. !obj->Is_Ignore_Me() )
  283. {
  284. if (obj->Intersection_Test(boxtest)) {
  285. return true;
  286. }
  287. }
  288. }
  289. } else {
  290. /*
  291. ** Test for intersection with objects in the static and dynamic culling systems
  292. */
  293. if (boxtest.CheckStaticObjs) {
  294. if (StaticCullingSystem->Intersection_Test(boxtest)) {
  295. return true;
  296. }
  297. }
  298. if (boxtest.CheckDynamicObjs) {
  299. if (DynamicCullingSystem->Intersection_Test(boxtest)) {
  300. return true;
  301. }
  302. }
  303. }
  304. return false;
  305. }
  306. bool PhysicsSceneClass::Intersection_Test(PhysMeshIntersectionTestClass & meshtest,bool use_collision_region)
  307. {
  308. if (use_collision_region) {
  309. /*
  310. ** Test for intersection with objects in the cached collision region
  311. */
  312. NonRefPhysListIterator it(&CollisionRegionList);
  313. for ( ; !it.Is_Done(); it.Next()) {
  314. PhysClass * obj = it.Peek_Obj();
  315. if ( Do_Groups_Collide(obj->Get_Collision_Group(),meshtest.CollisionGroup) &&
  316. !obj->Is_Ignore_Me() )
  317. {
  318. if (obj->Intersection_Test(meshtest)) {
  319. return true;
  320. }
  321. }
  322. }
  323. } else {
  324. if (meshtest.CheckStaticObjs) {
  325. if (StaticCullingSystem->Intersection_Test(meshtest)) {
  326. return true;
  327. }
  328. }
  329. if (meshtest.CheckDynamicObjs) {
  330. if (DynamicCullingSystem->Intersection_Test(meshtest)) {
  331. return true;
  332. }
  333. }
  334. }
  335. return false;
  336. }
  337. bool PhysicsSceneClass::Intersection_Test(const AABoxClass & box,int collision_group,int collision_type,bool use_collision_region)
  338. {
  339. NonRefPhysListClass intersect_list;
  340. PhysAABoxIntersectionTestClass test(box,collision_group,collision_type,&intersect_list);
  341. return Intersection_Test(test,use_collision_region);
  342. }
  343. bool PhysicsSceneClass::Intersection_Test(const OBBoxClass & box,int collision_group,int collision_type,bool use_collision_region)
  344. {
  345. NonRefPhysListClass intersect_list;
  346. PhysOBBoxIntersectionTestClass test(box,collision_group,collision_type,&intersect_list);
  347. return Intersection_Test(test,use_collision_region);
  348. }
  349. void PhysicsSceneClass::Add_Collected_Objects_To_List
  350. (
  351. bool static_objs,
  352. bool dynamic_objs,
  353. NonRefPhysListClass * list
  354. )
  355. {
  356. // link the static objects
  357. if (static_objs) {
  358. StaticPhysClass * obj;
  359. for ( obj = (StaticPhysClass *)StaticCullingSystem->Get_First_Collected_Object();
  360. obj != NULL;
  361. obj = (StaticPhysClass *)StaticCullingSystem->Get_Next_Collected_Object(obj) )
  362. {
  363. list->Add(obj);
  364. }
  365. }
  366. // link the dynamic objects
  367. if (dynamic_objs) {
  368. PhysClass * obj;
  369. for ( obj = (PhysClass *)DynamicCullingSystem->Get_First_Collected_Object();
  370. obj != NULL;
  371. obj = (PhysClass *)DynamicCullingSystem->Get_Next_Collected_Object(obj) )
  372. {
  373. list->Add(obj);
  374. }
  375. }
  376. }
  377. void PhysicsSceneClass::Add_Collected_Collideable_Objects_To_List
  378. (
  379. int colgroup,
  380. bool static_objs,
  381. bool dynamic_objs,
  382. NonRefPhysListClass * list
  383. )
  384. {
  385. // link the static objects
  386. if (static_objs) {
  387. StaticPhysClass * obj;
  388. for ( obj = (StaticPhysClass *)StaticCullingSystem->Get_First_Collected_Object();
  389. obj != NULL;
  390. obj = (StaticPhysClass *)StaticCullingSystem->Get_Next_Collected_Object(obj) )
  391. {
  392. if ( Do_Groups_Collide(obj->Get_Collision_Group(),colgroup) &&
  393. !obj->Is_Ignore_Me() )
  394. {
  395. list->Add(obj);
  396. }
  397. }
  398. }
  399. // link the dynamic objects
  400. if (dynamic_objs) {
  401. PhysClass * obj;
  402. for ( obj = (PhysClass *)DynamicCullingSystem->Get_First_Collected_Object();
  403. obj != NULL;
  404. obj = (PhysClass *)DynamicCullingSystem->Get_Next_Collected_Object(obj) )
  405. {
  406. if ( Do_Groups_Collide(obj->Get_Collision_Group(),colgroup) &&
  407. !obj->Is_Ignore_Me() )
  408. {
  409. list->Add(obj);
  410. }
  411. }
  412. }
  413. }
  414. void PhysicsSceneClass::Collect_Objects
  415. (
  416. const Vector3 & point,
  417. bool static_objs,
  418. bool dynamic_objs,
  419. NonRefPhysListClass * list
  420. )
  421. {
  422. WWASSERT(list != NULL);
  423. if (static_objs) {
  424. StaticCullingSystem->Reset_Collection();
  425. StaticCullingSystem->Collect_Objects(point);
  426. }
  427. if (dynamic_objs) {
  428. DynamicCullingSystem->Reset_Collection();
  429. DynamicCullingSystem->Collect_Objects(point);
  430. }
  431. Add_Collected_Objects_To_List(static_objs,dynamic_objs,list);
  432. }
  433. void PhysicsSceneClass::Collect_Objects
  434. (
  435. const AABoxClass & box,
  436. bool static_objs,
  437. bool dynamic_objs,
  438. NonRefPhysListClass * list
  439. )
  440. {
  441. WWASSERT(list != NULL);
  442. if (static_objs) {
  443. StaticCullingSystem->Reset_Collection();
  444. StaticCullingSystem->Collect_Objects(box);
  445. }
  446. if (dynamic_objs) {
  447. DynamicCullingSystem->Reset_Collection();
  448. DynamicCullingSystem->Collect_Objects(box);
  449. }
  450. Add_Collected_Objects_To_List(static_objs,dynamic_objs,list);
  451. }
  452. void PhysicsSceneClass::Collect_Objects
  453. (
  454. const OBBoxClass & box,
  455. bool static_objs,
  456. bool dynamic_objs,
  457. NonRefPhysListClass * list
  458. )
  459. {
  460. WWASSERT(list != NULL);
  461. if (static_objs) {
  462. StaticCullingSystem->Reset_Collection();
  463. StaticCullingSystem->Collect_Objects(box);
  464. }
  465. if (dynamic_objs) {
  466. DynamicCullingSystem->Reset_Collection();
  467. DynamicCullingSystem->Collect_Objects(box);
  468. }
  469. Add_Collected_Objects_To_List(static_objs,dynamic_objs,list);
  470. }
  471. void PhysicsSceneClass::Collect_Objects
  472. (
  473. const FrustumClass & frustum,
  474. bool static_objs,
  475. bool dynamic_objs,
  476. NonRefPhysListClass * list
  477. )
  478. {
  479. WWASSERT(list != NULL);
  480. if (static_objs) {
  481. StaticCullingSystem->Reset_Collection();
  482. StaticCullingSystem->Collect_Objects(frustum);
  483. }
  484. if (dynamic_objs) {
  485. DynamicCullingSystem->Reset_Collection();
  486. DynamicCullingSystem->Collect_Objects(frustum);
  487. }
  488. Add_Collected_Objects_To_List(static_objs,dynamic_objs,list);
  489. }
  490. void PhysicsSceneClass::Collect_Collideable_Objects
  491. (
  492. const AABoxClass & box,
  493. int colgroup,
  494. bool static_objs,
  495. bool dynamic_objs,
  496. NonRefPhysListClass * list
  497. )
  498. {
  499. WWASSERT(list != NULL);
  500. if (static_objs) {
  501. StaticCullingSystem->Reset_Collection();
  502. StaticCullingSystem->Collect_Objects(box);
  503. }
  504. if (dynamic_objs) {
  505. DynamicCullingSystem->Reset_Collection();
  506. DynamicCullingSystem->Collect_Objects(box);
  507. }
  508. Add_Collected_Collideable_Objects_To_List(colgroup,static_objs,dynamic_objs,list);
  509. }
  510. void PhysicsSceneClass::Collect_Collideable_Objects
  511. (
  512. const OBBoxClass & box,
  513. int colgroup,
  514. bool static_objs,
  515. bool dynamic_objs,
  516. NonRefPhysListClass * list
  517. )
  518. {
  519. WWASSERT(list != NULL);
  520. if (static_objs) {
  521. StaticCullingSystem->Reset_Collection();
  522. StaticCullingSystem->Collect_Objects(box);
  523. }
  524. if (dynamic_objs) {
  525. DynamicCullingSystem->Reset_Collection();
  526. DynamicCullingSystem->Collect_Objects(box);
  527. }
  528. Add_Collected_Collideable_Objects_To_List(colgroup,static_objs,dynamic_objs,list);
  529. }
  530. void PhysicsSceneClass::Add_Collected_Lights_To_List
  531. (
  532. bool static_lights,
  533. bool dynamic_lights,
  534. NonRefPhysListClass * list
  535. )
  536. {
  537. // link the static lights
  538. if (static_lights) {
  539. LightPhysClass * obj;
  540. for ( obj = StaticLightingSystem->Get_First_Collected_Object();
  541. obj != NULL;
  542. obj = StaticLightingSystem->Get_Next_Collected_Object(obj) )
  543. {
  544. list->Add(obj);
  545. }
  546. }
  547. // link the dynamic lights
  548. // TODO!!
  549. }
  550. void PhysicsSceneClass::Collect_Lights
  551. (
  552. const Vector3 & point,
  553. bool static_lights,
  554. bool dynamic_lights,
  555. NonRefPhysListClass * list
  556. )
  557. {
  558. WWASSERT(list != NULL);
  559. if (static_lights) {
  560. StaticLightingSystem->Reset_Collection();
  561. StaticLightingSystem->Collect_Objects(point);
  562. }
  563. // TODO: Dynamic lights!!
  564. Add_Collected_Lights_To_List(static_lights,dynamic_lights,list);
  565. }
  566. void PhysicsSceneClass::Collect_Lights
  567. (
  568. const AABoxClass & bounds,
  569. bool static_lights,
  570. bool dynamic_lights,
  571. NonRefPhysListClass * list
  572. )
  573. {
  574. WWASSERT(list != NULL);
  575. if (static_lights) {
  576. StaticLightingSystem->Reset_Collection();
  577. StaticLightingSystem->Collect_Objects(bounds);
  578. }
  579. // TODO: Dynamic lights!!
  580. Add_Collected_Lights_To_List(static_lights,dynamic_lights,list);
  581. }