| /** |
| * 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() {} |