2418 lines
65 KiB
C++
2418 lines
65 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "UserInterfaceExpressions.h"
|
|
#include "UserInterfaceLocal.h"
|
|
|
|
UI_CONST_EXPRESSION_HASH_IMPL( String )
|
|
UI_CONST_EXPRESSION_HASH_IMPL( Float )
|
|
|
|
const char sdUITransitionFloat_Identifier[] = "sdUITransitionFloat";
|
|
const char sdUITransitionVec2_Identifier[] = "sdUITransitionVec2";
|
|
const char sdUITransitionVec3_Identifier[] = "sdUITransitionVec3";
|
|
const char sdUITransitionVec4_Identifier[] = "sdUITransitionVec4";
|
|
|
|
const char sdFunctionExpression_Identifier[] = "sdFunctionExpression";
|
|
const char sdFloatParmExpression_Identifier[] = "sdFloatParmExpression";
|
|
const char sdStringParmExpression_Identifier[] = "sdStringParmExpression";
|
|
|
|
const char sdPropertyExpressionSingle_Identifier[] = "sdPropertyExpressionSingle";
|
|
const char sdPropertyExpressionField_Identifier[] = "sdPropertyExpressionField";
|
|
|
|
const char sdUIEvaluatorTypeInt_Identifier[] = "sdUIEvaluatorTypeInt";
|
|
const char sdUIEvaluatorTypeFloat_Identifier[] = "sdUIEvaluatorTypeFloat";
|
|
const char sdUIEvaluatorTypeVec2_Identifier[] = "sdUIEvaluatorTypeVec2";
|
|
const char sdUIEvaluatorTypeVec3_Identifier[] = "sdUIEvaluatorTypeVec2";
|
|
const char sdUIEvaluatorTypeVec4_Identifier[] = "sdUIEvaluatorTypeVec2";
|
|
const char sdUIEvaluatorTypeString_Identifier[] = "sdUIEvaluatorTypeString";
|
|
const char sdUIEvaluatorTypeWString_Identifier[] = "sdUIEvaluatorTypeWString";
|
|
|
|
const char sdUIEvaluatorInt_Identifier[] = "sdUIEvaluatorInt";
|
|
const char sdUIEvaluatorFloat_Identifier[] = "sdUIEvaluatorFloat";
|
|
const char sdUIEvaluatorVec2_Identifier[] = "sdUIEvaluatorVec2";
|
|
const char sdUIEvaluatorVec3_Identifier[] = "sdUIEvaluatorVec2";
|
|
const char sdUIEvaluatorVec4_Identifier[] = "sdUIEvaluatorVec2";
|
|
const char sdUIEvaluatorString_Identifier[] = "sdUIEvaluatorString";
|
|
const char sdUIEvaluatorWString_Identifier[] = "sdUIEvaluatorWString";
|
|
|
|
const char sdSingleParmExpressionInt_Identifier[] = "sdSingleParmExpressionInt";
|
|
const char sdSingleParmExpressionFloat_Identifier[] = "sdSingleParmExpressionFloat";
|
|
const char sdSingleParmExpressionString_Identifier[] = "sdSingleParmExpressionString";
|
|
const char sdSingleParmExpressionWString_Identifier[] = "sdSingleParmExpressionWString";
|
|
const char sdSingleParmExpressionVec2_Identifier[] = "sdSingleParmExpressionVec2";
|
|
const char sdSingleParmExpressionVec3_Identifier[] = "sdSingleParmExpressionVec3";
|
|
const char sdSingleParmExpressionVec4_Identifier[] = "sdSingleParmExpressionVec4";
|
|
|
|
const char sdConstParmExpressionInt_Identifier[] = "sdConstParmExpressionInt";
|
|
const char sdConstParmExpressionFloat_Identifier[] = "sdConstParmExpressionFloat";
|
|
const char sdConstParmExpressionString_Identifier[] = "sdConstParmExpressionString";
|
|
const char sdConstParmExpressionVec2_Identifier[] = "sdConstParmExpressionVec2";
|
|
const char sdConstParmExpressionVec3_Identifier[] = "sdConstParmExpressionVec3";
|
|
const char sdConstParmExpressionVec4_Identifier[] = "sdConstParmExpressionVec4";
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdUIExpression
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
idStaticList< sdUIExpression*, sdUIExpression::MAX_ACTIVE_ONCHANGED_HANDLERS > sdUIExpression::activeOnChangedHandlers;
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::IncActiveOnChangeHandlers
|
|
================
|
|
*/
|
|
void sdUIExpression::IncActiveOnChangeHandlers( sdUIExpression* expression ) {
|
|
sdUIExpression** newExpressionEntry = activeOnChangedHandlers.Alloc();
|
|
if ( newExpressionEntry == NULL ) {
|
|
for ( int i = 0; i < activeOnChangedHandlers.Num(); i++ ) {
|
|
activeOnChangedHandlers[ i ]->OnOnChangedOverflow();
|
|
}
|
|
activeOnChangedHandlers.Clear();
|
|
common->FatalError( "sdUIExpression; OnChanged Handler Overflow" );
|
|
}
|
|
|
|
*newExpressionEntry = expression;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::DecActiveOnChangeHandlers
|
|
================
|
|
*/
|
|
void sdUIExpression::DecActiveOnChangeHandlers( void ) {
|
|
if ( activeOnChangedHandlers.Num() == 0 ) {
|
|
gameLocal.Error( "sdUIExpression; OnChanged Handler Underflow" );
|
|
}
|
|
activeOnChangedHandlers.SetNum( activeOnChangedHandlers.Num() - 1 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocTransition
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocTransition( sdProperties::ePropertyType type, sdUserInterfaceScope* scope, idLexer* src ) {
|
|
idStr temp;
|
|
src->ParseBracedSection( temp, -1, true, '(', ')' );
|
|
|
|
idLexer parser( temp, temp.Length(), "AllocFunctionExpression" );
|
|
parser.ExpectTokenString( "(" );
|
|
|
|
idStr value;
|
|
idStrList terms;
|
|
sdUIScriptEvent::ReadExpression( &parser, value, terms, "(", ")", true );
|
|
|
|
switch ( type ) {
|
|
case sdProperties::PT_FLOAT:
|
|
return new sdUITransitionFloat( scope, terms );
|
|
case sdProperties::PT_VEC2:
|
|
return new sdUITransitionVec2( scope, terms );
|
|
case sdProperties::PT_VEC3:
|
|
return new sdUITransitionVec3( scope, terms );
|
|
case sdProperties::PT_VEC4:
|
|
return new sdUITransitionVec4( scope, terms );
|
|
default:
|
|
gameLocal.Error( "Transitions Only Valid For Floating Point Based Properties" );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocFunctionExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocFunctionExpression( const char* functionName, sdUIFunctionInstance* function, sdUserInterfaceScope* scope, idLexer* src ) {
|
|
idStr temp;
|
|
src->ParseBracedSection( temp, -1, true, '(', ')' );
|
|
|
|
idLexer parser( temp, temp.Length(), functionName );
|
|
parser.ExpectTokenString( "(" );
|
|
|
|
idStr value;
|
|
idStrList terms;
|
|
sdUIScriptEvent::ReadExpression( &parser, value, terms, "(", ")", true );
|
|
|
|
return new sdFunctionExpression( functionName, scope, function, terms );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
============
|
|
IsNumeric
|
|
similar to idStr::IsNumeric, but skips whitespace after a - sign
|
|
============
|
|
*/
|
|
static bool IsNumeric( const char *s ) {
|
|
int i;
|
|
bool dot;
|
|
|
|
if ( *s == '-' ) {
|
|
s++;
|
|
}
|
|
|
|
while( s && *s == ' ' ) {
|
|
s++;
|
|
}
|
|
|
|
dot = false;
|
|
for ( i = 0; s[i]; i++ ) {
|
|
if ( !isdigit( s[i] ) ) {
|
|
if ( ( s[ i ] == '.' ) && !dot ) {
|
|
dot = true;
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocSingleParmExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocSingleParmExpression( sdProperties::ePropertyType type, sdUserInterfaceScope* scope, const char* text ) {
|
|
idLexer parser( text, idStr::Length( text ), "AllocSingleParmExpression" );
|
|
|
|
sdUserInterfaceScope* altScope = gameLocal.GetUserInterfaceScope( *scope, &parser );
|
|
|
|
idToken token;
|
|
parser.ReadToken( &token );
|
|
|
|
sdProperties::sdProperty* rhs = altScope->GetProperty( token );
|
|
if ( rhs ) {
|
|
if ( rhs->GetValueType() != type ) {
|
|
gameLocal.Error( "Invalid Property Type in '%s'", text );
|
|
}
|
|
|
|
idToken token;
|
|
if ( parser.ReadToken( &token ) ) {
|
|
gameLocal.Error( "Invalid Parameters '%s' After Property", token.c_str() );
|
|
}
|
|
|
|
switch( type ) {
|
|
case sdProperties::PT_INT:
|
|
return new sdSingleParmExpressionInt( rhs );
|
|
case sdProperties::PT_FLOAT:
|
|
return new sdSingleParmExpressionFloat( rhs );
|
|
case sdProperties::PT_VEC2:
|
|
return new sdSingleParmExpressionVec2( rhs );
|
|
case sdProperties::PT_VEC3:
|
|
return new sdSingleParmExpressionVec3( rhs );
|
|
case sdProperties::PT_VEC4:
|
|
return new sdSingleParmExpressionVec4( rhs );
|
|
case sdProperties::PT_STRING:
|
|
return new sdSingleParmExpressionString( rhs );
|
|
case sdProperties::PT_WSTRING:
|
|
return new sdSingleParmExpressionWString( rhs );
|
|
}
|
|
assert( false );
|
|
return NULL;
|
|
}
|
|
|
|
sdUIFunctionInstance* function = altScope->GetFunction( token );
|
|
if ( function ) {
|
|
if ( function->GetFunctionInfo()->GetReturnType() != type ) {
|
|
gameLocal.Error( "Invalid Expression '%s'", text );
|
|
}
|
|
|
|
return sdUIExpression::AllocFunctionExpression( token, function, scope, &parser );
|
|
}
|
|
|
|
sdUIEvaluatorTypeBase* evaluator = altScope->GetEvaluator( token );
|
|
if ( evaluator ) {
|
|
if ( evaluator->GetReturnType() != type ) {
|
|
gameLocal.Error( "Invalid Expression '%s'", text );
|
|
}
|
|
|
|
switch ( type ) {
|
|
case sdProperties::PT_INT:
|
|
return new sdUIEvaluatorInt( evaluator, scope, &parser );
|
|
case sdProperties::PT_FLOAT:
|
|
return new sdUIEvaluatorFloat( evaluator, scope, &parser );
|
|
case sdProperties::PT_STRING:
|
|
return new sdUIEvaluatorString( evaluator, scope, &parser );
|
|
case sdProperties::PT_WSTRING:
|
|
return new sdUIEvaluatorWString( evaluator, scope, &parser );
|
|
case sdProperties::PT_VEC2:
|
|
return new sdUIEvaluatorVec2( evaluator, scope, &parser );
|
|
case sdProperties::PT_VEC3:
|
|
return new sdUIEvaluatorVec3( evaluator, scope, &parser );
|
|
case sdProperties::PT_VEC4:
|
|
return new sdUIEvaluatorVec4( evaluator, scope, &parser );
|
|
default:
|
|
gameLocal.Error( "Invalid Type on Evaluator" );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
idStr temp = text;
|
|
temp.StripLeadingOnce( "\"" );
|
|
temp.StripTrailingOnce( "\"" );
|
|
|
|
idStr value;
|
|
idStrList sublist;
|
|
idLexer parser2( temp, temp.Length(), "" );
|
|
sdUIScriptEvent::ReadExpression( &parser2, value, sublist, NULL, NULL );
|
|
|
|
int count = sdProperties::CountForPropertyType( type );
|
|
|
|
if ( sublist.Num() != count ) {
|
|
gameLocal.Error( "Invalid Number of Parms '%s' (expected %i but found %i)", text, count, sublist.Num() );
|
|
}
|
|
|
|
switch( type ) {
|
|
case sdProperties::PT_INT:
|
|
if( !IsNumeric( sublist[ 0 ].c_str() ) ) {
|
|
gameLocal.Error( "'%s' is not numeric", text );
|
|
}
|
|
return sdConstParmExpressionInt::Alloc( atoi( sublist[ 0 ] ) );
|
|
case sdProperties::PT_FLOAT:
|
|
if( !IsNumeric( sublist[ 0 ].c_str() ) ) {
|
|
gameLocal.Error( "'%s' is not numeric", text );
|
|
}
|
|
return sdConstParmExpressionFloat::Alloc( atof( sublist[ 0 ] ) );
|
|
case sdProperties::PT_VEC2:
|
|
if( !IsNumeric( sublist[ 0 ].c_str() ) || !IsNumeric( sublist[ 1 ].c_str() ) ) {
|
|
gameLocal.Error( "'%s' is not numeric", text );
|
|
}
|
|
return sdConstParmExpressionVec2::Alloc( idVec2( atof( sublist[ 0 ] ), atof( sublist[ 1 ] ) ) );
|
|
case sdProperties::PT_VEC3:
|
|
if( !IsNumeric( sublist[ 0 ].c_str() ) || !IsNumeric( sublist[ 1 ].c_str() ) || !IsNumeric( sublist[ 2 ].c_str() ) ) {
|
|
gameLocal.Error( "'%s' is not numeric", text );
|
|
}
|
|
return sdConstParmExpressionVec3::Alloc( idVec3( atof( sublist[ 0 ] ), atof( sublist[ 1 ] ), atof( sublist[ 2 ] ) ) );
|
|
case sdProperties::PT_VEC4:
|
|
if( !IsNumeric( sublist[ 0 ].c_str() ) || !IsNumeric( sublist[ 1 ].c_str() ) || !IsNumeric( sublist[ 2 ].c_str() ) || !IsNumeric( sublist[ 3 ].c_str() ) ) {
|
|
gameLocal.Error( "'%s' is not numeric", text );
|
|
}
|
|
return sdConstParmExpressionVec4::Alloc( idVec4( atof( sublist[ 0 ] ), atof( sublist[ 1 ] ), atof( sublist[ 2 ] ), atof( sublist[ 3 ] ) ) );
|
|
case sdProperties::PT_STRING:
|
|
return sdConstParmExpressionString::Alloc( sublist[ 0 ] );
|
|
default:
|
|
gameLocal.Error( "Invalid Type on Constant" );
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocIntExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocIntExpression( sdUserInterfaceScope* scope, const char* text ) {
|
|
idLexer src( text, idStr::Length( text ), "AllocIntExpression" );
|
|
idToken token;
|
|
|
|
sdUserInterfaceScope* altScope = gameLocal.GetUserInterfaceScope( *scope, &src );
|
|
|
|
src.ExpectAnyToken( &token );
|
|
|
|
idStr propertyName;
|
|
sdProperties::sdProperty* property = altScope->GetProperty( token );
|
|
if ( property != NULL ) {
|
|
if ( property->GetValueType() != sdProperties::PT_INT ) {
|
|
src.Error( "Cannot use '%s' in an Int expression", sdProperties::sdProperty::TypeToString( property->GetValueType() ) );
|
|
}
|
|
return new sdSingleParmExpressionInt( property );
|
|
}
|
|
|
|
sdUIFunctionInstance* function = altScope->GetFunction( token );
|
|
if ( function != NULL ) {
|
|
if ( function->GetFunctionInfo()->GetReturnType() != sdProperties::PT_INT ) {
|
|
int type = function->GetFunctionInfo()->GetReturnType();
|
|
delete function;
|
|
src.Error( "Return Type '%s' was not an Int", sdProperties::sdProperty::TypeToString( type ) );
|
|
}
|
|
return sdUIExpression::AllocFunctionExpression( token, function, scope, &src );
|
|
}
|
|
|
|
sdUIEvaluatorTypeBase* evaluator = altScope->GetEvaluator( token );
|
|
if ( evaluator != NULL ) {
|
|
if ( evaluator->GetReturnType() != sdProperties::PT_INT ) {
|
|
src.Error( "Return Type '%s' was not an Int", sdProperties::sdProperty::TypeToString( evaluator->GetReturnType() ) );
|
|
}
|
|
return new sdUIEvaluatorInt( evaluator, scope, &src );
|
|
}
|
|
|
|
idStr message = token;
|
|
while ( src.ReadToken( &token ) ) {
|
|
if ( token.linesCrossed ) {
|
|
src.UnreadToken( &token );
|
|
break;
|
|
}
|
|
message += token;
|
|
}
|
|
src.Error( "Invalid Term '%s' in '%s'", message.c_str(), scope->GetUI()->GetName() );
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocFloatExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocFloatExpression( sdUserInterfaceScope* scope, const char* text ) {
|
|
|
|
sdUIExpression* expression = NULL;
|
|
try {
|
|
idLexer parser( text, idStr::Length( text ), "AllocFloatExpression" );
|
|
sdFloatParmExpression* floatExpression = new sdFloatParmExpression( scope, &parser );
|
|
if ( floatExpression->IsConstant() ) {
|
|
float value = floatExpression->GetFloatValue();
|
|
// gameLocal.Printf( "%s = %f\n", text, value );
|
|
expression = sdConstParmExpressionFloat::Alloc( value );
|
|
delete floatExpression;
|
|
} else {
|
|
expression = floatExpression;
|
|
}
|
|
|
|
} catch( idException& ){
|
|
gameLocal.Printf( "Failed to parse expression ^7'%s'^0\n", text );
|
|
delete expression;
|
|
throw;
|
|
}
|
|
|
|
return expression;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocStringExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocStringExpression( sdUserInterfaceScope* scope, const char* text ) {
|
|
idLexer parser( text, idStr::Length( text ), "AllocStringExpression" );
|
|
sdUIExpression* expression = NULL;
|
|
|
|
try {
|
|
sdStringParmExpression* stringExpression = new sdStringParmExpression( scope, &parser );
|
|
if ( stringExpression->IsConstant() ) {
|
|
idStr temp;
|
|
idStr const &value = stringExpression->GetStringValue( temp );
|
|
// gameLocal.Printf( "%s = %s\n", text, value.c_str() );
|
|
expression = sdConstParmExpressionString::Alloc( value );
|
|
delete stringExpression;
|
|
} else {
|
|
expression = stringExpression;
|
|
}
|
|
} catch( idException& ){
|
|
gameLocal.Printf( "Failed to parse expression ^7'%s'^0\n", text );
|
|
delete expression;
|
|
expression = NULL;
|
|
throw;
|
|
}
|
|
|
|
return expression;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIExpression::AllocWStringExpression
|
|
================
|
|
*/
|
|
sdUIExpression* sdUIExpression::AllocWStringExpression( sdUserInterfaceScope* scope, const char* text ) {
|
|
idLexer src( text, idStr::Length( text ), "AllocWStringExpression" );
|
|
idToken token;
|
|
|
|
sdUserInterfaceScope* altScope = gameLocal.GetUserInterfaceScope( *scope, &src );
|
|
|
|
src.ExpectAnyToken( &token );
|
|
|
|
idStr propertyName;
|
|
sdProperties::sdProperty* property = altScope->GetProperty( token );
|
|
if ( property != NULL ) {
|
|
if ( property->GetValueType() != sdProperties::PT_WSTRING ) {
|
|
src.Error( "Only Wide String Terms May be Used" );
|
|
}
|
|
return new sdSingleParmExpressionWString( property );
|
|
}
|
|
|
|
sdUIFunctionInstance* function = altScope->GetFunction( token );
|
|
if ( function != NULL ) {
|
|
if ( function->GetFunctionInfo()->GetReturnType() != sdProperties::PT_WSTRING ) {
|
|
int type = function->GetFunctionInfo()->GetReturnType();
|
|
delete function;
|
|
src.Error( "Return Type '%s' was not a WString", sdProperties::sdProperty::TypeToString( type ) );
|
|
}
|
|
return sdUIExpression::AllocFunctionExpression( token, function, scope, &src );
|
|
}
|
|
|
|
sdUIEvaluatorTypeBase* evaluator = altScope->GetEvaluator( token );
|
|
if ( evaluator != NULL ) {
|
|
if ( evaluator->GetReturnType() != sdProperties::PT_WSTRING ) {
|
|
src.Error( "Return Type Was Not a Wide String" );
|
|
}
|
|
return new sdUIEvaluatorWString( evaluator, scope, &src );
|
|
}
|
|
|
|
idStr message = token;
|
|
while ( src.ReadToken( &token ) ) {
|
|
if ( token.linesCrossed ) {
|
|
src.UnreadToken( &token );
|
|
break;
|
|
}
|
|
message += token;
|
|
}
|
|
src.Error( "Invalid Term '%s' in '%s'", message.c_str(), scope->GetUI()->GetName() );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdUITransition
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdUITransition::sdUITransition
|
|
================
|
|
*/
|
|
template< typename T, sdProperties::ePropertyType TYPE, int COUNT >
|
|
sdUITransition< T, TYPE, COUNT >::sdUITransition( sdUserInterfaceScope* scope, idStrList& list ) : outputExpression( NULL ), table( NULL ), interpolator( NULL ) {
|
|
if ( list.Num() < 3 || list.Num() > 4 ) {
|
|
gameLocal.Error( "Transition Takes 3 or 4 Parameters" );
|
|
}
|
|
|
|
int j;
|
|
for ( j = 0; j < COUNT; j++ ) {
|
|
startExpressions[ j ] = NULL;
|
|
endExpressions[ j ] = NULL;
|
|
}
|
|
|
|
idStr temp;
|
|
for ( j = 0; j < 2; j++ ) {
|
|
sdUIExpression** valuePtr = ( j == 0 ? startExpressions : endExpressions );
|
|
|
|
temp = list[ j ];
|
|
temp.StripLeadingOnce( "\"" );
|
|
temp.StripTrailingOnce( "\"" );
|
|
|
|
idStr value;
|
|
idStrList sublist;
|
|
idLexer parser( temp, temp.Length(), "" );
|
|
sdUIScriptEvent::ReadExpression( &parser, value, sublist, NULL, NULL );
|
|
|
|
if ( sublist.Num() == COUNT ) {
|
|
int i;
|
|
for ( i = 0; i < COUNT; i++ ) {
|
|
valuePtr[ i ] = sdUIExpression::AllocFloatExpression( scope, sublist[ i ] );
|
|
assert( valuePtr[ 0 ] != NULL );
|
|
}
|
|
} else if ( sublist.Num() == 1 ) {
|
|
valuePtr[ 0 ] = sdUIExpression::AllocSingleParmExpression( TYPE, scope, sublist[ 0 ] );
|
|
assert( valuePtr[ 0 ] != NULL );
|
|
} else {
|
|
gameLocal.Error( "Invalid Size of Parameter to Transition" );
|
|
}
|
|
}
|
|
|
|
if( list.Num() >= 4 ) {
|
|
temp = list[ 3 ];
|
|
temp.StripLeading( "\"" );
|
|
temp.StripTrailing( "\"" );
|
|
|
|
if( !temp.IsEmpty() ) {
|
|
// parse an acceleration
|
|
bool isTable = idStr::Icmpn( temp, "table://", 8 ) == 0;
|
|
if( !isTable ) {
|
|
idLexer parser( temp, temp.Length(), "Transition Acceleration" );
|
|
|
|
accelTimes.x = parser.ParseFloat();
|
|
parser.ExpectTokenString( "," );
|
|
accelTimes.y = parser.ParseFloat();
|
|
} else if( temp.Length() > 8 ) {
|
|
table = gameLocal.declTableType[ temp.c_str() + 8 ];
|
|
if( !table ) {
|
|
gameLocal.Warning( "sdUITransition: could not find table '%s'", list[ 3 ].c_str() );
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
accelTimes.Set( 0.0f, 0.0f );
|
|
}
|
|
|
|
ui = scope->GetUI();
|
|
|
|
assert( startExpressions[ 0 ] != NULL );
|
|
assert( endExpressions[ 0 ] != NULL );
|
|
|
|
duration = sdUIExpression::AllocFloatExpression( scope, list[ 2 ] );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransition::~sdUITransition
|
|
================
|
|
*/
|
|
template< typename T, sdProperties::ePropertyType TYPE, int COUNT >
|
|
sdUITransition< T, TYPE, COUNT >::~sdUITransition( void ) {
|
|
for ( int i = 0; i < COUNT; i++ ) {
|
|
if ( startExpressions[ i ] != NULL ) {
|
|
startExpressions[ i ]->Free();
|
|
}
|
|
if ( endExpressions[ i ] != NULL ) {
|
|
endExpressions[ i ]->Free();
|
|
}
|
|
}
|
|
|
|
duration->Free();
|
|
|
|
if( interpolator ) {
|
|
interpolatorAllocator.Free( interpolator );
|
|
interpolator = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdUITransition::OnSnapshotHitch
|
|
============
|
|
*/
|
|
template< typename T, sdProperties::ePropertyType TYPE, int COUNT >
|
|
void sdUITransition< T, TYPE, COUNT >::OnSnapshotHitch( int delta ) {
|
|
startTime-= delta;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionFloat::UpdateValue
|
|
================
|
|
*/
|
|
template< typename T, sdProperties::ePropertyType TYPE, int COUNT >
|
|
bool sdUITransition< T, TYPE, COUNT >::UpdateValue( void ) {
|
|
|
|
int now = ui->GetCurrentTime();
|
|
if( now < startTime ) {
|
|
now = startTime;
|
|
}
|
|
|
|
if( interpolator ) {
|
|
bool isDone = interpolator->IsDone( now );
|
|
if( isDone ) {
|
|
value = interpolator->GetEndValue();
|
|
} else {
|
|
value = interpolator->GetCurrentValue( now );
|
|
}
|
|
|
|
outputExpression->InputChanged();
|
|
return !isDone;
|
|
}
|
|
|
|
// normal behavior
|
|
if ( now > startTime + _cachedDuration ) {
|
|
if ( table ) {
|
|
value = Lerp( start, end, table->TableLookup( 1.0f ) );
|
|
} else {
|
|
value = end;
|
|
}
|
|
outputExpression->InputChanged();
|
|
return false;
|
|
}
|
|
|
|
float frac = ( now - startTime ) / ( float )( _cachedDuration );
|
|
if ( table ) {
|
|
frac = table->TableLookup( frac );
|
|
}
|
|
value = Lerp( start, end, frac );
|
|
|
|
outputExpression->InputChanged();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionFloat::Detach
|
|
================
|
|
*/
|
|
template< typename T, sdProperties::ePropertyType TYPE, int COUNT >
|
|
void sdUITransition< T, TYPE, COUNT >::Detach( void ) {
|
|
ui->GetState().RemoveTransition( this );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionFloat::Attach
|
|
================
|
|
*/
|
|
void sdUITransitionFloat::Attach( sdUIExpression* _output ) {
|
|
outputExpression = _output;
|
|
|
|
startTime = ui->GetCurrentTime();
|
|
ui->GetState().AddTransition( this );
|
|
|
|
start = startExpressions[ 0 ]->GetFloatValue();
|
|
end = endExpressions[ 0 ]->GetFloatValue();
|
|
|
|
value = start;
|
|
|
|
_cachedDuration = duration->GetFloatValue();
|
|
|
|
if( accelTimes.x > idMath::FLT_EPSILON || accelTimes.y > idMath::FLT_EPSILON ) {
|
|
if ( interpolator == NULL ) {
|
|
interpolator = interpolatorAllocator.Alloc();
|
|
}
|
|
interpolator->Init( startTime, accelTimes.x * _cachedDuration, accelTimes.y * _cachedDuration, _cachedDuration, start, end );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionVec2::Attach
|
|
================
|
|
*/
|
|
void sdUITransitionVec2::Attach( sdUIExpression* _output ) {
|
|
outputExpression = _output;
|
|
|
|
startTime = ui->GetCurrentTime();
|
|
ui->GetState().AddTransition( this );
|
|
|
|
if ( startExpressions[ 0 ]->GetType() == sdProperties::PT_VEC2 ) {
|
|
idVec2 temp;
|
|
start = startExpressions[ 0 ]->GetVec2Value( temp );
|
|
} else {
|
|
start[ 0 ] = startExpressions[ 0 ]->GetFloatValue();
|
|
start[ 1 ] = startExpressions[ 1 ]->GetFloatValue();
|
|
}
|
|
|
|
if ( endExpressions[ 0 ]->GetType() == sdProperties::PT_VEC2 ) {
|
|
idVec2 temp;
|
|
end = endExpressions[ 0 ]->GetVec2Value( temp );
|
|
} else {
|
|
end[ 0 ] = endExpressions[ 0 ]->GetFloatValue();
|
|
end[ 1 ] = endExpressions[ 1 ]->GetFloatValue();
|
|
}
|
|
|
|
value = start;
|
|
|
|
_cachedDuration = duration->GetFloatValue();
|
|
|
|
if( accelTimes.x > idMath::FLT_EPSILON || accelTimes.y > idMath::FLT_EPSILON ) {
|
|
if ( interpolator == NULL ) {
|
|
interpolator = interpolatorAllocator.Alloc();
|
|
}
|
|
interpolator->Init( startTime, accelTimes.x * _cachedDuration, accelTimes.y * _cachedDuration, _cachedDuration, start, end );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionVec3::Attach
|
|
================
|
|
*/
|
|
void sdUITransitionVec3::Attach( sdUIExpression* _output ) {
|
|
outputExpression = _output;
|
|
|
|
startTime = ui->GetCurrentTime();
|
|
ui->GetState().AddTransition( this );
|
|
|
|
if ( startExpressions[ 0 ]->GetType() == sdProperties::PT_VEC3 ) {
|
|
idVec3 temp;
|
|
start = startExpressions[ 0 ]->GetVec3Value( temp );
|
|
} else {
|
|
start[ 0 ] = startExpressions[ 0 ]->GetFloatValue();
|
|
start[ 1 ] = startExpressions[ 1 ]->GetFloatValue();
|
|
start[ 2 ] = startExpressions[ 2 ]->GetFloatValue();
|
|
}
|
|
|
|
if ( endExpressions[ 0 ]->GetType() == sdProperties::PT_VEC3 ) {
|
|
idVec3 temp;
|
|
end = endExpressions[ 0 ]->GetVec3Value( temp );
|
|
} else {
|
|
end[ 0 ] = endExpressions[ 0 ]->GetFloatValue();
|
|
end[ 1 ] = endExpressions[ 1 ]->GetFloatValue();
|
|
end[ 2 ] = endExpressions[ 2 ]->GetFloatValue();
|
|
}
|
|
|
|
value = start;
|
|
|
|
_cachedDuration = duration->GetFloatValue();
|
|
|
|
if( accelTimes.x > idMath::FLT_EPSILON || accelTimes.y > idMath::FLT_EPSILON ) {
|
|
if ( interpolator == NULL ) {
|
|
interpolator = interpolatorAllocator.Alloc();
|
|
}
|
|
interpolator->Init( startTime, accelTimes.x * _cachedDuration, accelTimes.y * _cachedDuration, _cachedDuration, start, end );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUITransitionVec4::Attach
|
|
================
|
|
*/
|
|
void sdUITransitionVec4::Attach( sdUIExpression* _output ) {
|
|
outputExpression = _output;
|
|
|
|
startTime = ui->GetCurrentTime();
|
|
ui->GetState().AddTransition( this );
|
|
|
|
if ( startExpressions[ 0 ]->GetType() == sdProperties::PT_VEC4 ) {
|
|
idVec4 temp;
|
|
start = startExpressions[ 0 ]->GetVec4Value( temp );
|
|
} else {
|
|
start[ 0 ] = startExpressions[ 0 ]->GetFloatValue();
|
|
start[ 1 ] = startExpressions[ 1 ]->GetFloatValue();
|
|
start[ 2 ] = startExpressions[ 2 ]->GetFloatValue();
|
|
start[ 3 ] = startExpressions[ 3 ]->GetFloatValue();
|
|
}
|
|
|
|
if ( endExpressions[ 0 ]->GetType() == sdProperties::PT_VEC4 ) {
|
|
idVec4 temp;
|
|
end = endExpressions[ 0 ]->GetVec4Value( temp );
|
|
} else {
|
|
end[ 0 ] = endExpressions[ 0 ]->GetFloatValue();
|
|
end[ 1 ] = endExpressions[ 1 ]->GetFloatValue();
|
|
end[ 2 ] = endExpressions[ 2 ]->GetFloatValue();
|
|
end[ 3 ] = endExpressions[ 3 ]->GetFloatValue();
|
|
}
|
|
|
|
value = start;
|
|
|
|
_cachedDuration = duration->GetFloatValue();
|
|
|
|
if( accelTimes.x > idMath::FLT_EPSILON || accelTimes.y > idMath::FLT_EPSILON ) {
|
|
if ( interpolator == NULL ) {
|
|
interpolator = interpolatorAllocator.Alloc();
|
|
}
|
|
interpolator->Init( startTime, accelTimes.x * _cachedDuration, accelTimes.y * _cachedDuration, _cachedDuration, start, end );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdFunctionExpression
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
============
|
|
sdFunctionExpression::AllocStack
|
|
============
|
|
*/
|
|
void sdFunctionExpression::AllocStack( void ) {
|
|
if ( _stack == NULL ) {
|
|
_stack = sdUIFunctionStack::allocator.Alloc();
|
|
_stack->Clear();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
sdFunctionExpression::FreeStack
|
|
============
|
|
*/
|
|
void sdFunctionExpression::FreeStack( void ) {
|
|
if ( _stack != NULL && _stack->Empty() ) {
|
|
sdUIFunctionStack::allocator.Free( _stack );
|
|
_stack = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::sdFunctionExpression
|
|
================
|
|
*/
|
|
sdFunctionExpression::sdFunctionExpression( const char* functionName, sdUserInterfaceScope* scope, sdUIFunctionInstance* _function, idStrList& list ) : function( NULL ), _stack(NULL), expressions(1) {
|
|
const sdUIFunction* functionInfo = _function->GetFunctionInfo();
|
|
|
|
if ( list.Num() != functionInfo->GetNumParms() ) {
|
|
gameLocal.Error( "Invalid Number of Parms for Function '%s' ( expected %i but received %i )", functionName, functionInfo->GetNumParms(), list.Num() );
|
|
}
|
|
|
|
function = _function;
|
|
|
|
int i;
|
|
for ( i = 0; i < functionInfo->GetNumParms(); i++ ) {
|
|
sdProperties::ePropertyType type = functionInfo->GetParm( i );
|
|
|
|
switch ( type ) {
|
|
case sdProperties::PT_STRING:
|
|
expressions.Append( sdUIExpression::AllocStringExpression( scope, list[ i ] ) );
|
|
break;
|
|
case sdProperties::PT_WSTRING:
|
|
expressions.Append( sdUIExpression::AllocWStringExpression( scope, list[ i ] ) );
|
|
break;
|
|
case sdProperties::PT_INT:
|
|
expressions.Append( sdUIExpression::AllocIntExpression( scope, list[ i ] ) );
|
|
break;
|
|
case sdProperties::PT_FLOAT:
|
|
case sdProperties::PT_VEC2:
|
|
case sdProperties::PT_VEC3:
|
|
case sdProperties::PT_VEC4: {
|
|
|
|
idStr temp = list[ i ];
|
|
temp.StripLeadingOnce( "\"" );
|
|
temp.StripTrailingOnce( "\"" );
|
|
|
|
int count = sdProperties::CountForPropertyType( type );
|
|
|
|
idStr value;
|
|
idStrList sublist;
|
|
idLexer parser( temp, temp.Length(), "" );
|
|
sdUIScriptEvent::ReadExpression( &parser, value, sublist, NULL, NULL );
|
|
|
|
if ( sublist.Num() == count ) {
|
|
int j;
|
|
for ( j = 0; j < count; j++ ) {
|
|
expressions.Append( sdUIExpression::AllocFloatExpression( scope, sublist[ j ] ) );
|
|
}
|
|
} else if ( sublist.Num() == 1 ) {
|
|
expressions.Append( sdUIExpression::AllocSingleParmExpression( type, scope, sublist[ 0 ] ) );
|
|
} else {
|
|
gameLocal.Error( "Invalid Expression '%s' for Function Parm", value.c_str() );
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
assert( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::~sdFunctionExpression
|
|
================
|
|
*/
|
|
sdFunctionExpression::~sdFunctionExpression( void ) {
|
|
delete function;
|
|
if ( _stack ) {
|
|
_stack->Clear();
|
|
}
|
|
FreeStack();
|
|
|
|
for ( int i = 0; i < expressions.Num(); i++ ) {
|
|
expressions[ i ]->Free();
|
|
}
|
|
expressions.Clear();
|
|
}
|
|
|
|
/*
|
|
============
|
|
sdFunctionExpression::EvaluateInternal
|
|
============
|
|
*/
|
|
void sdFunctionExpression::EvaluateInternal( bool maintainStack ) {
|
|
AllocStack();
|
|
_stack->Clear();
|
|
_stack->SetID( function->GetName() );
|
|
|
|
int i;
|
|
for ( i = expressions.Num() - 1; i >= 0; i-- ) {
|
|
sdUIExpression* expression = expressions[ i ];
|
|
switch ( expression->GetType() ) {
|
|
case sdProperties::PT_STRING:
|
|
{
|
|
idStr temp;
|
|
_stack->Push( expression->GetStringValue( temp ) );
|
|
}
|
|
break;
|
|
case sdProperties::PT_WSTRING:
|
|
{
|
|
idWStr temp;
|
|
_stack->Push( expression->GetWStringValue( temp ).c_str() );
|
|
}
|
|
break;
|
|
case sdProperties::PT_INT:
|
|
_stack->Push( expression->GetIntValue() );
|
|
break;
|
|
case sdProperties::PT_FLOAT:
|
|
_stack->Push( expression->GetFloatValue() );
|
|
break;
|
|
case sdProperties::PT_VEC2:
|
|
{
|
|
idVec2 temp;
|
|
_stack->Push( expression->GetVec2Value( temp ) );
|
|
}
|
|
break;
|
|
case sdProperties::PT_VEC3:
|
|
{
|
|
idVec3 temp;
|
|
_stack->Push( expression->GetVec3Value( temp ) );
|
|
}
|
|
break;
|
|
case sdProperties::PT_VEC4:
|
|
{
|
|
idVec4 temp;
|
|
_stack->Push( expression->GetVec4Value( temp ) );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
function->Run( *_stack );
|
|
if( !maintainStack ) {
|
|
FreeStack();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::Evaluate
|
|
================
|
|
*/
|
|
void sdFunctionExpression::Evaluate( void ) {
|
|
EvaluateInternal( false );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetIntValue
|
|
================
|
|
*/
|
|
int sdFunctionExpression::GetIntValue( void ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_INT );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
int temp;
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetFloatValue
|
|
================
|
|
*/
|
|
float sdFunctionExpression::GetFloatValue( void ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_FLOAT );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
float temp;
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetStringValue
|
|
================
|
|
*/
|
|
const idStr & sdFunctionExpression::GetStringValue( idStr &temp ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_STRING );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetWStringValue
|
|
================
|
|
*/
|
|
const idWStr & sdFunctionExpression::GetWStringValue( idWStr &temp ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_WSTRING );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetVec2Value
|
|
================
|
|
*/
|
|
const idVec2 & sdFunctionExpression::GetVec2Value( idVec2 &temp ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_VEC2 );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetVec3Value
|
|
================
|
|
*/
|
|
const idVec3 & sdFunctionExpression::GetVec3Value( idVec3 &temp ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_VEC3 );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFunctionExpression::GetVec4Value
|
|
================
|
|
*/
|
|
const idVec4 & sdFunctionExpression::GetVec4Value( idVec4 &temp ) {
|
|
assert( function->GetFunctionInfo()->GetReturnType() == sdProperties::PT_VEC4 );
|
|
|
|
EvaluateInternal( true );
|
|
|
|
_stack->Pop( temp );
|
|
FreeStack();
|
|
return temp;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdFloatParmExpression
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::sdFloatParmExpression
|
|
================
|
|
*/
|
|
sdFloatParmExpression::sdFloatParmExpression( sdUserInterfaceScope* _scope, idLexer* src ) : symbols(1), registers(1), ops(1), outputExpression( NULL ), immediate( false ) {
|
|
Parse( src, _scope );
|
|
|
|
if ( registers.Num() == 0 ) {
|
|
src->Error( "Invalid Float Expression" );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ExpressionConstant
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::ExpressionConstant( float f ) {
|
|
int i;
|
|
|
|
for ( i = 0; i < registers.Num(); i++ ) {
|
|
if ( registers[ i ].value == f ) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.value = f;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ExpressionExpression
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::ExpressionExpression( sdUIExpression* expression ) {
|
|
int i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.value = idMath::FLT_EPSILON;
|
|
expressionSymbol_t& symbol = symbols.Alloc();
|
|
symbol.expression = expression;
|
|
symbol.position = i;
|
|
symbol.immediate = inImmediate != 0;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ExpressionTemporary
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::ExpressionTemporary( void ) {
|
|
int i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.value = idMath::FLT_EPSILON;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ExpressionOp
|
|
================
|
|
*/
|
|
sdFloatParmExpression::wexpOp_t& sdFloatParmExpression::ExpressionOp( void ) {
|
|
wexpOp_t& wop = ops.Alloc();
|
|
memset( &wop, 0, sizeof( wop ) );
|
|
return wop;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::EmitOp
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::EmitOp( int a, int b, wexpOpType_t opType, wexpOp_t** opp ) {
|
|
wexpOp_t& op = ExpressionOp();
|
|
int c = ExpressionTemporary();
|
|
|
|
if ( opType < 0 || opType > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdFloatParmExpression::EmitOp Opcode Out of Range" );
|
|
}
|
|
|
|
if ( a < 0 || a > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdFloatParmExpression::EmitOp Parm a Out of Range" );
|
|
}
|
|
|
|
if ( b < 0 || b > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdFloatParmExpression::EmitOp Parm b Out of Range" );
|
|
}
|
|
|
|
if ( c < 0 || c > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdFloatParmExpression::EmitOp Parm c Out of Range" );
|
|
}
|
|
|
|
op.opType = ( unsigned char )opType;
|
|
op.a = ( unsigned char )a;
|
|
op.b = ( unsigned char )b;
|
|
op.c = ( unsigned char )c;
|
|
|
|
if ( opp ) {
|
|
*opp = &op;
|
|
}
|
|
return op.c;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ParseEmitOp
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::ParseEmitOp( idLexer *src, int a, wexpOpType_t opType, int priority, const char* delimiter, sdUserInterfaceScope* scope, wexpOp_t** opp ) {
|
|
int b = ParseExpressionPriority( src, priority, delimiter, scope );
|
|
return EmitOp( a, b, opType, opp );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ParseTerm
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
int sdFloatParmExpression::ParseTerm( idLexer *src, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
idToken token;
|
|
int a, b;
|
|
|
|
src->ReadToken( &token );
|
|
|
|
if ( token == "(" ) {
|
|
a = ParseExpression( src, ")", scope );
|
|
src->ExpectTokenString( ")" );
|
|
return a;
|
|
} else if ( token == "-" ) {
|
|
src->ReadToken( &token );
|
|
if ( token.type == TT_NUMBER || token == "." ) {
|
|
return ExpressionConstant( -token.GetFloatValue() );
|
|
}
|
|
src->Warning( "Bad negative number '%s'", token.c_str() );
|
|
return 0;
|
|
} else if ( token.type == TT_NUMBER || token == "." ) {
|
|
return ExpressionConstant( token.GetFloatValue() );
|
|
}
|
|
|
|
// see if it is a table name
|
|
const idDeclTable *table = gameLocal.declTableType[ token.c_str() ];
|
|
if ( table ) {
|
|
a = table->Index();
|
|
// parse a table expression
|
|
src->ExpectTokenString( "[" );
|
|
b = ParseExpression( src, "]", scope );
|
|
src->ExpectTokenString( "]" );
|
|
return EmitOp( a, b, WOP_TYPE_TABLE );
|
|
}
|
|
|
|
if ( !token.Icmp( "immediate" ) ) {
|
|
inImmediate++;
|
|
|
|
src->ExpectTokenString( "(" );
|
|
a = ParseExpression( src, ")", scope );
|
|
src->ExpectTokenString( ")" );
|
|
|
|
inImmediate--;
|
|
|
|
return a;
|
|
}
|
|
|
|
if( !token.Cmp( "!" ) ) {
|
|
src->ReadToken( &token );
|
|
if( !token.Cmp( "(" ) ) {
|
|
src->UnreadToken( &token );
|
|
src->ExpectTokenString( "(" );
|
|
a = ParseExpression( src, ")", scope );
|
|
src->ExpectTokenString( ")" );
|
|
} else {
|
|
src->UnreadToken( &token );
|
|
a = ParseExpression( src, NULL, scope );
|
|
}
|
|
|
|
return EmitOp( a, 0, WOP_TYPE_NOT );
|
|
}
|
|
|
|
if( !token.Cmp( "~" ) ) {
|
|
src->ReadToken( &token );
|
|
if( !token.Cmp( "(" ) ) {
|
|
src->UnreadToken( &token );
|
|
src->ExpectTokenString( "(" );
|
|
a = ParseExpression( src, ")", scope );
|
|
src->ExpectTokenString( ")" );
|
|
} else {
|
|
src->UnreadToken( &token );
|
|
a = ParseExpression( src, NULL, scope );
|
|
}
|
|
|
|
return EmitOp( a, 0, WOP_TYPE_BIT_COMP );
|
|
}
|
|
|
|
|
|
|
|
src->UnreadToken( &token );
|
|
|
|
sdUserInterfaceScope* altScope = gameLocal.GetUserInterfaceScope( *scope, src );
|
|
|
|
src->ReadToken( &token );
|
|
|
|
idStr propertyName;
|
|
sdProperties::sdProperty* property = altScope->GetProperty( token );
|
|
if ( property ) {
|
|
int propertyIndex = sdUIScriptEvent::GetPropertyField( property->GetValueType(), src );
|
|
if ( propertyIndex == -1 ) {
|
|
if ( property->GetValueType() != sdProperties::PT_FLOAT ) {
|
|
src->Error( "Only Floating Point Terms May be Used" );
|
|
}
|
|
return ExpressionExpression( new sdSingleParmExpressionFloat( property ) );
|
|
} else {
|
|
switch( property->GetValueType() ) {
|
|
case sdProperties::PT_VEC2:
|
|
return ExpressionExpression( new sdSingleParmExpressionFieldVec2( property, propertyIndex ) );
|
|
case sdProperties::PT_VEC3:
|
|
return ExpressionExpression( new sdSingleParmExpressionFieldVec3( property, propertyIndex ) );
|
|
case sdProperties::PT_VEC4:
|
|
return ExpressionExpression( new sdSingleParmExpressionFieldVec4( property, propertyIndex ) );
|
|
}
|
|
src->Error( "Only Floating Point Terms May be Used" );
|
|
}
|
|
}
|
|
|
|
sdUIFunctionInstance* function = altScope->GetFunction( token );
|
|
if ( function ) {
|
|
if ( function->GetFunctionInfo()->GetReturnType() != sdProperties::PT_FLOAT ) {
|
|
int type = function->GetFunctionInfo()->GetReturnType();
|
|
delete function;
|
|
src->Error( "Return Type '%s' was not a Float", sdProperties::sdProperty::TypeToString( type ) );
|
|
}
|
|
immediate = true;
|
|
|
|
sdUIExpression* expression = sdUIExpression::AllocFunctionExpression( token, function, scope, src );
|
|
return ExpressionExpression( expression );
|
|
}
|
|
|
|
sdUIEvaluatorTypeBase* evaluator = altScope->GetEvaluator( token );
|
|
if ( evaluator ) {
|
|
if ( evaluator->GetReturnType() != sdProperties::PT_FLOAT ) {
|
|
src->Error( "Return Type Was Not a Float" );
|
|
}
|
|
return ExpressionExpression( new sdUIEvaluatorFloat( evaluator, scope, src ) );
|
|
}
|
|
|
|
idStr message = token;
|
|
while( src->ReadToken( &token ) ) {
|
|
if ( token.linesCrossed ) {
|
|
src->UnreadToken( &token );
|
|
break;
|
|
}
|
|
message += token;
|
|
}
|
|
src->Error( "Invalid Term '%s' in '%s'", message.c_str(), scope->GetUI()->GetName() );
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
sdFloatParmExpression::ParseExpressionPriority
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
int sdFloatParmExpression::ParseExpressionPriority( idLexer *src, int priority, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
idToken token;
|
|
int a;
|
|
|
|
if ( priority == 0 ) {
|
|
return ParseTerm( src, delimiter, scope );
|
|
}
|
|
|
|
a = ParseExpressionPriority( src, priority - 1, delimiter, scope );
|
|
|
|
if ( !src->ReadToken( &token ) ) {
|
|
if ( !delimiter ) {
|
|
// we won't get EOF in a real file, but we can
|
|
// when parsing from generated strings
|
|
return a;
|
|
} else {
|
|
src->Error( "Unexpected End of File" );
|
|
}
|
|
}
|
|
|
|
if ( delimiter && !token.Icmp( delimiter ) ) {
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
|
|
switch( priority ) {
|
|
case 1: {
|
|
if ( token == "*" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_MULTIPLY, priority, delimiter, scope );
|
|
}
|
|
if ( token == "/" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_DIVIDE, priority, delimiter, scope );
|
|
}
|
|
if ( token == "%" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_MOD, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 2: {
|
|
if ( token == "+" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_ADD, priority, delimiter, scope );
|
|
}
|
|
if ( token == "-" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_SUBTRACT, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 3: {
|
|
if ( token == ">" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_GT, priority, delimiter, scope );
|
|
}
|
|
if ( token == ">=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_GE, priority, delimiter, scope );
|
|
}
|
|
if ( token == "<" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_LT, priority, delimiter, scope );
|
|
}
|
|
if ( token == "<=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_LE, priority, delimiter, scope );
|
|
}
|
|
if ( token == "==" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_EQ, priority, delimiter, scope );
|
|
}
|
|
if ( token == "!=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_NE, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 4: {
|
|
if ( token == "&" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_BIT_AND, priority, delimiter, scope );
|
|
}
|
|
if ( token == "^" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_BIT_XOR, priority, delimiter, scope );
|
|
}
|
|
if ( token == "|" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_BIT_OR, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 5: {
|
|
if ( token == "&&" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_AND, priority, delimiter, scope );
|
|
}
|
|
if ( token == "||" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_OR, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
}
|
|
}
|
|
|
|
// assume that anything else terminates the expression
|
|
// not too robust error checking...
|
|
|
|
src->Error( "Unknown Token '%s'", token.c_str() );
|
|
|
|
return a;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdFloatParmExpression::ParseExpression
|
|
|
|
Returns a register index
|
|
================
|
|
*/
|
|
int sdFloatParmExpression::ParseExpression( idLexer *src, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
const int TOP_PRIORITY = 5;
|
|
return ParseExpressionPriority( src, TOP_PRIORITY, delimiter, scope );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::EvaluateRegisters
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::EvaluateRegisters( void ) {
|
|
int i;
|
|
|
|
for ( i = 0 ; i < symbols.Num() ; i++ ) {
|
|
registers[ symbols[ i ].position ].value = symbols[ i ].expression->GetFloatValue();
|
|
}
|
|
|
|
for ( i = 0 ; i < ops.Num() ; i++ ) {
|
|
wexpOp_t& op = ops[ i ];
|
|
|
|
switch( op.opType ) {
|
|
case WOP_TYPE_ADD:
|
|
registers[ op.c ].value = registers[ op.a ].value + registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_SUBTRACT:
|
|
registers[ op.c ].value = registers[ op.a ].value - registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_MULTIPLY:
|
|
registers[ op.c ].value = registers[ op.a ].value * registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_DIVIDE:
|
|
registers[ op.c ].value = registers[ op.a ].value / registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_MOD:
|
|
registers[ op.c ].value = registers[ op.a ].value - ( idMath::Floor( registers[ op.a ].value / registers[ op.b ].value ) * registers[ op.b ].value );
|
|
break;
|
|
case WOP_TYPE_TABLE: {
|
|
const idDeclTable* table = declHolder.declTableType.LocalFindByIndex( op.a );
|
|
registers[ op.c ].value = table->TableLookup( registers[ op.b ].value );
|
|
break;
|
|
}
|
|
case WOP_TYPE_NOT:
|
|
registers[ op.c ].value = !idMath::Ftoi( registers[ op.a ].value );
|
|
break;
|
|
case WOP_TYPE_BIT_COMP:
|
|
registers[ op.c ].value = ~idMath::Ftoi( registers[ op.a ].value );
|
|
break;
|
|
case WOP_TYPE_GT:
|
|
registers[ op.c ].value = registers[ op.a ].value > registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_GE:
|
|
registers[ op.c ].value = registers[ op.a ].value >= registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_LT:
|
|
registers[ op.c ].value = registers[ op.a ].value < registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_LE:
|
|
registers[ op.c ].value = registers[ op.a ].value <= registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_EQ:
|
|
registers[ op.c ].value = idMath::Fabs( registers[ op.a ].value - registers[ op.b ].value ) < idMath::FLT_EPSILON;
|
|
break;
|
|
case WOP_TYPE_NE:
|
|
registers[ op.c ].value = registers[ op.a ].value != registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_BIT_AND:
|
|
registers[ op.c ].value = idMath::Ftoi( registers[ op.a ].value ) & idMath::Ftoi( registers[ op.b ].value );
|
|
break;
|
|
case WOP_TYPE_BIT_XOR:
|
|
registers[ op.c ].value = idMath::Ftoi( registers[ op.a ].value ) ^ idMath::Ftoi( registers[ op.b ].value );
|
|
break;
|
|
case WOP_TYPE_BIT_OR:
|
|
registers[ op.c ].value = idMath::Ftoi( registers[ op.a ].value ) | idMath::Ftoi( registers[ op.b ].value );
|
|
break;
|
|
case WOP_TYPE_AND:
|
|
registers[ op.c ].value = registers[ op.a ].value && registers[ op.b ].value;
|
|
break;
|
|
case WOP_TYPE_OR:
|
|
registers[ op.c ].value = registers[ op.a ].value || registers[ op.b ].value;
|
|
break;
|
|
default:
|
|
gameLocal.Error( "EvaluateRegisters: bad opcode" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::~sdFloatParmExpression
|
|
===============
|
|
*/
|
|
sdFloatParmExpression::~sdFloatParmExpression( void ) {
|
|
for ( int i = 0; i < symbols.Num(); i++ ) {
|
|
symbols[ i ].expression->Free();
|
|
}
|
|
symbols.Clear();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::EvaluateRegisters
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::Parse( idLexer* src, sdUserInterfaceScope* scope ) {
|
|
inImmediate = 0;
|
|
|
|
valueRegister = ParseExpression( src, NULL, scope );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::InputChanged
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::InputChanged( void ) {
|
|
if ( immediate ) {
|
|
return;
|
|
}
|
|
|
|
if ( outputExpression ) {
|
|
outputExpression->InputChanged();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::Update
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::Update( void ) {
|
|
EvaluateRegisters();
|
|
|
|
if ( outputExpression ) {
|
|
outputExpression->InputChanged();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::Attach
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::Attach( sdUIExpression* output ) {
|
|
if ( !immediate ) {
|
|
int i;
|
|
for ( i = 0; i < symbols.Num(); i++ ) {
|
|
if ( symbols[ i ].immediate ) {
|
|
continue;
|
|
}
|
|
|
|
symbols[ i ].expression->Attach( this );
|
|
}
|
|
}
|
|
outputExpression = output;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdFloatParmExpression::Detach
|
|
===============
|
|
*/
|
|
void sdFloatParmExpression::Detach( void ) {
|
|
if ( !immediate ) {
|
|
int i;
|
|
for ( i = 0; i < symbols.Num(); i++ ) {
|
|
if ( symbols[ i ].immediate ) {
|
|
continue;
|
|
}
|
|
|
|
symbols[ i ].expression->Detach();
|
|
}
|
|
}
|
|
outputExpression = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdStringParmExpression
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::sdStringParmExpression
|
|
================
|
|
*/
|
|
sdStringParmExpression::sdStringParmExpression( sdUserInterfaceScope* _scope, idLexer* src ) :
|
|
symbols(1),
|
|
registers(1),
|
|
ops(1),
|
|
outputExpression( NULL ),
|
|
immediate( false ) {
|
|
Parse( src, _scope );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ExpressionConstant
|
|
================
|
|
*/
|
|
int sdStringParmExpression::ExpressionConstant( const char* str ) {
|
|
int i;
|
|
|
|
for ( i = 0; i < registers.Num(); i++ ) {
|
|
if ( !registers[ i ].temporary && registers[ i ].value == str ) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.temporary = false;
|
|
r.value = str;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ExpressionExpression
|
|
================
|
|
*/
|
|
int sdStringParmExpression::ExpressionExpression( sdUIExpression* expression ) {
|
|
int i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.temporary = true;
|
|
r.value = "";
|
|
expressionSymbol_t& symbol = symbols.Alloc();
|
|
symbol.expression = expression;
|
|
symbol.position = i;
|
|
symbol.immediate = inImmediate != 0;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ExpressionTemporary
|
|
================
|
|
*/
|
|
int sdStringParmExpression::ExpressionTemporary( void ) {
|
|
int i = registers.Num();
|
|
expressionRegister_t& r = registers.Alloc();
|
|
r.temporary = true;
|
|
r.value = "";
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ExpressionOp
|
|
================
|
|
*/
|
|
sdStringParmExpression::wexpOp_t& sdStringParmExpression::ExpressionOp( void ) {
|
|
wexpOp_t& wop = ops.Alloc();
|
|
memset( &wop, 0, sizeof( wop ) );
|
|
return wop;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::EmitOp
|
|
================
|
|
*/
|
|
int sdStringParmExpression::EmitOp( int a, int b, wexpOpType_t opType, wexpOp_t** opp ) {
|
|
wexpOp_t& op = ExpressionOp();
|
|
int c = ExpressionTemporary();
|
|
|
|
if ( opType < 0 || opType > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdStringParmExpression::EmitOp Opcode Out of Range" );
|
|
}
|
|
|
|
if ( a < 0 || a > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdStringParmExpression::EmitOp Parm a Out of Range" );
|
|
}
|
|
|
|
if ( b < 0 || b > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdStringParmExpression::EmitOp Parm b Out of Range" );
|
|
}
|
|
|
|
if ( c < 0 || c > UCHAR_MAX ) {
|
|
gameLocal.Error( "sdStringParmExpression::EmitOp Parm c Out of Range" );
|
|
}
|
|
|
|
op.opType = ( unsigned char )opType;
|
|
op.a = ( unsigned char )a;
|
|
op.b = ( unsigned char )b;
|
|
op.c = ( unsigned char )c;
|
|
|
|
if ( opp ) {
|
|
*opp = &op;
|
|
}
|
|
return op.c;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ParseEmitOp
|
|
================
|
|
*/
|
|
int sdStringParmExpression::ParseEmitOp( idLexer *src, int a, wexpOpType_t opType, int priority, const char* delimiter, sdUserInterfaceScope* scope, wexpOp_t** opp ) {
|
|
int b = ParseExpressionPriority( src, priority, delimiter, scope );
|
|
return EmitOp( a, b, opType, opp );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ParseTerm
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
int sdStringParmExpression::ParseTerm( idLexer *src, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
idToken token;
|
|
int a;
|
|
|
|
src->ReadToken( &token );
|
|
|
|
if ( token == "(" && token.type != TT_STRING ) {
|
|
a = ParseExpression( src, ")", scope );
|
|
src->ExpectTokenString( ")" );
|
|
return a;
|
|
} else if( !token.Icmp( "_quote" )) {
|
|
return ExpressionConstant( "\"" );
|
|
} else if( !token.Icmp( "_newline" )) {
|
|
return ExpressionConstant( "\n" );
|
|
} else if ( token.type == TT_STRING ) {
|
|
return ExpressionConstant( token );
|
|
}
|
|
|
|
if ( !token.Icmp( "immediate" ) ) {
|
|
inImmediate++;
|
|
|
|
src->ExpectTokenString( "(" );
|
|
|
|
a = ParseExpression( src, ")", scope );
|
|
|
|
src->ExpectTokenString( ")" );
|
|
|
|
inImmediate--;
|
|
|
|
return a;
|
|
}
|
|
|
|
src->UnreadToken( &token );
|
|
|
|
sdUserInterfaceScope* altScope = gameLocal.GetUserInterfaceScope( *scope, src );
|
|
|
|
src->ReadToken( &token );
|
|
|
|
idStr propertyName;
|
|
sdProperties::sdProperty* property = altScope->GetProperty( token );
|
|
if ( property ) {
|
|
if ( property->GetValueType() != sdProperties::PT_STRING ) {
|
|
src->Error( "Cannot assign a '%s' to a string", sdProperties::sdProperty::TypeToString( property->GetValueType() ) );
|
|
}
|
|
return ExpressionExpression( new sdSingleParmExpressionString( property ) );
|
|
}
|
|
|
|
sdUIFunctionInstance* function = altScope->GetFunction( token );
|
|
if ( function ) {
|
|
if ( function->GetFunctionInfo()->GetReturnType() != sdProperties::PT_STRING ) {
|
|
int type = function->GetFunctionInfo()->GetReturnType();
|
|
delete function;
|
|
src->Error( "Return Type '%s' was not a String", sdProperties::sdProperty::TypeToString( type ) );
|
|
}
|
|
immediate = true;
|
|
|
|
sdUIExpression* expression = sdUIExpression::AllocFunctionExpression( token, function, scope, src );
|
|
return ExpressionExpression( expression );
|
|
}
|
|
|
|
sdUIEvaluatorTypeBase* evaluator = altScope->GetEvaluator( token );
|
|
if ( evaluator ) {
|
|
if ( evaluator->GetReturnType() != sdProperties::PT_STRING ) {
|
|
src->Error( "Return Type '%s' was not a String", sdProperties::sdProperty::TypeToString( evaluator->GetReturnType() ) );
|
|
}
|
|
return ExpressionExpression( new sdUIEvaluatorString( evaluator, scope, src ) );
|
|
}
|
|
|
|
idStr backup = token;
|
|
|
|
idStr message = token;
|
|
while( src->ReadToken( &token ) ) {
|
|
if ( token.linesCrossed ) {
|
|
src->UnreadToken( &token );
|
|
break;
|
|
}
|
|
message += token;
|
|
}
|
|
src->Error( "Invalid Term '%s' in expression '%s' in '%s'", backup.c_str(), message.c_str(), scope->GetUI()->GetName() );
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
sdStringParmExpression::ParseExpressionPriority
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
int sdStringParmExpression::ParseExpressionPriority( idLexer *src, int priority, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
idToken token;
|
|
int a;
|
|
|
|
if ( priority == 0 ) {
|
|
return ParseTerm( src, delimiter, scope );
|
|
}
|
|
|
|
a = ParseExpressionPriority( src, priority - 1, delimiter, scope );
|
|
|
|
if ( !src->ReadToken( &token ) ) {
|
|
if ( !delimiter ) {
|
|
// we won't get EOF in a real file, but we can
|
|
// when parsing from generated strings
|
|
return a;
|
|
} else {
|
|
src->Error( "Unexpected End of File" );
|
|
}
|
|
}
|
|
|
|
if ( delimiter && !token.Icmp( delimiter ) ) {
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
|
|
switch( priority ) {
|
|
case 1: {
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 2: {
|
|
if ( token == "+" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_ADD, priority, delimiter, scope );
|
|
}
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 3: {
|
|
src->UnreadToken( &token );
|
|
return a;
|
|
}
|
|
case 4: {
|
|
src->UnreadToken( &token );
|
|
}
|
|
}
|
|
|
|
// assume that anything else terminates the expression
|
|
// not too robust error checking...
|
|
if( token == ")" ) {
|
|
src->Error( "Mismatched ')'" );
|
|
}
|
|
|
|
src->Error( "Unknown Token '%s'", token.c_str() );
|
|
|
|
return a;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdStringParmExpression::ParseExpression
|
|
|
|
Returns a register index
|
|
================
|
|
*/
|
|
int sdStringParmExpression::ParseExpression( idLexer *src, const char* delimiter, sdUserInterfaceScope* scope ) {
|
|
const int TOP_PRIORITY = 4;
|
|
return ParseExpressionPriority( src, TOP_PRIORITY, delimiter, scope );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::EvaluateRegisters
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::EvaluateRegisters( void ) {
|
|
int i;
|
|
|
|
for ( i = 0 ; i < symbols.Num() ; i++ ) {
|
|
idStr temp;
|
|
registers[ symbols[ i ].position ].value = symbols[ i ].expression->GetStringValue( temp );
|
|
}
|
|
|
|
for ( i = 0 ; i < ops.Num() ; i++ ) {
|
|
wexpOp_t& op = ops[ i ];
|
|
|
|
switch( op.opType ) {
|
|
case WOP_TYPE_ADD:
|
|
{
|
|
sdStringBuilder_Heap builder;
|
|
builder = registers[ op.a ].value;
|
|
builder += registers[ op.b ].value;
|
|
builder.ToString( registers[ op.c ].value );
|
|
//= builder;//registers[ op.a ].value + registers[ op.b ].value;
|
|
}
|
|
break;
|
|
default:
|
|
common->FatalError( "EvaluateRegisters: bad opcode" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::~sdStringParmExpression
|
|
===============
|
|
*/
|
|
sdStringParmExpression::~sdStringParmExpression( void ) {
|
|
for ( int i = 0; i < symbols.Num(); i++ ) {
|
|
symbols[ i ].expression->Free();
|
|
}
|
|
symbols.Clear();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::EvaluateRegisters
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::Parse( idLexer* src, sdUserInterfaceScope* scope ) {
|
|
inImmediate = 0;
|
|
|
|
valueRegister = ParseExpression( src, NULL, scope );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::Update
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::Update( void ) {
|
|
EvaluateRegisters();
|
|
|
|
if ( outputExpression ) {
|
|
outputExpression->InputChanged();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::Attach
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::Attach( sdUIExpression* output ) {
|
|
if ( !immediate ) {
|
|
int i;
|
|
for ( i = 0; i < symbols.Num(); i++ ) {
|
|
if ( symbols[ i ].immediate ) {
|
|
continue;
|
|
}
|
|
symbols[ i ].expression->Attach( this );
|
|
}
|
|
}
|
|
outputExpression = output;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::Detach
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::Detach( void ) {
|
|
if ( !immediate ) {
|
|
int i;
|
|
for ( i = 0; i < symbols.Num(); i++ ) {
|
|
if ( symbols[ i ].immediate ) {
|
|
continue;
|
|
}
|
|
symbols[ i ].expression->Detach();
|
|
}
|
|
}
|
|
outputExpression = NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdStringParmExpression::InputChanged
|
|
===============
|
|
*/
|
|
void sdStringParmExpression::InputChanged( void ) {
|
|
if ( immediate ) {
|
|
return;
|
|
}
|
|
|
|
if ( outputExpression ) {
|
|
outputExpression->InputChanged();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdPropertyExpressionSingle
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::sdPropertyExpressionSingle
|
|
================
|
|
*/
|
|
sdPropertyExpressionSingle::sdPropertyExpressionSingle( const char* name, sdUIExpression* input ) : outputProperty( NULL ) {
|
|
inputExpression = input;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::~sdPropertyExpressionSingle
|
|
================
|
|
*/
|
|
sdPropertyExpressionSingle::~sdPropertyExpressionSingle( void ) {
|
|
if ( outputProperty ) {
|
|
scope->ClearPropertyExpression( scopeKey, scopeIndex );
|
|
}
|
|
|
|
inputExpression->Free();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::OnOnChangedOverflow
|
|
================
|
|
*/
|
|
void sdPropertyExpressionSingle::OnOnChangedOverflow( void ) {
|
|
sdUserInterfaceScope* propertyScope;
|
|
const char* propertyName = scope->FindPropertyNameByKey( scopeKey, propertyScope );
|
|
if ( propertyName != NULL ) {
|
|
gameLocal.Printf( "Property: %s", propertyName );
|
|
if ( propertyScope != NULL ) {
|
|
gameLocal.Printf( " Scope: %s", propertyScope->GetName() );
|
|
|
|
sdUserInterfaceLocal* gui = propertyScope->GetUI();
|
|
if ( gui != NULL ) {
|
|
gameLocal.Printf( " GUI: %s", gui->GetDecl()->GetName() );
|
|
}
|
|
}
|
|
gameLocal.Printf( "\n" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::SetProperty
|
|
================
|
|
*/
|
|
void sdPropertyExpressionSingle::SetProperty( sdProperties::sdProperty* output, int index, int key, sdUserInterfaceScope* outputScope ) {
|
|
outputProperty = output;
|
|
scopeIndex = index;
|
|
scopeKey = key;
|
|
scope = outputScope;
|
|
|
|
inputExpression->Attach( this );
|
|
|
|
Update();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::Detach
|
|
================
|
|
*/
|
|
void sdPropertyExpressionSingle::Detach( void ) {
|
|
inputExpression->Detach();
|
|
outputProperty = NULL;
|
|
scope = NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::InputChanged
|
|
================
|
|
*/
|
|
void sdPropertyExpressionSingle::InputChanged( void ) {
|
|
Update();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionSingle::Update
|
|
================
|
|
*/
|
|
void sdPropertyExpressionSingle::Update( void ) {
|
|
switch ( outputProperty->GetValueType() ) {
|
|
case sdProperties::PT_INT:
|
|
*outputProperty->value.intValue = inputExpression->GetIntValue();
|
|
break;
|
|
case sdProperties::PT_FLOAT:
|
|
*outputProperty->value.floatValue = inputExpression->GetFloatValue();
|
|
break;
|
|
case sdProperties::PT_VEC2:
|
|
{
|
|
idVec2 temp;
|
|
*outputProperty->value.vec2Value = inputExpression->GetVec2Value( temp );
|
|
}
|
|
break;
|
|
case sdProperties::PT_VEC3:
|
|
{
|
|
idVec3 temp;
|
|
*outputProperty->value.vec3Value = inputExpression->GetVec3Value( temp );
|
|
}
|
|
break;
|
|
case sdProperties::PT_VEC4:
|
|
{
|
|
idVec4 temp;
|
|
*outputProperty->value.vec4Value = inputExpression->GetVec4Value( temp );
|
|
}
|
|
break;
|
|
case sdProperties::PT_STRING:
|
|
{
|
|
idStr temp;
|
|
*outputProperty->value.stringValue = inputExpression->GetStringValue( temp );
|
|
}
|
|
break;
|
|
case sdProperties::PT_WSTRING:
|
|
{
|
|
idWStr temp;
|
|
*outputProperty->value.wstringValue = inputExpression->GetWStringValue( temp );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdPropertyExpressionField
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionField::sdPropertyExpressionField
|
|
================
|
|
*/
|
|
sdPropertyExpressionField::sdPropertyExpressionField( const char* name, sdUIExpression* input, int index ) : sdPropertyExpressionSingle( name, input ) {
|
|
outputField = index;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdPropertyExpressionField::Update
|
|
================
|
|
*/
|
|
void sdPropertyExpressionField::Update( void ) {
|
|
switch ( outputProperty->GetValueType() ) {
|
|
case sdProperties::PT_FLOAT:
|
|
*outputProperty->value.floatValue = inputExpression->GetFloatValue();
|
|
break;
|
|
case sdProperties::PT_VEC2:
|
|
outputProperty->value.vec2Value->SetIndex( outputField, inputExpression->GetFloatValue() );
|
|
break;
|
|
case sdProperties::PT_VEC3:
|
|
outputProperty->value.vec3Value->SetIndex( outputField, inputExpression->GetFloatValue() );
|
|
break;
|
|
case sdProperties::PT_VEC4:
|
|
outputProperty->value.vec4Value->SetIndex( outputField, inputExpression->GetFloatValue() );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdUIEvaluatorType
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdUIEvaluatorType::sdUIEvaluatorType
|
|
================
|
|
*/
|
|
#define UI_EVALUATOR_TYPE_DEFINITION( TYPENAME ) \
|
|
sdUIEvaluatorType##TYPENAME::sdUIEvaluatorType##TYPENAME( const char* _parms, const char* _name, evaluationFunc_t func ) { \
|
|
isVariadic = false; \
|
|
int len = idStr::Length( _parms ); \
|
|
int i; \
|
|
for ( i = 0; i < len; i++ ) { \
|
|
switch ( _parms[ i ] ) { \
|
|
case 'i': parms.Append( sdProperties::PT_INT ); break; \
|
|
case 'f': parms.Append( sdProperties::PT_FLOAT ); break; \
|
|
case '2': parms.Append( sdProperties::PT_VEC2 ); break; \
|
|
case '3': parms.Append( sdProperties::PT_VEC3 ); break; \
|
|
case '4': parms.Append( sdProperties::PT_VEC4 ); break; \
|
|
case 's': parms.Append( sdProperties::PT_STRING ); break; \
|
|
case 'w': parms.Append( sdProperties::PT_WSTRING ); break; \
|
|
case '#': isVariadic = true; break; \
|
|
default: gameLocal.Error( "Invalid Paramter Type '%c'", _parms[ i ] ); break; \
|
|
} \
|
|
} \
|
|
function = func; \
|
|
name = _name; \
|
|
}
|
|
|
|
UI_EVALUATOR_TYPE_DEFINITION( Int )
|
|
UI_EVALUATOR_TYPE_DEFINITION( Float )
|
|
UI_EVALUATOR_TYPE_DEFINITION( Vec2 )
|
|
UI_EVALUATOR_TYPE_DEFINITION( Vec3 )
|
|
UI_EVALUATOR_TYPE_DEFINITION( Vec4 )
|
|
UI_EVALUATOR_TYPE_DEFINITION( String )
|
|
UI_EVALUATOR_TYPE_DEFINITION( WString )
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdUIEvaluator
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdUIEvaluator::sdUIEvaluator
|
|
================
|
|
*/
|
|
sdUIEvaluator::sdUIEvaluator( sdUIEvaluatorTypeBase* _type, sdUserInterfaceScope* _scope, idLexer* src ) : type( _type ), scope( _scope ), outputExpression( NULL ) {
|
|
using namespace sdProperties;
|
|
|
|
int count = type->GetNumParms();
|
|
|
|
idStr temp;
|
|
src->ParseBracedSection( temp, -1, true, '(', ')' );
|
|
|
|
idLexer parser( temp, temp.Length(), "sdUIExpression" );
|
|
parser.ExpectTokenString( "(" );
|
|
|
|
idStr value;
|
|
idStrList terms;
|
|
sdUIScriptEvent::ReadExpression( &parser, value, terms, "(", ")", true );
|
|
|
|
if ( terms.Num() != count && !IsVariadic() ) {
|
|
src->Error( "Invalid Number of Parameters for '%s'", type->GetName() );
|
|
return;
|
|
}
|
|
|
|
int i;
|
|
for ( i = 0; i < terms.Num(); i++ ) {
|
|
sdUIExpression* exp = NULL;
|
|
ePropertyType parmType;
|
|
if( i < count ) {
|
|
parmType = type->GetParmType( i );
|
|
} else if( IsVariadic() ) {
|
|
parmType = type->GetReturnType();
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
switch ( parmType ) {
|
|
case PT_INT:
|
|
exp = sdUIExpression::AllocIntExpression( _scope, terms[ i ] );
|
|
break;
|
|
case PT_FLOAT:
|
|
exp = sdUIExpression::AllocFloatExpression( _scope, terms[ i ] );
|
|
break;
|
|
case PT_STRING:
|
|
exp = sdUIExpression::AllocStringExpression( _scope, terms[ i ] );
|
|
break;
|
|
case PT_WSTRING:
|
|
exp = sdUIExpression::AllocWStringExpression( _scope, terms[ i ] );
|
|
break;
|
|
case PT_VEC2:
|
|
case PT_VEC3:
|
|
case PT_VEC4:
|
|
exp = sdUIExpression::AllocSingleParmExpression( parmType, _scope, terms[ i ] );
|
|
break;
|
|
default:
|
|
src->Error( "Unknown Parameter Type on '%s' index '%i'", type->GetName(), i );
|
|
break;
|
|
}
|
|
parms.Alloc() = exp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIEvaluator::~sdUIEvaluator
|
|
================
|
|
*/
|
|
sdUIEvaluator::~sdUIEvaluator( void ) {
|
|
for ( int i = 0; i < parms.Num(); i++ ) {
|
|
parms[ i ]->Free();
|
|
}
|
|
parms.Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIEvaluator::Attach
|
|
================
|
|
*/
|
|
void sdUIEvaluator::Attach( sdUIExpression* output ) {
|
|
outputExpression = output;
|
|
|
|
int i;
|
|
for ( i = 0; i < parms.Num(); i++ ) {
|
|
parms[ i ]->Attach( this );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdUIEvaluator::Detach
|
|
================
|
|
*/
|
|
void sdUIEvaluator::Detach( void ) {
|
|
outputExpression = NULL;
|
|
|
|
int i;
|
|
for ( i = 0; i < parms.Num(); i++ ) {
|
|
parms[ i ]->Detach();
|
|
}
|
|
}
|
|
|
|
|