mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-03-30 11:13:51 +00:00
Perf cleanup (#151)
* Param refactor collected all the code that reached inside Param (InitCond, Per*Eqn, Expr, Parser) to read/write and stuffed it all back into Param.cpp made Param extend Expr to avoid any perf penalty (I actually think eval() is a tiny bit faster now) * presets/tests * ALWAYS_MATRIX is used with PER_POINT * use SSE2 to impove initialize_PerPixelMeshes() performance * TestRunner very, very simple test framework, but it's better than no framework (consider investigating adopting something) * ProgramExpr
This commit is contained in:
18
presets/tests/100-square.milk
Executable file
18
presets/tests/100-square.milk
Executable file
@ -0,0 +1,18 @@
|
||||
[preset00]
|
||||
per_frame_1000=// just a double box
|
||||
per_frame_1001=//
|
||||
|
||||
fDecay=1
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=1
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=1.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
20
presets/tests/101-per_frame.milk
Executable file
20
presets/tests/101-per_frame.milk
Executable file
@ -0,0 +1,20 @@
|
||||
[preset00]
|
||||
per_frame_1000=// one per frame equation
|
||||
per_frame_1001=// varies outer frame color - red only
|
||||
|
||||
fDecay=0.98
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=0.0
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=1.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*sin(3*time);
|
||||
22
presets/tests/102-per_frame3.milk
Executable file
22
presets/tests/102-per_frame3.milk
Executable file
@ -0,0 +1,22 @@
|
||||
[preset00]
|
||||
per_frame_1000=// one per frame equation
|
||||
per_frame_1001=// varies outer frame color - multi-color
|
||||
|
||||
fDecay=0.98
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=0.0
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=0.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*sin(3*time);
|
||||
per_frame_2=ib_g=0.7+0.4*sin(4*time);
|
||||
per_frame_3=ib_b=0.7+0.4*sin(5*time);
|
||||
20
presets/tests/103-multiple-eqn.milk
Executable file
20
presets/tests/103-multiple-eqn.milk
Executable file
@ -0,0 +1,20 @@
|
||||
[preset00]
|
||||
per_frame_1000=// one per frame equation
|
||||
per_frame_1001=// test multiple equations one line
|
||||
|
||||
fDecay=0.98
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=0.0
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=0.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*sin(3*time); ib_g=0.7+0.4*sin(4*time); ib_b=0.7+0.4*sin(5*time);
|
||||
21
presets/tests/104-continued-eqn.milk
Executable file
21
presets/tests/104-continued-eqn.milk
Executable file
@ -0,0 +1,21 @@
|
||||
[preset00]
|
||||
per_frame_1000=// one per frame equation
|
||||
per_frame_1001=// test equation spanning two lines
|
||||
|
||||
fDecay=0.98
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=0.0
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=0.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*
|
||||
per_frame_2= sin(3*time);
|
||||
20
presets/tests/105-per_frame_init.milk
Executable file
20
presets/tests/105-per_frame_init.milk
Executable file
@ -0,0 +1,20 @@
|
||||
[preset00]
|
||||
per_frame_1000=// one per frame equation
|
||||
per_frame_1001=// initialize user variable
|
||||
|
||||
fDecay=0.98
|
||||
zoom=0
|
||||
rot=0.0
|
||||
warp=0.0
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.1
|
||||
ib_r=1.0
|
||||
ib_g=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_init_1=SPEED=10;
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*sin(time*SPEED);
|
||||
23
presets/tests/110-per_pixel.milk
Executable file
23
presets/tests/110-per_pixel.milk
Executable file
@ -0,0 +1,23 @@
|
||||
[preset00]
|
||||
fDecay=0.980000
|
||||
fWarpScale=2.853000
|
||||
fZoomExponent=1.000000
|
||||
warp=0.000000
|
||||
sx=1.000000
|
||||
sy=1.000000
|
||||
ob_size=0.2
|
||||
ob_r=0.0
|
||||
ob_g=0.0
|
||||
ob_b=0.0
|
||||
ob_a=0.0
|
||||
ib_size=0.01
|
||||
ib_r=1.0
|
||||
ib_g=0.0
|
||||
ib_b=0.0
|
||||
ib_a=1.0
|
||||
|
||||
per_frame_1=ib_r=0.7+0.4*sin(3*time);
|
||||
per_frame_2=ib_g=0.7+0.4*sin(4*time);
|
||||
per_frame_3=ib_b=0.7+0.4*sin(5*time);
|
||||
|
||||
per_pixel_1=zoom=0.9615-rad*0.1;
|
||||
20
presets/tests/200-wave.milk
Executable file
20
presets/tests/200-wave.milk
Executable file
@ -0,0 +1,20 @@
|
||||
[preset00]
|
||||
per_frame_1000=// simple wave to build
|
||||
per_frame_1001=//
|
||||
|
||||
fDecay=0.980000
|
||||
nWaveMode=0
|
||||
bMaximizeWaveColor=1
|
||||
fWaveAlpha=4.400000
|
||||
fWaveScale=1.605447
|
||||
fZoomExponent=1.000000
|
||||
zoom=1.000000
|
||||
rot=0.006000
|
||||
warp=0.000000
|
||||
sx=1.000000
|
||||
sy=1.000000
|
||||
wave_r=0.900000
|
||||
wave_g=0.90000
|
||||
wave_b=0.900000
|
||||
wave_x=0.500000
|
||||
wave_y=0.500000
|
||||
36
presets/tests/201-wavecode.milk
Executable file
36
presets/tests/201-wavecode.milk
Executable file
@ -0,0 +1,36 @@
|
||||
[preset00]
|
||||
per_frame_1000=// use wavecode
|
||||
per_frame_1001=// red circle with blue line
|
||||
|
||||
fDecay=0.980000
|
||||
nWaveMode=0
|
||||
bMaximizeWaveColor=1
|
||||
fWaveAlpha=4.400000
|
||||
fWaveScale=1.5
|
||||
fZoomExponent=1.000000
|
||||
zoom=1.000000
|
||||
rot=0.006000
|
||||
warp=0.000000
|
||||
sx=1.000000
|
||||
sy=1.000000
|
||||
wave_r=0.00000
|
||||
wave_g=0.0000
|
||||
wave_b=0.00000
|
||||
wave_a=0.00000
|
||||
wave_x=0.500000
|
||||
wave_y=0.5000000
|
||||
|
||||
wavecode_0_enabled=1
|
||||
wavecode_0_mode=0
|
||||
wavecode_0_bDrawThick=0
|
||||
wavecode_0_bAdditive=1
|
||||
wavecode_0_scaling=1.000000
|
||||
wavecode_0_smoothing=0.500000
|
||||
wavecode_0_r=0.000000
|
||||
wavecode_0_g=1.000000
|
||||
wavecode_0_b=1.000000
|
||||
wavecode_0_a=1.000000
|
||||
wave_0_per_point41=x=x+value1;
|
||||
wave_0_per_point42=y=y+value2;
|
||||
|
||||
per_frame_1=zoom=1
|
||||
1
presets/tests/README.md
Normal file
1
presets/tests/README.md
Normal file
@ -0,0 +1 @@
|
||||
These presets are designed to test very specific functionality to help with regression testing when code changes are made.
|
||||
@ -24,6 +24,7 @@ libprojectM_la_LIBADD = \
|
||||
libprojectM_la_SOURCES = ConfigFile.cpp Preset.cpp PresetLoader.cpp timer.cpp \
|
||||
KeyHandler.cpp PresetChooser.cpp TimeKeeper.cpp PCM.cpp PresetFactory.cpp \
|
||||
fftsg.cpp wipemalloc.cpp PipelineMerger.cpp PresetFactoryManager.cpp projectM.cpp \
|
||||
TestRunner.cpp TestRunner.hpp \
|
||||
Common.hpp PipelineMerger.hpp PresetLoader.hpp\
|
||||
HungarianMethod.hpp Preset.hpp RandomNumberGenerators.hpp\
|
||||
IdleTextures.hpp PresetChooser.hpp TimeKeeper.hpp\
|
||||
|
||||
@ -52,7 +52,7 @@ int BuiltinParams::load_builtin_param_float(const std::string & name, void * eng
|
||||
std::string lowerName(name);
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
|
||||
|
||||
if ((param = new Param(lowerName, P_TYPE_DOUBLE, flags, engine_val, matrix, iv, ub, lb)) == NULL)
|
||||
if ((param = Param::create(lowerName, P_TYPE_DOUBLE, flags, engine_val, matrix, iv, ub, lb)) == NULL)
|
||||
{
|
||||
return PROJECTM_OUTOFMEM_ERROR;
|
||||
}
|
||||
@ -171,7 +171,7 @@ int BuiltinParams::load_builtin_param_int(const std::string & name, void * engin
|
||||
std::string lowerName(name);
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
|
||||
|
||||
param = new Param(lowerName, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb);
|
||||
param = Param::create(lowerName, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb);
|
||||
|
||||
if (param == NULL)
|
||||
{
|
||||
@ -224,7 +224,7 @@ int BuiltinParams::load_builtin_param_bool(const std:: string & name, void * eng
|
||||
std::string lowerName(name);
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
|
||||
|
||||
param = new Param(lowerName, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb);
|
||||
param = Param::create(lowerName, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb);
|
||||
|
||||
if (param == NULL)
|
||||
{
|
||||
@ -397,7 +397,7 @@ int BuiltinParams::load_all_builtin_param(const PresetInputs & presetInputs, Pre
|
||||
for (unsigned int i = 0; i < NUM_Q_VARIABLES;i++) {
|
||||
std::ostringstream os;
|
||||
os << "q" << i;
|
||||
load_builtin_param_float(os.str().c_str(), (void*)&presetOutputs.q[i], NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, "");
|
||||
load_builtin_param_float(os.str().c_str(), (void*)&presetOutputs.q[i], NULL, P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, "");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,8 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
r(0),
|
||||
g(0),
|
||||
b(0),
|
||||
a(0)
|
||||
a(0),
|
||||
per_point_program(nullptr)
|
||||
{
|
||||
|
||||
Param * param;
|
||||
@ -308,7 +309,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((param = Param::new_param_float("t1", P_FLAG_PER_POINT | P_FLAG_TVAR, &this->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t1", P_FLAG_TVAR, &this->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
;
|
||||
abort();
|
||||
@ -320,7 +321,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((param = Param::new_param_float("t2", P_FLAG_PER_POINT |P_FLAG_TVAR, &this->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t2", P_FLAG_TVAR, &this->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
;
|
||||
abort();
|
||||
@ -331,7 +332,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((param = Param::new_param_float("t3", P_FLAG_PER_POINT |P_FLAG_TVAR, &this->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t3", P_FLAG_TVAR, &this->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
@ -341,7 +342,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
|
||||
abort();
|
||||
}
|
||||
if ((param = Param::new_param_float("t4", P_FLAG_PER_POINT |P_FLAG_TVAR, &this->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t4", P_FLAG_TVAR, &this->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
|
||||
abort();
|
||||
@ -361,7 +362,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((param = Param::new_param_float("t6", P_FLAG_TVAR | P_FLAG_PER_POINT, &this->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t6", P_FLAG_TVAR, &this->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
@ -371,7 +372,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
|
||||
abort();
|
||||
}
|
||||
if ((param = Param::new_param_float("t7", P_FLAG_TVAR | P_FLAG_PER_POINT, &this->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t7", P_FLAG_TVAR, &this->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
|
||||
abort();
|
||||
@ -383,7 +384,7 @@ CustomWave::CustomWave(int _id) : Waveform(512),
|
||||
abort();
|
||||
}
|
||||
|
||||
if ((param = Param::new_param_float("t8", P_FLAG_TVAR | P_FLAG_PER_POINT, &this->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
if ((param = Param::new_param_float("t8", P_FLAG_TVAR, &this->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||||
{
|
||||
;
|
||||
abort();
|
||||
@ -471,10 +472,10 @@ int CustomWave::add_per_point_eqn(char * name, Expr * gen_expr)
|
||||
index = per_point_eqn_tree.size();
|
||||
|
||||
/* Create the per point equation given the index, parameter, and general expression */
|
||||
if ((per_point_eqn = new PerPointEqn(index, param, gen_expr, samples)) == NULL)
|
||||
if ((per_point_eqn = new PerPointEqn(index, param, gen_expr)) == NULL)
|
||||
return PROJECTM_FAILURE;
|
||||
if (CUSTOM_WAVE_DEBUG)
|
||||
printf("add_per_point_eqn: created new equation (index = %d) (name = \"%s\")\n", per_point_eqn->index, per_point_eqn->param->name.c_str());
|
||||
printf("add_per_point_eqn: created new equation (index = %d) (name = \"%s\")\n", per_point_eqn->index, param->name.c_str());
|
||||
|
||||
/* Insert the per pixel equation into the preset per pixel database */
|
||||
|
||||
@ -498,18 +499,28 @@ void CustomWave::evalInitConds()
|
||||
|
||||
ColoredPoint CustomWave::PerPoint(ColoredPoint p, const WaveformContext context)
|
||||
{
|
||||
r_mesh[context.sample_int] = r;
|
||||
g_mesh[context.sample_int] = g;
|
||||
b_mesh[context.sample_int] = b;
|
||||
a_mesh[context.sample_int] = a;
|
||||
x_mesh[context.sample_int] = x;
|
||||
y_mesh[context.sample_int] = y;
|
||||
sample = context.sample;
|
||||
v1 = context.left;
|
||||
v2 = context.right;
|
||||
if (nullptr == per_point_program)
|
||||
{
|
||||
// see comment in MilkdropPreset, collect a list of assignments into one ProgramExpr
|
||||
// which (theoretically) could be compiled together.
|
||||
std::vector<Expr *> steps;
|
||||
for (auto pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end();++pos)
|
||||
steps.push_back((*pos)->assign_expr);
|
||||
per_point_program = new ProgramExpr(steps, false);
|
||||
}
|
||||
|
||||
for (std::vector<PerPointEqn*>::iterator pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end();++pos)
|
||||
(*pos)->evaluate(context.sample_int);
|
||||
|
||||
r_mesh[context.sample_int] = r;
|
||||
g_mesh[context.sample_int] = g;
|
||||
b_mesh[context.sample_int] = b;
|
||||
a_mesh[context.sample_int] = a;
|
||||
x_mesh[context.sample_int] = x;
|
||||
y_mesh[context.sample_int] = y;
|
||||
sample = context.sample;
|
||||
v1 = context.left;
|
||||
v2 = context.right;
|
||||
|
||||
per_point_program->eval(context.sample_int, -1);
|
||||
|
||||
p.a = a_mesh[context.sample_int];
|
||||
p.r = r_mesh[context.sample_int];
|
||||
|
||||
@ -105,6 +105,7 @@ public:
|
||||
std::map<std::string,InitCond*> init_cond_tree;
|
||||
std::vector<PerFrameEqn*> per_frame_eqn_tree;
|
||||
std::vector<PerPointEqn*> per_point_eqn_tree;
|
||||
Expr *per_point_program;
|
||||
std::map<std::string,InitCond*> per_frame_init_eqn_tree;
|
||||
|
||||
/* Denotes the index of the last character for each string buffer */
|
||||
|
||||
@ -47,18 +47,20 @@ InfixOp *Eval::infix_positive = NULL;
|
||||
/* Initializes all infix operators */
|
||||
int Eval::init_infix_ops() {
|
||||
|
||||
Eval::infix_add = new InfixOp(INFIX_ADD, 4);
|
||||
Eval::infix_minus = new InfixOp(INFIX_MINUS, 3);
|
||||
Eval::infix_div = new InfixOp(INFIX_DIV, 2);
|
||||
Eval::infix_or = new InfixOp(INFIX_OR, 5);
|
||||
Eval::infix_and = new InfixOp(INFIX_AND,4);
|
||||
Eval::infix_mod = new InfixOp(INFIX_MOD, 1);
|
||||
Eval::infix_mult = new InfixOp(INFIX_MULT, 2);
|
||||
|
||||
/* Prefix operators */
|
||||
Eval::infix_positive = new InfixOp(INFIX_ADD, 0);
|
||||
Eval::infix_negative = new InfixOp(INFIX_MINUS, 0);
|
||||
if (nullptr == Eval::infix_add)
|
||||
{
|
||||
Eval::infix_add = new InfixOp(INFIX_ADD, 4);
|
||||
Eval::infix_minus = new InfixOp(INFIX_MINUS, 3);
|
||||
Eval::infix_div = new InfixOp(INFIX_DIV, 2);
|
||||
Eval::infix_or = new InfixOp(INFIX_OR, 5);
|
||||
Eval::infix_and = new InfixOp(INFIX_AND, 4);
|
||||
Eval::infix_mod = new InfixOp(INFIX_MOD, 1);
|
||||
Eval::infix_mult = new InfixOp(INFIX_MULT, 2);
|
||||
|
||||
/* Prefix operators */
|
||||
Eval::infix_positive = new InfixOp(INFIX_ADD, 0);
|
||||
Eval::infix_negative = new InfixOp(INFIX_MINUS, 0);
|
||||
}
|
||||
return PROJECTM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "Eval.hpp"
|
||||
#include "BuiltinFuncs.hpp"
|
||||
|
||||
|
||||
/* Evaluates functions in prefix form */
|
||||
@ -77,6 +78,42 @@ class PrefunExprOne : public PrefunExpr
|
||||
}
|
||||
};
|
||||
|
||||
class SinExpr : public PrefunExpr
|
||||
{
|
||||
float eval ( int mesh_i, int mesh_j ) override
|
||||
{
|
||||
float val = expr_list[0]->eval ( mesh_i, mesh_j );
|
||||
return sinf(val);
|
||||
}
|
||||
};
|
||||
|
||||
class CosExpr : public PrefunExpr
|
||||
{
|
||||
float eval ( int mesh_i, int mesh_j ) override
|
||||
{
|
||||
float val = expr_list[0]->eval ( mesh_i, mesh_j );
|
||||
return cosf(val);
|
||||
}
|
||||
};
|
||||
|
||||
class LogExpr : public PrefunExpr
|
||||
{
|
||||
float eval ( int mesh_i, int mesh_j ) override
|
||||
{
|
||||
float val = expr_list[0]->eval ( mesh_i, mesh_j );
|
||||
return logf(val);
|
||||
}
|
||||
};
|
||||
|
||||
class PowExpr : public PrefunExpr
|
||||
{
|
||||
float eval ( int mesh_i, int mesh_j ) override
|
||||
{
|
||||
float x = expr_list[0]->eval ( mesh_i, mesh_j );
|
||||
float y = expr_list[1]->eval ( mesh_i, mesh_j );
|
||||
return powf(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
class ConstantExpr : public Expr
|
||||
{
|
||||
@ -98,79 +135,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ParameterExpr : public Expr
|
||||
{
|
||||
protected:
|
||||
Term term;
|
||||
public:
|
||||
ParameterExpr( int _type, Term *_term ) : Expr(PARAMETER), term(*_term) {}
|
||||
float eval(int mesh_i, int mesh_j ) = 0;
|
||||
std::ostream& to_string(std::ostream& out)
|
||||
{
|
||||
out << term.param->name;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
class BoolParameterExpr : public ParameterExpr
|
||||
{
|
||||
public:
|
||||
BoolParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
|
||||
float eval ( int mesh_i, int mesh_j )
|
||||
{
|
||||
assert( term.param->type == P_TYPE_BOOL );
|
||||
return ( float ) ( * ( ( bool* ) ( term.param->engine_val ) ) );
|
||||
}
|
||||
};
|
||||
class IntParameterExpr : public ParameterExpr
|
||||
{
|
||||
public:
|
||||
IntParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
|
||||
float eval ( int mesh_i, int mesh_j )
|
||||
{
|
||||
assert( term.param->type == P_TYPE_INT );
|
||||
return ( float ) ( * ( ( int* ) ( term.param->engine_val ) ) );
|
||||
}
|
||||
};
|
||||
class FloatParameterExpr : public ParameterExpr
|
||||
{
|
||||
public:
|
||||
FloatParameterExpr( int _type, Term *_term ) : ParameterExpr(_type,_term) {}
|
||||
float eval ( int mesh_i, int mesh_j );
|
||||
};
|
||||
/* TODO optimize FloatParameterExpr::eval() further.
|
||||
// - flag "never matrix" parameters
|
||||
// - always pass in 2d matrix. instead of using (i, -1) for 1d matrix, we could just use (0, i) and avoid check
|
||||
// - instead of using matrix_flag to give "copy on write" behavior, maybe pre-copy from engine_val to matrix[]
|
||||
*/
|
||||
float FloatParameterExpr::eval ( int mesh_i, int mesh_j )
|
||||
{
|
||||
assert( term.param->type == 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
|
||||
{
|
||||
// issue 64, make sure we're not reading a P_FLAG_PER_PIXEL matrix variable
|
||||
if (!(term.param->flags & P_FLAG_PER_PIXEL))
|
||||
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 ) );
|
||||
}
|
||||
|
||||
|
||||
class MultAndAddExpr : public Expr
|
||||
{
|
||||
@ -180,25 +144,50 @@ public:
|
||||
a(_a), b(_b), c(_c)
|
||||
{
|
||||
}
|
||||
~MultAndAddExpr() {
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
~MultAndAddExpr() override {
|
||||
Expr::delete_expr(a);
|
||||
Expr::delete_expr(b);
|
||||
Expr::delete_expr(c);
|
||||
}
|
||||
float eval(int mesh_i, int mesh_j)
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
float a_value = a->eval(mesh_i,mesh_j);
|
||||
float b_value = b->eval(mesh_i,mesh_j);
|
||||
float c_value = c->eval(mesh_i,mesh_j);
|
||||
return a_value * b_value + c_value;
|
||||
}
|
||||
std::ostream &to_string(std::ostream &out)
|
||||
std::ostream &to_string(std::ostream &out) override
|
||||
{
|
||||
out << "(" << a << " * " << b << ") + " << c;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
class MultConstExpr : public Expr
|
||||
{
|
||||
Expr *expr;
|
||||
float c;
|
||||
public:
|
||||
MultConstExpr(Expr *_expr, float _c) : Expr(OTHER),
|
||||
expr(_expr), c(_c)
|
||||
{
|
||||
}
|
||||
~MultConstExpr() override
|
||||
{
|
||||
Expr::delete_expr(expr);
|
||||
}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
float value = expr->eval(mesh_i,mesh_j);
|
||||
return value * c;
|
||||
}
|
||||
std::ostream &to_string(std::ostream &out) override
|
||||
{
|
||||
out << "(" << expr << " * " << c << ") + " << c;
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream &TreeExpr::to_string(std::ostream &out)
|
||||
{
|
||||
if (NULL == infix_op)
|
||||
@ -232,31 +221,31 @@ std::ostream &TreeExpr::to_string(std::ostream &out)
|
||||
return out;
|
||||
}
|
||||
|
||||
/* NOTE: Parser.cpp directly manipulates TreeExpr, so it is easier to optimizer AFTER parsing
|
||||
/* NOTE: Parser.cpp directly manipulates TreeExpr, so it is easier to _optimizer AFTER parsing
|
||||
* than while building up the tree initially
|
||||
*/
|
||||
Expr *TreeExpr::optimize()
|
||||
Expr *TreeExpr::_optimize()
|
||||
{
|
||||
if (infix_op == NULL)
|
||||
{
|
||||
Expr *opt = gen_expr->optimize();
|
||||
Expr *opt = gen_expr->_optimize();
|
||||
if (opt != gen_expr)
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
gen_expr = NULL;
|
||||
return opt;
|
||||
}
|
||||
if (left != NULL)
|
||||
{
|
||||
Expr *l = left->optimize();
|
||||
Expr *l = left->_optimize();
|
||||
if (l != left)
|
||||
delete left;
|
||||
Expr::delete_expr(left);
|
||||
left = l;
|
||||
}
|
||||
if (right != NULL)
|
||||
{
|
||||
Expr *r = right->optimize();
|
||||
Expr *r = right->_optimize();
|
||||
if (r != right)
|
||||
delete right;
|
||||
Expr::delete_expr(right);
|
||||
right = r;
|
||||
}
|
||||
if (left == NULL)
|
||||
@ -281,25 +270,26 @@ Expr *TreeExpr::optimize()
|
||||
{
|
||||
Expr *a, *b, *c;
|
||||
if (left->clazz == TREE && ((TreeExpr *)left)->infix_op->type == INFIX_MULT)
|
||||
{
|
||||
a = ((TreeExpr *)left)->left;
|
||||
b = ((TreeExpr *)left)->right;
|
||||
c = right;
|
||||
((TreeExpr *)left)->left = NULL;
|
||||
((TreeExpr *)left)->right = NULL;
|
||||
right = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = ((TreeExpr *)right)->left;
|
||||
b = ((TreeExpr *)right)->right;
|
||||
c = left;
|
||||
((TreeExpr *)right)->left = NULL;
|
||||
((TreeExpr *)right)->right = NULL;
|
||||
left = NULL;
|
||||
}
|
||||
std::swap(left,right);
|
||||
a = ((TreeExpr *)right)->left;
|
||||
b = ((TreeExpr *)right)->right;
|
||||
c = left;
|
||||
((TreeExpr *)right)->left = NULL;
|
||||
((TreeExpr *)right)->right = NULL;
|
||||
left = NULL;
|
||||
return new MultAndAddExpr(a,b,c);
|
||||
}
|
||||
|
||||
if (infix_op->type == INFIX_MULT && (left->isConstant() || right->isConstant()))
|
||||
{
|
||||
if (right->isConstant())
|
||||
std::swap(left, right);
|
||||
float c = left->eval(-1,-1);
|
||||
Expr *expr = right;
|
||||
right = left = nullptr;
|
||||
return new MultConstExpr(expr, c);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -308,7 +298,7 @@ float TreeExpr::eval ( int mesh_i, int mesh_j )
|
||||
{
|
||||
float left_arg, right_arg;
|
||||
|
||||
/* shouldn't be null if we've called optimize() */
|
||||
/* shouldn't be null if we've called _optimize() */
|
||||
assert(NULL != infix_op);
|
||||
|
||||
left_arg = left->eval ( mesh_i, mesh_j );
|
||||
@ -356,46 +346,52 @@ Expr * Expr::const_to_expr ( float val )
|
||||
/* Converts a regular parameter to an expression */
|
||||
Expr * Expr::param_to_expr ( Param * param )
|
||||
{
|
||||
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;
|
||||
|
||||
switch ( param->type )
|
||||
{
|
||||
case P_TYPE_BOOL:
|
||||
return new BoolParameterExpr( PARAM_TERM_T, &term );
|
||||
return param->getExpr();
|
||||
//return new BoolParameterExpr( PARAM_TERM_T, &term );
|
||||
case P_TYPE_INT:
|
||||
return new IntParameterExpr( PARAM_TERM_T, &term );
|
||||
return param->getExpr();
|
||||
//return new IntParameterExpr( PARAM_TERM_T, &term );
|
||||
case P_TYPE_DOUBLE:
|
||||
return new FloatParameterExpr( PARAM_TERM_T, &term );
|
||||
return param->getExpr();
|
||||
//return new FloatParameterExpr( PARAM_TERM_T, &term );
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Converts a prefix function to an expression */
|
||||
Expr * Expr::prefun_to_expr ( float ( *func_ptr ) ( void * ), Expr ** expr_list, int num_args )
|
||||
{
|
||||
PrefunExpr * prefun_expr;
|
||||
if (num_args == 1)
|
||||
prefun_expr = new PrefunExprOne();
|
||||
else
|
||||
prefun_expr = new PrefunExpr();
|
||||
PrefunExpr *prefun_expr;
|
||||
if (num_args == 1)
|
||||
{
|
||||
if (func_ptr == (float (*)(void *)) FuncWrappers::sin_wrapper)
|
||||
prefun_expr = new SinExpr();
|
||||
else if (func_ptr == (float (*)(void *)) FuncWrappers::cos_wrapper)
|
||||
prefun_expr = new CosExpr();
|
||||
else if (func_ptr == (float (*)(void *)) FuncWrappers::log_wrapper)
|
||||
prefun_expr = new LogExpr();
|
||||
else
|
||||
prefun_expr = new PrefunExprOne();
|
||||
}
|
||||
else if (num_args == 2)
|
||||
{
|
||||
if (func_ptr == (float (*)(void *)) FuncWrappers::pow_wrapper)
|
||||
prefun_expr = new PowExpr();
|
||||
else
|
||||
prefun_expr = new PrefunExpr();
|
||||
}
|
||||
else
|
||||
{
|
||||
prefun_expr = new PrefunExpr();
|
||||
}
|
||||
|
||||
prefun_expr->num_args = num_args;
|
||||
prefun_expr->func_ptr = ( float ( * ) ( void* ) ) func_ptr;
|
||||
prefun_expr->expr_list = expr_list;
|
||||
@ -463,7 +459,7 @@ PrefunExpr::~PrefunExpr()
|
||||
/* Free every element in expression list */
|
||||
for ( i = 0 ; i < num_args; i++ )
|
||||
{
|
||||
delete expr_list[i];
|
||||
Expr::delete_expr(expr_list[i]);
|
||||
}
|
||||
free ( expr_list );
|
||||
}
|
||||
@ -475,13 +471,13 @@ TreeExpr::~TreeExpr()
|
||||
/* free left tree */
|
||||
if ( left != NULL )
|
||||
{
|
||||
delete left;
|
||||
Expr::delete_expr(left);
|
||||
}
|
||||
|
||||
/* free general expression object */
|
||||
if ( gen_expr != NULL )
|
||||
{
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
}
|
||||
|
||||
/* Note that infix operators are always
|
||||
@ -491,7 +487,7 @@ TreeExpr::~TreeExpr()
|
||||
/* free right tree */
|
||||
if ( right != NULL )
|
||||
{
|
||||
delete right;
|
||||
Expr::delete_expr(right);
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,18 +502,27 @@ PrefunExpr::PrefunExpr() : Expr(FUNCTION)
|
||||
{
|
||||
}
|
||||
|
||||
Expr *PrefunExpr::optimize()
|
||||
bool isConstantFn(float (* fn)(void*))
|
||||
{
|
||||
return (float (*)(float *))fn != FuncWrappers::print_wrapper &&
|
||||
(float (*)(float *))fn != FuncWrappers::rand_wrapper;
|
||||
}
|
||||
|
||||
Expr *PrefunExpr::_optimize()
|
||||
{
|
||||
bool constant_args = true;
|
||||
for (int i=0 ; i < num_args ; i++)
|
||||
{
|
||||
Expr *orig = expr_list[i];
|
||||
expr_list[i] = orig->optimize();
|
||||
expr_list[i] = orig->_optimize();
|
||||
if (orig != expr_list[i])
|
||||
delete orig;
|
||||
constant_args &= expr_list[i]->isConstant();
|
||||
Expr::delete_expr(orig);
|
||||
constant_args = constant_args && expr_list[i]->isConstant();
|
||||
}
|
||||
// TODO most functions can be pre-evaluated if inputs are constant, but not all
|
||||
if (constant_args && isConstantFn(func_ptr))
|
||||
{
|
||||
return Expr::const_to_expr(eval(-1, -1));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -534,3 +539,127 @@ std::ostream& PrefunExpr::to_string(std::ostream& out)
|
||||
out << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
AssignExpr::AssignExpr(LValue *lhs_, Expr *rhs_) : Expr(ASSIGN), lhs(lhs_), rhs(rhs_) {}
|
||||
|
||||
AssignExpr::~AssignExpr()
|
||||
{
|
||||
Expr::delete_expr(lhs);
|
||||
Expr::delete_expr(rhs);
|
||||
}
|
||||
|
||||
Expr * AssignExpr::_optimize()
|
||||
{
|
||||
Expr *t = rhs->_optimize();
|
||||
if (t != rhs)
|
||||
Expr::delete_expr(rhs);
|
||||
rhs = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
float AssignExpr::eval(int mesh_i, int mesh_j)
|
||||
{
|
||||
float v = rhs->eval( mesh_i, mesh_j );
|
||||
lhs->set( v );
|
||||
return v;
|
||||
}
|
||||
|
||||
std::ostream& AssignExpr::to_string(std::ostream &out)
|
||||
{
|
||||
out << lhs << " = " << rhs;
|
||||
return out;
|
||||
}
|
||||
|
||||
AssignMatrixExpr::AssignMatrixExpr(LValue *lhs_, Expr *rhs_) : AssignExpr(lhs_, rhs_) {}
|
||||
|
||||
float AssignMatrixExpr::eval(int mesh_i, int mesh_j)
|
||||
{
|
||||
float v = rhs->eval( mesh_i, mesh_j );
|
||||
lhs->set_matrix( mesh_i, mesh_j, v );
|
||||
return v;
|
||||
}
|
||||
|
||||
std::ostream& AssignMatrixExpr::to_string(std::ostream &out)
|
||||
{
|
||||
out << lhs << "[i,j] = " << rhs;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TESTS
|
||||
|
||||
|
||||
#include <TestRunner.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#define TEST(cond) if (!verify(#cond,cond)) return false
|
||||
|
||||
|
||||
struct ExprTest : public Test
|
||||
{
|
||||
ExprTest() : Test("ExprTest")
|
||||
{}
|
||||
|
||||
public:
|
||||
bool optimize_constant_expr()
|
||||
{
|
||||
TreeExpr *a = TreeExpr::create(nullptr, Expr::const_to_expr( 1.0 ), nullptr, nullptr);
|
||||
TreeExpr *b = TreeExpr::create(nullptr, Expr::const_to_expr( 2.0 ), nullptr, nullptr);
|
||||
Expr *c = TreeExpr::create(Eval::infix_add, nullptr, a, b);
|
||||
//TEST(3.0f == c->eval(-1,-1));
|
||||
Expr *x = Expr::optimize(c);
|
||||
TEST(x != c);
|
||||
Expr::delete_expr(c);
|
||||
TEST(x->clazz == CONSTANT);
|
||||
TEST(3.0f == x->eval(-1,-1));
|
||||
Expr::delete_expr(x);
|
||||
|
||||
Expr **expr_array = (Expr **)malloc(sizeof(Expr *));
|
||||
expr_array[0] = TreeExpr::create(nullptr, Expr::const_to_expr( (float)M_PI ), nullptr, nullptr);
|
||||
Expr *sin = Expr::prefun_to_expr((float (*)(void *))FuncWrappers::sin_wrapper, expr_array, 1);
|
||||
x = Expr::optimize(sin);
|
||||
TEST(x != sin);
|
||||
Expr::delete_expr( sin );
|
||||
TEST(x->clazz == CONSTANT);
|
||||
TEST(sinf( (float)M_PI ) == x->eval(-1,-10));
|
||||
Expr::delete_expr(x);
|
||||
|
||||
// make sure rand() is not optimized away
|
||||
expr_array = (Expr **)malloc(sizeof(Expr *));
|
||||
expr_array[0] = TreeExpr::create(nullptr, Expr::const_to_expr( (float)M_PI ), nullptr, nullptr);
|
||||
Expr *rand = Expr::prefun_to_expr((float (*)(void *))FuncWrappers::rand_wrapper, expr_array, 1);
|
||||
x = Expr::optimize(rand);
|
||||
TEST(x == rand);
|
||||
TEST(x->clazz != CONSTANT);
|
||||
Expr::delete_expr(x);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test() override
|
||||
{
|
||||
Eval::init_infix_ops();
|
||||
bool result = true;
|
||||
result &= optimize_constant_expr();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Test* Expr::test()
|
||||
{
|
||||
return new ExprTest();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Test* Expr::test()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -31,8 +31,10 @@
|
||||
|
||||
#include "dlldefs.h"
|
||||
#include "CValue.hpp"
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
class Test;
|
||||
class Param;
|
||||
|
||||
#define CONST_STACK_ELEMENT 0
|
||||
@ -63,7 +65,7 @@ public:
|
||||
|
||||
enum ExprClass
|
||||
{
|
||||
TREE, CONSTANT, PARAMETER, FUNCTION, OTHER
|
||||
TREE, CONSTANT, PARAMETER, FUNCTION, ASSIGN, PROGRAM, OTHER
|
||||
};
|
||||
|
||||
class Expr
|
||||
@ -72,7 +74,7 @@ public:
|
||||
ExprClass clazz;
|
||||
Expr(ExprClass c) : clazz(c) {};
|
||||
virtual ~Expr() {};
|
||||
virtual Expr *optimize() { return this; };
|
||||
|
||||
virtual bool isConstant() { return false; };
|
||||
virtual float eval(int mesh_i, int mesh_j) = 0;
|
||||
virtual std::ostream& to_string(std::ostream &out)
|
||||
@ -80,9 +82,23 @@ public:
|
||||
std::cout << "nyi"; return out;
|
||||
}
|
||||
|
||||
static Test *test();
|
||||
static Expr *const_to_expr( float val );
|
||||
static Expr *param_to_expr( Param *param );
|
||||
static Expr *prefun_to_expr( float (*func_ptr)(void *), Expr **expr_list, int num_args );
|
||||
|
||||
static void delete_expr(Expr *expr) { if (nullptr != expr) expr->_delete_from_tree(); }
|
||||
static Expr *optimize(Expr *root) { return root->_optimize(); };
|
||||
|
||||
public: // but don't call these from outside Expr.cpp
|
||||
|
||||
virtual Expr *_optimize() { return this; };
|
||||
|
||||
// override if this expr is not 'owned' by the containg expression tree
|
||||
virtual void _delete_from_tree()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, Expr *expr)
|
||||
@ -111,11 +127,11 @@ public:
|
||||
TreeExpr *leftTree() { return dynamic_cast<TreeExpr *>(left); }
|
||||
TreeExpr *rightTree() { return dynamic_cast<TreeExpr *>(right); }
|
||||
|
||||
~TreeExpr();
|
||||
~TreeExpr() override;
|
||||
|
||||
Expr *optimize();
|
||||
float eval(int mesh_i, int mesh_j);
|
||||
std::ostream& to_string(std::ostream &out);
|
||||
Expr *_optimize() override;
|
||||
float eval(int mesh_i, int mesh_j) override;
|
||||
std::ostream& to_string(std::ostream &out) override;
|
||||
};
|
||||
|
||||
/* A function expression in prefix form */
|
||||
@ -126,12 +142,69 @@ public:
|
||||
int num_args;
|
||||
Expr **expr_list;
|
||||
PrefunExpr();
|
||||
~PrefunExpr();
|
||||
~PrefunExpr() override;
|
||||
|
||||
/* Evaluates functions in prefix form */
|
||||
Expr *optimize();
|
||||
float eval(int mesh_i, int mesh_j);
|
||||
std::ostream& to_string(std::ostream &out);
|
||||
Expr *_optimize() override;
|
||||
float eval(int mesh_i, int mesh_j) override;
|
||||
std::ostream& to_string(std::ostream &out) override;
|
||||
};
|
||||
|
||||
class LValue : public Expr
|
||||
{
|
||||
public:
|
||||
explicit LValue(ExprClass c) : Expr(c) {};
|
||||
virtual void set(float value) = 0;
|
||||
virtual void set_matrix(int mesh_i, int mesh_j, float value) = 0;
|
||||
};
|
||||
|
||||
|
||||
class AssignExpr : public Expr
|
||||
{
|
||||
protected:
|
||||
LValue *lhs;
|
||||
Expr *rhs;
|
||||
public:
|
||||
AssignExpr(LValue *lhs, Expr *rhs);
|
||||
~AssignExpr() override;
|
||||
Expr *_optimize() override;
|
||||
float eval(int mesh_i, int mesh_j) override;
|
||||
std::ostream& to_string(std::ostream &out) override;
|
||||
};
|
||||
|
||||
|
||||
class AssignMatrixExpr : public AssignExpr
|
||||
{
|
||||
public:
|
||||
AssignMatrixExpr(LValue *lhs, Expr *rhs);
|
||||
float eval(int mesh_i, int mesh_j) override;
|
||||
std::ostream& to_string(std::ostream &out) override;
|
||||
};
|
||||
|
||||
|
||||
class ProgramExpr : public Expr
|
||||
{
|
||||
protected:
|
||||
std::vector<Expr *> steps;
|
||||
bool own;
|
||||
public:
|
||||
ProgramExpr(std::vector<Expr*> &steps_, bool ownSteps) : Expr(PROGRAM), steps(steps_), own(ownSteps)
|
||||
{
|
||||
}
|
||||
~ProgramExpr()
|
||||
{
|
||||
if (!own)
|
||||
return;
|
||||
for (auto it=steps.begin() ; it<steps.end() ; it++)
|
||||
Expr::delete_expr(*it);
|
||||
}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
float f=0.0f;
|
||||
for (auto it=steps.begin() ; it<steps.end() ; it++)
|
||||
f = (*it)->eval(mesh_i,mesh_j);
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /** _EXPR_H */
|
||||
|
||||
@ -40,13 +40,9 @@ char InitCond::init_cond_string_buffer[STRING_BUFFER_SIZE];
|
||||
int InitCond::init_cond_string_buffer_index = 0;
|
||||
|
||||
/* Creates a new initial condition */
|
||||
InitCond::InitCond( Param * _param, CValue _init_val ):param(_param), init_val(_init_val) {
|
||||
|
||||
|
||||
// std::cerr << "InitCond::InitCond: " << this->param->name << std::endl;
|
||||
|
||||
InitCond::InitCond( Param * _param, CValue _init_val ):param(_param), init_val(_init_val)
|
||||
{
|
||||
assert(param);
|
||||
assert(param->engine_val);
|
||||
}
|
||||
|
||||
/* Frees initial condition structure */
|
||||
@ -58,59 +54,23 @@ void InitCond::evaluate()
|
||||
}
|
||||
|
||||
/* Evaluate an initial conditon */
|
||||
void InitCond::evaluate(bool evalUser) {
|
||||
void InitCond::evaluate(bool evalUser)
|
||||
{
|
||||
assert(this);
|
||||
assert(param);
|
||||
|
||||
if (param->flags & P_FLAG_USERDEF && !evalUser)
|
||||
return;
|
||||
|
||||
|
||||
assert(this);
|
||||
assert(param);
|
||||
|
||||
if (param->flags & P_FLAG_USERDEF && !evalUser)
|
||||
return;
|
||||
|
||||
/* Set matrix flag to zero. This ensures
|
||||
its constant value will be used rather than a matrix value
|
||||
*/
|
||||
param->matrix_flag = false;
|
||||
|
||||
/* Parameter is of boolean type, either true/false */
|
||||
|
||||
if (param->type == P_TYPE_BOOL) {
|
||||
|
||||
// printf( "init_cond: %s = %d (TYPE BOOL)\n", param->name.c_str(), init_val.bool_val);
|
||||
//std::cerr << "[InitCond] param is a boolean of with name "
|
||||
// << param->name << std::endl;
|
||||
|
||||
assert(param->engine_val);
|
||||
|
||||
*((bool*)param->engine_val) = init_val.bool_val;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parameter is an integer type, just like C */
|
||||
|
||||
if ( param->type == P_TYPE_INT) {
|
||||
assert(param->engine_val);
|
||||
*((int*)param->engine_val) = init_val.int_val;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parameter is of a float type, just like C */
|
||||
|
||||
if (param->type == P_TYPE_DOUBLE) {
|
||||
assert(param->engine_val);
|
||||
*((float*)param->engine_val) = init_val.float_val;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unknown type of parameter */
|
||||
return;
|
||||
/* Has side-effect of also setting matrix flag to zero. This ensures
|
||||
its constant value will be used rather than a matrix value
|
||||
*/
|
||||
param->set_param(init_val);
|
||||
}
|
||||
|
||||
/* WIP */
|
||||
void InitCond::init_cond_to_string() {
|
||||
|
||||
void InitCond::init_cond_to_string()
|
||||
{
|
||||
int string_length;
|
||||
char string[MAX_TOKEN_SIZE];
|
||||
|
||||
|
||||
@ -25,10 +25,6 @@ inline void LoadUnspecInitCond::operator() (Param * param) {
|
||||
InitCond * init_cond = 0;
|
||||
CValue init_val;
|
||||
|
||||
assert(param);
|
||||
assert(param->engine_val);
|
||||
|
||||
|
||||
/* Don't count these parameters as initial conditions */
|
||||
if (param->flags & P_FLAG_READONLY)
|
||||
return;
|
||||
@ -48,15 +44,7 @@ inline void LoadUnspecInitCond::operator() (Param * param) {
|
||||
if (m_perFrameInitEqnTree.find(param->name) != m_perFrameInitEqnTree.end())
|
||||
return;
|
||||
|
||||
// Set an initial vialue via correct union member
|
||||
if (param->type == P_TYPE_BOOL)
|
||||
init_val.bool_val = param->default_init_val.bool_val;
|
||||
else if (param->type == P_TYPE_INT)
|
||||
init_val.int_val = param->default_init_val.int_val;
|
||||
|
||||
else if (param->type == P_TYPE_DOUBLE) {
|
||||
init_val.float_val = param->default_init_val.float_val;
|
||||
}
|
||||
init_val = param->default_init_val;
|
||||
|
||||
//printf("%s\n", param->name);
|
||||
/* Create new initial condition */
|
||||
|
||||
@ -44,10 +44,15 @@
|
||||
#include "PresetFactoryManager.hpp"
|
||||
#include "MilkdropPresetFactory.hpp"
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
MilkdropPreset::MilkdropPreset(MilkdropPresetFactory *factory, std::istream & in, const std::string & presetName, PresetOutputs & presetOutputs):
|
||||
Preset(presetName),
|
||||
builtinParams(_presetInputs, presetOutputs),
|
||||
per_pixel_program(nullptr),
|
||||
_factory(factory),
|
||||
_presetOutputs(presetOutputs)
|
||||
{
|
||||
@ -58,6 +63,7 @@ MilkdropPreset::MilkdropPreset(MilkdropPresetFactory *factory, std::istream & in
|
||||
MilkdropPreset::MilkdropPreset(MilkdropPresetFactory *factory, const std::string & absoluteFilePath, const std::string & presetName, PresetOutputs & presetOutputs):
|
||||
Preset(presetName),
|
||||
builtinParams(_presetInputs, presetOutputs),
|
||||
per_pixel_program(nullptr),
|
||||
_filename(parseFilename(absoluteFilePath)),
|
||||
_absoluteFilePath(absoluteFilePath),
|
||||
_factory(factory),
|
||||
@ -76,6 +82,7 @@ MilkdropPreset::~MilkdropPreset()
|
||||
traverse<TraverseFunctors::Delete<InitCond> >(per_frame_init_eqn_tree);
|
||||
|
||||
traverse<TraverseFunctors::Delete<PerPixelEqn> >(per_pixel_eqn_tree);
|
||||
Expr::delete_expr(per_pixel_program);
|
||||
|
||||
traverseVector<TraverseFunctors::Delete<PerFrameEqn> >(per_frame_eqn_tree);
|
||||
|
||||
@ -387,94 +394,61 @@ void MilkdropPreset::evaluateFrame()
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef __SSE2__
|
||||
inline void init_mesh(float **mesh, const float value, const int gx, const int gy)
|
||||
{
|
||||
__m128 mvalue = _mm_set_ps1(value);
|
||||
for (int x = 0; x < gx; x++)
|
||||
for (int y = 0; y < gy; y += 4)
|
||||
_mm_store_ps(&mesh[x][y], mvalue);
|
||||
}
|
||||
#else
|
||||
inline void init_mesh(float **mesh, const float value, const int gx, const int gy)
|
||||
{
|
||||
for (x=0;x<gx;x++)
|
||||
for(y=0;gy;y++)
|
||||
mesh[x,y] = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MilkdropPreset::initialize_PerPixelMeshes()
|
||||
{
|
||||
int gx = presetInputs().gx;
|
||||
int gy = presetInputs().gy;
|
||||
|
||||
int x,y;
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.cx_mesh[x][y]=presetOutputs().cx;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.cy_mesh[x][y]=presetOutputs().cy;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.sx_mesh[x][y]=presetOutputs().sx;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.sy_mesh[x][y]=presetOutputs().sy;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.dx_mesh[x][y]=presetOutputs().dx;
|
||||
}}
|
||||
|
||||
//std::cout<<presetOutputs().cx<<","<<presetOutputs().cy<<" "<<presetOutputs().dx<<","<<presetOutputs().dy<<std::endl;
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.dy_mesh[x][y]=presetOutputs().dy;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.zoom_mesh[x][y]=presetOutputs().zoom;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.zoomexp_mesh[x][y]=presetOutputs().zoomexp;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.rot_mesh[x][y]=presetOutputs().rot;
|
||||
}}
|
||||
|
||||
|
||||
for (x=0;x<presetInputs().gx;x++){
|
||||
for(y=0;y<presetInputs().gy;y++){
|
||||
_presetOutputs.warp_mesh[x][y]=presetOutputs().warp;
|
||||
}}
|
||||
|
||||
|
||||
|
||||
init_mesh(_presetOutputs.cx_mesh, presetOutputs().cx, gx, gy);
|
||||
init_mesh(_presetOutputs.cy_mesh, presetOutputs().cy, gx, gy);
|
||||
init_mesh(_presetOutputs.sx_mesh, presetOutputs().sx, gx, gy);
|
||||
init_mesh(_presetOutputs.sy_mesh, presetOutputs().sy, gx, gy);
|
||||
init_mesh(_presetOutputs.dx_mesh, presetOutputs().dx, gx, gy);
|
||||
init_mesh(_presetOutputs.dy_mesh, presetOutputs().dy, gx, gy);
|
||||
init_mesh(_presetOutputs.zoom_mesh, presetOutputs().zoom, gx, gy);
|
||||
init_mesh(_presetOutputs.zoomexp_mesh, presetOutputs().zoomexp, gx, gy);
|
||||
init_mesh(_presetOutputs.rot_mesh, presetOutputs().rot, gx, gy);
|
||||
init_mesh(_presetOutputs.warp_mesh, presetOutputs().warp, gx, gy);
|
||||
}
|
||||
|
||||
|
||||
// Evaluates all per-pixel equations
|
||||
void MilkdropPreset::evalPerPixelEqns()
|
||||
{
|
||||
if (nullptr == per_pixel_program)
|
||||
{
|
||||
// This is a little forward looking, but if we want to JIT assignments expressions, we might
|
||||
// as well JIT the batch all together rather than one at a time. At the moment ProgramExpr is
|
||||
// just a different place to loop over the individual steps, but the idea is that this encapsulates
|
||||
// an optimizable chunk of work.
|
||||
// See also CustomWave which does the same for PerPointEqn
|
||||
std::vector<Expr *> steps;
|
||||
for (std::map<int, PerPixelEqn*>::iterator pos = per_pixel_eqn_tree.begin(); pos != per_pixel_eqn_tree.end(); ++pos)
|
||||
steps.push_back(pos->second->assign_expr);
|
||||
per_pixel_program = new ProgramExpr(steps,false);
|
||||
}
|
||||
|
||||
/* Evaluate all per pixel equations in the tree datastructure */
|
||||
for (int mesh_x = 0; mesh_x < presetInputs().gx; mesh_x++)
|
||||
for (int mesh_y = 0; mesh_y < presetInputs().gy; mesh_y++)
|
||||
for (std::map<int, PerPixelEqn*>::iterator pos = per_pixel_eqn_tree.begin();
|
||||
pos != per_pixel_eqn_tree.end(); ++pos)
|
||||
pos->second->evaluate(mesh_x, mesh_y);
|
||||
|
||||
for (int mesh_x = 0; mesh_x < presetInputs().gx; mesh_x++)
|
||||
for (int mesh_y = 0; mesh_y < presetInputs().gy; mesh_y++)
|
||||
per_pixel_program->eval( mesh_x, mesh_y );
|
||||
}
|
||||
|
||||
int MilkdropPreset::readIn(std::istream & fs) {
|
||||
|
||||
@ -130,6 +130,7 @@ public:
|
||||
/* Data structures that contain equation and initial condition information */
|
||||
std::vector<PerFrameEqn*> per_frame_eqn_tree; /* per frame equations */
|
||||
std::map<int, PerPixelEqn*> per_pixel_eqn_tree; /* per pixel equation tree */
|
||||
Expr *per_pixel_program;
|
||||
std::map<std::string,InitCond*> per_frame_init_eqn_tree; /* per frame initial equations */
|
||||
std::map<std::string,InitCond*> init_cond_tree; /* initial conditions */
|
||||
std::map<std::string,Param*> user_param_tree; /* user parameter splay tree */
|
||||
|
||||
@ -40,9 +40,10 @@
|
||||
#include <cassert>
|
||||
|
||||
/** Constructor */
|
||||
Param::Param( std::string _name, short int _type, short int _flags, void * _engine_val, void * _matrix,
|
||||
Param::Param( const std::string &_name, short int _type, short int _flags, void * _engine_val, void * _matrix,
|
||||
CValue _default_init_val, CValue _upper_bound, CValue _lower_bound):
|
||||
name(_name),
|
||||
LValue(PARAMETER),
|
||||
name(_name),
|
||||
type(_type),
|
||||
flags (_flags),
|
||||
matrix_flag (0),
|
||||
@ -52,24 +53,22 @@ Param::Param( std::string _name, short int _type, short int _flags, void * _engi
|
||||
upper_bound (_upper_bound),
|
||||
lower_bound (_lower_bound),
|
||||
local_value(0.0)
|
||||
{
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* Creates a user defined parameter */
|
||||
Param::Param(std::string _name) :
|
||||
name(_name),
|
||||
Param::Param(const std::string &_name) : LValue(PARAMETER),
|
||||
name(_name),
|
||||
type(P_TYPE_DOUBLE),
|
||||
flags(P_FLAG_USERDEF),
|
||||
flags(P_FLAG_USERDEF),
|
||||
matrix_flag(0),
|
||||
matrix(0),
|
||||
local_value(0.0)
|
||||
{
|
||||
local_value(0.0)
|
||||
{
|
||||
engine_val = (float *)&local_value;
|
||||
|
||||
engine_val = (float *)&local_value;
|
||||
|
||||
default_init_val.float_val = DEFAULT_DOUBLE_IV;
|
||||
default_init_val.float_val = DEFAULT_DOUBLE_IV;
|
||||
upper_bound.float_val = DEFAULT_DOUBLE_UB;
|
||||
lower_bound.float_val = DEFAULT_DOUBLE_LB;
|
||||
|
||||
@ -123,7 +122,7 @@ Param * Param::new_param_float(const char * name, short int flags, void * engine
|
||||
ub.float_val = upper_bound;
|
||||
lb.float_val = lower_bound;
|
||||
|
||||
if ((param = new Param(name, P_TYPE_DOUBLE, flags, engine_val, matrix,iv, ub, lb)) == NULL)
|
||||
if ((param = Param::create(name, P_TYPE_DOUBLE, flags, engine_val, matrix,iv, ub, lb)) == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
@ -132,7 +131,7 @@ Param * Param::new_param_float(const char * name, short int flags, void * engine
|
||||
}
|
||||
|
||||
/* Creates a new parameter of type int */
|
||||
Param * Param::new_param_int(const char * name, short int flags, void * engine_val,
|
||||
Param * Param::new_param_int(const char * name, short int flags, void * engine_val,
|
||||
int upper_bound, int lower_bound, int init_val) {
|
||||
|
||||
Param * param;
|
||||
@ -143,7 +142,7 @@ Param * Param::new_param_int(const char * name, short int flags, void * engine_v
|
||||
ub.int_val = upper_bound;
|
||||
lb.int_val = lower_bound;
|
||||
|
||||
if ((param = new Param(name, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
if ((param = Param::create(name, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
@ -163,7 +162,7 @@ Param * Param::new_param_bool(const char * name, short int flags, void * engine_
|
||||
ub.bool_val = upper_bound;
|
||||
lb.bool_val = lower_bound;
|
||||
|
||||
if ((param = new Param(name, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
if ((param = Param::create(name, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
@ -182,7 +181,7 @@ Param * Param::new_param_string(const char * name, short int flags, void * engin
|
||||
ub.bool_val = 0;
|
||||
lb.bool_val = 0;
|
||||
|
||||
if ((param = new Param(name, P_TYPE_STRING, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
if ((param = Param::create(name, P_TYPE_STRING, flags, engine_val, NULL, iv, ub, lb)) == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
@ -191,3 +190,267 @@ Param * Param::new_param_string(const char * name, short int flags, void * engin
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* I made Param extend Expr just to avoid inheritence of multiple virtual classes,
|
||||
* however, this is really the subclass that knows how to interact with Expr
|
||||
*/
|
||||
|
||||
struct _Param : public Param
|
||||
{
|
||||
_Param( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
Param(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_)
|
||||
{
|
||||
if (flags & P_FLAG_ALWAYS_MATRIX)
|
||||
matrix_flag = true;
|
||||
}
|
||||
explicit _Param( const std::string &name_) : Param(name_) {}
|
||||
|
||||
LValue *getExpr() override
|
||||
{
|
||||
return (LValue *)this;
|
||||
}
|
||||
|
||||
void _delete_from_tree() override
|
||||
{
|
||||
/* do nothing, as the param isn't owned by the expresion tree */
|
||||
}
|
||||
|
||||
void set(float value) override
|
||||
{
|
||||
set_param(value);
|
||||
}
|
||||
void set_matrix(int mesh_i, int mesh_j, float value) override
|
||||
{
|
||||
set_param(value);
|
||||
}
|
||||
};
|
||||
|
||||
class _BoolParam : public _Param
|
||||
{
|
||||
public:
|
||||
_BoolParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_Param(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
return *(bool *)engine_val ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
class _IntParam : public _Param
|
||||
{
|
||||
public:
|
||||
_IntParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_Param(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
return *(int *)engine_val;
|
||||
}
|
||||
};
|
||||
|
||||
class _StringParam : public _Param
|
||||
{
|
||||
public:
|
||||
_StringParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_Param(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class _FloatParam : public _Param
|
||||
{
|
||||
public:
|
||||
_FloatParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_Param(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
explicit _FloatParam( const std::string &name_) : _Param(name_) {}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
return *(float *)engine_val;
|
||||
}
|
||||
};
|
||||
|
||||
/*This isn't that useful yet. Maybe later
|
||||
class _AlwaysMatrixParam : public _FloatParam
|
||||
{
|
||||
public:
|
||||
_AlwaysMatrixParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_FloatParam(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_)
|
||||
{
|
||||
matrix_flag = true;
|
||||
}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
assert( mesh_i >=0 && mesh_j >= 0 );
|
||||
return ((float **)matrix)[mesh_i][mesh_j];
|
||||
}
|
||||
void set_matrix(int mesh_i, int mesh_j, float value) override
|
||||
{
|
||||
assert( mesh_i >=0 && mesh_j >= 0);
|
||||
// Yup, presets write to read-only ALWAYS_MATRIX parameters
|
||||
// assert(!(flags & P_FLAG_READONLY));
|
||||
((float **)matrix)[mesh_i][mesh_j] = value;
|
||||
}
|
||||
};*/
|
||||
|
||||
class _MeshParam : public _FloatParam
|
||||
{
|
||||
public:
|
||||
_MeshParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_FloatParam(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
assert( type == P_TYPE_DOUBLE );
|
||||
// see issue 64: There are presets with per_point equations that read from pre_frame/per_pixel parameters,
|
||||
// e.g. per_point1=dx=dx*1.01
|
||||
// any this means that we get called with (i>=0,j==-1)
|
||||
if ( matrix_flag && mesh_i >= 0 && mesh_j >= 0)
|
||||
return ( ( ( float** ) matrix ) [mesh_i][mesh_j] );
|
||||
return * ( ( float* ) ( engine_val ) );
|
||||
}
|
||||
void set_matrix(int mesh_i, int mesh_j, float value) override
|
||||
{
|
||||
if (nullptr == matrix)
|
||||
{
|
||||
*(float *)engine_val = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
((float **) matrix)[mesh_i][mesh_j] = value;
|
||||
matrix_flag = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO merge PointsParam/MeshParam
|
||||
class _PointsParam : public _FloatParam
|
||||
{
|
||||
public:
|
||||
_PointsParam( const std::string &name_, short int type_, short int flags_,
|
||||
void * eqn_val_, void *matrix_,
|
||||
CValue default_init_val_, CValue upper_bound_,
|
||||
CValue lower_bound_) :
|
||||
_FloatParam(name_, type_, flags_, eqn_val_, matrix_, default_init_val_, upper_bound_, lower_bound_) {}
|
||||
float eval(int mesh_i, int mesh_j) override
|
||||
{
|
||||
assert( mesh_j == -1 );
|
||||
assert( type == P_TYPE_DOUBLE );
|
||||
if ( matrix_flag && mesh_i >= 0 )
|
||||
return ( ( ( float* ) matrix ) [mesh_i] );
|
||||
return * ( ( float* ) ( engine_val ) );
|
||||
}
|
||||
void set_matrix(int mesh_i, int mesh_j, float value) override
|
||||
{
|
||||
if (nullptr == matrix)
|
||||
{
|
||||
*(float *)engine_val = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
((float *) matrix)[mesh_i] = value;
|
||||
matrix_flag = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Param * Param::create( const std::string &name, short int type, short int flags,
|
||||
void * eqn_val, void *matrix,
|
||||
CValue default_init_val, CValue upper_bound,
|
||||
CValue lower_bound)
|
||||
{
|
||||
if (type == P_TYPE_BOOL)
|
||||
{
|
||||
assert(nullptr == matrix);
|
||||
assert(0 == (flags & (P_FLAG_PER_PIXEL|P_FLAG_PER_POINT)));
|
||||
return new _BoolParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
if (type == P_TYPE_INT)
|
||||
{
|
||||
assert(nullptr == matrix);
|
||||
assert(0 ==(flags & (P_FLAG_PER_PIXEL|P_FLAG_PER_POINT)));
|
||||
return new _IntParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
if (type == P_TYPE_STRING)
|
||||
{
|
||||
assert(0 == (flags & (P_FLAG_PER_PIXEL|P_FLAG_PER_POINT)));
|
||||
return new _StringParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
assert(type == P_TYPE_DOUBLE);
|
||||
if (matrix == nullptr)
|
||||
{
|
||||
assert(0 == (flags & (P_FLAG_PER_PIXEL|P_FLAG_PER_POINT)));
|
||||
return new _FloatParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
assert( flags & (P_FLAG_PER_PIXEL|P_FLAG_PER_POINT) );
|
||||
if (flags & P_FLAG_PER_PIXEL)
|
||||
{
|
||||
return new _MeshParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
else
|
||||
{
|
||||
return new _PointsParam( name, type, flags, eqn_val, matrix, default_init_val, upper_bound, lower_bound );
|
||||
}
|
||||
}
|
||||
|
||||
Param * Param::createUser( const std::string &name )
|
||||
{
|
||||
return new _FloatParam( name );
|
||||
}
|
||||
|
||||
|
||||
// TESTS
|
||||
|
||||
|
||||
#include <TestRunner.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
struct ParamTest : public Test
|
||||
{
|
||||
ParamTest() : Test("ParamTest")
|
||||
{}
|
||||
|
||||
public:
|
||||
bool test() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Test* Param::test()
|
||||
{
|
||||
return new ParamTest();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Test* Param::test()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -57,64 +57,86 @@
|
||||
class InitCond;
|
||||
class Param;
|
||||
class Preset;
|
||||
class Test;
|
||||
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
/* Parameter Type */
|
||||
class Param {
|
||||
class Param : public LValue
|
||||
{
|
||||
protected:
|
||||
Param(const std::string &name, short int type, short int flags,
|
||||
void * eqn_val, void *matrix,
|
||||
CValue default_init_val, CValue upper_bound,
|
||||
CValue lower_bound);
|
||||
|
||||
/// Create a user defined floating point parameter
|
||||
explicit Param( const std::string &name );
|
||||
|
||||
public:
|
||||
std::string name; /* name of the parameter, not necessary but useful neverthless */
|
||||
short int type; /* parameter number type (int, bool, or float) */
|
||||
short int flags; /* read, write, user defined, etc */
|
||||
protected:
|
||||
short int matrix_flag; /* for optimization purposes */
|
||||
void * engine_val; /* pointer to the engine variable */
|
||||
void * matrix; /* per pixel / per point matrix for this variable */
|
||||
public:
|
||||
CValue default_init_val; /* a default initial condition value */
|
||||
protected:
|
||||
CValue upper_bound; /* this parameter's upper bound */
|
||||
CValue lower_bound; /* this parameter's lower bound */
|
||||
|
||||
// for a local variable, engine_val can point here
|
||||
float local_value;
|
||||
|
||||
public:
|
||||
/// Create a new parameter
|
||||
Param(std::string name, short int type, short int flags,
|
||||
static Param * create(const std::string &name, short int type, short int flags,
|
||||
void * eqn_val, void *matrix,
|
||||
CValue default_init_val, CValue upper_bound,
|
||||
CValue lower_bound);
|
||||
|
||||
~Param();
|
||||
static Param * createUser(const std::string &name);
|
||||
|
||||
/// Create a user defined floating point parameter
|
||||
Param( std::string name );
|
||||
static Test *test();
|
||||
|
||||
virtual ~Param();
|
||||
|
||||
static bool is_valid_param_string( const char *string );
|
||||
void set_param( float val );
|
||||
void set_param( CValue val );
|
||||
void set_param( std::string &text) { *((std::string*)engine_val) = text; }
|
||||
|
||||
static Param *new_param_float( const char *name, short int flags, void *engine_val,
|
||||
void *matrix, float upper_bound,
|
||||
float lower_bound,
|
||||
float init_val );
|
||||
static Param *new_param_double(const char *name, short int flags, void *engine_val,
|
||||
void *matrix, double upper_bound,
|
||||
double lower_bound,
|
||||
double init_val );
|
||||
|
||||
static Param * new_param_int(const char * name, short int flags, void * engine_val,
|
||||
int upper_bound, int lower_bound, int init_val );
|
||||
static Param * new_param_bool(const char * name, short int flags, void * engine_val,
|
||||
bool upper_bound, bool lower_bound, bool init_val );
|
||||
static Param * new_param_string(const char * name, short int flags, void * engine_val);
|
||||
|
||||
// return an Expr to inject directly into an Eqn
|
||||
// this allows the parameter to stay encapsulated, but not add extra levels of virtual functions
|
||||
// into the evaluation process
|
||||
|
||||
virtual LValue *getExpr() = 0;
|
||||
};
|
||||
|
||||
|
||||
/* Sets the parameter engine value to value val.
|
||||
clipping occurs if necessary */
|
||||
inline void Param::set_param( float val) {
|
||||
|
||||
switch (type) {
|
||||
|
||||
inline void Param::set_param( float val)
|
||||
{
|
||||
matrix_flag = false;
|
||||
switch (type)
|
||||
{
|
||||
case P_TYPE_BOOL:
|
||||
if (val < 0)
|
||||
*((bool*)engine_val) = false;
|
||||
@ -135,8 +157,6 @@ inline void Param::set_param( float val) {
|
||||
break;
|
||||
case P_TYPE_DOUBLE:
|
||||
/* Make sure value is an integer */
|
||||
|
||||
|
||||
if (val < lower_bound.float_val)
|
||||
*((float*)engine_val) = lower_bound.float_val;
|
||||
else if (val > upper_bound.float_val)
|
||||
@ -147,10 +167,27 @@ inline void Param::set_param( float val) {
|
||||
default:
|
||||
//abort();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
inline void Param::set_param( CValue val)
|
||||
{
|
||||
matrix_flag = false;
|
||||
switch (type)
|
||||
{
|
||||
case P_TYPE_BOOL:
|
||||
set_param( val.bool_val );
|
||||
break;
|
||||
case P_TYPE_INT:
|
||||
set_param( val.int_val );
|
||||
break;
|
||||
case P_TYPE_DOUBLE:
|
||||
set_param( val.float_val );
|
||||
break;
|
||||
default:
|
||||
//abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /** !_PARAM_TYPES_H */
|
||||
|
||||
@ -46,7 +46,7 @@ public:
|
||||
return NULL;
|
||||
|
||||
/* Now, create the user defined parameter given the passed name */
|
||||
if ((param = new Param(name)) == NULL)
|
||||
if ((param = Param::createUser(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Finally, insert the new parameter into this preset's parameter tree */
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "BuiltinFuncs.hpp"
|
||||
#include "MilkdropPresetFactory.hpp"
|
||||
|
||||
/* Grabs the next token from the file. The second argument points
|
||||
to the raw string */
|
||||
@ -276,9 +277,8 @@ Expr **Parser::parse_prefix_args(std::istream & fs, int num_args, MilkdropPrese
|
||||
{
|
||||
//if (PARSE_DEBUG) printf("parse_prefix_args: failed to get parameter # %d for function (LINE %d)\n", i+1, line_count);
|
||||
for (j = 0; j < i; j++)
|
||||
delete expr_list[j];
|
||||
Expr::delete_expr(expr_list[j]);
|
||||
free(expr_list);
|
||||
expr_list = NULL;
|
||||
return NULL;
|
||||
}
|
||||
/* Assign entry in expression list */
|
||||
@ -360,7 +360,7 @@ int Parser::parse_per_pixel_eqn(std::istream & fs, MilkdropPreset * preset, cha
|
||||
{
|
||||
|
||||
}
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return PROJECTM_PARSE_ERROR;
|
||||
}
|
||||
|
||||
@ -751,7 +751,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
}
|
||||
if ( tree_expr != NULL )
|
||||
{
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -762,11 +762,10 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
if (PARSE_DEBUG) printf("parse_prefix_args: failed to convert prefix function to general expression (LINE %d) \n",
|
||||
line_count);
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
for (i = 0; i < func->getNumArgs();i++)
|
||||
delete expr_list[i];
|
||||
Expr::delete_expr(expr_list[i]);
|
||||
free(expr_list);
|
||||
expr_list = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -789,7 +788,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
std::cerr << "token prefix is " << *string << std::endl;
|
||||
if (PARSE_DEBUG) printf("parse_gen_expr: implicit multiplication case unimplemented!\n");
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -800,7 +799,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_gen_expr: found left parentice, but failed to create new expression tree \n");
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -854,7 +853,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
if (*string == 0)
|
||||
{
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -864,7 +863,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
if ((gen_expr = Expr::const_to_expr(val)) == NULL)
|
||||
{
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -883,7 +882,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(std::string(string), ¤t_shape->param_tree)) == NULL)
|
||||
{
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -898,7 +897,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
/* Convert parameter to an expression */
|
||||
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
|
||||
{
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -917,7 +916,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(std::string(string), ¤t_wave->param_tree)) == NULL)
|
||||
{
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -932,7 +931,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
/* Convert parameter to an expression */
|
||||
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
|
||||
{
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -955,7 +954,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
/* Convert parameter to an expression */
|
||||
if ((gen_expr = Expr::param_to_expr(param)) == NULL)
|
||||
{
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -973,7 +972,7 @@ Expr * Parser::_parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkd
|
||||
|
||||
}
|
||||
if (tree_expr)
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -985,10 +984,10 @@ Expr * Parser::parse_gen_expr ( std::istream & fs, TreeExpr * tree_expr, Milkdr
|
||||
if (NULL == gen_expr)
|
||||
return NULL;
|
||||
//std::cout << gen_expr << std::endl;
|
||||
Expr *opt = gen_expr->optimize();
|
||||
Expr *opt = Expr::optimize(gen_expr);
|
||||
|
||||
if (opt != gen_expr) {
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
}
|
||||
//std::cout << opt << std::endl << std::endl;
|
||||
return opt;
|
||||
@ -1193,31 +1192,31 @@ Expr * Parser::parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found addition operator (LINE %d)\n", line_count);
|
||||
if (PARSE_DEBUG) std::cerr << "WRAP AROUND IS " << tokenWrapAroundEnabled << std::endl;
|
||||
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_add, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_add, &tree_expr), preset);
|
||||
case tMinus:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found subtraction operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_minus, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_minus, &tree_expr), preset);
|
||||
case tMult:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found multiplication operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_mult, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_mult, &tree_expr), preset);
|
||||
case tDiv:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found division operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_div, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_div, &tree_expr), preset);
|
||||
case tMod:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found modulo operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_mod, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_mod, &tree_expr), preset);
|
||||
case tOr:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found bitwise or operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_or, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_or, &tree_expr), preset);
|
||||
case tAnd:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found bitwise and operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_and, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_and, &tree_expr), preset);
|
||||
case tPositive:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found positive operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_positive, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_positive, &tree_expr), preset);
|
||||
case tNegative:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: found negative operator (LINE %d)\n", line_count);
|
||||
return parse_gen_expr(fs, insert_infix_op(Eval::infix_negative, &tree_expr), preset);
|
||||
return _parse_gen_expr(fs, insert_infix_op(Eval::infix_negative, &tree_expr), preset);
|
||||
|
||||
case tEOL:
|
||||
case tEOF:
|
||||
@ -1230,7 +1229,7 @@ Expr * Parser::parse_infix_op(std::istream & fs, token_t token, TreeExpr * tree
|
||||
return gen_expr;
|
||||
default:
|
||||
if (PARSE_DEBUG) printf("parse_infix_op: operator or terminal expected, but not found (LINE %d)\n", line_count);
|
||||
delete tree_expr;
|
||||
Expr::delete_expr(tree_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1406,7 +1405,7 @@ PerFrameEqn * Parser::parse_per_frame_eqn(std::istream & fs, int index, Milkdro
|
||||
if ((per_frame_eqn = new PerFrameEqn(index, param, gen_expr)) == NULL)
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1459,7 +1458,7 @@ PerFrameEqn * Parser::parse_implicit_per_frame_eqn(std::istream & fs, char * pa
|
||||
if ((per_frame_eqn = new PerFrameEqn(index, param, gen_expr)) == NULL)
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1616,7 +1615,7 @@ InitCond * Parser::parse_per_frame_init_eqn(std::istream & fs, MilkdropPreset *
|
||||
val = gen_expr->eval(-1,-1);
|
||||
|
||||
/* Free the general expression now that we are done with it */
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
|
||||
/* integer value (boolean is an integer in C) */
|
||||
if (param->type == P_TYPE_BOOL)
|
||||
@ -1918,7 +1917,7 @@ int Parser::parse_shapecode(char * token, std::istream & fs, MilkdropPreset * p
|
||||
|
||||
fs >> text;
|
||||
|
||||
*((std::string*)param->engine_val) = text;
|
||||
param->set_param(text);
|
||||
if (PARSE_DEBUG)
|
||||
std::cerr << "parse_shapecode: found image url, text is \""
|
||||
<< text << "\"" << std::endl;
|
||||
@ -2278,7 +2277,7 @@ int Parser::parse_wave_helper(std::istream & fs, MilkdropPreset * preset, int
|
||||
if ((per_frame_eqn = new PerFrameEqn(custom_wave->per_frame_count++, param, gen_expr)) == NULL)
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_wave (per_frame): failed to create a new per frame eqn, out of memory?\n");
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return PROJECTM_FAILURE;
|
||||
}
|
||||
|
||||
@ -2328,7 +2327,7 @@ int Parser::parse_wave_helper(std::istream & fs, MilkdropPreset * preset, int
|
||||
/* Add the per point equation */
|
||||
if (custom_wave->add_per_point_eqn(string, gen_expr) < 0)
|
||||
{
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
|
||||
return PROJECTM_PARSE_ERROR;
|
||||
}
|
||||
@ -2511,7 +2510,7 @@ int Parser::parse_shape_per_frame_eqn(std::istream & fs, CustomShape * custom_sh
|
||||
if ((per_frame_eqn = new PerFrameEqn(custom_shape->per_frame_count++, param, gen_expr)) == NULL)
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_shape (per_frame): failed to create a new per frame eqn, out of memory?\n");
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return PROJECTM_FAILURE;
|
||||
}
|
||||
|
||||
@ -2573,7 +2572,7 @@ int Parser::parse_wave_per_frame_eqn(std::istream & fs, CustomWave * custom_wav
|
||||
if ((per_frame_eqn = new PerFrameEqn(custom_wave->per_frame_count++, param, gen_expr)) == NULL)
|
||||
{
|
||||
if (PARSE_DEBUG) printf("parse_wave (per_frame): failed to create a new per frame eqn, out of memory?\n");
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(gen_expr);
|
||||
return PROJECTM_FAILURE;
|
||||
}
|
||||
|
||||
@ -2605,3 +2604,144 @@ else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TESTS
|
||||
|
||||
|
||||
#include <TestRunner.hpp>
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#include <PresetLoader.hpp>
|
||||
|
||||
#define TEST(cond) if (!verify(#cond,cond)) return false
|
||||
#define TEST2(str,cond) if (!verify(str,cond)) return false
|
||||
|
||||
struct ParserTest : public Test
|
||||
{
|
||||
ParserTest() : Test("ParserTest")
|
||||
{}
|
||||
|
||||
MilkdropPreset *preset;
|
||||
std::istringstream is;
|
||||
std::istringstream &ss(const char *s) { return is = std::istringstream(s); }
|
||||
|
||||
bool eq(float a, float b)
|
||||
{
|
||||
return abs(a-b) < (abs(a)+abs(b))/1000.0f;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool test_float()
|
||||
{
|
||||
float f=-1.0f;
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("1.1"),&f));
|
||||
TEST(1.1f == f);
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("+1.2"),&f));
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_float(ss("-1.3"),&f));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss(""),&f));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss("\n"),&f));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_float(ss("+"),&f));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_int()
|
||||
{
|
||||
int i=-1;
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("1"),&i));
|
||||
TEST(1 == i);
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("+2"),&i));
|
||||
TEST(PROJECTM_SUCCESS == Parser::parse_int(ss("-3"),&i));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss(""),&i));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss("\n"),&i));
|
||||
TEST(PROJECTM_PARSE_ERROR == Parser::parse_int(ss("+"),&i));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eval_expr(float expected, const char *s)
|
||||
{
|
||||
float f1, f2;
|
||||
Expr *expr = Parser::parse_gen_expr(ss(s),nullptr,preset);
|
||||
TEST(expr != nullptr);
|
||||
TEST(ParserTest::eq(expected, f1=expr->eval(-1,-1)));
|
||||
// this is really a test for Expr.cpp, but since we're here
|
||||
Expr *opt = Expr::optimize(expr);
|
||||
if (opt != expr)
|
||||
{
|
||||
TEST(ParserTest::eq(expected, f2 = opt->eval(-1, -1)));
|
||||
Expr::delete_expr(opt);
|
||||
}
|
||||
Expr::delete_expr(expr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_eqn()
|
||||
{
|
||||
TEST(eval_expr(1.0f, "1.0"));
|
||||
TEST(eval_expr(-1.0f, "-(1.0)")); // unary`
|
||||
TEST(eval_expr(0.5f, "5/10.000")); // binary
|
||||
TEST(eval_expr(1.0f, "sin(3.14159/2)"));
|
||||
preset->presetOutputs().rot = 0.99f;
|
||||
TEST(eval_expr(0.99f, "rot"));
|
||||
return true;
|
||||
}
|
||||
|
||||
// test multi-line expression, and multi-expression line
|
||||
bool test_lines()
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_params()
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _test()
|
||||
{
|
||||
bool success = true;
|
||||
success &= test_float();
|
||||
success &= test_int();
|
||||
success &= test_eqn();
|
||||
success &= test_lines();
|
||||
success &= test_params();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool test() override
|
||||
{
|
||||
// load IdlePreset
|
||||
PresetLoader *presetLoader = new PresetLoader ( 400, 400, "" );
|
||||
std::unique_ptr<Preset> preset_ptr = presetLoader->loadPreset("idle://Geiss & Sperl - Feedback (projectM idle HDR mix).milk");
|
||||
preset = (MilkdropPreset *)preset_ptr.get();
|
||||
|
||||
bool success = _test();
|
||||
|
||||
delete presetLoader;
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
Test* Parser::test()
|
||||
{
|
||||
return new ParserTest();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Test* Param::test()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -120,6 +120,7 @@ typedef enum {
|
||||
tStringBufferFilled /* the string buffer for this line is maxed out */
|
||||
} token_t;
|
||||
|
||||
class Test;
|
||||
class CustomShape;
|
||||
class CustomWave;
|
||||
class Expr;
|
||||
@ -145,6 +146,7 @@ public:
|
||||
static int last_token_size;
|
||||
static bool tokenWrapAroundEnabled;
|
||||
|
||||
static Test *test();
|
||||
static PerFrameEqn *parse_per_frame_eqn( std::istream & fs, int index,
|
||||
MilkdropPreset * preset);
|
||||
static int parse_per_pixel_eqn( std::istream & fs, MilkdropPreset * preset,
|
||||
|
||||
@ -36,8 +36,8 @@
|
||||
#include <cassert>
|
||||
|
||||
/* Evaluate an equation */
|
||||
void PerFrameEqn::evaluate() {
|
||||
|
||||
void PerFrameEqn::evaluate()
|
||||
{
|
||||
if (PER_FRAME_EQN_DEBUG) {
|
||||
printf("per_frame_%d=%s= ", index, param->name.c_str());
|
||||
fflush(stdout);
|
||||
@ -46,20 +46,19 @@ void PerFrameEqn::evaluate() {
|
||||
//*((float*)per_frame_eqn->param->engine_val) = eval(per_frame_eqn->gen_expr);
|
||||
assert(gen_expr);
|
||||
assert(param);
|
||||
param->set_param(gen_expr->eval(-1,-1));
|
||||
float v = gen_expr->eval(-1,-1);
|
||||
param->set_param(v);
|
||||
|
||||
if (PER_FRAME_EQN_DEBUG) printf(" = %.4f\n", *((float*)param->engine_val));
|
||||
|
||||
if (PER_FRAME_EQN_DEBUG) printf(" = %.4f\n", v);
|
||||
}
|
||||
|
||||
|
||||
/* Frees perframe equation structure. Warning: assumes gen_expr pointer is not freed by anyone else! */
|
||||
PerFrameEqn::~PerFrameEqn() {
|
||||
|
||||
delete gen_expr;
|
||||
|
||||
// param is freed in param_tree container of some other class
|
||||
PerFrameEqn::~PerFrameEqn()
|
||||
{
|
||||
Expr::delete_expr(gen_expr);
|
||||
|
||||
// param is freed in param_tree container of some other class
|
||||
}
|
||||
|
||||
/* Create a new per frame equation */
|
||||
|
||||
@ -35,47 +35,23 @@
|
||||
|
||||
#include "wipemalloc.h"
|
||||
#include <cassert>
|
||||
|
||||
/* Evaluates a per pixel equation */
|
||||
void PerPixelEqn::evaluate(int mesh_i, int mesh_j) {
|
||||
|
||||
Expr * eqn_ptr = 0;
|
||||
|
||||
|
||||
eqn_ptr = this->gen_expr;
|
||||
|
||||
float ** param_matrix = (float**)this->param->matrix;
|
||||
|
||||
if (param_matrix == 0) {
|
||||
assert(param->engine_val);
|
||||
(*(float*)param->engine_val) = eqn_ptr->eval(mesh_i, mesh_j);
|
||||
|
||||
} else {
|
||||
|
||||
assert(!(eqn_ptr == NULL || param_matrix == NULL));
|
||||
|
||||
param_matrix[mesh_i][mesh_j] = eqn_ptr->eval(mesh_i, mesh_j);
|
||||
|
||||
/* Now that this parameter has been referenced with a per
|
||||
pixel equation, we let the evaluator know by setting
|
||||
this flag */
|
||||
/// @bug review and verify this behavior
|
||||
param->matrix_flag = true;
|
||||
param->flags |= P_FLAG_PER_PIXEL;
|
||||
}
|
||||
void PerPixelEqn::evaluate(int mesh_i, int mesh_j)
|
||||
{
|
||||
assign_expr->eval( mesh_i, mesh_j );
|
||||
}
|
||||
|
||||
PerPixelEqn::PerPixelEqn(int _index, Param * _param, Expr * _gen_expr):index(_index), param(_param), gen_expr(_gen_expr) {
|
||||
|
||||
PerPixelEqn::PerPixelEqn(int _index, Param * param, Expr * gen_expr):index(_index)
|
||||
{
|
||||
assert(index >= 0);
|
||||
assert(param != 0);
|
||||
assert(gen_expr != 0);
|
||||
|
||||
assign_expr = new AssignMatrixExpr(param, gen_expr);
|
||||
}
|
||||
|
||||
|
||||
PerPixelEqn::~PerPixelEqn()
|
||||
{
|
||||
if (gen_expr)
|
||||
delete (gen_expr);
|
||||
|
||||
Expr::delete_expr(assign_expr);
|
||||
}
|
||||
|
||||
@ -51,9 +51,6 @@ class Preset;
|
||||
class PerPixelEqn {
|
||||
public:
|
||||
int index; /* used for splay tree ordering. */
|
||||
int flags; /* primarily to specify if this variable is user-defined */
|
||||
Param *param;
|
||||
Expr *gen_expr;
|
||||
|
||||
void evalPerPixelEqns( Preset *preset );
|
||||
void evaluate(int mesh_i, int mesh_j);
|
||||
@ -61,6 +58,7 @@ public:
|
||||
|
||||
PerPixelEqn(int index, Param * param, Expr * gen_expr);
|
||||
|
||||
Expr *assign_expr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -40,51 +40,17 @@
|
||||
/* Evaluates a per point equation for the current custom wave given by interface_wave ptr */
|
||||
void PerPointEqn::evaluate(int i)
|
||||
{
|
||||
|
||||
float * param_matrix;
|
||||
Expr * eqn_ptr;
|
||||
|
||||
// samples = CustomWave::interface_wave->samples;
|
||||
|
||||
eqn_ptr = gen_expr;
|
||||
|
||||
if (param->matrix == NULL)
|
||||
{
|
||||
assert(param->matrix_flag == false);
|
||||
(*(float*)param->engine_val) = eqn_ptr->eval(i,-1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
param_matrix = (float*)param->matrix;
|
||||
|
||||
// -1 is because per points only use one dimension
|
||||
param_matrix[i] = eqn_ptr->eval(i, -1);
|
||||
|
||||
|
||||
/* Now that this parameter has been referenced with a per
|
||||
point equation, we let the evaluator know by setting
|
||||
this flag */
|
||||
|
||||
if (!param->matrix_flag)
|
||||
param->matrix_flag = true;
|
||||
|
||||
}
|
||||
|
||||
assign_expr->eval( i, -1 );
|
||||
}
|
||||
|
||||
PerPointEqn::PerPointEqn(int _index, Param * _param, Expr * _gen_expr, int _samples):
|
||||
index(_index),
|
||||
samples(_samples),
|
||||
param(_param),
|
||||
gen_expr(_gen_expr)
|
||||
|
||||
{}
|
||||
PerPointEqn::PerPointEqn(int _index, Param * param, Expr * gen_expr):
|
||||
index(_index)
|
||||
{
|
||||
assign_expr = new AssignExpr(param, gen_expr);
|
||||
}
|
||||
|
||||
|
||||
PerPointEqn::~PerPointEqn()
|
||||
{
|
||||
delete gen_expr;
|
||||
Expr::delete_expr(assign_expr);
|
||||
}
|
||||
|
||||
@ -37,12 +37,10 @@ class PerPointEqn;
|
||||
class PerPointEqn {
|
||||
public:
|
||||
int index;
|
||||
int samples; // the number of samples to iterate over
|
||||
Param *param;
|
||||
Expr * gen_expr;
|
||||
Expr * assign_expr;
|
||||
~PerPointEqn();
|
||||
void evaluate(int i);
|
||||
PerPointEqn( int index, Param *param, Expr *gen_expr, int samples);
|
||||
PerPointEqn( int index, Param *param, Expr *gen_expr );
|
||||
};
|
||||
|
||||
|
||||
|
||||
43
src/libprojectM/TestRunner.cpp
Normal file
43
src/libprojectM/TestRunner.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by matthew on 1/7/19.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <MilkdropPresetFactory/Parser.hpp>
|
||||
#include <TestRunner.hpp>
|
||||
#include <MilkdropPresetFactory/Param.hpp>
|
||||
|
||||
std::vector<Test *> TestRunner::tests;
|
||||
|
||||
|
||||
bool TestRunner::run()
|
||||
{
|
||||
if (tests.empty())
|
||||
{
|
||||
// We still call register/run tests in NDEBUG (useful for performance testing)
|
||||
// but tests may choose to comment out body to save space
|
||||
tests.push_back(Param::test());
|
||||
tests.push_back(Parser::test());
|
||||
tests.push_back(Expr::test());
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
bool successful = true;
|
||||
for (auto it=tests.begin() ; it < tests.end() ; it++ )
|
||||
{
|
||||
if (nullptr == (*it))
|
||||
continue;
|
||||
count++;
|
||||
std::cout << "TestRunner: " << (*it)->getName() << " started" << std::endl;
|
||||
std::cout.flush();
|
||||
bool result = (*it)->test();
|
||||
successful &= result;
|
||||
if (result)
|
||||
std::cout << "TestRunner: " << (*it)->getName() << " passed" << std::endl;
|
||||
else
|
||||
std::cout << "TestRunner: " << (*it)->getName() << " FAILED" << std::endl;
|
||||
}
|
||||
if (0 == count)
|
||||
std::cout << "TestRunner: no tests found to run" << std::endl;
|
||||
return successful;
|
||||
}
|
||||
48
src/libprojectM/TestRunner.hpp
Normal file
48
src/libprojectM/TestRunner.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by matthew on 1/7/19.
|
||||
//
|
||||
// This is a place to collect/run non-graphical unit tests
|
||||
// CONSIDER using some framework like googletest etc, but for now didn't want new dependencies
|
||||
//
|
||||
|
||||
#ifndef PROJECTM_LUA_TESTRUNNER_H
|
||||
#define PROJECTM_LUA_TESTRUNNER_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
const std::string getName() { return name; };
|
||||
#ifdef NDEBUG
|
||||
virtual bool test() {return true;}
|
||||
#else
|
||||
virtual bool test() = 0;
|
||||
#endif
|
||||
virtual ~Test() = default;
|
||||
protected:
|
||||
explicit Test(std::string name_) : name(name_) {};
|
||||
const std::string name;
|
||||
|
||||
bool verify(const char *test, bool success)
|
||||
{
|
||||
if (!success)
|
||||
std::cout << "failed " << test << std::endl;
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TestRunner
|
||||
{
|
||||
public:
|
||||
static bool run();
|
||||
private:
|
||||
static std::vector<Test *> tests;
|
||||
};
|
||||
|
||||
|
||||
#endif //PROJECTM_LUA_TESTRUNNER_H
|
||||
@ -74,6 +74,7 @@ std::string read_config();
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <src/libprojectM/TestRunner.hpp>
|
||||
|
||||
//#include <pulsecore/gccmacro.h>
|
||||
|
||||
@ -108,6 +109,8 @@ class ProjectMApplication : public QApplication {
|
||||
|
||||
int main ( int argc, char*argv[] )
|
||||
{
|
||||
// if (!TestRunner::run()) exit(1);
|
||||
|
||||
int i;
|
||||
char projectM_data[1024];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user