/* ** 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 . */ /*********************************************************************************************** *** 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 : WW3D * * * * $Archive:: /Commando/Code/ww3d2/collect.cpp $* * * * Author:: Greg Hjelstrom * * * * $Modtime:: 1/08/01 10:04a $* * * * $Revision:: 1 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * CollectionClass::CollectionClass -- default constructor for collection render object * * CollectionClass::CollectionClass -- constructor for collection render object * * CollectionClass::CollectionClass -- copy constructor * * CollectionClass::CollectionClass -- assignment operator * * CollectionClass::~CollectionClass -- destructor * * CollectionClass::Clone -- virtual copy constructor * * CollectionClass::Free -- releases all assets in use by this collection * * CollectionClass::Class_ID -- returns class id for collection render objects * * CollectionClass::Get_Num_Polys -- returns the number of polygons in this collection * * CollectionClass::Render -- render this collection * * CollectionClass::Special_Render -- passes the special render call to all sub-objects * * CollectionClass::Set_Transform -- set the transform for this collection * * CollectionClass::Set_Position -- set the position for this collection * * CollectionClass::Get_Num_Sub_Objects -- returns the number of sub objects * * CollectionClass::Get_Sub_Object -- returns a pointer to the desired sub object * * CollectionClass::Add_Sub_Object -- adds another object into this collection * * CollectionClass::Remove_Sub_Object -- removes a sub object from this collection * * CollectionClass::Cast_Ray -- passes the ray test to each sub object * * CollectionClass::Cast_AABox -- passes the axis-aligned box test to each sub object * * CollectionClass::Cast_OBBox -- passes the oriented box test to each sub object * * CollectionClass::Intersect_AABox -- test for intersection with an AABox * * CollectionClass::Intersect_OBBox -- test for intersection with an OBBox * * CollectionClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding spher * * CollectionClass::Get_Obj_Space_Bounding_Box -- returns the object-space bounding box * * CollectionClass::Snap_Point_Count -- returns the number of snap points in this collecion * * CollectionClass::Get_Snap_Point -- return the desired snap point * * CollectionClass::Scale -- scale the objects in this collection * * CollectionClass::Scale -- scale the objects in this collection * * CollectionClass::Update_Obj_Space_Bounding_Volumes -- recomputes the object space boundin * * CollectionClass::Update_Sub_Object_Transforms -- recomputes all sub object transforms * * CollectionLoaderClass::Load -- reads a collection from a w3d file * * CollectionDefClass::CollectionDefClass -- constructor * * CollectionDefClass::~CollectionDefClass -- destructor for collection definition * * CollectionDefClass::Free -- releases assets in use by a collection definition * * CollectionDefClass::Get_Name -- returns name of the collection * * CollectionDefClass::Load -- loads a collection definition from a w3d file * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "collect.h" #include "chunkio.h" #include "camera.h" #include "wwdebug.h" #include "snappts.h" #include "assetmgr.h" #include "ww3d.h" #include "w3derr.h" //#include "sr.hpp" CollectionLoaderClass _CollectionLoader; /* ** CollectionDefClass. This is the "blueprint" for a collection object ** The asset manager will store these until someone actually asks it to ** create an instance of the collection object */ class CollectionDefClass { public: CollectionDefClass(void); ~CollectionDefClass(void); const char * Get_Name(void) const; WW3DErrorType Load(ChunkLoadClass & cload); protected: void Free(void); char Name[W3D_NAME_LEN]; DynamicVectorClass ObjectNames; SnapPointsClass * SnapPoints; DynamicVectorClass ProxyList; friend class CollectionClass; }; /* ** CollectionPrototypeClass this is the render object prototype for ** Collections. */ class CollectionPrototypeClass : public PrototypeClass { public: CollectionPrototypeClass(CollectionDefClass * def) { ColDef = def; WWASSERT(ColDef); } virtual ~CollectionPrototypeClass(void) { delete ColDef; } virtual const char * Get_Name(void) const { return ColDef->Get_Name(); } virtual int Get_Class_ID(void) const { return RenderObjClass::CLASSID_COLLECTION; } virtual RenderObjClass * Create(void) { return NEW_REF( CollectionClass, (*ColDef)); } CollectionDefClass * ColDef; }; /*********************************************************************************************** * CollectionClass::CollectionClass -- default constructor for collection render object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 23/8/00 GTH : Created. * *=============================================================================================*/ CollectionClass::CollectionClass(void) : SnapPoints(NULL) { Update_Obj_Space_Bounding_Volumes(); } /*********************************************************************************************** * CollectionClass::CollectionClass -- constructor for collection render object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionClass::CollectionClass(const CollectionDefClass & def) : SubObjects(def.ObjectNames.Count()), SnapPoints(NULL) { // Set our name Set_Name (def.Get_Name ()); // create the sub objects SubObjects.Resize(def.ObjectNames.Count()); for (int i=0; iCreate_Render_Obj(def.ObjectNames[i])); SubObjects[i]->Set_Container(this); } // Copy the list of placeholder objects from the definition ProxyList = def.ProxyList; // grab ahold of the snap points. SnapPoints = def.SnapPoints; if (SnapPoints) SnapPoints->Add_Ref(); // set up our collision typeas the union of all of our sub-objects Update_Sub_Object_Bits(); // update the object bounding volumes Update_Obj_Space_Bounding_Volumes(); } /*********************************************************************************************** * CollectionClass::CollectionClass -- copy constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionClass::CollectionClass(const CollectionClass & src) : CompositeRenderObjClass(src), SubObjects(src.SubObjects.Count()), SnapPoints(NULL) { *this = src; } /*********************************************************************************************** * CollectionClass::CollectionClass -- assignment operator * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionClass & CollectionClass::operator = (const CollectionClass & that) { if (this != &that) { Free(); CompositeRenderObjClass::operator = (that); SubObjects.Resize(that.SubObjects.Count()); for (int i=0; iClone()); SubObjects[i]->Set_Container(this); } // Copy the list of placeholder objects from the definition ProxyList = that.ProxyList; SnapPoints = that.SnapPoints; if (SnapPoints) SnapPoints->Add_Ref(); Update_Sub_Object_Bits(); Update_Obj_Space_Bounding_Volumes(); } return * this; } /*********************************************************************************************** * CollectionClass::~CollectionClass -- destructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionClass::~CollectionClass(void) { Free(); } /*********************************************************************************************** * CollectionClass::Clone -- virtual copy constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ RenderObjClass * CollectionClass::Clone(void) const { return NEW_REF( CollectionClass, (*this)); } /*********************************************************************************************** * CollectionClass::Free -- releases all assets in use by this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Free(void) { for (int i=0; iSet_Container(NULL); SubObjects[i]->Release_Ref(); SubObjects[i] = NULL; } SubObjects.Delete_All(); ProxyList.Delete_All (); REF_PTR_RELEASE(SnapPoints); } /*********************************************************************************************** * CollectionClass::Class_ID -- returns class id for collection render objects * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Class_ID(void) const { return RenderObjClass::CLASSID_COLLECTION; } /*********************************************************************************************** * CollectionClass::Get_Num_Polys -- returns the number of polygons in this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Get_Num_Polys(void) const { int pcount = 0; for (int i=0; iGet_Num_Polys(); } return pcount; } /*********************************************************************************************** * CollectionClass::Render -- render this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Render(RenderInfoClass & rinfo) { if (Is_Not_Hidden_At_All() == false) { return; } if (Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } for (int i=0; iRender(rinfo); } } /*********************************************************************************************** * CollectionClass::Special_Render -- passes the special render call to all sub-objects * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 3/2/99 GTH : Created. * *=============================================================================================*/ void CollectionClass::Special_Render(SpecialRenderInfoClass & rinfo) { if (Is_Not_Hidden_At_All() == false) { return; } if (Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } for (int i=0; iSpecial_Render(rinfo); } } /*********************************************************************************************** * CollectionClass::Set_Transform -- set the transform for this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Set_Transform(const Matrix3D &m) { RenderObjClass::Set_Transform(m); Set_Sub_Object_Transforms_Dirty(true); } /*********************************************************************************************** * CollectionClass::Set_Position -- set the position for this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Set_Position(const Vector3 &v) { RenderObjClass::Set_Position(v); Set_Sub_Object_Transforms_Dirty(true); } /*********************************************************************************************** * CollectionClass::Get_Num_Sub_Objects -- returns the number of sub objects * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Get_Num_Sub_Objects(void) const { return SubObjects.Count(); } /*********************************************************************************************** * CollectionClass::Get_Sub_Object -- returns a pointer to the desired sub object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ RenderObjClass * CollectionClass::Get_Sub_Object(int index) const { if (SubObjects[index]) { SubObjects[index]->Add_Ref(); } return SubObjects[index]; } /*********************************************************************************************** * CollectionClass::Add_Sub_Object -- adds another object into this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Add_Sub_Object(RenderObjClass * subobj) { WWASSERT(subobj); subobj->Add_Ref(); subobj->Set_Container(this); subobj->Set_Transform(Transform); int res = SubObjects.Add(subobj); Update_Sub_Object_Bits(); Update_Obj_Space_Bounding_Volumes(); if (Is_In_Scene()) { subobj->Notify_Added(Scene); } return res; } /*********************************************************************************************** * CollectionClass::Remove_Sub_Object -- removes a sub object from this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Remove_Sub_Object(RenderObjClass * robj) { if (robj == NULL) return 0; int res = 0; Matrix3D tm = Get_Transform(); for (int i=0; iNotify_Removed(Scene); } SubObjects[i]->Set_Container(NULL); SubObjects[i]->Set_Transform(tm); SubObjects[i]->Release_Ref(); res = SubObjects.Delete(i); break; } } if (res != 0) { Update_Sub_Object_Bits(); Update_Obj_Space_Bounding_Volumes(); } return res; } /*********************************************************************************************** * CollectionClass::Cast_Ray -- passes the ray test to each sub object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ bool CollectionClass::Cast_Ray(RayCollisionTestClass & raytest) { bool res = false; for (int i=0; iCast_Ray(raytest); } return res; } /*********************************************************************************************** * CollectionClass::Cast_AABox -- passes the axis-aligned box test to each sub object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ bool CollectionClass::Cast_AABox(AABoxCollisionTestClass & boxtest) { bool res = false; for (int i=0; iCast_AABox(boxtest); } return res; } /*********************************************************************************************** * CollectionClass::Cast_OBBox -- passes the oriented box test to each sub object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ bool CollectionClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest) { bool res = false; for (int i=0; iCast_OBBox(boxtest); } return res; } /*********************************************************************************************** * CollectionClass::Intersect_AABox -- test for intersection with an AABox * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/19/00 gth : Created. * *=============================================================================================*/ bool CollectionClass::Intersect_AABox(AABoxIntersectionTestClass & boxtest) { bool res = false; for (int i=0; iIntersect_AABox(boxtest); } return res; } /*********************************************************************************************** * CollectionClass::Intersect_OBBox -- test for intersection with an OBBox * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/19/00 gth : Created. * *=============================================================================================*/ bool CollectionClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest) { bool res = false; for (int i=0; iIntersect_OBBox(boxtest); } return res; } /*********************************************************************************************** * CollectionClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const { sphere = BoundSphere; } /*********************************************************************************************** * CollectionClass::Get_Obj_Space_Bounding_Box -- returns the object-space bounding box * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const { box = BoundBox; } /*********************************************************************************************** * CollectionClass::Snap_Point_Count -- returns the number of snap points in this collecion * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ int CollectionClass::Snap_Point_Count(void) { if (SnapPoints) { return SnapPoints->Count(); } else { return 0; } } /*********************************************************************************************** * CollectionClass::Get_Snap_Point -- return the desired snap point * * * * This function will set the passed vector to be equal to the object space coordinates of * * the desired snap point. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Get_Snap_Point(int index,Vector3 * set) { WWASSERT(set != NULL); if (SnapPoints) { *set = (*SnapPoints)[index]; } else { set->X = set->Y = set->Z = 0; } } /*********************************************************************************************** * CollectionClass::Scale -- scale the objects in this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Scale(float scale) { for (int i=0; iScale(scale); } } /*********************************************************************************************** * CollectionClass::Scale -- scale the objects in this collection * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Scale(float scalex, float scaley, float scalez) { for (int i=0; iScale(scalex,scaley,scalez); } } /*********************************************************************************************** * CollectionClass::Update_Obj_Space_Bounding_Volumes -- recomputes the object space bounding * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Update_Obj_Space_Bounding_Volumes(void) { int i; if (SubObjects.Count() <= 0) { BoundSphere = SphereClass(Vector3(0,0,0),0); BoundBox.Center.Set(0,0,0); BoundBox.Extent.Set(0,0,0); return; } Matrix3D tm = Get_Transform(); Set_Transform(Matrix3D(1)); // loop through all sub-objects, combining their bounding spheres. BoundSphere = SubObjects[0]->Get_Bounding_Sphere(); for (i=1; i < SubObjects.Count(); i++) { BoundSphere.Add_Sphere(SubObjects[i]->Get_Bounding_Sphere()); } // loop through the sub-objects, computing a box in the root coordinate // system which bounds all of the meshes. Note that we've set the // root coordinate system to identity for this. MinMaxAABoxClass box(Vector3(FLT_MAX,FLT_MAX,FLT_MAX),Vector3(-FLT_MAX,-FLT_MAX,-FLT_MAX)); for (i=0; i < SubObjects.Count(); i++) { box.Add_Box(SubObjects[i]->Get_Bounding_Box()); } BoundBox.Init(box); Invalidate_Cached_Bounding_Volumes(); // Now update the object space bounding volumes of this object's container: RenderObjClass *container = Get_Container(); if (container) container->Update_Obj_Space_Bounding_Volumes(); Set_Transform(tm); } /*********************************************************************************************** * CollectionClass::Update_Sub_Object_Transforms -- recomputes all sub object transforms * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionClass::Update_Sub_Object_Transforms(void) { RenderObjClass::Update_Sub_Object_Transforms(); for (int i=0; iSet_Transform(Transform); SubObjects[i]->Update_Sub_Object_Transforms(); } Set_Sub_Object_Transforms_Dirty(false); } /*********************************************************************************************** * CollectionClass::Get_Placeholder -- Returns information about a placeholder object. * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/28/99 PDS : Created. * *=============================================================================================*/ bool CollectionClass::Get_Proxy (int index, ProxyClass &proxy) const { bool retval = false; if (index >= 0 && index < ProxyList.Count ()) { // // Return the proxy information to the caller // proxy = ProxyList[index]; retval = true; } return retval; } /*********************************************************************************************** * CollectionClass::Get_Proxy_Count -- Returns the count of proxy objects in the collection. * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 4/28/99 PDS : Created. * *=============================================================================================*/ int CollectionClass::Get_Proxy_Count (void) const { return ProxyList.Count (); } /*********************************************************************************************** * CollectionDefClass::CollectionDefClass -- constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionDefClass::CollectionDefClass(void) { SnapPoints = NULL; } /*********************************************************************************************** * CollectionDefClass::~CollectionDefClass -- destructor for collection definition * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ CollectionDefClass::~CollectionDefClass(void) { Free(); } /*********************************************************************************************** * CollectionDefClass::Free -- releases assets in use by a collection definition * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ void CollectionDefClass::Free(void) { for (int i=0; i 0); char * name = new char [cload.Cur_Chunk_Length()]; cload.Read(name,cload.Cur_Chunk_Length()); ObjectNames.Add(name); break; } case W3D_CHUNK_PLACEHOLDER: { // Read the placeholder information from the chunk WWASSERT(cload.Cur_Chunk_Length() > 0); W3dPlaceholderStruct info; cload.Read(&info, sizeof (info)); // Read the placeholder name from the chunk char *name = new char[info.name_len + 1]; cload.Read(name, info.name_len); name[info.name_len] = 0; // Create a matrix from the data in the chunk Matrix3D transform (info.transform[0][0], info.transform[1][0], info.transform[2][0], info.transform[3][0], info.transform[0][1], info.transform[1][1], info.transform[2][1], info.transform[3][1], info.transform[0][2], info.transform[1][2], info.transform[2][2], info.transform[3][2]); // Add this placeholder to our list ProxyList.Add (ProxyClass (name, transform)); // Free the name array delete [] name; break; } case W3D_CHUNK_POINTS: SnapPoints = NEW_REF(SnapPointsClass, ()); SnapPoints->Load_W3D(cload); break; } cload.Close_Chunk(); } return WW3D_ERROR_OK; Error: return WW3D_ERROR_LOAD_FAILED; } /*********************************************************************************************** * CollectionLoaderClass::Load -- reads a collection from a w3d file * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/8/98 GTH : Created. * *=============================================================================================*/ PrototypeClass * CollectionLoaderClass::Load_W3D(ChunkLoadClass & cload) { CollectionDefClass * def = new CollectionDefClass; if (def == NULL) { return NULL; } if (def->Load(cload) != WW3D_ERROR_OK) { // load failed, delete the model and return an error delete def; return NULL; } else { // ok, accept this model! CollectionPrototypeClass * proto = new CollectionPrototypeClass(def); return proto; } }