#include "stdafx.h" /* ----------------------------------------------------------------------------- File: BitmapText.h Desc: A font class that draws characters from a bitmap. Copyright (c) 2001 Chris Danford. All rights reserved. ----------------------------------------------------------------------------- */ #include "BitmapText.h" #include "IniFile.h" #include #include "RageTextureManager.h" BitmapText::BitmapText() { // m_colorTop = D3DXCOLOR(1,1,1,1); // m_colorBottom = D3DXCOLOR(1,1,1,1); for( int i=0; iGetDevice()->CreateVertexBuffer( MAX_NUM_VERTICIES * sizeof(CUSTOMVERTEX), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &m_pVB ); if( FAILED( hr ) ) { RageErrorHr( "Vertex Buffer Could Not Be Created", hr ); } m_iNumV = 0; } BitmapText::~BitmapText() { SAFE_RELEASE( m_pVB ); } bool BitmapText::Load( CString sFontFilePath ) { //RageLog( "BitmapText::LoadFromFontName(%s)", sFontFilePath ); m_sFontFilePath = sFontFilePath; // save // Split for the directory. We'll need it below CString sFontDir, sFontFileName, sFontExtension; splitrelpath( sFontFilePath, sFontDir, sFontFileName, sFontExtension ); // Read .font file IniFile ini; ini.SetPath( m_sFontFilePath ); if( !ini.ReadFile() ) RageError( ssprintf("Error opening Font file '%s'.", m_sFontFilePath) ); // load texture CString sTextureFile = ini.GetValue( "Font", "Texture" ); if( sTextureFile == "" ) RageError( ssprintf("Error reading value 'Texture' from %s.", m_sFontFilePath) ); CString sTexturePath = sFontDir + sTextureFile; // save the path of the new texture // is this the first time the texture is being loaded? bool bFirstTimeBeingLoaded = !TM->IsTextureLoaded( sTexturePath ); LoadTexture( sTexturePath ); // the size of the sprite is the size of the image before it was scaled SetWidth( (float)m_pTexture->GetSourceFrameWidth() ); SetHeight( (float)m_pTexture->GetSourceFrameHeight() ); // find out what characters are in this font CString sCharacters = ini.GetValue( "Font", "Characters" ); if( sCharacters != "" ) // the creator supplied characters { // sanity check if( sCharacters.GetLength() != Sprite::GetNumStates() ) RageError( ssprintf("The characters in '%s' does not match the number of frames in the texture.", m_sFontFilePath) ); // set the char to frameno map for( int i=0; iGetSourceFrameWidth(); } } if( bFirstTimeBeingLoaded ) { // tweak the textures frame rectangles so we don't draw extra to the left and right of the character for( int i=0; iGetTextureCoordRect( i ); float fPixelsToChopOff = m_fFrameNoToWidth[i] - GetUnzoomedWidth(); float fTexCoordsToChopOff = fPixelsToChopOff / m_pTexture->GetSourceWidth(); pFrect->left -= fTexCoordsToChopOff/2; pFrect->right += fTexCoordsToChopOff/2; } } return true; } // get a rectangle for the text, considering a possible text scaling. // useful to know if some text is visible or not float BitmapText::GetWidestLineWidthInSourcePixels() { float fWidestLineWidth = 0; for( int i=0; i fWidestLineWidth ) fWidestLineWidth = fLineWidth; } return fWidestLineWidth; } float BitmapText::GetLineWidthInSourcePixels( int iLineNo ) { CString &sLine = m_sTextLines[iLineNo]; float fLineWidth = 0; for( int i=0; iLock( 0, 0, (BYTE**)&v, 0 ); m_iNumV = 0; // the current vertex number float fHeight = GetUnzoomedHeight(); float fY; switch( m_VertAlign ) { case align_top: fY = -(m_sTextLines.GetSize()) * fHeight / 2; break; case align_middle: fY = 0; break; case align_bottom: fY = (m_sTextLines.GetSize()) * fHeight / 2; break; default: ASSERT( true ); } for( int i=0; i 1-fPercentageOfFrame ) fPercentExtra = 1-fPercentageOfFrame; // set vertex positions v[m_iNumV++].p = D3DXVECTOR3( fX, fY+fHeight/2, 0 ); // bottom left v[m_iNumV++].p = D3DXVECTOR3( fX, fY-fHeight/2, 0 ); // top left fX += fCharWidth; float fExtraPixels = fPercentExtra * GetUnzoomedWidth(); v[m_iNumV++].p = D3DXVECTOR3( fX+fExtraPixels, fY+fHeight/2, 0 ); // bottom right v[m_iNumV++].p = D3DXVECTOR3( fX+fExtraPixels, fY-fHeight/2, 0 ); // top right // set texture coordinates m_iNumV -= 4; FRECT* pTexCoordRect = m_pTexture->GetTextureCoordRect( iFrameNo ); float fExtraTexCoords = fPercentExtra * m_pTexture->GetTextureFrameWidth() / m_pTexture->GetTextureWidth(); v[m_iNumV].tu = pTexCoordRect->left; v[m_iNumV++].tv = pTexCoordRect->bottom; // bottom left v[m_iNumV].tu = pTexCoordRect->left; v[m_iNumV++].tv = pTexCoordRect->top; // top left v[m_iNumV].tu = pTexCoordRect->right + fExtraTexCoords; v[m_iNumV++].tv = pTexCoordRect->bottom; // bottom right v[m_iNumV].tu = pTexCoordRect->right + fExtraTexCoords; v[m_iNumV++].tv = pTexCoordRect->top; // top right } fY += fHeight; } pVB->Unlock(); } // draw text at x, y using colorTop blended down to colorBottom, with size multiplied by scale void BitmapText::RenderPrimitives() { if( m_sTextLines.GetSize() == 0 ) return; if( m_pTexture == NULL ) return; D3DXCOLOR colorDiffuse[4]; for(int i=0; i<4; i++) colorDiffuse[i] = m_colorDiffuse[i]; D3DXCOLOR colorAdd = m_colorAdd; // update properties based on SpriteEffects switch( m_Effect ) { case no_effect: break; case blinking: { for(int i=0; i<4; i++) colorDiffuse[i] = m_bTweeningTowardEndColor ? m_effect_colorDiffuse1 : m_effect_colorDiffuse2; } break; case camelion: { for(int i=0; i<4; i++) colorDiffuse[i] = m_effect_colorDiffuse1*m_fPercentBetweenColors + m_effect_colorDiffuse2*(1.0f-m_fPercentBetweenColors); } break; case glowing: colorAdd = m_effect_colorAdd1*m_fPercentBetweenColors + m_effect_colorAdd2*(1.0f-m_fPercentBetweenColors); break; case wagging: break; case spinning: // nothing special needed break; case vibrating: break; case flickering: m_bVisibleThisFrame = !m_bVisibleThisFrame; if( !m_bVisibleThisFrame ) for(int i=0; i<4; i++) colorDiffuse[i] = D3DXCOLOR(0,0,0,0); // don't draw the frame break; } // RebuildVertexBuffer(); LPDIRECT3DVERTEXBUFFER8 pVB = m_pVB; CUSTOMVERTEX* v; // Set the stage... LPDIRECT3DDEVICE8 pd3dDevice = SCREEN->GetDevice(); pd3dDevice->SetTexture( 0, m_pTexture->GetD3DTexture() ); pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); //pd3dDevice->SetRenderState( D3DRS_SRCBLEND, bBlendAdd ? D3DBLEND_ONE : D3DBLEND_SRCALPHA ); //pd3dDevice->SetRenderState( D3DRS_DESTBLEND, bBlendAdd ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA ); pd3dDevice->SetRenderState( D3DRS_SRCBLEND, m_bBlendAdd ? D3DBLEND_ONE : D3DBLEND_SRCALPHA ); pd3dDevice->SetRenderState( D3DRS_DESTBLEND, m_bBlendAdd ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA ); pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX ); pd3dDevice->SetStreamSource( 0, pVB, sizeof(CUSTOMVERTEX) ); if( colorDiffuse[0].a != 0 ) { ////////////////////// // render the shadow ////////////////////// if( m_bHasShadow ) { SCREEN->PushMatrix(); SCREEN->Translate( 5, 5, 0 ); // shift by 5 units pVB->Lock( 0, 0, (BYTE**)&v, 0 ); for( int i=0; iUnlock(); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); for( i=0; iDrawPrimitive( D3DPT_TRIANGLESTRIP, i, 2 ); SCREEN->PopMatrix(); } ////////////////////// // render the diffuse pass ////////////////////// pVB->Lock( 0, 0, (BYTE**)&v, 0 ); for( int i=0; iUnlock(); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );//bBlendAdd ? D3DTOP_ADD : D3DTOP_MODULATE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );//bBlendAdd ? D3DTOP_ADD : D3DTOP_MODULATE ); for( i=0; iDrawPrimitive( D3DPT_TRIANGLESTRIP, i, 2 ); } ////////////////////// // render the add pass ////////////////////// if( colorAdd.a != 0 ) { pVB->Lock( 0, 0, (BYTE**)&v, 0 ); for( int i=0; iUnlock(); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); for( i=0; iDrawPrimitive( D3DPT_TRIANGLESTRIP, i, 2 ); } } void BitmapText::SetText( CString sText ) { if( sText.GetLength() > MAX_NUM_VERTICIES ) sText = sText.Left( MAX_NUM_VERTICIES ); // strip out foreign chars for( int i=0; i NUM_CHARS-1 ) sText.Delete(i); m_sTextLines.RemoveAll(); split( sText, "\n", m_sTextLines, false ); RebuildVertexBuffer(); } CString BitmapText::GetText() { return join( "\n", m_sTextLines ); }