Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

605 lines
19 KiB

  1. //=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
  2. //
  3. // The copyright to the contents herein is the property of Valve, L.L.C.
  4. // The contents may be used and/or copied only with the written permission of
  5. // Valve, L.L.C., or in accordance with the terms and conditions stipulated in
  6. // the agreement/contract under which the contents have been supplied.
  7. //
  8. // $Header: $
  9. // $NoKeywords: $
  10. //
  11. //=============================================================================
  12. // tier 1
  13. #include "tier1/strtools.h"
  14. #include "utlvector.h"
  15. #include "mathlib/vmatrix.h"
  16. #include "FileSystem.h"
  17. #include "bitmap/tgaloader.h"
  18. #include "tier1/utlbuffer.h"
  19. #include "tier1/utlstring.h"
  20. #include "pixelwriter.h"
  21. #include "vguimaterial.h"
  22. #include "materialsystem/itexture.h"
  23. #include "materialsystem/imaterial.h"
  24. #include "materialsystem/imaterialsystem.h"
  25. #include "materialsystem/materialsystemutil.h"
  26. #include "toolutils/enginetools_int.h"
  27. #include "bitmap/imageformat.h"
  28. #include "vtf/vtf.h"
  29. #include "tier1/keyvalues.h"
  30. #include "tier1/utllinkedlist.h"
  31. #include "materialsystem/imesh.h"
  32. #include <vstdlib/random.h>
  33. #include "tier0/vprof.h"
  34. #include "bitmap/psheet.h"
  35. #include "materialsystem/imaterialvar.h"
  36. #define WIN32_LEAN_AND_MEAN
  37. #include <windows.h>
  38. #include <vfw.h>
  39. #define MAX_LAYERS 10
  40. enum
  41. {
  42. SUBLAYER_STATIC,
  43. SUBLAYER_DYNAMIC,
  44. SUBLAYER_FONT,
  45. SUBLAYER_MAX,
  46. };
  47. //-----------------------------------------------------------------------------
  48. // Class to render a zillion boxes with a tga material.
  49. //-----------------------------------------------------------------------------
  50. class CTGARenderer : public ITGARenderer
  51. {
  52. public:
  53. void Init( int screenWidth, int screenHeight, int numTiles );
  54. void Render();
  55. void Shutdown();
  56. private:
  57. struct UIQuadInfo
  58. {
  59. public:
  60. UIQuadInfo()
  61. {
  62. sublayer = -1;
  63. sheetSequenceNumber = -1;
  64. color.r = 255;
  65. color.g = 255;
  66. color.b = 255;
  67. color.a = 255;
  68. textureName = "";
  69. }
  70. UIQuadInfo( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo )
  71. {
  72. Assign( inXPos, inYPos, inWidth, inHeight, inSublayer, inSheetSeqNo, color );
  73. }
  74. UIQuadInfo( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo, color32 inColor )
  75. {
  76. Assign( inXPos, inYPos, inWidth, inHeight, inSublayer, inSheetSeqNo, inColor );
  77. }
  78. void Assign( int inXPos, int inYPos, int inWidth, int inHeight, int inSublayer, int inSheetSeqNo, color32 inColor )
  79. {
  80. x1Pos = inXPos;
  81. y1Pos = inYPos;
  82. width = inWidth;
  83. height = inHeight;
  84. x2Pos = x1Pos + width;
  85. y2Pos = y1Pos + height;
  86. Assert( inSheetSeqNo != -1 );
  87. sublayer = inSublayer;
  88. sheetSequenceNumber = inSheetSeqNo;
  89. color = inColor;
  90. }
  91. int x1Pos;
  92. int y1Pos;
  93. int x2Pos;
  94. int y2Pos;
  95. int width;
  96. int height;
  97. CUtlString textureName; // name if the texture that is inside the sheet
  98. int sheetSequenceNumber;
  99. color32 color;
  100. int sublayer;
  101. };
  102. struct SheetInfo
  103. {
  104. CUtlVector< CUtlString > m_SheetTexEntry;
  105. };
  106. SheetInfo m_sheetDict[SUBLAYER_MAX];
  107. void AddSheetTextureEntry( int sublayer, const char *pTextureName );
  108. int FindSheetTextureEntry( int sublayer, const char *pTextureName );
  109. bool InitSheetTexture( int sublayer, const char *pBaseTextureName );
  110. CSheet *CTGARenderer::LoadSheet( IMaterial *pMaterial );
  111. CSheet *CTGARenderer::LoadSheet( char const *pszFname, ITexture *pTexture );
  112. void GenerateUIMesh( CMatRenderContextPtr &pRenderContext, IMesh* pMesh, CUtlLinkedList< UIQuadInfo > &quads, CSheet *pSheet );
  113. void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, color32 color, const char *pTextureName = NULL );
  114. void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, const char *pTextureName );
  115. void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo, color32 color );
  116. void InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo );
  117. UIQuadInfo CreateQuad( int xPos, int yPos, int width, int height, int sublayer, const char *pTextureName = NULL );
  118. UIQuadInfo CreateQuad( int xPos, int yPos, int width, int height, int sublayer, color32 color, const char *pTextureName = NULL );
  119. void AddQuad( UIQuadInfo &quadInfo, int layer );
  120. struct LayerTextureInfo
  121. {
  122. CMaterialReference m_SublayerMaterial;
  123. CUtlReference< CSheet > m_Sheet;
  124. };
  125. LayerTextureInfo m_LayerTextureInfo[SUBLAYER_MAX];
  126. struct LayerInfo
  127. {
  128. CUtlLinkedList< UIQuadInfo > *pQuads;
  129. };
  130. // For 3 draw call per layer test.
  131. struct Layer
  132. {
  133. public:
  134. // Layer 0 is static
  135. // Layer 1 is dynamic
  136. // Layer 2 is font
  137. LayerInfo layerInfo[SUBLAYER_MAX];
  138. };
  139. // Test with 10 layers, 3 draw calls per layer.
  140. CUtlVector< Layer > m_Layers;
  141. bool m_bInitialized;
  142. };
  143. //-----------------------------------------------------------------------------
  144. // Singleton
  145. //-----------------------------------------------------------------------------
  146. static CTGARenderer s_TGARenderer;
  147. extern ITGARenderer *g_pTGARenderer = &s_TGARenderer;
  148. // 3 drawcall one texture test.
  149. void CTGARenderer::Init( int screenWidth, int screenHeight, int numTiles )
  150. {
  151. m_bInitialized = false;
  152. // Build texture dictionary
  153. AddSheetTextureEntry( SUBLAYER_STATIC, "pixel.tga" );
  154. AddSheetTextureEntry( SUBLAYER_STATIC, "decalposter003a.tga" );
  155. AddSheetTextureEntry( SUBLAYER_STATIC, "decalgraffiti037a.tga" );
  156. AddSheetTextureEntry( SUBLAYER_STATIC, "Climb_node.tga" );
  157. AddSheetTextureEntry( SUBLAYER_STATIC, "gibshooter.tga" );
  158. AddSheetTextureEntry( SUBLAYER_STATIC, "ErrorIcon.tga" );;
  159. AddSheetTextureEntry( SUBLAYER_DYNAMIC, "glassclock001a.tga" );
  160. AddSheetTextureEntry( SUBLAYER_DYNAMIC, "decalgraffiti038a.tga" );
  161. AddSheetTextureEntry( SUBLAYER_DYNAMIC, "Air_node_hint.tga" );
  162. AddSheetTextureEntry( SUBLAYER_DYNAMIC, "info_lighting.tga" );
  163. AddSheetTextureEntry( SUBLAYER_DYNAMIC, "SelfIllumIcon.tga" );
  164. AddSheetTextureEntry( SUBLAYER_FONT, "glasswindow006a.tga" );
  165. AddSheetTextureEntry( SUBLAYER_FONT, "decalgraffiti043a.tga" );
  166. AddSheetTextureEntry( SUBLAYER_FONT, "Ground_node.tga" );
  167. AddSheetTextureEntry( SUBLAYER_FONT, "info_target.tga" );
  168. AddSheetTextureEntry( SUBLAYER_FONT, "translucenticon.tga" );
  169. // Load the sheet textures.
  170. bool bSuccess = InitSheetTexture( SUBLAYER_STATIC, "debug/sheettest/debug_meta1" );
  171. if ( !bSuccess )
  172. {
  173. Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta1" );
  174. return;
  175. }
  176. bSuccess = InitSheetTexture( SUBLAYER_DYNAMIC, "debug/sheettest/debug_meta2" );
  177. if ( !bSuccess )
  178. {
  179. Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta2" );
  180. return;
  181. }
  182. bSuccess = InitSheetTexture( SUBLAYER_FONT, "debug/sheettest/debug_meta3" );
  183. if ( !bSuccess )
  184. {
  185. Warning( "CDataModel: Unable to load sheet for %s\n", "debug/sheettest/debug_meta3" );
  186. return;
  187. }
  188. // Create an array of quads for each sublayer on each layer.
  189. m_Layers.RemoveAll();
  190. for ( int i = 0; i < MAX_LAYERS; ++i )
  191. {
  192. m_Layers.AddToTail();
  193. for ( int j = 0; j < SUBLAYER_MAX; ++j )
  194. {
  195. m_Layers[i].layerInfo[j].pQuads = new CUtlLinkedList< UIQuadInfo >;
  196. }
  197. }
  198. UIQuadInfo testQuad;
  199. testQuad = CreateQuad( 0, 0, 64, 64, SUBLAYER_STATIC, "gibshooter.tga" );
  200. AddQuad( testQuad, 0 );
  201. testQuad = CreateQuad( 0, 128, 128, 128, SUBLAYER_DYNAMIC, "Air_node_hint.tga" );
  202. AddQuad( testQuad, 0 );
  203. m_bInitialized = true;
  204. }
  205. bool CTGARenderer::InitSheetTexture( int sublayer, const char *pBaseTextureName )
  206. {
  207. CUtlString materialName;
  208. switch (sublayer)
  209. {
  210. case SUBLAYER_STATIC:
  211. materialName = "statictx";
  212. break;
  213. case SUBLAYER_DYNAMIC:
  214. materialName = "dynamictx";
  215. break;
  216. case SUBLAYER_FONT:
  217. materialName = "fonttx";
  218. break;
  219. default:
  220. Warning( "CTGARenderer: Invalid sublayer for %s\n", pBaseTextureName );
  221. Assert(0);
  222. break;
  223. };
  224. KeyValues *pVMTKeyValues = new KeyValues( "GameControls" );
  225. pVMTKeyValues->SetString( "$basetexture", pBaseTextureName );
  226. m_LayerTextureInfo[sublayer].m_SublayerMaterial.Init( materialName, TEXTURE_GROUP_OTHER, pVMTKeyValues );
  227. m_LayerTextureInfo[sublayer].m_SublayerMaterial->Refresh();
  228. CSheet *pSheet = LoadSheet( m_LayerTextureInfo[sublayer].m_SublayerMaterial );
  229. if ( pSheet == NULL )
  230. {
  231. Warning( "CTGARenderer: Unable to load sheet for %s %s\n", materialName.Get(), pBaseTextureName );
  232. return false;
  233. }
  234. else
  235. {
  236. m_LayerTextureInfo[sublayer].m_Sheet.Set( pSheet );
  237. return true;
  238. }
  239. }
  240. //-----------------------------------------------------------------------------
  241. //-----------------------------------------------------------------------------
  242. void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo, color32 color )
  243. {
  244. CUtlLinkedList< UIQuadInfo > *pQuads = m_Layers[layer].layerInfo[sublayer].pQuads;
  245. for ( int i = 0; i < count; ++i )
  246. {
  247. UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo, color );
  248. pQuads->AddToTail( quadInfo );
  249. xPos += width;
  250. if ( xPos >= screenWidth )
  251. {
  252. xPos = 0;
  253. yPos += height;
  254. }
  255. if ( yPos >= screenHeight )
  256. {
  257. // just wrap.
  258. yPos = 0;
  259. }
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. //-----------------------------------------------------------------------------
  264. void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count, int layer, int sublayer, int sheetSeqNo )
  265. {
  266. for ( int i = 0; i < count; ++i )
  267. {
  268. UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo );
  269. AddQuad( quadInfo, layer );
  270. xPos += width;
  271. if ( xPos >= screenWidth )
  272. {
  273. xPos = 0;
  274. yPos += height;
  275. }
  276. if ( yPos >= screenHeight )
  277. {
  278. // just wrap.
  279. yPos = 0;
  280. }
  281. }
  282. }
  283. //-----------------------------------------------------------------------------
  284. //-----------------------------------------------------------------------------
  285. void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count,
  286. int layer, int sublayer, color32 color, const char *pTextureName )
  287. {
  288. int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName );
  289. Assert( sheetSeqNo != -1 );
  290. InitTiles( screenWidth, screenHeight, xPos, yPos, width, height, count, layer, sublayer, sheetSeqNo, color );
  291. }
  292. //-----------------------------------------------------------------------------
  293. //-----------------------------------------------------------------------------
  294. void CTGARenderer::InitTiles( int screenWidth, int screenHeight, int &xPos, int &yPos, int width, int height, int count,
  295. int layer, int sublayer, const char *pTextureName )
  296. {
  297. int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName );
  298. InitTiles( screenWidth, screenHeight, xPos, yPos, width, height, count, layer, sublayer, sheetSeqNo );
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Create a quad on a sublayer
  302. // Texture name is optional.
  303. //-----------------------------------------------------------------------------
  304. CTGARenderer::UIQuadInfo CTGARenderer::CreateQuad( int xPos, int yPos, int width, int height, int sublayer, const char *pTextureName )
  305. {
  306. int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName );
  307. UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo );
  308. return quadInfo;
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Create a quad on a sublayer
  312. // Texture name is optional.
  313. //-----------------------------------------------------------------------------
  314. CTGARenderer::UIQuadInfo CTGARenderer::CreateQuad( int xPos, int yPos, int width, int height, int sublayer, color32 color, const char *pTextureName )
  315. {
  316. int sheetSeqNo = FindSheetTextureEntry( sublayer, pTextureName );
  317. UIQuadInfo quadInfo( xPos, yPos, width, height, sublayer, sheetSeqNo, color );
  318. return quadInfo;
  319. }
  320. //-----------------------------------------------------------------------------
  321. //-----------------------------------------------------------------------------
  322. void CTGARenderer::AddQuad( UIQuadInfo &quadInfo, int layer )
  323. {
  324. CUtlLinkedList< UIQuadInfo > *pQuads = m_Layers[layer].layerInfo[quadInfo.sublayer].pQuads;
  325. pQuads->AddToTail( quadInfo );
  326. }
  327. //-----------------------------------------------------------------------------
  328. //-----------------------------------------------------------------------------
  329. void CTGARenderer::AddSheetTextureEntry( int sublayer, const char *pTextureName )
  330. {
  331. m_sheetDict[sublayer].m_SheetTexEntry.AddToTail( pTextureName );
  332. }
  333. //-----------------------------------------------------------------------------
  334. //-----------------------------------------------------------------------------
  335. int CTGARenderer::FindSheetTextureEntry( int sublayer, const char *pTextureName )
  336. {
  337. if ( pTextureName == NULL )
  338. return 0;
  339. for ( int i = 0; i < m_sheetDict[sublayer].m_SheetTexEntry.Count(); ++i )
  340. {
  341. if ( !Q_strcmp( m_sheetDict[sublayer].m_SheetTexEntry[i], pTextureName ) )
  342. return i;
  343. }
  344. Assert(0);
  345. return -1;
  346. }
  347. #include "vgui/ISurface.h"
  348. #include "vguimatsurface/imatsystemsurface.h"
  349. //-----------------------------------------------------------------------------
  350. // 3 draw calls per layer.
  351. //-----------------------------------------------------------------------------
  352. void CTGARenderer::Render()
  353. {
  354. VPROF_BUDGET( "Render", "Render" );
  355. if ( !m_bInitialized )
  356. {
  357. Warning( "CTGARenderer: Unable to render.\n" );
  358. return;
  359. }
  360. int x, y, width, height;
  361. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  362. pRenderContext->ClearColor4ub( 76, 88, 68, 255 );
  363. pRenderContext->ClearBuffers( true, true );
  364. pRenderContext->GetViewport( x, y, width, height);
  365. float flPixelOffsetX = 0.5f;
  366. float flPixelOffsetY = 0.5f;
  367. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  368. pRenderContext->PushMatrix();
  369. pRenderContext->LoadIdentity();
  370. pRenderContext->Scale( 1, -1, 1 );
  371. pRenderContext->Ortho( flPixelOffsetX, flPixelOffsetY, width + flPixelOffsetX, height + flPixelOffsetY, -1.0f, 1.0f );
  372. // make sure there is no translation and rotation laying around
  373. pRenderContext->MatrixMode( MATERIAL_MODEL );
  374. pRenderContext->PushMatrix();
  375. pRenderContext->LoadIdentity();
  376. pRenderContext->MatrixMode( MATERIAL_VIEW );
  377. pRenderContext->PushMatrix();
  378. pRenderContext->LoadIdentity();
  379. // each sublayer should correspond to one meta texture binding.
  380. for ( int i = 0; i < MAX_LAYERS; ++i )
  381. {
  382. for ( int j = 0; j < SUBLAYER_MAX; ++j )
  383. {
  384. if ( m_Layers[i].layerInfo[j].pQuads->Count() == 0 )
  385. {
  386. continue;
  387. }
  388. pRenderContext->Bind( m_LayerTextureInfo[j].m_SublayerMaterial, NULL );
  389. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  390. GenerateUIMesh( pRenderContext, pMesh, *(m_Layers[i].layerInfo[j].pQuads), m_LayerTextureInfo[j].m_Sheet );
  391. pMesh->Draw();
  392. }
  393. }
  394. // Restore the matrices
  395. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  396. pRenderContext->PopMatrix();
  397. pRenderContext->MatrixMode( MATERIAL_MODEL );
  398. pRenderContext->PopMatrix();
  399. pRenderContext->MatrixMode( MATERIAL_VIEW );
  400. pRenderContext->PopMatrix();
  401. }
  402. //-----------------------------------------------------------------------------
  403. //-----------------------------------------------------------------------------
  404. void CTGARenderer::Shutdown()
  405. {
  406. int count = 0;
  407. for ( int i = 0; i < MAX_LAYERS; ++i )
  408. {
  409. for ( int j = 0; j < SUBLAYER_MAX; j++ )
  410. {
  411. count += m_Layers[i].layerInfo[j].pQuads->Count();
  412. }
  413. }
  414. Warning( "Total generated quads = %d\n", count );
  415. m_Layers.RemoveAll();
  416. }
  417. //--------------------------------------------------------------------------------
  418. // UI sheets
  419. //--------------------------------------------------------------------------------
  420. CSheet *CTGARenderer::LoadSheet( char const *pszFname, ITexture *pTexture )
  421. {
  422. CSheet *pNewSheet = NULL;
  423. // get compact sheet representation held by texture
  424. size_t numBytes;
  425. void const *pSheet = pTexture->GetResourceData( VTF_RSRC_SHEET, &numBytes );
  426. if ( pSheet )
  427. {
  428. // expand compact sheet into fatter runtime form
  429. CUtlBuffer bufLoad( pSheet, numBytes, CUtlBuffer::READ_ONLY );
  430. pNewSheet = new CSheet( bufLoad );
  431. }
  432. //m_SheetList[ pszFname ] = pNewSheet;
  433. return pNewSheet;
  434. }
  435. //-----------------------------------------------------------------------------
  436. //-----------------------------------------------------------------------------
  437. CSheet *CTGARenderer::LoadSheet( IMaterial *pMaterial )
  438. {
  439. if ( !pMaterial )
  440. return NULL;
  441. bool bFoundVar = false;
  442. IMaterialVar *pVar = pMaterial->FindVar( "$basetexture", &bFoundVar, true );
  443. if ( bFoundVar && pVar && pVar->IsDefined() )
  444. {
  445. ITexture *pTex = pVar->GetTextureValue();
  446. if ( pTex && !pTex->IsError() )
  447. return LoadSheet( pTex->GetName(), pTex );
  448. }
  449. return NULL;
  450. }
  451. //-----------------------------------------------------------------------------
  452. //-----------------------------------------------------------------------------
  453. void CTGARenderer::GenerateUIMesh( CMatRenderContextPtr &pRenderContext, IMesh* pMesh, CUtlLinkedList< UIQuadInfo > &quads, CSheet *pSheet )
  454. {
  455. VPROF_BUDGET( "GenerateUIMesh", "GenerateUIMesh" );
  456. if ( quads.Count() == 0 )
  457. return;
  458. CMeshBuilder meshBuilder;
  459. meshBuilder.Begin( pMesh, MATERIAL_QUADS, quads.Count() );
  460. int x, y, width, height;
  461. pRenderContext->GetViewport( x, y, width, height);
  462. {
  463. VPROF_BUDGET( "meshBuilder", "meshBuilder" );
  464. for( int i = quads.Head(); i != quads.InvalidIndex(); i = quads.Next( i ) )
  465. {
  466. Assert( pSheet );
  467. Assert( pSheet->m_SheetInfo[quads[i].sheetSequenceNumber].m_pSamples );
  468. SheetSequenceSample_t *pSample = pSheet->m_SheetInfo[quads[i].sheetSequenceNumber].m_pSamples;
  469. Assert( pSample );
  470. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  471. Assert( pSample0 );
  472. color32 c = quads[i].color;
  473. // Top left
  474. meshBuilder.Position3f( quads[i].x1Pos, quads[i].y1Pos, 0.0f );
  475. meshBuilder.Color4ub( c.r, c.g, c.b, c.a );
  476. meshBuilder.TexCoord3f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, 0 );
  477. meshBuilder.AdvanceVertex();
  478. // Top right
  479. meshBuilder.Position3f( quads[i].x2Pos, quads[i].y1Pos, 0.0f );
  480. meshBuilder.Color4ub( c.r, c.g, c.b, c.a );
  481. meshBuilder.TexCoord3f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0, 0 );
  482. meshBuilder.AdvanceVertex();
  483. // Bottom right
  484. meshBuilder.Position3f( quads[i].x2Pos, quads[i].y2Pos, 0.0f );
  485. meshBuilder.Color4ub( c.r, c.g, c.b, c.a );
  486. meshBuilder.TexCoord3f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0, 0 );
  487. meshBuilder.AdvanceVertex();
  488. // Bottom left
  489. meshBuilder.Position3f( quads[i].x1Pos, quads[i].y2Pos, 0.0f );
  490. meshBuilder.Color4ub( c.r, c.g, c.b, c.a );
  491. meshBuilder.TexCoord3f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0, 0 );
  492. meshBuilder.AdvanceVertex();
  493. }
  494. }
  495. meshBuilder.End();
  496. }