mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-27 16:19:34 +00:00
Oculus VR DK2 Support
- Updated to work with 0.5.x SDK - Uses Oculus Rendering rather than PostFX - Stereo rendering refactored so more rendering info is grabbed from the DisplayDevice - Implements an Offscreen Canvas for in-game gui with oculus - Message dialogs and metrics display can now go to the OffScreen Canvas (if oculus demo is setup correctly)
This commit is contained in:
parent
b3170bcddf
commit
3a457749ec
56 changed files with 2654 additions and 1426 deletions
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "platform/platform.h"
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#include "gui/core/guiOffscreenCanvas.h"
|
||||
|
||||
#include "console/engineAPI.h"
|
||||
#include "scene/sceneManager.h"
|
||||
|
|
@ -34,7 +35,12 @@
|
|||
#include "scene/reflectionManager.h"
|
||||
#include "postFx/postEffectManager.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
|
||||
GFXTextureObject *gLastStereoTexture = NULL;
|
||||
|
||||
#define TS_OVERLAY_SCREEN_WIDTH 0.75
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiTSCtrl );
|
||||
|
||||
|
|
@ -51,6 +57,7 @@ ConsoleDocClass( GuiTSCtrl,
|
|||
);
|
||||
|
||||
U32 GuiTSCtrl::smFrameCount = 0;
|
||||
bool GuiTSCtrl::smUseLatestDisplayTransform = true;
|
||||
Vector<GuiTSCtrl*> GuiTSCtrl::smAwakeTSCtrls;
|
||||
|
||||
ImplementEnumType( GuiTSRenderStyles,
|
||||
|
|
@ -60,7 +67,6 @@ ImplementEnumType( GuiTSRenderStyles,
|
|||
{ GuiTSCtrl::RenderStyleStereoSideBySide, "stereo side by side" },
|
||||
EndImplementEnumType;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
|
|
@ -153,7 +159,6 @@ GuiTSCtrl::GuiTSCtrl()
|
|||
mLastCameraQuery.nearPlane = 0.01f;
|
||||
|
||||
mLastCameraQuery.projectionOffset = Point2F::Zero;
|
||||
mLastCameraQuery.eyeOffset = Point3F::Zero;
|
||||
|
||||
mLastCameraQuery.ortho = false;
|
||||
}
|
||||
|
|
@ -192,6 +197,8 @@ void GuiTSCtrl::consoleInit()
|
|||
{
|
||||
Con::addVariable("$TSControl::frameCount", TypeS32, &smFrameCount, "The number of frames that have been rendered since this control was created.\n"
|
||||
"@ingroup Rendering\n");
|
||||
Con::addVariable("$TSControl::useLatestDisplayTransform", TypeBool, &smUseLatestDisplayTransform, "Use the latest view transform when rendering stereo instead of the one calculated by the last move.\n"
|
||||
"@ingroup Rendering\n");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -206,6 +213,9 @@ bool GuiTSCtrl::onWake()
|
|||
"GuiTSCtrl::onWake - This control is already in the awake list!" );
|
||||
smAwakeTSCtrls.push_back( this );
|
||||
|
||||
// For VR
|
||||
mLastCameraQuery.drawCanvas = getRoot();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +317,7 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
// Save the current transforms so we can restore
|
||||
// it for child control rendering below.
|
||||
GFXTransformSaver saver;
|
||||
bool renderingToTarget = false;
|
||||
|
||||
if(!processCameraQuery(&mLastCameraQuery))
|
||||
{
|
||||
|
|
@ -317,15 +328,52 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
return;
|
||||
}
|
||||
|
||||
GFXTargetRef origTarget = GFX->getActiveRenderTarget();
|
||||
|
||||
// Set up the appropriate render style
|
||||
U32 prevRenderStyle = GFX->getCurrentRenderStyle();
|
||||
Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset();
|
||||
Point3F prevEyeOffset = GFX->getStereoEyeOffset();
|
||||
Point2I renderSize = getExtent();
|
||||
|
||||
if(mRenderStyle == RenderStyleStereoSideBySide)
|
||||
{
|
||||
GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide);
|
||||
GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset);
|
||||
GFX->setStereoEyeOffset(mLastCameraQuery.eyeOffset);
|
||||
GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);
|
||||
GFX->setFovPort(mLastCameraQuery.fovPort); // NOTE: this specifies fov for BOTH eyes
|
||||
GFX->setSteroViewports(mLastCameraQuery.stereoViewports);
|
||||
GFX->setStereoTargets(mLastCameraQuery.stereoTargets);
|
||||
|
||||
MatrixF myTransforms[2];
|
||||
|
||||
if (smUseLatestDisplayTransform)
|
||||
{
|
||||
// Use the view matrix determined from the display device
|
||||
myTransforms[0] = mLastCameraQuery.eyeTransforms[0];
|
||||
myTransforms[1] = mLastCameraQuery.eyeTransforms[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the view matrix determined from the control object
|
||||
myTransforms[0] = mLastCameraQuery.cameraMatrix;
|
||||
myTransforms[1] = mLastCameraQuery.cameraMatrix;
|
||||
|
||||
QuatF qrot = mLastCameraQuery.cameraMatrix;
|
||||
Point3F pos = mLastCameraQuery.cameraMatrix.getPosition();
|
||||
Point3F rotEyePos;
|
||||
|
||||
myTransforms[0].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[0], &rotEyePos));
|
||||
myTransforms[1].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[1], &rotEyePos));
|
||||
}
|
||||
|
||||
GFX->setStereoEyeTransforms(myTransforms);
|
||||
|
||||
// Allow render size to originate from the render target
|
||||
if (mLastCameraQuery.stereoTargets[0])
|
||||
{
|
||||
renderSize = mLastCameraQuery.stereoViewports[0].extent;
|
||||
renderingToTarget = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -357,8 +405,8 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
// set up the camera and viewport stuff:
|
||||
F32 wwidth;
|
||||
F32 wheight;
|
||||
F32 renderWidth = (mRenderStyle == RenderStyleStereoSideBySide) ? F32(getWidth())*0.5f : F32(getWidth());
|
||||
F32 renderHeight = F32(getHeight());
|
||||
F32 renderWidth = F32(renderSize.x);
|
||||
F32 renderHeight = F32(renderSize.y);
|
||||
F32 aspectRatio = renderWidth / renderHeight;
|
||||
|
||||
// Use the FOV to calculate the viewport height scale
|
||||
|
|
@ -380,12 +428,8 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
Frustum frustum;
|
||||
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 );
|
||||
// NOTE: these calculations are essentially overridden later by the fov port settings when rendering each eye.
|
||||
MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -407,15 +451,24 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
|
||||
RectI tempRect = updateRect;
|
||||
|
||||
#ifdef TORQUE_OS_MAC
|
||||
Point2I screensize = getRoot()->getWindowSize();
|
||||
tempRect.point.y = screensize.y - (tempRect.point.y + tempRect.extent.y);
|
||||
#endif
|
||||
if (!renderingToTarget)
|
||||
{
|
||||
#ifdef TORQUE_OS_MAC
|
||||
Point2I screensize = getRoot()->getWindowSize();
|
||||
tempRect.point.y = screensize.y - (tempRect.point.y + tempRect.extent.y);
|
||||
#endif
|
||||
|
||||
GFX->setViewport( tempRect );
|
||||
GFX->setViewport( tempRect );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Activate stereo RT
|
||||
GFX->activateStereoTarget(-1);
|
||||
}
|
||||
|
||||
// Clear the zBuffer so GUI doesn't hose object rendering accidentally
|
||||
GFX->clear( GFXClearZBuffer , ColorI(20,20,20), 1.0f, 0 );
|
||||
//GFX->clear( GFXClearTarget, ColorI(255,0,0), 1.0f, 0);
|
||||
|
||||
GFX->setFrustum( frustum );
|
||||
if(mLastCameraQuery.ortho)
|
||||
|
|
@ -427,7 +480,7 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
// 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(getExtent());
|
||||
gClientSceneGraph->setDisplayTargetResolution(renderSize);
|
||||
|
||||
// Set the GFX world matrix to the world-to-camera transform, but don't
|
||||
// change the cameraMatrix in mLastCameraQuery. This is because
|
||||
|
|
@ -455,20 +508,121 @@ void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
renderWorld(updateRect);
|
||||
DebugDrawer::get()->render();
|
||||
|
||||
// Render the canvas overlay if its available
|
||||
if (mRenderStyle == RenderStyleStereoSideBySide && mStereoGuiTarget.getPointer())
|
||||
{
|
||||
GFXDEBUGEVENT_SCOPE( StereoGui_Render, ColorI( 255, 0, 0 ) );
|
||||
MatrixF proj(1);
|
||||
|
||||
Frustum originalFrustum = GFX->getFrustum();
|
||||
GFXTextureObject *texObject = mStereoGuiTarget->getTexture(0);
|
||||
const FovPort *currentFovPort = GFX->getSteroFovPort();
|
||||
const MatrixF *eyeTransforms = GFX->getStereoEyeTransforms();
|
||||
const MatrixF *worldEyeTransforms = GFX->getInverseStereoEyeTransforms();
|
||||
const Point3F *eyeOffset = GFX->getStereoEyeOffsets();
|
||||
|
||||
for (U32 i=0; i<2; i++)
|
||||
{
|
||||
GFX->activateStereoTarget(i);
|
||||
Frustum gfxFrustum = originalFrustum;
|
||||
const F32 frustumDepth = gfxFrustum.getNearDist();
|
||||
MathUtils::makeFovPortFrustum(&gfxFrustum, true, gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[i], eyeTransforms[i]);
|
||||
GFX->setFrustum(gfxFrustum);
|
||||
|
||||
MatrixF eyeWorldTrans(1);
|
||||
eyeWorldTrans.setPosition(Point3F(eyeOffset[i].x,eyeOffset[i].y,eyeOffset[i].z));
|
||||
MatrixF eyeWorld(1);
|
||||
eyeWorld.mul(eyeWorldTrans);
|
||||
eyeWorld.inverse();
|
||||
|
||||
GFX->setWorldMatrix(eyeWorld);
|
||||
GFX->setViewMatrix(MatrixF::Identity);
|
||||
|
||||
if (!mStereoOverlayVB.getPointer())
|
||||
{
|
||||
mStereoOverlayVB.set(GFX, 4, GFXBufferTypeStatic);
|
||||
GFXVertexPCT *verts = mStereoOverlayVB.lock(0, 4);
|
||||
|
||||
F32 texLeft = 0.0f;
|
||||
F32 texRight = 1.0f;
|
||||
F32 texTop = 1.0f;
|
||||
F32 texBottom = 0.0f;
|
||||
|
||||
F32 rectRatio = gfxFrustum.getWidth() / gfxFrustum.getHeight();
|
||||
F32 rectWidth = gfxFrustum.getWidth() * TS_OVERLAY_SCREEN_WIDTH;
|
||||
F32 rectHeight = rectWidth * rectRatio;
|
||||
|
||||
F32 screenLeft = -rectWidth * 0.5;
|
||||
F32 screenRight = rectWidth * 0.5;
|
||||
F32 screenTop = -rectHeight * 0.5;
|
||||
F32 screenBottom = rectHeight * 0.5;
|
||||
|
||||
const F32 fillConv = 0.0f;
|
||||
const F32 frustumDepth = gfxFrustum.getNearDist() + 0.012;
|
||||
verts[0].point.set( screenLeft - fillConv, frustumDepth, screenTop - fillConv );
|
||||
verts[1].point.set( screenRight - fillConv, frustumDepth, screenTop - fillConv );
|
||||
verts[2].point.set( screenLeft - fillConv, frustumDepth, screenBottom - fillConv );
|
||||
verts[3].point.set( screenRight - fillConv, frustumDepth, screenBottom - fillConv );
|
||||
|
||||
verts[0].color = verts[1].color = verts[2].color = verts[3].color = ColorI(255,255,255,255);
|
||||
|
||||
verts[0].texCoord.set( texLeft, texTop );
|
||||
verts[1].texCoord.set( texRight, texTop );
|
||||
verts[2].texCoord.set( texLeft, texBottom );
|
||||
verts[3].texCoord.set( texRight, texBottom );
|
||||
|
||||
mStereoOverlayVB.unlock();
|
||||
}
|
||||
|
||||
if (!mStereoGuiSB.getPointer())
|
||||
{
|
||||
// DrawBitmapStretchSR
|
||||
GFXStateBlockDesc bitmapStretchSR;
|
||||
bitmapStretchSR.setCullMode(GFXCullNone);
|
||||
bitmapStretchSR.setZReadWrite(false, false);
|
||||
bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
|
||||
bitmapStretchSR.samplersDefined = true;
|
||||
|
||||
bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
|
||||
bitmapStretchSR.samplers[0].minFilter = GFXTextureFilterPoint;
|
||||
bitmapStretchSR.samplers[0].mipFilter = GFXTextureFilterPoint;
|
||||
bitmapStretchSR.samplers[0].magFilter = GFXTextureFilterPoint;
|
||||
|
||||
mStereoGuiSB = GFX->createStateBlock(bitmapStretchSR);
|
||||
}
|
||||
|
||||
GFX->setVertexBuffer(mStereoOverlayVB);
|
||||
GFX->setStateBlock(mStereoGuiSB);
|
||||
GFX->setTexture( 0, texObject );
|
||||
GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
|
||||
GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the previous matrix state before
|
||||
// we begin rendering the child controls.
|
||||
saver.restore();
|
||||
|
||||
// Restore the render style and any stereo parameters
|
||||
GFX->setActiveRenderTarget(origTarget);
|
||||
GFX->setCurrentRenderStyle(prevRenderStyle);
|
||||
GFX->setCurrentProjectionOffset(prevProjectionOffset);
|
||||
GFX->setStereoEyeOffset(prevEyeOffset);
|
||||
|
||||
|
||||
if(mRenderStyle == RenderStyleStereoSideBySide && gLastStereoTexture)
|
||||
{
|
||||
GFX->setClipRect(updateRect);
|
||||
GFX->getDrawUtil()->drawBitmapStretch(gLastStereoTexture, updateRect);
|
||||
}
|
||||
|
||||
// Allow subclasses to render 2D elements.
|
||||
GFX->setClipRect(updateRect);
|
||||
renderGui( offset, updateRect );
|
||||
|
||||
renderChildControls(offset, updateRect);
|
||||
if (shouldRenderChildControls())
|
||||
{
|
||||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
smFrameCount++;
|
||||
}
|
||||
|
||||
|
|
@ -499,6 +653,12 @@ void GuiTSCtrl::drawLineList( const Vector<Point3F> &points, const ColorI color,
|
|||
drawLine( points[i], points[i+1], color, width );
|
||||
}
|
||||
|
||||
|
||||
void GuiTSCtrl::setStereoGui(GuiOffscreenCanvas *canvas)
|
||||
{
|
||||
mStereoGuiTarget = canvas ? canvas->getTarget() : NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Console Methods.
|
||||
//=============================================================================
|
||||
|
|
@ -547,3 +707,10 @@ DefineEngineMethod( GuiTSCtrl, calculateViewDistance, F32, ( F32 radius ),,
|
|||
{
|
||||
return object->calculateViewDistance( radius );
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiTSCtrl, setStereoGui, void, ( GuiOffscreenCanvas* canvas ),,
|
||||
"Sets the current stereo texture to an offscreen canvas\n"
|
||||
"@param canvas The desired canvas." )
|
||||
{
|
||||
object->setStereoGui(canvas);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,16 +30,29 @@
|
|||
#include "math/mMath.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _MATTEXTURETARGET_H_
|
||||
#include "materials/matTextureTarget.h"
|
||||
#endif
|
||||
|
||||
class IDisplayDevice;
|
||||
class GuiOffscreenCanvas;
|
||||
|
||||
struct CameraQuery
|
||||
{
|
||||
SimObject* object;
|
||||
F32 nearPlane;
|
||||
F32 farPlane;
|
||||
F32 fov;
|
||||
FovPort fovPort[2]; // fov for each eye
|
||||
Point2F projectionOffset;
|
||||
Point3F eyeOffset;
|
||||
Point3F eyeOffset[2];
|
||||
MatrixF eyeTransforms[2];
|
||||
bool ortho;
|
||||
MatrixF cameraMatrix;
|
||||
RectI stereoViewports[2]; // destination viewports
|
||||
GFXTextureTarget* stereoTargets[2];
|
||||
GuiCanvas* drawCanvas; // Canvas we are drawing to. Needed for VR
|
||||
};
|
||||
|
||||
/// Abstract base class for 3D viewport GUIs.
|
||||
|
|
@ -50,11 +63,12 @@ class GuiTSCtrl : public GuiContainer
|
|||
public:
|
||||
enum RenderStyles {
|
||||
RenderStyleStandard = 0,
|
||||
RenderStyleStereoSideBySide = (1<<0),
|
||||
RenderStyleStereoSideBySide = (1<<0)
|
||||
};
|
||||
|
||||
protected:
|
||||
static U32 smFrameCount;
|
||||
static bool smUseLatestDisplayTransform;
|
||||
F32 mCameraZRot;
|
||||
F32 mForceFOV;
|
||||
|
||||
|
|
@ -83,7 +97,11 @@ protected:
|
|||
|
||||
/// The last camera query set in onRender.
|
||||
/// @see getLastCameraQuery
|
||||
CameraQuery mLastCameraQuery;
|
||||
CameraQuery mLastCameraQuery;
|
||||
|
||||
NamedTexTargetRef mStereoGuiTarget;
|
||||
GFXVertexBufferHandle<GFXVertexPCT> mStereoOverlayVB;
|
||||
GFXStateBlockRef mStereoGuiSB;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -155,6 +173,10 @@ public:
|
|||
|
||||
static const U32& getFrameCount() { return smFrameCount; }
|
||||
|
||||
bool shouldRenderChildControls() { return mRenderStyle == RenderStyleStandard; }
|
||||
|
||||
void setStereoGui(GuiOffscreenCanvas *canvas);
|
||||
|
||||
DECLARE_CONOBJECT(GuiTSCtrl);
|
||||
DECLARE_CATEGORY( "Gui 3D" );
|
||||
DECLARE_DESCRIPTION( "Abstract base class for controls that render a 3D viewport." );
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "gfx/video/videoCapture.h"
|
||||
#include "lighting/lightManager.h"
|
||||
#include "core/strings/stringUnit.h"
|
||||
#include "gui/core/guiOffscreenCanvas.h"
|
||||
|
||||
#ifndef TORQUE_TGB_ONLY
|
||||
#include "scene/sceneObject.h"
|
||||
|
|
@ -126,7 +127,8 @@ GuiCanvas::GuiCanvas(): GuiControl(),
|
|||
mMouseDownPoint(0.0f,0.0f),
|
||||
mPlatformWindow(NULL),
|
||||
mLastRenderMs(0),
|
||||
mDisplayWindow(true)
|
||||
mDisplayWindow(true),
|
||||
mMenuBarCtrl(NULL)
|
||||
{
|
||||
setBounds(0, 0, 640, 480);
|
||||
mAwake = true;
|
||||
|
|
@ -508,6 +510,55 @@ bool GuiCanvas::isCursorShown()
|
|||
return mPlatformWindow->isCursorVisible();
|
||||
}
|
||||
|
||||
void GuiCanvas::cursorClick(S32 buttonId, bool isDown)
|
||||
{
|
||||
InputEventInfo inputEvent;
|
||||
inputEvent.deviceType = MouseDeviceType;
|
||||
inputEvent.deviceInst = 0;
|
||||
inputEvent.objType = SI_BUTTON;
|
||||
inputEvent.objInst = (InputObjectInstances)(KEY_BUTTON0 + buttonId);
|
||||
inputEvent.modifier = (InputModifiers)0;
|
||||
inputEvent.ascii = 0;
|
||||
inputEvent.action = isDown ? SI_MAKE : SI_BREAK;
|
||||
inputEvent.fValue = isDown ? 1.0 : 0.0;
|
||||
|
||||
processMouseEvent(inputEvent);
|
||||
}
|
||||
|
||||
void GuiCanvas::cursorNudge(F32 x, F32 y)
|
||||
{
|
||||
// Generate a base Movement along and Axis event
|
||||
InputEventInfo inputEvent;
|
||||
inputEvent.deviceType = MouseDeviceType;
|
||||
inputEvent.deviceInst = 0;
|
||||
inputEvent.objType = SI_AXIS;
|
||||
inputEvent.modifier = (InputModifiers)0;
|
||||
inputEvent.ascii = 0;
|
||||
|
||||
// Generate delta movement along each axis
|
||||
Point2F cursDelta(x, y);
|
||||
|
||||
// If X axis changed, generate a relative event
|
||||
if(mFabs(cursDelta.x) > 0.1)
|
||||
{
|
||||
inputEvent.objInst = SI_XAXIS;
|
||||
inputEvent.action = SI_MOVE;
|
||||
inputEvent.fValue = cursDelta.x;
|
||||
processMouseEvent(inputEvent);
|
||||
}
|
||||
|
||||
// If Y axis changed, generate a relative event
|
||||
if(mFabs(cursDelta.y) > 0.1)
|
||||
{
|
||||
inputEvent.objInst = SI_YAXIS;
|
||||
inputEvent.action = SI_MOVE;
|
||||
inputEvent.fValue = cursDelta.y;
|
||||
processMouseEvent(inputEvent);
|
||||
}
|
||||
|
||||
processMouseEvent(inputEvent);
|
||||
}
|
||||
|
||||
void GuiCanvas::addAcceleratorKey(GuiControl *ctrl, U32 index, U32 keyCode, U32 modifier)
|
||||
{
|
||||
if (keyCode > 0 && ctrl)
|
||||
|
|
@ -708,14 +759,22 @@ bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
|
|||
//
|
||||
// 'mCursorPt' basically is an accumulation of errors and the number of bugs that have cropped up with
|
||||
// the GUI clicking stuff where it is not supposed to are probably all to blame on this.
|
||||
|
||||
// Need to query platform for specific things
|
||||
AssertISV(mPlatformWindow, "GuiCanvas::processMouseEvent - no window present!");
|
||||
PlatformCursorController *pController = mPlatformWindow->getCursorController();
|
||||
AssertFatal(pController != NULL, "GuiCanvas::processInputEvent - No Platform Controller Found")
|
||||
|
||||
//copy the modifier into the new event
|
||||
mLastEvent.modifier = inputEvent.modifier;
|
||||
S32 mouseDoubleClickWidth = 12;
|
||||
S32 mouseDoubleClickHeight = 12;
|
||||
U32 mouseDoubleClickTime = 500;
|
||||
|
||||
// Query platform for mouse info if its available
|
||||
PlatformCursorController *pController = mPlatformWindow ? mPlatformWindow->getCursorController() : NULL;
|
||||
if (pController)
|
||||
{
|
||||
mouseDoubleClickWidth = pController->getDoubleClickWidth();
|
||||
mouseDoubleClickHeight = pController->getDoubleClickHeight();
|
||||
mouseDoubleClickTime = pController->getDoubleClickTime();
|
||||
}
|
||||
|
||||
//copy the modifier into the new event
|
||||
mLastEvent.modifier = inputEvent.modifier;
|
||||
|
||||
if(inputEvent.objType == SI_AXIS &&
|
||||
(inputEvent.objInst == SI_XAXIS || inputEvent.objInst == SI_YAXIS))
|
||||
|
|
@ -747,7 +806,7 @@ bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
|
|||
// moving too much.
|
||||
Point2F movement = mMouseDownPoint - mCursorPt;
|
||||
|
||||
if ((mAbs((S32)movement.x) > pController->getDoubleClickWidth()) || (mAbs((S32)movement.y) > pController->getDoubleClickHeight() ) )
|
||||
if ((mAbs((S32)movement.x) > mouseDoubleClickWidth) || (mAbs((S32)movement.y) > mouseDoubleClickHeight ) )
|
||||
{
|
||||
mLeftMouseLast = false;
|
||||
mMiddleMouseLast = false;
|
||||
|
|
@ -799,7 +858,7 @@ bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
|
|||
if (mLeftMouseLast)
|
||||
{
|
||||
//if it was within the double click time count the clicks
|
||||
if (curTime - mLastMouseDownTime <= pController->getDoubleClickTime())
|
||||
if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
|
||||
mLastMouseClickCount++;
|
||||
else
|
||||
mLastMouseClickCount = 1;
|
||||
|
|
@ -833,7 +892,7 @@ bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
|
|||
if (mRightMouseLast)
|
||||
{
|
||||
//if it was within the double click time count the clicks
|
||||
if (curTime - mLastMouseDownTime <= pController->getDoubleClickTime())
|
||||
if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
|
||||
mLastMouseClickCount++;
|
||||
else
|
||||
mLastMouseClickCount = 1;
|
||||
|
|
@ -864,7 +923,7 @@ bool GuiCanvas::processMouseEvent(InputEventInfo &inputEvent)
|
|||
if (mMiddleMouseLast)
|
||||
{
|
||||
//if it was within the double click time count the clicks
|
||||
if (curTime - mLastMouseDownTime <= pController->getDoubleClickTime())
|
||||
if (curTime - mLastMouseDownTime <= mouseDoubleClickTime)
|
||||
mLastMouseClickCount++;
|
||||
else
|
||||
mLastMouseClickCount = 1;
|
||||
|
|
@ -1768,6 +1827,21 @@ void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
|
|||
|
||||
PROFILE_END();
|
||||
|
||||
// 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->disableShaders(true);
|
||||
GFX->updateStates(true);
|
||||
|
||||
for (Vector<GuiOffscreenCanvas*>::iterator itr = GuiOffscreenCanvas::sList.begin(); itr != GuiOffscreenCanvas::sList.end(); itr++)
|
||||
{
|
||||
(*itr)->renderFrame(false, false);
|
||||
}
|
||||
|
||||
GFX->setActiveRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
// Can't render if waiting for device to reset.
|
||||
if ( !beginSceneRes )
|
||||
{
|
||||
|
|
@ -1907,7 +1981,8 @@ void GuiCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
|
|||
PROFILE_START(GFXEndScene);
|
||||
GFX->endScene();
|
||||
PROFILE_END();
|
||||
|
||||
|
||||
GFX->getDeviceEventSignal().trigger( GFXDevice::dePostFrame );
|
||||
swapBuffers();
|
||||
|
||||
GuiCanvas::getGuiCanvasFrameSignal().trigger(false);
|
||||
|
|
@ -2761,3 +2836,16 @@ ConsoleMethod( GuiCanvas, hideWindow, void, 2, 2, "" )
|
|||
WindowManager->setDisplayWindow(false);
|
||||
object->getPlatformWindow()->setDisplayWindow(false);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiCanvas, cursorClick, void, 4, 4, "button, isDown" )
|
||||
{
|
||||
const S32 buttonId = dAtoi(argv[2]);
|
||||
const bool isDown = dAtob(argv[3]);
|
||||
|
||||
object->cursorClick(buttonId, isDown);
|
||||
}
|
||||
|
||||
ConsoleMethod( GuiCanvas, cursorNudge, void, 4, 4, "x, y" )
|
||||
{
|
||||
object->cursorNudge(dAtof(argv[2]), dAtof(argv[3]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,6 +331,10 @@ public:
|
|||
|
||||
/// Returns true if the cursor is being rendered.
|
||||
virtual bool isCursorShown();
|
||||
|
||||
void cursorClick(S32 buttonId, bool isDown);
|
||||
|
||||
void cursorNudge(F32 x, F32 y);
|
||||
/// @}
|
||||
|
||||
///used by the tooltip resource
|
||||
|
|
|
|||
|
|
@ -2380,7 +2380,8 @@ void GuiControl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent
|
|||
// so set it back before we change it again.
|
||||
|
||||
PlatformWindow *pWindow = static_cast<GuiCanvas*>(getRoot())->getPlatformWindow();
|
||||
AssertFatal(pWindow != NULL,"GuiControl without owning platform window! This should not be possible.");
|
||||
if (!pWindow)
|
||||
return;
|
||||
PlatformCursorController *pController = pWindow->getCursorController();
|
||||
AssertFatal(pController != NULL,"PlatformWindow without an owned CursorController!");
|
||||
|
||||
|
|
|
|||
273
Engine/source/gui/core/guiOffscreenCanvas.cpp
Normal file
273
Engine/source/gui/core/guiOffscreenCanvas.cpp
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
#include "gui/core/guiOffscreenCanvas.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gfx/gfxTextureManager.h"
|
||||
#include "gfx/gfxAPI.h"
|
||||
#include "gfx/gfxDebugEvent.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/console.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiOffscreenCanvas);
|
||||
|
||||
Vector<GuiOffscreenCanvas*> GuiOffscreenCanvas::sList;
|
||||
|
||||
GuiOffscreenCanvas::GuiOffscreenCanvas()
|
||||
{
|
||||
mTargetFormat = GFXFormatR8G8B8A8;
|
||||
mTargetSize = Point2I(256,256);
|
||||
mTargetName = "offscreenCanvas";
|
||||
mTargetDirty = true;
|
||||
mDynamicTarget = false;
|
||||
}
|
||||
|
||||
GuiOffscreenCanvas::~GuiOffscreenCanvas()
|
||||
{
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::initPersistFields()
|
||||
{
|
||||
addField( "targetSize", TypePoint2I, Offset( mTargetSize, GuiOffscreenCanvas ),"" );
|
||||
addField( "targetFormat", TypeGFXFormat, Offset( mTargetFormat, GuiOffscreenCanvas ), "");
|
||||
addField( "targetName", TypeRealString, Offset( mTargetName, GuiOffscreenCanvas ), "");
|
||||
addField( "dynamicTarget", TypeBool, Offset( mDynamicTarget, GuiOffscreenCanvas ), "");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool GuiOffscreenCanvas::onAdd()
|
||||
{
|
||||
if (GuiControl::onAdd()) // jamesu - skip GuiCanvas onAdd since it sets up GFX which is bad
|
||||
{
|
||||
// ensure that we have a cursor
|
||||
setCursor(dynamic_cast<GuiCursor*>(Sim::findObject("DefaultCursor")));
|
||||
|
||||
mRenderFront = true;
|
||||
sList.push_back(this);
|
||||
|
||||
//Con::printf("Registering target %s...", mTargetName.c_str());
|
||||
mNamedTarget.registerWithName( mTargetName );
|
||||
|
||||
_setupTargets();
|
||||
|
||||
GFXTextureManager::addEventDelegate( this, &GuiOffscreenCanvas::_onTextureEvent );
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::onRemove()
|
||||
{
|
||||
GFXTextureManager::removeEventDelegate( this, &GuiOffscreenCanvas::_onTextureEvent );
|
||||
|
||||
_teardownTargets();
|
||||
|
||||
U32 idx = sList.find_next(this);
|
||||
if (idx != (U32)-1)
|
||||
{
|
||||
sList.erase(idx);
|
||||
}
|
||||
|
||||
mTarget = NULL;
|
||||
mTargetTexture = NULL;
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::_setupTargets()
|
||||
{
|
||||
_teardownTargets();
|
||||
|
||||
if (!mTarget.isValid())
|
||||
{
|
||||
mTarget = GFX->allocRenderToTextureTarget();
|
||||
}
|
||||
|
||||
// Update color
|
||||
if (!mTargetTexture.isValid() || mTargetSize != mTargetTexture.getWidthHeight())
|
||||
{
|
||||
mTargetTexture.set( mTargetSize.x, mTargetSize.y, mTargetFormat, &GFXDefaultRenderTargetProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ), 1, 0 );
|
||||
}
|
||||
|
||||
mTarget->attachTexture( GFXTextureTarget::RenderSlot(GFXTextureTarget::Color0), mTargetTexture );
|
||||
mNamedTarget.setTexture(0, mTargetTexture);
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::_teardownTargets()
|
||||
{
|
||||
mNamedTarget.release();
|
||||
mTargetTexture = NULL;
|
||||
mTargetDirty = true;
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::renderFrame(bool preRenderOnly, bool bufferSwap /* = true */)
|
||||
{
|
||||
if (!mTargetDirty)
|
||||
return;
|
||||
|
||||
#ifdef TORQUE_ENABLE_GFXDEBUGEVENTS
|
||||
char buf[256];
|
||||
dSprintf(buf, sizeof(buf), "OffsceenCanvas %s", getName() ? getName() : getIdString());
|
||||
GFXDEBUGEVENT_SCOPE_EX(GuiOffscreenCanvas_renderFrame, ColorI::GREEN, buf);
|
||||
#endif
|
||||
|
||||
PROFILE_START(OffscreenCanvasPreRender);
|
||||
|
||||
#ifdef TORQUE_GFX_STATE_DEBUG
|
||||
GFX->getDebugStateManager()->startFrame();
|
||||
#endif
|
||||
|
||||
if (mTarget->getSize() != mTargetSize)
|
||||
{
|
||||
_setupTargets();
|
||||
mNamedTarget.setViewport( RectI( Point2I::Zero, mTargetSize ) );
|
||||
}
|
||||
|
||||
// Make sure the root control is the size of the canvas.
|
||||
Point2I size = mTarget->getSize();
|
||||
|
||||
if(size.x == 0 || size.y == 0)
|
||||
{
|
||||
PROFILE_END();
|
||||
return;
|
||||
}
|
||||
|
||||
RectI screenRect(0, 0, size.x, size.y);
|
||||
|
||||
maintainSizing();
|
||||
|
||||
//preRender (recursive) all controls
|
||||
preRender();
|
||||
|
||||
PROFILE_END();
|
||||
|
||||
// Are we just doing pre-render?
|
||||
if(preRenderOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
resetUpdateRegions();
|
||||
|
||||
PROFILE_START(OffscreenCanvasRenderControls);
|
||||
|
||||
GuiCursor *mouseCursor = NULL;
|
||||
bool cursorVisible = true;
|
||||
|
||||
Point2I cursorPos((S32)mCursorPt.x, (S32)mCursorPt.y);
|
||||
mouseCursor = mDefaultCursor;
|
||||
|
||||
mLastCursorEnabled = cursorVisible;
|
||||
mLastCursor = mouseCursor;
|
||||
mLastCursorPt = cursorPos;
|
||||
|
||||
// Set active target
|
||||
GFX->pushActiveRenderTarget();
|
||||
GFX->setActiveRenderTarget(mTarget);
|
||||
|
||||
// Clear the current viewport area
|
||||
GFX->setViewport( screenRect );
|
||||
GFX->clear( GFXClearTarget, ColorF(0,0,0,0), 1.0f, 0 );
|
||||
|
||||
resetUpdateRegions();
|
||||
|
||||
// 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 );
|
||||
|
||||
RectI contentRect(Point2I(0,0), mTargetSize);
|
||||
{
|
||||
// Render active GUI Dialogs
|
||||
for(iterator i = begin(); i != end(); i++)
|
||||
{
|
||||
// Get the control
|
||||
GuiControl *contentCtrl = static_cast<GuiControl*>(*i);
|
||||
|
||||
GFX->setClipRect( contentRect );
|
||||
GFX->setStateBlock(mDefaultGuiSB);
|
||||
|
||||
contentCtrl->onRender(contentCtrl->getPosition(), contentRect);
|
||||
}
|
||||
|
||||
// Fill Blue if no Dialogs
|
||||
if(this->size() == 0)
|
||||
GFX->clear( GFXClearTarget, ColorF(0,0,1,1), 1.0f, 0 );
|
||||
|
||||
GFX->setClipRect( contentRect );
|
||||
|
||||
// Draw cursor
|
||||
//
|
||||
if (mCursorEnabled && mouseCursor && mShowCursor)
|
||||
{
|
||||
Point2I pos((S32)mCursorPt.x, (S32)mCursorPt.y);
|
||||
Point2I spot = mouseCursor->getHotSpot();
|
||||
|
||||
pos -= spot;
|
||||
mouseCursor->render(pos);
|
||||
}
|
||||
|
||||
GFX->getDrawUtil()->clearBitmapModulation();
|
||||
}
|
||||
|
||||
mTarget->resolve();
|
||||
GFX->popActiveRenderTarget();
|
||||
|
||||
PROFILE_END();
|
||||
|
||||
// Keep track of the last time we rendered.
|
||||
mLastRenderMs = Platform::getRealMilliseconds();
|
||||
mTargetDirty = mDynamicTarget;
|
||||
}
|
||||
|
||||
Point2I GuiOffscreenCanvas::getWindowSize()
|
||||
{
|
||||
return mTargetSize;
|
||||
}
|
||||
|
||||
Point2I GuiOffscreenCanvas::getCursorPos()
|
||||
{
|
||||
return Point2I(mCursorPt.x, mCursorPt.y);
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::setCursorPos(const Point2I &pt)
|
||||
{
|
||||
mCursorPt.x = F32( pt.x );
|
||||
mCursorPt.y = F32( pt.y );
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::showCursor(bool state)
|
||||
{
|
||||
mShowCursor = state;
|
||||
}
|
||||
|
||||
bool GuiOffscreenCanvas::isCursorShown()
|
||||
{
|
||||
return mShowCursor;
|
||||
}
|
||||
|
||||
void GuiOffscreenCanvas::_onTextureEvent( GFXTexCallbackCode code )
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case GFXZombify:
|
||||
_teardownTargets();
|
||||
break;
|
||||
|
||||
case GFXResurrect:
|
||||
_setupTargets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiOffscreenCanvas, resetTarget, void, (), , "")
|
||||
{
|
||||
object->_setupTargets();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiOffscreenCanvas, markDirty, void, (), , "")
|
||||
{
|
||||
object->markDirty();
|
||||
}
|
||||
|
||||
63
Engine/source/gui/core/guiOffscreenCanvas.h
Normal file
63
Engine/source/gui/core/guiOffscreenCanvas.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef _GUIOFFSCREENCANVAS_H_
|
||||
#define _GUIOFFSCREENCANVAS_H_
|
||||
|
||||
#include "math/mMath.h"
|
||||
#include "gui/core/guiCanvas.h"
|
||||
#include "core/util/tVector.h"
|
||||
|
||||
#ifndef _MATTEXTURETARGET_H_
|
||||
#include "materials/matTextureTarget.h"
|
||||
#endif
|
||||
|
||||
class GuiTextureDebug;
|
||||
|
||||
class GuiOffscreenCanvas : public GuiCanvas
|
||||
{
|
||||
public:
|
||||
typedef GuiCanvas Parent;
|
||||
|
||||
GuiOffscreenCanvas();
|
||||
~GuiOffscreenCanvas();
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void renderFrame(bool preRenderOnly, bool bufferSwap);
|
||||
|
||||
Point2I getWindowSize();
|
||||
|
||||
Point2I getCursorPos();
|
||||
void setCursorPos(const Point2I &pt);
|
||||
void showCursor(bool state);
|
||||
bool isCursorShown();
|
||||
|
||||
void _onTextureEvent( GFXTexCallbackCode code );
|
||||
|
||||
void _setupTargets();
|
||||
void _teardownTargets();
|
||||
|
||||
NamedTexTargetRef getTarget() { return &mNamedTarget; }
|
||||
|
||||
void markDirty() { mTargetDirty = true; }
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
DECLARE_CONOBJECT(GuiOffscreenCanvas);
|
||||
|
||||
protected:
|
||||
GFXTextureTargetRef mTarget;
|
||||
NamedTexTarget mNamedTarget;
|
||||
GFXTexHandle mTargetTexture;
|
||||
|
||||
GFXFormat mTargetFormat;
|
||||
Point2I mTargetSize;
|
||||
String mTargetName;
|
||||
|
||||
bool mTargetDirty;
|
||||
bool mDynamicTarget;
|
||||
|
||||
public:
|
||||
static Vector<GuiOffscreenCanvas*> sList;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue