Torque3D Documentation / _generateds / gfxDrawUtil.cpp

gfxDrawUtil.cpp

Engine/source/gfx/gfxDrawUtil.cpp

More...

Detailed Description

Public Variables

const Point2F circlePoints []
const U32 cubeFaces [6][4]
const Point3F cubePoints [8]
SphereMesh gSphere 
   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/gfxDrawUtil.h"
  26
  27#include "core/frameAllocator.h"
  28#include "core/strings/stringFunctions.h"
  29#include "core/strings/unicode.h"
  30#include "math/util/frustum.h"
  31#include "math/util/sphereMesh.h"
  32#include "math/mathUtils.h"
  33#include "gfx/gfxFontRenderBatcher.h"
  34#include "gfx/gfxTransformSaver.h"
  35#include "gfx/gfxPrimitiveBuffer.h"
  36#include "gfx/primBuilder.h"
  37#include "gfx/gfxDebugEvent.h"
  38
  39#include "math/mPolyhedron.impl.h"
  40
  41
  42GFXDrawUtil::GFXDrawUtil( GFXDevice * d)
  43{
  44   mDevice = d;
  45   mBitmapModulation.set(0xFF, 0xFF, 0xFF, 0xFF);
  46   mTextAnchorColor.set(0xFF, 0xFF, 0xFF, 0xFF);
  47   mFontRenderBatcher = new FontRenderBatcher();
  48
  49   _setupStateBlocks();   
  50}
  51
  52GFXDrawUtil::~GFXDrawUtil()
  53{
  54   delete mFontRenderBatcher;
  55}
  56
  57void GFXDrawUtil::_setupStateBlocks()
  58{
  59   // DrawBitmapStretchSR
  60   GFXStateBlockDesc bitmapStretchSR;
  61   bitmapStretchSR.setCullMode(GFXCullNone);
  62   bitmapStretchSR.setZReadWrite(false);
  63   bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  64   bitmapStretchSR.samplersDefined = true;
  65   bitmapStretchSR.setColorWrites(true, true, true, false); // NOTE: comment this out if alpha write is needed
  66
  67   // Linear: Create wrap SB
  68   bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getWrapLinear();
  69   mBitmapStretchWrapLinearSB = mDevice->createStateBlock(bitmapStretchSR);
  70
  71   // Linear: Create clamp SB
  72   bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
  73   mBitmapStretchLinearSB = mDevice->createStateBlock(bitmapStretchSR);
  74
  75   // Point:
  76   bitmapStretchSR.samplers[0].minFilter = GFXTextureFilterPoint;
  77   bitmapStretchSR.samplers[0].mipFilter = GFXTextureFilterPoint;
  78   bitmapStretchSR.samplers[0].magFilter = GFXTextureFilterPoint;
  79
  80   // Point: Create clamp SB, last created clamped so no work required here
  81   mBitmapStretchSB = mDevice->createStateBlock(bitmapStretchSR);
  82
  83   // Point: Create wrap SB, have to do this manually because getWrapLinear doesn't
  84   bitmapStretchSR.samplers[0].addressModeU = GFXAddressWrap;
  85   bitmapStretchSR.samplers[0].addressModeV = GFXAddressWrap;
  86   bitmapStretchSR.samplers[0].addressModeW = GFXAddressWrap;
  87   mBitmapStretchWrapSB = mDevice->createStateBlock(bitmapStretchSR);
  88
  89   GFXStateBlockDesc rectFill;
  90   rectFill.setCullMode(GFXCullNone);
  91   rectFill.setZReadWrite(false);
  92   rectFill.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  93   mRectFillSB = mDevice->createStateBlock(rectFill);
  94}
  95
  96//-----------------------------------------------------------------------------
  97// Color Modulation
  98//-----------------------------------------------------------------------------
  99void GFXDrawUtil::setBitmapModulation( const ColorI &modColor )
 100{
 101   mBitmapModulation = modColor;
 102}
 103
 104void GFXDrawUtil::clearBitmapModulation()
 105{
 106   mBitmapModulation.set( 255, 255, 255, 255 );
 107}
 108
 109void GFXDrawUtil::getBitmapModulation( ColorI *color )
 110{
 111   mBitmapModulation.getColor( color );
 112}
 113
 114void GFXDrawUtil::setTextAnchorColor( const ColorI &ancColor )
 115{
 116   mTextAnchorColor = ancColor;
 117}
 118
 119//-----------------------------------------------------------------------------
 120// Draw Text
 121//-----------------------------------------------------------------------------
 122U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, 
 123                          const ColorI *colorTable, const U32 maxColorIndex, F32 rot )
 124{
 125   return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot );
 126}
 127
 128U32 GFXDrawUtil::drawText( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, 
 129                          const ColorI *colorTable, const U32 maxColorIndex, F32 rot )
 130{
 131   return drawTextN( font, ptDraw, in_string, dStrlen(in_string), colorTable, maxColorIndex, rot );
 132}
 133
 134U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ )
 135{
 136   return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,colorTable,maxColorIndex,rot);
 137}
 138
 139U32 GFXDrawUtil::drawText( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ )
 140{
 141   return drawText(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,colorTable,maxColorIndex,rot);
 142}
 143
 144U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF8 *in_string, U32 n,
 145                           const ColorI *colorTable, const U32 maxColorIndex, F32 rot )
 146{
 147   // return on zero length strings
 148   if( n == 0 )
 149      return ptDraw.x;
 150
 151   // Convert to UTF16 temporarily.
 152   FrameTemp<UTF16> ubuf( n + 1 ); // (n+1) to add space for null terminator
 153   convertUTF8toUTF16N(in_string, ubuf, n + 1);
 154
 155   return drawTextN( font, ptDraw, ubuf, n, colorTable, maxColorIndex, rot );
 156}
 157
 158U32 GFXDrawUtil::drawTextN( GFont *font, const Point2I &ptDraw, const UTF16 *in_string, 
 159                           U32 n, const ColorI *colorTable, const U32 maxColorIndex, F32 rot )
 160{
 161   // return on zero length strings
 162   if( n == 0 )
 163      return ptDraw.x;
 164
 165   // If it's over about 4000 verts we want to break it up
 166   if( n > 666 )
 167   {
 168      U32 left = drawTextN(font, ptDraw, in_string, 666, colorTable, maxColorIndex, rot);
 169
 170      Point2I newDrawPt(left, ptDraw.y);
 171      const UTF16* str = (const UTF16*)in_string;
 172
 173      return drawTextN(font, newDrawPt, &(str[666]), n - 666, colorTable, maxColorIndex, rot);
 174   }
 175
 176   PROFILE_START(GFXDevice_drawTextN);
 177
 178   const PlatformFont::CharInfo *tabci = NULL;
 179
 180   S32 ptX = 0;
 181
 182   // Queue everything for render.   
 183   mFontRenderBatcher->init(font, n);
 184
 185   U32 i;
 186   UTF16 c;   
 187   for (i = 0, c = in_string[i]; i < n && in_string[i]; i++, c = in_string[i])
 188   {
 189      switch(c)
 190      {
 191         // We have to do a little dance here since \t = 0x9, \n = 0xa, and \r = 0xd
 192      case 1: case 2: case 3: case 4: case 5: case 6: case 7:
 193      case 11: case 12:
 194      case 14:
 195         {
 196            // Color code
 197            if (colorTable) 
 198            {
 199               static U8 remap[15] = 
 200               { 
 201                  0x0, // 0 special null terminator
 202                  0x0, // 1 ascii start-of-heading??
 203                  0x1, 
 204                  0x2, 
 205                  0x3, 
 206                  0x4, 
 207                  0x5, 
 208                  0x6, 
 209                  0x0, // 8 special backspace
 210                  0x0, // 9 special tab
 211                  0x0, // a special \n
 212                  0x7, 
 213                  0x8,
 214                  0x0, // a special \r
 215                  0x9 
 216               };
 217
 218               U8 remapped = remap[c];
 219
 220               // Ignore if the color is greater than the specified max index:
 221               if ( remapped <= maxColorIndex )
 222               {
 223                  const ColorI &clr = colorTable[remapped];
 224                  mBitmapModulation = clr;
 225               }
 226            }
 227
 228            // And skip rendering this character.
 229            continue;
 230         }
 231
 232         // reset color?
 233      case 15:
 234         {
 235            mBitmapModulation = mTextAnchorColor;
 236
 237            // And skip rendering this character.
 238            continue;
 239         }
 240
 241         // push color:
 242      case 16:
 243         {
 244            mTextAnchorColor = mBitmapModulation;
 245
 246            // And skip rendering this character.
 247            continue;
 248         }
 249
 250         // pop color:
 251      case 17:
 252         {
 253            mBitmapModulation = mTextAnchorColor;
 254
 255            // And skip rendering this character.
 256            continue;
 257         }
 258
 259         // Tab character
 260      case dT('\t'): 
 261         {
 262            if ( tabci == NULL )
 263               tabci = &(font->getCharInfo( dT(' ') ));
 264
 265            const U32   fontTabIncrement = tabci->xIncrement * GFont::TabWidthInSpaces;
 266
 267            ptX += fontTabIncrement;
 268
 269            // And skip rendering this character.
 270            continue;
 271         }
 272
 273         // Don't draw invalid characters.
 274      default:
 275         {
 276            if( !font->isValidChar( c ) ) 
 277               continue;
 278         }
 279      }
 280
 281      // Queue char for rendering..
 282      GFXVertexColor color = mBitmapModulation;
 283      mFontRenderBatcher->queueChar(c, ptX, color);
 284   }
 285
 286
 287   mFontRenderBatcher->render(rot, Point2F((F32)ptDraw.x, (F32)ptDraw.y));
 288
 289   PROFILE_END();
 290
 291   return ptX + ptDraw.x;
 292}
 293
 294U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF8 *in_string, U32 n, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ )
 295{
 296   return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n,colorTable,maxColorIndex,rot);
 297}
 298
 299U32 GFXDrawUtil::drawTextN( GFont *font, const Point2F &ptDraw, const UTF16 *in_string, U32 n, const ColorI *colorTable /*= NULL*/, const U32 maxColorIndex /*= 9*/, F32 rot /*= 0.f */ )
 300{
 301   return drawTextN(font,Point2I((S32)ptDraw.x,(S32)ptDraw.y),in_string,n,colorTable,maxColorIndex,rot);
 302}
 303
 304//-----------------------------------------------------------------------------
 305// Draw Bitmaps
 306//-----------------------------------------------------------------------------
 307void GFXDrawUtil::drawBitmap( GFXTextureObject* texture, const Point2I &in_rAt, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/ )
 308{
 309   drawBitmap(texture,Point2F((F32)in_rAt.x,(F32)in_rAt.y),in_flip,filter,in_wrap);
 310}
 311
 312void GFXDrawUtil::drawBitmapStretch( GFXTextureObject* texture, const RectI &dstRect, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/ )
 313{
 314   drawBitmapStretch(texture,RectF((F32)dstRect.point.x,(F32)dstRect.point.y,(F32)dstRect.extent.x,(F32)dstRect.extent.y),in_flip,filter,in_wrap);
 315}
 316
 317void GFXDrawUtil::drawBitmapSR( GFXTextureObject* texture, const Point2I &in_rAt, const RectI &srcRect, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/ )
 318{
 319   drawBitmapSR(texture,Point2F((F32)in_rAt.x,(F32)in_rAt.y),RectF((F32)srcRect.point.x,(F32)srcRect.point.y,(F32)srcRect.extent.x,(F32)srcRect.extent.y),in_flip,filter,in_wrap);
 320}
 321
 322void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject *texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/ ) 
 323{
 324   RectF dstRectF = RectF((F32)dstRect.point.x,(F32)dstRect.point.y,(F32)dstRect.extent.x,(F32)dstRect.extent.y);
 325   RectF srcRectF = RectF((F32)srcRect.point.x,(F32)srcRect.point.y,(F32)srcRect.extent.x,(F32)srcRect.extent.y);
 326   drawBitmapStretchSR(texture,dstRectF,srcRectF,in_flip,filter,in_wrap);
 327}
 328
 329void GFXDrawUtil::drawBitmap( GFXTextureObject*texture, const Point2F &in_rAt, const GFXBitmapFlip in_flip /*= GFXBitmapFlip_None*/, const GFXTextureFilterType filter /*= GFXTextureFilterPoint */ , bool in_wrap /*= true*/ )
 330{
 331   AssertFatal( texture != 0, "No texture specified for drawBitmap()" );
 332
 333   RectI subRegion( 0, 0, texture->mBitmapSize.x, texture->mBitmapSize.y );
 334   RectI stretch( in_rAt.x, in_rAt.y, texture->mBitmapSize.x, texture->mBitmapSize.y );
 335   drawBitmapStretchSR( texture, stretch, subRegion, in_flip, filter, in_wrap );
 336}
 337
 338void GFXDrawUtil::drawBitmapStretch( GFXTextureObject*texture, const RectF &dstRect, const GFXBitmapFlip in_flip /*= GFXBitmapFlip_None*/, const GFXTextureFilterType filter /*= GFXTextureFilterPoint */ , bool in_wrap /*= true*/ )
 339{
 340   AssertFatal( texture != 0, "No texture specified for drawBitmapStretch()" );
 341
 342   RectF subRegion( 0.f, 0.f, (F32)texture->mBitmapSize.x, (F32)texture->mBitmapSize.y );
 343   drawBitmapStretchSR( texture, dstRect, subRegion, in_flip, filter, in_wrap );
 344}
 345
 346void GFXDrawUtil::drawBitmapSR( GFXTextureObject*texture, const Point2F &in_rAt, const RectF &srcRect, const GFXBitmapFlip in_flip /*= GFXBitmapFlip_None*/, const GFXTextureFilterType filter /*= GFXTextureFilterPoint */ , bool in_wrap /*= true*/ )
 347{
 348   AssertFatal( texture != 0, "No texture specified for drawBitmapSR()" );
 349
 350   RectF stretch( in_rAt.x, in_rAt.y, srcRect.len_x(), srcRect.len_y() );
 351   drawBitmapStretchSR( texture, stretch, srcRect, in_flip, filter, in_wrap );
 352}
 353
 354void GFXDrawUtil::drawBitmapStretchSR( GFXTextureObject* texture, const RectF &dstRect, const RectF &srcRect, const GFXBitmapFlip in_flip /*= GFXBitmapFlip_None*/, const GFXTextureFilterType filter /*= GFXTextureFilterPoint */ , bool in_wrap /*= true*/ )
 355{
 356   // Sanity if no texture is specified.
 357   if(!texture)
 358      return;   
 359
 360   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile );
 361   verts.lock();
 362
 363   F32 texLeft   = (srcRect.point.x)                    / (texture->mTextureSize.x);
 364   F32 texRight  = (srcRect.point.x + srcRect.extent.x) / (texture->mTextureSize.x);
 365   F32 texTop    = (srcRect.point.y)                    / (texture->mTextureSize.y);
 366   F32 texBottom = (srcRect.point.y + srcRect.extent.y) / (texture->mTextureSize.y);
 367
 368   F32 screenLeft   = dstRect.point.x;
 369   F32 screenRight  = (dstRect.point.x + dstRect.extent.x);
 370   F32 screenTop    = dstRect.point.y;
 371   F32 screenBottom = (dstRect.point.y + dstRect.extent.y);
 372
 373   if( in_flip & GFXBitmapFlip_X ) 
 374   {
 375      F32 temp = texLeft;
 376      texLeft = texRight;
 377      texRight = temp;
 378   }
 379   if( in_flip & GFXBitmapFlip_Y ) 
 380   {
 381      F32 temp = texTop;
 382      texTop = texBottom;
 383      texBottom = temp;
 384   }
 385
 386   const F32 fillConv = mDevice->getFillConventionOffset();
 387   verts[0].point.set( screenLeft  - fillConv, screenTop    - fillConv, 0.f );
 388   verts[1].point.set( screenRight - fillConv, screenTop    - fillConv, 0.f );
 389   verts[2].point.set( screenLeft  - fillConv, screenBottom - fillConv, 0.f );
 390   verts[3].point.set( screenRight - fillConv, screenBottom - fillConv, 0.f );
 391
 392   verts[0].color = verts[1].color = verts[2].color = verts[3].color = mBitmapModulation;
 393
 394   verts[0].texCoord.set( texLeft,  texTop );
 395   verts[1].texCoord.set( texRight, texTop );
 396   verts[2].texCoord.set( texLeft,  texBottom );
 397   verts[3].texCoord.set( texRight, texBottom );
 398
 399   verts.unlock();
 400
 401   mDevice->setVertexBuffer( verts );
 402
 403   switch (filter)
 404   {
 405   case GFXTextureFilterPoint :
 406      mDevice->setStateBlock(in_wrap ? mBitmapStretchWrapSB : mBitmapStretchSB);
 407      break;
 408   case GFXTextureFilterLinear :
 409      mDevice->setStateBlock(in_wrap ? mBitmapStretchWrapLinearSB : mBitmapStretchLinearSB);
 410      break;
 411   default:
 412      AssertFatal(false, "No GFXDrawUtil state block defined for this filter type!");
 413      mDevice->setStateBlock(mBitmapStretchSB);
 414      break;
 415   }   
 416   mDevice->setTexture( 0, texture );
 417   mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );
 418
 419   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
 420}
 421
 422//-----------------------------------------------------------------------------
 423// Draw Rectangle
 424//-----------------------------------------------------------------------------
 425void GFXDrawUtil::drawRect( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ) 
 426{
 427   drawRect( Point2F((F32)upperLeft.x,(F32)upperLeft.y),Point2F((F32)lowerRight.x,(F32)lowerRight.y),color);
 428}
 429
 430void GFXDrawUtil::drawRect( const RectI &rect, const ColorI &color )
 431{
 432   drawRect( rect.point, Point2I(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1), color );
 433}
 434
 435void GFXDrawUtil::drawRect( const RectF &rect, const ColorI &color )
 436{
 437   drawRect( rect.point, Point2F(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1), color );
 438}
 439
 440void GFXDrawUtil::drawRect( const Point2F &upperLeft, const Point2F &lowerRight, const ColorI &color )
 441{
 442   //
 443   // Convert Box   a----------x
 444   //               |          |
 445   //               x----------b
 446   //
 447   // Into Triangle-Strip Outline
 448   //               v0-----------v2
 449   //               | a         x |
 450   //               |  v1-----v3  |
 451   //               |   |     |   |
 452   //               |  v7-----v5  |
 453   //               | x         b |
 454   //               v6-----------v4
 455   //
 456
 457   // NorthWest and NorthEast facing offset vectors
 458   // These adjust the thickness of the line, it'd be neat if one day
 459   // they were passed in as arguments.
 460   Point2F nw(-0.5f,-0.5f); /*  \  */
 461   Point2F ne(0.5f,-0.5f); /*  /  */
 462
 463   GFXVertexBufferHandle<GFXVertexPCT> verts (mDevice, 10, GFXBufferTypeVolatile );
 464   verts.lock();
 465
 466   F32 ulOffset = 0.5f - mDevice->getFillConventionOffset();
 467
 468   verts[0].point.set( upperLeft.x + ulOffset + nw.x, upperLeft.y + ulOffset + nw.y, 0.0f );
 469   verts[1].point.set( upperLeft.x + ulOffset - nw.x, upperLeft.y + ulOffset - nw.y, 0.0f );
 470   verts[2].point.set( lowerRight.x + ulOffset + ne.x, upperLeft.y + ulOffset + ne.y, 0.0f);
 471   verts[3].point.set( lowerRight.x + ulOffset - ne.x, upperLeft.y + ulOffset - ne.y, 0.0f);
 472   verts[4].point.set( lowerRight.x + ulOffset - nw.x, lowerRight.y + ulOffset - nw.y, 0.0f);
 473   verts[5].point.set( lowerRight.x + ulOffset + nw.x, lowerRight.y + ulOffset + nw.y, 0.0f);
 474   verts[6].point.set( upperLeft.x + ulOffset - ne.x, lowerRight.y + ulOffset - ne.y, 0.0f);
 475   verts[7].point.set( upperLeft.x + ulOffset + ne.x, lowerRight.y + ulOffset + ne.y, 0.0f);
 476   verts[8].point.set( upperLeft.x + ulOffset + nw.x, upperLeft.y + ulOffset + nw.y, 0.0f ); // same as 0
 477   verts[9].point.set( upperLeft.x + ulOffset - nw.x, upperLeft.y + ulOffset - nw.y, 0.0f ); // same as 1
 478
 479   for (S32 i = 0; i < 10; i++)
 480      verts[i].color = color;
 481
 482   verts.unlock();
 483   mDevice->setVertexBuffer( verts );
 484
 485   mDevice->setStateBlock(mRectFillSB);
 486   mDevice->setupGenericShaders();
 487   mDevice->drawPrimitive( GFXTriangleStrip, 0, 8 );
 488}
 489
 490//-----------------------------------------------------------------------------
 491// Draw Rectangle Fill
 492//-----------------------------------------------------------------------------
 493void GFXDrawUtil::drawRectFill( const RectF &rect, const ColorI &color )
 494{
 495   drawRectFill(rect.point, Point2F(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color );
 496}
 497
 498void GFXDrawUtil::drawRectFill( const Point2I &upperLeft, const Point2I &lowerRight, const ColorI &color ) 
 499{   
 500   drawRectFill(Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color);
 501}
 502
 503void GFXDrawUtil::drawRectFill( const RectI &rect, const ColorI &color )
 504{
 505   drawRectFill(rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color );
 506}
 507
 508void GFXDrawUtil::drawRectFill( const Point2F &upperLeft, const Point2F &lowerRight, const ColorI &color )
 509{
 510   //
 511   // Convert Box   a----------x
 512   //               |          |
 513   //               x----------b
 514   // Into Quad
 515   //               v0---------v1
 516   //               | a       x |
 517   //               |           |
 518   //               | x       b |
 519   //               v2---------v3
 520   //
 521
 522   // NorthWest and NorthEast facing offset vectors
 523   Point2F nw(-0.5,-0.5); /*  \  */
 524   Point2F ne(0.5,-0.5); /*  /  */
 525
 526   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile);
 527   verts.lock();
 528
 529   F32 ulOffset = 0.5f - mDevice->getFillConventionOffset();
 530   
 531   verts[0].point.set( upperLeft.x+nw.x + ulOffset, upperLeft.y+nw.y + ulOffset, 0.0f );
 532   verts[1].point.set( lowerRight.x + ne.x + ulOffset, upperLeft.y + ne.y + ulOffset, 0.0f);
 533   verts[2].point.set( upperLeft.x - ne.x + ulOffset, lowerRight.y - ne.y + ulOffset, 0.0f);
 534   verts[3].point.set( lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset, 0.0f);
 535   for (S32 i = 0; i < 4; i++)
 536      verts[i].color = color;
 537
 538   verts.unlock();
 539
 540   mDevice->setStateBlock(mRectFillSB);
 541   mDevice->setVertexBuffer( verts );
 542   mDevice->setupGenericShaders();
 543   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
 544}
 545
 546void GFXDrawUtil::draw2DSquare( const Point2F &screenPoint, F32 width, F32 spinAngle )
 547{
 548   width *= 0.5;
 549
 550   Point3F offset( screenPoint.x, screenPoint.y, 0.0 );
 551
 552   GFXVertexBufferHandle<GFXVertexPCT> verts( mDevice, 4, GFXBufferTypeVolatile );
 553   verts.lock();
 554
 555   verts[0].point.set( -width, -width, 0.0f );
 556   verts[1].point.set( -width, width, 0.0f );
 557   verts[2].point.set( width,  -width, 0.0f );
 558   verts[3].point.set( width,  width, 0.0f );
 559
 560   verts[0].color = verts[1].color = verts[2].color = verts[3].color = mBitmapModulation;
 561
 562   if (spinAngle == 0.0f)
 563   {
 564      for( S32 i = 0; i < 4; i++ )
 565         verts[i].point += offset;
 566   }
 567   else
 568   {
 569      MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
 570
 571      for( S32 i = 0; i < 4; i++ )
 572      {
 573         rotMatrix.mulP( verts[i].point );
 574         verts[i].point += offset;
 575      }
 576   }
 577
 578   verts.unlock();
 579   mDevice->setVertexBuffer( verts );
 580
 581   mDevice->setStateBlock(mRectFillSB);
 582   mDevice->setupGenericShaders();
 583
 584   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
 585}
 586
 587//-----------------------------------------------------------------------------
 588// Draw Line
 589//-----------------------------------------------------------------------------
 590void GFXDrawUtil::drawLine( const Point3F &startPt, const Point3F &endPt, const ColorI &color )
 591{
 592   drawLine( startPt.x, startPt.y, startPt.z, endPt.x, endPt.y, endPt.z, color );
 593}
 594
 595void GFXDrawUtil::drawLine( const Point2F &startPt, const Point2F &endPt, const ColorI &color )
 596{
 597   drawLine( startPt.x, startPt.y, 0.0f, endPt.x, endPt.y, 0.0f, color );
 598}
 599
 600void GFXDrawUtil::drawLine( const Point2I &startPt, const Point2I &endPt, const ColorI &color )
 601{
 602   drawLine( startPt.x, startPt.y, 0.0f, endPt.x, endPt.y, 0.0f, color );
 603}
 604
 605void GFXDrawUtil::drawLine( F32 x1, F32 y1, F32 x2, F32 y2, const ColorI &color )
 606{
 607   drawLine( x1, y1, 0.0f, x2, y2, 0.0f, color );
 608}
 609
 610void GFXDrawUtil::drawLine( F32 x1, F32 y1, F32 z1, F32 x2, F32 y2, F32 z2, const ColorI &color )
 611{
 612   GFXVertexBufferHandle<GFXVertexPCT> verts( mDevice, 2, GFXBufferTypeVolatile );
 613   verts.lock();
 614
 615   verts[0].point.set( x1, y1, z1 );
 616   verts[1].point.set( x2, y2, z2 );
 617   verts[0].color = color;
 618   verts[1].color = color;
 619
 620   verts.unlock();
 621
 622   mDevice->setVertexBuffer( verts );
 623   mDevice->setStateBlock( mRectFillSB );
 624   mDevice->setupGenericShaders();
 625   mDevice->drawPrimitive( GFXLineList, 0, 1 );
 626}
 627
 628//-----------------------------------------------------------------------------
 629// 3D World Draw Misc
 630//-----------------------------------------------------------------------------
 631
 632static SphereMesh gSphere;
 633
 634void GFXDrawUtil::drawSphere( const GFXStateBlockDesc &desc, F32 radius, const Point3F &pos, const ColorI &color, bool drawTop, bool drawBottom, const MatrixF *xfm )
 635{
 636   MatrixF mat;
 637   if ( xfm )
 638      mat = *xfm;
 639   else
 640      mat = MatrixF::Identity;
 641
 642   mat.scale(Point3F(radius,radius,radius));
 643   mat.setPosition(pos);
 644   GFX->pushWorldMatrix();
 645   GFX->multWorld(mat);
 646
 647   const SphereMesh::TriangleMesh * sphereMesh = gSphere.getMesh(2);
 648   S32 numPoly = sphereMesh->numPoly;
 649   S32 totalPoly = 0;
 650   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, numPoly*3, GFXBufferTypeVolatile);
 651   verts.lock();
 652   S32 vertexIndex = 0;
 653   for (S32 i=0; i<numPoly; i++)
 654   {
 655      if (!drawBottom)
 656      {
 657         if (sphereMesh->poly[i].pnt[0].z < -0.01f || sphereMesh->poly[i].pnt[1].z < -0.01f || sphereMesh->poly[i].pnt[2].z < -0.01f)
 658            continue;
 659      }
 660      if (!drawTop)
 661      {
 662         if (sphereMesh->poly[i].pnt[0].z > 0.01f || sphereMesh->poly[i].pnt[1].z > 0.01f || sphereMesh->poly[i].pnt[2].z > 0.01f)
 663            continue;
 664      }
 665      totalPoly++;
 666
 667      verts[vertexIndex].point = sphereMesh->poly[i].pnt[0];
 668      verts[vertexIndex].color = color;
 669      vertexIndex++;
 670
 671      verts[vertexIndex].point = sphereMesh->poly[i].pnt[1];
 672      verts[vertexIndex].color = color;
 673      vertexIndex++;
 674
 675      verts[vertexIndex].point = sphereMesh->poly[i].pnt[2];
 676      verts[vertexIndex].color = color;
 677      vertexIndex++;
 678   }
 679   verts.unlock();
 680
 681   mDevice->setStateBlockByDesc( desc );
 682
 683   mDevice->setVertexBuffer( verts );
 684   mDevice->setupGenericShaders();
 685
 686   mDevice->drawPrimitive( GFXTriangleList, 0, totalPoly );
 687
 688   GFX->popWorldMatrix();
 689}
 690
 691//-----------------------------------------------------------------------------
 692
 693static const Point3F cubePoints[8] = 
 694{
 695   Point3F(-1, -1, -1), Point3F(-1, -1,  1), Point3F(-1,  1, -1), Point3F(-1,  1,  1),
 696   Point3F( 1, -1, -1), Point3F( 1, -1,  1), Point3F( 1,  1, -1), Point3F( 1,  1,  1)
 697};
 698
 699static const U32 cubeFaces[6][4] = 
 700{
 701   { 0, 4, 6, 2 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 },
 702   { 3, 2, 6, 7 }, { 7, 6, 4, 5 }, { 3, 7, 5, 1 }
 703};
 704
 705void GFXDrawUtil::drawTriangle( const GFXStateBlockDesc &desc, const Point3F &p0, const Point3F &p1, const Point3F &p2, const ColorI &color, const MatrixF *xfm )
 706{
 707   if ( desc.fillMode == GFXFillWireframe )
 708      _drawWireTriangle( desc, p0, p1, p2, color, xfm );
 709   else
 710      _drawSolidTriangle( desc, p0, p1, p2, color, xfm );
 711}
 712
 713void GFXDrawUtil::_drawWireTriangle( const GFXStateBlockDesc &desc, const Point3F &p0, const Point3F &p1, const Point3F &p2, const ColorI &color, const MatrixF *xfm )
 714{
 715   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile);
 716   verts.lock();
 717   // Set up the line strip
 718   verts[0].point = p0;
 719   verts[0].color = color;
 720   verts[1].point = p1;
 721   verts[1].color = color;
 722   verts[2].point = p2;
 723   verts[2].color = color;
 724   verts[3].point = p0;
 725   verts[3].color = color;
 726
 727   // Apply xfm if we were passed one.
 728   if ( xfm != NULL )
 729   {
 730      for ( U32 i = 0; i < 4; i++ )
 731         xfm->mulP( verts[i].point );
 732   }
 733
 734   verts.unlock();
 735
 736   GFXStateBlockRef sb = mDevice->createStateBlock( desc );
 737   mDevice->setStateBlock( sb );
 738
 739   mDevice->setVertexBuffer( verts );
 740   mDevice->setupGenericShaders();
 741
 742   mDevice->drawPrimitive( GFXLineStrip, 0, 3 );
 743}
 744
 745void GFXDrawUtil::_drawSolidTriangle( const GFXStateBlockDesc &desc, const Point3F &p0, const Point3F &p1, const Point3F &p2, const ColorI &color, const MatrixF *xfm )
 746{
 747   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 3, GFXBufferTypeVolatile);
 748   verts.lock();
 749   // Set up the line strip
 750   verts[0].point = p0;
 751   verts[0].color = color;
 752   verts[1].point = p1;
 753   verts[1].color = color;
 754   verts[2].point = p2;
 755   verts[2].color = color;
 756
 757   // Apply xfm if we were passed one.
 758   if ( xfm != NULL )
 759   {
 760      for ( U32 i = 0; i < 3; i++ )
 761         xfm->mulP( verts[i].point );
 762   }
 763
 764   verts.unlock();
 765
 766   GFXStateBlockRef sb = mDevice->createStateBlock( desc );
 767   mDevice->setStateBlock( sb );
 768
 769   mDevice->setVertexBuffer( verts );
 770   mDevice->setupGenericShaders();
 771
 772   mDevice->drawPrimitive( GFXTriangleList, 0, 1 );
 773}
 774
 775void GFXDrawUtil::drawPolygon( const GFXStateBlockDesc& desc, const Point3F* points, U32 numPoints, const ColorI& color, const MatrixF* xfm /* = NULL */ )
 776{
 777   const bool isWireframe = ( desc.fillMode == GFXFillWireframe );
 778   const U32 numVerts = isWireframe ? numPoints + 1 : numPoints;
 779   GFXVertexBufferHandle< GFXVertexPCT> verts( mDevice, numVerts, GFXBufferTypeVolatile );
 780   verts.lock();
 781   for( U32 i = 0; i < numPoints; ++ i )
 782   {
 783      verts[ i ].point = points[ i ];
 784      verts[ i ].color = color;
 785   }
 786
 787   if( xfm )
 788   {
 789      for( U32 i = 0; i < numPoints; ++ i )
 790         xfm->mulP( verts[ i ].point );
 791   }
 792   
 793   if( isWireframe )
 794   {
 795      verts[ numVerts - 1 ].point = verts[ 0 ].point;
 796      verts[ numVerts - 1 ].color = color;
 797   }
 798
 799   verts.unlock();
 800
 801   mDevice->setStateBlockByDesc( desc );
 802
 803   mDevice->setVertexBuffer( verts );
 804   mDevice->setupGenericShaders();
 805
 806   if( desc.fillMode == GFXFillWireframe )
 807      mDevice->drawPrimitive( GFXLineStrip, 0, numPoints );
 808   else
 809      mDevice->drawPrimitive( GFXTriangleStrip, 0, numPoints - 2 );
 810}
 811
 812void GFXDrawUtil::drawCube( const GFXStateBlockDesc &desc, const Box3F &box, const ColorI &color, const MatrixF *xfm )
 813{
 814   drawCube( desc, box.getExtents(), box.getCenter(), color, xfm );
 815}
 816
 817void GFXDrawUtil::drawCube( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const ColorI &color, const MatrixF *xfm )
 818{
 819   if ( desc.fillMode == GFXFillWireframe )
 820      _drawWireCube( desc, size, pos, color, xfm );
 821   else
 822      _drawSolidCube( desc, size, pos, color, xfm );
 823}
 824
 825void GFXDrawUtil::_drawWireCube( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const ColorI &color, const MatrixF *xfm )
 826{
 827   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 30, GFXBufferTypeVolatile);
 828   verts.lock();
 829
 830   Point3F halfSize = size * 0.5f;
 831   // setup 6 line loops
 832   U32 vertexIndex = 0;
 833   for(S32 i = 0; i < 6; i++)
 834   {
 835      for(S32 j = 0; j < 5; j++)
 836      {
 837         S32 idx = cubeFaces[i][j%4];
 838
 839         verts[vertexIndex].point = cubePoints[idx] * halfSize;
 840         verts[vertexIndex].color = color;
 841         vertexIndex++;
 842      }
 843   }
 844
 845   // Apply xfm if we were passed one.
 846   if ( xfm != NULL )
 847   {
 848      for ( U32 i = 0; i < 30; i++ )
 849         xfm->mulV( verts[i].point );
 850   }
 851
 852   // Apply position offset
 853   for ( U32 i = 0; i < 30; i++ )
 854      verts[i].point += pos;
 855
 856   verts.unlock();
 857
 858   mDevice->setStateBlockByDesc( desc );
 859
 860   mDevice->setVertexBuffer( verts );
 861   mDevice->setupGenericShaders();
 862
 863   for( U32 i=0; i<6; i++ )
 864      mDevice->drawPrimitive( GFXLineStrip, i*5, 4 );
 865}
 866
 867void GFXDrawUtil::_drawSolidCube( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const ColorI &color, const MatrixF *xfm )
 868{
 869   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 36, GFXBufferTypeVolatile);
 870   verts.lock();
 871
 872   Point3F halfSize = size * 0.5f;
 873   // setup 6 line loops
 874   U32 vertexIndex = 0;
 875   U32 idx;
 876   for(S32 i = 0; i < 6; i++)
 877   {
 878      idx = cubeFaces[i][0];
 879      verts[vertexIndex].point = cubePoints[idx] * halfSize;      
 880      verts[vertexIndex].color = color;
 881      vertexIndex++;
 882
 883      idx = cubeFaces[i][1];
 884      verts[vertexIndex].point = cubePoints[idx] * halfSize;
 885      verts[vertexIndex].color = color;
 886      vertexIndex++;
 887
 888      idx = cubeFaces[i][3];
 889      verts[vertexIndex].point = cubePoints[idx] * halfSize;
 890      verts[vertexIndex].color = color;
 891      vertexIndex++;
 892
 893      idx = cubeFaces[i][1];
 894      verts[vertexIndex].point = cubePoints[idx] * halfSize;
 895      verts[vertexIndex].color = color;
 896      vertexIndex++;
 897
 898      idx = cubeFaces[i][2];
 899      verts[vertexIndex].point = cubePoints[idx] * halfSize;
 900      verts[vertexIndex].color = color;
 901      vertexIndex++;
 902
 903      idx = cubeFaces[i][3];
 904      verts[vertexIndex].point = cubePoints[idx] * halfSize;
 905      verts[vertexIndex].color = color;
 906      vertexIndex++;
 907   }
 908
 909   // Apply xfm if we were passed one.
 910   if ( xfm != NULL )
 911   {
 912      for ( U32 i = 0; i < 36; i++ )
 913         xfm->mulV( verts[i].point );
 914   }
 915
 916   // Apply position offset
 917   for ( U32 i = 0; i < 36; i++ )
 918      verts[i].point += pos;
 919
 920   verts.unlock();
 921
 922   mDevice->setStateBlockByDesc( desc );
 923
 924   mDevice->setVertexBuffer( verts );
 925   mDevice->setupGenericShaders();
 926
 927   mDevice->drawPrimitive( GFXTriangleList, 0, 12 );
 928}
 929
 930void GFXDrawUtil::drawPolyhedron( const GFXStateBlockDesc &desc, const AnyPolyhedron &poly, const ColorI &color, const MatrixF *xfm )
 931{
 932   if ( desc.fillMode == GFXFillWireframe )
 933      _drawWirePolyhedron( desc, poly, color, xfm );
 934   else
 935      _drawSolidPolyhedron( desc, poly, color, xfm );
 936}
 937
 938void GFXDrawUtil::_drawWirePolyhedron( const GFXStateBlockDesc &desc, const AnyPolyhedron &poly, const ColorI &color, const MatrixF *xfm )
 939{
 940   GFXDEBUGEVENT_SCOPE( GFXDrawUtil_DrawWirePolyhedron, ColorI::GREEN );
 941
 942   const U32 numEdges = poly.getNumEdges();
 943   const Point3F* points = poly.getPoints();
 944   const Polyhedron::Edge* edges = poly.getEdges();
 945
 946   // Allocate a temporary vertex buffer.
 947
 948   GFXVertexBufferHandle< GFXVertexPCT> verts( mDevice, numEdges * 2, GFXBufferTypeVolatile);
 949
 950   // Fill it with the vertices for the edges.
 951   verts.lock();
 952   for( U32 i = 0; i < numEdges; ++ i )
 953   {
 954      const U32 nvert = i * 2;
 955      verts[ nvert + 0 ].point = points[ edges[ i ].vertex[ 0 ] ];
 956      verts[ nvert + 0 ].color = color;
 957
 958      verts[ nvert + 1 ].point = points[ edges[ i ].vertex[ 1 ] ];
 959      verts[ nvert + 1 ].color = color;
 960   }
 961
 962   if( xfm )
 963   {
 964      for( U32 i = 0; i < numEdges; ++ i )
 965      {
 966         xfm->mulP( verts[ i + 0 ].point );
 967         xfm->mulP( verts[ i + 1 ].point );
 968      }
 969   }
 970   verts.unlock();
 971
 972   // Render the line list.
 973
 974   mDevice->setStateBlockByDesc( desc );
 975
 976   mDevice->setVertexBuffer( verts );
 977   mDevice->setupGenericShaders();
 978
 979   mDevice->drawPrimitive( GFXLineList, 0, numEdges );
 980}
 981
 982void GFXDrawUtil::_drawSolidPolyhedron( const GFXStateBlockDesc &desc, const AnyPolyhedron &poly, const ColorI &color, const MatrixF *xfm )
 983{
 984   GFXDEBUGEVENT_SCOPE( GFXDrawUtil_DrawSolidPolyhedron, ColorI::GREEN );
 985
 986   const U32 numPoints = poly.getNumPoints();
 987   const Point3F* points = poly.getPoints();
 988   const PlaneF* planes = poly.getPlanes();
 989   const Point3F viewDir = GFX->getViewMatrix().getForwardVector();
 990
 991   // Create a temp buffer for the vertices and
 992   // put all the polyhedron's points in there.
 993
 994   GFXVertexBufferHandle< GFXVertexPCT> verts( mDevice, numPoints, GFXBufferTypeVolatile );
 995   verts.lock();
 996   for( U32 i = 0; i < numPoints; ++ i )
 997   {
 998      verts[ i ].point = points[ i ];
 999      verts[ i ].color = color;
1000   }
1001
1002   if( xfm )
1003   {
1004      for( U32 i = 0; i < numPoints; ++ i )
1005         xfm->mulP( verts[ i ].point );
1006   }
1007   verts.unlock();
1008
1009   // Allocate a temp buffer for the face indices.
1010
1011   const U32 numIndices = poly.getNumEdges() * 3;
1012   const U32 numPlanes = poly.getNumPlanes();
1013
1014   GFXPrimitiveBufferHandle prims( mDevice, numIndices, 0, GFXBufferTypeVolatile );
1015
1016   // Unfortunately, since polygons may have varying numbers of
1017   // vertices, we also need to retain that information.
1018
1019   FrameTemp< U32> numIndicesForPoly( numPlanes );
1020   U32 numPolys = 0;
1021
1022   // Create all the polygon indices.
1023
1024   U16* indices;
1025   prims.lock( &indices );
1026   U32 idx = 0;
1027   for( U32 i = 0; i < numPlanes; ++ i )
1028   {
1029      // Since face extraction is somewhat costly, don't bother doing it for
1030      // backfacing polygons if culling is enabled.
1031
1032      if( !desc.cullDefined || desc.cullMode != GFXCullNone )
1033      {
1034         F32 dot = mDot( planes[ i ], viewDir );
1035
1036         // See if it faces *the same way* as the view direction.  This would
1037         // normally mean that the face is *not* backfacing but since we expect
1038         // planes on the polyhedron to be facing *inwards*, we need to reverse
1039         // the logic here.
1040
1041         if( dot > 0.f )
1042            continue;
1043      }
1044
1045      U32 polyIDx = poly.extractFace( i, &indices[ idx ], numIndices - idx );
1046      numIndicesForPoly[ numPolys ] = polyIDx;
1047      idx += polyIDx;
1048
1049      numPolys ++;
1050   }
1051   prims.unlock();
1052
1053   // Set up state.
1054
1055   mDevice->setStateBlockByDesc( desc );
1056   mDevice->setupGenericShaders();
1057
1058   mDevice->setVertexBuffer( verts );
1059   mDevice->setPrimitiveBuffer( prims );
1060
1061   // Render one triangle fan for each polygon.
1062
1063   U32 startIndex = 0;
1064   for( U32 i = 0; i < numPolys; ++ i )
1065   {
1066      U32 numVerts = numIndicesForPoly[ i ];
1067      mDevice->drawIndexedPrimitive( GFXTriangleStrip, 0, 0, numPoints, startIndex, numVerts - 2 );
1068      startIndex += numVerts;
1069   }
1070}
1071
1072void GFXDrawUtil::drawObjectBox( const GFXStateBlockDesc &desc, const Point3F &size, const Point3F &pos, const MatrixF &objMat, const ColorI &color )
1073{
1074   GFXTransformSaver saver;
1075
1076   mDevice->setStateBlockByDesc( desc );
1077
1078   MatrixF scaledObjMat( true );
1079   scaledObjMat = objMat;
1080
1081   scaledObjMat.scale( size );
1082   scaledObjMat.setPosition( pos );
1083   //to linear is done in primbuilder
1084   PrimBuild::color( color );
1085   PrimBuild::begin( GFXLineList, 48 );
1086
1087   Point3F cubePts[8];
1088   for (U32 i = 0; i < 8; i++)
1089   {
1090      cubePts[i] = cubePoints[i]/2;
1091   }
1092
1093   // 8 corner points of the box   
1094   for ( U32 i = 0; i < 8; i++ )
1095   {
1096      //const Point3F &start = cubePoints[i];  
1097
1098      // 3 lines per corner point
1099      for ( U32 j = 0; j < 3; j++ )
1100      {
1101         Point3F start = cubePoints[i];
1102         Point3F end = start;
1103         end[j] *= 0.8f;
1104
1105         scaledObjMat.mulP(start);
1106         PrimBuild::vertex3fv(start);
1107         scaledObjMat.mulP(end);
1108         PrimBuild::vertex3fv(end);            
1109      }
1110   }
1111
1112   PrimBuild::end();
1113}
1114
1115static const Point2F circlePoints[] =
1116{
1117   Point2F(0.707107f, 0.707107f),
1118   Point2F(0.923880f, 0.382683f),
1119   Point2F(1.000000f, 0.000000f),
1120   Point2F(0.923880f, -0.382684f),
1121   Point2F(0.707107f, -0.707107f),
1122   Point2F(0.382683f, -0.923880f),
1123   Point2F(0.000000f, -1.000000f),
1124   Point2F(-0.382683f, -0.923880f),
1125   Point2F(-0.707107f, -0.707107f),
1126   Point2F(-0.923880f, -0.382684f),
1127   Point2F(-1.000000f, 0.000000f),
1128   Point2F(-0.923879f, 0.382684f),
1129   Point2F(-0.707107f, 0.707107f),
1130   Point2F(-0.382683f, 0.923880f),
1131   Point2F(0.000000f, 1.000000f),
1132   Point2F(0.382684f, 0.923879f)
1133};
1134
1135void GFXDrawUtil::drawCapsule( const GFXStateBlockDesc &desc, const Point3F &center, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm )
1136{
1137   if ( desc.fillMode == GFXFillWireframe )
1138      _drawWireCapsule( desc, center, radius, height, color, xfm );
1139   else
1140      _drawSolidCapsule( desc, center, radius, height, color, xfm );
1141}
1142
1143void GFXDrawUtil::_drawSolidCapsule( const GFXStateBlockDesc &desc, const Point3F &center, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm )
1144{  
1145   MatrixF mat;
1146   if ( xfm )
1147      mat = *xfm;      
1148   else
1149      mat = MatrixF::Identity;
1150
1151   S32 numPoints = sizeof(circlePoints)/sizeof(Point2F);
1152   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, numPoints * 2 + 2, GFXBufferTypeVolatile);
1153   verts.lock();
1154   for (S32 i=0; i<numPoints + 1; i++)
1155   {
1156      S32 imod = i % numPoints;      
1157      verts[2 * i].point = Point3F( circlePoints[imod].x * radius, circlePoints[imod].y * radius, height/2 );
1158      verts[2 * i].color = color;
1159      verts[2 * i + 1].point = Point3F( circlePoints[imod].x * radius, circlePoints[imod].y * radius, -height/2 );
1160      verts[2 * i + 1].color = color;
1161   }
1162
1163   S32 totalNumPnts = numPoints * 2 + 2;
1164
1165   // Apply xfm if we were passed one.
1166   for ( U32 i = 0; i < totalNumPnts; i++ )
1167      mat.mulV( verts[i].point );
1168
1169   // Apply position offset
1170   for ( U32 i = 0; i < totalNumPnts; i++ )
1171      verts[i].point += center;
1172
1173   verts.unlock();
1174
1175   mDevice->setStateBlockByDesc( desc );
1176
1177   mDevice->setVertexBuffer( verts );
1178   mDevice->setupGenericShaders();
1179
1180   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 * numPoints );
1181
1182   Point3F sphereCenter;
1183   MatrixF sphereMat;
1184
1185   if ( xfm )
1186      sphereMat = *xfm;
1187   else
1188      sphereMat = MatrixF::Identity;   
1189
1190   sphereCenter.set( 0, 0, 0.5f * height );
1191   mat.mulV( sphereCenter );
1192   sphereCenter += center;
1193
1194   drawSphere( desc, radius, sphereCenter, color, true, false, &sphereMat );
1195
1196   sphereCenter.set( 0, 0, -0.5f * height );
1197   mat.mulV( sphereCenter );
1198   sphereCenter += center;
1199
1200   drawSphere( desc, radius, sphereCenter, color, false, true, &sphereMat );
1201}
1202
1203void GFXDrawUtil::_drawWireCapsule( const GFXStateBlockDesc &desc, const Point3F &center, F32 radius, F32 height, const ColorI &color, const MatrixF *xfm )
1204{
1205   MatrixF mat;
1206   if (xfm)
1207      mat = *xfm;
1208   else
1209      mat = MatrixF::Identity;
1210
1211   S32 numPoints = sizeof(circlePoints) / sizeof(Point2F);
1212   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, numPoints * 2 + 2, GFXBufferTypeVolatile);
1213   verts.lock();
1214   for (S32 i = 0; i < numPoints + 1; i++)
1215   {
1216      S32 imod = i % numPoints;
1217      verts[2 * i].point = Point3F(circlePoints[imod].x * radius, circlePoints[imod].y * radius, height / 2);
1218      verts[2 * i].color = color;
1219      verts[2 * i + 1].point = Point3F(circlePoints[imod].x * radius, circlePoints[imod].y * radius, -height / 2);
1220      verts[2 * i + 1].color = color;
1221   }
1222
1223   S32 totalNumPnts = numPoints * 2 + 2;
1224
1225   // Apply xfm if we were passed one.
1226   for (U32 i = 0; i < totalNumPnts; i++)
1227      mat.mulV(verts[i].point);
1228
1229   // Apply position offset
1230   for (U32 i = 0; i < totalNumPnts; i++)
1231      verts[i].point += center;
1232
1233   verts.unlock();
1234
1235   mDevice->setStateBlockByDesc(desc);
1236
1237   mDevice->setVertexBuffer(verts);
1238   mDevice->setupGenericShaders();
1239
1240   mDevice->drawPrimitive(GFXTriangleStrip, 0, 2 * numPoints);
1241
1242   Point3F sphereCenter;
1243   MatrixF sphereMat;
1244
1245   if (xfm)
1246      sphereMat = *xfm;
1247   else
1248      sphereMat = MatrixF::Identity;
1249
1250   sphereCenter.set(0, 0, 0.5f * height);
1251   mat.mulV(sphereCenter);
1252   sphereCenter += center;
1253
1254   drawSphere(desc, radius, sphereCenter, color, true, false, &sphereMat);
1255
1256   sphereCenter.set(0, 0, -0.5f * height);
1257   mat.mulV(sphereCenter);
1258   sphereCenter += center;
1259
1260   drawSphere(desc, radius, sphereCenter, color, false, true, &sphereMat);
1261}
1262
1263void GFXDrawUtil::drawCone( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 baseRadius, const ColorI &color )
1264{   
1265   VectorF uvec = tipPnt - basePnt;
1266   F32 height = uvec.len();
1267   uvec.normalize();
1268   MatrixF mat( true );
1269   MathUtils::getMatrixFromUpVector( uvec, &mat );   
1270   mat.setPosition(basePnt);
1271
1272   Point3F scale( baseRadius, baseRadius, height );
1273   mat.scale(scale);
1274
1275   GFXTransformSaver saver;
1276
1277   mDevice->pushWorldMatrix();
1278   mDevice->multWorld(mat);
1279
1280   S32 numPoints = sizeof(circlePoints)/sizeof(Point2F);
1281   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, numPoints * 3 + 2, GFXBufferTypeVolatile);
1282   verts.lock();
1283   F32 sign = -1.f;
1284   S32 indexDown = 0; //counting down from numPoints
1285   S32 indexUp = 0; //counting up from 0
1286   S32 index = 0; //circlePoints index for cap
1287
1288   for (S32 i = 0; i < numPoints + 1; i++)
1289   {
1290      //Top cap
1291      if (i != numPoints)
1292      {
1293         if (sign < 0)
1294            index = indexDown;
1295         else
1296            index = indexUp;
1297
1298         verts[i].point = Point3F(circlePoints[index].x, circlePoints[index].y, 0);
1299         verts[i].color = color;
1300
1301         if (sign < 0)
1302            indexUp += 1;
1303         else
1304            indexDown = numPoints - indexUp;
1305
1306         // invert sign
1307         sign *= -1.0f;
1308      }
1309
1310      //cone
1311      S32 imod = i % numPoints;
1312      S32 vertindex = 2 * i + numPoints;
1313      verts[vertindex].point = Point3F(circlePoints[imod].x, circlePoints[imod].y, 0);
1314      verts[vertindex].color = color;
1315      verts[vertindex + 1].point = Point3F(0.0f, 0.0f, 1.0f);
1316      verts[vertindex + 1].color = color;
1317   }
1318
1319   verts.unlock();
1320
1321   mDevice->setStateBlockByDesc( desc );
1322
1323   mDevice->setVertexBuffer( verts );
1324   mDevice->setupGenericShaders();
1325
1326   mDevice->drawPrimitive(GFXTriangleStrip, 0, numPoints - 2);
1327   mDevice->drawPrimitive(GFXTriangleStrip, numPoints, numPoints * 2);
1328
1329   mDevice->popWorldMatrix();
1330
1331}
1332
1333void GFXDrawUtil::drawCylinder( const GFXStateBlockDesc &desc, const Point3F &basePnt, const Point3F &tipPnt, F32 radius, const ColorI &color )
1334{
1335   VectorF uvec = tipPnt - basePnt;
1336   F32 height = uvec.len();
1337   uvec.normalize();
1338   MatrixF mat( true );
1339   MathUtils::getMatrixFromUpVector( uvec, &mat );   
1340   mat.setPosition(basePnt);
1341
1342   Point3F scale( radius, radius, height * 2 );
1343   mat.scale(scale);
1344   GFXTransformSaver saver;
1345
1346   mDevice->pushWorldMatrix();
1347   mDevice->multWorld(mat);
1348
1349   S32 numPoints = sizeof(circlePoints) / sizeof(Point2F);
1350   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, numPoints *4 + 2, GFXBufferTypeVolatile);
1351   verts.lock();
1352   F32 sign = -1.f;
1353   S32 indexDown = 0; //counting down from numPoints
1354   S32 indexUp = 0; //counting up from 0
1355   S32 index = 0; //circlePoints index for caps
1356
1357   for (S32 i = 0; i < numPoints + 1; i++)
1358   {
1359      //Top/Bottom cap
1360      if (i != numPoints)
1361      {
1362         if (sign < 0)
1363            index = indexDown;
1364         else
1365            index = indexUp;
1366
1367         verts[i].point = Point3F(circlePoints[index].x, circlePoints[index].y, 0);
1368         verts[i].color = color;
1369         verts[i + numPoints].point = Point3F(circlePoints[index].x, circlePoints[index].y, 0.5f);
1370         verts[i + numPoints].color = color;
1371
1372         if (sign < 0)
1373            indexUp += 1;
1374         else
1375            indexDown = numPoints - indexUp;
1376
1377         // invert sign
1378         sign *= -1.0f;
1379      }
1380
1381      //cylinder
1382      S32 imod = i % numPoints;
1383      S32 vertindex = 2 * i + (numPoints * 2);
1384      verts[vertindex].point = Point3F(circlePoints[imod].x, circlePoints[imod].y, 0);
1385      verts[vertindex].color = color;
1386      verts[vertindex + 1].point = Point3F(circlePoints[imod].x, circlePoints[imod].y, 0.5f);
1387      verts[vertindex + 1].color = color;
1388   }
1389
1390   verts.unlock();
1391
1392   mDevice->setStateBlockByDesc( desc );
1393
1394   mDevice->setVertexBuffer( verts );
1395   mDevice->setupGenericShaders();
1396
1397   mDevice->drawPrimitive( GFXTriangleStrip, 0, numPoints-2 );
1398   mDevice->drawPrimitive( GFXTriangleStrip, numPoints, numPoints - 2);
1399   mDevice->drawPrimitive( GFXTriangleStrip, numPoints*2, numPoints * 2);
1400
1401   mDevice->popWorldMatrix();
1402}
1403
1404void GFXDrawUtil::drawArrow( const GFXStateBlockDesc &desc, const Point3F &start, const Point3F &end, const ColorI &color, F32 baseRad )
1405{   
1406   GFXTransformSaver saver;
1407
1408   // Direction and length of the arrow.
1409   VectorF dir = end - start;
1410   F32 len = dir.len();
1411   dir.normalize();   
1412   len *= 0.2f;      
1413
1414   // Base of the cone will be a distance back from the end of the arrow
1415   // proportional to the total distance of the arrow... 0.3f looks about right.
1416   Point3F coneBase = end - dir * len * 0.3f;
1417
1418   // Calculate the radius of the cone given that we want the cone to have
1419   // an angle of 25 degrees (just because it looks good).
1420   F32 coneLen = (baseRad != 0.0f) ? baseRad * 4.0 :( end - coneBase ).len();
1421   F32 coneDiameter = (baseRad != 0.0f) ? baseRad*4.0f : mTan( mDegToRad(25.0f) ) * coneLen;
1422
1423   // Draw the cone on at the arrow's tip.
1424   drawCone( desc, coneBase, end, coneDiameter / 2.0f, color );
1425
1426   // Get the difference in length from
1427   // the start of the cone to the end
1428   // of the cylinder so we can put the
1429   // end of the cylinder right against where
1430   // the cone starts.
1431   Point3F coneDiff = end - coneBase;
1432
1433   // Draw the cylinder.
1434   F32 stickRadius = (baseRad != 0.0f) ? baseRad : len * 0.025f;
1435   drawCylinder( desc, start, end - coneDiff, stickRadius, color );
1436}
1437
1438void GFXDrawUtil::drawFrustum( const Frustum &f, const ColorI &color )
1439{
1440   const Point3F  *points = f.getPoints();
1441
1442   // Draw near and far planes.
1443   for (U32 offset = 0; offset < 8; offset+=4)
1444   {      
1445      drawLine(points[offset+0], points[offset+1], color);
1446      drawLine(points[offset+2], points[offset+3], color);
1447      drawLine(points[offset+0], points[offset+2], color);
1448      drawLine(points[offset+1], points[offset+3], color);            
1449   }
1450
1451   // connect the near and far planes
1452   drawLine(points[Frustum::NearTopLeft], points[Frustum::FarTopLeft], color);
1453   drawLine(points[Frustum::NearTopRight], points[Frustum::FarTopRight], color);
1454   drawLine(points[Frustum::NearBottomLeft], points[Frustum::FarBottomLeft], color);
1455   drawLine(points[Frustum::NearBottomRight], points[Frustum::FarBottomRight], color);
1456}
1457
1458void GFXDrawUtil::drawSolidPlane( const GFXStateBlockDesc &desc, const Point3F &pos, const Point2F &size, const ColorI &color )
1459{
1460   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile);
1461   verts.lock();
1462   verts[0].point = pos + Point3F( -size.x / 2.0f, -size.y / 2.0f, 0 );
1463   verts[0].color = color;
1464   verts[1].point = pos + Point3F( -size.x / 2.0f, size.y / 2.0f, 0 );
1465   verts[1].color = color;
1466   verts[2].point = pos + Point3F( size.x / 2.0f, size.y / 2.0f, 0 );
1467   verts[2].color = color;
1468   verts[3].point = pos + Point3F( size.x / 2.0f, -size.y / 2.0f, 0 );
1469   verts[3].color = color;
1470
1471   verts.unlock();
1472
1473   mDevice->setStateBlockByDesc( desc );
1474
1475   mDevice->setVertexBuffer( verts );
1476   mDevice->setupGenericShaders();
1477
1478   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
1479}
1480
1481void GFXDrawUtil::drawPlaneGrid( const GFXStateBlockDesc &desc, const Point3F &pos, const Point2F &size, const Point2F &step, const ColorI &color, Plane plane )
1482{
1483   // Note that when calculating the number of steps, we +0.5 to round up,
1484   // and +1 for the last line (ie. 4 steps needs 5 lines to be rendered)
1485   U32 uSteps = 0;
1486   if( step.x > 0 )
1487      uSteps = size.x / step.x + 0.5 + 1;
1488
1489   U32 vSteps = 0;
1490   if( step.y > 0 )
1491      vSteps = size.y / step.y + 0.5 + 1;
1492      
1493   if( uSteps <= 1 || vSteps <= 1 )
1494      return;
1495      
1496   const U32 numVertices = uSteps * 2 + vSteps * 2;
1497   const U32 numLines = uSteps + vSteps;
1498   
1499   Point3F origin;
1500   switch( plane )
1501   {
1502      case PlaneXY:
1503         origin = Point3F( pos.x - ( size.x / 2.0f ), pos.y - ( size.y / 2.0f ), pos.z );
1504         break;
1505
1506      case PlaneXZ:
1507         origin = Point3F( pos.x - ( size.x / 2.0f ), pos.y, pos.z - ( size.y / 2.0f ) );
1508         break;
1509
1510      case PlaneYZ:
1511         origin = Point3F( pos.x, pos.y - ( size.x / 2.0f ), pos.z - ( size.y / 2.0f ) );
1512         break;
1513   }
1514
1515   GFXVertexBufferHandle<GFXVertexPCT> verts( mDevice, numVertices, GFXBufferTypeVolatile );
1516   verts.lock();
1517   U32 vertCount = 0;
1518
1519   if( plane == PlaneXY || plane == PlaneXZ )
1520   {
1521      F32 start = mFloor( origin.x / step.x + 0.5f ) * step.x;
1522      for ( U32 i = 0; i < uSteps; i++ )
1523      {
1524         verts[vertCount].point = Point3F( start + step.x * i, origin.y, origin.z );
1525         verts[vertCount].color = color;
1526         ++vertCount;
1527
1528         if( plane == PlaneXY )
1529            verts[vertCount].point = Point3F( start + step.x * i, origin.y + size.y, origin.z );
1530         else
1531            verts[vertCount].point = Point3F( start + step.x * i, origin.y,  origin.z + size.y );
1532            
1533         verts[vertCount].color = color;
1534         ++vertCount;
1535      }
1536   }
1537
1538   if( plane == PlaneXY || plane == PlaneYZ )
1539   {      
1540      U32 num;
1541      F32 stp;
1542      if( plane == PlaneXY )
1543      {
1544         num = vSteps;
1545         stp = step.y;
1546      }
1547      else
1548      {
1549         num = uSteps;
1550         stp = step.x;
1551      }
1552
1553      F32 start = mFloor( origin.y / stp + 0.5f ) * stp;
1554         
1555      for ( U32 i = 0; i < num; i++ )
1556      {
1557         verts[vertCount].point = Point3F( origin.x, start + stp * i, origin.z );
1558         verts[vertCount].color = color;
1559         ++vertCount;
1560
1561         if( plane == PlaneXY )
1562            verts[vertCount].point = Point3F( origin.x + size.x, start + stp * i, origin.z );
1563         else
1564            verts[vertCount].point = Point3F( origin.x, start + stp * i, origin.z + size.x );
1565            
1566         verts[vertCount].color = color;
1567         ++vertCount;
1568      }
1569   }
1570
1571   if( plane == PlaneXZ || plane == PlaneYZ )
1572   {
1573      F32 start = mFloor( origin.z / step.y + 0.5f ) * step.y;
1574      for ( U32 i = 0; i < vSteps; i++ )
1575      {
1576         verts[vertCount].point = Point3F( origin.x, origin.y, start + step.y * i );
1577         verts[vertCount].color = color;
1578         ++vertCount;
1579
1580         if( plane == PlaneXZ )
1581            verts[vertCount].point = Point3F( origin.x + size.x, origin.y, start + step.y * i );
1582         else
1583            verts[vertCount].point = Point3F( origin.x, origin.y + size.x, start + step.y * i );
1584            
1585         verts[vertCount].color = color;
1586         ++vertCount;
1587      }
1588   }
1589
1590   verts.unlock();
1591
1592   mDevice->setStateBlockByDesc( desc );
1593
1594   mDevice->setVertexBuffer( verts );
1595   mDevice->setupGenericShaders();
1596
1597   mDevice->drawPrimitive( GFXLineList, 0, numLines );
1598}
1599
1600void GFXDrawUtil::drawTransform( const GFXStateBlockDesc &desc, const MatrixF &mat, const Point3F *scale, const ColorI colors[3] )
1601{
1602   GFXTransformSaver saver;
1603
1604   GFX->multWorld( mat );
1605
1606   GFXVertexBufferHandle<GFXVertexPCT> verts( mDevice, 6, GFXBufferTypeVolatile );
1607   verts.lock();
1608
1609   const static ColorI defColors[3] = 
1610   {
1611      ColorI::RED,
1612      ColorI::GREEN,
1613      ColorI::BLUE
1614   };
1615
1616   const ColorI *colArray = ( colors != NULL ) ? colors : defColors;
1617
1618   verts[0].point = Point3F::Zero;
1619   verts[0].color = colArray[0];
1620   verts[1].point = Point3F( 1, 0, 0 );
1621   verts[1].color = colArray[0];
1622   verts[2].point = Point3F::Zero;
1623   verts[2].color = colArray[1];
1624   verts[3].point = Point3F( 0, 1, 0 );
1625   verts[3].color = colArray[1];
1626   verts[4].point = Point3F::Zero;
1627   verts[4].color = colArray[2];
1628   verts[5].point = Point3F( 0, 0, 1 );
1629   verts[5].color = colArray[2];
1630
1631   if ( scale )
1632   {
1633      verts[1].point *= *scale;
1634      verts[3].point *= *scale;
1635      verts[5].point *= *scale;      
1636   }
1637
1638   verts.unlock();
1639
1640   mDevice->setStateBlockByDesc( desc );
1641
1642   mDevice->setVertexBuffer( verts );
1643   mDevice->setupGenericShaders();
1644   mDevice->drawPrimitive( GFXLineList, 0, 3 );
1645}
1646