188 lines
5.4 KiB
C++
188 lines
5.4 KiB
C++
//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
|
|
//
|
|
// The expression operator class - scalar math calculator
|
|
// for a good list of operators and simple functions, see:
|
|
// \\fileserver\user\MarcS\boxweb\aliveDistLite\v4.2.0\doc\alive\functions.txt
|
|
// (although we'll want to implement elerp as the standard 3x^2 - 2x^3 with rescale)
|
|
//
|
|
//=============================================================================
|
|
#include "movieobjects/dmeexpressionoperator.h"
|
|
#include "movieobjects_interfaces.h"
|
|
#include "datamodel/dmelementfactoryhelper.h"
|
|
#include "datamodel/dmattribute.h"
|
|
#include "mathlib/noise.h"
|
|
#include "mathlib/vector.h"
|
|
#include <ctype.h>
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
void TestCalculator( const char *expr, float answer )
|
|
{
|
|
CExpressionCalculator calc( expr );
|
|
float result = 0.0f;
|
|
|
|
#ifdef _DEBUG
|
|
bool success =
|
|
#endif
|
|
calc.Evaluate( result );
|
|
Assert( success && ( result == answer ) );
|
|
}
|
|
|
|
void TestCalculator( const char *expr, float answer, const char *var, float value )
|
|
{
|
|
CExpressionCalculator calc( expr );
|
|
calc.SetVariable( var, value );
|
|
float result = 0.0f;
|
|
|
|
#ifdef _DEBUG
|
|
bool success =
|
|
#endif
|
|
calc.Evaluate( result );
|
|
Assert( success && ( result == answer ) );
|
|
}
|
|
|
|
void TestCalculator()
|
|
{
|
|
// TestCalculator( "-1", 1 );
|
|
TestCalculator( "2 * 3 + 4", 10 );
|
|
TestCalculator( "2 + 3 * 4", 14 );
|
|
TestCalculator( "2 * 3 * 4", 24 );
|
|
TestCalculator( "2 * -3 + 4", -2 );
|
|
TestCalculator( "12.0 / 2.0", 6 );
|
|
TestCalculator( "(2*3)+4", 10 );
|
|
TestCalculator( "( 1 + 2 ) / (1+2)", 1 );
|
|
TestCalculator( "(((5)))", 5 );
|
|
TestCalculator( "--5", 5 );
|
|
TestCalculator( "3.5 % 2", 1.5 );
|
|
TestCalculator( "1e-2", 0.01 );
|
|
TestCalculator( "9 == ( 3 * ( 1 + 2 ) )", 1 );
|
|
TestCalculator( "9 != ( 3 * ( 1 + 2 ) )", 0 );
|
|
TestCalculator( "9 <= ( 3 * ( 1 + 2 ) )", 1 );
|
|
TestCalculator( "9 < ( 3 * ( 1 + 2 ) )", 0 );
|
|
TestCalculator( "9 < 3", 0 );
|
|
TestCalculator( "10 >= 5", 1 );
|
|
// TestCalculator( "9 < ( 3 * ( 2 + 2 ) )", 0 );
|
|
TestCalculator( "x + 1", 5, "x", 4 );
|
|
TestCalculator( "pi - 3.14159", 0, "pi", 3.14159 );
|
|
// TestCalculator( "pi / 2", 0, "pi", 3.14159 );
|
|
TestCalculator( "abs(-10)", 10 );
|
|
TestCalculator( "sqr(-5)", 25 );
|
|
TestCalculator( "sqrt(9)", 3 );
|
|
// TestCalculator( "sqrt(-9)", -3 );
|
|
TestCalculator( "pow(2,3)", 8 );
|
|
TestCalculator( "min(abs(-4),2+3/2)", 3.5 );
|
|
TestCalculator( "round(0.5)", 1 );
|
|
TestCalculator( "round(0.49)", 0 );
|
|
TestCalculator( "round(-0.5)", 0 );
|
|
TestCalculator( "round(-0.51)", -1 );
|
|
TestCalculator( "inrange( 5, -8, 10 )", 1 );
|
|
TestCalculator( "inrange( 5, 5, 10 )", 1 );
|
|
TestCalculator( "inrange( 5, 6, 10 )", 0 );
|
|
TestCalculator( "elerp( 1/4, 0, 1 )", 3/16.0f - 1/32.0f );
|
|
TestCalculator( "rescale( 0.5, -1, 1, 0, 100 )", 75 );
|
|
TestCalculator( "1 > 2 ? 6 : 9", 9 );
|
|
TestCalculator( "1 ? 1 ? 2 : 4 : 1 ? 6 : 8", 2 );
|
|
TestCalculator( "0 ? 1 ? 2 : 4 : 1 ? 6 : 8", 6 );
|
|
TestCalculator( "noise( 0.123, 4.56, 78.9 )", ImprovedPerlinNoise( Vector( 0.123, 4.56, 78.9 ) ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Expose this class to the scene database
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_ELEMENT_FACTORY( DmeExpressionOperator, CDmeExpressionOperator );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeExpressionOperator::OnConstruction()
|
|
{
|
|
m_result.Init( this, "result" );
|
|
m_expr.Init( this, "expr" );
|
|
m_bSpewResult.Init( this, "spewresult" );
|
|
|
|
#ifdef _DEBUG
|
|
TestCalculator();
|
|
#endif _DEBUG
|
|
}
|
|
|
|
void CDmeExpressionOperator::OnDestruction()
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool CDmeExpressionOperator::IsInputAttribute( CDmAttribute *pAttribute )
|
|
{
|
|
const char *pName = pAttribute->GetName( );
|
|
#if 0 // skip this test, since none of these are float attributes, but leave the code as a reminder
|
|
if ( Q_strcmp( pName, "name" ) == 0 )
|
|
return false;
|
|
|
|
if ( Q_strcmp( pName, "expr" ) == 0 )
|
|
return false;
|
|
#endif
|
|
|
|
if ( Q_strcmp( pName, "result" ) == 0 )
|
|
return false;
|
|
|
|
if ( pAttribute->GetType() != AT_FLOAT )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CDmeExpressionOperator::Operate()
|
|
{
|
|
m_calc.SetExpression( m_expr.Get() );
|
|
|
|
for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
|
|
{
|
|
if ( IsInputAttribute( pAttribute ) )
|
|
{
|
|
const char *pName = pAttribute->GetName( );
|
|
m_calc.SetVariable( pName, pAttribute->GetValue< float >() );
|
|
}
|
|
}
|
|
|
|
float oldValue = m_result;
|
|
|
|
m_calc.Evaluate( oldValue );
|
|
|
|
m_result = oldValue;
|
|
|
|
if ( m_bSpewResult )
|
|
{
|
|
Msg( "%s = '%f'\n", GetName(), (float)m_result );
|
|
}
|
|
}
|
|
|
|
void CDmeExpressionOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
|
|
{
|
|
for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
|
|
{
|
|
if ( IsInputAttribute( pAttribute ) )
|
|
{
|
|
attrs.AddToTail( pAttribute );
|
|
}
|
|
}
|
|
|
|
attrs.AddToTail( m_expr.GetAttribute() );
|
|
}
|
|
|
|
void CDmeExpressionOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
|
|
{
|
|
attrs.AddToTail( m_result.GetAttribute() );
|
|
}
|
|
|
|
|
|
void CDmeExpressionOperator::SetSpewResult( bool state )
|
|
{
|
|
m_bSpewResult = state;
|
|
}
|