You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
995 lines
18 KiB
995 lines
18 KiB
//========= 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; |
|
} |