/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of HPL1 Engine. */ #include "hpl1/engine/graphics/Renderer3D.h" #include "hpl1/debug.h" #include "hpl1/engine/graphics/GPUProgram.h" #include "hpl1/engine/graphics/LowLevelGraphics.h" #include "hpl1/engine/graphics/MeshCreator.h" #include "hpl1/engine/graphics/RenderList.h" #include "hpl1/engine/graphics/Renderable.h" #include "hpl1/engine/graphics/RendererPostEffects.h" #include "hpl1/engine/graphics/Texture.h" #include "hpl1/engine/graphics/VertexBuffer.h" #include "hpl1/engine/math/BoundingVolume.h" #include "hpl1/engine/math/Math.h" #include "hpl1/engine/resources/GpuProgramManager.h" #include "hpl1/engine/resources/Resources.h" #include "hpl1/engine/resources/TextureManager.h" #include "hpl1/engine/resources/low_level_resources.h" #include "hpl1/engine/scene/Camera3D.h" #include "hpl1/engine/scene/Entity3D.h" #include "hpl1/engine/scene/Light3D.h" #include "hpl1/engine/scene/RenderableContainer.h" #include "hpl1/engine/scene/World3D.h" #include "hpl1/engine/system/low_level_system.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // RENDER SETTINGS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cRenderSettings::cRenderSettings() { mbFogActive = false; mfFogStart = 5.0f; mfFogEnd = 5.0f; mFogColor = cColor(1, 1); mbFogCulling = false; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cRenderer3D::cRenderer3D(iLowLevelGraphics *apLowLevelGraphics, cResources *apResources, cMeshCreator *apMeshCreator, cRenderList *apRenderList) { Hpl1::logInfo(Hpl1::kDebugGraphics, "%s", "Creating Renderer3D\n"); mpLowLevelGraphics = apLowLevelGraphics; mpLowLevelResources = apResources->GetLowLevel(); mpResources = apResources; mpMeshCreator = apMeshCreator; mpSkyBoxTexture = NULL; mbAutoDestroySkybox = false; mbSkyBoxActive = false; mSkyBoxColor = cColor(1, 1); mRenderSettings.mAmbientColor = cColor(0, 1); mpRenderList = apRenderList; mDebugFlags = 0; mbLog = false; mfRenderTime = 0; mbRefractionUsed = true; mvVtxRect.resize(4); mvVtxRect[0] = cVertex(cVector3f(0, 0, 0), cVector2f(0, 1), cColor(1, 1)); mvVtxRect[1] = cVertex(cVector3f(1, 0, 0), cVector2f(1, 1), cColor(1, 1)); mvVtxRect[2] = cVertex(cVector3f(1, 1, 0), cVector2f(1, 0), cColor(1, 1)); mvVtxRect[3] = cVertex(cVector3f(0, 1, 40), cVector2f(0, 0), cColor(1, 1)); // Set up render settings. mRenderSettings.mpLowLevel = mpLowLevelGraphics; mRenderSettings.mbLog = false; mRenderSettings.mShowShadows = eRendererShowShadows_All; mRenderSettings.mpTempIndexArray = hplNewArray(unsigned int, 60000); Hpl1::logInfo(Hpl1::kDebugGraphics, "%s", "Load Renderer3D gpu programs:\n"); cGpuProgramManager *pProgramManager = apResources->GetGpuProgramManager(); mRenderSettings.extrudeProgram = pProgramManager->CreateProgram("hpl1_ShadowExtrude", "hpl1_ShadowExtrude"); /////////////////////////////////// // Load diffuse program, for stuff like query rendering _diffuseProgram = pProgramManager->CreateProgram("hpl1_Diffuse_Color", "hpl1_Diffuse_Color"); /////////////////////////////////// // Fog Vertex Program Init _solidFogProgram = pProgramManager->CreateProgram("hpl1_Fog_Solid", "hpl1_Fog_Solid"); /////////////////////////////////// // Fog Texture Init Log("Creating fog textures:"); unsigned char *pFogArray = hplNewArray(unsigned char, 256 * 2); // Solid Log("Solid"); iTexture *pTex = mpLowLevelGraphics->CreateTexture("FogLinearSolid", false, eTextureType_Normal, eTextureTarget_1D); for (int i = 0; i < 256; ++i) { pFogArray[i * 2 + 0] = 255; // pFogArray[i*2 + 0] = 255 - (unsigned char)i; pFogArray[i * 2 + 1] = 255 - (unsigned char)i; } if (pTex) { pTex->CreateFromArray(pFogArray, 2, cVector3l(256, 1, 1)); pTex->SetWrapR(eTextureWrap_ClampToEdge); pTex->SetWrapS(eTextureWrap_ClampToEdge); pTex->SetWrapT(eTextureWrap_ClampToEdge); } mpFogLinearSolidTexture = pTex; // Additive Log("Additive "); pTex = mpLowLevelGraphics->CreateTexture("FogLinearAdd", false, eTextureType_Normal, eTextureTarget_1D); for (int i = 0; i < 256; ++i) { pFogArray[i * 2 + 0] = (unsigned char)i; pFogArray[i * 2 + 1] = (unsigned char)i; } if (pTex) { pTex->CreateFromArray(pFogArray, 2, cVector3l(256, 1, 1)); pTex->SetWrapR(eTextureWrap_ClampToEdge); pTex->SetWrapS(eTextureWrap_ClampToEdge); } mpFogLinearAddTexture = pTex; // Alpha Log("Alpha "); pTex = mpLowLevelGraphics->CreateTexture("FogLinearAlpha", false, eTextureType_Normal, eTextureTarget_1D); for (int i = 0; i < 256; ++i) { pFogArray[i * 2 + 0] = 255; pFogArray[i * 2 + 1] = (unsigned char)i; } if (pTex) { pTex->CreateFromArray(pFogArray, 2, cVector3l(256, 1, 1)); pTex->SetWrapR(eTextureWrap_ClampToEdge); pTex->SetWrapS(eTextureWrap_ClampToEdge); } mpFogLinearAlphaTexture = pTex; hplDeleteArray(pFogArray); Log("\n"); ///////////////////////////////////////////// // Create Refraction programs mbRefractionAvailable = true; _refractProgram = pProgramManager->CreateProgram("hpl1_refract", "hpl1_refract"); _refractSpecProgram = pProgramManager->CreateProgram("hpl1_refract", "hpl1_refract_special"); if (!_refractProgram || !_refractSpecProgram) { mbRefractionAvailable = false; Hpl1::logInfo(Hpl1::kDebugGraphics, "%s", "refraction will not be supported"); } ///////////////////////////////////////////// // Create sky box graphics. Log("init sky box\n"); InitSkyBox(); Log("Renderer3D created\n"); } //----------------------------------------------------------------------- cRenderer3D::~cRenderer3D() { hplDeleteArray(mRenderSettings.mpTempIndexArray); if (mRenderSettings.extrudeProgram) mpResources->GetGpuProgramManager()->Destroy(mRenderSettings.extrudeProgram); if (_diffuseProgram) mpResources->GetGpuProgramManager()->Destroy(_diffuseProgram); if (_solidFogProgram) mpResources->GetGpuProgramManager()->Destroy(_solidFogProgram); if (_refractProgram) mpResources->GetGpuProgramManager()->Destroy(_refractProgram); if (_refractSpecProgram) mpResources->GetGpuProgramManager()->Destroy(_refractSpecProgram); if (mpSkyBox) hplDelete(mpSkyBox); if (mpSkyBoxTexture && mbAutoDestroySkybox) { mpResources->GetTextureManager()->Destroy(mpSkyBoxTexture); } if (mpFogLinearSolidTexture) hplDelete(mpFogLinearSolidTexture); if (mpFogLinearAddTexture) hplDelete(mpFogLinearAddTexture); if (mpFogLinearAlphaTexture) hplDelete(mpFogLinearAlphaTexture); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cRenderSettings::Clear() { mlLastShadowAlgo = 0; mbDepthTest = true; mAlphaMode = eMaterialAlphaMode_Solid; mBlendMode = eMaterialBlendMode_None; mChannelMode = eMaterialChannelMode_RGBA; gpuProgram = nullptr; mbVertexUseLight = false; mpSector = NULL; mbUsesLight = false; mbUsesEye = false; mbMatrixWasNULL = false; for (int i = 0; i < MAX_TEXTUREUNITS; i++) { mpTexture[i] = NULL; mTextureBlend[i] = eMaterialBlendMode_None; } mpVtxBuffer = NULL; } void cRenderSettings::Reset(iLowLevelGraphics *apLowLevel) { if (gpuProgram) gpuProgram->UnBind(); if (mpVtxBuffer) mpVtxBuffer->UnBind(); for (int i = 0; i < MAX_TEXTUREUNITS; i++) { if (mpTexture[i]) { apLowLevel->SetTexture(i, NULL); // mpLowLevelGraphics->SetTextureParam(eTextureParam_ColorOp1,eTextureOp_Color); // mpLowLevelGraphics->SetTextureParam(eTextureParam_ColorFunc, eTextureFunc_Modulate); } } Clear(); } //----------------------------------------------------------------------- eRendererShowShadows cRenderer3D::GetShowShadows() { return mRenderSettings.mShowShadows; } void cRenderer3D::SetShowShadows(eRendererShowShadows aState) { mRenderSettings.mShowShadows = aState; } //----------------------------------------------------------------------- void cRenderer3D::UpdateRenderList(cWorld3D *apWorld, cCamera3D *apCamera, float afFrameTime) { // Clear all objects to be rendereded mpRenderList->Clear(); // Set some variables mpRenderList->SetFrameTime(afFrameTime); mpRenderList->SetCamera(apCamera); // Set the frustum mRenderSettings.mpFrustum = apCamera->GetFrustum(); // Setup fog BV if (mRenderSettings.mbFogActive && mRenderSettings.mbFogCulling) { // This is because the fog line is a straight line infront of the camera. float fCornerDist = (mRenderSettings.mfFogEnd * 2.0f) / cos(apCamera->GetFOV() * apCamera->GetAspect() * 0.5f); mFogBV.SetSize(fCornerDist); mFogBV.SetPosition(apCamera->GetPosition()); } // Add all objects to be rendered apWorld->GetRenderContainer()->GetVisible(mRenderSettings.mpFrustum, mpRenderList); // Compile an optimized render list. mpRenderList->Compile(); } //----------------------------------------------------------------------- void cRenderer3D::RenderWorld(cWorld3D *apWorld, cCamera3D *apCamera, float afFrameTime) { mfRenderTime += afFrameTime; ////////////////////////////// // Setup render settings and logging if (mDebugFlags & eRendererDebugFlag_LogRendering) { mbLog = true; mRenderSettings.mbLog = true; } else if (mbLog) { mbLog = false; mRenderSettings.mbLog = false; } mRenderSettings.mDebugFlags = mDebugFlags; ///////////////////////////////// // Set up rendering BeginRendering(apCamera); mRenderSettings.Clear(); //////////////////////////// // Render Z // mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_E); mpLowLevelGraphics->SetColorWriteActive(true, true, true, true); mRenderSettings.mChannelMode = eMaterialChannelMode_RGBA; // mpLowLevelGraphics->SetColorWriteActive(false, false, false,false); // mRenderSettings.mChannelMode = eMaterialChannelMode_Z; // Set the ambient color mpLowLevelGraphics->SetActiveTextureUnit(0); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorFunc, eTextureFunc_Modulate); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource0, eTextureSource_Texture); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource1, eTextureSource_Constant); // mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource1,eTextureSource_Constant); mpLowLevelGraphics->SetTextureConstantColor(mRenderSettings.mAmbientColor); if (mbLog) Log("Rendering ZBuffer:\n"); RenderZ(apCamera); // reset parameters. mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource1, eTextureSource_Previous); // mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource1,eTextureSource_Previous); //////////////////////////// // Render Occlusion Queries mpLowLevelGraphics->SetColorWriteActive(false, false, false, false); mRenderSettings.mChannelMode = eMaterialChannelMode_Z; if (mbLog) Log("Rendering Occlusion Queries:\n"); mpLowLevelGraphics->SetDepthWriteActive(false); RenderOcclusionQueries(apCamera); //////////////////////////// // Render lighting mRenderSettings.mChannelMode = eMaterialChannelMode_RGBA; mpLowLevelGraphics->SetColorWriteActive(true, true, true, true); mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_Equal); if (mbLog) Log("Rendering Lighting:\n"); RenderLight(apCamera); //////////////////////////// // Render Diffuse if (mbLog) Log("Rendering Diffuse:\n"); RenderDiffuse(apCamera); //////////////////////////// // Render fog if (mbLog) Log("Rendering fog:\n"); RenderFog(apCamera); //////////////////////////// // Render sky box mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_LessOrEqual); //////////////////////////// if (mbLog) Log("Rendering Skybox:\n"); RenderSkyBox(apCamera); // Render transparent if (mbLog) Log("Rendering Transperant:\n"); RenderTrans(apCamera); mRenderSettings.Reset(mpLowLevelGraphics); //////////////////////////// // Render debug RenderDebug(apCamera); mpLowLevelGraphics->SetDepthWriteActive(true); } //----------------------------------------------------------------------- void cRenderer3D::SetSkyBox(iTexture *apTexture, bool abAutoDestroy) { if (mpSkyBoxTexture && mbAutoDestroySkybox) { mpResources->GetTextureManager()->Destroy(mpSkyBoxTexture); } mbAutoDestroySkybox = abAutoDestroy; mpSkyBoxTexture = apTexture; if (mpSkyBoxTexture) { mpSkyBoxTexture->SetWrapS(eTextureWrap_ClampToEdge); mpSkyBoxTexture->SetWrapT(eTextureWrap_ClampToEdge); } } void cRenderer3D::SetSkyBoxActive(bool abX) { mbSkyBoxActive = abX; } void cRenderer3D::SetSkyBoxColor(const cColor &aColor) { if (mSkyBoxColor == aColor) return; mSkyBoxColor = aColor; float *pColors = mpSkyBox->GetArray(eVertexFlag_Color0); int lNum = mpSkyBox->GetVertexNum(); for (int i = 0; i < lNum; ++i) { pColors[0] = mSkyBoxColor.r; pColors[1] = mSkyBoxColor.g; pColors[2] = mSkyBoxColor.b; pColors[3] = mSkyBoxColor.a; pColors += 4; } mpSkyBox->UpdateData(eVertexFlag_Color0, false); } //----------------------------------------------------------------------- void cRenderer3D::SetFogActive(bool abX) { if (_solidFogProgram) mRenderSettings.mbFogActive = abX; } void cRenderer3D::SetFogStart(float afX) { mRenderSettings.mfFogStart = afX; } void cRenderer3D::SetFogEnd(float afX) { mRenderSettings.mfFogEnd = afX; } //----------------------------------------------------------------------- void cRenderer3D::FetchOcclusionQueries() { if (mbLog) Log("Fetching Occlusion Queries Result:\n"); // With depth test cOcclusionQueryObjectIterator it = mpRenderList->GetQueryIterator(); while (it.HasNext()) { cOcclusionQueryObject *pObject = it.Next(); // LogUpdate("Query: %d!\n",pObject->mpQuery); while (pObject->mpQuery->FetchResults() == false) ; if (mbLog) Log(" Query: %d SampleCount: %d\n", pObject->mpQuery, pObject->mpQuery->GetSampleCount()); } if (mbLog) Log("Done fetching queries\n"); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cRenderer3D::BeginRendering(cCamera3D *apCamera) { ////////////////////////////////////////////////// /////Setup for clearing the screen // turn of scissor test. mpLowLevelGraphics->SetScissorActive(false); mpLowLevelGraphics->SetClearColor(cColor(0, 0)); mpLowLevelGraphics->SetClearColorActive(true); mpLowLevelGraphics->SetClearDepthActive(true); mpLowLevelGraphics->SetClearDepth(1); mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_LessOrEqual); mpLowLevelGraphics->SetClearStencilActive(false); mpLowLevelGraphics->ClearScreen(); ////////////////////////////////////////////////// // Cull and depth mode. mpLowLevelGraphics->SetCullActive(true); mpLowLevelGraphics->SetCullMode(eCullMode_CounterClockwise); mpLowLevelGraphics->SetDepthTestActive(true); mpLowLevelGraphics->SetMatrix(eMatrix_Projection, apCamera->GetProjectionMatrix()); mpLowLevelGraphics->SetColor(cColor(1, 1, 1, 1)); mRenderSettings.mpCamera = apCamera; for (int i = 0; i < MAX_TEXTUREUNITS; ++i) mpLowLevelGraphics->SetTexture(i, NULL); } //----------------------------------------------------------------------- void cRenderer3D::InitSkyBox() { mpSkyBox = mpMeshCreator->CreateSkyBoxVertexBuffer(1); } //----------------------------------------------------------------------- static void clearTextures(uint start, cRenderSettings &rendererSettings, iLowLevelGraphics *lowLevelGfx) { for (uint i = start; i < MAX_TEXTUREUNITS; ++i) { if (rendererSettings.mpTexture[i]) { lowLevelGfx->SetTexture(i, nullptr); rendererSettings.mpTexture[i] = nullptr; } } } void cRenderer3D::RenderFog(cCamera3D *apCamera) { if (mRenderSettings.mbFogActive == false || !_solidFogProgram) return; clearTextures(0, mRenderSettings, mpLowLevelGraphics); ////////////////////////////////// // Set fog program if (mRenderSettings.gpuProgram) mRenderSettings.gpuProgram->UnBind(); mRenderSettings.gpuProgram = nullptr; _solidFogProgram->Bind(); _solidFogProgram->SetColor3f("fogColor", mRenderSettings.mFogColor); _solidFogProgram->SetFloat("fogStart", mRenderSettings.mfFogStart); _solidFogProgram->SetFloat("fogEnd", mRenderSettings.mfFogEnd); ////////////////////////////////// // Blend mode mpLowLevelGraphics->SetBlendActive(true); // mpLowLevelGraphics->SetBlendFunc(eBlendFunc_One,eBlendFunc_Zero); mpLowLevelGraphics->SetBlendFunc(eBlendFunc_SrcAlpha, eBlendFunc_OneMinusSrcAlpha); mRenderSettings.mBlendMode = eMaterialBlendMode_LastEnum; ////////////////////////////////////// // Texture mpLowLevelGraphics->SetTexture(0, mpFogLinearSolidTexture); mRenderSettings.mpTexture[0] = mpFogLinearSolidTexture; ////////////////////////////////// // Render objects cMotionBlurObjectIterator it = mpRenderList->GetMotionBlurIterator(); while (it.HasNext()) { iRenderable *pObject = it.Next(); cMatrixf *pMtx = pObject->GetModelMatrix(apCamera); ////////////////// // Non static models if (pMtx) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, cMath::MatrixMul(apCamera->GetViewMatrix(), *pMtx)); _solidFogProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); } ////////////////// // NULL Model view matrix (static) else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); _solidFogProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); } pObject->GetVertexBuffer()->Bind(); pObject->GetVertexBuffer()->Draw(); pObject->GetVertexBuffer()->UnBind(); } _solidFogProgram->UnBind(); } //----------------------------------------------------------------------- void cRenderer3D::RenderSkyBox(cCamera3D *apCamera) { if (mbSkyBoxActive == false) return; Hpl1::logInfo(Hpl1::kDebugRenderer, "%s\n", "Drawing skybox"); if (mRenderSettings.gpuProgram) { mRenderSettings.gpuProgram->UnBind(); mRenderSettings.gpuProgram = nullptr; } if (mRenderSettings.mpVtxBuffer) { mRenderSettings.mpVtxBuffer->UnBind(); mRenderSettings.mpVtxBuffer = NULL; if (mbLog) Log(" Setting Vertex Buffer: NULL\n"); } clearTextures(1, mRenderSettings, mpLowLevelGraphics); mRenderSettings.mbMatrixWasNULL = false; cMatrixf mtxSky = cMatrixf::Identity; // Calculate the size of the sky box need to just touch the far clip plane. float fFarClip = apCamera->GetFarClipPlane(); float fSide = fFarClip / sqrt(3) * 0.95f; mtxSky.m[0][0] = fSide; mtxSky.m[1][1] = fSide; mtxSky.m[2][2] = fSide; mtxSky = cMath::MatrixMul(mtxSky, apCamera->GetViewMatrix()); mtxSky.SetTranslation(0); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, mtxSky); mpLowLevelGraphics->SetTexture(0, mpSkyBoxTexture); mRenderSettings.mpTexture[0] = mpSkyBoxTexture; mpLowLevelGraphics->SetBlendActive(false); mRenderSettings.mBlendMode = eMaterialBlendMode_Replace; mpSkyBox->Bind(); mpSkyBox->Draw(); mpSkyBox->UnBind(); } //----------------------------------------------------------------------- void cRenderer3D::RenderZ(cCamera3D *apCamera) { cRenderNode *pNode = mpRenderList->GetRootNode(eRenderListDrawType_Normal, eMaterialRenderType_Z, 0); mRenderSettings.mpLight = NULL; pNode->Render(&mRenderSettings); } //----------------------------------------------------------------------- void cRenderer3D::RenderOcclusionQueries(cCamera3D *apCamera) { #if 0 ////////////////////////////////////////////////// // Reset any vertex buffers,fragment or vertex programs. if (mRenderSettings.mpFragmentProgram) mRenderSettings.mpFragmentProgram->UnBind(); mRenderSettings.mpFragmentProgram = NULL; #endif //////////////////////////// // Vertex program if (mRenderSettings.gpuProgram != _diffuseProgram) { if (mRenderSettings.gpuProgram) mRenderSettings.gpuProgram->UnBind(); mRenderSettings.gpuProgram = _diffuseProgram; _diffuseProgram->Bind(); Hpl1::logInfo(Hpl1::kDebugGraphics, "%s", "binding Rendered3D::_diffuseProgram"); } //////////////////////// // Reset texture unit 0 mpLowLevelGraphics->SetTexture(0, NULL); mRenderSettings.mpTexture[0] = NULL; //////////////////////// // Keep track of what has been set iVertexBuffer *pPrevBuffer = mRenderSettings.mpVtxBuffer; cMatrixf *pPrevMatrix = NULL; bool bFirstRound = true; bool bPrevDepthTest = true; ////////////////////////////////// // Iterate the query objects cOcclusionQueryObjectIterator it = mpRenderList->GetQueryIterator(); while (it.HasNext()) { cOcclusionQueryObject *pObject = it.Next(); /*if(pObject->mbDepthTest) { mpLowLevelGraphics->SetColorWriteActive(true, true,true,true); mRenderSettings.mChannelMode = eMaterialChannelMode_RGBA; } else { mpLowLevelGraphics->SetColorWriteActive(false, false, false, false); mRenderSettings.mChannelMode = eMaterialChannelMode_Z; }*/ ///////////////////// // Set depth test if (bPrevDepthTest != pObject->mbDepthTest) { // mpLowLevelGraphics->SetDepthTestActive(pObject->mbDepthTest); if (pObject->mbDepthTest) mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_LessOrEqual); else mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_Always); bPrevDepthTest = pObject->mbDepthTest; if (mbLog) Log(" Setting depth test %d\n", pObject->mbDepthTest ? 1 : 0); } ///////////////////// // Set matrix if (pPrevMatrix != pObject->mpMatrix || bFirstRound) { if (pObject->mpMatrix) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, cMath::MatrixMul(apCamera->GetViewMatrix(), *pObject->mpMatrix)); } else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); } pPrevMatrix = pObject->mpMatrix; // Set the vertex program matrix. if (_diffuseProgram) _diffuseProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); if (mbLog) Log(" Setting matrix %d\n", pObject->mpMatrix); } ///////////////////// // Set Vertex buffer and draw if (pPrevBuffer != pObject->mpVtxBuffer) { if (pPrevBuffer) pPrevBuffer->UnBind(); pObject->mpVtxBuffer->Bind(); pPrevBuffer = pObject->mpVtxBuffer; if (mbLog) Log(" Setting vtx buffer %d\n", pObject->mpVtxBuffer); } pObject->mpQuery->Begin(); pObject->mpVtxBuffer->Draw(); pObject->mpQuery->End(); if (mbLog) Log(" Render with query: %d\n", pObject->mpQuery); bFirstRound = false; } mRenderSettings.mpVtxBuffer = pPrevBuffer; // mpLowLevelGraphics->FlushRendering(); // if(bPrevDepthTest==false) // mpLowLevelGraphics->SetDepthTestActive(true); } //----------------------------------------------------------------------- void cRenderer3D::RenderLight(cCamera3D *apCamera) { if (mDebugFlags & eRendererDebugFlag_DisableLighting) return; cLight3DIterator lightIt = mpRenderList->GetLightIt(); int lLightCount = 0; while (lightIt.HasNext()) { if (lLightCount >= MAX_NUM_OF_LIGHTS) break; iLight3D *pLight = lightIt.Next(); if (mpRenderList->GetLightObjects(lLightCount) == 0) { lLightCount++; continue; } if (mbLog) Log("-----Light %s/%d ------\n", pLight->GetName().c_str(), (size_t)pLight); cRenderNode *pNode = mpRenderList->GetRootNode(eRenderListDrawType_Normal, eMaterialRenderType_Light, lLightCount); if (pLight->BeginDraw(&mRenderSettings, mpLowLevelGraphics)) { pNode->Render(&mRenderSettings); } pLight->EndDraw(&mRenderSettings, mpLowLevelGraphics); lLightCount++; } } //----------------------------------------------------------------------- void cRenderer3D::RenderDiffuse(cCamera3D *apCamera) { cRenderNode *pNode = mpRenderList->GetRootNode(eRenderListDrawType_Normal, eMaterialRenderType_Diffuse, 0); mRenderSettings.mpLight = NULL; pNode->Render(&mRenderSettings); } //----------------------------------------------------------------------- /*void cRenderer3D::RenderTrans(cCamera3D *apCamera) { cRenderNode* pNode = mpRenderList->GetRootNode(eRenderListDrawType_Trans, eMaterialRenderType_Diffuse, 0); mRenderSettings.mpLight = NULL; pNode->Render(&mRenderSettings); }*/ void cRenderer3D::RenderTrans(cCamera3D *apCamera) { mpLowLevelGraphics->SetColorWriteActive(true, true, true, true); mpLowLevelGraphics->SetDepthWriteActive(false); bool bLog = mRenderSettings.mbLog; iTexture *vTextures[MAX_TEXTUREUNITS]; /*for(int i=0;iSetTexture(i,NULL); mRenderSettings.mpTexture[i] = NULL; }*/ /*cVector3f vForward = */ apCamera->GetForward(); ////////////////////////////////// // Iterate the query objects cTransperantObjectIterator it = mpRenderList->GetTransperantIterator(); while (it.HasNext()) { iRenderable *pObject = it.Next(); if (bLog) Log(" Rendering '%s'\n", pObject->GetName().c_str()); /*if(pObject->GetIsOneSided()) { cVector3f vNormal; if(pObject->GetModelMatrix(apCamera)) { vNormal = cMath::MatrixMul(pObject->GetWorldMatrix().GetRotation(), pObject->GetOneSidedNormal()); vNormal = cMath::MatrixMul(apCamera->GetViewMatrix().GetRotation(), vNormal); } else { vNormal = cMath::MatrixMul(apCamera->GetViewMatrix().GetRotation(), pObject->GetOneSidedNormal()); } if(cMath::Vector3Dot(vNormal, cVector3f(0,0,1)) < -0.5f) { continue; } }*/ ///////////////////////////////////////// // Get all data needed iMaterial *pMaterial = pObject->GetMaterial(); bool bDepthTest = pMaterial->GetDepthTest(); eMaterialAlphaMode alphaMode = pMaterial->GetAlphaMode(eMaterialRenderType_Diffuse, 0, NULL); eMaterialBlendMode blendMode = pMaterial->GetBlendMode(eMaterialRenderType_Diffuse, 0, NULL); for (int i = 0; i < MAX_TEXTUREUNITS; ++i) vTextures[i] = pMaterial->GetTexture(i, eMaterialRenderType_Diffuse, 0, NULL); iVertexBuffer *pVtxBuffer = pObject->GetVertexBuffer(); cMatrixf *pModelMatrix = pObject->GetModelMatrix(apCamera); cMatrixf *pInvModelMatrix = pObject->GetInvModelMatrix(); iTexture *pRefraction = pMaterial->GetTexture(eMaterialTexture_Refraction); if (mRenderSettings.mbDepthTest != bDepthTest) { mpLowLevelGraphics->SetDepthTestActive(bDepthTest); mRenderSettings.mbDepthTest = bDepthTest; if (bLog) Log(" Set depth test %d\n", bDepthTest); } ///////////////////////////////////////// // Refraction Rendering if (mbRefractionAvailable && pRefraction && mbRefractionUsed) { if (bLog) Log(" Start render refraction\n"); if (bLog) Log(" Unbind vtx buffer, vtx program and frag program\n"); if (mRenderSettings.mpVtxBuffer) mRenderSettings.mpVtxBuffer->UnBind(); if (mRenderSettings.gpuProgram) mRenderSettings.gpuProgram->UnBind(); ///////////////////////////////////// // Alpha and blend mode mRenderSettings.mAlphaMode = eMaterialAlphaMode_Solid; mpLowLevelGraphics->SetAlphaTestActive(false); mRenderSettings.mBlendMode = eMaterialBlendMode_None; mpLowLevelGraphics->SetBlendActive(false); ////////////////////////////// // Get Screen Clip space cVector2f vScreenSizeFloat = mpLowLevelGraphics->GetScreenSize(); cVector2l vScreenSize((int)mpLowLevelGraphics->GetScreenSize().x, (int)mpLowLevelGraphics->GetScreenSize().y); iTexture *pScreen = mpPostEffects->GetFreeScreenTexture(); // Get the cliprect objects bounding volume cRect2l clipRect; int lScale = cMath::Abs((int)pMaterial->GetValue()) + 1; bool bHasClipRect = cMath::GetClipRectFromBV(clipRect, *pObject->GetBoundingVolume(), apCamera->GetViewMatrix(), apCamera->GetProjectionMatrix(), apCamera->GetNearClipPlane(), vScreenSize); if (bHasClipRect) { clipRect.x -= lScale; if (clipRect.x < 0) { clipRect.w += clipRect.x; clipRect.x = 0; } clipRect.y -= lScale; if (clipRect.y < 0) { clipRect.h += clipRect.y; clipRect.y = 0; } clipRect.w += lScale * 2; if (clipRect.w + clipRect.x > vScreenSize.x) clipRect.w = vScreenSize.x - clipRect.x; clipRect.h += lScale * 2; if (clipRect.h + clipRect.y > vScreenSize.y) clipRect.h = vScreenSize.y - clipRect.y; } ////////////////////////////// // Render to alpha if water, (shitty test this is...) if (pMaterial->GetRefractionSkipsStandardTrans()) { if (bLog) Log(" Render alpha to screen\n"); // NULL all textuer for (int i = 0; i < MAX_TEXTUREUNITS; i++) { if (mRenderSettings.mpTexture[i] != NULL) { mpLowLevelGraphics->SetTexture(i, NULL); mRenderSettings.mpTexture[i] = NULL; if (bLog) Log(" Set texture[%d] NULL\n", i); } } // Only write to alpha mpLowLevelGraphics->SetColorWriteActive(false, false, false, true); //////////////////////////////////////////////// // Clear alpha using 2D quad. mpLowLevelGraphics->SetOrthoProjection(mpLowLevelGraphics->GetScreenSize(), -1000, 1000); mpLowLevelGraphics->SetIdentityMatrix(eMatrix_ModelView); if (bHasClipRect) { cVector2f vOffset = cVector2f((float)clipRect.x, (float)clipRect.y); cVector2f vSize = cVector2f((float)clipRect.w, (float)clipRect.h); mvVtxRect[0].pos = cVector3f(vOffset.x, vOffset.y, 0); mvVtxRect[1].pos = cVector3f(vOffset.x + vSize.x, vOffset.y, 0); mvVtxRect[2].pos = cVector3f(vOffset.x + vSize.x, vOffset.y + vSize.y, 0); mvVtxRect[3].pos = cVector3f(vOffset.x, vOffset.y + vSize.y, 0); } else { mvVtxRect[0].pos = cVector3f(0, 0, 0); mvVtxRect[1].pos = cVector3f(vScreenSizeFloat.x, 0, 0); mvVtxRect[2].pos = cVector3f(vScreenSizeFloat.x, vScreenSizeFloat.y, 0); mvVtxRect[3].pos = cVector3f(0, vScreenSizeFloat.y, 0); } for (int i = 0; i < 4; ++i) mvVtxRect[i].col.a = 0; mpLowLevelGraphics->DrawQuad(mvVtxRect); // Set back to ordinary projection... mpLowLevelGraphics->SetMatrix(eMatrix_Projection, apCamera->GetProjectionMatrix()); // Set Model matrix if (pModelMatrix) { cMatrixf mtxModel = cMath::MatrixMul(apCamera->GetViewMatrix(), *pModelMatrix); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, mtxModel); mRenderSettings.mbMatrixWasNULL = false; } else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); mRenderSettings.mbMatrixWasNULL = true; } pVtxBuffer->Bind(); if (bLog) Log(" Drawing vtx buffer %d\n", pVtxBuffer); pVtxBuffer->Draw(); pVtxBuffer->UnBind(); // Reset stuff mpLowLevelGraphics->SetColorWriteActive(true, true, true, true); } ////////////////////////////// // Copy Screen To Texture if (bHasClipRect) { cVector2l vOffset = cVector2l(clipRect.x, clipRect.y); cVector2l vSize = cVector2l(clipRect.w, clipRect.h); /*Log(" ScreenSize: %d:%d Offset: %d:%d Size: %d:%d Scale: %d\n",vScreenSize.x,vScreenSize.y, vOffset.x,vOffset.y, vSize.x, vSize.y, lScale);*/ mpLowLevelGraphics->CopyContextToTexure(pScreen, vOffset, vSize, vOffset); if (bLog) Log(" Copy clipped screen texture\n"); } else { mpLowLevelGraphics->CopyContextToTexure(pScreen, 0, vScreenSize); if (bLog) Log(" Copy full screen screen texture\n"); } ////////////////////////////// // Set up programs bool bSpecial = false; if (pMaterial->GetTexture(eMaterialTexture_Specular) != NULL && pMaterial->GetRefractionDiffuseTexture() == eMaterialTexture_Diffuse) { bSpecial = true; if (bLog) Log(" Special = true\n"); } iGpuProgram *refractProgram = pMaterial->getRefractionProgram(); if (!refractProgram) { if (bSpecial) refractProgram = _refractSpecProgram; else refractProgram = _refractProgram; } mRenderSettings.gpuProgram = refractProgram; refractProgram->Bind(); Hpl1::logInfo(Hpl1::kDebugRenderer, "Binding gpu program '%s'", refractProgram->GetName().c_str()); ///////////////////////////////////// // Vertex shader mRenderSettings.mbMatrixWasNULL = false; // Model matrix if (pModelMatrix) { cMatrixf mtxModel = cMath::MatrixMul(apCamera->GetViewMatrix(), *pModelMatrix); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, mtxModel); mRenderSettings.mbMatrixWasNULL = false; } else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); mRenderSettings.mbMatrixWasNULL = true; } refractProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); // Eye position if (pMaterial->GetRefractionUsesEye()) { if (pModelMatrix) { cVector3f vLocalEye = cMath::MatrixMul(*pInvModelMatrix, apCamera->GetEyePosition()); refractProgram->SetVec3f("EyePos", vLocalEye); } else { refractProgram->SetVec3f("EyePos", apCamera->GetEyePosition()); } } ///////////////////////////////////// // Fragment shader refractProgram->SetVec2f("screenSize", mpLowLevelGraphics->GetScreenSize()); if (bSpecial) { refractProgram->SetFloat("t", mfRenderTime * pRefraction->GetFrameTime()); } else if (pMaterial->GetRefractionUsesTime()) { refractProgram->SetFloat("t", mfRenderTime); } refractProgram->SetFloat("scale", pMaterial->GetValue()); //////////////////////////////////// // Textures for (int i = 0; i < MAX_TEXTUREUNITS; i++) { // float fTime; iTexture *pTex = NULL; switch (i) { case 0: pTex = pScreen; break; case 1: pTex = pRefraction; break; case 2: if (bSpecial) { pTex = pMaterial->GetTexture(eMaterialTexture_Specular); } else if (pMaterial->GetRefractionUsesDiffuse()) { pTex = pMaterial->GetTexture(pMaterial->GetRefractionDiffuseTexture()); } } if (mRenderSettings.mpTexture[i] != pTex) { mpLowLevelGraphics->SetTexture(i, pTex); mRenderSettings.mpTexture[i] = pTex; if (bLog) { if (pTex) Log(" Set texture[%d] %s (%d)\n", i, pTex->GetName().c_str(), pTex); else Log(" Set texture[%d] NULL\n", i); } } } ///////////////////////////////////// // Draw if (bLog) Log(" Drawing vtx buffer %d\n", pVtxBuffer); pVtxBuffer->Bind(); pVtxBuffer->Draw(); pVtxBuffer->UnBind(); mRenderSettings.mpVtxBuffer = pVtxBuffer; if (pMaterial->GetRefractionSkipsStandardTrans() || pMaterial->GetTexture(eMaterialTexture_Diffuse) == NULL) { if (bLog) Log(" Skipping normal trans rendering!\n"); continue; } } ///////////////////////////////////////////////// // Alpha mode if (alphaMode != mRenderSettings.mAlphaMode) { mRenderSettings.mAlphaMode = alphaMode; if (alphaMode == eMaterialAlphaMode_Solid) { mpLowLevelGraphics->SetAlphaTestActive(false); if (bLog) Log(" Set alpha test off!\n"); } else { mpLowLevelGraphics->SetAlphaTestActive(true); mpLowLevelGraphics->SetAlphaTestFunc(eAlphaTestFunc_GreaterOrEqual, 0.6f); if (bLog) Log(" Set alpha test on!\n"); } } ///////////////////////////////////////////////// // Blend mode if (blendMode != mRenderSettings.mBlendMode) { mRenderSettings.mBlendMode = blendMode; if (blendMode == eMaterialBlendMode_None) { mpLowLevelGraphics->SetBlendActive(false); if (bLog) Log(" Set blend mode off!\n"); } else { mpLowLevelGraphics->SetBlendActive(true); switch (blendMode) { case eMaterialBlendMode_Add: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_One, eBlendFunc_One); if (bLog) Log(" Set blend mode one-one!\n"); break; case eMaterialBlendMode_Replace: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_One, eBlendFunc_Zero); if (bLog) Log(" Set blend mode one-zero!\n"); break; case eMaterialBlendMode_Mul: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_Zero, eBlendFunc_SrcColor); if (bLog) Log(" Set blend mode zero-srccolor!\n"); break; case eMaterialBlendMode_MulX2: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_DestColor, eBlendFunc_SrcColor); if (bLog) Log(" Set blend mode destcolor-srccolor!\n"); break; case eMaterialBlendMode_Alpha: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_SrcAlpha, eBlendFunc_OneMinusSrcAlpha); if (bLog) Log(" Set blend mode srcalpha-oneminussrcalpha!\n"); break; case eMaterialBlendMode_DestAlphaAdd: mpLowLevelGraphics->SetBlendFunc(eBlendFunc_DestAlpha, eBlendFunc_One); if (bLog) Log(" Set blend mode destalpha-one!\n"); break; default: break; } } } iGpuProgram *gpuProgram = pMaterial->getGpuProgram(eMaterialRenderType_Diffuse, 0, nullptr); iMaterialProgramSetup *gpuProgramSetup = pMaterial->getGpuProgramSetup(eMaterialRenderType_Diffuse, 0, NULL); if (gpuProgram != mRenderSettings.gpuProgram) { if (mRenderSettings.gpuProgram) mRenderSettings.gpuProgram->UnBind(); mRenderSettings.gpuProgram = gpuProgram; if (gpuProgram) { gpuProgram->Bind(); if (gpuProgramSetup) gpuProgramSetup->Setup(gpuProgram, &mRenderSettings); mRenderSettings.gpuProgramSetup = gpuProgramSetup; mRenderSettings.mbMatrixWasNULL = false; } } ///////////////////////////////////////////////// // Texture for (int i = 0; i < MAX_TEXTUREUNITS; i++) { if (mRenderSettings.mpTexture[i] != vTextures[i]) { mpLowLevelGraphics->SetTexture(i, vTextures[i]); mRenderSettings.mpTexture[i] = vTextures[i]; if (bLog) { if (vTextures[i]) Log(" Set texture[%d] %s (%d)\n", i, vTextures[i]->GetName().c_str(), vTextures[i]); else Log(" Set texture[%d] NULL\n", i); } } } ///////////////////////////////////////////////// // Vertex buffer if (pVtxBuffer != mRenderSettings.mpVtxBuffer) { if (mRenderSettings.mpVtxBuffer) mRenderSettings.mpVtxBuffer->UnBind(); mRenderSettings.mpVtxBuffer = pVtxBuffer; if (pVtxBuffer) pVtxBuffer->Bind(); if (bLog) Log(" Set vtx buffer %d\n", pVtxBuffer); } ///////////////////////////////////////////////// // Matrix // It is a normal matrix bool bSetVtxProgMatrix = false; if (pModelMatrix) { cMatrixf mtxModel = cMath::MatrixMul(apCamera->GetViewMatrix(), *pModelMatrix); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, mtxModel); mRenderSettings.mbMatrixWasNULL = false; bSetVtxProgMatrix = true; } // NULL matrix else if (mRenderSettings.mbMatrixWasNULL == false) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); mRenderSettings.mbMatrixWasNULL = true; bSetVtxProgMatrix = true; } if (mRenderSettings.gpuProgram && bSetVtxProgMatrix) { // Might be quicker if this is set directly mRenderSettings.gpuProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); if (mRenderSettings.gpuProgramSetup) { mRenderSettings.gpuProgramSetup->SetupMatrix(pModelMatrix, &mRenderSettings); } } /////////////////////////////////////////// /// Draw if (bLog) Log("Draw\n"); pVtxBuffer->Draw(); } if (mRenderSettings.mpVtxBuffer) mRenderSettings.mpVtxBuffer->UnBind(); if (mRenderSettings.gpuProgram) mRenderSettings.gpuProgram->UnBind(); } //----------------------------------------------------------------------- void cRenderer3D::RenderDebug(cCamera3D *apCamera) { if (mDebugFlags) { mpLowLevelGraphics->SetDepthWriteActive(false); // Render Debug for objects cRenderableIterator objectIt = mpRenderList->GetObjectIt(); while (objectIt.HasNext()) { iRenderable *pObject = objectIt.Next(); RenderDebugObject(apCamera, pObject, NULL, 0, NULL, eMaterialRenderType_Diffuse, NULL); } // Render debug for lights. if (mDebugFlags & eRendererDebugFlag_DrawLightBoundingBox) { mpLowLevelGraphics->SetDepthTestActive(false); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); cLight3DIterator lightIt = mpRenderList->GetLightIt(); while (lightIt.HasNext()) { iLight3D *pLight = lightIt.Next(); cBoundingVolume *pBV = pLight->GetBoundingVolume(); cColor Col = pLight->GetDiffuseColor(); mpLowLevelGraphics->DrawSphere(pLight->GetWorldPosition(), 0.1f, Col); mpLowLevelGraphics->DrawBoxMaxMin(pBV->GetMax(), pBV->GetMin(), Col); } mpLowLevelGraphics->SetDepthTestActive(true); } mpLowLevelGraphics->SetDepthWriteActive(true); } } //----------------------------------------------------------------------- void cRenderer3D::RenderDebugObject(cCamera3D *apCamera, iRenderable *&apObject, iMaterial *apPrevMat, int alPrevMatId, iVertexBuffer *apPrevVtxBuff, eMaterialRenderType aRenderType, iLight3D *apLight) { iVertexBuffer *pVtxBuffer = apObject->GetVertexBuffer(); if (mDebugFlags & eRendererDebugFlag_DrawBoundingBox) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); cBoundingVolume *pBV = apObject->GetBoundingVolume(); mpLowLevelGraphics->DrawBoxMaxMin(pBV->GetMax(), pBV->GetMin(), cColor(1, 1.0f, 1.0f, 1)); } if (mDebugFlags & eRendererDebugFlag_DrawBoundingSphere) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, apCamera->GetViewMatrix()); cBoundingVolume *pBV = apObject->GetBoundingVolume(); mpLowLevelGraphics->DrawSphere(pBV->GetWorldCenter(), pBV->GetRadius(), cColor(1, 1.0f, 1.0f, 1)); } cMatrixf mtxModel; cMatrixf *pModelMtx = apObject->GetModelMatrix(apCamera); if (pModelMtx) mtxModel = cMath::MatrixMul(apCamera->GetViewMatrix(), *pModelMtx); else mtxModel = cMath::MatrixMul(apCamera->GetViewMatrix(), cMatrixf::Identity); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, mtxModel); // Draw the debug graphics for the object. for (int i = 0; i < pVtxBuffer->GetVertexNum(); i++) { cVector3f vPos = pVtxBuffer->GetVector3(eVertexFlag_Position, i); if (mDebugFlags & eRendererDebugFlag_DrawNormals) { cVector3f vNormal = pVtxBuffer->GetVector3(eVertexFlag_Normal, i); mpLowLevelGraphics->DrawLine(vPos, vPos + (vNormal * 0.1f), cColor(0.5f, 0.5f, 1, 1)); } if (mDebugFlags & eRendererDebugFlag_DrawTangents) { cVector3f vTan = pVtxBuffer->GetVector4(eVertexFlag_Texture1, i); mpLowLevelGraphics->DrawLine(vPos, vPos + (vTan * 0.2f), cColor(1, 0.0f, 0.0f, 1)); } } } //----------------------------------------------------------------------- } // namespace hpl