doom3-bfg/neo/swf/SWF_TextInstance.cpp
2012-11-26 12:58:24 -06:00

1242 lines
36 KiB
C++

/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#pragma hdrstop
#include "../idlib/precompiled.h"
#include "../renderer/Font.h"
idSWFScriptObject_TextInstancePrototype textInstanceScriptObjectPrototype;
idCVar swf_textScrollSpeed( "swf_textScrollSpeed", "80", CVAR_INTEGER, "scroll speed for text" );
idCVar swf_textRndLetterSpeed( "swf_textRndLetterSpeed", "8", CVAR_INTEGER, "scroll speed for text" );
idCVar swf_textRndLetterDelay( "swf_textRndLetterDelay", "100", CVAR_INTEGER, "scroll speed for text" );
idCVar swf_textParagraphSpeed( "swf_textParagraphSpeed", "15", CVAR_INTEGER, "scroll speed for text" );
idCVar swf_textParagraphInc( "swf_textParagraphInc", "1.3", CVAR_FLOAT, "scroll speed for text" );
idCVar swf_subtitleExtraTime( "swf_subtitleExtraTime", "3500", CVAR_INTEGER, "time after subtitles vo is complete" );
idCVar swf_subtitleEarlyTrans( "swf_subtitleEarlyTrans", "3500", CVAR_INTEGER, "early time out to switch the line" );
idCVar swf_subtitleLengthGuess( "swf_subtitleLengthGuess", "10000", CVAR_INTEGER, "early time out to switch the line" );
idCVar swf_textMaxInputLength( "swf_textMaxInputLength", "104", CVAR_INTEGER, "max number of characters that can go into the input line" );
idCVar swf_textStrokeSize( "swf_textStrokeSize", "1.65f", CVAR_FLOAT, "size of font glyph stroke", 0.0f, 2.0f );
idCVar swf_textStrokeSizeGlyphSpacer( "swf_textStrokeSizeGlyphSpacer", "1.5f", CVAR_FLOAT, "additional space for spacing glyphs using stroke" );
/*
========================
idSWFTextInstance::idSWFTextInstance
========================
*/
idSWFTextInstance::idSWFTextInstance() {
swf = NULL;
}
/*
========================
idSWFTextInstance::~idSWFTextInstance
================== ======
*/
idSWFTextInstance::~idSWFTextInstance() {
scriptObject.SetText( NULL );
scriptObject.Clear();
scriptObject.Release();
subtitleTimingInfo.Clear();
}
/*
========================
idSWFTextInstance::Init
========================
*/
void idSWFTextInstance::Init( idSWFEditText * _editText, idSWF * _swf ) {
editText = _editText;
swf = _swf;
text = idLocalization::GetString( editText->initialText );
lengthCalculated = false;
variable = editText->variable;
color = editText->color;
visible = true;
selectionStart = -1;
selectionEnd = -1;
scroll = 0;
scrollTime = 0;
maxscroll = 0;
maxLines = 0;
linespacing = 0;
glyphScale = 1.0f;
shiftHeld = false;
tooltip = false;
renderMode = SWF_TEXT_RENDER_NORMAL;
generatingText = false;
triggerGenerate = false;
rndSpotsVisible = 0;
textSpotsVisible = 0;
startRndTime = 0;
charMultiplier = 0;
prevReplaceIndex = 0;
scrollUpdate = false;
ignoreColor = false;
isSubtitle = false;
subLength = 0;
subAlign = 0;
subUpdating = false;
subCharStartIndex = 0;
subNextStartIndex = 0;
subCharEndIndex = 0;
subDisplayTime = 0;
subStartTime = -1;
subSourceID = -1;
subNeedsSwitch = false;
subForceKill = false;
subKillTimeDelay = 0;
subSwitchTime = 0;
subLastWordIndex = 0;
subPrevLastWordIndex = 0;
subInitialLine = true;
textLength = 0;
inputTextStartChar = 0;
renderDelay = swf_textRndLetterDelay.GetInteger();
needsSoundUpdate = false;
useDropShadow = false;
useStroke = false;
strokeStrength = 1.0f;
strokeWeight = swf_textStrokeSize.GetFloat();
scriptObject.SetPrototype( &textInstanceScriptObjectPrototype );
scriptObject.SetText( this );
scriptObject.SetNoAutoDelete( true );
}
/*
========================
idSWFTextInstance::GetTextLength
========================
*/
float idSWFTextInstance::GetTextLength() {
// CURRENTLY ONLY WORKS FOR SINGLE LINE TEXTFIELDS
if ( lengthCalculated && variable.IsEmpty() ) {
return textLength;
}
idStr txtLengthCheck = "";
float len = 0.0f;
if ( verify( swf != NULL ) ) {
if ( !variable.IsEmpty() ) {
idSWFScriptVar var = swf->GetGlobal( variable );
if ( var.IsUndefined() ) {
txtLengthCheck = text;
} else {
txtLengthCheck = var.ToString();
}
txtLengthCheck = idLocalization::GetString( txtLengthCheck );
} else {
txtLengthCheck = idLocalization::GetString( text );
}
const idSWFEditText * shape = editText;
idSWFDictionaryEntry * fontEntry = swf->FindDictionaryEntry( shape->fontID, SWF_DICT_FONT );
idSWFFont * swfFont = fontEntry->font;
float width = fabs( shape->bounds.br.x - shape->bounds.tl.x );
float postTrans = SWFTWIP( shape->fontHeight );
const idFont * fontInfo = swfFont->fontID;
float glyphScale = postTrans / 48.0f;
int tlen = txtLengthCheck.Length();
int index = 0;
while ( index < tlen ) {
scaledGlyphInfo_t glyph;
fontInfo->GetScaledGlyph( glyphScale, txtLengthCheck.UTF8Char( index ), glyph );
len += glyph.xSkip;
if ( useStroke ) {
len += ( swf_textStrokeSizeGlyphSpacer.GetFloat() * strokeWeight * glyphScale );
}
if ( !( shape->flags & SWF_ET_AUTOSIZE ) && len >= width ) {
len = width;
break;
}
}
}
lengthCalculated = true;
textLength = len;
return textLength;
}
/*
========================
idSWFTextInstance::StartParagraphText
========================
*/
void idSWFTextInstance::StartParagraphText( int time ) {
generatingText = true;
textSpotsVisible = 0;
randomtext = "";
triggerGenerate = false;
startRndTime = time;
rndTime = time;
rnd.SetSeed( time );
prevReplaceIndex = 0;
rndSpotsVisible = text.Length();
indexArray.Clear();
charMultiplier = 0;
text = idLocalization::GetString( text );
lengthCalculated = false;
for( int index = 0; index < text.Length(); ++index ) {
randomtext.Append( " " );
indexArray.Append( index );
}
for( int index = 0; index < indexArray.Num(); ++index ) {
int swapIndex = rnd.RandomInt( indexArray.Num() );
int val = indexArray[index];
indexArray[index] = indexArray[swapIndex];
indexArray[swapIndex] = val;
}
}
/*
========================
idSWFTextInstance::GetParagraphText
========================
*/
idStr idSWFTextInstance::GetParagraphText( int time ) {
if ( triggerGenerate ) {
return " ";
} else if ( time - startRndTime < renderDelay ) {
return " ";
} else if ( generatingText ) {
if ( time - rndTime >= renderDelay ) {
rndTime = time;
needsSoundUpdate = true;
if ( prevReplaceIndex >= text.Length() ) {
generatingText = false;
return text;
}
randomtext[prevReplaceIndex] = text[prevReplaceIndex];
prevReplaceIndex++;
}
} else {
scrollUpdate = false;
return text;
}
return randomtext;
}
/*
========================
idSWFTextInstance::StartRandomText
========================
*/
bool idSWFTextInstance::NeedsSoundPlayed() {
if ( soundClip.IsEmpty() ) {
return false;
}
return needsSoundUpdate;
}
/*
========================
idSWFTextInstance::StartRandomText
========================
*/
void idSWFTextInstance::StartRandomText( int time ) {
generatingText = true;
textSpotsVisible = 0;
randomtext = "";
triggerGenerate = false;
startRndTime = time;
rndTime = time;
rnd.SetSeed( time );
rndSpotsVisible = 0;
text = idLocalization::GetString( text );
lengthCalculated = false;
for( int index = 0; index < text.Length(); ++index ) {
if ( text[index] == ' ' ) {
randomtext.Append( " " );
} else {
randomtext.Append( "." );
rndSpotsVisible++;
}
}
}
/*
========================
idSWFTextInstance::GetRandomText
========================
*/
idStr idSWFTextInstance::GetRandomText( int time ) {
if ( triggerGenerate ) {
return " ";
} else if ( time - startRndTime < renderDelay ) {
return " ";
} else if ( generatingText ) {
if ( rndSpotsVisible > 0 ) {
int waitTime = swf_textRndLetterSpeed.GetInteger();
if ( randomtext.Length() >= 10 ) {
waitTime = waitTime / 3;
}
if ( time - rndTime >= waitTime ) {
rndTime = time;
int spotIndex = rnd.RandomInt( rndSpotsVisible );
int cIndex = 0;
for( int c = 0; c < randomtext.Length(); ++ c ) {
if ( c >= text.Length() ) {
rndSpotsVisible = 0;
break;
}
if ( randomtext[c] == '.' ) {
cIndex++;
}
if ( cIndex == spotIndex ) {
bool useCaps = false;
if ( c - 1 >= 0 && text[c-1] == ' ' ) {
useCaps = true;
} else if ( c == 0 ) {
useCaps = true;
}
if ( useCaps || renderMode == SWF_TEXT_RENDER_RANDOM_APPEAR_CAPS ) {
randomtext[c] = rnd.RandomInt( 'Z' - 'A' ) + 'A';
} else {
randomtext[c] = rnd.RandomInt( 'z' - 'a' ) + 'a';
}
rndSpotsVisible--;
if ( !soundClip.IsEmpty() ) {
needsSoundUpdate = true;
}
break;
}
}
}
} else if ( rndSpotsVisible == 0 && textSpotsVisible < text.Length() ) {
if ( textSpotsVisible >= randomtext.Length() ) {
textSpotsVisible++;
} else {
if ( time - rndTime >= swf_textRndLetterSpeed.GetInteger() ) {
rndTime = time;
randomtext[textSpotsVisible] = text[textSpotsVisible];
textSpotsVisible++;
if ( !soundClip.IsEmpty() ) {
needsSoundUpdate = true;
}
}
}
} else {
return " ";
}
} else {
return text;
}
if ( rndSpotsVisible == 0 && textSpotsVisible == text.Length() ) {
generatingText = false;
}
return randomtext;
}
/*
==============================================
SUBTITLE FUNCTIONALITY
==============================================
*/
/*
==============================================
idSWFTextInstance::SwitchSubtitleText
==============================================
*/
void idSWFTextInstance::SwitchSubtitleText( int time ) {
subNeedsSwitch = false;
}
void idSWFTextInstance::SetSubNextStartIndex( int value ) {
subNextStartIndex = value;
}
/*
==============================================
idSWFTextInstance::UpdateSubtitle
==============================================
*/
bool idSWFTextInstance::UpdateSubtitle( int time ) {
if ( subForceKillQueued ) {
subForceKillQueued = false;
subForceKill = true;
subKillTimeDelay = time + swf_subtitleExtraTime.GetInteger();
}
if ( subUpdating && !subForceKill ) {
if ( ( time >= subSwitchTime && !subNeedsSwitch ) || ( !subNeedsSwitch && subInitialLine ) ) {
//idLib::Printf( "SWITCH TIME %d / %d \n", time, subSwitchTime );
if ( subInitialLine && subtitleTimingInfo.Num() > 0 ) {
if ( subStartTime == -1 ) {
subStartTime = time - 600;
}
if ( time < subStartTime + subtitleTimingInfo[0].startTime ) {
return true;
} else {
text = subtitleText;//subtitleText = "";
subInitialLine = false;
}
}
if ( subNextStartIndex + 1 >= text.Length( ) ) {
subForceKillQueued = true;
} else {
subCharStartIndex = subNextStartIndex;
//subtitleText.CopyRange( text, subCharStartIndex, subCharEndIndex );
subNeedsSwitch = true;
}
}
}
if ( subForceKill ) {
if ( time >= subKillTimeDelay ) {
subForceKill = false;
return false;
}
}
return true;
}
/*
==============================================
idSWFTextInstance::SubtitleComplete
==============================================
*/
void idSWFTextInstance::SetSubEndIndex( int endChar, int time ) {
subCharEndIndex = endChar;
if ( subCharEndIndex + 1 >= text.Length() ) {
LastWordChanged( subtitleTimingInfo.Num(), time );
}
}
/*
==============================================
idSWFTextInstance::SubtitleComplete
==============================================
*/
void idSWFTextInstance::SubtitleComplete() {
subInitialLine = true;
subUpdating = false;
isSubtitle = false;
subNeedsSwitch = false;
subCharDisplayTime = 0;
subForceKillQueued = false;
subForceKill = false;
subKillTimeDelay = 0;
subSwitchTime = 0;
subLastWordIndex = 0;
subPrevLastWordIndex = 0;
subStartTime = -1;
subSpeaker = "";
subtitleText = "";
text = "";
subtitleTimingInfo.Clear();
}
/*
==============================================
idSWFTextInstance::LastWordChanged
==============================================
*/
void idSWFTextInstance::LastWordChanged( int wordCount, int time ) {
if ( subPrevLastWordIndex + wordCount >= subtitleTimingInfo.Num() ) {
subLastWordIndex = subtitleTimingInfo.Num() - 1;
} else {
subLastWordIndex = subPrevLastWordIndex + wordCount - 1;
}
if ( subStartTime == -1 ) {
if ( subtitleTimingInfo.Num() > 0 ) {
subStartTime = time + subtitleTimingInfo[0].startTime;
} else {
subStartTime = time;
}
}
subSwitchTime = subStartTime + subtitleTimingInfo[subLastWordIndex].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 1 %d last word %d\n", subSwitchTime, subLastWordIndex );
}
/*
==============================================
idSWFTextInstance::GetSubtitleBreak
==============================================
*/
int idSWFTextInstance::GetApporoximateSubtitleBreak( int time ) {
int wordIndex = subLastWordIndex;
bool setSwitchTime = false;
if ( subStartTime == -1 ) {
subStartTime = time;
}
if ( time >= subSwitchTime ) {
subPrevLastWordIndex = subLastWordIndex;
for( int i = wordIndex; i < subtitleTimingInfo.Num(); ++i ) {
if ( subtitleTimingInfo[i].forceBreak ) {
if ( i + 1 < subtitleTimingInfo.Num() ) {
subSwitchTime = subStartTime + subtitleTimingInfo[i+1].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 2 %d\n", subSwitchTime );
subLastWordIndex = i;
setSwitchTime = true;
break;
} else {
subSwitchTime = subStartTime + subtitleTimingInfo[i].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 3 %d\n", subSwitchTime );
subLastWordIndex = i;
setSwitchTime = true;
break;
}
} else {
int timeSpan = subtitleTimingInfo[i].startTime - subtitleTimingInfo[wordIndex].startTime;
if ( timeSpan > swf_subtitleLengthGuess.GetInteger() ) {
if ( i - 1 >= 0 ) {
subSwitchTime = subStartTime + subtitleTimingInfo[i].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 4 %d\n", subSwitchTime );
subLastWordIndex = i - 1;
} else {
subSwitchTime = subStartTime + subtitleTimingInfo[i].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 5 %d\n", subSwitchTime );
subLastWordIndex = i;
}
setSwitchTime = true;
break;
}
}
}
if ( !setSwitchTime && subtitleTimingInfo.Num() > 0 ) {
subSwitchTime = subStartTime + subtitleTimingInfo[ subtitleTimingInfo.Num() - 1 ].startTime;// - swf_subtitleEarlyTrans.GetInteger();
//idLib::Printf( "switchtime set 6 %d\n", subSwitchTime );
subLastWordIndex = subtitleTimingInfo.Num();
}
}
return subLastWordIndex;
}
/*
==============================================
idSWFTextInstance::SubtitleComplete
==============================================
*/
void idSWFTextInstance::SubtitleCleanup() {
subSourceID = -1;
subAlign = -1;
text = "";
}
/*
==============================================
idSWFTextInstance::SetStrokeInfo
==============================================
*/
void idSWFTextInstance::SetStrokeInfo( bool use, float strength, float weight ) {
useStroke = use;
if ( use ) {
strokeWeight = weight;
strokeStrength = strength;
}
}
/*
==============================================
idSWFTextInstance::CalcMaxScroll
==============================================
*/
int idSWFTextInstance::CalcMaxScroll( int numLines ) {
if ( numLines != -1 ) {
if ( numLines < 0 ) {
numLines = 0;
}
maxscroll = numLines;
return maxscroll;
}
const idSWFEditText * shape = editText;
if ( !( shape->flags & SWF_ET_MULTILINE ) ) {
return 0;
}
if ( swf == NULL ) {
return 0;
}
idSWFDictionaryEntry * fontEntry = swf->FindDictionaryEntry( shape->fontID, SWF_DICT_FONT );
if ( fontEntry == NULL ) {
return 0;
}
idSWFFont * swfFont = fontEntry->font;
if ( swfFont == NULL ) {
return 0;
}
const idFont * fontInfo = swfFont->fontID;
if ( fontInfo == NULL ) {
return 0;
}
idStr textCheck;
if ( variable.IsEmpty() ) {
textCheck = idLocalization::GetString( text );
} else {
textCheck = idLocalization::GetString( variable );
}
if ( textCheck.IsEmpty() ) {
return 0;
}
float x = bounds.tl.x;
float y = bounds.tl.y;
idList< idStr > textLines;
idStr * currentLine = &textLines.Alloc();
// tracks the last breakable character we found
int lastbreak = 0;
float lastbreakX = 0;
int charIndex = 0;
if ( IsSubtitle() ) {
charIndex = GetSubStartIndex();
}
while ( charIndex < textCheck.Length() ) {
if ( textCheck[ charIndex ] == '\n' ) {
if ( shape->flags & SWF_ET_MULTILINE ) {
currentLine->Append( '\n' );
x = bounds.tl.x;
y += linespacing;
currentLine = &textLines.Alloc();
lastbreak = 0;
charIndex++;
continue;
} else {
break;
}
}
int glyphStart = charIndex;
uint32 tc = textCheck.UTF8Char( charIndex );
scaledGlyphInfo_t glyph;
fontInfo->GetScaledGlyph( glyphScale, tc, glyph );
float glyphSkip = glyph.xSkip;
if ( HasStroke() ) {
glyphSkip += ( swf_textStrokeSizeGlyphSpacer.GetFloat() * GetStrokeWeight() * glyphScale );
}
if ( x + glyphSkip > bounds.br.x ) {
if ( shape->flags & ( SWF_ET_MULTILINE | SWF_ET_WORDWRAP ) ) {
if ( lastbreak > 0 ) {
int curLineIndex = currentLine - &textLines[0];
idStr * newline = &textLines.Alloc();
currentLine = &textLines[ curLineIndex ];
if ( maxLines == 1 ) {
currentLine->CapLength( currentLine->Length() - 3 );
currentLine->Append( "..." );
break;
} else {
*newline = currentLine->c_str() + lastbreak;
currentLine->CapLength( lastbreak );
currentLine = newline;
x -= lastbreakX;
}
} else {
currentLine = &textLines.Alloc();
x = bounds.tl.x;
}
lastbreak = 0;
} else {
break;
}
}
while ( glyphStart < charIndex && glyphStart < text.Length() ) {
currentLine->Append( text[ glyphStart++ ] );
}
x += glyphSkip;
if ( tc == ' ' || tc == '-' ) {
lastbreak = currentLine->Length();
lastbreakX = x;
}
}
maxscroll = textLines.Num() - maxLines;
if ( maxscroll < 0 ) {
maxscroll = 0;
}
return maxscroll;
}
int idSWFTextInstance::CalcNumLines() {
const idSWFEditText * shape = editText;
if ( !( shape->flags & SWF_ET_MULTILINE ) ) {
return 1;
}
idSWFDictionaryEntry * fontEntry = swf->FindDictionaryEntry( shape->fontID, SWF_DICT_FONT );
if ( fontEntry == NULL ) {
return 1;
}
idStr textCheck;
if ( variable.IsEmpty() ) {
textCheck = idLocalization::GetString( text );
} else {
textCheck = idLocalization::GetString( variable );
}
if ( textCheck.IsEmpty() ) {
return 1;
}
if ( swf == NULL ) {
return 1;
}
idSWFFont * swfFont = fontEntry->font;
float postTransformHeight = SWFTWIP( shape->fontHeight );
const idFont * fontInfo = swfFont->fontID;
float glyphScale = postTransformHeight / 48.0f;
swfRect_t bounds;
bounds.tl.x = ( shape->bounds.tl.x + SWFTWIP( shape->leftMargin ) );
bounds.br.x = ( shape->bounds.br.x - SWFTWIP( shape->rightMargin ) );
bounds.tl.y = ( shape->bounds.tl.y + ( 1.15f * glyphScale ) );
bounds.br.y = ( shape->bounds.br.y );
float linespacing = fontInfo->GetAscender( 1.15f * glyphScale );
if ( shape->leading != 0 ) {
linespacing += ( glyphScale * SWFTWIP( shape->leading ) );
}
float x = bounds.tl.x;
int maxLines = idMath::Ftoi( ( bounds.br.y - bounds.tl.y ) / linespacing );
if ( maxLines == 0 ) {
maxLines = 1;
}
// tracks the last breakable character we found
int numLines = 1;
int lastbreak = 0;
int charIndex = 0;
while ( charIndex < textCheck.Length() ) {
if ( textCheck[ charIndex ] == '\n' ) {
if ( numLines == maxLines ) {
return maxLines;
}
numLines++;
lastbreak = 0;
x = bounds.tl.x;
charIndex++;
} else {
uint32 tc = textCheck[ charIndex++ ];
scaledGlyphInfo_t glyph;
fontInfo->GetScaledGlyph( glyphScale, tc, glyph );
float glyphSkip = glyph.xSkip;
if ( useStroke ) {
glyphSkip += ( swf_textStrokeSizeGlyphSpacer.GetFloat() * strokeWeight * glyphScale );
}
if ( x + glyphSkip > bounds.br.x ) {
if ( numLines == maxLines ) {
return maxLines;
} else {
numLines++;
if ( lastbreak != 0 ) {
charIndex = charIndex - ( charIndex - lastbreak );
}
x = bounds.tl.x;
lastbreak = 0;
}
} else {
x += glyphSkip;
if ( tc == ' ' || tc == '-' ) {
lastbreak = charIndex;
}
}
}
}
return numLines;
}
/*
========================
idSWFScriptObject_TextInstancePrototype
========================
*/
#define SWF_TEXT_FUNCTION_DEFINE( x ) idSWFScriptVar idSWFScriptObject_TextInstancePrototype::idSWFScriptFunction_##x::Call( idSWFScriptObject * thisObject, const idSWFParmList & parms )
#define SWF_TEXT_NATIVE_VAR_DEFINE_GET( x ) idSWFScriptVar idSWFScriptObject_TextInstancePrototype::idSWFScriptNativeVar_##x::Get( class idSWFScriptObject * object )
#define SWF_TEXT_NATIVE_VAR_DEFINE_SET( x ) void idSWFScriptObject_TextInstancePrototype::idSWFScriptNativeVar_##x::Set( class idSWFScriptObject * object, const idSWFScriptVar & value )
#define SWF_TEXT_PTHIS_FUNC( x ) idSWFTextInstance * pThis = thisObject ? thisObject->GetText() : NULL; if ( !verify( pThis != NULL ) ) { idLib::Warning( "SWF: tried to call " x " on NULL edittext" ); return idSWFScriptVar(); }
#define SWF_TEXT_PTHIS_GET( x ) idSWFTextInstance * pThis = object ? object->GetText() : NULL; if ( pThis == NULL ) { return idSWFScriptVar(); }
#define SWF_TEXT_PTHIS_SET( x ) idSWFTextInstance * pThis = object ? object->GetText() : NULL; if ( pThis == NULL ) { return; }
#define SWF_TEXT_FUNCTION_SET( x ) scriptFunction_##x.AddRef(); Set( #x, &scriptFunction_##x );
#define SWF_TEXT_NATIVE_VAR_SET( x ) SetNative( #x, &swfScriptVar_##x );
idSWFScriptObject_TextInstancePrototype::idSWFScriptObject_TextInstancePrototype() {
SWF_TEXT_FUNCTION_SET( onKey );
SWF_TEXT_FUNCTION_SET( onChar );
SWF_TEXT_FUNCTION_SET( generateRnd );
SWF_TEXT_FUNCTION_SET( calcNumLines );
SWF_TEXT_FUNCTION_SET( clearTimingInfo );
SWF_TEXT_NATIVE_VAR_SET( text );
SWF_TEXT_NATIVE_VAR_SET( _textLength ); // only works on single lines of text not multiline
SWF_TEXT_NATIVE_VAR_SET( autoSize );
SWF_TEXT_NATIVE_VAR_SET( dropShadow );
SWF_TEXT_NATIVE_VAR_SET( _stroke );
SWF_TEXT_NATIVE_VAR_SET( _strokeStrength );
SWF_TEXT_NATIVE_VAR_SET( _strokeWeight );
SWF_TEXT_NATIVE_VAR_SET( variable );
SWF_TEXT_NATIVE_VAR_SET( _alpha );
SWF_TEXT_NATIVE_VAR_SET( textColor );
SWF_TEXT_NATIVE_VAR_SET( _visible );
SWF_TEXT_NATIVE_VAR_SET( selectionStart );
SWF_TEXT_NATIVE_VAR_SET( selectionEnd );
SWF_TEXT_NATIVE_VAR_SET( scroll );
SWF_TEXT_NATIVE_VAR_SET( maxscroll );
SWF_TEXT_NATIVE_VAR_SET( isTooltip );
SWF_TEXT_NATIVE_VAR_SET( mode );
SWF_TEXT_NATIVE_VAR_SET( delay );
SWF_TEXT_NATIVE_VAR_SET( renderSound );
SWF_TEXT_NATIVE_VAR_SET( updateScroll );
SWF_TEXT_NATIVE_VAR_SET( subtitle );
SWF_TEXT_NATIVE_VAR_SET( subtitleAlign );
SWF_TEXT_NATIVE_VAR_SET( subtitleSourceID );
SWF_TEXT_NATIVE_VAR_SET( subtitleSpeaker );
SWF_TEXT_FUNCTION_SET( subtitleSourceCheck );
SWF_TEXT_FUNCTION_SET( subtitleStart );
SWF_TEXT_FUNCTION_SET( subtitleLength );
SWF_TEXT_FUNCTION_SET( killSubtitle );
SWF_TEXT_FUNCTION_SET( forceKillSubtitle );
SWF_TEXT_FUNCTION_SET( subLastLine );
SWF_TEXT_FUNCTION_SET( addSubtitleInfo );
SWF_TEXT_FUNCTION_SET( terminateSubtitle );
}
SWF_TEXT_NATIVE_VAR_DEFINE_GET( text ) {
SWF_TEXT_PTHIS_GET( "text" );
return pThis->text;
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( text ) {
SWF_TEXT_PTHIS_SET( "text " );
pThis->text = idLocalization::GetString( value.ToString() );
if ( pThis->text.IsEmpty() ) {
pThis->selectionEnd = -1;
pThis->selectionStart = -1;
pThis->inputTextStartChar = 0;
}
pThis->lengthCalculated = false;
}
SWF_TEXT_NATIVE_VAR_DEFINE_GET( autoSize ) {
SWF_TEXT_PTHIS_GET( "autoSize" );
return ( pThis->editText->flags & SWF_ET_AUTOSIZE ) != 0;
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( autoSize ) {
SWF_TEXT_PTHIS_SET( "autoSize" );
if ( value.ToBool() ) {
pThis->editText->flags |= SWF_ET_AUTOSIZE;
} else {
pThis->editText->flags &= ~SWF_ET_AUTOSIZE;
}
pThis->lengthCalculated = false;
}
SWF_TEXT_NATIVE_VAR_DEFINE_GET( dropShadow ) { SWF_TEXT_PTHIS_GET( "dropShadow" ); return pThis->useDropShadow; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( dropShadow ) { SWF_TEXT_PTHIS_SET( "dropShadow" ); pThis->useDropShadow = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _stroke ) { SWF_TEXT_PTHIS_GET( "_stroke" ); return pThis->useStroke; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( _stroke ) { SWF_TEXT_PTHIS_SET( "_stroke" ); pThis->useStroke = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _strokeStrength ) { SWF_TEXT_PTHIS_GET( "_strokeStrength" ); return pThis->strokeStrength; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( _strokeStrength ) { SWF_TEXT_PTHIS_SET( "_strokeStrength" ); pThis->strokeStrength = value.ToFloat(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _strokeWeight ) { SWF_TEXT_PTHIS_GET( "_strokeWeight" ); return pThis->strokeWeight; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( _strokeWeight ) { SWF_TEXT_PTHIS_SET( "_strokeWeight" ); pThis->strokeWeight = value.ToFloat(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( variable ) { SWF_TEXT_PTHIS_GET( "variable" ); return pThis->variable; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( variable ) { SWF_TEXT_PTHIS_SET( "variable" ); pThis->variable = value.ToString(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _alpha ) { SWF_TEXT_PTHIS_GET( "_alpha" ); return pThis->color.a / 255.0f; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( _alpha ) { SWF_TEXT_PTHIS_SET( "_alpha" ); pThis->color.a = idMath::Ftob( value.ToFloat() * 255.0f ); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _visible ) { SWF_TEXT_PTHIS_GET( "_visible" ); return pThis->visible; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( _visible ) { SWF_TEXT_PTHIS_SET( "_visible" ); pThis->visible = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( selectionStart ) { SWF_TEXT_PTHIS_GET( "selectionStart" ); return pThis->selectionStart; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( selectionStart ) { SWF_TEXT_PTHIS_SET( "selectionStart" ); pThis->selectionStart = value.ToInteger(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( selectionEnd ) { SWF_TEXT_PTHIS_GET( "selectionEnd" ); return pThis->selectionEnd; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( selectionEnd ) { SWF_TEXT_PTHIS_SET( "selectionEnd" ); pThis->selectionEnd = value.ToInteger(); }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( isTooltip ) { SWF_TEXT_PTHIS_SET( "isTooltip" ); pThis->tooltip = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( isTooltip ) { SWF_TEXT_PTHIS_GET( "isTooltip" ); return pThis->tooltip; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( delay ) { SWF_TEXT_PTHIS_SET( "delay" ); pThis->renderDelay = value.ToInteger(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( delay ) { SWF_TEXT_PTHIS_GET( "delay" ); return pThis->renderDelay; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( renderSound ) { SWF_TEXT_PTHIS_SET( "renderSound" ); pThis->soundClip = value.ToString(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( renderSound ) { SWF_TEXT_PTHIS_GET( "renderSound" ); return pThis->soundClip; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( updateScroll ) { SWF_TEXT_PTHIS_SET( "updateScroll" ); pThis->scrollUpdate = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( updateScroll ) { SWF_TEXT_PTHIS_GET( "updateScroll" ); return pThis->scrollUpdate; }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( mode ) { SWF_TEXT_PTHIS_GET( "mode" ); return pThis->renderMode; }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( scroll ) { SWF_TEXT_PTHIS_GET( "scroll" ); return pThis->scroll; }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( maxscroll ) { SWF_TEXT_PTHIS_GET( "maxscroll" ); return pThis->maxscroll; }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( _textLength ) {
SWF_TEXT_PTHIS_GET( "_textLength" );
return pThis->GetTextLength();
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( mode ) {
SWF_TEXT_PTHIS_SET( "mode" );
int mode = value.ToInteger();
if ( mode >= (int)SWF_TEXT_RENDER_MODE_COUNT || mode < 0 ) {
mode = SWF_TEXT_RENDER_NORMAL;
}
pThis->renderMode = swfTextRenderMode_t(mode);
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( scroll ) {
SWF_TEXT_PTHIS_SET( "scroll" );
int time = Sys_Milliseconds();
if ( time >= pThis->scrollTime ) {
pThis->scrollTime = Sys_Milliseconds() + swf_textScrollSpeed.GetInteger();
pThis->scroll = value.ToInteger();
}
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( maxscroll ) {
SWF_TEXT_PTHIS_SET( "maxscroll" );
pThis->maxscroll = value.ToInteger();
}
SWF_TEXT_NATIVE_VAR_DEFINE_GET( textColor ) {
SWF_TEXT_PTHIS_GET( "textColor" );
int r = ( pThis->color.r << 16 );
int g = ( pThis->color.g << 8 );
int b = pThis->color.b;
int textColor = r | g | b;
return textColor;
}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( textColor ) {
SWF_TEXT_PTHIS_SET( "textColor" );
int textColor = value.ToInteger();
int r = ( textColor >> 16 ) & 0xFF;
int g = ( textColor >> 8 ) & 0x00FF;
int b = textColor & 0x0000FF;
pThis->color.r = r;
pThis->color.g = g;
pThis->color.b = b;
}
SWF_TEXT_FUNCTION_DEFINE( clearTimingInfo ) {
SWF_TEXT_PTHIS_FUNC( "clearTimingInfo" );
pThis->subtitleTimingInfo.Clear();
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( generateRnd ) {
SWF_TEXT_PTHIS_FUNC( "generateRnd" );
pThis->triggerGenerate = true;
pThis->rndSpotsVisible = -1;
pThis->generatingText = false;
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( calcNumLines ) {
SWF_TEXT_PTHIS_FUNC( "calcNumLines" );
return pThis->CalcNumLines();
}
SWF_TEXT_FUNCTION_DEFINE( onKey ) {
SWF_TEXT_PTHIS_FUNC( "onKey" );
int keyCode = parms[0].ToInteger();
bool keyDown = parms[1].ToBool();
if ( keyDown ) {
switch ( keyCode ) {
case K_LSHIFT:
case K_RSHIFT: {
pThis->shiftHeld = true;
break;
}
case K_BACKSPACE:
case K_DEL: {
if ( pThis->selectionStart == pThis->selectionEnd ) {
if ( keyCode == K_BACKSPACE ) {
pThis->selectionStart = pThis->selectionEnd - 1;
} else {
pThis->selectionEnd = pThis->selectionStart + 1;
}
}
int start = Min( pThis->selectionStart, pThis->selectionEnd );
int end = Max( pThis->selectionStart, pThis->selectionEnd );
idStr left = pThis->text.Left( Max( start, 0 ) );
idStr right = pThis->text.Right( Max( pThis->text.Length() - end, 0 ) );
pThis->text = left + right;
pThis->selectionStart = start;
pThis->selectionEnd = start;
break;
}
case K_LEFTARROW: {
if ( pThis->selectionEnd > 0 ) {
pThis->selectionEnd--;
if ( !pThis->shiftHeld ) {
pThis->selectionStart = pThis->selectionEnd;
}
}
break;
}
case K_RIGHTARROW: {
if ( pThis->selectionEnd < pThis->text.Length() ) {
pThis->selectionEnd++;
if ( !pThis->shiftHeld ) {
pThis->selectionStart = pThis->selectionEnd;
}
}
break;
}
case K_HOME: {
pThis->selectionEnd = 0;
if ( !pThis->shiftHeld ) {
pThis->selectionStart = pThis->selectionEnd;
}
break;
}
case K_END: {
pThis->selectionEnd = pThis->text.Length();
if ( !pThis->shiftHeld ) {
pThis->selectionStart = pThis->selectionEnd;
}
break;
}
}
} else {
if ( keyCode == K_LSHIFT || keyCode == K_RSHIFT ) {
pThis->shiftHeld = false;
}
}
return true;
}
SWF_TEXT_FUNCTION_DEFINE( onChar ) {
SWF_TEXT_PTHIS_FUNC( "onChar" );
int keyCode = parms[0].ToInteger();
if ( keyCode < 32 || keyCode == 127 ) {
return false;
}
char letter = ( char )keyCode;
// assume ` is meant for the console
if ( letter == '`' ) {
return false;
}
if ( pThis->selectionStart != pThis->selectionEnd ) {
int start = Min( pThis->selectionStart, pThis->selectionEnd );
int end = Max( pThis->selectionStart, pThis->selectionEnd );
idStr left = pThis->text.Left( Max( start, 0 ) );
idStr right = pThis->text.Right( Max( pThis->text.Length() - end, 0 ) );
pThis->text = left + right;
pThis->selectionStart = start;
pThis->text.Clear();
pThis->text.Append( left );
pThis->text.Append( letter );
pThis->text.Append( right );
pThis->selectionStart++;
} else if ( pThis->selectionStart < swf_textMaxInputLength.GetInteger() ) {
if ( pThis->selectionStart < 0 ) {
pThis->selectionStart = 0;
}
pThis->text.Insert( letter, pThis->selectionStart++ );
}
pThis->selectionEnd = pThis->selectionStart;
return true;
}
SWF_TEXT_NATIVE_VAR_DEFINE_GET( subtitle ) { SWF_TEXT_PTHIS_GET( "subtitle" ); return pThis->isSubtitle; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( subtitle ) { SWF_TEXT_PTHIS_SET( "subtitle" ); pThis->isSubtitle = value.ToBool(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( subtitleAlign ) { SWF_TEXT_PTHIS_GET( "subtitleAlign" ); return pThis->subAlign; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( subtitleAlign ) { SWF_TEXT_PTHIS_SET( "subtitleAlign" ); pThis->subAlign = value.ToInteger(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( subtitleSourceID ) { SWF_TEXT_PTHIS_GET( "subtitleSourceID" ); return pThis->subSourceID; }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( subtitleSourceID ) { SWF_TEXT_PTHIS_SET( "subtitleSourceID" ); pThis->subSourceID = value.ToInteger(); }
SWF_TEXT_NATIVE_VAR_DEFINE_GET( subtitleSpeaker ) { SWF_TEXT_PTHIS_GET( "subtitleSpeaker" ); return pThis->subSpeaker.c_str(); }
SWF_TEXT_NATIVE_VAR_DEFINE_SET( subtitleSpeaker ) { SWF_TEXT_PTHIS_SET( "subtitleSpeaker" ); pThis->subSpeaker = value.ToString(); }
SWF_TEXT_FUNCTION_DEFINE( subtitleLength ) {
SWF_TEXT_PTHIS_FUNC( "subtitleLength" );
pThis->subLength = parms[0].ToInteger();
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( subtitleSourceCheck ) {
SWF_TEXT_PTHIS_FUNC( "subtitleSourceCheck" );
int idCheck = parms[0].ToInteger();
if ( pThis->subSourceID == -1 ) {
pThis->subSourceID = idCheck;
return 1;
}
if ( idCheck == pThis->subSourceID ) { // || pThis->subForceKill ) {
pThis->SubtitleComplete();
pThis->subSourceID = idCheck;
return -1;
}
return 0;
}
SWF_TEXT_FUNCTION_DEFINE( subtitleStart ) {
SWF_TEXT_PTHIS_FUNC( "subtitleStart" );
pThis->subUpdating = true;
pThis->subNeedsSwitch = false;
pThis->subForceKillQueued = false;
pThis->subForceKill = false;
pThis->subKillTimeDelay = 0;
// trickery to swap the text so subtitles don't show until they should
pThis->subtitleText = pThis->text;
pThis->text = "";
pThis->subCharStartIndex = 0;
pThis->subNextStartIndex = 0;
pThis->subCharEndIndex = 0;
pThis->subSwitchTime = 0;
pThis->subLastWordIndex = 0;
pThis->subPrevLastWordIndex = 0;
pThis->subStartTime = -1;
pThis->subInitialLine = true;
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( forceKillSubtitle ) {
SWF_TEXT_PTHIS_FUNC( "forceKillSubtitle" );
pThis->subForceKill = true;
pThis->subKillTimeDelay = 0;
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( killSubtitle ) {
SWF_TEXT_PTHIS_FUNC( "killSubtitle" );
pThis->subForceKillQueued = true;
//pThis->SubtitleComplete();
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( terminateSubtitle ) {
SWF_TEXT_PTHIS_FUNC( "terminateSubtitle" );
pThis->SubtitleComplete();
pThis->SubtitleCleanup();
return idSWFScriptVar();
}
SWF_TEXT_FUNCTION_DEFINE( subLastLine ) {
SWF_TEXT_PTHIS_FUNC( "subLastLine" );
idStr lastLine;
int len = pThis->subCharEndIndex - pThis->subCharStartIndex;
pThis->text.Mid( pThis->subCharStartIndex, len, lastLine );
return lastLine;
}
SWF_TEXT_FUNCTION_DEFINE( addSubtitleInfo ) {
SWF_TEXT_PTHIS_FUNC( "addSubtitleInfo" );
if ( parms.Num() != 3 ) {
return idSWFScriptVar();
}
subTimingWordData_t info;
info.phrase = parms[0].ToString();
info.startTime = parms[1].ToInteger();
info.forceBreak = parms[2].ToBool();
pThis->subtitleTimingInfo.Append( info );
return idSWFScriptVar();
}