gfxDrawUtil.cpp
Engine/source/gfx/gfxDrawUtil.cpp
Public Variables
cubePoints [8]
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 ¢er, 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 ¢er, 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 ¢er, 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