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.
470 lines
15 KiB
470 lines
15 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
/////////////////////////////////////////////////////////////////////////////// |
|
// // |
|
// plPlasmaMAXLayer - MAX Layer type that is the basis for all Plasma layer // |
|
// types // |
|
// Note: All export-side functions are contained in // |
|
// MaxConvert/plPlasmaMaxLayerExport.cpp, for linking purposes. // |
|
// Cyan, Inc. // |
|
// // |
|
//// Version History ////////////////////////////////////////////////////////// |
|
// // |
|
// 1.13.2002 mcn - Created. // |
|
// // |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include "HeadSpin.h" |
|
#include "plPlasmaMAXLayer.h" |
|
|
|
#include "stdmat.h" |
|
#include "istdplug.h" |
|
#include "iparamb2.h" |
|
#include "iparamm2.h" |
|
#include "../resource.h" |
|
#ifdef MAXASS_AVAILABLE |
|
#include "../../AssetMan/PublicInterface/MaxAssInterface.h" |
|
#endif |
|
|
|
|
|
#include "pnKeyedObject/hsKeyedObject.h" |
|
#include "pnMessage/plRefMsg.h" |
|
#include "plSurface/plLayerInterface.h" |
|
#include "hsResMgr.h" |
|
|
|
|
|
//// Derived Types List /////////////////////////////////////////////////////// |
|
// If you create a new Plasma layer type, add a define for the class ID in |
|
// the header and add it to the list here. |
|
|
|
const Class_ID plPlasmaMAXLayer::fDerivedTypes[] = |
|
{ |
|
LAYER_TEX_CLASS_ID, |
|
STATIC_ENV_LAYER_CLASS_ID, |
|
DYNAMIC_ENV_LAYER_CLASS_ID, |
|
DYN_TEXT_LAYER_CLASS_ID, |
|
ANGLE_ATTEN_LAYER_CLASS_ID, |
|
MAX_CAMERA_LAYER_CLASS_ID |
|
}; |
|
|
|
//// Constructor/Destructor /////////////////////////////////////////////////// |
|
|
|
plPlasmaMAXLayer::plPlasmaMAXLayer() |
|
{ |
|
fConversionTargets = nil; |
|
} |
|
|
|
plPlasmaMAXLayer::~plPlasmaMAXLayer() |
|
{ |
|
} |
|
|
|
//// GetPlasmaMAXLayer //////////////////////////////////////////////////////// |
|
// Static function that checks the classID of the given texMap and, if it's a |
|
// valid Plasma MAX Layer, returns a pointer to such. |
|
|
|
plPlasmaMAXLayer *plPlasmaMAXLayer::GetPlasmaMAXLayer( Texmap *map ) |
|
{ |
|
if (!map) |
|
return NULL; |
|
|
|
int i; |
|
|
|
|
|
for( i = 0; i < sizeof( fDerivedTypes ) / sizeof( Class_ID ); i++ ) |
|
{ |
|
if( map->ClassID() == fDerivedTypes[ i ] ) |
|
return (plPlasmaMAXLayer *)map; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Conversion Targets /////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// plLayerTargetContainer /////////////////////////////////////////////////// |
|
// This is a helper class that just contains a passive ref list of the layers |
|
// that are our conversion targets at export time. See, it's possible that a |
|
// layer gets converted, added to the target list, then destroyed as the |
|
// parent material is suddenly thrown away. In order to avoid our pointers |
|
// from being trashed (or keeping active refs on the layers when they're not |
|
// actually used), we have a small helper class that just keep passive refs, |
|
// so when one of them goes away, we get a notify about it. |
|
|
|
class plLayerTargetContainer : public hsKeyedObject |
|
{ |
|
static uint32_t fKeyCount; |
|
|
|
public: |
|
hsTArray<plLayerInterface *> fLayers; |
|
|
|
virtual bool MsgReceive( plMessage *msg ) |
|
{ |
|
plGenRefMsg *ref = plGenRefMsg::ConvertNoRef( msg ); |
|
if( ref != nil ) |
|
{ |
|
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) |
|
fLayers[ ref->fWhich ] = plLayerInterface::ConvertNoRef( ref->GetRef() ); |
|
else |
|
fLayers[ ref->fWhich ] = nil; |
|
} |
|
|
|
return hsKeyedObject::MsgReceive( msg ); |
|
} |
|
|
|
plLayerTargetContainer() |
|
{ |
|
plString str = plString::Format( "plLayerTargetContainer-%d", fKeyCount++ ); |
|
hsgResMgr::ResMgr()->NewKey( str, this, plLocation::kGlobalFixedLoc ); |
|
} |
|
}; |
|
|
|
uint32_t plLayerTargetContainer::fKeyCount = 0; |
|
|
|
|
|
void plPlasmaMAXLayer::IAddConversionTarget( plLayerInterface *target ) |
|
{ |
|
if( fConversionTargets == nil ) |
|
{ |
|
// Create us a new container |
|
fConversionTargets = new plLayerTargetContainer; |
|
fConversionTargets->GetKey()->RefObject(); |
|
} |
|
|
|
fConversionTargets->fLayers.Append( target ); |
|
hsgResMgr::ResMgr()->AddViaNotify( target->GetKey(), |
|
new plGenRefMsg( fConversionTargets->GetKey(), plRefMsg::kOnCreate, |
|
fConversionTargets->fLayers.GetCount() - 1, 0 ), |
|
plRefFlags::kPassiveRef ); |
|
} |
|
|
|
void plPlasmaMAXLayer::IClearConversionTargets( void ) |
|
{ |
|
if( fConversionTargets != nil ) |
|
{ |
|
fConversionTargets->GetKey()->UnRefObject(); |
|
fConversionTargets = nil; |
|
} |
|
} |
|
|
|
int plPlasmaMAXLayer::GetNumConversionTargets( void ) |
|
{ |
|
if( fConversionTargets == nil ) |
|
return 0; |
|
|
|
|
|
int i, count = 0; |
|
for( i = 0; i < fConversionTargets->fLayers.GetCount(); i++ ) |
|
{ |
|
if( fConversionTargets->fLayers[ i ] != nil ) |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
plLayerInterface *plPlasmaMAXLayer::GetConversionTarget( int index ) |
|
{ |
|
if( fConversionTargets == nil ) |
|
return nil; |
|
|
|
int i; |
|
for( i = 0; i < fConversionTargets->fLayers.GetCount(); i++ ) |
|
{ |
|
if( fConversionTargets->fLayers[ i ] != nil ) |
|
{ |
|
if( index == 0 ) |
|
return fConversionTargets->fLayers[ i ]; |
|
index--; |
|
} |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Asset Management, and textures /////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
#ifdef MAXASS_AVAILABLE |
|
void plPlasmaMAXLayer::SetBitmapAssetId(jvUniqueId& assetId, int index /* = 0 */) |
|
{ |
|
PBBitmap *pbbm = GetPBBitmap(index); |
|
if (pbbm && GetMaxAssInterface()) |
|
{ |
|
char buf[20]; |
|
GetMaxAssInterface()->UniqueIdToString(assetId, buf); |
|
pbbm->bi.SetDevice(buf); |
|
} |
|
} |
|
|
|
void plPlasmaMAXLayer::GetBitmapAssetId(jvUniqueId& assetId, int index /* = 0 */) |
|
{ |
|
PBBitmap *pbbm = GetPBBitmap(index); |
|
if (pbbm && GetMaxAssInterface()) |
|
assetId = GetMaxAssInterface()->StringToUniqueId(pbbm->bi.Device()); |
|
else |
|
assetId.SetEmpty(); |
|
} |
|
#endif |
|
|
|
void plPlasmaMAXLayer::SetBitmap(BitmapInfo *bi, int index) |
|
{ |
|
#ifdef MAXASS_AVAILABLE |
|
jvUniqueId targetAssetId; |
|
GetBitmapAssetId(targetAssetId, index); |
|
#endif |
|
|
|
Bitmap *BM = GetMaxBitmap(index); |
|
if (BM) |
|
{ |
|
BM->DeleteThis(); |
|
BM = NULL; |
|
} |
|
|
|
if (bi) |
|
{ |
|
#ifdef MAXASS_AVAILABLE |
|
if (!targetAssetId.IsEmpty()) |
|
{ |
|
// If this texture has an assetId, we will check the |
|
// asset database and make sure we have the latest version |
|
// of the texture file before loading it |
|
MaxAssInterface* assInterface = GetMaxAssInterface(); |
|
if (assInterface) |
|
{ |
|
char buf[20]; |
|
assInterface->UniqueIdToString(targetAssetId, buf); |
|
bi->SetDevice(buf); |
|
|
|
const char* filename = bi->Name(); |
|
// Download the latest version and retrieve the filename |
|
char newfilename[MAX_PATH]; |
|
if (assInterface->GetLatestVersionFile(targetAssetId, newfilename, sizeof(newfilename))) |
|
{ |
|
// If the filename has changed, we have to reset the bitmap in the ParamBlock |
|
if(stricmp(filename, newfilename) != 0) |
|
bi->SetName(newfilename); |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
BMMRES result; |
|
BM = TheManager->Load(bi, &result); |
|
if (result == BMMRES_SUCCESS) |
|
ISetMaxBitmap(BM, index); |
|
else |
|
ISetMaxBitmap(NULL, index); |
|
|
|
// The load may have failed, but we still want to set the paramblock. We |
|
// don't want to modify the layer if we're just missing the file. |
|
PBBitmap pbBitmap(*bi); |
|
ISetPBBitmap(&pbBitmap, index); |
|
} |
|
else |
|
{ |
|
ISetMaxBitmap(NULL, index); |
|
ISetPBBitmap(NULL, index); |
|
} |
|
|
|
/* |
|
Bitmap *BM = GetMaxBitmap(index); |
|
|
|
if (BM) |
|
{ |
|
BM->DeleteThis(); |
|
BM = NULL; |
|
} |
|
|
|
if (filename) |
|
{ |
|
BitmapInfo bi; |
|
bi.SetName(filename); |
|
|
|
// If this texture has an assetId, get the latest version from AssetMan before loading it |
|
if (assetId && !assetId->IsEmpty()) |
|
{ |
|
MaxAssInterface* maxAssInterface = GetMaxAssInterface(); |
|
if (maxAssInterface) |
|
{ |
|
// Download the latest version and retrieve the filename |
|
char newfilename[MAX_PATH]; |
|
if (maxAssInterface->GetLatestVersionFile(*assetId, newfilename, sizeof(newfilename))) |
|
{ |
|
// If the filename has changed, we have to reset the bitmap in the ParamBlock |
|
if (stricmp(filename, newfilename) != 0) |
|
{ |
|
bi.SetName(newfilename); |
|
} |
|
} |
|
} |
|
} |
|
|
|
ISetMaxBitmap(TheManager->Load(&bi)); |
|
|
|
PBBitmap pbBitmap(bi); |
|
// TheManager->LoadInto(&pbBitmap.bi, &pbBitmap.bm, TRUE); |
|
ISetPBBitmap(&pbBitmap, index); |
|
|
|
if (assetId) |
|
SetBitmapAssetId(*assetId, index); |
|
} |
|
else |
|
{ |
|
ISetMaxBitmap(NULL, index); |
|
ISetPBBitmap(NULL, index); |
|
} |
|
|
|
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); |
|
*/ |
|
} |
|
|
|
//// RefreshBitmaps /////////////////////////////////////////////////////////// |
|
// Makes sure the bitmap asset is the latest from AssetMan, if we're using it. |
|
|
|
void plPlasmaMAXLayer::RefreshBitmaps() |
|
{ |
|
int i, count = GetNumBitmaps(); |
|
|
|
for( i = 0; i < count; i++ ) |
|
{ |
|
PBBitmap *pbbm = GetPBBitmap(i); |
|
if (pbbm) |
|
{ |
|
SetBitmap(&pbbm->bi, i); |
|
} |
|
} |
|
} |
|
|
|
//// GetBitmapFileName //////////////////////////////////////////////////////// |
|
// Returns the filename of the ith bitmap. Makes sure we have the latest |
|
// version from assetMan as well, if applicable. |
|
|
|
bool plPlasmaMAXLayer::GetBitmapFileName( char *destFilename, int maxLength, int index /* = 0 */ ) |
|
{ |
|
#ifdef MAXASS_AVAILABLE |
|
jvUniqueId targetAssetId; |
|
GetBitmapAssetId(targetAssetId, index); |
|
|
|
MaxAssInterface* maxAssInterface = GetMaxAssInterface(); |
|
if (maxAssInterface != nil && !targetAssetId.IsEmpty()) |
|
{ |
|
// Download the latest version and retrieve the filename |
|
if (maxAssInterface->GetLatestVersionFile(targetAssetId, destFilename, maxLength)) |
|
return true; |
|
} |
|
#endif |
|
|
|
// Normal return |
|
if( GetPBBitmap( index ) == nil ) |
|
return false; |
|
|
|
strncpy( destFilename, GetPBBitmap( index )->bi.Name(), maxLength ); |
|
return true; |
|
} |
|
|
|
BOOL plPlasmaMAXLayer::HandleBitmapSelection(int index /* = 0 */) |
|
{ |
|
static ICustButton* bmSelectBtn; |
|
|
|
PBBitmap *pbbm = GetPBBitmap( index ); |
|
|
|
#ifdef MAXASS_AVAILABLE |
|
MaxAssInterface* maxAssInterface = GetMaxAssInterface(); |
|
#endif |
|
|
|
// If the control key is held, we want to get rid of this texture |
|
if ((GetKeyState(VK_CONTROL) & 0x8000) && pbbm != nil) |
|
{ |
|
char msg[512]; |
|
sprintf(msg, "Are you sure you want to change this bitmap from %s to (none)?", pbbm->bi.Name()); |
|
if (hsMessageBox(msg, "Remove texture?", hsMessageBoxYesNo) == hsMBoxYes) |
|
{ |
|
SetBitmap(nil, index); |
|
return TRUE; |
|
} |
|
return FALSE; |
|
} |
|
// if we have the assetman plug-in, then try to use it, unless shift is held down |
|
#ifdef MAXASS_AVAILABLE |
|
else if(maxAssInterface && !(GetKeyState(VK_SHIFT) & 0x8000)) |
|
{ |
|
jvUniqueId assetId; |
|
GetBitmapAssetId(assetId, index); |
|
|
|
char filename[MAX_PATH]; |
|
if (maxAssInterface->OpenBitmapDlg(assetId, filename, sizeof(filename))) |
|
{ |
|
SetBitmapAssetId(assetId, index); |
|
|
|
BitmapInfo bi; |
|
bi.SetName(filename); |
|
SetBitmap(&bi, index); |
|
return TRUE; |
|
} |
|
} |
|
#endif |
|
else |
|
{ |
|
BitmapInfo bi; |
|
if( pbbm != NULL ) |
|
bi.SetName( pbbm->bi.Name() ); |
|
|
|
BOOL selectedNewBitmap = TheManager->SelectFileInput(&bi, |
|
GetCOREInterface()->GetMAXHWnd(), |
|
_T("Select Bitmap Image File")); |
|
if (selectedNewBitmap) |
|
{ |
|
#ifdef MAXASS_AVAILABLE |
|
// Set the assetId to empty so our new, unmanaged texture will take |
|
jvUniqueId emptyId; |
|
SetBitmapAssetId(emptyId, index); |
|
#endif |
|
|
|
SetBitmap(&bi, index); |
|
return TRUE; |
|
} |
|
} |
|
|
|
return FALSE; |
|
}
|
|
|