| /* |
| * 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 <limits> |
| #include <functional> |
| #include <map> |
| |
| |
| template <class T> |
| 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 R1, class R2=R1, class R3=R2> |
| 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<const R1*>(r1), dynamic_cast<const R2*>(r2), ratio); |
| else if (supported(r2,r1)) |
| return computeMerge(dynamic_cast<const R1*>(r2), dynamic_cast<const R2*>(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<Shape> { |
| 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<Border> { |
| 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<Waveform> |
| { |
| 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<RenderItem> { |
| |
| typedef std::map<TypeIdPair, RenderItemMergeFunction*> 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_ */ |