stealtheffect.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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/stealtheffect.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Byon_g $*
  29. * *
  30. * $Modtime:: 12/20/01 6:32p $*
  31. * *
  32. * $Revision:: 12 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "stealtheffect.h"
  38. #include "matpass.h"
  39. #include "vertmaterial.h"
  40. #include "physresourcemgr.h"
  41. #include "phys.h"
  42. #include "rinfo.h"
  43. #include "camera.h"
  44. #include "chunkio.h"
  45. /*************************************************************************************************
  46. **
  47. ** StealthEffectClass Implementation
  48. **
  49. *************************************************************************************************/
  50. static float STEALTH_FRACTION_RATE = 0.5f; // rate at which the fraction approaches its target
  51. static float STEALTH_DEFAULT_FADE_DISTANCE= 25.0f; // distance at which the intensity starts to fade due to camera proximity
  52. static float STEALTH_ZNEAR_AMOUNT = 0.40f; // amount the intensity can change as it approaches the camera
  53. static float STEALTH_FRIENDLY_FRACTION = 0.75f; // fraction at which friendly stealthed objects appear
  54. static float STEALTH_BROKEN_FRACTION = 0.25f; // fraction at which broken stealthed objects appear
  55. static float STEALTH_DAMAGED_FRACTION = 0.6f; // fraction that is jumped to when an object gets damaged
  56. static Vector2 MAX_STEALTH_UV_RATE(2.75f,-3.0f);
  57. static Vector2 MIN_STEALTH_UV_RATE(0.5f,-0.5f);
  58. StealthEffectClass::StealthEffectClass(void) :
  59. IsStealthEnabled(false),
  60. IsFriendly(false),
  61. IsBroken(false),
  62. FadeDistance(STEALTH_DEFAULT_FADE_DISTANCE),
  63. CurrentFraction(0.0f),
  64. TargetFraction(1.0f),
  65. UVRate(0.5f,0.5f),
  66. RenderBaseMaterial(true),
  67. RenderStealthMaterial(true),
  68. IntensityScale(0.0f),
  69. UVOffset(0.0f,0.0f),
  70. Mapper(NULL),
  71. MaterialPass(NULL)
  72. {
  73. MaterialPass = NEW_REF(MaterialPassClass,());
  74. VertexMaterialClass * vmtl = NEW_REF(VertexMaterialClass,()); //PhysResourceMgrClass::Get_Stealth_Material();
  75. vmtl->Set_Ambient(0,0,0);
  76. vmtl->Set_Diffuse(0,0,0);
  77. vmtl->Set_Specular(0,0,0);
  78. vmtl->Set_Emissive(1.0f,1.0f,1.0f);
  79. vmtl->Set_Opacity(1.0f);
  80. vmtl->Set_Shininess(0.0f);
  81. vmtl->Set_Lighting(true);
  82. Mapper = NEW_REF(MatrixMapperClass,(0));
  83. Mapper->Set_Type(MatrixMapperClass::ORTHO_PROJECTION);
  84. Mapper->Set_Texture_Transform(Matrix4(1),64.0f);
  85. vmtl->Set_Mapper(Mapper,0);
  86. MaterialPass->Set_Material(vmtl);
  87. REF_PTR_RELEASE(vmtl);
  88. ShaderClass shader = ShaderClass::_PresetAdditiveShader;
  89. shader.Set_Primary_Gradient(ShaderClass::GRADIENT_ADD);
  90. MaterialPass->Set_Shader(ShaderClass::_PresetAdditiveShader);
  91. MaterialPass->Set_Texture(PhysResourceMgrClass::Peek_Stealth_Texture());
  92. MaterialPass->Enable_On_Translucent_Meshes( false );
  93. }
  94. StealthEffectClass::~StealthEffectClass(void)
  95. {
  96. REF_PTR_RELEASE(MaterialPass);
  97. REF_PTR_RELEASE(Mapper);
  98. }
  99. void StealthEffectClass::Enable_Stealth(bool onoff)
  100. {
  101. IsStealthEnabled = onoff;
  102. Update_Target_Fraction();
  103. }
  104. void StealthEffectClass::Set_Friendly(bool onoff)
  105. {
  106. IsFriendly = onoff;
  107. Update_Target_Fraction();
  108. }
  109. void StealthEffectClass::Set_Broken(bool onoff)
  110. {
  111. IsBroken = onoff;
  112. Update_Target_Fraction();
  113. }
  114. void StealthEffectClass::Damage_Occured(void)
  115. {
  116. if (IsStealthEnabled && (CurrentFraction > STEALTH_DAMAGED_FRACTION)) {
  117. CurrentFraction = STEALTH_DAMAGED_FRACTION;
  118. }
  119. }
  120. void StealthEffectClass::Update_Target_Fraction(void)
  121. {
  122. if (IsStealthEnabled) {
  123. if (IsBroken) {
  124. TargetFraction = STEALTH_BROKEN_FRACTION;
  125. } else if (IsFriendly) {
  126. TargetFraction = STEALTH_FRIENDLY_FRACTION;
  127. } else {
  128. TargetFraction = 1.0f;
  129. }
  130. } else {
  131. TargetFraction = 0.0f;
  132. }
  133. }
  134. void StealthEffectClass::Timestep(float dt)
  135. {
  136. /*
  137. ** Update the stealth fraction
  138. */
  139. float step = STEALTH_FRACTION_RATE * dt;
  140. if (step > WWMath::Fabs(TargetFraction - CurrentFraction)) {
  141. CurrentFraction = TargetFraction;
  142. } else {
  143. if (TargetFraction < CurrentFraction) {
  144. CurrentFraction -= step;
  145. } else {
  146. CurrentFraction += step;
  147. }
  148. }
  149. /*
  150. ** The Intensity is computed as a function of the stealth fraction
  151. */
  152. IntensityScale = 1.0f - 2.0f * WWMath::Fabs(CurrentFraction - 0.5f);
  153. /*
  154. ** Update the uv cycling animation. I'm deriving the UV animation rate
  155. ** from the intensity
  156. */
  157. Vector2 uv_rate = MIN_STEALTH_UV_RATE + IntensityScale * IntensityScale * (MAX_STEALTH_UV_RATE - MIN_STEALTH_UV_RATE);
  158. UVOffset += uv_rate * dt;
  159. UVOffset.X = fmod(UVOffset.X , 2.0f);
  160. UVOffset.Y = fmod(UVOffset.Y , 2.0f);
  161. /*
  162. ** The base pass gets rendered when the stealh fraction is < 0.5
  163. ** shadows are also suppressed.
  164. */
  165. RenderBaseMaterial = (CurrentFraction < 0.5f);
  166. Enable_Suppress_Shadows(CurrentFraction > 0.5f);
  167. }
  168. void StealthEffectClass::Render_Push(RenderInfoClass & rinfo,PhysClass * obj)
  169. {
  170. /*
  171. ** If we are in the (0.5,1.0) range of the fraction (object is hidden) then
  172. ** the distance from the camera to the object can affect the intensity.
  173. */
  174. Vector3 obj_pos;
  175. obj->Get_Position(&obj_pos);
  176. float xydist = (rinfo.Camera.Get_Position() - obj_pos).Quick_Length();
  177. if (xydist <= FadeDistance) {
  178. float intensity_delta = STEALTH_ZNEAR_AMOUNT * (FadeDistance - xydist) / FadeDistance;
  179. float intensity = WWMath::Min(IntensityScale + intensity_delta, 1.0f);
  180. IntensityScale = intensity;
  181. }
  182. /*
  183. ** The stealth material gets rendered if the intensity is greater than 0.0
  184. */
  185. RenderStealthMaterial = (IntensityScale > 0.0f);
  186. if (RenderStealthMaterial) {
  187. /*
  188. ** Update the material settings and texture transform
  189. */
  190. MaterialPass->Peek_Material()->Set_Emissive(Vector3(1,1,1) * IntensityScale);
  191. Matrix4 tm(1);
  192. tm[0][3] = UVOffset.X;
  193. tm[1][3] = UVOffset.Y;
  194. Mapper->Set_Texture_Transform(tm,64.0f);
  195. /*
  196. ** Add the material pass!
  197. */
  198. rinfo.Push_Material_Pass(MaterialPass);
  199. }
  200. if (RenderBaseMaterial == false) {
  201. rinfo.Push_Override_Flags(RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY);
  202. }
  203. }
  204. void StealthEffectClass::Render_Pop(RenderInfoClass & rinfo)
  205. {
  206. if (RenderBaseMaterial == false) {
  207. rinfo.Pop_Override_Flags();
  208. }
  209. if (RenderStealthMaterial) {
  210. rinfo.Pop_Material_Pass();
  211. }
  212. }
  213. /************************************************************************************
  214. **
  215. ** Save-Load support
  216. **
  217. ************************************************************************************/
  218. enum
  219. {
  220. STEALTHEFFECT_CHUNK_VARIABLES = 0x055ffe07, // member variables.
  221. STEALTHEFFECT_VARIABLE_ISSTEALTHENABLED = 0x00,
  222. STEALTHEFFECT_VARIABLE_ISFRIENDLY,
  223. STEALTHEFFECT_VARIABLE_ISBROKEN,
  224. STEALTHEFFECT_VARIABLE_CURRENTFRACTION,
  225. STEALTHEFFECT_VARIABLE_TARGETFRACTION,
  226. STEALTHEFFECT_VARIABLE_UVRATE,
  227. STEALTHEFFECT_VARIABLE_FADEDISTANCE,
  228. };
  229. bool StealthEffectClass::Save(ChunkSaveClass & csave)
  230. {
  231. csave.Begin_Chunk(STEALTHEFFECT_CHUNK_VARIABLES);
  232. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_ISSTEALTHENABLED,IsStealthEnabled);
  233. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_ISFRIENDLY,IsFriendly);
  234. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_ISBROKEN,IsBroken);
  235. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_CURRENTFRACTION,CurrentFraction);
  236. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_TARGETFRACTION,TargetFraction);
  237. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_UVRATE,UVRate);
  238. WRITE_MICRO_CHUNK(csave,STEALTHEFFECT_VARIABLE_FADEDISTANCE,FadeDistance);
  239. csave.End_Chunk();
  240. return true;
  241. }
  242. bool StealthEffectClass::Load(ChunkLoadClass & cload)
  243. {
  244. while (cload.Open_Chunk()) {
  245. switch(cload.Cur_Chunk_ID()) {
  246. case STEALTHEFFECT_CHUNK_VARIABLES:
  247. while (cload.Open_Micro_Chunk()) {
  248. switch(cload.Cur_Micro_Chunk_ID()) {
  249. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_ISSTEALTHENABLED,IsStealthEnabled);
  250. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_ISFRIENDLY,IsFriendly);
  251. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_ISBROKEN,IsBroken);
  252. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_CURRENTFRACTION,CurrentFraction);
  253. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_TARGETFRACTION,TargetFraction);
  254. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_UVRATE,UVRate);
  255. READ_MICRO_CHUNK(cload,STEALTHEFFECT_VARIABLE_FADEDISTANCE,FadeDistance);
  256. }
  257. cload.Close_Micro_Chunk();
  258. }
  259. break;
  260. }
  261. cload.Close_Chunk();
  262. }
  263. return true;
  264. }