gfxDrawUtil.cpp 52 KB

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