It is currently Sat May 27, 2017 8:41 am

All times are UTC - 5 hours




 Page 1 of 1 [ 2 posts ] 
Author Message
 Post subject: A useful helper class Wink ;)
PostPosted: Tue Jan 20, 2009 8:45 pm 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
Hello and welcome...

Let me introduce the class Wink (or Oscillator); the first version was written about 7 or more years ago and since that time Wink was constantly revealed as being quite useful, especially in the field of applied computer graphics (CG).

Abstract.
In CG, we often need an object the color or the position of which is changing according to some simple linear law. For instance, the color could twinkle; the rectangle could move left and right within some bounds, and so on. Formalizing the law of variation we get a set of 4 values:

const Type MIN_VALUE;
const Type MAX_VALUE;
const Type STEP;
Type current_value;


It is beyond all question that each programmer is able to make the current_value be fluctuating between given MIN_VALUE and MAX_VALUE. Nevertheless, to remove the necessity to write the same trivial code again and again, and to provide a uniform interface, it is helpful to implement the task once and for all in the form of template class and put the code in header file.

An example of use.

#include "wink.h"

wink::wfloat m_x( -1.0f, +1.0f, 0.0f, 0.01f );
wink::wfloat m_y( -2.0f, +2.0f, 0.0f, 0.005f );

void Update()
{
    ++ m_x;
    ++ m_y;
}

void Render()
{
  :
  glTranslate2f( m_x, m_y );
  :
}

In general, to define a variable of the type Wink you write the code
wink::Wink<type, mode> wink_name;
To increment the current value use overloaded operator ++, i.e.
++ wink_name;
To get the current value in most cases you only need to write the name of variable; then C++ compiler will call the conversion operator:
operator T () const { return m_cur; }

If you look at my simple demo scene here you will find a lot of elements, the color, size, and position of which are varying in given ranges. Wink class helped me a lot, significantly decreasing the amount of code I had to write. (I also implemented the support of this feature as an extension of LVL format to add some dynamism to the static levels. Maybe I will write about this in VMK 31-"parsing text file" thread a little later.)

BTW, the class is sufficiently optimized, so in most cases the code will induce small or zero overhead in comparison with hand-written code.


Last edited by BugHunter on Tue Jan 20, 2009 8:52 pm, edited 2 times in total.

Offline
 Profile  
 
 Post subject: A useful helper class Wink - the CODE.
PostPosted: Tue Jan 20, 2009 8:49 pm 

Joined: Wed Aug 06, 2008 7:53 pm
Posts: 182
Location: Russia
(You are authorized to do with this code whatever you want, even to send it to your mother-in-law).

#ifndef __WINK_H__
#define __WINK_H__

/*
 * Copyright (c) 2008 Alex Mission (a.k.a. BugHunter).
 */

//
// Define USE_BOOST_TYPE_CHECK before including this file to use BOOST compile time type check
//
//  #define USE_BOOST_TYPE_CHECK // temp
//
#ifdef USE_BOOST_TYPE_CHECK
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#endif

/*------------------------------------------------------------------------------

Class Wink
    Qualified name: class wink::Wink< T, mode >

Abstract
    Wink class supports the linear variation of the value in the given range.

Type T requirements.
    These prerequisites can be ensured by BOOST.
    T type must support following set of operations:
    +, -, +=, -=, ++, --, =, ==, <
    Additionally, if mode == ModeUpDown then T must be signed type.

------------------------------------------------------------------------------*/

namespace wink {

enum Mode
{
    ModeUpDown, ModeUp, ModeDown
};

template <
    typename T = float,
    Mode mode = ModeUpDown
    >
class Wink
{
    T   m_min;  //
    T   m_max;  //
    T   m_cur;  //
    T   m_step; //

    void ReverseDir();
    void ResetDir();

public: // ctor(s)

    Wink(T min_, T max_, T cur, T step) { Set(min_, max_, cur, step); }

    Wink(T min_, T max_, T step) { Set(min_, max_, min_, step); } // note: assume cur = min

    Wink() { } // to permit an array of objects; don't forget to initialize each item of array later on

    // compiler-generated copy ctor, operator= (all are bitwise), and dtor are welcome.

public: // public interface

    void Reset();
    void Set(T min_, T max_, T cur, T step);
    void SetMin(T min_)     { Set(min_, m_max, m_cur, m_step); }
    void SetMax(T max_)     { Set(m_min, max_, m_cur, m_step); }
    void SetCur(T cur_)     { Set(m_min, m_max, cur_, m_step); }
    void SetStep(T step)    { Set(m_min, m_max, m_cur, step); }

    void operator() (T min_, T max_, T step)            { Set(min_, max_, min_, step); }
    void operator() (T min_, T max_, T cur_, T step)    { Set(min_, max_, cur_, step); }

//  T operator() () const { return m_cur; }

    operator T () const { return m_cur; }

    T       GetCur()    const   { return m_cur; }
    T       GetMin()    const   { return m_min; }
    T       GetMax()    const   { return m_max; }
    T       GetStep()   const   { return m_step; }
    Mode    GetMode()   const   { return mode; }
    Mode    GetDir()    const;
    bool    IsDirUp()   const   { return GetDir() == ModeUp; }
    bool    IsDirDown() const   { return GetDir() == ModeDown; }

    bool    GetHitMin() const   { return m_cur == m_min; }
    bool    GetHitMax() const   { return m_cur == m_max; }
    bool    GetHit()    const   { return (GetHitMin() || GetHitMax()); }

    T operator++ (int);
    T operator++ ();
    T operator-- (int);
    T operator-- ();

private: // compile-time concept check

    #if defined( USE_BOOST_TYPE_CHECK )
    BOOST_STATIC_ASSERT( (ModeUpDown != mode)
        ||  boost::is_signed<T>::value
        ||  boost::is_floating_point<T>::value
        );
    #endif
};

template<typename T, Mode mode>
inline
void Wink<T, mode>:: ReverseDir()
{
    m_step = -m_step;
}

template<typename T, Mode mode>
inline
void Wink<T, mode>:: ResetDir()
{
    if (ModeUpDown == mode)
        if (m_step < 0)
            ReverseDir();
}

template<typename T, Mode mode>
inline
T Wink<T, mode>:: operator++ (int)
{
    T temp = m_cur;
    this->operator ++();
    return temp;
}

template<typename T, Mode mode>
inline
T Wink<T, mode>:: operator-- (int)
{
    T temp = m_cur;
    this->operator --();
    return temp;
}

template<typename T, Mode mode>
inline
void Wink<T, mode>:: Set(T min_, T max_, T cur, T step)
{
    m_step = step;
    min_ < max_ ? ( m_min = min_, m_max = max_ ) : ( m_min = max_, m_max = min_ ) ;
    m_cur = (m_min <= cur) && (cur <= m_max) ? cur : m_min ;
}

template<typename T, Mode mode>
inline
void Wink<T, mode>::Reset()
{
    m_cur = m_min;
    ResetDir();
}

template<typename T, Mode mode>
inline
Mode Wink<T, mode>:: GetDir() const
{
    switch (mode)
    {
    case ModeUpDown: return (m_step > 0) ? ModeUp : ModeDown;
    case ModeUp: return ModeUp;
    case ModeDown: return ModeDown;
    }
    return ModeUp; // to suppress the warning "not all control paths return value"
}

//
// The algorithm ensures that min & max points are reachable
//
template<typename T, Mode mode>
inline
T Wink<T, mode>:: operator++()
{
    switch (mode)
    {
        case ModeUpDown:
            if ((m_cur += m_step) >= m_max)
            { m_cur = m_max; ReverseDir(); }
            else if (m_cur <= m_min)
            { m_cur = m_min; ReverseDir(); }
            break;
        case ModeUp:
            if (m_cur == m_max)
            { m_cur = m_min; }
            else if ((m_cur += m_step) > m_max)
            { m_cur = m_max; }
            break;
        case ModeDown:
            if (m_cur == m_min)
            { m_cur = m_max; }
            else if ((m_cur -= m_step) < m_min)
            { m_cur = m_min; }
            break;
    }
    return m_cur;
}

//
// The algorithm ensures that min & max points are reachable
//
template<typename T, Mode mode>
inline
T Wink<T, mode>:: operator--()
{
    switch (mode)
    {
        case ModeUpDown:
            if ((m_cur -= m_step) >= m_max)
            { m_cur = m_max; ReverseDir(); }
            else if (m_cur <= m_min)
            { m_cur = m_min; ReverseDir(); }
            break;
        case ModeDown:
            if (m_cur == m_max)
            { m_cur = m_min; }
            else if ((m_cur += m_step) > m_max)
            { m_cur = m_max; }
            break;
        case ModeUp:
            if (m_cur == m_min)
            { m_cur = m_max; }
            else if ((m_cur -= m_step) < m_min)
            { m_cur = m_min; }
            break;
    }
    return m_cur;
}

//
// Most frequently used types
//

typedef Wink <int   , ModeUpDown>   WinkInt;
typedef Wink <float , ModeUpDown>   WinkFloat;
typedef Wink <double, ModeUpDown>   WinkDouble;

typedef WinkInt     wint;
typedef WinkFloat   wfloat;
typedef WinkDouble  wdouble;

} // end of namespace "wink"


#endif // __WINK_H__


Offline
 Profile  
 
Display posts from previous:  Sort by  
 Page 1 of 1 [ 2 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  

cron