diff --git a/src/libprojectM/Common.hpp b/src/libprojectM/Common.hpp index 8a38e98be..7d4c6f934 100755 --- a/src/libprojectM/Common.hpp +++ b/src/libprojectM/Common.hpp @@ -209,6 +209,7 @@ inline double meanSquaredError(const double & x, const double & y) { return (x-y)*(x-y); } + #endif diff --git a/src/libprojectM/MilkdropPresetFactory/MilkdropPresetFactory.cpp b/src/libprojectM/MilkdropPresetFactory/MilkdropPresetFactory.cpp index eb2103d43..2dc1eabdb 100644 --- a/src/libprojectM/MilkdropPresetFactory/MilkdropPresetFactory.cpp +++ b/src/libprojectM/MilkdropPresetFactory/MilkdropPresetFactory.cpp @@ -1,7 +1,7 @@ // // C++ Implementation: MilkdropPresetFactory // -// Description: +// Description: // // // Author: Carmelo Piccione , (C) 2008 @@ -22,8 +22,8 @@ MilkdropPresetFactory::MilkdropPresetFactory(int gx, int gy) { BuiltinFuncs::init_builtin_func_db(); /* Initializes all infix operators */ - Eval::init_infix_ops(); - + Eval::init_infix_ops(); + initializePresetOutputs(gx,gy); } @@ -31,12 +31,12 @@ MilkdropPresetFactory::~MilkdropPresetFactory() { std::cerr << "[~MilkdropPresetFactory] destroy infix ops" << std::endl; Eval::destroy_infix_ops(); - std::cerr << "[~MilkdropPresetFactory] destroy builtin func" << std::endl; + std::cerr << "[~MilkdropPresetFactory] destroy builtin func" << std::endl; BuiltinFuncs::destroy_builtin_func_db(); std::cerr << "[~MilkdropPresetFactory] delete preset out puts" << std::endl; delete(_presetOutputs); std::cerr << "[~MilkdropPresetFactory] done" << std::endl; - + } /* Reinitializes the engine variables to a default (conservative and sane) value */ @@ -86,7 +86,7 @@ void MilkdropPresetFactory::reset() _presetOutputs->mv.x_offset = 0.02; _presetOutputs->mv.y_offset = 0.02; - + /* PER_FRAME CONSTANTS END */ _presetOutputs->fRating = 0; _presetOutputs->fGammaAdj = 1.0; @@ -121,7 +121,7 @@ void MilkdropPresetFactory::reset() /* PER_PIXEL CONSTANT END */ /* Q VARIABLES START */ - for (int i = 0;i<32;i++) + for (int i = 0;i< 32;i++) _presetOutputs->q[i] = 0; /* Q VARIABLES END */ @@ -197,7 +197,7 @@ std::auto_ptr MilkdropPresetFactory::allocate(const std::string & url, c std::string path; if (PresetFactory::protocol(url, path) == PresetFactory::IDLE_PRESET_PROTOCOL) { - return IdlePresets::allocate(path, *_presetOutputs); + return IdlePresets::allocate(path, *_presetOutputs); } else return std::auto_ptr(new MilkdropPreset(url, name, *_presetOutputs)); } diff --git a/src/libprojectM/PresetMerge.cpp b/src/libprojectM/PresetMerge.cpp index ec894cde2..5695ca744 100644 --- a/src/libprojectM/PresetMerge.cpp +++ b/src/libprojectM/PresetMerge.cpp @@ -1,21 +1,25 @@ #include "PresetMerge.hpp" #include "RenderItemMatcher.hpp" +#include "RenderItemMergeFunction.hpp" - -void PipelineMerger::MergePipelines(const Pipeline & a, const Pipeline & b, Pipeline & out, RenderItemMatcher & matcher, float ratio) +void PipelineMerger::MergePipelines(const Pipeline & a, const Pipeline & b, Pipeline & out, const RenderItemMatchList & matching, RenderItemMergeFunction & mergeFunction, float ratio) { double invratio = 1.0 - ratio; out.textureWrap = (ratio < 0.5) ? a.textureWrap : b.textureWrap; - out.screenDecay =lerp( b.screenDecay, a.screenDecay, ratio); + out.screenDecay = lerp( b.screenDecay, a.screenDecay, ratio); out.drawables.clear(); + + for (RenderItemMatchList::const_iterator pos = matching.begin(); pos != matching.end(); ++pos) { + - RenderItemMatcher::MatchResults results = matcher(a.drawables, b.drawables); - for (int i = 0; i < a.drawables.size();i++) - for (int j = 0; j < b.drawables.size();j++) - std::cerr << "[" << i << "][" << j << "]" << matcher.weight(i,j) << std::endl; + const RenderItem * itemA = pos->first; + const RenderItem * itemB = pos->second; + + //mergeFunction(itemA, itemB, out, ratio); + } for (std::vector::const_iterator pos = a.drawables.begin(); pos != a.drawables.end(); ++pos) diff --git a/src/libprojectM/PresetMerge.hpp b/src/libprojectM/PresetMerge.hpp index dde38b538..46c1207ca 100644 --- a/src/libprojectM/PresetMerge.hpp +++ b/src/libprojectM/PresetMerge.hpp @@ -3,6 +3,7 @@ #include "Preset.hpp" #include "Pipeline.hpp" #include "RenderItemMatcher.hpp" +#include "RenderItemMergeFunction.hpp" class PipelineMerger { @@ -12,7 +13,8 @@ class PipelineMerger } public: - static void MergePipelines(const Pipeline &a, const Pipeline &b, Pipeline &out, RenderItemMatcher & matcher, float ratio); + static void MergePipelines(const Pipeline &a, const Pipeline &b, Pipeline &out, + const RenderItemMatchList & matching, RenderItemMergeFunction & merger, float ratio); }; diff --git a/src/libprojectM/Renderer/RenderItemDistanceMetric.hpp b/src/libprojectM/Renderer/RenderItemDistanceMetric.hpp index d6aad5b05..bf8973b2a 100644 --- a/src/libprojectM/Renderer/RenderItemDistanceMetric.hpp +++ b/src/libprojectM/Renderer/RenderItemDistanceMetric.hpp @@ -35,7 +35,7 @@ virtual double computeDistance(const R1 * r1, const R2 * r2) const = 0; public: -inline virtual double operator()(const RenderItem * r1, const RenderItem * r2) const { +inline virtual double operator()(const RenderItem * r1, const RenderItem * r2) const { if (supported(r1, r2)) return computeDistance(dynamic_cast(r1), dynamic_cast(r2)); else if (supported(r2,r1)) diff --git a/src/libprojectM/Renderer/RenderItemMatcher.cpp b/src/libprojectM/Renderer/RenderItemMatcher.cpp index 603886acd..31252a665 100644 --- a/src/libprojectM/Renderer/RenderItemMatcher.cpp +++ b/src/libprojectM/Renderer/RenderItemMatcher.cpp @@ -9,6 +9,7 @@ double RenderItemMatcher::computeMatching(const RenderItemList & lhs, const Rend _weights[i][j] = RenderItemDistanceMetric::NOT_COMPARABLE_VALUE; } + const double error = _hungarianMethod(_weights, lhs.size()); std::cout << "[computeMatching] total error is " << error << std::endl; return error; diff --git a/src/libprojectM/Renderer/RenderItemMatcher.hpp b/src/libprojectM/Renderer/RenderItemMatcher.hpp index 89327b843..44659d491 100644 --- a/src/libprojectM/Renderer/RenderItemMatcher.hpp +++ b/src/libprojectM/Renderer/RenderItemMatcher.hpp @@ -33,9 +33,9 @@ struct MatchResults { /// @param lhs the "left-hand side" list of render items. /// @param rhs the "right-hand side" list of render items. /// @returns a list of match pairs, possibly self referencing, and an error estimate of the matching. - inline virtual MatchResults operator()(const RenderItemList & lhs, const RenderItemList & rhs) const { + inline virtual void operator()(const RenderItemList & lhs, const RenderItemList & rhs) const { - MatchResults results; + MatchResults & results = _results; // Ensure the first argument is greater than next to aid the helper function's logic. if (lhs.size() >= rhs.size()) { @@ -45,13 +45,15 @@ struct MatchResults { results.error = computeMatching(rhs, lhs); setMatches(results.matches, rhs, lhs); } - return results; + } RenderItemMatcher() {} virtual ~RenderItemMatcher() {} + inline const MatchResults & matchResults() { return _results; } + inline double weight(int i, int j) const { return _weights[i][j]; } MasterRenderItemDistance & distanceFunction() { return _distanceFunction; } @@ -60,11 +62,11 @@ private: mutable HungarianMethod _hungarianMethod; mutable double _weights[MAXIMUM_SET_SIZE][MAXIMUM_SET_SIZE]; + mutable MatchResults _results; /// @idea interface this entirely allow overriding of its type. mutable MasterRenderItemDistance _distanceFunction; - double computeMatching(const RenderItemList & lhs, const RenderItemList & rhs) const; void setMatches(RenderItemMatchList & dest, const RenderItemList & lhs_src, const RenderItemList & rhs_src) const; diff --git a/src/libprojectM/Renderer/RenderItemMergeFunction.hpp b/src/libprojectM/Renderer/RenderItemMergeFunction.hpp index c28d5628b..9fb41f80f 100644 --- a/src/libprojectM/Renderer/RenderItemMergeFunction.hpp +++ b/src/libprojectM/Renderer/RenderItemMergeFunction.hpp @@ -15,6 +15,26 @@ #include #include + +template +inline T interpolate(T a, T b, float ratio) +{ + return (ratio*a + (1-ratio)*b) * 0.5; +} + +template <> +inline int interpolate(int a, int b, float ratio) +{ + return (int)(ratio*(float)a + (1-ratio)*(float)b) * 0.5; +} + +template <> +inline bool interpolate(bool a, bool b, float ratio) +{ + return (ratio >= 0.5) ? a : b; +} + + /// Merges two render items and returns zero if they are virtually equivalent and large values /// when they are dissimilar. If two render items cannot be compared, NOT_COMPARABLE_VALUE is returned. class RenderItemMergeFunction { @@ -36,9 +56,9 @@ public: inline virtual void operator()(const RenderItem * r1, const RenderItem * r2, RenderItem * r3, double ratio) const { if (supported(r1, r2)) - return computeMerge(dynamic_cast(r1), dynamic_cast(r2), dynamic_cast(r3)); + return computeMerge(dynamic_cast(r1), dynamic_cast(r2), dynamic_cast(r3), ratio); else if (supported(r2,r1)) - return computeMerge(dynamic_cast(r2), dynamic_cast(r1), dynamic_cast(r3)); + return computeMerge(dynamic_cast(r2), dynamic_cast(r1), dynamic_cast(r3), ratio); else return; } @@ -55,22 +75,6 @@ inline TypeIdPair typeIdPair() const { }; -float interpolate(float a, float b, float ratio) -{ - return (ratio*a + (1-ratio)*b) * 0.5; -} - -int interpolate(int a, int b, float ratio) -{ - return (int)(ratio*(float)a + (1-ratio)*(float)b) * 0.5; -} - -int interpolate(bool a, bool b, float ratio) -{ - return (ratio >= 0.5) ? a : b; -} - - class ShapeMerge : public RenderItemMerge { public: @@ -82,9 +86,9 @@ protected: virtual inline void computeMerge(const Shape * lhs, const Shape * rhs, Shape * target, double ratio) const { - target->x = interpolate(lhs->x, rhs->x, ratio); + target->x = interpolate(lhs->x, rhs->x, ratio); target->y = interpolate(lhs->y, rhs->y, ratio); - target->a = interpolate(lhs->a, rhs->a, ratio); + target->a = interpolate(lhs->a, rhs->a, ratio); target->a2 = interpolate(lhs->a2, rhs->a2, ratio); target->r = interpolate(lhs->r, rhs->r, ratio); target->r2 = interpolate(lhs->r2, rhs->r2, ratio); @@ -114,7 +118,7 @@ protected: target->masterAlpha = interpolate(lhs->masterAlpha, rhs->masterAlpha, ratio); target->imageUrl = (ratio > 0.5) ? lhs->imageUrl : rhs->imageUrl, ratio; - return; + return; } }; @@ -177,9 +181,8 @@ protected: // If specialized mergeFunction exists, use it to get higher granularity // of correctness if (mergeFunction) - renderItem = (*mergeFunction)(lhs, rhs, ratio); - else - renderItem = 0; + (*mergeFunction)(lhs, rhs, renderItem, ratio); + } private: diff --git a/src/libprojectM/projectM.cpp b/src/libprojectM/projectM.cpp index dd6f036c6..bc9b2471a 100755 --- a/src/libprojectM/projectM.cpp +++ b/src/libprojectM/projectM.cpp @@ -20,6 +20,7 @@ */ #include "RenderItemMatcher.hpp" +#include "RenderItemMergeFunction.hpp" #include "fatal.h" #include "Common.hpp" @@ -320,19 +321,23 @@ DLLEXPORT void projectM::renderFrame() { timeKeeper->StartSmoothing(); - // printf("Start Smooth\n"); - // if(timeKeeper->IsSmoothing())printf("Confirmed\n"); switchPreset(m_activePreset2); + + // Compute best matching between the render items. + (*_matcher)(m_activePreset.get()->pipeline().drawables, + m_activePreset2.get()->pipeline().drawables); + presetSwitchedEvent(false, **m_presetPos); } - else if ( ( beatDetect->vol-beatDetect->vol_old>beatDetect->beat_sensitivity ) && timeKeeper->CanHardCut() ) + else if ((beatDetect->vol-beatDetect->vol_old>beatDetect->beat_sensitivity ) && + timeKeeper->CanHardCut()) { // printf("Hard Cut\n"); switchPreset(m_activePreset); - //switchPreset(m_activePreset, presetInputs, presetOutputs); + //fz(m_activePreset, presetInputs, presetOutputs); timeKeeper->StartPreset(); presetSwitchedEvent(true, **m_presetPos); @@ -344,7 +349,6 @@ DLLEXPORT void projectM::renderFrame() { // printf("start thread\n"); - assert ( m_activePreset.get() ); #ifdef USE_THREADS @@ -359,23 +363,21 @@ DLLEXPORT void projectM::renderFrame() evaluateSecondPreset(); #endif - //PresetMerger::MergePresets ( m_activePreset->presetOutputs(),m_activePreset2->presetOutputs(), - // timeKeeper->SmoothRatio(),presetInputs.gx, presetInputs.gy ); + //PresetMerger::MergePresets(m_activePreset->presetOutputs(), m_activePreset2->presetOutputs(), + // timeKeeper->SmoothRatio(), presetInputs.gx, presetInputs.gy); + Pipeline pipeline; + pipeline.setStaticPerPixel(settings().meshX, settings().meshY); -Pipeline pipeline; + assert(_matcher); + PipelineMerger::MergePipelines( m_activePreset->pipeline(), + m_activePreset2->pipeline(), pipeline, _matcher->matchResults().matches, + *_merger, timeKeeper->SmoothRatio()); -pipeline.setStaticPerPixel(settings().meshX, settings().meshY); + /// @bug not sure if this is correct + renderer->RenderFrame(pipeline, pipelineContext()); - -assert(_matcher); -PipelineMerger::MergePipelines( m_activePreset->pipeline(),m_activePreset2->pipeline(), pipeline, *_matcher, timeKeeper->SmoothRatio()); - -/// @bug not sure if this is correct -renderer->RenderFrame(pipeline, pipelineContext()); - -//renderer->RenderFrame ( pipeline, presetInputs ); } else { @@ -468,6 +470,7 @@ void projectM::projectM_init ( int gx, int gy, int fps, int texsize, int width, running = true; initPresetTools(gx, gy); + #ifdef USE_THREADS pthread_mutex_init(&mutex, NULL); @@ -569,13 +572,15 @@ int projectM::initPresetTools(int gx, int gy) // Case where no valid presets exist in directory. Could also mean // playlist initialization was deferred - if ( m_presetChooser->empty() ) + if (m_presetChooser->empty()) { std::cerr << "[projectM] warning: no valid files found in preset directory \"" << m_presetLoader->directoryName() << "\"" << std::endl; } _matcher = new RenderItemMatcher(); + _merger = new MasterRenderItemMerge(); + /// @bug These should be requested by the preset factories. _matcher->distanceFunction().addMetric(new ShapeXYDistance()); //std::cerr << "[projectM] Idle preset allocated." << std::endl; diff --git a/src/libprojectM/projectM.hpp b/src/libprojectM/projectM.hpp index b288c5f97..723992829 100755 --- a/src/libprojectM/projectM.hpp +++ b/src/libprojectM/projectM.hpp @@ -77,6 +77,7 @@ class PresetLoader; class TimeKeeper; class Pipeline; class RenderItemMatcher; +class MasterRenderItemMerge; #include #ifdef WIN32 @@ -304,7 +305,7 @@ private: int m_flags; RenderItemMatcher * _matcher; - + MasterRenderItemMerge * _merger; pthread_mutex_t mutex; pthread_cond_t condition; pthread_t thread; diff --git a/src/projectM-qt/qprojectmconfigdialog.cpp b/src/projectM-qt/qprojectmconfigdialog.cpp index 311da6a2e..1ded548fa 100644 --- a/src/projectM-qt/qprojectmconfigdialog.cpp +++ b/src/projectM-qt/qprojectmconfigdialog.cpp @@ -6,21 +6,15 @@ #include "qprojectmwidget.hpp" QProjectMConfigDialog::QProjectMConfigDialog(const std::string & configFile, QProjectMWidget * qprojectMWidget, QWidget * parent, Qt::WindowFlags f) : QDialog(parent, f), _configFile(configFile), _qprojectMWidget(qprojectMWidget), _settings("projectM", "qprojectM") { - - + + _ui.setupUi(this); - + QHBoxLayout * hboxLayout = new QHBoxLayout(); - + hboxLayout->addWidget(_ui.layoutWidget); this->setLayout(hboxLayout); - -// assert(!layout()); - -// _ui.layoutWidget->setLayout(_ui.gridLayout); - - - //_ui.setLayout + connect(_ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonBoxHandler(QAbstractButton*))); connect(this, SIGNAL(projectM_Reset()), _qprojectMWidget, SLOT(resetProjectM())); connect (_ui.startupPlaylistFileToolButton, SIGNAL(clicked()), this, SLOT(openPlaylistFileDialog())); @@ -31,7 +25,7 @@ QProjectMConfigDialog::QProjectMConfigDialog(const std::string & configFile, QPr } void QProjectMConfigDialog::buttonBoxHandler(QAbstractButton * button) { - + switch (_ui.buttonBox->standardButton(button)) { case QDialogButtonBox::Close: this->hide(); @@ -51,25 +45,25 @@ void QProjectMConfigDialog::buttonBoxHandler(QAbstractButton * button) { } void QProjectMConfigDialog::openPlaylistFileDialog() { - + QPlaylistFileDialog dialog(this); - + dialog.setAllowFileSelect(true); dialog.setAllowDirectorySelect(false); - + if (dialog.exec()) { Q_ASSERT(!dialog.selectedFiles().empty()); _ui.startupPlaylistFileLineEdit->setText(dialog.selectedFiles()[0]); - + } } void QProjectMConfigDialog::openPlaylistDirectoryDialog() { - + QPlaylistFileDialog dialog(this); - + dialog.setAllowFileSelect(false); dialog.setAllowDirectorySelect(true); @@ -77,23 +71,23 @@ void QProjectMConfigDialog::openPlaylistDirectoryDialog() { { Q_ASSERT(!dialog.selectedFiles().empty()); _ui.startupPlaylistDirectoryLineEdit->setText(dialog.selectedFiles()[0]); - + } } void QProjectMConfigDialog::openMenuFontFileDialog() { - - + + QFileDialog dialog(this, "Select a menu font", _settings.value("Menu Font Directory", QString()).toString(), "True Type Fonts (*.ttf)" ); dialog.setFileMode(QFileDialog::ExistingFile); - + if (dialog.exec()) { Q_ASSERT(!dialog.selectedFiles().empty()); _ui.menuFontPathLineEdit->setText(dialog.selectedFiles()[0]); - + _settings.setValue("Menu Font Directory", dialog.directory().absolutePath()); } - - + + } void QProjectMConfigDialog::openTitleFontFileDialog() { @@ -105,13 +99,13 @@ void QProjectMConfigDialog::openTitleFontFileDialog() { _ui.titleFontPathLineEdit->setText(dialog.selectedFiles()[0]); _settings.setValue("Title Font Directory", dialog.directory().absolutePath()); } - + } void QProjectMConfigDialog::saveConfig() { - + projectM::Settings settings = _qprojectMWidget->qprojectM()->settings(); - + settings.meshX = _ui.meshSizeWidthSpinBox->value(); settings.meshY = _ui.meshSizeHeightSpinBox->value(); settings.windowHeight = _ui.windowHeightSpinBox->value(); @@ -128,12 +122,12 @@ void QProjectMConfigDialog::saveConfig() { settings.easterEgg = _ui.easterEggParameterSpinBox->value(); settings.shuffleEnabled = _ui.shuffleOnStartupCheckBox->checkState() == Qt::Checked; projectM::writeConfig(_configFile, settings); - + QSettings qSettings("projectM", "qprojectM"); - + qSettings.setValue("FullscreenOnStartup", _ui.fullscreenOnStartupCheckBox->checkState() == Qt::Checked); qSettings.setValue("MenuOnStartup", _ui.menuOnStartupCheckBox->checkState() == Qt::Checked); - + qSettings.setValue("PlaylistFile", _ui.startupPlaylistFileLineEdit->text()); } @@ -143,21 +137,21 @@ void QProjectMConfigDialog::saveConfig() { void QProjectMConfigDialog::populateTextureSizeComboBox() { _ui.textureSizeComboBox->clear(); - for (int textureSize = 1<<1; textureSize < 1<<14; textureSize<<=1) { - _ui.textureSizeComboBox->addItem(QString("%1").arg(textureSize), textureSize); + for (int textureSize = 1<<1; textureSize < 1<<14; textureSize<<=1) { + _ui.textureSizeComboBox->addItem(QString("%1").arg(textureSize), textureSize); } } void QProjectMConfigDialog::loadConfig() { - + const projectM::Settings & settings = (* _qprojectMWidget->qprojectM()).settings(); - + _ui.meshSizeWidthSpinBox->setValue(settings.meshX); _ui.meshSizeHeightSpinBox->setValue(settings.meshY); - + _ui.titleFontPathLineEdit->setText(settings.titleFontURL.c_str()); _ui.menuFontPathLineEdit->setText(settings.menuFontURL.c_str()); - + _ui.startupPlaylistDirectoryLineEdit->setText(settings.presetURL.c_str()); _ui.useAspectCorrectionCheckBox->setCheckState(settings.aspectCorrection ? Qt::Checked : Qt::Unchecked); _ui.maxFPSSpinBox->setValue(settings.fps); @@ -168,15 +162,15 @@ void QProjectMConfigDialog::loadConfig() { populateTextureSizeComboBox(); _ui.textureSizeComboBox->insertItem(0, QString("%1").arg(settings.textureSize), settings.textureSize); _ui.textureSizeComboBox->setCurrentIndex(0); - + _ui.smoothPresetDurationSpinBox->setValue(settings.smoothPresetDuration); _ui.presetDurationSpinBox->setValue(settings.presetDuration); _ui.easterEggParameterSpinBox->setValue(settings.easterEgg); - - + + QSettings qSettings("projectM", "qprojectM"); _ui.fullscreenOnStartupCheckBox->setCheckState(qSettings.value("FullscreenOnStartup", false).toBool() ? Qt::Checked : Qt::Unchecked); _ui.menuOnStartupCheckBox->setCheckState(qSettings.value("MenuOnStartup", false).toBool() ? Qt::Checked : Qt::Unchecked); _ui.startupPlaylistFileLineEdit->setText(qSettings.value("PlaylistFile", QString()).toString() ); - + }