home *** CD-ROM | disk | FTP | other *** search
- #pragma once
- //
- // class flowdots is used for the rapid appliance of first order optic
- // flow to large numbers of dots. A large speed increases is obtained by performing
- // many operations in integers. At the same time the interface to the class uses
- // doubles for ease of use.
- // We store coordinates of dots in 16-bit signed fixed point format with an implied
- // decimal point after the second bit. This limits the values of the numbers used
- // to the range (-2.0, +2.0) (boundaries excluded)
- //
- // Two copies of the actual parameters of the flow are kept:
- //
- // 1. The user accessible ones, in doubles, and in degrees and per second
- // 2. A copy in fixed-point quantities, in 'per stimulus frame period'
- //
- // The user can set 1. directly.
- // When how_often (see below) is unequal to zero a call to 'changed()' computes 2.
- // When how_often is zero, 2. is recomputed by every call to 'apply_flow', which
- // is called by 'screendots::make_a_move'
- //
- // The translation from per-second parameters, as specified in the flowsettings
- // (copy 1) to per-frame coordinates (copy 2), takes place via one of two methods.
- // Firstly the user can call the constructor with how_often == 0 (or later call
- // 'set_how_often()' to set it to zero). If this is done the routine keeps track of
- // the time taken between subsequent calls of 'apply_flow' and scales the
- // displacements accordingly. Alternatively when 'how_often' is unequal to zero it
- // is assumed to signify the frequency (in Hz) with which 'apply_flow' gets called.
- //
- // Note that it generally is faster to explicitly set 'how_often' to something non-zero.
- //
- #define degrees * 0.0174532925199
- #define degrees_per_second * 0.0174532925199
- //
- // 950502: deriving flowdots from 'flowparams'. This allows one to switch
- // between different flow parameters at high speed, i.e. without having to
- // call 'changed()'. One can now do:
- //
- // flowdots fd( 8, 100, 100, 1000, 10, 75.0);
- // fd.rotation = 20;
- // fd.changed();
- // const flowparams rot_params = fd;
- //
- // fd.rotation = 0;
- // fd.expansion = 1.1;
- // fd.changed();
- // const flowparams div_params = fd;
- //
- // while( !done)
- // {
- // fd.setsettings( rot_params);
- // fd.make_a_move();
- // fd.setsettings( div_params);
- // fd.make_a_move();
- // }
- //
- // However, calling
- //
- // void flowdots::setsettings( const flowparams &theparams);
- //
- // only makes sense when 'how_often' is unequal to zero. If it is zero (signalling
- // that flowdots should figure out itself how often it gets called) flowdots
- // recomputes the fixed-point parameters everytime new dot positions must be
- // computed, thus overwriting any parameters present.
- //
- // if how_often then
- // ============ ====
- // == 0.0 use void setsettings( const flowsettings &thesettings);
- // != 0.0 use void setsettings( const flowparams &theparams);
- //
- // The first one is always safe to use, but slower.
- //
- class flowparams
- {
- protected:
- short x11;
- short x12;
- short x21;
- short x22;
- long trans_x;
- long trans_y;
- };
-
- class flowdots : protected flowparams, public dotcollection,
- public phaser, public flowsettings, public screendots
- {
- public:
-
- flowdots( int numbits, int xpos, int ypos,
- int aantaldots, int lifetime, double how_often = 0.0);
- flowdots( int numbits, screen_position where,
- int aantaldots, int lifetime, double how_often = 0.0);
-
- void set_how_often( const double how_often);
- //
- // Both the 'setsettings' calls change the actual flow to be shown
- // the one which uses 'flowparams' is faster, because it does not
- // have to do the float-fixed conversion (by calling 'changed').
- // This implies that calling 'changed' after calling
- // flowdots::setsettings( const flowparams &theparams)
- // is an error since the floating point flow parameters are not
- // changed by that call.
- //
- void setsettings( const flowsettings &thesettings);
- void setsettings( const flowparams &theparams);
- void changed();
-
- protected:
-
- virtual void compute_addresses();
- void apply_flow();
-
- double framerate;
- double updaterate;
-
- int auto_timing; // flag
- unsigned long time_of_last_apply_flow_call;
-
- void compute_matrices();
-
- static double scale( double orig, double updaterate);
-
- private:
- //
- // we use 'short_long_hack' to split an unsigned long in two
- // signed shorts (the unsigned long being returned by randomizer_step())
- // (could move these to 'dotcollection' and add a member 'uniformize')
- //
- typedef struct two_shorts
- {
- short left;
- short right;
- };
-
- typedef union short_long_hack
- {
- two_shorts shorties;
- unsigned long ulong;
- };
- };
-
- inline void flowdots::set_how_often( const double how_often)
- {
- if( how_often > 0.0)
- {
- auto_timing = false;
- updaterate = how_often;
- } else {
- auto_timing = true;
- }
- time_of_last_apply_flow_call = 0L;
- }
-
- inline void flowdots::changed()
- {
- if( !auto_timing)
- {
- compute_matrices();
- }
- }
-
- inline double flowdots::scale( double orig, double updaterate)
- {
- return( exp( log( orig) / updaterate));
- }
-