/* ** 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/decalsys.cpp $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Greg_h $* * * * $Modtime:: 3/12/02 11:03a $* * * * $Revision:: 8 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * DecalSystemClass::DecalSystemClass -- Constructor * * DecalSystemClass::~DecalSystemClass -- Destructor * * DecalSystemClass::Lock_Decal_Generator -- returns a DecalGenerator * * DecalSystemClass::Unlock_Decal_Generator -- Destroys the decal generator * * DecalSystemClass::Generate_Unique_Global_Decal_Id -- Generates a unique id for a decal * * DecalGeneratorClass::DecalGeneratorClass -- Constructor * * DecalGeneratorClass::~DecalGeneratorClass -- Destructor * * DecalGeneratorClass::Add_Mesh -- Meshes that generate a decal should add themselves * * DecalGeneratorClass::Get_Mesh_List -- returns the list of meshes * * DecalGeneratorClass::Set_Mesh_Transform -- sets the current mesh coordinate system * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "decalsys.h" #include "rendobj.h" #include "decalmsh.h" #include "mesh.h" #include "matrixmapper.h" #include "texture.h" uint32 DecalSystemClass::DecalIDGenerator = 0; /* ** DecalSystemClass Implementation */ /*********************************************************************************************** * DecalSystemClass::DecalSystemClass -- Constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ DecalSystemClass::DecalSystemClass(void) { } /*********************************************************************************************** * DecalSystemClass::~DecalSystemClass -- Destructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ DecalSystemClass::~DecalSystemClass(void) { } /*********************************************************************************************** * DecalSystemClass::Lock_Decal_Generator -- returns a DecalGenerator * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ DecalGeneratorClass * DecalSystemClass::Lock_Decal_Generator(void) { DecalGeneratorClass * gen = new DecalGeneratorClass(Generate_Decal_Id(), this); return gen; } /*********************************************************************************************** * DecalSystemClass::Unlock_Decal_Generator -- Destroys the decal generator * * * * Derived classes may take a record of the results of the generator here. Then they can * * put a cap on the total number of decals in the system or whatever... * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ void DecalSystemClass::Unlock_Decal_Generator(DecalGeneratorClass * generator) { delete generator; } /*********************************************************************************************** * DecalSystemClass::Generate_Unique_Global_Decal_Id -- Generates a unique id for a decal * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * Hopefully you won't use more than 4 billion decals at one time... * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ uint32 DecalSystemClass::Generate_Unique_Global_Decal_Id(void) { return DecalIDGenerator++; } /* ** DecalGeneratorClass Implementation */ /*********************************************************************************************** * DecalGeneratorClass::DecalGeneratorClass -- Constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ DecalGeneratorClass::DecalGeneratorClass(uint32 id,DecalSystemClass * system) : DecalID(id), System(system), BackfaceVal(0.0f), ApplyToTranslucentMeshes(false), Material(NULL) { Material = NEW_REF(MaterialPassClass,()); WWASSERT(System != NULL); WWASSERT(Material != NULL); } /*********************************************************************************************** * DecalGeneratorClass::~DecalGeneratorClass -- Destructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ DecalGeneratorClass::~DecalGeneratorClass(void) { REF_PTR_RELEASE(Material); } /*********************************************************************************************** * DecalGeneratorClass::Add_Mesh -- Meshes that generate a decal should add themselves * * * * This adds a mesh to the internal list. All meshes that actually add a decal should add * * themselves to this list so that the DecalSystem can keep track of them. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ void DecalGeneratorClass::Add_Mesh(RenderObjClass * mesh) { MeshList.Add(mesh); } /*********************************************************************************************** * DecalGeneratorClass::Get_Mesh_List -- returns the list of meshes * * * * This is the list of meshes which generated decals for this "logical decal" * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ NonRefRenderObjListClass & DecalGeneratorClass::Get_Mesh_List(void) { return MeshList; } /*********************************************************************************************** * DecalGeneratorClass::Set_Mesh_Transform -- sets the current mesh coordinate system * * * * The coordinate system of the mesh is needed in order to compute texture coordinates for * * the decal polygons. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 1/26/00 gth : Created. * *=============================================================================================*/ void DecalGeneratorClass::Set_Mesh_Transform(const Matrix3D & mesh_transform) { /* ** Mobj-texture = Projection * Mwrld-texture * Mobj-wrld */ Matrix3D world_to_texture; Matrix3D tmp; Matrix4 mesh_to_texture; Transform.Get_Orthogonal_Inverse(world_to_texture); Matrix3D::Multiply(world_to_texture,mesh_transform,&tmp); Matrix4::Multiply(Projection,tmp,&mesh_to_texture); /* ** Plug the matrix and texture size into the mapper */ if (WW3D::Is_Texturing_Enabled()) { float texsize = 64.0f; TextureClass * tex = Material->Peek_Texture(); WWASSERT(tex != NULL); if (tex) { // SurfaceClass::SurfaceDescription surface_desc; // tex->Get_Level_Description(surface_desc); // texsize = surface_desc.Width; texsize = tex->Get_Width(); } Mapper->Set_Texture_Transform(mesh_to_texture,texsize); } } /* ** MultiFixedPoolDecalSystemClass implementation */ MultiFixedPoolDecalSystemClass::MultiFixedPoolDecalSystemClass(uint32 num_pools, const uint32 *pool_sizes) : Pools(0), PoolCount(num_pools), Generator_PoolID(0), Generator_SlotID(0) { if (PoolCount) { WWASSERT(pool_sizes); Pools = new LogicalDecalPoolClass [PoolCount]; } for (uint32 i = 0; i < PoolCount; i++) { assert(pool_sizes[i]); Pools[i].Initialize(pool_sizes[i]); } } MultiFixedPoolDecalSystemClass::MultiFixedPoolDecalSystemClass(const MultiFixedPoolDecalSystemClass & that) : Pools(0), PoolCount(that.PoolCount), Generator_PoolID(that.Generator_PoolID), Generator_SlotID(that.Generator_SlotID) { uint32 i; // Allocate arrays (we dont' copy array contents because those are mesh-specific and will be // filled when the state is set anyway) if (PoolCount) Pools = new LogicalDecalPoolClass [PoolCount]; for (i = 0; i < PoolCount; i++) { Pools[i].Initialize(that.Pools[i].Size); } } MultiFixedPoolDecalSystemClass::~MultiFixedPoolDecalSystemClass(void) { if (Pools) { delete [] Pools; Pools = 0; } } // This clears the slot in addition to locking the generator, thus preventing any decal id // collisions (since any decal previously in that slot will have the same id as the new one). DecalGeneratorClass * MultiFixedPoolDecalSystemClass::Lock_Decal_Generator(void) { Clear_Decal_Slot(Generator_PoolID, Generator_SlotID); return DecalSystemClass::Lock_Decal_Generator(); } // This will register the decal in the system in the appropriate pool and slot (determined by // the generator's pool and slot ids), removing any decal which may have been there before. void MultiFixedPoolDecalSystemClass::Unlock_Decal_Generator(DecalGeneratorClass * generator) { find_logical_decal(generator->Get_Decal_ID()).Set(generator); DecalSystemClass::Unlock_Decal_Generator(generator); } // This notifies the system that a mesh which has decals on it was destroyed - therefore we // need to remove the mesh from our list to avoid dangling pointers. void MultiFixedPoolDecalSystemClass::Decal_Mesh_Destroyed(uint32 decal_id,DecalMeshClass * mesh) { // We must remove this mesh from all lists where it is present. The method is: for each // decal id present in the decal mesh, find the logical decal and remove the decal mesh from // its list. assert(mesh); RenderObjClass *parent = mesh->Peek_Parent(); find_logical_decal(decal_id).MeshList.Remove(parent); } // Not part of the DecalSystemClass interface - this function removes any decal currently in // the given slot in the given pool. void MultiFixedPoolDecalSystemClass::Clear_Decal_Slot(uint32 pool_id, uint32 slot_id) { find_logical_decal(pool_id, slot_id).Clear(encode_decal_id(pool_id, slot_id)); } // This one removes all decals in a given pool. void MultiFixedPoolDecalSystemClass::Clear_Pool(uint32 pool_id) { LogicalDecalPoolClass & pool = Pools[pool_id]; uint32 pool_size = pool.Size; for (uint32 slot_id = 0; slot_id < pool_size; slot_id++) { pool.Array[slot_id].Clear(encode_decal_id(pool_id, slot_id)); } } // And this one removes all decals in the system. void MultiFixedPoolDecalSystemClass::Clear_All_Decals(void) { for (uint32 pool_id = 0; pool_id < PoolCount; pool_id++) { LogicalDecalPoolClass & pool = Pools[pool_id]; uint32 pool_size = pool.Size; for (uint32 slot_id = 0; slot_id < pool_size; slot_id++) { pool.Array[slot_id].Clear(encode_decal_id(pool_id, slot_id)); } } } // Get a reference to the logical decal at the given pool and slot id (performs range checking) MultiFixedPoolDecalSystemClass::LogicalDecalClass & MultiFixedPoolDecalSystemClass::find_logical_decal(uint32 pool_id, uint32 slot_id) { assert(pool_id < PoolCount); pool_id = MIN(pool_id, PoolCount); LogicalDecalPoolClass & pool = Pools[pool_id]; assert(slot_id < pool.Size); slot_id = MIN(slot_id, pool.Size); return pool.Array[slot_id]; } // Get a reference to the logical decal with the given decal id MultiFixedPoolDecalSystemClass::LogicalDecalClass & MultiFixedPoolDecalSystemClass::find_logical_decal(uint32 decal_id) { uint32 pool_id, slot_id; decode_decal_id(decal_id, pool_id, slot_id); return find_logical_decal(pool_id, slot_id); } /* ** MultiFixedPoolDecalSystemClass::LogicalDecalClass implementation */ MultiFixedPoolDecalSystemClass::LogicalDecalClass::LogicalDecalClass(void) { } MultiFixedPoolDecalSystemClass::LogicalDecalClass::~LogicalDecalClass(void) { // We don't need to do anything here since the mesh list will get removed automatically and // the decals themselves don't neccessarily need to be removed because the logical decal is. // (we don't hold references to the meshes in the mesh list) } // Sets the logical decal to the one specified by the given generator (clearing any existing // decal information) void MultiFixedPoolDecalSystemClass::LogicalDecalClass::Set(DecalGeneratorClass * generator) { Clear(generator->Get_Decal_ID()); /* ** Copy the generators' mesh list into our mesh list */ NonRefRenderObjListIterator gen_mesh_it(&(generator->Get_Mesh_List())); for (gen_mesh_it.First(); !gen_mesh_it.Is_Done(); gen_mesh_it.Next()) { MeshList.Add(gen_mesh_it.Get_Obj()); } } // Just clears any existing logical decal information, leaving the decal empty. void MultiFixedPoolDecalSystemClass::LogicalDecalClass::Clear(uint32 decal_id) { // Remove the decal with this ID from all meshes where it appears NonRefRenderObjListIterator it(&MeshList); for (it.First(); !it.Is_Done(); it.Next()) { it.Get_Obj()->Delete_Decal(decal_id); } // Delete list while (!MeshList.Is_Empty()) { MeshList.Remove_Head(); } } /* ** MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass implementation */ MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::LogicalDecalPoolClass(void) : Array(0), Size(0) { } MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::~LogicalDecalPoolClass(void) { if (Array) { delete [] Array; Array = 0; } } void MultiFixedPoolDecalSystemClass::LogicalDecalPoolClass::Initialize(uint32 size) { if (Array) { delete [] Array; Array = 0; } Size = size; assert(Size); Array = new LogicalDecalClass[Size]; }