glx@9626: /* $Id$ */ glx@9626: glx@9626: /** @file blitter.hpp */ glx@9626: glx@9626: #ifndef BLITTER_HPP glx@9626: #define BLITTER_HPP glx@9626: glx@9626: #include "../spriteloader/spriteloader.hpp" glx@9626: #include "../spritecache.h" glx@9626: #include glx@9626: #include glx@9626: glx@9626: enum BlitterMode { glx@9626: BM_NORMAL, glx@9626: BM_COLOUR_REMAP, glx@9626: BM_TRANSPARENT, glx@9626: }; glx@9626: glx@9626: /** glx@9626: * How all blitters should look like. Extend this class to make your own. glx@9626: */ glx@9626: class Blitter { glx@9626: public: glx@9626: struct BlitterParams { glx@9626: const void *sprite; ///< Pointer to the sprite how ever the encoder stored it glx@9626: const byte *remap; ///< XXX -- Temporary storage for remap array glx@9626: glx@9626: int skip_left, skip_top; ///< How much pixels of the source to skip on the left and top (based on zoom of dst) glx@9626: int width, height; ///< The width and height in pixels that needs to be drawn to dst glx@9626: int sprite_width; ///< Real width of the sprite glx@9626: int sprite_height; ///< Real height of the sprite glx@9626: int left, top; ///< The offset in the 'dst' in pixels to start drawing glx@9626: glx@9626: void *dst; ///< Destination buffer glx@9626: int pitch; ///< The pitch of the destination buffer glx@9626: }; glx@9626: glx@9626: typedef void *AllocatorProc(size_t size); glx@9626: glx@9626: /** glx@9626: * Get the screen depth this blitter works for. glx@9626: * This is either: 8, 16, 24 or 32. glx@9626: */ glx@9626: virtual uint8 GetScreenDepth() = 0; glx@9626: glx@9626: /** glx@9626: * Draw an image to the screen, given an amount of params defined above. glx@9626: */ glx@9626: virtual void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) = 0; glx@9626: glx@9626: /** glx@9626: * Convert a sprite from the loader to our own format. glx@9626: */ glx@9626: virtual Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) = 0; glx@9626: glx@9626: virtual ~Blitter() { } glx@9626: }; glx@9626: glx@9626: /** glx@9626: * The base factory, keeping track of all blitters. glx@9626: */ glx@9626: class BlitterFactoryBase { glx@9626: private: glx@9626: char *name; glx@9626: typedef std::map Blitters; glx@9626: glx@9626: static Blitters &GetBlitters() glx@9626: { glx@9626: static Blitters &s_blitters = *new Blitters(); glx@9626: return s_blitters; glx@9626: } glx@9626: glx@9626: static Blitter **GetActiveBlitter() glx@9626: { glx@9626: static Blitter *s_blitter = NULL; glx@9626: return &s_blitter; glx@9626: } glx@9626: glx@9626: protected: glx@9626: /** glx@9626: * Register a blitter internally, based on his name. glx@9626: * @param name the name of the blitter. glx@9626: * @note an assert() will be trigger if 2 blitters with the same name try to register. glx@9626: */ glx@9626: void RegisterBlitter(const char *name) glx@9626: { glx@9626: /* Don't register nameless Blitters */ glx@9626: if (name == NULL) return; glx@9626: glx@9626: this->name = strdup(name); glx@9626: std::pair P = GetBlitters().insert(Blitters::value_type(name, this)); glx@9626: assert(P.second); glx@9626: } glx@9626: glx@9626: public: glx@9626: BlitterFactoryBase() : glx@9626: name(NULL) glx@9626: {} glx@9626: glx@9626: virtual ~BlitterFactoryBase() { if (this->name != NULL) GetBlitters().erase(this->name); free(this->name); } glx@9626: glx@9626: /** glx@9626: * Find the requested blitter and return his class. glx@9626: * @param name the blitter to select. glx@9626: * @post Sets the blitter so GetCurrentBlitter() returns it too. glx@9626: */ glx@9626: static Blitter *SelectBlitter(const char *name) glx@9626: { glx@9626: if (GetBlitters().size() == 0) return NULL; glx@9626: glx@9626: Blitters::iterator it = GetBlitters().begin(); glx@9626: for (; it != GetBlitters().end(); it++) { glx@9626: BlitterFactoryBase *b = (*it).second; glx@9626: if (strcasecmp(name, b->name) == 0) { glx@9626: Blitter *newb = b->CreateInstance(); glx@9626: *GetActiveBlitter() = newb; glx@9626: return newb; glx@9626: } glx@9626: } glx@9626: return NULL; glx@9626: } glx@9626: glx@9626: /** glx@9626: * Get the current active blitter (always set by calling SelectBlitter). glx@9626: */ glx@9626: static Blitter *GetCurrentBlitter() glx@9626: { glx@9626: return *GetActiveBlitter(); glx@9626: } glx@9626: glx@9626: glx@9626: static char *GetBlittersInfo(char *p, const char *last) glx@9626: { glx@9626: p += snprintf(p, last - p, "List of blitters:\n"); glx@9626: Blitters::iterator it = GetBlitters().begin(); glx@9626: for (; it != GetBlitters().end(); it++) { glx@9626: BlitterFactoryBase *b = (*it).second; glx@9626: p += snprintf(p, last - p, "%18s: %s\n", b->name, b->GetDescription()); glx@9626: } glx@9626: p += snprintf(p, last - p, "\n"); glx@9626: glx@9626: return p; glx@9626: } glx@9626: glx@9626: /** glx@9626: * Get a nice description of the blitter-class. glx@9626: */ glx@9626: virtual const char *GetDescription() = 0; glx@9626: glx@9626: /** glx@9626: * Create an instance of this Blitter-class. glx@9626: */ glx@9626: virtual Blitter *CreateInstance() = 0; glx@9626: }; glx@9626: glx@9626: /** glx@9626: * A template factory, so ->GetName() works correctly. This because else some compiler will complain. glx@9626: */ glx@9626: template glx@9626: class BlitterFactory: public BlitterFactoryBase { glx@9626: public: glx@9626: BlitterFactory() { this->RegisterBlitter(((T *)this)->GetName()); } glx@9626: glx@9626: /** glx@9626: * Get the long, human readable, name for the Blitter-class. glx@9626: */ glx@9626: const char *GetName(); glx@9626: }; glx@9626: glx@9626: #endif /* BLITTER_HPP */