You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

390 lines
16 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
///////////////////////////////////////////////////////////////////////////////
// //
// plMipmap Class Header //
// Derived bitmap class representing a single mipmap. //
// Cyan, Inc. //
// //
//// Version History //////////////////////////////////////////////////////////
// //
// 6.7.2001 mcn - Created. //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef _plMipmap_h
#define _plMipmap_h
#include "plBitmap.h"
#include "plString.h"
#ifdef HS_DEBUGGING
#define ASSERT_PIXELSIZE(bitmap, pixelsize) hsAssert((bitmap)->fPixelSize == (pixelsize), "pixelSize mismatch")
#define ASSERT_XY(bitmap, x, y) hsAssert(x < (bitmap)->fWidth && y < (bitmap)->fHeight, "bad XY")
#define ASSERT_UNCOMPRESSED() hsAssert(fCompressionType!=kDirectXCompression, "Can't operate on compressed map.")
// Define the following konstant to enable mipmap leak checking. This is because our normal
// memory manager sucks when trying to track down these problems
#define MEMORY_LEAK_TRACER
#else
#define ASSERT_PIXELSIZE(bitmap, pixelsize)
#define ASSERT_XY(bitmap, x, y)
#define ASSERT_UNCOMPRESSED()
#endif
//// Class Definition /////////////////////////////////////////////////////////
class plBitmapCreator;
class plTextGenerator;
class plMipmap : public plBitmap
{
friend class plBitmapCreator;
friend class plTextGenerator;
public:
//// Public Flags ////
//// Public Data /////
//// Public Members ////
plMipmap();
plMipmap( uint32_t width, uint32_t height, unsigned config, uint8_t numLevels = 0, uint8_t compType = kUncompressed, uint8_t format = UncompressedInfo::kRGB8888 );
plMipmap( plMipmap *bm, float sig, uint32_t createFlags,
float detailDropoffStart, float detailDropoffStop,
float detailMax, float detailMin );
virtual ~plMipmap();
CLASSNAME_REGISTER( plMipmap );
GETINTERFACE_ANY( plMipmap, plBitmap );
void Create( uint32_t width, uint32_t height, unsigned config, uint8_t numLevels, uint8_t compType = kUncompressed, uint8_t format = UncompressedInfo::kRGB8888 );
virtual void Reset();
// Get the total size in bytes
virtual uint32_t GetTotalSize() const;
virtual void Read( hsStream *s, hsResMgr *mgr ) { hsKeyedObject::Read( s, mgr ); this->Read( s ); }
virtual void Write( hsStream *s, hsResMgr *mgr ) { hsKeyedObject::Write( s, mgr ); this->Write( s ); }
virtual uint8_t GetNumLevels() const { return fNumLevels; }
virtual uint32_t GetLevelSize( uint8_t level ); // 0 is the largest
virtual void Colorize();
virtual plMipmap *Clone() const;
virtual void CopyFrom( const plMipmap *source );
inline uint32_t GetWidth() const { return fWidth; }
inline uint32_t GetHeight() const { return fHeight; }
inline uint32_t GetRowBytes() const { return fRowBytes; }
void *GetImage() const { return fImage; }
void SetImagePtr( void *ptr ) { fImage = ptr; }
uint8_t *GetLevelPtr( uint8_t level, uint32_t *width = nil, uint32_t *height = nil, uint32_t *rowBytes = nil );
// Sets the current level pointer for use with GetAddr*
virtual void SetCurrLevel(uint8_t level);
void *GetCurrLevelPtr() const { return fCurrLevelPtr; }
uint32_t GetCurrWidth() const { return fCurrLevelWidth; }
uint32_t GetCurrHeight() const { return fCurrLevelHeight; }
uint32_t GetCurrLevelSize() const { return fLevelSizes[ fCurrLevel ]; }
uint32_t GetCurrLevel() const { return fCurrLevel; }
// These methods return the address of the pixel specified by x and y
// They are meant to be fast, therefore they are inlined and do not check
// the fPixelSize field at runtime (except when debugging)
uint8_t* GetAddr8(unsigned x, unsigned y) const
{
ASSERT_PIXELSIZE(this, 8);
ASSERT_XY(this, x, y);
ASSERT_UNCOMPRESSED();
return (uint8_t*)((char*)fCurrLevelPtr + y * fCurrLevelRowBytes + x);
}
uint16_t* GetAddr16(unsigned x, unsigned y) const
{
ASSERT_PIXELSIZE(this, 16);
ASSERT_XY(this, x, y);
ASSERT_UNCOMPRESSED();
return (uint16_t*)((char*)fCurrLevelPtr + y * fCurrLevelRowBytes + (x << 1));
}
uint32_t* GetAddr32(unsigned x, unsigned y) const
{
ASSERT_PIXELSIZE(this, 32);
ASSERT_XY(this, x, y);
ASSERT_UNCOMPRESSED();
return (uint32_t*)((char*)fCurrLevelPtr + y * fCurrLevelRowBytes + (x << 2));
}
void* GetAddr64(unsigned x, unsigned y) const
{
ASSERT_PIXELSIZE(this, 64);
ASSERT_XY(this, x, y);
ASSERT_UNCOMPRESSED();
return (void*)((char*)fCurrLevelPtr + y * fCurrLevelRowBytes + (x << 3));
}
// This sets fPixelSize, fSpace, fFlags, for you
// All you need to set is
// fWidth, fHeight, fRowBytes, fImage and fColorTable
enum {
kColor8Config = 0,
kGray44Config = 1,
kGray4Config = 2,
kGray8Config = 8, // So we can use bit depths instead
kRGB16Config = 16,
kRGB32Config = 24,
kARGB32Config = 32,
};
void SetConfig( unsigned config );
//// Really complex creation stuff ////
enum {
kCreateDetailAlpha = 0x1,
kCreateDetailAdd = 0x2,
kCreateDetailMult = 0x4,
kCreateDetailMask = kCreateDetailAlpha | kCreateDetailAdd | kCreateDetailMult,
kCreateCarryAlpha = 0x8,
kCreateCarryWhite = 0x10,
kCreateCarryBlack = 0x20,
kCreateCarryMask = kCreateCarryAlpha | kCreateCarryWhite | kCreateCarryBlack
};
enum hsGPixelType {
kPixelARGB4444,
kPixelARGB1555,
kPixelAI88,
kPixelI8
};
enum hsGCopyOptions {
kCopyLODMask,
};
enum {
kColorDataRLE = 0x1,
kAlphaDataRLE = 0x2
};
void SetBitmapAsLevel(uint8_t iDst, plMipmap *bm, float sig, uint32_t createFlags,
float detailDropoffStart, float detailDropoffStop,
float detailMax, float detailMin);
void ICreateLevelNoDetail(uint8_t iDst, const plFilterMask& mask);
void IBlendLevelDetailAlpha(uint8_t iDst, const plFilterMask& mask,
float detailDropoffStart, float detailDropoffStop,
float detailMax, float detailMin);
void IBlendLevelDetailAdd(uint8_t iDst, const plFilterMask& mask,
float detailDropoffStart, float detailDropoffStop,
float detailMax, float detailMin);
void IBlendLevelDetailMult(uint8_t iDst, const plFilterMask& mask,
float detailDropoffStart, float detailDropoffStop,
float detailMax, float detailMin);
void Filter(float sig);
uint32_t CopyOutPixels(uint32_t destXSize, uint32_t destYSize, uint32_t dstFormat, void *destPixels, uint32_t copyOptions);
void ClipToMaxSize( uint32_t maxDimension );
void RemoveMipping();
void EnsureKonstantBorder( bool clampU, bool clampV );
enum CompositeFlags
{
kForceOpaque = 0x0001, // Copy src pixels raw, force dest alphas to opaque
kCopySrcAlpha = 0x0002, // Copy the src pixels raw, including alphas, overwrite dest
kBlendSrcAlpha = 0x0004, // Blend src pixels onto dest using src alpha, dest alpha = src alpha
kMaskSrcAlpha = 0x0008, // Same as copySrcAlpha, but dest is untouched when src alpha = 0
kBlendWriteAlpha = 0x0010, // Like default (0), but writes dest alpha values
kDestPremultiplied = 0x0020, // Dest has color premultiplied by alpha
// (src always assumed nonpremultiplied for now)
};
class CompositeOptions
{
// Helper class for specifying options to Composite()
public:
uint16_t fFlags;
uint8_t fSrcLevelsToSkip;
uint8_t fOpacity;
float fRedTint, fGreenTint, fBlueTint;
uint16_t fSrcClipX, fSrcClipY; // Clipping is applied AFTER levelSkip
uint16_t fSrcClipWidth, fSrcClipHeight; // 0 means max width/height
CompositeOptions() { fFlags = 0; fSrcLevelsToSkip = 0; fRedTint = fGreenTint = fBlueTint = 1.f;
fSrcClipX = fSrcClipY = fSrcClipWidth = fSrcClipHeight = 0; fOpacity = 255;}
CompositeOptions( uint16_t flags, uint8_t srcLevelsToSkip = 0, float red = 1.f, float green = 1.f,
float blue = 1.f, uint16_t srcClipX = 0, uint16_t srcClipY = 0,
uint16_t srcClipWidth = 0, uint16_t srcClipHeight = 0, uint8_t opacity = 255 )
{
fFlags = flags;
fSrcLevelsToSkip = srcLevelsToSkip;
fRedTint = red;
fGreenTint = green;
fBlueTint = blue;
fSrcClipX = srcClipX;
fSrcClipY = srcClipY;
fSrcClipWidth = srcClipWidth;
fSrcClipHeight = srcClipHeight;
fOpacity = opacity;
}
};
// Compositing function. Take a (smaller) mipmap and composite it onto this one at the given location. Nil options means use default
virtual void Composite( plMipmap *source, uint16_t x, uint16_t y, CompositeOptions *options = nil );
// Scaling function
enum ScaleFilter
{
kBoxFilter,
kDefaultFilter = kBoxFilter
};
virtual void ScaleNicely( uint32_t *destPtr, uint16_t destWidth, uint16_t destHeight,
uint16_t destStride, plMipmap::ScaleFilter filter ) const;
virtual bool ResizeNicely( uint16_t newWidth, uint16_t newHeight, plMipmap::ScaleFilter filter );
protected:
//// Protected Members ////
void *fImage;
uint32_t fWidth, fHeight, fRowBytes, fTotalSize;
uint8_t fNumLevels;
uint32_t *fLevelSizes;
void *fCurrLevelPtr;
uint8_t fCurrLevel;
uint32_t fCurrLevelWidth, fCurrLevelHeight, fCurrLevelRowBytes;
void IReadRawImage( hsStream *stream );
void IWriteRawImage( hsStream *stream );
plMipmap *ISplitAlpha();
void IRecombineAlpha( plMipmap *alphaChannel );
plMipmap *IReadRLEImage( hsStream *stream );
void IWriteRLEImage( hsStream *stream, plMipmap *mipmap );
void IReadJPEGImage( hsStream *stream );
void IWriteJPEGImage( hsStream *stream );
void IBuildLevelSizes();
void IColorLevel( uint8_t level, const uint8_t *colorMask );
float IGetDetailLevelAlpha( uint8_t level, float dropStart, float dropStop, float min, float max );
void ICarryZeroAlpha(uint8_t iDst);
void ICarryColor(uint8_t iDst, uint32_t col);
bool IGrabBorderColor( bool grabVNotU, uint32_t *color );
void ISetCurrLevelUBorder( uint32_t color );
void ISetCurrLevelVBorder( uint32_t color );
virtual uint32_t Read( hsStream *s );
virtual uint32_t Write( hsStream *s );
friend class plCubicEnvironmap;
#ifdef MEMORY_LEAK_TRACER
protected:
class plRecord
{
public:
plRecord *fNext;
plRecord **fBackPtr;
plString fKeyName;
void *fImage;
uint32_t fWidth, fHeight, fRowBytes;
uint8_t fNumLevels;
uint8_t fCompressionType;
union
{
DirectXInfo fDirectXInfo;
UncompressedInfo fUncompressedInfo;
};
enum Method
{
kViaCreate,
kViaRead,
kViaClipToMaxSize,
kViaDetailMapConstructor,
kViaCopyFrom,
kViaResize
} fCreationMethod;
void Link( plRecord **backPtr )
{
fBackPtr = backPtr;
fNext = *backPtr;
if( fNext != nil )
fNext->fBackPtr = &fNext;
*backPtr = this;
}
void Unlink()
{
*fBackPtr = fNext;
if( fNext != nil )
fNext->fBackPtr = fBackPtr;
}
};
static plRecord *fRecords;
static uint32_t fNumMipmaps;
static void IAddToMemRecord( plMipmap *mip, plRecord::Method method );
static void IRemoveFromMemRecord( uint8_t *image );
static void IReportLeaks();
#endif
};
#endif // _plMipmap_h