/* 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 "Shaders/StdH.h" #include <Shaders/Common.h> void DoSpecularLayer(INDEX iSpeculaTexture,INDEX iSpecularColor) { //GFXVertex4 *paVertices = shaGetVertexArray(); GFXNormal *paNormals = shaGetNormalArray(); INDEX ctVertices = shaGetVertexCount(); FLOAT3D vLightDir = -shaGetLightDirection().Normalize(); COLOR colLight = ByteSwap(shaGetLightColor()); COLOR colAmbient = ByteSwap(shaGetAmbientColor()); GFXTexCoord *ptcUVMap = shaGetNewTexCoordArray(); Matrix12 &mObjToView = *shaGetObjToViewMatrix(); shaCalculateLightForSpecular(); // determine multitexturing capability for overbrighting purposes const BOOL bOverbright = shaOverBrightningEnabled(); // cache light intensities (-1 in case of overbrighting compensation) const INDEX iBright = bOverbright ? 0 : 1; SLONG slLR = (colLight & CT_RMASK)>>(CT_RSHIFT-iBright); SLONG slLG = (colLight & CT_GMASK)>>(CT_GSHIFT-iBright); SLONG slLB = (colLight & CT_BMASK)>>(CT_BSHIFT-iBright); SLONG slAR = (colAmbient & CT_RMASK)>>(CT_RSHIFT-iBright); SLONG slAG = (colAmbient & CT_GMASK)>>(CT_GSHIFT-iBright); SLONG slAB = (colAmbient & CT_BMASK)>>(CT_BSHIFT-iBright); if( bOverbright) { slAR = ClampUp( slAR, 127); slAG = ClampUp( slAG, 127); slAB = ClampUp( slAB, 127); } // for each vertex INDEX ivx; for(ivx=0;ivx<ctVertices;ivx++) { // reflect light vector around vertex normal in object space GFXNormal &nor = paNormals[ivx]; FLOAT3D vNot = FLOAT3D(nor.nx,nor.ny,nor.nz); // vNot.Normalize(); //ASSERT(vNot.Normalize() == 1.0f); const FLOAT fNL = nor.nx*vLightDir(1) + nor.ny*vLightDir(2) + nor.nz*vLightDir(3); const FLOAT fRx = vLightDir(1) - 2*vNot(1)*fNL; const FLOAT fRy = vLightDir(2) - 2*vNot(2)*fNL; const FLOAT fRz = vLightDir(3) - 2*vNot(3)*fNL; FLOAT3D fRV = FLOAT3D(fRx,fRy,fRz); RotateVector(fRV.vector,mObjToView); // map reflected vector to texture const FLOAT f1oFM = 0.5f / sqrt(2+2*fRV(3)); // was 2*sqrt(2+2*fRVz) ptcUVMap[ivx].st.s = fRV(1)*f1oFM +0.5f; ptcUVMap[ivx].st.t = fRV(2)*f1oFM +0.5f; } GFXColor colSrfSpec = shaGetColor(iSpecularColor); colSrfSpec.AttenuateRGB( (shaGetModelColor()&CT_AMASK)>>CT_ASHIFT); colSrfSpec.ub.r = ClampUp( (colSrfSpec.ub.r *slLR)>>8, 255); colSrfSpec.ub.g = ClampUp( (colSrfSpec.ub.g *slLG)>>8, 255); colSrfSpec.ub.b = ClampUp( (colSrfSpec.ub.b *slLB)>>8, 255); GFXColor *pcolSpec = shaGetNewColorArray(); GFXColor *pcolBase = shaGetColorArray();; // for each vertex in the surface for(ivx=0;ivx<ctVertices;ivx++) { // set specular color const SLONG slShade = pcolBase[ivx].ub.a; pcolSpec[ivx].ul.abgr = (((colSrfSpec.ub.r)*slShade)>>8) | (((colSrfSpec.ub.g)*slShade)&0x0000FF00) |((((colSrfSpec.ub.b)*slShade)<<8)&0x00FF0000); } shaSetTexCoords(ptcUVMap); shaSetVertexColors(pcolSpec); shaSetTexture(iSpeculaTexture); shaBlendFunc( GFX_INV_SRC_ALPHA, GFX_ONE); shaEnableBlend(); shaCullFace(GFX_BACK); shaRender(); shaCullFace(GFX_FRONT); shaRender(); } void DoReflectionLayer(INDEX iReflectionTexture,INDEX iReflectionColor,BOOL bFullBright) { //GFXVertex4 *paVertices = NULL; GFXNormal *paNormals = NULL; //paVertices = shaGetVertexArray(); paNormals = shaGetNormalArray(); INDEX ctVertices = shaGetVertexCount(); GFXTexCoord *ptcUVMap = shaGetNewTexCoordArray(); //Matrix12 &mObjToView = *shaGetObjToViewMatrix(); Matrix12 &mObjToAbs = *shaGetObjToAbsMatrix(); CAnyProjection3D &apr = *shaGetProjection(); // calculate projection of viewer in absolute space FLOATmatrix3D &mViewer = apr->pr_ViewerRotationMatrix; FLOAT3D vViewer = FLOAT3D(-mViewer(3,1),-mViewer(3,2),-mViewer(3,3)); Matrix12 mTemp,mInvert; MatrixVectorToMatrix12(mTemp,mViewer,FLOAT3D(0,0,0)); MatrixTranspose(mInvert,mTemp); // mObjToAbs = !mViewer; // for each vertex for(INDEX ivx=0;ivx<ctVertices;ivx++) { // reflect light vector around vertex normal in object space FLOAT3D vNor = FLOAT3D(paNormals[ivx].nx,paNormals[ivx].ny,paNormals[ivx].nz); RotateVector(vNor.vector,mObjToAbs); // reflect viewer around normal const FLOAT fNV = vNor(1)*vViewer(1) + vNor(2)*vViewer(2) + vNor(3)*vViewer(3); const FLOAT fRVx = vViewer(1) - 2*vNor(1)*fNV; const FLOAT fRVy = vViewer(2) - 2*vNor(2)*fNV; const FLOAT fRVz = vViewer(3) - 2*vNor(3)*fNV; // map reflected vector to texture // NOTE: using X and Z axes, so that singularity gets on -Y axis (where it will least probably be seen) const FLOAT f1oFM = 0.5f / sqrt(2+2*fRVy); ptcUVMap[ivx].st.s = fRVx*f1oFM +0.5f; ptcUVMap[ivx].st.t = fRVz*f1oFM +0.5f; } GFXColor *pcolReflection = shaGetNewColorArray(); // get model reflection color GFXColor colSrfRefl; colSrfRefl.ul.abgr = ByteSwap(shaGetColor(iReflectionColor)); colSrfRefl.AttenuateA((shaGetModelColor()&CT_AMASK)>>CT_ASHIFT); if(bFullBright) { // just copy reflection color for( INDEX ivx=0;ivx<ctVertices;ivx++) { pcolReflection[ivx] = colSrfRefl; } } else { GFXColor *pcolSrfBase = shaGetColorArray(); // set reflection color smooth for( INDEX ivx=0;ivx<ctVertices;ivx++) { pcolReflection[ivx].MultiplyRGBCopyA1( colSrfRefl, pcolSrfBase[ivx]); } } shaSetTexCoords(ptcUVMap); shaSetVertexColors(pcolReflection); shaSetTexture(iReflectionTexture); shaBlendFunc( GFX_SRC_ALPHA, GFX_INV_SRC_ALPHA); shaEnableBlend(); BOOL bDoubleSided = shaGetFlags()&BASE_DOUBLE_SIDED; if(bDoubleSided) { shaCullFace(GFX_FRONT); shaRender(); } shaCullFace(GFX_BACK); shaRender(); }