mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-03-31 11:43:31 +00:00
first buildable implementation of a render item object optimal matching algorithm.
git-svn-id: https://projectm.svn.sourceforge.net/svnroot/projectm/personal/carm/represet@1207 6778bc44-b910-0410-a7a0-be141de4315d
This commit is contained in:
@ -24,12 +24,12 @@
|
||||
* $Log$
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifndef COMMON_HPP
|
||||
#define COMMON_HPP
|
||||
#include <typeinfo>
|
||||
#include <cstdarg>
|
||||
#include <cassert>
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _MSC_sVER
|
||||
#define strcasecmp(s, t) _strcmpi(s, t)
|
||||
#endif
|
||||
|
||||
@ -204,12 +204,10 @@ else
|
||||
|
||||
}
|
||||
|
||||
inline void DWRITE( char *fmt, ... ) {
|
||||
return;
|
||||
va_list args;
|
||||
va_start( args, fmt );
|
||||
va_end( args );
|
||||
}
|
||||
|
||||
inline double meanSquaredError(const double & x, const double & y) {
|
||||
return (x-y)*(x-y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <limits>
|
||||
|
||||
/// A function object which calculates the maximum-weighted bipartite matching between
|
||||
/// two sets via the hungarian method.
|
||||
@ -189,3 +189,4 @@ inline int inverseMatching(int j) const {
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//
|
||||
// C++ Interface: PresetFactory
|
||||
//
|
||||
// Description:
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2008
|
||||
@ -36,7 +36,7 @@ public:
|
||||
|
||||
/// Returns a space separated list of supported extensions
|
||||
virtual std::string supportedExtensions() const = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -139,7 +139,7 @@ std::auto_ptr<Preset> PresetLoader::loadPreset ( unsigned int index ) const
|
||||
|
||||
return _presetFactoryManager.factory(extension).allocate
|
||||
( _entries[index], _presetNames[index] );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#include "PresetMerge.hpp"
|
||||
#include "RenderItemMatcher.hpp"
|
||||
|
||||
|
||||
|
||||
void PipelineMerger::MergePipelines(const Pipeline & a, const Pipeline & b, Pipeline & out, float ratio)
|
||||
void PipelineMerger::MergePipelines(const Pipeline & a, const Pipeline & b, Pipeline & out, RenderItemMatcher & matcher, float ratio)
|
||||
{
|
||||
|
||||
double invratio = 1.0 - ratio;
|
||||
@ -12,6 +12,11 @@ void PipelineMerger::MergePipelines(const Pipeline & a, const Pipeline & b, Pipe
|
||||
out.screenDecay =lerp( b.screenDecay, a.screenDecay, ratio);
|
||||
out.drawables.clear();
|
||||
|
||||
double error = 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);
|
||||
|
||||
for (std::vector<RenderItem*>::const_iterator pos = a.drawables.begin();
|
||||
pos != a.drawables.end(); ++pos)
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#define PRESET_MERGE_HPP
|
||||
#include "Preset.hpp"
|
||||
#include "Pipeline.hpp"
|
||||
#include "RenderItemMatcher.hpp"
|
||||
|
||||
class PipelineMerger
|
||||
{
|
||||
@ -11,7 +12,8 @@ class PipelineMerger
|
||||
}
|
||||
|
||||
public:
|
||||
static void MergePipelines(const Pipeline &a, const Pipeline &b, Pipeline &out, float ratio);
|
||||
static void MergePipelines(const Pipeline &a, const Pipeline &b, Pipeline &out, RenderItemMatcher & matcher, float ratio);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,9 @@ cmake_minimum_required(VERSION 2.4.0)
|
||||
|
||||
SET(SOIL_SOURCES SOIL/image_DXT.c SOIL/image_helper.c SOIL/SOIL.c SOIL/stb_image_aug.c)
|
||||
|
||||
SET(Renderer_SOURCES FBO.cpp MilkdropWaveform.cpp PerPixelMesh.cpp Pipeline.cpp Renderer.cpp ShaderEngine.cpp UserTexture.cpp Waveform.cpp Filters.cpp PerlinNoise.cpp PipelineContext.cpp Renderable.cpp BeatDetect.cpp Shader.cpp TextureManager.cpp VideoEcho.cpp ${SOIL_SOURCES})
|
||||
SET(Renderer_SOURCES FBO.cpp MilkdropWaveform.cpp PerPixelMesh.cpp Pipeline.cpp Renderer.cpp ShaderEngine.cpp UserTexture.cpp Waveform.cpp
|
||||
Filters.cpp PerlinNoise.cpp PipelineContext.cpp Renderable.cpp BeatDetect.cpp Shader.cpp TextureManager.cpp VideoEcho.cpp
|
||||
RenderItemDistanceMetric.cpp ${SOIL_SOURCES})
|
||||
|
||||
SET (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fPIC)
|
||||
SET (CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -fPIC)
|
||||
|
||||
10
src/libprojectM/Renderer/RenderItemDistanceMetric.cpp
Normal file
10
src/libprojectM/Renderer/RenderItemDistanceMetric.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* RenderItemDistanceMetric.cpp
|
||||
*
|
||||
* Created on: Feb 18, 2009
|
||||
* Author: struktured
|
||||
*/
|
||||
|
||||
#include "RenderItemDistanceMetric.hpp"
|
||||
const double RenderItemDistanceMetric::NOT_COMPARABLE_VALUE
|
||||
(std::numeric_limits<double>::max());
|
||||
150
src/libprojectM/Renderer/RenderItemDistanceMetric.hpp
Normal file
150
src/libprojectM/Renderer/RenderItemDistanceMetric.hpp
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* RenderItemDistanceMetric.h
|
||||
*
|
||||
* Created on: Feb 16, 2009
|
||||
* Author: struktured
|
||||
*/
|
||||
|
||||
#ifndef RenderItemDISTANCEMETRIC_H_
|
||||
#define RenderItemDISTANCEMETRIC_H_
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "Renderable.hpp"
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
struct TypeIdPair {
|
||||
TypeIdPair(const std::type_info & info1, const std::type_info & info2): id1(info1.name()), id2(info2.name()) {}
|
||||
TypeIdPair(const std::string & id1, const std::string & id2): id1(id1), id2(id2) {}
|
||||
std::string id1;
|
||||
std::string id2;
|
||||
inline bool operator<(const TypeIdPair & rhs) const {
|
||||
return this->id1 < rhs.id1 || (this->id1 == rhs.id1 && this->id2 < rhs.id2);
|
||||
}
|
||||
|
||||
inline bool operator>(const TypeIdPair & rhs) const {
|
||||
return !operator<(rhs) && !operator==(rhs);
|
||||
}
|
||||
|
||||
inline bool operator==(const TypeIdPair & rhs) const {
|
||||
return this->id1 == rhs.id1 && this->id2 == rhs.id2;
|
||||
}
|
||||
};
|
||||
|
||||
/// Compares 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 RenderItemDistanceMetric : public std::binary_function<const RenderItem*, const RenderItem*, double> {
|
||||
public:
|
||||
const static double NOT_COMPARABLE_VALUE;
|
||||
virtual double operator()(const RenderItem * r1, const RenderItem * r2) const = 0;
|
||||
virtual TypeIdPair typeIdPair() const = 0;
|
||||
};
|
||||
|
||||
// A base class to construct render item distance metrics. Just specify your two concrete
|
||||
// render item types as template parameters and override the computeDistance() function.
|
||||
template <class R1, class R2>
|
||||
class RenderItemDistance : public RenderItemDistanceMetric {
|
||||
|
||||
protected:
|
||||
// Override to create your own distance metric for your specified custom types.
|
||||
virtual double computeDistance(const R1 * r1, const R2 * r2) const = 0;
|
||||
|
||||
public:
|
||||
|
||||
inline virtual double operator()(const RenderItem * r1, const RenderItem * r2) const {
|
||||
if (supported(r1, r2))
|
||||
return computeDistance(dynamic_cast<const R1*>(r1), dynamic_cast<const R2*>(r2));
|
||||
else if (supported(r2,r1))
|
||||
return computeDistance(dynamic_cast<const R2*>(r2), dynamic_cast<const R2*>(r1));
|
||||
else
|
||||
return NOT_COMPARABLE_VALUE;
|
||||
}
|
||||
|
||||
// Returns true if and only if r1 and r2 are of type R1 and R2 respectively.
|
||||
inline bool supported(const RenderItem * r1, const RenderItem * r2) const {
|
||||
return typeid(r1) == typeid(const R1 *) && typeid(r2) == typeid(const R2 *);
|
||||
}
|
||||
|
||||
inline TypeIdPair typeIdPair() const {
|
||||
return TypeIdPair(typeid(const R1*).name(), typeid(const R2*).name());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class RTIRenderItemDistance : public RenderItemDistance<RenderItem, RenderItem> {
|
||||
public:
|
||||
|
||||
RTIRenderItemDistance() {}
|
||||
virtual ~RTIRenderItemDistance() {}
|
||||
|
||||
protected:
|
||||
virtual inline double computeDistance(const RenderItem * lhs, const RenderItem * rhs) const {
|
||||
if (typeid(lhs) == typeid(rhs))
|
||||
return 0.0;
|
||||
else
|
||||
return NOT_COMPARABLE_VALUE;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ShapeXYDistance : public RenderItemDistance<Shape, Shape> {
|
||||
|
||||
public:
|
||||
|
||||
ShapeXYDistance() {}
|
||||
virtual ~ShapeXYDistance() {}
|
||||
|
||||
protected:
|
||||
|
||||
virtual inline double computeDistance(const Shape * lhs, const Shape * rhs) const {
|
||||
return (meanSquaredError(lhs->x, rhs->x) + meanSquaredError(lhs->y, rhs->y)) / 2;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MasterRenderItemDistance : public RenderItemDistance<RenderItem, RenderItem> {
|
||||
|
||||
typedef std::map<TypeIdPair, RenderItemDistanceMetric*> DistanceMetricMap;
|
||||
public:
|
||||
|
||||
MasterRenderItemDistance() {}
|
||||
virtual ~MasterRenderItemDistance() {}
|
||||
|
||||
inline void addMetric(RenderItemDistanceMetric * fun) {
|
||||
_distanceMetricMap[fun->typeIdPair()] = fun;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual inline double computeDistance(const RenderItem * lhs, const RenderItem * rhs) const {
|
||||
|
||||
RenderItemDistanceMetric * metric;
|
||||
|
||||
TypeIdPair pair(typeid(lhs), typeid(rhs));
|
||||
if (_distanceMetricMap.count(pair)) {
|
||||
metric = _distanceMetricMap[pair];
|
||||
} else if (_distanceMetricMap.count(pair = TypeIdPair(typeid(lhs), typeid(rhs)))) {
|
||||
metric = _distanceMetricMap[pair];
|
||||
} else {
|
||||
metric = 0;
|
||||
}
|
||||
|
||||
// If specialized metric exists, use it to get higher granularity
|
||||
// of correctness
|
||||
if (metric)
|
||||
return (*metric)(lhs, rhs);
|
||||
else // Failing that, use rtti and return 0 if they match, max value otherwise
|
||||
return _rttiDistance(lhs,rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable RTIRenderItemDistance _rttiDistance;
|
||||
mutable DistanceMetricMap _distanceMetricMap;
|
||||
};
|
||||
|
||||
#endif /* RenderItemDISTANCEMETRIC_H_ */
|
||||
65
src/libprojectM/Renderer/RenderItemMatcher.hpp
Normal file
65
src/libprojectM/Renderer/RenderItemMatcher.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* RenderItemMatcher.hpp
|
||||
*
|
||||
* Created on: Feb 16, 2009
|
||||
* Author: struktured
|
||||
*/
|
||||
|
||||
#ifndef RenderItemMatcher_HPP
|
||||
#define RenderItemMatcher_HPP
|
||||
|
||||
#include "RenderItemDistanceMetric.hpp"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include "HungarianMethod.hpp"
|
||||
|
||||
|
||||
class RenderItemMatcher : public std::binary_function<RenderItemList, RenderItemList, double> {
|
||||
public:
|
||||
static const std::size_t MAXIMUM_SET_SIZE = 1000;
|
||||
|
||||
/// Computes an optimal matching between two renderable item sets.
|
||||
inline virtual double operator()(const RenderItemList & lhs, const RenderItemList & rhs) const {
|
||||
|
||||
// Ensure the first argument is greater than next to aid the helper function's logic.
|
||||
if (lhs.size() >= rhs.size())
|
||||
return computeMatching(lhs, rhs);
|
||||
else
|
||||
return computeMatching(rhs, lhs);
|
||||
}
|
||||
|
||||
/// @idea could instead just pass back a vector of render item pointer pairs. ask sperl
|
||||
inline int matching(int i) const { return _hungarianMethod.matching(i); }
|
||||
inline int inverseMatching(int j) const { return _hungarianMethod.inverseMatching(j); }
|
||||
inline double weight(int i, int j) const { return _weights[i][j]; }
|
||||
|
||||
RenderItemMatcher() {}
|
||||
virtual ~RenderItemMatcher() {}
|
||||
|
||||
MasterRenderItemDistance & distanceFunction() { return _distanceFunction; }
|
||||
|
||||
private:
|
||||
mutable HungarianMethod<MAXIMUM_SET_SIZE> _hungarianMethod;
|
||||
mutable double _weights[MAXIMUM_SET_SIZE][MAXIMUM_SET_SIZE];
|
||||
|
||||
/// @idea interface this entirely allow overriding of its type.
|
||||
mutable MasterRenderItemDistance _distanceFunction;
|
||||
|
||||
inline double computeMatching(const RenderItemList & lhs, const RenderItemList & rhs) const {
|
||||
for (int i = 0; i < lhs.size();i++) {
|
||||
int j;
|
||||
for (j = 0; j < rhs.size();j++)
|
||||
_weights[i][j] = _distanceFunction(lhs[i], rhs[j]);
|
||||
for (; j < lhs.size();j++)
|
||||
_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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,9 +1,11 @@
|
||||
#ifndef Renderable_HPP
|
||||
#define Renderable_HPP
|
||||
#include <vector>
|
||||
|
||||
#include "TextureManager.hpp"
|
||||
class BeatDetect;
|
||||
|
||||
|
||||
class RenderContext
|
||||
{
|
||||
public:
|
||||
@ -25,6 +27,8 @@ public:
|
||||
RenderItem();
|
||||
};
|
||||
|
||||
typedef std::vector<RenderItem*> RenderItemList;
|
||||
|
||||
class DarkenCenter : public RenderItem
|
||||
{
|
||||
public:
|
||||
|
||||
@ -66,7 +66,7 @@ public:
|
||||
|
||||
Renderer( int width, int height, int gx, int gy, int texsize, BeatDetect *beatDetect, std::string presetURL, std::string title_fontURL, std::string menu_fontURL);
|
||||
~Renderer();
|
||||
|
||||
|
||||
void RenderFrame(const Pipeline &pipeline, const PipelineContext &pipelineContext);
|
||||
void ResetTextures();
|
||||
void reset(int w, int h);
|
||||
|
||||
@ -18,8 +18,8 @@
|
||||
* See 'LICENSE.txt' included within this release
|
||||
*
|
||||
*/
|
||||
#include "wipemalloc.h"
|
||||
|
||||
#include "RenderItemMatcher.hpp"
|
||||
#include "fatal.h"
|
||||
#include "Common.hpp"
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
#include "ConfigFile.h"
|
||||
#include "TextureManager.hpp"
|
||||
#include "TimeKeeper.hpp"
|
||||
|
||||
#ifdef USE_THREADS
|
||||
#include "pthread.h"
|
||||
#endif
|
||||
@ -330,7 +331,9 @@ Pipeline pipeline;
|
||||
|
||||
pipeline.setStaticPerPixel(settings().meshX, settings().meshY);
|
||||
|
||||
PipelineMerger::MergePipelines( m_activePreset->pipeline(),m_activePreset2->pipeline(), pipeline,timeKeeper->SmoothRatio());
|
||||
|
||||
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());
|
||||
@ -535,6 +538,9 @@ int projectM::initPresetTools(int gx, int gy)
|
||||
<< m_presetLoader->directoryName() << "\"" << std::endl;
|
||||
}
|
||||
|
||||
_matcher = new RenderItemMatcher();
|
||||
_matcher->distanceFunction().addMetric(new ShapeXYDistance());
|
||||
|
||||
//std::cerr << "[projectM] Idle preset allocated." << std::endl;
|
||||
|
||||
projectM_resetengine();
|
||||
|
||||
@ -77,6 +77,7 @@ class PresetChooser;
|
||||
class PresetLoader;
|
||||
class TimeKeeper;
|
||||
class Pipeline;
|
||||
class RenderItemMatcher;
|
||||
|
||||
#include <memory>
|
||||
#ifdef WIN32
|
||||
@ -104,7 +105,7 @@ typedef enum {
|
||||
/// A functor class that allows users of this library to specify random preset behavior
|
||||
class RandomizerFunctor {
|
||||
|
||||
public:
|
||||
public:
|
||||
RandomizerFunctor(PresetChooser & chooser) ;
|
||||
virtual ~RandomizerFunctor();
|
||||
virtual double operator() (int index);
|
||||
@ -299,6 +300,8 @@ private:
|
||||
|
||||
int m_flags;
|
||||
|
||||
RenderItemMatcher * _matcher;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t condition;
|
||||
pthread_t thread;
|
||||
|
||||
Reference in New Issue
Block a user