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.
1130 lines
42 KiB
1130 lines
42 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==*/ |
|
/////////////////////////////////////////////////////////////////////////////// |
|
// // |
|
// plLayerConverter - Utility class that converts plPlasmaMAXLayers into // |
|
// other stuff. // |
|
// Cyan, Inc. // |
|
// // |
|
//// Version History ////////////////////////////////////////////////////////// |
|
// // |
|
// 1.13.2002 mcn - Created. // |
|
// // |
|
//// Notes //////////////////////////////////////////////////////////////////// |
|
// // |
|
// If you add a new PlasmaMAXLayer type, you need to add the appropriate // |
|
// test in ConvertTexmap() as well as your own function to do the // |
|
// conversion. Messy, but thanks to the dependencies of the convert process,// |
|
// we can't do it the nice, pretty, OOP way. // |
|
// // |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
#include "Max.h" |
|
#include "stdmat.h" |
|
#include "istdplug.h" |
|
#include "iparamb2.h" |
|
#include "iparamm2.h" |
|
|
|
|
|
#include "hsExceptionStack.h" |
|
|
|
#include "plLayerConverter.h" |
|
|
|
#include "MaxConvert/hsMaxLayerBase.h" |
|
#include "MaxConvert/hsConverterUtils.h" |
|
#include "MaxConvert/hsControlConverter.h" |
|
#include "MaxConvert/hsMaterialConverter.h" |
|
#include "MaxConvert/plBitmapCreator.h" |
|
#include "hsResMgr.h" |
|
#include "MaxExport/plErrorMsg.h" |
|
#include "MaxMain/plMaxNode.h" |
|
|
|
#include "pnKeyedObject/plUoid.h" |
|
#include "pnKeyedObject/plKey.h" |
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "plSurface/plLayerInterface.h" |
|
#include "plSurface/plLayer.h" |
|
#include "pnMessage/plRefMsg.h" |
|
#include "pnMessage/plObjRefMsg.h" |
|
#include "plMessage/plLayRefMsg.h" |
|
#include "plDrawable/plGeometrySpan.h" |
|
|
|
#include "plGImage/plMipmap.h" |
|
#include "plGImage/plDynamicTextMap.h" |
|
#include "plGImage/plCubicEnvironmap.h" |
|
#include "plPipeline/plCubicRenderTarget.h" |
|
#include "plPipeline/plCubicRenderTargetModifier.h" |
|
#include "plPipeline/plDynamicEnvMap.h" |
|
|
|
#include "pfSurface/plLayerAVI.h" |
|
#include "pfSurface/plLayerBink.h" |
|
|
|
#include "MaxPlasmaMtls/Layers/plPlasmaMAXLayer.h" |
|
#include "MaxPlasmaMtls/Layers/plLayerTex.h" |
|
#include "MaxPlasmaMtls/Layers/plLayerTexBitmapPB.h" |
|
#include "MaxPlasmaMtls/Layers/plStaticEnvLayer.h" |
|
#include "MaxPlasmaMtls/Layers/plDynamicEnvLayer.h" |
|
#include "MaxPlasmaMtls/Layers/plDynamicTextLayer.h" |
|
#include "MaxPlasmaMtls/Layers/plAngleAttenLayer.h" |
|
#include "MaxPlasmaMtls/Layers/plMAXCameraLayer.h" |
|
|
|
#include "MaxComponent/plComponent.h" |
|
#include "MaxComponent/plWaterComponent.h" |
|
#include "pfCamera/plCameraModifier.h" |
|
|
|
//// Local Static Stuff /////////////////////////////////////////////////////// |
|
|
|
namespace |
|
{ |
|
enum { |
|
kWarnedTooManyUVs = 0x01, |
|
kWarnedNoBaseTexture = 0x02, |
|
kWarnedUpperTextureMissing = 0x04, |
|
kWarnedNoUpperTexture = 0x08, |
|
}; |
|
|
|
const char sWarnBaseTextureMissing[] = "The object \"%s\"'s material has a base layer that is assigned texture \"%s\", but the texture file is missing. " |
|
"This can cause unwanted effects during runtime."; |
|
const char sWarnUpperTextureMissing[] = "The object \"%s\"'s material has an upper layer that is assigned texture \"%s\", but the texture file is missing. " |
|
"This is not supported in the engine, so the upper layer will be ignored."; |
|
const char sWarnNoUpperTexture[] = "The object \"%s\"'s material has an uppper layer that is not assigned a texture. " |
|
"This is not supported in the engine, so the upper layer will be disabled."; |
|
} |
|
|
|
|
|
//// Constructor/Destructor /////////////////////////////////////////////////// |
|
|
|
plLayerConverter::plLayerConverter() : |
|
fInterface( nil ), |
|
fConverterUtils( hsConverterUtils::Instance() ) |
|
{ |
|
fErrorMsg = nil; |
|
fWarned = 0; |
|
fSaving = false; |
|
} |
|
|
|
plLayerConverter::~plLayerConverter() |
|
{ |
|
} |
|
|
|
plLayerConverter &plLayerConverter::Instance( void ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::Instance" ); |
|
|
|
static plLayerConverter instance; |
|
|
|
return instance; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
void plLayerConverter::Init( hsBool save, plErrorMsg *msg ) |
|
{ |
|
fSaving = save; |
|
fErrorMsg = msg; |
|
fWarned = 0; |
|
fInterface = GetCOREInterface(); |
|
} |
|
|
|
void plLayerConverter::DeInit( void ) |
|
{ |
|
int i; |
|
for( i = 0; i < fConvertedLayers.GetCount(); i++ ) |
|
{ |
|
if( fConvertedLayers[ i ] != nil ) |
|
fConvertedLayers[ i ]->IClearConversionTargets(); |
|
} |
|
fConvertedLayers.Reset(); |
|
} |
|
|
|
//// Mute/Unmute Warnings ///////////////////////////////////////////////////// |
|
|
|
void plLayerConverter::MuteWarnings( void ) |
|
{ |
|
fSavedWarned = fWarned; |
|
fWarned |= kWarnedNoBaseTexture | kWarnedUpperTextureMissing; |
|
} |
|
|
|
void plLayerConverter::UnmuteWarnings( void ) |
|
{ |
|
fWarned = fSavedWarned; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Main Switcheroo ////////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// ConvertTexmap //////////////////////////////////////////////////////////// |
|
|
|
plLayerInterface *plLayerConverter::ConvertTexmap( Texmap *texmap, |
|
plMaxNode *maxNode, |
|
uint32_t blendFlags, hsBool preserveUVOffset, |
|
hsBool upperLayer ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::ConvertTexmap" ); |
|
|
|
fDbgNodeName = maxNode->GetName(); |
|
|
|
// We only convert plPlasmaMAXLayers |
|
plPlasmaMAXLayer *layer = plPlasmaMAXLayer::GetPlasmaMAXLayer( texmap ); |
|
if( layer == nil ) |
|
{ |
|
fErrorMsg->Set( true, "Plasma Layer Error", "Cannot convert layer '%s'--unrecognized MAX layer type", texmap->GetName() ); |
|
fErrorMsg->Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
// KLUDGE - Some things don't set the name for their layers (ie projected |
|
// runtime lights). So that we don't end up with an empty keyname, set the |
|
// name to the nodes name if there isn't one. -Colin |
|
const char* layerName = layer->GetName(); |
|
if (!layerName || layerName[0] == '\0') |
|
layer->SetName(maxNode->GetName()); |
|
|
|
// Switch on the class ID |
|
plLayerInterface *plasmaLayer = nil; |
|
|
|
if( layer->ClassID() == LAYER_TEX_CLASS_ID ) |
|
plasmaLayer = IConvertLayerTex( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
else if( layer->ClassID() == STATIC_ENV_LAYER_CLASS_ID ) |
|
plasmaLayer = IConvertStaticEnvLayer( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
else if( layer->ClassID() == DYNAMIC_ENV_LAYER_CLASS_ID ) |
|
plasmaLayer = IConvertDynamicEnvLayer( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
else if( layer->ClassID() == DYN_TEXT_LAYER_CLASS_ID ) |
|
plasmaLayer = IConvertDynamicTextLayer( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
else if( layer->ClassID() == ANGLE_ATTEN_LAYER_CLASS_ID ) |
|
plasmaLayer = IConvertAngleAttenLayer( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
else if( layer->ClassID() == MAX_CAMERA_LAYER_CLASS_ID ) |
|
plasmaLayer = IConvertCameraLayer( layer, maxNode, blendFlags, preserveUVOffset, upperLayer ); |
|
|
|
|
|
IRegisterConversion( layer, plasmaLayer ); |
|
|
|
return plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IRegisterConversion ////////////////////////////////////////////////////// |
|
|
|
void plLayerConverter::IRegisterConversion( plPlasmaMAXLayer *origLayer, plLayerInterface *convertedLayer ) |
|
{ |
|
if( convertedLayer == nil ) |
|
return; |
|
|
|
// Add this to our list of converted layers (so we can clean them up later) |
|
if( fConvertedLayers.Find( origLayer ) == fConvertedLayers.kMissingIndex ) |
|
fConvertedLayers.Append( origLayer ); |
|
|
|
// Now add the converted layer to that layer's list of conversion targets. |
|
// (easier than us keeping a huge lookup table, since this is *acting* |
|
// as that lookup table more or less) |
|
origLayer->IAddConversionTarget( convertedLayer ); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Main Processing Functions //////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
//// IConvertLayerTex ///////////////////////////////////////////////////////// |
|
|
|
plLayerInterface *plLayerConverter::IConvertLayerTex( plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::IConvertLayerTex" ); |
|
|
|
IParamBlock2 *bitmapPB; |
|
plLocation loc; |
|
|
|
|
|
loc = maxNode->GetLocation(); |
|
bitmapPB = layer->GetParamBlockByID( plLayerTex::kBlkBitmap ); |
|
|
|
if( !bitmapPB ) |
|
{ |
|
fErrorMsg->Set( !bitmapPB, "Plasma Layer Error", "Bitmap paramblock for Plasma Layer not found" ).Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
// Get a new layer to play with |
|
plLayer *plasmaLayer = ICreateLayer( plString::FromUtf8( layer->GetName() ), upperLayer, loc ); |
|
|
|
// We're using a texture, try and get its info |
|
PBBitmap *pbbm = nil; |
|
BitmapInfo *bi = nil; |
|
|
|
if( bitmapPB->GetInt( kBmpUseBitmap ) ) |
|
{ |
|
if( bitmapPB ) |
|
pbbm = bitmapPB->GetBitmap( kBmpBitmap ); |
|
if( pbbm ) |
|
bi = &pbbm->bi; |
|
} |
|
|
|
// If the texture had bad info, assert and return the empty layer |
|
if( !bi || !bi->Name() || !strcmp(bi->Name(), "") ) |
|
{ |
|
if( upperLayer ) |
|
{ |
|
if( fErrorMsg->Set( !( fWarned & kWarnedNoUpperTexture ), "Plasma Export Error", sWarnNoUpperTexture, maxNode->GetName() ).CheckAskOrCancel() ) |
|
fWarned |= kWarnedNoUpperTexture; |
|
fErrorMsg->Set( false ); |
|
|
|
delete plasmaLayer; |
|
return nil; |
|
} |
|
else |
|
{ |
|
return (plLayerInterface *)plasmaLayer; |
|
} |
|
} |
|
|
|
// Setup the texture creation parameters |
|
plBitmapData bd; |
|
bd.fileName = bi->Name(); |
|
|
|
// Create texture and add it to list if unique |
|
int32_t texFlags = 0;//hsGTexture::kMipMap; |
|
|
|
// Texture Alpha/Color |
|
if( bitmapPB->GetInt( kBmpInvertColor ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendInvertColor ); |
|
if( bitmapPB->GetInt( kBmpDiscardColor ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendNoTexColor ); |
|
if( bitmapPB->GetInt( kBmpDiscardAlpha ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendNoTexAlpha ); |
|
if( bitmapPB->GetInt( kBmpInvertAlpha ) ) |
|
bd.invertAlpha = true; |
|
|
|
// Texture quality |
|
if( bitmapPB->GetInt( kBmpNonCompressed ) ) |
|
texFlags |= plBitmap::kForceNonCompressed; |
|
|
|
if( bitmapPB->GetInt( kBmpNoDiscard ) ) |
|
texFlags |= plBitmap::kDontThrowAwayImage; |
|
|
|
switch( bitmapPB->GetInt( kBmpScaling ) ) |
|
{ |
|
case kScalingHalf: texFlags |= plBitmap::kHalfSize; break; |
|
case kScalingNone: texFlags |= plBitmap::kNoMaxSize; break; |
|
} |
|
|
|
// Mip map filtering. |
|
if( bitmapPB->GetInt( kBmpNoFilter ) ) |
|
texFlags |= plBitmap::kForceOneMipLevel; |
|
if( bitmapPB->GetInt( kBmpMipBias ) ) |
|
{ |
|
plasmaLayer->SetZFlags( plasmaLayer->GetZFlags() | hsGMatState::kZLODBias ); |
|
plasmaLayer->SetLODBias( bitmapPB->GetFloat( kBmpMipBiasAmt, fConverterUtils.GetTime( fInterface ) ) ); |
|
} |
|
float sig = bitmapPB->GetFloat( kBmpMipBlur ); |
|
|
|
bd.texFlags = texFlags; |
|
bd.sig = sig; |
|
|
|
// Get detail parameters |
|
if( bitmapPB->GetInt( kBmpUseDetail ) ) |
|
{ // TODO: be smarter |
|
if( blendFlags & hsGMatState::kBlendAdd ) |
|
bd.createFlags |= plMipmap::kCreateDetailAdd; |
|
else if( blendFlags & hsGMatState::kBlendMult ) |
|
bd.createFlags |= plMipmap::kCreateDetailMult; |
|
else |
|
bd.createFlags |= plMipmap::kCreateDetailAlpha; |
|
bd.detailDropoffStart = float(bitmapPB->GetInt(kBmpDetailStartSize)) / 100.f; |
|
bd.detailDropoffStop = float(bitmapPB->GetInt(kBmpDetailStopSize)) / 100.f; |
|
bd.detailMax = float(bitmapPB->GetInt(kBmpDetailStartOpac)) / 100.f; |
|
bd.detailMin = float(bitmapPB->GetInt(kBmpDetailStopOpac)) / 100.f; |
|
} |
|
|
|
// Get max export dimension (since the function we eventually call |
|
// expects the max of the two dimensions, we figure that out here and |
|
// pass it on) |
|
bd.maxDimension = bitmapPB->GetInt( kBmpExportWidth ); |
|
int expHt = bitmapPB->GetInt( kBmpExportHeight ); |
|
if( bd.maxDimension < expHt ) |
|
bd.maxDimension = expHt; |
|
int clipID = 0, w; |
|
for( clipID = 0, w = bi->Width(); w > bd.maxDimension; w >>= 1, clipID++ ); |
|
|
|
// Do the UV gen (before we do texture, since it could modify the bitmapData struct) |
|
IProcessUVGen( layer, plasmaLayer, &bd, preserveUVOffset ); |
|
|
|
// Create the texture. If it works, assign it to the layer |
|
if( ( plasmaLayer = IAssignTexture( &bd, maxNode, plasmaLayer, upperLayer, clipID ) ) == nil ) |
|
return nil; |
|
|
|
// All done! |
|
return (plLayerInterface *)plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IConvertStaticEnvLayer /////////////////////////////////////////////////// |
|
|
|
plLayerInterface *plLayerConverter::IConvertStaticEnvLayer( plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::IConvertStaticEnvLayer" ); |
|
|
|
IParamBlock2 *bitmapPB; |
|
plLocation loc; |
|
|
|
loc = maxNode->GetLocation(); |
|
bitmapPB = layer->GetParamBlockByID( plStaticEnvLayer::kBlkBitmap ); |
|
|
|
if( !bitmapPB ) |
|
{ |
|
fErrorMsg->Set( !bitmapPB, "Plasma Layer Error", "Bitmap paramblock for Plasma Layer not found" ).Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
// Get a new layer to play with |
|
plLayer *plasmaLayer = ICreateLayer( plString::FromUtf8( layer->GetName() ), upperLayer, loc ); |
|
|
|
// Get the texture info |
|
PBBitmap *pbbm = bitmapPB->GetBitmap( plStaticEnvLayer::kBmpFrontBitmap + 0 ); |
|
BitmapInfo *bi = nil; |
|
if( pbbm ) |
|
bi = &pbbm->bi; |
|
|
|
// If the texture had bad info, assert and return the empty layer |
|
if (!bi || !bi->Name() || !strcmp(bi->Name(), "")) |
|
{ |
|
// Or don't assert since it can get annoying when you are using someone |
|
// elses file and don't have all the textures. |
|
return (plLayerInterface *)plasmaLayer; |
|
} |
|
|
|
// Setup the texture creation parameters |
|
plBitmapData bd; |
|
bd.fileName = bi->Name(); |
|
|
|
// Create texture and add it to list if unique |
|
int32_t texFlags = 0; |
|
|
|
// Texture Alpha/Color |
|
if( bitmapPB->GetInt( plStaticEnvLayer::kBmpInvertColor ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendInvertColor ); |
|
if( bitmapPB->GetInt( plStaticEnvLayer::kBmpDiscardColor ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendNoTexColor ); |
|
if( bitmapPB->GetInt( kBmpDiscardAlpha ) ) |
|
plasmaLayer->SetBlendFlags( plasmaLayer->GetBlendFlags() | hsGMatState::kBlendNoTexAlpha ); |
|
if( bitmapPB->GetInt( plStaticEnvLayer::kBmpInvertAlpha ) ) |
|
bd.invertAlpha = true; |
|
|
|
// Texture quality |
|
if( bitmapPB->GetInt( plStaticEnvLayer::kBmpNonCompressed ) ) |
|
texFlags |= plBitmap::kForceNonCompressed; |
|
|
|
switch( bitmapPB->GetInt( plStaticEnvLayer::kBmpScaling ) ) |
|
{ |
|
case plStaticEnvLayer::kScalingHalf: texFlags |= plBitmap::kHalfSize; break; |
|
case plStaticEnvLayer::kScalingNone: texFlags |= plBitmap::kNoMaxSize; break; |
|
} |
|
|
|
bd.texFlags = texFlags; |
|
bd.isStaticCubicEnvMap = true; |
|
for( int i = 0; i < 6; i++ ) |
|
{ |
|
PBBitmap *face = bitmapPB->GetBitmap( plStaticEnvLayer::kBmpFrontBitmap + i ); |
|
if( !face ) |
|
return (plLayerInterface *)plasmaLayer; |
|
bd.faceNames[ i ] = face->bi.Name(); |
|
} |
|
|
|
// Get detail parameters |
|
if( bitmapPB->GetInt( plStaticEnvLayer::kBmpUseDetail ) ) |
|
{ // TODO: be smarter |
|
if( blendFlags & hsGMatState::kBlendAdd ) |
|
bd.createFlags = plMipmap::kCreateDetailAdd; |
|
else if( blendFlags & hsGMatState::kBlendMult ) |
|
bd.createFlags = plMipmap::kCreateDetailMult; |
|
else |
|
bd.createFlags = plMipmap::kCreateDetailAlpha; |
|
|
|
bd.detailDropoffStart = float( bitmapPB->GetInt( plStaticEnvLayer::kBmpDetailStartSize ) ) / 100.f; |
|
bd.detailDropoffStop = float( bitmapPB->GetInt( plStaticEnvLayer::kBmpDetailStopSize ) ) / 100.f; |
|
bd.detailMax = float( bitmapPB->GetInt( plStaticEnvLayer::kBmpDetailStartOpac ) ) / 100.f; |
|
bd.detailMin = float( bitmapPB->GetInt( plStaticEnvLayer::kBmpDetailStopOpac ) ) / 100.f; |
|
} |
|
|
|
/// Since we're a cubic environMap, we don't care about the UV transform nor the uvwSrc |
|
plasmaLayer->SetUVWSrc( 0 ); |
|
plasmaLayer->SetUVWSrc( plasmaLayer->GetUVWSrc() | plLayerInterface::kUVWReflect ); |
|
|
|
// Create the texture. If it works, assign it to the layer |
|
if( ( plasmaLayer = IAssignTexture( &bd, maxNode, plasmaLayer, upperLayer ) ) == nil ) |
|
return nil; |
|
|
|
// Tag this layer as reflective cubic environmentmapping |
|
if( bitmapPB->GetInt(plStaticEnvLayer::kBmpRefract) ) |
|
plasmaLayer->SetMiscFlags( plasmaLayer->GetMiscFlags() | hsGMatState::kMiscUseRefractionXform ); |
|
else |
|
plasmaLayer->SetMiscFlags( plasmaLayer->GetMiscFlags() | hsGMatState::kMiscUseReflectionXform ); |
|
|
|
return (plLayerInterface *)plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IConvertDynamicEnvLayer ////////////////////////////////////////////////// |
|
|
|
plLayerInterface *plLayerConverter::IConvertDynamicEnvLayer( plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::IConvertDynamicEnvLayer" ); |
|
|
|
IParamBlock2 *bitmapPB; |
|
plLocation loc; |
|
|
|
loc = maxNode->GetLocation(); |
|
bitmapPB = layer->GetParamBlockByID( plDynamicEnvLayer::kBlkBitmap ); |
|
|
|
if( !bitmapPB ) |
|
{ |
|
fErrorMsg->Set( !bitmapPB, "Plasma Layer Error", "Bitmap paramblock for Plasma Layer not found" ).Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
// Get a new layer to play with |
|
plLayer *plasmaLayer = ICreateLayer( plString::FromUtf8( layer->GetName() ), upperLayer, loc ); |
|
|
|
// Get the anchor node |
|
plMaxNode *anchor = (plMaxNode *)bitmapPB->GetINode( plDynamicEnvLayer::kBmpAnchorNode ); |
|
if( anchor == nil ) |
|
// Default to self as the anchor--just make sure we make unique versions of this material! |
|
anchor = maxNode; |
|
|
|
if( !anchor->CanConvert() || !( anchor->GetForceLocal() || anchor->GetDrawable() ) ) |
|
{ |
|
fErrorMsg->Set( true, "Plasma Layer Error", "The dynamic envMap material %s has an invalid anchor specified. Please specify a valid Plasma scene object as an anchor.", plasmaLayer->GetKeyName().c_str() ).Show(); |
|
fErrorMsg->Set(); |
|
return (plLayerInterface *)plasmaLayer; |
|
} |
|
|
|
// Create texture and add it to list if unique |
|
int32_t texFlags = 0; |
|
|
|
/// Since we're a cubic environMap, we don't care about the UV transform nor the uvwSrc |
|
plasmaLayer->SetUVWSrc( 0 ); |
|
plasmaLayer->SetUVWSrc( plasmaLayer->GetUVWSrc() | plLayerInterface::kUVWReflect ); |
|
|
|
// Create the texture. If it works, assign it to the layer |
|
plString texName; |
|
if( anchor == maxNode ) |
|
{ |
|
// Self-anchoring material, make sure the name is unique via the nodeName |
|
texName = plString::Format( "%s_cubicRT@%s", plasmaLayer->GetKeyName().c_str(), maxNode->GetName() ); |
|
} |
|
else |
|
texName = plString::Format( "%s_cubicRT", plasmaLayer->GetKeyName().c_str() ); |
|
|
|
plBitmap *texture = (plBitmap *)IMakeCubicRenderTarget( texName, maxNode, anchor ); |
|
if( texture ) |
|
hsgResMgr::ResMgr()->AddViaNotify( texture->GetKey(), new plLayRefMsg( plasmaLayer->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef ); |
|
|
|
// Tag this layer as reflective cubic environmentmapping |
|
if( bitmapPB->GetInt(plDynamicEnvLayer::kBmpRefract) ) |
|
plasmaLayer->SetMiscFlags( plasmaLayer->GetMiscFlags() | hsGMatState::kMiscUseRefractionXform ); |
|
else |
|
plasmaLayer->SetMiscFlags( plasmaLayer->GetMiscFlags() | hsGMatState::kMiscUseReflectionXform ); |
|
|
|
return (plLayerInterface *)plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
plLayerInterface *plLayerConverter::IConvertCameraLayer(plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer) |
|
{ |
|
hsGuardBegin( "plLayerConverter::IConvertCameraLayer" ); |
|
|
|
IParamBlock2 *pb; |
|
plLocation loc; |
|
|
|
loc = maxNode->GetLocation(); |
|
pb = layer->GetParamBlockByID(plMAXCameraLayer::kBlkMain); |
|
|
|
if (!pb) |
|
{ |
|
fErrorMsg->Set(!pb, "Plasma Layer Error", "Paramblock for Plasma Camera Layer not found" ).Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
plLayer *plasmaLayer = ICreateLayer (plString::FromUtf8(layer->GetName()), upperLayer, loc); |
|
|
|
plMaxNode *rootNode = (plMaxNode*)pb->GetINode(ParamID(plMAXCameraLayer::kRootNode)); |
|
plDynamicCamMap *map = plEnvMapComponent::GetCamMap(rootNode ? rootNode : maxNode); |
|
if (map) |
|
{ |
|
int32_t texFlags = 0; |
|
if (!pb->GetInt(ParamID(plMAXCameraLayer::kExplicitCam))) |
|
{ |
|
plasmaLayer->SetUVWSrc(plLayerInterface::kUVWPosition); |
|
plasmaLayer->SetMiscFlags(hsGMatState::kMiscCam2Screen | hsGMatState::kMiscPerspProjection); |
|
hsgResMgr::ResMgr()->AddViaNotify(rootNode->GetSceneObject()->GetKey(), new plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefRootNode), plRefFlags::kActiveRef); |
|
hsgResMgr::ResMgr()->AddViaNotify(plasmaLayer->GetKey(), new plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefMatLayer), plRefFlags::kActiveRef); |
|
if (!pb->GetInt(ParamID(plMAXCameraLayer::kForce))) |
|
{ |
|
plBitmap *disableTexture = hsMaterialConverter::Instance().GetStaticColorTexture(pb->GetColor(ParamID(plMAXCameraLayer::kDisableColor)), loc); |
|
hsgResMgr::ResMgr()->AddViaNotify(disableTexture->GetKey(), new plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefDisableTexture), plRefFlags::kActiveRef); |
|
} |
|
} |
|
else |
|
{ |
|
plMaxNode *camNode = (plMaxNode*)pb->GetINode(ParamID(plMAXCameraLayer::kCamera)); |
|
if (camNode) |
|
{ |
|
const plCameraModifier1 *mod = plCameraModifier1::ConvertNoRef(camNode->GetSceneObject()->GetModifierByType(plCameraModifier1::Index())); |
|
if (mod) |
|
hsgResMgr::ResMgr()->AddViaNotify(mod->GetKey(), new plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefCamera), plRefFlags::kActiveRef); |
|
} |
|
|
|
plasmaLayer->SetUVWSrc(pb->GetInt(ParamID(plMAXCameraLayer::kUVSource))); |
|
} |
|
|
|
hsTArray<plMaxNode*> nodeList; |
|
hsMaterialConverter::GetNodesByMaterial(maxNode->GetMtl(), nodeList); |
|
int i; |
|
for (i = 0; i < nodeList.GetCount(); i++) |
|
{ |
|
hsgResMgr::ResMgr()->AddViaNotify(nodeList[i]->GetSceneObject()->GetKey(), new plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefTargetNode), plRefFlags::kActiveRef); |
|
} |
|
hsgResMgr::ResMgr()->AddViaNotify(map->GetKey(), new plLayRefMsg(plasmaLayer->GetKey(), plRefMsg::kOnCreate, -1, plLayRefMsg::kTexture), plRefFlags::kActiveRef); |
|
|
|
} |
|
|
|
return plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IConvertDynamicTextLayer ///////////////////////////////////////////////// |
|
|
|
plLayerInterface *plLayerConverter::IConvertDynamicTextLayer( plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer ) |
|
{ |
|
hsGuardBegin( "plLayerConverter::IConvertDynamicTextLayer" ); |
|
|
|
plDynamicTextLayer *maxLayer; |
|
IParamBlock2 *bitmapPB; |
|
plLocation loc; |
|
|
|
maxLayer = (plDynamicTextLayer *)layer; |
|
loc = maxNode->GetLocation(); |
|
bitmapPB = maxLayer->GetParamBlockByID( plDynamicTextLayer::kBlkBitmap ); |
|
|
|
if( !bitmapPB ) |
|
{ |
|
fErrorMsg->Set( !bitmapPB, "Plasma Layer Error", "Bitmap paramblock for Plasma Layer not found" ).Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
|
|
// Get a new layer to play with |
|
plLayer *plasmaLayer = ICreateLayer( plString::FromUtf8( maxLayer->GetName() ), upperLayer, loc ); |
|
|
|
|
|
/// UV Gen |
|
IProcessUVGen( maxLayer, plasmaLayer, nil, preserveUVOffset ); |
|
|
|
// Create the "texture" |
|
plDynamicTextMap *texture = ICreateDynTextMap( plasmaLayer->GetKeyName(), |
|
bitmapPB->GetInt( plDynamicTextLayer::kBmpExportWidth ), |
|
bitmapPB->GetInt( plDynamicTextLayer::kBmpExportHeight ), |
|
bitmapPB->GetInt( plDynamicTextLayer::kBmpIncludeAlphaChannel ), |
|
maxNode ); |
|
|
|
// Set the initial bitmap if necessary |
|
uint32_t *initBuffer = IGetInitBitmapBuffer( maxLayer ); |
|
if( initBuffer != nil ) |
|
{ |
|
texture->SetInitBuffer( initBuffer ); |
|
delete [] initBuffer; |
|
} |
|
|
|
// Add the texture in |
|
hsgResMgr::ResMgr()->AddViaNotify( texture->GetKey(), new plLayRefMsg( plasmaLayer->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef ); |
|
|
|
// All done! |
|
return (plLayerInterface *)plasmaLayer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IGetInitBitmapBuffer ///////////////////////////////////////////////////// |
|
// Called to get a 32-bit uncompressed ARGB version of the init bitmap of |
|
// a dynamic text layer |
|
|
|
uint32_t *plLayerConverter::IGetInitBitmapBuffer( plDynamicTextLayer *layer ) const |
|
{ |
|
uint32_t *buffer; |
|
hsRGBAColor32 *buffPtr; |
|
uint16_t width, height; |
|
|
|
|
|
IParamBlock2 *bitmapPB = layer->GetParamBlockByID( plDynamicTextLayer::kBlkBitmap ); |
|
Bitmap *initBitmap = layer->GetBitmap( TimeValue( 0 ) ); |
|
|
|
if( bitmapPB->GetInt( (ParamID)plDynamicTextLayer::kBmpUseInitImage ) == 0 || initBitmap == nil ) |
|
return nil; |
|
|
|
width = bitmapPB->GetInt( (ParamID)plDynamicTextLayer::kBmpExportWidth ); |
|
height = bitmapPB->GetInt( (ParamID)plDynamicTextLayer::kBmpExportHeight ); |
|
|
|
buffer = new uint32_t[ width * height ]; |
|
if( buffer == nil ) |
|
return nil; |
|
|
|
// Fill buffer from the MAX bitmap |
|
PixelBuf l64( width ); |
|
BMM_Color_64 *p64 = l64.Ptr(); |
|
|
|
buffPtr = (hsRGBAColor32 *)buffer; |
|
for( int y = 0; y < height; y++ ) |
|
{ |
|
hsRGBAColor32 color; |
|
|
|
if( !initBitmap->GetLinearPixels( 0, y, width, p64 ) ) |
|
{ |
|
delete [] buffer; |
|
return nil; |
|
} |
|
|
|
for( int x = 0; x < width; x++ ) |
|
{ |
|
color.SetARGB( p64[ x ].a * 255.f / 65535.f, |
|
p64[ x ].r * 255.f / 65535.f, |
|
p64[ x ].g * 255.f / 65535.f, |
|
p64[ x ].b * 255.f / 65535.f ); |
|
buffPtr[ x ] = color; |
|
} |
|
|
|
buffPtr += width; |
|
} |
|
|
|
return buffer; |
|
} |
|
|
|
static uint32_t MakeUInt32Color(float r, float g, float b, float a) |
|
{ |
|
return (uint32_t(a * 255.9f) << 24) |
|
|(uint32_t(r * 255.9f) << 16) |
|
|(uint32_t(g * 255.9f) << 8) |
|
|(uint32_t(b * 255.9f) << 0); |
|
} |
|
|
|
plBitmap* plLayerConverter::IGetAttenRamp(plMaxNode *node, BOOL isAdd, int loClamp, int hiClamp) |
|
{ |
|
plString funkName = plString::Format("%s_%d_%d", |
|
isAdd ? "AttenRampAdd" : "AttenRampMult", |
|
loClamp, |
|
hiClamp); |
|
|
|
float range = float(hiClamp - loClamp) * 1.e-2f; |
|
float lowest = float(loClamp) * 1.e-2f; |
|
const int kLUTWidth = 16; |
|
const int kLUTHeight = 16; |
|
|
|
// NOTE: CreateBlankMipmap might return an old mipmap if it was already created, so in those |
|
// cases we wouldn't really need to re-write the texture. However, there's no harm in doing so, |
|
// and since we're close to Alpha, I don't want to shake up the code any more than absolutely |
|
// necessary. -mcn |
|
plMipmap *texture = plBitmapCreator::Instance().CreateBlankMipmap( kLUTWidth, kLUTHeight, plMipmap::kARGB32Config, 1, funkName, node->GetLocation() ); |
|
|
|
uint32_t* pix = (uint32_t*)texture->GetImage(); |
|
|
|
if( isAdd ) |
|
{ |
|
int i; |
|
for( i = 0; i < kLUTHeight; i++ ) |
|
{ |
|
int j; |
|
for( j = 0; j < kLUTWidth; j++ ) |
|
{ |
|
float x = float(j) / (kLUTWidth-1); |
|
float y = float(i) / (kLUTHeight-1); |
|
if( x < y ) |
|
x = y; |
|
x *= range; |
|
x += lowest; |
|
*pix++ = MakeUInt32Color(1.f, 1.f, 1.f, x); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
int i; |
|
for( i = 0; i < kLUTHeight; i++ ) |
|
{ |
|
int j; |
|
for( j = 0; j < kLUTWidth; j++ ) |
|
{ |
|
float x = float(j) / (kLUTWidth-1); |
|
float y = float(i) / (kLUTHeight-1); |
|
float val = x * y; |
|
val *= range; |
|
val += lowest; |
|
*pix++ = MakeUInt32Color(1.f, 1.f, 1.f, val); |
|
} |
|
} |
|
} |
|
|
|
return texture; |
|
} |
|
|
|
|
|
plLayer* plLayerConverter::ICreateAttenuationLayer(const plString& name, plMaxNode *node, int uvwSrc, |
|
float tr0, float op0, float tr1, float op1, |
|
int loClamp, int hiClamp) |
|
{ |
|
hsMatrix44 uvwXfm; |
|
uvwXfm.Reset(); |
|
uvwXfm.fMap[0][0] = uvwXfm.fMap[1][1] = uvwXfm.fMap[2][2] = 0; |
|
uvwXfm.NotIdentity(); |
|
|
|
if( op0 != tr0 ) |
|
{ |
|
uvwXfm.fMap[0][2] = -1.f / (tr0 - op0); |
|
uvwXfm.fMap[0][3] = uvwXfm.fMap[0][2] * -tr0; |
|
} |
|
else |
|
{ |
|
uvwXfm.fMap[0][3] = 1.f; |
|
} |
|
|
|
if( op1 != tr1 ) |
|
{ |
|
uvwXfm.fMap[1][2] = -1.f / (tr1 - op1); |
|
uvwXfm.fMap[1][3] = uvwXfm.fMap[1][2] * -tr1; |
|
} |
|
else |
|
{ |
|
uvwXfm.fMap[1][3] = 1.f; |
|
} |
|
|
|
BOOL chanAdd = false; |
|
if( op0 < tr0 ) |
|
{ |
|
if( (op0 < op1) && (tr1 < op1) ) |
|
chanAdd = true; |
|
} |
|
else if( op0 > tr0 ) |
|
{ |
|
if( (op0 > op1) && (tr1 > op1) ) |
|
chanAdd = true; |
|
} |
|
plBitmap* funkRamp = IGetAttenRamp(node, chanAdd, loClamp, hiClamp); |
|
|
|
plLayer* layer = new plLayer; |
|
layer->InitToDefault(); |
|
hsgResMgr::ResMgr()->NewKey(name, layer, node->GetLocation()); |
|
hsgResMgr::ResMgr()->AddViaNotify(funkRamp->GetKey(), new plLayRefMsg(layer->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture), plRefFlags::kActiveRef); |
|
|
|
layer->SetAmbientColor(hsColorRGBA().Set(1.f, 1.f, 1.f, 1.f)); |
|
layer->SetPreshadeColor(hsColorRGBA().Set(0, 0, 0, 1.f)); |
|
layer->SetRuntimeColor(hsColorRGBA().Set(0, 0, 0, 1.f)); |
|
|
|
layer->SetZFlags(hsGMatState::kZNoZWrite); |
|
uint32_t blendFlags = hsGMatState::kBlendAlpha | hsGMatState::kBlendNoTexColor | hsGMatState::kBlendAlphaMult; |
|
layer->SetBlendFlags(blendFlags); |
|
layer->SetClampFlags(hsGMatState::kClampTexture); |
|
|
|
layer->SetTransform(uvwXfm); |
|
|
|
layer->SetUVWSrc(uvwSrc); |
|
|
|
return layer; |
|
} |
|
|
|
plLayerInterface* plLayerConverter::IConvertAngleAttenLayer(plPlasmaMAXLayer *layer, |
|
plMaxNode *maxNode, uint32_t blendFlags, |
|
hsBool preserveUVOffset, hsBool upperLayer) |
|
{ |
|
hsGuardBegin( "plPlasmaMAXLayer::IConvertAngleAttenLayer" ); |
|
if( !upperLayer ) |
|
{ |
|
fErrorMsg->Set(true, maxNode->GetName(), "Angle Attenuation layers can only be used as a top layer").Show(); |
|
fErrorMsg->Set(); |
|
return nil; |
|
} |
|
plAngleAttenLayer* aaLay = (plAngleAttenLayer*)layer; |
|
Box3 fade = aaLay->GetFade(); |
|
float tr0 = cosf(DegToRad(180.f - fade.Min().x)); |
|
float op0 = cosf(DegToRad(180.f - fade.Min().y)); |
|
float tr1 = cosf(DegToRad(180.f - fade.Max().x)); |
|
float op1 = cosf(DegToRad(180.f - fade.Max().y)); |
|
|
|
int loClamp = aaLay->GetLoClamp(); |
|
int hiClamp = aaLay->GetHiClamp(); |
|
|
|
int uvwSrc = aaLay->Reflect() ? plLayerInterface::kUVWReflect : plLayerInterface::kUVWNormal; |
|
|
|
plLayer* lut = ICreateAttenuationLayer(plString::FromUtf8(layer->GetName()), maxNode, uvwSrc, tr0, op0, tr1, op1, loClamp, hiClamp); |
|
|
|
return lut; |
|
|
|
hsGuardEnd; |
|
} |
|
//// ICreateLayer ///////////////////////////////////////////////////////////// |
|
|
|
plLayer *plLayerConverter::ICreateLayer( const plString &name, hsBool upperLayer, plLocation &loc ) |
|
{ |
|
hsGuardBegin( "plPlasmaMAXLayer::ICreateLayer" ); |
|
|
|
plLayer *layer = new plLayer; |
|
layer->InitToDefault(); |
|
|
|
hsgResMgr::ResMgr()->NewKey( name, layer, loc ); |
|
|
|
return layer; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
//// IProcessUVGen //////////////////////////////////////////////////////////// |
|
|
|
void plLayerConverter::IProcessUVGen( plPlasmaMAXLayer *srcLayer, plLayer *destLayer, |
|
plBitmapData *bitmapData, hsBool preserveUVOffset ) |
|
{ |
|
hsGuardBegin( "plPlasmaMAXLayer::IProcessUVGen" ); |
|
|
|
StdUVGen *uvGen = (StdUVGen *)srcLayer->GetTheUVGen(); |
|
|
|
int tiling = uvGen->GetTextureTiling(); |
|
|
|
// If set this indicates the texture map is tiled in U |
|
if (!(tiling & U_WRAP)) |
|
{ |
|
destLayer->SetClampFlags( destLayer->GetClampFlags() | hsGMatState::kClampTextureU ); |
|
if( bitmapData != nil ) |
|
bitmapData->clampFlags |= plBitmapData::kClampU; |
|
} |
|
|
|
// If set this indicates the texture map is tiled in V |
|
if (!(tiling & V_WRAP)) |
|
{ |
|
destLayer->SetClampFlags( destLayer->GetClampFlags() | hsGMatState::kClampTextureV ); |
|
if( bitmapData != nil ) |
|
bitmapData->clampFlags |= plBitmapData::kClampV; |
|
} |
|
|
|
// UVW Src |
|
int32_t uvwSrc = srcLayer->GetMapChannel() - 1; |
|
|
|
if( fErrorMsg->Set( !( fWarned & kWarnedTooManyUVs ) && |
|
( ( uvwSrc < 0 ) || ( uvwSrc >= plGeometrySpan::kMaxNumUVChannels ) ), |
|
destLayer->GetKeyName().c_str(), "Only %d UVW channels (1-%d) currently supported", |
|
plGeometrySpan::kMaxNumUVChannels, plGeometrySpan::kMaxNumUVChannels).CheckAskOrCancel() ) |
|
fWarned |= kWarnedTooManyUVs; |
|
fErrorMsg->Set( false ); |
|
|
|
destLayer->SetUVWSrc( uvwSrc ); |
|
|
|
// Get the actual texture transform |
|
hsMatrix44 hsTopX; |
|
if (uvGen && (hsControlConverter::Instance().StdUVGenToHsMatrix44(&hsTopX, uvGen, preserveUVOffset == true))) |
|
destLayer->SetTransform( hsTopX ); |
|
|
|
// All done! |
|
hsGuardEnd; |
|
} |
|
|
|
//// ICreateDynTextMap //////////////////////////////////////////////////////// |
|
|
|
plDynamicTextMap *plLayerConverter::ICreateDynTextMap( const plString &layerName, uint32_t width, uint32_t height, |
|
hsBool includeAlphaChannel, plMaxNode *node ) |
|
{ |
|
hsGuardBegin( "plPlasmaMAXLayer::ICreateDynTextMap" ); |
|
|
|
plKey key; |
|
plDynamicTextMap *map = nil; |
|
|
|
|
|
// Need a unique key name for every layer that uses one. We could also key |
|
// off of width and height, but layerName should be more than plenty |
|
plString texName = plString::Format( "%s_dynText", layerName ); |
|
|
|
// Does it already exist? |
|
key = node->FindPageKey( plDynamicTextMap::Index(), texName ); |
|
if( key != nil ) |
|
{ |
|
map = plDynamicTextMap::ConvertNoRef( key->GetObjectPtr() ); |
|
if( map != nil ) |
|
return map; |
|
} |
|
|
|
// Create |
|
map = new plDynamicTextMap(); |
|
map->SetNoCreate( width, height, includeAlphaChannel ); |
|
|
|
/// Add a key for it |
|
key = hsgResMgr::ResMgr()->NewKey( texName, map, node->GetLocation() ); |
|
|
|
// All done! |
|
return map; |
|
|
|
hsGuardEnd; |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// Texture/Bitmap Management //////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
plBitmap *plLayerConverter::CreateSimpleTexture(const char *fileName, const plLocation &loc, |
|
uint32_t clipID /* = 0 */, uint32_t texFlags /* = 0 */, bool useJPEG /* = false */) |
|
{ |
|
plBitmapData bd; |
|
bd.fileName = fileName; |
|
bd.texFlags = texFlags; |
|
bd.createFlags = 0; |
|
bd.detailDropoffStart = 0; |
|
bd.detailDropoffStop = 0; |
|
bd.detailMax = 0; |
|
bd.detailMin = 0; |
|
bd.sig = 0; |
|
bd.isStaticCubicEnvMap = false; |
|
bd.invertAlpha = false; |
|
bd.clampFlags = 0; |
|
bd.useJPEG = useJPEG; |
|
|
|
return plBitmapCreator::Instance().CreateTexture(&bd, loc, clipID); |
|
} |
|
|
|
//// IAssignTexture /////////////////////////////////////////////////////////// |
|
// Create a texture and assign it to the layer given. Returns the layer again, |
|
// or nil if there was an error and it got deleted. |
|
|
|
plLayer *plLayerConverter::IAssignTexture( plBitmapData *bd, plMaxNode *maxNode, plLayer *destLayer, hsBool upperLayer, int clipID ) |
|
{ |
|
plBitmap *texture = plBitmapCreator::Instance().CreateTexture( bd, maxNode->GetLocation(), clipID ); |
|
if( texture == nil ) |
|
{ |
|
if( upperLayer ) |
|
{ |
|
if( fErrorMsg->Set( !( fWarned & kWarnedUpperTextureMissing ), "Plasma Export Error", sWarnUpperTextureMissing, maxNode->GetName(), bd->fileName ).CheckAskOrCancel() ) |
|
fWarned |= kWarnedUpperTextureMissing; |
|
fErrorMsg->Set( false ); |
|
|
|
delete destLayer; |
|
return nil; |
|
} |
|
else |
|
{ |
|
if( fErrorMsg->Set( !( fWarned & kWarnedNoBaseTexture ), "Plasma Export Error", sWarnBaseTextureMissing, maxNode->GetName(), bd->fileName ).CheckAskOrCancel() ) |
|
fWarned |= kWarnedNoBaseTexture; |
|
fErrorMsg->Set( false ); |
|
|
|
return destLayer; |
|
} |
|
} |
|
else |
|
hsgResMgr::ResMgr()->AddViaNotify( texture->GetKey(), new plLayRefMsg( destLayer->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef ); |
|
|
|
return destLayer; |
|
} |
|
|
|
//// IMakeCubicRenderTarget /////////////////////////////////////////////////// |
|
// Makes a plCubicRenderTarget as a texture. Also constructs the associated |
|
// modifier and attaches it to the necessary object (hacked for now) |
|
|
|
plCubicRenderTarget *plLayerConverter::IMakeCubicRenderTarget( const plString &name, plMaxNode *node, plMaxNode *anchor ) |
|
{ |
|
plDynamicEnvMap* env = plEnvMapComponent::GetEnvMap(anchor); |
|
if( env ) |
|
return env; |
|
|
|
plCubicRenderTarget *cubic = nil; |
|
|
|
|
|
plKey key; |
|
|
|
key = node->FindPageKey( plCubicRenderTarget::Index(), name ); |
|
if( key != nil ) |
|
{ |
|
plCubicRenderTarget *cubic = plCubicRenderTarget::ConvertNoRef( key->GetObjectPtr() ); |
|
if( cubic != nil ) |
|
return cubic; |
|
} |
|
|
|
/// Get the key from the anchor |
|
if( anchor == nil || anchor->GetSceneObject() == nil ) |
|
return nil; |
|
|
|
plKey sObjKey = anchor->GetSceneObject()->GetKey(); |
|
if( sObjKey == nil ) |
|
return nil; |
|
|
|
/// Create |
|
cubic = new plCubicRenderTarget( plRenderTarget::kIsTexture, 256, 256, 32 ); |
|
hsAssert( cubic != nil, "Cannot create cubic render target!" ); |
|
|
|
/// Add a key |
|
key = hsgResMgr::ResMgr()->NewKey( name, cubic, node->GetLocation() ); |
|
|
|
/// Now make a modifier |
|
plCubicRenderTargetModifier *mod = new plCubicRenderTargetModifier(); |
|
plString modName = plString::Format( "%s_mod", name.c_str() ); |
|
|
|
hsgResMgr::ResMgr()->NewKey( modName, mod, node->GetLocation() ); |
|
hsgResMgr::ResMgr()->AddViaNotify( cubic->GetKey(), new plGenRefMsg( mod->GetKey(), plRefMsg::kOnCreate, 0, 0 ), plRefFlags::kPassiveRef ); |
|
hsgResMgr::ResMgr()->AddViaNotify( mod->GetKey(), new plObjRefMsg( sObjKey, plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef ); |
|
|
|
return cubic; |
|
}
|
|
|