the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "..\..\Tesselator.h"
3#include "XUI_FontData.h"
4#include "XUI_Font.h"
5
6extern IDirect3DDevice9 *g_pD3DDevice;
7
8//--------------------------------------------------------------------------------------
9// Name: XUI_Font()
10// Desc: Constructor
11//--------------------------------------------------------------------------------------
12XUI_Font::XUI_Font(int iFontData, float scaleFactor, XUI_FontData *fontData)
13 : m_iFontData(iFontData), m_fScaleFactor(scaleFactor)
14{
15 m_fontData = fontData;
16 refCount = 0;
17
18 m_fCursorX = 0.0f;
19 m_fCursorY = 0.0f;
20
21 m_fXScaleFactor = m_fYScaleFactor = scaleFactor;
22
23 m_fSlantFactor = 0.0f;
24 m_bRotate = FALSE;
25 m_dRotCos = cos( 0.0 );
26 m_dRotSin = sin( 0.0 );
27
28 m_dwNestedBeginCount = 0L;
29
30 // Initialize the window
31 D3DDISPLAYMODE DisplayMode;
32 g_pD3DDevice->GetDisplayMode( 0, &DisplayMode );
33 m_rcWindow.x1 = 0;
34 m_rcWindow.y1 = 0;
35 m_rcWindow.x2 = DisplayMode.Width;
36 m_rcWindow.y2 = DisplayMode.Height;
37}
38
39
40//--------------------------------------------------------------------------------------
41// Name: ~XUI_Font()
42// Desc: Destructor
43//--------------------------------------------------------------------------------------
44XUI_Font::~XUI_Font()
45{
46}
47
48//--------------------------------------------------------------------------------------
49// Name: GetTextExtent()
50// Desc: Get the dimensions of a text string
51//--------------------------------------------------------------------------------------
52
53VOID XUI_Font::GetTextExtent( const WCHAR* strText, FLOAT* pWidth,
54 FLOAT* pHeight, BOOL bFirstLineOnly ) const
55{
56 assert( pWidth != NULL );
57 assert( pHeight != NULL );
58
59 // Set default text extent in output parameters
60 int iWidth = 0;
61 FLOAT fHeight = 0.0f;
62
63 if( strText )
64 {
65 // Initialize counters that keep track of text extent
66 int ix = 0;
67 FLOAT fy = m_fontData->getFontHeight(); // One character high to start
68 if( fy > fHeight )
69 fHeight = fy;
70
71 // Loop through each character and update text extent
72 DWORD letter;
73 while( (letter = *strText) != 0 )
74 {
75 ++strText;
76
77 // Handle newline character
78 if( letter == L'\n' )
79 {
80 if( bFirstLineOnly )
81 break;
82 ix = 0;
83 fy += m_fontData->getFontYAdvance();
84 // since the height has changed, test against the height extent
85 if( fy > fHeight )
86 fHeight = fy;
87 }
88
89 // Handle carriage return characters by ignoring them. This helps when
90 // displaying text from a file.
91 if( letter == L'\r' )
92 continue;
93
94 // Translate unprintable characters
95 XUI_FontData::SChar sChar = m_fontData->getChar(letter);
96
97 // Get text extent for this character's glyph
98 ix += sChar.getOffset();
99 ix += sChar.getWAdvance();
100
101 // Since the x widened, test against the x extent
102 if (ix > iWidth) iWidth = ix;
103 }
104 }
105
106 // Convert the width to a float here, load/hit/store. :(
107 FLOAT fWidth = static_cast<FLOAT>(iWidth); // Delay the use if fWidth to reduce LHS pain
108 // Apply the scale factor to the result
109 fHeight *= m_fYScaleFactor;
110 // Store the final results
111 *pHeight = fHeight;
112
113 fWidth *= m_fXScaleFactor;
114 *pWidth = fWidth;
115}
116
117//--------------------------------------------------------------------------------------
118// Name: GetTextWidth()
119// Desc: Returns the width in pixels of a text string
120//--------------------------------------------------------------------------------------
121FLOAT XUI_Font::GetTextWidth( const WCHAR* strText ) const
122{
123 FLOAT fTextWidth;
124 FLOAT fTextHeight;
125 GetTextExtent( strText, &fTextWidth, &fTextHeight );
126 return fTextWidth;
127}
128
129//--------------------------------------------------------------------------------------
130// Name: Begin()
131// Desc: Prepares the font vertex buffers for rendering.
132//--------------------------------------------------------------------------------------
133VOID XUI_Font::Begin()
134{
135 PIXBeginNamedEvent( 0, "Text Rendering" );
136
137 // Set state on the first call
138 if( 0 == m_dwNestedBeginCount )
139 {
140 // Cache the global pointer into a register
141 IDirect3DDevice9 *pD3dDevice = g_pD3DDevice;
142 assert( pD3dDevice );
143
144 // Set the texture scaling factor as a vertex shader constant
145 //D3DSURFACE_DESC TextureDesc;
146 //m_pFontTexture->GetLevelDesc( 0, &TextureDesc ); // Get the description
147
148 // Set render state
149 assert(m_fontData->m_pFontTexture != NULL || m_fontData->m_iFontTexture > 0);
150 if(m_fontData->m_pFontTexture != NULL)
151 {
152 pD3dDevice->SetTexture( 0, m_fontData->m_pFontTexture );
153 }
154 else
155 {
156 glBindTexture(GL_TEXTURE_2D, m_fontData->m_iFontTexture);
157 }
158
159 //// Read the TextureDesc here to ensure no load/hit/store from GetLevelDesc()
160 //FLOAT vTexScale[4];
161 //vTexScale[0] = 1.0f / TextureDesc.Width; // LHS due to int->float conversion
162 //vTexScale[1] = 1.0f / TextureDesc.Height;
163 //vTexScale[2] = 0.0f;
164 //vTexScale[3] = 0.0f;
165 //
166 //pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
167 //pD3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
168 //pD3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
169 //pD3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
170 //pD3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
171 //pD3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
172 //pD3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
173 //pD3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
174 //pD3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
175 //pD3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
176 //pD3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE );
177 //pD3dDevice->SetRenderState( D3DRS_VIEWPORTENABLE, FALSE );
178 //pD3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
179 //pD3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
180 //pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
181 //pD3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
182 }
183
184 // Keep track of the nested begin/end calls.
185 m_dwNestedBeginCount++;
186}
187
188
189//--------------------------------------------------------------------------------------
190// Name: DrawText()
191// Desc: Draws text as textured polygons
192//--------------------------------------------------------------------------------------
193VOID XUI_Font::DrawText( DWORD dwColor, const WCHAR* strText, DWORD dwFlags,
194 FLOAT fMaxPixelWidth )
195{
196 DrawText( m_fCursorX, m_fCursorY, dwColor, strText, dwFlags, fMaxPixelWidth );
197}
198
199//--------------------------------------------------------------------------------------
200// Name: DrawShadowText()
201// Desc: Draws text as textured polygons
202//--------------------------------------------------------------------------------------
203VOID XUI_Font::DrawShadowText( FLOAT fOriginX, FLOAT fOriginY, DWORD dwColor, DWORD dwShadowColor,
204 const WCHAR* strText, DWORD dwFlags, FLOAT fMaxPixelWidth)
205{
206 float fXShadow=1.0f, fYShadow=1.0f;
207 // 4J Stu - Don't move the drop shadow as much
208 //DrawText( fOriginX + (1*m_fXScaleFactor), fOriginY + (1*m_fYScaleFactor), dwColor, strText, dwFlags, fMaxPixelWidth, true );
209
210 // 4J-PB - if we're in 480 widescreen, we need to draw the drop shadow at +2 pixels, so that when the scene is halved, it's at +1
211 if(!RenderManager.IsHiDef())
212 {
213 if(RenderManager.IsWidescreen())
214 {
215 fXShadow=2.0f;
216 fYShadow=2.0f;
217 }
218 //else
219 //{
220 // 480 SD mode - the draw text call will reposition the y
221 //}
222 }
223 DrawText( fOriginX + fXShadow, fOriginY + fYShadow, dwColor, strText, dwFlags, fMaxPixelWidth, true );
224 DrawText( fOriginX, fOriginY, dwColor, strText, dwFlags, fMaxPixelWidth );
225
226 //DrawText( fOriginX + 1, fOriginY + 1, dwShadowColor, strText, dwFlags, fMaxPixelWidth);
227 //DrawText( fOriginX, fOriginY, dwColor, strText, dwFlags, fMaxPixelWidth );
228}
229
230//--------------------------------------------------------------------------------------
231// Name: DrawText()
232// Desc: Draws text as textured polygons
233// TODO: This function should use the Begin/SetVertexData/End() API when it
234// becomes available.
235//--------------------------------------------------------------------------------------
236VOID XUI_Font::DrawText( FLOAT fOriginX, FLOAT fOriginY, DWORD dwColor,
237 const WCHAR* strText, DWORD dwFlags, FLOAT fMaxPixelWidth, bool darken /*= false*/ )
238{
239 if( NULL == strText ) return;
240 if( L'\0' == strText[0] ) return;
241
242 // 4J-PB - if we're in 480 widescreen mode, we need to ensure that the font characters are aligned on an even boundary if they are a 2x multiple
243 if(!RenderManager.IsHiDef())
244 {
245 if(RenderManager.IsWidescreen())
246 {
247 int iScaleX=(int)m_fXScaleFactor;
248 int iOriginX;
249 if(iScaleX%2==0)
250 {
251 iOriginX=(int)fOriginX;
252 if(iOriginX%2==1)
253 {
254 fOriginX+=1.0f;
255 }
256 }
257 int iScaleY=(int)m_fYScaleFactor;
258 int iOriginY;
259 if(iScaleY%2==0)
260 {
261 iOriginY=(int)fOriginY;
262 if(iOriginY%2==1)
263 {
264 fOriginY+=1.0f;
265 }
266 }
267 }
268 else
269 {
270 // 480 SD mode - y needs to be on a pixel boundary when multiplied by 1.5, so if it's an odd number, subtract 1/3 from it
271 int iOriginY=(int)fOriginY;
272 if(iOriginY%2==1)
273 {
274 fOriginY-=1.0f/3.0f;
275 }
276 }
277 }
278 // Create a PIX user-defined event that encapsulates all of the text draw calls.
279 // This makes DrawText calls easier to recognize in PIX captures, and it makes
280 // them take up fewer entries in the event list.
281 PIXBeginNamedEvent( dwColor, "DrawText: %S", strText );
282
283 // Set up stuff to prepare for drawing text
284 Begin();
285
286 if (darken)
287 {
288 int oldAlpha = dwColor & 0xff000000;
289 dwColor = (dwColor & 0xfcfcfc) >> 2;
290 dwColor += oldAlpha;
291 }
292
293 float r = ((dwColor >> 16) & 0xff) / 255.0f;
294 float g = ((dwColor >> 8) & 0xff) / 255.0f;
295 float b = ((dwColor) & 0xff) / 255.0f;
296 float a = ((dwColor >> 24) & 0xff) / 255.0f;
297 if (a == 0) a = 1;
298 // a = 1;
299 glColor4f(r, g, b, a);
300
301 // Set the starting screen position
302 if( ( fOriginX < 0.0f ) || ( ( dwFlags & ATGFONT_RIGHT ) && ( fOriginX <= 0.0f ) ) )
303 {
304 fOriginX += ( m_rcWindow.x2 - m_rcWindow.x1 );
305 }
306 // 4J-PB - not sure what this code was intending to do, but it removed a line of text that is slightly off the top of the control, rather than having it partially render
307// if( fOriginY < 0.0f )
308// {
309// fOriginY += ( m_rcWindow.y2 - m_rcWindow.y1 );
310// }
311
312 m_fCursorX = floorf( fOriginX );
313 m_fCursorY = floorf( fOriginY );
314
315 // Adjust for padding
316 fOriginY -= m_fontData->getFontTopPadding();
317
318 XUI_FontData::SChar sChar = m_fontData->getChar(L'.');
319 FLOAT fEllipsesPixelWidth = m_fXScaleFactor * 3.0f * (sChar.getOffset() + sChar.getWAdvance());
320
321 if( dwFlags & ATGFONT_TRUNCATED )
322 {
323 // Check if we will really need to truncate the string
324 if( fMaxPixelWidth <= 0.0f )
325 {
326 dwFlags &= ( ~ATGFONT_TRUNCATED );
327 }
328 else
329 {
330 FLOAT w, h;
331 GetTextExtent( strText, &w, &h, TRUE );
332
333 // If not, then clear the flag
334 if( w <= fMaxPixelWidth )
335 dwFlags &= ( ~ATGFONT_TRUNCATED );
336 }
337 }
338
339 // If vertically centered, offset the starting m_fCursorY value
340 if( dwFlags & ATGFONT_CENTER_Y )
341 {
342 FLOAT w, h;
343 GetTextExtent( strText, &w, &h );
344 m_fCursorY = floorf( m_fCursorY - (h * 0.5f) );
345 }
346
347 // Add window offsets
348 FLOAT Winx = static_cast<FLOAT>(m_rcWindow.x1);
349 FLOAT Winy = static_cast<FLOAT>(m_rcWindow.y1);
350 fOriginX += Winx;
351 fOriginY += Winy;
352 m_fCursorX += Winx;
353 m_fCursorY += Winy;
354
355 // Set a flag so we can determine initial justification effects
356 BOOL bStartingNewLine = TRUE;
357
358 DWORD dwNumEllipsesToDraw = 0;
359
360 // Begin drawing the vertices
361
362
363 DWORD dwNumChars = wcslen( strText ) + ( dwFlags & ATGFONT_TRUNCATED ? 3 : 0 );
364
365 bStartingNewLine = TRUE;
366
367 // Draw four vertices for each glyph
368 while( *strText )
369 {
370 WCHAR letter;
371
372 if( dwNumEllipsesToDraw )
373 {
374 letter = L'.';
375 }
376 else
377 {
378 // If starting text on a new line, determine justification effects
379 if( bStartingNewLine )
380 {
381 if( dwFlags & ( ATGFONT_RIGHT | ATGFONT_CENTER_X ) )
382 {
383 // Get the extent of this line
384 FLOAT w, h;
385 GetTextExtent( strText, &w, &h, TRUE );
386
387 // Offset this line's starting m_fCursorX value
388 if( dwFlags & ATGFONT_RIGHT )
389 m_fCursorX = floorf( fOriginX - w );
390 if( dwFlags & ATGFONT_CENTER_X )
391 m_fCursorX = floorf( fOriginX - w * 0.5f );
392 }
393 bStartingNewLine = FALSE;
394 }
395
396 // Get the current letter in the string
397 letter = *strText++;
398
399 // Handle the newline character
400 if( letter == L'\n' )
401 {
402 m_fCursorX = fOriginX;
403 m_fCursorY += m_fontData->getFontYAdvance() * m_fYScaleFactor;
404 bStartingNewLine = TRUE;
405
406 continue;
407 }
408
409 // Handle carriage return characters by ignoring them. This helps when
410 // displaying text from a file.
411 if( letter == L'\r' )
412 continue;
413 }
414
415 // Translate unprintable characters
416 XUI_FontData::SChar sChar = m_fontData->getChar( letter );
417
418 FLOAT fOffset = m_fXScaleFactor * ( FLOAT )sChar.getOffset();
419 FLOAT fAdvance = m_fXScaleFactor * ( FLOAT )sChar.getWAdvance();
420 // 4J Use the font max width otherwise scaling doesnt look right
421 FLOAT fWidth = m_fXScaleFactor * (sChar.tu2() - sChar.tu1());//( FLOAT )pGlyph->wWidth;
422 FLOAT fHeight = m_fYScaleFactor * m_fontData->getFontHeight();
423
424 if( 0 == dwNumEllipsesToDraw )
425 {
426 if( dwFlags & ATGFONT_TRUNCATED )
427 {
428 // Check if we will be exceeded the max allowed width
429 if( m_fCursorX + fOffset + fWidth + fEllipsesPixelWidth + m_fSlantFactor > fOriginX + fMaxPixelWidth )
430 {
431 // Yup, draw the three ellipses dots instead
432 dwNumEllipsesToDraw = 3;
433 continue;
434 }
435 }
436 }
437
438 // Setup the screen coordinates
439 m_fCursorX += fOffset;
440 FLOAT X4 = m_fCursorX;
441 FLOAT X1 = X4 + m_fSlantFactor;
442 FLOAT X3 = X4 + fWidth;
443 FLOAT X2 = X1 + fWidth;
444 FLOAT Y1 = m_fCursorY;
445 FLOAT Y3 = Y1 + fHeight;
446 FLOAT Y2 = Y1;
447 FLOAT Y4 = Y3;
448
449 m_fCursorX += fAdvance;
450
451 // Add the vertices to draw this glyph
452
453 FLOAT tu1 = sChar.tu1() / (float)m_fontData->getImageWidth();
454 FLOAT tv1 = sChar.tv1() / (float)m_fontData->getImageHeight();
455 FLOAT tu2 = sChar.tu2() / (float)m_fontData->getImageWidth();
456 FLOAT tv2 = sChar.tv2() / (float)m_fontData->getImageHeight();
457
458 Tesselator *t = Tesselator::getInstance();
459 t->begin();
460 t->vertexUV(X1, Y1, 0.0f, tu1, tv1);
461 t->vertexUV(X2, Y2, 0.0f, tu2, tv1);
462 t->vertexUV(X3, Y3, 0.0f, tu2, tv2);
463 t->vertexUV(X4, Y4, 0.0f, tu1, tv2);
464 t->end();
465
466
467 // If drawing ellipses, exit when they're all drawn
468 if( dwNumEllipsesToDraw )
469 {
470 if( --dwNumEllipsesToDraw == 0 )
471 break;
472 }
473
474 dwNumChars--;
475 }
476
477 // Undo window offsets
478 m_fCursorX -= Winx;
479 m_fCursorY -= Winy;
480
481 // Call End() to complete the begin/end pair for drawing text
482 End();
483
484 // Close off the user-defined event opened with PIXBeginNamedEvent.
485 PIXEndNamedEvent();
486}
487
488
489//--------------------------------------------------------------------------------------
490// Name: End()
491// Desc: Paired call that restores state set in the Begin() call.
492//--------------------------------------------------------------------------------------
493VOID XUI_Font::End()
494{
495 assert( m_dwNestedBeginCount > 0 );
496 if( --m_dwNestedBeginCount > 0 )
497 {
498 PIXEndNamedEvent();
499 return;
500 }
501
502 PIXEndNamedEvent();
503}