/* 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/RendererPostEffects.h" #include "hpl1/debug.h" #include "hpl1/engine/graphics/GPUProgram.h" #include "hpl1/engine/graphics/LowLevelGraphics.h" #include "hpl1/engine/graphics/RenderList.h" #include "hpl1/engine/graphics/Renderer3D.h" #include "hpl1/engine/graphics/Texture.h" #include "hpl1/engine/math/Math.h" #include "hpl1/engine/resources/GpuProgramManager.h" #include "hpl1/engine/resources/Resources.h" #include "hpl1/engine/resources/low_level_resources.h" #include "hpl1/engine/scene/Scene.h" #include "hpl1/engine/system/low_level_system.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cRendererPostEffects::cRendererPostEffects(iLowLevelGraphics *apLowLevelGraphics, cResources *apResources, cRenderList *apRenderList, cRenderer3D *apRenderer3D) { mpLowLevelGraphics = apLowLevelGraphics; mpLowLevelResources = apResources->GetLowLevel(); mpResources = apResources; mpRenderer3D = apRenderer3D; mpGpuManager = mpResources->GetGpuProgramManager(); mvScreenSize = mpLowLevelGraphics->GetScreenSize(); mpRenderList = apRenderList; /////////////////////////////////////////// // Create screen buffers Log(" Creating screen buffers size %s\n", mvScreenSize.ToString().c_str()); for (int i = 0; i < 2; i++) { if (mpLowLevelGraphics->GetCaps(eGraphicCaps_TextureTargetRectangle)) { mpScreenBuffer[i] = mpLowLevelGraphics->CreateTexture(cVector2l( (int)mvScreenSize.x, (int)mvScreenSize.y), 32, cColor(0, 0, 0, 0), false, eTextureType_Normal, eTextureTarget_Rect); if (mpScreenBuffer[i] == NULL) { Error("Couldn't create screenbuffer!\n"); mpScreenBuffer[0] = NULL; mpScreenBuffer[1] = NULL; break; } mpScreenBuffer[i]->SetWrapS(eTextureWrap_ClampToEdge); mpScreenBuffer[i]->SetWrapT(eTextureWrap_ClampToEdge); } else { mpScreenBuffer[i] = NULL; Error("Texture rectangle not supported. Posteffects will be turned off."); } } /////////////////////////////////////////// // Create programs Hpl1::logInfo(Hpl1::kDebugRenderer, "%s", "Creating RendererPostEffects programs"); ///////////////// // Blur programs mbBlurFallback = false; // Set to true if the fallbacks are used. _blur2DProgram = mpGpuManager->CreateProgram("hpl1_PostEffect_Blur", "hpl1_PostEffect_Blur_2D"); _blurRectProgram = mpGpuManager->CreateProgram("hpl1_PostEffect_Blur", "hpl1_PostEffect_Blur_Rect"); ///////////////// // Bloom programs _bloomProgram = mpGpuManager->CreateProgram("hpl1_PostEffect_Bloom", "hpl1_PostEffect_Bloom"); // Bloom blur textures mpBloomBlurTexture = mpLowLevelGraphics->CreateTexture( cVector2l(256, 256), 32, cColor(0, 0, 0, 0), false, eTextureType_Normal, eTextureTarget_2D); if (mpBloomBlurTexture == NULL) { Error("Couldn't create bloom blur textures!\n"); } else { mpBloomBlurTexture->SetWrapS(eTextureWrap_ClampToEdge); mpBloomBlurTexture->SetWrapT(eTextureWrap_ClampToEdge); } ///////////////// // MotionBlur programs _motionBlurProgram = mpGpuManager->CreateProgram("hpl1_PostEffect_Motion", "hpl1_PostEffect_Motion"); // CHECK APPLE ///////////////// // Depth of Field programs _depthOfFieldProgram = mpGpuManager->CreateProgram("hpl1_PostEffect_DoF", "hpl1_PostEffect_DoF"); // Depth of Field blur textures mpDofBlurTexture = mpLowLevelGraphics->CreateTexture(cVector2l(256, 256), 32, cColor(0, 0, 0, 0), false, eTextureType_Normal, eTextureTarget_2D); if (mpDofBlurTexture == NULL) { Error("Couldn't create Depth of Field blur textures!\n"); } else { mpDofBlurTexture->SetWrapS(eTextureWrap_ClampToEdge); mpDofBlurTexture->SetWrapT(eTextureWrap_ClampToEdge); } Log("RendererPostEffects created\n"); //////////////////////////////////// // Variable setup // General mbActive = false; mvTexRectVtx.resize(4); // Bloom mbBloomActive = false; mfBloomSpread = 2.0f; // Motion blur mbMotionBlurActive = false; mfMotionBlurAmount = 1.0f; mbMotionBlurFirstTime = true; // Depth of Field mbDofActive = false; mfDofMaxBlur = 1.0f; mfDofFocalPlane = 1.0f; mfDofNearPlane = 2.0f; mfDofFarPlane = 3.0f; } //----------------------------------------------------------------------- cRendererPostEffects::~cRendererPostEffects() { for (int i = 0; i < 2; i++) if (mpScreenBuffer[i]) hplDelete(mpScreenBuffer[i]); if (_blur2DProgram) mpGpuManager->Destroy(_blur2DProgram); if (_blurRectProgram) mpGpuManager->Destroy(_blurRectProgram); if (_bloomProgram) mpGpuManager->Destroy(_bloomProgram); if (_motionBlurProgram) mpGpuManager->Destroy(_motionBlurProgram); if (_depthOfFieldProgram) mpGpuManager->Destroy(_depthOfFieldProgram); if (mpBloomBlurTexture) hplDelete(mpBloomBlurTexture); if (mpDofBlurTexture) hplDelete(mpDofBlurTexture); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cRendererPostEffects::SetBloomActive(bool abX) { mbBloomActive = abX; } //----------------------------------------------------------------------- void cRendererPostEffects::SetMotionBlurActive(bool abX) { mbMotionBlurActive = abX; mbMotionBlurFirstTime = true; } //----------------------------------------------------------------------- void cRendererPostEffects::Render() { if (mpScreenBuffer[0] == NULL || mpScreenBuffer[1] == NULL) return; if (!mpLowLevelGraphics->GetCaps(eGraphicCaps_TextureTargetRectangle)) return; if (mbActive == false || (mImageTrailData.mbActive == false && mbBloomActive == false && mbMotionBlurActive == false && mbDofActive == false)) { return; } mvScreenSize = mpLowLevelGraphics->GetScreenSize(); RenderDepthOfField(); RenderMotionBlur(); mpLowLevelGraphics->SetDepthTestActive(false); mpLowLevelGraphics->PushMatrix(eMatrix_ModelView); mpLowLevelGraphics->SetIdentityMatrix(eMatrix_ModelView); mpLowLevelGraphics->SetOrthoProjection(mpLowLevelGraphics->GetVirtualSize(), -1000, 1000); RenderBloom(); RenderImageTrail(); mpLowLevelGraphics->PopMatrix(eMatrix_ModelView); } //----------------------------------------------------------------------- // TODO: Support source texture as 2D void cRendererPostEffects::RenderBlurTexture(iTexture *apDestination, iTexture *apSource, float afBlurAmount) { bool bProgramsLoaded = false; if (_blur2DProgram && _blurRectProgram) bProgramsLoaded = true; iLowLevelGraphics *pLowLevel = mpLowLevelGraphics; cVector2l vBlurSize = cVector2l(apDestination->getWidth(), apDestination->getHeight()); cVector2f vBlurDrawSize; vBlurDrawSize.x = ((float)vBlurSize.x / mvScreenSize.x) * mpLowLevelGraphics->GetVirtualSize().x; vBlurDrawSize.y = ((float)vBlurSize.y / mvScreenSize.y) * mpLowLevelGraphics->GetVirtualSize().y; pLowLevel->SetBlendActive(false); /////////////////////////////////////////// // Horizontal blur pass // Shader setup if (bProgramsLoaded) { // Setup vertex program _blurRectProgram->Bind(); _blurRectProgram->SetFloat("xOffset", 1); _blurRectProgram->SetFloat("yOffset", 0); _blurRectProgram->SetFloat("amount", afBlurAmount); _blurRectProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); } // Draw the screen texture with blur pLowLevel->SetTexture(0, apSource); if (mbBlurFallback) { mpLowLevelGraphics->SetTexture(1, apSource); mpLowLevelGraphics->SetTexture(2, apSource); } { mvTexRectVtx[0] = cVertex(cVector3f(0, 0, 40), cVector2f(0, mvScreenSize.y), cColor(1, 1.0f)); mvTexRectVtx[1] = cVertex(cVector3f(vBlurDrawSize.x, 0, 40), cVector2f(mvScreenSize.x, mvScreenSize.y), cColor(1, 1.0f)); mvTexRectVtx[2] = cVertex(cVector3f(vBlurDrawSize.x, vBlurDrawSize.y, 40), cVector2f(mvScreenSize.x, 0), cColor(1, 1.0f)); mvTexRectVtx[3] = cVertex(cVector3f(0, vBlurDrawSize.y, 40), cVector2f(0, 0), cColor(1, 1.0f)); mpLowLevelGraphics->DrawQuad(mvTexRectVtx); } pLowLevel->CopyContextToTexure(apDestination, 0, vBlurSize); /////////////////////////////////////////// // Vertical blur pass // Setup shaders // Shader setup if (bProgramsLoaded) { _blur2DProgram->Bind(); _blur2DProgram->SetFloat("xOffset", 0); _blur2DProgram->SetFloat("yOffset", 1); _blur2DProgram->SetFloat("amount", (1 / pLowLevel->GetScreenSize().x) * afBlurAmount); } // Set texture and draw pLowLevel->SetTexture(0, apDestination); if (mbBlurFallback) { mpLowLevelGraphics->SetTexture(1, apDestination); mpLowLevelGraphics->SetTexture(2, apDestination); } { mvTexRectVtx[0] = cVertex(cVector3f(0, 0, 40), cVector2f(0, 1), cColor(1, 1.0f)); mvTexRectVtx[1] = cVertex(cVector3f(vBlurDrawSize.x, 0, 40), cVector2f(1, 1), cColor(1, 1.0f)); mvTexRectVtx[2] = cVertex(cVector3f(vBlurDrawSize.x, vBlurDrawSize.y, 40), cVector2f(1, 0), cColor(1, 1.0f)); mvTexRectVtx[3] = cVertex(cVector3f(0, vBlurDrawSize.y, 40), cVector2f(0, 0), cColor(1, 1.0f)); mpLowLevelGraphics->DrawQuad(mvTexRectVtx); } // Shader setup if (bProgramsLoaded) { _blur2DProgram->UnBind(); } pLowLevel->CopyContextToTexure(apDestination, 0, vBlurSize); if (mbBlurFallback) { mpLowLevelGraphics->SetTexture(1, NULL); mpLowLevelGraphics->SetTexture(2, NULL); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cRendererPostEffects::RenderDepthOfField() { if (mbDofActive == false) return; if (!_depthOfFieldProgram) return; ////////////////////////////// // Setup cCamera3D *pCam = mpRenderList->GetCamera(); iTexture *pScreenTexture = mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]; // Size of the virtual screen cVector2f vVirtSize = mpLowLevelGraphics->GetVirtualSize(); // Copy screen to texture mpLowLevelGraphics->CopyContextToTexure(pScreenTexture, 0, cVector2l((int)mvScreenSize.x, (int)mvScreenSize.y)); // Set up things needed for blurring mpLowLevelGraphics->SetDepthWriteActive(false); mpLowLevelGraphics->SetDepthTestActive(false); mpLowLevelGraphics->SetIdentityMatrix(eMatrix_ModelView); mpLowLevelGraphics->SetOrthoProjection(mpLowLevelGraphics->GetVirtualSize(), -1000, 1000); // Render blur texture RenderBlurTexture(mpDofBlurTexture, pScreenTexture, 2.0f); // Set texture mpLowLevelGraphics->SetTexture(0, pScreenTexture); mpLowLevelGraphics->SetTexture(1, mpDofBlurTexture); // Render entire screen textur to screen, this to cover up what has been done by the // blur filter, should have support for frame_buffer_object so this can be skipped. if (mpRenderer3D->GetSkyBoxActive()) { tVector3fVec vUvVec; vUvVec.resize(4); vUvVec[0] = cVector2f(0, 1); vUvVec[1] = cVector2f(1, 1); vUvVec[2] = cVector2f(1, 0); vUvVec[3] = cVector2f(0, 0); mvTexRectVtx[0] = cVertex(cVector3f(0, 0, 40), cVector2f(0, mvScreenSize.y), cColor(1, 1.0f)); mvTexRectVtx[1] = cVertex(cVector3f(vVirtSize.x, 0, 40), cVector2f(mvScreenSize.x, mvScreenSize.y), cColor(1, 1.0f)); mvTexRectVtx[2] = cVertex(cVector3f(vVirtSize.x, vVirtSize.y, 40), cVector2f(mvScreenSize.x, 0), cColor(1, 1.0f)); mvTexRectVtx[3] = cVertex(cVector3f(0, vVirtSize.y, 40), cVector2f(0, 0), cColor(1, 1.0f)); mpLowLevelGraphics->SetActiveTextureUnit(1); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource0, eTextureSource_Texture); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource1, eTextureSource_Previous); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource2, eTextureSource_Constant); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorFunc, eTextureFunc_Interpolate); mpLowLevelGraphics->SetTextureConstantColor(cColor(mfDofMaxBlur, mfDofMaxBlur)); mpLowLevelGraphics->DrawQuadMultiTex(mvTexRectVtx, vUvVec); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorFunc, eTextureFunc_Modulate); } // Set things back to normal mpLowLevelGraphics->SetMatrix(eMatrix_Projection, pCam->GetProjectionMatrix()); /////////////////////////////////////////// // Draw motion blur objects mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_Equal); mpLowLevelGraphics->SetDepthTestActive(true); mpLowLevelGraphics->SetBlendActive(false); // Setup _depthOfFieldProgram->Bind(); _depthOfFieldProgram->SetVec3f("planes", cVector3f(mfDofNearPlane, mfDofFocalPlane, mfDofFarPlane)); _depthOfFieldProgram->SetFloat("maxBlur", mfDofMaxBlur); _depthOfFieldProgram->SetVec2f("screenSize", mvScreenSize); ////////////////// // Render objects cMotionBlurObjectIterator it = mpRenderList->GetMotionBlurIterator(); while (it.HasNext()) { iRenderable *pObject = it.Next(); cMatrixf *pMtx = pObject->GetModelMatrix(pCam); ////////////////// // Non static models if (pMtx) { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, cMath::MatrixMul(pCam->GetViewMatrix(), *pMtx)); _depthOfFieldProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); } ////////////////// // NULL Model view matrix (static) else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, pCam->GetViewMatrix()); _depthOfFieldProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); } pObject->GetVertexBuffer()->Bind(); pObject->GetVertexBuffer()->Draw(); pObject->GetVertexBuffer()->UnBind(); // Set the previous position to the current if (pMtx) pObject->SetPrevMatrix(*pMtx); } mpLowLevelGraphics->SetDepthTestFunc(eDepthTestFunc_LessOrEqual); mpLowLevelGraphics->SetDepthWriteActive(true); // Reset stuff _depthOfFieldProgram->UnBind(); mpLowLevelGraphics->SetTexture(0, NULL); mpLowLevelGraphics->SetTexture(1, NULL); } //----------------------------------------------------------------------- void cRendererPostEffects::RenderMotionBlur() { if (mbMotionBlurActive == false) return; if (!_motionBlurProgram) return; ////////////////////////////// // Setup iTexture *pScreenTexture = mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]; // Copy screen to texture mpLowLevelGraphics->CopyContextToTexure(pScreenTexture, 0, cVector2l((int)mvScreenSize.x, (int)mvScreenSize.y)); /////////////////////////////////////////// // Draw motion blur objects mpLowLevelGraphics->SetDepthTestActive(true); mpLowLevelGraphics->SetBlendActive(false); cCamera3D *pCam = mpRenderList->GetCamera(); if (mbMotionBlurFirstTime) { pCam->SetPrevView(pCam->GetViewMatrix()); pCam->SetPrevProjection(pCam->GetProjectionMatrix()); mbMotionBlurFirstTime = false; } cMotionBlurObjectIterator it = mpRenderList->GetMotionBlurIterator(); // Setup _motionBlurProgram->Bind(); _motionBlurProgram->SetFloat("blurScale", mfMotionBlurAmount); _motionBlurProgram->SetVec2f("halfScreenSize", cVector2f((float)pScreenTexture->getWidth() / 2.0f, (float)pScreenTexture->getHeight() / 2.0f)); mpLowLevelGraphics->SetTexture(0, pScreenTexture); ////////////////// // Render objects while (it.HasNext()) { iRenderable *pObject = it.Next(); cMatrixf *pMtx = pObject->GetModelMatrix(pCam); ////////////////// // Non static models if (pMtx) { cMatrixf mtxPrev = pObject->GetPrevMatrix(); mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, cMath::MatrixMul(pCam->GetViewMatrix(), *pMtx)); _motionBlurProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); cMatrixf mtxModelView = cMath::MatrixMul(pCam->GetViewMatrix(), *pMtx); cMatrixf mtxPrevModelView = cMath::MatrixMul(pCam->GetPrevView(), mtxPrev); cMatrixf mtxPrevViewProj = cMath::MatrixMul(pCam->GetPrevProjection(), mtxPrevModelView); _motionBlurProgram->SetMatrixf("prevWorldViewProj", mtxPrevViewProj); _motionBlurProgram->SetMatrixf("modelView", mtxModelView); _motionBlurProgram->SetMatrixf("prevModelView", mtxPrevModelView); } ////////////////// // NULL Model view matrix (static) else { mpLowLevelGraphics->SetMatrix(eMatrix_ModelView, pCam->GetViewMatrix()); _motionBlurProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); const cMatrixf &mtxModelView = pCam->GetViewMatrix(); const cMatrixf &mtxPrevModelView = pCam->GetPrevView(); cMatrixf mtxPrevViewProj = cMath::MatrixMul(pCam->GetPrevProjection(), mtxPrevModelView); _motionBlurProgram->SetMatrixf("prevWorldViewProj", mtxPrevViewProj); _motionBlurProgram->SetMatrixf("modelView", mtxModelView); _motionBlurProgram->SetMatrixf("prevModelView", mtxPrevModelView); } pObject->GetVertexBuffer()->Bind(); pObject->GetVertexBuffer()->Draw(); pObject->GetVertexBuffer()->UnBind(); // Set the previous position to the current if (pMtx) pObject->SetPrevMatrix(*pMtx); } // Reset stuff _motionBlurProgram->UnBind(); mpLowLevelGraphics->SetTexture(0, NULL); mpLowLevelGraphics->SetTexture(1, NULL); // Set the new pervious values. pCam->SetPrevView(pCam->GetViewMatrix()); pCam->SetPrevProjection(pCam->GetProjectionMatrix()); } //----------------------------------------------------------------------- void cRendererPostEffects::RenderBloom() { if (mbBloomActive == false) return; if (!_bloomProgram) return; ////////////////////////////// // Setup iTexture *pScreenTexture = mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]; // Copy screen to texture mpLowLevelGraphics->CopyContextToTexure(pScreenTexture, 0, cVector2l((int)mvScreenSize.x, (int)mvScreenSize.y)); // Get the blur texture RenderBlurTexture(mpBloomBlurTexture, pScreenTexture, mfBloomSpread); // Size of blur texture /*cVector2f vBlurSize = */ cVector2f((float)mpBloomBlurTexture->getWidth(), (float)mpBloomBlurTexture->getHeight()); // Size of the virtual screen cVector2f vVirtSize = mpLowLevelGraphics->GetVirtualSize(); /////////////////////////////////////////// // Draw Bloom // Setup bloom program _bloomProgram->Bind(); _bloomProgram->SetMatrixf("worldViewProj", eGpuProgramMatrix_ViewProjection, eGpuProgramMatrixOp_Identity); mpLowLevelGraphics->SetTexture(0, mpBloomBlurTexture); mpLowLevelGraphics->SetTexture(1, pScreenTexture); // Draw { tVector3fVec vUvVec; vUvVec.resize(4); vUvVec[0] = cVector2f(0, mvScreenSize.y); vUvVec[1] = cVector2f(mvScreenSize.x, mvScreenSize.y); vUvVec[2] = cVector2f(mvScreenSize.x, 0); vUvVec[3] = cVector2f(0, 0); mvTexRectVtx[0] = cVertex(cVector3f(0, 0, 40), cVector2f(0, 1), cColor(1, 1.0f)); mvTexRectVtx[1] = cVertex(cVector3f(vVirtSize.x, 0, 40), cVector2f(1, 1), cColor(1, 1.0f)); mvTexRectVtx[2] = cVertex(cVector3f(vVirtSize.x, vVirtSize.y, 40), cVector2f(1, 0), cColor(1, 1.0f)); mvTexRectVtx[3] = cVertex(cVector3f(0, vVirtSize.y, 40), cVector2f(0, 0), cColor(1, 1.0f)); mpLowLevelGraphics->DrawQuadMultiTex(mvTexRectVtx, vUvVec); } _bloomProgram->UnBind(); mpLowLevelGraphics->SetTexture(0, NULL); mpLowLevelGraphics->SetTexture(1, NULL); } //----------------------------------------------------------------------- void cRendererPostEffects::RenderImageTrail() { if (mImageTrailData.mbActive == false) return; tVertexVec vVtx; vVtx.push_back(cVertex(cVector3f(0, 0, 40), cVector2f(0, mvScreenSize.y), cColor(1, 0.6f))); vVtx.push_back(cVertex(cVector3f(800, 0, 40), cVector2f(mvScreenSize.x, mvScreenSize.y), cColor(1, 0.6f))); vVtx.push_back(cVertex(cVector3f(800, 600, 40), cVector2f(mvScreenSize.x, 0), cColor(1, 0.6f))); vVtx.push_back(cVertex(cVector3f(0, 600, 40), cVector2f(0, 0), cColor(1, 0.6f))); mpLowLevelGraphics->CopyContextToTexure(mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0], 0, cVector2l((int)mpLowLevelGraphics->GetScreenSize().x, (int)mpLowLevelGraphics->GetScreenSize().y)); { if (mImageTrailData.mbActive) { if (mImageTrailData.mbFirstPass) { mpLowLevelGraphics->SetBlendActive(false); mpLowLevelGraphics->SetTexture(0, mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]); } else { mpLowLevelGraphics->SetClearDepthActive(false); mpLowLevelGraphics->SetClearColor(cColor(0, 0)); mpLowLevelGraphics->ClearScreen(); mpLowLevelGraphics->SetClearDepthActive(true); // Draw the new image to screen transparently mpLowLevelGraphics->SetBlendActive(true); mpLowLevelGraphics->SetBlendFunc(eBlendFunc_SrcAlpha, eBlendFunc_Zero); mpLowLevelGraphics->SetTexture(0, mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]); mpLowLevelGraphics->SetTextureConstantColor(cColor(1, 1.0f - mImageTrailData.mfAmount)); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource0, eTextureSource_Constant); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaFunc, eTextureFunc_Replace); } } else { mpLowLevelGraphics->SetBlendActive(false); mpLowLevelGraphics->SetTexture(0, mpScreenBuffer[mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0]); } mpLowLevelGraphics->DrawQuad(vVtx); if (mImageTrailData.mbActive) { if (!mImageTrailData.mbFirstPass) { // Draw the old Blurred image to screen mpLowLevelGraphics->SetBlendFunc(eBlendFunc_SrcAlpha, eBlendFunc_One); mpLowLevelGraphics->SetTexture(0, mpScreenBuffer[mImageTrailData.mlCurrentBuffer]); mpLowLevelGraphics->SetTextureConstantColor(cColor(1, mImageTrailData.mfAmount)); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource0, eTextureSource_Constant); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaFunc, eTextureFunc_Replace); mpLowLevelGraphics->DrawQuad(vVtx); } else { mImageTrailData.mbFirstPass = false; } mImageTrailData.mlCurrentBuffer = mImageTrailData.mlCurrentBuffer == 0 ? 1 : 0; // Copy screen to new blur buffer mpLowLevelGraphics->CopyContextToTexure(mpScreenBuffer[mImageTrailData.mlCurrentBuffer], 0, cVector2l((int)mpLowLevelGraphics->GetScreenSize().x, (int)mpLowLevelGraphics->GetScreenSize().y)); } mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource0, eTextureSource_Texture); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaSource1, eTextureSource_Previous); mpLowLevelGraphics->SetTextureEnv(eTextureParam_AlphaFunc, eTextureFunc_Modulate); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource0, eTextureSource_Texture); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorSource1, eTextureSource_Previous); mpLowLevelGraphics->SetTextureEnv(eTextureParam_ColorFunc, eTextureFunc_Modulate); mpLowLevelGraphics->SetBlendActive(false); mpLowLevelGraphics->SetTexture(0, NULL); } } //----------------------------------------------------------------------- } // namespace hpl