/* * RenderItemMergeFunction.hpp * * Created on: Feb 16, 2009 * Author: struktured */ #ifndef RenderItemMergeFunction_HPP_ #define RenderItemMergeFunction_HPP_ #include "Common.hpp" #include "Renderable.hpp" #include "Waveform.hpp" #include #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 { public: virtual RenderItem * operator()(const RenderItem * r1, const RenderItem * r2, double ratio) const = 0; virtual TypeIdPair typeIdPair() const = 0; }; /// A base class to construct render item distance mergeFunctions. Just specify your two concrete /// render item types as template parameters and override the computeMerge() function. template class RenderItemMerge : public RenderItemMergeFunction { protected: /// Override to create your own distance mergeFunction for your specified custom types. virtual R3 * computeMerge(const R1 * r1, const R2 * r2, double ratio) const = 0; public: inline virtual R3 * operator()(const RenderItem * r1, const RenderItem * r2, double ratio) const { if (supported(r1, r2)) return computeMerge(dynamic_cast(r1), dynamic_cast(r2), ratio); else if (supported(r2,r1)) return computeMerge(dynamic_cast(r2), dynamic_cast(r1), ratio); else return 0; } /// 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 ShapeMerge : public RenderItemMerge { public: ShapeMerge() {} virtual ~ShapeMerge() {} protected: virtual inline Shape * computeMerge(const Shape * lhs, const Shape * rhs, double ratio) const { Shape * ret = new Shape(); Shape & target = *ret; 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.a2 = interpolate(lhs->a2, rhs->a2, ratio); target.r = interpolate(lhs->r, rhs->r, ratio); target.r2 = interpolate(lhs->r2, rhs->r2, ratio); target.g = interpolate(lhs->g, rhs->g, ratio); target.g2 = interpolate(lhs->g2, rhs->g2, ratio); target.b = interpolate(lhs->b, rhs->b, ratio); target.b2 = interpolate(lhs->b2, rhs->b2, ratio); target.ang = interpolate(lhs->ang, rhs->ang, ratio); target.radius = interpolate(lhs->radius, rhs->radius, ratio); target.tex_ang = interpolate(lhs->tex_ang, rhs->tex_ang, ratio); target.tex_zoom = interpolate(lhs->tex_zoom, rhs->tex_zoom, ratio); target.border_a = interpolate(lhs->border_a, rhs->border_a, ratio); target.border_r = interpolate(lhs->border_r, rhs->border_r, ratio); target.border_g = interpolate(lhs->border_g, rhs->border_g, ratio); target.border_b = interpolate(lhs->border_b, rhs->border_b, ratio); target.sides = interpolate(lhs->sides, rhs->sides, ratio); target.additive = interpolate(lhs->additive, rhs->additive, ratio); target.textured = interpolate(lhs->textured, rhs->textured, ratio); target.thickOutline = interpolate(lhs->thickOutline, rhs->thickOutline, ratio); target.enabled = interpolate(lhs->enabled, rhs->enabled, ratio); target.masterAlpha = interpolate(lhs->masterAlpha, rhs->masterAlpha, ratio); target.imageUrl = (ratio > 0.5) ? lhs->imageUrl : rhs->imageUrl, ratio; return ret; } }; class BorderMerge : public RenderItemMerge { public: BorderMerge() {} virtual ~BorderMerge() {} protected: virtual inline Border * computeMerge(const Border * lhs, const Border * rhs, double ratio) const { Border * ret = new Border(); Border & target = *ret; target.inner_a = interpolate(lhs->inner_a, rhs->inner_a, ratio); target.inner_r = interpolate(lhs->inner_r, rhs->inner_r, ratio); target.inner_g = interpolate(lhs->inner_g, rhs->inner_g, ratio); target.inner_b = interpolate(lhs->inner_b, rhs->inner_b, ratio); target.inner_size = interpolate(lhs->inner_size, rhs->inner_size, ratio); target.outer_a = interpolate(lhs->outer_a, rhs->outer_a, ratio); target.outer_r = interpolate(lhs->outer_r, rhs->outer_r, ratio); target.outer_g = interpolate(lhs->outer_g, rhs->outer_g, ratio); target.outer_b = interpolate(lhs->outer_b, rhs->outer_b, ratio); target.outer_size = interpolate(lhs->outer_size, rhs->outer_size, ratio); target.masterAlpha = interpolate(lhs->masterAlpha, rhs->masterAlpha, ratio); return ret; } }; class WaveformMerge : public RenderItemMerge { public: WaveformMerge() {} virtual ~WaveformMerge() {} protected: /// @BUG unimplemented virtual inline Waveform * computeMerge(const Waveform * lhs, const Waveform * rhs, double ratio) const { return 0; /* Waveform * ret = new Waveform(); Waveform & target = *ret; target.additive = interpolate(lhs->additive, rhs->additive, ratio); target.dots = interpolate(lhs->dots, rhs->dots, ratio); target.samples = (rhs->samples > lhs-> samples) ? lhs->samples : rhs->samples; target.scaling = interpolate(lhs->scaling, rhs->scaling, ratio); target.sep = interpolate(lhs->sep, rhs->sep, ratio); target.smoothing = interpolate(lhs->smoothing, rhs->smoothing, ratio); target.spectrum = interpolate(lhs->spectrum, rhs->spectrum, ratio); target.thick = interpolate(lhs->thick, rhs->thick, ratio); target.masterAlpha = interpolate(lhs->masterAlpha, rhs->masterAlpha, ratio); return ret; */ } }; /// Use as the top level merge function. It stores a map of all other /// merge functions, using the function that fits best with the /// incoming type parameters. class MasterRenderItemMerge : public RenderItemMerge { typedef std::map MergeFunctionMap; public: MasterRenderItemMerge() {} virtual ~MasterRenderItemMerge() {} inline void add(RenderItemMergeFunction * fun) { _mergeFunctionMap[fun->typeIdPair()] = fun; } protected: virtual inline RenderItem * computeMerge(const RenderItem * lhs, const RenderItem * rhs, double ratio) const { RenderItemMergeFunction * mergeFunction; TypeIdPair pair(typeid(lhs), typeid(rhs)); if (_mergeFunctionMap.count(pair)) { mergeFunction = _mergeFunctionMap[pair]; } else if (_mergeFunctionMap.count(pair = TypeIdPair(typeid(rhs), typeid(lhs)))) { mergeFunction = _mergeFunctionMap[pair]; } else { mergeFunction = 0; } // If specialized mergeFunction exists, use it to get higher granularity // of correctness if (mergeFunction) return (*mergeFunction)(lhs, rhs, ratio); else return 0; } private: mutable MergeFunctionMap _mergeFunctionMap; }; #endif /* RenderItemMergeFunction_HPP_ */