More shape and wave rendering fixes.

This commit is contained in:
Kai Blaschke
2021-12-12 17:05:32 +01:00
parent d272d4a354
commit c6078b7887
13 changed files with 652 additions and 930 deletions

View File

@ -1,7 +1,7 @@
if(ENABLE_TESTING)
install(DIRECTORY
tests
DESTINATION "${PROJECTM_DATADIR_PATH}/presets"
DESTINATION "presets"
COMPONENT Tests
)
endif()

View File

@ -36,220 +36,148 @@
#include "wipemalloc.h"
CustomShape::CustomShape() : Shape()
CustomShape::CustomShape()
: CustomShape(0)
{
CustomShape(0);
}
CustomShape::CustomShape ( int _id ) : Shape()
CustomShape::CustomShape(int _id)
: Shape()
{
Param * param;
this->id = _id;
this->per_frame_count = 0;
this->per_frame_count = 0;
/* Start: Load custom shape parameters */
param = Param::new_param_float ( "r", P_FLAG_NONE, &this->r, NULL, 1.0, 0.0, 0.5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "g", P_FLAG_NONE, &this->g, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "b", P_FLAG_NONE, &this->b, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "a", P_FLAG_NONE, &this->a, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "border_r", P_FLAG_NONE, &this->border_r, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "border_g", P_FLAG_NONE, &this->border_g, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "border_b", P_FLAG_NONE, &this->border_b, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "border_a", P_FLAG_NONE, &this->border_a, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "r2", P_FLAG_NONE, &this->r2, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "g2", P_FLAG_NONE, &this->g2, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "b2", P_FLAG_NONE, &this->b2, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "a2", P_FLAG_NONE, &this->a2, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "x", P_FLAG_NONE, &this->x, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "y", P_FLAG_NONE, &this->y, NULL, 1.0, 0.0, .5 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_bool ( "thickoutline", P_FLAG_NONE, &this->thickOutline, 1, 0, 0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_bool ( "enabled", P_FLAG_NONE, &this->enabled, 1, 0, 0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_int ( "sides", P_FLAG_NONE, &this->sides, 100, 3, 3 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_bool ( "additive", P_FLAG_NONE, &this->additive, 1, 0, 0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_bool ( "textured", P_FLAG_NONE, &this->textured, 1, 0, 0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "rad", P_FLAG_NONE, &this->radius, NULL, MAX_DOUBLE_SIZE, 0, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "ang", P_FLAG_NONE, &this->ang, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "tex_zoom", P_FLAG_NONE, &this->tex_zoom, NULL, MAX_DOUBLE_SIZE, .00000000001, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "tex_ang", P_FLAG_NONE, &this->tex_ang, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
/* Start: Load custom shape parameters */
ParamUtils::insert(Param::new_param_float(
"r", P_FLAG_NONE, &this->r, nullptr, 1.0, 0.0, 0.5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"g", P_FLAG_NONE, &this->g, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"b", P_FLAG_NONE, &this->b, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"a", P_FLAG_NONE, &this->a, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"border_r", P_FLAG_NONE, &this->border_r, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"border_g", P_FLAG_NONE, &this->border_g, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"border_b", P_FLAG_NONE, &this->border_b, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"border_a", P_FLAG_NONE, &this->border_a, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"r2", P_FLAG_NONE, &this->r2, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"g2", P_FLAG_NONE, &this->g2, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"b2", P_FLAG_NONE, &this->b2, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"a2", P_FLAG_NONE, &this->a2, nullptr, 1.0, 0.0, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"x", P_FLAG_NONE, &this->x, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"y", P_FLAG_NONE, &this->y, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, .5), &this->param_tree);
ParamUtils::insert(Param::new_param_bool(
"thickoutline", P_FLAG_NONE, &this->thickOutline, 1, 0, 0), &this->param_tree);
ParamUtils::insert(Param::new_param_bool(
"enabled", P_FLAG_NONE, &this->enabled, 1, 0, 0), &this->param_tree);
ParamUtils::insert(Param::new_param_int(
"sides", P_FLAG_NONE, &this->sides, 100, 3, 3), &this->param_tree);
ParamUtils::insert(Param::new_param_bool(
"additive", P_FLAG_NONE, &this->additive, 1, 0, 0), &this->param_tree);
ParamUtils::insert(Param::new_param_bool(
"textured", P_FLAG_NONE, &this->textured, 1, 0, 0), &this->param_tree);
ParamUtils::insert(Param::new_param_int(
"num_inst", P_FLAG_NONE, &this->num_inst, 1000, 1, 1), &this->param_tree);
ParamUtils::insert(Param::new_param_int(
"instance", P_FLAG_READONLY, &this->instance, 999, 0, 0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"rad", P_FLAG_NONE, &this->radius, nullptr, MAX_DOUBLE_SIZE, 0, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"ang", P_FLAG_NONE, &this->ang, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"tex_zoom", P_FLAG_NONE, &this->tex_zoom, nullptr, MAX_DOUBLE_SIZE, .00000000001, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"tex_ang", P_FLAG_NONE, &this->tex_ang, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t1", P_FLAG_TVAR, &this->t1, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t2", P_FLAG_TVAR, &this->t2, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t3", P_FLAG_TVAR, &this->t3, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t4", P_FLAG_TVAR, &this->t4, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t5", P_FLAG_TVAR, &this->t5, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t6", P_FLAG_TVAR, &this->t6, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t7", P_FLAG_TVAR, &this->t7, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
ParamUtils::insert(Param::new_param_float(
"t8", P_FLAG_TVAR, &this->t8, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
param = Param::new_param_float ( "t1", P_FLAG_TVAR, &this->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t2", P_FLAG_TVAR, &this->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t3", P_FLAG_TVAR, &this->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t4", P_FLAG_TVAR, &this->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t5", P_FLAG_TVAR, &this->t5, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t6", P_FLAG_TVAR, &this->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t7", P_FLAG_TVAR, &this->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
param = Param::new_param_float ( "t8", P_FLAG_TVAR, &this->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0 );
if ( !ParamUtils::insert( param, &this->param_tree ) )
{
abort();
}
for (unsigned int i = 0; i < NUM_Q_VARIABLES;i++) {
std::ostringstream os;
os << "q" << i+1;
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 ) )
{
abort();
}
}
param = Param::new_param_string ( "imageurl", P_FLAG_NONE, &this->imageUrl);
if ( !ParamUtils::insert( param, &this->text_properties_tree ) )
{
abort();
}
for (unsigned int i = 0; i < NUM_Q_VARIABLES; i++)
{
std::ostringstream os;
os << "q" << i + 1;
ParamUtils::insert(Param::new_param_float(
os.str().c_str(), P_FLAG_QVAR, &this->q[i], nullptr,
MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &this->param_tree);
}
}
/* Frees a custom shape form object */
CustomShape::~CustomShape()
{
traverseVector<TraverseFunctors::Delete<PerFrameEqn> > ( per_frame_eqn_tree );
traverse<TraverseFunctors::Delete<InitCond> > ( init_cond_tree );
traverse<TraverseFunctors::Delete<Param> > ( param_tree );
traverse<TraverseFunctors::Delete<InitCond> > ( per_frame_init_eqn_tree );
traverse<TraverseFunctors::Delete<Param> > ( text_properties_tree );
traverseVector<TraverseFunctors::Delete<PerFrameEqn> >(per_frame_eqn_tree);
traverse<TraverseFunctors::Delete<InitCond> >(init_cond_tree);
traverse<TraverseFunctors::Delete<Param> >(param_tree);
traverse<TraverseFunctors::Delete<InitCond> >(per_frame_init_eqn_tree);
traverse<TraverseFunctors::Delete<Param> >(text_properties_tree);
}
void CustomShape::loadUnspecInitConds()
{
InitCondUtils::LoadUnspecInitCond fun ( this->init_cond_tree, this->per_frame_init_eqn_tree );
traverse ( param_tree, fun );
InitCondUtils::LoadUnspecInitCond fun(this->init_cond_tree, this->per_frame_init_eqn_tree);
traverse(param_tree, fun);
}
void CustomShape::evalInitConds()
{
// NOTE: This is verified to be same behavior as trunk
for ( std::map<std::string, InitCond*>::iterator pos = per_frame_init_eqn_tree.begin();
pos != per_frame_init_eqn_tree.end();++pos )
pos->second->evaluate();
for (auto& pos: per_frame_init_eqn_tree)
{
pos.second->evaluate();
}
t1Init = t1;
t2Init = t2;
t3Init = t3;
t4Init = t4;
t5Init = t5;
t6Init = t6;
t7Init = t7;
t8Init = t8;
}
void CustomShape::Draw(RenderContext& context)
{
for (int i = 0; i < num_inst; i++)
{
t1 = t1Init;
t2 = t2Init;
t3 = t3Init;
t4 = t4Init;
t5 = t5Init;
t6 = t6Init;
t7 = t7Init;
t8 = t8Init;
instance = i;
for (auto& pos: per_frame_eqn_tree)
{
pos->evaluate();
}
Shape::Draw(context);
}
}

View File

@ -30,6 +30,7 @@
#define _CUSTOM_SHAPE_H
#define CUSTOM_SHAPE_DEBUG 0
#include <map>
#include "Param.hpp"
#include "PerFrameEqn.hpp"
@ -40,50 +41,68 @@
class Preset;
class CustomShape : public Shape {
class CustomShape : public Shape
{
public:
/* Numerical id */
int id;
int per_frame_count;
int id{ 0 };
int per_frame_count{ 0 };
/* Parameter tree associated with this custom shape */
std::map<std::string,Param*> param_tree;
std::map<std::string, Param*> param_tree;
/* Engine variables */
bool enabled;
bool enabled{ false };
int num_inst{ 1 }; //!< Number of shape instances to render
int instance{ 0 }; //!< Currently rendered instance
/* stupid t variables */
float t1;
float t2;
float t3;
float t4;
float t5;
float t6;
float t7;
float t8;
float t1{ 0.0f };
float t2{ 0.0f };
float t3{ 0.0f };
float t4{ 0.0f };
float t5{ 0.0f };
float t6{ 0.0f };
float t7{ 0.0f };
float t8{ 0.0f };
float t1Init{ 0.0f };
float t2Init{ 0.0f };
float t3Init{ 0.0f };
float t4Init{ 0.0f };
float t5Init{ 0.0f };
float t6Init{ 0.0f };
float t7Init{ 0.0f };
float t8Init{ 0.0f };
/* stupider q variables */
float q[NUM_Q_VARIABLES];
float q[NUM_Q_VARIABLES]{};
// Data structure to hold per frame / per frame init equations
std::map<std::string,InitCond*> init_cond_tree;
std::vector<PerFrameEqn*> per_frame_eqn_tree;
std::map<std::string,InitCond*> per_frame_init_eqn_tree;
std::map<std::string, InitCond*> init_cond_tree;
std::vector<PerFrameEqn*> per_frame_eqn_tree;
std::map<std::string, InitCond*> per_frame_init_eqn_tree;
std::map<std::string, Param*> text_properties_tree;
/// Allocate a new custom shape, including param associations, per point equations, and initial values.
/// \param id an integer id to associate with this custom wave. Future line parsing uses this as a reference key.
CustomShape(int _id );
CustomShape(int _id);
CustomShape();
virtual ~CustomShape();
void loadUnspecInitConds();
void evalInitConds();
};
void Draw(RenderContext& context) override;
};
#endif /** !_CUSTOM_SHAPE_H */

View File

@ -43,469 +43,165 @@
#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),
per_point_program(nullptr)
CustomWave::CustomWave(int _id)
: Waveform(512)
, id(_id)
{
this->r_mesh.resize(MAX_SAMPLE_SIZE);
this->g_mesh.resize(MAX_SAMPLE_SIZE);
this->b_mesh.resize(MAX_SAMPLE_SIZE);
this->a_mesh.resize(MAX_SAMPLE_SIZE);
this->x_mesh.resize(MAX_SAMPLE_SIZE);
this->y_mesh.resize(MAX_SAMPLE_SIZE);
/* Start: Load custom wave parameters */
ParamUtils::insert(Param::new_param_float(
"r", P_FLAG_NONE | P_FLAG_PER_POINT, &r, r_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_float(
"g", P_FLAG_NONE | P_FLAG_PER_POINT, &g, g_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_float(
"b", P_FLAG_NONE | P_FLAG_PER_POINT, &b, b_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_float(
"a", P_FLAG_NONE | P_FLAG_PER_POINT, &this->a, this->a_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_float(
"x", P_FLAG_NONE | P_FLAG_PER_POINT, &this->x, this->x_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_float(
"y", P_FLAG_NONE | P_FLAG_PER_POINT, &this->y, this->y_mesh.data(), 1.0, 0.0, .5), &param_tree);
ParamUtils::insert(Param::new_param_bool(
"enabled", P_FLAG_NONE, &this->enabled, 1, 0, 0), &param_tree);
ParamUtils::insert(Param::new_param_int(
"sep", P_FLAG_NONE, &this->sep, 100, -100, 0), &param_tree);
ParamUtils::insert(Param::new_param_bool(
"bspectrum", P_FLAG_NONE, &this->spectrum, 1, 0, 0), &param_tree);
ParamUtils::insert(Param::new_param_bool(
"bdrawthick", P_FLAG_NONE, &this->thick, 1, 0, 0), &param_tree);
ParamUtils::insert(Param::new_param_bool(
"busedots", P_FLAG_NONE, &this->dots, 1, 0, 0), &param_tree);
ParamUtils::insert(Param::new_param_bool(
"badditive", P_FLAG_NONE, &this->additive, 1, 0, 0), &param_tree);
ParamUtils::insert(Param::new_param_int(
"samples", P_FLAG_NONE, &this->samples, 2048, 1, 512), &param_tree);
ParamUtils::insert(Param::new_param_float(
"sample", P_FLAG_READONLY | P_FLAG_NONE, &this->sample, nullptr, 1.0, 0.0, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"value1", P_FLAG_READONLY | P_FLAG_NONE, &this->v1, nullptr, 1.0, -1.0, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"value2", P_FLAG_READONLY | P_FLAG_NONE, &this->v2, nullptr, 1.0, -1.0, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"smoothing", P_FLAG_NONE, &this->smoothing, nullptr, 1.0, 0.0, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"scaling", P_FLAG_NONE, &this->scaling, nullptr, MAX_DOUBLE_SIZE, 0.0, 1.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t1", P_FLAG_TVAR, &this->t1, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t2", P_FLAG_TVAR, &this->t2, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t3", P_FLAG_TVAR, &this->t3, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t4", P_FLAG_TVAR, &this->t4, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t5", P_FLAG_TVAR, &this->t5, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t6", P_FLAG_TVAR, &this->t6, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0),&param_tree);
ParamUtils::insert(Param::new_param_float(
"t7", P_FLAG_TVAR, &this->t7, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
ParamUtils::insert(Param::new_param_float(
"t8", P_FLAG_TVAR, &this->t8, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), &param_tree);
for (unsigned int i = 0; i < NUM_Q_VARIABLES; i++)
{
std::ostringstream os;
os << "q" << i + 1;
ParamUtils::insert(Param::new_param_float(
os.str().c_str(), P_FLAG_QVAR, &this->q[i], nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE,0.0), &this->param_tree);
}
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));
/* 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, &param_tree))
{
/// @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, &param_tree))
{
;
/// @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))
{
;
/// @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))
{
;
/// @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))
{
;
/// @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))
{
;
/// @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))
{
;
/// @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))
{
;
/// @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))
{
/// @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))
{
/// @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))
{
;
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))
{
;
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))
{
;
abort();
}
if ((param = Param::new_param_float("sample", P_FLAG_READONLY | P_FLAG_NONE,
&this->sample, NULL, 1.0, 0.0, 0.0)) == NULL)
{
;
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
abort();
}
if ((param = Param::new_param_float("value1", P_FLAG_READONLY | P_FLAG_NONE, &this->v1, NULL, 1.0, -1.0, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
abort();
}
if ((param = Param::new_param_float("value2", P_FLAG_READONLY | P_FLAG_NONE, &this->v2, NULL, 1.0, -1.0, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
;
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))
{
;
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))
{
;
abort();
}
if ((param = Param::new_param_float("t1", P_FLAG_TVAR, &this->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
;
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
;
abort();
}
if ((param = Param::new_param_float("t2", P_FLAG_TVAR, &this->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
;
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
abort();
}
if ((param = Param::new_param_float("t3", P_FLAG_TVAR, &this->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
abort();
}
if ((param = Param::new_param_float("t4", P_FLAG_TVAR, &this->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
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))
{
abort();
}
if ((param = Param::new_param_float("t6", P_FLAG_TVAR, &this->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
abort();
}
if ((param = Param::new_param_float("t7", P_FLAG_TVAR, &this->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
;
abort();
}
if ((param = Param::new_param_float("t8", P_FLAG_TVAR, &this->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL)
{
;
abort();
}
if (!ParamUtils::insert(param, &this->param_tree))
{
;
abort();
}
for (unsigned int i = 0; i < NUM_Q_VARIABLES;i++) {
std::ostringstream os;
os << "q" << i+1;
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 ) )
{
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. */
and not specific to the custom wave data structure. */
}
CustomWave::~CustomWave()
{
for (const auto& eqn : per_point_eqn_tree)
{
delete eqn;
}
for (const auto& eqn : per_frame_eqn_tree)
{
delete eqn;
}
for (std::vector<PerPointEqn*>::iterator pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end(); ++pos)
delete(*pos);
for (const auto& cond : init_cond_tree)
{
delete cond.second;
}
for (std::vector<PerFrameEqn*>::iterator pos = per_frame_eqn_tree.begin(); pos != per_frame_eqn_tree.end(); ++pos)
delete(*pos);
for (const auto& cond : per_frame_init_eqn_tree)
{
delete cond.second;
}
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);
for (const auto& param : param_tree)
{
delete param.second;
}
}
// Comments: index is not passed, so we assume monotonic increment by 1 is ok here
int CustomWave::add_per_point_eqn(char * name, Expr * gen_expr)
int CustomWave::add_per_point_eqn(char* name, Expr* gen_expr)
{
/* Argument checks */
if (!gen_expr || !name)
{
return PROJECTM_FAILURE;
}
PerPointEqn * per_point_eqn;
int index;
Param * param = NULL;
if (CUSTOM_WAVE_DEBUG)
{
printf("add_per_point_eqn: per pixel equation (name = \"%s\")\n", name);
}
/* Argument checks */
if (gen_expr == NULL)
return PROJECTM_FAILURE;
if (name == NULL)
return PROJECTM_FAILURE;
/* Search for the parameter so we know what matrix the per pixel equation is referencing */
auto param = ParamUtils::find<ParamUtils::AUTO_CREATE>(name, &param_tree);
if (!param)
{
if (CUSTOM_WAVE_DEBUG)
{
printf("add_per_point_eqn: failed to allocate a new parameter!\n");
}
return PROJECTM_FAILURE;
}
if (CUSTOM_WAVE_DEBUG) printf("add_per_point_eqn: per pixel equation (name = \"%s\")\n", name);
/* Get largest index in the tree */
per_point_eqn_tree.push_back(new PerPointEqn(static_cast<int>(per_point_eqn_tree.size()), param, gen_expr));
/* Search for the parameter so we know what matrix the per pixel equation is referencing */
if ((param = ParamUtils::find<ParamUtils::AUTO_CREATE>(name,&param_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)) == 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, 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;
/* 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();
}
for (auto& eqn: per_frame_init_eqn_tree)
{
assert(eqn.second);
eqn.second->evaluate();
}
}
ColoredPoint CustomWave::PerPoint(ColoredPoint p, const WaveformContext context)
Waveform::ColoredPoint CustomWave::PerPoint(ColoredPoint p, const Context& context)
{
if (nullptr == per_point_program)
if (!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);
std::vector<Expr*> steps;
for (const auto& eqn : per_point_eqn_tree)
{
steps.push_back(eqn->assign_expr);
}
Expr *program_expr = Expr::create_program_expr(steps, false);
Expr *jit = nullptr;
#if HAVE_LLVM

View File

@ -18,109 +18,99 @@
* See 'LICENSE.txt' included within this release
*
*/
/**
* $Id$
*
* Encapsulation of a custom wave
*
* $Log$
*/
#ifndef _CUSTOM_WAVE_H
#define _CUSTOM_WAVE_H
#pragma once
#define CUSTOM_WAVE_DEBUG 0
class CustomWave;
class Expr;
class PerPointEqn;
class Preset;
#include <vector>
#include "Common.hpp"
#include "Param.hpp"
#include "PerFrameEqn.hpp"
#include "Renderer/Waveform.hpp"
#include "Common.hpp"
#include "MilkdropPresetFactory/Param.hpp"
#include "MilkdropPresetFactory/PerFrameEqn.hpp"
#include <map>
#include <vector>
class CustomWave : public Waveform
{
public:
CustomWave() = delete;
/** Empty constructor leaves wave in undefined state **/
//CustomWave() {}
/**
* @brief Initializes a custom waveform with the given ID
* @param id The ID (index) of the custom wave.
*/
explicit CustomWave(int id);
/** Initializes a custom wave id given the integer id */
CustomWave(int id);
~CustomWave() override;
/** Destructor is necessary so we can free the per point matrices **/
virtual ~CustomWave();
int add_per_point_eqn(char* name, Expr* gen_expr);
ColoredPoint PerPoint(ColoredPoint p, const WaveformContext context);
void evalCustomWaveInitConditions(Preset* preset);
void loadUnspecInitConds();
void evalInitConds();
ColoredPoint PerPoint(ColoredPoint p, const Context& context) override;
/* Numerical id */
int id;
int per_frame_count;
int id{ 0 };
int per_frame_count{ 0 };
/* Parameter tree associated with this custom wave */
std::map<std::string,Param*> param_tree;
/* Engine variables */
float x; /* x position for per point equations */
float y; /* y position for per point equations */
float r; /* red color value */
float g; /* green color value */
float b; /* blue color value */
float a; /* alpha color value */
float * x_mesh;
float * y_mesh;
float * r_mesh;
float * b_mesh;
float * g_mesh;
float * a_mesh;
float x{ 0.0f }; /* x position for per point equations */
float y{ 0.0f }; /* y position for per point equations */
float r{ 0.0f }; /* red color value */
float g{ 0.0f }; /* green color value */
float b{ 0.0f }; /* blue color value */
float a{ 0.0f }; /* alpha color value */
bool enabled; /* if true then wave is visible, hidden otherwise */
std::vector<float> x_mesh;
std::vector<float> y_mesh;
std::vector<float> r_mesh;
std::vector<float> b_mesh;
std::vector<float> g_mesh;
std::vector<float> a_mesh;
float sample;
bool enabled{ false }; /* if true then wave is visible, hidden otherwise */
float sample{ 0.0f };
/* stupid t variables */
float t1;
float t2;
float t3;
float t4;
float t5;
float t6;
float t7;
float t8;
float t1{ 0.0f };
float t2{ 0.0f };
float t3{ 0.0f };
float t4{ 0.0f };
float t5{ 0.0f };
float t6{ 0.0f };
float t7{ 0.0f };
float t8{ 0.0f };
/* stupider q variables */
float q[NUM_Q_VARIABLES];
float q[NUM_Q_VARIABLES]{};
float v1,v2;
float v2{ 0.0f};
float v1{ 0.0f};
/* Data structures to hold per frame and per point equations */
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;
Expr* per_point_program{ nullptr };
std::map<std::string,InitCond*> per_frame_init_eqn_tree;
/* Denotes the index of the last character for each string buffer */
int per_point_eqn_string_index;
int per_frame_eqn_string_index;
int per_frame_init_eqn_string_index;
int add_per_point_eqn(char * name, Expr * gen_expr);
void evalCustomWaveInitConditions(Preset *preset);
void loadUnspecInitConds();
void evalInitConds();
};
#endif /** !_CUSTOM_WAVE_H */

View File

@ -107,9 +107,13 @@ Param* Param::new_param_float(const char* name, short int flags, void* engine_va
{
assert(engine_val);
CValue iv{ .float_val = init_val };
CValue ub{ .float_val = upper_bound };
CValue lb{ .float_val = lower_bound };
CValue iv;
CValue ub;
CValue lb;
iv.float_val = init_val;
ub.float_val = upper_bound;
lb.float_val = lower_bound;
return Param::create(name, P_TYPE_DOUBLE, flags, engine_val, matrix,iv, ub, lb);
}
@ -120,9 +124,13 @@ Param* Param::new_param_int(const char* name, short int flags, void* engine_val,
{
assert(engine_val);
CValue iv{ .int_val = init_val };
CValue ub{ .int_val = upper_bound };
CValue lb{ .int_val = lower_bound };
CValue iv;
CValue ub;
CValue lb;
iv.int_val = init_val;
ub.int_val = upper_bound;
lb.int_val = lower_bound;
return Param::create(name, P_TYPE_INT, flags, engine_val, nullptr, iv, ub, lb);
}
@ -133,9 +141,13 @@ Param* Param::new_param_bool(const char* name, short int flags, void* engine_val
{
assert(engine_val);
CValue iv{ .bool_val = init_val };
CValue ub{ .bool_val = upper_bound };
CValue lb{ .bool_val = lower_bound };
CValue iv;
CValue ub;
CValue lb;
iv.bool_val = init_val;
ub.bool_val = upper_bound;
lb.bool_val = lower_bound;
return Param::create(name, P_TYPE_BOOL, flags, engine_val, nullptr, iv, ub, lb);
}
@ -145,9 +157,13 @@ Param* Param::new_param_string(const char* name, short int flags, void* engine_v
{
assert(engine_val);
CValue iv{ .bool_val = false };
CValue ub{ .bool_val = false };
CValue lb{ .bool_val = false };
CValue iv;
CValue ub;
CValue lb;
iv.bool_val = false;
ub.bool_val = false;
lb.bool_val = false;
return Param::create(name, P_TYPE_STRING, flags, engine_val, nullptr, iv, ub, lb);
}

View File

@ -269,11 +269,6 @@ void MilkdropWaveform::WaveformMath(RenderContext& context)
}
}
float r2, theta;
float wave_x_temp{ 0.0f };
float wave_y_temp{ 0.0f };
// Aspect multipliers
float aspectX{ 1.0f };
float aspectY{ 1.0f };
@ -287,8 +282,6 @@ void MilkdropWaveform::WaveformMath(RenderContext& context)
aspectX = static_cast<float>(context.viewportSizeX) / static_cast<float>(context.viewportSizeY);
}
const float temp_y = -1 * (y - 1.0f);
loop = false;
float mysteryWaveParam = mystery;

View File

@ -16,8 +16,10 @@ public:
int texsize{ 512 }; //!< Size of the internal render texture.
int viewportSizeX{ 0 }; //!< Horizontal viewport size in pixels
int viewportSizeY{ 0 }; //!< Vertical viewport size in pixels
float aspectRatio{ 1.0 }; //!< X aspect ratio.
bool aspectCorrect{ false }; //!< Aspect ratio correction.
float aspectX{ 1.0 }; //!< X aspect ratio.
float aspectY{ 1.0 }; //!< Y aspect ratio.
float invAspectX{ 1.0 }; //!< Inverse X aspect ratio.
float invAspectY{ 1.0 }; //!< Inverse Y aspect ratio.
BeatDetect *beatDetect{ nullptr }; //!< Beat detection class to retrieve beat-related values.
TextureManager *textureManager{ nullptr }; //!< Holds all loaded textures for shader access.
GLuint programID_v2f_c4f{ 0 }; //!< Vertex shader program ID (no texture coordinates)

View File

@ -208,8 +208,10 @@ void Renderer::RenderItems(const Pipeline& pipeline, const PipelineContext& pipe
renderContext.texsize = nearestPower2(std::max(texsizeX, texsizeY));
renderContext.viewportSizeX = vw;
renderContext.viewportSizeY = vh;
renderContext.aspectCorrect = correction;
renderContext.aspectRatio = aspect;
renderContext.aspectX = m_fAspectX;
renderContext.aspectY = m_fAspectY;
renderContext.invAspectX = m_fInvAspectX;
renderContext.invAspectY = m_fInvAspectY;
renderContext.textureManager = textureManager;
renderContext.beatDetect = beatDetect;
@ -477,6 +479,9 @@ void Renderer::reset(int w, int h)
m_fAspectX = (texsizeY > texsizeX) ? static_cast<float>(texsizeX) / static_cast<float>(texsizeY) : 1.0f;
m_fAspectY = (texsizeX > texsizeY) ? static_cast<float>(texsizeY) / static_cast<float>(texsizeX) : 1.0f;
m_fInvAspectX = 1.0f / m_fAspectX;
m_fInvAspectY = 1.0f / m_fAspectY;
InitCompositeShaderVertex();
if (textureManager != nullptr)
@ -840,6 +845,7 @@ void Renderer::draw_stats()
stats += "Resolution: " + std::to_string(vw) + "x" + std::to_string(vh) + "\n";
stats += "Mesh X: " + std::to_string(mesh.width) + "\n";
stats += "Mesh Y: " + std::to_string(mesh.height) + "\n";
stats += "Time: " + std::to_string(renderContext.time) + "\n";
stats += "\n";
stats += "Beat Detect:""\n";

View File

@ -57,76 +57,60 @@ void Shape::InitVertexAttrib()
void Shape::Draw(RenderContext& context)
{
float xval{ x };
float yval{ -(y - 1) };
float t;
float temp_radius{ radius * (.707f * .707f * .707f * 1.04f) };
constexpr float pi = 3.141592653589793f;
// Additive Drawing or Overwrite
if (additive == 0)
glBlendFunc(GL_SRC_ALPHA, additive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
std::vector<ShapeVertexShaderData> vertexData(sides + 2);
vertexData[0].color_r = r;
vertexData[0].color_g = g;
vertexData[0].color_b = b;
vertexData[0].color_a = a * masterAlpha;
vertexData[0].tex_x = 0.5;
vertexData[0].tex_y = 0.5;
vertexData[0].point_x = x;
vertexData[0].point_y = -(y - 1.0f);
for (int i = 1; i < sides + 1; i++)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
float cornerProgress = static_cast<float>(i - 1) / static_cast<float>(sides);
float angle = cornerProgress * pi * 2.0f + ang + pi * 0.25f;
vertexData[i].color_r = r2;
vertexData[i].color_g = g2;
vertexData[i].color_b = b2;
vertexData[i].color_a = a2 * masterAlpha;
// Todo: There's still some issue with aspect ratio here, as everything gets squashed horizontally if Y > x.
vertexData[i].point_x = vertexData[0].point_x + radius * 0.5f * cosf(angle) * context.aspectY;
vertexData[i].point_y = vertexData[0].point_y + radius * 0.5f * sinf(angle);
}
auto vertexData = new ShapeVertexShaderData[sides + 2];
// Duplicate last vertex.
vertexData[sides + 1] = vertexData[1];
if (textured)
{
if (!imageUrl.empty())
{
TextureSamplerDesc tex = context.textureManager->getTexture(imageUrl, GL_CLAMP_TO_EDGE, GL_LINEAR);
if (tex.first != NULL)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex.first->texID);
glBindSampler(0, tex.second->samplerID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, context.textureManager->getMainTexture()->texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
context.aspectRatio = 1.0;
}
}
else
for (int i = 1; i < sides + 1; i++)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, context.textureManager->getMainTexture()->texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
float cornerProgress = static_cast<float>(i - 1) / static_cast<float>(sides);
vertexData[i].tex_x =
0.5f + 0.5f * cosf(cornerProgress * pi * 2.0f + ang + pi * 0.25f) / tex_zoom * context.aspectY;
vertexData[i].tex_y = 0.5f + 0.5f * sinf(cornerProgress * pi * 2.0f + ang + pi * 0.25f) / tex_zoom;
}
// Define the center point of the shape
vertexData[0].color_r = r;
vertexData[0].color_g = g;
vertexData[0].color_b = b;
vertexData[0].color_a = a * masterAlpha;
vertexData[0].tex_x = 0.5;
vertexData[0].tex_y = 0.5;
vertexData[0].point_x = xval;
vertexData[0].point_y = yval;
for (int i = 1; i < sides + 2; i++)
{
vertexData[i].color_r = r2;
vertexData[i].color_g = g2;
vertexData[i].color_b = b2;
vertexData[i].color_a = a2 * masterAlpha;
t = static_cast<float>(i - 1) / static_cast<float>(sides);
vertexData[i].tex_x = 0.5f + 0.5f * cosf(t * 3.1415927f * 2 + tex_ang + 3.1415927f * 0.25f) *
(context.aspectCorrect ? context.aspectRatio : 1.0) / tex_zoom;
vertexData[i].tex_y = 0.5f + 0.5f * sinf(t * 3.1415927f * 2 + tex_ang + 3.1415927f * 0.25f) / tex_zoom;
vertexData[i].point_x = temp_radius * cosf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) *
(context.aspectCorrect ? context.aspectRatio : 1.0) + xval;
vertexData[i].point_y = temp_radius * sinf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) + yval;
}
vertexData[sides + 1] = vertexData[1];
glBindBuffer(GL_ARRAY_BUFFER, m_vboID_texture);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), NULL, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), vertexData, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), vertexData.data(), GL_DYNAMIC_DRAW);
glUseProgram(context.programID_v2f_c4f_t2f);
@ -144,30 +128,9 @@ void Shape::Draw(RenderContext& context)
else
{//Untextured (use color values)
//Define the center point of the shape
vertexData[0].color_r = r;
vertexData[0].color_g = g;
vertexData[0].color_b = b;
vertexData[0].color_a = a * masterAlpha;
vertexData[0].point_x = xval;
vertexData[0].point_y = yval;
for (int i = 1; i < sides + 2; i++)
{
vertexData[i].color_r = r2;
vertexData[i].color_g = g2;
vertexData[i].color_b = b2;
vertexData[i].color_a = a2 * masterAlpha;
t = static_cast<float>(i - 1) / static_cast<float>(sides);
vertexData[i].point_x = temp_radius * cosf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) *
(context.aspectCorrect ? context.aspectRatio : 1.0) + xval;
vertexData[i].point_y = temp_radius * sinf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) + yval;
}
glBindBuffer(GL_ARRAY_BUFFER, m_vboID_not_texture);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), NULL, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), vertexData, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertexShaderData) * (sides + 2), vertexData.data(), GL_DYNAMIC_DRAW);
glUseProgram(context.programID_v2f_c4f);
@ -181,14 +144,12 @@ void Shape::Draw(RenderContext& context)
if (border_a > 0.0f)
{
auto points = new float[sides + 1][2];
std::vector<ShapeVertex> points(sides + 1);
for (int i = 0; i < sides; i++)
for (int i = 0; i < sides + 1; i++)
{
t = (i - 1) / (float) sides;
points[i][0] = temp_radius * cosf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) *
(context.aspectCorrect ? context.aspectRatio : 1.0) + xval;
points[i][1] = temp_radius * sinf(t * 3.1415927f * 2 + ang + 3.1415927f * 0.25f) + yval;
points[i].x = vertexData[i + 1].point_x;
points[i].y = vertexData[i + 1].point_y;
}
glUseProgram(context.programID_v2f_c4f);
@ -221,37 +182,33 @@ void Shape::Draw(RenderContext& context)
case 1:
for (auto j = 0; j < sides + 1; j++)
{
points[j][0] += incrementX;
points[j].x += incrementX;
}
break;
case 2:
for (auto j = 0; j < sides + 1; j++)
{
points[j][1] += incrementY;
points[j].y += incrementY;
}
break;
case 3:
for (auto j = 0; j < sides + 1; j++)
{
points[j][0] -= incrementX;
points[j].x -= incrementX;
}
break;
}
glBufferData(GL_ARRAY_BUFFER, sizeof(floatPair) * (sides), points, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(floatPair) * (sides), points.data(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINE_LOOP, 0, sides);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
delete[] points;
}
glDisable(GL_LINE_SMOOTH);
glUseProgram(0);
delete[] vertexData;
}

View File

@ -67,6 +67,12 @@ private:
float tex_y; //!< The vertex y (v) texture coordinate.
};
struct ShapeVertex
{
float x{ .0f }; //!< The vertex X coordinate.
float y{ .0f }; //!< The vertex Y coordinate.
};
GLuint m_vboID_texture{ 0 }; //!< Vertex buffer object ID for a textured shape.
GLuint m_vaoID_texture{ 0 }; //!< Vertex array object ID for a textured shape.

View File

@ -1,35 +1,20 @@
/*
* Waveform.hpp
*
* Created on: Jun 25, 2008
* Author: pete
*/
#include "projectM-opengl.h"
#include "Waveform.hpp"
#include <algorithm>
#include <cmath>
#include "BeatDetect.hpp"
#include "ShaderEngine.hpp"
#include <glm/gtc/type_ptr.hpp>
#ifdef WIN32
#include <functional>
#endif /** WIN32 */
typedef float floatPair[2];
Waveform::Waveform(int _samples)
: RenderItem(), samples(_samples), points(_samples), pointContext(_samples)
: RenderItem()
, samples(_samples)
, points(_samples)
{
spectrum = false; /* spectrum data or pcm data */
dots = false; /* draw wave as dots or lines */
thick = false; /* draw thicker lines */
additive = false; /* add color values together */
scaling= 1; /* scale factor of waveform */
smoothing = 0; /* smooth factor of waveform */
sep = 0;
Init();
}
@ -47,49 +32,70 @@ void Waveform::Draw(RenderContext &context)
const float vol_scale = context.beatDetect->getPCMScale();
// Make sure samples<=points.size(). We could reallocate points, but 512 is probably big enough.
size_t samples_count = this->samples;
if (samples_count > this->points.size())
samples_count = this->points.size();
int sampleCount{ std::min(this->samples, static_cast<int>(this->points.size())) };
float pcmL[512]{ 0.0f };
float pcmR[512]{ 0.0f };
float *value1 = new float[samples_count];
float *value2 = new float[samples_count];
if (spectrum)
{
context.beatDetect->pcm.getSpectrum( value1, CHANNEL_0, samples_count, smoothing );
context.beatDetect->pcm.getSpectrum( value2, CHANNEL_1, samples_count, smoothing );
context.beatDetect->pcm.getSpectrum(pcmL, CHANNEL_0, sampleCount, 0.0f );
context.beatDetect->pcm.getSpectrum(pcmR, CHANNEL_1, sampleCount, 0.0f );
}
else
{
context.beatDetect->pcm.getPCM( value1, CHANNEL_0, samples_count, smoothing );
context.beatDetect->pcm.getPCM( value2, CHANNEL_1, samples_count, smoothing );
context.beatDetect->pcm.getPCM(pcmL, CHANNEL_0, sampleCount, 0.0f );
context.beatDetect->pcm.getPCM(pcmR, CHANNEL_1, sampleCount, 0.0f );
}
const float mult = scaling * vol_scale * (spectrum ? 0.005f : 1.0f);
WaveformContext waveContext(samples_count, context.beatDetect);
const float mult = scaling * vol_scale * (spectrum ? 0.05f : 1.0f);
for (size_t x=0;x< samples_count;x++)
{
waveContext.sample = x/(float)(samples_count - 1);
waveContext.sample_int = x;
waveContext.left = value1[x] * mult;
waveContext.right = value2[x] * mult;
// PCM data smoothing
int offset1 = spectrum ? 0 : (512 - sampleCount) / 2 - sep / 2;
int offset2 = spectrum ? 0 : (512 - sampleCount) / 2 + sep / 2;
int t = spectrum ? (512 - sep) / static_cast<float>(sampleCount) : 1;
float mix1 = std::pow(smoothing * 0.98f, 0.5f);
float mix2 = 1.0f - mix1;
points[x] = PerPoint(points[x],waveContext);
}
float value1[512]{ 0.0f };
float value2[512]{ 0.0f };
std::vector<ColoredPoint> points_transf = points;
value1[0] = pcmL[offset1];
value2[0] = pcmR[offset2];
for (std::vector<ColoredPoint>::iterator iter = points_transf.begin(); iter != points_transf.end(); ++iter) {
(*iter).y = -( (*iter).y-1);
(*iter).a *= masterAlpha;
for (int j = 0; j < sampleCount; j++)
{
value1[j] = pcmL[static_cast<int>(j * t) + offset1] * mix2 + value1[j - 1] * mix1;
value2[j] = pcmR[static_cast<int>(j * t) + offset2] * mix2 + value2[j - 1] * mix1;
}
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
for (int j = sampleCount - 2; j >= 0; j--)
{
value1[j] = value1[j] * mix2 + value1[j + 1] * mix1;
value2[j] = value2[j] * mix2 + value2[j + 1] * mix1;
}
glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * samples_count, NULL, GL_DYNAMIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * samples_count, &points_transf[0], GL_DYNAMIC_DRAW);
Context waveContext(sampleCount, context.beatDetect);
std::vector<ColoredPoint> pointsTransformed(sampleCount);
glBindBuffer(GL_ARRAY_BUFFER, 0);
for (int x = 0; x < sampleCount; x++)
{
waveContext.sample = static_cast<float>(x) / static_cast<float>(sampleCount - 1);
waveContext.sample_int = x;
waveContext.left = value1[x] * mult;
waveContext.right = value2[x] * mult;
pointsTransformed[x] = PerPoint(points[x], waveContext);
}
for (auto& point : pointsTransformed)
{
point.y = 1.0f - point.y;
point.a *= masterAlpha;
}
std::vector<ColoredPoint> pointsSmoothed(sampleCount * 2);
auto smoothedVertexCount = SmoothWave(pointsTransformed.data(), sampleCount, pointsSmoothed.data());
glUseProgram(context.programID_v2f_c4f);
@ -98,36 +104,107 @@ void Waveform::Draw(RenderContext &context)
if (additive) glBlendFunc(GL_SRC_ALPHA, GL_ONE);
else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (thick)
{
glLineWidth(context.texsize <= 512 ? 2 : 2*context.texsize/512);
glDisable(GL_LINE_SMOOTH);
glLineWidth(1);
#ifndef GL_TRANSITION
glPointSize(context.texsize <= 512 ? 2 : 2*context.texsize/512);
#endif
glUniform1f(context.uniform_v2f_c4f_vertex_point_size, context.texsize <= 512 ? 2 : 2*context.texsize/512);
}
// Additive wave drawing (vice overwrite)
if (additive == 1)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
else
{
glLineWidth(1);
#ifndef GL_TRANSITION
glPointSize(context.texsize <= 512 ? 1 : context.texsize/512);
#endif
glUniform1f(context.uniform_v2f_c4f_vertex_point_size, context.texsize <= 512 ? 1 : context.texsize/512);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
// Always draw "thick" dots.
auto iterations = thick || dots ? 4 : 1;
// Need to use +/- 1.0 here instead of 2.0 used in Milkdrop to achieve the same rendering result.
auto incrementX = 1.0f / static_cast<float>(context.viewportSizeX);
auto incrementY = 1.0f / static_cast<float>(context.viewportSizeY);
GLuint drawType = dots ? GL_POINTS : GL_LINE_STRIP;
glBindVertexArray(m_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
if (dots) glDrawArrays(GL_POINTS,0,samples_count);
else glDrawArrays(GL_LINE_STRIP,0,samples_count);
// If thick outline is used, draw the shape four times with slight offsets
// (top left, top right, bottom right, bottom left).
for (auto iteration = 0; iteration < iterations; iteration++)
{
switch (iteration)
{
case 0:
default:
break;
case 1:
for (auto j = 0; j < smoothedVertexCount; j++)
{
pointsSmoothed[j].x += incrementX;
}
break;
case 2:
for (auto j = 0; j < smoothedVertexCount; j++)
{
pointsSmoothed[j].y += incrementY;
}
break;
case 3:
for (auto j = 0; j < smoothedVertexCount; j++)
{
pointsSmoothed[j].x -= incrementX;
}
break;
}
glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * smoothedVertexCount, &pointsSmoothed[0], GL_DYNAMIC_DRAW);
glDrawArrays(drawType, 0, smoothedVertexCount);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glLineWidth(context.texsize < 512 ? 1 : context.texsize/512);
glUseProgram(0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
delete[] value1;
delete[] value2;
}
int Waveform::SmoothWave(const Waveform::ColoredPoint* inputVertices, int vertexCount,
Waveform::ColoredPoint* outputVertices)
{
constexpr float c1{ -0.15f };
constexpr float c2{ 1.15f };
constexpr float c3{ 1.15f };
constexpr float c4{ -0.15f };
constexpr float inverseSum{ 1.0f / (c1 + c2 + c3 + c4) };
int outputIndex = 0;
int iBelow = 0;
int iAbove2 = 1;
for (auto inputIndex = 0; inputIndex < vertexCount - 1; inputIndex++)
{
int iAbove = iAbove2;
iAbove2 = std::min(vertexCount - 1, inputIndex + 2);
outputVertices[outputIndex] = inputVertices[inputIndex];
outputVertices[outputIndex + 1] = inputVertices[inputIndex];
outputVertices[outputIndex + 1].x = (c1 * inputVertices[iBelow].x
+ c2 * inputVertices[inputIndex].x
+ c3 * inputVertices[iAbove].x
+ c4 * inputVertices[iAbove2].x) * inverseSum;
outputVertices[outputIndex + 1].y = (c1 * inputVertices[iBelow].y
+ c2 * inputVertices[inputIndex].y
+ c3 * inputVertices[iAbove].y
+ c4 * inputVertices[iAbove2].y) * inverseSum;
iBelow = inputIndex;
outputIndex += 2;
}
outputVertices[outputIndex] = inputVertices[vertexCount - 1];
return outputIndex + 1;
}

View File

@ -12,55 +12,87 @@
#include <vector>
class ColoredPoint
{
public:
float x;
float y;
float r;
float g;
float b;
float a;
ColoredPoint():x(0.5),y(0.5),r(1),g(1),b(1),a(1){}
};
class WaveformContext
{
public:
float sample;
int samples;
int sample_int;
float left;
float right;
BeatDetect *music;
WaveformContext(int _samples, BeatDetect *_music):samples(_samples),music(_music){}
};
class Waveform : public RenderItem
{
public:
struct ColoredPoint
{
float x{ 0.5f }; //!< Vertex X coordinate.
float y{ 0.5f }; //!< Vertex Y coordinate.
float r{ 1.0f }; //!< Vertex red color value.
float g{ 1.0f }; //!< Vertex green color value.
float b{ 1.0f }; //!< Vertex blue color value.
float a{ 1.0f }; //!< Vertex alpha value.
};
int samples; /* number of samples associated with this wave form. Usually powers of 2 */
bool spectrum; /* spectrum data or pcm data */
bool dots; /* draw wave as dots or lines */
bool thick; /* draw thicker lines */
bool additive; /* add color values together */
class Context
{
public:
float sample{ 0.0f }; //!< Current sample value.
int samples{ 0 }; //!< Sample number
int sample_int{ 0 }; //!< Sample integer value.
float left{ 0.0f }; //!< Left channel value.
float right{ 0.0f }; //!< Right channe value.
BeatDetect* music{ nullptr }; //!< Beat detection instance.
float scaling; /* scale factor of waveform */
float smoothing; /* smooth factor of waveform */
int sep; /* no idea what this is yet... */
/**
* @brief Create a new context instance.
* @param _samples Number of samples.
* @param _music Beat detection instance, also used to access sample PCM data.
*/
Context(int _samples, BeatDetect* _music)
: samples(_samples)
, music(_music)
{
}
};
Waveform(int _samples);
void InitVertexAttrib();
void Draw(RenderContext &context);
/**
* @brief Creates a new waveform with the given number of samples.
* @param _samples The number of samples this waveform should display.
*/
explicit Waveform(int _samples);
private:
virtual ColoredPoint PerPoint(ColoredPoint p, const WaveformContext context)=0;
std::vector<ColoredPoint> points;
std::vector<float> pointContext;
/**
* @brief Initializes the waveform's vertex buffer and attribute data.
*/
void InitVertexAttrib() override;
/**
* @brief Renders the waveform.
* @param context The rendering context instance.
*/
void Draw(RenderContext& context) override;
int samples{ 0 }; //!< Number of samples associated with this wave form. Usually powers of 2.
bool spectrum{ false }; //!< Spectrum data or PCM data.
bool dots{ false }; //!< If true, draw wave as dots instead of lines.
bool thick{ false }; //!< Draw thicker lines.
bool additive{ false }; //!< Add color values together.
float scaling{ 1.0f }; //!< Scale factor of waveform.
float smoothing{ 0.0f }; //!< Smooth factor of waveform.
int sep{ 0 }; //!< Separation distance of dual waveforms.
protected:
/**
* @brief Does a better-than-linear smooth on a wave.
*
* Roughly doubles the number of points.
*
* @param inputVertices Pointer to an array of vertices to be smoothed.
* @param vertexCount Number of vertices/points in the input data.
* @param outputVertices Pointer to a buffer that will receive the smoothed data. Must be able to hold 2 * vertexCount vertices.
* @return The number of vertices in outputVertices after smoothing.
*/
static int SmoothWave(const ColoredPoint* inputVertices, int vertexCount, ColoredPoint* outputVertices);
virtual ColoredPoint PerPoint(ColoredPoint p, const Context& context) = 0;
std::vector<ColoredPoint> points; //!< Points in this waveform.
};
#endif /* WAVEFORM_HPP_ */