Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / General Programming / Maintaining larger number of (render) states Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
Hesterumpe

February 22, 2005, 01:02 PM

In an engine you have to maintain a large number of settings (should be backbuffer be cleared? How often must the game logic be updated? Etc.)

I would like to do it like Direct3D SetRenderState, that is, have one function with a argument indicating the value to set, and the second argument the value to set. The trouble is, how does one handle/store these states?

I can think of two obvious ways:

1) A large switch, and a member variable for each state. This will be hard to maintain, but gives flexibility in that setting a value can have side-effects (like, settings the window title signals to the window class the title have changed).

2) A (hash) map index with the value to set. This will be easy to maintain, but will lose the possibility of side-effects.

I think 2) is the best, but not having side-effects means a lot of redundant polling each frame of values that doesn't change. Also the lookups in the map could cost some performance.

So, what do you think? Any other/better solutions?

 
Victor Widell

February 22, 2005, 07:31 PM

How about a map, so you can call a member method depending on the string?

 
Hesterumpe

February 23, 2005, 04:31 AM

Its possible i guess... But then I would still have to write a function per state, which could be a lot of functions. Maybe a mix with something like

  1.  
  2. struct State {
  3.   State( unsigned int def_value ):fptr(0), value(def_value) {}
  4.  
  5.   unsigned int value;
  6.   FunctionPointer fptr;
  7. }
  8.  
  9. map<unsigned int, State>
  10.  


Then when a state is set, if fptr != 0 then it can be called, otherwise just set the value. I think I'll look into that. Thanks! :)

 
Victor Widell

February 23, 2005, 09:18 PM

Something like that should work...

Post again whan you have it working!

 
Hesterumpe

February 25, 2005, 02:45 PM

Here's what I've come up with. Pretty simple, but it works well enough for now :) All the Lua stuff can/should ofcourse be removed.

  1.  
  2. #pragma once
  3.  
  4. //! Behavior state manager
  5. /*! @param STATE The type of the state. STATE must implement the '<' (less than) operator.
  6.         @param VALUE the type of the value.
  7.  
  8.         Behavior manages <state, value> pairs. Before a state can be used, it must be
  9.         registered, so that a default value is set. A callback function that is called
  10.         whenever a states value is changed can also be set.
  11. */
  12. template<typename STATE, typename VALUE>
  13. class Behavior
  14. {
  15. public:
  16.         //! State value change callback function
  17.         typedef void(*BehaviorCB)(STATE, VALUE);
  18.  
  19.         Behavior() {}
  20.         ~Behavior() {}
  21.  
  22.         //! Register a new state
  23.         /*! @param state The new state.
  24.                 @param default_value The default value associated with the state.
  25.                 @param change_cb Change callback function. Whenever the value of the state
  26.                         changes, this function is called. Use 0 to indicate that no function
  27.                         should be called.
  28.  
  29.                 A state must be registered before it can be set or queried.
  30.         */
  31.         void regState( const STATE& state, const VALUE& default_value, BehaviorCB change_cb = 0 ) {
  32.                 Value val( default_value, change_cb );
  33.                 StateMap_[state] = val;
  34.         }
  35.  
  36.         //! Set state value
  37.         /*! @param L Originating Lua state. If 0 then assert is called on error, else a
  38.                         Lua error is raised.
  39.                 @param state The state to set.
  40.                 @param value The value to set.
  41.                 @return The old state value.
  42.  
  43.                 Use this value to assign a new value to a state. The state must have been
  44.                 registered before it can be set.
  45.         */
  46.         VALUE set( lua_State* L, const STATE& state, const VALUE& value ) {
  47.                 // Lookup state. All states must be registered previously. This can be changed
  48.                 // to Value& val = StateMap_[state] to allow new values to be registered on use
  49.                 StateMapIter iter = StateMap_.find( state );
  50.                 if( iter == StateMap_.end() ) {
  51.                         // Not the cleanest code, but it gets the job done...
  52.                         if( L )
  53.                                 luaL_error( L, "attempt to 'set' undefined behavior state" );
  54.                         else
  55.                                 assert( iter != StateMap_.end() );
  56.                 }
  57.  
  58.                 Value& val = iter->second;
  59.  
  60.                 // Change value, store old
  61.                 VALUE old = val.value;
  62.                 val.value = value;
  63.  
  64.                 // Invoke callback to indicate that a monitored value has changed
  65.                 if( val.set_cb )
  66.                         val.set_cb( state, value );
  67.  
  68.                 return old;
  69.         }
  70.  
  71.         //! Get state value
  72.         /*! @param L Originating Lua state. If 0 then assert is called on error, else a
  73.                         Lua error is raised.
  74.                 @param state The state to query.
  75.                 @return The state value.
  76.  
  77.                 Use this to get the value of a state. The state must have been registered
  78.                 before its value can be queried.
  79.         */
  80.         const VALUE& get( lua_State* L, const STATE& state ) {
  81.                 StateMapIter iter = StateMap_.find( state );
  82.                 if( iter == StateMap_.end() ) {
  83.                         // Not the cleanest code, but it gets the job done...
  84.                         if( L ) {
  85.                                 luaL_error( L, "attempt to 'get' undefined behavior state" );
  86.                         } else
  87.                                 assert( iter != StateMap_.end() );
  88.                 }
  89.  
  90.                 return iter->second.value;
  91.         }
  92. private:
  93.         struct Value {
  94.                 Value( VALUE def_value = 0, BehaviorCB change_callback = 0 )
  95.                         :set_cb(change_callback), value(def_value) {}
  96.  
  97.                 VALUE           value;
  98.                 BehaviorCB      set_cb;
  99.         };
  100.  
  101.         typedef std::map<STATE, Value>  StateMap;
  102.         typedef StateMap::iterator              StateMapIter;
  103.  
  104.         StateMap StateMap_;
  105. };
  106.  


Should be self-explaining. Anyway, share and enjoy :)


PS. Dang FlipCode messes up my tabs. It looks a bit better with 4-space-tabs.

 
This thread contains 5 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.