summaryrefslogtreecommitdiff
path: root/utils/hlfaceposer/CloseCaptionTool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlfaceposer/CloseCaptionTool.cpp')
-rw-r--r--utils/hlfaceposer/CloseCaptionTool.cpp995
1 files changed, 995 insertions, 0 deletions
diff --git a/utils/hlfaceposer/CloseCaptionTool.cpp b/utils/hlfaceposer/CloseCaptionTool.cpp
new file mode 100644
index 0000000..670439c
--- /dev/null
+++ b/utils/hlfaceposer/CloseCaptionTool.cpp
@@ -0,0 +1,995 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include <stdio.h>
+#include "hlfaceposer.h"
+#include "CloseCaptionTool.h"
+#include "choreowidgetdrawhelper.h"
+#include <vgui/ILocalize.h>
+
+extern vgui::ILocalize *g_pLocalize;
+
+using namespace vgui;
+
+CloseCaptionTool *g_pCloseCaptionTool = 0;
+
+#define STREAM_FONT "Tahoma"
+#define STREAM_POINTSIZE 12
+#define STREAM_LINEHEIGHT ( STREAM_POINTSIZE + 2 )
+#define STREAM_WEIGHT FW_NORMAL
+
+#define CAPTION_LINGER_TIME 1.5f
+// FIXME: Yahn, what is this, it's coded up as a DELAY before when the closed caption is displayed. That seems odd.
+#define CAPTION_PREDISPLAY_TIME 0.0f // 0.5f
+
+
+
+
+// A work unit is a pre-processed chunk of CC text to display
+// Any state changes (font/color/etc) cause a new work unit to be precomputed
+// Moving onto a new line also causes a new Work Unit
+// The width and height are stored so that layout can be quickly recomputed each frame
+class CCloseCaptionWorkUnit
+{
+public:
+ CCloseCaptionWorkUnit();
+ ~CCloseCaptionWorkUnit();
+
+ void SetWidth( int w );
+ int GetWidth() const;
+
+ void SetHeight( int h );
+ int GetHeight() const;
+
+ void SetPos( int x, int y );
+ void GetPos( int& x, int &y ) const;
+
+ void SetBold( bool bold );
+ bool GetBold() const;
+
+ void SetItalic( bool ital );
+ bool GetItalic() const;
+
+ void SetStream( const wchar_t *stream );
+ const wchar_t *GetStream() const;
+
+ void SetColor( COLORREF clr );
+ COLORREF GetColor() const;
+
+ int GetFontNumber() const
+ {
+ return CloseCaptionTool::GetFontNumber( m_bBold, m_bItalic );
+ }
+
+ void Dump()
+ {
+ char buf[ 2048 ];
+ g_pLocalize->ConvertUnicodeToANSI( GetStream(), buf, sizeof( buf ) );
+
+ Msg( "x = %i, y = %i, w = %i h = %i text %s\n", m_nX, m_nY, m_nWidth, m_nHeight, buf );
+ }
+
+private:
+
+ int m_nX;
+ int m_nY;
+ int m_nWidth;
+ int m_nHeight;
+
+ bool m_bBold;
+ bool m_bItalic;
+ wchar_t *m_pszStream;
+ COLORREF m_Color;
+};
+
+CCloseCaptionWorkUnit::CCloseCaptionWorkUnit() :
+ m_nWidth(0),
+ m_nHeight(0),
+ m_bBold(false),
+ m_bItalic(false),
+ m_pszStream(0),
+ m_Color( RGB( 255, 255, 255 ) )
+{
+}
+
+CCloseCaptionWorkUnit::~CCloseCaptionWorkUnit()
+{
+ delete[] m_pszStream;
+ m_pszStream = NULL;
+}
+
+void CCloseCaptionWorkUnit::SetWidth( int w )
+{
+ m_nWidth = w;
+}
+
+int CCloseCaptionWorkUnit::GetWidth() const
+{
+ return m_nWidth;
+}
+
+void CCloseCaptionWorkUnit::SetHeight( int h )
+{
+ m_nHeight = h;
+}
+
+int CCloseCaptionWorkUnit::GetHeight() const
+{
+ return m_nHeight;
+}
+
+void CCloseCaptionWorkUnit::SetPos( int x, int y )
+{
+ m_nX = x;
+ m_nY = y;
+}
+
+void CCloseCaptionWorkUnit::GetPos( int& x, int &y ) const
+{
+ x = m_nX;
+ y = m_nY;
+}
+
+void CCloseCaptionWorkUnit::SetBold( bool bold )
+{
+ m_bBold = bold;
+}
+
+bool CCloseCaptionWorkUnit::GetBold() const
+{
+ return m_bBold;
+}
+
+void CCloseCaptionWorkUnit::SetItalic( bool ital )
+{
+ m_bItalic = ital;
+}
+
+bool CCloseCaptionWorkUnit::GetItalic() const
+{
+ return m_bItalic;
+}
+
+void CCloseCaptionWorkUnit::SetStream( const wchar_t *stream )
+{
+ delete[] m_pszStream;
+ m_pszStream = NULL;
+
+ int len = wcslen( stream );
+ Assert( len < 4096 );
+ m_pszStream = new wchar_t[ len + 1 ];
+ wcsncpy( m_pszStream, stream, len );
+ m_pszStream[ len ] = L'\0';
+}
+
+const wchar_t *CCloseCaptionWorkUnit::GetStream() const
+{
+ return m_pszStream ? m_pszStream : L"";
+}
+
+void CCloseCaptionWorkUnit::SetColor( COLORREF clr )
+{
+ m_Color = clr;
+}
+
+COLORREF CCloseCaptionWorkUnit::GetColor() const
+{
+ return m_Color;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CCloseCaptionItem
+{
+public:
+ CCloseCaptionItem(
+ wchar_t *stream,
+ float timetolive,
+ float predisplay,
+ bool valid
+ ) :
+ m_flTimeToLive( 0.0f ),
+ m_bValid( false ),
+ m_nTotalWidth( 0 ),
+ m_nTotalHeight( 0 ),
+ m_bSizeComputed( false )
+ {
+ SetStream( stream );
+ SetTimeToLive( timetolive );
+ SetPreDisplayTime( CAPTION_PREDISPLAY_TIME + predisplay );
+ m_bValid = valid;
+ m_bSizeComputed = false;
+ }
+
+ CCloseCaptionItem( const CCloseCaptionItem& src )
+ {
+ SetStream( src.m_szStream );
+ m_flTimeToLive = src.m_flTimeToLive;
+ m_bValid = src.m_bValid;
+ }
+
+ ~CCloseCaptionItem( void )
+ {
+ while ( m_Work.Count() > 0 )
+ {
+ CCloseCaptionWorkUnit *unit = m_Work[ 0 ];
+ m_Work.Remove( 0 );
+ delete unit;
+ }
+ }
+
+ void SetStream( const wchar_t *stream)
+ {
+ wcsncpy( m_szStream, stream, sizeof( m_szStream ) / sizeof( wchar_t ) );
+ }
+
+ const wchar_t *GetStream() const
+ {
+ return m_szStream;
+ }
+
+ void SetTimeToLive( float ttl )
+ {
+ m_flTimeToLive = ttl;
+ }
+
+ float GetTimeToLive( void ) const
+ {
+ return m_flTimeToLive;
+ }
+
+ bool IsValid() const
+ {
+ return m_bValid;
+ }
+
+ void SetHeight( int h )
+ {
+ m_nTotalHeight = h;
+ }
+ int GetHeight() const
+ {
+ return m_nTotalHeight;
+ }
+ void SetWidth( int w )
+ {
+ m_nTotalWidth = w;
+ }
+ int GetWidth() const
+ {
+ return m_nTotalWidth;
+ }
+
+ void AddWork( CCloseCaptionWorkUnit *unit )
+ {
+ m_Work.AddToTail( unit );
+ }
+
+ int GetNumWorkUnits() const
+ {
+ return m_Work.Count();
+ }
+
+ CCloseCaptionWorkUnit *GetWorkUnit( int index )
+ {
+ Assert( index >= 0 && index < m_Work.Count() );
+
+ return m_Work[ index ];
+ }
+
+ void SetSizeComputed( bool computed )
+ {
+ m_bSizeComputed = computed;
+ }
+
+ bool GetSizeComputed() const
+ {
+ return m_bSizeComputed;
+ }
+
+ void SetPreDisplayTime( float t )
+ {
+ m_flPreDisplayTime = t;
+ }
+
+ float GetPreDisplayTime() const
+ {
+ return m_flPreDisplayTime;
+ }
+private:
+ wchar_t m_szStream[ 256 ];
+
+ float m_flPreDisplayTime;
+ float m_flTimeToLive;
+ bool m_bValid;
+ int m_nTotalWidth;
+ int m_nTotalHeight;
+
+ bool m_bSizeComputed;
+
+ CUtlVector< CCloseCaptionWorkUnit * > m_Work;
+};
+
+ICloseCaptionManager *closecaptionmanager = NULL;
+
+CloseCaptionTool::CloseCaptionTool( mxWindow *parent )
+: IFacePoserToolWindow( "CloseCaptionTool", "Close Caption" ), mxWindow( parent, 0, 0, 0, 0 )
+{
+ m_nLastItemCount = -1;
+ closecaptionmanager = this;
+
+ m_hFonts[ CCFONT_NORMAL ] = CreateFont(
+ -STREAM_POINTSIZE,
+ 0,
+ 0,
+ 0,
+ STREAM_WEIGHT,
+ FALSE,
+ FALSE,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ STREAM_FONT );
+
+ m_hFonts[ CCFONT_ITALIC ] = CreateFont(
+ -STREAM_POINTSIZE,
+ 0,
+ 0,
+ 0,
+ STREAM_WEIGHT,
+ TRUE,
+ FALSE,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ STREAM_FONT );
+
+ m_hFonts[ CCFONT_BOLD ] = CreateFont(
+ -STREAM_POINTSIZE,
+ 0,
+ 0,
+ 0,
+ 700,
+ FALSE,
+ FALSE,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ STREAM_FONT );
+
+ m_hFonts[ CCFONT_ITALICBOLD ] = CreateFont(
+ -STREAM_POINTSIZE,
+ 0,
+ 0,
+ 0,
+ 700,
+ TRUE,
+ FALSE,
+ FALSE,
+ DEFAULT_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ STREAM_FONT );
+}
+
+CloseCaptionTool::~CloseCaptionTool( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dt -
+//-----------------------------------------------------------------------------
+void CloseCaptionTool::Think( float dt )
+{
+ int c = m_Items.Count();
+ int i;
+
+ // Pass one decay all timers
+ for ( i = 0 ; i < c ; ++i )
+ {
+ CCloseCaptionItem *item = m_Items[ i ];
+
+ float predisplay = item->GetPreDisplayTime();
+ if ( predisplay > 0.0f )
+ {
+ predisplay -= dt;
+ predisplay = max( 0.0f, predisplay );
+ item->SetPreDisplayTime( predisplay );
+ }
+ else
+ {
+ // remove time from actual playback
+ float ttl = item->GetTimeToLive();
+ ttl -= dt;
+ ttl = max( 0.0f, ttl );
+ item->SetTimeToLive( ttl );
+ }
+ }
+
+ // Pass two, remove from head until we get to first item with time remaining
+ bool foundfirstnondeletion = false;
+ for ( i = 0 ; i < c ; ++i )
+ {
+ CCloseCaptionItem *item = m_Items[ i ];
+
+ // Skip items not yet showing...
+ float predisplay = item->GetPreDisplayTime();
+ if ( predisplay > 0.0f )
+ {
+ continue;
+ }
+
+ float ttl = item->GetTimeToLive();
+ if ( ttl > 0.0f )
+ {
+ foundfirstnondeletion = true;
+ continue;
+ }
+
+ // Skip the remainder of the items after we find the first/oldest active item
+ if ( foundfirstnondeletion )
+ {
+ continue;
+ }
+
+ delete item;
+ m_Items.Remove( i );
+ --i;
+ --c;
+ }
+
+ if ( m_Items.Count() != m_nLastItemCount )
+ {
+ redraw();
+ }
+ m_nLastItemCount = m_Items.Count();
+}
+
+struct VisibleStreamItem
+{
+ int height;
+ CCloseCaptionItem *item;
+};
+
+void CloseCaptionTool::redraw()
+{
+ if ( !ToolCanDraw() )
+ return;
+
+ CChoreoWidgetDrawHelper drawHelper( this );
+ HandleToolRedraw( drawHelper );
+
+ RECT rcOutput;
+ drawHelper.GetClientRect( rcOutput );
+
+ RECT rcText = rcOutput;
+ drawHelper.DrawFilledRect( RGB( 0, 0, 0 ), rcText );
+ drawHelper.DrawOutlinedRect( RGB( 200, 245, 150 ), PS_SOLID, 2, rcText );
+ InflateRect( &rcText, -4, 0 );
+
+ int avail_width = rcText.right - rcText.left;
+
+ int totalheight = 0;
+ int i;
+ CUtlVector< VisibleStreamItem > visibleitems;
+ int c = m_Items.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ CCloseCaptionItem *item = m_Items[ i ];
+
+ // Not ready for display yet.
+ if ( item->GetPreDisplayTime() > 0.0f )
+ {
+ continue;
+ }
+
+ if ( !item->GetSizeComputed() )
+ {
+ ComputeStreamWork( drawHelper, avail_width, item );
+ }
+
+ int itemheight = item->GetHeight();
+
+ totalheight += itemheight;
+
+ VisibleStreamItem si;
+ si.height = itemheight;
+ si.item = item;
+
+ visibleitems.AddToTail( si );
+ }
+
+ rcText.bottom -= 2;
+ rcText.top = rcText.bottom - totalheight;
+
+ // Now draw them
+ c = visibleitems.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ VisibleStreamItem *si = &visibleitems[ i ];
+
+ int height = si->height;
+ CCloseCaptionItem *item = si->item;
+
+ rcText.bottom = rcText.top + height;
+
+ DrawStream( drawHelper, rcText, item );
+
+ OffsetRect( &rcText, 0, height );
+
+ if ( rcText.top >= rcOutput.bottom )
+ break;
+ }
+}
+
+int CloseCaptionTool::handleEvent( mxEvent *event )
+{
+ //MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iret = 0;
+
+ if ( HandleToolEvent( event ) )
+ {
+ return iret;
+ }
+
+ return iret;
+}
+
+bool CloseCaptionTool::PaintBackground()
+{
+ redraw();
+ return false;
+}
+
+void CloseCaptionTool::Reset( void )
+{
+ while ( m_Items.Count() > 0 )
+ {
+ CCloseCaptionItem *i = m_Items[ 0 ];
+ delete i;
+ m_Items.Remove( 0 );
+ }
+}
+
+void CloseCaptionTool::Process( char const *tokenname, float duration, int languageid )
+{
+ bool valid = true;
+ wchar_t stream[ 256 ];
+ if ( !LookupUnicodeText( languageid, tokenname, stream, sizeof( stream ) / sizeof( wchar_t ) ) )
+ {
+ valid = false;
+ g_pLocalize->ConvertANSIToUnicode( va( "--> Missing Caption[%s]", tokenname ), stream, sizeof( stream ) );
+ }
+
+ if ( !wcsncmp( stream, L"!!!", wcslen( L"!!!" ) ) )
+ {
+ // It's in the text file, but hasn't been translated...
+ valid = false;
+ }
+
+ // Nothing to do...
+ if ( wcslen( stream ) == 0 )
+ {
+ return;
+ }
+
+ float delay = 0.0f;
+
+ wchar_t phrase[ 1024 ];
+ wchar_t *out = phrase;
+
+ for ( const wchar_t *curpos = stream; curpos && *curpos != L'\0'; ++curpos )
+ {
+ wchar_t cmd[ 256 ];
+ wchar_t args[ 256 ];
+
+ if ( SplitCommand( &curpos, cmd, args ) )
+ {
+ if ( !wcscmp( cmd, L"delay" ) )
+ {
+
+ // End current phrase
+ *out = L'\0';
+
+ if ( wcslen( phrase ) > 0 )
+ {
+ CCloseCaptionItem *item = new CCloseCaptionItem( phrase, duration + CAPTION_LINGER_TIME, delay, valid );
+ m_Items.AddToTail( item );
+ }
+
+ // Start new phrase
+ out = phrase;
+
+ // Delay must be positive
+ delay = max( 0.0f, (float)wcstod( args, NULL ) );
+
+ continue;
+ }
+ }
+
+ *out++ = *curpos;
+ }
+
+ // End final phrase, if any
+ *out = L'\0';
+ if ( wcslen( phrase ) > 0 )
+ {
+ CCloseCaptionItem *item = new CCloseCaptionItem( phrase, duration + CAPTION_LINGER_TIME, delay, valid );
+ m_Items.AddToTail( item );
+ }
+}
+
+bool CloseCaptionTool::LookupUnicodeText( int languageId, char const *token, wchar_t *outbuf, size_t count )
+{
+ wchar_t *outstr = g_pLocalize->Find( token );
+ if ( !outstr )
+ {
+ wcsncpy( outbuf, L"<can't find entry>", count );
+ return false;
+ }
+
+ wcsncpy( outbuf, outstr, count );
+
+ return true;
+}
+
+bool CloseCaptionTool::LookupStrippedUnicodeText( int languageId, char const *token, wchar_t *outbuf, size_t count )
+{
+ wchar_t *outstr = g_pLocalize->Find( token );
+ if ( !outstr )
+ {
+ wcsncpy( outbuf, L"<can't find entry>", count );
+ return false;
+ }
+
+ const wchar_t *curpos = outstr;
+ wchar_t *out = outbuf;
+ size_t outlen = 0;
+
+ for ( ;
+ curpos && *curpos != L'\0' && outlen < count;
+ ++curpos )
+ {
+ wchar_t cmd[ 256 ];
+ wchar_t args[ 256 ];
+
+ if ( SplitCommand( &curpos, cmd, args ) )
+ {
+ continue;
+ }
+
+ *out++ = *curpos;
+ ++outlen;
+ }
+
+ *out = L'\0';
+
+ return true;
+}
+
+bool CloseCaptionTool::SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args ) const
+{
+ const wchar_t *in = *ppIn;
+ const wchar_t *oldin = in;
+
+ if ( in[0] != L'<' )
+ {
+ *ppIn += ( oldin - in );
+ return false;
+ }
+
+ args[ 0 ] = 0;
+ cmd[ 0 ]= 0;
+ wchar_t *out = cmd;
+ in++;
+ while ( *in != L'\0' && *in != L':' && *in != L'>' && !isspace( *in ) )
+ {
+ *out++ = *in++;
+ }
+ *out = L'\0';
+
+ if ( *in != L':' )
+ {
+ *ppIn += ( in - oldin );
+ return true;
+ }
+
+ in++;
+ out = args;
+ while ( *in != L'\0' && *in != L'>' )
+ {
+ *out++ = *in++;
+ }
+ *out = L'\0';
+
+ //if ( *in == L'>' )
+ // in++;
+
+ *ppIn += ( in - oldin );
+ return true;
+}
+
+struct WorkUnitParams
+{
+ WorkUnitParams()
+ {
+ Q_memset( stream, 0, sizeof( stream ) );
+ out = stream;
+ x = 0;
+ y = 0;
+ width = 0;
+ bold = italic = false;
+ clr = RGB( 255, 255, 255 );
+ newline = false;
+ }
+
+ ~WorkUnitParams()
+ {
+ }
+
+ void Finalize()
+ {
+ *out = L'\0';
+ }
+
+ void Next()
+ {
+ // Restart output
+ Q_memset( stream, 0, sizeof( stream ) );
+ out = stream;
+
+ x += width;
+
+ width = 0;
+ // Leave bold, italic and color alone!!!
+
+ if ( newline )
+ {
+ newline = false;
+ x = 0;
+ y += STREAM_LINEHEIGHT;
+ }
+ }
+
+ int GetFontNumber()
+ {
+ return CloseCaptionTool::GetFontNumber( bold, italic );
+ }
+
+ wchar_t stream[ 1024 ];
+ wchar_t *out;
+
+ int x;
+ int y;
+ int width;
+ bool bold;
+ bool italic;
+ COLORREF clr;
+ bool newline;
+};
+
+void CloseCaptionTool::AddWorkUnit( CCloseCaptionItem *item,
+ WorkUnitParams& params )
+{
+ params.Finalize();
+
+ if ( wcslen( params.stream ) > 0 )
+ {
+ CCloseCaptionWorkUnit *wu = new CCloseCaptionWorkUnit();
+
+ wu->SetStream( params.stream );
+ wu->SetColor( params.clr );
+ wu->SetBold( params.bold );
+ wu->SetItalic( params.italic );
+ wu->SetWidth( params.width );
+ wu->SetHeight( STREAM_LINEHEIGHT );
+ wu->SetPos( params.x, params.y );
+
+
+ int curheight = item->GetHeight();
+ int curwidth = item->GetWidth();
+
+ curheight = max( curheight, params.y + wu->GetHeight() );
+ curwidth = max( curwidth, params.x + params.width );
+
+ item->SetHeight( curheight );
+ item->SetWidth( curwidth );
+
+ // Add it
+ item->AddWork( wu );
+
+ params.Next();
+ }
+}
+
+void CloseCaptionTool::ComputeStreamWork( CChoreoWidgetDrawHelper &helper, int available_width, CCloseCaptionItem *item )
+{
+ // Start with a clean param block
+ WorkUnitParams params;
+
+ const wchar_t *curpos = item->GetStream();
+
+ CUtlVector< COLORREF > colorStack;
+
+ for ( ; curpos && *curpos != L'\0'; ++curpos )
+ {
+ wchar_t cmd[ 256 ];
+ wchar_t args[ 256 ];
+
+ if ( SplitCommand( &curpos, cmd, args ) )
+ {
+ if ( !wcscmp( cmd, L"cr" ) )
+ {
+ params.newline = true;
+ AddWorkUnit( item, params);
+ }
+ else if ( !wcscmp( cmd, L"clr" ) )
+ {
+ AddWorkUnit( item, params );
+
+ if ( args[0] == 0 && colorStack.Count()>= 2)
+ {
+ colorStack.Remove( colorStack.Count() - 1 );
+ params.clr = colorStack[ colorStack.Count() - 1 ];
+ }
+ else
+ {
+ int r = 0, g = 0, b = 0;
+ COLORREF newcolor;
+ if ( 3 == swscanf( args, L"%i,%i,%i", &r, &g, &b ) )
+ {
+ newcolor = RGB( r, g, b );
+ colorStack.AddToTail( newcolor );
+ params.clr = colorStack[ colorStack.Count() - 1 ];
+ }
+ }
+ }
+ else if ( !wcscmp( cmd, L"playerclr" ) )
+ {
+ AddWorkUnit( item, params );
+
+ if ( args[0] == 0 && colorStack.Count()>= 2)
+ {
+ colorStack.Remove( colorStack.Count() - 1 );
+ params.clr = colorStack[ colorStack.Count() - 1 ];
+ }
+ else
+ {
+ // player and npc color selector
+ // e.g.,. 255,255,255:200,200,200
+ int pr = 0, pg = 0, pb = 0, nr = 0, ng = 0, nb = 0;
+ COLORREF newcolor;
+ if ( 6 == swscanf( args, L"%i,%i,%i:%i,%i,%i", &pr, &pg, &pb, &nr, &ng, &nb ) )
+ {
+ // FIXME: nothing in .vcds is ever from the player...
+ newcolor = /*item->IsFromPlayer()*/ false ? RGB( pr, pg, pb ) : RGB( nr, ng, nb );
+ colorStack.AddToTail( newcolor );
+ params.clr = colorStack[ colorStack.Count() - 1 ];
+ }
+ }
+ }
+ else if ( !wcscmp( cmd, L"I" ) )
+ {
+ AddWorkUnit( item, params );
+ params.italic = !params.italic;
+ }
+ else if ( !wcscmp( cmd, L"B" ) )
+ {
+ AddWorkUnit( item, params );
+ params.bold = !params.bold;
+ }
+
+ continue;
+ }
+
+ HFONT useF = m_hFonts[ params.GetFontNumber() ];
+
+ int w = helper.CalcTextWidthW( useF, L"%c", *curpos );
+
+ if ( ( params.x + params.width ) + w > available_width )
+ {
+ params.newline = true;
+ AddWorkUnit( item, params );
+ }
+ *params.out++ = *curpos;
+ params.width += w;
+ }
+
+ // Add the final unit.
+ params.newline = true;
+ AddWorkUnit( item, params );
+
+ item->SetSizeComputed( true );
+
+ // DumpWork( item );
+}
+
+void CloseCaptionTool:: DumpWork( CCloseCaptionItem *item )
+{
+ int c = item->GetNumWorkUnits();
+ for ( int i = 0 ; i < c; ++i )
+ {
+ CCloseCaptionWorkUnit *wu = item->GetWorkUnit( i );
+ wu->Dump();
+ }
+}
+
+void CloseCaptionTool::DrawStream( CChoreoWidgetDrawHelper &helper, RECT &rcText, CCloseCaptionItem *item )
+{
+ int c = item->GetNumWorkUnits();
+
+ RECT rcOut;
+ rcOut.left = rcText.left;
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ int x = 0;
+ int y = 0;
+
+ CCloseCaptionWorkUnit *wu = item->GetWorkUnit( i );
+
+ HFONT useF = m_hFonts[ wu->GetFontNumber() ];
+
+ wu->GetPos( x, y );
+
+ rcOut.left = rcText.left + x;
+ rcOut.right = rcOut.left + wu->GetWidth();
+ rcOut.top = rcText.top + y;
+ rcOut.bottom = rcOut.top + wu->GetHeight();
+
+ COLORREF useColor = wu->GetColor();
+
+ if ( !item->IsValid() )
+ {
+ useColor = RGB( 255, 255, 255 );
+ rcOut.right += 2;
+ helper.DrawFilledRect( RGB( 100, 100, 40 ), rcOut );
+ }
+
+ helper.DrawColoredTextW( useF, useColor,
+ rcOut, L"%s", wu->GetStream() );
+
+ }
+}
+
+int CloseCaptionTool::GetFontNumber( bool bold, bool italic )
+{
+ if ( bold || italic )
+ {
+ if( bold && italic )
+ {
+ return CloseCaptionTool::CCFONT_ITALICBOLD;
+ }
+
+ if ( bold )
+ {
+ return CloseCaptionTool::CCFONT_BOLD;
+ }
+
+ if ( italic )
+ {
+ return CloseCaptionTool::CCFONT_ITALIC;
+ }
+ }
+
+ return CloseCaptionTool::CCFONT_NORMAL;
+} \ No newline at end of file