mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
349 lines
12 KiB
C++
349 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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 8192 x 8192 images.
|
|
c_maxMipLevels = 14
|
|
};
|
|
|
|
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<String> 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<GBitmap> bitmap; // Correct!
|
|
/// bitmap = GBitmap::load( filename );
|
|
/// @endcode
|
|
///
|
|
static Resource<GBitmap> load(const Torque::Path &path);
|
|
|
|
protected:
|
|
|
|
static Resource<GBitmap> _load(const Torque::Path &path);
|
|
static Resource<GBitmap> _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<Torque::Path> *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<class T, dsize_t mapLength>
|
|
void swizzle(const Swizzle<T,mapLength> *s);
|
|
|
|
static Vector<Registration> 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<class T, dsize_t mapLength>
|
|
void GBitmap::swizzle(const Swizzle<T,mapLength> *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_
|