376 lines
8.2 KiB
C++
Executable File
376 lines
8.2 KiB
C++
Executable File
/**
|
|
* projectM -- Milkdrop-esque visualisation SDK
|
|
* Copyright (C)2003-2004 projectM Team
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
* See 'LICENSE.txt' included within this release
|
|
*
|
|
*/
|
|
|
|
#include "wipemalloc.h"
|
|
|
|
#include "Expr.hpp"
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
#include "Eval.hpp"
|
|
|
|
float GenExpr::eval_gen_expr ( int mesh_i, int mesh_j )
|
|
{
|
|
float l;
|
|
|
|
assert ( item );
|
|
switch ( this->type )
|
|
{
|
|
case VAL_T:
|
|
return ( ( ValExpr* ) item )->eval_val_expr ( mesh_i, mesh_j );
|
|
case PREFUN_T:
|
|
l = ( ( PrefunExpr * ) item )->eval_prefun_expr ( mesh_i, mesh_j );
|
|
//if (EVAL_DEBUG) DWRITE( "eval_gen_expr: prefix function return value: %f\n", l);
|
|
return l;
|
|
case TREE_T:
|
|
return ( ( TreeExpr* ) ( item ) )->eval_tree_expr ( mesh_i, mesh_j );
|
|
default:
|
|
return EVAL_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
/* Evaluates functions in prefix form */
|
|
float PrefunExpr::eval_prefun_expr ( int mesh_i, int mesh_j )
|
|
{
|
|
|
|
|
|
assert ( func_ptr );
|
|
|
|
float * arg_list = new float[this->num_args];
|
|
|
|
assert(arg_list);
|
|
|
|
//printf("numargs %d", num_args);
|
|
|
|
/* Evaluate each argument before calling the function itself */
|
|
for ( int i = 0; i < num_args; i++ )
|
|
{
|
|
arg_list[i] = expr_list[i]->eval_gen_expr ( mesh_i, mesh_j );
|
|
//printf("numargs %x", arg_list[i]);
|
|
|
|
|
|
}
|
|
/* Now we call the function, passing a list of
|
|
floats as its argument */
|
|
|
|
const float value = ( func_ptr ) ( arg_list );
|
|
|
|
delete[](arg_list);
|
|
return value;
|
|
}
|
|
|
|
|
|
/* Evaluates a value expression */
|
|
float ValExpr::eval_val_expr ( int mesh_i, int mesh_j )
|
|
{
|
|
|
|
|
|
/* Value is a constant, return the float value */
|
|
if ( type == CONSTANT_TERM_T )
|
|
{
|
|
return ( term.constant );
|
|
}
|
|
|
|
/* Value is variable, dereference it */
|
|
if ( type == PARAM_TERM_T )
|
|
{
|
|
switch ( term.param->type )
|
|
{
|
|
|
|
case P_TYPE_BOOL:
|
|
|
|
|
|
return ( float ) ( * ( ( bool* ) ( term.param->engine_val ) ) );
|
|
case P_TYPE_INT:
|
|
|
|
|
|
return ( float ) ( * ( ( int* ) ( term.param->engine_val ) ) );
|
|
case P_TYPE_DOUBLE:
|
|
|
|
|
|
if ( term.param->matrix_flag | ( term.param->flags & P_FLAG_ALWAYS_MATRIX ) )
|
|
{
|
|
|
|
/* Sanity check the matrix is there... */
|
|
assert ( term.param->matrix != NULL );
|
|
|
|
/// @slow boolean check could be expensive in this critical (and common) step of evaluation
|
|
if ( mesh_i >= 0 )
|
|
{
|
|
if ( mesh_j >= 0 )
|
|
{
|
|
return ( ( ( float** ) term.param->matrix ) [mesh_i][mesh_j] );
|
|
}
|
|
else
|
|
{
|
|
return ( ( ( float* ) term.param->matrix ) [mesh_i] );
|
|
}
|
|
}
|
|
//assert(mesh_i >=0);
|
|
}
|
|
//std::cout << term.param->name << ": " << (*((float*)term.param->engine_val)) << std::endl;
|
|
return * ( ( float* ) ( term.param->engine_val ) );
|
|
default:
|
|
return EVAL_ERROR;
|
|
}
|
|
}
|
|
/* Unknown type, return failure */
|
|
return PROJECTM_FAILURE;
|
|
}
|
|
|
|
/* Evaluates an expression tree */
|
|
float TreeExpr::eval_tree_expr ( int mesh_i, int mesh_j )
|
|
{
|
|
|
|
float left_arg, right_arg;
|
|
|
|
/* A leaf node, evaluate the general expression. If the expression is null as well, return zero */
|
|
if ( infix_op == NULL )
|
|
{
|
|
if ( gen_expr == NULL )
|
|
return 0;
|
|
else
|
|
return gen_expr->eval_gen_expr ( mesh_i, mesh_j );
|
|
}
|
|
|
|
/* Otherwise, this node is an infix operator. Evaluate
|
|
accordingly */
|
|
|
|
assert(left);
|
|
left_arg = left->eval_tree_expr ( mesh_i, mesh_j );
|
|
|
|
assert(right);
|
|
right_arg = right->eval_tree_expr ( mesh_i, mesh_j );
|
|
|
|
|
|
switch ( infix_op->type )
|
|
{
|
|
case INFIX_ADD:
|
|
return ( left_arg + right_arg );
|
|
case INFIX_MINUS:
|
|
return ( left_arg - right_arg );
|
|
case INFIX_MULT:
|
|
return ( left_arg * right_arg );
|
|
case INFIX_MOD:
|
|
if ( ( int ) right_arg == 0 )
|
|
{
|
|
return PROJECTM_DIV_BY_ZERO;
|
|
}
|
|
return ( ( int ) left_arg % ( int ) right_arg );
|
|
case INFIX_OR:
|
|
return ( ( int ) left_arg | ( int ) right_arg );
|
|
case INFIX_AND:
|
|
return ( ( int ) left_arg & ( int ) right_arg );
|
|
case INFIX_DIV:
|
|
if ( right_arg == 0 )
|
|
{
|
|
return MAX_DOUBLE_SIZE;
|
|
}
|
|
return ( left_arg / right_arg );
|
|
default:
|
|
return EVAL_ERROR;
|
|
}
|
|
|
|
return EVAL_ERROR;
|
|
}
|
|
|
|
/* Converts a float value to a general expression */
|
|
GenExpr * GenExpr::const_to_expr ( float val )
|
|
{
|
|
|
|
GenExpr * gen_expr;
|
|
ValExpr * val_expr;
|
|
Term term;
|
|
|
|
term.constant = val;
|
|
|
|
if ( ( val_expr = new ValExpr ( CONSTANT_TERM_T, &term ) ) == NULL )
|
|
return NULL;
|
|
|
|
gen_expr = new GenExpr ( VAL_T, ( void* ) val_expr );
|
|
|
|
if ( gen_expr == NULL )
|
|
{
|
|
delete val_expr;
|
|
}
|
|
|
|
return gen_expr;
|
|
}
|
|
|
|
/* Converts a regular parameter to an expression */
|
|
GenExpr * GenExpr::param_to_expr ( Param * param )
|
|
{
|
|
|
|
GenExpr * gen_expr = NULL;
|
|
ValExpr * val_expr = NULL;
|
|
Term term;
|
|
|
|
if ( param == NULL )
|
|
return NULL;
|
|
|
|
/* This code is still a work in progress. We need
|
|
to figure out if the initial condition is used for
|
|
each per frame equation or not. I am guessing that
|
|
it isn't, and it is thusly implemented this way */
|
|
|
|
/* Current guess of true behavior (08/01/03) note from carm
|
|
First try to use the per_pixel_expr (with cloning)
|
|
If it is null however, use the engine variable instead. */
|
|
|
|
/* 08/20/03 : Presets are now objects, as well as per pixel equations. This ends up
|
|
making the parser handle the case where parameters are essentially per pixel equation
|
|
substitutions */
|
|
|
|
|
|
term.param = param;
|
|
if ( ( val_expr = new ValExpr ( PARAM_TERM_T, &term ) ) == NULL )
|
|
return NULL;
|
|
|
|
if ( ( gen_expr = new GenExpr ( VAL_T, ( void* ) val_expr ) ) == NULL )
|
|
{
|
|
delete val_expr;
|
|
return NULL;
|
|
}
|
|
return gen_expr;
|
|
}
|
|
|
|
/* Converts a prefix function to an expression */
|
|
GenExpr * GenExpr::prefun_to_expr ( float ( *func_ptr ) ( void * ), GenExpr ** expr_list, int num_args )
|
|
{
|
|
|
|
GenExpr * gen_expr;
|
|
PrefunExpr * prefun_expr;
|
|
|
|
prefun_expr = new PrefunExpr();
|
|
|
|
if ( prefun_expr == NULL )
|
|
return NULL;
|
|
|
|
prefun_expr->num_args = num_args;
|
|
prefun_expr->func_ptr = ( float ( * ) ( void* ) ) func_ptr;
|
|
prefun_expr->expr_list = expr_list;
|
|
|
|
gen_expr = new GenExpr ( PREFUN_T, ( void* ) prefun_expr );
|
|
|
|
if ( gen_expr == NULL )
|
|
delete prefun_expr;
|
|
|
|
return gen_expr;
|
|
}
|
|
|
|
/* Creates a new tree expression */
|
|
TreeExpr::TreeExpr ( InfixOp * _infix_op, GenExpr * _gen_expr, TreeExpr * _left, TreeExpr * _right ) :
|
|
infix_op ( _infix_op ), gen_expr ( _gen_expr ),
|
|
left ( _left ), right ( _right ) {}
|
|
|
|
|
|
/* Creates a new value expression */
|
|
ValExpr::ValExpr ( int _type, Term * _term ) :type ( _type )
|
|
{
|
|
|
|
|
|
//val_expr->type = _type;
|
|
term.constant = _term->constant;
|
|
term.param = _term->param;
|
|
|
|
//return val_expr;
|
|
}
|
|
|
|
/* Creates a new general expression */
|
|
|
|
GenExpr::GenExpr ( int _type, void * _item ) :type ( _type ), item ( _item ) {}
|
|
|
|
/* Frees a general expression */
|
|
GenExpr::~GenExpr()
|
|
{
|
|
|
|
switch ( type )
|
|
{
|
|
case VAL_T:
|
|
delete ( ( ValExpr* ) item );
|
|
break;
|
|
case PREFUN_T:
|
|
delete ( ( PrefunExpr* ) item );
|
|
break;
|
|
case TREE_T:
|
|
delete ( ( TreeExpr* ) item );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Frees a function in prefix notation */
|
|
PrefunExpr::~PrefunExpr()
|
|
{
|
|
|
|
int i;
|
|
|
|
/* Free every element in expression list */
|
|
for ( i = 0 ; i < num_args; i++ )
|
|
{
|
|
delete expr_list[i];
|
|
}
|
|
free ( expr_list );
|
|
}
|
|
|
|
/* Frees values of type VARIABLE and CONSTANT */
|
|
ValExpr::~ValExpr()
|
|
{}
|
|
|
|
/* Frees a tree expression */
|
|
TreeExpr::~TreeExpr()
|
|
{
|
|
|
|
/* free left tree */
|
|
if ( left != NULL )
|
|
{
|
|
delete left;
|
|
}
|
|
|
|
/* free general expression object */
|
|
if ( gen_expr != NULL )
|
|
{
|
|
delete gen_expr;
|
|
}
|
|
|
|
/* Note that infix operators are always
|
|
stored in memory unless the program
|
|
exits, so we don't remove them here */
|
|
|
|
/* free right tree */
|
|
if ( right != NULL )
|
|
{
|
|
delete right;
|
|
}
|
|
}
|
|
|
|
/* Initializes an infix operator */
|
|
InfixOp::InfixOp ( int type, int precedence )
|
|
{
|
|
|
|
this->type = type;
|
|
this->precedence = precedence;
|
|
}
|
|
|
|
|
|
|
|
PrefunExpr::PrefunExpr() {}
|