physaabtreecull.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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/physaabtreecull.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 5/05/01 5:14p $*
  29. * *
  30. * $Revision:: 23 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "physaabtreecull.h"
  36. #include "pscene.h"
  37. #include "physcoltest.h"
  38. #include "physinttest.h"
  39. #include "wwstring.h"
  40. /*
  41. ** Static members of PhysAABTreeCullClass
  42. */
  43. bool PhysAABTreeCullClass::_HierarchicalVisCullingEnabled = true;
  44. /*
  45. ** PhysAABTreeCullClass is a derived AABTree which assumes it contains PhysClasses
  46. ** these two functions encapsulate some typecasting which happens in a lot
  47. ** of places...
  48. */
  49. inline PhysClass * get_first_object(AABTreeNodeClass * node)
  50. {
  51. return (PhysClass *)(node->Object);
  52. }
  53. inline PhysClass * get_next_object(PhysClass * tile)
  54. {
  55. return (PhysClass *)(((AABTreeLinkClass *)tile->Get_Cull_Link())->NextObject);
  56. }
  57. /*
  58. ** Implementation of PhysAABTreeCullClass
  59. */
  60. PhysAABTreeCullClass::PhysAABTreeCullClass(PhysicsSceneClass * pscene) :
  61. Scene(pscene)
  62. {
  63. }
  64. PhysAABTreeCullClass::~PhysAABTreeCullClass(void)
  65. {
  66. }
  67. bool PhysAABTreeCullClass::Verify(StringClass & error_report)
  68. {
  69. return Verify_Recursive(RootNode,error_report);
  70. }
  71. bool PhysAABTreeCullClass::Cast_Ray_Recursive
  72. (
  73. AABTreeNodeClass * node,
  74. PhysRayCollisionTestClass & raytest
  75. )
  76. {
  77. /*
  78. ** Cull the collision test against the bounding volume of this node
  79. ** If it is culled, stop descending the tree.
  80. */
  81. if (raytest.Cull(node->Box)) {
  82. return false;
  83. }
  84. /*
  85. ** Test any objects in this node
  86. */
  87. bool res = false;
  88. if (node->Object) {
  89. PhysClass * obj = get_first_object(node);
  90. while (obj) {
  91. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),raytest.CollisionGroup) &&
  92. !obj->Is_Ignore_Me())
  93. {
  94. res |= obj->Cast_Ray(raytest);
  95. }
  96. obj = get_next_object(obj);
  97. }
  98. }
  99. /*
  100. ** If it wasn't culled, collision test on to the children
  101. */
  102. if (node->Back) {
  103. res = res | Cast_Ray_Recursive(node->Back,raytest);
  104. }
  105. if (node->Front) {
  106. res = res | Cast_Ray_Recursive(node->Front,raytest);
  107. }
  108. return res;
  109. }
  110. bool PhysAABTreeCullClass::Cast_AABox_Recursive
  111. (
  112. AABTreeNodeClass * node,
  113. PhysAABoxCollisionTestClass & boxtest
  114. )
  115. {
  116. /*
  117. ** Cull the collision test against the bounding volume of this node
  118. ** If it is culled, stop descending the tree.
  119. */
  120. if (boxtest.Cull(node->Box)) {
  121. return false;
  122. }
  123. /*
  124. ** Test any objects in this node
  125. */
  126. bool res = false;
  127. if (node->Object) {
  128. PhysClass * obj = get_first_object(node);
  129. while (obj) {
  130. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  131. !obj->Is_Ignore_Me() )
  132. {
  133. res |= obj->Cast_AABox(boxtest);
  134. }
  135. obj = get_next_object(obj);
  136. }
  137. }
  138. /*
  139. ** If it wasn't culled, collision test on to the children
  140. */
  141. if (node->Back) {
  142. res = res | Cast_AABox_Recursive(node->Back,boxtest);
  143. }
  144. if (node->Front) {
  145. res = res | Cast_AABox_Recursive(node->Front,boxtest);
  146. }
  147. return res;
  148. }
  149. bool PhysAABTreeCullClass::Cast_OBBox_Recursive
  150. (
  151. AABTreeNodeClass * node,
  152. PhysOBBoxCollisionTestClass & boxtest
  153. )
  154. {
  155. /*
  156. ** Cull the collision test against the bounding volume of this node
  157. ** If it is culled, stop descending the tree.
  158. */
  159. if (boxtest.Cull(node->Box)) {
  160. return false;
  161. }
  162. /*
  163. ** Test any objects in this node
  164. */
  165. bool res = false;
  166. if (node->Object) {
  167. PhysClass * obj = get_first_object(node);
  168. while (obj) {
  169. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  170. !obj->Is_Ignore_Me() ) {
  171. res |= obj->Cast_OBBox(boxtest);
  172. }
  173. obj = get_next_object(obj);
  174. }
  175. }
  176. /*
  177. ** If it wasn't culled, collision test on to the children
  178. */
  179. if (node->Back) {
  180. res = res | Cast_OBBox_Recursive(node->Back,boxtest);
  181. }
  182. if (node->Front) {
  183. res = res | Cast_OBBox_Recursive(node->Front,boxtest);
  184. }
  185. return res;
  186. }
  187. bool PhysAABTreeCullClass::Intersection_Test(PhysAABoxIntersectionTestClass & boxtest)
  188. {
  189. Reset_Collection();
  190. Collect_Objects(boxtest.Box);
  191. PhysClass * obj = Get_First_Collected_Object();
  192. while (obj != NULL) {
  193. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  194. !obj->Is_Ignore_Me() ) {
  195. if (obj->Intersection_Test(boxtest)) {
  196. return true;
  197. }
  198. }
  199. obj = Get_Next_Collected_Object(obj);
  200. }
  201. return false;
  202. }
  203. bool PhysAABTreeCullClass::Intersection_Test(PhysOBBoxIntersectionTestClass & boxtest)
  204. {
  205. Reset_Collection();
  206. Collect_Objects(boxtest.BoundingBox);
  207. PhysClass * obj = Get_First_Collected_Object();
  208. while (obj != NULL) {
  209. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
  210. !obj->Is_Ignore_Me() ) {
  211. if (obj->Intersection_Test(boxtest)) {
  212. return true;
  213. }
  214. }
  215. obj = Get_Next_Collected_Object(obj);
  216. }
  217. return false;
  218. }
  219. bool PhysAABTreeCullClass::Intersection_Test(PhysMeshIntersectionTestClass & meshtest)
  220. {
  221. Reset_Collection();
  222. Collect_Objects(meshtest.BoundingBox);
  223. PhysClass * obj = Get_First_Collected_Object();
  224. while (obj != NULL) {
  225. if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),meshtest.CollisionGroup) &&
  226. !obj->Is_Ignore_Me() ) {
  227. if (obj->Intersection_Test(meshtest)) {
  228. return true;
  229. }
  230. }
  231. obj = Get_Next_Collected_Object(obj);
  232. }
  233. return false;
  234. }
  235. bool PhysAABTreeCullClass::Verify_Recursive(AABTreeNodeClass * node,StringClass & error_report)
  236. {
  237. /*
  238. ** Test any objects in this node
  239. */
  240. bool res = true;
  241. StringClass working;
  242. if (node->Object) {
  243. PhysClass * obj = get_first_object(node);
  244. while (obj) {
  245. const AABoxClass & box = node->Box;
  246. const AABoxClass & box2 = obj->Get_Cull_Box();
  247. bool outside = false;
  248. Vector3 dc;
  249. Vector3::Subtract(box.Center,box2.Center,&dc);
  250. if (box.Extent.X + box2.Extent.X < WWMath::Fabs(dc.X)) outside = true;
  251. if (box.Extent.Y + box2.Extent.Y < WWMath::Fabs(dc.Y)) outside = true;
  252. if (box.Extent.Z + box2.Extent.Z < WWMath::Fabs(dc.Z)) outside = true;
  253. if ( (dc.X + box2.Extent.X <= box.Extent.X + WWMATH_EPSILON)&
  254. (dc.Y + box2.Extent.Y <= box.Extent.Y + WWMATH_EPSILON) &&
  255. (dc.Z + box2.Extent.Z <= box.Extent.Z + WWMATH_EPSILON) &&
  256. (dc.X - box2.Extent.X >= -box.Extent.X - WWMATH_EPSILON) &&
  257. (dc.Y - box2.Extent.Y >= -box.Extent.Y - WWMATH_EPSILON) &&
  258. (dc.Z - box2.Extent.Z >= -box.Extent.Z - WWMATH_EPSILON))
  259. {
  260. outside = false;
  261. } else {
  262. outside = true;
  263. }
  264. if ( outside ) { //CollisionMath::Overlap_Test(node->Box,obj->Get_Cull_Box()) != CollisionMath::INSIDE) {
  265. //CollisionMath::Overlap_Test(node->Box,obj->Get_Cull_Box());
  266. working.Format("Node %d doesn't contain object: %s\r\n",node->Index,obj->Peek_Model()->Get_Name());
  267. error_report += working;
  268. res = false;
  269. }
  270. obj = get_next_object(obj);
  271. }
  272. }
  273. /*
  274. ** If it wasn't culled, collision test on to the children
  275. */
  276. if (node->Back) {
  277. res &= Verify_Recursive(node->Back,error_report);
  278. }
  279. if (node->Front) {
  280. res &= Verify_Recursive(node->Front,error_report);
  281. }
  282. return res;
  283. }