//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #ifndef _GBITMAP_H_ #define _GBITMAP_H_ #ifndef __RESOURCE_H__ #include "core/resource.h" #endif #ifndef _SWIZZLE_H_ #include "core/util/swizzle.h" #endif #ifndef _TVECTOR_H_ #include "core/util/tVector.h" #endif #ifndef _GFXENUMS_H_ #include "gfx/gfxEnums.h" // For the format #endif #ifndef _PROFILER_H_ #include "platform/profiler.h" #endif //-------------------------------------- Forward decls. class Stream; class RectI; class Point2I; class ColorI; class LinearColorF; //------------------------------------------------------------------------------ //-------------------------------------- GBitmap class GBitmap { public: enum Constants { /// The maximum mipmap levels we support. The current /// value lets us support up to 4096 x 4096 images. c_maxMipLevels = 13 }; enum TextureOp { Add, Subtract }; struct Registration { /// The read function prototype. typedef bool(*ReadFunc)(Stream &stream, GBitmap *bitmap); /// The write function prototype. Compression levels are image-specific - see their registration declaration for details. typedef bool(*WriteFunc)(GBitmap *bitmap, Stream &stream, U32 compressionLevel); /// Used to sort the registrations so that /// lookups occur in a fixed order. U32 priority; Vector extensions; ///< the list of file extensions for this bitmap type [these should be lower case] ReadFunc readFunc; ///< the read function to call for this bitmap type WriteFunc writeFunc; ///< the write function to call for this bitmap type U32 defaultCompression; ///< the default compression level [levels are image-specific - see their registration declaration for details] Registration() { readFunc = NULL; writeFunc = NULL; defaultCompression = 0; priority = 0; VECTOR_SET_ASSOCIATION( extensions ); } }; /// Load the given bitmap file. It will try known file /// extensions if one is not specified. If all else fails /// it will look up the folder hierarchy for a match. /// /// Important: Don't do something like this... /// /// @code /// GBitmap* bitmap; // WRONG TYPE! /// bitmap = GBitmap::load( filename ); /// @endcode /// /// Resources are reference-counted and the smart pointer conversion will /// release the bitmap and thus render the resulting bitmap pointer invalid! /// The right way is like this: /// /// @code /// Resource bitmap; // Correct! /// bitmap = GBitmap::load( filename ); /// @endcode /// static Resource load(const Torque::Path &path); protected: static Resource _load(const Torque::Path &path); static Resource _search(const Torque::Path &path); public: GBitmap(); GBitmap(const GBitmap&); GBitmap(const U32 in_width, const U32 in_height, const bool in_extrudeMipLevels = false, const GFXFormat in_format = GFXFormatR8G8B8 ); // This builds a GBitmap with the R8G8B8A8 format using the passed in // data (assumes that there is width * height * 4 U8's in data) GBitmap(const U32 in_width, const U32 in_height, const U8* data ); virtual ~GBitmap(); static void sRegisterFormat( const Registration ® ); static const Registration* sFindRegInfo( const String &extension ); /// Find the first file matching the registered extensions /// skipping the original. static bool sFindFile( const Torque::Path &path, Torque::Path *outPath ); /// Given a path to a file, try all known extensions. If the file exists on disk, fill in path /// with the correct extension and return true. Otherwise, return false. static bool sFindFiles( const Torque::Path &path, Vector *outFoundPaths ); /// Returns a space separated string of all registered extensions. static String sGetExtensionList(); void allocateBitmap(const U32 in_width, const U32 in_height, const bool in_extrudeMipLevels = false, const GFXFormat in_format = GFXFormatR8G8B8 ); void allocateBitmapWithMips(const U32 in_width, const U32 in_height, const U32 in_numMips, const GFXFormat in_format = GFXFormatR8G8B8); void extrudeMipLevels(bool clearBorders = false); void chopTopMips(U32 mipsToChop); void extrudeMipLevelsDetail(); U32 getNumMipLevels() const { return mNumMipLevels; } GBitmap *createPaddedBitmap() const; GBitmap *createPow2Bitmap() const; /// Copies a color channel by index into the first channel /// of the output bitmap. The output bitmap must be the same /// dimensions as the source. void copyChannel( U32 index, GBitmap *outBitmap ) const; void copyRect(const GBitmap *in, const RectI &srcRect, const Point2I &dstPoint, const U32 srcMipLevel = 0, const U32 dstMipLevel = 0); GFXFormat getFormat() const { return mInternalFormat; } bool setFormat(GFXFormat fmt); U32 getWidth(const U32 in_mipLevel = 0) const; U32 getHeight(const U32 in_mipLevel = 0) const; U32 getDepth(const U32 in_mipLevel = 0) const; U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0); const U8* getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel = 0) const; const U8* getBits(const U32 in_mipLevel = 0) const; U8* getWritableBits(const U32 in_mipLevel = 0); U32 getByteSize() const { return mByteSize; } U32 getBytesPerPixel() const { return mBytesPerPixel; } U32 getSurfaceSize(const U32 mipLevel) const; /// Use these functions to set and get the mHasTransparency value /// This is used to indicate that this bitmap has pixels that have /// an alpha value less than 255 (used by the auto-Material mapper) bool getHasTransparency() const { return mHasTransparency; } void setHasTransparency(bool hasTransparency) { mHasTransparency = hasTransparency; } /// In general you will want to use this function if there is not a /// good spot in the bitmap loader(s) to check the alpha value of /// the pixels. This function uses the texture format to loop over /// the bitmap bits and to check for alpha values less than 255 bool checkForTransparency(); LinearColorF sampleTexel(F32 u, F32 v, bool retAlpha = false) const; bool getColor(const U32 x, const U32 y, ColorI& rColor) const; bool setColor(const U32 x, const U32 y, const ColorI& rColor); U8 getChanelValueAt(U32 x, U32 y, U32 chan); /// This method will combine bitmapA and bitmapB using the operation specified /// by combineOp. The result will be stored in the bitmap that this method is /// called on. The size of the resulting bitmap will be the larger of A and B. /// The format of the resulting bitmap will be the format of A or B, whichever /// has a larger byte size. /// /// @note There are some restrictions on ops and formats that will probably change /// based on how we use this function. bool combine( const GBitmap *bitmapA, const GBitmap *bitmapB, const TextureOp combineOp ); /// Fills the first mip level of the bitmap with the specified color. void fill( const ColorI &rColor ); /// An optimized version of fill(). void fillWhite(); //-------------------------------------- Internal data/operators void deleteImage(); //-------------------------------------- Input/Output interface /// Read a bitmap from a stream /// @param bmType This is a file extension to describe the type of the data [i.e. "png" for PNG file, etc] /// @param ioStream The stream to read from bool readBitmap( const String &bmType, Stream &ioStream ); /// Write a bitmap to a stream /// @param bmType This is a file extension to describe the type of the data [i.e. "png" for PNG file, etc] /// @param ioStream The stream to read from /// @param compressionLevel Image format-specific compression level. If set to U32_MAX, we use the default compression defined when the format was registered. bool writeBitmap( const String &bmType, Stream &ioStream, U32 compressionLevel = U32_MAX ); bool readMNG(Stream& io_rStream); // located in bitmapMng.cc bool writeMNG(Stream& io_rStream) const; bool read(Stream& io_rStream); bool write(Stream& io_rStream) const; template void swizzle(const Swizzle *s); static Vector sRegistrations; private: GFXFormat mInternalFormat; U8* mBits; // Master bytes U32 mByteSize; U32 mWidth; U32 mHeight; U32 mBytesPerPixel; U32 mNumMipLevels; U32 mMipLevelOffsets[c_maxMipLevels]; bool mHasTransparency; static const U32 csFileVersion; }; //------------------------------------------------------------------------------ //-------------------------------------- Inlines // inline U32 GBitmap::getWidth(const U32 in_mipLevel) const { AssertFatal(in_mipLevel < mNumMipLevels, avar("GBitmap::getWidth: mip level out of range: (%d, %d)", in_mipLevel, mNumMipLevels)); U32 retVal = mWidth >> in_mipLevel; return (retVal != 0) ? retVal : 1; } inline U32 GBitmap::getHeight(const U32 in_mipLevel) const { AssertFatal(in_mipLevel < mNumMipLevels, avar("Bitmap::getHeight: mip level out of range: (%d, %d)", in_mipLevel, mNumMipLevels)); U32 retVal = mHeight >> in_mipLevel; return (retVal != 0) ? retVal : 1; } inline const U8* GBitmap::getBits(const U32 in_mipLevel) const { AssertFatal(in_mipLevel < mNumMipLevels, avar("GBitmap::getBits: mip level out of range: (%d, %d)", in_mipLevel, mNumMipLevels)); return &mBits[mMipLevelOffsets[in_mipLevel]]; } inline U8* GBitmap::getWritableBits(const U32 in_mipLevel) { AssertFatal(in_mipLevel < mNumMipLevels, avar("GBitmap::getWritableBits: mip level out of range: (%d, %d)", in_mipLevel, mNumMipLevels)); return &mBits[mMipLevelOffsets[in_mipLevel]]; } inline U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel) { return (getWritableBits(mipLevel) + ((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel); } inline const U8* GBitmap::getAddress(const S32 in_x, const S32 in_y, const U32 mipLevel) const { return (getBits(mipLevel) + ((in_y * getWidth(mipLevel)) + in_x) * mBytesPerPixel); } template void GBitmap::swizzle(const Swizzle *s ) { const U32 memSize = getWidth() * getHeight() * mBytesPerPixel; void *b = dMalloc(memSize); s->ToBuffer(b, getWritableBits(), memSize); dMemcpy(getWritableBits(), b, memSize); dFree(b); } #endif //_GBITMAP_H_