Commit b32e7688 authored by DavidWyand-GG's avatar DavidWyand-GG

Side by side rendering

- Side by side rendering implemented throughout the graphics pipeline.
- New GuiTSCtrl renderStyle property is set to "stereo side by side" to
activate.
- You set an IDisplayDevice on the GameConnection to define any vertical
FOV, projection offset, and stereo eye offset properties required for
the stereo rendering (no display device included with this commit).
- Full and Empty templates updated with correct scripts and shaders.
parent b1feed56
......@@ -219,6 +219,7 @@ GameConnection::GameConnection()
// first person
mFirstPerson = true;
mUpdateFirstPerson = false;
clearDisplayDevice();
}
GameConnection::~GameConnection()
......@@ -1729,6 +1730,13 @@ DefineEngineMethod( GameConnection, setControlObject, bool, (GameBase* ctrlObj),
return true;
}
DefineEngineMethod( GameConnection, clearDisplayDevice, void, (),,
"@brief Clear any display device.\n\n"
"A display device may define a number of properties that are used during rendering.\n\n")
{
object->clearDisplayDevice();
}
DefineEngineMethod( GameConnection, getControlObject, GameBase*, (),,
"@brief On the server, returns the object that the client is controlling."
"By default the control object is an instance of the Player class, but can also be an instance "
......
......@@ -45,6 +45,7 @@ enum GameConnectionConstants
DataBlockQueueCount = 16
};
class IDisplayDevice;
class SFXProfile;
class MatrixF;
class MatrixF;
......@@ -86,6 +87,8 @@ private:
F32 mCameraFov; ///< Current camera fov (in degrees).
F32 mCameraPos; ///< Current camera pos (0-1).
F32 mCameraSpeed; ///< Camera in/out speed.
IDisplayDevice* mDisplayDevice; ///< Optional client display device that imposes rendering properties.
/// @}
public:
......@@ -263,6 +266,10 @@ public:
void setFirstPerson(bool firstPerson);
bool hasDisplayDevice() const { return mDisplayDevice != NULL; }
const IDisplayDevice* getDisplayDevice() const { return mDisplayDevice; }
void setDisplayDevice(IDisplayDevice* display) { mDisplayDevice = display; }
void clearDisplayDevice() { mDisplayDevice = NULL; }
/// @}
void detectLag();
......
......@@ -32,7 +32,7 @@
#include "math/mEase.h"
#include "core/module.h"
#include "console/engineAPI.h"
#include "platform/output/IDisplayDevice.h"
static void RegisterGameFunctions();
static void Process3D();
......@@ -82,6 +82,8 @@ static S32 gEaseBack = Ease::Back;
static S32 gEaseBounce = Ease::Bounce;
extern bool gEditingMission;
extern void ShowInit();
//------------------------------------------------------------------------------
......@@ -354,9 +356,44 @@ bool GameProcessCameraQuery(CameraQuery *query)
sVisDistanceScale = mClampF( sVisDistanceScale, 0.01f, 1.0f );
query->farPlane = gClientSceneGraph->getVisibleDistance() * sVisDistanceScale;
F32 cameraFov;
if(!connection->getControlCameraFov(&cameraFov))
// Provide some default values
query->projectionOffset = Point2F::Zero;
query->eyeOffset = Point3F::Zero;
F32 cameraFov = 0.0f;
bool fovSet = false;
// Try to use the connection's display deivce, if any, but only if the editor
// is not open
if(!gEditingMission && connection->hasDisplayDevice())
{
const IDisplayDevice* display = connection->getDisplayDevice();
// The connection's display device may want to set the FOV
if(display->providesYFOV())
{
cameraFov = mRadToDeg(display->getYFOV());
fovSet = true;
}
// The connection's display device may want to set the projection offset
if(display->providesProjectionOffset())
{
query->projectionOffset = display->getProjectionOffset();
}
// The connection's display device may want to set the eye offset
if(display->providesEyeOffset())
{
query->eyeOffset = display->getEyeOffset();
}
}
// Use the connection's FOV settings if requried
if(!fovSet && !connection->getControlCameraFov(&cameraFov))
{
return false;
}
query->fov = mDegToRad(cameraFov);
return true;
......
......@@ -278,7 +278,11 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
// the last result.
const Point3F &lightPos = flareState->lightMat.getPosition();
const RectI &viewport = GFX->getViewport();
bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), state->getSceneManager()->getNonClipProjection() );
MatrixF projMatrix;
state->getFrustum().getProjectionMatrix(&projMatrix);
if( state->isReflectPass() )
projMatrix = state->getSceneManager()->getNonClipProjection();
bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix );
// It is onscreen, so raycast as a simple occlusion test.
const LightInfo *lightInfo = flareState->lightInfo;
......@@ -452,13 +456,17 @@ void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flare
Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f );
// Really convert it to screen space.
lightPosSS.x -= viewport.point.x;
lightPosSS.y -= viewport.point.y;
lightPosSS *= oneOverViewportExtent;
lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
lightPosSS.y = -lightPosSS.y;
lightPosSS.z = 0.0f;
Point3F flareVec( -lightPosSS );
// Take any projection offset into account so that the point where the flare's
// elements converge is at the 'eye' point rather than the center of the viewport.
const Point2F& projOffset = state->getFrustum().getProjectionOffset();
Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) );
const F32 flareLength = flareVec.len();
if ( flareLength > 0.0f )
flareVec *= 1.0f / flareLength;
......
......@@ -159,6 +159,9 @@ GFXDevice::GFXDevice()
// misc
mAllowRender = true;
mCurrentRenderStyle = RS_Standard;
mCurrentProjectionOffset = Point2F::Zero;
mStereoEyeOffset = Point3F::Zero;
mCanCurrentlyRender = false;
mInitialized = false;
......
......@@ -231,6 +231,13 @@ private:
//--------------------------------------------------------------------------
// Core GFX interface
//--------------------------------------------------------------------------
public:
enum GFXDeviceRenderStyles
{
RS_Standard = 0,
RS_StereoSideBySide = (1<<0),
};
private:
/// Adapter for this device.
......@@ -254,6 +261,15 @@ protected:
/// Set if we're in a mode where we want rendering to occur.
bool mAllowRender;
/// The style of rendering that is to be performed, based on GFXDeviceRenderStyles
U32 mCurrentRenderStyle;
/// The current projection offset. May be used during side-by-side rendering, for example.
Point2F mCurrentProjectionOffset;
/// Eye offset used when using a stereo rendering style
Point3F mStereoEyeOffset;
/// This will allow querying to see if a device is initialized and ready to
/// have operations performed on it.
bool mInitialized;
......@@ -285,6 +301,24 @@ public:
inline bool allowRender() const { return mAllowRender; }
/// Retrieve the current rendering style based on GFXDeviceRenderStyles
U32 getCurrentRenderStyle() const { return mCurrentRenderStyle; }
/// Set the current rendering style, based on GFXDeviceRenderStyles
void setCurrentRenderStyle(U32 style) { mCurrentRenderStyle = style; }
/// Set the current projection offset used during stereo rendering
const Point2F& getCurrentProjectionOffset() { return mCurrentProjectionOffset; }
/// Get the current projection offset used during stereo rendering
void setCurrentProjectionOffset(const Point2F& offset) { mCurrentProjectionOffset = offset; }
/// Get the current eye offset used during stereo rendering
const Point3F& getStereoEyeOffset() { return mStereoEyeOffset; }
/// Set the current eye offset used during stereo rendering
void setStereoEyeOffset(const Point3F& offset) { mStereoEyeOffset = offset; }
GFXCardProfiler* getCardProfiler() const { return mCardProfiler; }
/// Returns active graphics adapter type.
......
......@@ -53,6 +53,13 @@ ConsoleDocClass( GuiTSCtrl,
U32 GuiTSCtrl::smFrameCount = 0;
Vector<GuiTSCtrl*> GuiTSCtrl::smAwakeTSCtrls;
ImplementEnumType( GuiTSRenderStyles,
"Style of rendering for a GuiTSCtrl.\n\n"
"@ingroup Gui3D" )
{ GuiTSCtrl::RenderStyleStandard, "standard" },
{ GuiTSCtrl::RenderStyleStereoSideBySide, "stereo side by side" },
EndImplementEnumType;
//-----------------------------------------------------------------------------
......@@ -131,6 +138,8 @@ GuiTSCtrl::GuiTSCtrl()
mForceFOV = 0;
mReflectPriority = 1.0f;
mRenderStyle = RenderStyleStandard;
mSaveModelview.identity();
mSaveProjection.identity();
mSaveViewport.set( 0, 0, 10, 10 );
......@@ -142,6 +151,9 @@ GuiTSCtrl::GuiTSCtrl()
mLastCameraQuery.farPlane = 10.0f;
mLastCameraQuery.nearPlane = 0.01f;
mLastCameraQuery.projectionOffset = Point2F::Zero;
mLastCameraQuery.eyeOffset = Point3F::Zero;
mLastCameraQuery.ortho = false;
}
......@@ -165,6 +177,9 @@ void GuiTSCtrl::initPersistFields()
"The reflect update priorities of all visible GuiTSCtrls are added together and each control is assigned "
"a share of the per-frame reflection update time according to its percentage of the total priority value." );
addField("renderStyle", TYPEID< RenderStyles >(), Offset(mRenderStyle, GuiTSCtrl),
"Indicates how this control should render its contents." );
endGroup( "Rendering" );
Parent::initPersistFields();
......@@ -256,7 +271,9 @@ F32 GuiTSCtrl::calculateViewDistance(F32 radius)
F32 fov = mLastCameraQuery.fov;
F32 wwidth;
F32 wheight;
F32 aspectRatio = F32(getWidth()) / F32(getHeight());
F32 renderWidth = (mRenderStyle == RenderStyleStereoSideBySide) ? F32(getWidth())*0.5f : F32(getWidth());
F32 renderHeight = F32(getHeight());
F32 aspectRatio = renderWidth / renderHeight;
// Use the FOV to calculate the viewport height scale
// then generate the width scale from the aspect ratio.
......@@ -321,10 +338,27 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
mLastCameraQuery.cameraMatrix.mul(rotMat);
}
// Set up the appropriate render style
U32 prevRenderStyle = GFX->getCurrentRenderStyle();
Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset();
Point3F prevEyeOffset = GFX->getStereoEyeOffset();
if(mRenderStyle == RenderStyleStereoSideBySide)
{
GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide);
GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset);
GFX->setStereoEyeOffset(mLastCameraQuery.eyeOffset);
}
else
{
GFX->setCurrentRenderStyle(GFXDevice::RS_Standard);
}
// set up the camera and viewport stuff:
F32 wwidth;
F32 wheight;
F32 aspectRatio = F32(getWidth()) / F32(getHeight());
F32 renderWidth = (mRenderStyle == RenderStyleStereoSideBySide) ? F32(getWidth())*0.5f : F32(getWidth());
F32 renderHeight = F32(getHeight());
F32 aspectRatio = renderWidth / renderHeight;
// Use the FOV to calculate the viewport height scale
// then generate the width scale from the aspect ratio.
......@@ -339,16 +373,28 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
wwidth = aspectRatio * wheight;
}
F32 hscale = wwidth * 2.0f / F32(getWidth());
F32 vscale = wheight * 2.0f / F32(getHeight());
F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
F32 top = wheight - vscale * (updateRect.point.y - offset.y);
F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);
F32 hscale = wwidth * 2.0f / renderWidth;
F32 vscale = wheight * 2.0f / renderHeight;
Frustum frustum;
frustum.set( mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane );
if(mRenderStyle == RenderStyleStereoSideBySide)
{
F32 left = 0.0f * hscale - wwidth;
F32 right = renderWidth * hscale - wwidth;
F32 top = wheight - vscale * 0.0f;
F32 bottom = wheight - vscale * renderHeight;
frustum.set( mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane );
}
else
{
F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
F32 top = wheight - vscale * (updateRect.point.y - offset.y);
F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);
frustum.set( mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane );
}
// Manipulate the frustum for tiled screenshots
const bool screenShotMode = gScreenShot && gScreenShot->isPending();
......@@ -412,6 +458,11 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
// we begin rendering the child controls.
saver.restore();
// Restore the render style and any stereo parameters
GFX->setCurrentRenderStyle(prevRenderStyle);
GFX->setCurrentProjectionOffset(prevProjectionOffset);
GFX->setStereoEyeOffset(prevEyeOffset);
// Allow subclasses to render 2D elements.
GFX->setClipRect(updateRect);
renderGui( offset, updateRect );
......
......@@ -36,6 +36,8 @@ struct CameraQuery
F32 nearPlane;
F32 farPlane;
F32 fov;
Point2F projectionOffset;
Point3F eyeOffset;
bool ortho;
MatrixF cameraMatrix;
};
......@@ -45,12 +47,17 @@ class GuiTSCtrl : public GuiContainer
{
typedef GuiContainer Parent;
public:
enum RenderStyles {
RenderStyleStandard = 0,
RenderStyleStereoSideBySide = (1<<0),
};
protected:
static U32 smFrameCount;
F32 mCameraZRot;
F32 mForceFOV;
protected:
/// A list of GuiTSCtrl which are awake and
/// most likely rendering.
static Vector<GuiTSCtrl*> smAwakeTSCtrls;
......@@ -59,8 +66,11 @@ protected:
/// update timeslice for this viewport to get.
F32 mReflectPriority;
F32 mOrthoWidth;
F32 mOrthoHeight;
/// The current render type
U32 mRenderStyle;
F32 mOrthoWidth;
F32 mOrthoHeight;
MatrixF mSaveModelview;
MatrixF mSaveProjection;
......@@ -150,4 +160,8 @@ public:
DECLARE_DESCRIPTION( "Abstract base class for controls that render a 3D viewport." );
};
typedef GuiTSCtrl::RenderStyles GuiTSRenderStyles;
DefineEnumType( GuiTSRenderStyles );
#endif // _GUITSCONTROL_H_
......@@ -41,7 +41,6 @@
#include "math/util/matrixSet.h"
#include "console/consoleTypes.h"
const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "LightInfo" );
const String AdvancedLightBinManager::smBufferName( "lightinfo" );
......@@ -49,7 +48,6 @@ ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_
bool AdvancedLightBinManager::smPSSMDebugRender = false;
bool AdvancedLightBinManager::smUseSSAOMask = false;
ImplementEnumType( ShadowFilterMode,
"The shadow filtering modes for Advanced Lighting shadows.\n"
"@ingroup AdvancedLighting" )
......@@ -221,7 +219,7 @@ void AdvancedLightBinManager::addLight( LightInfo *light )
curBin.push_back( lEntry );
}
void AdvancedLightBinManager::clear()
void AdvancedLightBinManager::clearAllLights()
{
Con::setIntVariable("lightMetrics::activeLights", mLightBin.size());
Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled);
......@@ -454,6 +452,33 @@ void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *
const Point3F *wsFrustumPoints = frustum.getPoints();
const Point3F& cameraPos = frustum.getPosition();
// Perform a camera offset. We need to manually perform this offset on the sun (or vector) light's
// polygon, which is at the far plane.
const Point2F& projOffset = frustum.getProjectionOffset();
Point3F cameraOffsetPos = cameraPos;
if(!projOffset.isZero())
{
// First we need to calculate the offset at the near plane. The projOffset
// given above can be thought of a percent as it ranges from 0..1 (or 0..-1).
F32 nearOffset = frustum.getNearRight() * projOffset.x;
// Now given the near plane distance from the camera we can solve the right
// triangle and calcuate the SIN theta for the offset at the near plane.
// SIN theta = x/y
F32 sinTheta = nearOffset / frustum.getNearDist();
// Finally, we can calcuate the offset at the far plane, which is where our sun (or vector)
// light's polygon is drawn.
F32 farOffset = frustum.getFarDist() * sinTheta;
// We can now apply this far plane offset to the far plane itself, which then compensates
// for the project offset.
MatrixF camTrans = frustum.getTransform();
VectorF offset = camTrans.getRightVector();
offset *= farOffset;
cameraOffsetPos += offset;
}
// Now build the quad for drawing full-screen vector light
// passes.... this is a volatile VB and updates every frame.
FarFrustumQuadVert verts[4];
......@@ -461,18 +486,22 @@ void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *
verts[0].point.set( wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos );
invCam.mulP( wsFrustumPoints[Frustum::FarBottomLeft], &verts[0].normal );
verts[0].texCoord.set( -1.0, -1.0 );
verts[0].tangent.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos);
verts[1].point.set( wsFrustumPoints[Frustum::FarTopLeft] - cameraPos );
invCam.mulP( wsFrustumPoints[Frustum::FarTopLeft], &verts[1].normal );
verts[1].texCoord.set( -1.0, 1.0 );
verts[1].tangent.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraOffsetPos);
verts[2].point.set( wsFrustumPoints[Frustum::FarTopRight] - cameraPos );
invCam.mulP( wsFrustumPoints[Frustum::FarTopRight], &verts[2].normal );
verts[2].texCoord.set( 1.0, 1.0 );
verts[2].tangent.set(wsFrustumPoints[Frustum::FarTopRight] - cameraOffsetPos);
verts[3].point.set( wsFrustumPoints[Frustum::FarBottomRight] - cameraPos );
invCam.mulP( wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal );
verts[3].texCoord.set( 1.0, -1.0 );
verts[3].tangent.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraOffsetPos);
}
mFarFrustumQuadVerts.set( GFX, 4 );
dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) );
......
......@@ -107,12 +107,15 @@ public:
// RenderBinManager
virtual void render(SceneRenderState *);
virtual void clear();
virtual void clear() {}
virtual void sort() {}
// Add a light to the bins
void addLight( LightInfo *light );
// Clear all lights from the bins
void clearAllLights();
virtual bool setTargetSize(const Point2I &newTargetSize);
// ConsoleObject interface
......@@ -220,7 +223,7 @@ protected:
AdvancedLightBufferConditioner *mConditioner;
typedef GFXVertexPNT FarFrustumQuadVert;
typedef GFXVertexPNTT FarFrustumQuadVert;
GFXVertexBufferHandle<FarFrustumQuadVert> mFarFrustumQuadVerts;
......
......@@ -438,7 +438,7 @@ void AdvancedLightManager::unregisterAllLights()
Parent::unregisterAllLights();
if ( mLightBinManager )
mLightBinManager->clear();
mLightBinManager->clearAllLights();
}
bool AdvancedLightManager::setTextureStage( const SceneData &sgData,
......
......@@ -76,6 +76,9 @@ Frustum::Frustum( bool isOrtho,
mNumTiles = 1;
mCurrTile.set(0,0);
mTileOverlap.set(0.0f, 0.0f);
mProjectionOffset.zero();
mProjectionOffsetMatrix.identity();
}
//-----------------------------------------------------------------------------
......@@ -433,12 +436,27 @@ void Frustum::mulL( const MatrixF& mat )
//-----------------------------------------------------------------------------
void Frustum::setProjectionOffset(const Point2F& offsetMat)
{
mProjectionOffset = offsetMat;
mProjectionOffsetMatrix.identity();
mProjectionOffsetMatrix.setPosition(Point3F(mProjectionOffset.x, mProjectionOffset.y, 0.0f));
}
//-----------------------------------------------------------------------------
void Frustum::getProjectionMatrix( MatrixF *proj, bool gfxRotate ) const
{
if (mIsOrtho)
{
MathUtils::makeOrthoProjection(proj, mNearLeft, mNearRight, mNearTop, mNearBottom, mNearDist, mFarDist, gfxRotate);
proj->mulL(mProjectionOffsetMatrix);
}
else
{
MathUtils::makeProjection(proj, mNearLeft, mNearRight, mNearTop, mNearBottom, mNearDist, mFarDist, gfxRotate);
proj->mulL(mProjectionOffsetMatrix);
}
}
//-----------------------------------------------------------------------------
......
......@@ -246,6 +246,12 @@ class Frustum : public PolyhedronImpl< FrustumData >
/// @}
/// Offset used for projection matrix calculations
Point2F mProjectionOffset;
/// The calculated projection offset matrix
MatrixF mProjectionOffsetMatrix;
public:
/// @name Constructors
......@@ -403,9 +409,23 @@ class Frustum : public PolyhedronImpl< FrustumData >
/// points typically used for early rejection.
const Box3F& getBounds() const { _update(); return mBounds; }
/// Get the offset used when calculating the projection matrix
const Point2F& getProjectionOffset() const { return mProjectionOffset; }
/// Get the offset matrix used when calculating the projection matrix
const MatrixF& getProjectionOffsetMatrix() const { return mProjectionOffsetMatrix; }
/// Set the offset used when calculating the projection matrix
void setProjectionOffset(const Point2F& offsetMat);
/// Clear any offset used when calculating the projection matrix
void clearProjectionOffset() { mProjectionOffset.zero(); mProjectionOffsetMatrix.identity(); }
/// Generates a projection matrix from the frustum.
void getProjectionMatrix( MatrixF *proj, bool gfxRotate=true ) const;
/// Will update the frustum if it is dirty
void update() { _update(); }
/// @}
/// @name Culling
......
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _IDISPLAYDEVICE_H_
#define _IDISPLAYDEVICE_H_
#include "console/consoleTypes.h"
// Defines a custom display device that requires particular rendering settings
// in order for a scene to display correctly.
class IDisplayDevice
{
public:
virtual bool providesYFOV() const = 0;
virtual F32 getYFOV() const = 0;
virtual bool providesEyeOffset() const = 0;
virtual const Point3F& getEyeOffset() const = 0;
virtual bool providesProjectionOffset() const = 0;
virtual const Point2F& getProjectionOffset() const = 0;
};
#endif // _IDISPLAYDEVICE_H_
......@@ -435,26 +435,53 @@ void PostEffect::_updateScreenGeometry( const Frustum &frustum,
const Point3F *frustumPoints = frustum.getPoints();
const Point3F& cameraPos = frustum.getPosition();
// Perform a camera offset. We need to manually perform this offset on the postFx's
// polygon, which is at the far plane.
const Point2F& projOffset = frustum.getProjectionOffset();
Point3F cameraOffsetPos = cameraPos;
if(!projOffset.isZero())
{
// First we need to calculate the offset at the near plane. The projOffset
// given above can be thought of a percent as it ranges from 0..1 (or 0..-1).
F32 nearOffset = frustum.getNearRight() * projOffset.x;
// Now given the near plane distance from the camera we can solve the right
// triangle and calcuate the SIN theta for the offset at the near plane.
// SIN theta = x/y
F32 sinTheta = nearOffset / frustum.getNearDist();
// Finally, we can calcuate the offset at the far plane, which is where our sun (or vector)
// light's polygon is drawn.
F32 farOffset = frustum.getFarDist() * sinTheta;
// We can now apply this far plane offset to the far plane itself, which then compensates
// for the project offset.
MatrixF camTrans = frustum.getTransform();
VectorF offset = camTrans.getRightVector();
offset *= farOffset;
cameraOffsetPos += offset;
}
PFXVertex *vert = outVB->lock();
vert->point.set( -1.0, -1.0, 0.0 );
vert->texCoord.set( 0.0f, 1.0f );
vert->wsEyeRay = frustumPoints[Frustum::FarBottomLeft] - cameraPos;
vert->wsEyeRay = frustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos;
vert++;
vert->point.set( -1.0, 1.0, 0.0 );
vert->texCoord.set( 0.0f, 0.0f );
vert->wsEyeRay = frustumPoints[Frustum::FarTopLeft] - cameraPos;
vert->wsEyeRay = frustumPoints[Frustum::FarTopLeft] - cameraOffsetPos;
vert++;
vert->point.set( 1.0, 1.0, 0.0 );
vert->texCoord.set( 1.0f, 0.0f );
vert->wsEyeRay = frustumPoints[Frustum::FarTopRight] - cameraPos;
vert->wsEyeRay = frustumPoints[Frustum::FarTopRight] - cameraOffsetPos;
vert++;
vert->point.set( 1.0, -1.0, 0.0 );
vert->texCoord.set( 1.0f, 1.0f );
vert->wsEyeRay = frustumPoints[Frustum::FarBottomRight] - cameraPos;
vert->wsEyeRay = frustumPoints[Frustum::FarBottomRight] - cameraOffsetPos;
vert++;
outVB->unlock();
......@@ -710,6 +737,8 @@ void PostEffect::_setupConstants( const SceneRenderState *state )
MathUtils::mProjectWorldToScreen( lightPos, &sunPos, GFX->getViewport(), tmp, proj );
// And normalize it to the 0 to 1 range.
sunPos.x -= (F32)GFX->getViewport().point.x;
sunPos.y -= (F32)GFX->getViewport().point.y;
sunPos.x /= (F32)GFX->getViewport().extent.x;
sunPos.y /= (F32)GFX->getViewport().extent.y;
......
......@@ -233,7 +233,70 @@ void SceneManager::renderScene( SceneRenderState* renderState, U32 objectMask, S
// Render the scene.
renderSceneNoLights( renderState, objectMask, baseObject, baseZone );
if(GFX->getCurrentRenderStyle() == GFXDevice::RS_StereoSideBySide)
{
// Store previous values
RectI originalVP = GFX->getViewport();
MatrixF originalWorld = GFX->getWorldMatrix();