debugDraw.cpp

Engine/source/gfx/sim/debugDraw.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(DebugDrawer , "@brief A debug helper <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rendering debug primitives <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" "The <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> debug primitives <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> testing. It is " "often useful when debugging collision code or complex 3d algorithms <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have " "them draw debug information, like culling hulls or bounding volumes, normals , " "simple lines, and so <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">forth.\n\n</a>" "A key feature of the <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is that each primitive gets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> \"time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> live\" (TTL) " "which allows them <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> continue <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> fixed period of time. You " "can freeze or resume the system at any time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow you <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> examine the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">output.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "DebugDraw.drawLine( %player.getMuzzlePoint( 0 ), %hitPoint );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "DebugDraw.setLastTTL( 5000 ); // 5 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">seconds.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "The <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> renders solely in world space and all primitives are rendered with the " "cull <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">disabled.\n</a>" "@note This feature can easily be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> cheat in online games, so you should be sure " "it is disabled in your shipping game. By default the <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is disabled in all " "TORQUE_SHIPPING <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">builds.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GFX\n</a>" )
DefineEngineMethod(DebugDrawer , drawBox , void , (Point3F a, Point3F b, LinearColorF color) , (LinearColorF::WHITE) , "Draws an axis aligned box primitive within the two 3d points." )
DefineEngineMethod(DebugDrawer , drawLine , void , (Point3F a, Point3F b, LinearColorF color) , (LinearColorF::WHITE) , "Draws <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> line primitive between two 3d points." )
DefineEngineMethod(DebugDrawer , setLastTTL , void , (U32 ms) , "Sets the \"time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> live\" (TTL) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the last rendered primitive." )
DefineEngineMethod(DebugDrawer , setLastZTest , void , (bool enabled) , "Sets the z buffer reading state <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the last rendered primitive." )
DefineEngineMethod(DebugDrawer , toggleDrawing , void , () , "Toggles the rendering of <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> primitives." )
DefineEngineMethod(DebugDrawer , toggleFreeze , void , () , "Toggles freeze <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> which keeps the currently rendered primitives from expiring." )

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 

Public Functions

ConsoleDocClass(DebugDrawer , "@brief A debug helper <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> rendering debug primitives <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" "The <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> debug primitives <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> testing. It is " "often useful when debugging collision code or complex 3d algorithms <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have " "them draw debug information, like culling hulls or bounding volumes, normals , " "simple lines, and so <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">forth.\n\n</a>" "A key feature of the <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is that each primitive gets <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> \"time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> live\" (TTL) " "which allows them <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> continue <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> fixed period of time. You " "can freeze or resume the system at any time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow you <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> examine the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">output.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "DebugDraw.drawLine( %player.getMuzzlePoint( 0 ), %hitPoint );\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "DebugDraw.setLastTTL( 5000 ); // 5 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">seconds.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "The <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> renders solely in world space and all primitives are rendered with the " "cull <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">disabled.\n</a>" "@note This feature can easily be used <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> cheat in online games, so you should be sure " "it is disabled in your shipping game. By default the <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> is disabled in all " "TORQUE_SHIPPING <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">builds.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">GFX\n</a>" )

DefineEngineMethod(DebugDrawer , drawBox , void , (Point3F a, Point3F b, LinearColorF color) , (LinearColorF::WHITE) , "Draws an axis aligned box primitive within the two 3d points." )

DefineEngineMethod(DebugDrawer , drawLine , void , (Point3F a, Point3F b, LinearColorF color) , (LinearColorF::WHITE) , "Draws <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> line primitive between two 3d points." )

DefineEngineMethod(DebugDrawer , setLastTTL , void , (U32 ms) , "Sets the \"time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> live\" (TTL) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the last rendered primitive." )

DefineEngineMethod(DebugDrawer , setLastZTest , void , (bool enabled) , "Sets the z buffer reading state <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the last rendered primitive." )

DefineEngineMethod(DebugDrawer , toggleDrawing , void , () , "Toggles the rendering of <a href="/coding/class/classdebugdrawer/">DebugDrawer</a> primitives." )

DefineEngineMethod(DebugDrawer , toggleFreeze , void , () , "Toggles freeze <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> which keeps the currently rendered primitives from expiring." )

IMPLEMENT_CONOBJECT(DebugDrawer )

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