/* $Id: spriteset.hpp,v 1.16.4.1 2006/01/20 11:33:53 chfreund Exp $ */ #ifndef SPRITE_SET_CLASS_DEFINED #define SPRITE_SET_CLASS_DEFINED /********************************************************** * needed source files: string.cpp settings.cpp * sprite.cpp spritesequence.cpp * spriteset.cpp **********************************************************/ #include "spritesequence.hpp" #include "progresslog.hpp" /**********************************************************/ #define TPLCOL_RGB(r,g,b) (((((Uint32)r)&0xff)<<16) | \ ((((Uint32)g)&0xff)<< 8) | \ ( ((Uint32)b)&0xff) ) #define TPLCOL_RED(c) ((c >> 16) & 0xff) #define TPLCOL_GREEN(c) ((c >> 8) & 0xff) #define TPLCOL_BLUE(c) ((c ) & 0xff) #define TPLCOL_NOT_USED(c) (c & (0x01 << 24)) #define TPLCOL_AS_IS(c) (c & (0x01 << 25)) #define TPLCOL_DONT_USE TPLCOL_NOT_USED(0xffffffff) #define TPLCOL_DONT_COL TPLCOL_AS_IS(0xffffffff) /**********************************************************/ /*! This class represents a vector of various sprite sequences, i.e. * a vector with entries of type class SpriteSequence. All functions * concerning graphic is already contained in class Sprite. SpriteSet * offers a comfortable way to load various sprite sequences as defined * in a configuration file with special format. This loading mechanism * is supported by just one public function SpriteSet:load. *
* Color Templates
* A sprite set can be loaded and treated as a template for different * colors. Let's assume you load the sprite sets for the avatar in a * game. If the game has more than one player you might want to use * one sprite set for all players, but colored with different colors. * The class Sprite supports coloring of all grayscale pixels in a * sprite (see Sprite::colorGrayPixels). Thus we could create a * colored instance from each sprite in the sprite set, which means * a colore instance from the whole sprite set. To enable this coloring * you have to specify the flag "templated = true".
* If the set is templated a vector of sprite sets will be created in * the protected section of the class. Whenever a new colored instance * is created, it will be placed in this vector. If a colored instance * is demanded (see SpriteSet::getColoredInstance), that is already * present, no new one will be created. Each of these instances must * remember its colors. So the routines setColorID and compareColorID * should be used internally only.
* There is also the possibility to create a colored instance from more * than one layer, colored with different colors. Let's think of an * example: You want to have striped worms as avatars in your game. * Create images for the worms, create images showing their stripes, * load them templated. Then you could create worms in their player * color, wearing stripes in their team color. To specify the number * of layers in a sprite set, set the setting "nlayers". If nlayers * == n, the n subsequent sequences in the sprite set are assumed to * build the n layers for one sequence, respectively. The tolerance * value for coloring (see Sprite::colorGrayPixels) can be set by * "graytol".
* If the sprite is composed out of several layers you may want the * resulting sprite to be smoothed. This can be achieved by setting * "smooth = ". The smoothing works as simple weighted * averaging on a five point stencil. The four boundary pixels * always have weight 1, the weight of the center pixel is specified * as parameter of setting "smooth". The colors RGB are calculated * separately. The pixels are changed in lexicographic order, and * the new values are written immediately. Therefore this is a * Gauss-Seidel like iteration. This smoothing works in templates * sets only. The alpha channel or the keycolor map is not changed. * *
* SYNTAX of the configuration file *
* The configuration file consists of two main parts. The map part, * and the sequence part. All settings in the configuration file must * be assigned expicitly by a "=". Different setting strings must * be separated by a comma. Every character following after a "#" in * a line is ignored as comment. *
* * The map part specifies an arbitrary number of sequences, just by * giving each of them a name. These names are used only temporarily * inside this configuration file, but must be unique inside the * configuration file; they are set by setting the variable "sequences". *
* e.g.: * \code * sequences = walk_left, walk_right, * jump_left, jump_right * \endcode *
* * There might also be a list of subdirectories, containing further * configuration files of the same type, defining further sprite sets. * These subdirectories are specified by setting the variable "subdirs". * The "subdirs" setting only specifies the path, where the additional * configuration file can be found. This path is interpreted relatively * to the one, where this configuration file can be found. *
* e.g.: * \code * subdirs = dig, fly, crawl * \endcode *
* * Similar to the function "SpriteSet::load" we also need the name of * the additional configuration file. These filenames are specified by * setting the variable "subconf". The names of the configuration files * in the subdirectories must have the same ordering as the sub- * directories (setting "subdirs") they are contained in. *
* e.g.: * \code * subconf = dig.conf fly.conf crawl.conf * \endcode *
* * Optional: You can specify an ID string (here called object ID) for * a sprite set. This ID must be unique for the whole sprite set. The * loading routine will print out an error, if you specify a different * ID string in one of the subdirectories (see keyword subdir). If you * have specified the ID string in a directory, this ID is valid for * all subdirectories. You can only specifiy the same string again in * the sets loaded from subdirectories using "subdirs". *
* e.g.: * \code * objectID = AVATAR * \endcode *
* * Optional: Definition as color template (see above) using "templated", * "nlayers" (mandatory for "templated"), "graytol" (optional). *
* e.g.: * \code * templated = yes * nlayers = 2 * graytol = 10 * \endcode *
* * For the definition of subdirectories and their configuration files * there also exist some modified modes. If they are defined as described * below, then the number of subdirectory paths and subdirectory con- * figuration files must be identical. You can also specify some * subdirectories, but only one name for a configuration file. In * this case this file name is used for each of the subdirectories. * Vice versa it is also possible to define one subdirectory and * several configuration files. Then it is assumed, that all of these * configuration files are contained in the one subdirectory. *
* As optional setting for a sprite set a object ID string can be * defined by setting the variable "objectID". This ID must be valid * for the whole sprite set. That means that sprite sets included from * subdirectories are only allowed to set an identical object ID or * none at all. *
* This definition part of the "map" of the sprite set must be con- * tained inside a configuration section with name "SET_MAP". That means * that it is introduced by the line ">>section_enter<< SET_MAP" and * ended by the line ">>section_leave<< SET_MAP". It is important that * there is no space in front of these directives. *
* The sequence part must be embedded in a section named like one of * the strings, assigned to the setting "sequences" in the map section * "SET_MAP". Inside this section the configuration of a sprite sequence * must be placed. For a description of the configuration of a sprite * sequence see "spritesequence.hpp". * *

* example for a set configuration file:
* (the indentation is for your eyes only, but not necessary) *
* \code * >>section_enter<< SET_MAP * templated = yes * nlayers = 1 * graytol = 10 * smooth = 6 * sequences = walk_left, walk_right, \ ## walking * jump_left, jump_right ## jumping * subdirs = dig, special/fly * subconf = set.conf * >>end<< # not necessary, but accelerates the reading of the * # configuration file, since it causes an immediate * # termination of reading and this is no problem, because * # there is no second section "SET_MAP" * >>section_leave<< SET_MAP * * >>section_enter<< walk_left * frames = walk_left%d.jpg * indices = 0, 5 * hotspot = 5, 11 * >>end<< * >>section_leave<< walk_left * * >>section_enter<< walk_right * frames = walk_right%d.jpg * indices = 0, 5 * hotspot = 5, 11 * >>end<< * >>section_leave<< walk_right * * >>section_enter<< jump_left * frames = jump_left%02d.jpg * indices = 0, 12 * colorkey = 0, 255, 0 * >>end<< * >>section_leave<< jump_left * * >>section_enter<< jump_right * frames = jump_right%02d.jpg * indices = 0, 12 * >>end<< * >>section_leave<< jump_right * \endcode */ template class SpriteSet : public PointerVector< SpriteSequence >, public SpriteSetSettingDefs { public: SpriteSet(); ~SpriteSet(); //! access the object ID const String& getObjectID() const { return m_ObjectID; } //! returns true, if set is templated bool isTemplated() const { return NULL != m_Instances; } //! returns number of present colored instances int getNumInstances() const { return m_Instances ? m_Instances->getSize() : 0; } //! returns the number of layers int getNumLayers() const { return m_nLayers; } //! returns a pointer to the colored instance [i] const SpriteSet* getColorInstance( const int i ) { return (const SpriteSet*)(*m_Instances)[i]; } //! sets the color ID (only used, if this SpriteSet is an instance) void setColorID( const Uint32 *const colors, const int ncolors ); //! compare the color ID (only used, if this SpriteSet is an instance) bool compareColorID( const Uint32 *const colors ) const; //! loading set as defined in configuration file /*! Loads the spriteset as specified in the configuration file * with the full path "path/configfile". The separate passing * of the path, where the configuration file can be found, and * the name of the configuration file is crucial, since all * paths given in this configuration file a interpreted * relatively to the passed "path". * \param path full path where the configuration file * can be found * \param name of the configuration file * \return number of loaded sprite sequences */ int load( const char* const path, const char* const configfile, ProgressLog* const progresslog = NULL ); // resets the class to the state after construction void reset(); //! returns the index of an instance with specified color /*! If this sprite set is a color template (see documentation * of this class), this function supports the creation of the * colored instances and the access to them. This function * can only be called successfully, if the sprite set has been * created as a color template (e.g. check SpriteSet::isTemplated()). * The first parameter is an Uint32 pointer, that must point * to an array, containing the colors needed for an * instantiation. That means that the size of this array must * be equal to the number of layers (this can be retrieved * from SpriteSet::getNumLayers()). The colors must have the * format, that is defined by the macros TPLCOL_* (TemPLate * COLors) in spriteset.hpp (explanation below). The colors * will be applied in their ordering in the array to the * corresponding layer (colors[i] is used for sequence[(n * * #layers) + i]).
* The function will inspect the already present instances * and return the index of the instance, thats colors match * coincide with all passed colors. If no matching instance can * be found, the function tries to create a new instance, but * only, if the flag "build" is set to true. *

* color format:
* RGB colors, bits[0-7] = blue, bits[8-15] = green, * bits[16-23] = red, bit[24] = layer is not used, * bit[26] = use layer as is (do not color) *

* color macros: * - TPLCOL_RGB(red,green,blue) : * creates a color Uint32 from the color components red, * green, blue * - TPLCOL_RED(color) : * extracts the red color component * - TPLCOL_GREEN(color) : * extracts the green color component * - TPLCOL_BLUE(color) : * extracts the blue color component * - TPLCOL_NOT_USED(color) : * extracts bit[25]. If this bit is set, the layer belonging * to this color is not used. To set this bit in a color C, * write C |= TPLCOL_DONT_USE. * - TPLCOL_AS_IS(color) : * extracts bit[26]. If this bit is set, the layer belonging * to this color is used, but not colored. To set this bit * in a color C, write C |= TPLCOL_DONT_COL. * - TPLCOL_DONT_USE : * simply the constant, in which only the bit for omitted * use is set * - TPLCOL_DONT_COL : * simply the constant, in which only the bit for usage * without coloring is set */ int getColoredInstance( const Uint32 *const colors, const bool build = true, const real smoothingweight = -1.0 ); //! deletes the colored instance at index "index" void deleteColoredInstance( const int index ); protected: //! reads the basic settings of the sprite set bool readMapSettings( const char* const configfile, SettingDataBase& settings ); //! some special checks of settings and images, if the set is templated bool checkTemplate() const; const char* SettingID( const int i ) const; // get string of sequence [i] void getSequence( SettingDataBase& settings, const int i, String& string ) const; // void getSubdir( SettingDataBase& settings, const int i, String& string ) const; // void getSubdirConf( SettingDataBase& settings, const int i, String& string ) const; String m_ObjectID; //! object ID, if defined // data for templated sprite sequences PointerVector< SpriteSet > *m_Instances; //! eventual template Uint32 *m_Colors; //! colors, IF this is a colored instance int m_nColors, //! number of colors m_nLayers, //! number of layers, if the set is templated m_grayTolerance; real m_SmoothCenterWeight; }; /**********************************************************/ #endif // SPRITE_SET_CLASS_DEFINED