/*============================================================================= GLRendPipeline.cpp : OpenGL specific rendering using shaders pipeline. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honich Andrey =============================================================================*/ #include "RenderPCH.h" #include "GL_Renderer.h" #include #include "..\common\shadow_renderer.h" #include "GLCGPShader.h" #include "GLCGVProgram.h" #include "I3dengine.h" #include "CryHeaders.h" //================================================================== //============================================================================================ // Shaders rendering //============================================================================================ //============================================================================================ // Init Shaders rendering void CGLRenderer::EF_InitRandTables() { int i; float f; for (i=0; i<256; i++) { f = (float)rand() / 32767.0f; m_RP.m_tRandFloats[i] = f + f - 1.0f; m_RP.m_tRandBytes[i] = (byte)((float)rand() / 32767.0f * 255.0f); } } void CGLRenderer::EF_InitWaveTables() { int i; //Init wave Tables for (i=0; i<1024; i++) { float f = (float)i; m_RP.m_tSinTable[i] = cry_sinf(f * (360.0f/1023.0f) * M_PI / 180.0f); m_RP.m_tHalfSinTable[i] = cry_sinf(f * (360.0f/1023.0f) * M_PI / 180.0f); if (m_RP.m_tHalfSinTable[i] < 0) m_RP.m_tHalfSinTable[i] = 0; m_RP.m_tCosTable[i] = cry_cosf(f * (360.0f/1023.0f) * M_PI / 180.0f); m_RP.m_tHillTable[i] = cry_sinf(f * (180.0f/1023.0f) * M_PI / 180.0f); if (i < 512) m_RP.m_tSquareTable[i] = 1.0f; else m_RP.m_tSquareTable[i] = -1.0f; m_RP.m_tSawtoothTable[i] = f / 1024.0f; m_RP.m_tInvSawtoothTable[i] = 1.0f - m_RP.m_tSawtoothTable[i]; if (i < 512) { if (i < 256) m_RP.m_tTriTable[i] = f / 256.0f; else m_RP.m_tTriTable[i] = 1.0f - m_RP.m_tTriTable[i-256]; } else m_RP.m_tTriTable[i] = 1.0f - m_RP.m_tTriTable[i-512]; } } void CGLRenderer::EF_InitEvalFuncs(int num) { switch(num) { case 0: m_RP.m_pCurFuncs = &m_RP.m_EvalFuncs_C; break; default: case 1: m_RP.m_pCurFuncs = &m_RP.m_EvalFuncs_RE; break; } } // Register new fog volume int CGLRenderer::EF_RegisterFogVolume(float fMaxFogDist, float fFogLayerZ, CFColor color, int nIndex, bool bCaustics) { if (nIndex < 0) { SMFog Fog; memset(&Fog,0,sizeof(Fog)); Fog.m_fMaxDist = fMaxFogDist; Fog.m_FogInfo.m_FogColor = color; Fog.m_Dist = fFogLayerZ; Fog.m_Color = color; Fog.m_Color.a = 1.0f; Fog.bCaustics = bCaustics; //Fog.m_FogInfo.m_FogColor = m_FogColor; Fog.m_Normal = Vec3d(0,0,1); m_RP.m_FogVolumes.AddElem(Fog); return m_RP.m_FogVolumes.Num()-1; } else { assert (nIndex < m_RP.m_FogVolumes.Num()); SMFog *pFog = &m_RP.m_FogVolumes[nIndex]; pFog->m_fMaxDist = fMaxFogDist; pFog->m_FogInfo.m_FogColor = color; pFog->m_Dist = fFogLayerZ; pFog->m_Color = color; pFog->m_Color.a = 1.0f; pFog->bCaustics = bCaustics; return nIndex; } } _inline static void *sAlign0x20(byte *vrts) { INT_PTR b = (INT_PTR)vrts; //AMD Port if (!(b & 0x1f)) return vrts; // Was b = (b+0x20)&0xffffffe0; b = (b+0x20) & (~0x1f); //AMD Port return (void *)b; } // Allocate render buffers in video/agp memory bool CGLRenderer::EF_AllocateBuffersVid() { iLog->Log("\nAllocate vertex buffers in Video/AGP memory (%d verts, %d tris)...\n", m_RP.m_MaxVerts, m_RP.m_MaxTris); int i; int n = 0; int nv = 0; byte *buf = NULL; for (i=0; i 2) { float kbytes = ((float)nv/1024.0f); iLog->Log(" Allocating %.2f kbytes of AGP/Video memory for (%d buffers)...", kbytes, m_RP.m_NumFences); m_BigArray = (float *)AllocateVarShunk(nv, "Shaders pipeline"); if(!m_BigArray) { iLog->Log("Failed\n"); m_SizeBigArray -= 2*singleSize; nv = m_SizeBigArray; m_RP.m_NumFences -= 2; } else break; } if(!m_BigArray) { iLog->Log("Failed\n"); m_RP.m_NumFences = 0; return false; } iLog->LogPlus("Ok\n"); buf = (byte *)m_BigArray; memset(buf, 0, nv); int size = sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts+32; for (i=0; iExit("Can't allocate system vertex buffers"); memset(buf, 0, n); m_RP.m_Ptr.Ptr = sAlign0x20(buf); buf += sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts + 32; m_RP.m_pFogVertValues = (float *)sAlign0x20(buf); buf += sizeof(float)*m_RP.m_MaxVerts+32; m_RP.m_pBaseTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf); buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; m_RP.m_pLMTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf); buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; m_RP.m_pClientColors = (bvec4 *)sAlign0x20(buf); buf += sizeof(bvec4)*m_RP.m_MaxVerts+32; m_RP.m_RendIndices = (ushort *)sAlign0x20(buf); m_RP.m_SysRendIndices = m_RP.m_RendIndices; buf += sizeof(ushort)*3*m_RP.m_MaxTris+32; if (GetFeatures() & RFT_BUMP) { m_RP.m_pBinormals = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pTangents = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pTNormals = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; for (i=0; i<4; i++) { m_RP.m_pLightVectors[i] = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pHalfAngleVectors[i] = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } m_RP.m_pAttenuation = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pLAttenSpec0 = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pLAttenSpec1 = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } return true; } // Allocate render buffers/tables void CGLRenderer::EF_AllocateBuffers() { iLog->Log("\nAllocate vertex buffers in system memory (%d verts, %d tris)...\n", m_RP.m_MaxVerts, m_RP.m_MaxTris); int n = 0; n += sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts + 32; //m_RP.mFogVertValues n += sizeof(float)*m_RP.m_MaxVerts+32; //m_RP.mBaseTexCoordPointer n += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; //m_RP.mLMTexCoordPointer n += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; //m_RP.mClientColors n += sizeof(bvec4)*m_RP.m_MaxVerts+32; //m_RP.mRendIndices; n += sizeof(ushort)*3*m_RP.m_MaxTris+32; int i; if (GetFeatures() & RFT_BUMP) { //m_RP.mBinormals n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; //m_RP.mTangents n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; //m_RP.mTNormals n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; for (i=0; i<4; i++) { //m_RP.mHalfAngleVectors n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; //m_RP.mLightVectors n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } //m_RP.mAttenuation n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; //m_RP.mLAttenSpec0 n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; //m_RP.mLAttenSpec1 n += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } SAFE_DELETE_ARRAY(m_SysArray); byte *buf = new byte [n]; m_SysArray = buf; if (!buf) iConsole->Exit("Can't allocate vertex buffers in system memory"); memset(buf, 0, n); m_RP.m_Ptr.Ptr = sAlign0x20(buf); buf += sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts + 32; m_RP.m_pClientColors = (bvec4 *)sAlign0x20(buf); buf += sizeof(bvec4)*m_RP.m_MaxVerts+32; m_RP.m_pBaseTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf); buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; m_RP.m_pLMTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf); buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32; m_RP.m_pFogVertValues = (float *)sAlign0x20(buf); buf += sizeof(float)*m_RP.m_MaxVerts+32; m_RP.m_RendIndices = (ushort *)sAlign0x20(buf); m_RP.m_SysRendIndices = m_RP.m_RendIndices; buf += sizeof(ushort)*3*m_RP.m_MaxTris+32; if (GetFeatures() & RFT_BUMP) { m_RP.m_pBinormals = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pTangents = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pTNormals = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; for (i=0; i<4; i++) { m_RP.m_pLightVectors[i] = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pHalfAngleVectors[i] = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } m_RP.m_pAttenuation = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pLAttenSpec0 = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; m_RP.m_pLAttenSpec1 = (Vec3d *)sAlign0x20(buf); buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32; } } // Initialize of shaders pipeline void CGLRenderer::EF_PipelineInit() { bool nv = 0; m_RP.m_pCurFuncs = NULL; m_RP.m_MaxVerts = CV_gl_rb_verts; m_RP.m_MaxTris = CV_gl_rb_tris; m_RP.m_CurFence = 0; m_RP.m_FenceCount = 0; if (m_RP.m_NumFences) nv = EF_AllocateBuffersVid(); if (!nv) EF_AllocateBuffers(); if (SUPPORTS_GL_ARB_vertex_buffer_object) { m_RP.m_IBDynSize = m_RP.m_MaxTris*3*sizeof(ushort); int nVerts = m_RP.m_MaxVerts; for (int i=0; im_bDynamic = true; int size = m_VertexSize[VERTEX_FORMAT_P3F_N_COL4UB_TEX2F]*nVerts*4; glGenBuffersARB(1, &pBuf->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glBindBufferARB(GL_ARRAY_BUFFER_ARB, pBuf->m_VS[VSF_GENERAL].m_VertBuf.m_nID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, GL_STREAM_DRAW_ARB); m_CurVertBufferSize += size; pBuf->m_vertexformat = VERTEX_FORMAT_P3F_N_COL4UB_TEX2F; pBuf->m_NumVerts = nVerts; m_RP.m_VidBufs[i].m_pVBDyn = pBuf; m_RP.m_VidBufs[i].m_nCount = size; } int nInds = m_RP.m_MaxTris*3; ReleaseIndexBuffer(&m_RP.m_IBDyn); glGenBuffersARB(1, &m_RP.m_IBDyn.m_VertBuf.m_nID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_RP.m_IBDyn.m_VertBuf.m_nID); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, nInds*sizeof(ushort), NULL, GL_STREAM_DRAW_ARB); m_RP.m_IBDyn.m_nItems = nInds; } glEnableClientState(GL_VERTEX_ARRAY); m_Features |= RFT_ZLOCKABLE; EF_InitWaveTables(); EF_InitRandTables(); EF_InitEvalFuncs(0); EF_InitFogVolumes(); for (int i=0; iInit(); m_RP.m_TempObjects[i]->m_Id = i; m_RP.m_TempObjects[i]->m_VisId = 0; m_RP.m_TempObjects[i]->m_Color = Col_White; m_RP.m_TempObjects[i]->m_ObjFlags = 0; m_RP.m_TempObjects[i]->m_Matrix.SetIdentity(); m_RP.m_TempObjects[i]->m_RenderState = 0; } m_RP.m_VisObjects[0] = &m_RP.m_ObjectsPool[0]; } for (i=0; i 16) { glClearStencil(0); if (bOnlyDepth) glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); else glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if (CV_r_measureoverdraw) { if (m_sbpp <= 4) { iLog->Log("Not enough stencil bits to measure overdraw: %d\n"); CV_r_measureoverdraw = 0; m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW; } else { m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW; EF_SetState(GS_STENCIL | GS_DEPTHWRITE); m_RP.m_PersFlags |= RBPF_MEASUREOVERDRAW; EF_SetStencilState(STENC_FUNC(FSS_STENCFUNC_ALWAYS) | STENCOP_FAIL(FSS_STENCOP_KEEP) | STENCOP_ZFAIL(FSS_STENCOP_INCR) | STENCOP_PASS(FSS_STENCOP_INCR), 0, 0xffffffff); } } else m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW; } else { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } } // Set clip plane for the current scene // on NVidia GPUs we use fake clip planes using texkill PS instruction : m_RP.m_ClipPlaneEnabled = 1 // on ATI hardware we use native ClipPlanes : m_RP.m_ClipPlaneEnabled = 2 void CGLRenderer::EF_SetClipPlane (bool bEnable, float *pPlane, bool bRefract) { if (!CV_gl_clipplanes) return; if (bEnable) { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "Set clip-plane\n"); if (m_RP.m_ClipPlaneEnabled) return; m_RP.m_ClipPlaneWasOverrided = 0; m_RP.m_bClipPlaneRefract = bRefract; m_RP.m_CurClipPlane.m_Normal.x = pPlane[0]; m_RP.m_CurClipPlane.m_Normal.y = pPlane[1]; m_RP.m_CurClipPlane.m_Normal.z = pPlane[2]; m_RP.m_CurClipPlane.m_Dist = pPlane[3]; m_RP.m_CurClipPlane.Init(); m_RP.m_CurClipPlaneCull = m_RP.m_CurClipPlane; m_RP.m_CurClipPlaneCull.m_Dist = -m_RP.m_CurClipPlaneCull.m_Dist; if (m_MaxClipPlanes) { m_RP.m_ClipPlaneEnabled = 2; double p[4]; p[0] = pPlane[0]; p[1] = pPlane[1]; p[2] = pPlane[2]; p[3] = pPlane[3]; glPushMatrix(); glLoadMatrixf(m_CameraMatrix.GetData()); glClipPlane(GL_CLIP_PLANE0, p); glEnable(GL_CLIP_PLANE0); glPopMatrix(); } else { m_RP.m_ClipPlaneEnabled = 1; if (m_MaxActiveTexturesARB_VP > 6) m_RP.m_nClipPlaneTMU = 3; else m_RP.m_nClipPlaneTMU = 3; // Set the tex-gen clipping plane for fixed pipeline. // Special set for terrain detail textures (fixed pipe) glLoadMatrixf(m_CameraMatrix.GetData()); EF_SelectTMU(3); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); if (bRefract) { float plane[4]; plane[0] = pPlane[0]; plane[1] = pPlane[1]; plane[2] = pPlane[2]; plane[3] = pPlane[3]; glTexGenfv(GL_S, GL_EYE_PLANE, plane); glTexGenfv(GL_T, GL_EYE_PLANE, plane); glTexGenfv(GL_R, GL_EYE_PLANE, plane); glTexGenfv(GL_Q, GL_EYE_PLANE, plane); } else { glTexGenfv(GL_S, GL_EYE_PLANE, pPlane); glTexGenfv(GL_T, GL_EYE_PLANE, pPlane); glTexGenfv(GL_R, GL_EYE_PLANE, pPlane); glTexGenfv(GL_Q, GL_EYE_PLANE, pPlane); } glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glEnable(GL_TEXTURE_GEN_Q); if (SUPPORTS_GL_NV_texture_shader) { for (int i=0; im_TexMan->m_CurStage].m_Target); } } EF_SelectTMU(0); if (SUPPORTS_GL_NV_texture_shader) glEnable(GL_TEXTURE_SHADER_NV); } } else { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "Reset clip-plane\n"); if (!m_RP.m_ClipPlaneEnabled) return; if (m_RP.m_ClipPlaneEnabled == 2) { glDisable(GL_CLIP_PLANE0); } else { if (SUPPORTS_GL_NV_texture_shader) glDisable(GL_TEXTURE_SHADER_NV); EF_SelectTMU(3); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); EF_SelectTMU(0); } m_RP.m_ClipPlaneEnabled = 0; m_RP.m_ClipPlaneWasOverrided = 0; } } // Shutdown shaders pipeline void CGLRenderer::EF_PipelineShutdown() { int i, j; CCObject::m_Waves.Free(); SAFE_DELETE_ARRAY(m_RP.m_VisObjects); SAFE_DELETE_ARRAY(m_SysArray); if (m_BigArray) { ReleaseVarShunk(m_BigArray); m_BigArray = NULL; } //m_RP.m_DLights.Free(); m_RP.m_FogVolumes.Free(); for (i=0; imfReset(); } } if (nFlags & EFRF_PSHADERS) { for (i=0; imfReset(); } } } //========================================================================== // Init states before rendering of the scene void CGLRenderer::EF_PreRender(int Stage) { if (Stage & 1) { // Before preprocess m_RP.m_RenderFrame++; m_RP.m_Flags = 0; m_RP.m_pPrevObject = NULL; m_RP.m_FrameObject++; EF_SetCameraInfo(); if (Stage == 1) CCGVProgram_GL::mfSetGlobalParams(); for (int i=0; im_Flags & DLF_FAKE) continue; if (dl->m_Flags & DLF_POINT) { } if (dl->m_Flags & DLF_SUN) { Vec3d pos = GetCamera().GetPos(); Vec3d delta = dl->m_Origin - pos; delta.Normalize(); m_RP.m_SunDir = delta; } } // if (i == m_RP.m_DLights.Num() && m_RP.m_SunDir == Vec3d(0,0,0)) if (i == m_RP.m_DLights[SRendItem::m_RecurseLevel].Num() && IsEquivalent(m_RP.m_SunDir,Vec3d(0,0,0))) m_RP.m_SunDir = Vec3d(0,0,1); } if (Stage & 2) { // After preprocess if (!m_RP.m_bStartPipeline && !m_bWasCleared && !(m_RP.m_PersFlags & RBPF_NOCLEARBUF)) { m_RP.m_bStartPipeline = true; glDepthRange(0, 1); EF_ClearBuffers(false, false); } if (!m_RP.m_WasPortals) { m_RP.m_fMinDepthRange = 0; m_RP.m_fMaxDepthRange = 1.0f; } else { if (!m_RP.m_CurPortal) { m_RP.m_fMinDepthRange = 0; m_RP.m_fMaxDepthRange = 0.5f; } else { float strt = 0.5f; float end = 1; float delta = (end - strt) / (float)m_RP.m_WasPortals; strt += delta * (float)(m_RP.m_CurPortal-1); m_RP.m_fMinDepthRange = strt+0; m_RP.m_fMaxDepthRange = strt+delta; } } glDepthRange(m_RP.m_fMinDepthRange, m_RP.m_fMaxDepthRange); } } //============================================================================== // Shader Pipeline //======================================================================= // Software vertex deformations stages handling for the current shader void CGLRenderer::EF_Eval_DeformVerts(TArray* Defs) { int i; if (!Defs) return; for (i=0; iNum(); i++) { SDeform *df = &Defs->Get(i); switch (df->m_eType) { case eDT_Wave: m_RP.m_pCurFuncs->WaveDeform(df); break; case eDT_Flare: m_RP.m_pCurFuncs->FlareDeform(df); break; case eDT_Beam: m_RP.m_pCurFuncs->BeamDeform(df); break; case eDT_VerticalWave: m_RP.m_pCurFuncs->VerticalWaveDeform(df); break; case eDT_Bulge: m_RP.m_pCurFuncs->BulgeDeform(df); break; case eDT_FromCenter: m_RP.m_pCurFuncs->FromCenterDeform(df); break; case eDT_Squeeze: m_RP.m_pCurFuncs->SqueezeDeform(df); break; default: iLog->Log("Unknown deform type %d in Shader '%s'\n", df->m_eType, m_RP.m_pShader->m_Name); break; } } } // Software/hardware texture coordinates generating modes handling for the current shader void CGLRenderer::EF_Eval_TexGen(SShaderPass *sfm) { int j, n; SShaderTexUnit *shl; SShader *ef = m_RP.m_pShader; SMRendTexVert *src; int m; for (j=0; jm_TUnits.Num(); j++) { shl = &sfm->m_TUnits[j]; if (!shl->m_TexPic || shl->m_GTC) continue; switch (shl->m_eGenTC) { case eGTC_NoFill: break; case eGTC_None: break; case eGTC_Base: if (!m_RP.m_pRE) { m = m_RP.m_RendNumVerts; src = m_RP.m_pBaseTexCoordPointer; byte *ptr = m_RP.m_Ptr.PtrB + m_RP.m_OffsT + j*8; for (n=0; nETC_Environment(j); break; case eGTC_Projection: if (shl->m_TexPic->m_Matrix) m_RP.m_pCurFuncs->ETC_Projection(j, shl->m_TexPic->m_Matrix, 1, 1); break; case eGTC_SphereMap: m_RP.m_pCurFuncs->ETC_SphereMap(j); break; case eGTC_SphereMapEnvironment: m_RP.m_pCurFuncs->ETC_SphereMapEnvironment(j); break; case eGTC_ShadowMap: m_RP.m_pCurFuncs->ETC_ShadowMap(j); break; default: iLog->Log("ERROR: invalid eGenTC '%d' specified for Shader\n", shl->m_eGenTC); break; } } } // Software/hardware RGBA generating/modificating modes handling for the current shader void CGLRenderer::EF_Eval_RGBAGen(SShaderPass *sfm) { SShader *ef = m_RP.m_pShader; int n; UCol color; bool bSetCol = false; color.dcolor = -1; switch(sfm->m_eEvalRGB) { case eERGB_NoFill: break; case eERGB_Identity: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { color.dcolor = -1; bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } } else { byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD; for (n=0; nm_FixedColor; bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; break; case eERGB_StyleIntens: { CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime); color = sfm->m_FixedColor; color.bcolor[0] = (byte)((float)color.bcolor[0] * ls->m_fIntensity); color.bcolor[1] = (byte)((float)color.bcolor[1] * ls->m_fIntensity); color.bcolor[2] = (byte)((float)color.bcolor[2] * ls->m_fIntensity); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } break; case eERGB_StyleColor: { CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime); color.dcolor = ls->m_Color.GetTrue(); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } break; case eERGB_Comps: { if (sfm->m_RGBComps) { float *vals = sfm->m_RGBComps->mfGet(); color.bcolor[0] = (byte)(vals[0] * 255.0f); color.bcolor[1] = (byte)(vals[1] * 255.0f); color.bcolor[2] = (byte)(vals[2] * 255.0f); color.bcolor[3] = (byte)(vals[3] * 255.0f); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } } break; case eERGB_OneMinusFromClient: if (!gbRgb) { byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD; for (n=0; nm_WaveEvalRGB) { if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { float val = SEvalFuncs::EvalWaveForm(sfm->m_WaveEvalRGB); if (val < 0) val = 0; if (val > 1) val = 1; color.bcolor[0] = color.bcolor[1] = color.bcolor[2] = (int)(val * 255.0f); COLCONV(color.dcolor); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } else m_RP.m_pCurFuncs->ERGB_Wave(sfm->m_WaveEvalRGB, color); } } break; case eERGB_Noise: if (sfm->m_RGBNoise) { if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { float v = RandomNum(); byte r = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeR + sfm->m_RGBNoise->m_ConstR, 0.0f, 1.0f) * 255.0f); v = RandomNum(); byte g = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeG + sfm->m_RGBNoise->m_ConstG, 0.0f, 1.0f) * 255.0f); v = RandomNum(); byte b = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeB + sfm->m_RGBNoise->m_ConstB, 0.0f, 1.0f) * 255.0f); color.bcolor[0] = r; color.bcolor[1] = g; color.bcolor[2] = b; COLCONV(color.dcolor); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } else m_RP.m_pCurFuncs->ERGB_Noise(sfm->m_RGBNoise, color); } } break; case eERGB_Object: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { bSetCol = true; color.bcolor[0] = (byte)(m_RP.m_pCurObject->m_Color[0] * 255.0f); color.bcolor[1] = (byte)(m_RP.m_pCurObject->m_Color[1] * 255.0f); color.bcolor[2] = (byte)(m_RP.m_pCurObject->m_Color[2] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } else m_RP.m_pCurFuncs->ERGB_Object(); } break; case eERGB_OneMinusObject: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { bSetCol = true; color.bcolor[0] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[0]) * 255.0f); color.bcolor[1] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[1]) * 255.0f); color.bcolor[2] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[2]) * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } } else m_RP.m_pCurFuncs->ERGB_OneMinusObject(); break; case eERGB_RE: if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { bSetCol = true; color.bcolor[0] = (byte)(m_RP.m_pRE->m_Color[0] * 255.0f); color.bcolor[1] = (byte)(m_RP.m_pRE->m_Color[1] * 255.0f); color.bcolor[2] = (byte)(m_RP.m_pRE->m_Color[2] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } break; case eERGB_OneMinusRE: if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { bSetCol = true; color.bcolor[0] = (byte)((1.0f - m_RP.m_pRE->m_Color[0]) * 255.0f); color.bcolor[1] = (byte)((1.0f - m_RP.m_pRE->m_Color[1]) * 255.0f); color.bcolor[2] = (byte)((1.0f - m_RP.m_pRE->m_Color[2]) * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } break; case eERGB_World: if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { bSetCol = true; color.bcolor[0] = (byte)(m_WorldColor[0] * 255.0f); color.bcolor[1] = (byte)(m_WorldColor[1] * 255.0f); color.bcolor[2] = (byte)(m_WorldColor[2] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } break; default: assert(0); } switch(sfm->m_eEvalAlpha) { case eEALPHA_NoFill: break; case eEALPHA_Identity: if (sfm->m_eEvalRGB!=eERGB_Identity && sfm->m_eEvalRGB!=eERGB_Fixed) { if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN)) { color.bcolor[3] = 255; bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; } } else { byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD; for (n=0; nm_eEvalRGB == eERGB_Fixed) break; if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { color.bcolor[3] = sfm->m_FixedColor.bcolor[3]; bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } break; case eEALPHA_Style: { CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime); color.bcolor[3] = (byte)((float)sfm->m_FixedColor.bcolor[3] * ls->m_fIntensity); bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } break; case eEALPHA_Comps: { if (sfm->m_eEvalRGB == eERGB_Comps) break; if (sfm->m_RGBComps) { float *vals = sfm->m_RGBComps->mfGet(); if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { color.bcolor[3] = (byte)(vals[0] * 255.0f); bSetCol = true; m_RP.m_FlagsPerFlush = RBSI_ALPHAGEN; } } else { byte a = (byte)(vals[0] * 255.0f); byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD; for (n=0; nm_WaveEvalAlpha) { if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { float val = SEvalFuncs::EvalWaveForm(sfm->m_WaveEvalAlpha); if (val < 0) val = 0; if (val > 1) val = 1; color.bcolor[3] = (int)(val * 255.0f); bSetCol = true; m_RP.m_FlagsPerFlush = RBSI_ALPHAGEN; } } else m_RP.m_pCurFuncs->EALPHA_Wave(sfm->m_WaveEvalAlpha, color); } break; case eEALPHA_Noise: if (sfm->m_ANoise) { if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { float v = RandomNum(); byte a = (byte)(CLAMP(v * sfm->m_ANoise->m_RangeA + sfm->m_ANoise->m_ConstA, 0.0f, 1.0f) * 255.0f); color.bcolor[3] = a; bSetCol = true; m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } else m_RP.m_pCurFuncs->EALPHA_Noise(sfm->m_ANoise, color); } break; case eEALPHA_Beam: m_RP.m_pCurFuncs->EALPHA_Beam(); break; case eEALPHA_Object: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { bSetCol = true; color.bcolor[3] = (byte)(m_RP.m_pCurObject->m_Color[3] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } else m_RP.m_pCurFuncs->EALPHA_Object(); break; case eEALPHA_OneMinusObject: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { bSetCol = true; color.bcolor[3] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[3]) * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } else m_RP.m_pCurFuncs->EALPHA_OneMinusObject(); break; case eEALPHA_RE: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { bSetCol = true; color.bcolor[3] = (byte)(m_RP.m_pRE->m_Color[3] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } break; case eEALPHA_OneMinusRE: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { bSetCol = true; color.bcolor[3] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[3]) * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } break; case eEALPHA_World: if (m_RP.m_pRE) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN)) { bSetCol = true; color.bcolor[3] = (byte)(m_WorldColor[3] * 255.0f); m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; } } break; case eEALPHA_FromClient: if (!m_RP.m_pRE) { if (sfm->m_eEvalRGB!=eERGB_FromClient) { byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD; for (n=0; nm_NormGen) return; SNormalsGen *ng = ef->m_NormGen; if (ng->m_eNormal == eNORM_Identity || !m_RP.m_OffsN) return; int i; int nums = m_RP.m_RendNumVerts; byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsN; switch(ng->m_eNormal) { case eNORM_Custom: for (i=0; im_CustomNormal[0]; tsnrm[1] = ng->m_CustomNormal[1]; tsnrm[2] = ng->m_CustomNormal[2]; } break; } } //================================================================================= // Set current geometry culling modes void CGLRenderer::GLSetCull(ECull eCull) { //eCull = eCULL_Front; if (m_RP.m_Flags & RBF_2D) { glDisable(GL_CULL_FACE); m_RP.m_eCull = eCULL_None; return; } if (m_RP.m_eCull == eCull) return; if (eCull == eCULL_None) glDisable(GL_CULL_FACE); else { glEnable(GL_CULL_FACE); if ((eCull == eCULL_Back && !(m_RP.m_PersFlags & RBPF_DRAWMIRROR)) || (eCull != eCULL_Back && (m_RP.m_PersFlags & RBPF_DRAWMIRROR))) glCullFace(GL_BACK); else glCullFace(GL_FRONT); } m_RP.m_eCull = eCull; } //================================================================================= // Set current stencil states void SStencil::mfSet() { gRenDev->EF_SetStencilState(m_State, m_FuncRef, m_FuncMask); } // Set current stencil states void CRenderer::EF_SetStencilState(int st, uint nStencRef, uint nStencMask) { bool bChanged = false; if (nStencRef != m_CurStencRef || nStencMask != m_CurStencMask) { m_CurStencRef = nStencRef; m_CurStencMask = nStencMask; bChanged = true; } int Changed = st ^ m_CurStencilState; if (!Changed && !bChanged) return; if (SUPPORTS_GL_ATI_separate_stencil) { int nFrontFunc, nBackFunc; if ((Changed & FSS_STENCFUNC_MASK) || bChanged) { bChanged = true; int nCurFunc = st & FSS_STENCFUNC_MASK; switch(nCurFunc) { case FSS_STENCFUNC_ALWAYS: nBackFunc = GL_ALWAYS; break; case FSS_STENCFUNC_NEVER: nBackFunc = GL_NEVER; break; case FSS_STENCFUNC_LESS: nBackFunc = GL_LESS; break; case FSS_STENCFUNC_LEQUAL: nBackFunc = GL_LEQUAL; break; case FSS_STENCFUNC_GREATER: nBackFunc = GL_GREATER; break; case FSS_STENCFUNC_GEQUAL: nBackFunc = GL_GEQUAL; break; case FSS_STENCFUNC_EQUAL: nBackFunc = GL_EQUAL; break; case FSS_STENCFUNC_NOTEQUAL: nBackFunc = GL_NOTEQUAL; break; default: assert(false); } } if ((Changed & (FSS_STENCFUNC_MASK << FSS_STENCIL_TWOSIDED)) || bChanged) { bChanged = true; int nCurFunc; nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)); switch(nCurFunc >> FSS_CCW_SHIFT) { case FSS_STENCFUNC_ALWAYS: nFrontFunc = GL_ALWAYS; break; case FSS_STENCFUNC_NEVER: nFrontFunc = GL_NEVER; break; case FSS_STENCFUNC_LESS: nFrontFunc = GL_LESS; break; case FSS_STENCFUNC_LEQUAL: nFrontFunc = GL_LEQUAL; break; case FSS_STENCFUNC_GREATER: nFrontFunc = GL_GREATER; break; case FSS_STENCFUNC_GEQUAL: nFrontFunc = GL_GEQUAL; break; case FSS_STENCFUNC_EQUAL: nFrontFunc = GL_EQUAL; break; case FSS_STENCFUNC_NOTEQUAL: nFrontFunc = GL_NOTEQUAL; break; default: assert(false); } } if (bChanged) glStencilFuncSeparateATI(nBackFunc, nFrontFunc, nStencRef, nStencMask); if (Changed & (FSS_STENCFAIL_MASK | FSS_STENCZFAIL_MASK | FSS_STENCPASS_MASK)) { int nFail, nZFail, nPass; int nCurOp = (st & FSS_STENCFAIL_MASK); switch(nCurOp >> FSS_STENCFAIL_SHIFT) { case FSS_STENCOP_KEEP: nFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nFail = GL_INCR; break; case FSS_STENCOP_DECR: nFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & FSS_STENCZFAIL_MASK); switch(nCurOp >> FSS_STENCZFAIL_SHIFT) { case FSS_STENCOP_KEEP: nZFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nZFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nZFail = GL_INCR; break; case FSS_STENCOP_DECR: nZFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nZFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nZFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nZFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & FSS_STENCPASS_MASK); switch(nCurOp >> FSS_STENCPASS_SHIFT) { case FSS_STENCOP_KEEP: nPass = GL_KEEP; break; case FSS_STENCOP_REPLACE: nPass = GL_REPLACE; break; case FSS_STENCOP_INCR: nPass = GL_INCR; break; case FSS_STENCOP_DECR: nPass = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nPass = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nPass = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nPass = GL_ZERO; break; default: assert(false); } glStencilOpSeparateATI(GL_FRONT, nFail, nZFail, nPass); } if (Changed & ((FSS_STENCFAIL_MASK | FSS_STENCZFAIL_MASK | FSS_STENCPASS_MASK) << FSS_CCW_SHIFT)) { int nFail, nZFail, nPass; int nCurOp = (st & (FSS_STENCFAIL_MASK<> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nFail = GL_INCR; break; case FSS_STENCOP_DECR: nFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & (FSS_STENCZFAIL_MASK<> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nZFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nZFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nZFail = GL_INCR; break; case FSS_STENCOP_DECR: nZFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nZFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nZFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nZFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & (FSS_STENCPASS_MASK<> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nPass = GL_KEEP; break; case FSS_STENCOP_REPLACE: nPass = GL_REPLACE; break; case FSS_STENCOP_INCR: nPass = GL_INCR; break; case FSS_STENCOP_DECR: nPass = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nPass = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nPass = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nPass = GL_ZERO; break; default: assert(false); } glStencilOpSeparateATI(GL_BACK, nFail, nZFail, nPass); } m_CurStencilState = st; return; } if (Changed & FSS_STENCIL_TWOSIDED) { if (SUPPORTS_GL_EXT_stencil_two_side) { if (st & FSS_STENCIL_TWOSIDED) glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); else glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); } } if ((Changed & FSS_STENCFUNC_MASK) || bChanged) { if (SUPPORTS_GL_EXT_stencil_two_side) { if (m_CurStencilSide != GL_FRONT) { m_CurStencilSide = GL_FRONT; glActiveStencilFaceEXT(GL_FRONT); } } int nCurFunc = st & FSS_STENCFUNC_MASK; switch(nCurFunc) { case FSS_STENCFUNC_ALWAYS: glStencilFunc(GL_ALWAYS, nStencRef, nStencMask); break; case FSS_STENCFUNC_NEVER: glStencilFunc(GL_NEVER, nStencRef, nStencMask); break; case FSS_STENCFUNC_LESS: glStencilFunc(GL_LESS, nStencRef, nStencMask); break; case FSS_STENCFUNC_LEQUAL: glStencilFunc(GL_LEQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_GREATER: glStencilFunc(GL_GREATER, nStencRef, nStencMask); break; case FSS_STENCFUNC_GEQUAL: glStencilFunc(GL_GEQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_EQUAL: glStencilFunc(GL_EQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_NOTEQUAL: glStencilFunc(GL_NOTEQUAL, nStencRef, nStencMask); break; default: assert(false); } } if (Changed & (FSS_STENCFAIL_MASK | FSS_STENCZFAIL_MASK | FSS_STENCPASS_MASK)) { if (SUPPORTS_GL_EXT_stencil_two_side) { if (m_CurStencilSide != GL_FRONT) { m_CurStencilSide = GL_FRONT; glActiveStencilFaceEXT(GL_FRONT); } } int nFail, nZFail, nPass; int nCurOp = (st & FSS_STENCFAIL_MASK); switch(nCurOp >> FSS_STENCFAIL_SHIFT) { case FSS_STENCOP_KEEP: nFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nFail = GL_INCR; break; case FSS_STENCOP_DECR: nFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & FSS_STENCZFAIL_MASK); switch(nCurOp >> FSS_STENCZFAIL_SHIFT) { case FSS_STENCOP_KEEP: nZFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nZFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nZFail = GL_INCR; break; case FSS_STENCOP_DECR: nZFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nZFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nZFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nZFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & FSS_STENCPASS_MASK); switch(nCurOp >> FSS_STENCPASS_SHIFT) { case FSS_STENCOP_KEEP: nPass = GL_KEEP; break; case FSS_STENCOP_REPLACE: nPass = GL_REPLACE; break; case FSS_STENCOP_INCR: nPass = GL_INCR; break; case FSS_STENCOP_DECR: nPass = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nPass = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nPass = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nPass = GL_ZERO; break; default: assert(false); } glStencilOp(nFail, nZFail, nPass); } if (SUPPORTS_GL_EXT_stencil_two_side) { if ((Changed & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)) || bChanged) { if (m_CurStencilSide != GL_BACK) { m_CurStencilSide = GL_BACK; glActiveStencilFaceEXT(GL_BACK); } int nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)); switch(nCurFunc >> FSS_CCW_SHIFT) { case FSS_STENCFUNC_ALWAYS: glStencilFunc(GL_ALWAYS, nStencRef, nStencMask); break; case FSS_STENCFUNC_NEVER: glStencilFunc(GL_NEVER, nStencRef, nStencMask); break; case FSS_STENCFUNC_LESS: glStencilFunc(GL_LESS, nStencRef, nStencMask); break; case FSS_STENCFUNC_LEQUAL: glStencilFunc(GL_LEQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_GREATER: glStencilFunc(GL_GREATER, nStencRef, nStencMask); break; case FSS_STENCFUNC_GEQUAL: glStencilFunc(GL_GEQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_EQUAL: glStencilFunc(GL_EQUAL, nStencRef, nStencMask); break; case FSS_STENCFUNC_NOTEQUAL: glStencilFunc(GL_NOTEQUAL, nStencRef, nStencMask); break; default: assert(false); } } if (Changed & ((FSS_STENCFAIL_MASK | FSS_STENCZFAIL_MASK | FSS_STENCPASS_MASK) << FSS_CCW_SHIFT)) { if (m_CurStencilSide != GL_BACK) { m_CurStencilSide = GL_BACK; glActiveStencilFaceEXT(GL_BACK); } int nFail, nZFail, nPass; int nCurOp = (st & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nFail = GL_INCR; break; case FSS_STENCOP_DECR: nFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nZFail = GL_KEEP; break; case FSS_STENCOP_REPLACE: nZFail = GL_REPLACE; break; case FSS_STENCOP_INCR: nZFail = GL_INCR; break; case FSS_STENCOP_DECR: nZFail = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nZFail = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nZFail = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nZFail = GL_ZERO; break; default: assert(false); } nCurOp = (st & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: nPass = GL_KEEP; break; case FSS_STENCOP_REPLACE: nPass = GL_REPLACE; break; case FSS_STENCOP_INCR: nPass = GL_INCR; break; case FSS_STENCOP_DECR: nPass = GL_DECR; break; case FSS_STENCOP_INCR_WRAP: nPass = GL_INCR_WRAP_EXT; break; case FSS_STENCOP_DECR_WRAP: nPass = GL_DECR_WRAP_EXT; break; case FSS_STENCOP_ZERO: nPass = GL_ZERO; break; default: assert(false); } glStencilOp(nFail, nZFail, nPass); } } m_CurStencilState = st; } // Set current render states void CRenderer::EF_SetState(int st) { int Changed; int src, dst; if (m_RP.m_Flags & RBF_SHOWLINES) st |= GS_NODEPTHTEST; if (st & (GS_DEPTHWRITE | GS_DEPTHFUNC_EQUAL)) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND)) m_RP.m_FlagsPerFlush |= RBSI_WASDEPTHWRITE; } if (st & GS_DEPTHWRITE) { if (m_RP.m_LastVP && m_RP.m_pRE) m_RP.m_pRE->m_LastVP = m_RP.m_LastVP; } Changed = st ^ m_CurState; if (!Changed) return; //PROFILE_FRAME(State_RStates); if (Changed & (GS_DEPTHFUNC_EQUAL | GS_DEPTHFUNC_GREAT)) { if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHFUNC)) { if (st & (GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT)) { if (st & GS_DEPTHFUNC_EQUAL) glDepthFunc(GL_EQUAL); else glDepthFunc(GL_GREATER); } else glDepthFunc(GL_LEQUAL); } else { st &= ~(GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT); st |= (m_CurState & (GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT)); } } if (Changed & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB)) { if (st & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB)) { if (st & GS_NOCOLMASK) glColorMask(0, 0, 0, 0); else if (st & GS_COLMASKONLYALPHA) glColorMask(0, 0, 0, 1); else if (st & GS_COLMASKONLYRGB) glColorMask(1, 1, 1, 0); } else glColorMask(1, 1, 1, 1); } if ((Changed & GS_BLEND_MASK)) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND)) { if ((st & GS_BLEND_MASK) == GS_BLEND_MASK) { st &= ~GS_BLEND_MASK; st |= (m_CurState & GS_BLEND_MASK); goto skip; } if (st & GS_BLEND_MASK) { // Src factor switch (st & GS_BLSRC_MASK) { case GS_BLSRC_ZERO: src = GL_ZERO; break; case GS_BLSRC_ONE: src = GL_ONE; break; case GS_BLSRC_DSTCOL: src = GL_DST_COLOR; break; case GS_BLSRC_ONEMINUSDSTCOL: src = GL_ONE_MINUS_DST_COLOR; break; case GS_BLSRC_SRCALPHA: src = GL_SRC_ALPHA; break; case GS_BLSRC_ONEMINUSSRCALPHA: src = GL_ONE_MINUS_SRC_ALPHA; break; case GS_BLSRC_DSTALPHA: src = GL_DST_ALPHA; break; case GS_BLSRC_ONEMINUSDSTALPHA: src = GL_ONE_MINUS_DST_ALPHA; break; case GS_BLSRC_ALPHASATURATE: src = GL_SRC_ALPHA_SATURATE; break; default: iLog->Log("CGLRenderer::mfState: invalid src blend state bits '0x%x'", st & GS_BLSRC_MASK); src = GL_ONE; break; } // Dst factor switch (st & GS_BLDST_MASK) { case GS_BLDST_ZERO: dst = GL_ZERO; break; case GS_BLDST_ONE: dst = GL_ONE; break; case GS_BLDST_SRCCOL: dst = GL_SRC_COLOR; break; case GS_BLDST_ONEMINUSSRCCOL: dst = GL_ONE_MINUS_SRC_COLOR; break; case GS_BLDST_SRCALPHA: dst = GL_SRC_ALPHA; break; case GS_BLDST_ONEMINUSSRCALPHA: dst = GL_ONE_MINUS_SRC_ALPHA; break; case GS_BLDST_DSTALPHA: dst = GL_DST_ALPHA; break; case GS_BLDST_ONEMINUSDSTALPHA: dst = GL_ONE_MINUS_DST_ALPHA; break; default: iLog->Log("CGLRenderer::mfState: invalid dst blend state bits '0x%x'", st & GS_BLDST_MASK); src = GL_ZERO; break; } if (!(m_CurState & GS_BLEND_MASK)) glEnable(GL_BLEND); glBlendFunc(src, dst); } else glDisable(GL_BLEND); } else { st &= ~GS_BLEND_MASK; st |= (m_CurState & GS_BLEND_MASK); } } skip: if (Changed & GS_DEPTHWRITE) { if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHWRITE)) { if (st & GS_DEPTHWRITE) glDepthMask(GL_TRUE); else glDepthMask(GL_FALSE); } else { st &= ~GS_DEPTHWRITE; st |= (m_CurState & GS_DEPTHWRITE); } } if (Changed & GS_POLYLINE) { if (m_polygon_mode == R_SOLID_MODE) { if (st & GS_POLYLINE) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } if (Changed & GS_NODEPTHTEST) { if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHTEST)) { if (st & GS_NODEPTHTEST) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); } else { st &= ~GS_NODEPTHTEST; st |= (m_CurState & GS_NODEPTHTEST); } } if (Changed & GS_STENCIL) { if (!(m_RP.m_FlagsPerFlush & RBSI_STENCIL) && !(m_RP.m_PersFlags & RBPF_MEASUREOVERDRAW)) { if (st & GS_STENCIL) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); } else { st &= ~GS_STENCIL; st |= (m_CurState & GS_STENCIL); } } if ((Changed & GS_ALPHATEST_MASK)) { if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHATEST)) { if (st & GS_ALPHATEST_MASK) { if (!(m_CurState & GS_ALPHATEST_MASK)) glEnable(GL_ALPHA_TEST); switch (st & GS_ALPHATEST_MASK) { case GS_ALPHATEST_GREATER0: glAlphaFunc(GL_GREATER, 0); break; case GS_ALPHATEST_LESS128: glAlphaFunc(GL_LESS, 0.5f); break; case GS_ALPHATEST_GEQUAL128: glAlphaFunc(GL_GEQUAL, 0.5f); break; case GS_ALPHATEST_GEQUAL64: glAlphaFunc(GL_GEQUAL, 0.25f); break; } } else glDisable(GL_ALPHA_TEST); } else { st &= ~GS_ALPHATEST_MASK; st |= m_CurState & GS_ALPHATEST_MASK; } } m_CurState = st; } // Set current texture color op modes (used in fixed pipeline shaders) void CGLRenderer::SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa) { EF_SetColorOp(eCo, eAo, eCa, eAa); } // Set current texture color op modes (used in fixed pipeline shaders) void CGLRenderer::EF_SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa) { int stage = m_TexMan->m_CurStage; if (CGLTexMan::m_TUState[stage].m_Color.dcolor != m_RP.m_CurGlobalColor.dcolor) { CGLTexMan::m_TUState[stage].m_Color.dcolor = m_RP.m_CurGlobalColor.dcolor; CFColor fCol = CFColor(m_RP.m_CurGlobalColor.bcolor); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&fCol[0]); } if (eCo != 255 && eCo != m_eCurColorOp[stage]) { float fScale = 1.0f; if (eCo == eCO_MODULATE2X) fScale = 2.0f; else if (eCo == eCO_MODULATE4X) fScale = 4.0f; if (m_fCurRGBScale[stage] != fScale) { m_fCurRGBScale[stage] = fScale; glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, fScale); } switch (eCo) { case eCO_MODULATE: default: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); break; case eCO_REPLACE: case eCO_DECAL: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); break; case eCO_MODULATE2X: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); break; case eCO_MODULATE4X: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); break; case eCO_ADD: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); break; case eCO_ADDSIGNED: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT); break; case eCO_BLENDDIFFUSEALPHA: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); break; case eCO_BLENDTEXTUREALPHA: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); break; case eCO_MULTIPLYADD: break; case eCO_BUMPENVMAP: break; case eCO_DISABLE: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE); break; } m_eCurColorOp[stage] = eCo; } if (eAo != 255 && eAo != m_eCurAlphaOp[stage]) { switch (eAo) { case eCO_MODULATE: case eCO_MODULATE2X: case eCO_MODULATE4X: default: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); break; case eCO_BLENDDIFFUSEALPHA: break; case eCO_BLENDTEXTUREALPHA: break; case eCO_ADD: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD); break; case eCO_ADDSIGNED: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_ADD_SIGNED_EXT); break; case eCO_MULTIPLYADD: break; case eCO_REPLACE: case eCO_DECAL: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); break; case eCO_BUMPENVMAP: break; case eCO_DISABLE: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); break; } m_eCurAlphaOp[stage] = eAo; } if (eCa != 255 && eCa != m_eCurColorArg[stage]) { if ((eCa & 7) != (m_eCurColorArg[stage] & 7)) { switch (eCa & 7) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); break; } } if (((eCa>>3) & 7) != ((m_eCurColorArg[stage]>>3) & 7)) { switch ((eCa >> 3) & 7) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); break; } } if ((eCa >> 6) != (m_eCurColorArg[stage] >> 6)) { switch (eCa >> 6) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); break; } } m_eCurColorArg[stage] = eCa; } if (eAa != 255 && eAa != m_eCurAlphaArg[stage]) { if ((eAa & 7) != (m_eCurAlphaArg[stage] & 7)) { switch (eAa & 7) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA); break; } } if (((eAa>>3) & 7) != ((m_eCurAlphaArg[stage]>>3) & 7)) { switch ((eAa >> 3) & 7) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA); break; } } if ((eAa >> 6) != (m_eCurAlphaArg[stage] >> 6)) { switch (eAa >> 6) { case eCA_Texture: default: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Diffuse: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Specular: break; case eCA_Previous: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); break; case eCA_Constant: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, GL_CONSTANT_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA); break; } } m_eCurAlphaArg[stage] = eAa; } } //================================================================================= // Object changing handling (skinning, shadow maps updating, initial states setting, ...) bool CGLRenderer::EF_ObjectChange(SShader *Shader, SRenderShaderResources *Res, int nObject, CRendElement *pRE) { //PROFILE_FRAME(Objects_Changes); CCObject *obj = m_RP.m_VisObjects[nObject]; if ((obj->m_ObjFlags & FOB_NEAREST) && ((m_RP.m_PersFlags & RBPF_DONTDRAWNEAREST) || CV_r_nodrawnear)) return false; if (Shader) { // if (m_RP.m_IgnoreObject && !(Shader->m_Flags & EF_SKY) && m_RP.m_IgnoreObject->m_Trans == obj->m_Trans) if (m_RP.m_pIgnoreObject && !(Shader->m_Flags & EF_SKY) && IsEquivalent(m_RP.m_pIgnoreObject->GetTranslation(),obj->GetTranslation())) return false; if ((m_RP.m_PersFlags & RBPF_ONLYREFRACTED) && !(obj->m_ObjFlags & FOB_REFRACTED)) return false; if ((m_RP.m_PersFlags & RBPF_IGNOREREFRACTED) && (obj->m_ObjFlags & FOB_REFRACTED)) return false; } if (obj == m_RP.m_pPrevObject) return true; m_RP.m_FrameObject++; m_RP.m_pCurObject = obj; bool bTheSameCM = false; if (m_RP.m_pPrevObject->m_ObjFlags & FOB_CUBE_MASK) { bTheSameCM = (obj && (obj->m_ObjFlags & FOB_CUBE_MASK) == (m_RP.m_pPrevObject->m_ObjFlags & FOB_CUBE_MASK)); if (!bTheSameCM) { bool bNeedClear; if (obj && (obj->m_ObjFlags & FOB_CUBE_MASK)) bNeedClear = false; else bNeedClear = true; m_TexMan->EndCubeSide(m_RP.m_pPrevObject, bNeedClear); } } int flags = 0; if (nObject) { m_RP.m_PS.m_NumRendObjects++; // Skinning if (obj->m_pCharInstance && !CV_r_character_nodeform) { PROFILE_FRAME(Objects_ChangesSkinning); double time0 = 0; ticks(time0); m_RP.m_PS.m_NumRendSkinnedObjects++; CREOcLeaf *pREOCL = (CREOcLeaf *)pRE; int nFlags = 0; int nVertFormat = -1; for (int i=0; im_pBuffer->m_pMats->Count(); i++) { CMatInfo *mi = pREOCL->m_pBuffer->m_pMats->Get(i); if (!mi->pRE || !mi->shaderItem.m_pShader) continue; SShader *pSH = (SShader *)mi->shaderItem.m_pShader->GetTemplate(-1); if (pSH->m_Flags3 & EF3_NODRAW) continue; if (nVertFormat < 0) nVertFormat = pSH->m_VertexFormatId; else nVertFormat = m_RP.m_VFormatsMerge[nVertFormat][pSH->m_VertexFormatId]; if (Shader->m_Flags & EF_NEEDTANGENTS) nFlags |= SHPF_TANGENTS; if (mi->shaderItem.m_pShaderResources && mi->shaderItem.m_pShaderResources->m_bNeedNormals) nFlags |= SHPF_NORMALS; } pRE->mfCheckUpdate(nVertFormat, nFlags | FHF_FORANIM); CLeafBuffer *pLB = pREOCL->m_pBuffer->GetVertexContainer(); bool bForceUpdate = (pLB->m_UpdateFrame == GetFrameID()); if (pLB->m_pVertexBuffer && pLB->m_pVertexBuffer->m_bFenceSet) bForceUpdate = true; obj->m_pCharInstance->ProcessSkinning(Vec3(zero),obj->m_Matrix, obj->m_nTemplId, obj->m_nLod, bForceUpdate); unticks(time0); m_RP.m_PS.m_fSkinningTime += (float)(time0*1000.0*g_SecondsPerCycle); } if(obj->m_ObjFlags & FOB_NEAREST) flags |= RBF_NEAREST; if ((flags ^ m_RP.m_Flags) & RBF_NEAREST) { if (flags & RBF_NEAREST) { glDepthRange(0, 0.1); //glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); CCamera Cam = GetCamera(); m_RP.m_PrevCamera = Cam; Cam.SetZMin(0.01f); Cam.SetZMax(40.0f); // set nice fov for weapons Cam.SetFov( Cam.GetFov()*0.6666f ); Cam.Update(); SetCamera(Cam); m_RP.m_Flags |= RBF_NEAREST; } else { glDepthRange(m_RP.m_fMinDepthRange, m_RP.m_fMaxDepthRange); SetCamera(m_RP.m_PrevCamera); m_RP.m_Flags &= ~RBF_NEAREST; } } if ((obj->m_ObjFlags & FOB_CUBE_MASK) && !bTheSameCM) m_TexMan->StartCubeSide(obj); } else { if (m_RP.m_Flags & RBF_NEAREST) { glDepthRange(m_RP.m_fMinDepthRange, m_RP.m_fMaxDepthRange); SetCamera(m_RP.m_PrevCamera); m_RP.m_Flags &= ~RBF_NEAREST; } m_RP.m_pCurObject->m_Matrix.SetIdentity(); m_ViewMatrix = m_CameraMatrix; if (!Shader || !(Shader->m_Flags & EF_HASVSHADER)) { m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; glLoadMatrixf(&m_ViewMatrix[0][0]); } else m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED; } m_RP.m_pPrevObject = obj; return true; } _declspec(align(16)) static Matrix44 sIdentityMatrix(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); // Get inverted matrix of the object matrix // All matrices are 16 bytes alligned to speedup matrix calculations using SSE instructions Matrix44 &CCObject::GetInvMatrix() { if (m_InvMatrixId == 0) return sIdentityMatrix; if (m_InvMatrixId > 0) return m_ObjMatrices[m_InvMatrixId]; //PROFILE_FRAME(Objects_ObjInvTransform); int n = m_ObjMatrices.size(); m_ObjMatrices.resize(n+1); m_InvMatrixId = n; CRenderer *rd = gRenDev; Matrix44 &m = m_ObjMatrices[m_InvMatrixId]; if (m_ObjFlags & FOB_TRANS_ROTATE) { mathMatrixInverse(m.GetData(), m_Matrix.GetData(), g_CpuFlags); } else if (m_ObjFlags & FOB_TRANS_SCALE) { float fiScaleX = 1.0f / m_Matrix(0,0); float fiScaleY = 1.0f / m_Matrix(1,1); float fiScaleZ = 1.0f / m_Matrix(2,2); m(0,0) = fiScaleX; m(0,1) = m_Matrix(0,1); m(0,2) = m_Matrix(0,2); m(0,3) = m_Matrix(0,3); m(1,0) = m_Matrix(1,0); m(1,1) = fiScaleY; m(1,2) = m_Matrix(1,2); m(1,3) = m_Matrix(1,3); m(2,0) = m_Matrix(2,0); m(2,1) = m_Matrix(2,1); m(2,2) = fiScaleZ; m(2,3) = m_Matrix(2,3); m(3,0) = -m_Matrix(3,0) * fiScaleX; m(3,1) = -m_Matrix(3,1) * fiScaleY; m(3,2) = -m_Matrix(3,2) * fiScaleZ; m(3,3) = m_Matrix(3,3); } else if (m_ObjFlags & FOB_TRANS_TRANSLATE) { m(0,0) = m_Matrix(0,0); m(0,1) = m_Matrix(0,1); m(0,2) = m_Matrix(0,2); m(0,3) = m_Matrix(0,3); m(1,0) = m_Matrix(1,0); m(1,1) = m_Matrix(1,1); m(1,2) = m_Matrix(1,2); m(1,3) = m_Matrix(1,3); m(2,0) = m_Matrix(2,0); m(2,1) = m_Matrix(2,1); m(2,2) = m_Matrix(2,2); m(2,3) = m_Matrix(2,3); m(3,0) = -m_Matrix(3,0); m(3,1) = -m_Matrix(3,1); m(3,2) = -m_Matrix(3,2); m(3,3) = m_Matrix(3,3); } else m.SetIdentity(); return m; } // Get Project-ModelView matrix for the current object // This matrix is passed to the vertex shader // All matrices are 16 bytes alligned to speedup matrix calculations using SSE instructions Matrix44 &CCObject::GetVPMatrix() { CRenderer *rd = gRenDev; if (m_VPMatrixId == 0) return rd->m_CameraProjMatrix; if (m_VPMatrixId > 0 && m_VPMatrixFrame == rd->m_RP.m_TransformFrame) return m_ObjMatrices[m_VPMatrixId]; m_VPMatrixFrame = rd->m_RP.m_TransformFrame; int n = m_ObjMatrices.size(); m_ObjMatrices.resize(n+1); m_VPMatrixId = n; Matrix44 &m = m_ObjMatrices[m_VPMatrixId]; mathMatrixMultiply(m.GetData(), rd->m_CameraProjMatrix.GetData(), m_Matrix.GetData(), g_CpuFlags); //D3DXMatrixMultiplyTranspose((D3DXMATRIX *)m.GetData(), (D3DXMATRIX *)m_Matrix.GetData(), (D3DXMATRIX *)rd->m_CameraProjMatrix.GetData()); return m; } // Set scissor rectangle for the current object void CCObject::SetScissor() { if (CRenderer::CV_r_scissor) { if (m_nScissorX2) { int w = m_nScissorX2 - m_nScissorX1; int h = m_nScissorY2 - m_nScissorY1; gcpOGL->EF_Scissor(true, m_nScissorX1, m_nScissorY1, w, h); } else gcpOGL->EF_Scissor(false, 0, 0, 0, 0); } } // Sets per-object alpha blending state to fade-in/fade-out objects on the distance void CCObject::SetAlphaState(CPShader *pPS, int nCurState) { CGLRenderer *rd = gcpOGL; // Fake to prevent light coronas from custom blending if (!rd->m_RP.m_pRE || rd->m_RP.m_pRE->mfGetType() != eDATA_OcLeaf) return; if (rd->m_RP.m_pShader->m_Flags2 & EF2_IGNORERESOURCESTATES) return; rd->m_RP.m_FlagsPerFlush &= ~(RBSI_ALPHABLEND | RBSI_DEPTHWRITE | RBSI_ALPHAGEN); if (!(nCurState & GS_BLEND_MASK) && !(rd->m_RP.m_ResourceState & GS_BLEND_MASK)) { int State = rd->m_CurState &= ~GS_BLEND_MASK; State |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; State &= ~GS_DEPTHWRITE; rd->EF_SetState(State); } else if (rd->m_CurState & GS_DEPTHFUNC_EQUAL) rd->EF_SetState(rd->m_CurState & ~GS_DEPTHFUNC_EQUAL); rd->m_RP.m_fCurOpacity = rd->m_RP.m_pCurObject->m_Color.a; if (!pPS) { float fColor = 1.0f; int State = rd->m_RP.m_ResourceState & GS_BLEND_MASK; if (!State) State = nCurState & GS_BLEND_MASK; if (State == (GS_BLSRC_DSTCOL | GS_BLDST_ZERO) || State == (GS_BLSRC_ZERO | GS_BLDST_SRCCOL)) { fColor = rd->m_RP.m_fCurOpacity; byte bCol = (byte)((1.0f-fColor)*255.0f); rd->m_RP.m_NeedGlobalColor.bcolor[0] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[1] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[2] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(rd->m_RP.m_fCurOpacity * 255.0f); rd->m_RP.m_TexStages[0].m_CO = eCO_ADD; rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE; rd->m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Constant<<3); rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3); rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB; } else if (State == (GS_BLSRC_ONE | GS_BLDST_ONE)) { fColor = rd->m_RP.m_fCurOpacity; byte bCol = (byte)(fColor*255.0f); rd->m_RP.m_NeedGlobalColor.bcolor[0] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[1] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[2] = bCol; rd->m_RP.m_NeedGlobalColor.bcolor[3] = bCol; rd->m_RP.m_TexStages[0].m_CO = eCO_MODULATE; rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE; rd->m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Constant<<3); rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3); rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB; } else { rd->m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(rd->m_RP.m_fCurOpacity * 255.0f); rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE; rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3); rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALALPHA; } } rd->m_RP.m_FlagsPerFlush |= RBSI_ALPHABLEND | RBSI_DEPTHWRITE | RBSI_ALPHAGEN; } // Set object transform for fixed pipeline shader void CGLRenderer::EF_SetObjectTransform(CCObject *obj, SShader *pSH, int nTransFlags) { if (nTransFlags & FOB_TRANS_MASK) mathMatrixMultiply(m_ViewMatrix.GetData(), m_CameraMatrix.GetData(), obj->m_Matrix.GetData(), g_CpuFlags); else m_ViewMatrix = m_CameraMatrix; if (!pSH || !(pSH->m_Flags & EF_HASVSHADER)) { glLoadMatrixf(m_ViewMatrix.GetData()); m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; } else m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED; } // Calculate current scene node matrices void CGLRenderer::EF_SetCameraInfo() { m_RP.m_ViewOrg = m_cam.GetPos(); float fm[16]; glGetFloatv(GL_MODELVIEW_MATRIX, fm); m_ViewMatrix = (Matrix44&)fm; m_CameraMatrix = m_ViewMatrix; Matrix44 m = m_CameraMatrix; m.Transpose(); m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; // Forward m_RP.m_CamVecs[0][0] = -m(2,0); m_RP.m_CamVecs[0][1] = -m(2,1); m_RP.m_CamVecs[0][2] = -m(2,2); // Up m_RP.m_CamVecs[1][0] = m(1,0); m_RP.m_CamVecs[1][1] = m(1,1); m_RP.m_CamVecs[1][2] = m(1,2); // Right m_RP.m_CamVecs[2][0] = m(0,0); m_RP.m_CamVecs[2][1] = m(0,1); m_RP.m_CamVecs[2][2] = m(0,2); m_RP.m_TransformFrame++; m_RP.m_FrameObject++; glGetFloatv(GL_PROJECTION_MATRIX, &m_ProjMatrix(0,0)); mathMatrixMultiply(m_CameraProjMatrix.GetData(), m_ProjMatrix.GetData(), m_CameraMatrix.GetData(), g_CpuFlags); mathMatrixInverse(m_InvCameraProjMatrix.GetData(), m_CameraProjMatrix.GetData(), g_CpuFlags); m_RP.m_PersFlags &= ~RBPF_WASWORLDSPACE; m_RP.m_ObjFlags = FOB_TRANS_MASK; } //================================================================================= // Check buffer overflow during geometry batching void CGLRenderer::EF_CheckOverflow(int nVerts, int nInds, CRendElement *re) { if (m_RP.m_pRE || (m_RP.m_RendNumVerts+nVerts >= m_RP.m_MaxVerts || m_RP.m_RendNumIndices+nInds >= m_RP.m_MaxTris*3)) { m_RP.m_pRenderFunc(); if (nVerts >= m_RP.m_MaxVerts) { iLog->Log("CGLRenderer::EF_CheckOverflow: numVerts > MAX (%d > %d)\n", nVerts, m_RP.m_MaxVerts); nVerts = m_RP.m_MaxVerts; } if (nInds >= m_RP.m_MaxTris*3) { iLog->Log("CGLRenderer::EF_CheckOverflow: numIndices > MAX (%d > %d)\n", nInds, m_RP.m_MaxTris*3); nInds = m_RP.m_MaxTris*3; } EF_Start(m_RP.m_pShader, m_RP.m_pStateShader, m_RP.m_pShaderResources, m_RP.m_pFogVolume ? (m_RP.m_pFogVolume-&m_RP.m_FogVolumes[0]) : 0, re); } } // Initialize of the new shader pipeline (only 2d) void CGLRenderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, CRendElement *re) { m_RP.m_RendPass = 0; m_RP.m_RendNumIndices = 0; m_RP.m_RendNumVerts = 0; m_RP.m_pShader = ef; m_RP.m_RendIndices = m_RP.m_SysRendIndices; #ifdef PIPE_USE_INSTANCING m_RP.m_MergedObjects.SetUse(0); #endif m_RP.m_pCurLightMaterial = NULL; m_RP.m_pStateShader = efState; m_RP.m_pShaderResources = Res; m_RP.m_FlagsPerFlush = 0; m_RP.m_FlagsModificators = 0; m_RP.m_pFogVolume = NULL; m_RP.m_pRE = NULL; m_RP.m_fCurOpacity = 1.0f; SArrayPointer::m_CurEnabled = 0; // Choose appropriate shader technique depend on some input parameters if (ef->m_HWTechniques.Num()) { int nHW = EF_SelectHWTechnique(ef); if (nHW >= 0) m_RP.m_pCurTechnique = ef->m_HWTechniques[nHW]; else m_RP.m_pCurTechnique = NULL; } else m_RP.m_pCurTechnique = NULL; m_RP.m_CurVFormat = ef->m_VertexFormatId; SBufInfoTable *pOffs = &gBufInfoTable[m_RP.m_CurVFormat]; int Size = m_VertexSize[m_RP.m_CurVFormat]; m_RP.m_Stride = Size; m_RP.m_OffsD = pOffs->OffsColor; m_RP.m_OffsT = pOffs->OffsTC; m_RP.m_OffsN = pOffs->OffsNormal; m_RP.m_NextPtr = m_RP.m_Ptr; m_RP.m_Frame++; } // Initialize of the new shader pipeline void CGLRenderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, int numFog, CRendElement *re) { m_RP.m_RendPass = 0; m_RP.m_RendNumIndices = 0; m_RP.m_RendNumVerts = 0; m_RP.m_RendIndices = m_RP.m_SysRendIndices; m_RP.m_pShader = ef; m_RP.m_pStateShader = efState; m_RP.m_pShaderResources = Res; m_RP.m_DynLMask = 0; m_RP.m_fCurOpacity = 1.0f; #ifdef PIPE_USE_INSTANCING m_RP.m_MergedObjects.SetUse(0); #endif SArrayPointer::m_CurEnabled = 0; m_RP.m_FlagsPerFlush = 0; m_RP.m_FlagsModificators = 0; m_RP.m_pCurLightMaterial = NULL; if (numFog && numFogm_ObjFlags; m_RP.m_CurVFormat = ef->m_VertexFormatId; SBufInfoTable *pOffs = &gBufInfoTable[m_RP.m_CurVFormat]; int Size = m_VertexSize[m_RP.m_CurVFormat]; m_RP.m_Stride = Size; m_RP.m_OffsD = pOffs->OffsColor; m_RP.m_OffsT = pOffs->OffsTC; m_RP.m_OffsN = pOffs->OffsNormal; m_RP.m_NextPtr = m_RP.m_Ptr; m_RP.m_DynLMask = m_RP.m_pCurObject->m_DynLMMask; m_RP.m_MergedREs.SetUse(0); m_RP.m_MergedObjs.SetUse(0); if (!EF_BuildLightsList()) iLog->Log("WARNING: CGLRenderer::EF_BuildLightsList: Too many light sources per render item (> 16). Shader: '%s'\n", ef->m_Name.c_str()); // Choose appropriate shader technique depend on some input parameters if (ef->m_HWTechniques.Num()) { m_RP.m_pRE = re; int nHW = EF_SelectHWTechnique(ef); if (nHW >= 0) m_RP.m_pCurTechnique = ef->m_HWTechniques[nHW]; else m_RP.m_pCurTechnique = NULL; } else m_RP.m_pCurTechnique = NULL; m_RP.m_pRE = NULL; m_RP.m_Frame++; } //======================================================================================== // Set current HW light states (used in fixed pipeline shaders) void CGLRenderer::EF_SetHWLight(int Num, vec4_t Pos, CFColor& Diffuse, CFColor& Specular, float ca, float la, float qa) { GLfloat fAmbientLight[] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_EnableLights |= 1<= 8) break; CDLight *dl = m_RP.m_pActiveDLights[i]; if ((Flags & LMF_IGNOREPROJLIGHTS) && (dl->m_Flags & DLF_PROJECT)) continue; bool bSpecularOnly = false; int nlM; if (nlM=(Flags & LMF_LIGHT_MASK)) { if ((nlM >> LMF_LIGHT_SHIFT) != i) continue; } if (dl->m_Flags & DLF_LM) { if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP]) || m_RP.m_pCurObject->m_nLMId) { if (Flags & LMF_NOSPECULAR) continue; bSpecularOnly = true; } } // some statistics if (!(m_RP.m_StatLightMask & (1<GetInvMatrix(); TransformPosition(lpos, dl->m_Origin, m); //TransformPosition33(lpos, dl->m_Origin-m_RP.m_pCurObject->m_Matrix.GetTranslationOLD(), Matrix33(GetTransposed44(m_RP.m_pCurObject->m_Matrix))); if (dl->m_Flags & DLF_DIRECTIONAL) { lpos.Normalize(); Pos[3] = 0.0f; fCA = 1.0f; fLA = 0.0f; fQA = 0.0f; cDiffuse = dl->m_Color * 1.5f; } else { Pos[3] = 1.0f; if (m_RP.m_pRE && !bCalcDist) { Vec3d vMins, vMaxs; bCalcDist = true; m_RP.m_pRE->mfGetBBox(vMins, vMaxs); vCenterRE = (vMins + vMaxs) * 0.5f; vCenterRE += m_RP.m_pCurObject->GetTranslation(); fRadRE = (vMaxs - vMins).Length() * 0.5f; } else { fRadRE = 1000.0f; vCenterRE = Vec3(0,0,0); } float fDist = max(0.1f, (vCenterRE - dl->m_Origin).Length()); float fMaxDist = CLAMP(fDist + fRadRE, dl->m_fRadius * 0.1f, dl->m_fRadius * 0.99f); float fMinDist = CLAMP(fDist - fRadRE, dl->m_fRadius * 0.1f, dl->m_fRadius * 0.99f); float fMinAtt = 1.0f / sAttenuation(fMinDist, dl->m_fRadius); float fMaxAtt = 1.0f / sAttenuation(fMaxDist, dl->m_fRadius); if(fabsf(fMinAtt - fMaxAtt) < 0.00001f) { fCA = fMinAtt; fLA = 0.0f; } else { fCA = max(0.01f, fMinAtt - (fMaxAtt - fMinAtt) / (fMaxDist - fMinDist) * fMinDist); fLA = max(0.0f, (fMinAtt - fCA) / fMinDist); } fQA = 0.0f; cDiffuse = dl->m_Color; // * 1.25f; } fCA = max(0.0f, fCA); fLA = max(0.0f, fLA); fQA = max(0.0f, fQA); Pos[0] = lpos.x; Pos[1] = lpos.y; Pos[2] = lpos.z; if (!(Flags & LMF_NOSPECULAR)) cSpecular = dl->m_SpecColor; if (bSpecularOnly) cDiffuse = Col_Black; cDiffuse.a = 1.0f; EF_SetHWLight(n, Pos, cDiffuse, cSpecular, fCA, fLA, fQA); n++; } return true; } // Initialize HW vertex lighting states for the fixed pipeline shader void CGLRenderer::EF_LightMaterial(SLightMaterial *lm, int Flags) { if (!(m_RP.m_pShader->m_Flags & EF_NEEDNORMALS)) return; if (m_RP.m_ObjFlags & FOB_FOGPASS) return; //PROFILE_FRAME(State_LightStates); // Use fake lighting with TFactor if (!m_RP.m_NumActiveDLights) { EF_ConstantLightMaterial(lm, Flags); return; } if (!(Flags & LMF_IGNORELIGHTS) && EF_SetLights(Flags)) { if (!(m_RP.m_CurrentVLights & 0xff)) { EF_ConstantLightMaterial(lm, Flags); return; } m_RP.m_FlagsPerFlush &= ~(RBSI_GLOBALRGB | RBSI_GLOBALALPHA); CFColor colAmb = EF_GetCurrentAmbient(lm, Flags); CFColor colDif = EF_GetCurrentDiffuse(lm, Flags); CFColor colSpec = lm->Front.m_Specular; float fPow = lm->Front.m_SpecShininess; if (Flags & LMF_NOSPECULAR) { fPow = 0; colSpec = Col_Black; } glMaterialfv(GL_FRONT, GL_AMBIENT, &colAmb[0]); glMaterialfv(GL_FRONT, GL_DIFFUSE, &colDif[0]); glMaterialfv(GL_FRONT, GL_SPECULAR, &colSpec[0]); glMaterialf(GL_FRONT, GL_SHININESS, fPow); } m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Diffuse<<3); m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Diffuse<<3); m_RP.m_CurrentVLights |= 0x80000000; } //=================================================================================================== // Calculate matrices (usually texture matrices) for fixed pipeline shaders // Set texture transform modes void CGLRenderer::EF_ApplyMatrixOps(TArray* MatrixOps, bool bEnable) { if (!MatrixOps) return; int CurMatrix = GL_MODELVIEW; int PrevStage = m_TexMan->m_CurStage; int PrevStage1 = PrevStage; for (int i=0; iNum(); i++) { SMatrixTransform *mt = &MatrixOps->Get(i); if (mt->m_Stage != PrevStage) { PrevStage = mt->m_Stage; EF_SelectTMU(mt->m_Stage); } if (mt->m_Matrix != CurMatrix) { glMatrixMode(mt->m_Matrix); if (!bEnable && mt->m_Matrix != GL_PROJECTION && mt->m_Matrix != GL_MODELVIEW) glLoadIdentity(); CurMatrix = mt->m_Matrix; } if (mt->m_Stage != PrevStage) { PrevStage = mt->m_Stage; EF_SelectTMU(mt->m_Stage); if (!bEnable && mt->m_Matrix != GL_PROJECTION && mt->m_Matrix != GL_MODELVIEW) glLoadIdentity(); } mt->mfSet(bEnable); } EF_SelectTMU(PrevStage1); if (CurMatrix != GL_MODELVIEW) glMatrixMode(GL_MODELVIEW); } // Set/Restore shader resources overrided states bool CGLRenderer::EF_SetResourcesState(bool bSet) { if (m_RP.m_pShader->m_Flags2 & EF2_IGNORERESOURCESTATES) return true; bool bRes = true; if (bSet) { if (m_RP.m_pShaderResources->m_ResFlags & MTLFLAG_2SIDED) { GLSetCull(eCULL_None); m_RP.m_FlagsPerFlush |= RBSI_NOCULL; } if (m_RP.m_pShaderResources->m_AlphaRef) { if (!(m_CurState & GS_ALPHATEST_MASK)) glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, m_RP.m_pShaderResources->m_AlphaRef); m_RP.m_FlagsPerFlush |= RBSI_ALPHATEST; } else if (m_RP.m_pShaderResources->m_Opacity != 1.0f) { int State = m_CurState &= ~GS_BLEND_MASK; byte bCol = (byte)(m_RP.m_pShaderResources->m_Opacity*255.0f); if (m_RP.m_pShaderResources->m_ResFlags & MTLFLAG_ADDITIVE) { State |= GS_BLSRC_ONE | GS_BLDST_ONE; State &= ~GS_DEPTHWRITE; m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB; m_RP.m_NeedGlobalColor.bcolor[0] = bCol; m_RP.m_NeedGlobalColor.bcolor[1] = bCol; m_RP.m_NeedGlobalColor.bcolor[2] = bCol; } else { State |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA; State &= ~GS_DEPTHWRITE; m_RP.m_FlagsPerFlush |= RBSI_GLOBALALPHA; m_RP.m_NeedGlobalColor.bcolor[3] = bCol; } EF_SetState(State); m_RP.m_ResourceState = State; m_RP.m_fCurOpacity = m_RP.m_pShaderResources->m_Opacity; m_RP.m_FlagsPerFlush |= RBSI_ALPHABLEND | RBSI_DEPTHWRITE | RBSI_ALPHAGEN; m_RP.m_ObjFlags &= ~FOB_LIGHTPASS; } } else { if (m_RP.m_pShaderResources->m_AlphaRef) { switch (m_CurState & GS_ALPHATEST_MASK) { case GS_ALPHATEST_GREATER0: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); break; case GS_ALPHATEST_LESS128: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_LESS, 0.5f); break; case GS_ALPHATEST_GEQUAL128: glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.5f); break; default: glDisable(GL_ALPHA_TEST); break; } } } return true; } // Set overrided shader states from State shader void CGLRenderer::EF_SetStateShaderState() { SShader *ef = m_RP.m_pStateShader; SEfState *st = ef->m_State; if (st->m_bClearStencil) { if (CV_r_measureoverdraw) { iLog->Log("Stencil shadows and overdraw measurement are mutually exclusive\n"); CV_r_measureoverdraw = 0; } glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); } if (st->m_Stencil) { st->m_Stencil->mfSet(); } if (st->m_Flags & ESF_POLYLINE) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (st->m_Flags & ESF_NOCULL) { GLSetCull(eCULL_None); m_RP.m_FlagsPerFlush |= RBSI_NOCULL; } else if (st->m_Flags & ESF_CULLFRONT) { GLSetCull(eCULL_Front); m_RP.m_FlagsPerFlush |= RBSI_NOCULL; } if (st->m_Flags & ESF_STATE) { EF_SetState(st->m_State); if (st->m_State & GS_NODEPTHTEST) m_RP.m_FlagsPerFlush |= RBSI_DEPTHTEST; if (st->m_State & (GS_DEPTHFUNC_EQUAL | GS_DEPTHFUNC_GREAT)) m_RP.m_FlagsPerFlush |= RBSI_DEPTHFUNC; } bool bSetCol = false; UCol Col; Col.dcolor = 0; if (st->m_Flags & ESF_RGBGEN) { m_RP.m_FlagsPerFlush |= RBSI_RGBGEN; switch (st->m_eEvalRGB) { case eERGB_Fixed: Col.bcolor[0] = st->m_FixedColor[0]; Col.bcolor[1] = st->m_FixedColor[1]; Col.bcolor[2] = st->m_FixedColor[2]; Col.bcolor[3] = st->m_FixedColor[3]; break; } bSetCol = true; } if (st->m_Flags & ESF_ALPHAGEN) { m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN; switch (st->m_eEvalAlpha) { case eEALPHA_Fixed: Col.bcolor[3] = st->m_FixedColor[3]; break; } bSetCol = true; } if (bSetCol) { Exchange(Col.bcolor[0], Col.bcolor[3]); m_RP.m_NeedGlobalColor = Col; } if (st->m_Flags & ESF_COLORMASK) { m_RP.m_FlagsPerFlush |= RBSI_COLORMASK; glColorMask(st->m_ColorMask[0], st->m_ColorMask[1], st->m_ColorMask[2], st->m_ColorMask[3]); } } // Reset overrided shader states from State shader void CGLRenderer::EF_ResetStateShaderState() { SShader *ef = m_RP.m_pStateShader; SEfState *st = ef->m_State; if (st->m_Flags & ESF_COLORMASK) glColorMask(1, 1, 1, 1); if (st->m_Flags & ESF_POLYLINE) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #include "../Common/NvTriStrip/NVTriStrip.h" // Used for HW effectors for rendering of tri mesh (vertex array) void CGLRenderer::EF_DrawIndexedMesh (int nPrimType) { //PROFILE_FRAME(Draw_IndexMesh); int nType = -1; switch (nPrimType) { case R_PRIMV_TRIANGLES: nType = GL_TRIANGLES; m_nPolygons += (m_RP.m_RendNumIndices / 3); break; case R_PRIMV_TRIANGLE_STRIP: nType = GL_TRIANGLE_STRIP; m_nPolygons += (m_RP.m_RendNumIndices - 2); break; case R_PRIMV_TRIANGLE_FAN: nType = GL_TRIANGLE_FAN; m_nPolygons += (m_RP.m_RendNumIndices - 2); break; case R_PRIMV_QUADS: nType = GL_QUADS; m_nPolygons += (m_RP.m_RendNumIndices / 2); break; case R_PRIMV_MULTI_STRIPS: { list2 *mats = m_RP.m_pRE->mfGetMatInfoList(); if (mats) { CMatInfo *m = mats->Get(0); //assert(m_RP.m_RendIndices[0]<60000); for (int i=0; iCount(); i++, m++) { glDrawElements(GL_TRIANGLE_STRIP, m->nNumIndices, GL_UNSIGNED_SHORT, &m_RP.m_RendIndices[m->nFirstIndexId]); m_nPolygons += (m->nNumIndices - 2); } } return; } case R_PRIMV_MULTI_GROUPS: { CMatInfo *mi = m_RP.m_pRE->mfGetMatInfo(); if (mi) { for (int i=0; im_dwNumSections; i++) { SPrimitiveGroup *g = &mi->m_pPrimitiveGroups[i]; switch (g->type) { case PT_STRIP: glDrawElements(GL_TRIANGLE_STRIP, g->numIndices, GL_UNSIGNED_SHORT, &m_RP.m_RendIndices[g->offsIndex]); break; case PT_LIST: glDrawElements(GL_TRIANGLES, g->numIndices, GL_UNSIGNED_SHORT, &m_RP.m_RendIndices[g->offsIndex]); break; case PT_FAN: glDrawElements(GL_TRIANGLE_FAN, g->numIndices, GL_UNSIGNED_SHORT, &m_RP.m_RendIndices[g->offsIndex]); break; } m_nPolygons += g->numTris; } } return; } break; default: iLog->Log("WARNING: CGLRenderer::EF_DrawIndexedMesh: Unknown primitive type %d\n"); return; } if (nType >= 0) { if(m_RP.m_RendNumIndices) glDrawElements(nType, m_RP.m_RendNumIndices, GL_UNSIGNED_SHORT, m_RP.m_RendIndices); else { static int tic=10; // variable will be removed when this problem will be fixed if(tic>0) { iLog->Log("CGLRenderer::EF_DrawIndexedMesh: m_RP.mRendNumIndices (Shader: '%s')", m_RP.m_pShader->GetName()); tic--; } } } } bool CGLRenderer::EF_PreDraw(SShaderPass *slw) { bool bRet = true; if (!m_RP.m_pRE && m_RP.m_RendNumVerts && m_RP.m_RendNumIndices) { // Mergable geometry (no single render element) int nStart; int nCurVB; int nSize = m_RP.m_Stride*m_RP.m_RendNumVerts; if (!(m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED)) { m_RP.m_FlagsPerFlush |= RBSI_VERTSMERGED; int nFormat = m_RP.m_CurVFormat; nCurVB = m_RP.m_CurVB; if (VB_BytesOffset(nCurVB)+nSize >= VB_BytesCount(nCurVB)) { VB_Reset(nCurVB); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; byte *pVB = VB_Lock(nCurVB, nSize, nStart); cryMemcpy(pVB, m_RP.m_Ptr.Ptr, nSize); VB_Unlock(nCurVB); m_RP.m_FirstVertex = 0; m_RP.m_MergedStreams[0] = nCurVB; m_RP.m_nStreamOffset[0] = nStart; if (SUPPORTS_GL_ARB_vertex_buffer_object) { // Update indices int sizeI = m_RP.m_RendNumIndices*sizeof(ushort); int nOffsetI; if (sizeI+m_RP.m_IBDynOffs > m_RP.m_IBDynSize) { nOffsetI = 0; m_RP.m_IBDynOffs = sizeI; } else { nOffsetI = m_RP.m_IBDynOffs; m_RP.m_IBDynOffs += sizeI; } { PROFILE_FRAME(Mesh_UpdateIBuffersDynMerge); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_RP.m_IBDyn.m_VertBuf.m_nID); glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, nOffsetI, sizeI, m_RP.m_SysRendIndices); } m_RP.m_RendIndices = (ushort *)(nOffsetI); m_RP.m_FlagsPerFlush |= RBSI_INDEXSTREAM; } } VB_Bind(0); if (m_RP.m_FlagsModificators & FHF_TANGENTS) { if (!(m_RP.m_FlagsPerFlush & RBSI_TANGSMERGED)) { m_RP.m_FlagsPerFlush |= RBSI_TANGSMERGED; int i; int nCurVB = m_RP.m_CurVB; int nSize = m_RP.m_RendNumVerts*sizeof(SPipTangents); if (VB_BytesOffset(nCurVB)+nSize >= VB_BytesCount(nCurVB)) { VB_Reset(nCurVB); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; SPipTangents *dst = (SPipTangents *)VB_Lock(nCurVB, nSize, nStart); for (i=0; im_pBuffer; CMatInfo *mi = re->m_pChunk; SPipTangents *src = (SPipTangents *)lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData; src += mi->nFirstVertId; int nVerts = mi->nNumVerts; if (obj->m_ObjFlags & FOB_TRANS_ROTATE) { Matrix44 *mat = &obj->m_Matrix; #ifdef DO_ASM _asm { mov ecx, nVerts; mov eax, mat mov esi, src mov edi, dst movaps xmm2,xmmword ptr [eax] movaps xmm4,xmmword ptr [eax+10h] movaps xmm6,xmmword ptr [eax+20h] align 16 _Loop: movlps xmm1,qword ptr [esi] movss xmm0,dword ptr [esi+8] shufps xmm0,xmm0,0 prefetcht0 [esi+10h] mulps xmm0,xmm6 movaps xmm3,xmm1 shufps xmm3,xmm1,55h mulps xmm3,xmm4 shufps xmm1,xmm1,0 mulps xmm1,xmm2 addps xmm3,xmm1 addps xmm3,xmm0 movhlps xmm5,xmm3 movlps qword ptr [edi],xmm3 movss xmm0,dword ptr [esi+20] movss dword ptr [edi+8],xmm5 movlps xmm1,qword ptr [esi+12] shufps xmm0,xmm0,0 mulps xmm0,xmm6 prefetcht0 [esi+20h] movaps xmm3,xmm1 shufps xmm3,xmm1,55h mulps xmm3,xmm4 shufps xmm1,xmm1,0 mulps xmm1,xmm2 addps xmm3,xmm1 addps xmm3,xmm0 movhlps xmm5,xmm3 movlps qword ptr [edi+12],xmm3 movss xmm0,dword ptr [esi+32] movss dword ptr [edi+20],xmm5 movlps xmm1,qword ptr [esi+24] shufps xmm0,xmm0,0 prefetcht0 [esi+30h] mulps xmm0,xmm6 movaps xmm3,xmm1 shufps xmm3,xmm1,55h mulps xmm3,xmm4 shufps xmm1,xmm1,0 mulps xmm1,xmm2 addps xmm1,xmm3 addps xmm0,xmm1 add esi, 36 movhlps xmm1,xmm0 movlps qword ptr [edi+24],xmm0 movss dword ptr [edi+32],xmm1 add edi, 36 dec ecx jne _Loop mov dst, edi } #else for (int j=0; jnNumVerts; j++) { dst->m_Tangent = mat->TransformVectorOLD(src->m_Tangent); dst->m_Binormal = mat->TransformVectorOLD(src->m_Binormal); dst->m_TNormal = mat->TransformVectorOLD(src->m_TNormal); src++; dst++; } #endif } else { for (i=0; inNumVerts; i++) { *dst = *src; src++; dst++; } } } VB_Unlock(nCurVB); m_RP.m_MergedStreams[1] = nCurVB; m_RP.m_nStreamOffset[1] = nStart; } VB_Bind(1); } if (m_RP.m_FlagsModificators & RBMF_LMTCUSED) { if (!(m_RP.m_FlagsPerFlush & RBSI_LMTCMERGED)) { m_RP.m_FlagsPerFlush |= RBSI_LMTCMERGED; nSize = sizeof(struct_VERTEX_FORMAT_TEX2F)*m_RP.m_RendNumVerts; int nCurVB = m_RP.m_CurVB; if (VB_BytesOffset(nCurVB)+nSize >= VB_BytesCount(nCurVB)) { VB_Reset(nCurVB); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; struct_VERTEX_FORMAT_TEX2F *dst = (struct_VERTEX_FORMAT_TEX2F *)VB_Lock(nCurVB, nSize, nStart); for (int i=0; im_pChunk->nNumVerts; if (!pObj->m_pLMTCBufferO) { dst += nNumVerts; continue; } struct_VERTEX_FORMAT_TEX2F *src = (struct_VERTEX_FORMAT_TEX2F *)pObj->m_pLMTCBufferO->m_pSecVertBuffer->m_VS[0].m_VData; src += re->m_pChunk->nFirstVertId; for (int n=0; nmfPreDraw(slw); EF_CommitPS(); EF_CommitVS(); EF_CommitStreams(); EF_CommitVLights(); return bRet; } // Draw detail textures passes (used in FP shaders and in programmable pipeline shaders) void CGLRenderer::EF_DrawDetailOverlayPasses() { // Usually it means first pass in indoor engine (before shadow pass) if (m_RP.m_ObjFlags & FOB_ZPASS) return; if (!m_RP.m_pShaderResources || !m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY]) return; SEfResTexture *rt = m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY]; SShader *sh = m_RP.m_pShader; int i; SParamComp_FogMatrix FM; vec4_t Vals; float fDistToCam = 500.0f; float fDist = CV_r_detaildistance; static TArray sbNeedRender; if (m_RP.m_pRE) { #ifndef PIPE_USE_INSTANCING fDistToCam = m_RP.m_pRE->mfMinDistanceToCamera(m_RP.m_pCurObject); if (fDistToCam > fDist+1.0f) return; #else CCObject *pObj = gRenDev->m_RP.m_pCurObject; int nObj = 0; float fDistToCam = 999999.0f; sbNeedRender.SetUse(0); while (true) { float fDistObj = m_RP.m_pRE->mfMinDistanceToCamera(pObj); if (fDistObj <= fDist+1.0f) sbNeedRender.AddElem(true); else sbNeedRender.AddElem(false); fDistToCam = min(fDistToCam, fDistObj); nObj++; if (nObj >= gRenDev->m_RP.m_MergedObjects.Num()) break; pObj = gRenDev->m_RP.m_MergedObjects[nObj]; } if (fDistToCam > fDist+1.0f) return; glPushMatrix(); #endif } else return; PROFILE_FRAME(DrawShader_DetailPasses); CGLTexMan::BindNULL(2); EF_SelectTMU(1); gRenDev->m_TexMan->m_Text_Fog->Set(); EnableTMU(true); EF_SelectTMU(0); rt->m_TU.m_TexPic->Set(); if (m_RP.m_FlagsPerFlush & RBSI_WASDEPTHWRITE) EF_SetState(GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL | GS_DEPTHFUNC_EQUAL); else EF_SetState(GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL); SMFog fg; SMFog *fb = m_RP.m_pFogVolume; fg.m_FogInfo.m_WaveFogGen.m_eWFType = eWF_None; m_RP.m_pFogVolume = &fg; m_RP.m_CurrentVLights = 0; m_RP.m_FlagsModificators &= ~(7 | (RBMF_TCM | RBMF_TCG)); EF_Scissor(false, 0, 0, 0, 0); if (!(sh->m_Flags & EF_HASVSHADER)) { m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; SArrayPointer_Vertex vpv; SArrayPointer_Texture vpt; vpv.ePT = eSrcPointer_Vert; vpv.eDst = eDstPointer_Vert; vpv.NumComponents = 3; vpv.Type = GL_FLOAT; vpv.mfSet(1); vpt.ePT = eSrcPointer_Tex; vpt.eDst = eDstPointer_Tex0; vpt.NumComponents = 2; vpt.Type = GL_FLOAT; vpt.mfSet(1); int n = CLAMP(CV_r_detailnumlayers, 1, 4); float fUScale = rt->m_TexModificator.m_Tiling[0]; float fVScale = rt->m_TexModificator.m_Tiling[1]; if (!fUScale) fUScale = CV_r_detailscale; if (!fVScale) fVScale = CV_r_detailscale; for (i=0; imfSet(true); // Draw primitives EF_Draw(sh, NULL); #else int bFogOverrided = 0; EF_PreDraw(NULL); if (m_FS.m_bEnable) bFogOverrided = EF_FogCorrection(false, false); if (m_Features & (RFT_HW_RC | RFT_HW_PS20)) { if (!m_RP.m_RCDetail) m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten"); if (m_RP.m_RCDetail) m_RP.m_RCDetail->mfSet(true); EF_CommitPS(); } else { m_RP.m_CurGlobalColor.dcolor = 0xff808080; EF_SelectTMU(0); EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, DEF_TEXARG0, DEF_TEXARG0); EF_SelectTMU(1); EF_SetColorOp(eCO_BLENDTEXTUREALPHA, eCO_REPLACE, eCA_Constant|(eCA_Previous<<3), DEF_TEXARG0); } CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; int nObj = 0; while (true) { if (sbNeedRender[nObj]) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; m_RP.m_FrameObject++; pObj = m_RP.m_pCurObject; EF_SetObjectTransform(pObj, sh, pObj->m_ObjFlags); } EF_SelectTMU(1); FM.m_Offs = 0; FM.mfGet4f(Vals); glTexGenfv(GL_S, GL_OBJECT_PLANE, Vals); FM.m_Offs = 1; FM.mfGet4f(Vals); glTexGenfv(GL_T, GL_OBJECT_PLANE, Vals); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); EF_SelectTMU(0); { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(sh, NULL); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; EF_SetObjectTransform(m_RP.m_pCurObject, sh, pSaveObj->m_ObjFlags); } #endif fDist /= 2.0f; if (fDistToCam > fDist+1.0f) break; fUScale *= 2.0f; fVScale *= 2.0f; } glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); EF_SelectTMU(1); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); EF_SelectTMU(0); } else { float param[4]; if (!m_RP.m_VPDetail) m_RP.m_VPDetail = CVProgram::mfForName("CGVProgDetail"); if (!m_RP.m_RCDetail) m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten"); if (m_RP.m_RCDetail) m_RP.m_RCDetail->mfSet(true); CCGVProgram_GL *vpGL = (CCGVProgram_GL *)m_RP.m_VPDetail; vpGL->mfSet(true, NULL, VPF_DONTSETMATRICES | VPF_SETPOINTERSFORSHADER); vpGL->mfSetVariables(false, NULL); SCGBind *pBindScale = vpGL->mfGetParameterBind("DetailScaling"); SCGBind *pBindTG0 = vpGL->mfGetParameterBind("TexGen00"); SCGBind *pBindTG1 = vpGL->mfGetParameterBind("TexGen01"); int n = CLAMP(CV_r_detailnumlayers, 1, 4); float fUScale = rt->m_TexModificator.m_Tiling[0]; float fVScale = rt->m_TexModificator.m_Tiling[1]; if (!fUScale) fUScale = CV_r_detailscale; if (!fVScale) fVScale = CV_r_detailscale; for (i=0; imfParameter4f(pBindScale, param); #ifndef PIPE_USE_INSTANCING FM.m_Offs = 0; FM.mfGet4f(Vals); if (pBindTG0) vpGL->mfParameter4f(pBindTG0, Vals); FM.m_Offs = 1; FM.mfGet4f(Vals); if (pBindTG1) vpGL->mfParameter4f(pBindTG1, param); // Draw primitives EF_Draw(sh, NULL); #else int bFogOverrided = 0; EF_PreDraw(NULL); if (m_FS.m_bEnable) bFogOverrided = EF_FogCorrection(false, false); CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; int nObj = 0; while (true) { if (sbNeedRender[nObj]) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; m_RP.m_FrameObject++; pObj = m_RP.m_pCurObject; } FM.m_Offs = 0; FM.mfGet4f(Vals); if (pBindTG0) vpGL->mfParameter4f(pBindTG0, Vals); FM.m_Offs = 1; FM.mfGet4f(Vals); if (pBindTG1) vpGL->mfParameter4f(pBindTG1, Vals); vpGL->mfSetVariables(true, NULL); vpGL->mfSetStateMatrices(); { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(sh, NULL); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; } #endif fDist /= 2.0f; if (fDistToCam > fDist+1.0f) break; fUScale *= 2.0f; fVScale *= 2.0f; } } CGLTexMan::BindNULL(0); gRenDev->m_RP.m_pFogVolume = fb; #ifdef PIPE_USE_INSTANCING glPopMatrix(); #endif } void CGLRenderer::EF_DrawFogOverlayPasses() { // Usually it means first pass in indoor engine (before shadow pass) if (m_RP.m_ObjFlags & FOB_ZPASS) return; if (m_RP.m_FlagsPerFlush & RBSI_FOGVOLUME) return; if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "--- Fog Pass ---\n"); float fWatLevel = iSystem->GetI3DEngine()->GetWaterLevel(); SMFog *fb = m_RP.m_pFogVolume; SShader *sh = NULL; bool bVFFP = false; if (!(m_Features & RFT_HW_VS) || CV_r_Quality_BumpMapping == 0) bVFFP = true; if (!bVFFP || (m_RP.m_pShader->m_Flags & EF_HASVSHADER)) { if (m_RP.m_pShader->m_eSort != eS_Water && fabs(fb->m_Dist-fWatLevel) < 0.1f && SRendItem::m_RecurseLevel <= 1) { if (m_RP.m_pRE) { float fDist; #ifndef PIPE_USE_INSTANCING fDist = m_RP.m_pRE->mfMinDistanceToCamera(m_RP.m_pCurObject); #else CCObject *pObj = m_RP.m_pCurObject; int nObj = 0; fDist = 999999.0f; while (true) { fDist = min(fDist, m_RP.m_pRE->mfMinDistanceToCamera(pObj)); nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; pObj = m_RP.m_MergedObjects[nObj]; } #endif if (fDist < 40.0f) sh = m_cEF.m_ShaderFogCaust; else sh = m_cEF.m_ShaderFog; } else sh = gRenDev->m_cEF.m_ShaderFogCaust; } else sh = gRenDev->m_cEF.m_ShaderFog; } else sh = m_cEF.m_ShaderFog_FP; if (sh && sh->m_HWTechniques.Num()) { if (m_RP.m_pShader->m_eSort == eS_Water && m_RP.m_pFogVolume) m_RP.m_pFogVolume->m_Dist += 0.1f; EF_DrawGeneralPasses(sh->m_HWTechniques[0], sh, true, 0, sh->m_HWTechniques[0]->m_Passes.Num()-1); if (m_RP.m_pShader->m_eSort == eS_Water && m_RP.m_pFogVolume) m_RP.m_pFogVolume->m_Dist -= 0.1f; } } // Draw light passes (up to 4 light sources per single pass) void CGLRenderer::EF_DrawLightPasses_PS30(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd) { SShaderPassHW *slw; int i; m_RP.m_nCurLight = 0; CVProgram *curVP = NULL; PROFILE_FRAME(DrawShader_LightPasses_PS30); int nLight; int nLights = m_RP.m_NumActiveDLights; // make sure for each pass not more then 1 projected light if (gRenDev->m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED) { int nnn = 0; } int nStencState = 0; bool bStencState = m_RP.m_pStateShader && m_RP.m_pStateShader->m_State && m_RP.m_pStateShader->m_State->m_Stencil; slw = &hs->m_Passes[nStart]; CDLight *ProjLights[16]; int nProjLights = 0; CDLight *OtherLights[16]; int nOtherLights = 0; CDLight *StencLights[16]; int nStencLights = 0; bool bHasLM = m_RP.m_pCurObject->m_nLMId != 0; bool bHasAmb = ((m_RP.m_ObjFlags & FOB_LIGHTPASS) == 0); for (nLight=0; nLightm_Flags & DLF_LM) && (slw->m_LMFlags & LMF_NOSPECULAR)) continue; if (bStencState && (dl->m_Flags & DLF_CASTSHADOW_VOLUME)) StencLights[nStencLights++] = dl; else if (dl->m_Flags & DLF_PROJECT) ProjLights[nProjLights++] = dl; else OtherLights[nOtherLights++] = dl; } if (!bHasAmb && !nOtherLights && !nProjLights && !nStencLights) return; float fFP = 0.334f; float fFO = 1.0f; int nO = 0; int nP = 0; float fO = 0; float fP = 0; int nAmbLights = NUM_PPLIGHTS_PERPASS_PS30; if (bHasAmb) { for (i=nStart; i<=nEnd; i++, slw++) { if (slw->m_LMFlags & LMF_HASAMBIENT) { if (slw->m_LMFlags & LMF_HASDOT3LM) { if (!m_RP.m_pShaderResources || !m_RP.m_pCurObject->m_nLMDirId) continue; } } break; } nAmbLights = slw->m_nAmbMaxLights; } slw = &hs->m_Passes[nStart]; for (i=0; i= nProjLights && nO >= nOtherLights) { if (!i && bHasAmb) { m_RP.m_LPasses[0].nLights = 0; m_RP.m_LPasses[0].nProjectors = 0; i++; } break; } m_RP.m_LPasses[i].nLights = 0; m_RP.m_LPasses[i].nProjectors = 0; int j = 0; while (true) { fO += fFO; if ((int)fO >= nO+1 && nO < nOtherLights) { m_RP.m_LPasses[i].nLights++; m_RP.m_LPasses[i].pLights[j] = OtherLights[nO]; j++; nO++; } if (m_RP.m_LPasses[i].nProjectors == 0) { fP += fFP; if ((int)fP >= nP+1 && nP < nProjLights) { m_RP.m_LPasses[i].nLights++; m_RP.m_LPasses[i].nProjectors++; m_RP.m_LPasses[i].pLights[j] = ProjLights[nP]; j++; nP++; } } else { if (nO >= nOtherLights) break; } if (nP >= nProjLights && nO >= nOtherLights) break; if (j == nAmbLights) { if (nAmbLights != NUM_PPLIGHTS_PERPASS_PS30) nAmbLights = NUM_PPLIGHTS_PERPASS_PS30; break; } } } int nPasses = i; int nPass; m_RP.m_nCurLight = 0; m_RP.m_PersFlags |= RBPF_MULTILIGHTS; for (nPass=0; nPassnLights; m_RP.m_pCurLight = NULL; int Types[4]; bool bUseOccl = false; for (i=0; inLights; i++) { CDLight *dl = lp->pLights[i]; if (dl->m_Flags & DLF_POINT) Types[i] = SLMF_POINT; else if (dl->m_Flags & DLF_PROJECT) { Types[i] = SLMF_PROJECTED; m_RP.m_pCurLight = dl; } else Types[i] = SLMF_DIRECT; if ((dl->m_Flags & DLF_LM) && bHasLM) { Types[i] |= SLMF_ONLYSPEC; if (*(int *)m_RP.m_pCurObject->m_OcclLights != 0) { byte nLight = dl->m_Id+1; if (m_RP.m_pCurObject->m_OcclLights[0] == nLight || m_RP.m_pCurObject->m_OcclLights[1] == nLight || m_RP.m_pCurObject->m_OcclLights[2] == nLight || m_RP.m_pCurObject->m_OcclLights[3] == nLight) { Types[i] |= SLMF_SPECOCCLUSION; bUseOccl = true; } } } } switch(lp->nLights) { case 2: if (Types[0] > Types[1]) { Exchange(Types[0], Types[1]); Exchange(lp->pLights[0], lp->pLights[1]); } break; case 3: if (Types[0] > Types[1]) { Exchange(Types[0], Types[1]); Exchange(lp->pLights[0], lp->pLights[1]); } if (Types[0] > Types[2]) { Exchange(Types[0], Types[2]); Exchange(lp->pLights[0], lp->pLights[2]); } if (Types[1] > Types[2]) { Exchange(Types[1], Types[2]); Exchange(lp->pLights[1], lp->pLights[2]); } break; case 4: { for (int i=0; i<4; i++) { for (int j=i; j<4; j++) { if (Types[i] > Types[j]) { Exchange(Types[i], Types[j]); Exchange(lp->pLights[i], lp->pLights[j]); } } } } break; } for (i=0; inLights; i++) { m_RP.m_ShaderLightMask |= Types[i] << (SLMF_LTYPE_SHIFT + i*4); } if (lp->nLights == 1 && bStencState) { nStencState = (lp->pLights[0]->m_Flags & DLF_CASTSHADOW_VOLUME) ? GS_STENCIL : 0; } for (i=nStart; i<=nEnd; i++, slw++) { m_RP.m_CurrPass = slw; m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); if (slw->m_LMFlags & LMF_HASAMBIENT) { if (nPass || !bHasAmb) continue; if (slw->m_LMFlags & LMF_HASDOT3LM) { if (!m_RP.m_pShaderResources || !m_RP.m_pCurObject->m_nLMDirId) continue; } } if ((slw->m_LMFlags & LMF_USEOCCLUSIONMAP) && !bUseOccl) continue; EF_Eval_TexGen(slw); EF_Eval_RGBAGen(slw); EF_SetVertexStreams(slw->m_Pointers, 1); // Set all textures and HW TexGen modes for the current pass (ShadeLayer) curVP = slw->m_VProgram; if (curVP) m_RP.m_FlagsPerFlush |= RBSI_USEVP; if (slw->mfSetTextures()) { if (curVP) curVP->mfSet(true, slw, VPF_DONTSETMATRICES); EF_ApplyMatrixOps(slw->m_MatrixOps, true); if (curVP) { #ifndef PIPE_USE_INSTANCING curVP->mfSetStateMatrices(); #endif curVP->mfSetVariables(false, &slw->m_VPParamsNoObj); } else { m_RP.m_CurrentVLights = 0; m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; } // Set Pixel shaders and Register combiners for the current pass if (slw->m_FShader) slw->m_FShader->mfSet(true, slw); else m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET; int State; if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS)) State = slw->m_SecondRenderState; else State = slw->m_RenderState; EF_SetState(State | nStencState); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [%d Lights]\n", m_RP.m_RendPass, m_RP.m_nCurLights); #endif EF_Scissor(false, 0, 0, 0, 0); EF_Draw(ef, slw); m_RP.m_RendPass++; #else //PIPE_USE_INSTANCING m_RP.m_RendPass++; int bFogOverrided = 0; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); bool bFogDisable = (curVP && (curVP->m_Flags & VPFI_NOFOG)) || (m_RP.m_PersFlags & RBPF_HDR); bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY)); bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; SArrayPointer_Texture pt; pt.ePT = eSrcPointer_TexLM; pt.Stage = m_RP.m_nLMStage; pt.Type = GL_FLOAT; pt.NumComponents = 2; while (true) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; m_RP.m_FrameObject++; pObj = m_RP.m_pCurObject; if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED)) { if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer) pt.mfSet(1); } if (!curVP) { EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags); m_RP.m_CurrentVLights = 0; if (m_RP.m_FrameGTC == m_RP.m_Frame) { for (int nt=0; ntm_TexMan->m_nCurStages; nt++) { if (m_RP.m_pGTC[nt]) { EF_SelectTMU(nt); m_RP.m_pGTC[nt]->mfSet(true); } } } } } EF_Scissor(false, 0, 0, 0, 0); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [%d Lights] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, lp->nLights, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif if (curVP) { curVP->mfSetStateMatrices(); curVP->mfSetVariables(true, &slw->m_VPParamsObj); } // Set per-object alpha-blending if (pObj->m_ObjFlags & FOB_HASALPHA) pObj->SetAlphaState(slw->m_FShader, State); if (slw->m_FShader) slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj); else { if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject) { float *vals = slw->m_RGBComps->mfGet(); UCol color; color.bcolor[2] = (byte)(vals[0] * 255.0f); color.bcolor[1] = (byte)(vals[1] * 255.0f); color.bcolor[0] = (byte)(vals[2] * 255.0f); color.bcolor[3] = (byte)(vals[3] * 255.0f); m_RP.m_NeedGlobalColor = color; } EF_CommitTexStageState(); } { //PROFILE_FRAME(Draw_ShaderIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (!CVProgram::m_LastVP) { if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); } else m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG); if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; if (!curVP) EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags); } #endif } slw->mfResetTextures(); EF_ApplyMatrixOps(slw->m_MatrixOps, false); break; } } m_RP.m_ShaderLightMask = 0; m_RP.m_nCurLightPass = 0; m_RP.m_PersFlags &= ~RBPF_MULTILIGHTS; } // Draw light passes - for each light source (used in FP shaders and in programmable pipeline shaders) void CGLRenderer::EF_DrawLightPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd) { int i, l; int nl = 0; int n; CVProgram *curVP = NULL; CVProgram *newVP; // Just single pass for transparent objects if (m_RP.m_RendPass && m_RP.m_fCurOpacity != 1.0f) return; PROFILE_FRAME(DrawShader_LightPasses); int nStencState = 0; bool bStencState = m_RP.m_pStateShader && m_RP.m_pStateShader->m_State && m_RP.m_pStateShader->m_State->m_Stencil; // For each light source for (l=0; lm_Id; SShaderPassHW* slw = &hs->m_Passes[nStart]; nl++; // Ignore diffuse passes for specular only light sources if ((m_RP.m_pCurLight->m_Flags & DLF_LM) && slw->m_ePassType == eSHP_DiffuseLight) { if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) || m_RP.m_pCurObject->m_nLMId) continue; } if (bStencState) nStencState = (m_RP.m_pCurLight->m_Flags & DLF_CASTSHADOW_VOLUME) ? GS_STENCIL : 0; bool bOnlyLightPass; bool bShadowMask = false; n = 0; SArrayPointer::m_LastEnabledPass = 0; bool bBreak = false; // For each layer/pass for (i=nStart; i<=nEnd; i++, slw++) { int msk; // Check light type and filter passes if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK)) { if (!(msk & (m_RP.m_pCurLight->m_Flags & DLF_LIGHTTYPE_MASK))) continue; // If light type doesn't match pass type ignore this pass if (slw->m_LMFlags & LMF_USEOCCLUSIONMAP) { if (*(int *)m_RP.m_pCurObject->m_OcclLights == 0) continue; } // If we have only-specular pass and no LM on surface ignore this pass if (slw->m_LightFlags & DLF_LM) { if (!(m_RP.m_pCurLight->m_Flags & DLF_LM)) continue; if ((!m_RP.m_pShaderResources || !m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) && !m_RP.m_pCurObject->m_nLMId) continue; assert (m_RP.m_pCurLight->m_SpecColor.r!=0 || m_RP.m_pCurLight->m_SpecColor.g!=0 || m_RP.m_pCurLight->m_SpecColor.b!=0); // Ignore specular pass if specular is less threshold if (m_RP.m_pCurLight->m_SpecColor.r<=0.01f && m_RP.m_pCurLight->m_SpecColor.g<=0.01f && m_RP.m_pCurLight->m_SpecColor.b<=0.01f) continue; } } if (slw->m_LMFlags & LMF_NOBUMP) { if (m_RP.m_pShaderResources && (!m_RP.m_pShaderResources->m_Textures[EFTT_BUMP] || !(m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_nFlags & FTU_NOBUMP))) continue; bBreak = true; } else if (bBreak) break; if (EF_RejectLightPass(slw)) continue; bOnlyLightPass = EF_IsOnlyLightPass(slw); if (CV_r_bumpselfshadow && bOnlyLightPass && m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP] && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic->m_pSH) { EF_DrawLightShadowMask(l); curVP = NULL; bShadowMask = true; } if (!n) { if (!(m_RP.m_StatLightMask & (1<mfApply(slw->m_LMFlags | (l<m_Flags & 3); // Evaluating of the main shader parameters EF_Eval_TexGen(slw); EF_Eval_RGBAGen(slw); EF_SetVertexStreams(slw->m_Pointers, 1); // Set all textures and HW TexGen modes for the current pass (ShadeLayer) if (slw->mfSetTextures()) { if (m_RP.m_pCurLightMaterial) m_RP.m_pCurLightMaterial->mfApply(slw->m_LMFlags | (l<m_VProgram; // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, VPF_SETPOINTERSFORPASS | VPF_DONTSETMATRICES); } else curVP = NULL; } EF_ApplyMatrixOps(slw->m_MatrixOps, true); if (curVP) { #ifndef PIPE_USE_INSTANCING curVP->mfSetStateMatrices(); #endif curVP->mfSetVariables(false, &slw->m_VPParamsNoObj); } else m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; if (slw->m_FShader) slw->m_FShader->mfSet(true, slw); else m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_PS2NEEDSET | RBPF_TSNEEDSET); int State; // Set Render states for the current pass if (m_RP.m_pCurObject->m_RenderState) State = m_RP.m_pCurObject->m_RenderState | nStencState; else { if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS)) State = bShadowMask ? (slw->m_SecondRenderState & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE : slw->m_SecondRenderState | nStencState; else State = bShadowMask ? (slw->m_RenderState & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE : slw->m_RenderState | nStencState; } EF_SetState(State); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [Light %d]\n", m_RP.m_RendPass, l); #endif // Set scissor rect if (CV_r_scissor) { if (bOnlyLightPass && m_RP.m_pCurLight->m_sWidth && m_RP.m_pCurLight->m_sHeight) EF_Scissor(true, m_RP.m_pCurLight->m_sX, m_RP.m_pCurLight->m_sY, m_RP.m_pCurLight->m_sWidth, m_RP.m_pCurLight->m_sHeight); else m_RP.m_pCurObject->SetScissor(); } EF_Draw(ef, slw); m_RP.m_RendPass++; #else //PIPE_USE_INSTANCING m_RP.m_RendPass++; int bFogOverrided = 0; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); if (m_FS.m_bEnable) bFogOverrided = EF_FogCorrection(false, false); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; bool bLightSicssorWasSet = false; // Set scissor rect if (CV_r_scissor) { if (bOnlyLightPass && m_RP.m_pCurLight->m_sWidth && m_RP.m_pCurLight->m_sHeight) { bLightSicssorWasSet = true; if (!(m_RP.m_ObjFlags & FOB_NOSCISSOR)) EF_Scissor(true, m_RP.m_pCurLight->m_sX, m_RP.m_pCurLight->m_sY, m_RP.m_pCurLight->m_sWidth, m_RP.m_pCurLight->m_sHeight); else EF_Scissor(false, 0, 0, 0, 0); } else pObj->SetScissor(); } SArrayPointer_Texture pt; pt.ePT = eSrcPointer_TexLM; pt.Stage = m_RP.m_nLMStage; pt.Type = GL_FLOAT; pt.NumComponents = 2; while (true) { if (nObj) { // Object changed m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; pObj = m_RP.m_pCurObject; m_RP.m_FrameObject++; if (CV_r_scissor && !bLightSicssorWasSet) pObj->SetScissor(); if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED)) { if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer) { pt.mfSet(1); } } if (!curVP) { // Specify transform EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags); if (m_RP.m_pCurLightMaterial) m_RP.m_pCurLightMaterial->mfApply(slw->m_LMFlags | (l<m_TexMan->m_nCurStages; nt++) { if (m_RP.m_pGTC[nt]) { EF_SelectTMU(nt); m_RP.m_pGTC[nt]->mfSet(true); } } } } } #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [Light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, l, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif if (curVP) { curVP->mfSetStateMatrices(); curVP->mfSetVariables(true, &slw->m_VPParamsObj); } // Set per-object alpha-blending if (pObj->m_ObjFlags & FOB_HASALPHA) pObj->SetAlphaState(slw->m_FShader, State); if (slw->m_FShader) slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj); else { if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject) { float *vals = slw->m_RGBComps->mfGet(); m_RP.m_NeedGlobalColor.bcolor[0] = (byte)(vals[0] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[1] = (byte)(vals[1] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[2] = (byte)(vals[2] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(vals[3] * 255.0f); } EF_CommitTexStageState(); } { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (!(m_RP.m_PersFlags & RBPF_VSWASSET)) { if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; if (!curVP) EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags); } #endif } slw->mfResetTextures(); EF_ApplyMatrixOps(slw->m_MatrixOps, false); if ((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence) glSetFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence, GL_ALL_COMPLETED_NV); break; } } m_RP.m_nCurLight = -1; m_RP.m_pCurLight = NULL; } void CGLRenderer::EF_DrawLightShadowMask(int nLight) { STexPic *pTX = m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic; STexShadow *pTSH = pTX->m_pSH; EF_SelectTMU(0); pTSH->m_pHorizonTex[0]->Set(); EF_SelectTMU(1); pTSH->m_pBasisTex[0]->Set(); EF_SelectTMU(2); pTSH->m_pHorizonTex[1]->Set(); EF_SelectTMU(3); pTSH->m_pBasisTex[1]->Set(); EF_SetState(GS_COLMASKONLYALPHA); if (!m_RP.m_VPTexShadow) m_RP.m_VPTexShadow = CVProgram::mfForName("CGVProgTexShadow"); if (!m_RP.m_RCTexShadow) m_RP.m_RCTexShadow = CPShader::mfForName("CGRCTexShadow"); m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~0xf) | RBMF_TANGENTSUSED; m_RP.m_VPTexShadow->mfSet(true, NULL, VPF_DONTSETMATRICES); m_RP.m_VPTexShadow->mfSetVariables(false, NULL); m_RP.m_RCTexShadow->mfSet(true, NULL); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Bump shadow pass %d [light %d]\n", m_RP.m_RendPass, nLight); #endif m_RP.m_VPTexShadow->mfSetStateMatrices(); m_RP.m_VPTexShadow->mfSetVariables(true, NULL); m_RP.m_RCTexShadow->mfSetVariables(true, NULL); EF_Draw(m_RP.m_pShader, NULL); #else EF_PreDraw(NULL); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; while (true) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; pObj = m_RP.m_pCurObject; m_RP.m_FrameObject++; } #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Bump shadow pass %d [light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, nLight, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif if (m_RP.m_VPTexShadow) { m_RP.m_VPTexShadow->mfSetStateMatrices(); m_RP.m_VPTexShadow->mfSetVariables(true, NULL); } if (m_RP.m_RCTexShadow) m_RP.m_RCTexShadow->mfSetVariables(true, NULL); { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(m_RP.m_pShader, NULL); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; } #endif CGLTexMan::BindNULL(1); } void CGLRenderer::EF_DrawSubsurfacePasses(SShaderTechnique *hs, SShader *ef) { int l; // For each light source for (l=0; lm_Id; // Ignore diffuse passes for specular only light sources if ((m_RP.m_pCurLight->m_Flags & DLF_LM)) { if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) || m_RP.m_pCurObject->m_nLMId) continue; } STexPic *pTX = m_RP.m_pShaderResources->m_Textures[EFTT_SUBSURFACE]->m_TU.m_TexPic; EF_SelectTMU(0); pTX->Set(); EF_SetState(GS_BLSRC_ONE | GS_BLDST_ONE); if (!m_RP.m_VPSubSurfaceScatering) m_RP.m_VPSubSurfaceScatering= CVProgram::mfForName("CGVProgSubSurface"); if (!m_RP.m_RCSubSurfaceScatering) m_RP.m_RCSubSurfaceScatering= CPShader::mfForName("CGRCSubSurface"); m_RP.m_VPSubSurfaceScatering->mfSet(true, NULL); m_RP.m_VPSubSurfaceScatering->mfSetVariables(false, NULL); m_RP.m_RCSubSurfaceScatering->mfSet(true, NULL); m_RP.m_RCSubSurfaceScatering->mfSetVariables(false, NULL); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Subsurface scattering pass %d [light %d]\n", m_RP.m_RendPass, l); #endif m_RP.m_VPSubSurfaceScatering->mfSetVariables(true, NULL); m_RP.m_RCSubSurfaceScatering->mfSetVariables(true, NULL); EF_Draw(m_RP.m_pShader, NULL); #else EF_PreDraw(NULL); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; while (true) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; pObj = m_RP.m_pCurObject; m_RP.m_FrameObject++; } #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Subsurface scattering pass %d [light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, l, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif if (m_RP.m_VPSubSurfaceScatering) { m_RP.m_VPSubSurfaceScatering->mfSetStateMatrices(); m_RP.m_VPSubSurfaceScatering->mfSetVariables(true, NULL); } if (m_RP.m_RCSubSurfaceScatering) { m_RP.m_RCSubSurfaceScatering->mfSetVariables(true, NULL); } { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(m_RP.m_pShader, NULL); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; } #endif } CGLTexMan::BindNULL(1); } // Draw fur layer passes (used in programmable pipeline shaders only) void CGLRenderer::EF_DrawFurPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, EShaderPassType eShPass) { m_RP.m_FlagsPerFlush |= RBSI_FURPASS; PROFILE_FRAME(DrawShader_FurPasses); m_RP.m_pCurLight = NULL; } struct SShadowLight { list2 *pSmLI; CDLight *pDL; }; static _inline int Compare(SShadowLight &a, SShadowLight &b) { if (a.pSmLI->Count() > b.pSmLI->Count()) return -1; if (a.pSmLI->Count() < b.pSmLI->Count()) return 1; return 0; } #include int CGLRenderer::EF_DrawMultiShadowPasses(SShaderTechnique *hs, SShader *ef, int nStart) { int i, j; int nStartShadowLM = -1; int nEndShadowLM = -1; int nStartShadow = -1; int nEndShadow = -1; int nStartLight = -1; int nEndLight = -1; int nEnd = -1; nStart++; for (i=nStart; im_Passes.Num(); i++) { switch (hs->m_Passes[i].m_ePassType) { case eSHP_SpecularLight: case eSHP_DiffuseLight: case eSHP_Light: if (nStartLight < 0) nStartLight = i; else nEndLight = i; break; case eSHP_Shadow: if ((hs->m_Passes[i].m_SecondRenderState & GS_BLEND_MASK) == (GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA)) { if (nStartShadowLM < 0) nStartShadowLM = i; else nEndShadowLM = i; } else { if (nStartShadow < 0) nStartShadow = i; else nEndShadow = i; } break; default: nEnd = i; } } if (nEnd < 0) nEnd = i-1; list2 * lsources = (list2*)m_RP.m_pCurObject->m_pShadowCasters; if (!lsources || !lsources->Count()) return nEnd; if (nEndLight < 0) nEndLight = nStartLight; if (nEndShadow < 0) nEndShadow = nStartShadow; if (nEndShadowLM < 0) nEndShadowLM = nStartShadowLM; assert(nStartShadow>=0); assert(nStartLight>=0); int nFrustrums = 0; list2 SmLI[16]; list2 SmLI_LM; SShadowLight SL[16]; int nLights = m_RP.m_NumActiveDLights; bool bHasDot3LM = m_RP.m_pShaderResources && m_RP.m_pCurObject->m_nLMDirId; for (i=0; im_Id; for (j=0; jCount(); j++) { ShadowMapLightSourceInstance *Inst = lsources->Get(j); if (bHasDot3LM && Inst->m_pLS->nDLightId == nLightID && (SL[i].pDL->m_Flags & DLF_LM)) { if (!Inst->m_pLS->m_LightFrustums[0].pOwner || !(Inst->m_pLS->m_LightFrustums[0].pOwner->GetRndFlags() & ERF_CASTSHADOWINTOLIGHTMAP)) SmLI_LM.Add(*Inst); } else if (Inst->m_pLS->nDLightId == nLightID) SmLI[i].Add(*Inst); } } ::Sort(&SL[0], nLights); int nStartLightWithoutSC = -1; if (SmLI_LM.Count() && nStartShadowLM >= 0) { m_RP.m_pCurObject->m_pShadowCasters = &SmLI_LM; EF_DrawShadowPasses(hs, ef, nStartShadowLM, nEndShadowLM); } for (i=0; iCount()) { m_RP.m_pCurObject->m_pShadowCasters = SL[i].pSmLI; EF_DrawShadowPasses(hs, ef, nStartShadow, nEndShadow); m_RP.m_pActiveDLights[0] = SL[i].pDL; m_RP.m_NumActiveDLights = 1; EF_DrawLightPasses(hs, ef, nStartLight, nEndLight); } else { if (nStartLightWithoutSC < 0) nStartLightWithoutSC = i; m_RP.m_pActiveDLights[i-nStartLightWithoutSC] = SL[i].pDL; } } if (nStartLightWithoutSC >= 0) { m_RP.m_NumActiveDLights = nLights-nStartLightWithoutSC; EF_DrawLightPasses(hs, ef, nStartLight, nEndLight); } m_RP.m_pCurObject->m_pShadowCasters = lsources; for (i=0; im_Flags & EF_USELIGHTS)) return; m_RP.m_nCurLight = 0; CVProgram *curVP = NULL; CVProgram *newVP; SArrayPointer::m_LastEnabledPass = 0; list2 * lsources = (list2*)m_RP.m_pCurObject->m_pShadowCasters; if (!lsources) return; m_RP.m_FlagsPerFlush |= RBSI_SHADOWPASS; PROFILE_FRAME(DrawShader_ShadowPasses); int nCaster = 0; if (ef->m_eSort != eS_TerrainShadowPass) { if (!CRenderer::CV_r_selfshadow || !(m_Features & RFT_SHADOWMAP_SELFSHADOW)) { if( lsources->Get(0)->m_pLS->GetShadowMapFrustum()->pOwner == lsources->Get(0)->m_pReceiver && !(lsources->Get(0)->m_pLS->GetShadowMapFrustum()->dwFlags & SMFF_ACTIVE_SHADOW_MAP)) nCaster++; // skip self shadowing pass } } int nCasters = lsources->Count(); int nDeltaCasters = 1; for (; nCasterm_Passes[nStart]; for (i=nStart; i<=nEnd; i++, slw++) { int msk; if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK)) { if (!m_RP.m_NumActiveDLights) return; m_RP.m_pCurLight = m_RP.m_pActiveDLights[0]; m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id; if (!(msk & (m_RP.m_pCurLight->m_Flags & DLF_LIGHTTYPE_MASK))) continue; } if (slw->m_LMFlags & LMF_SAMPLES) { if (slw->m_LMFlags & LMF_4SAMPLES) { if (nCasters-nCaster < 4) continue; nDeltaCasters = 4; } else if (slw->m_LMFlags & LMF_3SAMPLES) { if (nCasters-nCaster < 3) continue; nDeltaCasters = 3; } else if (slw->m_LMFlags & LMF_2SAMPLES) { if (nCasters-nCaster < 2) continue; nDeltaCasters = 2; } else if (slw->m_LMFlags & LMF_1SAMPLES) { if (nCasters-nCaster < 1) continue; nDeltaCasters = 1; } } m_RP.m_CurrPass = slw; SArrayPointer::m_CurEnabledPass = 0; if((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence && (m_RP.m_Flags & RBF_MODIF_MASK) && !glTestFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence)) glFinishFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence); if (slw->m_LMFlags & LMF_POLYOFFSET) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(CV_gl_offsetfactor, CV_gl_offsetunits); } m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); // Evaluating of the main shader parameters EF_Eval_DeformVerts(slw->m_Deforms); EF_Eval_TexGen(slw); EF_Eval_RGBAGen(slw); EF_SetVertexStreams(slw->m_Pointers, 1); // Set all textures and HW TexGen modes for the current pass if (slw->mfSetTextures()) { m_RP.m_CurrentVLights = 0; newVP = slw->m_VProgram; // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, VPF_SETPOINTERSFORPASS | VPF_DONTSETMATRICES); } else curVP = NULL; } EF_ApplyMatrixOps(slw->m_MatrixOps, true); if (curVP) { #ifndef PIPE_USE_INSTANCING curVP->mfSetStateMatrices(); #endif curVP->mfSetVariables(false, &slw->m_VPParamsNoObj); } else m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; // Set Pixel shaders and Register combiners for the current pass if (slw->m_FShader) slw->m_FShader->mfSet(true, slw); else m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_PS2NEEDSET | RBPF_TSNEEDSET); if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS)) EF_SetState(slw->m_SecondRenderState); else EF_SetState(slw->m_RenderState); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Shadow Pass %d [%d Samples]\n", m_RP.m_RendPass, nDeltaCasters); #endif EF_Scissor(false, 0, 0, 0, 0); EF_Draw(ef, slw); m_RP.m_RendPass++; #else //PIPE_USE_INSTANCING m_RP.m_RendPass++; int bFogOverrided = 0; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); if (m_FS.m_bEnable) bFogOverrided = EF_FogCorrection(false, false); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; while (true) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; m_RP.m_FrameObject++; pObj = m_RP.m_pCurObject; if (!curVP) { EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags); if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial && !(ef->m_LMFlags & LMF_DISABLE)) m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags); else m_RP.m_CurrentVLights = 0; if (m_RP.m_FrameGTC == m_RP.m_Frame) { for (int nt=0; ntm_TexMan->m_nCurStages; nt++) { if (m_RP.m_pGTC[nt]) { EF_SelectTMU(nt); m_RP.m_pGTC[nt]->mfSet(true); } } } } } EF_Scissor(false, 0, 0, 0, 0); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Shadow Pass %d [%d Samples] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, nDeltaCasters, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif if (curVP) { curVP->mfSetStateMatrices(); curVP->mfSetVariables(true, &slw->m_VPParamsObj); } if (slw->m_FShader) slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj); else { if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject) { float *vals = slw->m_RGBComps->mfGet(); m_RP.m_NeedGlobalColor.bcolor[0] = (byte)(vals[0] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[1] = (byte)(vals[1] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[2] = (byte)(vals[2] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(vals[3] * 255.0f); } EF_CommitTexStageState(); } { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (!(m_RP.m_PersFlags & RBPF_VSWASSET)) { if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; if (!curVP) EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags); } #endif } slw->mfResetTextures(); EF_ApplyMatrixOps(slw->m_MatrixOps, false); if ((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence) glSetFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence, GL_ALL_COMPLETED_NV); if (slw->m_LMFlags & LMF_POLYOFFSET) glDisable(GL_POLYGON_OFFSET_FILL); } } m_RP.m_nCurStartCaster = 0; } void CGLRenderer::EF_DrawGeneralPasses(SShaderTechnique *hs, SShader *ef, bool bFog, int nStart, int nEnd) { SShaderPassHW *slw; int i; if ((m_RP.m_ObjFlags & FOB_LIGHTPASS) && (ef->m_Flags & EF_USELIGHTS)) return; if (!bFog && (m_RP.m_ObjFlags & FOB_FOGPASS)) return; m_RP.m_nCurLight = 0; CVProgram *curVP = NULL; CVProgram *newVP; PROFILE_FRAME(DrawShader_GeneralPasses); int bFogOverrided = 0; SArrayPointer::m_LastEnabledPass = 0; slw = &hs->m_Passes[nStart]; for (i=nStart; i<=nEnd; i++, slw++) { SArrayPointer::m_CurEnabledPass = 0; if((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence && (m_RP.m_Flags & RBF_MODIF_MASK) && !glTestFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence)) glFinishFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence); if (slw->m_LMFlags & LMF_POLYOFFSET) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(CV_gl_offsetfactor, CV_gl_offsetunits); } m_RP.m_StatNumPasses++; m_RP.m_CurrPass = slw; m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); // Evaluating of the main shader parameters EF_Eval_DeformVerts(slw->m_Deforms); EF_Eval_TexGen(slw); EF_Eval_RGBAGen(slw); EF_SetVertexStreams(slw->m_Pointers, 1); // Set all textures and HW TexGen modes for the current pass if (slw->mfSetTextures()) { newVP = slw->m_VProgram; if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial && !(ef->m_LMFlags & LMF_DISABLE)) { m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags); if (!newVP && !(slw->m_LMFlags & LMF_DISABLE) && !(m_RP.m_CurrentVLights & 0xff)) EF_ConstantLightMaterial(m_RP.m_pShaderResources->m_LMaterial, slw->m_LMFlags); } else m_RP.m_CurrentVLights = 0; // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, VPF_SETPOINTERSFORPASS | VPF_DONTSETMATRICES); } else curVP = NULL; } EF_ApplyMatrixOps(slw->m_MatrixOps, true); if (curVP) { #ifndef PIPE_USE_INSTANCING curVP->mfSetStateMatrices(); #endif curVP->mfSetVariables(false, &slw->m_VPParamsNoObj); } else m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; // Set Pixel shaders and Register combiners for the current pass if (slw->m_FShader) slw->m_FShader->mfSet(true, slw); else m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_PS2NEEDSET | RBPF_TSNEEDSET); int State; // Set Render states for the current pass if (bFog) { State = slw->m_RenderState; if (m_RP.m_pShader->m_Flags2 & EF2_OPAQUE) State |= GS_DEPTHFUNC_EQUAL; EF_SetState(State); } else if (m_RP.m_pCurObject->m_RenderState) State = m_RP.m_pCurObject->m_RenderState; else { if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS)) State = slw->m_SecondRenderState; else State = slw->m_RenderState; } EF_SetState(State); int bFogOverrided = 0; bool bFogDisable = (curVP && (curVP->m_Flags & VPFI_NOFOG)); bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY)); bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { if (bFog) Logv(SRendItem::m_RecurseLevel, "+++ Fog Pass %d\n", m_RP.m_RendPass); else Logv(SRendItem::m_RecurseLevel, "+++ General Pass %d\n", m_RP.m_RendPass); } #endif m_RP.m_pCurObject->SetScissor(); EF_Draw(ef, slw); m_RP.m_RendPass++; #else //PIPE_USE_INSTANCING m_RP.m_RendPass++; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; SArrayPointer_Texture pt; pt.ePT = eSrcPointer_TexLM; pt.Stage = m_RP.m_nLMStage; pt.Type = GL_FLOAT; pt.NumComponents = 2; while (true) { if (nObj) { m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; m_RP.m_FrameObject++; pObj = m_RP.m_pCurObject; if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED)) { if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer) { pt.mfSet(1); } } if (!curVP) { EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags); if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial && !(ef->m_LMFlags & LMF_DISABLE)) m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags); else m_RP.m_CurrentVLights = 0; if (m_RP.m_FrameGTC == m_RP.m_Frame) { for (int nt=0; ntm_TexMan->m_nCurStages; nt++) { if (m_RP.m_pGTC[nt]) { EF_SelectTMU(nt); m_RP.m_pGTC[nt]->mfSet(true); } } } } } pObj->SetScissor(); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); if (bFog) Logv(SRendItem::m_RecurseLevel, "+++ Fog Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); else Logv(SRendItem::m_RecurseLevel, "+++ General Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif // Set per-object alpha-blending if (pObj->m_ObjFlags & FOB_HASALPHA) pObj->SetAlphaState(slw->m_FShader, State); if (curVP) { curVP->mfSetStateMatrices(); curVP->mfSetVariables(true, &slw->m_VPParamsObj); } if (slw->m_FShader) slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj); else { if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject) { float *vals = slw->m_RGBComps->mfGet(); m_RP.m_NeedGlobalColor.bcolor[0] = (byte)(vals[0] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[1] = (byte)(vals[1] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[2] = (byte)(vals[2] * 255.0f); m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(vals[3] * 255.0f); } EF_CommitTexStageState(); } { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (!(m_RP.m_PersFlags & RBPF_VSWASSET)) { if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; if (!curVP) EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags); } #endif } slw->mfResetTextures(); EF_ApplyMatrixOps(slw->m_MatrixOps, false); if ((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence) glSetFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence, GL_ALL_COMPLETED_NV); if (slw->m_LMFlags & LMF_POLYOFFSET) glDisable(GL_POLYGON_OFFSET_FILL); } } // Flush HW shader technique (used in FP shaders and in programmable pipeline shaders) void CGLRenderer::EF_FlushHW() { int i; SShader *ef = m_RP.m_pShader; int nPolys = m_nPolygons; if (m_RP.m_pRE || (m_RP.m_RendNumIndices && m_RP.m_RendNumVerts)) { // Set Z-Bias if (ef->m_Flags & EF_POLYGONOFFSET) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(CV_gl_offsetfactor, CV_gl_offsetunits); } SShaderTechnique *hs = m_RP.m_pCurTechnique; if (!hs) return; // Check updating of mesh (vertices/indices) if (m_RP.m_pRE) { SRenderShaderResources *Res = m_RP.m_pShaderResources; int nFlags = hs->m_Flags; if (Res && Res->m_bNeedNormals) nFlags |= SHPF_NORMALS; if (ef->m_eSort == eS_TerrainLightPass || ef->m_eSort == eS_Terrain) nFlags |= FHF_TERRAIN; m_RP.m_pRE->mfCheckUpdate(ef->m_VertexFormatId, nFlags); } if (ef->m_Flags & EF_NEEDNORMALS) EF_EvalNormalsRB(ef); EF_Eval_DeformVerts(ef->m_Deforms); // Set culling mode if (!(m_RP.m_FlagsPerFlush & RBSI_NOCULL)) { if (hs->m_eCull != -1) GLSetCull(hs->m_eCull); else GLSetCull(ef->m_eCull); } if (m_RP.m_pShaderResources) m_RP.m_pCurLightMaterial = m_RP.m_pShaderResources->m_LMaterial; else if (ef->m_Flags2 & EF2_USELIGHTMATERIAL) m_RP.m_pCurLightMaterial = &m_RP.m_DefLightMaterial; else m_RP.m_pCurLightMaterial = NULL; EF_SetVertexStreams(hs->m_Pointers, 0); EF_ApplyMatrixOps(hs->m_MatrixOps, true); // Draw shader passes bool bLights = false; if (hs->m_Passes.Num()) { int nStart = 0; EShaderPassType eShPass = m_SHPTable[hs->m_Passes[0].m_ePassType]; for (i=1; im_Passes.Num(); i++) { if (m_SHPTable[hs->m_Passes[i].m_ePassType] != eShPass) { int nEnd = i-1; bLights |= EF_DrawPasses(eShPass, hs, ef, nStart, nEnd); i = nEnd+1; nStart = i; if (i >= hs->m_Passes.Num()) break; eShPass = m_SHPTable[hs->m_Passes[i].m_ePassType]; } } if (i-nStart > 0) { int nEnd = i-1; bLights |= EF_DrawPasses(eShPass, hs, ef, nStart, nEnd); } } if (bLights) { if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_SUBSURFACE]) EF_DrawSubsurfacePasses(hs, ef); } // Restore matrix transform states EF_ApplyMatrixOps(hs->m_MatrixOps, false); // Restore Z-Bias if (ef->m_Flags & EF_POLYGONOFFSET) glDisable(GL_POLYGON_OFFSET_FILL); // Draw detail texture passes if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY] && CV_r_detailtextures) EF_DrawDetailOverlayPasses(); // Draw volumetric fog passes if (m_RP.m_pFogVolume && CV_r_VolumetricFog) EF_DrawFogOverlayPasses(); } } void CGLRenderer::EF_Set2DMode(bool bSet, int orthox, int orthoy) { Set2DMode(bSet, orthox, orthoy); EF_SetCameraInfo(); } // Flush current shader void CGLRenderer::EF_FlushShader() { SShader *ef = m_RP.m_pShader; int i; SShaderPass *slw; if (m_RP.m_pRE) // Without buffer fill EF_InitEvalFuncs(1); // VP else { // Buffer filling (merging case) EF_InitEvalFuncs(0); if (!m_RP.m_RendNumIndices) return; if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume) return; // should never happen if (m_RP.m_RendNumIndices > m_RP.m_MaxTris*3) { iLog->Log("CGLRenderer::EF_FlushShader: Shader MAX_RENDTRIS hit\n"); m_RP.m_RendNumIndices = m_RP.m_MaxTris*3; } if (m_RP.m_RendNumVerts > m_RP.m_MaxVerts) { iLog->Log("CGLRenderer::EF_FlushShader: Shader MAX_RENDVERTS hit\n"); m_RP.m_RendNumVerts = m_RP.m_MaxVerts; } } m_RP.m_ResourceState = 0; // Set overrided states from shader resources if (m_RP.m_pShaderResources) { if (!EF_SetResourcesState(true)) return; } // Set overrided states from state shader if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_SetStateShaderState(); bool bDraw2D = false; if (!(m_RP.m_Flags & RBF_2D) && (m_RP.m_FlagsPerFlush & RBSI_DRAWAS2D)) { bDraw2D = true; EF_Set2DMode(true,800,600); } // Draw using HW shader techniques if (ef->m_HWTechniques.Num()) { EF_FlushHW(); if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_ResetStateShaderState(); if (m_RP.m_pShaderResources) EF_SetResourcesState(false); if (bDraw2D) EF_Set2DMode(false,800,600); return; } if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume) { // Should never happen if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_ResetStateShaderState(); if (m_RP.m_pShaderResources) EF_SetResourcesState(false); if (bDraw2D) EF_Set2DMode(false,800,600); return; } // Update mesh if necessary (create video streams / streaming) if (m_RP.m_pRE) { int nFlags = 0; if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_bNeedNormals) nFlags |= SHPF_NORMALS; if (!m_RP.m_pRE->mfCheckUpdate(ef->m_VertexFormatId, nFlags)) return; } // In common shaders we don't have pixel or vertex shaders m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_PS2NEEDSET | RBPF_TSNEEDSET | RBPF_VSNEEDSET); CGLTexMan::BindNULL(1); EF_SelectTMU(0); if (ef->m_Flags & EF_NEEDNORMALS) EF_EvalNormalsRB(ef); EF_Eval_DeformVerts(ef->m_Deforms); SArrayPointer::m_CurEnabled = PFE_POINTER_VERT; if (ef->m_Flags & EF_POLYGONOFFSET) { glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(CV_gl_offsetfactor, CV_gl_offsetunits); } if (!(m_RP.m_FlagsPerFlush & RBSI_NOCULL)) GLSetCull(ef->m_eCull); if (!m_RP.m_pRE) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, m_RP.m_Stride, m_RP.m_Ptr.PtrB + m_RP.m_OffsT); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_UNSIGNED_BYTE, m_RP.m_Stride, m_RP.m_Ptr.PtrB + m_RP.m_OffsD); glVertexPointer(3, GL_FLOAT, m_RP.m_Stride, m_RP.m_Ptr.PtrB); if (m_RP.m_FT & FLT_N) { glNormalPointer(GL_FLOAT, m_RP.m_Stride, m_RP.m_Ptr.PtrB+m_RP.m_OffsN); glEnableClientState(GL_NORMAL_ARRAY); } } if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial) m_RP.m_pShaderResources->m_LMaterial->mfApply(ef->m_LMFlags); else m_RP.m_CurrentVLights = 0; int nPolys = m_nPolygons; slw = &ef->m_Passes[0]; m_RP.m_StatNumPasses += ef->m_Passes.Num(); // Draw all passes for (i=0; im_Passes.Num(); i++, slw++) { EF_Eval_TexGen(slw); EF_Eval_RGBAGen(slw); // Set all textures and HW TexGen modes for the current pass (ShadeLayer) if (slw->mfSetTextures()) { // Set Render states for the current pass int nState; if (m_RP.m_RendPass || (m_RP.m_pCurObject->m_ObjFlags & FOB_LIGHTPASS)) nState = slw->m_SecondRenderState; else nState = slw->m_RenderState; EF_SetState(nState); #ifndef PIPE_USE_INSTANCING #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Pass %d \n", m_RP.m_RendPass); #endif // Set scissor rect m_RP.m_pCurObject->SetScissor(); EF_Draw(ef, slw); m_RP.m_RendPass++; #else m_RP.m_RendPass++; int bFogOverrided = 0; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); if (m_FS.m_bEnable) bFogOverrided = EF_FogCorrection(false, false); int nObj = 0; CCObject *pSaveObj = m_RP.m_pCurObject; CCObject *pObj = pSaveObj; bool bLightSicssorWasSet = false; // Set scissor rect pObj->SetScissor(); while (true) { if (nObj) { // Object changed m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; pObj = m_RP.m_pCurObject; m_RP.m_FrameObject++; pObj->SetScissor(); EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags); if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial) m_RP.m_pShaderResources->m_LMaterial->mfApply(ef->m_LMFlags); } #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif // Set per-object alpha blending state if (pObj->m_ObjFlags & FOB_HASALPHA) pObj->SetAlphaState(NULL, nState); // Commit per-texture states / color ops EF_CommitTexStageState(); { //PROFILE_FRAME(Draw_EFIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogCorrectionRestore(bFogOverrided); if (!m_RP.m_LastVP) { if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG)) EF_CommitTexTransforms(false); } if (pSaveObj != m_RP.m_pCurObject) { m_RP.m_pCurObject = pSaveObj; m_RP.m_FrameObject++; EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags); } #endif } slw->mfResetTextures(); } if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY] && CV_r_detailtextures) EF_DrawDetailOverlayPasses(); if (m_RP.m_pFogVolume && CV_r_VolumetricFog) EF_DrawFogOverlayPasses(); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); if ((m_RP.m_FT & FLT_N) && !m_RP.m_pRE) glDisableClientState(GL_NORMAL_ARRAY); if ((m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED) && SUPPORTS_GL_NV_fence) glSetFenceNV(m_RP.m_VidBufs[m_RP.m_MergedStreams[0]].m_Fence, GL_ALL_COMPLETED_NV); if (ef->m_Flags & EF_POLYGONOFFSET) glDisable(GL_POLYGON_OFFSET_FILL); if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_ResetStateShaderState(); if (m_RP.m_pShaderResources) EF_SetResourcesState(false); if (bDraw2D) EF_Set2DMode(false,800,600); SArrayPointer_Texture::m_pLastPointer[0] = NULL; SArrayPointer::m_LastEnabled = 0; SArrayPointer_Vertex::m_pLastPointer = NULL; SArrayPointer_Normal::m_pLastPointer = NULL; SArrayPointer_Color::m_pLastPointer = NULL; } // Flush current render item void CGLRenderer::EF_Flush() { CGLRenderer *rd = gcpOGL; SShader *ef = rd->m_RP.m_pShader; if (rd->m_RP.m_ExcludeShader) { if (!strcmp(rd->m_RP.m_ExcludeShader, ef->m_Name.c_str())) return; if(rd->m_RP.m_ExcludeShader[0] == '#') if (strstr(ef->m_Name.c_str(), rd->m_RP.m_ExcludeShader)) return; } if (rd->m_RP.m_ShowOnlyShader) { if (strcmp(rd->m_RP.m_ShowOnlyShader, ef->m_Name.c_str())) return; } /*{ Vec3d vObj = rd->m_RP.m_pCurObject->GetTranslation(); Vec3d vv = Vec3d(1452.625, 1345.750, 27.500); if ((vv-vObj).GetLength() > 0.1f) return; }*/ //if ((int)rd->m_RP.m_pRE != 0x1261c840) // return; if (ef->m_nPreprocess) { if (ef->m_nPreprocess & FSPR_PORTAL) { if (CV_r_portals && (rd->m_RP.m_PersFlags & (RBPF_DRAWPORTAL | RBPF_DRAWMIRROR))) return; } if(ef->m_nPreprocess & FSPR_HEATVIS) { if (rd->m_RP.m_PersFlags & RBPF_DRAWHEATMAP) rd->m_TexMan->EndHeatMap(); } if (ef->m_nPreprocess & FSPR_SCANSCR) { if (rd->m_RP.m_PersFlags & RBPF_DRAWSCREENMAP) rd->m_TexMan->EndScreenMap(); } if (ef->m_nPreprocess & FSPR_SCREENTEXMAP) { if (rd->m_RP.m_PersFlags & RBPF_DRAWSCREENTEXMAP) { // check when refraction is active.. rd->m_TexMan->EndScreenTexMap(); // disable flag if(rd->m_RP.m_PersFlags& RBPF_IGNOREREFRACTED) rd->m_RP.m_PersFlags&= ~RBPF_IGNOREREFRACTED; } } } if (rd->m_LogFile && CV_r_log == 3) rd->Logv(SRendItem::m_RecurseLevel, "--------------------------------- Start Flush: '%s' -----------------------------------\n", ef->m_Name.c_str()); rd->m_RP.m_StatNumLightPasses = 0; rd->m_RP.m_StatNumLights = 0; rd->m_RP.m_StatNumPasses = 0; rd->m_RP.m_StatLightMask = 0; rd->m_RP.m_PS.m_NumRendBatches++; #ifdef PIPE_USE_INSTANCING if (rd->m_RP.m_MergedObjects.Num()) rd->m_RP.m_PS.m_NumRendItems += rd->m_RP.m_MergedObjects.Num(); else #endif rd->m_RP.m_PS.m_NumRendItems++; CCObject *obj = rd->m_RP.m_pCurObject; int VPMId, IMId; if (!(rd->m_RP.m_ObjFlags & FOB_TRANS_MASK)) { VPMId = rd->m_RP.m_pCurObject->m_VPMatrixId; IMId = rd->m_RP.m_pCurObject->m_InvMatrixId; rd->m_RP.m_pCurObject->m_VPMatrixId = 0; rd->m_RP.m_pCurObject->m_InvMatrixId = 0; } rd->m_RP.m_DynLMask = CV_r_hwlights ? obj->m_DynLMMask : 0; if (!(ef->m_Flags & EF_HASVSHADER)) rd->EF_SetObjectTransform(obj, ef, obj->m_ObjFlags); if (CV_r_showlight->GetString()[0] != '0') { for (int i=0; im_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); i++) { CDLight *dl = rd->m_RP.m_DLights[SRendItem::m_RecurseLevel][i]; if (!dl) continue; char *str = CV_r_showlight->GetString(); if (strcmp(str, "0") != 0) { if (!dl->m_Name || !strstr(dl->m_Name, str)) rd->m_RP.m_DynLMask &= ~(1<m_Flags3 & EF3_CLIPPLANE) && !(rd->m_RP.m_PersFlags & RBPF_SETCLIPPLANE) && !rd->m_RP.m_ClipPlaneEnabled) { switch (ef->m_Flags3 & EF3_CLIPPLANE) { case EF3_CLIPPLANE_WATER_FRONT: case EF3_CLIPPLANE_WATER_BACK: { SPlane Pl; Pl.m_Normal = Vec3d (0, 0, 1); Pl.m_Dist = iSystem->GetI3DEngine()->GetWaterLevel(); if (ef->m_Flags3 & EF3_CLIPPLANE_WATER_BACK) { Pl.m_Normal = -Pl.m_Normal; Pl.m_Dist = -Pl.m_Dist; } Pl.m_Dist = -Pl.m_Dist; rd->EF_SetClipPlane(true, &Pl.m_Normal.x, false); rd->m_RP.m_PersFlags |= RBPF_SETCLIPPLANE; } } } else if (!(ef->m_Flags3 & EF3_CLIPPLANE) && (rd->m_RP.m_PersFlags & RBPF_SETCLIPPLANE)) { rd->EF_SetClipPlane(false, NULL, false); rd->m_RP.m_PersFlags &= ~RBPF_SETCLIPPLANE; } bool bProfile; double time0 = 0; int nNumPolys = rd->m_nPolygons; if (CRenderer::CV_r_profileshaders || CRenderer::CV_r_log>=2) { ticks(time0); bProfile = true; } else bProfile = false; if (rd->m_LogFile && CV_r_log >= 3) rd->Logv(SRendItem::m_RecurseLevel, "\n"); rd->EF_FlushShader(); if (rd->m_RP.m_DynLMask) rd->m_RP.m_PS.m_NumLitShaders++; #ifdef DO_RENDERLOG nNumPolys = rd->m_nPolygons - nNumPolys; if (bProfile) { unticks(time0); time0 = time0*1000.0*g_SecondsPerCycle; } if (CRenderer::CV_r_profileshaders) { SProfInfo pi; pi.Time = time0; pi.NumPolys = nNumPolys; pi.ef = ef; pi.m_nItems = 0; rd->m_RP.m_Profile.AddElem(pi); } if (rd->m_RP.m_DynLMask) rd->m_RP.m_PS.m_NumLitShaders++; if (rd->m_LogFile) { if (CV_r_log >= 3 && rd->m_RP.m_DynLMask) { for (int n=0; nm_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); n++) { CDLight *dl = rd->m_RP.m_DLights[SRendItem::m_RecurseLevel][n]; if (rd->m_RP.m_DynLMask & (1<Logv(SRendItem::m_RecurseLevel, " Light %d (\"%s\")\n", n, dl->m_Name ? dl->m_Name : ""); } } GLenum err = glGetError(); int errnum=0; while (err != GL_NO_ERROR) { char * pErrText = (char*)rd->ErrorString(err); rd->Logv(SRendItem::m_RecurseLevel, "glGetError: %s:", pErrText ? pErrText : "-"); rd->Logv(SRendItem::m_RecurseLevel, "\n"); err = glGetError(); if (++errnum>10) break; } char *str; if (ef->m_HWTechniques.Num()) str = "FlushHW"; else str = "Flush"; rd->Logv(SRendItem::m_RecurseLevel, "%s: '%s', (St: %s) Id:%d, ResId:%d, Obj:%d, Tech: %d, Cp: %d, Fog:%d, VF:%d, NL:%d, LPas:%d, Pas:%d (time: %f, %d polys)\n", str, ef->m_Name.c_str(), rd->m_RP.m_pStateShader ? rd->m_RP.m_pStateShader->m_Name.c_str() : "NULL", ef->m_Id, rd->m_RP.m_pShaderResources ? rd->m_RP.m_pShaderResources->m_Id : -1, rd->m_RP.m_pCurObject->m_VisId, rd->m_RP.m_pCurTechnique ? rd->m_RP.m_pCurTechnique->m_Id : -1, rd->m_RP.m_ClipPlaneEnabled, rd->m_RP.m_pFogVolume ? (rd->m_RP.m_pFogVolume-&rd->m_RP.m_FogVolumes[0]) : 0, rd->m_RP.m_pShader->m_VertexFormatId, rd->m_RP.m_StatNumLights, rd->m_RP.m_StatNumLightPasses, rd->m_RP.m_StatNumPasses, time0, nNumPolys); if (rd->m_RP.m_ObjFlags & FOB_SELECTED) { if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHATEST) rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), LM: %d, (AT) (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask); else if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND) rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x) (AB), LM: %d (Dist: %.3f) (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask, rd->m_RP.m_pRE ? rd->m_RP.m_pRE->mfDistanceToCameraSquared(*gRenDev->m_RP.m_pCurObject) : 0); else rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), RE: 0x%x, LM: 0x%x (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_pRE, rd->m_RP.m_DynLMask); } else { if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHATEST) rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), LM: %d, (AT)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask); else if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND) rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x) (AB), LM: %d (Dist: %.3f)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask, rd->m_RP.m_pRE ? rd->m_RP.m_pRE->mfDistanceToCameraSquared(*gRenDev->m_RP.m_pCurObject) : 0); else rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), RE: 0x%x, LM: 0x%x\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_pRE, rd->m_RP.m_DynLMask); } } #endif } // Process all render item lists void CGLRenderer::EF_EndEf3D(int nFlags) { double time0 = 0; ticks(time0); assert(SRendItem::m_RecurseLevel >= 1); if (SRendItem::m_RecurseLevel < 1) { iLog->Log("Error: CRenderer::EF_EndEf3D without CRenderer::EF_StartEf"); return; } if (CV_r_nodrawshaders == 1) { SetClearColor(Vec3d(0,0,0)); EF_ClearBuffers(false, false); SRendItem::m_RecurseLevel--; return; } m_RP.m_PersFlags &= ~(RBPF_DRAWNIGHTMAP | RBPF_DRAWHEATMAP); m_RP.m_RealTime = iTimer->GetCurrTime(); if (CV_r_fullbrightness) { m_RP.m_NeedGlobalColor.dcolor = -1; m_RP.m_FlagsPerFlush |= RBSI_RGBGEN | RBSI_ALPHAGEN; } if (CV_r_excludeshader->GetString()[0] != '0') m_RP.m_ExcludeShader = CV_r_excludeshader->GetString(); else m_RP.m_ExcludeShader = NULL; if (CV_r_showonlyshader->GetString()[0] != '0') m_RP.m_ShowOnlyShader = CV_r_showonlyshader->GetString(); else m_RP.m_ShowOnlyShader = NULL; EF_UpdateSplashes(m_RP.m_RealTime); EF_AddClientPolys3D(); EF_AddClientPolys2D(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID] = SRendItem::m_RendItems[EFSLIST_PREPROCESS_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID] = SRendItem::m_RendItems[EFSLIST_STENCIL_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID] = SRendItem::m_RendItems[EFSLIST_GENERAL_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID] = SRendItem::m_RendItems[EFSLIST_UNSORTED_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID] = SRendItem::m_RendItems[EFSLIST_DISTSORT_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID] = SRendItem::m_RendItems[EFSLIST_LAST_ID].Num(); EF_RenderPipeLine(EF_Flush); EF_DrawDebugTools(); EF_RemovePolysFromScene(); SRendItem::m_RecurseLevel--; unticks(time0); m_RP.m_PS.m_fFlushTime += (float)(time0*1000.0*g_SecondsPerCycle); } // Process all render item lists void CGLRenderer::EF_RenderPipeLine(void (*RenderFunc)()) { EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID], EFSLIST_PREPROCESS_ID, RenderFunc); // Preprocess and probably sky if (!(m_RP.m_PersFlags & RBPF_IGNORERENDERING)) { EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID], EFSLIST_STENCIL_ID, RenderFunc); // Unsorted list for indoor EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID], EFSLIST_GENERAL_ID, RenderFunc); // Sorted list without preprocess EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID], EFSLIST_UNSORTED_ID, RenderFunc); // Unsorted list EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID], EFSLIST_DISTSORT_ID, RenderFunc); // Sorted by distance elements if (SRendItem::m_RecurseLevel <= 1) EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID], EFSLIST_LAST_ID, RenderFunc); // Sorted list without preprocess of all fog passes and screen shaders } else m_RP.m_PersFlags &= ~RBPF_IGNORERENDERING; } static char *sDescList[] = {"General", "DistSort", "Preprocess", "Unsorted", "Last"}; // Process render items list [nList] from [nums] to [nume] // 1. Sorting of the list // 2. Preprocess shaders handling // 3. Process sorted ordered list of render items void CGLRenderer::EF_PipeLine(int nums, int nume, int nList, void (*RenderFunc)()) { int i; CCObject *pSavedObj; SShader *pShader, *pCurShader, *pShaderState, *pCurShaderState; SRenderShaderResources *pRes, *pCurRes; int nObject, nCurObject; int nFog, nCurFog; if (nume-nums < 1) return; m_RP.m_pRenderFunc = RenderFunc; m_RP.m_nCurLightParam = -1; pSavedObj = m_RP.m_pCurObject; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; m_RP.m_pPrevObject = m_RP.m_pCurObject; if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Start frame for list %s ***\n", sDescList[nList]); EF_PreRender(1); if (nList==EFSLIST_PREPROCESS_ID || nList==EFSLIST_GENERAL_ID || nList==EFSLIST_LAST_ID) { { PROFILE_FRAME(State_Sorting); SRendItem::mfSort(&SRendItem::m_RendItems[nList][nums], nume-nums); } // If sort number of the first shader is 1 (eS_Preprocess) // run preprocess operations for the current frame if ((SRendItem::m_RendItems[nList][nums].SortVal.i.High >> 26) == eS_PreProcess) nums += EF_Preprocess(&SRendItem::m_RendItems[nList][0], nums, nume); if (m_RP.m_PersFlags & RBPF_IGNORERENDERING) return; } else if (nList==EFSLIST_DISTSORT_ID) { PROFILE_FRAME(State_SortingDist); SRendItem::mfSortByDist(&SRendItem::m_RendItems[nList][nums], nume-nums); } #ifdef PIPE_USE_INSTANCING else if (nList==EFSLIST_STENCIL_ID) { PROFILE_FRAME(State_Sorting); int nStart = nums; for (i=nums; iItem->mfGetType(); if (Type == eDATA_ClearStencil || Type == eDATA_TriMeshShadow) { SRendItem::mfSortForStencil(&SRendItem::m_RendItems[nList][nStart], i-nStart); do { i++; if (i >= nume) break; ri = &SRendItem::m_RendItems[nList][i]; Type = ri->Item->mfGetType(); } while(Type == eDATA_ClearStencil || Type == eDATA_TriMeshShadow); nStart = i; i--; } } SRendItem::mfSortForStencil(&SRendItem::m_RendItems[nList][nStart], i-nStart); } #endif EF_PreRender(3); // if (!m_RP.m_CurPortal) // return; m_RP.m_Flags |= RBF_3D; glPushMatrix(); /*float plane[4]; { plane[0] = 0; plane[1] = 0; plane[2] = 1; plane[3] = -50; EF_SetClipPlane(true, plane, false); }*/ PROFILE_FRAME(DrawShader_PipeLine); UnINT64 oldVal; oldVal.SortVal = -1; nCurObject = -2; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; m_RP.m_pPrevObject = m_RP.m_pCurObject; nCurFog = 0; pCurShader = NULL; pCurShaderState = NULL; pCurRes = NULL; bool bIgnore = false; bool bChanged; bool bUseBatching = (RenderFunc == EF_Flush); for (i=nums; iItem; #ifndef PIPE_USE_INSTANCING if (ri->SortVal.SortVal == oldVal.SortVal) { if (bIgnore) continue; // Optimizations: not necessary to check of changing shaders and objects // if sort value is the same (contains the same info about shaders, objects, fog volumes, ...) { //PROFILE_FRAME_TOTAL(Mesh_REPrepare); re->mfPrepare(); } continue; } oldVal.SortVal = ri->SortVal.SortVal; SRendItem::mfGet(ri->SortVal, &nObject, &pShader, &pShaderState, &nFog, &pRes); bChanged = (pShader != pCurShader || pCurRes != pRes || pShaderState != pCurShaderState || nFog != nCurFog); #else if (oldVal.i.High == ri->SortVal.i.High && !((oldVal.i.Low ^ ri->SortVal.i.Low) & 0x000fffff)) { SRendItem::mfGetObj(ri->SortVal, &nObject); bChanged = false; } else { SRendItem::mfGet(ri->SortVal, &nObject, &pShader, &pShaderState, &nFog, &pRes); bChanged = true; } oldVal.SortVal = ri->SortVal.SortVal; #endif if (nObject != nCurObject) { if (!bChanged && !pShader->m_Deforms && bUseBatching) { if (EF_TryToMerge(nObject, nCurObject, pRE)) continue; } if (pCurShader) { m_RP.m_pRenderFunc(); pCurShader = NULL; bChanged = true; } if (!EF_ObjectChange(pShader, pRes, nObject, pRE)) { bIgnore = true; continue; } bIgnore = false; nCurObject = nObject; } if (bChanged) { if (pCurShader) m_RP.m_pRenderFunc(); EF_Start(pShader, pShaderState, pRes, nFog, pRE); nCurFog = nFog; pCurShader = pShader; pCurShaderState = pShaderState; pCurRes = pRes; } { //PROFILE_FRAME_TOTAL(Mesh_REPrepare); pRE->mfPrepare(); } } if (pCurShader) m_RP.m_pRenderFunc(); m_RP.m_pRE = NULL; if (m_RP.m_PersFlags & RBPF_SETCLIPPLANE) { EF_SetClipPlane(false, NULL, false); m_RP.m_PersFlags &= ~RBPF_SETCLIPPLANE; } glDepthRange(m_RP.m_fMinDepthRange, m_RP.m_fMaxDepthRange); EF_ObjectChange(NULL, NULL, 0, NULL); m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; glPopMatrix(); //EF_SetClipPlane(false, plane, false); SArrayPointer::m_CurEnabled = PFE_POINTER_VERT; m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_PS2NEEDSET | RBPF_TSNEEDSET | RBPF_VSNEEDSET); m_RP.m_CurrentVLights = 0; m_RP.m_FlagsModificators = 0; m_RP.m_FlagsPerFlush = 0; EF_CommitPS(); EF_CommitVS(); EF_CommitStreams(); EF_CommitVLights(); m_RP.m_Flags &= ~RBF_3D; CGLTexMan::BindNULL(1); EF_SelectTMU(0); EF_Scissor(false, 0, 0, 0, 0); m_RP.m_pShader = NULL; #ifdef DO_RENDERLOG if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** End pipeline list ***\n\n"); #endif m_RP.m_pCurObject = pSavedObj; } void CGLRenderer::EF_DrawWire() { if (CV_r_showlines == 1) gcpOGL->EF_SetState(GS_POLYLINE | GS_NODEPTHTEST); else if (CV_r_showlines == 2) gcpOGL->EF_SetState(GS_POLYLINE); gcpOGL->SetMaterialColor(1,1,1,1); gRenDev->m_TexMan->m_Text_White->Set(); gcpOGL->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); if (gcpOGL->m_RP.m_pRE) gcpOGL->m_RP.m_pRE->mfCheckUpdate(gcpOGL->m_RP.m_pShader->m_VertexFormatId, 0); gcpOGL->EF_SetObjectTransform(gcpOGL->m_RP.m_pCurObject, NULL, gcpOGL->m_RP.m_pCurObject->m_ObjFlags); int StrVrt; void *verts = (void *)gcpOGL->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, 0); glVertexPointer(3, GL_FLOAT, StrVrt, verts); SArrayPointer_Vertex::m_pLastPointer = verts; glEnableClientState(GL_VERTEX_ARRAY); gcpOGL->EF_Draw(gcpOGL->m_RP.m_pShader, NULL); } void CGLRenderer::EF_DrawNormals() { gcpOGL->EF_SetObjectTransform(gcpOGL->m_RP.m_pCurObject, NULL, gcpOGL->m_RP.m_pCurObject->m_ObjFlags); float len = CRenderer::CV_r_normalslength; if (gcpOGL->m_bEditor) len *= 100.0f; if (gcpOGL->m_RP.m_pRE) gcpOGL->m_RP.m_pRE->mfCheckUpdate(gcpOGL->m_RP.m_pShader->m_VertexFormatId, SHPF_NORMALS); int StrVrt, StrNrm; int flags = CV_r_shownormals==1 ? (FGP_SRC | FGP_REAL) : (FGP_REAL); byte *verts = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, flags); byte *norms = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_Normal, &StrNrm, GL_FLOAT, eSrcPointer_Normal, flags); if (((UINT_PTR)norms|(UINT_PTR)verts) > 256) { int numVerts = gcpOGL->m_RP.m_RendNumVerts; float e[3]; gRenDev->m_TexMan->m_Text_White->Set(); gcpOGL->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); gRenDev->EF_SetState(GS_POLYLINE); glBegin(GL_LINES); for (int v=0; vEF_SetState(GS_DEPTHWRITE); } } void CGLRenderer::EF_DrawTangents() { gcpOGL->EF_SetObjectTransform(gcpOGL->m_RP.m_pCurObject, NULL, gcpOGL->m_RP.m_pCurObject->m_ObjFlags); //tangent, binormal, normal float len = CRenderer::CV_r_normalslength; if (gcpOGL->m_bEditor) len *= 100.0f; if (gcpOGL->m_RP.m_pRE) gcpOGL->m_RP.m_pRE->mfCheckUpdate(gcpOGL->m_RP.m_pShader->m_VertexFormatId, SHPF_TANGENTS); int StrVrt, StrTang, StrBinorm, StrTNorm; byte *verts = NULL; byte *tangs = NULL; byte *binorm = NULL; byte *tnorm = NULL; int flags = 0; if (CRenderer::CV_r_showtangents == 1) flags = FGP_SRC | FGP_REAL; else flags = FGP_REAL; verts = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, flags); tangs = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_Tangent, &StrTang, GL_FLOAT, eSrcPointer_Tangent, flags); binorm = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_Binormal, &StrBinorm, GL_FLOAT, eSrcPointer_Binormal, flags); tnorm = (byte *)gcpOGL->EF_GetPointer(eSrcPointer_TNormal, &StrTNorm, GL_FLOAT, eSrcPointer_TNormal, flags); if (((UINT_PTR)tangs|(UINT_PTR)binorm|(UINT_PTR)tnorm)>256) { int numVerts = gcpOGL->m_RP.m_RendNumVerts; float e[3]; gRenDev->m_TexMan->m_Text_White->Set(); gcpOGL->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); if (gcpOGL->m_polygon_mode == R_SOLID_MODE) gcpOGL->EF_SetState(GS_POLYLINE); else gcpOGL->EF_SetState(0); glBegin(GL_LINES); for (int v=0; vEF_SetState(GS_DEPTHWRITE); } void CGLRenderer::EF_DrawDebugLights() { static int sFrame = 0; if (m_nFrameID != sFrame) { int i; sFrame = m_nFrameID; for (i=0; iGetString(); if (strcmp(str, "0") != 0) { if (!dl->m_Name || !strstr(dl->m_Name, str)) continue; } SetMaterialColor(dl->m_Color[0], dl->m_Color[1], dl->m_Color[2], dl->m_Color[3]); if (dl->m_Flags & DLF_DIRECTIONAL) DrawPoint(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], 10); else if (dl->m_Flags & DLF_POINT) DrawBall(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], 0.05f); if (dl->m_Flags & DLF_PROJECT) { Vec3d dir, rgt, org; EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); dir = dl->m_Orientation.m_vForward; rgt = dl->m_Orientation.m_vRight; float ang = dl->m_fLightFrustumAngle; if (ang == 0) ang = 45.0f; org = dl->m_Origin; dir *= 0.3f; CFColor Col = dl->m_Color; Matrix44 m; Vec3d vertex = dir; // vertex = m.GetRotation(rgt, ang)*vertex; vertex = Matrix33::CreateRotationAA(DEG2RAD(ang),GetNormalized(rgt)) * vertex; //NOTE: angle need to be in radians // Matrix mat = m.GetRotation(dir, 60); Matrix44 mat = Matrix33::CreateRotationAA(DEG2RAD(60),GetNormalized(dir)); //NOTE: angle need to be in radians Vec3d tmpvertex; int ctr; //fill the inside of the light glDisable(GL_TEXTURE_2D); CFColor cl = Col*0.3f; glColor3fv(&cl[0]); glBegin(GL_TRIANGLE_FAN); glVertex3fv(&org[0]); glColor3fv(&Col[0]); tmpvertex = org + vertex; glVertex3fv((float*) &tmpvertex); for (ctr=0; ctr<6; ctr++) { vertex = mat * vertex; Vec3d tmpvertex = org + vertex; glVertex3fv((float*) &tmpvertex); } glEnd(); //draw the inside of the light with lines and the outside filled glPolygonMode(GL_FRONT, GL_LINE); glDisable(GL_CULL_FACE); glColor3f(0.3f,0.3f, 0.3f); glBegin(GL_TRIANGLE_FAN); glVertex3fv(&org[0]); glColor3f(1,1,1); tmpvertex = org + vertex; glVertex3fv(&tmpvertex[0]); for (ctr=0; ctr<6; ctr++) { vertex = mat * vertex; Vec3d tmpvertex = org + vertex; glVertex3fv(&tmpvertex[0]); } glEnd(); glEnable(GL_CULL_FACE); glPolygonMode(GL_FRONT, GL_FILL); //set the color to the color of the light glColor3fv(&Col[0]); //draw a point at the origin of the light glBegin(GL_POINTS); glVertex3fv(&org[0]); glEnd(); //draw a line in the center of the light glBegin(GL_LINES); glVertex3fv(&org[0]); glVertex3fv(&(org + dir)[0]); glEnd(); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_TEXTURE_2D); } if (((CV_r_debuglights==2) || (CV_r_debuglights==3)) && !(dl->m_Flags & DLF_DIRECTIONAL)) { EF_SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA); SetCullMode(R_CULL_NONE); SetMaterialColor(dl->m_Color[0], dl->m_Color[1], dl->m_Color[2], 0.25f); DrawBall(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], dl->m_fRadius); } } } } void CGLRenderer::EF_DrawDebugTools() { //ResetToDefault(); if (CV_r_showlines) { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Restart pipeline for wire-frame ***\n"); EF_RenderPipeLine(EF_DrawWire); } if (CV_r_shownormals) EF_RenderPipeLine(EF_DrawNormals); if (CV_r_showtangents) EF_RenderPipeLine(EF_DrawTangents); if (SRendItem::m_RecurseLevel==1 && CV_r_debuglights) EF_DrawDebugLights(); } int TimeProfCallback( const VOID* arg1, const VOID* arg2 ) { SProfInfo *pi1 = (SProfInfo *)arg1; SProfInfo *pi2 = (SProfInfo *)arg2; if (pi1->ef->m_fProfileTime > pi2->ef->m_fProfileTime) return -1; if (pi1->ef->m_fProfileTime < pi2->ef->m_fProfileTime) return 1; return 0; } int NameCallback( const VOID* arg1, const VOID* arg2 ) { SProfInfo *pi1 = (SProfInfo *)arg1; SProfInfo *pi2 = (SProfInfo *)arg2; if (pi1->ef > pi2->ef) return -1; if (pi1->ef < pi2->ef) return 1; return 0; } Matrix33 m33; void CGLRenderer::EF_PrintProfileInfo() { double fTime = 0; int i; if (CV_r_profileshaders) { // group by name qsort(&m_RP.m_Profile[0], m_RP.m_Profile.Num(), sizeof(SProfInfo), NameCallback ); for(i=0; im_fProfileTime = (float)(m_RP.m_Profile[i].Time+m_RP.m_Profile[i].ef->m_fProfileTime*50)/51.0f; } TextToScreenColor(1,14, 0,2,0,1, "Items: %d, Batches: %d, Obj: %d, DrawCalls: %d, Text: %d, Stat: %d, PShad: %d, VShad: %d", m_RP.m_PS.m_NumRendItems, m_RP.m_PS.m_NumRendBatches, m_RP.m_PS.m_NumRendObjects, m_RP.m_PS.m_NumDrawCalls, m_RP.m_PS.m_NumTextChanges, m_RP.m_PS.m_NumStateChanges, m_RP.m_PS.m_NumPShadChanges, m_RP.m_PS.m_NumVShadChanges); TextToScreenColor(1,17, 0,2,0,1, "VShad: %d, PShad: %d, Text: %d, Lit Shaders: %d", m_RP.m_PS.m_NumVShaders, m_RP.m_PS.m_NumPShaders, m_RP.m_PS.m_NumTextures, m_RP.m_PS.m_NumLitShaders); TextToScreenColor(1,20, 0,2,0,1, "Preprocess: %8.02f ms, Occl. queries: %8.02f ms", m_RP.m_PS.m_fPreprocessTime, m_RP.m_PS.m_fOcclusionTime); TextToScreenColor(1,23, 0,2,0,1, "Skinning: %8.02f ms (Skinned Objects: %d)", m_RP.m_PS.m_fSkinningTime, m_RP.m_PS.m_NumRendSkinnedObjects); int nLine; { // sort by interpolated time and print qsort(&m_RP.m_Profile[0], m_RP.m_Profile.Num(), sizeof(SProfInfo), TimeProfCallback ); for(nLine=0; nLine= 18) continue; m_RP.m_Profile[nLine].ef->m_fProfileTime = (float)(m_RP.m_Profile[nLine].ef->m_fProfileTime + m_RP.m_Profile[nLine].Time); TextToScreenColor(4,(24+(nLine*3)), 1,0,0,1, "%8.02f ms, %5d polys, '%s', %d item(s)", m_RP.m_Profile[nLine].Time, m_RP.m_Profile[nLine].NumPolys, m_RP.m_Profile[nLine].ef->m_Name.c_str(), m_RP.m_Profile[nLine].m_nItems+1); } } int nShaders = nLine; if (nLine > 18) nLine = 18; TextToScreenColor(8,(26+(nLine*3)), 0,2,0,1, "Total unique shaders: %d", nShaders); TextToScreenColor(8,(29+(nLine*3)), 0,2,0,1, "Total flush time: %8.02f ms", fTime); TextToScreenColor(8,(32+(nLine*3)), 0,2,0,1, "Total shaders processing time: %8.02f ms", m_RP.m_PS.m_fFlushTime); /*{ int i = 0; double timeC = 0; double timeC33 = 0; double timeSSE = 0; double time3DN = 0; _declspec(align(16)) Matrix m; m = m_cam.GetMatrix(); int ft = m_Cpu->mCpu[0].mFeatures; m_Cpu->mCpu[0].mFeatures &= ~(CFI_SSE | CFI_3DNOW); m_RP.m_pCurObject = m_RP.m_VisObjects[0]; Matrix33 m31; Matrix33 m32; ticks(timeC33); for (i=0; i<100000; i++) { SGLFuncs::glMultMatrix33(m33, m31, m32); } unticks(timeC33); ticks(timeC); for (i=0; i<100000; i++) { SGLFuncs::glMultMatrix(m_ViewMatrix.GetData(), &m[0][0], m_RP.m_pCurObject->m_Matrix.GetData()); } unticks(timeC); if (ft & CFI_SSE) { ticks(timeSSE); m_Cpu->mCpu[0].mFeatures |= CFI_SSE; for (i=0; i<100000; i++) { _declspec(align(16)) Matrix m; SGLFuncs::glMultMatrix(m_ViewMatrix.GetData(), &m[0][0], m_RP.m_pCurObject->m_Matrix.GetData()); } unticks(timeSSE); } if (ft & CFI_3DNOW) { ticks(time3DN); m_Cpu->mCpu[0].mFeatures &= ~CFI_SSE; m_Cpu->mCpu[0].mFeatures |= CFI_3DNOW; for (i=0; i<100000; i++) { _declspec(align(16)) Matrix m; SGLFuncs::glMultMatrix(m_ViewMatrix.GetData(), &m[0][0], m_RP.m_pCurObject->m_Matrix.GetData()); } unticks(time3DN); } m_Cpu->mCpu[0].mFeatures = ft; TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC %8.02f ms, TimeC33 %8.02f ms,, TimeSSE %8.02f ms, Time3DN %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeC33*1000.0*m_RP.m_SecondsPerCycle), (float)(timeSSE*1000.0*m_RP.m_SecondsPerCycle), (float)(time3DN*1000.0*m_RP.m_SecondsPerCycle)); }*/ /*{ int i = 0; double timeC = 0; double timeC33 = 0; double time3DN = 0; double timeSSE = 0; _declspec(align(16)) Matrix m, mOut; m = m_cam.GetMatrix(); m_RP.m_pCurObject = m_RP.m_VisObjects[0]; Matrix33 m31; Matrix33 m32; m31.SetIdentity33(); ticks(timeC33); for (i=0; i<100000; i++) { m31.Invert33(); } unticks(timeC33); ticks(timeC); for (i=0; i<100000; i++) { QQinvertMatrixf(mOut.GetData(), m.GetData()); } unticks(timeC); if (m_Cpu->mCpu[0].mFeatures & CFI_3DNOW) { ticks(time3DN); for (i=0; i<100000; i++) { invertMatrixf_3DNow(mOut.GetData(), m.GetData()); } unticks(time3DN); } ticks(timeSSE); for (i=0; i<100000; i++) { invertMatrixf_SSE(mOut.GetData(), m.GetData()); } unticks(timeSSE); TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC: %8.02f ms, TimeC33: %8.02f ms,, Time3DN: %8.02f ms, TimeSSE: %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeC33*1000.0*m_RP.m_SecondsPerCycle), (float)(time3DN*1000.0*m_RP.m_SecondsPerCycle), (float)(timeSSE*1000.0*m_RP.m_SecondsPerCycle)); }*/ /*{ int i = 0; double timeC = 0; double timeMMX = 0; byte *dataSrc = new byte[1024*1024*10]; byte *dataDst = new byte[1024*1024*10]; ticks(timeC); for (i=0; i<10; i++) { memcpy(dataDst, dataSrc, 1024*1024*10); } unticks(timeC); ticks(timeMMX); for (i=0; i<10; i++) { cryMemcpy(dataDst, dataSrc, 1024*1024*10); } unticks(timeMMX); delete [] dataSrc; delete [] dataDst; TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC: %8.02f ms, TimeMMX: %8.02f ms: %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeMMX*1000.0*m_RP.m_SecondsPerCycle)); }*/ } void CGLRenderer::EF_DrawREPreprocess(SRendItemPreprocess *ris, int Nums) { int i; CCObject *savedObj; SShader *Shader, *CurShader, *ShaderState, *CurShaderState; SRenderShaderResources *Res, *CurRes; int nObject, nCurObject; int nFog, nCurFog; if (Nums < 1) return; savedObj = m_RP.m_pCurObject; EF_PreRender(3); glPushMatrix(); UnINT64 oldVal; oldVal.SortVal = -1; nCurObject = -2; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; m_RP.m_pPrevObject = m_RP.m_pCurObject; nCurFog = 0; CurShader = NULL; CurShaderState = NULL; CurRes = NULL; for (i=0; iItem; if (ri->SortVal.SortVal == oldVal.SortVal) { // Optimizations: not necessary to check of changing shaders and objects // if sort value is the same (consist the same info about shaders, objects, fog volumes, ...) re->mfPrepare(); continue; } oldVal.SortVal = ri->SortVal.SortVal; SRendItem::mfGet(ri->SortVal, &nObject, &Shader, &ShaderState, &nFog, &Res); if (nObject != nCurObject) { if (CurShader) EF_Flush(); if (!EF_ObjectChange(Shader, Res, nObject, re)) continue; nCurObject = nObject; } if (Shader != CurShader || Res != CurRes || ShaderState != CurShaderState || nFog != nCurFog) { if (CurShader) EF_Flush(); EF_Start(Shader, ShaderState, Res, nFog, re); nCurFog = nFog; CurShader = Shader; CurShaderState = ShaderState; CurRes = Res; } re->mfPrepare(); } if (CurShader) EF_Flush(); glDepthRange(m_RP.m_fMinDepthRange, m_RP.m_fMaxDepthRange); //ResetToDefault(); glPopMatrix(); m_RP.m_pCurObject = savedObj; } struct SPreprocess { int m_nPreprocess; int m_Num; int m_nObject; SShader *m_Shader; SRenderShaderResources *m_pRes; CRendElement *m_RE; }; STWarpZone *CGLRenderer::EF_SetWarpZone(SWarpSurf *sf, int *NumWarps, STWarpZone Warps[]) { int i; STWarpZone *wp; Plane p, pl; sf->srf->mfGetPlane(pl); if (sf->nobj > 0) { p = pl; CCObject *obj = m_RP.m_VisObjects[sf->nobj]; pl = TransformPlane(obj->GetMatrix(), p); } for (i=0; inumSrf = 0; wp->plane.d = pl.d; wp->plane.n = pl.n; } EF_UpdateWarpZone(&Warps[i], sf); return &Warps[i]; } void CGLRenderer::EF_UpdateWarpZone(STWarpZone *wp, SWarpSurf *srf) { if (wp->numSrf == MAX_WARPSURFS) return; wp->Surfs[wp->numSrf].nobj = srf->nobj; wp->Surfs[wp->numSrf].Shader = srf->Shader; wp->Surfs[wp->numSrf].ShaderRes = srf->ShaderRes; wp->Surfs[wp->numSrf].srf = srf->srf; wp->numSrf++; } bool CGLRenderer::EF_CalcWarpCamera(STWarpZone *wp, int nObject, CCamera& prevCam, CCamera& newCam) { Vec3d vPrevPos = prevCam.GetPos(); Vec3d vPrevAngs = prevCam.GetAngles(); Vec3d vNewPos, vNewOccPos, vNewAngs; bool bMirror = true; if (nObject > 0) { CCObject *pObj = m_RP.m_VisObjects[nObject]; if (pObj->m_ObjFlags & FOB_PORTAL) { bMirror = false; m_RP.m_PersFlags &= ~RBPF_DRAWMIRROR; m_RP.m_PersFlags |= RBPF_DRAWPORTAL; vNewPos = Vec3d(pObj->m_Trans2[0], pObj->m_Trans2[1], pObj->m_Trans2[2]); vNewOccPos = vNewPos; vNewAngs = Vec3d(pObj->m_Angs2[0], pObj->m_Angs2[1], pObj->m_Angs2[2]); } } if (bMirror) { float fDot = vPrevPos.Dot(wp->plane.n) - wp->plane.d; vNewPos = vPrevPos + wp->plane.n * -2.0f*fDot; vNewOccPos = vPrevPos + wp->plane.n * -0.99f*fDot; if (fDot < 0) m_RP.m_MirrorClipSide = 1; else m_RP.m_MirrorClipSide = 2; fDot = m_RP.m_CamVecs[0].Dot(wp->plane.n); Vec3d vNewDir = m_RP.m_CamVecs[0] + wp->plane.n * -2.0f*fDot; vNewAngs[0] = cry_asinf (vNewDir[2])/M_PI*180.0f; vNewAngs[1] = vPrevAngs[1] + 180.0f; vNewAngs[2] = -cry_atan2f (vNewDir[0], -vNewDir[1])/M_PI*180.0f; m_RP.m_PersFlags &= ~RBPF_DRAWPORTAL; m_RP.m_PersFlags |= RBPF_DRAWMIRROR; } newCam.SetPos(vNewPos); newCam.SetOccPos(vNewOccPos); newCam.SetAngle(vNewAngs); if (bMirror) newCam.SetScale(Vec3d(-1.0f, 1.0f, 1.0f)); newCam.Update(); return true; } bool CGLRenderer::EF_RenderWarpZone(STWarpZone *wp) { if (!wp->numSrf) return false; CCamera prevCam = GetCamera(); CCamera newCam = prevCam; int prevFlags = m_RP.m_PersFlags; if (!EF_CalcWarpCamera(wp, wp->Surfs[0].nobj, prevCam, newCam)) return false; if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "\n ********** Start Render Portal **********\n"); STWarpZone *prevWarp = m_RP.m_CurWarp; m_RP.m_CurWarp = wp; glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); iSystem->SetViewCamera(newCam); SetCamera(newCam); float plane[4]; plane[0] = wp->plane.n[0]; plane[1] = wp->plane.n[1]; plane[2] = wp->plane.n[2]; plane[3] = -wp->plane.d; EF_PushFog(); EF_SetClipPlane(true, plane, false); I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine(); eng->DrawLowDetail(DLD_TERRAIN_WATER | DLD_DETAIL_TEXTURES | DLD_DETAIL_OBJECTS | DLD_FAR_SPRITES | DLD_ENTITIES | DLD_STATIC_OBJECTS); /*unsigned char *pic=new unsigned char [m_width*m_height*4]; glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, pic); WriteTGA(pic, m_width, m_height,"Warp.tga"); delete [] pic;*/ if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "\n ********** End Render Portal **********\n"); m_RP.m_PersFlags &= ~(RBPF_DRAWMIRROR | RBPF_DRAWPORTAL); m_RP.m_PersFlags |= prevFlags & (RBPF_DRAWMIRROR | RBPF_DRAWPORTAL); EF_SetClipPlane(false, plane, false); EF_PopFog(); m_RP.m_CurWarp = prevWarp; iSystem->SetViewCamera(prevCam); SetCamera(prevCam); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); return true; } static _inline int Compare(SPreprocess &a, SPreprocess &b) { int nPr1 = a.m_nPreprocess; int nPr2 = b.m_nPreprocess; if (nPr1 < nPr2) return -1; if (nPr1 > nPr2) return 1; return 0; } void CGLRenderer::EF_FlushRefractedObjects(SShader *pSHRefr[], CRendElement *pRERefr[], CCObject *pObjRefr[], int nRefrObjects, int nRefrFlags, int DLDFlags) { if (nRefrFlags & 2) { Vec3d Angs = GetCamera().GetAngles(); Vec3d Pos = GetCamera().GetPos(); m_RP.m_PersFlags |= RBPF_IGNOREREFRACTED; if (nRefrObjects > 1) pSHRefr[0] = NULL; float fMinDist = 99999.0f; int nSelectObj = -1; for (int i=0; imfMinDistanceToCamera(pObjRefr[i]); if (fMinDist > fDist) { fMinDist = fDist; nSelectObj = i; } } if (nSelectObj >= 0) { m_RP.m_pRE = pRERefr[nSelectObj]; m_RP.m_pCurObject = pObjRefr[nSelectObj]; SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvTex(Pos, Angs, false, DLDFlags, true, pSHRefr[0], NULL, NULL, false, NULL); } m_RP.m_PersFlags &= ~RBPF_IGNOREREFRACTED; } if (nRefrFlags & 1) { m_RP.m_bDrawToTexture = true; m_TexMan->StartRefractMap(TO_REFRACTMAP); m_RP.m_PersFlags |= RBPF_ONLYREFRACTED; EF_RenderPipeLine(EF_Flush); m_RP.m_PersFlags &= ~RBPF_ONLYREFRACTED; m_TexMan->EndRefractMap(); // m_TexMan->StartScreenTexMap(TO_SCREENMAP); // EF_RenderPipeLine(EF_Flush); // m_TexMan->EndScreenTexMap(); m_RP.m_bDrawToTexture = false; //m_RP.m_PersFlags |= RBPF_ONLYREFRACTED; //m_RP.m_PersFlags |= RBPF_IGNORERENDERING; } } int CGLRenderer::EF_Preprocess(SRendItemPre *ri, int nums, int nume) { int i, j, nNumItems; SShader *Shader; SShader *ShaderState; SRenderShaderResources *Res; int nObject; int nFog; TArray Procs; SPreprocess Proc; TArray RIs; SWarpSurf srfs[1024]; int nPortals = 0; int nRefractedStuff = 0; int NumWarps = 0; STWarpZone Warps[MAX_WARPS]; STWarpZone *wp; double time0 = 0; ticks(time0); if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "\n\n*** Start preprocess frame ***\n"); int nReturn = 0; for (i=nums; i> 26) != eS_PreProcess) break; nReturn++; for (j=0; j<32; j++) { int nMask = 1<= FSPR_MAX || nMask > Shader->m_nPreprocess) break; if (nMask & Shader->m_nPreprocess) { Proc.m_nPreprocess = j; Proc.m_Num = i; Proc.m_Shader = Shader; Proc.m_pRes = Res; Proc.m_RE = ri[i].Item; Proc.m_nObject = nObject; Procs.AddElem(Proc); } } } if (!Procs.Num()) return 0; nNumItems = Procs.Num(); ::Sort(&Procs[0], nNumItems); if (m_RP.m_pRenderFunc != EF_Flush || CV_r_nopreprocess) return nReturn; int DLDFlags = 0; int nRefrObjects = 0; SShader *pSHRefr[8]; CRendElement *pRERefr[8]; CCObject *pObjRefr[8]; for (i=0; im_Shader) continue; switch (pr->m_nPreprocess) { case SPRID_SCANCM: // Draw environment to cube texture if (!m_RP.m_bDrawToTexture) { CCObject *objIgn = m_RP.m_pIgnoreObject; Vec3d Pos; m_RP.m_pRE = pr->m_RE; if (pr->m_nObject < 0) Pos(0,0,0); else { CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0))) m_RP.m_pIgnoreObject = obj; Pos = obj->GetTranslation(); } if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Draw environment to cube-map ***\n"); if (!IsEquivalent(Pos,Vec3d(0,0,0))) { float fDistToCam = (Pos-m_cam.GetPos()).Length(); SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvCMap(Pos, false, pr->m_Shader->m_DLDFlags, fDistToCam); } m_RP.m_pIgnoreObject = objIgn; } break; case SPRID_SCANLCM: // Draw environment to cube texture if (!m_RP.m_bDrawToTexture) { CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; if ((obj->m_ObjFlags & FOB_ENVLIGHTING) && CV_r_envlighting) { CCObject *objIgn = m_RP.m_pIgnoreObject; Vec3d Pos; m_RP.m_pRE = pr->m_RE; if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0))) m_RP.m_pIgnoreObject = obj; Pos = obj->GetTranslation(); if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Draw environment to light cube-map ***\n"); if (!IsEquivalent(Pos,Vec3d(0,0,0))) { float fDistToCam = (Pos-m_cam.GetPos()).Length(); SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvLCMap(Pos, false, pr->m_Shader->m_DLDFlags, fDistToCam); } m_RP.m_pIgnoreObject = objIgn; } } break; case SPRID_SCANSCR: m_TexMan->StartScreenMap(TO_ENVIRONMENT_SCR); break; case SPRID_SCANTEXWATER: if (!m_RP.m_bDrawToTexture && CV_r_waterreflections) { if (!(gRenDev->m_TexMan->m_Text_WaterMap->m_Flags & FT_BUILD)) { I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine(); float fTimeUpd = eng->GetDistanceToSectorWithWater(); fTimeUpd *= CV_r_waterupdateFactor; if (fTimeUpd > 0.3f) fTimeUpd = 0.3f; Vec3d camAngs = GetCamera().GetAngles(); Vec3d camPos = GetCamera().GetPos(); float fDistCam = (camPos - m_RP.m_LastWaterPosUpdate).Length(); float fDistAng = (camAngs - m_RP.m_LastWaterAngleUpdate).Length(); float fFOV = GetCamera().GetFov(); if (m_RP.m_fLastWaterUpdate-1.0f > m_RP.m_RealTime) m_RP.m_fLastWaterUpdate = m_RP.m_RealTime; if (m_RP.m_RealTime-m_RP.m_fLastWaterUpdate > fTimeUpd || fDistCam > CV_r_waterupdateDistance || fDistAng>CV_r_waterupdateDeltaAngle || fFOV != m_RP.m_fLastWaterFOVUpdate) { m_RP.m_fLastWaterUpdate = m_RP.m_RealTime; m_RP.m_LastWaterAngleUpdate = camAngs; m_RP.m_fLastWaterFOVUpdate = fFOV; m_RP.m_LastWaterPosUpdate = camPos; CCamera tmp_cam = GetCamera(); Plane Pl; Pl.n = Vec3d(0,0,1); Pl.d = eng->GetWaterLevel(); Vec3d vCamPos = tmp_cam.GetPos(); if ((vCamPos | Pl.n) - Pl.d < 0) { Pl.d = -Pl.d; Pl.n = -Pl.n; } CCObject *savedObj = m_RP.m_pCurObject; CCObject *objIgn = m_RP.m_pIgnoreObject; CCObject *obj = NULL; if (pr->m_nObject > 0) { obj = m_RP.m_VisObjects[pr->m_nObject]; } m_RP.m_PersFlags |= RBPF_DONTDRAWSUN; m_RP.m_pCurObject = obj; if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0))) m_RP.m_pIgnoreObject = obj; if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Draw environment to texture for water reflections ***\n"); m_TexMan->DrawToTexture(Pl, gRenDev->m_TexMan->m_Text_WaterMap, pr->m_Shader->m_DLDFlags); m_RP.m_pCurObject = savedObj; m_RP.m_pIgnoreObject = objIgn; m_RP.m_PersFlags &= ~RBPF_DONTDRAWSUN; } } } break; case SPRID_SCANTEX: if (!m_RP.m_bDrawToTexture) { // Draw environment to texture bool bWater = (pr->m_Shader->m_nPreprocess & FSPR_SCANTEXWATER) != 0; bool bDraw = true; if (!bWater || CV_r_waterrefractions) { if (pr->m_Shader->m_fUpdateFactor > 0) { float fDist = pr->m_RE->mfMinDistanceToCamera(m_RP.m_VisObjects[pr->m_nObject]); if (fDist > 0) { fDist *= pr->m_Shader->m_fUpdateFactor; if (fDist > 0.5f) fDist = 0.5f; if (m_RP.m_RealTime-m_RP.m_pCurObject->m_fLastUpdate < fDist) bDraw = false; else m_RP.m_pCurObject->m_fLastUpdate = m_RP.m_RealTime; } } if (bDraw) { CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; Vec3d Angs = GetCamera().GetAngles(); Vec3d Pos = GetCamera().GetPos(); m_RP.m_pRE = pr->m_RE; if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Draw environment to texture ***\n"); bool bReflect = false; if ((pr->m_Shader->m_Flags3 & (EF3_CLIPPLANE_FRONT | EF3_REFLECTION))) bReflect = true; if (bReflect) { m_RP.m_PersFlags |= RBPF_DONTDRAWSUN; m_RP.m_pIgnoreObject = obj; m_RP.m_pCurObject = obj; SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvTex(Pos, Angs, false, pr->m_Shader->m_DLDFlags, false, pr->m_Shader, pr->m_pRes, obj, bReflect, pr->m_RE); m_RP.m_pIgnoreObject = NULL; } else { nRefractedStuff |= 2; DLDFlags |= pr->m_Shader->m_DLDFlags; obj->m_ObjFlags |= FOB_REFRACTED; pSHRefr[nRefrObjects] = pr->m_Shader; pRERefr[nRefrObjects] = pr->m_RE; pObjRefr[nRefrObjects] = obj; if (nRefrObjects != 7) nRefrObjects++; } } } } break; case SPRID_RAINOVERLAY: if (!m_RP.m_bDrawToTexture) m_TexMan->DrawToTextureForRainMap(TO_RAINMAP); break; case SPRID_REFRACTED: if (!m_RP.m_bDrawToTexture) { nRefractedStuff |= 1; CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; obj->m_ObjFlags |= FOB_REFRACTED; } break; case SPRID_SCREENTEXMAP: EF_FlushRefractedObjects(pSHRefr, pRERefr, pObjRefr, nRefrObjects, nRefractedStuff, DLDFlags); nRefractedStuff = 0; nRefrObjects = 0; // copy screen to texture if (!m_RP.m_bDrawToTexture) { m_TexMan->StartScreenTexMap(TO_SCREENMAP); // check when refraction is active.. if(pr->m_RE->mfGetType() != eDATA_Dummy) { m_RP.m_PersFlags |= RBPF_IGNOREREFRACTED; m_bRefraction=1; } } break; case SPRID_SHADOWMAPGEN: { CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; m_RP.m_pCurObject = obj; if (pr->m_RE->mfGetType() == eDATA_OcLeaf || pr->m_RE->mfGetType() == eDATA_ShadowMapGen) { if(!m_RP.m_bDrawToTexture && obj->m_pShadowCasters) { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Prepare shadow maps for REOcLeaf***\n"); // prepare casters frustums for(int i=0; im_pShadowCasters->Count(); i++) { if(obj->m_pShadowCasters->GetAt(i).m_pLS) { if(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum()) PrepareDepthMap(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum(), false); m_RP.m_pCurObject = obj; // if(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustumPassiveCasters()) // PrepareDepthMap(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustumPassiveCasters(), false); // m_RP.m_pCurObject = obj; } } } } } break; case SPRID_CORONA: if (pr->m_nObject>0) { if (pr->m_RE->mfGetType() == eDATA_Flare) { CREFlare *fl = (CREFlare *)pr->m_RE; CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Check corona visibility ***\n"); bool bVis = fl->mfCheckVis(obj); } } break; case SPRID_PORTAL: { if (!CV_r_portals) continue; if (m_RP.m_RecurseLevel+1 >= MAX_PORTAL_RECURSES) continue; if (!CV_r_portalsrecursive && m_RP.m_CurWarp) continue; if (!m_RP.m_CurWarp) { srfs[nPortals].nobj = pr->m_nObject; srfs[nPortals].srf = pr->m_RE; srfs[nPortals].Shader = pr->m_Shader; nPortals++; } else { Plane pl; pr->m_RE->mfGetPlane(pl); if (m_RP.m_CurWarp->plane.d != pl.d || !IsEquivalent(m_RP.m_CurWarp->plane.n,pl.n)) { srfs[nPortals].nobj = pr->m_nObject; srfs[nPortals].srf = pr->m_RE; srfs[nPortals].Shader = pr->m_Shader; nPortals++; } } } break; default: { if (pr->m_nObject < 0) continue; SRendItemPreprocess rip; SRendItemPre *r = &ri[pr->m_Num]; rip.Item = r->Item; rip.m_Object = m_RP.m_VisObjects[pr->m_nObject]; if (rip.m_Object->m_ObjFlags & FOB_CUBE_MASK) RIs.AddElem(rip); } break; } } if (RIs.Num()) { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Preprocess pipeline ***\n"); SRendItemPreprocess::mfSort(&RIs[0], RIs.Num()); EF_DrawREPreprocess(&RIs[0], RIs.Num()); } EF_FlushRefractedObjects(pSHRefr, pRERefr, pObjRefr, nRefrObjects, nRefractedStuff, DLDFlags); if (nPortals) { for (i=0; inumSrf; j++) { SWarpSurf *ws = &wp->Surfs[j]; if (nObj != ws->nobj) { if (sh) EF_Flush(); if (!EF_ObjectChange(sh, Res, ws->nobj, ws->srf)) continue; nObj = ws->nobj; } if (ws->Shader != sh || ws->ShaderRes != Res) { if (sh) EF_Flush(); EF_Start(ws->Shader, NULL, ws->ShaderRes, 0, ws->srf); sh = ws->Shader; Res = ws->ShaderRes; } ws->srf->mfPrepare(); } if (sh) EF_Flush(); } m_RP.m_RecurseLevel--; } if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** End preprocess frame ***\n"); unticks(time0); m_RP.m_PS.m_fPreprocessTime += (float)(time0*1000.0*g_SecondsPerCycle); return nReturn; } void CGLRenderer::EF_EndEf2D(bool bSort) { int i; SShader *Shader, *CurShader, *ShaderState, *CurShaderState; SRenderShaderResources *Res, *CurRes; assert(SRendItem::m_RecurseLevel >= 1); if (SRendItem::m_RecurseLevel < 1) { iLog->Log("Error: CRenderer::EF_EndEf2D without CRenderer::EF_StartEf"); return; } EF_AddClientPolys2D(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID] = SRendItem::m_RendItems[EFSLIST_PREPROCESS_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID] = SRendItem::m_RendItems[EFSLIST_STENCIL_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID] = SRendItem::m_RendItems[EFSLIST_GENERAL_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID] = SRendItem::m_RendItems[EFSLIST_UNSORTED_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID] = SRendItem::m_RendItems[EFSLIST_DISTSORT_ID].Num(); SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID] = SRendItem::m_RendItems[EFSLIST_LAST_ID].Num(); int nums = SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID]; int nume = SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID]; if (bSort) { SRendItem::mfSort(&SRendItem::m_RendItems[0][0], nume); // If sort number of the first shader is 1 (eS_Preprocess) // run preprocess operations for the current list if ((SRendItem::m_RendItems[0][nums].SortVal.i.High >> 26) == eS_PreProcess) nums += EF_Preprocess(&SRendItem::m_RendItems[0][0], nums, nume); } EF_PreRender(3); CurShader = NULL; CurRes = NULL; CurShaderState = NULL; UnINT64 oldVal; oldVal.SortVal = -1; m_RP.m_Flags = RBF_2D; for (i=nums; iItem; if (ri->SortVal.SortVal == oldVal.SortVal) { re->mfPrepare(); continue; } oldVal.SortVal = ri->SortVal.SortVal; SRendItem::mfGet(ri->SortVal, &Shader, &ShaderState, &Res); if (Shader != CurShader || Res != CurRes || ShaderState != CurShaderState) { if (CurShader) EF_Flush(); EF_Start(Shader, ShaderState, Res, re); CurShader = Shader; CurShaderState = ShaderState; CurRes = Res; } re->mfPrepare(); } if (CurShader) EF_Flush(); //ResetToDefault(); EF_RemovePolysFromScene(); }