Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

942 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // The expression operator class - scalar math calculator
  4. // for a good list of operators and simple functions, see:
  5. // \\fileserver\user\MarcS\boxweb\aliveDistLite\v4.2.0\doc\alive\functions.txt
  6. // (although we'll want to implement elerp as the standard 3x^2 - 2x^3 with rescale)
  7. //
  8. //=============================================================================
  9. #include "movieobjects/dmeexpressionoperator.h"
  10. #include "movieobjects_interfaces.h"
  11. #include "datamodel/dmelementfactoryhelper.h"
  12. #include "datamodel/dmattribute.h"
  13. #include "mathlib/noise.h"
  14. #include "mathlib/vector.h"
  15. #include <ctype.h>
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. //-----------------------------------------------------------------------------
  19. // Parsing helper methods
  20. //-----------------------------------------------------------------------------
  21. bool ParseLiteral( const char *&expr, float &value )
  22. {
  23. const char *startExpr = expr;
  24. value = ( float )strtod( startExpr, const_cast< char** >( &expr ) );
  25. return ( startExpr != expr );
  26. }
  27. bool ParseString( const char *&expr, const char *str )
  28. {
  29. const char *startExpr = expr;
  30. while ( ( *expr == ' ' ) || ( *expr == '\t' ) )
  31. expr++; // skip whitespace
  32. expr = StringAfterPrefix( expr, str );
  33. if ( expr )
  34. return true;
  35. expr = startExpr;
  36. return false;
  37. }
  38. bool ParseStringList( const char *&expr, const char **pOps, int &nOp )
  39. {
  40. while ( nOp-- )
  41. {
  42. if ( ParseString( expr, pOps[ nOp ] ) )
  43. return true;
  44. }
  45. return false;
  46. }
  47. bool ParseStringList( const char *&expr, const CUtlVector< CUtlString > &strings, int &nOp )
  48. {
  49. while ( nOp-- )
  50. {
  51. if ( ParseString( expr, strings[ nOp ] ) )
  52. return true;
  53. }
  54. return false;
  55. }
  56. int FindString( const CUtlVector< CUtlString > &strings, const char *str )
  57. {
  58. uint sn = strings.Count();
  59. for ( uint si = 0; si < sn; ++si )
  60. {
  61. if ( !Q_strcmp( str, strings[ si ] ) )
  62. return si;
  63. }
  64. return -1;
  65. }
  66. class ParseState_t
  67. {
  68. public:
  69. ParseState_t( const CUtlStack<float> &stack, const char *expr )
  70. : m_stacksize( stack.Count() ), m_startingExpr( expr ) {}
  71. void Reset( CUtlStack<float> &stack, const char *&expr )
  72. {
  73. Assert( m_stacksize <= stack.Count() );
  74. stack.PopMultiple( stack.Count() - m_stacksize );
  75. expr = m_startingExpr;
  76. }
  77. private:
  78. int m_stacksize;
  79. const char* m_startingExpr;
  80. };
  81. void CExpressionCalculator::SetVariable( int nVariableIndex, float value )
  82. {
  83. m_varValues[ nVariableIndex ] = value;
  84. }
  85. void CExpressionCalculator::SetVariable( const char *var, float value )
  86. {
  87. int vi = FindString( m_varNames, var );
  88. if ( vi >= 0 )
  89. {
  90. m_varValues[ vi ] = value;
  91. }
  92. else
  93. {
  94. m_varNames.AddToTail( var );
  95. m_varValues.AddToTail( value );
  96. }
  97. }
  98. int CExpressionCalculator::FindVariableIndex( const char *var )
  99. {
  100. return FindString( m_varNames, var );
  101. }
  102. bool CExpressionCalculator::Evaluate( float &value )
  103. {
  104. m_bIsBuildingArgumentList = false;
  105. m_stack.PopMultiple( m_stack.Count() );
  106. const char *pExpr = m_expr.Get();
  107. bool success = ParseExpr( pExpr );
  108. if ( success && m_stack.Count() == 1 )
  109. {
  110. value = m_stack.Top();
  111. return true;
  112. }
  113. value = 0.0f;
  114. return false;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Builds a list of variable names from the expression
  118. //-----------------------------------------------------------------------------
  119. bool CExpressionCalculator::BuildVariableListFromExpression( )
  120. {
  121. m_bIsBuildingArgumentList = true;
  122. m_stack.PopMultiple( m_stack.Count() );
  123. const char *pExpr = m_expr.Get();
  124. bool bSuccess = ParseExpr( pExpr );
  125. m_bIsBuildingArgumentList = false;
  126. if ( !bSuccess || m_stack.Count() != 1 )
  127. {
  128. m_varNames.RemoveAll();
  129. return false;
  130. }
  131. return true;
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Iterate over variables
  135. //-----------------------------------------------------------------------------
  136. int CExpressionCalculator::VariableCount()
  137. {
  138. return m_varNames.Count();
  139. }
  140. const char *CExpressionCalculator::VariableName( int nIndex )
  141. {
  142. return m_varNames[nIndex];
  143. }
  144. bool CExpressionCalculator::ParseExpr( const char *&expr )
  145. {
  146. return ( expr != NULL ) && ParseConditional( expr );
  147. }
  148. bool CExpressionCalculator::ParseConditional( const char *&expr )
  149. {
  150. ParseState_t ps0( m_stack, expr );
  151. if ( !ParseOr( expr ) )
  152. {
  153. ps0.Reset( m_stack, expr );
  154. return false; // nothing matched
  155. }
  156. ParseState_t ps1( m_stack, expr );
  157. if ( ParseString( expr, "?" ) &&
  158. ParseExpr( expr ) &&
  159. ParseString( expr, ":" ) &&
  160. ParseExpr( expr ) )
  161. {
  162. float f3 = m_stack.Top();
  163. m_stack.Pop();
  164. float f2 = m_stack.Top();
  165. m_stack.Pop();
  166. float f1 = m_stack.Top();
  167. m_stack.Pop();
  168. m_stack.Push( f1 != 0.0f ? f2 : f3 );
  169. return true; // and matched
  170. }
  171. ps1.Reset( m_stack, expr );
  172. return true; // equality (or lower) matched
  173. }
  174. bool CExpressionCalculator::ParseOr( const char *&expr )
  175. {
  176. ParseState_t ps0( m_stack, expr );
  177. if ( !ParseAnd( expr ) )
  178. {
  179. ps0.Reset( m_stack, expr );
  180. return false; // nothing matched
  181. }
  182. ParseState_t ps1( m_stack, expr );
  183. if ( ParseString( expr, "||" ) &&
  184. ParseOr( expr ) )
  185. {
  186. float f2 = m_stack.Top();
  187. m_stack.Pop();
  188. float f1 = m_stack.Top();
  189. m_stack.Pop();
  190. m_stack.Push( ( f1 != 0.0f ) || ( f2 != 0.0f ) ? 1 : 0 );
  191. return true; // and matched
  192. }
  193. ps1.Reset( m_stack, expr );
  194. return true; // equality (or lower) matched
  195. }
  196. bool CExpressionCalculator::ParseAnd( const char *&expr )
  197. {
  198. ParseState_t ps0( m_stack, expr );
  199. if ( !ParseEquality( expr ) )
  200. {
  201. ps0.Reset( m_stack, expr );
  202. return false; // nothing matched
  203. }
  204. ParseState_t ps1( m_stack, expr );
  205. if ( ParseString( expr, "&&" ) &&
  206. ParseAnd( expr ) )
  207. {
  208. float f2 = m_stack.Top();
  209. m_stack.Pop();
  210. float f1 = m_stack.Top();
  211. m_stack.Pop();
  212. m_stack.Push( ( f1 != 0.0f ) && ( f2 != 0.0f ) ? 1 : 0 );
  213. return true; // and matched
  214. }
  215. ps1.Reset( m_stack, expr );
  216. return true; // equality (or lower) matched
  217. }
  218. bool CExpressionCalculator::ParseEquality( const char *&expr )
  219. {
  220. ParseState_t ps0( m_stack, expr );
  221. if ( !ParseLessGreater( expr ) )
  222. {
  223. ps0.Reset( m_stack, expr );
  224. return false; // nothing matched
  225. }
  226. const char *pOps[] = { "==", "!=" };
  227. int nOp = 2;
  228. ParseState_t ps1( m_stack, expr );
  229. if ( ParseStringList( expr, pOps, nOp ) &&
  230. ParseEquality( expr ) )
  231. {
  232. float f2 = m_stack.Top();
  233. m_stack.Pop();
  234. float f1 = m_stack.Top();
  235. m_stack.Pop();
  236. switch ( nOp )
  237. {
  238. case 0: // ==
  239. m_stack.Push( f1 == f2 ? 1 : 0 );
  240. break;
  241. case 1: // !=
  242. m_stack.Push( f1 != f2 ? 1 : 0 );
  243. break;
  244. }
  245. return true; // equality matched
  246. }
  247. ps1.Reset( m_stack, expr );
  248. return true; // lessgreater (or lower) matched
  249. }
  250. bool CExpressionCalculator::ParseLessGreater( const char *&expr )
  251. {
  252. ParseState_t ps0( m_stack, expr );
  253. if ( !ParseAddSub( expr ) )
  254. {
  255. ps0.Reset( m_stack, expr );
  256. return false; // nothing matched
  257. }
  258. const char *pOps[] = { "<", ">", "<=", ">=" };
  259. int nOp = 4;
  260. ParseState_t ps1( m_stack, expr );
  261. if ( ParseStringList( expr, pOps, nOp ) &&
  262. ParseLessGreater( expr ) )
  263. {
  264. float f2 = m_stack.Top();
  265. m_stack.Pop();
  266. float f1 = m_stack.Top();
  267. m_stack.Pop();
  268. switch ( nOp )
  269. {
  270. case 0: // <
  271. m_stack.Push( f1 < f2 ? 1 : 0 );
  272. break;
  273. case 1: // >
  274. m_stack.Push( f1 > f2 ? 1 : 0 );
  275. break;
  276. case 2: // <=
  277. m_stack.Push( f1 <= f2 ? 1 : 0 );
  278. break;
  279. case 3: // >=
  280. m_stack.Push( f1 >= f2 ? 1 : 0 );
  281. break;
  282. }
  283. return true; // inequality matched
  284. }
  285. ps1.Reset( m_stack, expr );
  286. return true; // addsub (or lower) matched
  287. }
  288. bool CExpressionCalculator::ParseAddSub( const char *&expr )
  289. {
  290. ParseState_t ps0( m_stack, expr );
  291. if ( !ParseDivMul( expr ) )
  292. {
  293. ps0.Reset( m_stack, expr );
  294. return false; // nothing matched
  295. }
  296. const char *pOps[] = { "+", "-" };
  297. int nOp = 2;
  298. ParseState_t ps1( m_stack, expr );
  299. if ( ParseStringList( expr, pOps, nOp ) &&
  300. ParseAddSub( expr ) )
  301. {
  302. float f2 = m_stack.Top();
  303. m_stack.Pop();
  304. float f1 = m_stack.Top();
  305. m_stack.Pop();
  306. switch ( nOp )
  307. {
  308. case 0: // +
  309. m_stack.Push( f1 + f2 );
  310. break;
  311. case 1: // -
  312. m_stack.Push( f1 - f2 );
  313. break;
  314. }
  315. return true; // addsub matched
  316. }
  317. ps1.Reset( m_stack, expr );
  318. return true; // divmul (or lower) matched
  319. }
  320. bool CExpressionCalculator::ParseDivMul( const char *&expr )
  321. {
  322. ParseState_t ps0( m_stack, expr );
  323. if ( !ParseUnary( expr ) )
  324. {
  325. ps0.Reset( m_stack, expr );
  326. return false; // nothing matched
  327. }
  328. const char *pOps[] = { "*", "/", "%" };
  329. int nOp = 3;
  330. ParseState_t ps1( m_stack, expr );
  331. if ( ParseStringList( expr, pOps, nOp ) &&
  332. ParseDivMul( expr ) )
  333. {
  334. float f2 = m_stack.Top();
  335. m_stack.Pop();
  336. float f1 = m_stack.Top();
  337. m_stack.Pop();
  338. switch ( nOp )
  339. {
  340. case 0: // *
  341. m_stack.Push( f1 * f2 );
  342. break;
  343. case 1: // /
  344. m_stack.Push( f1 / f2 );
  345. break;
  346. case 2: // %
  347. m_stack.Push( fmod( f1, f2 ) );
  348. break;
  349. }
  350. return true; // divmul matched
  351. }
  352. ps1.Reset( m_stack, expr );
  353. return true; // unary (or lower) matched
  354. }
  355. bool CExpressionCalculator::ParseUnary( const char *&expr )
  356. {
  357. ParseState_t ps( m_stack, expr );
  358. const char *pOps[] = { "+", "-", "!" };
  359. int nOp = 3;
  360. if ( ParseStringList( expr, pOps, nOp ) &&
  361. ParseUnary( expr ) )
  362. {
  363. float f1 = m_stack.Top();
  364. m_stack.Pop();
  365. switch ( nOp )
  366. {
  367. case 0: // +
  368. m_stack.Push( f1 );
  369. break;
  370. case 1: // -
  371. m_stack.Push( -f1 );
  372. break;
  373. case 2: // !
  374. m_stack.Push( f1 == 0 ? 1 : 0 );
  375. break;
  376. }
  377. return true;
  378. }
  379. ps.Reset( m_stack, expr );
  380. if ( ParsePrimary( expr ) )
  381. return true;
  382. ps.Reset( m_stack, expr );
  383. return false;
  384. }
  385. bool CExpressionCalculator::ParsePrimary( const char *&expr )
  386. {
  387. ParseState_t ps( m_stack, expr );
  388. float value = 0.0f;
  389. if ( ParseLiteral( expr, value ) )
  390. {
  391. m_stack.Push( value );
  392. return true;
  393. }
  394. ps.Reset( m_stack, expr );
  395. int nVar = m_varNames.Count();
  396. if ( ParseStringList( expr, m_varNames, nVar) )
  397. {
  398. m_stack.Push( m_varValues[ nVar ] );
  399. return true;
  400. }
  401. ps.Reset( m_stack, expr );
  402. if ( ParseString( expr, "(" ) &&
  403. ParseExpr( expr ) &&
  404. ParseString( expr, ")" ) )
  405. {
  406. return true;
  407. }
  408. ps.Reset( m_stack, expr );
  409. if ( Parse1ArgFunc( expr ) ||
  410. Parse2ArgFunc( expr ) ||
  411. Parse3ArgFunc( expr ) ||
  412. // Parse4ArgFunc( expr ) ||
  413. Parse5ArgFunc( expr ) )
  414. {
  415. return true;
  416. }
  417. // If we're parsing it to discover names of variable names, add them here
  418. if ( !m_bIsBuildingArgumentList )
  419. return false;
  420. // Variables can't start with a number
  421. if ( isdigit( *expr ) )
  422. return false;
  423. const char *pStart = expr;
  424. while ( isalnum( *expr ) || *expr == '_' )
  425. {
  426. ++expr;
  427. }
  428. int nLen = (size_t)expr - (size_t)pStart;
  429. char *pVariableName = (char*)_alloca( nLen+1 );
  430. memcpy( pVariableName, pStart, nLen );
  431. pVariableName[nLen] = 0;
  432. SetVariable( pVariableName, 0.0f );
  433. m_stack.Push( 0.0f );
  434. return true;
  435. }
  436. /*
  437. dtor(d) : converts degrees to radians
  438. rtod(r) : converts radians to degrees
  439. abs(a) : absolute value
  440. floor(a) : rounds down to the nearest integer
  441. ceiling(a) : rounds up to the nearest integer
  442. round(a) : rounds to the nearest integer
  443. sgn(a) : if a < 0 returns -1 else 1
  444. sqr(a) : returns a * a
  445. sqrt(a) : returns sqrt(a)
  446. sin(a) : sin(a), a is in degrees
  447. asin(a) : asin(a) returns degrees
  448. cos(a) : cos(a), a is in degrees
  449. acos(a) : acos(a) returns degrees
  450. tan(a) : tan(a), a is in degrees
  451. exp(a) : returns the exponential function of a
  452. log(a) : returns the natural logaritm of a
  453. */
  454. bool CExpressionCalculator::Parse1ArgFunc( const char *&expr )
  455. {
  456. ParseState_t ps( m_stack, expr );
  457. const char *pFuncs[] =
  458. {
  459. "abs", "sqr", "sqrt", "sin", "asin", "cos", "acos", "tan",
  460. "exp", "log", "dtor", "rtod", "floor", "ceiling", "round", "sign"
  461. };
  462. int nFunc = 16;
  463. if ( ParseStringList( expr, pFuncs, nFunc ) &&
  464. ParseString( expr, "(" ) &&
  465. ParseExpr( expr ) &&
  466. ParseString( expr, ")" ) )
  467. {
  468. float f1 = m_stack.Top();
  469. m_stack.Pop();
  470. switch ( nFunc )
  471. {
  472. case 0: // abs
  473. m_stack.Push( fabs( f1 ) );
  474. break;
  475. case 1: // sqr
  476. m_stack.Push( f1 * f1 );
  477. break;
  478. case 2: // sqrt
  479. m_stack.Push( sqrt( f1 ) );
  480. break;
  481. case 3: // sin
  482. m_stack.Push( sin( f1 ) );
  483. break;
  484. case 4: // asin
  485. m_stack.Push( asin( f1 ) );
  486. break;
  487. case 5: // cos
  488. m_stack.Push( cos( f1 ) );
  489. break;
  490. case 6: // acos
  491. m_stack.Push( acos( f1 ) );
  492. break;
  493. case 7: // tan
  494. m_stack.Push( tan( f1 ) );
  495. break;
  496. case 8: // exp
  497. m_stack.Push( exp( f1 ) );
  498. break;
  499. case 9: // log
  500. m_stack.Push( log( f1 ) );
  501. break;
  502. case 10: // dtor
  503. m_stack.Push( DEG2RAD( f1 ) );
  504. break;
  505. case 11: // rtod
  506. m_stack.Push( RAD2DEG( f1 ) );
  507. break;
  508. case 12: // floor
  509. m_stack.Push( floor( f1 ) );
  510. break;
  511. case 13: // ceiling
  512. m_stack.Push( ceil( f1 ) );
  513. break;
  514. case 14: // round
  515. m_stack.Push( floor( f1 + 0.5f ) );
  516. break;
  517. case 15: // sign
  518. m_stack.Push( f1 >= 0.0f ? 1.0f : -1.0f );
  519. break;
  520. }
  521. return true;
  522. }
  523. return false;
  524. }
  525. /*
  526. min(a,b) : if a<b returns a else b
  527. max(a,b) : if a>b returns a else b
  528. atan2(a,b) : atan2(a/b) returns degrees
  529. pow(a,b) : function returns a raised to the power of b
  530. */
  531. bool CExpressionCalculator::Parse2ArgFunc( const char *&expr )
  532. {
  533. ParseState_t ps( m_stack, expr );
  534. const char *pFuncs[] = { "min", "max", "atan2", "pow" };
  535. int nFunc = 4;
  536. if ( ParseStringList( expr, pFuncs, nFunc ) &&
  537. ParseString( expr, "(" ) &&
  538. ParseExpr( expr ) &&
  539. ParseString( expr, "," ) &&
  540. ParseExpr( expr ) &&
  541. ParseString( expr, ")" ) )
  542. {
  543. float f2 = m_stack.Top();
  544. m_stack.Pop();
  545. float f1 = m_stack.Top();
  546. m_stack.Pop();
  547. switch ( nFunc )
  548. {
  549. case 0: // min
  550. m_stack.Push( min( f1, f2 ) );
  551. break;
  552. case 1: // max
  553. m_stack.Push( max( f1, f2 ) );
  554. break;
  555. case 2: // atan2
  556. m_stack.Push( atan2( f1, f2 ) );
  557. break;
  558. case 3: // pow
  559. m_stack.Push( pow( f1, f2 ) );
  560. break;
  561. }
  562. return true;
  563. }
  564. return false;
  565. }
  566. /*
  567. inrange(x,a,b) : if x is between a and b, returns 1 else returns 0
  568. clamp(x,a,b) : see bound() above
  569. ramp(value,a,b) : returns 0 -> 1 as value goes from a to b
  570. lerp(factor,a,b) : returns a -> b as value goes from 0 to 1
  571. cramp(value,a,b) : clamp(ramp(value,a,b),0,1)
  572. clerp(factor,a,b) : clamp(lerp(factor,a,b),a,b)
  573. elerp(x,a,b) : ramp( 3*x*x - 2*x*x*x, a, b)
  574. //elerp(factor,a,b) : lerp(lerp(sind(clerp(factor,-90,90)),0.5,1.0),a,b)
  575. noise(a,b,c) : { solid noise pattern (improved perlin noise) indexed with three numbers }
  576. */
  577. float ramp( float x, float a, float b )
  578. {
  579. return ( x - a ) / ( b - a );
  580. }
  581. float lerp( float x, float a, float b )
  582. {
  583. return a + x * ( b - a );
  584. }
  585. float smoothstep( float x )
  586. {
  587. return 3*x*x - 2*x*x*x;
  588. }
  589. bool CExpressionCalculator::Parse3ArgFunc( const char *&expr )
  590. {
  591. ParseState_t ps( m_stack, expr );
  592. const char *pFuncs[] = { "inrange", "clamp", "ramp", "lerp", "cramp", "clerp", "elerp", "noise" };
  593. int nFunc = 8;
  594. if ( ParseStringList( expr, pFuncs, nFunc ) &&
  595. ParseString( expr, "(" ) &&
  596. ParseExpr( expr ) &&
  597. ParseString( expr, "," ) &&
  598. ParseExpr( expr ) &&
  599. ParseString( expr, "," ) &&
  600. ParseExpr( expr ) &&
  601. ParseString( expr, ")" ) )
  602. {
  603. float f3 = m_stack.Top();
  604. m_stack.Pop();
  605. float f2 = m_stack.Top();
  606. m_stack.Pop();
  607. float f1 = m_stack.Top();
  608. m_stack.Pop();
  609. switch ( nFunc )
  610. {
  611. case 0: // inrange
  612. m_stack.Push( ( f1 >= f2 ) && ( f1 <= f3 ) ? 1.0f : 0.0f );
  613. break;
  614. case 1: // clamp
  615. m_stack.Push( clamp( f1, f2, f3 ) );
  616. break;
  617. case 2: // ramp
  618. m_stack.Push( ramp( f1, f2, f3 ) );
  619. break;
  620. case 3: // lerp
  621. m_stack.Push( lerp( f1, f2, f3 ) );
  622. break;
  623. case 4: // cramp
  624. m_stack.Push( clamp( ramp( f1, f2, f3 ), 0, 1 ) );
  625. break;
  626. case 5: // clerp
  627. m_stack.Push( clamp( lerp( f1, f2, f3 ), f2, f3 ) );
  628. break;
  629. case 6: // elerp
  630. m_stack.Push( lerp( smoothstep( f1 ), f2, f3 ) );
  631. break;
  632. case 7: // noise
  633. m_stack.Push( ImprovedPerlinNoise( Vector( f1, f2, f3 ) ) );
  634. break;
  635. }
  636. return true;
  637. }
  638. return false;
  639. }
  640. //bool CExpressionCalculator::Parse4ArgFunc( const char *&expr );
  641. /*
  642. rescale (X,Xa,Xb,Ya,Yb) : lerp(ramp(X,Xa,Xb),Ya,Yb)
  643. crescale(X,Xa,Xb,Ya,Yb) : clamp(rescale(X,Xa,Xb,Ya,Yb),Ya,Yb)
  644. */
  645. float rescale( float x, float a, float b, float c, float d )
  646. {
  647. return lerp( ramp( x, a, b ), c, d );
  648. }
  649. bool CExpressionCalculator::Parse5ArgFunc( const char *&expr )
  650. {
  651. ParseState_t ps( m_stack, expr );
  652. const char *pFuncs[] = { "rescale", "crescale" };
  653. int nFunc = 2;
  654. if ( ParseStringList( expr, pFuncs, nFunc ) &&
  655. ParseString( expr, "(" ) &&
  656. ParseExpr( expr ) &&
  657. ParseString( expr, "," ) &&
  658. ParseExpr( expr ) &&
  659. ParseString( expr, "," ) &&
  660. ParseExpr( expr ) &&
  661. ParseString( expr, "," ) &&
  662. ParseExpr( expr ) &&
  663. ParseString( expr, "," ) &&
  664. ParseExpr( expr ) &&
  665. ParseString( expr, ")" ) )
  666. {
  667. float f5 = m_stack.Top();
  668. m_stack.Pop();
  669. float f4 = m_stack.Top();
  670. m_stack.Pop();
  671. float f3 = m_stack.Top();
  672. m_stack.Pop();
  673. float f2 = m_stack.Top();
  674. m_stack.Pop();
  675. float f1 = m_stack.Top();
  676. m_stack.Pop();
  677. switch ( nFunc )
  678. {
  679. case 0: // rescale
  680. m_stack.Push( rescale( f1, f2, f3, f4, f5 ) );
  681. break;
  682. case 1: // crescale
  683. m_stack.Push( clamp( rescale( f1, f2, f3, f4, f5 ), f4, f5 ) );
  684. break;
  685. }
  686. return true;
  687. }
  688. return false;
  689. }
  690. void TestCalculator( const char *expr, float answer )
  691. {
  692. CExpressionCalculator calc( expr );
  693. float result = 0.0f;
  694. #ifdef DBGFLAG_ASSERT
  695. bool success =
  696. #endif
  697. calc.Evaluate( result );
  698. Assert( success && ( result == answer ) );
  699. }
  700. void TestCalculator( const char *expr, float answer, const char *var, float value )
  701. {
  702. CExpressionCalculator calc( expr );
  703. calc.SetVariable( var, value );
  704. float result = 0.0f;
  705. #ifdef DBGFLAG_ASSERT
  706. bool success =
  707. #endif
  708. calc.Evaluate( result );
  709. Assert( success && ( result == answer ) );
  710. }
  711. void TestCalculator()
  712. {
  713. // TestCalculator( "-1", 1 );
  714. TestCalculator( "2 * 3 + 4", 10 );
  715. TestCalculator( "2 + 3 * 4", 14 );
  716. TestCalculator( "2 * 3 * 4", 24 );
  717. TestCalculator( "2 * -3 + 4", -2 );
  718. TestCalculator( "12.0 / 2.0", 6 );
  719. TestCalculator( "(2*3)+4", 10 );
  720. TestCalculator( "( 1 + 2 ) / (1+2)", 1 );
  721. TestCalculator( "(((5)))", 5 );
  722. TestCalculator( "--5", 5 );
  723. TestCalculator( "3.5 % 2", 1.5 );
  724. TestCalculator( "1e-2", 0.01 );
  725. TestCalculator( "9 == ( 3 * ( 1 + 2 ) )", 1 );
  726. TestCalculator( "9 != ( 3 * ( 1 + 2 ) )", 0 );
  727. TestCalculator( "9 <= ( 3 * ( 1 + 2 ) )", 1 );
  728. TestCalculator( "9 < ( 3 * ( 1 + 2 ) )", 0 );
  729. TestCalculator( "9 < 3", 0 );
  730. TestCalculator( "10 >= 5", 1 );
  731. // TestCalculator( "9 < ( 3 * ( 2 + 2 ) )", 0 );
  732. TestCalculator( "x + 1", 5, "x", 4 );
  733. TestCalculator( "pi - 3.14159", 0, "pi", 3.14159 );
  734. // TestCalculator( "pi / 2", 0, "pi", 3.14159 );
  735. TestCalculator( "abs(-10)", 10 );
  736. TestCalculator( "sqr(-5)", 25 );
  737. TestCalculator( "sqrt(9)", 3 );
  738. // TestCalculator( "sqrt(-9)", -3 );
  739. TestCalculator( "pow(2,3)", 8 );
  740. TestCalculator( "min(abs(-4),2+3/2)", 3.5 );
  741. TestCalculator( "round(0.5)", 1 );
  742. TestCalculator( "round(0.49)", 0 );
  743. TestCalculator( "round(-0.5)", 0 );
  744. TestCalculator( "round(-0.51)", -1 );
  745. TestCalculator( "inrange( 5, -8, 10 )", 1 );
  746. TestCalculator( "inrange( 5, 5, 10 )", 1 );
  747. TestCalculator( "inrange( 5, 6, 10 )", 0 );
  748. TestCalculator( "elerp( 1/4, 0, 1 )", 3/16.0f - 1/32.0f );
  749. TestCalculator( "rescale( 0.5, -1, 1, 0, 100 )", 75 );
  750. TestCalculator( "1 > 2 ? 6 : 9", 9 );
  751. TestCalculator( "1 ? 1 ? 2 : 4 : 1 ? 6 : 8", 2 );
  752. TestCalculator( "0 ? 1 ? 2 : 4 : 1 ? 6 : 8", 6 );
  753. TestCalculator( "noise( 0.123, 4.56, 78.9 )", ImprovedPerlinNoise( Vector( 0.123, 4.56, 78.9 ) ) );
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Expose this class to the scene database
  757. //-----------------------------------------------------------------------------
  758. IMPLEMENT_ELEMENT_FACTORY( DmeExpressionOperator, CDmeExpressionOperator );
  759. //-----------------------------------------------------------------------------
  760. // Purpose:
  761. //-----------------------------------------------------------------------------
  762. void CDmeExpressionOperator::OnConstruction()
  763. {
  764. m_result.Init( this, "result" );
  765. m_expr.Init( this, "expr" );
  766. m_bSpewResult.Init( this, "spewresult" );
  767. #ifdef _DEBUG
  768. TestCalculator();
  769. #endif _DEBUG
  770. }
  771. void CDmeExpressionOperator::OnDestruction()
  772. {
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Purpose:
  776. //-----------------------------------------------------------------------------
  777. bool CDmeExpressionOperator::IsInputAttribute( CDmAttribute *pAttribute )
  778. {
  779. const char *pName = pAttribute->GetName( );
  780. #if 0 // skip this test, since none of these are float attributes, but leave the code as a reminder
  781. if ( Q_strcmp( pName, "name" ) == 0 )
  782. return false;
  783. if ( Q_strcmp( pName, "expr" ) == 0 )
  784. return false;
  785. #endif
  786. if ( Q_strcmp( pName, "result" ) == 0 )
  787. return false;
  788. if ( pAttribute->GetType() != AT_FLOAT )
  789. return false;
  790. return true;
  791. }
  792. void CDmeExpressionOperator::Operate()
  793. {
  794. CExpressionCalculator calc( m_expr.Get() );
  795. for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  796. {
  797. if ( IsInputAttribute( pAttribute ) )
  798. {
  799. const char *pName = pAttribute->GetName( );
  800. calc.SetVariable( pName, pAttribute->GetValue< float >() );
  801. }
  802. }
  803. float oldValue = m_result;
  804. calc.Evaluate( oldValue );
  805. m_result = oldValue;
  806. if ( m_bSpewResult )
  807. {
  808. Msg( "%s = '%f'\n", GetName(), (float)m_result );
  809. }
  810. }
  811. void CDmeExpressionOperator::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs )
  812. {
  813. for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  814. {
  815. if ( IsInputAttribute( pAttribute ) )
  816. {
  817. attrs.AddToTail( pAttribute );
  818. }
  819. }
  820. attrs.AddToTail( m_expr.GetAttribute() );
  821. }
  822. void CDmeExpressionOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
  823. {
  824. attrs.AddToTail( m_result.GetAttribute() );
  825. }
  826. void CDmeExpressionOperator::SetSpewResult( bool state )
  827. {
  828. m_bSpewResult = state;
  829. }