| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889 | //-----------------------------------------------------------------------------// 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.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "gui/3d/guiTSControl.h"#include "gui/core/guiOffscreenCanvas.h"#include "console/engineAPI.h"#include "scene/sceneManager.h"#include "lighting/lightManager.h"#include "gfx/sim/debugDraw.h"#include "gfx/gfxTransformSaver.h"#include "gfx/screenshot.h"#include "math/mathUtils.h"#include "gui/core/guiCanvas.h"#include "scene/reflectionManager.h"#include "postFx/postEffectManager.h"#include "gfx/gfxTransformSaver.h"#include "gfx/gfxDrawUtil.h"#include "gfx/gfxDebugEvent.h"#include "core/stream/fileStream.h"#include "platform/output/IDisplayDevice.h"#include "T3D/gameBase/extended/extendedMove.h"#define TS_OVERLAY_SCREEN_WIDTH 0.75IMPLEMENT_CONOBJECT( GuiTSCtrl );ConsoleDocClass( GuiTSCtrl,   "@brief Abstract base class for controls that render 3D scenes.\n\n"      "GuiTSCtrl is the base class for controls that render 3D camera views in Torque.  The class itself "   "does not implement a concrete scene rendering.  Use GuiObjectView to display invidiual shapes in "   "the Gui and GameTSCtrl to render full scenes.\n\n"      "@see GameTSCtrl\n"   "@see GuiObjectView\n"   "@ingroup Gui3D\n");U32 GuiTSCtrl::smFrameCount = 0;bool GuiTSCtrl::smUseLatestDisplayTransform = true;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"   },   { GuiTSCtrl::RenderStyleStereoSeparate,   "stereo separate" },EndImplementEnumType;//-----------------------------------------------------------------------------namespace {   void _drawLine( const Point3F &p0, const Point3F &p1, const ColorI &color, F32 width )   {      F32 x1, x2, y1, y2, z1, z2;      x1 = p0.x;      y1 = p0.y;      z1 = p0.z;      x2 = p1.x;      y2 = p1.y;      z2 = p1.z;      //      // Convert Line   a----------b      //      // Into Quad      v0---------v1      //                 a         b      //                v2---------v3      //      Point2F start(x1, y1);      Point2F end(x2, y2);      Point2F perp, lineVec;      // handle degenerate case where point a = b      if(x1 == x2 && y1 == y2)      {         perp.set(0.0f, width * 0.5f);         lineVec.set(0.1f, 0.0f);      }      else      {         perp.set(start.y - end.y, end.x - start.x);         lineVec.set(end.x - start.x, end.y - start.y);         perp.normalize(width * 0.5f);         lineVec.normalize(0.1f);      }      start -= lineVec;      end   += lineVec;      GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, 4, GFXBufferTypeVolatile);      verts.lock();      verts[0].point.set( start.x+perp.x, start.y+perp.y, z1 );      verts[1].point.set( end.x+perp.x, end.y+perp.y, z2 );      verts[2].point.set( start.x-perp.x, start.y-perp.y, z1 );      verts[3].point.set( end.x-perp.x, end.y-perp.y, z2 );      verts[0].color = color;      verts[1].color = color;      verts[2].color = color;      verts[3].color = color;      verts.unlock();      GFX->setVertexBuffer( verts );      GFXStateBlockDesc desc;      desc.setCullMode(GFXCullNone);      desc.setZReadWrite(false);      desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);      GFX->setupGenericShaders();      GFX->setStateBlockByDesc( desc );            GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );   }}//-----------------------------------------------------------------------------GuiTSCtrl::GuiTSCtrl(){   mCameraZRot = 0;   mForceFOV = 0;   mReflectPriority = 1.0f;   mRenderStyle = RenderStyleStandard;   mSaveModelview.identity();   mSaveProjection.identity();   mSaveViewport.set( 0, 0, 10, 10 );   mSaveWorldToScreenScale.set( 0, 0 );   mLastCameraQuery.cameraMatrix.identity();   mLastCameraQuery.fov = 45.0f;   mLastCameraQuery.object = NULL;   mLastCameraQuery.farPlane = 10.0f;   mLastCameraQuery.nearPlane = 0.01f;   mLastCameraQuery.hasFovPort = false;   mLastCameraQuery.hasStereoTargets = false;   mLastCameraQuery.ortho = false;   mOrthoWidth = 0.1f;   mOrthoHeight = 0.1f;}//-----------------------------------------------------------------------------void GuiTSCtrl::initPersistFields(){   addGroup( "Camera" );         addField("cameraZRot", TypeF32, Offset(mCameraZRot, GuiTSCtrl),         "Z rotation angle of camera." );      addField("forceFOV",   TypeF32, Offset(mForceFOV,   GuiTSCtrl),         "The vertical field of view in degrees or zero to use the normal camera FOV." );            endGroup( "Camera" );      addGroup( "Rendering" );         addField( "reflectPriority", TypeF32, Offset( mReflectPriority, GuiTSCtrl ),         "The share of the per-frame reflection update work this control's rendering should run.\n"         "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();}//-----------------------------------------------------------------------------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");}//-----------------------------------------------------------------------------bool GuiTSCtrl::onWake(){   if ( !Parent::onWake() )      return false;   // Add ourselves to the active viewport list.   AssertFatal( !smAwakeTSCtrls.contains( this ),       "GuiTSCtrl::onWake - This control is already in the awake list!" );   smAwakeTSCtrls.push_back( this );   // For VR   mLastCameraQuery.drawCanvas = getRoot();   return true;}//-----------------------------------------------------------------------------void GuiTSCtrl::onSleep(){   Parent::onSleep();   AssertFatal( smAwakeTSCtrls.contains( this ),       "GuiTSCtrl::onSleep - This control is not in the awake list!" );   smAwakeTSCtrls.remove( this );}//-----------------------------------------------------------------------------void GuiTSCtrl::onPreRender(){   setUpdate();}//-----------------------------------------------------------------------------bool GuiTSCtrl::processCameraQuery(CameraQuery *){   return false;}//-----------------------------------------------------------------------------void GuiTSCtrl::renderWorld(const RectI& /*updateRect*/){}//-----------------------------------------------------------------------------F32 GuiTSCtrl::projectRadius( F32 dist, F32 radius ) const{   // Fixup any negative or zero distance so we   // don't get a divide by zero.   dist = dist > 0.0f ? dist : 0.001f;   return ( radius / dist ) * mSaveWorldToScreenScale.y;   }//-----------------------------------------------------------------------------bool GuiTSCtrl::project( const Point3F &pt, Point3F *dest ) const{   return MathUtils::mProjectWorldToScreen(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection);}//-----------------------------------------------------------------------------bool GuiTSCtrl::unproject( const Point3F &pt, Point3F *dest ) const{   MathUtils::mProjectScreenToWorld(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection,mLastCameraQuery.farPlane,mLastCameraQuery.nearPlane);   return true;}//-----------------------------------------------------------------------------F32 GuiTSCtrl::calculateViewDistance(F32 radius){   F32 fov = mLastCameraQuery.fov;   F32 wwidth;   F32 wheight;   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.   if(!mLastCameraQuery.ortho)   {      wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);      wwidth = aspectRatio * wheight;   }   else   {      wheight = mLastCameraQuery.fov;      wwidth = aspectRatio * wheight;   }   // Now determine if we should use the width    // fov or height fov.   //   // If the window is taller than it is wide, use the    // width fov to keep the object completely in view.   if (wheight > wwidth)      fov = mAtan( wwidth / mLastCameraQuery.nearPlane ) * 2.0f;   return radius / mTan(fov / 2.0f);}//-----------------------------------------------------------------------------static FovPort CalculateFovPortForCanvas(const RectI viewport, const CameraQuery &cameraQuery){   F32 wwidth;   F32 wheight;   F32 renderWidth = viewport.extent.x;   F32 renderHeight = viewport.extent.y;   F32 aspectRatio = renderWidth / renderHeight;   // Use the FOV to calculate the viewport height scale   // then generate the width scale from the aspect ratio.   if(!cameraQuery.ortho)   {      wheight = /*cameraQuery.nearPlane * */ mTan(cameraQuery.fov / 2.0f);      wwidth = aspectRatio * wheight;   }   else   {      wheight = cameraQuery.fov;      wwidth = aspectRatio * wheight;   }   F32 hscale = wwidth * 2.0f / renderWidth;   F32 vscale = wheight * 2.0f / renderHeight;   F32 left = 0.0f * hscale - wwidth;   F32 right = renderWidth * hscale - wwidth;   F32 top = wheight - vscale * 0.0f;   F32 bottom = wheight - vscale * renderHeight;   FovPort fovPort;   fovPort.upTan = top;   fovPort.downTan = -bottom;   fovPort.leftTan = -left;   fovPort.rightTan = right;   return fovPort;}void GuiTSCtrl::_internalRender(RectI guiViewport, RectI renderViewport, Frustum &frustum){   GFXTransformSaver saver;   Point2I renderSize = renderViewport.extent;   GFXTarget *origTarget = GFX->getActiveRenderTarget();   S32 origStereoTarget = GFX->getCurrentStereoTarget();   if (mForceFOV != 0)      mLastCameraQuery.fov = mDegToRad(mForceFOV);   if (mCameraZRot)   {      MatrixF rotMat(EulerF(0, 0, mDegToRad(mCameraZRot)));      mLastCameraQuery.cameraMatrix.mul(rotMat);   }   if (mReflectPriority > 0)   {      // Get the total reflection priority.      F32 totalPriority = 0;      for (U32 i = 0; i < smAwakeTSCtrls.size(); i++)         if (smAwakeTSCtrls[i]->isVisible())            totalPriority += smAwakeTSCtrls[i]->mReflectPriority;      REFLECTMGR->update(mReflectPriority / totalPriority,         renderSize,         mLastCameraQuery);   }   GFX->setActiveRenderTarget(origTarget);   GFX->setCurrentStereoTarget(origStereoTarget);   GFX->setViewport(renderViewport);   // Clear the zBuffer so GUI doesn't hose object rendering accidentally   GFX->clear(GFXClearZBuffer, ColorI(20, 20, 20), 1.0f, 0);   GFX->setFrustum(frustum);   mSaveProjection = GFX->getProjectionMatrix();   if (mLastCameraQuery.ortho)   {      mOrthoWidth = frustum.getWidth();      mOrthoHeight = frustum.getHeight();   }   // 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(renderSize);   // 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.   MatrixF worldToCamera = mLastCameraQuery.cameraMatrix;   worldToCamera.inverse();   GFX->setWorldMatrix(worldToCamera);   mSaveProjection = GFX->getProjectionMatrix();   mSaveModelview = GFX->getWorldMatrix();   mSaveViewport = guiViewport;   mSaveWorldToScreenScale = GFX->getWorldToScreenScale();   mSaveFrustum = GFX->getFrustum();   mSaveFrustum.setTransform(mLastCameraQuery.cameraMatrix);   // 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);   DebugDrawer* debugDraw = DebugDrawer::get();   if (mRenderStyle == RenderStyleStereoSideBySide && debugDraw->willDraw())   {      // For SBS we need to render over each viewport      GFX->setViewport(mLastCameraQuery.stereoViewports[0]);      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);      GFX->setFrustum(frustum);      debugDraw->render(false);      GFX->setViewport(mLastCameraQuery.stereoViewports[1]);      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[1]);      GFX->setFrustum(frustum);      debugDraw->render();   }   else   {      debugDraw->render();   }   saver.restore();}//-----------------------------------------------------------------------------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;   mLastCameraQuery.displayDevice = NULL;   if (!processCameraQuery(&mLastCameraQuery))   {      // We have no camera, but render the GUI children       // anyway.  This makes editing GuiTSCtrl derived      // controls easier in the GuiEditor.      renderChildControls(offset, updateRect);      return;   }   // jamesu - currently a little bit of a hack. Ideally we need to ditch the viewports in the query data and just rely on the display device   if (mLastCameraQuery.displayDevice)   {      if (mRenderStyle == RenderStyleStereoSideBySide)      {         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_StereoSideBySide);      }      else if (mRenderStyle == RenderStyleStereoSeparate)      {         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_StereoSeparate);      }      else      {         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_Standard);      }      // The connection's display device may want to set the eye offset      if (mLastCameraQuery.displayDevice->providesEyeOffsets())      {         mLastCameraQuery.displayDevice->getEyeOffsets(mLastCameraQuery.eyeOffset);      }      // Grab field of view for both eyes      if (mLastCameraQuery.displayDevice->providesFovPorts())      {         mLastCameraQuery.displayDevice->getFovPorts(mLastCameraQuery.fovPort);         mLastCameraQuery.hasFovPort = true;      }      mLastCameraQuery.displayDevice->getStereoViewports(mLastCameraQuery.stereoViewports);      mLastCameraQuery.displayDevice->getStereoTargets(mLastCameraQuery.stereoTargets);      mLastCameraQuery.hasStereoTargets = mLastCameraQuery.stereoTargets[0];   }   GFXTargetRef origTarget = GFX->getActiveRenderTarget();   U32 origStyle = GFX->getCurrentRenderStyle();   // Set up the appropriate render style   Point2I renderSize = getExtent();   Frustum frustum;   mLastCameraQuery.currentEye = -1;   if (mRenderStyle == RenderStyleStereoSideBySide)   {      GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide);      GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);      GFX->setStereoHeadTransform(mLastCameraQuery.headMatrix);      if (!mLastCameraQuery.hasStereoTargets)      {         // Need to calculate our current viewport here         mLastCameraQuery.stereoViewports[0] = updateRect;         mLastCameraQuery.stereoViewports[0].extent.x /= 2;         mLastCameraQuery.stereoViewports[1] = mLastCameraQuery.stereoViewports[0];         mLastCameraQuery.stereoViewports[1].point.x += mLastCameraQuery.stereoViewports[1].extent.x;      }      if (!mLastCameraQuery.hasFovPort)      {         // Need to make our own fovPort         mLastCameraQuery.fovPort[0] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[0], mLastCameraQuery);         mLastCameraQuery.fovPort[1] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[1], mLastCameraQuery);      }      GFX->setStereoFovPort(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;         mLastCameraQuery.headMatrix = mLastCameraQuery.cameraMatrix; // override head         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.stereoTargets[0]->getSize();         renderingToTarget = true;      }      // 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]);      GFX->activateStereoTarget(-1);      _internalRender(RectI(updateRect.point, updateRect.extent), RectI(Point2I(0,0), renderSize), frustum);           // Notify device we've rendered the right, thus the last stereo frame.      GFX->getDeviceEventSignal().trigger(GFXDevice::deRightStereoFrameRendered);      // Render preview      if (mLastCameraQuery.displayDevice)      {         GFXTexHandle previewTexture = mLastCameraQuery.displayDevice->getPreviewTexture();         if (!previewTexture.isNull())         {            GFX->setActiveRenderTarget(origTarget);            GFX->setCurrentRenderStyle(origStyle);            GFX->setClipRect(updateRect);            renderDisplayPreview(updateRect, previewTexture);         }      }   }   else if (mRenderStyle == RenderStyleStereoSeparate && mLastCameraQuery.displayDevice)   {      // In this case we render the scene twice to different render targets, then      // render the final composite view       GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSeparate);      GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);      GFX->setStereoHeadTransform(mLastCameraQuery.headMatrix);      GFX->setStereoFovPort(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));      }      MatrixF origMatrix = mLastCameraQuery.cameraMatrix;      // Left      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);      mLastCameraQuery.cameraMatrix = myTransforms[0];      frustum.update();     GFX->activateStereoTarget(0);     mLastCameraQuery.currentEye = 0;     GFX->beginField();     _internalRender(RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), frustum);      GFX->getDeviceEventSignal().trigger(GFXDevice::deLeftStereoFrameRendered);     GFX->endField();      // Right     GFX->activateStereoTarget(1);     mLastCameraQuery.currentEye = 1;      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[1]);      mLastCameraQuery.cameraMatrix = myTransforms[1];     frustum.update();     GFX->beginField();     _internalRender(RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[1]->getSize()), RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), frustum);     GFX->getDeviceEventSignal().trigger(GFXDevice::deRightStereoFrameRendered);     GFX->endField();      mLastCameraQuery.cameraMatrix = origMatrix;      // Render preview      if (mLastCameraQuery.displayDevice)      {         GFXTexHandle previewTexture = mLastCameraQuery.displayDevice->getPreviewTexture();         if (!previewTexture.isNull())         {            GFX->setActiveRenderTarget(origTarget);            GFX->setCurrentRenderStyle(origStyle);            GFX->setClipRect(updateRect);            renderDisplayPreview(updateRect, previewTexture);         }      }   }   else   {      // set up the camera and viewport stuff:      F32 wwidth;      F32 wheight;      F32 renderWidth = F32(renderSize.x);      F32 renderHeight = F32(renderSize.y);      F32 aspectRatio = renderWidth / renderHeight;      // Use the FOV to calculate the viewport height scale      // then generate the width scale from the aspect ratio.      if (!mLastCameraQuery.ortho)      {         wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);         wwidth = aspectRatio * wheight;      }      else      {         wheight = mLastCameraQuery.fov;         wwidth = aspectRatio * wheight;      }      F32 hscale = wwidth * 2.0f / renderWidth;      F32 vscale = wheight * 2.0f / renderHeight;      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();      if (screenShotMode)      {         gScreenShot->tileFrustum(frustum);         GFX->setViewMatrix(MatrixF::Identity);      }      RectI tempRect = updateRect;      _internalRender(tempRect, tempRect, frustum);   }   // TODO: Some render to sort of overlay system?   // Allow subclasses to render 2D elements.   GFX->setActiveRenderTarget(origTarget);   GFX->setCurrentRenderStyle(origStyle);   GFX->setClipRect(updateRect);   renderGui(offset, updateRect);   if (shouldRenderChildControls())   {      renderChildControls(offset, updateRect);   }   smFrameCount++;}//-----------------------------------------------------------------------------void GuiTSCtrl::drawLine( Point3F p0, Point3F p1, const ColorI &color, F32 width ){      if ( !mSaveFrustum.clipSegment( p0, p1 ) )      return;   MathUtils::mProjectWorldToScreen( p0, &p0, mSaveViewport, mSaveModelview, mSaveProjection );      MathUtils::mProjectWorldToScreen( p1, &p1, mSaveViewport, mSaveModelview, mSaveProjection );      p0.x = mClampF( p0.x, 0.0f, mSaveViewport.extent.x );   p0.y = mClampF( p0.y, 0.0f, mSaveViewport.extent.y );   p1.x = mClampF( p1.x, 0.0f, mSaveViewport.extent.x );   p1.y = mClampF( p1.y, 0.0f, mSaveViewport.extent.y );   p0.z = p1.z = 0.0f;   _drawLine( p0, p1, color, width );}//-----------------------------------------------------------------------------void GuiTSCtrl::drawLineList( const Vector<Point3F> &points, const ColorI color, F32 width ){   for ( S32 i = 0; i < points.size() - 1; i++ )      drawLine( points[i], points[i+1], color, width );}//-----------------------------------------------------------------------------void GuiTSCtrl::setStereoGui(GuiOffscreenCanvas *canvas){   mStereoGuiTarget = canvas ? canvas->getTarget() : NULL;   mStereoCanvas = canvas;}//-----------------------------------------------------------------------------void GuiTSCtrl::renderDisplayPreview(const RectI &updateRect, GFXTexHandle &previewTexture){   GFX->setWorldMatrix(MatrixF(1));   GFX->setViewMatrix(MatrixF::Identity);   GFX->setClipRect(updateRect);   GFX->getDrawUtil()->drawRectFill(RectI(Point2I(0, 0), Point2I(1024, 768)), ColorI::BLACK);   GFX->getDrawUtil()->drawRect(RectI(Point2I(0, 0), Point2I(1024, 768)), ColorI::RED);   if (!mStereoPreviewVB.getPointer())   {      mStereoPreviewVB.set(GFX, 4, GFXBufferTypeStatic);      GFXVertexPCT *verts = mStereoPreviewVB.lock(0, 4);      F32 texLeft = 0.0f;      F32 texRight = 1.0f;      F32 texTop = 0.0f;      F32 texBottom = 1.0f;      F32 rectWidth = updateRect.extent.x;      F32 rectHeight = updateRect.extent.y;      F32 screenLeft = 0;      F32 screenRight = rectWidth;      F32 screenTop = 0;      F32 screenBottom = rectHeight;      const F32 fillConv = 0.0f;      verts[0].point.set(screenLeft - fillConv, screenTop - fillConv, 0.f);      verts[1].point.set(screenRight - fillConv, screenTop - fillConv, 0.f);      verts[2].point.set(screenLeft - fillConv, screenBottom - fillConv, 0.f);      verts[3].point.set(screenRight - fillConv, screenBottom - fillConv, 0.f);      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);      mStereoPreviewVB.unlock();   }   if (!mStereoPreviewSB.getPointer())   {      // DrawBitmapStretchSR      GFXStateBlockDesc bitmapStretchSR;      bitmapStretchSR.setCullMode(GFXCullNone);      bitmapStretchSR.setZReadWrite(false, false);      bitmapStretchSR.setBlend(false, 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;      mStereoPreviewSB = GFX->createStateBlock(bitmapStretchSR);   }   GFX->setVertexBuffer(mStereoPreviewVB);   GFX->setStateBlock(mStereoPreviewSB);   GFX->setTexture(0, previewTexture);   GFX->setupGenericShaders(GFXDevice::GSModColorTexture);   GFX->drawPrimitive(GFXTriangleStrip, 0, 2);}//=============================================================================//    Console Methods.//=============================================================================// MARK: ---- Console Methods ----//-----------------------------------------------------------------------------DefineEngineMethod( GuiTSCtrl, unproject, Point3F, ( Point3F screenPosition ),,   "Transform 3D screen-space coordinates (x, y, depth) to world space.\n"   "This method can be, for example, used to find the world-space position relating to the current mouse cursor position.\n"   "@param screenPosition The x/y position on the screen plus the depth from the screen-plane outwards.\n"   "@return The world-space position corresponding to the given screen-space coordinates." ){   Point3F worldPos;   object->unproject( screenPosition, &worldPos );   return worldPos;}//-----------------------------------------------------------------------------DefineEngineMethod( GuiTSCtrl, project, Point3F, ( Point3F worldPosition ),,   "Transform world-space coordinates to screen-space (x, y, depth) coordinates.\n"   "@param worldPosition The world-space position to transform to screen-space.\n"   "@return The " ){   Point3F screenPos;   object->project( worldPosition, &screenPos );   return screenPos;}//-----------------------------------------------------------------------------DefineEngineMethod( GuiTSCtrl, getWorldToScreenScale, Point2F, (),,   "Get the ratio between world-space units and pixels.\n"   "@return The amount of world-space units covered by the extent of a single pixel." ){   return object->getWorldToScreenScale();}//-----------------------------------------------------------------------------DefineEngineMethod( GuiTSCtrl, calculateViewDistance, F32, ( F32 radius ),,   "Given the camera's current FOV, get the distance from the camera's viewpoint at which the given radius will fit in the render area.\n"   "@param radius Radius in world-space units which should fit in the view.\n"   "@return The distance from the viewpoint at which the given radius would be fully visible." ){   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);}
 |