diff --git a/Engine/source/T3D/gameFunctions.cpp b/Engine/source/T3D/gameFunctions.cpp index cea4d4c69..23d048f7c 100644 --- a/Engine/source/T3D/gameFunctions.cpp +++ b/Engine/source/T3D/gameFunctions.cpp @@ -33,6 +33,8 @@ #include "core/module.h" #include "console/engineAPI.h" #include "platform/output/IDisplayDevice.h" +#include "postFx/postEffectManager.h" +#include "gfx/gfxTransformSaver.h" static void RegisterGameFunctions(); static void Process3D(); @@ -432,7 +434,197 @@ void GameRenderWorld() PROFILE_END(); } +//================================================================================================ +//Render a full frame from a given transform and frustum, and render out to a target +//================================================================================================ +void renderFrame(GFXTextureTargetRef* target, MatrixF transform, Frustum frustum, U32 typeMask, ColorI canvasClearColor) +{ + if (!GFX->allowRender() || GFX->canCurrentlyRender()) + return; + PROFILE_START(GameFunctions_RenderFrame); + + GFX->setActiveRenderTarget(*target); + if (!GFX->getActiveRenderTarget()) + return; + + GFXTarget* renderTarget = GFX->getActiveRenderTarget(); + if (renderTarget == NULL) + return; + + // Make sure the root control is the size of the canvas. + Point2I size = renderTarget->getSize(); + if (size.x == 0 || size.y == 0) + return; + + //Now, getting to the meat of it! +#ifdef TORQUE_GFX_STATE_DEBUG + GFX->getDebugStateManager()->startFrame(); +#endif + RectI targetRect(0, 0, size.x, size.y); + + // Signal the interested parties. + GuiCanvas::getGuiCanvasFrameSignal().trigger(true); + + GFXTransformSaver saver; + + // Gross hack to make sure we don't end up with advanced lighting and msaa + // at the same time, which causes artifacts. At the same time we don't + // want to just throw the settings the user has chosen if the light manager + // changes at a later time. + /*GFXVideoMode mode = mPlatformWindow->getVideoMode(); + if (dStricmp(LIGHTMGR->getId(), "ADVLM") == 0 && mode.antialiasLevel > 0) + { + const char *pref = Con::getVariable("$pref::Video::mode"); + mode.parseFromString(pref); + mode.antialiasLevel = 0; + mPlatformWindow->setVideoMode(mode); + + Con::printf("AntiAliasing has been disabled; it is not compatible with AdvancedLighting."); + } + else if (dStricmp(LIGHTMGR->getId(), "BLM") == 0) + { + const char *pref = Con::getVariable("$pref::Video::mode"); + + U32 prefAA = dAtoi(StringUnit::getUnit(pref, 5, " ")); + if (prefAA != mode.antialiasLevel) + { + mode.parseFromString(pref); + mPlatformWindow->setVideoMode(mode); + + Con::printf("AntiAliasing has been enabled while running BasicLighting."); + } + }*/ + + // Begin GFX + PROFILE_START(GameFunctions_RenderFrame_GFXBeginScene); + bool beginSceneRes = GFX->beginScene(); + PROFILE_END(); + + PROFILE_START(GameFunctions_RenderFrame_OffscreenCanvases); + + // Render all offscreen canvas objects here since we may need them in the render loop + if (GuiOffscreenCanvas::sList.size() != 0) + { + // Reset the entire state since oculus shit will have barfed it. + GFX->updateStates(true); + + for (Vector::iterator itr = GuiOffscreenCanvas::sList.begin(); itr != GuiOffscreenCanvas::sList.end(); itr++) + { + (*itr)->renderFrame(false, false); + } + + GFX->setActiveRenderTarget(renderTarget); + } + + PROFILE_END(); + + // Can't render if waiting for device to reset. + if (!beginSceneRes) + { + // Since we already triggered the signal once for begin-of-frame, + // we should be consistent and trigger it again for end-of-frame. + GuiCanvas::getGuiCanvasFrameSignal().trigger(false); + + return; + } + + // Clear the current viewport area + GFX->setViewport(targetRect); + GFX->clear(GFXClearZBuffer | GFXClearStencil | GFXClearTarget, canvasClearColor, 1.0f, 0); + + // Make sure we have a clean matrix state + // before we start rendering anything! + GFX->setWorldMatrix(MatrixF::Identity); + GFX->setViewMatrix(MatrixF::Identity); + GFX->setProjectionMatrix(MatrixF::Identity); + + { + GFXStateBlockDesc d; + + d.cullDefined = true; + d.cullMode = GFXCullNone; + d.zDefined = true; + d.zEnable = false; + + GFXStateBlockRef mDefaultGuiSB = GFX->createStateBlock(d); + + GFX->setClipRect(targetRect); + GFX->setStateBlock(mDefaultGuiSB); + + GFXTargetRef origTarget = GFX->getActiveRenderTarget(); + U32 origStyle = GFX->getCurrentRenderStyle(); + + // Clear the zBuffer so GUI doesn't hose object rendering accidentally + GFX->clear(GFXClearZBuffer, ColorI(20, 20, 20), 1.0f, 0); + + GFX->setFrustum(frustum); + MatrixF mSaveProjection = GFX->getProjectionMatrix(); + + // We're going to be displaying this render at size of this control in + // pixels - let the scene know so that it can calculate e.g. reflections + // correctly for that final display result. + gClientSceneGraph->setDisplayTargetResolution(size); + + // Set the GFX world matrix to the world-to-camera transform, but don't + // change the cameraMatrix in mLastCameraQuery. This is because + // mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world + // transform. In-place invert would save a copy but mess up any GUIs that + // depend on that value. + CameraQuery camera; + GameProcessCameraQuery(&camera); + + MatrixF worldToCamera = transform; + + RotationF tranRot = RotationF(transform); + EulerF trf = tranRot.asEulerF(RotationF::Degrees); + Point3F pos = transform.getPosition(); + + GFX->setWorldMatrix(worldToCamera); + + mSaveProjection = GFX->getProjectionMatrix(); + MatrixF mSaveModelview = GFX->getWorldMatrix(); + + Point2F mSaveWorldToScreenScale = GFX->getWorldToScreenScale(); + Frustum mSaveFrustum = GFX->getFrustum(); + mSaveFrustum.setTransform(transform); + + // Set the default non-clip projection as some + // objects depend on this even in non-reflect cases. + gClientSceneGraph->setNonClipProjection(mSaveProjection); + + // Give the post effect manager the worldToCamera, and cameraToScreen matrices + PFXMGR->setFrameMatrices(mSaveModelview, mSaveProjection); + + //renderWorld(guiViewport); + PROFILE_START(GameFunctions_RenderFrame_RenderWorld); + FrameAllocator::setWaterMark(0); + + gClientSceneGraph->renderScene(SPT_Reflect, typeMask); + + // renderScene leaves some states dirty, which causes problems if GameTSCtrl is the last Gui object rendered + GFX->updateStates(); + + AssertFatal(FrameAllocator::getWaterMark() == 0, + "Error, someone didn't reset the water mark on the frame allocator!"); + FrameAllocator::setWaterMark(0); + PROFILE_END(); + } + + PROFILE_START(GameFunctions_RenderFrame_GFXEndScene); + GFX->endScene(); + PROFILE_END(); + +#ifdef TORQUE_GFX_STATE_DEBUG + GFX->getDebugStateManager()->endFrame(); +#endif + + saver.restore(); + + PROFILE_END(); +} + +//================================================================================================ static void Process3D() { MATMGR->updateTime(); diff --git a/Engine/source/T3D/gameFunctions.h b/Engine/source/T3D/gameFunctions.h index 6eea00b55..c772cde5a 100644 --- a/Engine/source/T3D/gameFunctions.h +++ b/Engine/source/T3D/gameFunctions.h @@ -29,6 +29,15 @@ #ifndef _MMATRIX_H_ #include "math/mMatrix.h" #endif +#ifndef _GFXTARGET_H_ +#include "gfx/gfxTarget.h" +#endif +#ifndef _MATHUTIL_FRUSTUM_H_ +#include "math/util/frustum.h" +#endif +#ifndef _COLOR_H_ +#include "core/color.h" +#endif struct CameraQuery; @@ -37,6 +46,10 @@ struct CameraQuery; /// scene ONLY - new guis, no damage flashes. void GameRenderWorld(); +/// Does a full, top-to-bottom call to render a frame. This does all the setup to make a render happen +/// Allowing setting of a intended render target, a view transform, the view frustum, resolution, objects-to-render typemask, and the clear color +void renderFrame(GFXTextureTargetRef* target, MatrixF transform, Frustum frustum, U32 typeMask, ColorI canvasClearColor); + /// Renders overlays such as damage flashes, white outs, and water masks. /// These are usually a color applied over the entire screen. void GameRenderFilters(const CameraQuery& camq); diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index c10a1cbe3..2fe99bde3 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -267,7 +267,7 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) sgData.init( state ); // There are cases where shadow rendering is disabled. - const bool disableShadows = state->isReflectPass() || ShadowMapPass::smDisableShadows; + const bool disableShadows = /*state->isReflectPass() || */ShadowMapPass::smDisableShadows; // Pick the right material for rendering the sunlight... we only // cast shadows when its enabled and we're not in a reflection. @@ -300,6 +300,8 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) GFX->setVertexBuffer( mFarFrustumQuadVerts ); GFX->setPrimitiveBuffer( NULL ); + vectorMatInfo->matInstance->mSpecialLight = true; + // Render the material passes while( vectorMatInfo->matInstance->setupPass( state, sgData ) ) { @@ -337,6 +339,8 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) lsp->getOcclusionQuery()->begin(); + curLightMat->matInstance->mSpecialLight = false; + // Render the material passes while( curLightMat->matInstance->setupPass( state, sgData ) ) { @@ -497,6 +501,17 @@ void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState * farPlane, vsFarPlane); } + + MatrixSet &matrixSet = getRenderPass()->getMatrixSet(); + //matrixSet.restoreSceneViewProjection(); + + const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera(); + + MatrixF inverseViewMatrix = worldToCameraXfm; + //inverseViewMatrix.fullInverse(); + //inverseViewMatrix.transpose(); + + //MatrixF inverseViewMatrix = MatrixF::Identity; } void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light ) @@ -747,6 +762,10 @@ bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgDa mProcessedMaterial->getNumPasses() == 0 ) return false; + U32 reflectStatus = Base; + if (state->isReflectPass()) + reflectStatus = Reflecting; + // Fetch the lightmap params const LightMapParams *lmParams = sgData.lights[0]->getExtended(); @@ -795,14 +814,21 @@ bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgDa { // If this is not an internal pass, and this light is represented in lightmaps // than only effect non-lightmapped geometry for this pass - if(lmParams->representedInLightmap) - GFX->setStateBlock(mLitState[StaticLightNonLMGeometry]); + if (lmParams->representedInLightmap) + { + GFX->setStateBlock(mLitState[StaticLightNonLMGeometry][reflectStatus]); + } else // This is a normal, dynamic light. - GFX->setStateBlock(mLitState[DynamicLight]); - + { + if (mSpecialLight) + GFX->setStateBlock(mLitState[SunLight][reflectStatus]); + else + GFX->setStateBlock(mLitState[DynamicLight][reflectStatus]); + } + } else // Internal pass, this is the add-specular/multiply-darken-color pass - GFX->setStateBlock(mLitState[StaticLightLMGeometry]); + GFX->setStateBlock(mLitState[StaticLightLMGeometry][reflectStatus]); return bRetVal; } @@ -832,17 +858,32 @@ bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat * //DynamicLight State: This will effect lightmapped and non-lightmapped geometry // in the same way. + litState.separateAlphaBlendDefined = true; litState.separateAlphaBlendEnable = false; litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask; - mLitState[DynamicLight] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCW); + mLitState[DynamicLight][Base] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCCW); + mLitState[DynamicLight][Reflecting] = GFX->createStateBlock(litState); + + litState.separateAlphaBlendDefined = true; + litState.separateAlphaBlendEnable = false; + litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask; + litState.setCullMode(GFXCullCCW); + mLitState[SunLight][Base] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCCW); + mLitState[SunLight][Reflecting] = GFX->createStateBlock(litState); // StaticLightNonLMGeometry State: This will treat non-lightmapped geometry // in the usual way, but will not effect lightmapped geometry. litState.separateAlphaBlendDefined = true; litState.separateAlphaBlendEnable = false; litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask; - mLitState[StaticLightNonLMGeometry] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCW); + mLitState[StaticLightNonLMGeometry][Base] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCCW); + mLitState[StaticLightNonLMGeometry][Reflecting] = GFX->createStateBlock(litState); // StaticLightLMGeometry State: This will add specular information (alpha) but // multiply-darken color information. @@ -854,7 +895,10 @@ bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat * litState.separateAlphaBlendSrc = GFXBlendOne; litState.separateAlphaBlendDest = GFXBlendOne; litState.separateAlphaBlendOp = GFXBlendOpAdd; - mLitState[StaticLightLMGeometry] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCW); + mLitState[StaticLightLMGeometry][Base] = GFX->createStateBlock(litState); + litState.setCullMode(GFXCullCCW); + mLitState[StaticLightLMGeometry][Reflecting] = GFX->createStateBlock(litState); return true; } diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index 1b94c10c7..1e13665f5 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -60,19 +60,23 @@ protected: enum { DynamicLight = 0, + SunLight, StaticLightNonLMGeometry, StaticLightLMGeometry, - NUM_LIT_STATES + NUM_LIT_STATES, + Base = 0, + Reflecting = 1 }; - GFXStateBlockRef mLitState[NUM_LIT_STATES]; + GFXStateBlockRef mLitState[NUM_LIT_STATES][2]; public: LightMatInstance(Material &mat) : Parent(mat), mLightMapParamsSC(NULL), mInternalPass(false) {} virtual bool init( const FeatureSet &features, const GFXVertexFormat *vertexFormat ); virtual bool setupPass( SceneRenderState *state, const SceneData &sgData ); -}; + bool mSpecialLight; +}; class AdvancedLightBinManager : public RenderTexTargetBinManager {