| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /*
- ** 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/physdecalsys.cpp $*
- * *
- * Original Author:: Greg Hjelstrom *
- * *
- * $Author:: Ian_l $*
- * *
- * $Modtime:: 7/17/01 9:52p $*
- * *
- * $Revision:: 20 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "physdecalsys.h"
- #include "colmathaabox.h"
- #include "pscene.h"
- #include "phys.h"
- #include "camera.h"
- #include "mesh.h"
- #include "decalmsh.h"
- #include "assetmgr.h"
- #include "wwdebug.h"
- #include "robjlist.h"
- #include "texture.h"
- #define DEBUG_DECALS 0
- const float DECAL_BACKFACE_THRESHHOLD = 0.4f; // backface rejection threshhold
- const float DECAL_HALF_SLAB_THICKNESS = 0.2f; // thickness of the bounding volume for decals
- PhysDecalSysClass::PhysDecalSysClass(PhysicsSceneClass * parent_scene) :
- ParentScene(parent_scene),
- CreatePermanentDecals(false),
- NextTempDecalIndex(0),
- DecalMaterial(NULL),
- DecalShader(0)
- {
- allocate_resources();
- Set_Temporary_Decal_Pool_Size(50);
- }
- PhysDecalSysClass::~PhysDecalSysClass(void)
- {
- release_resources();
- }
- void PhysDecalSysClass::Update_Decal_Fade_Distances(const CameraClass & camera)
- {
- /*
- ** Since we don't have decal fading any more, set the decal fade distance to the far clip plane
- */
- float znear,zfar;
- camera.Get_Clip_Planes(znear,zfar);
- WW3D::Set_Decal_Rejection_Distance(zfar);
- }
- int PhysDecalSysClass::Create_Decal
- (
- const Matrix3D & tm,
- const char * texture_name,
- float radius,
- bool is_permanent,
- bool apply_to_translucent_meshes,
- PhysClass * only_this_obj
- )
- {
- /*
- ** Allocate the decal generator
- */
- CreatePermanentDecals = is_permanent;
- DecalGeneratorClass * gen = Lock_Decal_Generator();
- WWASSERT(gen != NULL);
- /*
- ** Set up the transform, projection, and bounding volume parameters
- ** I want a thin bounding volume. Since the transform given is right at the impact point,
- ** we need to back-up some amount and then set the near and far z depths such that
- ** they bound the point
- */
- float backup_dist = DECAL_HALF_SLAB_THICKNESS + 0.01f;
- Matrix3D transform = tm;
- transform.Translate_Z(backup_dist);
- gen->Set_Transform(transform);
- gen->Set_Ortho_Projection(-radius,radius,-radius,radius,0.01f,backup_dist + 2.0f * DECAL_HALF_SLAB_THICKNESS);
- gen->Set_Backface_Threshhold(DECAL_BACKFACE_THRESHHOLD);
- gen->Apply_To_Translucent_Meshes(apply_to_translucent_meshes);
- #if DEBUG_DECALS
- ParentScene->Add_Debug_OBBox(gen->Get_Bounding_Volume(),Vector3(0,0,1));
- ParentScene->Add_Debug_Axes(tm,Vector3(1,1,1));
- ParentScene->Add_Debug_Axes(transform,Vector3(1,1,1));
- #endif
- /*
- ** Set up the material settings. Just plug in the standard alpha shader and the
- ** vertex material which all decals use. Then grab the texture which the user
- ** specified...
- */
- MaterialPassClass * material = gen->Get_Material();
- material->Set_Shader(DecalShader);
- material->Set_Material(DecalMaterial);
- TextureClass * tex = WW3DAssetManager::Get_Instance()->Get_Texture(texture_name,TextureClass::MIP_LEVELS_ALL);
- tex->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- tex->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- material->Set_Texture(tex);
- tex->Release_Ref();
- material->Release_Ref();
- /*
- ** Collect objects to apply the decal to
- */
- NonRefPhysListClass list;
- if (only_this_obj == NULL) {
- ParentScene->Collect_Objects(gen->Get_Bounding_Volume(),true,false,&list);
- } else {
- list.Add(only_this_obj);
- }
- /*
- ** Apply!
- */
- NonRefPhysListIterator it(&list);
- for (it.First(); !it.Is_Done(); it.Next()) {
- it.Peek_Obj()->Peek_Model()->Create_Decal(gen);
- }
- /*
- ** Done. Return the logical id of the decal if we actually created anything,
- ** otherwise return -1
- */
- int return_id = -1;
- if (gen->Get_Mesh_List().Is_Empty() == false) {
- return_id = gen->Get_Decal_ID();
- }
- Unlock_Decal_Generator(gen);
- return return_id;
- }
- bool PhysDecalSysClass::Remove_Decal(uint32 id)
- {
- return internal_remove_decal(id,NULL);
- }
- void PhysDecalSysClass::Unlock_Decal_Generator(DecalGeneratorClass * generator)
- {
- /*
- ** If the generator actually created decal polygons, add the results
- ** to our internal pools
- */
- if (generator->Get_Mesh_List().Is_Empty() == false) {
-
- if (is_decal_id_permanent(generator->Get_Decal_ID())) {
-
- LogicalDecalClass * newdecal = new LogicalDecalClass;
- newdecal->Init(generator);
- PermanentDecals.Add(newdecal);
- } else {
- /*
- ** the id should match the "next temp decal index"
- */
- WWASSERT(generator->Get_Decal_ID() == NextTempDecalIndex);
- TempDecals[NextTempDecalIndex].Init(generator);
- /*
- ** bump the index forward
- */
- NextTempDecalIndex = (NextTempDecalIndex + 1) % TempDecals.Length();
-
- }
- }
- DecalSystemClass::Unlock_Decal_Generator(generator);
- }
- void PhysDecalSysClass::Decal_Mesh_Destroyed(uint32 decal_id,DecalMeshClass * mesh)
- {
- /*
- ** Must remove this mesh from any decals
- */
- internal_remove_decal(decal_id,mesh->Peek_Parent());
- }
- void PhysDecalSysClass::Set_Temporary_Decal_Pool_Size(int count)
- {
- WWASSERT(count > 0);
- /*
- ** If we are shrinking, remove all decals in the slots that are going away
- */
- if (count < TempDecals.Length()) {
- for (int i=count; i<TempDecals.Length(); i++) {
- TempDecals[i].Reset();
- }
- }
- /*
- ** Resize the array
- */
- TempDecals.Resize(count);
- /*
- ** Make sure that our NextTempDecalIndex is valid, if not wrap it around
- */
- if (NextTempDecalIndex >= (uint32)TempDecals.Length()) {
- NextTempDecalIndex = 0;
- }
- }
- int PhysDecalSysClass::Get_Temporary_Decal_Pool_Size(void)
- {
- return TempDecals.Length();
- }
- uint32 PhysDecalSysClass::Generate_Decal_Id(void)
- {
- uint32 id;
- if (CreatePermanentDecals) {
-
- id = Generate_Unique_Global_Decal_Id() & 0x7FFFFFFF;
- id |= 0x80000000;
- } else {
-
- id = NextTempDecalIndex;
- }
- return id;
- }
- bool PhysDecalSysClass::is_decal_id_permanent(uint32 id)
- {
- if (id & 0x80000000) {
- return true;
- } else {
- return false;
- }
- }
- void PhysDecalSysClass::allocate_resources(void)
- {
- WWASSERT(DecalMaterial == NULL);
- DecalMaterial = NEW_REF(VertexMaterialClass,());
- DecalMaterial->Set_Ambient(0,0,0);
- DecalMaterial->Set_Diffuse(0,0,0);
- DecalMaterial->Set_Specular(0,0,0);
- DecalMaterial->Set_Emissive(1,1,1);
- DecalMaterial->Set_Opacity(1.0f);
- DecalMaterial->Set_Shininess(0.0f);
- DecalShader = ShaderClass::_PresetAlphaShader;
- }
- void PhysDecalSysClass::release_resources(void)
- {
- REF_PTR_RELEASE(DecalMaterial);
- }
- bool PhysDecalSysClass::internal_remove_decal(uint32 id,MeshClass * deleted_mesh)
- {
- bool success = false;
- if (is_decal_id_permanent(id)) {
-
- /*
- ** Find the decal with the given id in the Permanent decal array
- */
- MultiListIterator<LogicalDecalClass> it(&PermanentDecals);
- for (it.First(); !it.Is_Done(); it.Next()) {
-
- LogicalDecalClass * decal = it.Get_Obj();
-
- if (decal->DecalID == id) {
- /*
- ** Just remove the deleted mesh from our list. We don't need to delete
- ** its decals since it is telling us that it has been deleted already.
- */
- if (deleted_mesh != NULL) {
- decal->Meshes.Delete(deleted_mesh);
- }
- /*
- ** Now destroy this logical decal, this results in all decal-meshes that
- ** are referenced by this logical decal being told to remove this decal id.
- */
- PermanentDecals.Remove(decal);
- delete decal;
- success = true;
- break;
- }
- }
-
- } else {
- /*
- ** Temporary decals use their index as the id
- */
- WWASSERT(id >= 0);
- WWASSERT(id < (uint32)TempDecals.Length());
- if (deleted_mesh != NULL) {
- TempDecals[id].Meshes.Delete(deleted_mesh);
- }
- TempDecals[id].Reset();
- success = true;
- }
- return success;
- }
- /*
- ** LogicalDecalClass Implementation
- */
- PhysDecalSysClass::LogicalDecalClass::LogicalDecalClass(void) :
- DecalID(0xFFFFFFFF)
- {
- }
- PhysDecalSysClass::LogicalDecalClass::~LogicalDecalClass(void)
- {
- Reset();
- }
- void PhysDecalSysClass::LogicalDecalClass::Init(DecalGeneratorClass * gen)
- {
- /*
- ** Reset ourselves in case we were being used to track a previous decal.
- ** This causes that decal to get removed from the system.
- */
- Reset();
-
- /*
- ** Record the data for this decal
- */
- DecalID = gen->Get_Decal_ID();
- NonRefRenderObjListIterator it(&(gen->Get_Mesh_List()));
- for (it.First(); !it.Is_Done(); it.Next()) {
- MeshClass * mesh = (MeshClass *)it.Get_Obj();
- WWASSERT(mesh->Class_ID()==RenderObjClass::CLASSID_MESH);
- Meshes.Add(mesh);
- }
- }
- void PhysDecalSysClass::LogicalDecalClass::Reset(void)
- {
- for (int i=0; i<Meshes.Count(); i++) {
- Meshes[i]->Delete_Decal(DecalID);
- }
- Meshes.Delete_All();
- DecalID = 0xFFFFFFFF;
- }
|