guiTSControl.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gui/3d/guiTSControl.h"
  24. #include "gui/core/guiOffscreenCanvas.h"
  25. #include "console/engineAPI.h"
  26. #include "scene/sceneManager.h"
  27. #include "lighting/lightManager.h"
  28. #include "gfx/sim/debugDraw.h"
  29. #include "gfx/gfxTransformSaver.h"
  30. #include "gfx/screenshot.h"
  31. #include "math/mathUtils.h"
  32. #include "gui/core/guiCanvas.h"
  33. #include "scene/reflectionManager.h"
  34. #include "postFx/postEffectManager.h"
  35. #include "gfx/gfxTransformSaver.h"
  36. #include "gfx/gfxDrawUtil.h"
  37. #include "gfx/gfxDebugEvent.h"
  38. GFXTextureObject *gLastStereoTexture = NULL;
  39. #define TS_OVERLAY_SCREEN_WIDTH 0.75
  40. IMPLEMENT_CONOBJECT( GuiTSCtrl );
  41. ConsoleDocClass( GuiTSCtrl,
  42. "@brief Abstract base class for controls that render 3D scenes.\n\n"
  43. "GuiTSCtrl is the base class for controls that render 3D camera views in Torque. The class itself "
  44. "does not implement a concrete scene rendering. Use GuiObjectView to display invidiual shapes in "
  45. "the Gui and GameTSCtrl to render full scenes.\n\n"
  46. "@see GameTSCtrl\n"
  47. "@see GuiObjectView\n"
  48. "@ingroup Gui3D\n"
  49. );
  50. U32 GuiTSCtrl::smFrameCount = 0;
  51. bool GuiTSCtrl::smUseLatestDisplayTransform = true;
  52. Vector<GuiTSCtrl*> GuiTSCtrl::smAwakeTSCtrls;
  53. ImplementEnumType( GuiTSRenderStyles,
  54. "Style of rendering for a GuiTSCtrl.\n\n"
  55. "@ingroup Gui3D" )
  56. { GuiTSCtrl::RenderStyleStandard, "standard" },
  57. { GuiTSCtrl::RenderStyleStereoSideBySide, "stereo side by side" },
  58. EndImplementEnumType;
  59. //-----------------------------------------------------------------------------
  60. namespace
  61. {
  62. void _drawLine( const Point3F &p0, const Point3F &p1, const ColorI &color, F32 width )
  63. {
  64. F32 x1, x2, y1, y2, z1, z2;
  65. x1 = p0.x;
  66. y1 = p0.y;
  67. z1 = p0.z;
  68. x2 = p1.x;
  69. y2 = p1.y;
  70. z2 = p1.z;
  71. //
  72. // Convert Line a----------b
  73. //
  74. // Into Quad v0---------v1
  75. // a b
  76. // v2---------v3
  77. //
  78. Point2F start(x1, y1);
  79. Point2F end(x2, y2);
  80. Point2F perp, lineVec;
  81. // handle degenerate case where point a = b
  82. if(x1 == x2 && y1 == y2)
  83. {
  84. perp.set(0.0f, width * 0.5f);
  85. lineVec.set(0.1f, 0.0f);
  86. }
  87. else
  88. {
  89. perp.set(start.y - end.y, end.x - start.x);
  90. lineVec.set(end.x - start.x, end.y - start.y);
  91. perp.normalize(width * 0.5f);
  92. lineVec.normalize(0.1f);
  93. }
  94. start -= lineVec;
  95. end += lineVec;
  96. GFXVertexBufferHandle<GFXVertexPC> verts(GFX, 4, GFXBufferTypeVolatile);
  97. verts.lock();
  98. verts[0].point.set( start.x+perp.x, start.y+perp.y, z1 );
  99. verts[1].point.set( end.x+perp.x, end.y+perp.y, z2 );
  100. verts[2].point.set( start.x-perp.x, start.y-perp.y, z1 );
  101. verts[3].point.set( end.x-perp.x, end.y-perp.y, z2 );
  102. verts[0].color = color;
  103. verts[1].color = color;
  104. verts[2].color = color;
  105. verts[3].color = color;
  106. verts.unlock();
  107. GFX->setVertexBuffer( verts );
  108. GFXStateBlockDesc desc;
  109. desc.setCullMode(GFXCullNone);
  110. desc.setZReadWrite(false);
  111. desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  112. GFX->setStateBlockByDesc( desc );
  113. GFX->setupGenericShaders();
  114. GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
  115. }
  116. }
  117. //-----------------------------------------------------------------------------
  118. GuiTSCtrl::GuiTSCtrl()
  119. {
  120. mCameraZRot = 0;
  121. mForceFOV = 0;
  122. mReflectPriority = 1.0f;
  123. mRenderStyle = RenderStyleStandard;
  124. mSaveModelview.identity();
  125. mSaveProjection.identity();
  126. mSaveViewport.set( 0, 0, 10, 10 );
  127. mSaveWorldToScreenScale.set( 0, 0 );
  128. mLastCameraQuery.cameraMatrix.identity();
  129. mLastCameraQuery.fov = 45.0f;
  130. mLastCameraQuery.object = NULL;
  131. mLastCameraQuery.farPlane = 10.0f;
  132. mLastCameraQuery.nearPlane = 0.01f;
  133. mLastCameraQuery.projectionOffset = Point2F::Zero;
  134. mLastCameraQuery.hasFovPort = false;
  135. mLastCameraQuery.hasStereoTargets = false;
  136. mLastCameraQuery.ortho = false;
  137. }
  138. //-----------------------------------------------------------------------------
  139. void GuiTSCtrl::initPersistFields()
  140. {
  141. addGroup( "Camera" );
  142. addField("cameraZRot", TypeF32, Offset(mCameraZRot, GuiTSCtrl),
  143. "Z rotation angle of camera." );
  144. addField("forceFOV", TypeF32, Offset(mForceFOV, GuiTSCtrl),
  145. "The vertical field of view in degrees or zero to use the normal camera FOV." );
  146. endGroup( "Camera" );
  147. addGroup( "Rendering" );
  148. addField( "reflectPriority", TypeF32, Offset( mReflectPriority, GuiTSCtrl ),
  149. "The share of the per-frame reflection update work this control's rendering should run.\n"
  150. "The reflect update priorities of all visible GuiTSCtrls are added together and each control is assigned "
  151. "a share of the per-frame reflection update time according to its percentage of the total priority value." );
  152. addField("renderStyle", TYPEID< RenderStyles >(), Offset(mRenderStyle, GuiTSCtrl),
  153. "Indicates how this control should render its contents." );
  154. endGroup( "Rendering" );
  155. Parent::initPersistFields();
  156. }
  157. //-----------------------------------------------------------------------------
  158. void GuiTSCtrl::consoleInit()
  159. {
  160. Con::addVariable("$TSControl::frameCount", TypeS32, &smFrameCount, "The number of frames that have been rendered since this control was created.\n"
  161. "@ingroup Rendering\n");
  162. Con::addVariable("$TSControl::useLatestDisplayTransform", TypeBool, &smUseLatestDisplayTransform, "Use the latest view transform when rendering stereo instead of the one calculated by the last move.\n"
  163. "@ingroup Rendering\n");
  164. }
  165. //-----------------------------------------------------------------------------
  166. bool GuiTSCtrl::onWake()
  167. {
  168. if ( !Parent::onWake() )
  169. return false;
  170. // Add ourselves to the active viewport list.
  171. AssertFatal( !smAwakeTSCtrls.contains( this ),
  172. "GuiTSCtrl::onWake - This control is already in the awake list!" );
  173. smAwakeTSCtrls.push_back( this );
  174. // For VR
  175. mLastCameraQuery.drawCanvas = getRoot();
  176. return true;
  177. }
  178. //-----------------------------------------------------------------------------
  179. void GuiTSCtrl::onSleep()
  180. {
  181. Parent::onSleep();
  182. AssertFatal( smAwakeTSCtrls.contains( this ),
  183. "GuiTSCtrl::onSleep - This control is not in the awake list!" );
  184. smAwakeTSCtrls.remove( this );
  185. }
  186. //-----------------------------------------------------------------------------
  187. void GuiTSCtrl::onPreRender()
  188. {
  189. setUpdate();
  190. }
  191. //-----------------------------------------------------------------------------
  192. bool GuiTSCtrl::processCameraQuery(CameraQuery *)
  193. {
  194. return false;
  195. }
  196. //-----------------------------------------------------------------------------
  197. void GuiTSCtrl::renderWorld(const RectI& /*updateRect*/)
  198. {
  199. }
  200. //-----------------------------------------------------------------------------
  201. F32 GuiTSCtrl::projectRadius( F32 dist, F32 radius ) const
  202. {
  203. // Fixup any negative or zero distance so we
  204. // don't get a divide by zero.
  205. dist = dist > 0.0f ? dist : 0.001f;
  206. return ( radius / dist ) * mSaveWorldToScreenScale.y;
  207. }
  208. //-----------------------------------------------------------------------------
  209. bool GuiTSCtrl::project( const Point3F &pt, Point3F *dest ) const
  210. {
  211. return MathUtils::mProjectWorldToScreen(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection);
  212. }
  213. //-----------------------------------------------------------------------------
  214. bool GuiTSCtrl::unproject( const Point3F &pt, Point3F *dest ) const
  215. {
  216. MathUtils::mProjectScreenToWorld(pt,dest,mSaveViewport,mSaveModelview,mSaveProjection,mLastCameraQuery.farPlane,mLastCameraQuery.nearPlane);
  217. return true;
  218. }
  219. //-----------------------------------------------------------------------------
  220. F32 GuiTSCtrl::calculateViewDistance(F32 radius)
  221. {
  222. F32 fov = mLastCameraQuery.fov;
  223. F32 wwidth;
  224. F32 wheight;
  225. F32 renderWidth = (mRenderStyle == RenderStyleStereoSideBySide) ? F32(getWidth())*0.5f : F32(getWidth());
  226. F32 renderHeight = F32(getHeight());
  227. F32 aspectRatio = renderWidth / renderHeight;
  228. // Use the FOV to calculate the viewport height scale
  229. // then generate the width scale from the aspect ratio.
  230. if(!mLastCameraQuery.ortho)
  231. {
  232. wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);
  233. wwidth = aspectRatio * wheight;
  234. }
  235. else
  236. {
  237. wheight = mLastCameraQuery.fov;
  238. wwidth = aspectRatio * wheight;
  239. }
  240. // Now determine if we should use the width
  241. // fov or height fov.
  242. //
  243. // If the window is taller than it is wide, use the
  244. // width fov to keep the object completely in view.
  245. if (wheight > wwidth)
  246. fov = mAtan( wwidth / mLastCameraQuery.nearPlane ) * 2.0f;
  247. return radius / mTan(fov / 2.0f);
  248. }
  249. //-----------------------------------------------------------------------------
  250. static FovPort CalculateFovPortForCanvas(const RectI viewport, const CameraQuery &cameraQuery)
  251. {
  252. F32 wwidth;
  253. F32 wheight;
  254. F32 renderWidth = viewport.extent.x;
  255. F32 renderHeight = viewport.extent.y;
  256. F32 aspectRatio = renderWidth / renderHeight;
  257. // Use the FOV to calculate the viewport height scale
  258. // then generate the width scale from the aspect ratio.
  259. if(!cameraQuery.ortho)
  260. {
  261. wheight = /*cameraQuery.nearPlane * */ mTan(cameraQuery.fov / 2.0f);
  262. wwidth = aspectRatio * wheight;
  263. }
  264. else
  265. {
  266. wheight = cameraQuery.fov;
  267. wwidth = aspectRatio * wheight;
  268. }
  269. F32 hscale = wwidth * 2.0f / renderWidth;
  270. F32 vscale = wheight * 2.0f / renderHeight;
  271. F32 left = 0.0f * hscale - wwidth;
  272. F32 right = renderWidth * hscale - wwidth;
  273. F32 top = wheight - vscale * 0.0f;
  274. F32 bottom = wheight - vscale * renderHeight;
  275. FovPort fovPort;
  276. fovPort.upTan = top;
  277. fovPort.downTan = -bottom;
  278. fovPort.leftTan = -left;
  279. fovPort.rightTan = right;
  280. return fovPort;
  281. }
  282. //-----------------------------------------------------------------------------
  283. void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
  284. {
  285. // Save the current transforms so we can restore
  286. // it for child control rendering below.
  287. GFXTransformSaver saver;
  288. bool renderingToTarget = false;
  289. if(!processCameraQuery(&mLastCameraQuery))
  290. {
  291. // We have no camera, but render the GUI children
  292. // anyway. This makes editing GuiTSCtrl derived
  293. // controls easier in the GuiEditor.
  294. renderChildControls( offset, updateRect );
  295. return;
  296. }
  297. GFXTargetRef origTarget = GFX->getActiveRenderTarget();
  298. // Set up the appropriate render style
  299. U32 prevRenderStyle = GFX->getCurrentRenderStyle();
  300. Point2F prevProjectionOffset = GFX->getCurrentProjectionOffset();
  301. Point2I renderSize = getExtent();
  302. if(mRenderStyle == RenderStyleStereoSideBySide)
  303. {
  304. GFX->setCurrentRenderStyle(GFXDevice::RS_StereoSideBySide);
  305. GFX->setCurrentProjectionOffset(mLastCameraQuery.projectionOffset);
  306. GFX->setStereoEyeOffsets(mLastCameraQuery.eyeOffset);
  307. if (!mLastCameraQuery.hasStereoTargets)
  308. {
  309. // Need to calculate our current viewport here
  310. mLastCameraQuery.stereoViewports[0] = updateRect;
  311. mLastCameraQuery.stereoViewports[0].extent.x /= 2;
  312. mLastCameraQuery.stereoViewports[1] = mLastCameraQuery.stereoViewports[0];
  313. mLastCameraQuery.stereoViewports[1].point.x += mLastCameraQuery.stereoViewports[1].extent.x;
  314. }
  315. if (!mLastCameraQuery.hasFovPort)
  316. {
  317. // Need to make our own fovPort
  318. mLastCameraQuery.fovPort[0] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[0], mLastCameraQuery);
  319. mLastCameraQuery.fovPort[1] = CalculateFovPortForCanvas(mLastCameraQuery.stereoViewports[1], mLastCameraQuery);
  320. }
  321. GFX->setStereoFovPort(mLastCameraQuery.fovPort); // NOTE: this specifies fov for BOTH eyes
  322. GFX->setSteroViewports(mLastCameraQuery.stereoViewports);
  323. GFX->setStereoTargets(mLastCameraQuery.stereoTargets);
  324. MatrixF myTransforms[2];
  325. if (smUseLatestDisplayTransform)
  326. {
  327. // Use the view matrix determined from the display device
  328. myTransforms[0] = mLastCameraQuery.eyeTransforms[0];
  329. myTransforms[1] = mLastCameraQuery.eyeTransforms[1];
  330. }
  331. else
  332. {
  333. // Use the view matrix determined from the control object
  334. myTransforms[0] = mLastCameraQuery.cameraMatrix;
  335. myTransforms[1] = mLastCameraQuery.cameraMatrix;
  336. QuatF qrot = mLastCameraQuery.cameraMatrix;
  337. Point3F pos = mLastCameraQuery.cameraMatrix.getPosition();
  338. Point3F rotEyePos;
  339. myTransforms[0].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[0], &rotEyePos));
  340. myTransforms[1].setPosition(pos + qrot.mulP(mLastCameraQuery.eyeOffset[1], &rotEyePos));
  341. }
  342. GFX->setStereoEyeTransforms(myTransforms);
  343. // Allow render size to originate from the render target
  344. if (mLastCameraQuery.stereoTargets[0])
  345. {
  346. renderSize = mLastCameraQuery.stereoViewports[0].extent;
  347. renderingToTarget = true;
  348. }
  349. }
  350. else
  351. {
  352. GFX->setCurrentRenderStyle(GFXDevice::RS_Standard);
  353. }
  354. if ( mReflectPriority > 0 )
  355. {
  356. // Get the total reflection priority.
  357. F32 totalPriority = 0;
  358. for ( U32 i=0; i < smAwakeTSCtrls.size(); i++ )
  359. if ( smAwakeTSCtrls[i]->isVisible() )
  360. totalPriority += smAwakeTSCtrls[i]->mReflectPriority;
  361. REFLECTMGR->update( mReflectPriority / totalPriority,
  362. getExtent(),
  363. mLastCameraQuery );
  364. }
  365. if(mForceFOV != 0)
  366. mLastCameraQuery.fov = mDegToRad(mForceFOV);
  367. if(mCameraZRot)
  368. {
  369. MatrixF rotMat(EulerF(0, 0, mDegToRad(mCameraZRot)));
  370. mLastCameraQuery.cameraMatrix.mul(rotMat);
  371. }
  372. Frustum frustum;
  373. if(mRenderStyle == RenderStyleStereoSideBySide)
  374. {
  375. // NOTE: these calculations are essentially overridden later by the fov port settings when rendering each eye.
  376. MathUtils::makeFovPortFrustum(&frustum, mLastCameraQuery.ortho, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane, mLastCameraQuery.fovPort[0]);
  377. }
  378. else
  379. {
  380. // set up the camera and viewport stuff:
  381. F32 wwidth;
  382. F32 wheight;
  383. F32 renderWidth = F32(renderSize.x);
  384. F32 renderHeight = F32(renderSize.y);
  385. F32 aspectRatio = renderWidth / renderHeight;
  386. // Use the FOV to calculate the viewport height scale
  387. // then generate the width scale from the aspect ratio.
  388. if(!mLastCameraQuery.ortho)
  389. {
  390. wheight = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2.0f);
  391. wwidth = aspectRatio * wheight;
  392. }
  393. else
  394. {
  395. wheight = mLastCameraQuery.fov;
  396. wwidth = aspectRatio * wheight;
  397. }
  398. F32 hscale = wwidth * 2.0f / renderWidth;
  399. F32 vscale = wheight * 2.0f / renderHeight;
  400. F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
  401. F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
  402. F32 top = wheight - vscale * (updateRect.point.y - offset.y);
  403. F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);
  404. frustum.set( mLastCameraQuery.ortho, left, right, top, bottom, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane );
  405. }
  406. // Manipulate the frustum for tiled screenshots
  407. const bool screenShotMode = gScreenShot && gScreenShot->isPending();
  408. if ( screenShotMode )
  409. {
  410. gScreenShot->tileFrustum( frustum );
  411. GFX->setViewMatrix(MatrixF::Identity);
  412. }
  413. RectI tempRect = updateRect;
  414. if (!renderingToTarget)
  415. {
  416. #ifdef TORQUE_OS_MAC
  417. Point2I screensize = getRoot()->getWindowSize();
  418. tempRect.point.y = screensize.y - (tempRect.point.y + tempRect.extent.y);
  419. #endif
  420. GFX->setViewport( tempRect );
  421. }
  422. else
  423. {
  424. // Activate stereo RT
  425. GFX->activateStereoTarget(-1);
  426. }
  427. // Clear the zBuffer so GUI doesn't hose object rendering accidentally
  428. GFX->clear( GFXClearZBuffer , ColorI(20,20,20), 1.0f, 0 );
  429. //GFX->clear( GFXClearTarget, ColorI(255,0,0), 1.0f, 0);
  430. GFX->setFrustum( frustum );
  431. if(mLastCameraQuery.ortho)
  432. {
  433. mOrthoWidth = frustum.getWidth();
  434. mOrthoHeight = frustum.getHeight();
  435. }
  436. // We're going to be displaying this render at size of this control in
  437. // pixels - let the scene know so that it can calculate e.g. reflections
  438. // correctly for that final display result.
  439. gClientSceneGraph->setDisplayTargetResolution(renderSize);
  440. // Set the GFX world matrix to the world-to-camera transform, but don't
  441. // change the cameraMatrix in mLastCameraQuery. This is because
  442. // mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world
  443. // transform. In-place invert would save a copy but mess up any GUIs that
  444. // depend on that value.
  445. MatrixF worldToCamera = mLastCameraQuery.cameraMatrix;
  446. worldToCamera.inverse();
  447. GFX->setWorldMatrix( worldToCamera );
  448. mSaveProjection = GFX->getProjectionMatrix();
  449. mSaveModelview = GFX->getWorldMatrix();
  450. mSaveViewport = updateRect;
  451. mSaveWorldToScreenScale = GFX->getWorldToScreenScale();
  452. mSaveFrustum = GFX->getFrustum();
  453. mSaveFrustum.setTransform( mLastCameraQuery.cameraMatrix );
  454. // Set the default non-clip projection as some
  455. // objects depend on this even in non-reflect cases.
  456. gClientSceneGraph->setNonClipProjection( mSaveProjection );
  457. // Give the post effect manager the worldToCamera, and cameraToScreen matrices
  458. PFXMGR->setFrameMatrices( mSaveModelview, mSaveProjection );
  459. renderWorld(updateRect);
  460. DebugDrawer::get()->render();
  461. // Render the canvas overlay if its available
  462. if (mRenderStyle == RenderStyleStereoSideBySide && mStereoGuiTarget.getPointer())
  463. {
  464. GFXDEBUGEVENT_SCOPE( StereoGui_Render, ColorI( 255, 0, 0 ) );
  465. MatrixF proj(1);
  466. Frustum originalFrustum = GFX->getFrustum();
  467. GFXTextureObject *texObject = mStereoGuiTarget->getTexture(0);
  468. const FovPort *currentFovPort = GFX->getStereoFovPort();
  469. const MatrixF *eyeTransforms = GFX->getStereoEyeTransforms();
  470. const Point3F *eyeOffset = GFX->getStereoEyeOffsets();
  471. Frustum gfxFrustum = originalFrustum;
  472. for (U32 i=0; i<2; i++)
  473. {
  474. GFX->activateStereoTarget(i);
  475. MathUtils::makeFovPortFrustum(&gfxFrustum, true, gfxFrustum.getNearDist(), gfxFrustum.getFarDist(), currentFovPort[i], eyeTransforms[i]);
  476. GFX->setFrustum(gfxFrustum);
  477. MatrixF eyeWorldTrans(1);
  478. eyeWorldTrans.setPosition(Point3F(eyeOffset[i].x,eyeOffset[i].y,eyeOffset[i].z));
  479. MatrixF eyeWorld(1);
  480. eyeWorld.mul(eyeWorldTrans);
  481. eyeWorld.inverse();
  482. GFX->setWorldMatrix(eyeWorld);
  483. GFX->setViewMatrix(MatrixF::Identity);
  484. if (!mStereoOverlayVB.getPointer())
  485. {
  486. mStereoOverlayVB.set(GFX, 4, GFXBufferTypeStatic);
  487. GFXVertexPCT *verts = mStereoOverlayVB.lock(0, 4);
  488. F32 texLeft = 0.0f;
  489. F32 texRight = 1.0f;
  490. F32 texTop = 1.0f;
  491. F32 texBottom = 0.0f;
  492. F32 rectRatio = gfxFrustum.getWidth() / gfxFrustum.getHeight();
  493. F32 rectWidth = gfxFrustum.getWidth() * TS_OVERLAY_SCREEN_WIDTH;
  494. F32 rectHeight = rectWidth * rectRatio;
  495. F32 screenLeft = -rectWidth * 0.5;
  496. F32 screenRight = rectWidth * 0.5;
  497. F32 screenTop = -rectHeight * 0.5;
  498. F32 screenBottom = rectHeight * 0.5;
  499. const F32 fillConv = 0.0f;
  500. const F32 frustumDepthAdjusted = gfxFrustum.getNearDist() + 0.012;
  501. verts[0].point.set( screenLeft - fillConv, frustumDepthAdjusted, screenTop - fillConv );
  502. verts[1].point.set( screenRight - fillConv, frustumDepthAdjusted, screenTop - fillConv );
  503. verts[2].point.set( screenLeft - fillConv, frustumDepthAdjusted, screenBottom - fillConv );
  504. verts[3].point.set( screenRight - fillConv, frustumDepthAdjusted, screenBottom - fillConv );
  505. verts[0].color = verts[1].color = verts[2].color = verts[3].color = ColorI(255,255,255,255);
  506. verts[0].texCoord.set( texLeft, texTop );
  507. verts[1].texCoord.set( texRight, texTop );
  508. verts[2].texCoord.set( texLeft, texBottom );
  509. verts[3].texCoord.set( texRight, texBottom );
  510. mStereoOverlayVB.unlock();
  511. }
  512. if (!mStereoGuiSB.getPointer())
  513. {
  514. // DrawBitmapStretchSR
  515. GFXStateBlockDesc bitmapStretchSR;
  516. bitmapStretchSR.setCullMode(GFXCullNone);
  517. bitmapStretchSR.setZReadWrite(false, false);
  518. bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  519. bitmapStretchSR.samplersDefined = true;
  520. bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
  521. bitmapStretchSR.samplers[0].minFilter = GFXTextureFilterPoint;
  522. bitmapStretchSR.samplers[0].mipFilter = GFXTextureFilterPoint;
  523. bitmapStretchSR.samplers[0].magFilter = GFXTextureFilterPoint;
  524. mStereoGuiSB = GFX->createStateBlock(bitmapStretchSR);
  525. }
  526. GFX->setVertexBuffer(mStereoOverlayVB);
  527. GFX->setStateBlock(mStereoGuiSB);
  528. GFX->setTexture( 0, texObject );
  529. GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
  530. GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
  531. }
  532. }
  533. // Restore the previous matrix state before
  534. // we begin rendering the child controls.
  535. saver.restore();
  536. // Restore the render style and any stereo parameters
  537. GFX->setActiveRenderTarget(origTarget);
  538. GFX->setCurrentRenderStyle(prevRenderStyle);
  539. GFX->setCurrentProjectionOffset(prevProjectionOffset);
  540. if(mRenderStyle == RenderStyleStereoSideBySide && gLastStereoTexture)
  541. {
  542. GFX->setClipRect(updateRect);
  543. GFX->getDrawUtil()->drawBitmapStretch(gLastStereoTexture, updateRect);
  544. }
  545. // Allow subclasses to render 2D elements.
  546. GFX->setClipRect(updateRect);
  547. renderGui( offset, updateRect );
  548. if (shouldRenderChildControls())
  549. {
  550. renderChildControls(offset, updateRect);
  551. }
  552. smFrameCount++;
  553. }
  554. //-----------------------------------------------------------------------------
  555. void GuiTSCtrl::drawLine( Point3F p0, Point3F p1, const ColorI &color, F32 width )
  556. {
  557. if ( !mSaveFrustum.clipSegment( p0, p1 ) )
  558. return;
  559. MathUtils::mProjectWorldToScreen( p0, &p0, mSaveViewport, mSaveModelview, mSaveProjection );
  560. MathUtils::mProjectWorldToScreen( p1, &p1, mSaveViewport, mSaveModelview, mSaveProjection );
  561. p0.x = mClampF( p0.x, 0.0f, mSaveViewport.extent.x );
  562. p0.y = mClampF( p0.y, 0.0f, mSaveViewport.extent.y );
  563. p1.x = mClampF( p1.x, 0.0f, mSaveViewport.extent.x );
  564. p1.y = mClampF( p1.y, 0.0f, mSaveViewport.extent.y );
  565. p0.z = p1.z = 0.0f;
  566. _drawLine( p0, p1, color, width );
  567. }
  568. //-----------------------------------------------------------------------------
  569. void GuiTSCtrl::drawLineList( const Vector<Point3F> &points, const ColorI color, F32 width )
  570. {
  571. for ( S32 i = 0; i < points.size() - 1; i++ )
  572. drawLine( points[i], points[i+1], color, width );
  573. }
  574. void GuiTSCtrl::setStereoGui(GuiOffscreenCanvas *canvas)
  575. {
  576. mStereoGuiTarget = canvas ? canvas->getTarget() : NULL;
  577. }
  578. //=============================================================================
  579. // Console Methods.
  580. //=============================================================================
  581. // MARK: ---- Console Methods ----
  582. //-----------------------------------------------------------------------------
  583. DefineEngineMethod( GuiTSCtrl, unproject, Point3F, ( Point3F screenPosition ),,
  584. "Transform 3D screen-space coordinates (x, y, depth) to world space.\n"
  585. "This method can be, for example, used to find the world-space position relating to the current mouse cursor position.\n"
  586. "@param screenPosition The x/y position on the screen plus the depth from the screen-plane outwards.\n"
  587. "@return The world-space position corresponding to the given screen-space coordinates." )
  588. {
  589. Point3F worldPos;
  590. object->unproject( screenPosition, &worldPos );
  591. return worldPos;
  592. }
  593. //-----------------------------------------------------------------------------
  594. DefineEngineMethod( GuiTSCtrl, project, Point3F, ( Point3F worldPosition ),,
  595. "Transform world-space coordinates to screen-space (x, y, depth) coordinates.\n"
  596. "@param worldPosition The world-space position to transform to screen-space.\n"
  597. "@return The " )
  598. {
  599. Point3F screenPos;
  600. object->project( worldPosition, &screenPos );
  601. return screenPos;
  602. }
  603. //-----------------------------------------------------------------------------
  604. DefineEngineMethod( GuiTSCtrl, getWorldToScreenScale, Point2F, (),,
  605. "Get the ratio between world-space units and pixels.\n"
  606. "@return The amount of world-space units covered by the extent of a single pixel." )
  607. {
  608. return object->getWorldToScreenScale();
  609. }
  610. //-----------------------------------------------------------------------------
  611. DefineEngineMethod( GuiTSCtrl, calculateViewDistance, F32, ( F32 radius ),,
  612. "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"
  613. "@param radius Radius in world-space units which should fit in the view.\n"
  614. "@return The distance from the viewpoint at which the given radius would be fully visible." )
  615. {
  616. return object->calculateViewDistance( radius );
  617. }
  618. DefineEngineMethod( GuiTSCtrl, setStereoGui, void, ( GuiOffscreenCanvas* canvas ),,
  619. "Sets the current stereo texture to an offscreen canvas\n"
  620. "@param canvas The desired canvas." )
  621. {
  622. object->setStereoGui(canvas);
  623. }