540 lines
13 KiB
C++
540 lines
13 KiB
C++
|
/**
|
||
|
* 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 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 <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <sstream>
|
||
|
|
||
|
#include "Common.hpp"
|
||
|
#include "fatal.h"
|
||
|
|
||
|
#include "CustomWave.hpp"
|
||
|
#include "Eval.hpp"
|
||
|
#include "Expr.hpp"
|
||
|
#include "InitCond.hpp"
|
||
|
#include "Param.hpp"
|
||
|
#include "PerFrameEqn.hpp"
|
||
|
#include "PerPointEqn.hpp"
|
||
|
#include "Preset.hpp"
|
||
|
#include <map>
|
||
|
#include "ParamUtils.hpp"
|
||
|
#include "InitCondUtils.hpp"
|
||
|
#include "wipemalloc.h"
|
||
|
#define MAX_SAMPLE_SIZE 4096
|
||
|
|
||
|
|
||
|
CustomWave::CustomWave(int _id) : Waveform(512),
|
||
|
id(_id),
|
||
|
per_frame_count(0),
|
||
|
r(0),
|
||
|
g(0),
|
||
|
b(0),
|
||
|
a(0)
|
||
|
{
|
||
|
|
||
|
Param * param;
|
||
|
|
||
|
/// @bug deprecate the use of wipemalloc
|
||
|
this->r_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->g_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->b_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->a_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->x_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->y_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->value1 = (float*) wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->value2 = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
this->sample_mesh = (float*)wipemalloc(MAX_SAMPLE_SIZE*sizeof(float));
|
||
|
|
||
|
/* Start: Load custom wave parameters */
|
||
|
|
||
|
if ((param = Param::new_param_float("r", P_FLAG_NONE | P_FLAG_PER_POINT, &this->r, this->r_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, ¶m_tree) < 0)
|
||
|
{
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("g", P_FLAG_NONE | P_FLAG_PER_POINT, &this->g, this->g_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, ¶m_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("b", P_FLAG_NONE | P_FLAG_PER_POINT, &this->b, this->b_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("a", P_FLAG_NONE | P_FLAG_PER_POINT, &this->a, this->a_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("x", P_FLAG_NONE | P_FLAG_PER_POINT, &this->x, this->x_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("y", P_FLAG_NONE | P_FLAG_PER_POINT, &this->y, this->y_mesh, 1.0, 0.0, .5)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_bool("enabled", P_FLAG_NONE, &this->enabled, 1, 0, 0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_int("sep", P_FLAG_NONE, &this->sep, 100, -100, 0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_bool("bspectrum", P_FLAG_NONE, &this->spectrum, 1, 0, 0)) == NULL)
|
||
|
{
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_bool("bdrawthick", P_FLAG_NONE, &this->thick, 1, 0, 0)) == NULL)
|
||
|
{
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_bool("busedots", P_FLAG_NONE, &this->dots, 1, 0, 0)) == NULL)
|
||
|
{
|
||
|
|
||
|
/// @bug make exception
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_bool("badditive", P_FLAG_NONE, &this->additive, 1, 0, 0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_int("samples", P_FLAG_NONE, &this->samples, 2048, 1, 512)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("sample", P_FLAG_READONLY | P_FLAG_NONE | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT,
|
||
|
&this->sample, this->sample_mesh, 1.0, 0.0, 0.0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("value1", P_FLAG_READONLY | P_FLAG_NONE | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT, &this->v1, this->value1, 1.0, -1.0, 0.0)) == NULL)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("value2", P_FLAG_READONLY | P_FLAG_NONE | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT, &this->v2, this->value2, 1.0, -1.0, 0.0)) == NULL)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("smoothing", P_FLAG_NONE, &this->smoothing, NULL, 1.0, 0.0, 0.0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if ((param = Param::new_param_float("scaling", P_FLAG_NONE, &this->scaling, NULL, MAX_DOUBLE_SIZE, 0.0, 1.0)) == NULL)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
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)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
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)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
if ((param = Param::new_param_float("t5", P_FLAG_TVAR, &this->t5, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
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)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
if (ParamUtils::insert(param, &this->param_tree) < 0)
|
||
|
{
|
||
|
;
|
||
|
abort();
|
||
|
}
|
||
|
|
||
|
for (unsigned int i = 1; i <= NUM_Q_VARIABLES;i++) {
|
||
|
std::ostringstream os;
|
||
|
os << "q" << i;
|
||
|
param = Param::new_param_float ( os.str().c_str(), P_FLAG_QVAR, &this->q[i], NULL, MAX_DOUBLE_SIZE,
|
||
|
-MAX_DOUBLE_SIZE, 0.0 );
|
||
|
if ( ParamUtils::insert ( param, &this->param_tree ) < 0 )
|
||
|
{
|
||
|
abort();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* End of parameter loading. Note that the read only parameters associated
|
||
|
with custom waves (ie, sample) are variables stored in PresetFrameIO.hpp,
|
||
|
and not specific to the custom wave datastructure. */
|
||
|
|
||
|
}
|
||
|
|
||
|
CustomWave::~CustomWave()
|
||
|
{
|
||
|
|
||
|
|
||
|
for (std::vector<PerPointEqn*>::iterator pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end(); ++pos)
|
||
|
delete(*pos);
|
||
|
|
||
|
for (std::vector<PerFrameEqn*>::iterator pos = per_frame_eqn_tree.begin(); pos != per_frame_eqn_tree.end(); ++pos)
|
||
|
delete(*pos);
|
||
|
|
||
|
for (std::map<std::string, InitCond*>::iterator pos = init_cond_tree.begin(); pos != init_cond_tree.end(); ++pos)
|
||
|
delete(pos->second);
|
||
|
|
||
|
for (std::map<std::string, InitCond*>::iterator pos = per_frame_init_eqn_tree.begin(); pos != per_frame_init_eqn_tree.end(); ++pos)
|
||
|
delete(pos->second);
|
||
|
|
||
|
for (std::map<std::string, Param*>::iterator pos = param_tree.begin(); pos != param_tree.end(); ++pos)
|
||
|
delete(pos->second);
|
||
|
|
||
|
free(r_mesh);
|
||
|
free(g_mesh);
|
||
|
free(b_mesh);
|
||
|
free(a_mesh);
|
||
|
free(x_mesh);
|
||
|
free(y_mesh);
|
||
|
free(value1);
|
||
|
free(value2);
|
||
|
free(sample_mesh);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Comments: index is not passed, so we assume monotonic increment by 1 is ok here
|
||
|
int CustomWave::add_per_point_eqn(char * name, GenExpr * gen_expr)
|
||
|
{
|
||
|
|
||
|
PerPointEqn * per_point_eqn;
|
||
|
int index;
|
||
|
Param * param = NULL;
|
||
|
|
||
|
/* Argument checks */
|
||
|
if (gen_expr == NULL)
|
||
|
return PROJECTM_FAILURE;
|
||
|
if (name == NULL)
|
||
|
return PROJECTM_FAILURE;
|
||
|
|
||
|
if (CUSTOM_WAVE_DEBUG) printf("add_per_point_eqn: per pixel equation (name = \"%s\")\n", name);
|
||
|
|
||
|
/* Search for the parameter so we know what matrix the per pixel equation is referencing */
|
||
|
|
||
|
if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(name,¶m_tree)) == NULL)
|
||
|
{
|
||
|
if (CUSTOM_WAVE_DEBUG) printf("add_per_point_eqn: failed to allocate a new parameter!\n");
|
||
|
return PROJECTM_FAILURE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Get largest index in the tree */
|
||
|
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)
|
||
|
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());
|
||
|
|
||
|
/* Insert the per pixel equation into the preset per pixel database */
|
||
|
|
||
|
per_point_eqn_tree.push_back(per_point_eqn);
|
||
|
|
||
|
/* Done */
|
||
|
return PROJECTM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CustomWave::evalInitConds()
|
||
|
{
|
||
|
|
||
|
for (std::map<std::string, InitCond*>::iterator pos = per_frame_init_eqn_tree.begin(); pos != per_frame_init_eqn_tree.end(); ++pos)
|
||
|
{
|
||
|
assert(pos->second);
|
||
|
pos->second->evaluate();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
sample_mesh[context.sample_int] = context.sample;
|
||
|
v1 = context.left;
|
||
|
v2 = context.right;
|
||
|
|
||
|
for (std::vector<PerPointEqn*>::iterator pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end();++pos)
|
||
|
(*pos)->evaluate(context.sample_int);
|
||
|
|
||
|
p.a = a_mesh[context.sample_int];
|
||
|
p.r = r_mesh[context.sample_int];
|
||
|
p.g = g_mesh[context.sample_int];
|
||
|
p.b = b_mesh[context.sample_int];
|
||
|
p.x = x_mesh[context.sample_int];
|
||
|
p.y = y_mesh[context.sample_int];
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CustomWave::loadUnspecInitConds()
|
||
|
{
|
||
|
|
||
|
InitCondUtils::LoadUnspecInitCond fun(this->init_cond_tree, this->per_frame_init_eqn_tree);
|
||
|
traverse(param_tree, fun);
|
||
|
}
|
||
|
|