diff --git a/presets/CMakeLists.txt b/presets/CMakeLists.txt index 90db02ef9..151eeb18c 100644 --- a/presets/CMakeLists.txt +++ b/presets/CMakeLists.txt @@ -1,7 +1,7 @@ if(ENABLE_TESTING) install(DIRECTORY tests - DESTINATION "${PROJECTM_DATADIR_PATH}/presets" + DESTINATION "presets" COMPONENT Tests ) endif() diff --git a/src/libprojectM/MilkdropPresetFactory/CustomShape.cpp b/src/libprojectM/MilkdropPresetFactory/CustomShape.cpp index ff32e1c15..a958e1120 100755 --- a/src/libprojectM/MilkdropPresetFactory/CustomShape.cpp +++ b/src/libprojectM/MilkdropPresetFactory/CustomShape.cpp @@ -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 > ( per_frame_eqn_tree ); - traverse > ( init_cond_tree ); - traverse > ( param_tree ); - traverse > ( per_frame_init_eqn_tree ); - traverse > ( text_properties_tree ); - + traverseVector >(per_frame_eqn_tree); + traverse >(init_cond_tree); + traverse >(param_tree); + traverse >(per_frame_init_eqn_tree); + traverse >(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::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); + } } diff --git a/src/libprojectM/MilkdropPresetFactory/CustomShape.hpp b/src/libprojectM/MilkdropPresetFactory/CustomShape.hpp index 9a8a7fcc9..2c0945be2 100755 --- a/src/libprojectM/MilkdropPresetFactory/CustomShape.hpp +++ b/src/libprojectM/MilkdropPresetFactory/CustomShape.hpp @@ -30,6 +30,7 @@ #define _CUSTOM_SHAPE_H #define CUSTOM_SHAPE_DEBUG 0 + #include #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 param_tree; + std::map 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 init_cond_tree; - std::vector per_frame_eqn_tree; - std::map per_frame_init_eqn_tree; + std::map init_cond_tree; + std::vector per_frame_eqn_tree; + std::map per_frame_init_eqn_tree; std::map 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 */ diff --git a/src/libprojectM/MilkdropPresetFactory/CustomWave.cpp b/src/libprojectM/MilkdropPresetFactory/CustomWave.cpp index b9637dec9..5ce94dcfc 100755 --- a/src/libprojectM/MilkdropPresetFactory/CustomWave.cpp +++ b/src/libprojectM/MilkdropPresetFactory/CustomWave.cpp @@ -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), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "g", P_FLAG_NONE | P_FLAG_PER_POINT, &g, g_mesh.data(), 1.0, 0.0, .5), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "b", P_FLAG_NONE | P_FLAG_PER_POINT, &b, b_mesh.data(), 1.0, 0.0, .5), ¶m_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), ¶m_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), ¶m_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), ¶m_tree); + ParamUtils::insert(Param::new_param_bool( + "enabled", P_FLAG_NONE, &this->enabled, 1, 0, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_int( + "sep", P_FLAG_NONE, &this->sep, 100, -100, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_bool( + "bspectrum", P_FLAG_NONE, &this->spectrum, 1, 0, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_bool( + "bdrawthick", P_FLAG_NONE, &this->thick, 1, 0, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_bool( + "busedots", P_FLAG_NONE, &this->dots, 1, 0, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_bool( + "badditive", P_FLAG_NONE, &this->additive, 1, 0, 0), ¶m_tree); + ParamUtils::insert(Param::new_param_int( + "samples", P_FLAG_NONE, &this->samples, 2048, 1, 512), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "sample", P_FLAG_READONLY | P_FLAG_NONE, &this->sample, nullptr, 1.0, 0.0, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "value1", P_FLAG_READONLY | P_FLAG_NONE, &this->v1, nullptr, 1.0, -1.0, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "value2", P_FLAG_READONLY | P_FLAG_NONE, &this->v2, nullptr, 1.0, -1.0, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "smoothing", P_FLAG_NONE, &this->smoothing, nullptr, 1.0, 0.0, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "scaling", P_FLAG_NONE, &this->scaling, nullptr, MAX_DOUBLE_SIZE, 0.0, 1.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t1", P_FLAG_TVAR, &this->t1, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t2", P_FLAG_TVAR, &this->t2, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t3", P_FLAG_TVAR, &this->t3, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t4", P_FLAG_TVAR, &this->t4, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t5", P_FLAG_TVAR, &this->t5, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t6", P_FLAG_TVAR, &this->t6, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0),¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t7", P_FLAG_TVAR, &this->t7, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_tree); + ParamUtils::insert(Param::new_param_float( + "t8", P_FLAG_TVAR, &this->t8, nullptr, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0), ¶m_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, ¶m_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, ¶m_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::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::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::iterator pos = init_cond_tree.begin(); pos != init_cond_tree.end(); ++pos) - delete(pos->second); - - for (std::map::iterator pos = per_frame_init_eqn_tree.begin(); pos != per_frame_init_eqn_tree.end(); ++pos) - delete(pos->second); - - for (std::map::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(name, ¶m_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(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(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)) == 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::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 steps; - for (auto pos = per_point_eqn_tree.begin(); pos != per_point_eqn_tree.end();++pos) - steps.push_back((*pos)->assign_expr); + std::vector 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 diff --git a/src/libprojectM/MilkdropPresetFactory/CustomWave.hpp b/src/libprojectM/MilkdropPresetFactory/CustomWave.hpp index f7f30e59a..a00016b05 100755 --- a/src/libprojectM/MilkdropPresetFactory/CustomWave.hpp +++ b/src/libprojectM/MilkdropPresetFactory/CustomWave.hpp @@ -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 - -#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 +#include 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 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 x_mesh; + std::vector y_mesh; + std::vector r_mesh; + std::vector b_mesh; + std::vector g_mesh; + std::vector 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 init_cond_tree; std::vector per_frame_eqn_tree; std::vector per_point_eqn_tree; - Expr *per_point_program; + Expr* per_point_program{ nullptr }; std::map 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 */ diff --git a/src/libprojectM/MilkdropPresetFactory/Param.cpp b/src/libprojectM/MilkdropPresetFactory/Param.cpp index c608602e2..fa6f16ded 100755 --- a/src/libprojectM/MilkdropPresetFactory/Param.cpp +++ b/src/libprojectM/MilkdropPresetFactory/Param.cpp @@ -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); } diff --git a/src/libprojectM/Renderer/MilkdropWaveform.cpp b/src/libprojectM/Renderer/MilkdropWaveform.cpp index 8e9d1cca0..cbbc3a900 100644 --- a/src/libprojectM/Renderer/MilkdropWaveform.cpp +++ b/src/libprojectM/Renderer/MilkdropWaveform.cpp @@ -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(context.viewportSizeX) / static_cast(context.viewportSizeY); } - const float temp_y = -1 * (y - 1.0f); - loop = false; float mysteryWaveParam = mystery; diff --git a/src/libprojectM/Renderer/RenderContext.hpp b/src/libprojectM/Renderer/RenderContext.hpp index ee786c99b..b0a063b6c 100644 --- a/src/libprojectM/Renderer/RenderContext.hpp +++ b/src/libprojectM/Renderer/RenderContext.hpp @@ -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) diff --git a/src/libprojectM/Renderer/Renderer.cpp b/src/libprojectM/Renderer/Renderer.cpp index 62d57d43d..0845fa06d 100644 --- a/src/libprojectM/Renderer/Renderer.cpp +++ b/src/libprojectM/Renderer/Renderer.cpp @@ -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(texsizeX) / static_cast(texsizeY) : 1.0f; m_fAspectY = (texsizeX > texsizeY) ? static_cast(texsizeY) / static_cast(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"; diff --git a/src/libprojectM/Renderer/Shape.cpp b/src/libprojectM/Renderer/Shape.cpp index f31b032c3..d92155516 100644 --- a/src/libprojectM/Renderer/Shape.cpp +++ b/src/libprojectM/Renderer/Shape.cpp @@ -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 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(i - 1) / static_cast(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(i - 1) / static_cast(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(i - 1) / static_cast(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(i - 1) / static_cast(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 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; } diff --git a/src/libprojectM/Renderer/Shape.hpp b/src/libprojectM/Renderer/Shape.hpp index b04528abe..1cd894aaa 100644 --- a/src/libprojectM/Renderer/Shape.hpp +++ b/src/libprojectM/Renderer/Shape.hpp @@ -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. diff --git a/src/libprojectM/Renderer/Waveform.cpp b/src/libprojectM/Renderer/Waveform.cpp index d076c0a7f..2be320de0 100644 --- a/src/libprojectM/Renderer/Waveform.cpp +++ b/src/libprojectM/Renderer/Waveform.cpp @@ -1,35 +1,20 @@ -/* - * Waveform.hpp - * - * Created on: Jun 25, 2008 - * Author: pete - */ - #include "projectM-opengl.h" #include "Waveform.hpp" #include #include #include "BeatDetect.hpp" -#include "ShaderEngine.hpp" + #include + #ifdef WIN32 #include #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(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(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 points_transf = points; + value1[0] = pcmL[offset1]; + value2[0] = pcmR[offset2]; - for (std::vector::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(j * t) + offset1] * mix2 + value1[j - 1] * mix1; + value2[j] = pcmR[static_cast(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 pointsTransformed(sampleCount); - glBindBuffer(GL_ARRAY_BUFFER, 0); + for (int x = 0; x < sampleCount; x++) + { + waveContext.sample = static_cast(x) / static_cast(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 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(context.viewportSizeX); + auto incrementY = 1.0f / static_cast(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; } diff --git a/src/libprojectM/Renderer/Waveform.hpp b/src/libprojectM/Renderer/Waveform.hpp index 00ccab86a..c4a0aa569 100644 --- a/src/libprojectM/Renderer/Waveform.hpp +++ b/src/libprojectM/Renderer/Waveform.hpp @@ -12,55 +12,87 @@ #include -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 points; - std::vector 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 points; //!< Points in this waveform. }; + #endif /* WAVEFORM_HPP_ */