1367 lines
35 KiB
C++
1367 lines
35 KiB
C++
|
/****************************************************************************
|
|||
|
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
|||
|
|
|||
|
http://www.genesis-3d.com.cn
|
|||
|
|
|||
|
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.
|
|||
|
****************************************************************************/
|
|||
|
#include "resource/resource_stdneb.h"
|
|||
|
#include "resource/imageresloader.h"
|
|||
|
#include "rendersystem/config/RenderDeviceConfig.h"
|
|||
|
#include "ETC_Header.h"
|
|||
|
#include "foundation/io/filestream.h"
|
|||
|
#include "foundation/io/memorystream.h"
|
|||
|
|
|||
|
// must define FREEIMAGE_LIB when use FreeImage as static lib
|
|||
|
#define FREEIMAGE_LIB
|
|||
|
// use free image to load image
|
|||
|
#include "FreeImage/FreeImage.h"
|
|||
|
|
|||
|
// freeimage 3.9.1~3.11.0 interoperability fix
|
|||
|
#ifndef FREEIMAGE_COLORORDER
|
|||
|
// we have freeimage 3.9.1, define these symbols in such way as 3.9.1 really work (do not use 3.11.0 definition, as color order was changed between these two versions on Apple systems)
|
|||
|
#define FREEIMAGE_COLORORDER_BGR 0
|
|||
|
#define FREEIMAGE_COLORORDER_RGB 1
|
|||
|
#if defined(FREEIMAGE_BIGENDIAN)
|
|||
|
#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB
|
|||
|
#else
|
|||
|
#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef __WIN32__
|
|||
|
|
|||
|
//#error // @todo in iphone
|
|||
|
|
|||
|
// Color order is actually RGB on iPhone
|
|||
|
//#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
|
|||
|
//#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB
|
|||
|
//#endif
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
/*
|
|||
|
From Google<EFBFBD><EFBFBD>The DevIL And FreeImage All Are Not ThreadSafe<EFBFBD><EFBFBD>
|
|||
|
We Use FreeImage From OgreDependencies_MSVC_20101231 As Static Lib.
|
|||
|
If Only Use ResourceServer::LoadResource, We Had Only One Thread when Decode The Image. It's<EFBFBD><EFBFBD>Thread Safe
|
|||
|
If Use ResourceServer::LoadResource And Image::Load In Two Thread . It's Dangerous !!!!!!!!!!!!!!!!!!
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef __GENESIS_EDITOR__
|
|||
|
static Util::Dictionary<Util::String, bool> g_TexSquareInfo;
|
|||
|
static Util::Dictionary<Util::String, bool> g_TexDDSCollection;
|
|||
|
#endif
|
|||
|
|
|||
|
namespace Resources
|
|||
|
{
|
|||
|
__ImplementClass(Resources::ImageResCodecReg,'IRCR', Resources::ResCodecReg);
|
|||
|
__ImplementClass(Resources::ImageResLoader,'IRLD', Resources::ResourceLoader);
|
|||
|
__ImplementImageSingleton(Resources::ImageResCodecReg);
|
|||
|
|
|||
|
#define FOURCC(c0, c1, c2, c3) (c0 | (c1 << 8) | (c2 << 16) | (c3 << 24))
|
|||
|
|
|||
|
typedef uint uint32; // static_assert sizeof(uint)==4 later
|
|||
|
typedef ushort uint16; // static_assert sizeof(uint16)==2 later
|
|||
|
typedef ubyte uint8; // static_assert sizeof(uint16)==1 later
|
|||
|
|
|||
|
|
|||
|
#include "PVRTC_Header.h"
|
|||
|
#include "DDS_Header.h"
|
|||
|
|
|||
|
|
|||
|
//------------------------------------------------------------------------
|
|||
|
void FreeImageLoadErrorHandler(FREE_IMAGE_FORMAT fif, const char *message)
|
|||
|
{
|
|||
|
// Callback method as required by FreeImage to report problems
|
|||
|
#if __OSX__
|
|||
|
|
|||
|
#else
|
|||
|
const char* typeName = FreeImage_GetFormatFromFIF(fif);
|
|||
|
|
|||
|
|
|||
|
if (typeName)
|
|||
|
{
|
|||
|
n_warning("FreeImage error: %s when loading format %s\n" , message, typeName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
n_warning("FreeImage error: %s \n", message);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
//------------------------------------------------------------------------
|
|||
|
ImageResCodecReg::ImageResCodecReg()
|
|||
|
: mIsOpen(false)
|
|||
|
{
|
|||
|
__ConstructImageSingleton;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
ImageResCodecReg::~ImageResCodecReg()
|
|||
|
{
|
|||
|
__DestructImageSingleton;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
void
|
|||
|
ImageResCodecReg::Open(void)
|
|||
|
{
|
|||
|
if ( mIsOpen )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
n_static_assert( sizeof(uint32) == 4 );
|
|||
|
n_static_assert( sizeof(uint16) == 2 );
|
|||
|
n_static_assert( sizeof(uint8) == 1 );
|
|||
|
|
|||
|
//#if __OSX__
|
|||
|
//
|
|||
|
//#else
|
|||
|
FreeImage_Initialise(false);
|
|||
|
|
|||
|
n_printf("FreeImage version: %s Info: %s \n", FreeImage_GetVersion(), FreeImage_GetCopyrightMessage());
|
|||
|
n_printf("FreeImage Supported formats: \n");
|
|||
|
|
|||
|
for (int iType = 0; iType < FreeImage_GetFIFCount(); ++iType)
|
|||
|
{
|
|||
|
// Skip DDS codec since FreeImage does not have the option
|
|||
|
// to keep DXT data compressed, we'll use our own codec
|
|||
|
if ((FREE_IMAGE_FORMAT)iType == FIF_DDS)
|
|||
|
continue;
|
|||
|
|
|||
|
Util::String exts(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)iType));
|
|||
|
|
|||
|
Util::Array<Util::String> strArray;
|
|||
|
exts.Tokenize(",", strArray);
|
|||
|
// Pull off individual formats (separated by comma by FI)
|
|||
|
for (IndexT index = 0 ; index < strArray.Size(); ++index )
|
|||
|
{
|
|||
|
// FreeImage 3.13 lists many formats twice: once under their own codec and
|
|||
|
// once under the "RAW" codec, which is listed last. Avoid letting the RAW override
|
|||
|
// the dedicated codec!
|
|||
|
|
|||
|
Util::String strType = strArray[index];
|
|||
|
strType.ToUpper();
|
|||
|
n_printf( " %s", strType.AsCharPtr() );
|
|||
|
|
|||
|
if ( InvalidIndex == mExtReg.FindIndex( strType ) )
|
|||
|
{
|
|||
|
mExtReg.Add(strType, iType );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
n_printf("\n");
|
|||
|
|
|||
|
// Set error handler
|
|||
|
FreeImage_SetOutputMessage(FreeImageLoadErrorHandler);
|
|||
|
//#endif
|
|||
|
mIsOpen = true;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
void
|
|||
|
ImageResCodecReg::Close(void)
|
|||
|
{
|
|||
|
if ( mIsOpen )
|
|||
|
{
|
|||
|
//#if __OSX__
|
|||
|
//
|
|||
|
//#else
|
|||
|
FreeImage_DeInitialise();
|
|||
|
//#endif
|
|||
|
}
|
|||
|
mIsOpen = false;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
IndexT
|
|||
|
ImageResCodecReg::FindType(const Util::String& strExt, int& ImageFiletype)
|
|||
|
{
|
|||
|
IndexT findIndex = mExtReg.FindIndex( strExt );
|
|||
|
if ( findIndex != InvalidIndex )
|
|||
|
{
|
|||
|
ImageFiletype = mExtReg.ValueAtIndex( findIndex );
|
|||
|
}
|
|||
|
return findIndex;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadResource(Resource* res )
|
|||
|
{
|
|||
|
if ( !res )
|
|||
|
return false;
|
|||
|
|
|||
|
if ( res->GetRtti() != &ImageRes::RTTI )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
GPtr<Resource> pRes = res;
|
|||
|
GPtr<ImageRes> pImageRes = pRes.downcast<ImageRes>();
|
|||
|
n_assert(pImageRes);
|
|||
|
|
|||
|
if ( !mStream.isvalid() )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if ( mStream->GetSize() <= 0 )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Image does not support streaming for now. In order to reload correctly, unload existing data first.
|
|||
|
pImageRes->UnLoadImpl();
|
|||
|
|
|||
|
bool NeedClose = false;
|
|||
|
if ( !mStream->IsOpen() )
|
|||
|
{
|
|||
|
if ( !mStream->Open() )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
NeedClose = true;
|
|||
|
}
|
|||
|
|
|||
|
// load data
|
|||
|
if ( !LoadImage(mStream, pImageRes) )
|
|||
|
{
|
|||
|
if ( NeedClose )
|
|||
|
{
|
|||
|
mStream->Close();
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if ( NeedClose )
|
|||
|
{
|
|||
|
mStream->Close();
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadImage(GPtr<IO::Stream>& stream, GPtr<ImageRes>& pImage)
|
|||
|
{
|
|||
|
n_assert( mStream.isvalid() && pImage.isvalid() );
|
|||
|
|
|||
|
// check if dds
|
|||
|
if ( stream->GetSize() >= 4 )
|
|||
|
{
|
|||
|
//Read first byte to identify format
|
|||
|
uint32 magic;
|
|||
|
stream->Read(&magic,sizeof(uint32) );
|
|||
|
FlipEndian(&magic, sizeof(uint32), 1);
|
|||
|
|
|||
|
if ( DDS_MAGIC == magic )
|
|||
|
{
|
|||
|
stream->Seek(0, IO::Stream::Begin );
|
|||
|
return LoadDXT(stream, pImage );
|
|||
|
}
|
|||
|
|
|||
|
// prepare check other
|
|||
|
stream->Seek(0, IO::Stream::Begin );
|
|||
|
}
|
|||
|
|
|||
|
// check if PVRTC
|
|||
|
if ( stream->GetSize() >= sizeof(PVRTCTexHeader) )
|
|||
|
{
|
|||
|
// PVRTCTexHeader header;
|
|||
|
|
|||
|
uint32 magic;
|
|||
|
stream->Read(&magic,sizeof(uint32) );
|
|||
|
FlipEndian(&magic, sizeof(uint32), 1);
|
|||
|
|
|||
|
const uint32 PVRTEX3_IDENT = 0x03525650; // 'P''V''R'3
|
|||
|
|
|||
|
if (PVRTEX3_IDENT== magic)
|
|||
|
{
|
|||
|
stream->Seek(0, IO::Stream::Begin );
|
|||
|
return LoadPVRTC(stream, pImage );
|
|||
|
}
|
|||
|
|
|||
|
// prepare check other
|
|||
|
stream->Seek(0, IO::Stream::Begin );
|
|||
|
}
|
|||
|
|
|||
|
if ( stream->GetSize() >= sizeof(ETCHeader) )
|
|||
|
{
|
|||
|
static const char* ETC_MAGIC = "PKM ";
|
|||
|
char magicNum[5];
|
|||
|
magicNum[4] = '\0';
|
|||
|
stream->Read(&magicNum, 4);
|
|||
|
|
|||
|
if (!strcmp(ETC_MAGIC, magicNum))
|
|||
|
{
|
|||
|
stream->Seek(0, IO::Stream::Begin );
|
|||
|
return LoadETC(stream, pImage);
|
|||
|
}
|
|||
|
|
|||
|
stream->Seek(0, IO::Stream::Begin);
|
|||
|
}
|
|||
|
|
|||
|
// check if ETC
|
|||
|
// not impl now
|
|||
|
|
|||
|
// use FreeImage
|
|||
|
return LoadCommon(stream, pImage );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//------------------------------------------------------------------------
|
|||
|
RenderBase::PixelFormat::Code DXT_convertFourCCFormat(uint32 fourcc)
|
|||
|
{
|
|||
|
// convert dxt pixel format
|
|||
|
switch(fourcc)
|
|||
|
{
|
|||
|
case FOURCC('D','X','T','1'):
|
|||
|
return RenderBase::PixelFormat::DXT1;
|
|||
|
case FOURCC('D','X','T','2'):
|
|||
|
return RenderBase::PixelFormat::DXT2;
|
|||
|
case FOURCC('D','X','T','3'):
|
|||
|
return RenderBase::PixelFormat::DXT3;
|
|||
|
case FOURCC('D','X','T','4'):
|
|||
|
return RenderBase::PixelFormat::DXT4;
|
|||
|
case FOURCC('D','X','T','5'):
|
|||
|
return RenderBase::PixelFormat::DXT5;
|
|||
|
case D3DFMT_R16F:
|
|||
|
return RenderBase::PixelFormat::R16F;
|
|||
|
case D3DFMT_G16R16F:
|
|||
|
return RenderBase::PixelFormat::G16R16F;
|
|||
|
case D3DFMT_A16B16G16R16F:
|
|||
|
return RenderBase::PixelFormat::A16B16G16R16F;
|
|||
|
case D3DFMT_R32F:
|
|||
|
return RenderBase::PixelFormat::R32F;
|
|||
|
case D3DFMT_G32R32F:
|
|||
|
return RenderBase::PixelFormat::G32R32F;
|
|||
|
case D3DFMT_A32B32G32R32F:
|
|||
|
return RenderBase::PixelFormat::A32B32G32R32F;
|
|||
|
// We could support 3Dc here, but only ATI cards support it, not nVidia
|
|||
|
default:
|
|||
|
return RenderBase::PixelFormat::InvalidPixelFormat;
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
//------------------------------------------------------------------------
|
|||
|
RenderBase::PixelFormat::Code DXT_convertPixelFormat(uint32 rgbBits, uint32 rMask,
|
|||
|
uint32 gMask, uint32 bMask, uint32 aMask)
|
|||
|
{
|
|||
|
// General search through pixel formats
|
|||
|
for (IndexT i = 0; i < RenderBase::PixelFormat::NumPixelFormats; ++i)
|
|||
|
{
|
|||
|
RenderBase::PixelFormat::Code pf = static_cast<RenderBase::PixelFormat::Code>(i);
|
|||
|
|
|||
|
SizeT numBits = RenderBase::PixelFormat::GetNumElemBytes(pf) * 8;
|
|||
|
if (numBits == rgbBits)
|
|||
|
{
|
|||
|
uint32 testMasks[4];
|
|||
|
RenderBase::PixelFormat::GetBitMasks(pf, testMasks);
|
|||
|
int testBits[4];
|
|||
|
RenderBase::PixelFormat::GetBitDepths(pf, testBits);
|
|||
|
if (testMasks[0] == rMask && testMasks[1] == gMask &&
|
|||
|
testMasks[2] == bMask &&
|
|||
|
// for alpha, deal with 'X8' formats by checking bit counts
|
|||
|
(testMasks[3] == aMask || (aMask == 0 && testBits[3] == 0)))
|
|||
|
{
|
|||
|
return pf;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return RenderBase::PixelFormat::InvalidPixelFormat;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadDXT(GPtr<IO::Stream>& stream, GPtr<ImageRes>& pImage)
|
|||
|
{
|
|||
|
uint32 magic;
|
|||
|
stream->Read(&magic,sizeof(uint32) );
|
|||
|
FlipEndian(&magic, sizeof(uint32), 1);
|
|||
|
if ( DDS_MAGIC != magic )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Read header in full
|
|||
|
DDSHeader header;
|
|||
|
stream->Read(&header, sizeof(DDSHeader));
|
|||
|
|
|||
|
// Endian flip if required, all 32-bit values
|
|||
|
FlipEndian(&header, 4, sizeof(DDSHeader) / 4);
|
|||
|
|
|||
|
// Check some sizes
|
|||
|
if (header.size != DDS_HEADER_SIZE)
|
|||
|
{
|
|||
|
n_warning(" ImageResLoader::LoadDXT DDS header size mismatch!\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
|
|||
|
{
|
|||
|
n_warning(" ImageResLoader::LoadDXT DDS header size mismatch!\n");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
pImage->mDepth = 1; // (deal with volume later)
|
|||
|
pImage->mWidth = header.width;
|
|||
|
pImage->mHeight = header.height;
|
|||
|
#ifdef __GENESIS_EDITOR__
|
|||
|
bool bSquare = (header.width == header.height);
|
|||
|
Util::String texName = pImage->GetResourceId().AsString();
|
|||
|
IndexT res = g_TexSquareInfo.FindIndex(texName);
|
|||
|
if (res != InvalidIndex)
|
|||
|
{
|
|||
|
g_TexSquareInfo[texName] = bSquare;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
g_TexSquareInfo.Add(texName, bSquare);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
pImage->mNumFace = 1; // assume one face until we know otherwise
|
|||
|
pImage->mDepth = 1; // assume one depth until we know otherwise
|
|||
|
|
|||
|
if (header.caps.caps1 & DDSCAPS_MIPMAP)
|
|||
|
{
|
|||
|
pImage->mMipMapLevel = static_cast<ushort>(header.mipMapCount - 1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pImage->mMipMapLevel = 0;
|
|||
|
}
|
|||
|
|
|||
|
bool decompressDXT = false;
|
|||
|
|
|||
|
// Figure out basic image type
|
|||
|
if (header.caps.caps2 & DDSCAPS2_CUBEMAP)
|
|||
|
{
|
|||
|
pImage->mNumFace = 6; // cube map
|
|||
|
}
|
|||
|
else if (header.caps.caps2 & DDSCAPS2_VOLUME)
|
|||
|
{
|
|||
|
pImage->mDepth = header.depth; // 3d texture
|
|||
|
}
|
|||
|
|
|||
|
// Pixel format
|
|||
|
RenderBase::PixelFormat::Code sourceFormat = RenderBase::PixelFormat::InvalidPixelFormat;
|
|||
|
|
|||
|
if (header.pixelFormat.flags & DDPF_FOURCC)
|
|||
|
{
|
|||
|
sourceFormat = DXT_convertFourCCFormat(header.pixelFormat.fourCC);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sourceFormat = DXT_convertPixelFormat(header.pixelFormat.rgbBits,
|
|||
|
header.pixelFormat.redMask, header.pixelFormat.greenMask,
|
|||
|
header.pixelFormat.blueMask,
|
|||
|
header.pixelFormat.flags & DDPF_ALPHAPIXELS ?
|
|||
|
header.pixelFormat.alphaMask : 0);
|
|||
|
}
|
|||
|
|
|||
|
if ( sourceFormat == RenderBase::PixelFormat::InvalidPixelFormat)
|
|||
|
{
|
|||
|
n_warning( "ImageResLoader::LoadDXT Cannot determine pixel format\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
pImage->mPixelFormat = sourceFormat;
|
|||
|
|
|||
|
#ifdef __GENESIS_EDITOR__
|
|||
|
|
|||
|
if (g_TexDDSCollection.FindIndex(texName) == InvalidIndex)
|
|||
|
{
|
|||
|
if (sourceFormat == RenderBase::PixelFormat::DXT1 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT2 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT3 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT4 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT5 )
|
|||
|
{
|
|||
|
g_TexDDSCollection.Add(texName, true);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (sourceFormat != RenderBase::PixelFormat::DXT1 &&
|
|||
|
sourceFormat != RenderBase::PixelFormat::DXT2 &&
|
|||
|
sourceFormat != RenderBase::PixelFormat::DXT3 &&
|
|||
|
sourceFormat != RenderBase::PixelFormat::DXT4 &&
|
|||
|
sourceFormat != RenderBase::PixelFormat::DXT5 )
|
|||
|
{
|
|||
|
g_TexDDSCollection[texName] = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
// Calculate total size from number of mipmaps, faces and size
|
|||
|
SizeT dataSize = ImageRes::S_CalculateSize(pImage->mMipMapLevel, pImage->mNumFace,
|
|||
|
pImage->mWidth, pImage->mHeight, pImage->mDepth, pImage->mPixelFormat);
|
|||
|
|
|||
|
if ( dataSize == 0 )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
GPtr<ImageData> pData = ImageData::Create();
|
|||
|
pData->Setup( dataSize );
|
|||
|
|
|||
|
pImage->mData = pData;
|
|||
|
|
|||
|
// Now deal with the data
|
|||
|
ubyte* destPtr = pData->Ptr();
|
|||
|
n_assert(destPtr);
|
|||
|
|
|||
|
// all mips for a face, then each face
|
|||
|
for(IndexT i = 0; i < pImage->mNumFace; ++i)
|
|||
|
{
|
|||
|
SizeT width = pImage->mWidth;
|
|||
|
SizeT height = pImage->mHeight;
|
|||
|
SizeT depth = pImage->mDepth;
|
|||
|
|
|||
|
for(IndexT mip = 0; mip <= pImage->mMipMapLevel; ++mip)
|
|||
|
{
|
|||
|
SizeT dstPitch = width * RenderBase::PixelFormat::GetNumElemBytes(pImage->mPixelFormat);
|
|||
|
|
|||
|
if (RenderBase::PixelFormat::IsCompressed(sourceFormat))
|
|||
|
{
|
|||
|
// load directly
|
|||
|
// DDS format lies! sizeOrPitch is not always set for DXT!!
|
|||
|
size_t dxtSize = RenderBase::PixelFormat::GetMemorySize(width, height, depth, pImage->mPixelFormat);
|
|||
|
|
|||
|
stream->Read(destPtr, dxtSize);
|
|||
|
destPtr += dxtSize;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Final data - trim incoming pitch
|
|||
|
SizeT srcPitch;
|
|||
|
if (header.flags & DDSD_PITCH)
|
|||
|
{
|
|||
|
srcPitch = header.sizeOrPitch / Math::n_max( 1, mip * 2 );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// assume same as final pitch
|
|||
|
srcPitch = dstPitch;
|
|||
|
}
|
|||
|
|
|||
|
n_assert (dstPitch <= srcPitch);
|
|||
|
|
|||
|
long srcAdvance = srcPitch - dstPitch;
|
|||
|
|
|||
|
for (IndexT z = 0; z < depth; ++z)
|
|||
|
{
|
|||
|
for (IndexT y = 0; y < height; ++y)
|
|||
|
{
|
|||
|
stream->Read(destPtr, dstPitch);
|
|||
|
if (srcAdvance > 0)
|
|||
|
{
|
|||
|
stream->Seek(srcAdvance, IO::Stream::Current);
|
|||
|
}
|
|||
|
|
|||
|
destPtr = destPtr + dstPitch;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/// Next mip
|
|||
|
if(width!=1) width /= 2;
|
|||
|
if(height!=1) height /= 2;
|
|||
|
if(depth!=1) depth /= 2;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadPVRTC(GPtr<IO::Stream>& stream, GPtr<ImageRes>& pImage)
|
|||
|
{
|
|||
|
n_assert( stream->GetSize() >= sizeof(New_PVRTCTexHeader) );
|
|||
|
|
|||
|
New_PVRTCTexHeader header;
|
|||
|
uint64 formatFlags = 0 ;
|
|||
|
|
|||
|
// Read the PVRTC header
|
|||
|
stream->Read(&header, sizeof(New_PVRTCTexHeader));
|
|||
|
|
|||
|
// Get format flags
|
|||
|
formatFlags = header.u64PixelFormat;
|
|||
|
|
|||
|
FlipEndian((void *)formatFlags, sizeof(uint64));
|
|||
|
|
|||
|
if (formatFlags == ePVRTPF_PVRTCI_2bpp_RGBA || formatFlags == ePVRTPF_PVRTCI_4bpp_RGBA)
|
|||
|
{
|
|||
|
if (formatFlags == ePVRTPF_PVRTCI_4bpp_RGBA)
|
|||
|
{
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::PVRTC_RGBA4 ;
|
|||
|
}
|
|||
|
else if (formatFlags == ePVRTPF_PVRTCI_2bpp_RGBA)
|
|||
|
{
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::PVRTC_RGBA2 ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
else if (formatFlags == ePVRTPF_ETC1)
|
|||
|
{
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::ETC1_RGB8;
|
|||
|
}
|
|||
|
|
|||
|
pImage->mDepth = header.u32Depth;
|
|||
|
pImage->mWidth = header.u32Width;
|
|||
|
pImage->mHeight = header.u32Height;
|
|||
|
pImage->mMipMapLevel = static_cast<ushort>(header.u32MIPMapCount)-1;
|
|||
|
pImage->mNumFace = header.u32NumFaces;
|
|||
|
|
|||
|
// Calculate total size from number of mipmaps, faces and size
|
|||
|
SizeT dataSize = ImageRes::S_CalculateSize(pImage->mMipMapLevel, pImage->mNumFace,
|
|||
|
pImage->mWidth, pImage->mHeight, pImage->mDepth, pImage->mPixelFormat);
|
|||
|
|
|||
|
if ( dataSize == 0 )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
stream->Seek(header.u32MetaDataSize, IO::Stream::Current);
|
|||
|
|
|||
|
GPtr<ImageData> pData = ImageData::Create();
|
|||
|
pData->Setup( dataSize );
|
|||
|
pImage->mData = pData;
|
|||
|
|
|||
|
// Now deal with the data
|
|||
|
ubyte *destPtr = pData->Ptr();
|
|||
|
|
|||
|
|
|||
|
if (header.u32NumFaces == 1)
|
|||
|
{
|
|||
|
stream->Read(destPtr, dataSize);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ubyte* pPix = n_new_array(ubyte, dataSize);
|
|||
|
stream->Read(pPix, dataSize);
|
|||
|
|
|||
|
SizeT nFaces = header.u32NumFaces;
|
|||
|
SizeT nMips = header.u32MIPMapCount;
|
|||
|
|
|||
|
for (IndexT iFace = 0; iFace < nFaces; ++iFace)
|
|||
|
{
|
|||
|
SizeT width = pImage->mWidth;
|
|||
|
SizeT height = pImage->mHeight;
|
|||
|
SizeT depth = pImage->mDepth;
|
|||
|
|
|||
|
ubyte* pSource = pPix + iFace * RenderBase::PixelFormat::GetMemorySize(width, height, depth, pImage->mPixelFormat);
|
|||
|
|
|||
|
for (IndexT iMip = 0; iMip < nMips; ++iMip)
|
|||
|
{
|
|||
|
SizeT size = RenderBase::PixelFormat::GetMemorySize(width, height, depth, pImage->mPixelFormat);
|
|||
|
Memory::Copy(pSource, destPtr, size);
|
|||
|
destPtr += size;
|
|||
|
|
|||
|
pSource += size * (nFaces - iFace);
|
|||
|
|
|||
|
if (width != 1)
|
|||
|
{
|
|||
|
width /= 2;
|
|||
|
}
|
|||
|
|
|||
|
if (height != 1)
|
|||
|
{
|
|||
|
height /= 2;
|
|||
|
}
|
|||
|
|
|||
|
if (depth != 1)
|
|||
|
{
|
|||
|
depth /= 2;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
n_delete_array(pPix);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return true;
|
|||
|
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
class AutoMemory
|
|||
|
{
|
|||
|
public:
|
|||
|
AutoMemory(GPtr<IO::Stream>& stream, ubyte** data)
|
|||
|
: mStream( stream )
|
|||
|
, mNewData(NULL)
|
|||
|
, mMap(false)
|
|||
|
{
|
|||
|
SizeT streamSize = mStream->GetSize();
|
|||
|
n_assert(streamSize > 0 );
|
|||
|
|
|||
|
if ( mStream->CanBeMapped() && !mStream->IsMapped() )
|
|||
|
{
|
|||
|
(*data) = (ubyte*)stream->Map();
|
|||
|
mMap = true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
mNewData = n_new_array(ubyte, streamSize);
|
|||
|
(*data) = mNewData;
|
|||
|
mMap = false;
|
|||
|
}
|
|||
|
}
|
|||
|
~AutoMemory()
|
|||
|
{
|
|||
|
if ( mMap )
|
|||
|
{
|
|||
|
mStream->Unmap();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
n_delete_array(mNewData);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
bool mMap;
|
|||
|
GPtr<IO::Stream>& mStream;
|
|||
|
ubyte* mNewData;
|
|||
|
};
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadCommon(GPtr<IO::Stream>& stream, GPtr<ImageRes>& pImage)
|
|||
|
{
|
|||
|
n_assert( stream.isvalid() && pImage.isvalid() );
|
|||
|
SizeT streamSize = stream->GetSize();
|
|||
|
if ( streamSize <= 0 )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
FreeImage_SetOutputMessage(FreeImageLoadErrorHandler);
|
|||
|
|
|||
|
Util::String resName = pImage->GetResourceId().AsString();
|
|||
|
Util::String fileExt = resName.GetFileExtension();
|
|||
|
fileExt.ToUpper();
|
|||
|
|
|||
|
ubyte* pStreamData = NULL;
|
|||
|
AutoMemory autoMem( stream, &pStreamData );
|
|||
|
n_assert( pStreamData != NULL );
|
|||
|
|
|||
|
// To identify image format, analysis with FreeImage stream first, then try ImageResCodecReg
|
|||
|
int fileType = FIF_UNKNOWN;
|
|||
|
FIMEMORY* fiMem = FreeImage_OpenMemory( pStreamData, static_cast<DWORD>(streamSize) );
|
|||
|
if( !fiMem )
|
|||
|
{
|
|||
|
n_warning( "mageResLoader::LoadCommon Can Not Open image Memory\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
fileType = FreeImage_GetFileTypeFromMemory(fiMem);
|
|||
|
|
|||
|
if ( fileType == FIF_UNKNOWN )
|
|||
|
{
|
|||
|
if ( ImageResCodecReg::HasInstance() )
|
|||
|
{
|
|||
|
ImageResCodecReg::Instance()->FindType(fileExt, fileType);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( fileType == FIF_UNKNOWN )
|
|||
|
{
|
|||
|
n_warning( "mageResLoader::LoadCommon Can Not Get image Type\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
FIBITMAP* fiBitmap = FreeImage_LoadFromMemory( (FREE_IMAGE_FORMAT)fileType, fiMem );
|
|||
|
if (!fiBitmap)
|
|||
|
{
|
|||
|
n_warning( "mageResLoader::LoadCommon Error decoding image\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
pImage->mDepth = 1; // only 2D formats handled by this codec
|
|||
|
pImage->mWidth = FreeImage_GetWidth(fiBitmap);
|
|||
|
pImage->mHeight = FreeImage_GetHeight(fiBitmap);
|
|||
|
pImage->mMipMapLevel = 0; // no mipmaps in non-DDS
|
|||
|
#ifdef __GENESIS_EDITOR__
|
|||
|
bool bSquare = (pImage->mWidth == pImage->mHeight);
|
|||
|
|
|||
|
IndexT res = g_TexSquareInfo.FindIndex(resName);
|
|||
|
if (res !=InvalidIndex )
|
|||
|
{
|
|||
|
g_TexSquareInfo[resName] = bSquare;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
g_TexSquareInfo.Add(resName, bSquare);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
// Must derive format first, this may perform conversions
|
|||
|
FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(fiBitmap);
|
|||
|
FREE_IMAGE_COLOR_TYPE colourType = FreeImage_GetColorType(fiBitmap);
|
|||
|
unsigned bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
|
|||
|
switch(imageType)
|
|||
|
{
|
|||
|
case FIT_UNKNOWN:
|
|||
|
case FIT_COMPLEX:
|
|||
|
case FIT_UINT32:
|
|||
|
case FIT_INT32:
|
|||
|
case FIT_DOUBLE:
|
|||
|
n_warning(" ImageResLoader::LoadCommon: Unknown or unsupported image format\n");
|
|||
|
return false;
|
|||
|
case FIT_RGBA16:
|
|||
|
{
|
|||
|
FIBITMAP* newBitmap = FreeImage_ConvertTo32Bits(fiBitmap);
|
|||
|
// free old bitmap and replace
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
fiBitmap = newBitmap;
|
|||
|
// get new formats
|
|||
|
bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
// big endian. RGBA in memory, RGBA in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8A8;
|
|||
|
#else
|
|||
|
// little endian. BGRA in memory, ARGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::A8R8G8B8;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case FIT_RGB16:
|
|||
|
{
|
|||
|
FIBITMAP* newBitmap = FreeImage_ConvertTo32Bits(fiBitmap);
|
|||
|
// free old bitmap and replace
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
fiBitmap = newBitmap;
|
|||
|
// get new formats
|
|||
|
bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
// big endian. RGBA in memory, RGBA in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8A8;
|
|||
|
#else
|
|||
|
// little endian. BGRA in memory, ARGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::A8R8G8B8;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case FIT_BITMAP:
|
|||
|
// Standard image type
|
|||
|
// Perform any colour conversions for greyscale
|
|||
|
if (colourType == FIC_MINISWHITE || colourType == FIC_MINISBLACK)
|
|||
|
{
|
|||
|
FIBITMAP* newBitmap = FreeImage_ConvertToGreyscale(fiBitmap);
|
|||
|
// free old bitmap and replace
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
fiBitmap = newBitmap;
|
|||
|
// get new formats
|
|||
|
bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
colourType = FreeImage_GetColorType(fiBitmap);
|
|||
|
}
|
|||
|
// Perform any colour conversions for RGB
|
|||
|
else if (bpp < 8 || colourType == FIC_PALETTE || colourType == FIC_CMYK)
|
|||
|
{
|
|||
|
FIBITMAP* newBitmap = FreeImage_ConvertTo32Bits(fiBitmap);
|
|||
|
// free old bitmap and replace
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
fiBitmap = newBitmap;
|
|||
|
// get new formats
|
|||
|
bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
colourType = FreeImage_GetColorType(fiBitmap);
|
|||
|
}
|
|||
|
else if ( bpp == 24 )
|
|||
|
{
|
|||
|
// most graphics chip does not support 24bit but 32bit
|
|||
|
FIBITMAP* newBitmap = FreeImage_ConvertTo32Bits(fiBitmap);
|
|||
|
// free old bitmap and replace
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
fiBitmap = newBitmap;
|
|||
|
// get new formats
|
|||
|
bpp = FreeImage_GetBPP(fiBitmap);
|
|||
|
colourType = FreeImage_GetColorType(fiBitmap);
|
|||
|
}
|
|||
|
|
|||
|
// by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A]
|
|||
|
switch(bpp)
|
|||
|
{
|
|||
|
case 8:
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::L8;
|
|||
|
break;
|
|||
|
case 16:
|
|||
|
// Determine 555 or 565 from green mask
|
|||
|
// cannot be 16-bit greyscale since that's FIT_UINT16
|
|||
|
if(FreeImage_GetGreenMask(fiBitmap) == FI16_565_GREEN_MASK)
|
|||
|
{
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R5G6B5;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// FreeImage doesn't support 4444 format so must be 1555
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::A1R5G5B5;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 24:
|
|||
|
// FreeImage differs per platform
|
|||
|
// little endian: BGR[A]
|
|||
|
// for big endian: RGB[A]
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
// big endian. RGB in memory, RGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8;
|
|||
|
#else
|
|||
|
// little endian. BGR in memory, RGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8;
|
|||
|
#endif
|
|||
|
break;
|
|||
|
case 32:
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
// big endian. RGBA in memory, RGBA in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8A8;
|
|||
|
#else
|
|||
|
// little endian. BGRA in memory, ARGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::A8R8G8B8;
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
};
|
|||
|
break;
|
|||
|
case FIT_UINT16:
|
|||
|
case FIT_INT16:
|
|||
|
// 16-bit greyscale
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::L16;
|
|||
|
break;
|
|||
|
case FIT_FLOAT:
|
|||
|
// Single-component floating point data
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R32F;
|
|||
|
break;
|
|||
|
// not support now
|
|||
|
//case FIT_RGB16:
|
|||
|
// pImage->mPixelFormat = PF_SHORT_RGB;
|
|||
|
// break;
|
|||
|
//case FIT_RGBA16:
|
|||
|
// pImage->mPixelFormat = PF_SHORT_RGBA;
|
|||
|
// break;
|
|||
|
case FIT_RGBF:
|
|||
|
{
|
|||
|
//Convert to 8bit format
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
// big endian. RGBA in memory, RGBA in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::R8G8B8A8;
|
|||
|
#else
|
|||
|
// little endian. BGRA in memory, ARGB in native
|
|||
|
pImage->mPixelFormat = RenderBase::PixelFormat::A8R8G8B8;
|
|||
|
#endif
|
|||
|
}
|
|||
|
// pImage->mPixelFormat = PF_FLOAT32_RGB;
|
|||
|
break;
|
|||
|
//case FIT_RGBAF:
|
|||
|
// pImage->mPixelFormat = PF_FLOAT32_RGBA;
|
|||
|
// break;
|
|||
|
default:
|
|||
|
n_warning(" ImageResLoader::LoadCommon: Unknown or unsupported image format\n");
|
|||
|
return false;
|
|||
|
};
|
|||
|
|
|||
|
unsigned char* srcData = FreeImage_GetBits(fiBitmap);
|
|||
|
unsigned srcPitch = FreeImage_GetPitch(fiBitmap);
|
|||
|
|
|||
|
uint texSize = FreeImage_GetDIBSize(fiBitmap);
|
|||
|
|
|||
|
// Final data - invert image and trim pitch at the same time
|
|||
|
SizeT dstPitch = pImage->mWidth * RenderBase::PixelFormat::GetNumElemBytes(pImage->mPixelFormat);
|
|||
|
SizeT dataSize = dstPitch * pImage->mHeight;
|
|||
|
|
|||
|
if ( dataSize == 0 || pImage->mHeight < 1 || pImage->mWidth < 1)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
GPtr<ImageData> pData = ImageData::Create();
|
|||
|
pData->Setup( dataSize );
|
|||
|
pImage->mData = pData;
|
|||
|
|
|||
|
ubyte* pSrc;
|
|||
|
ubyte* pDst = pData->Ptr();
|
|||
|
|
|||
|
if ( imageType == FIT_RGBF)
|
|||
|
{
|
|||
|
const float maxColorComponent = 6.0f;
|
|||
|
const float overMaxColorComponent = 1.0f / maxColorComponent;
|
|||
|
const float minColorComponent = 2.0f * 1e-6f;
|
|||
|
ubyte * bits = pDst;
|
|||
|
|
|||
|
pSrc = srcData;
|
|||
|
|
|||
|
// encoding Float Texture with RGBM
|
|||
|
// reference from network www.gamedev.net
|
|||
|
for ( IndexT y = 0; y < pImage->mHeight; y++ )
|
|||
|
{
|
|||
|
FIRGBF* srcPixel = (FIRGBF*)(pSrc + (pImage->mHeight - y - 1) * srcPitch);
|
|||
|
ubyte * destPixel = bits;
|
|||
|
|
|||
|
for ( int x = 0; x < pImage->mWidth; x++ )
|
|||
|
{
|
|||
|
float redComponent = srcPixel[x].red;
|
|||
|
float greenComponent = srcPixel[x].green;
|
|||
|
float blueComponent = srcPixel[x].blue;
|
|||
|
|
|||
|
float maxComponent = Math::n_max( Math::n_max(redComponent, greenComponent), Math::n_max(blueComponent, minColorComponent));
|
|||
|
float alphaComponent = ((int)(maxComponent * overMaxColorComponent * 255.0f) + 0.5f) * 1.0f / 255.0f;
|
|||
|
|
|||
|
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
|
|||
|
destPixel[0] = (ubyte)(Math::n_min(alphaComponent , 1.0f) * 255.0f + 0.5f);
|
|||
|
destPixel[1] = (ubyte)(Math::n_min(redComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f + 0.5f);
|
|||
|
destPixel[2] = (ubyte)(Math::n_min(greenComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f + 0.5f);
|
|||
|
destPixel[3] = (ubyte)(Math::n_min(blueComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f + 0.5f);
|
|||
|
|
|||
|
|
|||
|
#else
|
|||
|
destPixel[3] = (ubyte)(Math::n_min(alphaComponent, 1.0f) * 255.0f);
|
|||
|
destPixel[2] = (ubyte)(Math::n_min(redComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f);
|
|||
|
destPixel[1] = (ubyte)(Math::n_min(greenComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f);
|
|||
|
destPixel[0] = (ubyte)(Math::n_min(blueComponent * overMaxColorComponent / alphaComponent, 1.0f) * 255.0f);
|
|||
|
#if RENDERDEVICE_OPENGLES
|
|||
|
|
|||
|
ubyte temp = destPixel[2];
|
|||
|
destPixel[2] = destPixel[0];
|
|||
|
destPixel[0] = temp;
|
|||
|
#endif
|
|||
|
|
|||
|
#endif
|
|||
|
destPixel += 4;
|
|||
|
}
|
|||
|
bits += dstPitch;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if RENDERDEVICE_OPENGLES
|
|||
|
SizeT nPixel = RenderBase::PixelFormat::GetNumElemBytes(pImage->mPixelFormat);
|
|||
|
for (IndexT i = 0; i < pImage->mWidth * pImage->mHeight * nPixel; i += nPixel)
|
|||
|
{
|
|||
|
uchar temp = srcData[i];
|
|||
|
srcData[i] = srcData[i+2];
|
|||
|
srcData[i+2] = temp;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
for (IndexT y = 0; y < pImage->mHeight; ++y)
|
|||
|
{
|
|||
|
pSrc = srcData + (pImage->mHeight - y - 1) * srcPitch;
|
|||
|
memcpy(pDst, pSrc, dstPitch);
|
|||
|
pDst += dstPitch;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FreeImage_Unload(fiBitmap);
|
|||
|
FreeImage_CloseMemory(fiMem);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool
|
|||
|
ImageResLoader::LoadETC(GPtr<IO::Stream>& stream, GPtr<ImageRes>& pImage)
|
|||
|
{
|
|||
|
ubyte* pStreamData = NULL;
|
|||
|
AutoMemory autoMem( stream, &pStreamData );
|
|||
|
|
|||
|
ETCHeader loadedETCHeader = ETCHeader(pStreamData);
|
|||
|
uint width = loadedETCHeader.getWidth();
|
|||
|
uint height = loadedETCHeader.getHeight();
|
|||
|
|
|||
|
uint texSize = (loadedETCHeader.getPaddedWidth() * loadedETCHeader.getPaddedHeight()) >> 1;
|
|||
|
|
|||
|
ubyte* pRaw = n_new_array(ubyte, texSize);
|
|||
|
memcpy(pRaw, pStreamData + 16, texSize);
|
|||
|
|
|||
|
GPtr<ImageData> pData = ImageData::Create();
|
|||
|
|
|||
|
pData->SetData(pRaw, texSize);
|
|||
|
|
|||
|
|
|||
|
pImage->mData = pData;
|
|||
|
pImage->SetWidth(width);
|
|||
|
pImage->SetHeight(height);
|
|||
|
pImage->SetMipMapLevel(0);
|
|||
|
pImage->SetDepth(1);
|
|||
|
pImage->SetPixelFormat(RenderBase::PixelFormat::ETC1_RGB8);
|
|||
|
|
|||
|
return true;
|
|||
|
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
#ifdef __GENESIS_EDITOR__
|
|||
|
bool
|
|||
|
ImageResLoader::IsSquare(const Util::String& path)
|
|||
|
{
|
|||
|
if (g_TexSquareInfo.FindIndex(path) != InvalidIndex)
|
|||
|
{
|
|||
|
return g_TexSquareInfo[path];
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
IO::URI uri(path);
|
|||
|
uri.SetScheme("file");
|
|||
|
|
|||
|
GPtr<IO::Stream> pFileStream = IO::FileStream::Create();
|
|||
|
pFileStream->SetAccessMode(IO::Stream::ReadAccess);
|
|||
|
pFileStream->SetURI(uri);
|
|||
|
GPtr<IO::Stream> pMemoryStream = IO::MemoryStream::Create();
|
|||
|
|
|||
|
bool bRet = false;
|
|||
|
|
|||
|
if (pFileStream->Open())
|
|||
|
{
|
|||
|
SizeT size = pFileStream->GetSize();
|
|||
|
|
|||
|
if (size > 0)
|
|||
|
{
|
|||
|
pMemoryStream->SetAccessMode(IO::Stream::ReadWriteAccess);
|
|||
|
if (pMemoryStream->Open())
|
|||
|
{
|
|||
|
pMemoryStream->SetSize(size);
|
|||
|
void* ptr = pMemoryStream->Map();
|
|||
|
pFileStream->Read(ptr, size);
|
|||
|
pMemoryStream->Unmap();
|
|||
|
bRet = true;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (bRet)
|
|||
|
{
|
|||
|
// check if dds
|
|||
|
if ( pMemoryStream->GetSize() >= 4 )
|
|||
|
{
|
|||
|
//Read first byte to identify format
|
|||
|
uint32 magic;
|
|||
|
pMemoryStream->Read(&magic,sizeof(uint32) );
|
|||
|
|
|||
|
if ( DDS_MAGIC == magic )
|
|||
|
{
|
|||
|
pMemoryStream->Seek(0, IO::Stream::Begin );
|
|||
|
|
|||
|
uint32 magic;
|
|||
|
pMemoryStream->Read(&magic,sizeof(uint32) );
|
|||
|
|
|||
|
if ( DDS_MAGIC != magic )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Read header in full
|
|||
|
DDSHeader header;
|
|||
|
pMemoryStream->Read(&header, sizeof(DDSHeader));
|
|||
|
|
|||
|
|
|||
|
// Check some sizes
|
|||
|
if (header.size != DDS_HEADER_SIZE)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
|
|||
|
{
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return header.width == header.height;
|
|||
|
}
|
|||
|
|
|||
|
// prepare check other
|
|||
|
pMemoryStream->Seek(0, IO::Stream::Begin );
|
|||
|
}
|
|||
|
|
|||
|
{
|
|||
|
int fileType = FIF_UNKNOWN;
|
|||
|
FIMEMORY* fiMem = FreeImage_OpenMemory( (ubyte*)pMemoryStream->Map(), static_cast<DWORD>(pMemoryStream->GetSize()) );
|
|||
|
if( !fiMem )
|
|||
|
{
|
|||
|
n_warning( "mageResLoader::LoadCommon Can Not Open image Memory\n");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
fileType = FreeImage_GetFileTypeFromMemory(fiMem);
|
|||
|
|
|||
|
|
|||
|
if ( fileType == FIF_UNKNOWN )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
FIBITMAP* fiBitmap = FreeImage_LoadFromMemory( (FREE_IMAGE_FORMAT)fileType, fiMem );
|
|||
|
if (!fiBitmap)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return FreeImage_GetWidth(fiBitmap) == FreeImage_GetHeight(fiBitmap);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
//------------------------------------------------------------------------
|
|||
|
bool ImageResLoader::IsDDS(const Util::String& path)
|
|||
|
{
|
|||
|
if (g_TexDDSCollection.FindIndex(path) != InvalidIndex)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IO::URI uri(path);
|
|||
|
uri.SetScheme("file");
|
|||
|
|
|||
|
GPtr<IO::Stream> pFileStream = IO::FileStream::Create();
|
|||
|
pFileStream->SetAccessMode(IO::Stream::ReadAccess);
|
|||
|
pFileStream->SetURI(uri);
|
|||
|
GPtr<IO::Stream> pMemoryStream = IO::MemoryStream::Create();
|
|||
|
|
|||
|
bool bRet = false;
|
|||
|
|
|||
|
if (pFileStream->Open())
|
|||
|
{
|
|||
|
SizeT size = pFileStream->GetSize();
|
|||
|
|
|||
|
if (size > 0)
|
|||
|
{
|
|||
|
pMemoryStream->SetAccessMode(IO::Stream::ReadWriteAccess);
|
|||
|
if (pMemoryStream->Open())
|
|||
|
{
|
|||
|
pMemoryStream->SetSize(size);
|
|||
|
void* ptr = pMemoryStream->Map();
|
|||
|
pFileStream->Read(ptr, size);
|
|||
|
pMemoryStream->Unmap();
|
|||
|
bRet = true;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (bRet)
|
|||
|
{
|
|||
|
if ( pMemoryStream->GetSize() >= 4 )
|
|||
|
{
|
|||
|
//Read first byte to identify format
|
|||
|
uint32 magic;
|
|||
|
pMemoryStream->Read(&magic,sizeof(uint32) );
|
|||
|
|
|||
|
if ( DDS_MAGIC == magic )
|
|||
|
{
|
|||
|
pMemoryStream->Seek(0, IO::Stream::Begin );
|
|||
|
|
|||
|
uint32 magic;
|
|||
|
pMemoryStream->Read(&magic,sizeof(uint32) );
|
|||
|
|
|||
|
if ( DDS_MAGIC != magic )
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// Read header in full
|
|||
|
DDSHeader header;
|
|||
|
pMemoryStream->Read(&header, sizeof(DDSHeader));
|
|||
|
|
|||
|
|
|||
|
// Check some sizes
|
|||
|
if (header.size != DDS_HEADER_SIZE)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
|
|||
|
{
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
RenderBase::PixelFormat::Code sourceFormat = RenderBase::PixelFormat::InvalidPixelFormat;
|
|||
|
|
|||
|
if (header.pixelFormat.flags & DDPF_FOURCC)
|
|||
|
{
|
|||
|
sourceFormat = DXT_convertFourCCFormat(header.pixelFormat.fourCC);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sourceFormat = DXT_convertPixelFormat(header.pixelFormat.rgbBits,
|
|||
|
header.pixelFormat.redMask, header.pixelFormat.greenMask,
|
|||
|
header.pixelFormat.blueMask,
|
|||
|
header.pixelFormat.flags & DDPF_ALPHAPIXELS ?
|
|||
|
header.pixelFormat.alphaMask : 0);
|
|||
|
}
|
|||
|
|
|||
|
if (sourceFormat == RenderBase::PixelFormat::DXT1 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT2 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT3 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT4 ||
|
|||
|
sourceFormat == RenderBase::PixelFormat::DXT5 )
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// prepare check other
|
|||
|
pMemoryStream->Seek(0, IO::Stream::Begin );
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
}
|