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:
James Urquhart 2015-05-06 23:07:48 +01:00
parent b3170bcddf
commit 3a457749ec
56 changed files with 2654 additions and 1426 deletions

View file

@ -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]));
}

View file

@ -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

View file

@ -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!");

View 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();
}

View 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