ad5cd7b16a
match the genesis editor version 1.3.1.921.
1397 lines
36 KiB
C++
1397 lines
36 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"
|
||
#include "rendersystem/base/GraphicCardCapability.h"
|
||
#include "rendersystem/RenderSystem.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<6C><65>The DevIL And FreeImage All Are Not ThreadSafe<66><65>
|
||
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<><73>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_debuglog("FreeImage version: %s Info: %s \n", FreeImage_GetVersion(), FreeImage_GetCopyrightMessage());
|
||
n_debuglog("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_debuglog( " %s", strType.AsCharPtr() );
|
||
|
||
if ( InvalidIndex == mExtReg.FindIndex( strType ) )
|
||
{
|
||
mExtReg.Add(strType, iType );
|
||
}
|
||
}
|
||
}
|
||
n_debuglog("\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() );
|
||
|
||
#if RENDERDEVICE_D3D9
|
||
// 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 );
|
||
}
|
||
#endif
|
||
|
||
#if RENDERDEVICE_OPENGLES
|
||
const RenderBase::GraphicCardCapability& caps = RenderBase::RenderSystem::Instance()->GetGraphicCardCapability();
|
||
if (caps.mS3TC)
|
||
{
|
||
// 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 );
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
// 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
|
||
|
||
|
||
}
|