Torque3D Documentation / _generateds / guiTSControl.cpp

guiTSControl.cpp

Engine/source/gui/3d/guiTSControl.cpp

More...

Public Defines

Public Variables

Public Functions

ConsoleDocClass(GuiTSCtrl , "@brief Abstract base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that render 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scenes.\n\n</a>" "<a href="/coding/class/classguitsctrl/">GuiTSCtrl</a> is the base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that render 3D camera views in Torque. The class itself " "does not implement a concrete scene rendering. Use <a href="/coding/class/classguiobjectview/">GuiObjectView</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> display invidiual shapes in " "the Gui and <a href="/coding/class/classgametsctrl/">GameTSCtrl</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> render full <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scenes.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameTSCtrl\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiObjectView\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Gui3D\n</a>" )
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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">area.\n</a>" " @param radius Radius in world-space units which should fit in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n</a>" " @return The distance from the viewpoint at which the given radius would be fully visible." )
DefineEngineMethod(GuiTSCtrl , getWorldToScreenScale , Point2F , () , "Get the ratio between world-space units and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@return The amount of world-space units covered by the extent of a single pixel." )
DefineEngineMethod(GuiTSCtrl , project , Point3F , (Point3F worldPosition) , "Transform world-space coordinates <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> screen-space (x, y, depth) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coordinates.\n</a>" "@param worldPosition The world-space position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> screen-<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n</a>" "@return The " )
DefineEngineMethod(GuiTSCtrl , setStereoGui , void , (GuiOffscreenCanvas *canvas) , "Sets the current stereo texture <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an offscreen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">canvas\n</a>" "@param canvas The desired canvas." )
DefineEngineMethod(GuiTSCtrl , unproject , Point3F , (Point3F screenPosition) , "Transform 3D screen-space coordinates (x, y, depth) <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n</a>" "This method can be, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> example, used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/talgorithm_8h/#talgorithm_8h_1a113846f47aa4d2409fe12e783dcd69cf">find</a> the world-space position relating <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the current mouse <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" " @param screenPosition The x/y position on the screen plus the depth from the screen-plane <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">outwards.\n</a>" " @return The world-space position corresponding <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given screen-space coordinates." )
ImplementEnumType(GuiTSRenderStyles , "Style of rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTSCtrl.\n\n</a>" "@ingroup Gui3D" )

Detailed Description

Public Defines

TS_OVERLAY_SCREEN_WIDTH() 0.75

Public Variables

 EndImplementEnumType 

Public Functions

CalculateFovPortForCanvas(const RectI viewport, const CameraQuery & cameraQuery)

ConsoleDocClass(GuiTSCtrl , "@brief Abstract base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that render 3D <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scenes.\n\n</a>" "<a href="/coding/class/classguitsctrl/">GuiTSCtrl</a> is the base class <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> controls that render 3D camera views in Torque. The class itself " "does not implement a concrete scene rendering. Use <a href="/coding/class/classguiobjectview/">GuiObjectView</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> display invidiual shapes in " "the Gui and <a href="/coding/class/classgametsctrl/">GameTSCtrl</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> render full <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scenes.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GameTSCtrl\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiObjectView\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Gui3D\n</a>" )

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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">area.\n</a>" " @param radius Radius in world-space units which should fit in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">view.\n</a>" " @return The distance from the viewpoint at which the given radius would be fully visible." )

DefineEngineMethod(GuiTSCtrl , getWorldToScreenScale , Point2F , () , "Get the ratio between world-space units and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@return The amount of world-space units covered by the extent of a single pixel." )

DefineEngineMethod(GuiTSCtrl , project , Point3F , (Point3F worldPosition) , "Transform world-space coordinates <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> screen-space (x, y, depth) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coordinates.\n</a>" "@param worldPosition The world-space position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> screen-<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n</a>" "@return The " )

DefineEngineMethod(GuiTSCtrl , setStereoGui , void , (GuiOffscreenCanvas *canvas) , "Sets the current stereo texture <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an offscreen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">canvas\n</a>" "@param canvas The desired canvas." )

DefineEngineMethod(GuiTSCtrl , unproject , Point3F , (Point3F screenPosition) , "Transform 3D screen-space coordinates (x, y, depth) <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> world <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">space.\n</a>" "This method can be, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> example, used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/talgorithm_8h/#talgorithm_8h_1a113846f47aa4d2409fe12e783dcd69cf">find</a> the world-space position relating <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the current mouse <a href="/coding/file/sdlcursorcontroller_8cpp/#sdlcursorcontroller_8cpp_1a06e8dd1f849973ccc456f8553601e8b9">cursor</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" " @param screenPosition The x/y position on the screen plus the depth from the screen-plane <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">outwards.\n</a>" " @return The world-space position corresponding <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the given screen-space coordinates." )

IMPLEMENT_CONOBJECT(GuiTSCtrl )

ImplementEnumType(GuiTSRenderStyles , "Style of rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GuiTSCtrl.\n\n</a>" "@ingroup Gui3D" )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "gui/3d/guiTSControl.h"
 26#include "gui/core/guiOffscreenCanvas.h"
 27
 28#include "console/engineAPI.h"
 29#include "scene/sceneManager.h"
 30#include "lighting/lightManager.h"
 31#include "gfx/sim/debugDraw.h"
 32#include "gfx/gfxTransformSaver.h"
 33#include "gfx/screenshot.h"
 34#include "math/mathUtils.h"
 35#include "gui/core/guiCanvas.h"
 36#include "scene/reflectionManager.h"
 37#include "postFx/postEffectManager.h"
 38#include "gfx/gfxTransformSaver.h"
 39#include "gfx/gfxDrawUtil.h"
 40#include "gfx/gfxDebugEvent.h"
 41#include "core/stream/fileStream.h"
 42#include "platform/output/IDisplayDevice.h"
 43#include "T3D/gameBase/extended/extendedMove.h"
 44
 45#define TS_OVERLAY_SCREEN_WIDTH 0.75
 46
 47IMPLEMENT_CONOBJECT( GuiTSCtrl );
 48
 49ConsoleDocClass( GuiTSCtrl,
 50   "@brief Abstract base class for controls that render 3D scenes.\n\n"
 51   
 52   "GuiTSCtrl is the base class for controls that render 3D camera views in Torque.  The class itself "
 53   "does not implement a concrete scene rendering.  Use GuiObjectView to display invidiual shapes in "
 54   "the Gui and GameTSCtrl to render full scenes.\n\n"
 55   
 56   "@see GameTSCtrl\n"
 57   "@see GuiObjectView\n"
 58   "@ingroup Gui3D\n"
 59);
 60
 61U32 GuiTSCtrl::smFrameCount = 0;
 62bool GuiTSCtrl::smUseLatestDisplayTransform = true;
 63Vector<GuiTSCtrl*> GuiTSCtrl::smAwakeTSCtrls;
 64
 65ImplementEnumType( GuiTSRenderStyles,
 66   "Style of rendering for a GuiTSCtrl.\n\n"
 67   "@ingroup Gui3D" )
 68   { GuiTSCtrl::RenderStyleStandard,         "standard"              },
 69   { GuiTSCtrl::RenderStyleStereoSideBySide, "stereo side by side"   },
 70   { GuiTSCtrl::RenderStyleStereoSeparate,   "stereo separate" },
 71EndImplementEnumType;
 72
 73//-----------------------------------------------------------------------------
 74
 75namespace 
 76{
 77   void _drawLine( const Point3F &p0, const Point3F &p1, const ColorI &color, F32 width )
 78   {
 79      F32 x1, x2, y1, y2, z1, z2;
 80
 81      x1 = p0.x;
 82      y1 = p0.y;
 83      z1 = p0.z;
 84      x2 = p1.x;
 85      y2 = p1.y;
 86      z2 = p1.z;
 87
 88      //
 89      // Convert Line   a----------b
 90      //
 91      // Into Quad      v0---------v1
 92      //                 a         b
 93      //                v2---------v3
 94      //
 95
 96      Point2F start(x1, y1);
 97      Point2F end(x2, y2);
 98      Point2F perp, lineVec;
 99
100      // handle degenerate case where point a = b
101      if(x1 == x2 && y1 == y2)
102      {
103         perp.set(0.0f, width * 0.5f);
104         lineVec.set(0.1f, 0.0f);
105      }
106      else
107      {
108         perp.set(start.y - end.y, end.x - start.x);
109         lineVec.set(end.x - start.x, end.y - start.y);
110         perp.normalize(width * 0.5f);
111         lineVec.normalize(0.1f);
112      }
113      start -= lineVec;
114      end   += lineVec;
115
116      GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, 4, GFXBufferTypeVolatile);
117      verts.lock();
118
119      verts[0].point.set( start.x+perp.x, start.y+perp.y, z1 );
120      verts[1].point.set( end.x+perp.x, end.y+perp.y, z2 );
121      verts[2].point.set( start.x-perp.x, start.y-perp.y, z1 );
122      verts[3].point.set( end.x-perp.x, end.y-perp.y, z2 );
123
124      verts[0].color = color;
125      verts[1].color = color;
126      verts[2].color = color;
127      verts[3].color = color;
128
129      verts.unlock();
130      GFX->setVertexBuffer( verts );
131
132      GFXStateBlockDesc desc;
133      desc.setCullMode(GFXCullNone);
134      desc.setZReadWrite(false);
135      desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
136      GFX->setStateBlockByDesc( desc );
137
138      GFX->setupGenericShaders();
139      GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
140   }
141}
142
143//-----------------------------------------------------------------------------
144
145GuiTSCtrl::GuiTSCtrl()
146{
147   mCameraZRot = 0;
148   mForceFOV = 0;
149   mReflectPriority = 1.0f;
150
151   mRenderStyle = RenderStyleStandard;
152
153   mSaveModelview.identity();
154   mSaveProjection.identity();
155   mSaveViewport.set( 0, 0, 10, 10 );
156   mSaveWorldToScreenScale.set( 0, 0 );
157
158   mLastCameraQuery.cameraMatrix.identity();
159   mLastCameraQuery.fov = 45.0f;
160   mLastCameraQuery.object = NULL;
161   mLastCameraQuery.farPlane = 10.0f;
162   mLastCameraQuery.nearPlane = 0.01f;
163
164   mLastCameraQuery.hasFovPort = false;
165   mLastCameraQuery.hasStereoTargets = false;
166
167   mLastCameraQuery.ortho = false;
168}
169
170//-----------------------------------------------------------------------------
171
172void GuiTSCtrl::initPersistFields()
173{
174   addGroup( "Camera" );
175   
176      addField("cameraZRot", TypeF32, Offset(mCameraZRot, GuiTSCtrl),
177         "Z rotation angle of camera." );
178      addField("forceFOV",   TypeF32, Offset(mForceFOV,   GuiTSCtrl),
179         "The vertical field of view in degrees or zero to use the normal camera FOV." );
180         
181   endGroup( "Camera" );
182   
183   addGroup( "Rendering" );
184   
185      addField( "reflectPriority", TypeF32, Offset( mReflectPriority, GuiTSCtrl ),
186         "The share of the per-frame reflection update work this control's rendering should run.\n"
187         "The reflect update priorities of all visible GuiTSCtrls are added together and each control is assigned "
188         "a share of the per-frame reflection update time according to its percentage of the total priority value." );
189
190      addField("renderStyle", TYPEID< RenderStyles >(), Offset(mRenderStyle, GuiTSCtrl),
191         "Indicates how this control should render its contents." );
192
193   endGroup( "Rendering" );
194   
195   Parent::initPersistFields();
196}
197
198//-----------------------------------------------------------------------------
199
200void GuiTSCtrl::consoleInit()
201{
202   Con::addVariable("$TSControl::frameCount", TypeS32, &smFrameCount, "The number of frames that have been rendered since this control was created.\n"
203      "@ingroup Rendering\n");
204   Con::addVariable("$TSControl::useLatestDisplayTransform", TypeBool, &smUseLatestDisplayTransform, "Use the latest view transform when rendering stereo instead of the one calculated by the last move.\n"
205      "@ingroup Rendering\n");
206}
207
208//-----------------------------------------------------------------------------
209
210bool GuiTSCtrl::onWake()
211{
212   if ( !Parent::onWake() )
213      return false;
214
215   // Add ourselves to the active viewport list.
216   AssertFatal( !smAwakeTSCtrls.contains( this ), 
217      "GuiTSCtrl::onWake - This control is already in the awake list!" );
218   smAwakeTSCtrls.push_back( this );
219
220   // For VR
221   mLastCameraQuery.drawCanvas = getRoot();
222
223   return true;
224}
225
226//-----------------------------------------------------------------------------
227
228void GuiTSCtrl::onSleep()
229{
230   Parent::onSleep();
231
232   AssertFatal( smAwakeTSCtrls.contains( this ), 
233      "GuiTSCtrl::onSleep - This control is not in the awake list!" );
234   smAwakeTSCtrls.remove( this );
235}
236
237//-----------------------------------------------------------------------------
238
239void GuiTSCtrl::onPreRender()
240{
241   setUpdate();
242}
243
244//-----------------------------------------------------------------------------
245
246bool GuiTSCtrl::processCameraQuery(CameraQuery *)
247{
248   return false;
249}
250
251//-----------------------------------------------------------------------------
252
253void GuiTSCtrl::renderWorld(const RectI& /*updateRect*/)
254{
255}
256
257//-----------------------------------------------------------------------------
258
259F32 GuiTSCtrl::projectRadius( F32 dist, F32 radius ) const
260{
261   // Fixup any negative or zero distance so we
262   // don't get a divide by zero.
263   dist = dist > 0.0f ? dist : 0.001f;
264   return ( radius / dist ) * mSaveWorldToScreenScale.y;   
265}
266
267//-----------------------------------------------------------------------------
268
269bool GuiTSCtrl::project( const Point3F &pt, Point3F *dest ) const
270{
271   return MathUtils::mProjectWorldToScreen(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection);
272}
273
274//-----------------------------------------------------------------------------
275
276bool GuiTSCtrl::unproject( const Point3F &pt, Point3F *dest ) const
277{
278   MathUtils::mProjectScreenToWorld(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection,mLastCameraQuery.farPlane,mLastCameraQuery.nearPlane);
279   return true;
280}
281
282//-----------------------------------------------------------------------------
283
284F32 GuiTSCtrl::calculateViewDistance(F32 radius)
285{
286   F32 fov = mLastCameraQuery.fov;
287   F32 wwidth;
288   F32 wheight;
289   F32 renderWidth = (mRenderStyle == RenderStyleStereoSideBySide) ? F32(getWidth())*0.5f : F32(getWidth());
290   F32 renderHeight = F32(getHeight());
291   F32 aspectRatio = renderWidth / renderHeight;
292   
293   // Use the FOV to calculate the viewport height scale
294   // then generate the width scale from the aspect ratio.
295   if(!mLastCameraQuery.ortho)
296   {
297      wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);
298      wwidth = aspectRatio * wheight;
299   }
300   else
301   {
302      wheight = mLastCameraQuery.fov;
303      wwidth = aspectRatio * wheight;
304   }
305
306   // Now determine if we should use the width 
307   // fov or height fov.
308   //
309   // If the window is taller than it is wide, use the 
310   // width fov to keep the object completely in view.
311   if (wheight > wwidth)
312      fov = mAtan( wwidth / mLastCameraQuery.nearPlane ) * 2.0f;
313
314   return radius / mTan(fov / 2.0f);
315}
316
317//-----------------------------------------------------------------------------
318
319static FovPort CalculateFovPortForCanvas(const RectI viewport, const CameraQuery &cameraQuery)
320{
321   F32 wwidth;
322   F32 wheight;
323   F32 renderWidth = viewport.extent.x;
324   F32 renderHeight = viewport.extent.y;
325   F32 aspectRatio = renderWidth / renderHeight;
326
327   // Use the FOV to calculate the viewport height scale
328   // then generate the width scale from the aspect ratio.
329   if(!cameraQuery.ortho)
330   {
331      wheight = /*cameraQuery.nearPlane * */ mTan(cameraQuery.fov / 2.0f);
332      wwidth = aspectRatio * wheight;
333   }
334   else
335   {
336      wheight = cameraQuery.fov;
337      wwidth = aspectRatio * wheight;
338   }
339
340   F32 hscale = wwidth * 2.0f / renderWidth;
341   F32 vscale = wheight * 2.0f / renderHeight;
342
343   F32 left = 0.0f * hscale - wwidth;
344   F32 right = renderWidth * hscale - wwidth;
345   F32 top = wheight - vscale * 0.0f;
346   F32 bottom = wheight - vscale * renderHeight;
347
348   FovPort fovPort;
349   fovPort.upTan = top;
350   fovPort.downTan = -bottom;
351   fovPort.leftTan = -left;
352   fovPort.rightTan = right;
353
354   return fovPort;
355}
356
357void GuiTSCtrl::_internalRender(RectI guiViewport, RectI renderViewport, Frustum &frustum)
358{
359   GFXTransformSaver saver;
360   Point2I renderSize = renderViewport.extent;
361   GFXTarget *origTarget = GFX->getActiveRenderTarget();
362   S32 origStereoTarget = GFX->getCurrentStereoTarget();
363
364   if (mForceFOV != 0)
365      mLastCameraQuery.fov = mDegToRad(mForceFOV);
366
367   if (mCameraZRot)
368   {
369      MatrixF rotMat(EulerF(0, 0, mDegToRad(mCameraZRot)));
370      mLastCameraQuery.cameraMatrix.mul(rotMat);
371   }
372
373   if (mReflectPriority > 0)
374   {
375      // Get the total reflection priority.
376      F32 totalPriority = 0;
377      for (U32 i = 0; i < smAwakeTSCtrls.size(); i++)
378         if (smAwakeTSCtrls[i]->isVisible())
379            totalPriority += smAwakeTSCtrls[i]->mReflectPriority;
380
381      REFLECTMGR->update(mReflectPriority / totalPriority,
382         renderSize,
383         mLastCameraQuery);
384   }
385
386   GFX->setActiveRenderTarget(origTarget);
387   GFX->setCurrentStereoTarget(origStereoTarget);
388   GFX->setViewport(renderViewport);
389
390   // Clear the zBuffer so GUI doesn't hose object rendering accidentally
391   GFX->clear(GFXClearZBuffer, ColorI(20, 20, 20), 1.0f, 0);
392
393   GFX->setFrustum(frustum);
394   mSaveProjection = GFX->getProjectionMatrix();
395
396   if (mLastCameraQuery.ortho)
397   {
398      mOrthoWidth = frustum.getWidth();
399      mOrthoHeight = frustum.getHeight();
400   }
401
402   // We're going to be displaying this render at size of this control in
403   // pixels - let the scene know so that it can calculate e.g. reflections
404   // correctly for that final display result.
405   gClientSceneGraph->setDisplayTargetResolution(renderSize);
406
407   // Set the GFX world matrix to the world-to-camera transform, but don't 
408   // change the cameraMatrix in mLastCameraQuery. This is because 
409   // mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world
410   // transform. In-place invert would save a copy but mess up any GUIs that
411   // depend on that value.
412   MatrixF worldToCamera = mLastCameraQuery.cameraMatrix;
413   worldToCamera.inverse();
414   GFX->setWorldMatrix(worldToCamera);
415
416   mSaveProjection = GFX->getProjectionMatrix();
417   mSaveModelview = GFX->getWorldMatrix();
418   mSaveViewport = guiViewport;
419   mSaveWorldToScreenScale = GFX->getWorldToScreenScale();
420   mSaveFrustum = GFX->getFrustum();
421   mSaveFrustum.setTransform(mLastCameraQuery.cameraMatrix);
422
423   // Set the default non-clip projection as some 
424   // objects depend on this even in non-reflect cases.
425   gClientSceneGraph->setNonClipProjection(mSaveProjection);
426
427   // Give the post effect manager the worldToCamera, and cameraToScreen matrices
428   PFXMGR->setFrameMatrices(mSaveModelview, mSaveProjection);
429
430   renderWorld(guiViewport);
431
432   DebugDrawer* debugDraw = DebugDrawer::get();
433   if (mRenderStyle == RenderStyleStereoSideBySide && debugDraw->willDraw())
434   {
435      // For SBS we need to render over each viewport
436      Frustum frustum;
437
438      GFX->setViewport(mLastCameraQuery.stereoViewports[0]);
439      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);
440      GFX->setFrustum(frustum);
441      debugDraw->render(false);
442
443      GFX->setViewport(mLastCameraQuery.stereoViewports[1]);
444      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[1]);
445      GFX->setFrustum(frustum);
446      debugDraw->render();
447   }
448   else
449   {
450      debugDraw->render();
451   }
452
453   saver.restore();
454}
455
456//-----------------------------------------------------------------------------
457
458void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
459{
460   // Save the current transforms so we can restore
461   // it for child control rendering below.
462   GFXTransformSaver saver;
463   bool renderingToTarget = false;
464
465   mLastCameraQuery.displayDevice = NULL;
466
467   if (!processCameraQuery(&mLastCameraQuery))
468   {
469      // We have no camera, but render the GUI children 
470      // anyway.  This makes editing GuiTSCtrl derived
471      // controls easier in the GuiEditor.
472      renderChildControls(offset, updateRect);
473      return;
474   }
475
476   // 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
477   if (mLastCameraQuery.displayDevice)
478   {
479      if (mRenderStyle == RenderStyleStereoSideBySide)
480      {
481         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_StereoSideBySide);
482      }
483      else if (mRenderStyle == RenderStyleStereoSeparate)
484      {
485         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_StereoSeparate);
486      }
487      else
488      {
489         mLastCameraQuery.displayDevice->setDrawMode(GFXDevice::RS_Standard);
490      }
491
492      // The connection's display device may want to set the eye offset
493      if (mLastCameraQuery.displayDevice->providesEyeOffsets())
494      {
495         mLastCameraQuery.displayDevice->getEyeOffsets(mLastCameraQuery.eyeOffset);
496      }
497
498      // Grab field of view for both eyes
499      if (mLastCameraQuery.displayDevice->providesFovPorts())
500      {
501         mLastCameraQuery.displayDevice->getFovPorts(mLastCameraQuery.fovPort);
502         mLastCameraQuery.hasFovPort = true;
503      }
504
505      mLastCameraQuery.displayDevice->getStereoViewports(mLastCameraQuery.stereoViewports);
506      mLastCameraQuery.displayDevice->getStereoTargets(mLastCameraQuery.stereoTargets);
507
508      mLastCameraQuery.hasStereoTargets = mLastCameraQuery.stereoTargets[0];
509   }
510
511   GFXTargetRef origTarget = GFX->getActiveRenderTarget();
512   U32 origStyle = GFX->getCurrentRenderStyle();
513
514   // Set up the appropriate render style
515   Point2I renderSize = getExtent();
516   Frustum frustum;
517
518   mLastCameraQuery.currentEye = -1;
519
520   if (mRenderStyle == RenderStyleStereoSideBySide)
521   {
522      GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide);
523      GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);
524      GFX->setStereoHeadTransform(mLastCameraQuery.headMatrix);
525
526      if (!mLastCameraQuery.hasStereoTargets)
527      {
528         // Need to calculate our current viewport here
529         mLastCameraQuery.stereoViewports[0] = updateRect;
530         mLastCameraQuery.stereoViewports[0].extent.x /= 2;
531         mLastCameraQuery.stereoViewports[1] = mLastCameraQuery.stereoViewports[0];
532         mLastCameraQuery.stereoViewports[1].point.x += mLastCameraQuery.stereoViewports[1].extent.x;
533      }
534
535      if (!mLastCameraQuery.hasFovPort)
536      {
537         // Need to make our own fovPort
538         mLastCameraQuery.fovPort[0] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[0], mLastCameraQuery);
539         mLastCameraQuery.fovPort[1] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[1], mLastCameraQuery);
540      }
541
542      GFX->setStereoFovPort(mLastCameraQuery.fovPort); // NOTE: this specifies fov for BOTH eyes
543      GFX->setSteroViewports(mLastCameraQuery.stereoViewports);
544      GFX->setStereoTargets(mLastCameraQuery.stereoTargets);
545
546      MatrixF myTransforms[2];
547      Frustum frustum;
548
549      if (smUseLatestDisplayTransform)
550      {
551         // Use the view matrix determined from the display device
552         myTransforms[0] = mLastCameraQuery.eyeTransforms[0];
553         myTransforms[1] = mLastCameraQuery.eyeTransforms[1];
554      }
555      else
556      {
557         // Use the view matrix determined from the control object
558         myTransforms[0] = mLastCameraQuery.cameraMatrix;
559         myTransforms[1] = mLastCameraQuery.cameraMatrix;
560         mLastCameraQuery.headMatrix = mLastCameraQuery.cameraMatrix; // override head
561
562         QuatF qrot = mLastCameraQuery.cameraMatrix;
563         Point3F pos = mLastCameraQuery.cameraMatrix.getPosition();
564         Point3F rotEyePos;
565
566         myTransforms[0].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[0], &rotEyePos));
567         myTransforms[1].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[1], &rotEyePos));
568      }
569
570      GFX->setStereoEyeTransforms(myTransforms);
571
572      // Allow render size to originate from the render target
573      if (mLastCameraQuery.stereoTargets[0])
574      {
575         renderSize = mLastCameraQuery.stereoTargets[0]->getSize();
576         renderingToTarget = true;
577      }
578
579      // NOTE: these calculations are essentially overridden later by the fov port settings when rendering each eye.
580      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);
581
582      GFX->activateStereoTarget(-1);
583      _internalRender(RectI(updateRect.point, updateRect.extent), RectI(Point2I(0,0), renderSize), frustum);
584     
585      // Notify device we've rendered the right, thus the last stereo frame.
586      GFX->getDeviceEventSignal().trigger(GFXDevice::deRightStereoFrameRendered);
587
588      // Render preview
589      if (mLastCameraQuery.displayDevice)
590      {
591         GFXTexHandle previewTexture = mLastCameraQuery.displayDevice->getPreviewTexture();
592         if (!previewTexture.isNull())
593         {
594            GFX->setActiveRenderTarget(origTarget);
595            GFX->setCurrentRenderStyle(origStyle);
596            GFX->setClipRect(updateRect);
597            renderDisplayPreview(updateRect, previewTexture);
598         }
599      }
600   }
601   else if (mRenderStyle == RenderStyleStereoSeparate && mLastCameraQuery.displayDevice)
602   {
603      // In this case we render the scene twice to different render targets, then
604      // render the final composite view 
605      GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSeparate);
606      GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);
607      GFX->setStereoHeadTransform(mLastCameraQuery.headMatrix);
608      GFX->setStereoFovPort(mLastCameraQuery.fovPort); // NOTE: this specifies fov for BOTH eyes
609      GFX->setSteroViewports(mLastCameraQuery.stereoViewports);
610      GFX->setStereoTargets(mLastCameraQuery.stereoTargets);
611
612      MatrixF myTransforms[2];
613
614      if (smUseLatestDisplayTransform)
615      {
616         // Use the view matrix determined from the display device
617         myTransforms[0] = mLastCameraQuery.eyeTransforms[0];
618         myTransforms[1] = mLastCameraQuery.eyeTransforms[1];
619      }
620      else
621      {
622         // Use the view matrix determined from the control object
623         myTransforms[0] = mLastCameraQuery.cameraMatrix;
624         myTransforms[1] = mLastCameraQuery.cameraMatrix;
625
626         QuatF qrot = mLastCameraQuery.cameraMatrix;
627         Point3F pos = mLastCameraQuery.cameraMatrix.getPosition();
628         Point3F rotEyePos;
629
630         myTransforms[0].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[0], &rotEyePos));
631         myTransforms[1].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[1], &rotEyePos));
632      }
633
634      MatrixF origMatrix = mLastCameraQuery.cameraMatrix;
635
636      // Left
637      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);
638      mLastCameraQuery.cameraMatrix = myTransforms[0];
639      frustum.update();
640     GFX->activateStereoTarget(0);
641     mLastCameraQuery.currentEye = 0;
642     GFX->beginField();
643     _internalRender(RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), frustum);
644      GFX->getDeviceEventSignal().trigger(GFXDevice::deLeftStereoFrameRendered);
645     GFX->endField();
646
647      // Right
648     GFX->activateStereoTarget(1);
649     mLastCameraQuery.currentEye = 1;
650      MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[1]);
651      mLastCameraQuery.cameraMatrix = myTransforms[1];
652     frustum.update();
653     GFX->beginField();
654     _internalRender(RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[1]->getSize()), RectI(Point2I(0, 0), mLastCameraQuery.stereoTargets[0]->getSize()), frustum);
655     GFX->getDeviceEventSignal().trigger(GFXDevice::deRightStereoFrameRendered);
656     GFX->endField();
657
658      mLastCameraQuery.cameraMatrix = origMatrix;
659
660      // Render preview
661      if (mLastCameraQuery.displayDevice)
662      {
663         GFXTexHandle previewTexture = mLastCameraQuery.displayDevice->getPreviewTexture();
664         if (!previewTexture.isNull())
665         {
666            GFX->setActiveRenderTarget(origTarget);
667            GFX->setCurrentRenderStyle(origStyle);
668            GFX->setClipRect(updateRect);
669            renderDisplayPreview(updateRect, previewTexture);
670         }
671      }
672   }
673   else
674   {
675      // set up the camera and viewport stuff:
676      F32 wwidth;
677      F32 wheight;
678      F32 renderWidth = F32(renderSize.x);
679      F32 renderHeight = F32(renderSize.y);
680      F32 aspectRatio = renderWidth / renderHeight;
681
682      // Use the FOV to calculate the viewport height scale
683      // then generate the width scale from the aspect ratio.
684      if (!mLastCameraQuery.ortho)
685      {
686         wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);
687         wwidth = aspectRatio * wheight;
688      }
689      else
690      {
691         wheight = mLastCameraQuery.fov;
692         wwidth = aspectRatio * wheight;
693      }
694
695      F32 hscale = wwidth * 2.0f / renderWidth;
696      F32 vscale = wheight * 2.0f / renderHeight;
697
698      F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
699      F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
700      F32 top = wheight - vscale * (updateRect.point.y - offset.y);
701      F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);
702
703      frustum.set(mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane);
704
705      // Manipulate the frustum for tiled screenshots
706      const bool screenShotMode = gScreenShot && gScreenShot->isPending();
707      if (screenShotMode)
708      {
709         gScreenShot->tileFrustum(frustum);
710         GFX->setViewMatrix(MatrixF::Identity);
711      }
712
713      RectI tempRect = updateRect;
714      _internalRender(tempRect, tempRect, frustum);
715   }
716
717   // TODO: Some render to sort of overlay system?
718
719   // Allow subclasses to render 2D elements.
720   GFX->setActiveRenderTarget(origTarget);
721   GFX->setCurrentRenderStyle(origStyle);
722   GFX->setClipRect(updateRect);
723   renderGui(offset, updateRect);
724
725   if (shouldRenderChildControls())
726   {
727      renderChildControls(offset, updateRect);
728   }
729   smFrameCount++;
730}
731
732//-----------------------------------------------------------------------------
733
734void GuiTSCtrl::drawLine( Point3F p0, Point3F p1, const ColorI &color, F32 width )
735{   
736   if ( !mSaveFrustum.clipSegment( p0, p1 ) )
737      return;
738
739   MathUtils::mProjectWorldToScreen( p0, &p0, mSaveViewport, mSaveModelview, mSaveProjection );   
740   MathUtils::mProjectWorldToScreen( p1, &p1, mSaveViewport, mSaveModelview, mSaveProjection );   
741
742   p0.x = mClampF( p0.x, 0.0f, mSaveViewport.extent.x );
743   p0.y = mClampF( p0.y, 0.0f, mSaveViewport.extent.y );
744   p1.x = mClampF( p1.x, 0.0f, mSaveViewport.extent.x );
745   p1.y = mClampF( p1.y, 0.0f, mSaveViewport.extent.y );
746   p0.z = p1.z = 0.0f;
747
748   _drawLine( p0, p1, color, width );
749}
750
751//-----------------------------------------------------------------------------
752
753void GuiTSCtrl::drawLineList( const Vector<Point3F> &points, const ColorI color, F32 width )
754{
755   for ( S32 i = 0; i < points.size() - 1; i++ )
756      drawLine( points[i], points[i+1], color, width );
757}
758
759//-----------------------------------------------------------------------------
760
761void GuiTSCtrl::setStereoGui(GuiOffscreenCanvas *canvas)
762{
763   mStereoGuiTarget = canvas ? canvas->getTarget() : NULL;
764   mStereoCanvas = canvas;
765}
766
767
768//-----------------------------------------------------------------------------
769
770void GuiTSCtrl::renderDisplayPreview(const RectI &updateRect, GFXTexHandle &previewTexture)
771{
772   GFX->setWorldMatrix(MatrixF(1));
773   GFX->setViewMatrix(MatrixF::Identity);
774   GFX->setClipRect(updateRect);
775
776   GFX->getDrawUtil()->drawRectFill(RectI(Point2I(0, 0), Point2I(1024, 768)), ColorI::BLACK);
777   GFX->getDrawUtil()->drawRect(RectI(Point2I(0, 0), Point2I(1024, 768)), ColorI::RED);
778
779   if (!mStereoPreviewVB.getPointer())
780   {
781      mStereoPreviewVB.set(GFX, 4, GFXBufferTypeStatic);
782      GFXVertexPCT *verts = mStereoPreviewVB.lock(0, 4);
783
784      F32 texLeft = 0.0f;
785      F32 texRight = 1.0f;
786      F32 texTop = 0.0f;
787      F32 texBottom = 1.0f;
788
789      F32 rectWidth = updateRect.extent.x;
790      F32 rectHeight = updateRect.extent.y;
791
792      F32 screenLeft = 0;
793      F32 screenRight = rectWidth;
794      F32 screenTop = 0;
795      F32 screenBottom = rectHeight;
796
797      const F32 fillConv = 0.0f;
798      verts[0].point.set(screenLeft - fillConv, screenTop - fillConv, 0.f);
799      verts[1].point.set(screenRight - fillConv, screenTop - fillConv, 0.f);
800      verts[2].point.set(screenLeft - fillConv, screenBottom - fillConv, 0.f);
801      verts[3].point.set(screenRight - fillConv, screenBottom - fillConv, 0.f);
802
803      verts[0].color = verts[1].color = verts[2].color = verts[3].color = ColorI(255, 255, 255, 255);
804
805      verts[0].texCoord.set(texLeft, texTop);
806      verts[1].texCoord.set(texRight, texTop);
807      verts[2].texCoord.set(texLeft, texBottom);
808      verts[3].texCoord.set(texRight, texBottom);
809
810      mStereoPreviewVB.unlock();
811   }
812
813   if (!mStereoPreviewSB.getPointer())
814   {
815      // DrawBitmapStretchSR
816      GFXStateBlockDesc bitmapStretchSR;
817      bitmapStretchSR.setCullMode(GFXCullNone);
818      bitmapStretchSR.setZReadWrite(false, false);
819      bitmapStretchSR.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
820      bitmapStretchSR.samplersDefined = true;
821
822      bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
823      bitmapStretchSR.samplers[0].minFilter = GFXTextureFilterPoint;
824      bitmapStretchSR.samplers[0].mipFilter = GFXTextureFilterPoint;
825      bitmapStretchSR.samplers[0].magFilter = GFXTextureFilterPoint;
826
827      mStereoPreviewSB = GFX->createStateBlock(bitmapStretchSR);
828   }
829
830   GFX->setVertexBuffer(mStereoPreviewVB);
831   GFX->setStateBlock(mStereoPreviewSB);
832   GFX->setTexture(0, previewTexture);
833   GFX->setupGenericShaders(GFXDevice::GSModColorTexture);
834   GFX->drawPrimitive(GFXTriangleStrip, 0, 2);
835}
836
837//=============================================================================
838//    Console Methods.
839//=============================================================================
840// MARK: ---- Console Methods ----
841
842//-----------------------------------------------------------------------------
843
844DefineEngineMethod( GuiTSCtrl, unproject, Point3F, ( Point3F screenPosition ),,
845   "Transform 3D screen-space coordinates (x, y, depth) to world space.\n"
846   "This method can be, for example, used to find the world-space position relating to the current mouse cursor position.\n"
847   "@param screenPosition The x/y position on the screen plus the depth from the screen-plane outwards.\n"
848   "@return The world-space position corresponding to the given screen-space coordinates." )
849{
850   Point3F worldPos;
851   object->unproject( screenPosition, &worldPos );
852   return worldPos;
853}
854
855//-----------------------------------------------------------------------------
856
857DefineEngineMethod( GuiTSCtrl, project, Point3F, ( Point3F worldPosition ),,
858   "Transform world-space coordinates to screen-space (x, y, depth) coordinates.\n"
859   "@param worldPosition The world-space position to transform to screen-space.\n"
860   "@return The " )
861{
862   Point3F screenPos;
863   object->project( worldPosition, &screenPos );
864   return screenPos;
865}
866
867//-----------------------------------------------------------------------------
868
869DefineEngineMethod( GuiTSCtrl, getWorldToScreenScale, Point2F, (),,
870   "Get the ratio between world-space units and pixels.\n"
871   "@return The amount of world-space units covered by the extent of a single pixel." )
872{
873   return object->getWorldToScreenScale();
874}
875
876//-----------------------------------------------------------------------------
877
878DefineEngineMethod( GuiTSCtrl, calculateViewDistance, F32, ( F32 radius ),,
879   "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"
880   "@param radius Radius in world-space units which should fit in the view.\n"
881   "@return The distance from the viewpoint at which the given radius would be fully visible." )
882{
883   return object->calculateViewDistance( radius );
884}
885
886DefineEngineMethod( GuiTSCtrl, setStereoGui, void, ( GuiOffscreenCanvas* canvas ),,
887   "Sets the current stereo texture to an offscreen canvas\n"
888   "@param canvas The desired canvas." )
889{
890   object->setStereoGui(canvas);
891}
892