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.
1137 lines
37 KiB
1137 lines
37 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==*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// 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 "hsWindows.h"
|
||
|
#include "Max.h"
|
||
|
#include "stdmat.h"
|
||
|
#include "istdplug.h"
|
||
|
#include "iparamb2.h"
|
||
|
#include "iparamm2.h"
|
||
|
|
||
|
#include "hsUtils.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"
|
||
|
#ifdef USE_BINK_SDK
|
||
|
#include "../pfSurface/plLayerBink.h"
|
||
|
#endif
|
||
|
|
||
|
#include "../MaxPlasmaMtls/Layers/plPlasmaMAXLayer.h"
|
||
|
#include "../MaxPlasmaMtls/Layers/plLayerTex.h"
|
||
|
#include "../MaxPlasmaMtls/Layers/plLayerTexBasicPB.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 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 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( 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 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 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( 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 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 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( 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() ).Show();
|
||
|
fErrorMsg->Set();
|
||
|
return (plLayerInterface *)plasmaLayer;
|
||
|
}
|
||
|
|
||
|
// Create texture and add it to list if unique
|
||
|
Int32 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
|
||
|
char texName[ 256 ];
|
||
|
if( anchor == maxNode )
|
||
|
{
|
||
|
// Self-anchoring material, make sure the name is unique via the nodeName
|
||
|
sprintf( texName, "%s_cubicRT@%s", plasmaLayer->GetKeyName(), maxNode->GetName() );
|
||
|
}
|
||
|
else
|
||
|
sprintf( texName, "%s_cubicRT", plasmaLayer->GetKeyName() );
|
||
|
|
||
|
plBitmap *texture = (plBitmap *)IMakeCubicRenderTarget( texName, maxNode, anchor );
|
||
|
if( texture )
|
||
|
hsgResMgr::ResMgr()->AddViaNotify( texture->GetKey(), TRACKED_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 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 (layer->GetName(), upperLayer, loc);
|
||
|
|
||
|
plMaxNode *rootNode = (plMaxNode*)pb->GetINode(ParamID(plMAXCameraLayer::kRootNode));
|
||
|
plDynamicCamMap *map = plEnvMapComponent::GetCamMap(rootNode ? rootNode : maxNode);
|
||
|
if (map)
|
||
|
{
|
||
|
Int32 texFlags = 0;
|
||
|
if (!pb->GetInt(ParamID(plMAXCameraLayer::kExplicitCam)))
|
||
|
{
|
||
|
plasmaLayer->SetUVWSrc(plLayerInterface::kUVWPosition);
|
||
|
plasmaLayer->SetMiscFlags(hsGMatState::kMiscCam2Screen | hsGMatState::kMiscPerspProjection);
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(rootNode->GetSceneObject()->GetKey(), TRACKED_NEW plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefRootNode), plRefFlags::kActiveRef);
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(plasmaLayer->GetKey(), TRACKED_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(), TRACKED_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(), TRACKED_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(), TRACKED_NEW plGenRefMsg(map->GetKey(), plRefMsg::kOnCreate, -1, plDynamicCamMap::kRefTargetNode), plRefFlags::kActiveRef);
|
||
|
}
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(map->GetKey(), TRACKED_NEW plLayRefMsg(plasmaLayer->GetKey(), plRefMsg::kOnCreate, -1, plLayRefMsg::kTexture), plRefFlags::kActiveRef);
|
||
|
|
||
|
}
|
||
|
|
||
|
return plasmaLayer;
|
||
|
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
|
||
|
//// IConvertDynamicTextLayer /////////////////////////////////////////////////
|
||
|
|
||
|
plLayerInterface *plLayerConverter::IConvertDynamicTextLayer( plPlasmaMAXLayer *layer,
|
||
|
plMaxNode *maxNode, UInt32 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( 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 *initBuffer = IGetInitBitmapBuffer( maxLayer );
|
||
|
if( initBuffer != nil )
|
||
|
{
|
||
|
texture->SetInitBuffer( initBuffer );
|
||
|
delete [] initBuffer;
|
||
|
}
|
||
|
|
||
|
// Add the texture in
|
||
|
hsgResMgr::ResMgr()->AddViaNotify( texture->GetKey(), TRACKED_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 *plLayerConverter::IGetInitBitmapBuffer( plDynamicTextLayer *layer ) const
|
||
|
{
|
||
|
UInt32 *buffer;
|
||
|
hsRGBAColor32 *buffPtr;
|
||
|
UInt16 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 = TRACKED_NEW UInt32[ 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 MakeUInt32Color(float r, float g, float b, float a)
|
||
|
{
|
||
|
return (UInt32(a * 255.9f) << 24)
|
||
|
|(UInt32(r * 255.9f) << 16)
|
||
|
|(UInt32(g * 255.9f) << 8)
|
||
|
|(UInt32(b * 255.9f) << 0);
|
||
|
}
|
||
|
|
||
|
plBitmap* plLayerConverter::IGetAttenRamp(plMaxNode *node, BOOL isAdd, int loClamp, int hiClamp)
|
||
|
{
|
||
|
char funkName[512];
|
||
|
sprintf(funkName, "%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* pix = (UInt32*)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 char* 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 = TRACKED_NEW plLayer;
|
||
|
layer->InitToDefault();
|
||
|
hsgResMgr::ResMgr()->NewKey(name, layer, node->GetLocation());
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(funkRamp->GetKey(), TRACKED_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 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 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(layer->GetName(), maxNode, uvwSrc, tr0, op0, tr1, op1, loClamp, hiClamp);
|
||
|
|
||
|
return lut;
|
||
|
|
||
|
hsGuardEnd;
|
||
|
}
|
||
|
//// ICreateLayer /////////////////////////////////////////////////////////////
|
||
|
|
||
|
plLayer *plLayerConverter::ICreateLayer( const char *name, hsBool upperLayer, plLocation &loc )
|
||
|
{
|
||
|
hsGuardBegin( "plPlasmaMAXLayer::ICreateLayer" );
|
||
|
|
||
|
plLayer *layer = TRACKED_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 uvwSrc = srcLayer->GetMapChannel() - 1;
|
||
|
|
||
|
if( fErrorMsg->Set( !( fWarned & kWarnedTooManyUVs ) &&
|
||
|
( ( uvwSrc < 0 ) || ( uvwSrc >= plGeometrySpan::kMaxNumUVChannels ) ),
|
||
|
destLayer->GetKeyName(), "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 char *layerName, UInt32 width, UInt32 height,
|
||
|
hsBool includeAlphaChannel, plMaxNode *node )
|
||
|
{
|
||
|
hsGuardBegin( "plPlasmaMAXLayer::ICreateDynTextMap" );
|
||
|
|
||
|
char texName[ 256 ];
|
||
|
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
|
||
|
sprintf( texName, "%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 = TRACKED_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 clipID /* = 0 */, UInt32 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(), TRACKED_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 char *name, plMaxNode *node, plMaxNode *anchor )
|
||
|
{
|
||
|
plDynamicEnvMap* env = plEnvMapComponent::GetEnvMap(anchor);
|
||
|
if( env )
|
||
|
return env;
|
||
|
|
||
|
char modName[ 256 ];
|
||
|
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 = TRACKED_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 = TRACKED_NEW plCubicRenderTargetModifier();
|
||
|
sprintf( modName, "%s_mod", name );
|
||
|
|
||
|
hsgResMgr::ResMgr()->NewKey( modName, mod, node->GetLocation() );
|
||
|
hsgResMgr::ResMgr()->AddViaNotify( cubic->GetKey(), TRACKED_NEW plGenRefMsg( mod->GetKey(), plRefMsg::kOnCreate, 0, 0 ), plRefFlags::kPassiveRef );
|
||
|
hsgResMgr::ResMgr()->AddViaNotify( mod->GetKey(), TRACKED_NEW plObjRefMsg( sObjKey, plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
|
||
|
|
||
|
return cubic;
|
||
|
}
|