/* $Id: wopsprites.cpp,v 1.32 2005/10/16 17:53:06 pohlt Exp $ */ #include "wopsprites.hpp" #include "global.hpp" #include "object.hpp" #include "settingdefs.hpp" #include "wopsettings.hpp" /**********************************************************/ #ifdef SUPPRESS_COLORED_OUTPUT #define BLACK(str) str #else #define BLACK(str) "\033[0;1m" << str << "\033[0m" #endif /**********************************************************/ template WopSprites::WopSprites() : PointerVector< SpriteSet >(NUMBER_OF_OBJECT_IDs) { } template WopSprites::~WopSprites() { reset(); } /**********************************************************/ template int WopSprites::getSequenceLength( const Object& object ) const { return getSequence(object.getID(), object.getSequence())->getSize(); } /**********************************************************/ template int WopSprites::getSequenceLength( const Sint32 id, const Sint32 iseq ) const { return getSequence(id, iseq)->getSize(); } /**********************************************************/ template int WopSprites::getNumSequences( const Object& object ) const { return getSet(object.getID())->getSize(); } /**********************************************************/ template inline const SpriteSet* WopSprites::getSet( const int objectID ) const { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getSet(ID):"; // check range of object ID ASSERT( objectID > INVALID_OBJECT && objectID < NUMBER_OF_OBJECT_IDs, "%s: objectID %d out of valid range [%d,%d]\n", fn, objectID, INVALID_OBJECT+1, NUMBER_OF_OBJECT_IDs-1 ); // check, if there is a sprite set loaded ASSERT( NULL != this->m_Data[objectID], "%s: no sprite set present for object ID %s\n", fn, ObjectIDString[objectID] ); #endif return (const SpriteSet*)this->m_Data[objectID]; } /**********************************************************/ template inline const SpriteSet* WopSprites::getSet( Object& object, const bool create ) { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getSet(object):"; #endif // get pointer to sprite set (in debug mode granted to be != NULL) SpriteSet* set2 = (SpriteSet*)getSet( object.getID() ); // this is a color templated sprite set if( set2->isTemplated() ) { int instance = object.getColorInstance(); // instance not yet set if( instance < 0 ) { #if DBG_LEVEL >= 1 // check, whether the object supports coloring ASSERT( object.getColors(), "%s: SpriteSet for object ID %s is templated, but " "object neither brings an instance index nor has " "a valid pointer to its colors\n", fn, ObjectIDString[object.getID()] ); // check, if the number of object colors and the number // of sprite set layers match ASSERT( set2->getNumLayers() == object.getNumColors(), "%s: number of layers (%d) and number of object " "colors (%d) do not match\n", fn, object.getNumColors(), set2->getNumLayers() ); #endif // find or create new colored instance instance = set2->getColoredInstance( object.getColors(), create ); #if DBG_LEVEL >= 1 if( instance < 0 ) { if( create == false ) { CHECK( false, "%s: could not find colored instance for object " "with ID %d (first color %x), creation explicitely " "permitted -> returning NULL pointer\n", fn, object.getID(), *object.getColors() ); return NULL; } else { // check, whether the instance is valid ASSERT( false, "%s: could not create colored instance for " "object with ID %d (first color %x)\n", fn, object.getID(), *object.getColors() ); } } #endif // register the instance at the object object.setColorInstance( instance ); } // let set point to the colored instance set2 = (SpriteSet*)set2->getColorInstance( instance ); #if DBG_LEVEL >= 1 // check, whether we recieved a valid set pointer ASSERT( set2, "%s: retrieved non valid instance " "(demanded %d)\n", instance ); #endif } return set2; } /**********************************************************/ template inline const SpriteSet* WopSprites::getColorInstance( const int objectID, const int instance ) const { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getColorInstance(id,inst):"; // check, whether the sprite set is templated ASSERT( getSet(objectID)->isTemplated(), "%s: set of ID %s is not templated\n", fn, objectID ); // check, whether the demanded instance exists ASSERT( instance >= 0 && instance < this->m_Data[objectID]->getNumInstances(), "%s: instance %d of set %d does not exist (valid range [0,%d])\n", fn, instance, objectID, this->m_Data[objectID]->getNumInstances()-1 ); // check, whether the pointer is NULL ASSERT( NULL != (*this->m_Data[objectID])[instance], "%s: returns NULL pointer for ID %s and instance %d\n", fn, objectID, instance ); #endif return (const SpriteSet*)(*this->m_Data[objectID])[instance]; } /**********************************************************/ template inline const SpriteSet* WopSprites::getColorInstance( const int objectID, const Uint32* const colors, const bool create ) { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getColorInstance(id,col,..):"; // check, whether the sprite set is templated ASSERT( getSet(objectID)->isTemplated(), "%s: set of ID %s is not templated\n", fn, objectID ); // check, whether the color pointer is valid ASSERT( colors, "%s: color pointer is NULL\n", fn ); // check, the found or createt instance ASSERT( 0 > ((SpriteSet*)getSet(objectID)) ->getColoredInstance(colors, create), "%s: could not %s colored instance for object ID %d, " "first color %x\n", fn, create ? "create" : "find", *colors ); #endif return this->m_Data[objectID]->getColorInstance( ((SpriteSet*)getSet(objectID)) ->getColoredInstance(colors, create) ); } /**********************************************************/ template inline const SpriteSequence* WopSprites::getSequence( const int objectID, const int sequence ) const { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getSequence(id,seq):"; const SpriteSet& set2 = *getSet(objectID); ASSERT( 0 <= sequence && sequence < set2.getSize(), "%s: sequence index %d in object with ID %d is out of valid " "range [0,%d]\n", fn, sequence, objectID, set2.getSize()-1 ); ASSERT( set2[sequence] != NULL, "%s: sequence %d of sprite set for ID %d is NULL\n", fn, sequence, objectID ); return set2[sequence]; #else return (*getSet(objectID))[sequence]; #endif } /**********************************************************/ template inline const T* WopSprites::getSprite( const int objectID, const int sequence, const int frame ) const { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getSprite(id,seq,fra):"; const SpriteSequence& seq = *getSequence( objectID, sequence ); ASSERT( 0 <= frame && frame < seq.getSize(), "%s: frame index %d is not in valid range [0,%d] for " "sequence %d of sprite set for ID %d\n", fn, frame, sequence, objectID ); ASSERT( seq[frame] != NULL, "%s: frame %d of sequence %d of sprite set for ID %d is NULL\n", fn, frame, sequence, objectID ); return seq[frame]; #else return (*getSequence(objectID, sequence))[frame]; #endif } /**********************************************************/ template const T* WopSprites::getSprite( const Object& object, Sint32* nextSequence, const bool create ) { #if DBG_LEVEL >= 1 const char fn[] = "WopSprites::getSprite(obj,..):"; const SpriteSequence& seq = *getSequence( object.getID(), object.getSequence() ); ASSERT( object.getFrame() >= 0 && object.getFrame() < seq.getSize(), "%s: frame index %d is not in valid range [0,%d] for " "sequence %d of sprite set for ID %d\n", fn, object.getFrame(), object.getSequence(), object.getID() ); ASSERT( seq[object.getFrame()] != NULL, "%s: frame %d of sequence %d of sprite set for ID %d is NULL\n", fn, object.getFrame(), object.getSequence(), object.getID() ); #else SpriteSequence& seq = *getSequence( object.getID(), object.getSequence() ); #endif if( nextSequence ) { *nextSequence = object.getSequence() >= seq.getSize()-1 ? 0 : object.getSequence()+1; } return seq[object.getFrame()]; } /**********************************************************/ template void WopSprites::removeColoredInstance( Object& object ) { #if DBG_LEVEL >= 1 if( !CHECK( object.getColorInstance() >= 0, "WopSprites::removeColoredInstance: attempt to " "remove color instance for not registered object " "with ID %d\n", object.getID()) ) { return; } #endif // get the sprite set for the object and ... ( (SpriteSet*)getSet(object.getID()) )-> // ... remove its colored instance inside this sprite set deleteColoredInstance( object.getColorInstance() ); } /**********************************************************/ template void WopSprites::reset() { PointerVector< SpriteSet >::reset(); } /**********************************************************/ template bool WopSprites::load( ProgressLog* const progresslog ) { const WopSettings* const settings = WopSettings::getInstance(); if( !settings ) return false; String path; #ifdef USE_PHYSFS path = SPRITE_CONFIG_PATH; #else path = settings->getData(); path += "/"SPRITE_CONFIG_PATH; #endif return load( path, SPRITE_CONFIG, progresslog ); } /**********************************************************/ template bool WopSprites::load( const char* const BasePath, const char* const ConfigFile, ProgressLog* const progresslog ) { // initialize progress object Progress* progress = NULL; if( progresslog != NULL ) { if( progresslog->getNumLevels() <= 0 ) { progresslog->create( 30, 1 ); } progress = &progresslog->getProgressObject( 0 ); progress->setProgress( 0.0 ); progress->setTitle( "configuration" ); } const char fn[] = "WopSprites::load"; INFO( "WopSprites::load: loading sprites, lean back for a few seconds\n" ); SettingDataBase Settings; bool pickySuccess = true; String Path( BasePath ); SpriteSet *newSet = NULL; const int BasePathLength = Path.getLength() + 1; Path += '/'; Path += ConfigFile; Settings.restrictToSection( "GAME_SPRITES" ); // load settings and check them: // settings must have been read correctly ASSERT( Settings.readSettings(m_SettingDef, Path, true, &pickySuccess) // must be REALLY successful && pickySuccess == true // settings must have passed the final check && Settings.finalCheck(m_SettingDef) // as we expect pairs of strings, their number must be even && 0 == (1 & Settings.getNumParameters(m_SettingDef[0].m_IDString)), // output for ASSERT "could not read correct settings for the object sprites " "from configuration file \"%s\"\n", (char*)Path ); // reset the section, just for proper section management Settings.removeSection(); // since we have passed SettingDataBase::finalCheck and also have // checked the number of strings, these initializations are save Setting *pathpairs = Settings.getSetting(m_SettingDef[0].m_IDString); int nSets = pathpairs->getNumParameters() / 2; // get maximal length of the subdirectory strings, to be // able to lock the path to a save length int maxLength = 0; for( int i = 0; i < nSets; i++ ) { int length = strlen( pathpairs->getString(2*i) ); if( length > maxLength ) maxLength = length; } Path.lockBuffer( BasePathLength + maxLength ); // load all sprite sets and insert them at the index, // that corresponds to their enumeration constant (constants.hpp) for( int i = 0; i < nSets; i++ ) { // cut string to the base path and build path for sprite Path.cut( BasePathLength ); Path += pathpairs->getString( 2*i ); // create a new sprite sets ASSERT( NULL != (newSet = NEW SpriteSet()), "could not create new SpriteSet in %s\n", fn ); // load the new set if( 0 >= newSet->load(Path, pathpairs->getString(2*i+1), progresslog) ) { cerr << PVEC_CALLED_FROM( fn ) << " while loading sprite set\n from " << BLACK("\""<getString(2*i+1)<<"\"") << "\n in " << BLACK("\""<getObjectID() ) { cerr << PVEC_FN_ERR( fn ) << " sprite sequence loaded\n from " << BLACK("\""<getString(2*i+1)<<"\"") << "\n in " << BLACK("\""<getObjectID(), ObjectIDString[j]) ) { if( this->m_Data[j] ) { cerr << PVEC_FN_ERR( fn ) << "sprite set " << BLACK("\""< I take the first one\n"; delete newSet; newSet = NULL; } else { this->set( j, newSet ); INFO( "%s: loaded sprite set \"%s\"\n", fn, ObjectIDString[j] ); } break; } else if( j == NUMBER_OF_OBJECT_IDs-1 ) { cerr << PVEC_FN_ERR( fn ) << BLACK("\""<getObjectID()<<"\"") << " is not a valid ID for a sprite set\n"; delete newSet; return false; } } // sprite set inserted } // check, if all sprites could be loaded DBG( 1 ) { for( int i = FIRST_AVATAR; i < NUMBER_OF_OBJECT_IDs; i++ ) { CHECK( NULL != this->m_Data[i], "no sprite set loaded for ID %s\n", ObjectIDString[i] ); } } return true; } /**********************************************************/ template int WopSprites::draw( Object& object, SDL_Surface *const surface ) { SpriteSet *const set2 = (SpriteSet*)getSet( object, true ); Sint32 iseq = object.getSequence(); if( iseq < 0 ) { object.setSequence( iseq = localRnd.getUint32() % set2->getSize() ); } // draw the object return ((*set2)[iseq])->draw( surface, object.getFrame(), object.getIntPosX(), object.getIntPosY() ); } /**********************************************************/ template int WopSprites::draw( Object& object, const int x, const int y, SDL_Surface *const surface ) { SpriteSet *const set2 = (SpriteSet*)getSet( object, true ); Sint32 iseq = object.getSequence(); if( iseq < 0 ) { object.setSequence( iseq = localRnd.getUint32() % set2->getSize() ); } // draw the object return ((*set2)[iseq])->draw( surface, object.getFrame(), x, y ); } /**********************************************************/