debugDraw.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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 "gfx/sim/debugDraw.h"
  24. #include "gfx/gFont.h"
  25. #include "gfx/gfxDrawUtil.h"
  26. #include "gfx/gfxTransformSaver.h"
  27. #include "gfx/gfxDebugEvent.h"
  28. #include "math/mathUtils.h"
  29. #include "math/util/frustum.h"
  30. #include "console/console.h"
  31. #include "scene/sceneManager.h"
  32. #include "core/module.h"
  33. #include "console/engineAPI.h"
  34. #include "math/mPolyhedron.impl.h"
  35. MODULE_BEGIN( DebugDrawer )
  36. MODULE_INIT_AFTER( Sim )
  37. MODULE_INIT_AFTER( GFX )
  38. // DebugDrawer will register itself as a SimObject and
  39. // thus get automatically shut down with Sim.
  40. MODULE_INIT
  41. {
  42. DebugDrawer::init();
  43. }
  44. MODULE_END;
  45. DebugDrawer* DebugDrawer::sgDebugDrawer = NULL;
  46. IMPLEMENT_CONOBJECT(DebugDrawer);
  47. ConsoleDocClass( DebugDrawer,
  48. "@brief A debug helper for rendering debug primitives to the scene.\n\n"
  49. "The DebugDrawer is used to render debug primitives to the scene for testing. It is "
  50. "often useful when debugging collision code or complex 3d algorithms to have "
  51. "them draw debug information, like culling hulls or bounding volumes, normals, "
  52. "simple lines, and so forth.\n\n"
  53. "A key feature of the DebugDrawer is that each primitive gets a \"time to live\" (TTL) "
  54. "which allows them to continue to render to the scene for a fixed period of time. You "
  55. "can freeze or resume the system at any time to allow you to examine the output.\n"
  56. "@tsexample\n"
  57. "DebugDraw.drawLine( %player.getMuzzlePoint( 0 ), %hitPoint );\n"
  58. "DebugDraw.setLastTTL( 5000 ); // 5 seconds.\n"
  59. "@endtsexample\n"
  60. "The DebugDrawer renders solely in world space and all primitives are rendered with the "
  61. "cull mode disabled.\n"
  62. "@note This feature can easily be used to cheat in online games, so you should be sure "
  63. "it is disabled in your shipping game. By default the DebugDrawer is disabled in all "
  64. "TORQUE_SHIPPING builds.\n"
  65. "@ingroup GFX\n" );
  66. DebugDrawer::DebugDrawer()
  67. {
  68. mHead = NULL;
  69. isFrozen = false;
  70. shouldToggleFreeze = false;
  71. #ifdef ENABLE_DEBUGDRAW
  72. isDrawing = true;
  73. #else
  74. isDrawing = false;
  75. #endif
  76. }
  77. DebugDrawer::~DebugDrawer()
  78. {
  79. if( sgDebugDrawer == this )
  80. sgDebugDrawer = NULL;
  81. }
  82. DebugDrawer* DebugDrawer::get()
  83. {
  84. if (sgDebugDrawer)
  85. {
  86. return sgDebugDrawer;
  87. } else {
  88. DebugDrawer::init();
  89. return sgDebugDrawer;
  90. }
  91. }
  92. void DebugDrawer::init()
  93. {
  94. #ifdef ENABLE_DEBUGDRAW
  95. sgDebugDrawer = new DebugDrawer();
  96. sgDebugDrawer->registerObject("DebugDraw");
  97. Sim::getRootGroup()->addObject( sgDebugDrawer );
  98. Con::warnf( "DebugDrawer Enabled!" );
  99. #endif
  100. }
  101. void DebugDrawer::setupStateBlocks()
  102. {
  103. GFXStateBlockDesc d;
  104. d.setCullMode(GFXCullNone);
  105. mRenderZOnSB = GFX->createStateBlock(d);
  106. d.setZReadWrite(false);
  107. mRenderZOffSB = GFX->createStateBlock(d);
  108. d.setCullMode(GFXCullCCW);
  109. d.setZReadWrite(true, false);
  110. d.setBlend(true);
  111. mRenderAlpha = GFX->createStateBlock(d);
  112. }
  113. void DebugDrawer::drawBoxOutline(const Point3F &a, const Point3F &b, const LinearColorF &color)
  114. {
  115. Point3F point0(a.x, a.y, a.z);
  116. Point3F point1(a.x, b.y, a.z);
  117. Point3F point2(b.x, b.y, a.z);
  118. Point3F point3(b.x, a.y, a.z);
  119. Point3F point4(a.x, a.y, b.z);
  120. Point3F point5(a.x, b.y, b.z);
  121. Point3F point6(b.x, b.y, b.z);
  122. Point3F point7(b.x, a.y, b.z);
  123. // Draw one plane
  124. drawLine(point0, point1, color);
  125. drawLine(point1, point2, color);
  126. drawLine(point2, point3, color);
  127. drawLine(point3, point0, color);
  128. // Draw the other plane
  129. drawLine(point4, point5, color);
  130. drawLine(point5, point6, color);
  131. drawLine(point6, point7, color);
  132. drawLine(point7, point4, color);
  133. // Draw the connecting corners
  134. drawLine(point0, point4, color);
  135. drawLine(point1, point5, color);
  136. drawLine(point2, point6, color);
  137. drawLine(point3, point7, color);
  138. }
  139. void DebugDrawer::drawTransformedBoxOutline(const Point3F &a, const Point3F &b, const LinearColorF &color, const MatrixF& transform)
  140. {
  141. Point3F point0(a.x, a.y, a.z);
  142. Point3F point1(a.x, b.y, a.z);
  143. Point3F point2(b.x, b.y, a.z);
  144. Point3F point3(b.x, a.y, a.z);
  145. Point3F point4(a.x, a.y, b.z);
  146. Point3F point5(a.x, b.y, b.z);
  147. Point3F point6(b.x, b.y, b.z);
  148. Point3F point7(b.x, a.y, b.z);
  149. transform.mulP(point0);
  150. transform.mulP(point1);
  151. transform.mulP(point2);
  152. transform.mulP(point3);
  153. transform.mulP(point4);
  154. transform.mulP(point5);
  155. transform.mulP(point6);
  156. transform.mulP(point7);
  157. // Draw one plane
  158. drawLine(point0, point1, color);
  159. drawLine(point1, point2, color);
  160. drawLine(point2, point3, color);
  161. drawLine(point3, point0, color);
  162. // Draw the other plane
  163. drawLine(point4, point5, color);
  164. drawLine(point5, point6, color);
  165. drawLine(point6, point7, color);
  166. drawLine(point7, point4, color);
  167. // Draw the connecting corners
  168. drawLine(point0, point4, color);
  169. drawLine(point1, point5, color);
  170. drawLine(point2, point6, color);
  171. drawLine(point3, point7, color);
  172. }
  173. void DebugDrawer::render(bool clear)
  174. {
  175. #ifdef ENABLE_DEBUGDRAW
  176. if(!isDrawing)
  177. return;
  178. GFXDEBUGEVENT_SCOPE( DebugDrawer, ColorI::GREEN );
  179. if (!mRenderZOnSB)
  180. {
  181. setupStateBlocks();
  182. String fontCacheDir = Con::getVariable("$GUI::fontCacheDirectory");
  183. mFont = GFont::create("Arial", 12, fontCacheDir);
  184. }
  185. SimTime curTime = Sim::getCurrentTime();
  186. for(DebugPrim **walk = &mHead; *walk; )
  187. {
  188. GFX->setupGenericShaders();
  189. DebugPrim *p = *walk;
  190. // Set up the state block...
  191. GFXStateBlockRef currSB;
  192. if(p->type==DebugPrim::Capsule)
  193. {
  194. currSB = mRenderAlpha;
  195. }
  196. else if(p->useZ)
  197. {
  198. currSB = mRenderZOnSB;
  199. }
  200. else
  201. {
  202. currSB = mRenderZOffSB;
  203. }
  204. GFX->setStateBlock( currSB );
  205. Point3F d;
  206. const ColorI color = p->color.toColorI();
  207. switch(p->type)
  208. {
  209. case DebugPrim::Tri:
  210. PrimBuild::begin( GFXLineStrip, 4);
  211. PrimBuild::color(p->color);
  212. PrimBuild::vertex3fv(p->a);
  213. PrimBuild::vertex3fv(p->b);
  214. PrimBuild::vertex3fv(p->c);
  215. PrimBuild::vertex3fv(p->a);
  216. PrimBuild::end();
  217. break;
  218. case DebugPrim::DirectionLine:
  219. {
  220. const static F32 ARROW_LENGTH = 0.2f, ARROW_RADIUS = 0.035f, CYLINDER_RADIUS = 0.008f;
  221. Point3F &start = p->a, &end = p->b;
  222. Point3F direction = end - start;
  223. F32 length = direction.len();
  224. if( length>ARROW_LENGTH )
  225. {
  226. //cylinder with arrow on end
  227. direction *= (1.0f/length);
  228. Point3F baseArrow = end - (direction*ARROW_LENGTH);
  229. GFX->getDrawUtil()->drawCone(currSB->getDesc(), baseArrow, end, ARROW_RADIUS, color);
  230. GFX->getDrawUtil()->drawCylinder(currSB->getDesc(), start, baseArrow, CYLINDER_RADIUS, color);
  231. }
  232. else if( length>0 )
  233. {
  234. //short, so just draw arrow
  235. GFX->getDrawUtil()->drawCone(currSB->getDesc(), start, end, ARROW_RADIUS, color);
  236. }
  237. }
  238. break;
  239. case DebugPrim::Capsule:
  240. GFX->getDrawUtil()->drawCapsule(currSB->getDesc(), p->a, p->b.x, p->b.y, color);
  241. break;
  242. case DebugPrim::OutlinedText:
  243. {
  244. GFXTransformSaver saver;
  245. Point3F result;
  246. if (MathUtils::mProjectWorldToScreen(p->a, &result, GFX->getViewport(), GFX->getWorldMatrix(), GFX->getProjectionMatrix()))
  247. {
  248. GFX->setClipRect(GFX->getViewport());
  249. Point2I where = Point2I(result.x, result.y);
  250. //only switch statement that uses p->color2
  251. GFX->getDrawUtil()->setBitmapModulation(p->color2.toColorI());
  252. GFX->getDrawUtil()->drawText(mFont, Point2I(where.x-1, where.y), p->mText);
  253. GFX->getDrawUtil()->drawText(mFont, Point2I(where.x+1, where.y), p->mText);
  254. GFX->getDrawUtil()->drawText(mFont, Point2I(where.x, where.y-1), p->mText);
  255. GFX->getDrawUtil()->drawText(mFont, Point2I(where.x, where.y+1), p->mText);
  256. GFX->getDrawUtil()->setBitmapModulation(color);
  257. GFX->getDrawUtil()->drawText(mFont, where, p->mText);
  258. }
  259. }
  260. break;
  261. case DebugPrim::Box:
  262. d = p->a - p->b;
  263. GFX->getDrawUtil()->drawCube(currSB->getDesc(), d * 0.5, (p->a + p->b) * 0.5, color);
  264. break;
  265. case DebugPrim::Line:
  266. PrimBuild::begin( GFXLineStrip, 2);
  267. PrimBuild::color(color);
  268. PrimBuild::vertex3fv(p->a);
  269. PrimBuild::vertex3fv(p->b);
  270. PrimBuild::end();
  271. break;
  272. case DebugPrim::Text:
  273. {
  274. GFXTransformSaver saver;
  275. Point3F result;
  276. if (MathUtils::mProjectWorldToScreen(p->a, &result, GFX->getViewport(), GFX->getWorldMatrix(), GFX->getProjectionMatrix()))
  277. {
  278. GFX->setClipRect(GFX->getViewport());
  279. GFX->getDrawUtil()->setBitmapModulation(color);
  280. GFX->getDrawUtil()->drawText(mFont, Point2I(result.x, result.y), p->mText);
  281. }
  282. }
  283. break;
  284. }
  285. // Ok, we've got data, now freeze here if needed.
  286. if (shouldToggleFreeze)
  287. {
  288. isFrozen = !isFrozen;
  289. shouldToggleFreeze = false;
  290. }
  291. if(clear && p->dieTime <= curTime && !isFrozen && p->dieTime != U32_MAX)
  292. {
  293. *walk = p->next;
  294. mPrimChunker.free(p);
  295. }
  296. else
  297. walk = &((*walk)->next);
  298. }
  299. #endif
  300. }
  301. void DebugDrawer::drawBox(const Point3F &a, const Point3F &b, const LinearColorF &color)
  302. {
  303. if(isFrozen || !isDrawing)
  304. return;
  305. DebugPrim *n = mPrimChunker.alloc();
  306. n->useZ = true;
  307. n->dieTime = 0;
  308. n->a = a;
  309. n->b = b;
  310. n->color = color;
  311. n->type = DebugPrim::Box;
  312. n->next = mHead;
  313. mHead = n;
  314. }
  315. void DebugDrawer::drawLine(const Point3F &a, const Point3F &b, const LinearColorF &color)
  316. {
  317. if(isFrozen || !isDrawing)
  318. return;
  319. DebugPrim *n = mPrimChunker.alloc();
  320. n->useZ = true;
  321. n->dieTime = 0;
  322. n->a = a;
  323. n->b = b;
  324. n->color = color;
  325. n->type = DebugPrim::Line;
  326. n->next = mHead;
  327. mHead = n;
  328. }
  329. void DebugDrawer::drawCapsule(const Point3F &a, const F32 &radius, const F32 &height, const LinearColorF &color)
  330. {
  331. if(isFrozen || !isDrawing)
  332. return;
  333. DebugPrim *n = mPrimChunker.alloc();
  334. n->useZ = true;
  335. n->dieTime = 0;
  336. n->a = a;
  337. n->b.x = radius;
  338. n->b.y = height;
  339. n->color = color;
  340. n->type = DebugPrim::Capsule;
  341. n->next = mHead;
  342. mHead = n;
  343. }
  344. void DebugDrawer::drawDirectionLine(const Point3F &a, const Point3F &b, const LinearColorF &color)
  345. {
  346. if(isFrozen || !isDrawing)
  347. return;
  348. DebugPrim *n = mPrimChunker.alloc();
  349. n->useZ = true;
  350. n->dieTime = 0;
  351. n->a = a;
  352. n->b = b;
  353. n->color = color;
  354. n->type = DebugPrim::DirectionLine;
  355. n->next = mHead;
  356. mHead = n;
  357. }
  358. void DebugDrawer::drawOutlinedText(const Point3F& pos, const String& text, const LinearColorF &color, const LinearColorF &colorOutline)
  359. {
  360. if(isFrozen || !isDrawing)
  361. return;
  362. DebugPrim *n = mPrimChunker.alloc();
  363. n->useZ = false;
  364. n->dieTime = 0;
  365. n->a = pos;
  366. n->color = color;
  367. n->color2 = colorOutline;
  368. dStrncpy(n->mText, text.c_str(), 256);
  369. n->type = DebugPrim::OutlinedText;
  370. n->next = mHead;
  371. mHead = n;
  372. }
  373. void DebugDrawer::drawTri(const Point3F &a, const Point3F &b, const Point3F &c, const LinearColorF &color)
  374. {
  375. if(isFrozen || !isDrawing)
  376. return;
  377. DebugPrim *n = mPrimChunker.alloc();
  378. n->useZ = true;
  379. n->dieTime = 0;
  380. n->a = a;
  381. n->b = b;
  382. n->c = c;
  383. n->color = color;
  384. n->type = DebugPrim::Tri;
  385. n->next = mHead;
  386. mHead = n;
  387. }
  388. void DebugDrawer::drawPolyhedron( const AnyPolyhedron& polyhedron, const LinearColorF& color )
  389. {
  390. const PolyhedronData::Edge* edges = polyhedron.getEdges();
  391. const Point3F* points = polyhedron.getPoints();
  392. const U32 numEdges = polyhedron.getNumEdges();
  393. for( U32 i = 0; i < numEdges; ++ i )
  394. {
  395. const PolyhedronData::Edge& edge = edges[ i ];
  396. drawLine( points[ edge.vertex[ 0 ] ], points[ edge.vertex[ 1 ] ], color );
  397. }
  398. }
  399. void DebugDrawer::drawPolyhedronDebugInfo( const AnyPolyhedron& polyhedron, const MatrixF& transform, const Point3F& scale )
  400. {
  401. Point3F center = polyhedron.getCenterPoint();
  402. center.convolve( scale );
  403. transform.mulP( center );
  404. // Render plane indices and normals.
  405. const U32 numPlanes = polyhedron.getNumPlanes();
  406. for( U32 i = 0; i < numPlanes; ++ i )
  407. {
  408. const AnyPolyhedron::PlaneType& plane = polyhedron.getPlanes()[ i ];
  409. Point3F planePos = plane.getPosition();
  410. planePos.convolve( scale );
  411. transform.mulP( planePos );
  412. Point3F normal = plane.getNormal();
  413. transform.mulV( normal );
  414. drawText( planePos, String::ToString( i ), ColorI::BLACK );
  415. drawLine( planePos, planePos + normal, ColorI::GREEN );
  416. }
  417. // Render edge indices and direction indicators.
  418. const U32 numEdges = polyhedron.getNumEdges();
  419. for( U32 i = 0; i < numEdges; ++ i )
  420. {
  421. const AnyPolyhedron::EdgeType& edge = polyhedron.getEdges()[ i ];
  422. Point3F v1 = polyhedron.getPoints()[ edge.vertex[ 0 ] ];
  423. Point3F v2 = polyhedron.getPoints()[ edge.vertex[ 1 ] ];
  424. v1.convolve( scale );
  425. v2.convolve( scale );
  426. transform.mulP( v1 );
  427. transform.mulP( v2 );
  428. const Point3F midPoint = v1 + ( v2 - v1 ) / 2.f;
  429. drawText( midPoint, String::ToString( "%i (%i, %i)", i, edge.face[ 0 ], edge.face[ 1 ] ), ColorI::WHITE );
  430. // Push out the midpoint away from the center to place the direction indicator.
  431. Point3F pushDir = midPoint - center;
  432. pushDir.normalize();
  433. const Point3F dirPoint = midPoint + pushDir;
  434. const Point3F lineDir = ( v2 - v1 ) / 2.f;
  435. drawLine( dirPoint, dirPoint + lineDir, ColorI::RED );
  436. }
  437. // Render point indices and coordinates.
  438. const U32 numPoints = polyhedron.getNumPoints();
  439. for( U32 i = 0; i < numPoints; ++ i )
  440. {
  441. Point3F p = polyhedron.getPoints()[ i ];
  442. p.convolve( scale );
  443. transform.mulP( p );
  444. drawText( p, String::ToString( "%i: (%.2f, %.2f, %.2f)", i, p.x, p.y, p.z ), LinearColorF::WHITE );
  445. }
  446. }
  447. void DebugDrawer::drawText(const Point3F& pos, const String& text, const LinearColorF &color)
  448. {
  449. if(isFrozen || !isDrawing)
  450. return;
  451. DebugPrim *n = mPrimChunker.alloc();
  452. n->useZ = false;
  453. n->dieTime = 0;
  454. n->a = pos;
  455. n->color = color;
  456. dStrncpy(n->mText, text.c_str(), 256);
  457. n->type = DebugPrim::Text;
  458. n->next = mHead;
  459. mHead = n;
  460. }
  461. void DebugDrawer::setLastTTL(U32 ms)
  462. {
  463. AssertFatal(mHead, "Tried to set last with nothing in the list!");
  464. if (ms != U32_MAX)
  465. mHead->dieTime = Sim::getCurrentTime() + ms;
  466. else
  467. mHead->dieTime = U32_MAX;
  468. }
  469. void DebugDrawer::setLastZTest(bool enabled)
  470. {
  471. AssertFatal(mHead, "Tried to set last with nothing in the list!");
  472. mHead->useZ = enabled;
  473. }
  474. DefineEngineMethod( DebugDrawer, drawLine, void, ( Point3F a, Point3F b, LinearColorF color ), ( LinearColorF::WHITE ),
  475. "Draws a line primitive between two 3d points." )
  476. {
  477. object->drawLine( a, b, color );
  478. }
  479. DefineEngineMethod( DebugDrawer, drawBox, void, ( Point3F a, Point3F b, LinearColorF color ), ( LinearColorF::WHITE ),
  480. "Draws an axis aligned box primitive within the two 3d points." )
  481. {
  482. object->drawBox( a, b, color );
  483. }
  484. DefineEngineMethod( DebugDrawer, setLastTTL, void, ( U32 ms ),,
  485. "Sets the \"time to live\" (TTL) for the last rendered primitive." )
  486. {
  487. object->setLastTTL( ms );
  488. }
  489. DefineEngineMethod( DebugDrawer, setLastZTest, void, ( bool enabled ),,
  490. "Sets the z buffer reading state for the last rendered primitive." )
  491. {
  492. object->setLastZTest( enabled );
  493. }
  494. DefineEngineMethod( DebugDrawer, toggleFreeze, void, (),,
  495. "Toggles freeze mode which keeps the currently rendered primitives from expiring." )
  496. {
  497. object->toggleFreeze();
  498. }
  499. DefineEngineMethod( DebugDrawer, toggleDrawing, void, (),,
  500. "Toggles the rendering of DebugDrawer primitives." )
  501. {
  502. object->toggleDrawing();
  503. }