/*============================================================================= D3DRendPipeline.cpp : Direct3D specific rendering using shaders pipeline. Copyright (c) 2001 Crytek Studios. All Rights Reserved. Revision history: * Created by Honitch Andrey =============================================================================*/ #include "RenderPCH.h" #include "DriverD3D9.h" #include #include "..\common\shadow_renderer.h" #include "D3DCGPShader.h" #include "D3DCGVProgram.h" #include "I3dengine.h" #include "CryHeaders.h" //============================================================================================ // Shaders rendering //============================================================================================ //============================================================================================ // Init Shaders rendering void CD3D9Renderer::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 CD3D9Renderer::EF_InitWaveTables() { int i; //Init wave Tables for (i=0; i<1024; i++) { float f = (float)i; m_RP.m_tSinTable[i] = sin_tpl(f * (360.0f/1023.0f) * M_PI / 180.0f); m_RP.m_tHalfSinTable[i] = sin_tpl(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] = cos_tpl(f * (360.0f/1023.0f) * M_PI / 180.0f); m_RP.m_tHillTable[i] = sin_tpl(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 CD3D9Renderer::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; } } int CD3D9Renderer::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; } } // Init vertex declarations (for fixed pipeline and for programmable pipeline) void CD3D9Renderer::EF_InitD3DFixedPipeline() { if (m_RP.m_D3DFixedPipeline[0][0].m_Declaration.Num()) return; int i, j; SBufInfoTable *pOffs; // base formats declarations (stream 0) int n = 0; pOffs = &gBufInfoTable[n]; { m_RP.m_D3DFixedPipeline[0][n].m_Handle = 0; D3DVERTEXELEMENT9 elem[] = { D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 1; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 2; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_COL4UB m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 3; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 4; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_COL4UB_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 5; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_TRP3F_COL4UB_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 6; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_COL4UB_COL4UB m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // normal {0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 7; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 8; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N_COL4UB m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 9; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 10; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N_COL4UB_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 11; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N_COL4UB_COL4UB m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_SPECULAR; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 12; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_COL4UB_COL4UB_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 13; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_N_COL4UB_COL4UB_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 14; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_T3F_B3F_N3F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_TEX3; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // tangent {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, // binormal {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, // tnormal D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 15; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_T2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // tangent D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } n = 16; pOffs = &gBufInfoTable[n]; { // VERTEX_FORMAT_P3F_COL4UB_TEX2F_TEX2F m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2; D3DVERTEXELEMENT9 elem[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position {0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse {0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0 {0, pOffs->OffsTC+8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // texture1 D3DDECL_END() }; i = 0; while (true) { m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration if (elem[i++].Stream == 0xff) break; } m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink(); m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL; } // Additional streams: // stream 1 (tangent vectors) for (i=0; iLog("Direct3D texture streaming log file '%s' opened\n", "Direct3DLogStreaming.txt"); char time[128]; char date[128]; _strtime( time ); _strdate( date ); fprintf(m_LogFileStr, "\n==========================================\n"); fprintf(m_LogFileStr, "Direct3D Textures streaming Log file opened: %s (%s)\n", date, time); fprintf(m_LogFileStr, "==========================================\n"); } } m_RP.m_pCurFuncs = NULL; m_RP.m_MaxVerts = CV_d3d9_rb_verts; m_RP.m_MaxTris = CV_d3d9_rb_tris; iLog->Log("\nAllocate render buffer (%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; 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; } byte *buf = new byte [n]; m_SysArray = buf; if (!buf) iConsole->Exit("Can't allocate buffers for RB"); 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_RendIndices = (ushort *)sAlign0x20(buf); m_RP.m_SysRendIndices = m_RP.m_RendIndices; buf += sizeof(ushort)*3*m_RP.m_MaxTris+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; 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; } EF_Restore(); EF_InitWaveTables(); EF_InitRandTables(); EF_InitEvalFuncs(0); EF_InitFogVolumes(); EF_InitD3DFixedPipeline(); for (i=0; iInit(); 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(m_pd3dDevice, m_RP.m_MaxTris*3); m_RP.m_VB_Inst = new DynamicVB (m_pd3dDevice, 0, MAX_HWINST_PARAMS); for (j=0; j(m_pd3dDevice, 0, m_RP.m_MaxVerts*8); } } // Shutdown shaders pipeline void CD3D9Renderer::EF_PipelineShutdown() { int i, j; EF_Invalidate(); CCObject::m_Waves.Free(); SAFE_DELETE_ARRAY(m_RP.m_VisObjects); SAFE_DELETE_ARRAY(m_SysArray); m_RP.m_FogVolumes.Free(); SAFE_RELEASE(m_RP.m_pREGlare); for (i=0; imfReset(); } } if (nFlags & EFRF_PSHADERS) { for (i=0; imfReset(); } } } void DrawFullScreenQuad(float fLeftU, float fTopV, float fRightU, float fBottomV); // Clear buffers (color, depth/stencil) void CD3D9Renderer::EF_ClearBuffers(bool bForce, bool bOnlyDepth, float *Colors) { if (m_bWasCleared && !bForce) return; m_bWasCleared = true; DWORD cColor; if (Colors) cColor = D3DRGBA(Colors[0], Colors[1], Colors[2], Colors[3]); else if(m_polygon_mode==R_WIREFRAME_MODE) { m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME ); cColor = D3DRGBA(0.25,0.5,1,0); } else { m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); cColor = D3DRGBA(m_vClearColor[0], m_vClearColor[1], m_vClearColor[2], 0); } int nFlags = D3DCLEAR_ZBUFFER; if (m_sbpp) nFlags |= D3DCLEAR_STENCIL; if (!bOnlyDepth) { // Fill float buffer by HDR fog color if (m_RP.m_PersFlags & RBPF_HDR) { CCGPShader_D3D *fpHDR = NULL; //if (m_nHDRType == 1) fpHDR = (CCGPShader_D3D *)PShaderForName(m_RP.m_PS_HDR_ClearScreen, "CGRC_HDR_ClearScreen_PS20"); //else //if (m_nHDRType == 2) // fpHDR = (CCGPShader_D3D *)PShaderForName(m_RP.m_PS_HDR_ClearScreen, "CGRC_HDR_ClearScreen_MRT_PS20"); if (fpHDR) { EF_SetState(GS_NODEPTHTEST); D3DSetCull(eCULL_None); m_TexMan->m_Text_White->Set(); fpHDR->mfSet(true); // Draw a fullscreen quad to sample the RT DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f); fpHDR->mfSet(false); } } else nFlags |= D3DCLEAR_TARGET; } m_pd3dDevice->Clear(0, NULL, nFlags, cColor, 1.0f, 0); if (CV_r_measureoverdraw) { if (m_sbpp <= 4) { iLog->Log("Warning: 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; } //========================================================================== // Calculate current scene node matrices void CD3D9Renderer::EF_SetCameraInfo() { m_RP.m_ViewOrg = m_cam.GetPos(); float fm[16]; GetModelViewMatrix(fm); m_ViewMatrix = (Matrix44&)fm; m_CameraMatrix = m_ViewMatrix; Matrix44 m; mathMatrixTranspose(m.GetData(), m_CameraMatrix.GetData(), g_CpuFlags); 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); 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); 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++; GetProjectionMatrix(&m_ProjMatrix(0,0)); D3DXMatrixMultiply((D3DXMATRIXA16 *)m_CameraProjMatrix.GetData(), (D3DXMATRIXA16 *)m_CameraMatrix.GetData(), (D3DXMATRIXA16 *)m_ProjMatrix.GetData()); D3DXMatrixInverse((D3DXMATRIXA16 *)m_InvCameraProjMatrix.GetData(), NULL, (D3DXMATRIXA16 *)m_CameraProjMatrix.GetData()); m_RP.m_PersFlags &= ~RBPF_WASWORLDSPACE; m_RP.m_ObjFlags = FOB_TRANS_MASK; } _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; gcpRendD3D->EF_Scissor(true, m_nScissorX1, m_nScissorY1, w, h); } else gcpRendD3D->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) { CD3D9Renderer *rd = gcpRendD3D; // 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; 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; } } } // Set object transform for fixed pipeline shader void CD3D9Renderer::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)) { m_matView->LoadMatrix((D3DXMATRIX *)m_ViewMatrix.GetData()); m_pd3dDevice->SetTransform(D3DTS_VIEW, m_matView->GetTop()); m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; } else m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED; m_bInvertedMatrix = false; } // Object changing handling (skinning, shadow maps updating, initial states setting, ...) bool CD3D9Renderer::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_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_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; if (pREOCL->m_pBuffer && pREOCL->m_pBuffer->m_pMats) { 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(obj->m_Matrix.GetTranslationOLD(), obj->m_Matrix, obj->m_nTemplId, obj->m_nLod, bForceUpdate); } unticks(time0); m_RP.m_PS.m_fSkinningTime += (float)(time0*1000.0*g_SecondsPerCycle); } // shadow map generation if (obj->m_pShadowCasters) { // process casters maps for(int i=0; im_pShadowCasters->Count(); i++) if(obj->m_pShadowCasters->GetAt(i).m_pLS && obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum()) { #ifdef DO_RENDERLOG if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Prepare shadow maps for REOcLeaf***\n"); #endif PrepareDepthMap(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum(), false); m_RP.m_pCurObject = obj; } // process receiver map /*if(obj->m_pShadowCasters->Count() && obj->m_pShadowCasters->GetAt(0).m_pLS) if(obj->m_pShadowCasters->GetAt(0).m_pLS->GetShadowMapFrustumPassiveCasters()) PrepareDepthMap(obj->m_pShadowCasters->GetAt(0).m_pLS->GetShadowMapFrustumPassiveCasters(), false); m_RP.m_pCurObject = obj;*/ } if(obj->m_ObjFlags & FOB_NEAREST) flags |= RBF_NEAREST; if ((flags ^ m_RP.m_Flags) & RBF_NEAREST) { if (flags & RBF_NEAREST) { CCamera Cam = GetCamera(); m_RP.m_PrevCamera = Cam; Cam.SetZMin(0.01f); Cam.SetZMax(40.0f); if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Prepare nearest Z range ***\n"); // set nice fov for weapons Cam.SetFov( Cam.GetFov() * 0.6666f ); SetCamera(Cam); m_Viewport.MaxZ = 0.1f; m_pd3dDevice->SetViewport(&m_Viewport); m_RP.m_Flags |= RBF_NEAREST; } else { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Restore Z range ***\n"); SetCamera(m_RP.m_PrevCamera); m_Viewport.MaxZ = 1.0f; m_pd3dDevice->SetViewport(&m_Viewport); 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) { if (m_LogFile) Logv(SRendItem::m_RecurseLevel, "*** Restore Z range ***\n"); SetCamera(m_RP.m_PrevCamera); m_Viewport.MaxZ = 1.0f; m_pd3dDevice->SetViewport(&m_Viewport); m_RP.m_Flags &= ~RBF_NEAREST; } m_RP.m_pCurObject->m_Matrix.SetIdentity(); m_ViewMatrix = m_CameraMatrix; // Restore transform if (!Shader || !(Shader->m_Flags & EF_HASVSHADER)) { m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED; m_matView->LoadMatrix((D3DXMATRIX *)&m_CameraMatrix(0,0)); m_pd3dDevice->SetTransform(D3DTS_VIEW, m_matView->GetTop()); } else m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED; m_bInvertedMatrix = false; } m_RP.m_pPrevObject = m_RP.m_pCurObject; return true; } // 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 CD3D9Renderer::EF_SetClipPlane (bool bEnable, float *pPlane, bool bRefract) { if (!CV_d3d9_clipplanes) return; if (bEnable) { #ifdef DO_RENDERLOG if (CV_r_log) Logv(SRendItem::m_RecurseLevel, "Set clip-plane\n"); #endif if (m_RP.m_ClipPlaneEnabled) return; float p[4]; p[0] = pPlane[0]; p[1] = pPlane[1]; p[2] = pPlane[2]; p[3] = pPlane[3]; //if (bRefract) //p[3] += 0.1f; m_RP.m_ClipPlaneWasOverrided = 0; m_RP.m_bClipPlaneRefract = bRefract; m_RP.m_CurClipPlane.m_Normal.x = p[0]; m_RP.m_CurClipPlane.m_Normal.y = p[1]; m_RP.m_CurClipPlane.m_Normal.z = p[2]; m_RP.m_CurClipPlane.m_Dist = p[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; int nGPU = m_Features & RFT_HW_MASK; if (m_d3dCaps.MaxUserClipPlanes > 0 && nGPU != RFT_HW_GF3 && nGPU != RFT_HW_GF2 && nGPU != RFT_HW_GFFX) { m_RP.m_ClipPlaneEnabled = 2; m_pd3dDevice->SetClipPlane(0, p); m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 1); } else { m_RP.m_ClipPlaneEnabled = 1; } } else { #ifdef DO_RENDERLOG if (CV_r_log) Logv(SRendItem::m_RecurseLevel, "Reset clip-plane\n"); #endif m_RP.m_ClipPlaneEnabled = 0; m_RP.m_ClipPlaneWasOverrided = 0; if (m_d3dCaps.MaxUserClipPlanes > 0) { m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); } } } //============================================================================== // Shader Pipeline //======================================================================= // Software vertex deformations stages handling for the current shader void CD3D9Renderer::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 CD3D9Renderer::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*16; 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 CD3D9Renderer::EF_Eval_RGBAGen(SShaderPass *sfm) { SShader *ef = m_RP.m_pShader; int n; UCol color; bool bSetCol = false; color = m_RP.m_NeedGlobalColor; 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_Wave: if (sfm->m_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_pCurObject && !(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_pCurObject && !(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)(gRenDev->m_WorldColor[0] * 255.0f); color.bcolor[1] = (byte)(gRenDev->m_WorldColor[1] * 255.0f); color.bcolor[2] = (byte)(gRenDev->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_pCurObject && !(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_pCurObject && !(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)(gRenDev->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; } } // Updating of textures animating sequence void CD3D9Renderer::EF_UpdateTextures(SShaderPass *Layer) { SShaderTexUnit *stl; int j; for (j=0; jm_TUnits.Num(); j++) { stl = &Layer->m_TUnits[j]; if (!stl->m_TexPic && !stl->m_AnimInfo) break; stl->mfUpdate(); } } // Updating of textures animating sequence void CD3D9Renderer::EF_UpdateTextures(SShaderPassHW *Layer) { SShaderTexUnit *stl; int j; for (j=0; jm_TUnits.Num(); j++) { stl = &Layer->m_TUnits[j]; if (!stl->m_TexPic && !stl->m_AnimInfo) break; stl->mfUpdate(); } } //================================================================================= // Set current stencil states void SStencil::mfSet() { gRenDev->EF_SetStencilState(m_State, m_FuncRef, m_FuncMask); } void CRenderer::EF_SetStencilState(int st, uint nStencRef, uint nStencMask) { LPDIRECT3DDEVICE9 dv = gcpRendD3D->mfGetD3DDevice(); if (nStencRef != m_CurStencRef) { m_CurStencRef = nStencRef; dv->SetRenderState(D3DRS_STENCILREF, nStencRef); } if (nStencMask != m_CurStencMask) { m_CurStencMask = nStencMask; dv->SetRenderState(D3DRS_STENCILMASK, nStencMask); } int Changed = st ^ m_CurStencilState; if (!Changed) return; if (Changed & FSS_STENCIL_TWOSIDED) { if (st & FSS_STENCIL_TWOSIDED) dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); else dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); } if (Changed & FSS_STENCFUNC_MASK) { int nCurFunc = st & FSS_STENCFUNC_MASK; switch(nCurFunc) { case FSS_STENCFUNC_ALWAYS: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); break; case FSS_STENCFUNC_NEVER: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER); break; case FSS_STENCFUNC_LESS: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESS); break; case FSS_STENCFUNC_LEQUAL: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL); break; case FSS_STENCFUNC_GREATER: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATER); break; case FSS_STENCFUNC_GEQUAL: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL); break; case FSS_STENCFUNC_EQUAL: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); break; case FSS_STENCFUNC_NOTEQUAL: dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL); break; default: assert(false); } } if (Changed & FSS_STENCFAIL_MASK) { int nCurOp = (st & FSS_STENCFAIL_MASK); switch(nCurOp >> FSS_STENCFAIL_SHIFT) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO); break; default: assert(false); } } if (Changed & FSS_STENCZFAIL_MASK) { int nCurOp = (st & FSS_STENCZFAIL_MASK); switch(nCurOp >> FSS_STENCZFAIL_SHIFT) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_ZERO); break; default: assert(false); } } if (Changed & FSS_STENCPASS_MASK) { int nCurOp = (st & FSS_STENCPASS_MASK); switch(nCurOp >> FSS_STENCPASS_SHIFT) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO); break; default: assert(false); } } if (Changed & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)) { int nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT)); switch(nCurFunc >> FSS_CCW_SHIFT) { case FSS_STENCFUNC_ALWAYS: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS); break; case FSS_STENCFUNC_NEVER: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NEVER); break; case FSS_STENCFUNC_LESS: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESS); break; case FSS_STENCFUNC_LEQUAL: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESSEQUAL); break; case FSS_STENCFUNC_GREATER: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATER); break; case FSS_STENCFUNC_GEQUAL: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATEREQUAL); break; case FSS_STENCFUNC_EQUAL: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_EQUAL); break; case FSS_STENCFUNC_NOTEQUAL: dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NOTEQUAL); break; default: assert(false); } } if (Changed & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT)) { int nCurOp = (st & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_ZERO); break; default: assert(false); } } if (Changed & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT)) { int nCurOp = (st & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_ZERO); break; default: assert(false); } } if (Changed & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT)) { int nCurOp = (st & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT)); switch(nCurOp >> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT)) { case FSS_STENCOP_KEEP: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP); break; case FSS_STENCOP_REPLACE: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_REPLACE); break; case FSS_STENCOP_INCR: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCRSAT); break; case FSS_STENCOP_DECR: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECRSAT); break; case FSS_STENCOP_INCR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCR); break; case FSS_STENCOP_DECR_WRAP: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECR); break; case FSS_STENCOP_ZERO: dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_ZERO); break; default: assert(false); } } 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); LPDIRECT3DDEVICE9 dv = gcpRendD3D->mfGetD3DDevice(); m_RP.m_PS.m_NumStateChanges++; 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) dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); else dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER); } else dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); } else { st &= ~(GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT); st |= (m_CurState & (GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT)); } } if (Changed & GS_POLYLINE) { if (m_polygon_mode == R_SOLID_MODE) { if (st & GS_POLYLINE) dv->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME ); else dv->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); } } if (Changed & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB)) { if (st & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB)) { if (st & GS_NOCOLMASK) dv->SetRenderState(D3DRS_COLORWRITEENABLE, 0); else if (st & GS_COLMASKONLYALPHA) dv->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); else if (st & GS_COLMASKONLYRGB) dv->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE); } else dv->SetRenderState(D3DRS_COLORWRITEENABLE, 0xf); } 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) { // Source factor switch (st & GS_BLSRC_MASK) { case GS_BLSRC_ZERO: src = D3DBLEND_ZERO; break; case GS_BLSRC_ONE: src = D3DBLEND_ONE; break; case GS_BLSRC_DSTCOL: src = D3DBLEND_DESTCOLOR; break; case GS_BLSRC_ONEMINUSDSTCOL: src = D3DBLEND_INVDESTCOLOR; break; case GS_BLSRC_SRCALPHA: src = D3DBLEND_SRCALPHA; break; case GS_BLSRC_ONEMINUSSRCALPHA: src = D3DBLEND_INVSRCALPHA; break; case GS_BLSRC_DSTALPHA: src = D3DBLEND_DESTALPHA; break; case GS_BLSRC_ONEMINUSDSTALPHA: src = D3DBLEND_INVDESTALPHA; break; case GS_BLSRC_ALPHASATURATE: src = D3DBLEND_SRCALPHASAT; break; default: iLog->Log("CD3D9Renderer::SetState: invalid src blend state bits '%d'", st & GS_BLSRC_MASK); break; } //Destination factor switch (st & GS_BLDST_MASK) { case GS_BLDST_ZERO: dst = D3DBLEND_ZERO; break; case GS_BLDST_ONE: dst = D3DBLEND_ONE; break; case GS_BLDST_SRCCOL: dst = D3DBLEND_SRCCOLOR; break; case GS_BLDST_ONEMINUSSRCCOL: dst = D3DBLEND_INVSRCCOLOR; if (m_nHDRType == 1 && (m_RP.m_PersFlags & RBPF_HDR)) dst = D3DBLEND_ONE; break; case GS_BLDST_SRCALPHA: dst = D3DBLEND_SRCALPHA; break; case GS_BLDST_ONEMINUSSRCALPHA: dst = D3DBLEND_INVSRCALPHA; break; case GS_BLDST_DSTALPHA: dst = D3DBLEND_DESTALPHA; break; case GS_BLDST_ONEMINUSDSTALPHA: dst = D3DBLEND_INVDESTALPHA; break; default: iLog->Log("CD3D9Renderer::SetState: invalid dst blend state bits '%d'", st & GS_BLDST_MASK); break; } if (!(m_CurState & GS_BLEND_MASK)) dv->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); dv->SetRenderState(D3DRS_SRCBLEND, src); dv->SetRenderState(D3DRS_DESTBLEND, dst); } else dv->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); } 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) dv->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); else dv->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); } else { st &= ~GS_DEPTHWRITE; st |= (m_CurState & GS_DEPTHWRITE); } } if (Changed & GS_NODEPTHTEST) { if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHTEST)) { if (st & GS_NODEPTHTEST) dv->SetRenderState(D3DRS_ZENABLE, FALSE); else dv->SetRenderState(D3DRS_ZENABLE, TRUE); } 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) dv->SetRenderState(D3DRS_STENCILENABLE, TRUE); else dv->SetRenderState(D3DRS_STENCILENABLE, FALSE); } 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)) dv->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); switch (st & GS_ALPHATEST_MASK) { case GS_ALPHATEST_GREATER0: dv->SetRenderState(D3DRS_ALPHAREF, 0); dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); break; case GS_ALPHATEST_LESS128: dv->SetRenderState(D3DRS_ALPHAREF, 0x80); dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS); break; case GS_ALPHATEST_GEQUAL128: dv->SetRenderState(D3DRS_ALPHAREF, 0x80); dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); break; case GS_ALPHATEST_GEQUAL64: dv->SetRenderState(D3DRS_ALPHAREF, 0x40); dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); break; } } else dv->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); } 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 CD3D9Renderer::SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa) { EF_SetColorOp(eCo, eAo, eCa, eAa); } void CD3D9Renderer::EF_SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa) { int stage = m_TexMan->m_CurStage; if (eCo != 255 && eCo != m_eCurColorOp[stage]) { switch (eCo) { case eCO_MODULATE: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE); break; case eCO_BLENDDIFFUSEALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA); break; case eCO_BLENDTEXTUREALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); break; case eCO_MODULATE4X: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE4X); break; case eCO_MODULATE2X: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE2X); break; case eCO_ADD: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADD); break; case eCO_ADDSIGNED: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADDSIGNED); break; case eCO_MULTIPLYADD: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD); break; case eCO_REPLACE: case eCO_DECAL: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG1); break; case eCO_ARG2: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG2); break; case eCO_BUMPENVMAP: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP); break; case eCO_MODULATEALPHA_ADDCOLOR: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEALPHA_ADDCOLOR); break; case eCO_MODULATECOLOR_ADDALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATECOLOR_ADDALPHA); break; case eCO_MODULATEINVALPHA_ADDCOLOR: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEINVALPHA_ADDCOLOR); break; case eCO_MODULATEINVCOLOR_ADDALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEINVCOLOR_ADDALPHA); break; case eCO_DOTPRODUCT3: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3); break; case eCO_LERP: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_LERP); break; case eCO_SUBTRACT: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SUBTRACT); break; case eCO_DISABLE: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE); break; } m_eCurColorOp[stage] = eCo; } if (eAo != 255 && eAo != m_eCurAlphaOp[stage]) { switch (eAo) { case eCO_MODULATE: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE); break; case eCO_BLENDDIFFUSEALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BLENDDIFFUSEALPHA); break; case eCO_BLENDTEXTUREALPHA: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BLENDTEXTUREALPHA); break; case eCO_MODULATE4X: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE4X); break; case eCO_MODULATE2X: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE2X); break; case eCO_ADD: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD); break; case eCO_ADDSIGNED: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADDSIGNED); break; case eCO_MULTIPLYADD: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MULTIPLYADD); break; case eCO_REPLACE: case eCO_DECAL: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); break; case eCO_ARG2: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); break; case eCO_BUMPENVMAP: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BUMPENVMAP); break; case eCO_SUBTRACT: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SUBTRACT); break; case eCO_LERP: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_LERP); break; case eCO_DISABLE: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE); 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: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TFACTOR); break; } } if (((eCa>>3) & 7) != ((m_eCurColorArg[stage]>>3) & 7)) { switch ((eCa >> 3) & 7) { case eCA_Texture: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_TFACTOR); break; } } if ((eCa >> 6) != (m_eCurColorArg[stage] >> 6)) { switch (eCa >> 6) { case eCA_Texture: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_TFACTOR); 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: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TFACTOR); break; } } if (((eAa>>3) & 7) != ((m_eCurAlphaArg[stage]>>3) & 7)) { switch ((eAa >> 3) & 7) { case eCA_Texture: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TFACTOR); break; } } if ((eAa >> 6) != (m_eCurAlphaArg[stage] >> 6)) { switch (eAa >> 6) { case eCA_Texture: default: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_TEXTURE); break; case eCA_Diffuse: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_DIFFUSE); break; case eCA_Specular: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_SPECULAR); break; case eCA_Previous: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_CURRENT); break; case eCA_Constant: m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_TFACTOR); break; } } m_eCurAlphaArg[stage] = eAa; } } // Set current geometry culling modes void CD3D9Renderer::D3DSetCull(ECull eCull) { if (eCull == m_eCull) return; if (eCull == eCULL_None) m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); else { if ((eCull == eCULL_Back && !(m_RP.m_PersFlags & RBPF_DRAWMIRROR)) || (eCull != eCULL_Back && (m_RP.m_PersFlags & RBPF_DRAWMIRROR))) m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); else m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); } m_eCull = eCull; } // Init states before rendering of the scene void CD3D9Renderer::EF_PreRender(int Stage) { int i; if (m_bDeviceLost) return; if (Stage & 1) { // Before preprocess m_RP.m_RealTime = iTimer->GetCurrTime(); m_RP.m_Flags = 0; m_RP.m_pPrevObject = NULL; m_RP.m_FrameObject++; EF_SetCameraInfo(); if (Stage == 1) CCGVProgram_D3D::mfSetGlobalParams(); for (i=0; im_Flags & DLF_FAKE) continue; if (dl->m_Flags & DLF_SUN) { Vec3d pos = GetCamera().GetPos(); Vec3d delta = dl->m_Origin - pos; delta.Normalize(); m_RP.m_SunDir = delta; m_RP.m_SunColor = dl->m_Color; } } // 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; EF_ClearBuffers(false, false, NULL); } } m_RP.m_pCurLight = NULL; } // Restore states after rendering of the scene void CD3D9Renderer::EF_PostRender() { //FrameProfiler f("CD3D9Renderer:EF_PostRender", iSystem ); EF_ObjectChange(NULL, NULL, 0, NULL); m_RP.m_pRE = NULL; HRESULT h; if (m_RP.m_PersFlags & RBPF_USESTREAM1) { m_RP.m_PersFlags &= ~RBPF_USESTREAM1; h = m_pd3dDevice->SetStreamSource( 1, NULL, 0, 0); } if (m_RP.m_PersFlags & RBPF_USESTREAM2) { m_RP.m_PersFlags &= ~RBPF_USESTREAM2; h = m_pd3dDevice->SetStreamSource( 2, NULL, 0, 0); } if (m_RP.m_PersFlags & RBPF_SETCLIPPLANE) { EF_SetClipPlane(false, NULL, false); m_RP.m_PersFlags &= ~RBPF_SETCLIPPLANE; } m_Viewport.MaxZ = 1.0f; m_pd3dDevice->SetViewport(&m_Viewport); CD3D9TexMan::BindNULL(1); EF_SelectTMU(0); m_RP.m_PersFlags &= ~(RBPF_VSNEEDSET | RBPF_PS1NEEDSET); m_RP.m_FlagsModificators = 0; m_RP.m_CurrentVLights = 0; m_RP.m_FlagsPerFlush = 0; EF_CommitShadersState(); EF_CommitVLightsState(); m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); if (m_RP.m_TexStages[0].TCIndex != 0) { m_RP.m_TexStages[0].TCIndex = 0; m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 0); } EF_Scissor(false, 0, 0, 0, 0); m_RP.m_pShader = NULL; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; //ResetToDefault(); } //================================================================================= // Check buffer overflow during geometry batching void CD3D9Renderer::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("CD3D9Renderer::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("CD3D9Renderer::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 CD3D9Renderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, CRendElement *re) { //FrameProfiler f("CD3D9Renderer:EF_Start", iSystem ); m_RP.m_RendPass = 0; m_RP.m_RendNumIndices = 0; m_RP.m_RendNumVerts = 0; m_RP.m_FirstIndex = 0; m_RP.m_FirstVertex = 0; m_RP.m_BaseVertex = 0; m_RP.m_pShader = ef; #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; // 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_Frame++; } // Start of the new shader pipeline (3D pipeline version) void CD3D9Renderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, int numFog, CRendElement *re) { m_RP.m_RendPass = 0; m_RP.m_FirstIndex = 0; m_RP.m_FirstVertex = 0; m_RP.m_BaseVertex = 0; m_RP.m_RendNumIndices = 0; m_RP.m_RendNumVerts = 0; m_RP.m_pShader = ef; m_RP.m_pStateShader = efState; m_RP.m_pShaderResources = Res; m_RP.m_pCurEnvTexture = NULL; #ifdef PIPE_USE_INSTANCING m_RP.m_MergedObjects.SetUse(0); #endif m_RP.m_pCurLightMaterial = NULL; m_RP.m_FlagsPerFlush = 0; m_RP.m_FlagsModificators = 0; m_RP.m_fCurOpacity = 1.0f; if (numFog && CV_r_VolumetricFog) m_RP.m_pFogVolume = &m_RP.m_FogVolumes[numFog]; else m_RP.m_pFogVolume = NULL; m_RP.m_ObjFlags = m_RP.m_pCurObject->m_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: CD3D9Renderer::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 CD3D9Renderer::EF_SetHWLight(int Num, vec4_t Pos, CFColor& Diffuse, CFColor& Specular, float ca, float la, float qa, float fRange) { m_Lights[Num].Position.x = Pos[0]; m_Lights[Num].Position.y = Pos[1]; m_Lights[Num].Position.z = Pos[2]; m_Lights[Num].Range = fRange; if (!Pos[3]) { Vec3d v = Vec3d(Pos[0], Pos[1], Pos[2]); v.Normalize(); m_Lights[Num].Direction.x = -v[0]; m_Lights[Num].Direction.y = -v[1]; m_Lights[Num].Direction.z = -v[2]; m_Lights[Num].Type = D3DLIGHT_DIRECTIONAL; } else m_Lights[Num].Type = D3DLIGHT_POINT; m_Lights[Num].Diffuse.r = Diffuse.r; m_Lights[Num].Diffuse.g = Diffuse.g; m_Lights[Num].Diffuse.b = Diffuse.b; m_Lights[Num].Diffuse.a = Diffuse.a; m_Lights[Num].Specular.r = Specular.r; m_Lights[Num].Specular.g = Specular.g; m_Lights[Num].Specular.b = Specular.b; m_Lights[Num].Specular.a = Specular.a; m_Lights[Num].Attenuation0 = ca; m_Lights[Num].Attenuation1 = la; m_Lights[Num].Attenuation2 = qa; m_pd3dDevice->SetLight(Num, &m_Lights[Num]); m_RP.m_CurrentVLights |= 1<= 16) break; CDLight *dl = m_RP.m_pActiveDLights[i]; if ((Flags & LMF_IGNOREPROJLIGHTS) && (dl->m_Flags & DLF_PROJECT)) continue; int nlM; bool bSpecularOnly = false; 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); //TransformPoint(m, dl->m_Origin, lpos); //TransformPosition33(lpos, dl->m_Origin-m_RP.m_pCurObject->m_Matrix.GetTranslationOLD(), Matrix33(GetTransposed44(m_RP.m_pCurObject->m_Matrix))); float fRange = 0; if (dl->m_Flags & DLF_DIRECTIONAL) { Pos[3] = 0.0f; fCA = 1.0f; fLA = 0.0f; fQA = 0.0f; cDiffuse = dl->m_Color; } else { fRange = dl->m_fRadius; Pos[3] = 1.0f; if (!bCalcDist) { bCalcDist = true; if (m_RP.m_pRE) { Vec3d vMins, vMaxs; 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*0.9f); float fMaxAtt = 1.0f / sAttenuation(fMaxDist, dl->m_fRadius*0.9f); 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; fRange = (256.0f - fCA) / max(0.01f, fLA); if (fRange < 0) fRange = 0; cDiffuse = dl->m_Color; } /*static float sCA = 0; static float sLA = 0; static float sRange = 0; if (GetAsyncKeyState(VK_NUMPAD1) & 0x8000) sCA -= 0.001f; if (GetAsyncKeyState(VK_NUMPAD3) & 0x8000) sCA += 0.001f; if (GetAsyncKeyState(VK_NUMPAD4) & 0x8000) sLA -= 0.01f; if (GetAsyncKeyState(VK_NUMPAD6) & 0x8000) sLA += 0.01f; if (GetAsyncKeyState(VK_NUMPAD7) & 0x8000) sRange -= 0.1f; if (GetAsyncKeyState(VK_NUMPAD9) & 0x8000) sRange += 0.1f; fCA += sCA; fLA += sLA; fRange += sRange;*/ 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; cDiffuse.a = 1.0f; if (!(Flags & LMF_NOSPECULAR)) cSpecular = dl->m_SpecColor; if (bSpecularOnly) cDiffuse = Col_Black; EF_SetHWLight(n, Pos, cDiffuse, cSpecular, fCA, fLA, fQA, fRange); n++; } m_RP.m_CurrentVLightFlags = Flags; return true; } // Initialize HW vertex lighting states for the fixed pipeline shader void CD3D9Renderer::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 && !(Flags & LMF_HASPSHADER)) { EF_ConstantLightMaterial(lm, Flags); return; } if (!(Flags & LMF_IGNORELIGHTS) && EF_SetLights(Flags)) { if (!(m_RP.m_CurrentVLights & 0xff) && !(Flags & LMF_HASPSHADER)) { EF_ConstantLightMaterial(lm, Flags); return; } m_RP.m_FlagsPerFlush &= ~(RBSI_GLOBALRGB | RBSI_GLOBALALPHA); CFColor colAmb = EF_GetCurrentAmbient(lm, Flags); m_Material.Ambient.r = colAmb.r; m_Material.Ambient.g = colAmb.g; m_Material.Ambient.b = colAmb.b; m_Material.Ambient.a = colAmb.a; CFColor colDif = EF_GetCurrentDiffuse(lm, Flags); m_Material.Diffuse.r = colDif.r; m_Material.Diffuse.g = colDif.g; m_Material.Diffuse.b = colDif.b; m_Material.Diffuse.a = colAmb.a; // Disable emissive materials to match result to programmable pipeline // Pixel shaders don't support emmissive parameters //m_Material.Emissive.r = 0; //lm->Front.m_Emission.r; //m_Material.Emissive.g = 0; //lm->Front.m_Emission.g; //m_Material.Emissive.b = 0; //lm->Front.m_Emission.b; //m_Material.Emissive.a = 0; //lm->Front.m_Emission.a; if (!(Flags & LMF_NOSPECULAR)) { m_Material.Specular.r = lm->Front.m_Specular.r; m_Material.Specular.g = lm->Front.m_Specular.g; m_Material.Specular.b = lm->Front.m_Specular.b; m_Material.Specular.a = lm->Front.m_Specular.a; m_Material.Power = lm->Front.m_SpecShininess; if (lm->Front.m_Specular == CFColor(0.0f)) m_Material.Power = 0; } else { m_Material.Specular.r = 0; m_Material.Specular.g = 0; m_Material.Specular.b = 0; m_Material.Specular.a = 0; m_Material.Power = 0; } } m_pd3dDevice->SetMaterial(&m_Material); m_RP.m_CurrentVLights |= 0x80000000; m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Diffuse<<3); m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Diffuse<<3); } //============================================================= // Calculate matrices (usually texture matrices) for fixed pipeline shaders // Set texture transform modes void CD3D9Renderer::EF_ApplyMatrixOps(TArray* MatrixOps, bool bEnable) { if (!MatrixOps) return; LPDIRECT3DDEVICE9 dv = m_pd3dDevice; int CurMatrix = D3DTS_VIEW; m_CurOpMatrix = NULL; int Stage = -1; bool bProjected; int nCoords = 2; int nCurMatrix; for (int i=0; iNum(); i++) { SMatrixTransform *mt = &MatrixOps->Get(i); nCurMatrix = mt->m_Matrix & 0xff; bProjected = (mt->m_Matrix & 0x8000) != 0; if (mt->m_Matrix >> 16) nCoords = (mt->m_Matrix >> 16); if (nCurMatrix != CurMatrix) { if (m_CurOpMatrix) { if (Stage >= 0) dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); dv->SetTransform((D3DTRANSFORMSTATETYPE)CurMatrix, m_CurOpMatrix); m_CurOpMatrix = NULL; } switch (nCurMatrix) { case D3DTS_TEXTURE0: m_CurOpMatrix = &m_TexMatrix[0]; Stage = 0; break; case D3DTS_TEXTURE1: m_CurOpMatrix = &m_TexMatrix[1]; Stage = 1; break; case D3DTS_TEXTURE2: m_CurOpMatrix = &m_TexMatrix[2]; Stage = 2; break; case D3DTS_TEXTURE3: m_CurOpMatrix = &m_TexMatrix[3]; Stage = 3; break; default: Stage = -1; } if (!bEnable && mt->m_Matrix != D3DTS_PROJECTION && mt->m_Matrix != D3DTS_VIEW) { if (m_CurOpMatrix) { D3DXMatrixIdentity(m_CurOpMatrix); dv->SetTransform((D3DTRANSFORMSTATETYPE)nCurMatrix, m_CurOpMatrix); if (Stage >= 0) dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); } } CurMatrix = nCurMatrix; } mt->mfSet(bEnable); } if (m_CurOpMatrix && bEnable) { if (Stage >= 0) { if (bProjected) dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, nCoords | D3DTTFF_PROJECTED); else dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, nCoords); } if (nCoords < 3) { m_CurOpMatrix->_31 = m_CurOpMatrix->_41; m_CurOpMatrix->_32 = m_CurOpMatrix->_42; m_CurOpMatrix->_33 = m_CurOpMatrix->_43; m_CurOpMatrix->_34 = m_CurOpMatrix->_44; } //D3DXMatrixTranspose(m_CurOpMatrix, m_CurOpMatrix); dv->SetTransform((D3DTRANSFORMSTATETYPE)nCurMatrix, m_CurOpMatrix); } } #include "../Common/NvTriStrip/NVTriStrip.h" // Commit changed states to the hardware before drawing bool CD3D9Renderer::EF_PreDraw(SShaderPass *sl, bool bSetVertexDecl) { bool bRet = true; //PROFILE_FRAME(Draw_Predraw); EF_CommitShadersState(); EF_CommitVLightsState(); HRESULT hr; if (bSetVertexDecl) { hr = EF_SetVertexDeclaration(m_RP.m_FlagsModificators&7, m_RP.m_CurVFormat); if (hr != S_OK) return false; } if (!m_RP.m_pRE && m_RP.m_RendNumVerts && m_RP.m_RendNumIndices) { // Mergable geometry (no single render element) int nStart; 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; int nCurVB = m_RP.m_CurVB; if (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount()) { m_RP.m_VBs[nCurVB].VBPtr_0->Reset(); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; Vec3 *pVB = m_RP.m_VBs[nCurVB].VBPtr_0->Lock(nSize, nStart); cryMemcpy(pVB, m_RP.m_Ptr.Ptr, nSize); m_RP.m_VBs[nCurVB].VBPtr_0->Unlock(); m_RP.m_FirstVertex = 0; m_RP.m_MergedStreams[0] = m_RP.m_VBs[nCurVB]; m_RP.m_nStreamOffset[0] = nStart; ushort *pIB = m_RP.m_IndexBuf->Lock(m_RP.m_RendNumIndices, nStart); cryMemcpy(pIB, m_RP.m_SysRendIndices, m_RP.m_RendNumIndices*sizeof(short)); m_RP.m_IndexBuf->Unlock(); m_RP.m_FirstIndex = nStart; } m_RP.m_MergedStreams[0].VBPtr_0->Bind(m_pd3dDevice, 0, m_RP.m_nStreamOffset[0], m_RP.m_Stride); m_RP.m_IndexBuf->Bind(m_pd3dDevice); 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 (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount()) { m_RP.m_VBs[nCurVB].VBPtr_0->Reset(); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; SPipTangents *dst = (SPipTangents *)m_RP.m_VBs[nCurVB].VBPtr_0->Lock(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 movaps xmm1,xmm3 // r1 = vx, vy, vz, X mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X movaps xmm0,xmm1 // r0 = r1 shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X 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 movaps xmm1,xmm3 // r1 = vx, vy, vz, X mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X movaps xmm0,xmm1 // r0 = r1 shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X 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 add edi, 36 addps xmm3,xmm1 addps xmm3,xmm0 movaps xmm1,xmm3 // r1 = vx, vy, vz, X mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X add esi, 36 movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X movaps xmm0,xmm1 // r0 = r1 shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X dec ecx movhlps xmm5,xmm3 movlps qword ptr [edi+24-36],xmm3 movss dword ptr [edi+32-36],xmm5 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++; } } } m_RP.m_VBs[nCurVB].VBPtr_0->Unlock(); m_RP.m_MergedStreams[1] = m_RP.m_VBs[nCurVB]; m_RP.m_nStreamOffset[1] = nStart; } m_RP.m_MergedStreams[1].VBPtr_0->Bind(m_pd3dDevice, 1, m_RP.m_nStreamOffset[1], sizeof(SPipTangents)); m_RP.m_PersFlags |= RBPF_USESTREAM1; } else if (m_RP.m_PersFlags & RBPF_USESTREAM1) { m_RP.m_PersFlags &= ~RBPF_USESTREAM1; m_pd3dDevice->SetStreamSource(1, NULL, 0, 0); } 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 (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount()) { m_RP.m_VBs[nCurVB].VBPtr_0->Reset(); m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1); } nCurVB = m_RP.m_CurVB; struct_VERTEX_FORMAT_TEX2F *dst = (struct_VERTEX_FORMAT_TEX2F *)m_RP.m_VBs[nCurVB].VBPtr_0->Lock(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; nUnlock(); m_RP.m_MergedStreams[2] = m_RP.m_VBs[nCurVB]; m_RP.m_nStreamOffset[2] = nStart; } m_RP.m_MergedStreams[2].VBPtr_0->Bind(m_pd3dDevice, 2, m_RP.m_nStreamOffset[2], sizeof(SMRendTexVert)); m_RP.m_PersFlags |= RBPF_USESTREAM2; } else if (m_RP.m_PersFlags & RBPF_USESTREAM2) { m_RP.m_PersFlags &= ~RBPF_USESTREAM2; m_pd3dDevice->SetStreamSource(2, NULL, 0, 0); } } else if (m_RP.m_pRE) bRet = m_RP.m_pRE->mfPreDraw(sl); return bRet; } // Draw current indexed mesh void CD3D9Renderer::EF_DrawIndexedMesh (int nPrimType) { HRESULT h = 0; if (CV_r_nodrawshaders) return; D3DPRIMITIVETYPE nType; int nFaces; switch (nPrimType) { case R_PRIMV_TRIANGLES: nType = D3DPT_TRIANGLELIST; nFaces = m_RP.m_RendNumIndices/3; break; case R_PRIMV_TRIANGLE_STRIP: nType = D3DPT_TRIANGLESTRIP; nFaces = m_RP.m_RendNumIndices-2; break; case R_PRIMV_TRIANGLE_FAN: nType = D3DPT_TRIANGLEFAN; nFaces = 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); for (int i=0; iCount(); i++, m++) { m_RP.m_PS.m_NumDrawCalls++; if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, m_RP.m_BaseVertex, m->nFirstVertId, m->nNumVerts, m->nFirstIndexId, m->nNumIndices - 2))) { Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h); return; } m_nPolygons += (m->nNumIndices - 2); } } return; } break; case R_PRIMV_MULTI_GROUPS: { CMatInfo *mi = m_RP.m_pRE->mfGetMatInfo(); if (mi) { int offs = mi->nFirstIndexId; for (int i=0; im_dwNumSections; i++) { SPrimitiveGroup *g = &mi->m_pPrimitiveGroups[i]; m_RP.m_PS.m_NumDrawCalls++; switch (g->type) { case PT_STRIP: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2))) { Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices - 2); break; case PT_LIST: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices / 3))) { Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices / 3); break; case PT_FAN: if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2))) { Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h); return; } m_nPolygons += (g->numIndices - 2); break; } } } return; } break; default: assert(0); } if (nFaces) { m_RP.m_PS.m_NumDrawCalls++; //m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(nType, m_RP.m_BaseVertex, m_RP.m_FirstVertex, m_RP.m_RendNumVerts, m_RP.m_FirstIndex, nFaces))) { Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h); return; } m_nPolygons += nFaces; } else { int nnn = 0; } } // Draw volumetric fog passes (used in FP shaders and in programmable pipeline shaders) void CD3D9Renderer::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; #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "--- Fog Pass ---\n"); #endif 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 = gRenDev->m_RP.m_MergedObjects[nObj]; } #endif if (fDist < 40.0f && fb->bCaustics) sh = m_cEF.m_ShaderFogCaust; else sh = m_cEF.m_ShaderFog; } else if (fb->bCaustics) sh = m_cEF.m_ShaderFogCaust; else sh = m_cEF.m_ShaderFog; } else sh = 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, false); if (m_RP.m_pShader->m_eSort == eS_Water && m_RP.m_pFogVolume) m_RP.m_pFogVolume->m_Dist -= 0.1f; } } // Draw detail textures passes (used in FP shaders and in programmable pipeline shaders) void CD3D9Renderer::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; SMFog fg; float fDistToCam = 500.0f; float fDist = CV_r_detaildistance; static TArray sfDistRender; 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; sfDistRender.SetUse(0); while (true) { float fDistObj = m_RP.m_pRE->mfMinDistanceToCamera(pObj); if (fDistObj <= fDist+1.0f) sfDistRender.AddElem(fDistObj); else sfDistRender.AddElem(-1.0f); 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; EF_PushMatrix(); #endif } else return; PROFILE_FRAME(DrawShader_DetailPasses); SMFog *fb = gRenDev->m_RP.m_pFogVolume; fg.m_FogInfo.m_WaveFogGen.m_eWFType = eWF_None; gRenDev->m_RP.m_pFogVolume = &fg; CD3D9TexMan::BindNULL(2); EF_SelectTMU(1); gRenDev->m_TexMan->m_Text_Fog->Set(); EF_SelectTMU(0); rt->m_TU.m_TexPic->Set(); m_RP.m_CurrentVLights = 0; 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); SParamComp_FogMatrix FM; vec4_t Vals; m_RP.m_FlagsModificators &= ~(7 | (RBMF_TCM | RBMF_TCG)); if (m_RP.m_TexStages[0].TCIndex != 0) { m_RP.m_TexStages[0].TCIndex = 0; m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 0); } EF_Scissor(false, 0, 0, 0, 0); if (!(sh->m_Flags & EF_HASVSHADER)) { m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; 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; m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1); D3DXMATRIX mat, ma, *mi; for (i=0; iSetTransform(D3DTS_TEXTURE0, &ma); #ifndef PIPE_USE_INSTANCING mi = EF_InverseMatrix(); FM.m_Offs = 0; FM.mfGet4f(Vals); mat.m[0][0] = Vals[0]; mat.m[1][0] = Vals[1]; mat.m[2][0] = Vals[2]; mat.m[3][0] = Vals[3]; FM.m_Offs = 1; FM.mfGet4f(Vals); mat.m[0][1] = Vals[0]; mat.m[1][1] = Vals[1]; mat.m[2][1] = Vals[2]; mat.m[3][1] = Vals[3]; D3DXMatrixMultiply(&ma, mi, &mat); m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &ma ); if (!m_RP.m_RCDetail) m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten", true); if (m_RP.m_RCDetail) m_RP.m_RCDetail->mfSet(true); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f]\n", m_RP.m_RendPass, fDist); #endif // 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); } else { UCol col; col.dcolor = 0xff808080; if (m_RP.m_CurGlobalColor.dcolor != col.dcolor) { m_RP.m_CurGlobalColor = col; m_pd3dDevice->SetRenderState(D3DRS_TEXTUREFACTOR, m_RP.m_CurGlobalColor.dcolor); } 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 (sfDistRender[nObj] > 0) { 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); } mi = EF_InverseMatrix(); FM.m_Offs = 0; FM.mfGet4f(Vals); mat.m[0][0] = Vals[0]; mat.m[1][0] = Vals[1]; mat.m[2][0] = Vals[2]; mat.m[3][0] = Vals[3]; FM.m_Offs = 1; FM.mfGet4f(Vals); mat.m[0][1] = Vals[0]; mat.m[1][1] = Vals[1]; mat.m[2][1] = Vals[2]; mat.m[3][1] = Vals[3]; D3DXMatrixMultiply(&ma, mi, &mat); m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &ma ); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, fDist, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif { //PROFILE_FRAME(Draw_ShaderIndexMesh); 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_FogRestore(bFogOverrided); 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++; EF_SetObjectTransform(pSaveObj, sh, pSaveObj->m_ObjFlags); } #endif fDist /= 2.0f; if (fDistToCam > fDist+1.0f) break; fUScale *= 2.0f; fVScale *= 2.0f; } D3DXMatrixIdentity(&mat); m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); m_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat); m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &mat); m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 1); m_RP.m_TexStages[1].TCIndex = 1; EF_SelectTMU(0); } else { 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_D3D *vpD3D = (CCGVProgram_D3D *)m_RP.m_VPDetail; vpD3D->mfSet(true, NULL, VPF_DONTSETMATRICES); vpD3D->mfSetVariables(false, NULL); vpD3D->mfSetStateMatrices(); SCGBind *pBindScale = vpD3D->mfGetParameterBind("DetailScaling"); SCGBind *pBindTG0 = vpD3D->mfGetParameterBind("TexGen00"); SCGBind *pBindTG1 = vpD3D->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, Vals); Plane plane; #ifndef PIPE_USE_INSTANCING FM.m_Offs = 0; FM.mfGet4f(Vals); if (pBindTG0) vpD3D->mfParameter4f(pBindTG0, Vals); FM.m_Offs = 1; FM.mfGet4f(Vals); if (pBindTG1) vpD3D->mfParameter4f(pBindTG1, Vals); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f]\n", m_RP.m_RendPass, fDist); #endif // 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 (sfDistRender[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) vpD3D->mfParameter4f(pBindTG0, Vals); FM.m_Offs = 1; FM.mfGet4f(Vals); if (pBindTG1) vpD3D->mfParameter4f(pBindTG1, Vals); vpD3D->mfSetVariables(true, NULL); vpD3D->mfSetStateMatrices(); #ifdef DO_RENDERLOG if (CRenderer::CV_r_log >= 3) { Vec3d vPos = pObj->GetTranslation(); Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, fDist, pObj->m_VisId, vPos[0], vPos[1], vPos[2]); } #endif { //PROFILE_FRAME(Draw_ShaderIndexMesh); 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_FogRestore(bFogOverrided); 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++; } #endif fDist /= 2.0f; if (fDistToCam > fDist+1.0f) break; fUScale *= 2.0f; fVScale *= 2.0f; } } CD3D9TexMan::BindNULL(0); gRenDev->m_RP.m_pFogVolume = fb; #ifdef PIPE_USE_INSTANCING EF_PopMatrix(); #endif } // Draw fur layer passes (used in programmable pipeline shaders only) void CD3D9Renderer::EF_DrawFurPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, EShaderPassType eShPass) { SShaderPassHW *slw; int i; CVProgram *curVP = NULL; CVProgram *newVP; m_RP.m_FlagsPerFlush |= RBSI_FURPASS; PROFILE_FRAME(DrawShader_FurPasses); slw = &hs->m_Passes[nStart]; if (slw->m_TUnits.Num() < 3) return; CFurMap *fm = (CFurMap *)slw->m_TUnits[2].m_TexPic->m_pFuncMap; CFurNormalMap *fnm = (CFurNormalMap *)slw->m_TUnits[0].m_TexPic->m_pFuncMap; if (!fm || !fnm) return; SParamComp_User user; user.m_Name = "furlength"; float fFurLength = user.mfGet(); fFurLength = CLAMP(fFurLength, 0.001f, 4.0f); user.m_Name = "furnumlayers"; int nLayers = (int)user.mfGet(); nLayers = CLAMP(nLayers, 1, 60); fm->Update(nLayers); bool bFurSimulation = (eShPass == eSHP_SimulatedFur); fnm->Update(eShPass, iTimer->GetFrameTime(), slw, bFurSimulation); m_RP.m_CurrPass = slw; m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); EF_SetVertexStreams(slw->m_Pointers, 1); // Set all textures and HW TexGen modes for the current pass (ShadeLayer) newVP = slw->m_VProgram; if (newVP) m_RP.m_FlagsPerFlush |= RBSI_USEVP; if (slw->mfSetTextures()) { fnm->Bind(0); // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, 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_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; 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); 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, "+++ Fur Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, 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(); 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(); } CCGVProgram_D3D *vpD3D = (CCGVProgram_D3D *)curVP; vec4_t v; SParamComp_OSLightPos comp; m_RP.m_pCurLight = m_RP.m_pActiveDLights[0]; comp.mfGet4f(v); vpD3D->mfParameter4f("LightPos", v); float fLodBias = -0.5f; m_pd3dDevice->SetSamplerState(2, D3DSAMP_MIPMAPLODBIAS, *((LPDWORD)(&fLodBias))); CREOcLeaf *re = (CREOcLeaf *)m_RP.m_pRE; CLeafBuffer *lb = re->m_pBuffer; v[2] = -lb->m_fMinU; v[0] = 1.0f / (lb->m_fMaxU + v[2]); v[3] = -lb->m_fMinV; v[1] = 1.0f / (lb->m_fMaxV + v[3]); vpD3D->mfParameter4f("ScaleBiasTC", v); for (i=0; iBind(layer, 2); float vModifiers[4]; vModifiers[0] = length; vModifiers[1] = 0.0f; vModifiers[2] = 0.0f; vModifiers[3] = scale; vpD3D->mfParameter4f("Modifiers", vModifiers); { //PROFILE_FRAME(Draw_ShaderIndexMesh); if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); } } m_pd3dDevice->SetSamplerState(2, D3DSAMP_MIPMAPLODBIAS, 0); nObj++; if (nObj >= m_RP.m_MergedObjects.Num()) break; } EF_FogRestore(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); } m_RP.m_pCurLight = NULL; } struct SShadowLight { list2 *pSmLI; CDLight *pDL; }; static bool sbHasDot3LM; 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; if (sbHasDot3LM) { if ((a.pDL->m_Flags & DLF_LM) < (b.pDL->m_Flags & DLF_LM)) return -1; if ((a.pDL->m_Flags & DLF_LM) > (b.pDL->m_Flags & DLF_LM)) return -1; } return 0; } #include int CD3D9Renderer::EF_DrawMultiShadowPasses(SShaderTechnique *hs, SShader *ef, int nStart) { int i, j; int nStartAmb = -1; int nEndAmb = -1; int nStartShadow = -1; int nEndShadow = -1; int nStartLight = -1; int nEndLight = -1; int nEnd = -1; nStart++; if (m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED) { int nnn = 0; } bool bMultiLights = false; for (i=nStart; im_Passes.Num(); i++) { switch (hs->m_Passes[i].m_ePassType) { case eSHP_MultiLights: bMultiLights = true; case eSHP_SpecularLight: case eSHP_DiffuseLight: case eSHP_Light: if (nStartLight < 0) nStartLight = i; else nEndLight = i; break; case eSHP_General: if (nStartAmb < 0) nStartAmb = i; else nEndAmb = i; break; case eSHP_Shadow: 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; 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 } }*/ if (nEndLight < 0) nEndLight = nStartLight; if (nEndShadow < 0) nEndShadow = nStartShadow; if (nEndAmb < 0) nEndAmb = nStartAmb; assert(nStartShadow>=0); assert(nStartLight>=0); int nFrustrums = 0; list2 SmLI[16]; 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=nCaster; jCount(); j++) { ShadowMapLightSourceInstance *Inst = lsources->Get(j); if (Inst->m_pLS->nDLightId == nLightID) SmLI[i].Add(*Inst); } } sbHasDot3LM = bHasDot3LM; ::Sort(&SL[0], nLights); int nStartLightWithoutSC = -1; m_RP.m_FlagsPerFlush &= ~RBSI_ALPHATEST; for (i=0; iCount()) { m_RP.m_pCurObject->m_pShadowCasters = SL[i].pSmLI; m_RP.m_pActiveDLights[0] = SL[i].pDL; m_RP.m_NumActiveDLights = 1; m_RP.m_pCurLight = SL[i].pDL; // Draw shadows in back-buffer alpha-channel EF_DrawShadowPasses(hs, ef, nStartShadow, nEndShadow, true); if (bHasDot3LM && (SL[i].pDL->m_Flags & DLF_LM)) { // Shadow maps on light-map case // Specular pass if (bMultiLights) EF_DrawLightPasses_PS30(hs, ef, nStartLight, nEndLight, true); else EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, true); // LM pass EF_DrawGeneralPasses(hs, ef, false, nStartAmb, nEndAmb, true); } else { // Shadow maps on dynamically lighted object case if (bMultiLights) EF_DrawLightPasses_PS30(hs, ef, nStartLight, nEndLight, true); else EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, true); } } else { if (nStartLightWithoutSC < 0) nStartLightWithoutSC = i; m_RP.m_pActiveDLights[i-nStartLightWithoutSC] = SL[i].pDL; } } if (nStartLightWithoutSC >= 0) { // Draw light sources without shadow-casters m_RP.m_NumActiveDLights = nLights-nStartLightWithoutSC; EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, false); } 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; list2 * lsources = (list2*)m_RP.m_pCurObject->m_pShadowCasters; if (!lsources || !lsources->Count()) return; m_RP.m_FlagsPerFlush |= RBSI_SHADOWPASS; PROFILE_FRAME(DrawShader_ShadowPasses); CDLight *pSaveLight = m_RP.m_pCurLight; 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; int nPass = 0; for (; nCasterm_Passes[nStart]; for (i=nStart; i<=nEnd; i++, slw++) { int msk; bool bUseLight = false; if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK)) { bUseLight = true; 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; m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); 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) newVP = slw->m_VProgram; if (newVP) m_RP.m_FlagsPerFlush |= RBSI_USEVP; if (slw->mfSetTextures()) { // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, 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_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; if (bDstAlpha) { if (nPass) State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONE | GS_BLDST_ONE; nPass++; } EF_SetState(State); #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++; // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); 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); 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); 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(); 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_FogRestore(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_nCurStartCaster = 0; m_RP.m_pCurLight = pSaveLight; if (m_RP.m_pCurLight) m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id; } #define INST_PARAM_SIZE 4*sizeof(float) void CD3D9Renderer::EF_DrawInstances(SShader *ef, SShaderPassHW *slw, int nCurInst, int nLastInst, int nUsage, byte bUsage[], int nInstMask) { int i; if (!nCurInst) { // Set the stream 3 to be per instance data and iterate once per instance m_pd3dDevice->SetStreamSourceFreq(3, 1 | D3DSTREAMSOURCE_INSTANCEDATA); int nCompared = 0; EF_PreDraw(slw, false); int StreamMask = m_RP.m_FlagsModificators&7; SVertexDeclaration *vd; for (i=0; iStreamMask == StreamMask && vd->VertFormat == m_RP.m_CurVFormat && vd->InstMask == nInstMask) break; } if (i == m_RP.m_CustomVD.Num()) { vd = new SVertexDeclaration; m_RP.m_CustomVD.AddElem(vd); vd->StreamMask = StreamMask; vd->VertFormat = m_RP.m_CurVFormat; vd->InstMask = nInstMask; vd->m_pDeclaration = NULL; for (i=0; im_Declaration.AddElem(m_RP.m_D3DFixedPipeline[StreamMask][m_RP.m_CurVFormat].m_Declaration[i]); } D3DVERTEXELEMENT9 ve; ve.Stream = 3; ve.Type = D3DDECLTYPE_FLOAT4; ve.Method = D3DDECLMETHOD_DEFAULT; ve.Usage = D3DDECLUSAGE_TEXCOORD; for (i=0; im_Declaration.AddElem(ve); } ve.Stream = 0xff; ve.Type = D3DDECLTYPE_UNUSED; ve.Usage = 0; ve.UsageIndex = 0; ve.Offset = 0; vd->m_Declaration.AddElem(ve); } HRESULT hr; if (!vd->m_pDeclaration) { hr = m_pd3dDevice->CreateVertexDeclaration(&vd->m_Declaration[0], &vd->m_pDeclaration); assert (hr == S_OK); } if (m_pLastVDeclaration != vd->m_pDeclaration) { m_pLastVDeclaration = vd->m_pDeclaration; hr = m_pd3dDevice->SetVertexDeclaration(vd->m_pDeclaration); assert (hr == S_OK); } } { //PROFILE_FRAME(Draw_ShaderIndexMesh); int nPolys = m_nPolygons; if (m_RP.m_pRE) m_RP.m_pRE->mfDraw(ef, slw); else EF_DrawIndexedMesh(R_PRIMV_TRIANGLES); int nPolysPerInst = m_nPolygons - nPolys; m_nPolygons += nPolysPerInst*(nLastInst-nCurInst); } } void CD3D9Renderer::EF_DrawGeometryInstancing_VS30(SShader *ef, SShaderPassHW *slw, CVProgram *curVP) { PROFILE_FRAME(DrawShader_GeometryInstancing_VS30); int i, j, n; CCGVProgram_D3D *vp = (CCGVProgram_D3D *)curVP; int nOffs; int nUsage = 1; byte bUsage[16]; Matrix44 m; int nCurInst = 0; SCGBind bind; bind.m_dwBind = 65536; bind.m_nBindComponents = 4; bind.m_dwFrameCreated = vp->m_dwFrame; mathMatrixTranspose(m.GetData(), m_CameraProjMatrix.GetData(), g_CpuFlags); vp->mfParameter(&bind, m.GetData(), 4); m_RP.m_RotatedMergedObjects.SetUse(0); m_RP.m_NonRotatedMergedObjects.SetUse(0); int nSimple = 0; for (i=0; im_ObjFlags & FOB_TRANS_ROTATE) m_RP.m_RotatedMergedObjects.AddElem(pObj); else m_RP.m_NonRotatedMergedObjects.AddElem(pObj); } if (m_RP.m_NonRotatedMergedObjects.Num()) { memset(bUsage, 0, sizeof(bUsage)); bUsage[0] = 1; int nInstMask = 0x2; for (j=0; jm_Params_Inst.Num(); j++) { bUsage[nUsage] = nUsage+1; nInstMask |= 1<<(nUsage+1); nUsage++; } while (nCurInst < m_RP.m_NonRotatedMergedObjects.Num()) { int nLastInst = m_RP.m_NonRotatedMergedObjects.Num() - 1; if ((nLastInst-nCurInst+1)*nUsage >= MAX_HWINST_PARAMS) nLastInst = nCurInst+(MAX_HWINST_PARAMS/nUsage)-1; byte *data = (byte *)m_RP.m_VB_Inst->Lock((nLastInst-nCurInst+1)*nUsage*INST_PARAM_SIZE, nOffs); CCObject *curObj = m_RP.m_pCurObject; n = 0; // Fill the stream 3 for per-instance data for (i=nCurInst; i<=nLastInst; i++) { CCObject *pObj = m_RP.m_NonRotatedMergedObjects[i]; /*if (i != nLastInst) { CCObject *pObj = m_RP.m_NonRotatedMergedObjects[i+1]; cryPrefetchNTSSE(pObj->m_Matrix.GetData()); }*/ float *fParm = (float *)&data[n*nUsage*INST_PARAM_SIZE]; n++; float *fSrc = pObj->m_Matrix.GetData(); fParm[0] = fSrc[12]; fParm[1] = fSrc[13]; fParm[2] = fSrc[14]; fParm[3] = fSrc[0]; fParm += 4; //mathMatrixTranspose((float *)&data[nOffset], m_RP.m_MergedObjects[i]->GetVPMatrix().GetData(), g_CpuFlags); //memcpy(&data[n*nUsage*4*sizeof(float)], pObj->GetVPMatrix().GetData(), 4*4*sizeof(float)); m_RP.m_pCurObject = pObj; m_RP.m_FrameObject++; for (j=0; jm_Params_Inst.Num(); j++) { float *v = vp->m_Params_Inst[j].mfGet(); fParm[0] = v[0]; fParm[1] = v[1]; fParm[2] = v[2]; fParm[3] = v[3]; fParm += 4; } } m_RP.m_pCurObject = curObj; m_RP.m_VB_Inst->Unlock(); // Set the first stream to be the indexed data and render N instances m_pd3dDevice->SetStreamSourceFreq(0, n | D3DSTREAMSOURCE_INDEXEDDATA); m_RP.m_VB_Inst->Bind(m_pd3dDevice, 3, nOffs, nUsage*INST_PARAM_SIZE); EF_DrawInstances(ef, slw, nCurInst, nLastInst, nUsage, bUsage, nInstMask); nCurInst = nLastInst+1; } } if (m_RP.m_RotatedMergedObjects.Num()) { int nFlags = VPF_DONTSETMATRICES | VPF_INSTANCING_ROTATE; curVP->mfSet(true, slw, nFlags); nUsage = 4; memset(bUsage, 0, sizeof(bUsage)); bUsage[0] = 1; bUsage[1] = 2; bUsage[2] = 3; bUsage[3] = 4; int nInstMask = 0x1e; for (j=0; jm_Params_Inst.Num(); j++) { bUsage[nUsage] = nUsage+1; nInstMask |= 1<<(nUsage+1); nUsage++; } Matrix44 m; int nCurInst = 0; SCGBind bind; while (nCurInst < m_RP.m_RotatedMergedObjects.Num()) { int nLastInst = m_RP.m_RotatedMergedObjects.Num() - 1; if ((nLastInst-nCurInst+1)*nUsage >= MAX_HWINST_PARAMS) nLastInst = nCurInst+(MAX_HWINST_PARAMS/nUsage)-1; byte *data = (byte *)m_RP.m_VB_Inst->Lock((nLastInst-nCurInst+1)*nUsage*INST_PARAM_SIZE, nOffs); CCObject *curObj = m_RP.m_pCurObject; n = 0; // Fill the stream 3 for per-instance data for (i=nCurInst; i<=nLastInst; i++) { CCObject *pObj = m_RP.m_RotatedMergedObjects[i]; float *fParm = (float *)&data[n*nUsage*INST_PARAM_SIZE]; n++; mathMatrixTranspose(fParm, m_RP.m_RotatedMergedObjects[i]->GetVPMatrix().GetData(), g_CpuFlags); fParm += 4*4; m_RP.m_pCurObject = m_RP.m_RotatedMergedObjects[i]; m_RP.m_pCurObject = pObj; m_RP.m_FrameObject++; for (j=0; jm_Params_Inst.Num(); j++) { float *v = vp->m_Params_Inst[j].mfGet(); fParm[0] = v[0]; fParm[1] = v[1]; fParm[2] = v[2]; fParm[3] = v[3]; fParm += 4; } } m_RP.m_pCurObject = curObj; m_RP.m_VB_Inst->Unlock(); // Set the first stream to be the indexed data and render N instances m_pd3dDevice->SetStreamSourceFreq(0, n | D3DSTREAMSOURCE_INDEXEDDATA); m_RP.m_VB_Inst->Bind(m_pd3dDevice, 3, nOffs, nUsage*INST_PARAM_SIZE); EF_DrawInstances(ef, slw, nCurInst, nLastInst, nUsage, bUsage, nInstMask); nCurInst = nLastInst+1; } } m_pd3dDevice->SetStreamSource(3, NULL, 0, 0); m_pd3dDevice->SetStreamSourceFreq(0, 1); } // Draw general/ambient passes (used in FP shaders and in programmable pipeline shaders) void CD3D9Renderer::EF_DrawGeneralPasses(SShaderTechnique *hs, SShader *ef, bool bFog, int nStart, int nEnd, bool bDstAlpha) { 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; PROFILE_FRAME(DrawShader_GeneralPasses); m_RP.m_nCurLight = 0; CVProgram *curVP = NULL; CVProgram *newVP; slw = &hs->m_Passes[nStart]; for (i=nStart; i<=nEnd; i++, slw++) { m_RP.m_StatNumPasses++; m_RP.m_CurrPass = slw; m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3); 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 (ShadeLayer) newVP = slw->m_VProgram; if (newVP) m_RP.m_FlagsPerFlush |= RBSI_USEVP; if (slw->mfSetTextures()) { bool bInstancing = false; // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; int nFlags = VPF_DONTSETMATRICES; if (CV_r_geominstancing && m_RP.m_MergedObjects.Num() > 2 && m_bDeviceSupportsInstancing && (curVP->m_Flags & VPFI_SUPPORTS_INSTANCING) && !(m_RP.m_FlagsModificators & RBMF_TCG)) { bInstancing = true; nFlags |= VPF_INSTANCING_NOROTATE; } curVP->mfSet(true, slw, nFlags); } 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 { 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 (!(slw->m_LMFlags & (LMF_DISABLE | LMF_HASPSHADER)) && !(m_RP.m_CurrentVLights & 0xff)) EF_ConstantLightMaterial(m_RP.m_pShaderResources->m_LMaterial, slw->m_LMFlags); } 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) { if (!bInstancing) slw->m_FShader->mfSet(true, slw, 0); else slw->m_FShader->mfSet(true, slw, PSF_INSTANCING); } else m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET; // Set Render states for the current pass int State; if (bFog) { State = slw->m_RenderState; if (m_RP.m_pShader->m_Flags2 & EF2_OPAQUE) State |= GS_DEPTHFUNC_EQUAL; } 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; if (bDstAlpha) State = (State & ~GS_BLEND_MASK) | GS_BLSRC_DSTALPHA | GS_BLDST_ONEMINUSDSTALPHA; EF_SetState(State); #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 HRESULT h; m_RP.m_RendPass++; int bFogOverrided = 0; bool bFogDisable = bFog || (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); // Assume if HW supports PS3.0, VS3.0 are supported as well if (bInstancing) { // Using geometry instancing approach EF_DrawGeometryInstancing_VS30(ef, slw, curVP); } else { // Unlock all VB (if needed) and set current streams EF_PreDraw(slw); 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 (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED)) { if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer) { int nOffs; IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs); h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]); } } 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(); 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_FogRestore(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); } } // Draw light passes (up to 4 light sources per single pass) void CD3D9Renderer::EF_DrawLightPasses_PS30(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, bool bDstAlpha) { SShaderPassHW *slw; int i; m_RP.m_nCurLight = 0; CVProgram *curVP = NULL; PROFILE_FRAME(DrawShader_MultiLight_Passes); 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); if (bDstAlpha || m_RP.m_RendPass) { bHasAmb = false; } 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; if (!(m_Features & RFT_HW_PS30)) fFP = 0.5f; float fFO = 1.0f; int nO = 0; int nP = 0; float fO = 0; float fP = 0; int nMaxLights = (m_Features & RFT_HW_PS30) ? NUM_PPLIGHTS_PERPASS_PS30 : NUM_PPLIGHTS_PERPASS_PS2X; int nAmbLights = nMaxLights; 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; } nAmbLights = min(nAmbLights, nMaxLights); 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 (nP >= nProjLights && nO >= nOtherLights) break; if (j == nAmbLights) { nAmbLights = nMaxLights; break; } 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) { nAmbLights = nMaxLights; 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++) { assert(lp->nLights <= nMaxLights); 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; if (bDstAlpha) State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE | GS_COLMASKONLYRGB; 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; HRESULT h; 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) { int nOffs; IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs); h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]); } } 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_FogRestore(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 CD3D9Renderer::EF_DrawLightPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, bool bDstAlpha) { int i, l; int nl = 0; int n; CVProgram *curVP = NULL; CVProgram *newVP; PROFILE_FRAME(DrawShader_LightPasses); // Just single pass for transparent objects //if (m_RP.m_RendPass && m_RP.m_fCurOpacity != 1.0f) // return; int nStencState = 0; bool bStencState = m_RP.m_pStateShader && m_RP.m_pStateShader->m_State && m_RP.m_pStateShader->m_State->m_Stencil; //return; // 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; bool bBreak = false; // For each layer/pass for (i=nStart; i<=nEnd; i++, slw++) { int msk; if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK)) { if (!(msk & (m_RP.m_pCurLight->m_Flags & DLF_LIGHTTYPE_MASK))) continue; if (slw->m_LMFlags & LMF_USEOCCLUSIONMAP) { byte *nOccl = m_RP.m_pCurObject->m_OcclLights; if (*(int *)nOccl == 0) continue; byte nLight = m_RP.m_nCurLight+1; if (nLight != nOccl[0] && nLight != nOccl[1] && nLight != nOccl[2] && nLight != nOccl[3]) continue; } if (slw->m_LightFlags & DLF_LM) { // Ignore OnlySpecular passes if light source is non-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); if (m_RP.m_pCurObject->m_pLMTCBufferO && m_RP.m_pCurObject->m_pLMTCBufferO->m_pVertexBuffer && m_RP.m_pCurObject->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat != VERTEX_FORMAT_TEX2F) m_RP.m_FlagsModificators |= RBMF_BENDINFOUSED; 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) newVP = slw->m_VProgram; if (newVP) m_RP.m_FlagsPerFlush |= RBSI_USEVP; if (slw->mfSetTextures()) { // Set vertex program for the current pass if needed if (newVP != curVP) { if (newVP) { curVP = newVP; curVP->mfSet(true, slw, VPF_DONTSETMATRICES); } else curVP = NULL; } EF_ApplyMatrixOps(slw->m_MatrixOps, true); if (!curVP) m_RP.m_PersFlags &= ~RBPF_VSNEEDSET; else { #ifndef PIPE_USE_INSTANCING curVP->mfSetStateMatrices(); #endif curVP->mfSetVariables(false, &slw->m_VPParamsNoObj); } // Set Pixel shaders for the current pass if (slw->m_FShader) slw->m_FShader->mfSet(true, slw); else m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET; // Set Render states for the current pass int State; 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; if (bDstAlpha || bShadowMask) State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE | GS_COLMASKONLYRGB; } State |= 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); 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); 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(); } 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) { int nOffs; IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs); HRESULT h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]); } } if (!curVP) { 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(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 // 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) { // Set constant color which is depends on object 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_FogRestore(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_nCurLight = -1; //m_RP.m_pCurLight = NULL; } // Draw bump self-shadowing pass using horizon-maps technique (used in programmable pipeline shaders only) void CD3D9Renderer::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(); //pTSH->m_pHorizonTex[0]->SaveJPG("Horiz0.jpg", false); EF_SelectTMU(1); pTSH->m_pBasisTex[0]->Set(); //pTSH->m_pBasisTex[0]->SaveJPG("Basis0.jpg", false); EF_SelectTMU(2); pTSH->m_pHorizonTex[1]->Set(); //pTSH->m_pHorizonTex[1]->SaveJPG("Horiz1.jpg", false); EF_SelectTMU(3); pTSH->m_pBasisTex[1]->Set(); //pTSH->m_pBasisTex[1]->SaveJPG("Basis1.jpg", false); CTexMan::m_nCurStages = 4; 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_ShaderIndexMesh); 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 CD3D9TexMan::BindNULL(1); } // Draw sub-surface scattering passes (used in programmable pipeline shaders only) void CD3D9Renderer::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; } //// ignore sun ? //if ((m_RP.m_pCurLight->m_Flags & DLF_SUN)) //{ // continue; //} EF_SetState(GS_BLSRC_ONE | GS_BLDST_ONE); //EF_SetState(GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE); CVProgram *m_VP; CPShader *m_RC; if (!m_RP.m_VPSubSurfaceScatering) m_RP.m_VPSubSurfaceScatering= CVProgram::mfForName("CGVProgSubSurface"); if (!m_RP.m_RCSubSurfaceScatering) m_RP.m_RCSubSurfaceScatering= CPShader::mfForName("CGRCSubSurface"); if (!m_RP.m_VPSubSurfaceScatering_pp) m_RP.m_VPSubSurfaceScatering_pp= CVProgram::mfForName("CGVProgSubSurface_pp"); if (!m_RP.m_RCSubSurfaceScatering_pp) m_RP.m_RCSubSurfaceScatering_pp= CPShader::mfForName("CGRCSubSurface_pp"); // setup texture stages textures STexPic *pSubSurfaceTex = m_RP.m_pShaderResources->m_Textures[EFTT_SUBSURFACE]->m_TU.m_TexPic; EF_SelectTMU(0); pSubSurfaceTex->Set(); STexPic *pBumpTex = m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic; if(pBumpTex) { EF_SelectTMU(1); SetLodBias(-1.5); pBumpTex->Set(); } STexPic *pNormalizationCubeMapTex=gRenDev->m_TexMan->m_Text_NormalizeCMap; EF_SelectTMU(2); pNormalizationCubeMapTex->Set(); if(CRenderer::CV_r_subsurface_type==0 || !pBumpTex) { m_VP=m_RP.m_VPSubSurfaceScatering; m_RC=m_RP.m_RCSubSurfaceScatering; } // make sure to only use per-pixel subsurface scatering, when model has normal map texture if(CRenderer::CV_r_subsurface_type==1 && pBumpTex) { m_VP=m_RP.m_VPSubSurfaceScatering_pp; m_RC=m_RP.m_RCSubSurfaceScatering_pp; } if(!m_VP || !m_RC) { return; } m_VP->mfSet(true, NULL); m_VP->mfSetVariables(false, NULL); m_RC->mfSet(true, NULL); m_RC->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_VP->mfSetVariables(true, NULL); m_RC->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 m_VP->mfSetStateMatrices(); m_VP->mfSetVariables(true, NULL); m_RC->mfSetVariables(true, NULL); { //PROFILE_FRAME(Draw_ShaderIndexMesh); 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++; } EF_SelectTMU(1); SetLodBias(0); #endif } CD3D9TexMan::BindNULL(1); } // Flush HW shader technique (used in FP shaders and in programmable pipeline shaders) void CD3D9Renderer::EF_FlushHW() { SShader *ef = m_RP.m_pShader; int i; int nPolys = m_nPolygons; if (m_RP.m_ObjFlags & FOB_SELECTED) { int nnn = 0; } if (m_RP.m_pRE || (m_RP.m_RendNumIndices && m_RP.m_RendNumVerts)) { 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; // Set Z-Bias if (ef->m_Flags & EF_POLYGONOFFSET) { if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) { float fOffs = (float)CV_d3d9_decaloffset; m_pd3dDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)(&fOffs) ); } } SShaderTechnique *hs = m_RP.m_pCurTechnique; if (!hs) return; 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) D3DSetCull(hs->m_eCull); else D3DSetCull(ef->m_eCull); } EF_SetVertexStreams(hs->m_Pointers, 1); 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); // Reset Z-Bias if (ef->m_Flags & EF_POLYGONOFFSET) { if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); } // 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(); } } // Set/Restore shader resources overrided states bool CD3D9Renderer::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) { D3DSetCull(eCULL_None); m_RP.m_FlagsPerFlush |= RBSI_NOCULL; } if ((m_RP.m_pShaderResources->m_AlphaRef) && !(m_RP.m_ObjFlags & FOB_FOGPASS)) { if (!(m_CurState & GS_ALPHATEST_MASK)) m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, (DWORD)(m_RP.m_pShaderResources->m_AlphaRef*255.0f)); m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); m_RP.m_FlagsPerFlush |= RBSI_ALPHATEST; m_CurState |= GS_ALPHATEST_GEQUAL128; } 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) && !(m_RP.m_ObjFlags & FOB_FOGPASS)) { switch (m_CurState & GS_ALPHATEST_MASK) { case GS_ALPHATEST_GREATER0: m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0); m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); break; case GS_ALPHATEST_LESS128: m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x80); m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS); break; case GS_ALPHATEST_GEQUAL128: m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x80); m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); break; default: m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); break; } } } return true; } // Set overrided shader states from State shader void CD3D9Renderer::EF_SetStateShaderState() { SShader *ef = m_RP.m_pStateShader; SEfState *st = ef->m_State; if (st->m_bClearStencil) m_pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0); if (st->m_Stencil) st->m_Stencil->mfSet(); if (st->m_Flags & ESF_NOCULL) { D3DSetCull(eCULL_None); m_RP.m_FlagsPerFlush |= RBSI_NOCULL; } else if (st->m_Flags & ESF_CULLFRONT) { D3DSetCull(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; int mask = 0; for (int i=0; i<4; i++) { if (st->m_ColorMask[i]) mask |= 1<SetRenderState(D3DRS_COLORWRITEENABLE, mask); } } // Reset overrided shader states from State shader void CD3D9Renderer::EF_ResetStateShaderState() { SShader *ef = m_RP.m_pStateShader; SEfState *st = ef->m_State; if (st->m_Flags & ESF_COLORMASK) m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xf); if (st->m_Flags & ESF_POLYLINE) m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } // Flush current shader void CD3D9Renderer::EF_FlushShader() { SShader *ef = m_RP.m_pShader; int i; SShaderPass *slw; if (m_RP.m_pRE) // Without buffer fill { EF_InitEvalFuncs(1); // VP if (CV_r_rb_merge < 0) return; } else { // Buffer filling EF_InitEvalFuncs(0); if (!m_RP.m_RendNumIndices) return; if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume) return; if (m_RP.m_RendNumIndices > m_RP.m_MaxTris*3) { iLog->Log("CD3D9Renderer::EF_FlushShader: Shader MaxTris hit for batched RenderElements\n"); m_RP.m_RendNumIndices = m_RP.m_MaxTris*3; } if (m_RP.m_RendNumVerts > m_RP.m_MaxVerts) { iLog->Log("CD3D9Renderer::EF_FlushShader: Shader MaxVerts hit for batched RenderElements\n"); m_RP.m_RendNumVerts = m_RP.m_MaxVerts; } } m_RP.m_ResourceState = 0; if (m_RP.m_pShaderResources) { if (!EF_SetResourcesState(true)) return; } 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; Set2DMode(true,800,600); } // Draw using HW shader 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) Set2DMode(false,800,600); return; } if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume) { if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_ResetStateShaderState(); if (m_RP.m_pShaderResources) EF_SetResourcesState(false); if (bDraw2D) Set2DMode(false,800,600); return; } // In common shaders we don't have pixel or vertex shaders m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_VSNEEDSET); CD3D9TexMan::BindNULL(1); EF_SelectTMU(0); EF_Scissor(false, 0, 0, 0, 0); if (ef->m_Flags & EF_NEEDNORMALS) EF_EvalNormalsRB(ef); EF_Eval_DeformVerts(ef->m_Deforms); if (ef->m_Flags & EF_POLYGONOFFSET) { if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) { float fOffs = (float)CV_d3d9_decaloffset; m_pd3dDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)&fOffs ); } } if (!(m_RP.m_FlagsPerFlush & RBSI_NOCULL)) D3DSetCull(ef->m_eCull); int nPolys = m_nPolygons; 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; m_RP.m_StatNumPasses += ef->m_Passes.Num(); slw = &ef->m_Passes[0]; 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()) { int nState; // Set Render states for the current pass 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 //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; while (true) { if (nObj) { // Object changed m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj]; pObj = m_RP.m_pCurObject; m_RP.m_FrameObject++; 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); } // Set scissor rect if (!(m_RP.m_ObjFlags & FOB_NOSCISSOR)) pObj->SetScissor(); else EF_Scissor(false, 0, 0, 0, 0); // Set per-object alpha blending state if (pObj->m_ObjFlags & FOB_HASALPHA) pObj->SetAlphaState(NULL, nState); // Commit per-texture states / color ops EF_CommitTexStageState(); #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 { //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_FogRestore(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++; 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(); if (ef->m_Flags & EF_POLYGONOFFSET) { if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); } if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State) EF_ResetStateShaderState(); if (m_RP.m_pShaderResources) EF_SetResourcesState(false); if (bDraw2D) Set2DMode(false,800,600); } // Flush current render item void CD3D9Renderer::EF_Flush() { CD3D9Renderer *rd = gcpRendD3D; 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; } //if ((int)rd->m_RP.m_pRE != 0xed45090) // return; /*{ Vec3d vObj = rd->m_RP.m_pCurObject->GetTranslation(); Vec3d vv = Vec3d(1170.025, 1396.100, 74.500); //if ((vv-vObj).GetLength() > 0.1f) // 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) { rd->m_TexMan->EndScreenTexMap(); // reset flag state rd->m_RP.m_PersFlags&= ~RBPF_IGNOREREFRACTED; } } } #ifdef DO_RENDERLOG if (rd->m_LogFile && CV_r_log == 3) rd->Logv(SRendItem::m_RecurseLevel, ".. Start Flush: '%s' ..\n", ef->m_Name.c_str()); #endif 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; } /*if (ef->m_eSort == eS_Water) { obj->m_DynLMMask |= 1; }*/ rd->m_RP.m_DynLMask = CV_r_hwlights ? obj->m_DynLMMask : 0; if (!(ef->m_Flags & EF_HASVSHADER)) rd->EF_SetObjectTransform(obj, ef, rd->m_RP.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; } #ifdef DO_RENDERLOG bool bProfile; double time0 = 0; int nNumPolys = rd->m_nPolygons; if (CRenderer::CV_r_profileshaders || CRenderer::CV_r_log>=2) { bProfile = true; ticks(time0); } else bProfile = false; if (rd->m_LogFile && CV_r_log >= 3) rd->Logv(SRendItem::m_RecurseLevel, "\n"); #endif rd->EF_FlushShader(); if (rd->m_RP.m_DynLMask) rd->m_RP.m_PS.m_NumLitShaders++; if (!(rd->m_RP.m_ObjFlags & FOB_TRANS_MASK)) { rd->m_RP.m_pCurObject->m_VPMatrixId = VPMId; rd->m_RP.m_pCurObject->m_InvMatrixId = IMId; } #ifdef DO_RENDERLOG nNumPolys = rd->m_nPolygons - nNumPolys; if (bProfile) { unticks(time0); time0 = time0*1000.0*g_SecondsPerCycle; } if (CRenderer::CV_r_profileshaders) { if (CRenderer::CV_r_profileshaders == 1 || (rd->m_RP.m_ObjFlags & FOB_SELECTED)) { 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_LogFile) { if (CV_r_log == 4 && 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 : ""); } } 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, ef->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 CD3D9Renderer::EF_EndEf3D(int nFlags) { double time0 = 0; ticks(time0); if (m_bDeviceLost) { SRendItem::m_RecurseLevel--; return; } 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, NULL); SRendItem::m_RecurseLevel--; return; } #ifdef USE_HDR bool bUseHDR = false; if ((nFlags & SHDF_ALLOWHDR) && SRendItem::m_RecurseLevel == 1 && (m_Features & RFT_HW_HDR) && CV_r_hdrrendering && !(m_RP.m_PersFlags & RBPF_MAKESPRITE)) bUseHDR = true; #endif 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(); #ifdef USE_HDR if (bUseHDR) EF_AddEf(0, m_RP.m_pREHDR, CShader::m_ShaderHDRProcess, NULL, NULL, 0, 0, EFSLIST_LAST | eS_HDR); #endif 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(); #ifdef USE_HDR CD3D9TexMan *tm = (CD3D9TexMan *)m_TexMan; if (bUseHDR) { if (!tm->m_Text_HDRTarget || tm->m_Text_HDRTarget->m_Width != m_width || tm->m_Text_HDRTarget->m_Height != m_height) tm->GenerateHDRMaps(); // Set float render target for HDR rendering if( tm->m_HDR_RT_FSAA ) { assert(!m_pHDRTargetSurf); if (!m_pHDRTargetSurf) { m_pHDRTargetSurf = tm->m_HDR_RT_FSAA; m_pHDRTargetSurf->AddRef(); } HRESULT hr = m_pd3dDevice->SetRenderTarget( 0, m_pHDRTargetSurf ); } else { STexPic *tp = tm->m_Text_HDRTarget; LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex; assert(pTexture); assert(!m_pHDRTargetSurf); if (!m_pHDRTargetSurf) pTexture->GetSurfaceLevel(0, &m_pHDRTargetSurf); assert(m_pHDRTargetSurf); //D3DSURFACE_DESC dtdsdRT; //m_pHDRTargetSurf->GetDesc(&dtdsdRT); HRESULT hr = m_pd3dDevice->SetRenderTarget(0, m_pHDRTargetSurf); } if (m_nHDRType == 2) { //tp = tm->m_Text_HDRTarget_K; //LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex; //if (!m_pHDRTargetSurf_K) // pTexture->GetSurfaceLevel(0, &m_pHDRTargetSurf_K); //hr = m_pd3dDevice->SetRenderTarget(1, m_pHDRTargetSurf_K); } //hr = m_pd3dDevice->SetDepthStencilSurface(m_pTempZBuffer); //m_pCurZBuffer = m_pTempZBuffer; m_RP.m_PersFlags |= RBPF_HDR; } else if (!CV_r_hdrrendering && tm->m_Text_HDRTarget) tm->DestroyHDRMaps(); #endif 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 CD3D9Renderer::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", "Stencil", "Last", "Unsorted"}; // 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 CD3D9Renderer::EF_PipeLine(int nums, int nume, int nList, void (*RenderFunc)()) { int i; SShader *pShader, *pCurShader, *pShaderState, *pCurShaderState; SRenderShaderResources *pRes, *pCurRes; int nObject, nCurObject; int nFog, nCurFog; if (nume-nums < 1) return; CheckDeviceLost(); m_RP.m_pRenderFunc = RenderFunc; m_RP.m_nCurLightParam = -1; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; m_RP.m_pPrevObject = m_RP.m_pCurObject; #ifdef DO_RENDERLOG if (CV_r_log) Logv(SRendItem::m_RecurseLevel, "*** Start frame for list %s ***\n", sDescList[nList]); #endif 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 m_RP.m_Flags |= RBF_3D; EF_PreRender(3); EF_PushMatrix(); /*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; 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); pRE->mfPrepare(); } continue; } oldVal.SortVal = ri->SortVal.SortVal; SRendItem::mfGet(ri->SortVal, &nObject, &pShader, &pShaderState, &nFog, &pRes); bChanged = (pCurRes != pRes || pShader != pCurShader || 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(); //EF_SetClipPlane(false, plane, false); EF_PostRender(); EF_PopMatrix(); #ifdef DO_RENDERLOG if (CV_r_log) Logv(SRendItem::m_RecurseLevel, "*** End frame ***\n\n"); #endif } // Draw overlay geometry in wireframe mode void CD3D9Renderer::EF_DrawWire() { if (CV_r_showlines == 1) gcpRendD3D->EF_SetState(GS_POLYLINE | GS_NODEPTHTEST); else if (CV_r_showlines == 2) gcpRendD3D->EF_SetState(GS_POLYLINE); gcpRendD3D->SetMaterialColor(1,1,1,1); gRenDev->m_TexMan->m_Text_White->Set(); gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); if (gcpRendD3D->m_RP.m_pRE) gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->m_RP.m_pShader->m_VertexFormatId, 0); int StrVrt; gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags); void *verts = (void *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, 0); gcpRendD3D->EF_Draw(gcpRendD3D->m_RP.m_pShader, NULL); } // Draw geometry normal vectors void CD3D9Renderer::EF_DrawNormals() { HRESULT h; float len = CRenderer::CV_r_normalslength; int StrVrt, StrNrm; //if (gcpRendD3D->m_RP.m_pRE) // gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->m_RP.m_pShader->m_VertexFormatId, SHPF_NORMALS); byte *verts = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, FGP_SRC | FGP_REAL); byte *norms = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Normal, &StrNrm, GL_FLOAT, eSrcPointer_Normal, FGP_SRC | FGP_REAL); if ((INT_PTR)norms > 256 && (INT_PTR)verts > 256) { gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags); int numVerts = gcpRendD3D->m_RP.m_RendNumVerts; gRenDev->m_TexMan->m_Text_White->Set(); gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); gcpRendD3D->EF_SetState(GS_POLYLINE); struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *Verts = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[numVerts*2]; uint col0 = 0x000000ff; uint col1 = 0x00ffffff; for (int v=0; vEF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F); h = gcpRendD3D->m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, numVerts, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); delete [] Verts; } } // Draw geometry tangent vectors void CD3D9Renderer::EF_DrawTangents() { HRESULT h; float len = CRenderer::CV_r_normalslength; //if (gcpRendD3D->m_RP.m_pRE) // gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->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 *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, flags); tangs = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Tangent, &StrTang, GL_FLOAT, eSrcPointer_Tangent, flags); binorm = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Binormal, &StrBinorm, GL_FLOAT, eSrcPointer_Binormal, flags); tnorm = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_TNormal, &StrTNorm, GL_FLOAT, eSrcPointer_TNormal, flags); if ((INT_PTR)tangs>256 && (INT_PTR)binorm>256 && (INT_PTR)tnorm>256) { gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags); int numVerts = gcpRendD3D->m_RP.m_RendNumVerts; gRenDev->m_TexMan->m_Text_White->Set(); gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0); if (gcpRendD3D->m_polygon_mode == R_SOLID_MODE) gcpRendD3D->EF_SetState(GS_POLYLINE | GS_DEPTHWRITE); else gcpRendD3D->EF_SetState(0); struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *Verts = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[numVerts*6]; for (int v=0; vEF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F); h = gcpRendD3D->m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, numVerts*3, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F)); delete [] Verts; } } // Draw light sources in debug mode void CD3D9Renderer::EF_DrawDebugLights() { static int sFrame = 0; if (m_nFrameUpdateID != sFrame) { int i; sFrame = m_nFrameID; gRenDev->m_TexMan->m_Text_White->Set(); for (i=0; iGetString(); if (strcmp(str, "0") != 0) { if (!dl->m_Name || strcmp(str, dl->m_Name)) 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); EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB); 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(ang*gf_DEGTORAD,GetNormalized(rgt)) * vertex; //NOTE: angle need to be in radians // Matrix mat = m.GetRotation(dir, 60); Matrix44 mat = Matrix33::CreateRotationAA(60*gf_DEGTORAD,GetNormalized(dir)); //NOTE: angle need to be in radians Vec3d tmpvertex; int ctr; //fill the inside of the light EnableTMU(false); struct_VERTEX_FORMAT_P3F_COL4UB Verts[32]; memset(Verts, 0, sizeof(Verts)); CFColor cl = Col*0.3f; int n = 0; Verts[n].xyz = org; Verts[n].color.dcolor = D3DRGBA(cl[0], cl[1], cl[2], 1.0f); n++; tmpvertex = org + vertex; Verts[n].xyz = tmpvertex; Verts[n].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f); n++; for (ctr=0; ctr<6; ctr++) { vertex = mat * vertex; Vec3d tmpvertex = org + vertex; Verts[n].xyz = tmpvertex; Verts[n].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f); n++; } m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, n-2, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB)); //draw the inside of the light with lines and the outside filled m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME ); SetCullMode(R_CULL_NONE); n = 0; Verts[n].xyz = org; Verts[n].color.dcolor = D3DRGBA(0.3f, 0.3f, 0.3f, 1.0f); n++; tmpvertex = org + vertex; Verts[n].xyz = tmpvertex; Verts[n].color.dcolor = D3DRGBA(1.0f, 1.0f, 1.0f, 1.0f); n++; for (ctr=0; ctr<6; ctr++) { vertex = mat * vertex; Vec3d tmpvertex = org + vertex; Verts[n].xyz = tmpvertex; Verts[n].color.dcolor = D3DRGBA(1.0f, 1.0f, 1.0f, 1.0f); n++; } m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, n-2, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB)); SetCullMode(R_CULL_FRONT); m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); //set the color to the color of the light Verts[0].xyz = org; Verts[0].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f); //draw a point at the origin of the light m_pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB)); //draw a line in the center of the light Verts[0].xyz = org; Verts[0].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f); tmpvertex = org + dir; Verts[1].xyz = tmpvertex; Verts[1].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f); m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB)); EnableTMU(true); } if (CV_r_debuglights == 2 && !(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); } } } } // Draw debug geometry/info void CD3D9Renderer::EF_DrawDebugTools() { if (CV_r_showlines) 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(); } static int __cdecl 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; } static int __cdecl 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; } //#include "FMallocWindows.h" // Print shaders profile info on the screen void CD3D9Renderer::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; TextToScreenColor(4,(27+(nLine*3)), 1,0,0,1, "%8.02f ms, %5d polys, '%s', %d item(s)", m_RP.m_Profile[nLine].ef->m_fProfileTime, 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; TextToScreenColor(2,(28+(nLine*3)), 0,2,0,1, "Total unique shaders: %d", nShaders); TextToScreenColor(2,(31+(nLine*3)), 0,2,0,1, "Total flush time: %8.02f ms", fTime); TextToScreenColor(2,(34+(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 timeSSE = 0; CCamera cam = GetCamera(); Vec3d camPos = cam.GetPos(); AABB aabb; aabb.min = camPos+Vec3d(-10, -16,-16); aabb.max = camPos+Vec3d(16,32,16); Vec3d Origin = (aabb.min+aabb.max)*0.5f; Vec3d Extent = aabb.max - Origin; ticks(timeC); for (i=0; i<100000; i++) { cam.IsAABBVisible_exact(aabb, NULL); } unticks(timeC); ticks(timeSSE); for (i=0; i<100000; i++) { cam.IsAABBVisible_exact_SSE(Origin, Extent, NULL); } unticks(timeSSE); TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC %8.02f ms, TimeSSE %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeSSE*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 timeSSE = 0; double timeSSENew = 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-128); } unticks(timeC); byte *Dst = (byte *)((int)(dataDst+15)&0xfffffff0); byte *Src = (byte *)((int)(dataSrc+15)&0xfffffff0); ticks(timeSSE); for (i=0; i<10; i++) { cryMemcpy(Dst, Src, 1024*1024*10-128); } unticks(timeSSE); ticks(timeSSENew); for (i=0; i<10; i++) { cryMemcpy(Dst, Src, 1024*1024*10-128, 0); } unticks(timeSSENew); delete [] dataSrc; delete [] dataDst; TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC: %8.02f ms, TimeSSE: %8.02f ms", (float)(timeC*1000.0*g_SecondsPerCycle), (float)(timeSSE*1000.0*g_SecondsPerCycle)); }*/ /*{ int i = 0; double timeCM10 = 0; double timeCF10 = 0; double timeCM60 = 0; double timeCF60 = 0; double timeCM110 = 0; double timeCF110 = 0; double timeCM510 = 0; double timeCF510 = 0; double timeCM1010 = 0; double timeCF1010 = 0; double timeCM5010 = 0; double timeCF5010 = 0; double timeCM10010 = 0; double timeCF10010 = 0; double timeCM100010 = 0; double timeCF100010 = 0; double timeUM10 = 0; double timeUF10 = 0; double timeUM60 = 0; double timeUF60 = 0; double timeUM110 = 0; double timeUF110 = 0; double timeUM510 = 0; double timeUF510 = 0; double timeUM1010 = 0; double timeUF1010 = 0; double timeUM5010 = 0; double timeUF5010 = 0; double timeUM10010 = 0; double timeUF10010 = 0; double timeUM100010 = 0; double timeUF100010 = 0; static FMallocWindows *pM; if (!pM) { pM = new FMallocWindows; pM->Init(); } void *pPtr[1000]; ticks(timeCM10); for (i=0; i<1000; i++) pPtr[i] = malloc(10); unticks(timeCM10); ticks(timeCF10); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF10); ticks(timeUM10); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(10, "Test"); unticks(timeUM10); ticks(timeUF10); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF10); ticks(timeCM60); for (i=0; i<1000; i++) pPtr[i] = malloc(60); unticks(timeCM60); ticks(timeCF60); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF60); ticks(timeUM60); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(60, "Test"); unticks(timeUM60); ticks(timeUF60); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF60); ticks(timeCM110); for (i=0; i<1000; i++) pPtr[i] = malloc(110); unticks(timeCM110); ticks(timeCF110); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF110); ticks(timeUM110); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(110, "Test"); unticks(timeUM110); ticks(timeUF110); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF110); ticks(timeCM510); for (i=0; i<1000; i++) pPtr[i] = malloc(510); unticks(timeCM510); ticks(timeCF510); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF510); ticks(timeUM510); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(510, "Test"); unticks(timeUM510); ticks(timeUF510); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF510); ticks(timeCM1010); for (i=0; i<1000; i++) pPtr[i] = malloc(1010); unticks(timeCM1010); ticks(timeCF1010); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF1010); ticks(timeUM1010); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(1010, "Test"); unticks(timeUM1010); ticks(timeUF1010); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF1010); ticks(timeCM5010); for (i=0; i<1000; i++) pPtr[i] = malloc(5010); unticks(timeCM5010); ticks(timeCF5010); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF5010); ticks(timeUM5010); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(5010, "Test"); unticks(timeUM5010); ticks(timeUF5010); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF5010); ticks(timeCM10010); for (i=0; i<1000; i++) pPtr[i] = malloc(10010); unticks(timeCM10010); ticks(timeCF10010); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF10010); ticks(timeUM10010); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(10010, "Test"); unticks(timeUM10010); ticks(timeUF10010); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF10010); ticks(timeCM100010); for (i=0; i<1000; i++) pPtr[i] = malloc(100010); unticks(timeCM100010); ticks(timeCF100010); for (i=0; i<1000; i++) free(pPtr[i]); unticks(timeCF100010); ticks(timeUM100010); for (i=0; i<1000; i++) pPtr[i] = pM->Malloc(100010, "Test"); unticks(timeUM100010); ticks(timeUF100010); for (i=0; i<1000; i++) pM->Free(pPtr[i]); unticks(timeUF100010); TextToScreenColor(1,(36+(nLine*3)), 0,2,0,1, "CM_10: %3.02f, CM_60: %3.02f, CM_110: %3.02f, CM_510: %3.02f, CM_1010: %3.02f, CM_5010: %3.02f, CM_10010: %3.02f, CM_100010: %3.02f", (float)(timeCM10*1000.0*g_SecondsPerCycle), (float)(timeCM60*1000.0*g_SecondsPerCycle), (float)(timeCM110*1000.0*g_SecondsPerCycle), (float)(timeCM510*1000.0*g_SecondsPerCycle), (float)(timeCM1010*1000.0*g_SecondsPerCycle), (float)(timeCM5010*1000.0*g_SecondsPerCycle), (float)(timeCM10010*1000.0*g_SecondsPerCycle), (float)(timeCM100010*1000.0*g_SecondsPerCycle)); TextToScreenColor(1,(40+(nLine*3)), 0,2,0,1, "UM_10: %3.02f, UM_60: %3.02f, UM_110: %3.02f, UM_510: %3.02f, UM_1010: %3.02f, UM_5010: %3.02f, UM_10010: %3.02f, UM_100010: %3.02f", (float)(timeUM10*1000.0*g_SecondsPerCycle), (float)(timeUM60*1000.0*g_SecondsPerCycle), (float)(timeUM110*1000.0*g_SecondsPerCycle), (float)(timeUM510*1000.0*g_SecondsPerCycle), (float)(timeUM1010*1000.0*g_SecondsPerCycle), (float)(timeUM5010*1000.0*g_SecondsPerCycle), (float)(timeUM10010*1000.0*g_SecondsPerCycle), (float)(timeUM100010*1000.0*g_SecondsPerCycle)); TextToScreenColor(1,(44+(nLine*3)), 0,2,0,1, "CF_10: %3.02f, CF_60: %3.02f, CF_110: %3.02f, CF_510: %3.02f, CF_1010: %3.02f, CF_5010: %3.02f, CF_10010: %3.02f, CF_100010: %3.02f", (float)(timeCF10*1000.0*g_SecondsPerCycle), (float)(timeCF60*1000.0*g_SecondsPerCycle), (float)(timeCF110*1000.0*g_SecondsPerCycle), (float)(timeCF510*1000.0*g_SecondsPerCycle), (float)(timeCF1010*1000.0*g_SecondsPerCycle), (float)(timeCF5010*1000.0*g_SecondsPerCycle), (float)(timeCF10010*1000.0*g_SecondsPerCycle), (float)(timeCF100010*1000.0*g_SecondsPerCycle)); TextToScreenColor(1,(48+(nLine*3)), 0,2,0,1, "UF_10: %3.02f, UF_60: %3.02f, UF_110: %3.02f, UF_510: %3.02f, UF_1010: %3.02f, UF_5010: %3.02f, UF_10010: %3.02f, UF_100010: %3.02f", (float)(timeUF10*1000.0*g_SecondsPerCycle), (float)(timeUF60*1000.0*g_SecondsPerCycle), (float)(timeUF110*1000.0*g_SecondsPerCycle), (float)(timeUF510*1000.0*g_SecondsPerCycle), (float)(timeUF1010*1000.0*g_SecondsPerCycle), (float)(timeUF5010*1000.0*g_SecondsPerCycle), (float)(timeUF10010*1000.0*g_SecondsPerCycle), (float)(timeUF100010*1000.0*g_SecondsPerCycle)); }*/ } void CD3D9Renderer::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; m_RP.m_pCurObject = m_RP.m_VisObjects[0]; m_RP.m_pPrevObject = m_RP.m_pCurObject; EF_PreRender(1); EF_PushMatrix(); UnINT64 oldVal; oldVal.SortVal = -1; nCurObject = -2; 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) m_RP.m_pRenderFunc(); EF_Start(Shader, ShaderState, Res, nFog, re); nCurFog = nFog; CurShader = Shader; CurShaderState = ShaderState; CurRes = Res; } re->mfPrepare(); } if (CurShader) m_RP.m_pRenderFunc(); EF_PostRender(); EF_PopMatrix(); 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 *CD3D9Renderer::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 CD3D9Renderer::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].srf = srf->srf; wp->numSrf++; } bool CD3D9Renderer::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 CD3D9Renderer::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; m_matProj->Push(); EF_PushMatrix(); 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); /*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); EF_PopMatrix(); m_matProj->Pop(); return true; } void sTransformPlane( float *u, const float *v, const float *m ) { float v0=v[0], v1=v[1], v2=v[2], v3=v[3]; #define M(row,col) m[col*4+row] u[0] = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + v3 * M(3,0); u[1] = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + v3 * M(3,1); u[2] = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + v3 * M(3,2); u[3] = v0 * M(0,3) + v1 * M(1,3) + v2 * M(2,3) + v3 * M(3,3); #undef M } 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; } // Flush all refracted objects in the list void CD3D9Renderer::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; } } // Current scene preprocess operations (drawing to texture, screen effects initializing, ...) int CD3D9Renderer::EF_Preprocess(SRendItemPre *ri, int nums, int nume) { int i, j; SShader *Shader; SShader *ShaderState; SRenderShaderResources *Res; int nObject; int nFog; SPreprocess Procs[512]; int nProcs = 0; TArray RIs; TArray srfs; 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, "*** Start preprocess frame ***\n"); int DLDFlags = 0; int nReturn = 0; for (i=nums; i= 512) break; SRendItem::mfGet(ri[i].SortVal, &nObject, &Shader, &ShaderState, &nFog, &Res); if ((ri[i].SortVal.i.High >> 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) { Procs[nProcs].m_nPreprocess = j; Procs[nProcs].m_Num = i; Procs[nProcs].m_Shader = Shader; Procs[nProcs].m_pRes = Res; Procs[nProcs].m_RE = ri[i].Item; Procs[nProcs].m_nObject = nObject; nProcs++; } } } if (!nProcs) return 0; ::Sort(&Procs[0], nProcs); if (m_RP.m_pRenderFunc != EF_Flush) return nReturn; 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(); m_RP.m_pCurObject = obj; } 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 (%.3f, %.3f, %.3f), Time: %.3f s ***\n", Pos.x, Pos.y, Pos.z, iTimer->GetAsyncCurTime()); if (!IsEquivalent(Pos,Vec3d(0,0,0))) { float fDR; ICVar * pVarDR = iConsole->GetCVar("e_obj_view_dist_ratio"); if (pVarDR) { fDR = pVarDR->GetFVal(); pVarDR->Set(fDR/3.0f); } int nDLDFlags = -1; nDLDFlags &= ~(DLD_SHADOW_MAPS | DLD_ENTITIES | DLD_FIRST_PERSON_CAMERA_OWNER | DLD_TERRAIN_LIGHT | DLD_PARTICLES | DLD_FAR_SPRITES | DLD_DETAIL_TEXTURES | DLD_DETAIL_OBJECTS); float fDistToCam = (Pos-m_cam.GetPos()).Length(); SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvLCMap(Pos, false, nDLDFlags, fDistToCam, obj); if (pVarDR) pVarDR->Set(fDR); } 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) { CCObject *obj = m_RP.m_VisObjects[pr->m_nObject]; if (pr->m_Shader->m_fUpdateFactor > 0) { float fDist = pr->m_RE->mfMinDistanceToCamera(obj); if (fDist > 0) { fDist *= pr->m_Shader->m_fUpdateFactor; if (fDist > 0.5f) fDist = 0.5f; if (m_RP.m_pCurObject->m_fLastUpdate-1.0f > m_RP.m_RealTime) m_RP.m_pCurObject->m_fLastUpdate = m_RP.m_RealTime; 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) { Vec3d Angs = GetCamera().GetAngles(); Vec3d Pos = GetCamera().GetPos(); m_RP.m_pRE = pr->m_RE; 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_pCurObject = obj; m_RP.m_pIgnoreObject = 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; m_RP.m_PersFlags &= ~RBPF_DONTDRAWSUN; } 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); // always skip refractive objects.. m_RP.m_PersFlags |= RBPF_IGNOREREFRACTED; } case SPRID_DOFMAP: if (!m_RP.m_bDrawToTexture) { m_TexMan->DrawToTextureForDof(TO_DOFMAP); } 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) { CREOcLeaf * pRE = (CREOcLeaf*)pr->m_RE; //ShadowMapFrustum * pFr = obj->m_pShadowFrustum; // Please never comment this lines !!! //if (m_LogFile) // Logv(SRendItem::m_RecurseLevel, "*** Prepare shadow maps for REOcLeaf***\n"); //if(obj && pFr && !m_RP.m_bDrawToTexture) // PrepareDepthMap(pFr, false); } } break; case SPRID_CORONA: if (pr->m_nObject>0 && !m_RP.m_bDrawToTexture) { 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) { nPortals = srfs.Num(); srfs.AddIndex(1); srfs[nPortals].nobj = pr->m_nObject; srfs[nPortals].srf = pr->m_RE; srfs[nPortals].Shader = pr->m_Shader; } 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)) { nPortals = srfs.Num(); srfs.AddIndex(1); srfs[nPortals].nobj = pr->m_nObject; srfs[nPortals].srf = pr->m_RE; srfs[nPortals].Shader = pr->m_Shader; } } } 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 (srfs.Num()) { 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) { m_RP.m_pRenderFunc(); sh = NULL; } EF_Start(ws->Shader, NULL, ws->ShaderRes, 0, ws->srf); sh = ws->Shader; } ws->srf->mfPrepare(); } if (sh) m_RP.m_pRenderFunc(); } 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); //ResetToDefault(); return nReturn; } void CD3D9Renderer::EF_EndEf2D(bool bSort) { int i; SShader *Shader, *CurShader, *ShaderState, *CurShaderState; SRenderShaderResources *Res, *CurRes; 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 frame if ((SRendItem::m_RendItems[0][nums].SortVal.i.High >> 26) == eS_PreProcess) nums += EF_Preprocess(&SRendItem::m_RendItems[0][0], nums, nume); } EF_PreRender(1); //ResetToDefault(); 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) m_RP.m_pRenderFunc(); EF_Start(Shader, ShaderState, Res, re); CurShader = Shader; CurShaderState = ShaderState; CurRes = Res; } re->mfPrepare(); } if (CurShader) m_RP.m_pRenderFunc(); EF_PostRender(); }