Fog.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdH.h"
  13. #include <Engine/Base/Memory.h>
  14. #include <Engine/Base/Filename.h>
  15. #include <Engine/Base/Statistics_internal.h>
  16. #include <Engine/Math/Matrix.h>
  17. #include <Engine/Math/Functions.h>
  18. #include <Engine/Graphics/Color.h>
  19. #include <Engine/Graphics/GfxLibrary.h>
  20. #include <Engine/Graphics/Fog_internal.h>
  21. #include <Engine/Graphics/GfxProfile.h>
  22. #include <Engine/Graphics/ImageInfo.h>
  23. // asm shortcuts
  24. #define O offset
  25. #define Q qword ptr
  26. #define D dword ptr
  27. #define W word ptr
  28. #define B byte ptr
  29. // current fog parameters
  30. BOOL _fog_bActive = FALSE;
  31. CFogParameters _fog_fp;
  32. CTexParams _fog_tpLocal;
  33. FLOAT _fog_fViewerH = 0.0f;
  34. FLOAT3D _fog_vViewPosAbs;
  35. FLOAT3D _fog_vViewDirAbs;
  36. FLOAT3D _fog_vHDirAbs;
  37. FLOAT3D _fog_vHDirView;
  38. FLOAT _fog_fMulZ=0;
  39. FLOAT _fog_fMulH=0;
  40. FLOAT _fog_fAddH=0;
  41. ULONG _fog_ulAlpha=0;
  42. ULONG _fog_ulTexture=0;
  43. ULONG _fog_ulFormat=0;
  44. PIX _fog_pixSizeH=0;
  45. PIX _fog_pixSizeL=0;
  46. FLOAT _fog_fStart=0; // where in height fog starts
  47. FLOAT _fog_fEnd=0; // where in height fog ends
  48. UBYTE *_fog_pubTable=NULL;
  49. extern INDEX gfx_bRenderFog;
  50. extern BOOL _bMultiPlayer;
  51. // prepares fog and haze parameters and eventualy converts texture
  52. ULONG PrepareTexture( UBYTE *pubTexture, PIX pixSizeI, PIX pixSizeJ)
  53. {
  54. // need to upload from RGBA format
  55. const PIX pixTextureSize = pixSizeI*pixSizeJ;
  56. __asm {
  57. mov esi,D [pubTexture]
  58. mov edi,D [pubTexture]
  59. mov ecx,D [pixTextureSize]
  60. lea edi,[esi+ecx]
  61. pixLoop:
  62. movzx eax,B [esi]
  63. or eax,0xFFFFFF00
  64. bswap eax
  65. mov D [edi],eax
  66. add esi,1
  67. add edi,4
  68. dec ecx
  69. jnz pixLoop
  70. }
  71. // determine internal format
  72. extern INDEX gap_bAllowGrayTextures;
  73. extern INDEX tex_bFineFog;
  74. if( gap_bAllowGrayTextures) return TS.ts_tfLA8;
  75. if( tex_bFineFog) return TS.ts_tfRGBA8;
  76. return TS.ts_tfRGBA4;
  77. }
  78. // start fog with given parameters
  79. void StartFog( CFogParameters &fp, const FLOAT3D &vViewPosAbs, const FLOATmatrix3D &mAbsToView)
  80. {
  81. ASSERT( !_fog_bActive);
  82. if( _bMultiPlayer) gfx_bRenderFog = 1;
  83. if( !gfx_bRenderFog) return;
  84. _fog_bActive = TRUE;
  85. _fog_fp = fp;
  86. _fog_vHDirAbs = -_fog_fp.fp_vFogDir;
  87. _fog_vViewPosAbs = vViewPosAbs;
  88. _fog_vViewDirAbs(1) = -mAbsToView(3, 1);
  89. _fog_vViewDirAbs(2) = -mAbsToView(3, 2);
  90. _fog_vViewDirAbs(3) = -mAbsToView(3, 3);
  91. _fog_fViewerH = _fog_vViewPosAbs%-_fog_fp.fp_vFogDir;
  92. _fog_vHDirView = _fog_vHDirAbs*mAbsToView;
  93. // calculate fog mapping factors
  94. _fog_fMulZ = 1/(_fog_fp.fp_fFar);
  95. _fog_fMulH = 1/(_fog_fp.fp_fH3-_fog_fp.fp_fH0);
  96. _fog_fAddH = _fog_fp.fp_fH3+_fog_fViewerH;
  97. // calculate fog table size wanted
  98. extern INDEX tex_iFogSize;
  99. tex_iFogSize = Clamp( tex_iFogSize, 4L, 8L);
  100. PIX pixSizeH = ClampUp( _fog_fp.fp_iSizeH, 1L<<tex_iFogSize);
  101. PIX pixSizeL = ClampUp( _fog_fp.fp_iSizeL, 1L<<tex_iFogSize);
  102. BOOL bNoDiscard = TRUE;
  103. // if fog table is not allocated in right size
  104. if( (_fog_pixSizeH!=pixSizeH || _fog_pixSizeL!=pixSizeL) && _fog_pubTable!=NULL) {
  105. FreeMemory( _fog_pubTable); // free it
  106. _fog_pubTable = NULL;
  107. }
  108. // allocate table if needed
  109. if( _fog_pubTable==NULL) {
  110. // allocate byte table (for intensity values) and ULONG table (color values for uploading) right behind!
  111. _fog_pubTable = (UBYTE*)AllocMemory( pixSizeH*pixSizeL * (sizeof(UBYTE)+sizeof(ULONG)));
  112. _fog_pixSizeH = pixSizeH;
  113. _fog_pixSizeL = pixSizeL;
  114. _fog_tpLocal.Clear();
  115. bNoDiscard = FALSE;
  116. }
  117. // update fog alpha value
  118. _fog_ulAlpha = (_fog_fp.fp_colColor&CT_AMASK)>>CT_ASHIFT;
  119. // get parameters
  120. const FLOAT fH0 = _fog_fp.fp_fH0; // lowest point in LUT ->texture t=1
  121. const FLOAT fH1 = _fog_fp.fp_fH1; // bottom of fog in LUT
  122. const FLOAT fH2 = _fog_fp.fp_fH2; // top of fog in LUT
  123. const FLOAT fH3 = _fog_fp.fp_fH3; // highest point in LUT ->texture t=0
  124. const FLOAT fFar = _fog_fp.fp_fFar; // farthest point in LUT ->texture s=1
  125. const FLOAT fDensity = _fog_fp.fp_fDensity;
  126. const AttenuationType at = _fog_fp.fp_atType;
  127. const FogGraduationType fgt = _fog_fp.fp_fgtType;
  128. const FLOAT fHFogSize = fH2-fH1;
  129. const FLOAT fHV = -_fog_fViewerH;
  130. const FLOAT fEpsilon = 0.001f;
  131. ASSERT( fHFogSize>0);
  132. // for each row (height in fog)
  133. for( PIX pixH=0; pixH<pixSizeH; pixH++)
  134. {
  135. // get fog height of the point from row coordinate in texture
  136. FLOAT fHP = fH3+FLOAT(pixH)/pixSizeH*(fH0-fH3);
  137. // sort viewer and point and get A (lower) and B (higher) fog coord
  138. // making sure that they are never same
  139. FLOAT fHA, fHB;
  140. if (fHP<fHV-fEpsilon) {
  141. fHA=fHP;
  142. fHB=fHV;
  143. } else if (fHP>fHV+fEpsilon) {
  144. fHA=fHV;
  145. fHB=fHP;
  146. } else {
  147. fHA=fHV-fEpsilon;
  148. fHB=fHP+fEpsilon;
  149. }
  150. // get distance between the two points in height axis
  151. FLOAT fDH = fHB-fHA;
  152. FLOAT fOoDH = 1/fDH;
  153. // calculate relative part of height that goes through the fog
  154. FLOAT fA2 = (fH2-fHA)*fOoDH;
  155. fA2 = Clamp(fA2,0.0f,1.0f);
  156. FLOAT fA1 = (fH1-fHA)*fOoDH;
  157. fA1 = Clamp(fA1,0.0f,1.0f);
  158. FLOAT fA = fA2-fA1;
  159. fA = Clamp(fA,0.0f,1.0f);
  160. // if not constant graduation
  161. if( fgt!=FGT_CONSTANT) {
  162. // calculate fog height for two points, limited to be inside fog
  163. FLOAT fFH0 = (fHFogSize-Clamp(fHA-fH1, 0.0f, fHFogSize));
  164. FLOAT fFH1 = (fHFogSize-Clamp(fHB-fH1, 0.0f, fHFogSize));
  165. // multiply the heights by graduation factor
  166. fFH0 *= _fog_fp.fp_fGraduation;
  167. fFH1 *= _fog_fp.fp_fGraduation;
  168. FLOAT fDens;
  169. // if linear graduation
  170. if (fgt==FGT_LINEAR) {
  171. // get linear integrated density factor
  172. fDens = (fFH0+fFH1)/2.0f;
  173. // if exponential graduation
  174. } else {
  175. ASSERT(fgt==FGT_EXP);
  176. // sort the two heights and make sure they are not same
  177. FLOAT fFA, fFB;
  178. if (fFH0<fFH1-fEpsilon) {
  179. fFA=fFH0;
  180. fFB=fFH1;
  181. } else if (fFH0>fFH1+fEpsilon) {
  182. fFA=fFH1;
  183. fFB=fFH0;
  184. } else {
  185. fFA=fFH1-fEpsilon;
  186. fFB=fFH0+fEpsilon;
  187. }
  188. // calculate exponential integrated density factor normally
  189. fDens = 1.0f+(exp(-fFB)-exp(-fFA))/(fFB-fFA);
  190. }
  191. // limit the intergrated density factor
  192. fDens = Clamp(fDens, 0.0f, 1.0f);
  193. // relative size multiplied by integrated density factor gives total fog sum
  194. fA *= fDens;
  195. }
  196. // do per-row loop
  197. switch(at)
  198. {
  199. // linear fog
  200. case AT_LINEAR: {
  201. // calculate linear step for the fog parameter
  202. FLOAT fT = 0.0f;
  203. FLOAT fTStep = 1.0f/pixSizeL *fFar*fDensity*fA *255;
  204. // fog is just clamped fog parameter in each pixel
  205. for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
  206. _fog_pubTable[pixH*pixSizeL+pixL] = Clamp( FloatToInt(fT), 0L, 255L);
  207. fT += fTStep;
  208. }
  209. } break;
  210. // exp fog
  211. case AT_EXP: {
  212. // calculate linear step for the fog parameter
  213. FLOAT fT = 0.0f;
  214. FLOAT fTStep = 1.0f/pixSizeL*fFar*fDensity*fA;
  215. // fog is exp(-t) function of fog parameter, now calculate
  216. // step (actually multiplication) for the fog
  217. FLOAT fExp = 255.0f;
  218. FLOAT fExpMul = exp(-fTStep);
  219. for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
  220. _fog_pubTable[pixH*pixSizeL+pixL] = 255-FloatToInt(fExp);
  221. fExp *= fExpMul;
  222. }
  223. } break;
  224. case AT_EXP2: {
  225. // calculate linear step for the fog parameter
  226. FLOAT fT = 0.0f;
  227. FLOAT fTStep = 1.0f/pixSizeL*fFar*fDensity*fA;
  228. // fog is exp(-t^2) function of fog parameter, now calculate
  229. // first and second order step (actually multiplication) for the fog
  230. FLOAT fExp2 = 255.0f;
  231. FLOAT fExp2Mul = exp(-fTStep*fTStep);
  232. FLOAT fExp2MulMul = exp(-2*fTStep*fTStep);
  233. for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
  234. _fog_pubTable[pixH*pixSizeL+pixL] = 255-FloatToInt(fExp2);
  235. fExp2 *= fExp2Mul;
  236. fExp2Mul *= fExp2MulMul;
  237. }
  238. } break;
  239. }
  240. }
  241. // determine where fog starts and ends
  242. _fog_fStart = LowerLimit(0.0f);
  243. _fog_fEnd = UpperLimit(0.0f);
  244. if( _fog_pubTable[pixSizeL-1]) {
  245. // going from bottom
  246. INDEX pix=pixSizeH-1;
  247. for( ; pix>0; pix--) {
  248. if( (_fog_pubTable[(pix+1)*pixSizeL-1]*_fog_ulAlpha)>>8) break;
  249. }
  250. if( pix<(pixSizeH-1)) _fog_fEnd = (FLOAT)(pix+1) / (FLOAT)(pixSizeH-1);
  251. } else {
  252. // going from top
  253. INDEX pix=0;
  254. for( ; pix<pixSizeH; pix++) {
  255. if( (_fog_pubTable[(pix+1)*pixSizeL-1]*_fog_ulAlpha)>>8) break;
  256. }
  257. if( pix>0) _fog_fStart = (FLOAT)(pix-1) / (FLOAT)(pixSizeH-1);
  258. }
  259. // prepare and upload the fog table
  260. _fog_tpLocal.tp_bSingleMipmap = TRUE;
  261. const ULONG ulFormat = PrepareTexture( _fog_pubTable, _fog_pixSizeL, _fog_pixSizeH);
  262. if( _fog_ulFormat!=ulFormat) {
  263. _fog_ulFormat = ulFormat;
  264. bNoDiscard = FALSE;
  265. } // set'n'upload
  266. gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
  267. gfxSetTexture( _fog_ulTexture, _fog_tpLocal);
  268. gfxUploadTexture( (ULONG*)(_fog_pubTable + _fog_pixSizeL*_fog_pixSizeH),
  269. _fog_pixSizeL, _fog_pixSizeH, ulFormat, bNoDiscard);
  270. }
  271. // stop fog
  272. void StopFog(void)
  273. {
  274. _fog_bActive = FALSE;
  275. }
  276. // current haze parameters
  277. BOOL _haze_bActive = FALSE;
  278. CHazeParameters _haze_hp;
  279. CTexParams _haze_tpLocal;
  280. PIX _haze_pixSize=0;
  281. FLOAT _haze_fStart=0; // where in depth haze starts
  282. UBYTE *_haze_pubTable=NULL;
  283. FLOAT3D _haze_vViewPosAbs;
  284. FLOAT3D _haze_vViewDirAbs;
  285. FLOAT _haze_fMul=0;
  286. FLOAT _haze_fAdd=0;
  287. ULONG _haze_ulAlpha=0;
  288. ULONG _haze_ulTexture=0;
  289. ULONG _haze_ulFormat=0;
  290. // start haze with given parameters
  291. void StartHaze( CHazeParameters &hp,
  292. const FLOAT3D &vViewPosAbs, const FLOATmatrix3D &mAbsToView)
  293. {
  294. ASSERT( !_haze_bActive);
  295. if( _bMultiPlayer) gfx_bRenderFog = 1;
  296. if( !gfx_bRenderFog) return;
  297. _haze_bActive = TRUE;
  298. _haze_hp = hp;
  299. _haze_vViewPosAbs = vViewPosAbs;
  300. _haze_vViewDirAbs(1) = -mAbsToView(3, 1);
  301. _haze_vViewDirAbs(2) = -mAbsToView(3, 2);
  302. _haze_vViewDirAbs(3) = -mAbsToView(3, 3);
  303. // calculate haze mapping factors
  304. _haze_fMul = 1/(_haze_hp.hp_fFar-_haze_hp.hp_fNear);
  305. _haze_fAdd = -_haze_hp.hp_fNear;
  306. PIX pixSize = _haze_hp.hp_iSize;
  307. BOOL bNoDiscard = TRUE;
  308. // if haze table is not allocated in right size
  309. if( _haze_pixSize!=pixSize && _haze_pubTable!=NULL) {
  310. FreeMemory( _haze_pubTable); // free it
  311. _haze_pubTable = NULL;
  312. }
  313. // allocate table if needed
  314. if( _haze_pubTable==NULL) {
  315. // allocate byte table (for intensity values) and ULONG table (color values for uploading) right behind!
  316. _haze_pubTable = (UBYTE*)AllocMemory(pixSize *(sizeof(UBYTE)+sizeof(ULONG)));
  317. _haze_pixSize = pixSize;
  318. _haze_tpLocal.Clear();
  319. bNoDiscard = FALSE;
  320. }
  321. // update fog alpha value
  322. _haze_ulAlpha = (_haze_hp.hp_colColor&CT_AMASK)>>CT_ASHIFT;
  323. // get parameters
  324. FLOAT fNear = _haze_hp.hp_fNear;
  325. FLOAT fFar = _haze_hp.hp_fFar;
  326. FLOAT fDensity = _haze_hp.hp_fDensity;
  327. AttenuationType at = _haze_hp.hp_atType;
  328. // generate table
  329. INDEX pix;
  330. for( pix=0; pix<pixSize; pix++) {
  331. FLOAT fD = FLOAT(pix)/pixSize*(fFar-fNear);
  332. FLOAT fT = fDensity*fD;
  333. FLOAT fHaze=0.0f;
  334. switch(at) {
  335. case AT_LINEAR: fHaze = Clamp(fT,0.0f,1.0f); break;
  336. case AT_EXP: fHaze = 1-exp(-fT); break;
  337. case AT_EXP2: fHaze = 1-exp(-fT*fT); break;
  338. }
  339. const UBYTE ubValue = NormFloatToByte(fHaze);
  340. _haze_pubTable[pix] = ubValue;
  341. }
  342. // determine where haze starts
  343. for( pix=1; pix<pixSize; pix++) if( (_haze_pubTable[pix]*_haze_ulAlpha)>>8) break;
  344. _haze_fStart = (FLOAT)(pix-1) / (FLOAT)(pixSize-1);
  345. // prepare haze table
  346. _haze_tpLocal.tp_bSingleMipmap = TRUE;
  347. const ULONG ulFormat = PrepareTexture( _haze_pubTable, _haze_pixSize, 1);
  348. if( _haze_ulFormat!=ulFormat) {
  349. _haze_ulFormat = ulFormat;
  350. bNoDiscard = FALSE;
  351. } // set'n'upload
  352. gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
  353. gfxSetTexture( _haze_ulTexture, _haze_tpLocal);
  354. gfxUploadTexture( (ULONG*)(_haze_pubTable + _haze_pixSize*1), _haze_pixSize, 1, ulFormat, bNoDiscard);
  355. }
  356. // stop haze
  357. void StopHaze(void)
  358. {
  359. _haze_bActive = FALSE;
  360. }