123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- 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, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "StdH.h"
- #include <Engine/Base/Memory.h>
- #include <Engine/Base/Filename.h>
- #include <Engine/Base/Statistics_internal.h>
- #include <Engine/Math/Matrix.h>
- #include <Engine/Math/Functions.h>
- #include <Engine/Graphics/Color.h>
- #include <Engine/Graphics/GfxLibrary.h>
- #include <Engine/Graphics/Fog_internal.h>
- #include <Engine/Graphics/GfxProfile.h>
- #include <Engine/Graphics/ImageInfo.h>
- // asm shortcuts
- #define O offset
- #define Q qword ptr
- #define D dword ptr
- #define W word ptr
- #define B byte ptr
- // current fog parameters
- BOOL _fog_bActive = FALSE;
- CFogParameters _fog_fp;
- CTexParams _fog_tpLocal;
- FLOAT _fog_fViewerH = 0.0f;
- FLOAT3D _fog_vViewPosAbs;
- FLOAT3D _fog_vViewDirAbs;
- FLOAT3D _fog_vHDirAbs;
- FLOAT3D _fog_vHDirView;
- FLOAT _fog_fMulZ=0;
- FLOAT _fog_fMulH=0;
- FLOAT _fog_fAddH=0;
- ULONG _fog_ulAlpha=0;
- ULONG _fog_ulTexture=0;
- ULONG _fog_ulFormat=0;
- PIX _fog_pixSizeH=0;
- PIX _fog_pixSizeL=0;
- FLOAT _fog_fStart=0; // where in height fog starts
- FLOAT _fog_fEnd=0; // where in height fog ends
- UBYTE *_fog_pubTable=NULL;
- extern INDEX gfx_bRenderFog;
- extern BOOL _bMultiPlayer;
- // prepares fog and haze parameters and eventualy converts texture
- ULONG PrepareTexture( UBYTE *pubTexture, PIX pixSizeI, PIX pixSizeJ)
- {
- // need to upload from RGBA format
- const PIX pixTextureSize = pixSizeI*pixSizeJ;
- __asm {
- mov esi,D [pubTexture]
- mov edi,D [pubTexture]
- mov ecx,D [pixTextureSize]
- lea edi,[esi+ecx]
- pixLoop:
- movzx eax,B [esi]
- or eax,0xFFFFFF00
- bswap eax
- mov D [edi],eax
- add esi,1
- add edi,4
- dec ecx
- jnz pixLoop
- }
- // determine internal format
- extern INDEX gap_bAllowGrayTextures;
- extern INDEX tex_bFineFog;
- if( gap_bAllowGrayTextures) return TS.ts_tfLA8;
- if( tex_bFineFog) return TS.ts_tfRGBA8;
- return TS.ts_tfRGBA4;
- }
- // start fog with given parameters
- void StartFog( CFogParameters &fp, const FLOAT3D &vViewPosAbs, const FLOATmatrix3D &mAbsToView)
- {
- ASSERT( !_fog_bActive);
- if( _bMultiPlayer) gfx_bRenderFog = 1;
- if( !gfx_bRenderFog) return;
- _fog_bActive = TRUE;
- _fog_fp = fp;
- _fog_vHDirAbs = -_fog_fp.fp_vFogDir;
- _fog_vViewPosAbs = vViewPosAbs;
- _fog_vViewDirAbs(1) = -mAbsToView(3, 1);
- _fog_vViewDirAbs(2) = -mAbsToView(3, 2);
- _fog_vViewDirAbs(3) = -mAbsToView(3, 3);
- _fog_fViewerH = _fog_vViewPosAbs%-_fog_fp.fp_vFogDir;
- _fog_vHDirView = _fog_vHDirAbs*mAbsToView;
- // calculate fog mapping factors
- _fog_fMulZ = 1/(_fog_fp.fp_fFar);
- _fog_fMulH = 1/(_fog_fp.fp_fH3-_fog_fp.fp_fH0);
- _fog_fAddH = _fog_fp.fp_fH3+_fog_fViewerH;
- // calculate fog table size wanted
- extern INDEX tex_iFogSize;
- tex_iFogSize = Clamp( tex_iFogSize, 4L, 8L);
- PIX pixSizeH = ClampUp( _fog_fp.fp_iSizeH, 1L<<tex_iFogSize);
- PIX pixSizeL = ClampUp( _fog_fp.fp_iSizeL, 1L<<tex_iFogSize);
- BOOL bNoDiscard = TRUE;
- // if fog table is not allocated in right size
- if( (_fog_pixSizeH!=pixSizeH || _fog_pixSizeL!=pixSizeL) && _fog_pubTable!=NULL) {
- FreeMemory( _fog_pubTable); // free it
- _fog_pubTable = NULL;
- }
- // allocate table if needed
- if( _fog_pubTable==NULL) {
- // allocate byte table (for intensity values) and ULONG table (color values for uploading) right behind!
- _fog_pubTable = (UBYTE*)AllocMemory( pixSizeH*pixSizeL * (sizeof(UBYTE)+sizeof(ULONG)));
- _fog_pixSizeH = pixSizeH;
- _fog_pixSizeL = pixSizeL;
- _fog_tpLocal.Clear();
- bNoDiscard = FALSE;
- }
- // update fog alpha value
- _fog_ulAlpha = (_fog_fp.fp_colColor&CT_AMASK)>>CT_ASHIFT;
- // get parameters
- const FLOAT fH0 = _fog_fp.fp_fH0; // lowest point in LUT ->texture t=1
- const FLOAT fH1 = _fog_fp.fp_fH1; // bottom of fog in LUT
- const FLOAT fH2 = _fog_fp.fp_fH2; // top of fog in LUT
- const FLOAT fH3 = _fog_fp.fp_fH3; // highest point in LUT ->texture t=0
- const FLOAT fFar = _fog_fp.fp_fFar; // farthest point in LUT ->texture s=1
- const FLOAT fDensity = _fog_fp.fp_fDensity;
- const AttenuationType at = _fog_fp.fp_atType;
- const FogGraduationType fgt = _fog_fp.fp_fgtType;
- const FLOAT fHFogSize = fH2-fH1;
- const FLOAT fHV = -_fog_fViewerH;
- const FLOAT fEpsilon = 0.001f;
- ASSERT( fHFogSize>0);
- // for each row (height in fog)
- for( PIX pixH=0; pixH<pixSizeH; pixH++)
- {
- // get fog height of the point from row coordinate in texture
- FLOAT fHP = fH3+FLOAT(pixH)/pixSizeH*(fH0-fH3);
- // sort viewer and point and get A (lower) and B (higher) fog coord
- // making sure that they are never same
- FLOAT fHA, fHB;
- if (fHP<fHV-fEpsilon) {
- fHA=fHP;
- fHB=fHV;
- } else if (fHP>fHV+fEpsilon) {
- fHA=fHV;
- fHB=fHP;
- } else {
- fHA=fHV-fEpsilon;
- fHB=fHP+fEpsilon;
- }
- // get distance between the two points in height axis
- FLOAT fDH = fHB-fHA;
- FLOAT fOoDH = 1/fDH;
- // calculate relative part of height that goes through the fog
- FLOAT fA2 = (fH2-fHA)*fOoDH;
- fA2 = Clamp(fA2,0.0f,1.0f);
- FLOAT fA1 = (fH1-fHA)*fOoDH;
- fA1 = Clamp(fA1,0.0f,1.0f);
- FLOAT fA = fA2-fA1;
- fA = Clamp(fA,0.0f,1.0f);
-
- // if not constant graduation
- if( fgt!=FGT_CONSTANT) {
- // calculate fog height for two points, limited to be inside fog
- FLOAT fFH0 = (fHFogSize-Clamp(fHA-fH1, 0.0f, fHFogSize));
- FLOAT fFH1 = (fHFogSize-Clamp(fHB-fH1, 0.0f, fHFogSize));
- // multiply the heights by graduation factor
- fFH0 *= _fog_fp.fp_fGraduation;
- fFH1 *= _fog_fp.fp_fGraduation;
- FLOAT fDens;
- // if linear graduation
- if (fgt==FGT_LINEAR) {
- // get linear integrated density factor
- fDens = (fFH0+fFH1)/2.0f;
- // if exponential graduation
- } else {
- ASSERT(fgt==FGT_EXP);
- // sort the two heights and make sure they are not same
- FLOAT fFA, fFB;
- if (fFH0<fFH1-fEpsilon) {
- fFA=fFH0;
- fFB=fFH1;
- } else if (fFH0>fFH1+fEpsilon) {
- fFA=fFH1;
- fFB=fFH0;
- } else {
- fFA=fFH1-fEpsilon;
- fFB=fFH0+fEpsilon;
- }
- // calculate exponential integrated density factor normally
- fDens = 1.0f+(exp(-fFB)-exp(-fFA))/(fFB-fFA);
- }
- // limit the intergrated density factor
- fDens = Clamp(fDens, 0.0f, 1.0f);
- // relative size multiplied by integrated density factor gives total fog sum
- fA *= fDens;
- }
- // do per-row loop
- switch(at)
- {
- // linear fog
- case AT_LINEAR: {
- // calculate linear step for the fog parameter
- FLOAT fT = 0.0f;
- FLOAT fTStep = 1.0f/pixSizeL *fFar*fDensity*fA *255;
- // fog is just clamped fog parameter in each pixel
- for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
- _fog_pubTable[pixH*pixSizeL+pixL] = Clamp( FloatToInt(fT), 0L, 255L);
- fT += fTStep;
- }
- } break;
- // exp fog
- case AT_EXP: {
- // calculate linear step for the fog parameter
- FLOAT fT = 0.0f;
- FLOAT fTStep = 1.0f/pixSizeL*fFar*fDensity*fA;
- // fog is exp(-t) function of fog parameter, now calculate
- // step (actually multiplication) for the fog
- FLOAT fExp = 255.0f;
- FLOAT fExpMul = exp(-fTStep);
- for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
- _fog_pubTable[pixH*pixSizeL+pixL] = 255-FloatToInt(fExp);
- fExp *= fExpMul;
- }
- } break;
- case AT_EXP2: {
- // calculate linear step for the fog parameter
- FLOAT fT = 0.0f;
- FLOAT fTStep = 1.0f/pixSizeL*fFar*fDensity*fA;
- // fog is exp(-t^2) function of fog parameter, now calculate
- // first and second order step (actually multiplication) for the fog
- FLOAT fExp2 = 255.0f;
- FLOAT fExp2Mul = exp(-fTStep*fTStep);
- FLOAT fExp2MulMul = exp(-2*fTStep*fTStep);
- for( INDEX pixL=0; pixL<pixSizeL; pixL++) {
- _fog_pubTable[pixH*pixSizeL+pixL] = 255-FloatToInt(fExp2);
- fExp2 *= fExp2Mul;
- fExp2Mul *= fExp2MulMul;
- }
- } break;
- }
- }
- // determine where fog starts and ends
- _fog_fStart = LowerLimit(0.0f);
- _fog_fEnd = UpperLimit(0.0f);
- if( _fog_pubTable[pixSizeL-1]) {
- // going from bottom
- INDEX pix=pixSizeH-1;
- for( ; pix>0; pix--) {
- if( (_fog_pubTable[(pix+1)*pixSizeL-1]*_fog_ulAlpha)>>8) break;
- }
- if( pix<(pixSizeH-1)) _fog_fEnd = (FLOAT)(pix+1) / (FLOAT)(pixSizeH-1);
- } else {
- // going from top
- INDEX pix=0;
- for( ; pix<pixSizeH; pix++) {
- if( (_fog_pubTable[(pix+1)*pixSizeL-1]*_fog_ulAlpha)>>8) break;
- }
- if( pix>0) _fog_fStart = (FLOAT)(pix-1) / (FLOAT)(pixSizeH-1);
- }
- // prepare and upload the fog table
- _fog_tpLocal.tp_bSingleMipmap = TRUE;
- const ULONG ulFormat = PrepareTexture( _fog_pubTable, _fog_pixSizeL, _fog_pixSizeH);
- if( _fog_ulFormat!=ulFormat) {
- _fog_ulFormat = ulFormat;
- bNoDiscard = FALSE;
- } // set'n'upload
- gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
- gfxSetTexture( _fog_ulTexture, _fog_tpLocal);
- gfxUploadTexture( (ULONG*)(_fog_pubTable + _fog_pixSizeL*_fog_pixSizeH),
- _fog_pixSizeL, _fog_pixSizeH, ulFormat, bNoDiscard);
- }
- // stop fog
- void StopFog(void)
- {
- _fog_bActive = FALSE;
- }
- // current haze parameters
- BOOL _haze_bActive = FALSE;
- CHazeParameters _haze_hp;
- CTexParams _haze_tpLocal;
- PIX _haze_pixSize=0;
- FLOAT _haze_fStart=0; // where in depth haze starts
- UBYTE *_haze_pubTable=NULL;
- FLOAT3D _haze_vViewPosAbs;
- FLOAT3D _haze_vViewDirAbs;
- FLOAT _haze_fMul=0;
- FLOAT _haze_fAdd=0;
- ULONG _haze_ulAlpha=0;
- ULONG _haze_ulTexture=0;
- ULONG _haze_ulFormat=0;
- // start haze with given parameters
- void StartHaze( CHazeParameters &hp,
- const FLOAT3D &vViewPosAbs, const FLOATmatrix3D &mAbsToView)
- {
- ASSERT( !_haze_bActive);
- if( _bMultiPlayer) gfx_bRenderFog = 1;
- if( !gfx_bRenderFog) return;
- _haze_bActive = TRUE;
- _haze_hp = hp;
- _haze_vViewPosAbs = vViewPosAbs;
- _haze_vViewDirAbs(1) = -mAbsToView(3, 1);
- _haze_vViewDirAbs(2) = -mAbsToView(3, 2);
- _haze_vViewDirAbs(3) = -mAbsToView(3, 3);
- // calculate haze mapping factors
- _haze_fMul = 1/(_haze_hp.hp_fFar-_haze_hp.hp_fNear);
- _haze_fAdd = -_haze_hp.hp_fNear;
- PIX pixSize = _haze_hp.hp_iSize;
- BOOL bNoDiscard = TRUE;
- // if haze table is not allocated in right size
- if( _haze_pixSize!=pixSize && _haze_pubTable!=NULL) {
- FreeMemory( _haze_pubTable); // free it
- _haze_pubTable = NULL;
- }
- // allocate table if needed
- if( _haze_pubTable==NULL) {
- // allocate byte table (for intensity values) and ULONG table (color values for uploading) right behind!
- _haze_pubTable = (UBYTE*)AllocMemory(pixSize *(sizeof(UBYTE)+sizeof(ULONG)));
- _haze_pixSize = pixSize;
- _haze_tpLocal.Clear();
- bNoDiscard = FALSE;
- }
- // update fog alpha value
- _haze_ulAlpha = (_haze_hp.hp_colColor&CT_AMASK)>>CT_ASHIFT;
- // get parameters
- FLOAT fNear = _haze_hp.hp_fNear;
- FLOAT fFar = _haze_hp.hp_fFar;
- FLOAT fDensity = _haze_hp.hp_fDensity;
- AttenuationType at = _haze_hp.hp_atType;
- // generate table
- INDEX pix;
- for( pix=0; pix<pixSize; pix++) {
- FLOAT fD = FLOAT(pix)/pixSize*(fFar-fNear);
- FLOAT fT = fDensity*fD;
- FLOAT fHaze=0.0f;
- switch(at) {
- case AT_LINEAR: fHaze = Clamp(fT,0.0f,1.0f); break;
- case AT_EXP: fHaze = 1-exp(-fT); break;
- case AT_EXP2: fHaze = 1-exp(-fT*fT); break;
- }
- const UBYTE ubValue = NormFloatToByte(fHaze);
- _haze_pubTable[pix] = ubValue;
- }
- // determine where haze starts
- for( pix=1; pix<pixSize; pix++) if( (_haze_pubTable[pix]*_haze_ulAlpha)>>8) break;
- _haze_fStart = (FLOAT)(pix-1) / (FLOAT)(pixSize-1);
- // prepare haze table
- _haze_tpLocal.tp_bSingleMipmap = TRUE;
- const ULONG ulFormat = PrepareTexture( _haze_pubTable, _haze_pixSize, 1);
- if( _haze_ulFormat!=ulFormat) {
- _haze_ulFormat = ulFormat;
- bNoDiscard = FALSE;
- } // set'n'upload
- gfxSetTextureWrapping( GFX_CLAMP, GFX_CLAMP);
- gfxSetTexture( _haze_ulTexture, _haze_tpLocal);
- gfxUploadTexture( (ULONG*)(_haze_pubTable + _haze_pixSize*1), _haze_pixSize, 1, ulFormat, bNoDiscard);
- }
- // stop haze
- void StopHaze(void)
- {
- _haze_bActive = FALSE;
- }
|