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/ww3d2/decalsys.cpp

487 lines
24 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 : 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];
}