Files
FC1/RenderDll/XRenderOGL/GL_Shadows.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

922 lines
28 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek CryENGINE Source code
//
// File:GlRenderer.cpp
// Description: Implementation of the OpenGL renderer API
// shadow map calculations
//
// History:
// -Jan 31,2001:Created by Vladimir Kajain
//
//////////////////////////////////////////////////////////////////////
#include "RenderPCH.h"
#include "GL_Renderer.h"
#include <IEntityRenderState.h>
#include "../Common/shadow_renderer.h"
#include "../Common/RendElements/CREScreenCommon.h"
#include "GLCGVProgram.h"
#include "GLCGPShader.h"
#include "I3dengine.h"
void WriteTGA8(byte *data8, int width, int height, char *filename);
void BlurImage8(byte * pImage, int nSize, int nPassesNum);
void MakePenumbraTextureFromDepthMap(byte * pDepthMapIn, int nSize, byte * pPenumbraMapOut);
void CGLRenderer::DrawAllShadowsOnTheScreen()
{
float width=800;
float height=600;
Set2DMode(true, (int)width, (int)height);
float fArrDim = max(4, sqrt(float(MAX_DYNAMIC_SHADOW_MAPS_COUNT)));
float fPicDimX = width/fArrDim;
float fPicDimY = height/fArrDim;
int nShadowId=0;
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
for(float x=0; nShadowId<MAX_DYNAMIC_SHADOW_MAPS_COUNT && x<width-10; x+=fPicDimX)
for(float y=0; nShadowId<MAX_DYNAMIC_SHADOW_MAPS_COUNT && y<height-10; y+=fPicDimY)
{
ShadowMapTexInfo * pInf = &m_ShadowTexIDBuffer[nShadowId++];
if(pInf->nTexId && pInf->pOwner)
{
STexPic *tp = (STexPic *)EF_GetTextureByID(pInf->nTexId);
if (tp)
{
byte bSaveProj = tp->m_RefTex.bProjected;
tp->m_RefTex.bProjected = 1;
SetState( GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST );
Draw2dImage(x, y, fPicDimX, fPicDimY, pInf->nTexId, 0,0,1,1,180);
TextToScreen(x/width*100.f, y/height*100.f,
"%8s", pInf->pOwner->GetName());
tp->m_RefTex.bProjected = bSaveProj;
}
}
}
Set2DMode(false, m_width, m_height);
}
void CGLRenderer::BlurImage(int nSizeX, int nSizeY, int nType, int nTexIdSrc, int nTexIdTmp)
{
if (nType == 1)
{
EF_SetState(GS_NODEPTHTEST);
m_TexMan->SetTexture(nTexIdSrc, eTT_Base);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, nSizeX, nSizeY, 0);
Set2DMode(true, 1, 1);
struct_VERTEX_FORMAT_P3F_TEX2F pScreenBlur[] =
{
Vec3(0, 1, 0), 0, 0,
Vec3(0, 0, 0), 0, 1,
Vec3(1, 1, 0), 1, 0,
Vec3(1, 0, 0), 1, 1,
};
EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, DEF_TEXARG0, DEF_TEXARG0);
DrawTriStrip(&(CVertexBuffer (pScreenBlur,VERTEX_FORMAT_P3F_TEX2F)), 4);
EF_SetState(GS_NODEPTHTEST | GS_COLMASKONLYALPHA);
// set current vertex/fragment program
CCGVProgram_GL *vpBlur=(CCGVProgram_GL *)m_RP.m_VPBlur;
CCGPShader_GL *fpBlur=(CCGPShader_GL *)m_RP.m_RCBlur;
if (vpBlur && fpBlur)
{
vpBlur->mfSet(true, 0);
fpBlur->mfSet(true, 0);
// setup texture offsets, for texture neighboors sampling
float s1=1.0f/(float) nSizeX;
float t1=1.0f/(float) nSizeY;
float pfOffset0[]={ s1*0.5f, t1, 0.0f, 0.0f};
float pfOffset1[]={ -s1, t1*0.5f, 0.0f, 0.0f};
float pfOffset2[]={ -s1*0.5f, -t1, 0.0f, 0.0f};
float pfOffset3[]={ s1, -t1*0.5f, 0.0f, 0.0f};
EF_SelectTMU(0);
m_TexMan->SetTexture(nTexIdSrc, eTT_Base);
EF_SelectTMU(1);
m_TexMan->SetTexture(nTexIdSrc, eTT_Base);
EF_SelectTMU(2);
m_TexMan->SetTexture(nTexIdSrc, eTT_Base);
EF_SelectTMU(3);
m_TexMan->SetTexture(nTexIdSrc, eTT_Base);
vpBlur->mfParameter4f("Offset0", pfOffset0);
vpBlur->mfParameter4f("Offset1", pfOffset1);
vpBlur->mfParameter4f("Offset2", pfOffset2);
vpBlur->mfParameter4f("Offset3", pfOffset3);
int iBlurAmount = CV_r_shadowblur-1;
EF_CommitPS();
EF_CommitVS();
for(int iBlurPasses=1; iBlurPasses<=iBlurAmount; iBlurPasses++)
{
// set texture coordinates scale (needed for rectangular textures in gl ..)
float pfScale[]={ 1.0f, 1.0f, 1.0f, (float) iBlurPasses};
vpBlur->mfParameter4f("vTexCoordScale", pfScale);
// set current rendertarget
//pRenderer->m_pd3dDevice->SetRenderTarget( 0, pTexSurf);
// render screen aligned quad...
DrawTriStrip(&(CVertexBuffer (pScreenBlur,VERTEX_FORMAT_P3F_TEX2F)), 4);
}
vpBlur->mfSet(false, 0);
fpBlur->mfSet(false, 0);
EF_CommitPS();
EF_CommitVS();
EnableTMU(false);
EF_SelectTMU(2);
EnableTMU(false);
EF_SelectTMU(1);
EnableTMU(false);
EF_SelectTMU(0);
}
Set2DMode(false, 1, 1);
}
else
if (nType == 2)
{
assert(false);
}
}
void CGLRenderer::OnEntityDeleted(IEntityRender * pEntityRender)
{
}
// render depth/shadow map into texture from light source position
void CGLRenderer::PrepareDepthMap(ShadowMapFrustum * lof, bool make_new_tid)
{
PROFILE_FRAME(Prep_PrepareDepthMap);
if(!lof || !lof->pLs)
return;
static int nCurTexIdSlot = 0;
//lof->bUpdateRequested = true;
lof->nTexSize = max(lof->nTexSize, 32);
if(lof->nTexIdSlot>=0)
{
if(m_ShadowTexIDBuffer[lof->nTexIdSlot].pOwner == lof->pOwner)
{
char * pName = 0;
if(lof->pOwner)
pName = (char*)lof->pOwner->GetName();
if(m_ShadowTexIDBuffer[lof->nTexIdSlot].pOwnerGroup == lof->pOwnerGroup)
if(m_ShadowTexIDBuffer[lof->nTexIdSlot].dwFlags == lof->dwFlags)
if(lof->depth_tex_id && !lof->bUpdateRequested)
{
m_ShadowTexIDBuffer[lof->nTexIdSlot].nLastFrameID = GetFrameID();
return;
}
}
}
int nShadowTexSize = lof->nTexSize;
lof->bUpdateRequested = false;
//assert(lof->nTexSize);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Render objects into frame and Z buffers
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// remember fog value
int bFog=0;
glGetIntegerv(GL_FOG,&bFog);
glDisable(GL_FOG);
// glPush
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// check extension
bool bDepth = (m_Features & RFT_DEPTHMAPS) != 0;
//if(!bSGIX_shadow && lof->shadow_type == EST_DEPTH_BUFFER)
// return;
// normalize size
while(nShadowTexSize>m_height || nShadowTexSize>m_width)
nShadowTexSize/=2;
if (m_LogFile)
Logv(SRendItem::m_RecurseLevel, " Really generating %dx%d shadow map for %s \n", nShadowTexSize, nShadowTexSize, lof->pOwner ? lof->pOwner->GetName() : "NoOwner");
// setup matrices
int vX, vY, vWidth, vHeight;
gRenDev->GetViewport(&vX, &vY, &vWidth, &vHeight);
gRenDev->SetViewport(0, 0, nShadowTexSize, nShadowTexSize);
float lightFrustumMatrix[16];
float lightViewMatrix[16];
glMatrixMode(GL_PROJECTION);
makeProjectionMatrix(lof->FOV, lof->ProjRatio, lof->min_dist, lof->max_dist, lightFrustumMatrix);
glLoadMatrixf(lightFrustumMatrix);
glMatrixMode(GL_MODELVIEW);
SGLFuncs::gluLookAt( lof->pLs->vSrcPos.x, lof->pLs->vSrcPos.y, lof->pLs->vSrcPos.z,
lof->target.x, lof->target.y, lof->target.z,
0, 0, 1, lightViewMatrix);
glLoadMatrixf(lightViewMatrix);
//iLog->Log("Generate SM: From (%.3f,%.3f,%.3f) To (%.3f,%.3f,%.3f), FOV: %.3f, MinD: %.3f, MaxD: %.3f", lof->pLs->vSrcPos.x, lof->pLs->vSrcPos.y, lof->pLs->vSrcPos.z, lof->target.x, lof->target.y, lof->target.z, lof->FOV, lof->min_dist, lof->max_dist);
memcpy(lof->debugLightFrustumMatrix,lightFrustumMatrix,sizeof(lof->debugLightFrustumMatrix));
memcpy(lof->debugLightViewMatrix, lightViewMatrix, sizeof(lof->debugLightViewMatrix));
// clear frame buffer
CFColor col;
if (!(m_Features & RFT_DEPTHMAPS) && (m_Features & RFT_SHADOWMAP_SELFSHADOW))
col = CFColor(1,0.879f,0,0);
else
col = CFColor(0,0,0,0);
EF_ClearBuffers(true, false, &col[0]);
// disable rendering of borders
glScissor(1, 1, nShadowTexSize-2, nShadowTexSize-2);
glEnable (GL_SCISSOR_TEST);
IShader * pStateShader = EF_LoadShader("StateNoCull", eSH_World);
// draw static objects (not entities)
if(lof->pModelsList && lof->pModelsList->Count())
{
// cut underground geometry
float plane[] = {0,0,1,0};
//if(!bDepth)
// gRenDev->SetClipPlane(0,plane);
EF_StartEf();
for(int m=0; m<lof->pModelsList->Count(); m++)
{
SRendParams rParms;
rParms.pStateShader = pStateShader;
if(!lof->m_fBending)
rParms.nShaderTemplate = EFT_WHITESHADOW;
// set pos relative to entity 0
if(lof->pEntityList && lof->pEntityList->Count())
rParms.vPos -= (*lof->pEntityList)[0]->GetPos();
rParms.dwFObjFlags |= FOB_TRANS_MASK;
rParms.dwFObjFlags |= FOB_RENDER_INTO_SHADOWMAP;
rParms.fBending = lof->m_fBending;
(*lof->pModelsList)[m]->Render(rParms,Vec3(zero),0);
}
EF_EndEf3D(true);
gRenDev->SetClipPlane(0,NULL);
}
// draw entities
EF_StartEf();
for(int m=0; lof->pEntityList && m_RP.m_pCurObject && m<lof->pEntityList->Count(); m++)
{
IEntityRender * pEnt = (*lof->pEntityList)[m];
const char *name = pEnt->GetName();
Vec3d vOffSetDir = GetNormalized( m_RP.m_pCurObject->GetTranslation() - lof->pLs->vSrcPos )*(0.1f+0.035f*(256.f/nShadowTexSize));
IEntityRender * pEnt0 = (*lof->pEntityList)[0];
SRendParams rParams;
rParams.nShaderTemplate = bDepth ? EFT_WHITE : EFT_WHITESHADOW;
rParams.pStateShader = pStateShader;
rParams.vPos = vOffSetDir + (pEnt->GetPos() - lof->pOwner->GetPos());
rParams.dwFObjFlags |= FOB_RENDER_INTO_SHADOWMAP;
rParams.dwFObjFlags |= FOB_TRANS_MASK;
pEnt->DrawEntity(rParams);
}
EF_EndEf3D(true);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now make texture from frame buffer
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(make_new_tid)
{ // new id for static objects
glGenTextures(1,&lof->depth_tex_id);
assert(lof->depth_tex_id<14000);
}
else
{
// try to reuse slot if it was not modified
if( lof->nTexIdSlot>=0 &&
m_ShadowTexIDBuffer[lof->nTexIdSlot].nTexId == lof->depth_tex_id &&
m_ShadowTexIDBuffer[lof->nTexIdSlot].nTexSize == nShadowTexSize &&
m_ShadowTexIDBuffer[lof->nTexIdSlot].pOwner == lof->pOwner &&
m_ShadowTexIDBuffer[lof->nTexIdSlot].pOwnerGroup == lof->pOwnerGroup &&
m_ShadowTexIDBuffer[lof->nTexIdSlot].dwFlags == lof->dwFlags)
{
nCurTexIdSlot = lof->nTexIdSlot;
}
else
{ // find oldest slot
int nOldestSlot = -1;
int nOldestFrameId = GetFrameID();
for(int i=0; i<MAX_DYNAMIC_SHADOW_MAPS_COUNT; i++)
{
if(m_ShadowTexIDBuffer[i].nLastFrameID < nOldestFrameId && nShadowTexSize == m_ShadowTexIDBuffer[i].nTexSize)
{
nOldestFrameId = m_ShadowTexIDBuffer[i].nLastFrameID;
nOldestSlot = i;
}
}
if(nOldestSlot<0)
nCurTexIdSlot++;
else
nCurTexIdSlot=nOldestSlot;
nCurTexIdSlot = nCurTexIdSlot;
}
if(nCurTexIdSlot>=MAX_DYNAMIC_SHADOW_MAPS_COUNT)
nCurTexIdSlot=0;
if(!m_ShadowTexIDBuffer[nCurTexIdSlot].nTexId)
{
glGenTextures(1,&m_ShadowTexIDBuffer[nCurTexIdSlot].nTexId);
assert(m_ShadowTexIDBuffer[nCurTexIdSlot].nTexId<14000);
make_new_tid = true;
}
if (m_ShadowTexIDBuffer[nCurTexIdSlot].nTexSize != nShadowTexSize)
make_new_tid = true;
lof->nTexIdSlot = nCurTexIdSlot;
lof->depth_tex_id = m_ShadowTexIDBuffer[nCurTexIdSlot].nTexId;
m_ShadowTexIDBuffer[nCurTexIdSlot].pOwner = lof->pOwner;
m_ShadowTexIDBuffer[nCurTexIdSlot].pOwnerGroup = lof->pOwnerGroup;
m_ShadowTexIDBuffer[nCurTexIdSlot].dwFlags = lof->dwFlags;
m_ShadowTexIDBuffer[nCurTexIdSlot].nLastFrameID = GetFrameID();
m_ShadowTexIDBuffer[nCurTexIdSlot].nTexSize = nShadowTexSize;
}
ShadowMapTexInfo *st = NULL;
if (CV_r_shadowblur && !(m_Features & RFT_DEPTHMAPS))
{
int i;
for (i=0; i<m_TempShadowTextures.Num(); i++)
{
st = &m_TempShadowTextures[i];
if (st->nTexSize == nShadowTexSize)
break;
}
if (i == m_TempShadowTextures.Num())
{
ShadowMapTexInfo smt;
smt.nTexId = 0;
smt.nTexSize = nShadowTexSize;
m_TempShadowTextures.AddElem(smt);
}
st = &m_TempShadowTextures[i];
if (!st->nTexId)
{
glGenTextures(1,&st->nTexId);
gRenDev->m_TexMan->SetTexture(st->nTexId, eTT_Base);
}
if (CV_r_shadowblur > 2 && !CRenderer::CV_r_nops20 && !st->nTexIdTemp)
glGenTextures(1,&st->nTexIdTemp);
int BlurType = CV_r_shadowblur-1;
if (CV_r_shadowblur > 2 && CRenderer::CV_r_nops20)
BlurType = 1;
BlurImage(nShadowTexSize, nShadowTexSize, BlurType, st->nTexId, st->nTexIdTemp);
}
//assert(nShadowTexSize);
//assert(lof->nTexSize);
static ICVar * pVar = iConsole->GetCVar("e_shadow_maps_debug");
if (pVar && pVar->GetIVal()==1)
{
int width = nShadowTexSize;
int height = nShadowTexSize;
if (bDepth)
{
byte *pic = new byte [width * height];
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pic);
char buff[128];
sprintf(buff, "ShadowMap%00d.tga", nCurTexIdSlot);
WriteTGA8(pic,width,height,buff);
delete [] pic;
}
else
{
byte *pic = new byte [width * height * 4];
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pic);
char buff[128];
sprintf(buff, "ShadowMap%00d.tga", nCurTexIdSlot);
::WriteTGA(pic,width,height,buff,32);
delete [] pic;
}
}
gRenDev->m_TexMan->SetTexture(lof->depth_tex_id, eTT_Base);
// make texture of requested type
if(bDepth)
{
glCopyTexImage2D( GL_TEXTURE_2D,
0,
bDepth ? (m_zbpp == 24 ? GL_DEPTH_COMPONENT24_SGIX : GL_DEPTH_COMPONENT16_SGIX) : GL_DEPTH_COMPONENT,
0,
0,
nShadowTexSize,
nShadowTexSize,
0);
}
else if(lof->shadow_type == EST_PENUMBRA)
{ // make penumbra texture
int width = nShadowTexSize;
int height = nShadowTexSize;
byte * pDepthMap = new byte [width * height];
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pDepthMap);
WriteTGA8(pDepthMap,width,height,"_DepthMap.tga");
byte * pPenumbra = new byte [width * height];
assert(width==height);
MakePenumbraTextureFromDepthMap(pDepthMap, width, pPenumbra);
WriteTGA8(pPenumbra,width,height,"_Penumbra.tga");
delete [] pDepthMap;
// make gl texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8, width, width, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pPenumbra);
delete [] pPenumbra;
}
else
{
if(1)//lof->dynamic)
{ // entities
if(make_new_tid)
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, nShadowTexSize, nShadowTexSize, 0);
else
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, nShadowTexSize, nShadowTexSize);
}
else
{ // static objects
assert(nShadowTexSize<=512);
byte *depth_map = new byte[512*512];
glReadPixels(0, 0, nShadowTexSize, nShadowTexSize, GL_RED, GL_UNSIGNED_BYTE, depth_map);
for(int x=0; x<nShadowTexSize; x++)
for(int y=0; y<nShadowTexSize; y++)
{
byte b;
if(depth_map[x+y*nShadowTexSize] < 12) // we render normal object, not black
b = 0;
else
b = 255;
// clear border
if(x==0 || x==nShadowTexSize-1)
if(y==0 || y==nShadowTexSize-1)
b = 0;
depth_map[x+y*nShadowTexSize] = b;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_ALPHA_ARB,//GL_ALPHA,
nShadowTexSize, nShadowTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, depth_map);
delete [] depth_map;
}
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if(bDepth)
{ // enable extension
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX, GL_TEXTURE_LEQUAL_R_SGIX);
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
gRenDev->SetViewport(vX, vY, vWidth, vHeight);
gRenDev->SetScissor(0, 0, 0, 0);
glDisable(GL_SCISSOR_TEST);
glClearColor(m_vClearColor.x,m_vClearColor.y,m_vClearColor.z,0);
SetState(GS_DEPTHWRITE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(bFog)
glEnable(GL_FOG);
if(lof->pPenumbra && lof->pPenumbra->bUpdateRequested)
PrepareDepthMap(lof->pPenumbra, make_new_tid);
}
void MakePenumbraTextureFromDepthMap(byte * pDepthMapIn, int nSize, byte * pPenumbraMapOut)
{
memcpy(pPenumbraMapOut,pDepthMapIn,nSize*nSize);
BlurImage8(pPenumbraMapOut, nSize, 3);
#define DATA_TMP(_x,_y) (pTemp[(_x)+nSize*(_y)])
#define DATA(_x,_y) (pPenumbraMapOut[(_x)+nSize*(_y)])
{ // substract
for(int x=0; x<nSize; x++)
for(int y=0; y<nSize; y++)
{
float fVal = (float)DATA(x,y) - (float)pDepthMapIn[x+nSize*y];
fVal = (fVal*2.f) + 127.f;
DATA(x,y) = uchar( max(min(fVal,255),0) );
}
}
memcpy(pDepthMapIn,pPenumbraMapOut,nSize*nSize);
{ // per fragment normalization
int nRange = 1;
for(int X=nRange; X<nSize-nRange; X++)
for(int Y=nRange; Y<nSize-nRange; Y++)
{
// DATA(X,Y) = DATA(X,Y)>4 ? 255 : 0;
}
}
/*
{ // per fragment normalization
int nRange = 8;
for(int X=nRange; X<nSize-nRange-1; X++)
for(int Y=nRange; Y<nSize-nRange-1; Y++)
{
float fMax = 0;
for(int x=X-nRange; x<=X+nRange; x++)
for(int y=Y-nRange; y<=Y+nRange; y++)
{
if(fMax < pDepthMapIn[x+nSize*y])
fMax = pDepthMapIn[x+nSize*y];
}
if(fMax)
{
float fValue = (float)pDepthMapIn[X+nSize*Y];
float fNewValue = (fValue/fMax)*255.f;
DATA(X,Y) = uchar( max(min(fNewValue,255),0) );
}
else
{
DATA(X,Y) = 0;
}
}
}*/
#undef DATA
#undef DATA_IN
// BlurImage8(pPenumbraMapOut, nSize, 1);
}
inline void glShadowVertex(int x, int y)
{
glVertex3f((float)x, (float)y, iSystem->GetI3DEngine()->GetTerrainZ(x,y)+0.05f);//iTerrain->GetZSafe(x,y)/*+0.05f*/);
}
void CGLRenderer::SetupShadowOnlyPass(int Num, ShadowMapFrustum * pFrustum, Vec3d * vShadowTrans, const float fShadowScale,
Vec3d vObjTrans, float fObjScale, const Vec3d vObjAngles, Matrix44 * pObjMat)
{
if(!pFrustum)
return;
float lightFrustumMatrix[16];
float lightViewMatrix[16];
if(vShadowTrans)
{ // make tmp matrix for this obj position if shadow frustum is not translated (translate original mats)
// float fDist = (pFrustum->min_dist + pFrustum->max_dist)*0.5f;
// float fRadius = (pFrustum->max_dist - pFrustum->min_dist)*0.5f*fShadowScale;
makeProjectionMatrix(pFrustum->FOV*fShadowScale, pFrustum->ProjRatio, pFrustum->min_dist, pFrustum->max_dist, lightFrustumMatrix);
Vec3d mv_trans = *vShadowTrans; // - vObjTrans;
float mat[16];
SGLFuncs::gluLookAt(
pFrustum->pLs->vSrcPos.x+mv_trans.x,
pFrustum->pLs->vSrcPos.y+mv_trans.y,
pFrustum->pLs->vSrcPos.z+mv_trans.z,
fShadowScale*pFrustum->target.x+mv_trans.x,
fShadowScale*pFrustum->target.y+mv_trans.y,
fShadowScale*pFrustum->target.z+mv_trans.z,
0, 0, 1, mat );
if(pObjMat)
mathMatrixMultiply(lightViewMatrix, mat, pObjMat->GetData(), g_CpuFlags);
else
{
mathRotateZ(mat, vObjAngles.z, g_CpuFlags);
mathRotateY(mat, vObjAngles.y, g_CpuFlags);
mathRotateX(mat, vObjAngles.x, g_CpuFlags);
mathScale(mat, Vec3d(fObjScale,fObjScale,fObjScale), g_CpuFlags);
memcpy(lightViewMatrix, mat, sizeof(float)*16);
}
}
CGLTexMan::BindNULL(1);
gcpOGL->ConfigShadowTexgen(Num, 0, pFrustum, lightFrustumMatrix, lightViewMatrix);
}
// Make 8-bit identity texture that maps (s)=(z) to [0,255]/255.
int MakeShadowIdentityTexture()
{
uchar texmap[256];
for (unsigned int i=0; i<256; i++)
texmap[i] = i;
unsigned int tid;
glGenTextures(1,&tid);
assert(tid<14000);
glBindTexture(GL_TEXTURE_1D, tid);
glTexImage1D(GL_TEXTURE_1D, 0, GL_INTENSITY8, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texmap);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tid;
}
// setup projection texgen
void CGLRenderer::ConfigShadowTexgen(int Num, int rangeMap, ShadowMapFrustum * pFrustum, float * pLightFrustumMatrix, float * pLightViewMatrix)
{
float m1[16], m2[16], mtexSc[16];
if (rangeMap)
{
static int to_map_8bit = MakeShadowIdentityTexture();
float RSmatrix[16] =
{
0, 0, 0, 0,
0, 0, 0, 0,
0.5f, 128, 0, 0,
0.5f, 128, 0, 1.0f
};
if (Num >= 0)
{
m_RP.m_pRE->m_CustomTexBind[Num] = to_map_8bit;
gRenDev->m_TexMan->SetTexture(to_map_8bit, eTT_Base);
}
else
{
glBindTexture(GL_TEXTURE_1D, to_map_8bit);
glEnable(GL_TEXTURE_1D);
glDisable(GL_TEXTURE_2D);
}
memcpy(mtexSc,RSmatrix,sizeof(m1));
}
else
{
float Smatrix[16] =
{
0.5f, 0, 0, 0,
0, 0.5f, 0, 0,
0, 0, 0.5f, 0,
0.5f, 0.5f, 0.5f, 1.0f
};
if (Num >= 0)
{
if(pFrustum->depth_tex_id<=0)
iLog->Log("Warning: CGLRenderer::ConfigShadowTexgen: pFrustum->depth_tex_id not set");
else
{
if (m_RP.m_pRE)
{
m_RP.m_pRE->m_CustomTexBind[Num] = pFrustum->depth_tex_id;
m_RP.m_pRE->m_Color[Num] = pFrustum->fAlpha;
}
else
{
m_RP.m_RECustomTexBind[Num] = pFrustum->depth_tex_id;
m_RP.m_REColor[Num] = pFrustum->fAlpha;
}
}
}
else
{
gRenDev->m_TexMan->SetTexture(pFrustum->depth_tex_id, eTT_Base);
}
memcpy(mtexSc,Smatrix,sizeof(m1));
}
mathMatrixMultiply(m2, pLightFrustumMatrix, pLightViewMatrix, g_CpuFlags);
if (Num >= 0)
{
Matrix44 *mt = &gRenDev->m_cEF.m_TempMatrices[Num][0];
float *pf = mt->GetData();
mathMatrixMultiply(m1, mtexSc, m2, g_CpuFlags);
mathMatrixTranspose(pf, m1, g_CpuFlags);
if ((m_Features & RFT_SHADOWMAP_SELFSHADOW) && !(m_Features & RFT_DEPTHMAPS))
{
Matrix44 *mt = &gRenDev->m_cEF.m_TempMatrices[Num][7];
float *pf = mt->GetData();
mathMatrixTranspose(pf, m2, g_CpuFlags);
}
}
else
{
assert(false);
}
}
//#include "nvparse/nvparse.h"
///////////////////////////////////////////////////////////////////
// Render shadows on the object as first pass
///////////////////////////////////////////////////////////////////
/*bool CREShadowMap::mfDraw(SShader *ef, SShaderPass *sfm)
{
if(m_pShadowFrustum==0 && m_fAlpha == -1)
{ // special case: draw all tree shadows
iSystem->GetI3DEngine()->DrawTerrainShadowMaps();
return true;
}
if(gRenDev->m_RP.m_pCurObject->m_Trans.GetDistance(Vec3d(512,512,100))>2000)
return true;
// iConsole->Exit("CREShadowMap::mfDraw");
if(gRenDev->m_RP.m_pCurObject->m_ObjFlags != FOB_USEMATRIX)
gRenDev->MakeMatrix(gRenDev->m_RP.m_pCurObject->m_Trans, gRenDev->m_RP.m_pCurObject->m_Angs, Vec3d(1,1,1), &(gRenDev->m_RP.m_pCurObject->m_Matrix));
// draw shadow on the ground
ShadowMapLightSource * pFrustum = (ShadowMapLightSource*)m_pShadowFrustum;
if(pFrustum && pFrustum->m_LightFrustums.Count() && m_fAlpha>0)
{
// float alpha = gRenDev->m_RP.m_pCurObject->m_Trans.Distance(iSystem->GetViewCamera().GetPos());
// alpha = 1 - alpha/32;
if(m_fAlpha>0)
{
// restore world space
Matrix mat(gRenDev->m_RP.m_pCurObject->m_Matrix);
mat.Invert();
gRenDev->PushMatrix();
gRenDev->MultMatrix(&mat.m_values[0][0]);
gRenDev->ResetToDefault();
gRenDev->DrawShadowGrid(gRenDev->m_RP.m_pCurObject->m_Trans, gRenDev->m_RP.m_pCurObject->m_Scale,
&pFrustum->m_LightFrustums[0], false, m_fAlpha, 0, 0);
gRenDev->PopMatrix();
}
}
return true;
*/
/* if(!m_pBuffer->m_pVertexBuffer || !gRenDev->m_RP.m_pCurObject->m_pShadowCasters)
return true;
list2<ShadowMapLightSourceInstance> * lsources = (list2<ShadowMapLightSourceInstance>*)gRenDev->m_RP.m_pCurObject->m_pShadowCasters;
if(lsources->Count()==1)
if((*lsources)[0].ls->m_LightFrustums.Count()==0)
return true;
// restore world space
Matrix mat(gRenDev->m_RP.m_pCurObject->m_Matrix);
mat.Invert();
gRenDev->PushMatrix();
gRenDev->MultMatrix(&mat.m_values[0][0]);
gRenDev->ResetToDefault();
// draw white
gRenDev->ResetToDefault();
gRenDev->EnableTMU(false);
gRenDev->SetMaterialColor(1, 1, 1, 1);
gRB.mStateIgnore |= (RBSI_ALPHAGEN | RBSI_RGBGEN);
gRenDev->SetEnviMode(R_MODE_MODULATE);
gRenDev->PushMatrix();
gRenDev->MultMatrix(gRenDev->m_RP.m_pCurObject->m_Matrix);
static int lid =0;
if(!lid)
{
lid = glGenLists(1);
glNewList(lid,GL_COMPILE);
nvparse(
"!!RC1.0"
"out.rgb = col0;"
"out.a = tex0.a;"
);
glEndList();
}
glCallList(lid);
glEnable(GL_REGISTER_COMBINERS_NV);
char * const * const p = nvparse_get_errors();
assert(!p[0]);
gRenDev->EnableAlphaTest(true);
gRenDev->SetCullMode(R_CULL_NONE);
gRenDev->EnableTMU(true);
gRB.mStateIgnore = 0;
for(int m=0; m<m_pBuffer->m_pMats->Count(); m++)
{
CMatInfo * pMat = &(*m_pBuffer->m_pMats)[m];
if(pMat->nNumIndices && pMat->pShader)
{
SShader *ef = pMat->pShader->mfGetTemplate(-1);
int bind = ef->m_Layers[0].m_MTLayers[0]->m_TexPic->m_Bind;
gRenDev->SetTexture(bind);
gRenDev->DrawBuffer(m_pBuffer->m_pVertexBuffer,
&m_pBuffer->m_Indices[pMat->nFirstIndexId],
pMat->nNumIndices,
m_pBuffer->m_nPrimetiveType);
}
}
gRenDev->PopMatrix();
glDisable(GL_REGISTER_COMBINERS_NV);
// draw closest shadows
for(int s=0; s<lsources->Count() && s<4; s++)
if((*lsources)[s].ls->m_LightFrustums.Count())
{
gRenDev->ResetToDefault();
gRenDev->SetCullMode(R_CULL_NONE);
gRenDev->SetupShadowOnlyPass(&((*lsources)[s].ls->m_LightFrustums[0]), &((*lsources)[s].translation));
gRenDev->EnableBlend(true);
gRenDev->SetEnviMode(R_MODE_MODULATE);
gRenDev->SetBlendMode(R_BLEND_MODE__ZERO__ONE_MINUS_SRC_COLOR);
gRenDev->SetDepthFunc(R_EQUAL);
gRenDev->SetMaterialColor(1, 1, 1, 1);
gRB.mStateIgnore |= (RBSI_ALPHAGEN | RBSI_RGBGEN);
gRenDev->PushMatrix();
gRenDev->MultMatrix(gRenDev->m_RP.m_pCurObject->m_Matrix);
gRenDev->DrawBuffer(m_pBuffer->m_pVertexBuffer, &m_pBuffer->m_Indices[0], m_pBuffer->m_Indices.Count(), m_pBuffer->m_nPrimetiveType);
gRenDev->PopMatrix();
gRenDev->ResetToDefault();
}
gRenDev->PopMatrix();
gRenDev->CheckError("CREShadowMap::mfDraw");
return true;*/
/*}
*/
/*void CGLRenderer::ClearAlphaBuffer(float fAlphaValue)
{
glColorMask(0,0,0,1);
glColor4f(fAlphaValue,fAlphaValue,fAlphaValue,fAlphaValue);
SelectTMU(1);
EnableTMU(false);
SelectTMU(0);
EnableTMU(false);
int x1=0,x2=m_width,y1=0,y2=m_height;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(x1, x2, y2, y1, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glBegin(GL_QUADS);
glVertex2i(x1,y1);
glVertex2i(x2,y1);
glVertex2i(x2,y2);
glVertex2i(x1,y2);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
EnableTMU(true);
}
*/