#include "stdafx.h" /* ----------------------------------------------------------------------------- File: BitmapText Desc: See header. Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. Chris Danford ----------------------------------------------------------------------------- */ #include "BitmapText.h" #include "IniFile.h" #include "FontManager.h" #include "RageLog.h" #include "RageException.h" #include "RageTimer.h" #include "PrefsManager.h" #define RAINBOW_COLOR_1 THEME->GetMetricC("BitmapText","RainbowColor1") #define RAINBOW_COLOR_2 THEME->GetMetricC("BitmapText","RainbowColor2") #define RAINBOW_COLOR_3 THEME->GetMetricC("BitmapText","RainbowColor3") #define RAINBOW_COLOR_4 THEME->GetMetricC("BitmapText","RainbowColor4") #define RAINBOW_COLOR_5 THEME->GetMetricC("BitmapText","RainbowColor5") #define RAINBOW_COLOR_6 THEME->GetMetricC("BitmapText","RainbowColor6") #define RAINBOW_COLOR_7 THEME->GetMetricC("BitmapText","RainbowColor7") const int NUM_RAINBOW_COLORS = 7; D3DXCOLOR RAINBOW_COLORS[NUM_RAINBOW_COLORS]; BitmapText::BitmapText() { // Loading these theme metrics is slow, so only do it ever 20th time. static int iReloadCounter = 0; if( iReloadCounter%20==0 ) { RAINBOW_COLORS[0] = RAINBOW_COLOR_1; RAINBOW_COLORS[1] = RAINBOW_COLOR_2; RAINBOW_COLORS[2] = RAINBOW_COLOR_3; RAINBOW_COLORS[3] = RAINBOW_COLOR_4; RAINBOW_COLORS[4] = RAINBOW_COLOR_5; RAINBOW_COLORS[5] = RAINBOW_COLOR_6; RAINBOW_COLORS[6] = RAINBOW_COLOR_7; } iReloadCounter++; m_HorizAlign = align_center; m_VertAlign = align_middle; m_pFont = NULL; m_iNumLines = 0; m_iWidestLineWidth = 0; for( int i=0; iUnloadFont( m_pFont->m_sFontFilePath ); } bool BitmapText::LoadFromFont( CString sFontFilePath ) { LOG->Trace( "BitmapText::LoadFromFontName(%s)", sFontFilePath ); // load font m_pFont = FONT->LoadFont( sFontFilePath, "" ); return true; } void BitmapText::SetText( CString sText ) { //LOG->Trace( "BitmapText::SetText()" ); if( m_pFont->m_bCapitalsOnly ) sText.MakeUpper(); // // save the string and crop if necessary // ASSERT( sText.GetLength() < MAX_TEXT_CHARS/2 ); strncpy( m_szText, sText, MAX_TEXT_CHARS ); m_szText[MAX_TEXT_CHARS-1] = '\0'; int iLength = strlen( m_szText ); // // strip out non-low ASCII chars // for( int i=0; i MAX_FONT_CHARS-1 ) m_szText[i] = ' '; } // // break the string into lines // m_iNumLines = 0; LPSTR token; /* Establish string and get the first token: */ token = strtok( m_szText, "\n" ); while( token != NULL ) { m_szTextLines[m_iNumLines++] = token; token = strtok( NULL, "\n" ); } // // calculate line lengths and widths // m_iWidestLineWidth = 0; for( int l=0; lGetLineWidthInSourcePixels( m_szTextLines[l], m_iLineLengths[l] ); if( m_iLineWidths[l] > m_iWidestLineWidth ) m_iWidestLineWidth = m_iLineWidths[l]; } // fill the RageScreen's vertex buffer with what we're going to draw //RebuildVertexBuffer(); } void BitmapText::CropToWidth( int iMaxWidthInSourcePixels ) { iMaxWidthInSourcePixels = max( 0, iMaxWidthInSourcePixels ); for( int l=0; l iMaxWidthInSourcePixels ) { m_iLineLengths[l]--; m_iLineWidths[l] = m_pFont->GetLineWidthInSourcePixels( m_szTextLines[l], m_iLineLengths[l] ); } } } // draw text at x, y using colorTop blended down to colorBottom, with size multiplied by scale void BitmapText::DrawPrimitives() { // offset so that pixels are aligned to texels if( PREFSMAN->m_iDisplayResolution == 320 ) DISPLAY->TranslateLocal( -1, -1, 0 ); else DISPLAY->TranslateLocal( -0.5f, -0.5f, 0 ); if( m_iNumLines == 0 ) return; RageTexture* pTexture = m_pFont->m_pTexture; // make the object in logical units centered at the origin static RAGEVERTEX v[4000]; int iNumV = 0; // the current vertex number const int iHeight = pTexture->GetSourceFrameHeight(); // height of a character const int iFrameWidth = pTexture->GetSourceFrameWidth(); // width of a character frame in logical units int iY; // the center position of the first row of characters switch( m_VertAlign ) { case align_bottom: iY = -(m_iNumLines) * iHeight + iHeight/2; break; case align_middle: iY = -(m_iNumLines-1) * iHeight/2; break; case align_top: iY = + iHeight/2; break; default: ASSERT( false ); } for( int i=0; im_iCharToFrameNo[c]; if( iFrameNo == -1 ) // this font doesn't impelemnt this character throw RageException( "The font '%s' does not implement the character '%c'", m_sFontFilePath, c ); const int iCharWidth = m_pFont->m_iFrameNoToWidth[iFrameNo]; // HACK: // The right side of any italic letter is being cropped. So, we're going to draw a little bit // to the right of the normal character. const float fPercentExtra = min( m_pFont->m_fDrawExtraPercent, (iFrameWidth-iCharWidth)/(float)iFrameWidth ); // don't draw from the adjacent frame // // set vertex positions // const float fExtraPixels = fPercentExtra * pTexture->GetSourceFrameWidth(); v[iNumV++].p = D3DXVECTOR3( (float)iX, iY-iHeight/2.0f, 0 ); // top left v[iNumV++].p = D3DXVECTOR3( iX+iCharWidth+fExtraPixels, iY-iHeight/2.0f, 0 ); // top right v[iNumV++].p = D3DXVECTOR3( (float)iX, iY+iHeight/2.0f, 0 ); // bottom left v[iNumV++].p = D3DXVECTOR3( iX+iCharWidth+fExtraPixels, iY+iHeight/2.0f, 0 ); // bottom right iX += iCharWidth; // // set texture coordinates // iNumV -= 4; FRECT frectTexCoords = *pTexture->GetTextureCoordRect( iFrameNo ); // Tweak the textures frame rectangles so we don't draw extra // to the left and right of the character, saving us fill rate. float fPixelsToChopOff = pTexture->GetSourceFrameWidth() - (float)iCharWidth; float fTexCoordsToChopOff = fPixelsToChopOff / pTexture->GetSourceWidth(); frectTexCoords.left += fTexCoordsToChopOff/2; frectTexCoords.right -= fTexCoordsToChopOff/2; const float fExtraTexCoords = fPercentExtra * pTexture->GetTextureFrameWidth() / pTexture->GetTextureWidth(); v[iNumV++].t = D3DXVECTOR2( frectTexCoords.left, frectTexCoords.top ); // top left v[iNumV++].t = D3DXVECTOR2( frectTexCoords.right + fExtraTexCoords, frectTexCoords.top ); // top right v[iNumV++].t = D3DXVECTOR2( frectTexCoords.left, frectTexCoords.bottom ); // bottom left v[iNumV++].t = D3DXVECTOR2( frectTexCoords.right + fExtraTexCoords, frectTexCoords.bottom ); // bottom right } iY += iHeight; } DISPLAY->SetTexture( pTexture ); DISPLAY->SetColorTextureMultDiffuse(); DISPLAY->SetAlphaTextureMultDiffuse(); if( m_bBlendAdd ) DISPLAY->SetBlendModeAdd(); else DISPLAY->SetBlendModeNormal(); if( m_temp_colorDiffuse[0].a != 0 ) { ////////////////////// // render the shadow ////////////////////// if( m_bShadow ) { DISPLAY->PushMatrix(); DISPLAY->TranslateLocal( m_fShadowLength, m_fShadowLength, 0 ); // shift by 5 units DWORD dwColor = D3DXCOLOR(0,0,0,0.5f*m_temp_colorDiffuse[0].a); // semi-transparent black int i; for( i=0; iAddQuad( &v[i] ); DISPLAY->PopMatrix(); } ////////////////////// // render the diffuse pass ////////////////////// if( m_bRainbow ) { int color_index = int(TIMER->GetTimeSinceStart() / 0.200) % NUM_RAINBOW_COLORS; for( int i=0; iAddQuad( &v[i] ); } ////////////////////// // render the glow pass ////////////////////// if( m_temp_colorGlow.a != 0 ) { DISPLAY->SetColorDiffuse(); int i; for( i=0; iAddQuad( &v[i] ); } }