/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2004-2007 by The Allacrost Project // All Rights Reserved // // This code is licensed under the GNU GPL version 2. It is free software // and you may modify it and/or redistribute it under the terms of this license. // See http://www.gnu.org/copyleft/gpl.html for details. /////////////////////////////////////////////////////////////////////////////// /** **************************************************************************** *** \file tex_mgmt.h *** \author Raj Sharma, roos@allacrost.org *** \brief Header file for texture management code *** *** We use texture management so that at runtime, we can load many small images *** (e.g. tiles) and stick them together into larger textures called "texture *** sheets". This improves performance, because then we don't have to constantly *** switch textures while rendering. *** *** This file contains several classes: *** *** - TexSheet: represents a large OpenGL texture which is shared among *** multiple texture objects (images). Abstract to allow for derivative classes *** to define how they manage their texture objects. *** *** - FixedTexSheet: a texture sheet for fixed-size textures, i.e. 32x32 *** This class can do all of its operations in O(1) time because it knows in *** advance that all textures are the same size. *** *** - FixedTexNode: represents a texture node entry for the *** FixedTexSheet class. *** *** - VariableTexSheet: a texture sheet for variable-size textures. *** This sheet allows textures of any size to be inserted, but has slower *** performance than the FixedTexSheet. *** *** - VariableTexNode: represents a texture node entry for the *** VariableTexSheet class. *** ***************************************************************************/ #ifndef __TEXTURE_HEADER__ #define __TEXTURE_HEADER__ #include "defs.h" #include "utils.h" // OpenGL includes #ifdef __APPLE__ #include #include #else #include #include #endif namespace hoa_video { namespace private_video { //! \brief Used to indicate an invalid texture ID const GLuint INVALID_TEXTURE_ID = 0xFFFFFFFF; //! \brief Represents the different image sizes that a texture sheet can hold enum TexSheetType { VIDEO_TEXSHEET_INVALID = -1, VIDEO_TEXSHEET_32x32 = 0, VIDEO_TEXSHEET_32x64 = 1, VIDEO_TEXSHEET_64x64 = 2, VIDEO_TEXSHEET_ANY = 3, VIDEO_TEXSHEET_TOTAL = 4 }; /** **************************************************************************** *** \brief An OpenGL texture which can store multiple smaller textures in itself *** *** The purpose of texture sheets is to save computation resources on texture *** switches, so that an increased performance can be achieved. TexSheet is *** an abstract class because the inner textures are stored via different means *** (fixed size versus variable size textures), so the specific implementation *** of the inner texture management is defined in a derived class. *** *** \note This is called TexSheet instead of Texture, so that it is clear that *** this doesn't represent a texture that you would draw on the screen, but *** is rather a container for smaller textures. *** ***************************************************************************/ class TexSheet { public: /** \brief Constructs a new texture sheet *** \param sheet_width The width of the sheet *** \param sheet_height The height of the sheet *** \param sheet_id The OpenGL texture ID value for the sheet *** \param sheet_type The type of texture data that the texture sheet should hold *** \param sheet_static Whether the sheet should be labeled static or not **/ TexSheet(int32 sheet_width, int32 sheet_height, GLuint sheet_id, TexSheetType sheet_type, bool sheet_static); virtual ~TexSheet(); // ---------- Public methods /** \brief Adds a new texture to the tex sheet *** \param img A pointer to the new image to add *** \param data The image's pixel data to place in the sheet *** \return Success/failure *** *** \note The BaseTexture object which is passed into this function will have its *** properties modified once it is successfully added to the texture sheet. **/ virtual bool AddTexture(BaseTexture* img, ImageMemory& data) = 0; /** \brief Inserts a new texture into the tex sheet *** \param img A pointer to the new image to insert *** \return Success/failure *** *** The difference between this function and the AddTexture function is that the *** texture sheet image data is not modified by this function (i.e., pixel data *** is not copied to the texture sheet like it is with AddImage). All it does *** is allocate space for the texture pointer to use. Therefore, a call to this *** function is usually followed by a call to a function which will modify the *** image data at the inserted textures location (CopyRect, CopyScreenRect). **/ virtual bool InsertTexture(BaseTexture* img) = 0; /** \brief Removes an image texture from the texture sheet's memory manager *** \param img The image to remove **/ virtual void RemoveTexture(BaseTexture* img) = 0; /** \brief Marks the texture as free *** \param img The image to mark as free *** \note Marking an image as free does not delete it. The image may be later *** restored from the free state so that it does not have to be re-fetched *** from the hard disk. **/ virtual void FreeTexture(BaseTexture* img) = 0; /** \brief Restores a texture which was previously freed *** \param img The image to mark as used **/ virtual void RestoreTexture(BaseTexture* img) = 0; //! \brief Returns the number of textures that are contained on this texture sheet virtual uint32 GetNumberTextures() = 0; /** \brief Unloads all texture memory used by OpenGL for this sheet *** \return Success/failure **/ bool Unload(); /** \brief Reloads all the images into the sheet and reallocates OpenGL memory *** \return Success/failure **/ bool Reload(); /** \brief Copies pixel data of an image over to a sub-rectangle in the texture sheet *** \param x X coordinate of the texture sheet where to copy the pixel data to *** \param y Y coordinate of the texture sheet where to copy the pixel data to *** \param data The pixel data to copy *** \return Success/failure *** *** \note Take extreme care when using this function, as it does not bother to check *** whether it is overwriting occupied space within the texture sheet. This can lead *** to image corruption. It also does not make any attempt to indicate that the copied *** area is now occupied; that must be done externally by the caller (through the use *** of creating a new BaseTexture class). **/ bool CopyRect(int32 x, int32 y, private_video::ImageMemory& data); /** \brief Copies a portion of the current contents of the screen into the texture sheet *** \param x X coordinate of rectangle to copy screen to *** \param y Y coordinate of rectangle to copy screen to *** \param screen_rect The portion of the screen to copy *** \return Success/failure *** *** \note Take extreme care when using this function, as it does not bother to check *** whether it is overwriting occupied space within the texture sheet. This can lead *** to image corruption. It also does not make any attempt to indicate that the copied *** area is now occupied; that must be done externally by the caller (through the use *** of creating a new BaseTexture class). **/ bool CopyScreenRect(int32 x, int32 y, const ScreenRect &screen_rect); /** \brief Enables (GL_LINEAR) or disables (GL_NEAREST) smoothing for this texture sheet *** \param flag True enables smoothing while false disables it. Default value is true. **/ void Smooth(bool flag = true); /** \brief Draws the entire texture sheet to the screen *** This is used for debugging, as it draws all images contained within the texture to the screen. *** It ignores any blending or lighting properties that are enabled in the VideoManager **/ void DEBUG_Draw() const; // ---------- Public members //! \brief The width and height of the texsheet int32 width, height; //! \brief The interger that OpenGL uses to refer to this texture GLuint tex_id; //! \brief The type (dimensions) of images that this texture sheet holds TexSheetType type; //! \brief If true, images in this sheet that are unlikely to change bool is_static; //! \brief True if this texture sheet is currently set to GL_LINEAR bool smoothed; //! \brief Flag indicating if texture sheet is loaded or not bool loaded; protected: //! \brief The width and height of the sheet in number of texture blocks int32 _block_width, _block_height; }; // class TexSheet /** **************************************************************************** *** \brief Represents a node in a linked list of texture blocks *** *** This class is used by the FixedTexSheet class to manage its allocated *** texture blocks. *** ***************************************************************************/ class FixedTexNode { public: //! \brief The image that belongs to the block BaseTexture* image; //! \brief The next node in the list FixedTexNode* next; //! \brief The block index int32 block_index; }; // class FixedTexNode /** **************************************************************************** *** \brief Used to manage texture sheets which are designated for fixed image sizes. *** *** An example where this class would be used would be a 512x512 pixel sheet that *** only holds 32x32 pixel tiles. The texture sheet's size must be divisible by *** the size of the images that it holds. For example, you can't create a 256x256 *** sheet which holds tiles which are 17x93. *** The open list keeps track of which blocks of memory are open. Note that *** we track blocks with both an array and a list. Although it takes up *** more memory, this makes all operations dealing with the blocklist *** O(1) so that performance is awesome. Memory isn't too bad either, *** since the block list is fairly small. *** The open list keeps track of which blocks of memory are open. The tail *** pointer is also kept so that we can add newly freed blocks to the end *** of the list. That way, essentially blocks that are freed are given a *** little bit of time from the time they're freed to the time they're *** removed, in case they are loaded again in the near future. *** ***************************************************************************/ class FixedTexSheet : public TexSheet { public: /** \brief Constructs a new memory manager for a texture sheet *** \param tex_sheet The texture sheet which this object will manage *** \param img_width The width of the images which will be stored in this sheet *** \param img_height The height of the images which will be stored in this sheet **/ /** \brief Constructs a new texture sheet *** \param sheet_width The width of the sheet *** \param sheet_height The height of the sheet *** \param sheet_id The OpenGL texture ID value for the sheet *** \param sheet_type The type of texture data that the texture sheet should hold *** \param sheet_static Whether the sheet should be labeled static or not *** \param block_width The width of the texture blocks which will be stored in this sheet *** \param block_height The height of the texture blocks which will be stored in this sheet *** *** \note The block_width and block_height parameters must evenly divide into the sheet_width and *** sheet_height parameters. Otherwise the constructor will throw an exception **/ FixedTexSheet(int32 sheet_width, int32 sheet_height, GLuint sheet_id, TexSheetType sheet_type, bool sheet_static, int32 img_width, int32 img_height); ~FixedTexSheet(); //! \name Methods inherited from TexSheet //@{ bool AddTexture(BaseTexture* img, ImageMemory& data); bool InsertTexture(BaseTexture* img); void RemoveTexture(BaseTexture* img); void FreeTexture(BaseTexture* img); void RestoreTexture(BaseTexture* img); uint32 GetNumberTextures(); //@} private: //! \brief The width and height of each texture block, in number of pixels int32 _texture_width, _texture_height; //! \brief Head of the list of open texture blocks FixedTexNode* _open_list_head; //! \brief Tail of the list of open memory blocks FixedTexNode* _open_list_tail; /** \brief A pointer to an array of blocks which is indexed like a 2D array *** For example, blocks[x + y * width]->image would tell us which image is *** currently allocated at spot (x,y). **/ FixedTexNode* _blocks; /** \brief Grabs the block index based off of the image *** \param img The image to look for *** \return The block index for that image **/ int32 _CalculateBlockIndex(BaseTexture* img); /** \brief Adds a node onto the tail of the open list *** \param node A pointer to the node to add to the open list **/ void _AddOpenNode(FixedTexNode* node); /** \brief Removes a node from the head of the open list to be used *** \return A pointer to the node to use, or NULL if no nodes were available **/ FixedTexNode* _RemoveOpenNode(); }; // class FixedTexSheet : public TexSheet /** **************************************************************************** *** \brief Keeps track of which images are used/freed in the variable texture mem manager *** ***************************************************************************/ class VariableTexNode { public: VariableTexNode() : image(NULL), free_image(true) {} //! \brief A pointer to the image BaseTexture* image; //! \brief Set to true if the image is freed bool free_image; }; // class VariableTexNode /** **************************************************************************** *** \brief Used to manage texture sheets of variable image sizes *** *** This class divides a texture sheet up into 16x16 pixel blocks, and keeps *** track of which images have allocated which blocks. This is done to reduce *** the time complexity for doing texture insertion and removal operations, but *** the downside is that it may leave some space in the texture sheet occupied *** but unused for images that are not divisible by 16 in width or height. *** ***************************************************************************/ class VariableTexSheet : public TexSheet { public: /** \brief Constructs a new texture sheet *** \param sheet_width The width of the sheet *** \param sheet_height The height of the sheet *** \param sheet_id The OpenGL texture ID value for the sheet *** \param sheet_type The type of texture data that the texture sheet should hold *** \param sheet_static Whether the sheet should be labeled static or not **/ VariableTexSheet(int32 sheet_width, int32 sheet_height, GLuint sheet_id, TexSheetType sheet_type, bool sheet_static); ~VariableTexSheet(); //! \name Methods inherited from TexSheet //@{ bool AddTexture(BaseTexture* img, ImageMemory& data); bool InsertTexture(BaseTexture* img); void RemoveTexture(BaseTexture* img); void FreeTexture(BaseTexture* img) { _SetBlockProperties(img, img, true); } void RestoreTexture(BaseTexture* img) { _SetBlockProperties(img, img, false); } uint32 GetNumberTextures() { return _textures.size(); } //@} private: /** \brief The list of 16x16 pixel blocks in the sheet. *** The size of this structure is: (width / 16) * (height / 16) **/ VariableTexNode* _blocks; /** \brief A set containing each texture that has been inserted into this class *** This container is used to be able to quickly determine if a texture is loaded by an object of this class **/ std::set _textures; /** \brief Updates the properties of all of the blocks associated with a given texture *** \param tex The texture to update *** \param new_tex The texture pointer to set the block to *** \param new_image The boolean value to set the free status flag to **/ void _SetBlockProperties(BaseTexture* tex, BaseTexture* new_tex, bool free); }; // class VariableTexSheet : public TexSheet } // namespace private_video } // namespace hoa_video #endif // __TEXTURE_HEADER__