physdecalsys.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWPhys *
  23. * *
  24. * $Archive:: /Commando/Code/wwphys/physdecalsys.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Ian_l $*
  29. * *
  30. * $Modtime:: 7/17/01 9:52p $*
  31. * *
  32. * $Revision:: 20 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "physdecalsys.h"
  38. #include "colmathaabox.h"
  39. #include "pscene.h"
  40. #include "phys.h"
  41. #include "camera.h"
  42. #include "mesh.h"
  43. #include "decalmsh.h"
  44. #include "assetmgr.h"
  45. #include "wwdebug.h"
  46. #include "robjlist.h"
  47. #include "texture.h"
  48. #define DEBUG_DECALS 0
  49. const float DECAL_BACKFACE_THRESHHOLD = 0.4f; // backface rejection threshhold
  50. const float DECAL_HALF_SLAB_THICKNESS = 0.2f; // thickness of the bounding volume for decals
  51. PhysDecalSysClass::PhysDecalSysClass(PhysicsSceneClass * parent_scene) :
  52. ParentScene(parent_scene),
  53. CreatePermanentDecals(false),
  54. NextTempDecalIndex(0),
  55. DecalMaterial(NULL),
  56. DecalShader(0)
  57. {
  58. allocate_resources();
  59. Set_Temporary_Decal_Pool_Size(50);
  60. }
  61. PhysDecalSysClass::~PhysDecalSysClass(void)
  62. {
  63. release_resources();
  64. }
  65. void PhysDecalSysClass::Update_Decal_Fade_Distances(const CameraClass & camera)
  66. {
  67. /*
  68. ** Since we don't have decal fading any more, set the decal fade distance to the far clip plane
  69. */
  70. float znear,zfar;
  71. camera.Get_Clip_Planes(znear,zfar);
  72. WW3D::Set_Decal_Rejection_Distance(zfar);
  73. }
  74. int PhysDecalSysClass::Create_Decal
  75. (
  76. const Matrix3D & tm,
  77. const char * texture_name,
  78. float radius,
  79. bool is_permanent,
  80. bool apply_to_translucent_meshes,
  81. PhysClass * only_this_obj
  82. )
  83. {
  84. /*
  85. ** Allocate the decal generator
  86. */
  87. CreatePermanentDecals = is_permanent;
  88. DecalGeneratorClass * gen = Lock_Decal_Generator();
  89. WWASSERT(gen != NULL);
  90. /*
  91. ** Set up the transform, projection, and bounding volume parameters
  92. ** I want a thin bounding volume. Since the transform given is right at the impact point,
  93. ** we need to back-up some amount and then set the near and far z depths such that
  94. ** they bound the point
  95. */
  96. float backup_dist = DECAL_HALF_SLAB_THICKNESS + 0.01f;
  97. Matrix3D transform = tm;
  98. transform.Translate_Z(backup_dist);
  99. gen->Set_Transform(transform);
  100. gen->Set_Ortho_Projection(-radius,radius,-radius,radius,0.01f,backup_dist + 2.0f * DECAL_HALF_SLAB_THICKNESS);
  101. gen->Set_Backface_Threshhold(DECAL_BACKFACE_THRESHHOLD);
  102. gen->Apply_To_Translucent_Meshes(apply_to_translucent_meshes);
  103. #if DEBUG_DECALS
  104. ParentScene->Add_Debug_OBBox(gen->Get_Bounding_Volume(),Vector3(0,0,1));
  105. ParentScene->Add_Debug_Axes(tm,Vector3(1,1,1));
  106. ParentScene->Add_Debug_Axes(transform,Vector3(1,1,1));
  107. #endif
  108. /*
  109. ** Set up the material settings. Just plug in the standard alpha shader and the
  110. ** vertex material which all decals use. Then grab the texture which the user
  111. ** specified...
  112. */
  113. MaterialPassClass * material = gen->Get_Material();
  114. material->Set_Shader(DecalShader);
  115. material->Set_Material(DecalMaterial);
  116. TextureClass * tex = WW3DAssetManager::Get_Instance()->Get_Texture(texture_name,TextureClass::MIP_LEVELS_ALL);
  117. tex->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  118. tex->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  119. material->Set_Texture(tex);
  120. tex->Release_Ref();
  121. material->Release_Ref();
  122. /*
  123. ** Collect objects to apply the decal to
  124. */
  125. NonRefPhysListClass list;
  126. if (only_this_obj == NULL) {
  127. ParentScene->Collect_Objects(gen->Get_Bounding_Volume(),true,false,&list);
  128. } else {
  129. list.Add(only_this_obj);
  130. }
  131. /*
  132. ** Apply!
  133. */
  134. NonRefPhysListIterator it(&list);
  135. for (it.First(); !it.Is_Done(); it.Next()) {
  136. it.Peek_Obj()->Peek_Model()->Create_Decal(gen);
  137. }
  138. /*
  139. ** Done. Return the logical id of the decal if we actually created anything,
  140. ** otherwise return -1
  141. */
  142. int return_id = -1;
  143. if (gen->Get_Mesh_List().Is_Empty() == false) {
  144. return_id = gen->Get_Decal_ID();
  145. }
  146. Unlock_Decal_Generator(gen);
  147. return return_id;
  148. }
  149. bool PhysDecalSysClass::Remove_Decal(uint32 id)
  150. {
  151. return internal_remove_decal(id,NULL);
  152. }
  153. void PhysDecalSysClass::Unlock_Decal_Generator(DecalGeneratorClass * generator)
  154. {
  155. /*
  156. ** If the generator actually created decal polygons, add the results
  157. ** to our internal pools
  158. */
  159. if (generator->Get_Mesh_List().Is_Empty() == false) {
  160. if (is_decal_id_permanent(generator->Get_Decal_ID())) {
  161. LogicalDecalClass * newdecal = new LogicalDecalClass;
  162. newdecal->Init(generator);
  163. PermanentDecals.Add(newdecal);
  164. } else {
  165. /*
  166. ** the id should match the "next temp decal index"
  167. */
  168. WWASSERT(generator->Get_Decal_ID() == NextTempDecalIndex);
  169. TempDecals[NextTempDecalIndex].Init(generator);
  170. /*
  171. ** bump the index forward
  172. */
  173. NextTempDecalIndex = (NextTempDecalIndex + 1) % TempDecals.Length();
  174. }
  175. }
  176. DecalSystemClass::Unlock_Decal_Generator(generator);
  177. }
  178. void PhysDecalSysClass::Decal_Mesh_Destroyed(uint32 decal_id,DecalMeshClass * mesh)
  179. {
  180. /*
  181. ** Must remove this mesh from any decals
  182. */
  183. internal_remove_decal(decal_id,mesh->Peek_Parent());
  184. }
  185. void PhysDecalSysClass::Set_Temporary_Decal_Pool_Size(int count)
  186. {
  187. WWASSERT(count > 0);
  188. /*
  189. ** If we are shrinking, remove all decals in the slots that are going away
  190. */
  191. if (count < TempDecals.Length()) {
  192. for (int i=count; i<TempDecals.Length(); i++) {
  193. TempDecals[i].Reset();
  194. }
  195. }
  196. /*
  197. ** Resize the array
  198. */
  199. TempDecals.Resize(count);
  200. /*
  201. ** Make sure that our NextTempDecalIndex is valid, if not wrap it around
  202. */
  203. if (NextTempDecalIndex >= (uint32)TempDecals.Length()) {
  204. NextTempDecalIndex = 0;
  205. }
  206. }
  207. int PhysDecalSysClass::Get_Temporary_Decal_Pool_Size(void)
  208. {
  209. return TempDecals.Length();
  210. }
  211. uint32 PhysDecalSysClass::Generate_Decal_Id(void)
  212. {
  213. uint32 id;
  214. if (CreatePermanentDecals) {
  215. id = Generate_Unique_Global_Decal_Id() & 0x7FFFFFFF;
  216. id |= 0x80000000;
  217. } else {
  218. id = NextTempDecalIndex;
  219. }
  220. return id;
  221. }
  222. bool PhysDecalSysClass::is_decal_id_permanent(uint32 id)
  223. {
  224. if (id & 0x80000000) {
  225. return true;
  226. } else {
  227. return false;
  228. }
  229. }
  230. void PhysDecalSysClass::allocate_resources(void)
  231. {
  232. WWASSERT(DecalMaterial == NULL);
  233. DecalMaterial = NEW_REF(VertexMaterialClass,());
  234. DecalMaterial->Set_Ambient(0,0,0);
  235. DecalMaterial->Set_Diffuse(0,0,0);
  236. DecalMaterial->Set_Specular(0,0,0);
  237. DecalMaterial->Set_Emissive(1,1,1);
  238. DecalMaterial->Set_Opacity(1.0f);
  239. DecalMaterial->Set_Shininess(0.0f);
  240. DecalShader = ShaderClass::_PresetAlphaShader;
  241. }
  242. void PhysDecalSysClass::release_resources(void)
  243. {
  244. REF_PTR_RELEASE(DecalMaterial);
  245. }
  246. bool PhysDecalSysClass::internal_remove_decal(uint32 id,MeshClass * deleted_mesh)
  247. {
  248. bool success = false;
  249. if (is_decal_id_permanent(id)) {
  250. /*
  251. ** Find the decal with the given id in the Permanent decal array
  252. */
  253. MultiListIterator<LogicalDecalClass> it(&PermanentDecals);
  254. for (it.First(); !it.Is_Done(); it.Next()) {
  255. LogicalDecalClass * decal = it.Get_Obj();
  256. if (decal->DecalID == id) {
  257. /*
  258. ** Just remove the deleted mesh from our list. We don't need to delete
  259. ** its decals since it is telling us that it has been deleted already.
  260. */
  261. if (deleted_mesh != NULL) {
  262. decal->Meshes.Delete(deleted_mesh);
  263. }
  264. /*
  265. ** Now destroy this logical decal, this results in all decal-meshes that
  266. ** are referenced by this logical decal being told to remove this decal id.
  267. */
  268. PermanentDecals.Remove(decal);
  269. delete decal;
  270. success = true;
  271. break;
  272. }
  273. }
  274. } else {
  275. /*
  276. ** Temporary decals use their index as the id
  277. */
  278. WWASSERT(id >= 0);
  279. WWASSERT(id < (uint32)TempDecals.Length());
  280. if (deleted_mesh != NULL) {
  281. TempDecals[id].Meshes.Delete(deleted_mesh);
  282. }
  283. TempDecals[id].Reset();
  284. success = true;
  285. }
  286. return success;
  287. }
  288. /*
  289. ** LogicalDecalClass Implementation
  290. */
  291. PhysDecalSysClass::LogicalDecalClass::LogicalDecalClass(void) :
  292. DecalID(0xFFFFFFFF)
  293. {
  294. }
  295. PhysDecalSysClass::LogicalDecalClass::~LogicalDecalClass(void)
  296. {
  297. Reset();
  298. }
  299. void PhysDecalSysClass::LogicalDecalClass::Init(DecalGeneratorClass * gen)
  300. {
  301. /*
  302. ** Reset ourselves in case we were being used to track a previous decal.
  303. ** This causes that decal to get removed from the system.
  304. */
  305. Reset();
  306. /*
  307. ** Record the data for this decal
  308. */
  309. DecalID = gen->Get_Decal_ID();
  310. NonRefRenderObjListIterator it(&(gen->Get_Mesh_List()));
  311. for (it.First(); !it.Is_Done(); it.Next()) {
  312. MeshClass * mesh = (MeshClass *)it.Get_Obj();
  313. WWASSERT(mesh->Class_ID()==RenderObjClass::CLASSID_MESH);
  314. Meshes.Add(mesh);
  315. }
  316. }
  317. void PhysDecalSysClass::LogicalDecalClass::Reset(void)
  318. {
  319. for (int i=0; i<Meshes.Count(); i++) {
  320. Meshes[i]->Delete_Decal(DecalID);
  321. }
  322. Meshes.Delete_All();
  323. DecalID = 0xFFFFFFFF;
  324. }