From 8f7ca9130aa73508d787854158fa9bc53f5263d8 Mon Sep 17 00:00:00 2001 From: TwinAphex51224 Date: Mon, 7 May 2012 16:43:16 +0200 Subject: [PATCH] Revert "(360) Cleanups fonts.cpp" This reverts commit 0c5c3c4299d7115610bd0f6de119238dc28f7372. --- 360/fonts.cpp | 236 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 190 insertions(+), 46 deletions(-) diff --git a/360/fonts.cpp b/360/fonts.cpp index 9ae1ad7fe0..71823cfd9b 100644 --- a/360/fonts.cpp +++ b/360/fonts.cpp @@ -62,6 +62,7 @@ HRESULT xdk360_console_init( LPCSTR strFontFileName, unsigned long colBackColor, video_console.m_Lines = NULL; video_console.m_nScrollOffset = 0; + // Calculate the safe area unsigned int uiSafeAreaPct = vid->video_mode.fIsHiDef ? SAFE_AREA_PCT_HDTV : SAFE_AREA_PCT_4x3; @@ -71,6 +72,7 @@ HRESULT xdk360_console_init( LPCSTR strFontFileName, unsigned long colBackColor, video_console.m_cxSafeAreaOffset = ( vid->d3dpp.BackBufferWidth - video_console.m_cxSafeArea ) / 2; video_console.m_cySafeAreaOffset = ( vid->d3dpp.BackBufferHeight - video_console.m_cySafeArea ) / 2; + // Create the font HRESULT hr = xdk360_video_font_init(&m_Font, strFontFileName ); if( FAILED( hr ) ) { @@ -78,9 +80,11 @@ HRESULT xdk360_console_init( LPCSTR strFontFileName, unsigned long colBackColor, return -1; } + // Save the colors video_console.m_colBackColor = colBackColor; video_console.m_colTextColor = colTextColor; + // Calculate the number of lines on the screen float fCharWidth, fCharHeight; xdk360_video_font_get_text_width(&m_Font, L"i", &fCharWidth, &fCharHeight, FALSE); @@ -91,9 +95,11 @@ HRESULT xdk360_console_init( LPCSTR strFontFileName, unsigned long colBackColor, video_console.m_fLineHeight = fCharHeight; + // Allocate memory to hold the lines video_console.m_Buffer = new wchar_t[ video_console.m_cScreenHeightVirtual * ( video_console.m_cScreenWidth + 1 ) ]; video_console.m_Lines = new wchar_t *[ video_console.m_cScreenHeightVirtual ]; + // Set the line pointers as indexes into the buffer for( unsigned int i = 0; i < video_console.m_cScreenHeightVirtual; i++ ) video_console.m_Lines[ i ] = video_console.m_Buffer + ( video_console.m_cScreenWidth + 1 ) * i; @@ -107,6 +113,7 @@ HRESULT xdk360_console_init( LPCSTR strFontFileName, unsigned long colBackColor, void xdk360_console_deinit() { + // Delete the memory we've allocated if(video_console.m_Lines) { delete[] video_console.m_Lines; @@ -119,11 +126,13 @@ void xdk360_console_deinit() video_console.m_Buffer = NULL; } + // Destroy the font xdk360_video_font_deinit(&m_Font); } void xdk360_console_add( wchar_t wch ) { + // If this is a newline, just increment lines and move on if( wch == L'\n' ) { video_console.m_nCurLine = ( video_console.m_nCurLine + 1 ) @@ -134,12 +143,13 @@ void xdk360_console_add( wchar_t wch ) return; } - int bIncrementLine = FALSE; + int bIncrementLine = FALSE; // Whether to wrap to the next line if( video_console.m_cCurLineLength == video_console.m_cScreenWidth ) bIncrementLine = TRUE; else { + // Try to append the character to the line video_console.m_Lines[ video_console.m_nCurLine ][ video_console.m_cCurLineLength ] = wch; float fTextWidth, fTextHeight; @@ -149,11 +159,13 @@ void xdk360_console_add( wchar_t wch ) if( fTextHeight > video_console.m_cxSafeArea ) { + // The line is too long, we need to wrap the character to the next line video_console.m_Lines[video_console.m_nCurLine][ video_console.m_cCurLineLength ] = L'\0'; bIncrementLine = TRUE; } } + // If we need to skip to the next line, do so if( bIncrementLine ) { video_console.m_nCurLine = ( video_console.m_nCurLine + 1 ) @@ -179,21 +191,24 @@ void xdk360_console_format(_In_z_ _Printf_format_string_ LPCSTR strFormat, ... ) va_list pArgList; va_start( pArgList, strFormat ); + // Count the required length of the string unsigned long dwStrLen = _vscprintf( strFormat, pArgList ) + 1; + // +1 = null terminator char * strMessage = ( char * )_malloca( dwStrLen ); vsprintf_s( strMessage, dwStrLen, strFormat, pArgList ); + // Output the string to the console unsigned long uStringLength = strlen( strMessage ); for( unsigned long i = 0; i < uStringLength; i++ ) { wchar_t wch; int ret = MultiByteToWideChar( - CP_ACP, - 0, - &strMessage[i], - 1, - &wch, - 1 ); + CP_ACP, // ANSI code page + 0, // No flags + &strMessage[i], // Character to convert + 1, // Convert one byte + &wch, // Target wide character buffer + 1 ); // One wide character xdk360_console_add( wch ); } @@ -212,10 +227,12 @@ void xdk360_console_format_w(_In_z_ _Printf_format_string_ LPCWSTR wstrFormat, . va_list pArgList; va_start( pArgList, wstrFormat ); - unsigned long dwStrLen = _vscwprintf( wstrFormat, pArgList ) + 1; + // Count the required length of the string + unsigned long dwStrLen = _vscwprintf( wstrFormat, pArgList ) + 1; // +1 = null terminator wchar_t * strMessage = ( wchar_t * )_malloca( dwStrLen * sizeof( wchar_t ) ); vswprintf_s( strMessage, dwStrLen, wstrFormat, pArgList ); + // Output the string to the console unsigned long uStringLength = wcslen( strMessage ); for( unsigned long i = 0; i < uStringLength; i++ ) xdk360_console_add( strMessage[i] ); @@ -226,19 +243,24 @@ void xdk360_console_format_w(_In_z_ _Printf_format_string_ LPCWSTR wstrFormat, . } #define CALCFONTFILEHEADERSIZE(x) ( sizeof(unsigned long) + (sizeof(float)* 4) + sizeof(unsigned short) + (sizeof(wchar_t)*(x)) ) +#define FONTFILEVERSION 5 typedef struct FontFileHeaderImage_t { - float m_fFontHeight; - float m_fFontTopPadding; - float m_fFontBottomPadding; - float m_fFontYAdvance; - unsigned short m_cMaxGlyph; - wchar_t m_TranslatorTable[1]; + unsigned long m_dwFileVersion; // Version of the font file (Must match FONTFILEVERSION) + float m_fFontHeight; // Height of the font strike in pixels + float m_fFontTopPadding; // Padding above the strike zone + float m_fFontBottomPadding; // Padding below the strike zone + float m_fFontYAdvance; // Number of pixels to move the cursor for a line feed + unsigned short m_cMaxGlyph; // Number of font characters (Should be an odd number to maintain DWORD Alignment) + wchar_t m_TranslatorTable[1]; // ASCII to Glyph lookup table, NOTE: It's m_cMaxGlyph+1 in size. } FontFileHeaderImage_t; +// Font strike array. Immediately follows the FontFileHeaderImage_t +// structure image + typedef struct FontFileStrikesImage_t { - unsigned long m_dwNumGlyphs; - GLYPH_ATTR m_Glyphs[1]; + unsigned long m_dwNumGlyphs; // Size of font strike array (First entry is the unknown glyph) + GLYPH_ATTR m_Glyphs[1]; // Array of font strike uv's etc... NOTE: It's m_dwNumGlyphs in size } FontFileStrikesImage_t; static PackedResource m_xprResource; @@ -274,21 +296,37 @@ static const char g_strFontShader[] = "}\n"; typedef struct Font_Locals_t { - D3DVertexDeclaration* m_pFontVertexDecl; - D3DVertexShader* m_pFontVertexShader; - D3DPixelShader* m_pFontPixelShader; + D3DVertexDeclaration* m_pFontVertexDecl; // Shared vertex buffer + D3DVertexShader* m_pFontVertexShader; // Created vertex shader + D3DPixelShader* m_pFontPixelShader; // Created pixel shader } Font_Locals_t; -static Font_Locals_t s_FontLocals; +// All elements are defaulted to NULL +static Font_Locals_t s_FontLocals; // Global static instance static HRESULT xdk360_video_font_create_shaders (xdk360_video_font_t * font) { + // + // There are only two states the globals could be in, + // Initialized, in which the ref count is increased, + // Uninialized, in which the vertex/pixel shaders need to be + // started up and a vertex array created. + /// + HRESULT hr; if (!s_FontLocals.m_pFontVertexDecl) { + // Use the do {} while(0); trick for a fake goto + // It simplies tear down on error conditions. do { + + // Step #1, create my vertex array with 16 bytes per entry + // Floats for the position, + // shorts for the uvs + // 32 bit packed ARGB 8:8:8:8 for color + static const D3DVERTEXELEMENT9 decl[] = { { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, @@ -297,6 +335,7 @@ static HRESULT xdk360_video_font_create_shaders (xdk360_video_font_t * font) D3DDECL_END() }; + // Cache this global into a register xdk360_video_t *vid = (xdk360_video_t*)g_d3d; D3DDevice *pd3dDevice = vid->d3d_render_device; @@ -304,6 +343,7 @@ static HRESULT xdk360_video_font_create_shaders (xdk360_video_font_t * font) if (SUCCEEDED(hr)) { + // Step #2, create my vertex shader ID3DXBuffer* pShaderCode; hr = D3DXCompileShader( g_strFontShader, sizeof(g_strFontShader)-1 , @@ -312,35 +352,42 @@ static HRESULT xdk360_video_font_create_shaders (xdk360_video_font_t * font) { hr = pd3dDevice->CreateVertexShader( ( unsigned long * )pShaderCode->GetBufferPointer(), &s_FontLocals.m_pFontVertexShader ); + // Release the compiled shader pShaderCode->Release(); if(SUCCEEDED(hr)) { + // Step #3, create my pixel shader hr = D3DXCompileShader( g_strFontShader, sizeof(g_strFontShader)-1 , NULL, NULL, "main_fragment", "ps.2.0", 0,&pShaderCode, NULL, NULL ); if ( SUCCEEDED(hr)) { hr = pd3dDevice->CreatePixelShader( ( DWORD* )pShaderCode->GetBufferPointer(), &s_FontLocals.m_pFontPixelShader ); + // Release the compiled shader pShaderCode->Release(); if (SUCCEEDED(hr)) { hr = S_OK; - break; + break; // Skip the teardown code } } + // If the code got to here, a fatal error has occured + // and a clean shutdown needs to be performed. D3DResource_Release((D3DResource *)s_FontLocals.m_pFontVertexShader); } + // Ensure the pointer is NULL s_FontLocals.m_pFontVertexShader = NULL; } D3DResource_Release((D3DResource *)s_FontLocals.m_pFontVertexDecl); } + // Ensure this pointer is NULL s_FontLocals.m_pFontVertexDecl = NULL; - }while(0); + }while(0); // Exit point for the break command. return hr; } else @@ -350,7 +397,7 @@ static HRESULT xdk360_video_font_create_shaders (xdk360_video_font_t * font) D3DResource_AddRef((D3DResource *)s_FontLocals.m_pFontPixelShader); hr = S_OK; } - return hr; + return hr; // Return the error code if any } void xdk360_video_font_set_size(xdk360_video_font_t * font, float x, float y) @@ -372,28 +419,45 @@ HRESULT xdk360_video_font_init(xdk360_video_font_t * font, const char * strFontF font->m_TranslatorTable = NULL; font->m_dwNestedBeginCount = 0L; + // Create the font if( FAILED( m_xprResource.Create( strFontFileName ) ) ) return E_FAIL; D3DTexture * pFontTexture = m_xprResource.GetTexture( "FontTexture" ); const void * pFontData = m_xprResource.GetData( "FontData"); + // Save a copy of the texture font->m_pFontTexture = pFontTexture; + // Check version of file (to make sure it matches up with the FontMaker tool) const unsigned char * pData = static_cast(pFontData); + unsigned long dwFileVersion = reinterpret_cast(pData)->m_dwFileVersion; - font->m_fFontHeight = reinterpret_cast(pData)->m_fFontHeight; - font->m_fFontTopPadding = reinterpret_cast(pData)->m_fFontTopPadding; - font->m_fFontBottomPadding = reinterpret_cast(pData)->m_fFontBottomPadding; - font->m_fFontYAdvance = reinterpret_cast(pData)->m_fFontYAdvance; - font->m_cMaxGlyph = reinterpret_cast(pData)->m_cMaxGlyph; - font->m_TranslatorTable = const_cast(reinterpret_cast(pData))->m_TranslatorTable; + if( dwFileVersion == FONTFILEVERSION ) + { + font->m_fFontHeight = reinterpret_cast(pData)->m_fFontHeight; + font->m_fFontTopPadding = reinterpret_cast(pData)->m_fFontTopPadding; + font->m_fFontBottomPadding = reinterpret_cast(pData)->m_fFontBottomPadding; + font->m_fFontYAdvance = reinterpret_cast(pData)->m_fFontYAdvance; - pData += CALCFONTFILEHEADERSIZE( font->m_cMaxGlyph + 1 ); + // Point to the translator string which immediately follows the 4 floats + font->m_cMaxGlyph = reinterpret_cast(pData)->m_cMaxGlyph; - font->m_dwNumGlyphs = reinterpret_cast(pData)->m_dwNumGlyphs; - font->m_Glyphs = reinterpret_cast(pData)->m_Glyphs; + font->m_TranslatorTable = const_cast(reinterpret_cast(pData))->m_TranslatorTable; + pData += CALCFONTFILEHEADERSIZE( font->m_cMaxGlyph + 1 ); + + // Read the glyph attributes from the file + font->m_dwNumGlyphs = reinterpret_cast(pData)->m_dwNumGlyphs; + font->m_Glyphs = reinterpret_cast(pData)->m_Glyphs; // Pointer + } + else + { + RARCH_ERR( "Incorrect version number on font file.\n" ); + return E_FAIL; + } + + // Create the vertex and pixel shaders for rendering the font if( FAILED( xdk360_video_font_create_shaders(font) ) ) { RARCH_ERR( "Could not create font shaders.\n" ); @@ -403,6 +467,7 @@ HRESULT xdk360_video_font_init(xdk360_video_font_t * font, const char * strFontF xdk360_video_t *vid = (xdk360_video_t*)g_d3d; D3DDevice *pd3dDevice = vid->d3d_render_device; + // Initialize the window D3DDISPLAYMODE DisplayMode; pd3dDevice->GetDisplayMode( 0, &DisplayMode ); font->m_rcWindow.x1 = 0; @@ -410,6 +475,7 @@ HRESULT xdk360_video_font_init(xdk360_video_font_t * font, const char * strFontF font->m_rcWindow.x2 = DisplayMode.Width; font->m_rcWindow.y2 = DisplayMode.Height; + // Determine whether we should save/restore state font->m_bSaveState = TRUE; return S_OK; @@ -424,6 +490,10 @@ void xdk360_video_font_deinit(xdk360_video_font_t * font) font->m_TranslatorTable = NULL; font->m_dwNestedBeginCount = 0L; + // Safely release shaders + // NOTE: They are released in reverse order of creation + // to make sure any interdependencies are dealt with + if( ( s_FontLocals.m_pFontPixelShader != NULL ) && ( s_FontLocals.m_pFontPixelShader->Release() == 0 ) ) s_FontLocals.m_pFontPixelShader = NULL; if( ( s_FontLocals.m_pFontVertexShader != NULL ) && ( s_FontLocals.m_pFontVertexShader->Release() == 0 ) ) @@ -443,53 +513,67 @@ void xdk360_video_font_set_cursor_position(xdk360_video_font_t *font, float fCur void xdk360_video_font_get_text_width(xdk360_video_font_t * font, const wchar_t * strText, float * pWidth, float * pHeight, int bFirstLineOnly) { + // Set default text extent in output parameters int iWidth = 0; float fHeight = 0.0f; if( strText ) { + // Initialize counters that keep track of text extent int ix = 0; - float fy = font->m_fFontHeight; + float fy = font->m_fFontHeight; // One character high to start if( fy > fHeight ) fHeight = fy; + // Loop through each character and update text extent unsigned long letter; while( (letter = *strText) != 0 ) { ++strText; + // Handle newline character if( letter == L'\n' ) { if( bFirstLineOnly ) break; ix = 0; fy += font->m_fFontYAdvance; + // since the height has changed, test against the height extent if( fy > fHeight ) fHeight = fy; } + // Handle carriage return characters by ignoring them. This helps when + // displaying text from a file. if( letter == L'\r' ) continue; + // Translate unprintable characters const GLYPH_ATTR* pGlyph; if( letter > font->m_cMaxGlyph ) - letter = 0; + letter = 0; // Out of bounds? else - letter = font->m_TranslatorTable[letter]; + letter = font->m_TranslatorTable[letter]; // Remap ASCII to glyph - pGlyph = &font->m_Glyphs[letter]; + pGlyph = &font->m_Glyphs[letter]; // Get the requested glyph + // Get text extent for this character's glyph ix += pGlyph->wOffset; ix += pGlyph->wAdvance; + // Since the x widened, test against the x extent + if( ix > iWidth ) iWidth = ix; } } - float fWidth = static_cast(iWidth); + // Convert the width to a float here, load/hit/store. :( + float fWidth = static_cast(iWidth); // Delay the use if fWidth to reduce LHS pain + // Apply the scale factor to the result fHeight *= font->m_fYScaleFactor; + // Store the final results *pHeight = fHeight; fWidth *= font->m_fXScaleFactor; @@ -498,14 +582,21 @@ void xdk360_video_font_get_text_width(xdk360_video_font_t * font, const wchar_t void xdk360_video_font_begin (xdk360_video_font_t * font) { + // Set state on the first call if( font->m_dwNestedBeginCount == 0 ) { + // Cache the global pointer into a register xdk360_video_t *vid = (xdk360_video_t*)g_d3d; D3DDevice *pD3dDevice = vid->d3d_render_device; + // Save state if( font->m_bSaveState ) { - pD3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE, &font->m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] ); + // Note, we are not saving the texture, vertex, or pixel shader, + // since it's not worth the performance. We're more interested + // in saving state that would cause hard to find problems. + pD3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE, + &font->m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] ); pD3dDevice->GetRenderState( D3DRS_SRCBLEND, &font->m_dwSavedState[ SAVEDSTATE_D3DRS_SRCBLEND ] ); pD3dDevice->GetRenderState( D3DRS_DESTBLEND, &font->m_dwSavedState[ SAVEDSTATE_D3DRS_DESTBLEND ] ); pD3dDevice->GetRenderState( D3DRS_BLENDOP, &font->m_dwSavedState[ SAVEDSTATE_D3DRS_BLENDOP ] ); @@ -521,12 +612,16 @@ void xdk360_video_font_begin (xdk360_video_font_t * font) font->m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSV ] = D3DDevice_GetSamplerState_AddressV( pD3dDevice, 0); } + // Set the texture scaling factor as a vertex shader constant D3DSURFACE_DESC TextureDesc; - D3DTexture_GetLevelDesc(font->m_pFontTexture, 0, &TextureDesc); + D3DTexture_GetLevelDesc(font->m_pFontTexture, 0, &TextureDesc); // Get the description + + // Set render state D3DDevice_SetTexture_Inline(pD3dDevice, 0, font->m_pFontTexture); + // Read the TextureDesc here to ensure no load/hit/store from GetLevelDesc() float vTexScale[4]; - vTexScale[0] = 1.0f / TextureDesc.Width; + vTexScale[0] = 1.0f / TextureDesc.Width; // LHS due to int->float conversion vTexScale[1] = 1.0f / TextureDesc.Height; vTexScale[2] = 0.0f; vTexScale[3] = 0.0f; @@ -550,9 +645,12 @@ void xdk360_video_font_begin (xdk360_video_font_t * font) D3DDevice_SetVertexShader(pD3dDevice, s_FontLocals.m_pFontVertexShader ); D3DDevice_SetPixelShader(pD3dDevice, s_FontLocals.m_pFontPixelShader ); + // Set the texture scaling factor as a vertex shader constant + // Call here to avoid load hit store from writing to vTexScale above pD3dDevice->SetVertexShaderConstantF( 2, vTexScale, 1 ); } + // Keep track of the nested begin/end calls. font->m_dwNestedBeginCount++; } @@ -561,8 +659,10 @@ void xdk360_video_font_end(xdk360_video_font_t * font) if( --font->m_dwNestedBeginCount > 0 ) return; + // Restore state if( font->m_bSaveState ) { + // Cache the global pointer into a register xdk360_video_t *vid = (xdk360_video_t*)g_d3d; D3DDevice *pD3dDevice = vid->d3d_render_device; @@ -596,16 +696,22 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo xdk360_video_t *vid = (xdk360_video_t*)g_d3d; D3DDevice *pd3dDevice = vid->d3d_render_device; + // Set the color as a vertex shader constant float vColor[4]; vColor[0] = ( ( dwColor & 0x00ff0000 ) >> 16L ) / 255.0F; vColor[1] = ( ( dwColor & 0x0000ff00 ) >> 8L ) / 255.0F; vColor[2] = ( ( dwColor & 0x000000ff ) >> 0L ) / 255.0F; vColor[3] = ( ( dwColor & 0xff000000 ) >> 24L ) / 255.0F; + // Set up stuff to prepare for drawing text xdk360_video_font_begin(font); + // Perform the actual storing of the color constant here to prevent + // a load-hit-store by inserting work between the store and the use of + // the vColor array. pd3dDevice->SetVertexShaderConstantF( 1, vColor, 1 ); + // Set the starting screen position if((fOriginX < 0.0f)) fOriginX += font->m_rcWindow.x2; if( fOriginY < 0.0f ) @@ -613,8 +719,11 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo font->m_fCursorX = floorf( fOriginX ); font->m_fCursorY = floorf( fOriginY ); + + // Adjust for padding fOriginY -= font->m_fFontTopPadding; + // Add window offsets float Winx = 0.0f; float Winy = 0.0f; fOriginX += Winx; @@ -622,21 +731,32 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo font->m_fCursorX += Winx; font->m_fCursorY += Winy; + // Begin drawing the vertices + + // Declared as volatile to force writing in ascending + // address order. It prevents out of sequence writing in write combined + // memory. + volatile float * pVertex; unsigned long dwNumChars = wcslen(strText); HRESULT hr = pd3dDevice->BeginVertices( D3DPT_QUADLIST, 4 * dwNumChars, sizeof( XMFLOAT4 ) , ( VOID** )&pVertex ); + // The ring buffer may run out of space when tiling, doing z-prepasses, + // or using BeginCommandBuffer. If so, make the buffer larger. if( FAILED( hr ) ) RARCH_ERR( "Ring buffer out of memory.\n" ); + // Draw four vertices for each glyph while( *strText ) { wchar_t letter; + // Get the current letter in the string letter = *strText++; + // Handle the newline character if( letter == L'\n' ) { font->m_fCursorX = fOriginX; @@ -644,6 +764,7 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo continue; } + // Translate unprintable characters const GLYPH_ATTR * pGlyph = &font->m_Glyphs[ ( letter <= font->m_cMaxGlyph ) ? font->m_TranslatorTable[letter] : 0 ]; float fOffset = font->m_fXScaleFactor * (float)pGlyph->wOffset; @@ -651,6 +772,7 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo float fWidth = font->m_fXScaleFactor * (float)pGlyph->wWidth; float fHeight = font->m_fYScaleFactor * font->m_fFontHeight; + // Setup the screen coordinates font->m_fCursorX += fOffset; float X4 = font->m_fCursorX; float X1 = X4; @@ -663,39 +785,58 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo font->m_fCursorX += fAdvance; - unsigned long dwChannelSelector = pGlyph->wMask; + // Select the RGBA channel that the compressed glyph is stored in + // Takes a 4 bit per pixel ARGB value and expand it to an 8 bit per pixel ARGB value + unsigned long dwChannelSelector = pGlyph->wMask; // Convert to 32 bit + // Perform the conversion without branching + + // Splat the 4 bit per pixels from 0x1234 to 0x01020304 dwChannelSelector = ((dwChannelSelector&0xF000)<<(24-12))|((dwChannelSelector&0xF00)<<(16-8))| ((dwChannelSelector&0xF0)<<(8-4))|(dwChannelSelector&0xF); + // Perform a vectorized multiply to make 0x01020304 into 0x11223344 dwChannelSelector *= 0x11; - unsigned long tu1 = pGlyph->tu1; + // Add the vertices to draw this glyph + + unsigned long tu1 = pGlyph->tu1; // Convert shorts to 32 bit longs for in register merging unsigned long tv1 = pGlyph->tv1; unsigned long tu2 = pGlyph->tu2; unsigned long tv2 = pGlyph->tv2; + // NOTE: The vertexs are 2 floats for the screen coordinates, + // followed by two USHORTS for the u/vs of the character, + // terminated with the ARGB 32 bit color. + // This makes for 16 bytes per vertex data (Easier to read) + // Second NOTE: The uvs are merged and written using a DWORD due + // to the write combining hardware being only able to handle 32, + // 64 and 128 writes. Never store to write combined memory with + // 8 or 16 bit instructions. You've been warned. + pVertex[0] = X1; pVertex[1] = Y1; - reinterpret_cast(pVertex)[2] = (tu1<<16)|tv1; + reinterpret_cast(pVertex)[2] = (tu1<<16)|tv1; // Merged using big endian rules reinterpret_cast(pVertex)[3] = dwChannelSelector; pVertex[4] = X2; pVertex[5] = Y2; - reinterpret_cast(pVertex)[6] = (tu2<<16)|tv1; + reinterpret_cast(pVertex)[6] = (tu2<<16)|tv1; // Merged using big endian rules reinterpret_cast(pVertex)[7] = dwChannelSelector; pVertex[8] = X3; pVertex[9] = Y3; - reinterpret_cast(pVertex)[10] = (tu2<<16)|tv2; + reinterpret_cast(pVertex)[10] = (tu2<<16)|tv2; // Merged using big endian rules reinterpret_cast(pVertex)[11] = dwChannelSelector; pVertex[12] = X4; pVertex[13] = Y4; - reinterpret_cast(pVertex)[14] = (tu1<<16)|tv2; + reinterpret_cast(pVertex)[14] = (tu1<<16)|tv2; // Merged using big endian rules reinterpret_cast(pVertex)[15] = dwChannelSelector; pVertex+=16; dwNumChars--; } + // Since we allocated vertex data space based on the string length, we now need to + // add some dummy verts for any skipped characters (like newlines, etc.) while( dwNumChars ) { pVertex[0] = 0; @@ -718,10 +859,13 @@ void xdk360_video_font_draw_text(xdk360_video_font_t * font, float fOriginX, flo dwNumChars--; } + // Stop drawing vertices D3DDevice_EndVertices(pd3dDevice); + // Undo window offsets font->m_fCursorX -= Winx; font->m_fCursorY -= Winy; + // Call End() to complete the begin/end pair for drawing text xdk360_video_font_end(font); }