/*==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 3 ds 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 , 3 ds 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 "HeadSpin.h"
# include "max.h"
# include <commdlg.h>
# include "bmmlib.h"
# include "plGImage/plMipmap.h"
# include "hsExceptionStack.h"
# include "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 bool 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 ( bool 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
bool 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 = 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 = new plMipmap ( hBitmap , sigma , bd - > createFlags , bd - > detailDropoffStart ,
bd - > detailDropoffStop , bd - > detailMax , bd - > detailMin ) ;
}
else
{
hMipmap = 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_t 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
plString name ;
char 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 )
name = plString : : Format ( " %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
name = plString : : Format ( " %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 )
name = plString : : Format ( " %s*%x#%d " , temp , bd - > texFlags , clipID ) ;
else
name = plString : : Format ( " %s*%x " , temp , bd - > texFlags ) ;
if ( bd - > invertAlpha )
name + = _TEMP_CONVERT_FROM_LITERAL ( " _inva " ) ;
name + = _TEMP_CONVERT_FROM_LITERAL ( " .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 = 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 , bool 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_t width , uint32_t height , unsigned config , uint8_t numLevels ,
const plString & 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 = new plMipmap ( width , height , config , numLevels ) ;
// Assign key
hsgResMgr : : ResMgr ( ) - > NewKey ( keyName , mip , textureLoc ) ;
// Add to our list
IAddBitmap ( mip ) ;
return mip ;
hsGuardEnd ;
}