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.
701 lines
21 KiB
701 lines
21 KiB
4 years ago
|
/*==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==*/
|
||
|
#include "hsTypes.h"
|
||
|
#include "max.h"
|
||
|
#include <commdlg.h>
|
||
|
#include "bmmlib.h"
|
||
|
|
||
|
#include "../../Plasma/PubUtilLib/plGImage/plMipmap.h"
|
||
|
#include "hsExceptionStack.h"
|
||
|
#include "../../Plasma/PubUtilLib/plGImage/hsCodecManager.h"
|
||
|
|
||
|
#include "plBitmapCreator.h"
|
||
|
|
||
|
#include "../MaxMain/plPluginResManager.h"
|
||
|
#include "../MaxExport/plErrorMsg.h"
|
||
|
#include "../MaxPlasmaMtls/Layers/plStaticEnvLayer.h"
|
||
|
|
||
|
#include "../plGImage/plMipmap.h"
|
||
|
#include "../plGImage/plDynamicTextMap.h"
|
||
|
#include "../plGImage/plCubicEnvironmap.h"
|
||
|
#include "../pnKeyedObject/plKey.h"
|
||
|
#include "../pnKeyedObject/plUoid.h"
|
||
|
#include "../plResMgr/plRegistryHelpers.h"
|
||
|
#include "../plResMgr/plLocalization.h"
|
||
|
#include "../plAgeDescription/plAgeDescription.h"
|
||
|
|
||
|
//// plCommonBitmapLib ///////////////////////////////////////////////////////
|
||
|
// Derived class for our textures, since they all go in a common page
|
||
|
// (namely, "Textures")
|
||
|
|
||
|
#include "../MaxMain/plCommonObjLib.h"
|
||
|
|
||
|
class plCommonBitmapLib : public plCommonObjLib
|
||
|
{
|
||
|
public:
|
||
|
virtual hsBool IsInteresting( const plKey &objectKey )
|
||
|
{
|
||
|
if( objectKey->GetUoid().GetClassType() == plCubicEnvironmap::Index() ||
|
||
|
objectKey->GetUoid().GetClassType() == plMipmap::Index() )
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static plCommonBitmapLib sCommonBitmapLib;
|
||
|
|
||
|
|
||
|
plBitmapCreator::plBitmapCreator()
|
||
|
{
|
||
|
fErrorMsg = nil;
|
||
|
}
|
||
|
plBitmapCreator::~plBitmapCreator()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
plBitmapCreator &plBitmapCreator::Instance()
|
||
|
{
|
||
|
static plBitmapCreator fInstance;
|
||
|
return fInstance;
|
||
|
}
|
||
|
|
||
|
void plBitmapCreator::Init( hsBool save, plErrorMsg *msg )
|
||
|
{
|
||
|
fErrorMsg = msg;
|
||
|
}
|
||
|
|
||
|
void plBitmapCreator::DeInit( void )
|
||
|
{
|
||
|
CleanUpMaps();
|
||
|
}
|
||
|
|
||
|
void plBitmapCreator::CleanUpMaps( void )
|
||
|
{
|
||
|
sCommonBitmapLib.ClearObjectList();
|
||
|
}
|
||
|
|
||
|
void plBitmapCreator::DeleteExportedBitmap( const plKey &constKey )
|
||
|
{
|
||
|
plKey key = constKey;
|
||
|
sCommonBitmapLib.RemoveObjectAndKey( key );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create Bitmap
|
||
|
//
|
||
|
plMipmap *plBitmapCreator::ICreateBitmap(plBitmapData *bd)
|
||
|
{
|
||
|
hsGuardBegin("hsConverterUtils::CreateBitmap");
|
||
|
|
||
|
// Load the bitmap
|
||
|
BitmapInfo bi;
|
||
|
bi.SetName(bd->fileName);
|
||
|
|
||
|
#if 0 // This isn't really an issue since the textures are packed -Colin
|
||
|
const int kMaxFileNameLength = 30;
|
||
|
if (strlen(bi.Filename()) > kMaxFileNameLength)
|
||
|
{
|
||
|
// Allow to continue, But make it painful
|
||
|
char errStr[256];
|
||
|
sprintf(errStr, "File name longer than %d, won't burn to CD (%s)", kMaxFileNameLength, bi.Filename());//bitmapTex->GetName());
|
||
|
MessageBox(GetActiveWindow(), errStr, bd->fileName, MB_OK|MB_ICONEXCLAMATION);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
hsBool notMipped = (bd->texFlags & plMipmap::kForceOneMipLevel) != 0;
|
||
|
float sigma = bd->sig;
|
||
|
|
||
|
// Load the bitmap
|
||
|
Bitmap *bm = TheManager->Load(&bi);
|
||
|
if (!bm)
|
||
|
{
|
||
|
// FIXME
|
||
|
/*
|
||
|
if (fErrorMsg->Set(!(fWarned & kWarnedNoMoreBitmapLoadErr),
|
||
|
"Error loading bitmap", pathName).CheckAskOrCancel())
|
||
|
{
|
||
|
fWarned |= kWarnedNoMoreBitmapLoadErr;
|
||
|
}
|
||
|
*/
|
||
|
return nil;
|
||
|
}
|
||
|
BitmapStorage *storage = bm->Storage();
|
||
|
BitmapInfo *bInfo = &storage->bi;
|
||
|
|
||
|
ICheckOutBitmap(bInfo, bm, bd->fileName);
|
||
|
|
||
|
//
|
||
|
// Create a plMipmap
|
||
|
//
|
||
|
plMipmap *hBitmap = TRACKED_NEW plMipmap;
|
||
|
if( (bm->Width() ^ (bm->Width() & -bm->Width()))
|
||
|
||(bm->Height() ^ (bm->Height() & -bm->Height())) )
|
||
|
{
|
||
|
IResampBitmap(bm, *hBitmap);
|
||
|
}
|
||
|
else if( ((bm->Width() >> 3) > bm->Height())||((bm->Height() >> 3) > bm->Width()) )
|
||
|
{
|
||
|
IResampBitmap(bm, *hBitmap);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ICopyBitmap(bm, *hBitmap);
|
||
|
}
|
||
|
bm->DeleteThis();
|
||
|
|
||
|
if( bd->invertAlpha )
|
||
|
IInvertAlpha(*hBitmap);
|
||
|
|
||
|
// Do it
|
||
|
plMipmap *hMipmap = nil;
|
||
|
if (sigma > 0.f)
|
||
|
{
|
||
|
hMipmap = TRACKED_NEW plMipmap(hBitmap, sigma, bd->createFlags, bd->detailDropoffStart,
|
||
|
bd->detailDropoffStop, bd->detailMax, bd->detailMin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hMipmap = TRACKED_NEW plMipmap(hBitmap, -1.f, bd->createFlags, bd->detailDropoffStart,
|
||
|
bd->detailDropoffStop, bd->detailMax, bd->detailMin);
|
||
|
}
|
||
|
delete hBitmap;
|
||
|
|
||
|
/// Clamp the border if we're using clamping
|
||
|
if( bd->clampFlags != 0 )
|
||
|
{
|
||
|
hMipmap->EnsureKonstantBorder( ( bd->clampFlags & plBitmapData::kClampU ) ? true : false,
|
||
|
( bd->clampFlags & plBitmapData::kClampV ) ? true : false );
|
||
|
}
|
||
|
|
||
|
/// Cut this down to whatever size we were told to :)
|
||
|
if( bd->maxDimension != 0 )
|
||
|
hMipmap->ClipToMaxSize( bd->maxDimension );
|
||
|
|
||
|
if( notMipped )
|
||
|
{
|
||
|
// Done AFTER ClipToMaxSize() so we still get the export size specified
|
||
|
hMipmap->RemoveMipping();
|
||
|
}
|
||
|
|
||
|
hBitmap = hMipmap;
|
||
|
|
||
|
UInt32 flagsToSet = 0;
|
||
|
|
||
|
if( bd->texFlags & plMipmap::kNoMaxSize )
|
||
|
flagsToSet |= plMipmap::kNoMaxSize;
|
||
|
if( bd->texFlags & plMipmap::kHalfSize )
|
||
|
flagsToSet |= plMipmap::kHalfSize;
|
||
|
if( bd->texFlags & plMipmap::kDontThrowAwayImage )
|
||
|
flagsToSet |= plMipmap::kDontThrowAwayImage;
|
||
|
|
||
|
hBitmap->SetFlags( hBitmap->GetFlags() | flagsToSet );
|
||
|
if (bd->useJPEG)
|
||
|
hBitmap->fCompressionType = plMipmap::kJPEGCompression;
|
||
|
|
||
|
// FIXME
|
||
|
if (/*fSave &&*/ !(bd->texFlags & plMipmap::kForceNonCompressed) && !bd->useJPEG)
|
||
|
{
|
||
|
// Are we on? Check Plasma Util panel
|
||
|
// SwitchUtil *pu = (SwitchUtil *)CreateInstance(UTILITY_CLASS_ID, PlasmaUtilClassID);
|
||
|
// if (!pu || pu->TextureCompressionEnabled())
|
||
|
{
|
||
|
plMipmap *compressed = hsCodecManager::Instance().CreateCompressedMipmap(plMipmap::kDirectXCompression, hBitmap);
|
||
|
// hsDXTSoftwareCodec::Instance().CreateCompressedBitmap(hBitmap);
|
||
|
// hsDXTDirectXCodec::Instance().CreateCompressedBitmap(hBitmap);
|
||
|
|
||
|
if (compressed)
|
||
|
{
|
||
|
delete hBitmap;
|
||
|
hBitmap = compressed;
|
||
|
hBitmap->SetFlags( hBitmap->GetFlags() | flagsToSet );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hBitmap;
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Verify that bitmap is the correct type/size
|
||
|
//
|
||
|
void plBitmapCreator::ICheckOutBitmap(BitmapInfo* bInfo, Bitmap* bm, const char *fileName)
|
||
|
{
|
||
|
hsGuardBegin("hsConverterUtils::ICheckOutBitmap");
|
||
|
|
||
|
// Check out bitmap
|
||
|
if (bm->Flags() & MAP_FLIPPED)
|
||
|
MessageBox(GetActiveWindow(), "Bitmap is flipped horizontally", fileName, MB_OK);
|
||
|
if (bm->Flags() & MAP_INVERTED)
|
||
|
MessageBox(GetActiveWindow(), "Bitmap is inverted vertically", fileName, MB_OK);
|
||
|
|
||
|
if (bInfo->Flags() & MAP_FLIPPED)
|
||
|
MessageBox(GetActiveWindow(), "BI:Bitmap is flipped horizontally", fileName, MB_OK);
|
||
|
if (bInfo->Flags() & MAP_INVERTED)
|
||
|
MessageBox(GetActiveWindow(), "BI:Bitmap is inverted vertically", fileName, MB_OK);
|
||
|
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
int plBitmapCreator::IResampBitmap(Bitmap *bm, plMipmap &hBitmap)
|
||
|
{
|
||
|
hsGuardBegin("hsConverterUtils::IResampBitmap");
|
||
|
|
||
|
BitmapStorage *storage = bm->Storage();
|
||
|
BitmapInfo *bInfo = &storage->bi;
|
||
|
|
||
|
int dbgW = bm->Width(), dbgH = bm->Height();
|
||
|
int it;
|
||
|
for( it = 1; it <= bm->Width(); it <<= 1 );
|
||
|
it >>= 1;
|
||
|
hBitmap.fWidth = it;
|
||
|
for( it = 1; it <= bm->Height(); it <<= 1 );
|
||
|
it >>= 1;
|
||
|
hBitmap.fHeight = it;
|
||
|
if( (hBitmap.fHeight >> 3) > hBitmap.fWidth )
|
||
|
hBitmap.fHeight = hBitmap.fWidth << 3;
|
||
|
else
|
||
|
if( (hBitmap.fWidth >> 3) > hBitmap.fHeight )
|
||
|
hBitmap.fWidth = hBitmap.fHeight << 3;
|
||
|
|
||
|
hBitmap.fPixelSize = 32;
|
||
|
hBitmap.fRowBytes = hBitmap.fWidth * hBitmap.fPixelSize >> 3;
|
||
|
hBitmap.fNumLevels = 1;
|
||
|
|
||
|
hBitmap.fImage = HSMemory::New(hBitmap.fRowBytes * hBitmap.fHeight);
|
||
|
|
||
|
#ifdef COLOR_BLACK_WHITE
|
||
|
hBitmap.fFlags |= plMipmap::kColorWhite | plMipmap::kColorBlack;
|
||
|
#endif // COLOR_BLACK_WHITE
|
||
|
hBitmap.fFlags &= ~( plMipmap::kAlphaBitFlag | plMipmap::kAlphaChannelFlag );
|
||
|
|
||
|
int y,x;
|
||
|
float scaleY, scaleX;
|
||
|
hsRGBAColor32 *dstColor;
|
||
|
dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||
|
|
||
|
scaleX = ((float)bm->Width())/(float)hBitmap.fWidth;
|
||
|
scaleY = ((float)bm->Height())/(float)hBitmap.fHeight;
|
||
|
for (y = 0; y < hBitmap.fHeight; y++)
|
||
|
{
|
||
|
for (x = 0; x < hBitmap.fWidth; x++)
|
||
|
{
|
||
|
BMM_Color_64 c64_00, c64_01, c64_10, c64_11;
|
||
|
int ix, iy;
|
||
|
float fracX, fracY;
|
||
|
float t;
|
||
|
t = x * scaleX;
|
||
|
ix = (int)t;
|
||
|
fracX = t-ix;
|
||
|
t = y * scaleY;
|
||
|
iy = (int)t;
|
||
|
fracY = t-iy;
|
||
|
|
||
|
int ret = storage->GetPixels(ix,iy,1,&c64_00);
|
||
|
// FIXME
|
||
|
// fErrorMsg->Set(ret == 0, "ResampBitmap", "Failure getting pixels %dX%d", x, y).Check();
|
||
|
ret = storage->GetPixels(ix+1,iy,1,&c64_10);
|
||
|
ret = storage->GetPixels(ix,iy+1,1,&c64_01);
|
||
|
ret = storage->GetPixels(ix+1,iy+1,1,&c64_11);
|
||
|
|
||
|
dstColor->r = (unsigned char)(255.0 / 65535.0
|
||
|
* ( c64_00.r * (1.f - fracX) * (1.f - fracY)
|
||
|
+ c64_10.r * ( fracX) * (1.f - fracY)
|
||
|
+ c64_01.r * (1.f - fracX) * ( fracY)
|
||
|
+ c64_11.r * ( fracX) * ( fracY) ));
|
||
|
dstColor->g = (unsigned char)(255.0 / 65535.0
|
||
|
* ( c64_00.g * (1.f - fracX) * (1.f - fracY)
|
||
|
+ c64_10.g * ( fracX) * (1.f - fracY)
|
||
|
+ c64_01.g * (1.f - fracX) * ( fracY)
|
||
|
+ c64_11.g * ( fracX) * ( fracY) ));
|
||
|
dstColor->b = (unsigned char)(255.0 / 65535.0
|
||
|
* ( c64_00.b * (1.f - fracX) * (1.f - fracY)
|
||
|
+ c64_10.b * ( fracX) * (1.f - fracY)
|
||
|
+ c64_01.b * (1.f - fracX) * ( fracY)
|
||
|
+ c64_11.b * ( fracX) * ( fracY) ));
|
||
|
dstColor->a = (unsigned char)(255.0 / 65535.0
|
||
|
* ( c64_00.a * (1.f - fracX) * (1.f - fracY)
|
||
|
+ c64_10.a * ( fracX) * (1.f - fracY)
|
||
|
+ c64_01.a * (1.f - fracX) * ( fracY)
|
||
|
+ c64_11.a * ( fracX) * ( fracY) ));
|
||
|
|
||
|
|
||
|
#ifdef COLOR_BLACK_WHITE
|
||
|
if( dstColor->r | dstColor->g | dstColor->b )
|
||
|
hBitmap.fFlags &= ~plMipmap::kColorBlack;
|
||
|
if( ~(dstColor->r & dstColor->g & dstColor->b) )
|
||
|
hBitmap.fFlags &= ~plMipmap::kColorWhite;
|
||
|
#endif // COLOR_BLACK_WHITE
|
||
|
|
||
|
if( dstColor->a < 255 )
|
||
|
{
|
||
|
hBitmap.fFlags |= plMipmap::kAlphaBitFlag;
|
||
|
if( dstColor->a > 0 )
|
||
|
hBitmap.fFlags |= plMipmap::kAlphaChannelFlag;
|
||
|
}
|
||
|
dstColor++;
|
||
|
}
|
||
|
}
|
||
|
if( hBitmap.fFlags & plMipmap::kAlphaChannelFlag )
|
||
|
hBitmap.fFlags &= ~plMipmap::kAlphaBitFlag;
|
||
|
|
||
|
return 0;
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
int plBitmapCreator::ICopyBitmap(Bitmap *bm, plMipmap &hBitmap)
|
||
|
{
|
||
|
hsGuardBegin("hsConverterUtils::ICopyBitmap");
|
||
|
|
||
|
BitmapStorage *storage = bm->Storage();
|
||
|
BitmapInfo *bInfo = &storage->bi;
|
||
|
|
||
|
hBitmap.fWidth = bm->Width();
|
||
|
hBitmap.fHeight = bm->Height();
|
||
|
hBitmap.fPixelSize = 32;
|
||
|
hBitmap.fRowBytes = bm->Width()*hBitmap.fPixelSize/8;
|
||
|
hBitmap.fNumLevels = 1;
|
||
|
|
||
|
hBitmap.fImage = HSMemory::New(hBitmap.fRowBytes * hBitmap.fHeight);
|
||
|
|
||
|
#ifdef COLOR_BLACK_WHITE
|
||
|
hBitmap.fFlags |= plMipmap::kColorWhite | plMipmap::kColorBlack;
|
||
|
#endif // COLOR_BLACK_WHITE
|
||
|
hBitmap.fFlags &= ~( plMipmap::kAlphaBitFlag | plMipmap::kAlphaChannelFlag );
|
||
|
|
||
|
int y,x;
|
||
|
hsRGBAColor32 *dstColor;
|
||
|
dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||
|
|
||
|
for (y = 0; y < hBitmap.fHeight; y++)
|
||
|
{
|
||
|
for (x = 0; x < hBitmap.fWidth; x++)
|
||
|
{
|
||
|
BMM_Color_64 c64;
|
||
|
int ret = storage->GetPixels(x,y,1,&c64);
|
||
|
// FIXME
|
||
|
// fErrorMsg->Set(ret == 0, "CopyBitmap", "Failure getting pixels %dX%d", x, y).Check();
|
||
|
|
||
|
// Convert from 16 bits to 8 bits
|
||
|
dstColor->r = (char)(255.0*c64.r/65535.0);
|
||
|
dstColor->g = (char)(255.0*c64.g/65535.0);
|
||
|
dstColor->b = (char)(255.0*c64.b/65535.0);
|
||
|
dstColor->a = (char)(255.0*c64.a/65535.0);
|
||
|
|
||
|
#ifdef COLOR_BLACK_WHITE
|
||
|
if( dstColor->r | dstColor->g | dstColor->b )
|
||
|
hBitmap.fFlags &= ~plMipmap::kColorBlack;
|
||
|
if( ~(dstColor->r & dstColor->g & dstColor->b) )
|
||
|
hBitmap.fFlags &= ~plMipmap::kColorWhite;
|
||
|
#endif // COLOR_BLACK_WHITE
|
||
|
|
||
|
if( dstColor->a < 255 )
|
||
|
{
|
||
|
hBitmap.fFlags |= plMipmap::kAlphaBitFlag;
|
||
|
if( dstColor->a > 0 )
|
||
|
hBitmap.fFlags |= plMipmap::kAlphaChannelFlag;
|
||
|
}
|
||
|
dstColor++;
|
||
|
}
|
||
|
}
|
||
|
if( hBitmap.fFlags & plMipmap::kAlphaChannelFlag )
|
||
|
hBitmap.fFlags &= ~plMipmap::kAlphaBitFlag;
|
||
|
|
||
|
return 0;
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
int plBitmapCreator::IInvertAlpha(plMipmap& hBitmap)
|
||
|
{
|
||
|
hsGuardBegin("hsConverterUtils::ICopyBitmap");
|
||
|
|
||
|
hsAssert(hBitmap.fPixelSize == 32, "Only RGBA32 implemented");
|
||
|
if( hBitmap.fPixelSize != 32 )
|
||
|
return -1;
|
||
|
|
||
|
hsRGBAColor32* dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||
|
int n = hBitmap.GetWidth() * hBitmap.GetHeight();
|
||
|
int i;
|
||
|
for( i = 0; i < n; i++ )
|
||
|
{
|
||
|
dstColor->a = 255 - dstColor->a;
|
||
|
dstColor++;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
plBitmap *plBitmapCreator::CreateTexture(plBitmapData *bd, const plLocation &loc, int clipID)
|
||
|
{
|
||
|
plBitmap* bm = ICreateTexture(bd, loc, clipID);
|
||
|
|
||
|
for (int i = 0; i < plLocalization::GetNumLocales(); i++)
|
||
|
{
|
||
|
char localName[MAX_PATH];
|
||
|
if (plLocalization::ExportGetLocalized(bd->fileName, i, localName))
|
||
|
{
|
||
|
const char* oldName = bd->fileName;
|
||
|
bd->fileName = localName;
|
||
|
ICreateTexture(bd, loc, clipID);
|
||
|
bd->fileName = oldName;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bm;
|
||
|
}
|
||
|
|
||
|
//// ICreateTexture ////////////////////////////////////////////////////////////
|
||
|
// Plasma texture creator. Pass it a completed bitmapdata structure and it
|
||
|
// returns a registered texture pointer, or nil if something goes wrong.
|
||
|
//
|
||
|
// 9.14.2001 mcn - clipID added to uniquely identify mipmaps that have been
|
||
|
// rescaled differently (approximately represents how many powers of 2 it was
|
||
|
// scaled down from the original source).
|
||
|
//
|
||
|
// 3.29.2002 mcn - Moved to plBitmapCreator, where it really belongs, and
|
||
|
// added code to handle tracking/cleaning up all materials that are exported.
|
||
|
|
||
|
plBitmap *plBitmapCreator::ICreateTexture( plBitmapData *bd, const plLocation &loc, int clipID )
|
||
|
{
|
||
|
hsGuardBegin( "plBitmapCreator::CreateTexture" );
|
||
|
|
||
|
const plLocation &textureLoc = plPluginResManager::ResMgr()->GetCommonPage( loc, plAgeDescription::kTextures );
|
||
|
|
||
|
if( !bd )
|
||
|
{
|
||
|
fErrorMsg->Set( true, "Bitmap Error", "No bitmap data" ).Show();
|
||
|
fErrorMsg->Set();
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
if( bd->fileName == nil || bd->fileName[ 0 ] == 0 )
|
||
|
{
|
||
|
fErrorMsg->Set( true, "Bitmap Error", "Material texture has null bitmap name." ).Show();
|
||
|
fErrorMsg->Set();
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
// Get and mangle key name
|
||
|
char name[ 256 ], temp[ 256 ];
|
||
|
_splitpath(bd->fileName, NULL, NULL, temp, NULL);
|
||
|
|
||
|
// Somehow, sometimes, we get the same file in with different cases. So we need to force the
|
||
|
// case identical all the time, else the patching process for dat files will think they're
|
||
|
// "different" when they're really not
|
||
|
strlwr( temp );
|
||
|
|
||
|
/// Mangle name for detail textures, so we don't end up overwriting settings elsewhere
|
||
|
if( bd->createFlags & plMipmap::kCreateDetailMask )
|
||
|
{
|
||
|
// Mangle of the form: name@dropStart&dropStop&max&min
|
||
|
if( clipID != -1 )
|
||
|
sprintf( name, "%s*%x#%d@%s&%3.2f&%3.2f&%3.2f&%3.2f", temp, bd->texFlags, clipID,
|
||
|
bd->createFlags & plMipmap::kCreateDetailAlpha ? "al" : ( bd->createFlags & plMipmap::kCreateDetailAdd ? "ad" : "mu" ),
|
||
|
bd->detailDropoffStart, bd->detailDropoffStop, bd->detailMax, bd->detailMin );
|
||
|
else
|
||
|
sprintf( name, "%s*%x@%s&%3.2f&%3.2f&%3.2f&%3.2f", temp, bd->texFlags,
|
||
|
bd->createFlags & plMipmap::kCreateDetailAlpha ? "al" : ( bd->createFlags == plMipmap::kCreateDetailAdd ? "ad" : "mu" ),
|
||
|
bd->detailDropoffStart, bd->detailDropoffStop, bd->detailMax, bd->detailMin );
|
||
|
}
|
||
|
else if( clipID != -1 )
|
||
|
sprintf( name, "%s*%x#%d", temp, bd->texFlags, clipID );
|
||
|
else
|
||
|
sprintf( name, "%s*%x", temp, bd->texFlags );
|
||
|
if( bd->invertAlpha )
|
||
|
strcat( name, "_inva" );
|
||
|
strcat( name, ".hsm" );
|
||
|
|
||
|
|
||
|
// Has this texture been used before?
|
||
|
plKey key;
|
||
|
|
||
|
plBitmap *texture = plBitmap::ConvertNoRef( sCommonBitmapLib.FindObject( name, ( bd->isStaticCubicEnvMap ) ? plCubicEnvironmap::Index() : plMipmap::Index() ) );
|
||
|
//hsAssert( texture == nil || texture->GetKey()->GetUoid().GetLocation() == textureLoc, "Somehow our texture objectLib has a texture not in the right page? Should be harmless tho..." );
|
||
|
|
||
|
// Texture reuse optimization
|
||
|
if( texture )
|
||
|
{
|
||
|
WIN32_FILE_ATTRIBUTE_DATA fileAttrib;
|
||
|
GetFileAttributesEx(bd->fileName, GetFileExInfoStandard, &fileAttrib);
|
||
|
FILETIME &fileTime = fileAttrib.ftLastWriteTime;
|
||
|
|
||
|
// If this texture has been modified since the last export, delete the old version but reuse the key
|
||
|
if (!texture->IsSameModifiedTime(fileTime.dwLowDateTime, fileTime.dwHighDateTime))
|
||
|
{
|
||
|
DeleteExportedBitmap( texture->GetKey() );
|
||
|
texture = nil;
|
||
|
key = nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( texture )
|
||
|
{
|
||
|
// If it's in the registry, great, use it.
|
||
|
if( bd->texFlags & plMipmap::kNoMaxSize )
|
||
|
texture->SetFlags( texture->GetFlags() | plMipmap::kNoMaxSize );
|
||
|
|
||
|
if( bd->texFlags & plMipmap::kHalfSize )
|
||
|
texture->SetFlags( texture->GetFlags() | plMipmap::kHalfSize );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If it hasn't been used before, make a new texture
|
||
|
if( bd->isStaticCubicEnvMap )
|
||
|
{
|
||
|
plCubicEnvironmap *cubic = TRACKED_NEW plCubicEnvironmap;
|
||
|
|
||
|
plMipmap *face;
|
||
|
|
||
|
/// Build and set the faces
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kTopFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kTopFace );
|
||
|
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kBottomFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kBottomFace );
|
||
|
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kLeftFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kLeftFace );
|
||
|
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kRightFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kRightFace );
|
||
|
|
||
|
/// NOTE: For whatever reason, MAX decided that the front and back faces should be'
|
||
|
/// switched, literally. It's as if the cube for the cube map starts at the back face
|
||
|
/// and then wraps around, instead of starting at the front face. Since we do things
|
||
|
/// the RIGHT way (or rather, the front way :) on client-side, we need to flip the
|
||
|
/// two here. If you convert this to the real MAX UI, make sure the faces are still
|
||
|
/// flipped!!!!!!!!
|
||
|
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kBackFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kFrontFace );
|
||
|
|
||
|
bd->fileName = bd->faceNames[ plStaticEnvLayer::kFrontFace ];
|
||
|
face = ICreateBitmap( bd );
|
||
|
if( face == nil ) return nil;
|
||
|
cubic->CopyToFace( face, plCubicEnvironmap::kBackFace );
|
||
|
|
||
|
|
||
|
key = hsgResMgr::ResMgr()->NewKey( name, cubic, textureLoc );
|
||
|
|
||
|
texture = (plBitmap *)cubic;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
plMipmap *mipmap = ICreateBitmap(bd);
|
||
|
if (!mipmap)
|
||
|
return nil;
|
||
|
|
||
|
key = hsgResMgr::ResMgr()->NewKey( name, mipmap, textureLoc );
|
||
|
|
||
|
texture = (plBitmap *)mipmap;
|
||
|
}
|
||
|
|
||
|
// Texture reuse optimization
|
||
|
WIN32_FILE_ATTRIBUTE_DATA fileAttrib;
|
||
|
GetFileAttributesEx(bd->fileName, GetFileExInfoStandard, &fileAttrib);
|
||
|
FILETIME &fileTime = fileAttrib.ftLastWriteTime;
|
||
|
texture->SetModifiedTime(fileTime.dwLowDateTime, fileTime.dwHighDateTime);
|
||
|
|
||
|
// Add to our list of created textures and ref, since we have a hold of them
|
||
|
IAddBitmap( texture );
|
||
|
}
|
||
|
|
||
|
return texture;
|
||
|
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
//// IAddBitmap ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plBitmapCreator::IAddBitmap( plBitmap *bitmap, hsBool dontRef )
|
||
|
{
|
||
|
sCommonBitmapLib.AddObject( bitmap );
|
||
|
}
|
||
|
|
||
|
//// CreateBlankMipmap ////////////////////////////////////////////////////////
|
||
|
// Simple mipmap creator, but importantly, it also adds the mipmap to the list
|
||
|
// of "converted" maps to clean up at the end of export.
|
||
|
|
||
|
plMipmap *plBitmapCreator::CreateBlankMipmap( UInt32 width, UInt32 height, unsigned config, UInt8 numLevels,
|
||
|
const char *keyName, const plLocation &keyLocation )
|
||
|
{
|
||
|
hsGuardBegin( "plBitmapCreator::CreateBlankMipmap" );
|
||
|
|
||
|
// Get our real location
|
||
|
const plLocation &textureLoc = plPluginResManager::ResMgr()->GetCommonPage( keyLocation, plAgeDescription::kTextures );
|
||
|
|
||
|
// Is it already created?
|
||
|
plKey key = hsgResMgr::ResMgr()->FindKey( plUoid( textureLoc, plMipmap::Index(), keyName ) );
|
||
|
if( key != nil )
|
||
|
return plMipmap::ConvertNoRef( key->GetObjectPtr() );
|
||
|
|
||
|
// Create
|
||
|
plMipmap *mip = TRACKED_NEW plMipmap( width, height, config, numLevels );
|
||
|
|
||
|
// Assign key
|
||
|
hsgResMgr::ResMgr()->NewKey( keyName, mip, textureLoc );
|
||
|
|
||
|
// Add to our list
|
||
|
IAddBitmap( mip );
|
||
|
|
||
|
return mip;
|
||
|
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|