blob: 2f3efdf29144f713ea7a75cbd1ad29c0c29cd8ea [file] [log] [blame]
/**
* 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;
if (item == 0)
return EVAL_ERROR;
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() {}