This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwphys/physaabtreecull.cpp

335 lines
8.9 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** 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 ***
***********************************************************************************************
* *
* Project Name : WWPhys *
* *
* $Archive:: /Commando/Code/wwphys/physaabtreecull.cpp $*
* *
* Author:: Greg Hjelstrom *
* *
* $Modtime:: 5/05/01 5:14p $*
* *
* $Revision:: 23 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "physaabtreecull.h"
#include "pscene.h"
#include "physcoltest.h"
#include "physinttest.h"
#include "wwstring.h"
/*
** Static members of PhysAABTreeCullClass
*/
bool PhysAABTreeCullClass::_HierarchicalVisCullingEnabled = true;
/*
** PhysAABTreeCullClass is a derived AABTree which assumes it contains PhysClasses
** these two functions encapsulate some typecasting which happens in a lot
** of places...
*/
inline PhysClass * get_first_object(AABTreeNodeClass * node)
{
return (PhysClass *)(node->Object);
}
inline PhysClass * get_next_object(PhysClass * tile)
{
return (PhysClass *)(((AABTreeLinkClass *)tile->Get_Cull_Link())->NextObject);
}
/*
** Implementation of PhysAABTreeCullClass
*/
PhysAABTreeCullClass::PhysAABTreeCullClass(PhysicsSceneClass * pscene) :
Scene(pscene)
{
}
PhysAABTreeCullClass::~PhysAABTreeCullClass(void)
{
}
bool PhysAABTreeCullClass::Verify(StringClass & error_report)
{
return Verify_Recursive(RootNode,error_report);
}
bool PhysAABTreeCullClass::Cast_Ray_Recursive
(
AABTreeNodeClass * node,
PhysRayCollisionTestClass & raytest
)
{
/*
** Cull the collision test against the bounding volume of this node
** If it is culled, stop descending the tree.
*/
if (raytest.Cull(node->Box)) {
return false;
}
/*
** Test any objects in this node
*/
bool res = false;
if (node->Object) {
PhysClass * obj = get_first_object(node);
while (obj) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),raytest.CollisionGroup) &&
!obj->Is_Ignore_Me())
{
res |= obj->Cast_Ray(raytest);
}
obj = get_next_object(obj);
}
}
/*
** If it wasn't culled, collision test on to the children
*/
if (node->Back) {
res = res | Cast_Ray_Recursive(node->Back,raytest);
}
if (node->Front) {
res = res | Cast_Ray_Recursive(node->Front,raytest);
}
return res;
}
bool PhysAABTreeCullClass::Cast_AABox_Recursive
(
AABTreeNodeClass * node,
PhysAABoxCollisionTestClass & boxtest
)
{
/*
** Cull the collision test against the bounding volume of this node
** If it is culled, stop descending the tree.
*/
if (boxtest.Cull(node->Box)) {
return false;
}
/*
** Test any objects in this node
*/
bool res = false;
if (node->Object) {
PhysClass * obj = get_first_object(node);
while (obj) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
!obj->Is_Ignore_Me() )
{
res |= obj->Cast_AABox(boxtest);
}
obj = get_next_object(obj);
}
}
/*
** If it wasn't culled, collision test on to the children
*/
if (node->Back) {
res = res | Cast_AABox_Recursive(node->Back,boxtest);
}
if (node->Front) {
res = res | Cast_AABox_Recursive(node->Front,boxtest);
}
return res;
}
bool PhysAABTreeCullClass::Cast_OBBox_Recursive
(
AABTreeNodeClass * node,
PhysOBBoxCollisionTestClass & boxtest
)
{
/*
** Cull the collision test against the bounding volume of this node
** If it is culled, stop descending the tree.
*/
if (boxtest.Cull(node->Box)) {
return false;
}
/*
** Test any objects in this node
*/
bool res = false;
if (node->Object) {
PhysClass * obj = get_first_object(node);
while (obj) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
!obj->Is_Ignore_Me() ) {
res |= obj->Cast_OBBox(boxtest);
}
obj = get_next_object(obj);
}
}
/*
** If it wasn't culled, collision test on to the children
*/
if (node->Back) {
res = res | Cast_OBBox_Recursive(node->Back,boxtest);
}
if (node->Front) {
res = res | Cast_OBBox_Recursive(node->Front,boxtest);
}
return res;
}
bool PhysAABTreeCullClass::Intersection_Test(PhysAABoxIntersectionTestClass & boxtest)
{
Reset_Collection();
Collect_Objects(boxtest.Box);
PhysClass * obj = Get_First_Collected_Object();
while (obj != NULL) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
!obj->Is_Ignore_Me() ) {
if (obj->Intersection_Test(boxtest)) {
return true;
}
}
obj = Get_Next_Collected_Object(obj);
}
return false;
}
bool PhysAABTreeCullClass::Intersection_Test(PhysOBBoxIntersectionTestClass & boxtest)
{
Reset_Collection();
Collect_Objects(boxtest.BoundingBox);
PhysClass * obj = Get_First_Collected_Object();
while (obj != NULL) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),boxtest.CollisionGroup) &&
!obj->Is_Ignore_Me() ) {
if (obj->Intersection_Test(boxtest)) {
return true;
}
}
obj = Get_Next_Collected_Object(obj);
}
return false;
}
bool PhysAABTreeCullClass::Intersection_Test(PhysMeshIntersectionTestClass & meshtest)
{
Reset_Collection();
Collect_Objects(meshtest.BoundingBox);
PhysClass * obj = Get_First_Collected_Object();
while (obj != NULL) {
if ( Scene->Do_Groups_Collide(obj->Get_Collision_Group(),meshtest.CollisionGroup) &&
!obj->Is_Ignore_Me() ) {
if (obj->Intersection_Test(meshtest)) {
return true;
}
}
obj = Get_Next_Collected_Object(obj);
}
return false;
}
bool PhysAABTreeCullClass::Verify_Recursive(AABTreeNodeClass * node,StringClass & error_report)
{
/*
** Test any objects in this node
*/
bool res = true;
StringClass working;
if (node->Object) {
PhysClass * obj = get_first_object(node);
while (obj) {
const AABoxClass & box = node->Box;
const AABoxClass & box2 = obj->Get_Cull_Box();
bool outside = false;
Vector3 dc;
Vector3::Subtract(box.Center,box2.Center,&dc);
if (box.Extent.X + box2.Extent.X < WWMath::Fabs(dc.X)) outside = true;
if (box.Extent.Y + box2.Extent.Y < WWMath::Fabs(dc.Y)) outside = true;
if (box.Extent.Z + box2.Extent.Z < WWMath::Fabs(dc.Z)) outside = true;
if ( (dc.X + box2.Extent.X <= box.Extent.X + WWMATH_EPSILON)&
(dc.Y + box2.Extent.Y <= box.Extent.Y + WWMATH_EPSILON) &&
(dc.Z + box2.Extent.Z <= box.Extent.Z + WWMATH_EPSILON) &&
(dc.X - box2.Extent.X >= -box.Extent.X - WWMATH_EPSILON) &&
(dc.Y - box2.Extent.Y >= -box.Extent.Y - WWMATH_EPSILON) &&
(dc.Z - box2.Extent.Z >= -box.Extent.Z - WWMATH_EPSILON))
{
outside = false;
} else {
outside = true;
}
if ( outside ) { //CollisionMath::Overlap_Test(node->Box,obj->Get_Cull_Box()) != CollisionMath::INSIDE) {
//CollisionMath::Overlap_Test(node->Box,obj->Get_Cull_Box());
working.Format("Node %d doesn't contain object: %s\r\n",node->Index,obj->Peek_Model()->Get_Name());
error_report += working;
res = false;
}
obj = get_next_object(obj);
}
}
/*
** If it wasn't culled, collision test on to the children
*/
if (node->Back) {
res &= Verify_Recursive(node->Back,error_report);
}
if (node->Front) {
res &= Verify_Recursive(node->Front,error_report);
}
return res;
}