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:
w1z7ard
2009-02-18 09:31:41 +00:00
parent 92f282a9bb
commit cf83c16e3e
14 changed files with 269 additions and 23 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -139,7 +139,7 @@ std::auto_ptr<Preset> PresetLoader::loadPreset ( unsigned int index ) const
return _presetFactoryManager.factory(extension).allocate
( _entries[index], _presetNames[index] );
}

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View 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());

View 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_ */

View 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

View File

@ -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:

View File

@ -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);

View File

@ -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();

View File

@ -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;