2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301356 additions and 0 deletions

View File

@ -0,0 +1,266 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// Export/convert-specific functionality of plAnimStealthNode //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plAnimStealthNode.h"
#include "plPassMtlBase.h"
#include "resource.h"
#include "../MaxMain/plMaxNode.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "../MaxConvert/plConvert.h"
#include "../MaxConvert/hsMaterialConverter.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayerAnimation.h"
#include "iparamm2.h"
//// Helpers /////////////////////////////////////////////////////////////////
static void ISearchLayerRecur( plLayerInterface *layer, const char *segName, hsTArray<plKey>& keys )
{
if( !layer )
return;
plLayerAnimation *animLayer = plLayerAnimation::ConvertNoRef(layer);
if (animLayer)
{
char *ID = animLayer->GetSegmentID();
if (ID == nil)
ID = "";
if (!strcmp(ID, segName))
{
if( keys.kMissingIndex == keys.Find(animLayer->GetKey()) )
keys.Append(animLayer->GetKey());
}
}
ISearchLayerRecur(layer->GetAttached(), segName, keys);
}
static int ISearchLayerRecur(hsGMaterial* mat, const char *segName, hsTArray<plKey>& keys)
{
if (segName == nil || strcmp( segName, ENTIRE_ANIMATION_NAME ) == 0 )
segName = "";
int i;
for( i = 0; i < mat->GetNumLayers(); i++ )
ISearchLayerRecur(mat->GetLayer(i), segName, keys);
return keys.GetCount();
}
static int GetMatAnimModKey(Mtl* mtl, plMaxNodeBase* node, const char* segName, hsTArray<plKey>& keys)
{
int retVal = 0;
int i;
//if( begin < 0 )
// begin = 0;
if( mtl->ClassID() == Class_ID(MULTI_CLASS_ID,0) )
{
for( i = 0; i < mtl->NumSubMtls(); i++ )
retVal += GetMatAnimModKey(mtl->GetSubMtl(i), node, segName, keys);
}
else
{
hsTArray<hsGMaterial*> matList;
if (node)
hsMaterialConverter::Instance().GetMaterialArray(mtl, (plMaxNode*)node, matList);
else
hsMaterialConverter::Instance().CollectConvertedMaterials(mtl, matList);
for( i = 0; i < matList.GetCount(); i++ )
{
retVal += ISearchLayerRecur(matList[i], segName, keys);
}
}
return retVal;
}
SegmentSpec *plAnimStealthNode::IGetSegmentSpec( void ) const
{
if( fCachedSegMap != nil )
{
const char *name = GetSegmentName();
if( name != nil )
{
SegmentMap::iterator i = fCachedSegMap->find( name );
if( i != fCachedSegMap->end() )
{
SegmentSpec *spec = i->second;
return spec;
}
}
}
return nil;
}
hsScalar plAnimStealthNode::GetSegStart( void ) const
{
SegmentSpec *spec = IGetSegmentSpec();
if( spec != nil )
return spec->fStart;
return 0.f;
}
hsScalar plAnimStealthNode::GetSegEnd( void ) const
{
SegmentSpec *spec = IGetSegmentSpec();
if( spec != nil )
return spec->fEnd;
return 0.f;
}
void plAnimStealthNode::GetLoopPoints( hsScalar &start, hsScalar &end ) const
{
start = GetSegStart();
end = GetSegEnd();
const char *loopName = GetLoopName();
if( loopName != nil && loopName[ 0 ] != 0 && fCachedSegMap != nil )
GetSegMapAnimTime( loopName, fCachedSegMap, SegmentSpec::kLoop, start, end );
}
void plAnimStealthNode::GetAllStopPoints( hsTArray<hsScalar> &out )
{
if( fCachedSegMap == nil )
return;
for (SegmentMap::iterator it = fCachedSegMap->begin(); it != fCachedSegMap->end(); it++)
{
SegmentSpec *spec = it->second;
if( spec->fType == SegmentSpec::kStopPoint )
{
out.Append( spec->fStart );
}
}
}
//// StuffToTimeConvert //////////////////////////////////////////////////////
// Handles converting all the settings we have that are applicable for an
// animTimeConvert and stuffing it into said ATC.
void plAnimStealthNode::StuffToTimeConvert( plAnimTimeConvert &convert, hsScalar maxLength )
{
const char *segName = GetSegmentName();
bool isEntire = ( segName == nil || strcmp( segName, ENTIRE_ANIMATION_NAME ) == 0 ) ? true : false;
if( isEntire )
{
convert.SetBegin( 0 );
convert.SetEnd( maxLength );
}
else
{
SegmentSpec *spec = IGetSegmentSpec();
convert.SetBegin( ( spec != nil ) ? spec->fStart : 0.f );
convert.SetEnd( ( spec != nil ) ? spec->fEnd : 0.f );
}
// Even if we're not looping, set the loop points. (A responder
// could tell us later to start looping.)
if( isEntire )
convert.SetLoopPoints( 0, maxLength );
else
{
hsScalar loopStart, loopEnd;
GetLoopPoints( loopStart, loopEnd );
convert.SetLoopPoints( loopStart, loopEnd );
}
convert.Loop( GetLoop() );
// Auto-start
if( GetAutoStart() )
convert.Start( 0 );
else
convert.Stop( true );
// Stuff stop points
GetAllStopPoints( convert.GetStopPoints() );
// Ease curve stuff
if( GetEaseInType() != plAnimEaseTypes::kNoEase )
{
convert.SetEase( true, GetEaseInType(), GetEaseInMin(), GetEaseInMax(), GetEaseInLength() );
}
if( GetEaseOutType() != plAnimEaseTypes::kNoEase )
{
convert.SetEase( false, GetEaseOutType(), GetEaseOutMin(), GetEaseOutMax(), GetEaseOutLength() );
}
}
//// plAnimObjInterface Functions ////////////////////////////////////////////
hsBool plAnimStealthNode::GetKeyList( INode *restrictedNode, hsTArray<plKey> &outKeys )
{
if( !fPreppedForConvert )
{
hsMessageBox( "This messages is to warn you that mcn screwed up in his attempt to create "
"a SetupProperties() pass for materials in this scene. You should probably let him know as soon as "
"possible, and also make a copy of this exact scene so that he can test with it and figure out what "
"is going wrong. Thank you.", "Mathew is Stupid Error", hsMessageBoxNormal );
}
GetMatAnimModKey( GetParentMtl(), (plMaxNode *)restrictedNode, GetSegmentName(), outKeys );
return true;
}
//// SetupProperties /////////////////////////////////////////////////////////
hsBool plAnimStealthNode::SetupProperties( plMaxNode *node, plErrorMsg *pErrMsg )
{
fPreppedForConvert = true;
plPassMtlBase *parent = GetParentMtl();
if( parent != nil && fCachedSegMap == nil )
{
fCachedSegMap = GetAnimSegmentMap( parent, nil );
}
return true;
}
//// ConvertDeInit ///////////////////////////////////////////////////////////
hsBool plAnimStealthNode::ConvertDeInit( plMaxNode *node, plErrorMsg *pErrMsg )
{
fPreppedForConvert = false;
if( fCachedSegMap != nil )
DeleteSegmentMap( fCachedSegMap );
fCachedSegMap = nil;
return true;
}

View File

@ -0,0 +1,970 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAnimStealthNode - Stealthy hidden INode that represents a single //
// segment's worth of animation info for a material. //
// Stored as an INode so they can be "selected" //
// by components as targets of animation messages. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plAnimStealthNode.h"
#include "plPassMtlBase.h"
#include "resource.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "../MaxComponent/plPickNodeBase.h"
#include "iparamm2.h"
extern TCHAR *GetString( int id );
extern HINSTANCE hInstance;
//// Stealthy Class Desc /////////////////////////////////////////////////////
class plStealthClassDesc : public ClassDesc2
{
public:
int IsPublic() { return FALSE; }
void* Create(BOOL loading) { return TRACKED_NEW plAnimStealthNode(loading); }
const TCHAR* ClassName() { return GetString( IDS_STEALTH_NAME ); }
SClass_ID SuperClassID() { return HELPER_CLASS_ID; }
Class_ID ClassID() { return ANIMSTEALTH_CLASSID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaAnimStealthInfo"); }
HINSTANCE HInstance() { return hInstance; }
};
static plStealthClassDesc sStealthClassDesc;
ClassDesc2* GetStealthClassDesc() { return &sStealthClassDesc; }
//// plStealthDlgProc /////////////////////////////////////////////////////////
// Dialog proc for the anim stealth child dialog
class plStealthDlgProc : public ParamMap2UserDlgProc
{
protected:
// Combo itemdata values
enum
{
kName, // Name of an animation/loop
kDefault, // Default combo value
kInvalid, // Invalid entry (couldn't find)
};
SegmentMap *fSegMap;
HWND fhWnd;
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void DeleteThis() { IDeleteSegMap(); }
void SetThing(ReferenceTarget *m);
void Update( TimeValue t, Interval &valid, IParamMap2 *pmap );
protected:
// Set all the controls to their stored value
void IInitControls( plAnimStealthNode *stealth, IParamBlock2 *pb);
// Deletes all the allocated memory
void IDeleteSegMap();
void ILoadLoops(IParamBlock2 *pb);
void ISetSel(HWND hCombo, const char *name);
};
const char *kAnimNameNone = ENTIRE_ANIMATION_NAME;
static plStealthDlgProc sStealthDlgProc;
//// Stealthy ParamBlock Desc ////////////////////////////////////////////////
static plEaseAccessor sEaseAccessor( plAnimStealthNode::kBlockPB, plAnimStealthNode::kPBEaseInMin,
plAnimStealthNode::kPBEaseInMax, plAnimStealthNode::kPBEaseInLength,
plAnimStealthNode::kPBEaseOutMin, plAnimStealthNode::kPBEaseOutMax,
plAnimStealthNode::kPBEaseOutLength );
ParamBlockDesc2 plAnimStealthNode::sAnimStealthPB
(
kBlockPB, _T( "animStealth" ), IDS_STEALTH_NAME, GetStealthClassDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI, kRefParamBlock,
// UI
IDD_STEALTH_ANIM, IDS_STEALTH_NAME, 0, 0, &sStealthDlgProc,
kPBName, _T("animName"), TYPE_STRING, 0, 0,
end,
kPBAutoStart, _T("autoStart"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_AUTO_START,
p_default, FALSE,
end,
kPBLoop, _T("loop"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_LOOP,
p_default, TRUE,
end,
kPBLoopName, _T("loopName"), TYPE_STRING, 0, 0,
end,
// Anim Ease
kPBEaseInType, _T("easeInType"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_PASS_ANIM_EASE_IN_NONE, IDC_PASS_ANIM_EASE_IN_CONST_ACCEL, IDC_PASS_ANIM_EASE_IN_SPLINE,
p_vals, plAnimEaseTypes::kNoEase, plAnimEaseTypes::kConstAccel, plAnimEaseTypes::kSpline,
p_default, plAnimEaseTypes::kNoEase,
end,
kPBEaseInLength, _T("easeInLength"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_IN_TIME, IDC_PASS_ANIM_EASE_IN_TIME_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
kPBEaseInMin, _T("easeInMin"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_IN_MIN, IDC_PASS_ANIM_EASE_IN_MIN_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
kPBEaseInMax, _T("easeInMax"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_IN_MAX, IDC_PASS_ANIM_EASE_IN_MAX_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
kPBEaseOutType, _T("easeOutType"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_PASS_ANIM_EASE_OUT_NONE, IDC_PASS_ANIM_EASE_OUT_CONST_ACCEL, IDC_PASS_ANIM_EASE_OUT_SPLINE,
p_vals, plAnimEaseTypes::kNoEase, plAnimEaseTypes::kConstAccel, plAnimEaseTypes::kSpline,
p_default, plAnimEaseTypes::kNoEase,
end,
kPBEaseOutLength, _T("easeOutLength"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_OUT_TIME, IDC_PASS_ANIM_EASE_OUT_TIME_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
kPBEaseOutMin, _T("easeOutMin"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_OUT_MIN, IDC_PASS_ANIM_EASE_OUT_MIN_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
kPBEaseOutMax, _T("easeOutMax"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.1, 99.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_PASS_ANIM_EASE_OUT_MAX, IDC_PASS_ANIM_EASE_OUT_MAX_SPIN, 1.0,
p_accessor, &sEaseAccessor,
end,
end
);
plAnimStealthNode::plAnimStealthNode( BOOL loading ) : fClassDesc(nil), fParamBlock(nil), fParentMtl(nil)
{
fCachedSegMap = nil;
fClassDesc = &sStealthClassDesc;
fClassDesc->MakeAutoParamBlocks( this );
}
plAnimStealthNode::~plAnimStealthNode()
{
// DeleteAllRefsFromMe();
}
CreateMouseCallBack *plAnimStealthNode::GetCreateMouseCallBack()
{
return nil;
}
void plAnimStealthNode::SetParentMtl( plPassMtlBase *parent )
{
fParentMtl = parent;
}
bool plAnimStealthNode::CanConvertToStealth( INode *objNode )
{
return ( ConvertToStealth( objNode ) != nil );
}
plAnimStealthNode *plAnimStealthNode::ConvertToStealth( INode *objNode )
{
if( objNode == nil )
return nil;
Object *obj = objNode->GetObjectRef();
if( obj == nil )
return nil;
if( obj->CanConvertToType( ANIMSTEALTH_CLASSID ) )
return (plAnimStealthNode *)obj;
return nil;
}
const char *plAnimStealthNode::GetSegmentName( void ) const
{
const char *str = fParamBlock->GetStr( (ParamID)kPBName );
if( str == nil || str[ 0 ] == 0 )
return ENTIRE_ANIMATION_NAME;
return str;
}
void plAnimStealthNode::SetSegment( const char *name )
{
if( name == nil || strcmp(name, ENTIRE_ANIMATION_NAME) == 0 || name[ 0 ] == 0 )
fParamBlock->SetValue( (ParamID)kPBName, 0, "" );
else
fParamBlock->SetValue( (ParamID)kPBName, 0, (char *)name );
}
void plAnimStealthNode::SetNodeName( const char *parentName )
{
INode *node = GetINode();
if( node != nil )
{
char name[ 512 ], newName[ 512 ];
sprintf( name, "%s : %s", parentName, GetSegmentName() );
if( GetCOREInterface()->GetINodeByName( name ) != nil )
{
// For whatever reason, MakeNameUnique() doesn't ACTUALLY make a name unique!
// So we just need to more or less do it ourselves...
int i;
for( i = 1; i < 1024; i++ )
{
sprintf( newName, "%s(%d)", name, i );
if( GetCOREInterface()->GetINodeByName( newName ) == nil )
break;
}
if( i == 1024 )
{
// You've got to be kidding me...
char msg[ 2048 ];
sprintf( msg, "WARNING: For some reason, we cannot find a unique name for the node '%s'. This"
" will most likely cause export problems. Exactly how many of these do we HAVE??",
name );
hsMessageBox( msg, "WARNING!", hsMessageBoxNormal );
}
}
else
strcpy( newName, name );
node->SetName( newName );
}
}
int plAnimStealthNode::NumParamBlocks()
{
return 1;
}
IParamBlock2 *plAnimStealthNode::GetParamBlock( int i )
{
if( i == kRefParamBlock )
return fParamBlock;
return nil;
}
IParamBlock2 *plAnimStealthNode::GetParamBlockByID( BlockID id )
{
if( fParamBlock && fParamBlock->ID() == id )
return fParamBlock;
return nil;
}
RefTargetHandle plAnimStealthNode::Clone(RemapDir &remap)
{
plAnimStealthNode *obj = (plAnimStealthNode *)fClassDesc->Create( false );
// Do the base clone
BaseClone(this, obj, remap);
// Copy our references
if (fParamBlock)
obj->ReplaceReference( kRefParamBlock, fParamBlock->Clone( remap ) );
return obj;
}
void plAnimStealthNode::BuildMesh(TimeValue t)
{
}
void plAnimStealthNode::FreeCaches()
{
}
void plAnimStealthNode::GetLocalBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box)
{
box.MakeCube(Point3(0,0,0), 0);
}
void plAnimStealthNode::GetWorldBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box)
{
box.MakeCube(Point3(0,0,0), 0);
}
int plAnimStealthNode::Display(TimeValue t, INode *node, ViewExp *vpt, int flags)
{
return 0;
}
int plAnimStealthNode::HitTest(TimeValue t, INode *node, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt)
{
return 0;
}
int plAnimStealthNode::NumRefs()
{
return 1;
}
RefTargetHandle plAnimStealthNode::GetReference( int i )
{
if( i == kRefParamBlock )
return fParamBlock;
else if( i == kRefParentMtl )
return fParentMtl;
return nil;
}
void plAnimStealthNode::SetReference( int i, RefTargetHandle rtarg )
{
if( i == kRefParamBlock )
fParamBlock = (IParamBlock2 *)rtarg;
else if( i == kRefParentMtl )
fParentMtl = (plPassMtlBase *)rtarg;
}
RefResult plAnimStealthNode::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
return REF_SUCCEED;
}
IOResult plAnimStealthNode::Save(ISave* isave)
{
return IO_OK;
}
IOResult plAnimStealthNode::Load(ILoad* iload)
{
return IO_OK;
}
plPassMtlBase *plAnimStealthNode::GetParentMtl( void )
{
return fParentMtl;
}
class plGetRefs : public DependentEnumProc
{
public:
hsTArray<ReferenceMaker *> fList;
plGetRefs() { }
virtual int proc( ReferenceMaker *rmaker )
{
fList.Append( rmaker );
return DEP_ENUM_CONTINUE;
}
};
hsBool plAnimStealthNode::IsParentUsedInScene( void )
{
if( GetParentMtl() == nil )
return false;
// There are two possibilities: either a node uses us and thus has a ref to us,
// or a multi-sub uses us that a node has a ref to us.
// Note: we could do the loop as a helper function, but we only do it twice,
// so it's not *really* worth the effort...
//// NOTE: the following doesn't seem to work, but keeping here in case it ever does.
//// What really actually finds something is the enum dependents loop below
const char *mtlName = GetParentMtl()->GetName();
RefList &refList = GetRefList();
RefListItem *item = refList.FirstItem();
while( item != nil )
{
TSTR s;
item->maker->GetClassName( s );
if( item->maker->SuperClassID() == BASENODE_CLASS_ID && !CanConvertToStealth( (INode *)( item->maker ) ) )
return true; // Horray, a node has a ref to us!
else if( item->maker->ClassID() == Class_ID(MULTI_CLASS_ID,0) )
{
// Multi-sub, run the refs on that guy (we only go one up)
Mtl *multisub = (Mtl *)item->maker;
RefList &refList2 = multisub->GetRefList();
RefListItem *item2 = refList.FirstItem();
while( item2 != nil )
{
if( item2->maker->SuperClassID() == BASENODE_CLASS_ID )
return true; // Horray, a node has a ref to us!
item2 = item2->next;
}
// No go, keep trying
}
else if( item->maker->SuperClassID() == MATERIAL_CLASS_ID )
{
int q = 0;
}
item = item->next;
}
// Enum dependents
int i;
plGetRefs callback;
GetParentMtl()->EnumDependents( &callback );
for( i = 0; i < callback.fList.GetCount(); i++ )
{
ReferenceMaker *maker = callback.fList[ i ];
TSTR s;
maker->GetClassName( s );
if( maker->SuperClassID() == BASENODE_CLASS_ID && !CanConvertToStealth( (INode *)maker ) )
return true; // Horray, a node has a ref to us!
}
return false;
}
INode *plAnimStealthNode::GetINode()
{
// Go through the reflist looking for RefMakers with a ref to this component.
// There should only be one INode in this list.
RefList &refList = GetRefList();
RefListItem *item = refList.FirstItem();
while( item )
{
if( item->maker->SuperClassID() == BASENODE_CLASS_ID )
return (INode *)item->maker;
item = item->next;
}
return nil;
}
void plStealthDlgProc::Update(TimeValue t, Interval& valid, IParamMap2* pmap)
{
// Does the pmap match our pmap?
}
//// plStealthMouseOverrideProc //////////////////////////////////////////////
// Because of wonderful linking problems with the MAX libraries, we can't
// actually use CreateChildMParamMap2 like we should. So instead, we use
// CreateChildCPParamMap2. However, *that* function calls the wrong interface
// to handle untrapped mouse messages, with the result that clicking and
// dragging scrolls the command pane (where components are displayed) instead
// of the material editor pane.
// To override this, we subclass each dialog so that we can capture the mouse
// messages before MAX processes them and then reroute them appropriately.
// Note: because MAX already uses the window long of the given window, we can't
// store the old proc of the window. However, since we always use
// CreateChildCPParamMap2, and because the MAX source code shows us that it
// always uses the same dialog proc for all windows created with that function,
// we can simply store the address of that proc the first time we subclass and
// use it for restoring every time thereafter (see the following DlgProc)
static WNDPROC sOldStealthDlgProc = nil;
static INT_PTR CALLBACK plStealthMouseOverrideProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
IParamMap2 *map = (IParamMap2 *)GetWindowLongPtr( hWnd, GWLP_USERDATA );
switch( msg )
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
{
// We don't want the COREInterface to process our mouse messages with RollupMouseMessage;
// rather, we want IMtlParams to do it just like it would if we could actually call
// CreateChildMParamMap2
IParamBlock2 *pb = map->GetParamBlock();
if( pb != nil )
{
plAnimStealthNode *stealth = (plAnimStealthNode *)pb->GetOwner();
if( stealth != nil )
{
plPassMtlBase *mtl = (plPassMtlBase *)stealth->GetParentMtl();
mtl->fIMtlParams->RollupMouseMessage( hWnd, msg, wParam, lParam );
}
}
return 0;
}
}
if( sOldStealthDlgProc != nil )
return CallWindowProc( sOldStealthDlgProc, hWnd, msg, wParam, lParam );
else
return 0;
}
BOOL plStealthDlgProc::DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
IParamBlock2 *pb = map->GetParamBlock();
plAnimStealthNode *stealth = (plAnimStealthNode *)pb->GetOwner();
switch (msg)
{
case WM_INITDIALOG:
{
// Install our override proc so we can capture mouse messages ourselves.
// Note that the first time, we grab the old proc so we can restore with that
// one every time after, since they should always be the same proc
WNDPROC old = (WNDPROC)SetWindowLongPtr( hWnd, DWLP_DLGPROC, (LONG_PTR)plStealthMouseOverrideProc );
if( sOldStealthDlgProc == nil )
sOldStealthDlgProc = old;
fhWnd = hWnd;
IInitControls( stealth, pb );
return TRUE;
}
case WM_DESTROY:
// Restore our old proc
SetWindowLongPtr( hWnd, DWLP_DLGPROC, (LONG_PTR)sOldStealthDlgProc );
break;
case WM_ENABLE:
// The entire dialog was either enabled or disabled.
break;
case WM_COMMAND:
// Loop selection changed
if( LOWORD( wParam ) == IDC_LOOPS && HIWORD( wParam ) == CBN_SELCHANGE )
{
// If a loop is selected, save it
HWND hCombo = (HWND)lParam;
int sel = SendMessage( hCombo, CB_GETCURSEL, 0, 0 );
if( sel != CB_ERR )
{
if( SendMessage( hCombo, CB_GETITEMDATA, sel, 0 ) == kName )
{
char buf[256];
SendMessage( hCombo, CB_GETLBTEXT, sel, (LPARAM)buf );
pb->SetValue( (ParamID)plAnimStealthNode::kPBLoopName, 0, buf );
}
else
pb->SetValue( (ParamID)plAnimStealthNode::kPBLoopName, 0, "" );
}
return TRUE;
}
// Auto-start or loop checkbox checked
if( LOWORD( wParam ) == IDC_LOOP && HIWORD( wParam ) == BN_CLICKED )
{
BOOL checked = ( SendMessage( (HWND)lParam, BM_GETCHECK, 0, 0 ) == BST_CHECKED );
pb->SetValue( plAnimStealthNode::kPBLoop, 0, checked );
EnableWindow( GetDlgItem( hWnd, IDC_LOOPS ), checked );
return TRUE;
}
// Refresh clicked
else if( LOWORD( wParam ) == IDC_REFRESH_ANIMS && HIWORD( wParam ) == BN_CLICKED )
{
IInitControls( stealth, pb );
return TRUE;
}
break;
}
return FALSE;
}
void plStealthDlgProc::SetThing(ReferenceTarget *m)
{
plAnimStealthNode *stealth = (plAnimStealthNode *)m;
IParamBlock2 *pb = stealth->GetParamBlockByID( plAnimStealthNode::kBlockPB );
IInitControls( stealth, pb );
}
void plStealthDlgProc::IDeleteSegMap()
{
// If we have a segment map, delete the memory associated with it
DeleteSegmentMap( fSegMap );
fSegMap = nil;
}
void plStealthDlgProc::ISetSel(HWND hCombo, const char *name)
{
// If there is a name, try and set that
if( name && strcmp( name, "" ) )
{
int idx = SendMessage( hCombo, CB_FINDSTRINGEXACT, -1, (LPARAM)name );
// If we can't find the saved name add a "not found" entry, so they know what it was
if( idx == -1 )
{
char buf[256];
sprintf( buf, "(not found) %s", name );
idx = SendMessage( hCombo, CB_ADDSTRING, 0, (LPARAM)buf );
SendMessage( hCombo, CB_SETITEMDATA, idx, kInvalid );
}
SendMessage( hCombo, CB_SETCURSEL, idx, 0 );
}
// No name, set it to none
else
{
int count = SendMessage( hCombo, CB_GETCOUNT, 0, 0 );
for( int i = 0; i < count; i++ )
{
if( SendMessage( hCombo, CB_GETITEMDATA, i, 0 ) == kDefault )
SendMessage( hCombo, CB_SETCURSEL, i, 0 );
}
}
}
void plStealthDlgProc::IInitControls( plAnimStealthNode *stealth, IParamBlock2 *pb )
{
IDeleteSegMap();
if( stealth->GetParentMtl() != nil )
{
fSegMap = GetAnimSegmentMap( stealth->GetParentMtl(), nil );
ILoadLoops( pb );
}
else
{
// ?? What should we do?
fSegMap = nil;
hsStatusMessage( "No parent material yet in plStealthDlgProc::IInitControls()...not good..." );
}
// Enable/disable the loop dropdown
EnableWindow( GetDlgItem( fhWnd, IDC_LOOPS ), pb->GetInt( (ParamID)plAnimStealthNode::kPBLoop ) );
}
void plStealthDlgProc::ILoadLoops(IParamBlock2 *pb)
{
HWND hLoops = GetDlgItem( fhWnd, IDC_LOOPS );
SendMessage( hLoops, CB_RESETCONTENT, 0, 0 );
// Add the default option
int defIdx = SendMessage( hLoops, CB_ADDSTRING, 0, (LPARAM)ENTIRE_ANIMATION_NAME );
SendMessage( hLoops, CB_SETITEMDATA, defIdx, kDefault );
const char *segName = pb->GetStr( (ParamID)plAnimStealthNode::kPBName );
if( segName == nil || fSegMap == nil )
{
// Default of "entire animation", no other loop options
SendMessage( hLoops, CB_SETCURSEL, defIdx, 0 );
return;
}
SegmentSpec *animSpec = (*fSegMap)[ segName ];
if( animSpec && fSegMap )
{
// for each segment we found:
for( SegmentMap::iterator i = fSegMap->begin(); i != fSegMap->end(); i++ )
{
SegmentSpec *spec = (*i).second;
if( spec->fType == SegmentSpec::kLoop )
{
// If the loop is contained by the animation, add it
if( (spec->fStart == -1 || spec->fStart >= animSpec->fStart) &&
(spec->fEnd == -1 || spec->fEnd <= animSpec->fEnd) )
{
// Add the name
int idx = SendMessage( hLoops, CB_ADDSTRING, 0, (LPARAM)spec->fName );
SendMessage( hLoops, CB_SETITEMDATA, idx, kName );
}
}
}
}
ISetSel( hLoops, pb->GetStr( (ParamID)plAnimStealthNode::kPBLoopName ) );
}
void plAnimStealthNode::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev)
{
fClassDesc->BeginEditParams(ip, this, flags, prev);
}
void plAnimStealthNode::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next)
{
fClassDesc->EndEditParams(ip, this, flags, next);
}
//// ReleaseDlg //////////////////////////////////////////////////////////////
void plAnimStealthNode::ReleaseDlg( void )
{
IParamMap2 *map = fParamBlock->GetMap();
fParamBlock->SetMap( nil );
if( map != nil )
DestroyChildCPParamMap2( map );
}
//// SwitchDlg ///////////////////////////////////////////////////////////////
// Switch underlying objects in the dialog (to avoid unnecessary deletion/
// recreations)
void plAnimStealthNode::SwitchDlg( plAnimStealthNode *toSwitchTo )
{
IParamMap2 *map = fParamBlock->GetMap();
fParamBlock->SetMap( nil );
toSwitchTo->fParamBlock->SetMap( map );
map->SetParamBlock( toSwitchTo->fParamBlock );
map->SetThing( (ReferenceTarget *)toSwitchTo );
map->Invalidate();
map->UpdateUI( 0 );
}
//// CreateAndEmbedDlg ///////////////////////////////////////////////////////
// Create the dialog for this object and place it inside the given dialog,
// centering it in the given control if any.
bool plAnimStealthNode::CreateAndEmbedDlg( IParamMap2 *parentMap, IMtlParams *parentParams, HWND frameCtrl )
{
IParamMap2 *map = CreateChildCPParamMap2( fParamBlock, GetCOREInterface(), hInstance,
parentMap, MAKEINTRESOURCE( IDD_STEALTH_ANIM ),
nil, &sStealthDlgProc );
fParamBlock->SetMap( map );
if( frameCtrl != nil )
{
HWND child = fParamBlock->GetMap()->GetHWnd();
RECT childFrame, centerFrame;
::GetClientRect( child, &childFrame );
::GetWindowRect( frameCtrl, &centerFrame );
::MapWindowPoints( nil, parentMap->GetHWnd(), (POINT *)&centerFrame, 2 );
int frameWidth = centerFrame.right - centerFrame.left;
int frameHeight = centerFrame.bottom - centerFrame.top;
int childWidth = childFrame.right - childFrame.left;
int childHeight = childFrame.bottom - childFrame.top;
::OffsetRect( &childFrame, ( frameWidth - childWidth ) >> 1, ( frameHeight - childHeight ) >> 1 );
::OffsetRect( &childFrame, centerFrame.left, centerFrame.top );
::SetWindowPos( child, nil, childFrame.left, childFrame.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
}
return true;
}
//// GetWinDlg ///////////////////////////////////////////////////////////////
// Get the actual window handle of the currently active dialog displaying us
HWND plAnimStealthNode::GetWinDlg( void ) const
{
IParamMap2 *map = fParamBlock->GetMap();
if( map != nil )
return map->GetHWnd();
return nil;
}
//// Picker Dialog for Restricted Animation Components //////////////////////////////////////////
class plPickAnimStealthNode : public plPickMtlNode
{
protected:
ParamID fTypeID;
void IAddUserType(HWND hList)
{
int type = fPB->GetInt(fTypeID);
int idx = ListBox_AddString( hList, kUseParamBlockNodeString );
if (type == plAnimObjInterface::kUseParamBlockNode && !fPB->GetINode(fNodeParamID))
ListBox_SetCurSel(hList, idx);
idx = ListBox_AddString( hList, kUseOwnerNodeString );
if (type == plAnimObjInterface::kUseOwnerNode)
ListBox_SetCurSel(hList, idx);
}
void ISetUserType(plMaxNode* node, const char* userType)
{
if( hsStrEQ( userType, kUseParamBlockNodeString ) )
{
ISetNodeValue(nil);
fPB->SetValue(fTypeID, 0, plAnimObjInterface::kUseParamBlockNode);
}
else if( hsStrEQ(userType, kUseOwnerNodeString ) )
{
ISetNodeValue(nil);
fPB->SetValue(fTypeID, 0, plAnimObjInterface::kUseOwnerNode);
}
else
fPB->SetValue(fTypeID, 0, plAnimObjInterface::kUseParamBlockNode);
}
public:
plPickAnimStealthNode(IParamBlock2* pb, ParamID nodeParamID, ParamID typeID, Mtl *mtl) :
plPickMtlNode(pb, nodeParamID, mtl), fTypeID(typeID)
{
}
};
//// plAnimObjInterface Functions ////////////////////////////////////////////
void plAnimStealthNode::PickTargetNode( IParamBlock2 *destPB, ParamID destParamID, ParamID typeID )
{
plPickAnimStealthNode pick( destPB, destParamID, typeID, (Mtl *)GetParentMtl() );
pick.DoPick();
}
const char *plAnimStealthNode::GetIfaceSegmentName( hsBool allowNil )
{
// When sending messages to material animations, they're already addressed for the right
// layer, no need for a segment name
return nil;
}
//// Parameter Access Functions //////////////////////////////////////////////
#pragma warning( push )
#pragma warning( disable:4800 ) // Forcing value to bool true or false (go figure, i'm even explicitly casting)
bool plAnimStealthNode::GetAutoStart( void ) const { return (bool)fParamBlock->GetInt( (ParamID)kPBAutoStart ); }
void plAnimStealthNode::SetAutoStart( bool b ) { fParamBlock->SetValue( (ParamID)kPBAutoStart, 0, (int)b ); };
bool plAnimStealthNode::GetLoop( void ) const { return fParamBlock->GetInt( (ParamID)kPBLoop ); }
const char *plAnimStealthNode::GetLoopName( void ) const { return fParamBlock->GetStr( (ParamID)kPBLoopName ); }
void plAnimStealthNode::SetLoop( bool b, const char *name )
{
fParamBlock->SetValue( (ParamID)kPBLoop, 0, (int)b );
if( name == nil )
fParamBlock->SetValue( (ParamID)kPBLoopName, 0, "" );
else
fParamBlock->SetValue( (ParamID)kPBLoopName, 0, (char *)name );
}
UInt8 plAnimStealthNode::GetEaseInType( void ) const { return (UInt8)fParamBlock->GetInt( (ParamID)kPBEaseInType ); }
hsScalar plAnimStealthNode::GetEaseInLength( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseInLength ); }
hsScalar plAnimStealthNode::GetEaseInMin( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseInMin ); }
hsScalar plAnimStealthNode::GetEaseInMax( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseInMax ); }
void plAnimStealthNode::SetEaseIn( UInt8 type, hsScalar length, hsScalar min, hsScalar max )
{
fParamBlock->SetValue( (ParamID)kPBEaseInType, 0, (int)type );
fParamBlock->SetValue( (ParamID)kPBEaseInLength, 0, (float)length );
fParamBlock->SetValue( (ParamID)kPBEaseInMin, 0, (float)min );
fParamBlock->SetValue( (ParamID)kPBEaseInMax, 0, (float)max );
}
UInt8 plAnimStealthNode::GetEaseOutType( void ) const { return (UInt8)fParamBlock->GetInt( (ParamID)kPBEaseOutType ); }
hsScalar plAnimStealthNode::GetEaseOutLength( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseOutLength ); }
hsScalar plAnimStealthNode::GetEaseOutMin( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseOutMin ); }
hsScalar plAnimStealthNode::GetEaseOutMax( void ) const { return (hsScalar)fParamBlock->GetFloat( (ParamID)kPBEaseOutMax ); }
void plAnimStealthNode::SetEaseOut( UInt8 type, hsScalar length, hsScalar min, hsScalar max )
{
fParamBlock->SetValue( (ParamID)kPBEaseOutType, 0, (int)type );
fParamBlock->SetValue( (ParamID)kPBEaseOutLength, 0, (float)length );
fParamBlock->SetValue( (ParamID)kPBEaseOutMin, 0, (float)min );
fParamBlock->SetValue( (ParamID)kPBEaseOutMax, 0, (float)max );
}
#pragma warning( pop ) // Forcing value to bool true or false (go figure, i'm even explicitly casting)
//// Parent Accessor Functions ///////////////////////////////////////////////
plStealthNodeAccessor &plStealthNodeAccessor::GetInstance( void )
{
static plStealthNodeAccessor instance;
return instance;
}
void plStealthNodeAccessor::ISetParent( ReferenceTarget *target, plPassMtlBase *parent )
{
if( target != nil && target->ClassID() == ANIMSTEALTH_CLASSID )
{
( (plAnimStealthNode *)target )->SetParentMtl( parent );
}
}
void plStealthNodeAccessor::TabChanged( tab_changes changeCode, Tab<PB2Value> *tab, ReferenceMaker *owner,
ParamID id, int tabIndex, int count )
{
if( changeCode == tab_insert || changeCode == tab_append )
{
if( owner->SuperClassID() != MATERIAL_CLASS_ID )
return;
plPassMtlBase *mtl = (plPassMtlBase *)owner;
while( count > 0 )
{
ISetParent( (*tab)[ tabIndex ].r, mtl );
tabIndex++;
count--;
}
}
else if( changeCode == tab_delete || changeCode == tab_ref_deleted )
{
// How are we supposed to handle this if we don't even get a stinkin pointer??
}
}
void plStealthNodeAccessor::Set( PB2Value &v, ReferenceMaker *owner, ParamID id, int tabIndex, TimeValue t )
{
// Bit of error checking
if( owner->SuperClassID() != MATERIAL_CLASS_ID )
return;
plPassMtlBase *mtl = (plPassMtlBase *)owner;
IParamBlock2 *pb = mtl->fAnimPB;
// A stealth node paramBlock value just got set. First make sure we
// un-set the old stealth's parent
ISetParent( pb->GetReferenceTarget( id, tabIndex ), nil );
// So make sure that the stealth node that was just added gets its parent mtl set properly
ISetParent( v.r, mtl );
}

View File

@ -0,0 +1,247 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAnimStealthNode - Stealthy hidden INode that represents a single //
// segment's worth of animation info for a material. //
// Stored as an INode so they can be "selected" //
// by components as targets of animation messages. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plAnimStealthNode_h
#define _plAnimStealthNode_h
#include "Max.h"
#include "iparamb2.h"
#include "iparamm2.h"
#include "hsTypes.h"
#include "../pnKeyedObject/plKey.h"
#include "../MaxComponent/plAnimObjInterface.h"
#include "../MaxComponent/plMaxAnimUtils.h"
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;
#define ANIMSTEALTH_CLASSID Class_ID(0xd0272f8, 0x750349c9)
#define REFMSG_NOTETRACK_ADDED REFMSG_USER + 1
class plPassMtlBase;
class NoteTrack;
class plMaxNode;
class plErrorMsg;
class plAnimTimeConvert;
//// Class Def ///////////////////////////////////////////////////////////////
class plAnimStealthNode : public HelperObject, public plAnimObjInterface
{
protected:
ClassDesc2 *fClassDesc;
IParamBlock2 *fParamBlock;
plPassMtlBase *fParentMtl;
static ParamBlockDesc2 sAnimStealthPB;
hsBool fPreppedForConvert;
SegmentMap *fCachedSegMap;
SegmentSpec *IGetSegmentSpec( void ) const;
public:
// Some IDs
enum
{
kBlockPB = 0
};
enum Refs
{
kRefParamBlock,
kRefParentMtl
};
// ParamBlock IDs
enum ParamBlockIDs
{
kPBAutoStart, // Start the Animation on load (V2)
kPBLoop, // Start Looping at Begin Location
kPBName, // Name of the notetrack animation to play
kPBLoopName, // Name of the notetrack specified loop
kPBEaseInType,
kPBEaseOutType,
kPBEaseInLength,
kPBEaseOutLength,
kPBEaseInMin,
kPBEaseInMax,
kPBEaseOutMin,
kPBEaseOutMax
};
plAnimStealthNode( BOOL loading );
virtual ~plAnimStealthNode();
void DeleteThis() { delete this; }
INode *GetINode( void );
plPassMtlBase *GetParentMtl( void );
void SetParentMtl( plPassMtlBase *parent );
void SetNodeName( const char *parentName );
// Create the dialog for this object and place it inside the given dialog, centering it in the given control if any
bool CreateAndEmbedDlg( IParamMap2 *parentMap, IMtlParams *parentParams, HWND frameCtrl = nil );
// Release said dialog
void ReleaseDlg( void );
// Switch underlying objects in the dialog (to avoid unnecessary deletion/recreations)
void SwitchDlg( plAnimStealthNode *toSwitchTo );
// Get the actual window handle of the currently active dialog displaying us
HWND GetWinDlg( void ) const;
// Interesting functions
const char *GetSegmentName( void ) const;
void SetSegment( const char *name ); // nil for "entire animation"
// Conversion from stealth's INode to the actual object
static bool CanConvertToStealth( INode *objNode );
static plAnimStealthNode *ConvertToStealth( INode *objNode );
///////////////////////////////////////////////////////////////////////////////////////
// Required Max functions
//
TCHAR* GetObjectName() { return (TCHAR*)fClassDesc->ClassName(); }
void InitNodeName(TSTR& s) { s = fClassDesc->InternalName(); }
void GetClassName(TSTR& s) { s = fClassDesc->ClassName(); }
Class_ID ClassID() { return ANIMSTEALTH_CLASSID; }
RefTargetHandle Clone(RemapDir &remap);
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
RefResult NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget, PartID& partID, RefMessage message);
// allow retreival of our paramblock from other plug-ins
// and the max core
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// We override because we don't want to be able to animate this sucker
int NumSubs() { return 0; }
Animatable *SubAnim( int i ) { return nil; }
TSTR SubAnimName( int i ) { return fClassDesc->ClassName(); }
// plug-in mouse creation callback
CreateMouseCallBack* GetCreateMouseCallBack();
void BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev);
void EndEditParams(IObjParam *ip, ULONG flags, Animatable *next);
// void SelectionSetChanged(Interface *ip, IUtil *iu);
void BuildMesh(TimeValue t);
void FreeCaches();
void GetLocalBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box);
void GetWorldBoundBox(TimeValue t, INode *node, ViewExp *vpt, Box3 &box);
int Display(TimeValue t, INode *node, ViewExp *vpt, int flags);
int HitTest(TimeValue t, INode *node, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt);
ObjectState Eval(TimeValue t) { return ObjectState(this); }
IOResult Save(ISave* isave);
IOResult Load(ILoad* iload);
int CanConvertToType( Class_ID obtype ) { return ( obtype == ANIMSTEALTH_CLASSID ) ? 1 : 0; }
const char *GetCategory() { return fClassDesc->Category(); }
/// Parameter access
bool GetAutoStart( void ) const;
void SetAutoStart( bool b );
bool GetLoop( void ) const;
const char *GetLoopName( void ) const;
void SetLoop( bool b, const char *name );
UInt8 GetEaseInType( void ) const;
hsScalar GetEaseInLength( void ) const;
hsScalar GetEaseInMin( void ) const;
hsScalar GetEaseInMax( void ) const;
void SetEaseIn( UInt8 type, hsScalar length, hsScalar min, hsScalar max );
UInt8 GetEaseOutType( void ) const;
hsScalar GetEaseOutLength( void ) const;
hsScalar GetEaseOutMin( void ) const;
hsScalar GetEaseOutMax( void ) const;
void SetEaseOut( UInt8 type, hsScalar length, hsScalar min, hsScalar max );
// Conversion stuff
void GetAllStopPoints( hsTArray<hsScalar> &out );
hsScalar GetSegStart( void ) const;
hsScalar GetSegEnd( void ) const;
void GetLoopPoints( hsScalar &start, hsScalar &end ) const;
void StuffToTimeConvert( plAnimTimeConvert &convert, hsScalar maxLength );
// plAnimObjInterface functions
virtual void PickTargetNode( IParamBlock2 *destPB, ParamID destParamID, ParamID typeID );
virtual hsBool IsNodeRestricted( void ) { return true; }
virtual const char *GetIfaceSegmentName( hsBool allowNil );
virtual hsBool GetKeyList( INode *restrictedNode, hsTArray<plKey> &outKeys );
virtual hsBool MightRequireSeparateMaterial( void ) { return true; }
// Convert time, called on the setupProps pass for each material applied to a node in the scene
virtual hsBool SetupProperties( plMaxNode *node, plErrorMsg *pErrMsg );
virtual hsBool ConvertDeInit( plMaxNode *node, plErrorMsg *pErrMsg );
// Returns true if the parent material is applied to any node in the scene, false otherwise
hsBool IsParentUsedInScene( void );
};
//// Accessor for Parent's ParamBlock ////////////////////////////////////////
class plStealthNodeAccessor : public PBAccessor
{
protected:
void ISetParent( ReferenceTarget *target, plPassMtlBase *parent );
void IHandleSet( PB2Value &v, ReferenceMaker *owner, ParamID id, int tabIndex, TimeValue t );
public:
plStealthNodeAccessor() { }
static plStealthNodeAccessor &GetInstance( void );
virtual void Set( PB2Value &v, ReferenceMaker *owner, ParamID id, int tabIndex, TimeValue t );
virtual void TabChanged( tab_changes changeCode, Tab<PB2Value> *tab, ReferenceMaker *owner,
ParamID id, int tabIndex, int count );
};
#endif //_plAnimStealthNode_h

View File

@ -0,0 +1,660 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plBumpMtl.h"
#include "resource.h"
//extern ClassDesc2* GetMaxLayerDesc();
#include "Shaders.h"
#include "plBumpMtlBasicPB.h"
#include "iparamm2.h"
#include "Layers/plLayerTex.h"
#include "Layers/plStaticEnvLayer.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
extern HINSTANCE hInstance;
class plBumpMtlClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plBumpMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_BUMP_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return BUMP_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaMaterial"); }
HINSTANCE HInstance() { return hInstance; }
};
static plBumpMtlClassDesc plBumpMtlDesc;
ClassDesc2* GetBumpMtlDesc() { return &plBumpMtlDesc; }
// For initializing paramblock descriptor
ParamBlockDesc2 *GetBumpBasicPB();
ParamBlockDesc2 *GetBumpLayersPB();
#include "plBumpMtlBasicPBDec.h"
#include "plBumpMtlAnimPBDec.h"
plBumpMtl::plBumpMtl(BOOL loading) : plPassMtlBase( loading )
{
plBumpMtlDesc.MakeAutoParamBlocks( this );
fBasicPB->SetValue( kBumpBasLayer, 0, TRACKED_NEW plLayerTex );
// If we do this later (like, when the dialog loads) something blows up,
// somewhere in Max. It didn't in 4, it does in 7. This seems to fix it.
if (!loading)
IVerifyStealthPresent(ENTIRE_ANIMATION_NAME);
}
ParamDlg* plBumpMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fIMtlParams = imp;
IAutoMParamDlg* masterDlg = plBumpMtlDesc.CreateParamDlgs(hwMtlEdit, imp, this);
return (ParamDlg*)masterDlg;
}
BOOL plBumpMtl::SetDlgThing(ParamDlg* dlg)
{
return FALSE;
}
Interval plBumpMtl::Validity(TimeValue t)
{
#if 0 // mf horse
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
#else // mf horse
const char* name = GetName();
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
Interval v = FOREVER;
fBasicPB->GetValidity(t, v);
if( fBasicPB->GetTexmap(kBumpBasLayer) )
v &= fBasicPB->GetTexmap(kBumpBasLayer)->Validity(t);
return v;
#endif // mf horse
}
//// GetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
RefTargetHandle plBumpMtl::GetReference( int i )
{
switch( i )
{
case kRefBasic: return fBasicPB;
case kRefAnim: return fAnimPB;
}
return plPassMtlBase::GetReference( i );
}
//// SetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
void plBumpMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefBasic)
fBasicPB = (IParamBlock2 *)rtarg;
else if (i == kRefAnim)
fAnimPB = (IParamBlock2 *)rtarg;
else
plPassMtlBase::SetReference( i, rtarg );
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plBumpMtl::NumSubs()
{
return 3;
}
TSTR plBumpMtl::SubAnimName(int i)
{
switch (i)
{
case 0: return fBasicPB->GetLocalName();
case 1: return fAnimPB->GetLocalName();
case 2: return "Base Layer";
}
return "";
}
Animatable* plBumpMtl::SubAnim(int i)
{
switch (i)
{
case 0: return fBasicPB;
case 1: return fAnimPB;
case 2: return fBasicPB->GetTexmap(kBumpBasLayer);
break;
}
return NULL;
}
int plBumpMtl::NumParamBlocks()
{
return 2;
}
IParamBlock2* plBumpMtl::GetParamBlock(int i)
{
return (IParamBlock2*)GetReference(i);
}
IParamBlock2* plBumpMtl::GetParamBlockByID(BlockID id)
{
if (fBasicPB->ID() == id)
return fBasicPB;
else if (fAnimPB->ID() == id)
return fAnimPB;
return NULL;
}
RefResult plBumpMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
return plPassMtlBase::NotifyRefChanged( changeInt, hTarget, partID, message );
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plBumpMtl::NumSubTexmaps()
{
return 1;
}
Texmap* plBumpMtl::GetSubTexmap(int i)
{
if (i == 0)
return fBasicPB->GetTexmap(kBumpBasLayer);
return NULL;
}
void plBumpMtl::SetSubTexmap(int i, Texmap *m)
{
if (i == 0)
fBasicPB->SetValue(kBumpBasLayer, 0, m);
}
TSTR plBumpMtl::GetSubTexmapSlotName(int i)
{
if (i == 0)
return "Base";
return "";
}
TSTR plBumpMtl::GetSubTexmapTVName(int i)
{
return GetSubTexmapSlotName(i);
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plBumpMtl::Clone(RemapDir &remap)
{
plBumpMtl *mnew = TRACKED_NEW plBumpMtl(FALSE);
plPassMtlBase::ICloneBase( mnew, remap );
return (RefTargetHandle)mnew;
}
void plBumpMtl::ICloneRefs( plPassMtlBase *target, RemapDir &remap )
{
target->ReplaceReference(kRefBasic, remap.CloneRef(fBasicPB));
target->ReplaceReference(kRefAnim, remap.CloneRef(fAnimPB));
}
void plBumpMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plBumpMtl::Update(TimeValue t, Interval& valid)
{
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
if (!fIValid.InInterval(t))
{
fIValid.SetInfinite();
if( fBasicPB->GetTexmap(kBumpBasLayer) )
fBasicPB->GetTexmap(kBumpBasLayer)->Update(t, fIValid);
// fLayersPB->GetValue(kMtlLayLayer1On, t, fMapOn[0], fIValid);
/*
for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
fSubTexmap[i]->Update(t,fIValid);
}
*/
}
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plBumpMtl::SetAmbient(Color c, TimeValue t) {}
void plBumpMtl::SetDiffuse(Color c, TimeValue t) {}
void plBumpMtl::SetSpecular(Color c, TimeValue t) {}
void plBumpMtl::SetShininess(float v, TimeValue t) {}
Color plBumpMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plBumpMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plBumpMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plBumpMtl::GetXParency(int mtlNum, BOOL backFace)
{
return 0.f;
}
float plBumpMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plBumpMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plBumpMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/////////////////////////////////////////////////////////////////
void plBumpMtl::SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb)
{
#if 0
if (texHandleValid.InInterval(t)) {
mtl->texture.SetCount(numTexHandlesUsed);
for (int i=0; i<numTexHandlesUsed; i++) {
if (texHandle[i]) {
mtl->texture[i].textHandle = texHandle[i]->GetHandle();
Texmap *tx = (*maps)[useSubForTex[i]].map;
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[i], tx );
SetTexOps(mtl,i,texOpsType[i]);
}
}
return;
}
#endif
#if 0 // WTF?!?!?!?
Texmap *tx[2];
int diffChan = stdIDToChannel[ ID_DI ];
int opacChan = stdIDToChannel[ ID_OP ];
tx[0] = (*maps)[diffChan].IsActive()?(*maps)[diffChan].map:NULL;
tx[1] = (*maps)[opacChan].IsActive()?(*maps)[opacChan].map:NULL;
#endif
int nsupport = cb.NumberTexturesSupported();
#if 0
BITMAPINFO *bmi[NTEXHANDLES];
int nmaps=0;
for (int i=0; i<NTEXHANDLES; i++) {
if (tx[i]) nmaps ++;
bmi[i] = NULL;
}
mtl->texture.SetCount(nmaps);
if (nmaps==0)
return;
for (i=0; i<nmaps; i++)
mtl->texture[i].textHandle = NULL;
texHandleValid.SetInfinite();
Interval valid;
BOOL needDecal = FALSE;
int ntx = 0;
int op;
int forceW = 0;
int forceH = 0;
if (tx[0]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[0], tx[0]);
TextureInfo &ti = mtl->texture[0];
if (ti.tiling[0]==GW_TEX_NO_TILING||ti.tiling[1]==GW_TEX_NO_TILING)
needDecal = TRUE;
op = needDecal?TXOP_ALPHABLEND:TXOP_MODULATE;
bmi[0] = tx[0]->GetVPDisplayDIB(t,cb,valid,FALSE);
if (bmi[0]) {
texHandleValid &= valid;
useSubForTex[0] = diffChan;
ntx = 1;
forceW = bmi[0]->bmiHeader.biWidth;
forceH = bmi[0]->bmiHeader.biHeight;
}
}
if (tx[1]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[ntx], tx[1]);
if (nsupport>ntx) {
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlpha(bmi[1], (*maps)[opacChan].amount, GetOpacity(t),ntx?whiteCol:pShader->GetDiffuseClr(t));
texHandle[ntx] = cb.MakeHandle(bmi[1]);
bmi[1] = NULL;
mtl->texture[ntx].textHandle = texHandle[ntx]->GetHandle();
SetTexOps(mtl,ntx,TXOP_OPACITY);
useSubForTex[ntx] = opacChan;
ntx++;
}
}
else {
if (!needDecal) {
TextureInfo ti;
// if (SameUV(mtl->texture[0],mtl->texture[1])) {
// Not really correct to combine channels for different UV's but what the heck.
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE, forceW, forceH);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlphaInto(bmi[1], bmi[0], (*maps)[opacChan].amount, GetOpacity(t));
op = TXOP_OPACITY;
free(bmi[1]);
bmi[1] = NULL;
}
// }
}
}
}
if (bmi[0]) {
texHandle[0] = cb.MakeHandle(bmi[0]);
bmi[0] = NULL;
mtl->texture[0].textHandle = texHandle[0]->GetHandle();
SetTexOps(mtl,0,op);
}
mtl->texture.SetCount(ntx);
numTexHandlesUsed = ntx;
#endif
}
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plBumpMtl::GetInterpVtxValue(int channel, ShadeContext &sc, Point3 &val)
{
Mesh *mesh = sc.globContext->GetRenderInstance(sc.NodeID())->mesh;
if (mesh != nil)
{
Face *maxFace = &mesh->faces[ sc.FaceNumber() ];
UVVert *map = mesh->mapVerts(channel);
if (map != nil)
{
Point3 p0 = map[maxFace->getVert( 0 )];
Point3 p1 = map[maxFace->getVert( 1 )];
Point3 p2 = map[maxFace->getVert( 2 )];
Point3 interp = sc.BarycentricCoords();
val.x = interp.x * p0.x + interp.y * p1.x + interp.z * p2.x;
val.y = interp.x * p0.y + interp.y * p1.y + interp.z * p2.y;
val.z = interp.x * p0.z + interp.y * p1.z + interp.z * p2.z;
return;
}
}
// No value defined... set default.
if (channel == MAP_SHADING)
val.x = val.y = val.z = 0.0f;
else
val.x = val.y = val.z = 1.0f;
}
void plBumpMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
sc.GetBGColor(backColor, backTrans);
ShadeWithBackground(sc, backColor);
}
//// Requirements ////////////////////////////////////////////////////////////
// Tells MAX what we need to render ourselves properly, such as translucency,
// two-sidedness, etc. Flags are in imtl.h in the MAX SDK.
ULONG plBumpMtl::Requirements( int subMtlNum )
{
ULONG req = 0;
req = Mtl::Requirements( subMtlNum );
// Uncomment this to get the background color fed to our ShadeWithBackground()
// (slower processing tho)
//req |= MTLREQ_BGCOL;
req |= MTLREQ_UV;
req |= MTLREQ_TRANSP;
if (req & MTLREQ_FACEMAP)
{
int i = 0;
}
return req;
}
void plBumpMtl::ShadeWithBackground(ShadeContext &sc, Color background, bool useVtxAlpha /* = true */)
{
#if 1
// old
#if 0
Color lightCol,rescol, diffIllum0;
RGBA mval;
Point3 N0,P;
BOOL bumped = FALSE;
int i;
if (gbufID)
sc.SetGBufferID(gbufID);
if (sc.mode == SCMODE_SHADOW) {
float opac = 0.0;
for (i=0; i < NumSubTexmaps(); i++) {
if (SubTexmapOn(i)) {
hsMaxLayerBase *hsmLay = (hsMaxLayerBase *)GetSubTexmap(i);
opac += hsmLay->GetOpacity(t);
}
}
float f = 1.0f - opac;
sc.out.t = Color(f,f,f);
return;
}
N0 = sc.Normal();
P = sc.P();
#endif
TimeValue t = sc.CurTime();
Color color(0, 0, 0);
float alpha = 0.0;
// Evaluate Base layer
Texmap *map = fBasicPB->GetTexmap(kBumpBasLayer);
if (map && ( map->ClassID() == LAYER_TEX_CLASS_ID
|| map->ClassID() == STATIC_ENV_LAYER_CLASS_ID ) )
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
color = evalColor;
alpha = evalColor.a;
}
#if 1
AColor black;
black.Black();
AColor white;
white.White();
SIllumParams ip;
//
// Shading setup
//
// Setup the parameters for the shader
ip.amb = black;
ip.diff = white;
ip.diffIllum = black;
ip.specIllum = black;
ip.N = sc.Normal();
ip.V = sc.V();
//
// Specularity
//
ip.spec = black;
ip.sh_str = 0;
ip.ph_exp = 0;
ip.shine = 0;
ip.softThresh = 0;
//
// Do the shading
Shader *myShader = GetShader(SHADER_BLINN);
myShader->Illum(sc, ip);
ip.diffIllum.ClampMinMax();
ip.specIllum.ClampMinMax();
ip.diffIllum = ip.amb * sc.ambientLight + ip.diff * ip.diffIllum;
// AColor returnColor = AColor(opac * ip.diffIllum + ip.specIllum, opac)
#endif
float vtxAlpha = 1.0f;
if (useVtxAlpha && GetOutputBlend() == plPassMtlBase::kBlendAlpha)
{
Point3 p;
GetInterpVtxValue(MAP_ALPHA, sc, p);
vtxAlpha = p.x;
}
alpha *= vtxAlpha;
// MAX will do the additive/alpha/no blending for us based on what Requirements()
// we tell it. However, since MAX's formula is bgnd*sc.out.t + sc.out.c,
// we have to multiply our output color by the alpha.
// If we ever need a more complicated blending function, you can request the
// background color via Requirements() (otherwise it's just black) and then do
// the blending yourself; however, if the transparency isn't set, the shadows
// will be opaque, so be careful.
Color outC = ip.diffIllum + ip.specIllum;
sc.out.c = ( outC * alpha );
sc.out.t = Color( 1.f - alpha, 1.f - alpha, 1.f - alpha );
#endif
}
float plBumpMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plBumpMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
bool plBumpMtl::HasAlpha()
{
return ((plLayerTex *)fBasicPB->GetTexmap(kBumpBasLayer))->HasAlpha();
}
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
int plBumpMtl::GetBasicWire() { return 0; }
int plBumpMtl::GetMeshOutlines() { return 0; }
int plBumpMtl::GetTwoSided() { return 0; }
int plBumpMtl::GetSoftShadow() { return 0; }
int plBumpMtl::GetNoProj() { return 0; }
int plBumpMtl::GetVertexShade() { return 0; }
int plBumpMtl::GetNoShade() { return 0; }
int plBumpMtl::GetNoFog() { return 0; }
int plBumpMtl::GetWhite() { return 0; }
int plBumpMtl::GetZOnly() { return 0; }
int plBumpMtl::GetZClear() { return 0; }
int plBumpMtl::GetZNoRead() { return 0; }
int plBumpMtl::GetZNoWrite() { return 0; }
int plBumpMtl::GetZInc() { return 0; }
int plBumpMtl::GetAlphaTestHigh() { return 0; }
// Animation block
char * plBumpMtl::GetAnimName() { return fAnimPB->GetStr(kPBAnimName); }
int plBumpMtl::GetAutoStart() { return fAnimPB->GetInt(kPBAnimAutoStart); }
int plBumpMtl::GetLoop() { return fAnimPB->GetInt(kPBAnimLoop); }
char * plBumpMtl::GetAnimLoopName() { return fAnimPB->GetStr(kPBAnimLoopName); }
// Basic block
int plBumpMtl::GetColorLock() { return 0; }
Color plBumpMtl::GetAmbColor() { return Color(0,0,0); }
Color plBumpMtl::GetColor() { return Color(0,0,0); }
int plBumpMtl::GetOpacity() { return 100; }
int plBumpMtl::GetEmissive() { return 0; }
int plBumpMtl::GetUseSpec() { return 0; }
int plBumpMtl::GetShine() { return 0; }
Color plBumpMtl::GetSpecularColor() { return Color(0,0,0); }
int plBumpMtl::GetDiffuseColorLock() { return 0; }
Color plBumpMtl::GetRuntimeColor() { return fBasicPB->GetColor(kBumpBasRunColor); }
Control *plBumpMtl::GetPreshadeColorController() { return nil; }
Control *plBumpMtl::GetAmbColorController() { return nil; }
Control *plBumpMtl::GetOpacityController() { return nil; }
Control *plBumpMtl::GetSpecularColorController() { return nil; }
Control *plBumpMtl::GetRuntimeColorController() { return fBasicPB->GetController(ParamID(kBumpBasRunColor)); }
// Layer block
Texmap *plBumpMtl::GetBaseLayer() { return fBasicPB->GetTexmap(kBumpBasLayer); }
int plBumpMtl::GetTopLayerOn() { return 0; }
Texmap *plBumpMtl::GetTopLayer() { return nil; }
int plBumpMtl::GetLayerBlend() { return 0; }
int plBumpMtl::GetOutputAlpha() { return 0; }
int plBumpMtl::GetOutputBlend() { return fBasicPB->GetInt( kBumpBasSpecular ) ? plPassMtlBase::kBlendAdd : plPassMtlBase::kBlendAlpha; }

View File

@ -0,0 +1,178 @@
/*==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/>.
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==*/
#ifndef PL_BUMPMTL_H
#define PL_BUMPMTL_H
#include "Max.h"
#include "iparamb2.h"
#include "../resource.h"
#include "plPassMtlBase.h"
#define BUMP_MTL_CLASS_ID Class_ID(0x4dbf7b0a, 0x92226de)
extern TCHAR *GetString(int id);
class plBumpMtl : public plPassMtlBase
{
protected:
virtual void ICloneRefs( plPassMtlBase *target, RemapDir &remap );
public:
enum RefIDs
{
kRefBasic,
kRefAnim,
};
enum BlockIDs
{
kBlkBasic,
kBlkAnim,
};
plBumpMtl(BOOL loading);
void DeleteThis() { delete this; }
//From Animatable
Class_ID ClassID() { return BUMP_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_BUMP_MTL); }
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void NotifyChanged();
BOOL SupportsMultiMapsInViewport() { return FALSE; }
void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);
// Shade and displacement calculation
static void GetInterpVtxValue(int channel, ShadeContext &sc, Point3 &interpVal);
void Shade(ShadeContext& sc);
void ShadeWithBackground(ShadeContext &sc, Color background, bool useVtxAlpha = true);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
virtual RefTargetHandle GetReference( int i );
virtual void SetReference( int i, RefTargetHandle rtarg );
// SubTexmap access methods
int NumSubTexmaps();
Texmap* GetSubTexmap(int i);
void SetSubTexmap(int i, Texmap *m);
TSTR GetSubTexmapSlotName(int i);
TSTR GetSubTexmapTVName(int i);
BOOL SetDlgThing(ParamDlg* dlg);
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// void SetParamDlg(ParamDlg *dlg);
// void SetNumSubTexmaps(int num);
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
ULONG Requirements( int subMtlNum );
virtual bool HasAlpha();
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
virtual int GetBasicWire();
virtual int GetMeshOutlines();
virtual int GetTwoSided();
virtual int GetSoftShadow();
virtual int GetNoProj();
virtual int GetVertexShade();
virtual int GetNoShade();
virtual int GetNoFog();
virtual int GetWhite();
virtual int GetZOnly();
virtual int GetZClear();
virtual int GetZNoRead();
virtual int GetZNoWrite();
virtual int GetZInc();
virtual int GetAlphaTestHigh();
// Animation block
virtual char * GetAnimName();
virtual int GetAutoStart();
virtual int GetLoop();
virtual char * GetAnimLoopName();
// Basic block
virtual int GetColorLock();
virtual Color GetAmbColor();
virtual Color GetColor();
virtual int GetOpacity();
virtual int GetEmissive();
virtual int GetUseSpec();
virtual int GetShine();
virtual Color GetSpecularColor();
virtual Control *GetPreshadeColorController();
virtual Control *GetAmbColorController();
virtual Control *GetOpacityController();
virtual Control *GetSpecularColorController();
virtual int GetDiffuseColorLock();
virtual Color GetRuntimeColor();
virtual Control *GetRuntimeColorController();
// Layer block
virtual Texmap *GetBaseLayer();
virtual int GetTopLayerOn();
virtual Texmap *GetTopLayer();
virtual int GetLayerBlend();
virtual int GetOutputAlpha();
virtual int GetOutputBlend();
};
#endif //PL_BUMPMTL_H

View File

@ -0,0 +1,37 @@
/*==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/>.
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==*/
#ifndef PL_BUMPMTLANIMPB_H
#define PL_BUMPMTLANIMPB_H
enum
{
kBumpAnimName,
kBumpAnimAutoStart,
kBumpAnimLoop,
kBumpAnimLoopName,
};
#endif

View File

@ -0,0 +1,93 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plBumpMtl.h"
#include "plPassBaseParamIDs.h"
#include "resource.h"
#include "iparamm2.h"
#include "plPassAnimDlgProc.h"
#include "plAnimStealthNode.h"
using namespace plPassBaseParamIDs;
static ParamBlockDesc2 gBumpAnimPB
(
plBumpMtl::kBlkAnim, _T("anim"), IDS_PASS_ANIM, GetBumpMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI + P_CALLSETS_ON_LOAD, plBumpMtl::kRefAnim,
// UI
IDD_PASS_ANIM, IDS_PASS_ANIM, 0, 0, &plPassAnimDlgProc::Get(),
#ifdef MCN_UPGRADE_OLD_ANIM_BLOCKS
// THE FOLLOWING ARE ALL OLD PARAMETERS AND SHOULD NO LONGER BE USED. The only reason
// they're here is so we can convert old paramBlocks into the new plAnimStealthNode format
kPBAnimName, _T("animName"), TYPE_STRING, 0, 0,
end,
kPBAnimAutoStart, _T("autoStart"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoop, _T("loop"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoopName, _T("loopName"), TYPE_STRING, 0, 0,
end,
// Anim Ease
kPBAnimEaseInType, _T("easeInType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseInLength, _T("easeInLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMin, _T("easeInMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMax, _T("easeInMax"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutType, _T("easeOutType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseOutLength, _T("easeOutLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMin, _T("easeOutMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMax, _T("easeOutMax"), TYPE_FLOAT, 0, 0,
end,
#endif // MCN_UPGRADE_OLD_ANIM_BLOCKS
kPBAnimUseGlobal, _T("UseGlobal"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_MTL_USE_GLOBAL,
end,
kPBAnimGlobalName, _T("GlobalName"), TYPE_STRING, 0, 0,
p_default, _T(""),
end,
kPBAnimStealthNodes, _T( "testing" ), TYPE_REFTARG_TAB, 0, 0, 0,
p_accessor, &plStealthNodeAccessor::GetInstance(),
end,
end
);
ParamBlockDesc2 *GetBumpAnimPB() { return &gBumpAnimPB; }

View File

@ -0,0 +1,38 @@
/*==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/>.
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==*/
#ifndef PL_BUMPMTLBASICPB_H
#define PL_BUMPMTLBASICPB_H
// Param ID's
enum
{
kBumpBasSpecular,
kBumpBasRunColor,
kBumpBasLayer
};
#endif //PL_BUMPMTLBASICPB_H

View File

@ -0,0 +1,92 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plBumpMtl.h"
#include "plBumpMtlBasicPB.h"
#include "resource.h"
#include "iparamm2.h"
class BumpBasicDlgProc;
extern BumpBasicDlgProc gBumpBasicDlgProc;
static ParamBlockDesc2 gBumpBasicPB
(
plBumpMtl::kBlkBasic, _T("basic"), IDS_PASS_BASIC, GetBumpMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI, plBumpMtl::kRefBasic,
// UI
IDD_BUMP_BASIC, IDS_PASS_BASIC, 0, 0, &gBumpBasicDlgProc,
kBumpBasLayer, _T("bumpLayer"), TYPE_TEXMAP, 0, IDS_BASIC_AMB,
p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER1,
p_subtexno, 0,
end,
kBumpBasRunColor, _T("runtimeColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_RUNCOLOR,
// p_ui, TYPE_COLORSWATCH, IDC_LAYER_RUNCOLOR,
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_INTEN_EDIT, IDC_INTEN_SPIN,
IDC_DUMMY_EDIT1, IDC_DUMMY_SPIN1, IDC_DUMMY_EDIT2, IDC_DUMMY_SPIN2,
SPIN_AUTOSCALE,
p_default, Color(1,0,0),
end,
// Specularity
kBumpBasSpecular, _T("useSpec"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_SPECULAR,
end,
end
);
ParamBlockDesc2 *GetBumpBasicPB() { return &gBumpBasicPB; }
class BumpBasicDlgProc : public ParamMap2UserDlgProc
{
#if 1
protected:
public:
BumpBasicDlgProc() {}
~BumpBasicDlgProc() { }
#endif
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
IParamBlock2 *pb = map->GetParamBlock();
switch (msg)
{
case WM_INITDIALOG:
{
}
return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
static BumpBasicDlgProc gBumpBasicDlgProc;

View File

@ -0,0 +1,699 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsUtils.h"
#include "plClothingMtl.h"
#include "resource.h"
#include "Shaders.h"
#include "iparamm2.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
#include "plBMSampler.h"
#include "stdmat.h"
#include "Layers/plLayerTex.h"
#include "Layers/plLayerTexBitmapPB.h"
#include "../../Plasma/PubUtilLib/plAvatar/plClothingLayout.h"
extern HINSTANCE hInstance;
class plClothingMtlClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plClothingMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_CLOTHING_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return CLOTHING_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("ClothingMaterial"); }
HINSTANCE HInstance() { return hInstance; }
};
static plClothingMtlClassDesc plClothingMtlDesc;
ClassDesc2* GetClothingMtlDesc() { return &plClothingMtlDesc; }
// For initializing paramblock descriptor
ParamBlockDesc2 *GetClothingPB();
#include "plClothingMtlPBDec.h"
const UINT32 plClothingMtl::ButtonConstants[] =
{
IDC_CLOTHING_TEXTURE1,
IDC_CLOTHING_TEXTURE2,
IDC_CLOTHING_TEXTURE3,
IDC_CLOTHING_TEXTURE4
};
const UINT32 plClothingMtl::TextConstants[] =
{
IDC_CLOTHING_TILE1_NAME,
IDC_CLOTHING_TILE1_SIZE,
IDC_CLOTHING_TILE2_NAME,
IDC_CLOTHING_TILE2_SIZE,
IDC_CLOTHING_TILE3_NAME,
IDC_CLOTHING_TILE3_SIZE,
IDC_CLOTHING_TILE4_NAME,
IDC_CLOTHING_TILE4_SIZE
};
const char *plClothingMtl::LayerStrings[] =
{
"Base",
"Skin",
"Skin Blend (1)",
"Skin Blend (2)",
"Skin Blend (3)",
"Skin Blend (4)",
"Skin Blend (5)",
"Skin Blend (6)",
"Tint 1",
"Tint 2"
};
const UInt8 plClothingMtl::LayerToPBIdx[] =
{
kTexmapBase,
kTexmapSkin,
kTexmapSkinBlend1,
kTexmapSkinBlend2,
kTexmapSkinBlend3,
kTexmapSkinBlend4,
kTexmapSkinBlend5,
kTexmapSkinBlend6,
kTexmap,
kTexmap2
};
plClothingMtl::plClothingMtl(BOOL loading) : fBasicPB(NULL)
{
plClothingMtlDesc.MakeAutoParamBlocks(this);
Reset();
int i;
for (i = 0; i < plClothingMtl::kMaxTiles; i++)
{
plLayerTex *tex = TRACKED_NEW plLayerTex;
fBasicPB->SetValue(ParamID(kTexmap), 0, tex, i);
}
fBasicPB->SetValue(ParamID(kThumbnail), 0, TRACKED_NEW plLayerTex);
}
void plClothingMtl::Reset()
{
fIValid.SetEmpty();
}
ParamDlg* plClothingMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fIMtlParams = imp;
IAutoMParamDlg* masterDlg = plClothingMtlDesc.CreateParamDlgs(hwMtlEdit, imp, this);
return (ParamDlg*)masterDlg;
}
BOOL plClothingMtl::SetDlgThing(ParamDlg* dlg)
{
return FALSE;
}
Interval plClothingMtl::Validity(TimeValue t)
{
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
Interval v = FOREVER;
fBasicPB->GetValidity(t, v);
return v;
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
/*
int plClothingMtl::NumSubs()
{
return 2;
}
TSTR plClothingMtl::SubAnimName(int i)
{
switch (i)
{
case 0: return fBasicPB->GetLocalName();
case 1: return "Texmap";
}
return "";
}
Animatable* plClothingMtl::SubAnim(int i)
{
switch (i)
{
case 0: return fBasicPB;
case 1: return fBasicPB->GetTexmap(kTexmap);
}
return NULL;
}
*/
int plClothingMtl::NumRefs()
{
return 1;
}
RefTargetHandle plClothingMtl::GetReference(int i)
{
switch (i)
{
case kRefBasic: return fBasicPB;
}
return NULL;
}
void plClothingMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefBasic)
fBasicPB = (IParamBlock2 *)rtarg;
}
int plClothingMtl::NumParamBlocks()
{
return 1;
}
IParamBlock2* plClothingMtl::GetParamBlock(int i)
{
return (IParamBlock2*)GetReference(i);
}
IParamBlock2* plClothingMtl::GetParamBlockByID(BlockID id)
{
if (fBasicPB->ID() == id)
return fBasicPB;
return NULL;
}
RefResult plClothingMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
switch (message)
{
case REFMSG_CHANGE:
fIValid.SetEmpty();
// see if this message came from a changing parameter in the pblock,
// if so, limit rollout update to the changing item
if (hTarget == fBasicPB)
{
IParamBlock2 *pb = (IParamBlock2*)hTarget;
ParamID changingParam = pb->LastNotifyParamID();
pb->GetDesc()->InvalidateUI(changingParam);
// And let the SceneWatcher know that the material on some of it's
// referenced objects changed.
NotifyDependents(FOREVER, PART_ALL, REFMSG_USER_MAT);
}
break;
}
return REF_SUCCEED;
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plClothingMtl::NumSubTexmaps()
{
return plClothingElement::kLayerMax * kMaxTiles + 1; // add one for the thumbnail
}
Texmap* plClothingMtl::GetSubTexmap(int i)
{
if (i >= 0 && i < plClothingElement::kLayerMax * kMaxTiles)
return fBasicPB->GetTexmap(ParamID(LayerToPBIdx[i / kMaxTiles]), 0, i % kMaxTiles);
if (i == plClothingElement::kLayerMax * kMaxTiles)
return fBasicPB->GetTexmap(ParamID(kThumbnail));
return NULL;
}
void plClothingMtl::SetSubTexmap(int i, Texmap *m)
{
if (i >= 0 && i < plClothingElement::kLayerMax * kMaxTiles)
fBasicPB->SetValue(ParamID(LayerToPBIdx[i / kMaxTiles]), 0, m, i % kMaxTiles);
if (i == plClothingElement::kLayerMax * kMaxTiles)
fBasicPB->SetValue(kThumbnail, 0, m);
}
TSTR plClothingMtl::GetSubTexmapSlotName(int i)
{
if (i >= 0 && i < plClothingElement::kLayerMax * kMaxTiles)
return "Texmap";
if (i == plClothingElement::kLayerMax * kMaxTiles)
return "Thumbnail";
return "";
}
TSTR plClothingMtl::GetSubTexmapTVName(int i)
{
return GetSubTexmapSlotName(i);
}
DllExport Texmap *plClothingMtl::GetTexmap(int index, int layer)
{
return fBasicPB->GetTexmap(ParamID(LayerToPBIdx[layer]), 0, index);
}
/*===========================================================================*\
| Standard IO
\*===========================================================================*/
#define MTL_HDR_CHUNK 0x4000
IOResult plClothingMtl::Save(ISave *isave)
{
IOResult res;
isave->BeginChunk(MTL_HDR_CHUNK);
res = MtlBase::Save(isave);
if (res!=IO_OK) return res;
isave->EndChunk();
return IO_OK;
}
IOResult plClothingMtl::Load(ILoad *iload)
{
IOResult res;
int id;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(id = iload->CurChunkID())
{
case MTL_HDR_CHUNK:
res = MtlBase::Load(iload);
break;
}
iload->CloseChunk();
if (res!=IO_OK)
return res;
}
return IO_OK;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plClothingMtl::Clone(RemapDir &remap)
{
plClothingMtl *mnew = TRACKED_NEW plClothingMtl(FALSE);
*((MtlBase*)mnew) = *((MtlBase*)this);
mnew->ReplaceReference(kRefBasic, remap.CloneRef(fBasicPB));
BaseClone(this, mnew, remap);
mnew->fIValid.SetEmpty();
return (RefTargetHandle)mnew;
}
void plClothingMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plClothingMtl::Update(TimeValue t, Interval& valid)
{
//StdUVGen *gen = (StdUVGen *)fUVGen;
//gen->SetUScl(1.0f, t);
//gen->SetVScl(1.0f, t);
//gen->Update(t, fIValid);
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plClothingMtl::SetAmbient(Color c, TimeValue t) {}
void plClothingMtl::SetDiffuse(Color c, TimeValue t) {}
void plClothingMtl::SetSpecular(Color c, TimeValue t) {}
void plClothingMtl::SetShininess(float v, TimeValue t) {}
Color plClothingMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plClothingMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plClothingMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plClothingMtl::GetXParency(int mtlNum, BOOL backFace)
{
/*
int opacity = fBasicPB->GetInt( kOpacity, 0 );
float alpha = 1.0f - ( (float)opacity / 100.0f );
return alpha;
*/
return 0;
}
float plClothingMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plClothingMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plClothingMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/////////////////////////////////////////////////////////////////
void plClothingMtl::SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb)
{
}
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plClothingMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
sc.GetBGColor(backColor, backTrans);
ShadeWithBackground(sc, backColor);
}
//// Requirements ////////////////////////////////////////////////////////////
// Tells MAX what we need to render ourselves properly, such as translucency,
// two-sidedness, etc. Flags are in imtl.h in the MAX SDK.
ULONG plClothingMtl::Requirements( int subMtlNum )
{
ULONG req = 0;
req = Mtl::Requirements( subMtlNum );
// Uncomment this to get the background color fed to our ShadeWithBackground()
// (slower processing tho)
// req |= MTLREQ_BGCOL;
//int blendType = fBasicPB->GetInt( kBlend );
//if( blendType == kBlendAdd )
// req |= MTLREQ_ADDITIVE_TRANSP | MTLREQ_TRANSP;
//else if( blendType == kBlendAlpha )
// req |= MTLREQ_TRANSP;
//else if( fBasicPB->GetInt( kOpacity, 0 ) != 100 )
// req |= MTLREQ_TRANSP;
return req;
}
void plClothingMtl::ShadeWithBackground(ShadeContext &sc, Color background)
{
#if 1
TimeValue t = sc.CurTime();
Color color(0, 0, 0);
float alpha = 0.0;
// Evaluate Base layer
Texmap *map = fBasicPB->GetTexmap(kTexmap);
if (map && map->ClassID() == LAYER_TEX_CLASS_ID)
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
color = evalColor;
alpha = evalColor.a;
}
#if 1
AColor black;
black.Black();
AColor white;
white.White();
SIllumParams ip;
//if( fBasicPB->GetInt( kNormal ) == kEmissive )
//{
// Emissive objects don't get shaded
// ip.diffIllum = fBasicPB->GetColor(kColorAmb, t) * color;
// ip.diffIllum.ClampMinMax();
// ip.specIllum = black;
//}
//else
{
//
// Shading setup
//
// Setup the parameters for the shader
ip.amb = black;
ip.diff = white; //fBasicPB->GetColor(kColor, t) * color;
ip.spec = white;
ip.diffIllum = black;
ip.specIllum = black;
ip.N = sc.Normal();
ip.V = sc.V();
//
// Specularity
//
ip.sh_str = 0;
ip.ph_exp = 0;
ip.shine = 0;
ip.softThresh = 0;
// Do the shading
Shader *myShader = GetShader(SHADER_BLINN);
myShader->Illum(sc, ip);
ip.diffIllum.ClampMinMax();
ip.specIllum.ClampMinMax();
ip.diffIllum = ip.amb * sc.ambientLight + ip.diff * ip.diffIllum;
}
// AColor returnColor = AColor(opac * ip.diffIllum + ip.specIllum, opac)
#endif
// Get opacity and combine with alpha
float opac = 1.0f; //float(fBasicPB->GetInt(kOpacity, t)) / 100.0f;
//float opac = 1.0f;
alpha *= opac;
// MAX will do the additive/alpha/no blending for us based on what Requirements()
// we tell it. However, since MAX's formula is bgnd*sc.out.t + sc.out.c,
// we have to multiply our output color by the alpha.
// If we ever need a more complicated blending function, you can request the
// background color via Requirements() (otherwise it's just black) and then do
// the blending yourself; however, if the transparency isn't set, the shadows
// will be opaque, so be careful.
Color outC = ip.diffIllum + ip.specIllum;
sc.out.c = ( outC * alpha );
sc.out.t = Color( 1.f - alpha, 1.f - alpha, 1.f - alpha );
#endif
}
float plClothingMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plClothingMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
plClothingElement *plClothingMtl::FindElementByName(char *name)
{
int i;
for (i = 0; i < fElements.GetCount(); i++)
{
if (!strcmp(fElements.Get(i)->fName, name))
return fElements.Get(i);
}
return nil;
}
void plClothingMtl::InitTilesets()
{
hsAssert(fElements.GetCount() == 0, "Tilesets already initialized");
fElements.Reset();
fTilesets.SetCountAndZero(plClothingLayout::kMaxTileset);
plClothingElement::GetElements(fElements);
/*
plClothingTileset *tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("shirt");
tileset->AddElement(FindElementByName("shirt-chest"));
tileset->AddElement(FindElementByName("shirt-sleeve"));
fTilesets[plClothingLayout::kSetShirt] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("face");
tileset->AddElement(FindElementByName("face"));
fTilesets[plClothingLayout::kSetFace] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("eye");
tileset->AddElement(FindElementByName("eyeball"));
fTilesets[plClothingLayout::kSetEye] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("shoe");
tileset->AddElement(FindElementByName("shoe-top"));
tileset->AddElement(FindElementByName("shoe-bottom"));
fTilesets[plClothingLayout::kSetShoe] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("pants");
tileset->AddElement(FindElementByName("pants"));
fTilesets[plClothingLayout::kSetPants] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("hand");
tileset->AddElement(FindElementByName("hand-LOD"));
tileset->AddElement(FindElementByName("hand-square"));
tileset->AddElement(FindElementByName("hand-wide"));
fTilesets[plClothingLayout::kSetHand] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("playerbook");
tileset->AddElement(FindElementByName("playerbook"));
fTilesets[plClothingLayout::kSetPlayerBook] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("backpack");
tileset->AddElement(FindElementByName("backpack"));
fTilesets[plClothingLayout::kSetBackpack] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("glasses");
tileset->AddElement(FindElementByName("glasses-front"));
tileset->AddElement(FindElementByName("glasses-side"));
fTilesets[plClothingLayout::kSetGlasses] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("KI");
tileset->AddElement(FindElementByName("KI"));
fTilesets[plClothingLayout::kSetKI] = tileset;
*/
plClothingTileset *tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Torso");
tileset->AddElement(FindElementByName("Chest"));
tileset->AddElement(FindElementByName("Arm"));
fTilesets[plClothingLayout::kSetShirt] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Head");
tileset->AddElement(FindElementByName("Eye"));
tileset->AddElement(FindElementByName("Extra Hair"));
tileset->AddElement(FindElementByName("Face"));
tileset->AddElement(FindElementByName("Hat"));
fTilesets[plClothingLayout::kSetFace] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Foot");
tileset->AddElement(FindElementByName("Foot"));
fTilesets[plClothingLayout::kSetShoe] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Legs");
tileset->AddElement(FindElementByName("Legs"));
fTilesets[plClothingLayout::kSetPants] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Hand");
tileset->AddElement(FindElementByName("Finger"));
tileset->AddElement(FindElementByName("LOD"));
tileset->AddElement(FindElementByName("Palm"));
fTilesets[plClothingLayout::kSetHand] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Player Book");
tileset->AddElement(FindElementByName("Player Book"));
fTilesets[plClothingLayout::kSetPlayerBook] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("Glasses");
tileset->AddElement(FindElementByName("Glasses"));
fTilesets[plClothingLayout::kSetGlasses] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("KI");
tileset->AddElement(FindElementByName("KI"));
fTilesets[plClothingLayout::kSetKI] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("(unused)");
fTilesets[plClothingLayout::kSetEye] = tileset;
tileset = TRACKED_NEW plClothingTileset();
tileset->SetName("(unused)");
fTilesets[plClothingLayout::kSetBackpack] = tileset;
}
void plClothingMtl::ReleaseTilesets()
{
while (fElements.GetCount() > 0)
delete fElements.Pop();
while (fTilesets.GetCount() > 0)
delete fTilesets.Pop();
}
/////////////////////////////////////////////////////////////////////////////////
plClothingTileset::plClothingTileset() : fName(nil)
{
fElements.Reset();
}
plClothingTileset::~plClothingTileset()
{
delete [] fName;
}
void plClothingTileset::AddElement(plClothingElement *element)
{
fElements.Append(element);
}
void plClothingTileset::SetName(char *name)
{
delete fName; fName = hsStrcpy(name);
}

View File

@ -0,0 +1,201 @@
/*==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/>.
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==*/
#ifndef PL_CLOTHINGMTL_H
#define PL_CLOTHINGMTL_H
#include "Max.h"
#include "iparamb2.h"
#include "../resource.h"
#include "hsTemplates.h"
class Bitmap;
class plClothingItem;
class plMaxNode;
class plClothingElement;
#define CLOTHING_MTL_CLASS_ID Class_ID(0x792c6de4, 0x1f952b65)
extern TCHAR *GetString(int id);
class plClothingTileset
{
public:
char *fName;
hsTArray<plClothingElement *> fElements;
plClothingTileset();
~plClothingTileset();
void SetName(char *name);
void AddElement(plClothingElement *element);
};
class plClothingMtl : public Mtl
{
protected:
IParamBlock2 *fBasicPB;
Interval fIValid;
public:
IMtlParams *fIMtlParams;
static const char *LayerStrings[];
static const UInt8 LayerToPBIdx[];
enum
{
kRefBasic,
};
enum
{
kBlkBasic,
};
enum // Param block indicies
{
kTileset,
kTexmap,
kDescription,
kThumbnail,
kLayer,
kTexmapSkin,
kTexmap2,
kDefault,
kCustomTextSpecs,
kTexmapBase,
kTexmapSkinBlend1,
kTexmapSkinBlend2,
kTexmapSkinBlend3,
kTexmapSkinBlend4,
kTexmapSkinBlend5,
kTexmapSkinBlend6,
kDefaultTint1,
kDefaultTint2,
kForcedAcc,
};
enum
{
kMaxTiles = 4,
};
enum
{
kBlendNone,
kBlendAlpha,
//kBlendAdd,
};
static const UINT32 ButtonConstants[kMaxTiles];
static const UINT32 TextConstants[kMaxTiles * 2];
hsTArray<plClothingTileset *> fTilesets;
hsTArray<plClothingElement *> fElements;
virtual void InitTilesets();
virtual void ReleaseTilesets();
plClothingElement *FindElementByName(char *name);
int GetTilesetIndex() { return fBasicPB->GetInt(ParamID(kTileset)); }
DllExport Texmap *GetTexmap(int index, int layer);
Texmap *GetThumbnail() { return fBasicPB->GetTexmap(ParamID(kThumbnail)); }
char *GetDescription() { return fBasicPB->GetStr(ParamID(kDescription)); }
char *GetCustomText() { return fBasicPB->GetStr(ParamID(kCustomTextSpecs)); }
hsBool GetDefault() { return fBasicPB->GetInt(ParamID(kDefault)) != 0; }
Color GetDefaultTint1() { return fBasicPB->GetColor(plClothingMtl::kDefaultTint1); }
Color GetDefaultTint2() { return fBasicPB->GetColor(plClothingMtl::kDefaultTint2); }
char *GetForcedAccessoryName() { return fBasicPB->GetStr(ParamID(kForcedAcc)); }
plClothingMtl(BOOL loading);
void DeleteThis() { delete this; }
//From Animatable
Class_ID ClassID() { return CLOTHING_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_CLOTHING_MTL); }
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void Reset();
void NotifyChanged();
BOOL SupportsMultiMapsInViewport() { return FALSE; }
void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);
// Shade and displacement calculation
void Shade(ShadeContext& sc);
void ShadeWithBackground(ShadeContext &sc, Color background);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
// SubTexmap access methods
int NumSubTexmaps();
Texmap* GetSubTexmap(int i);
void SetSubTexmap(int i, Texmap *m);
TSTR GetSubTexmapSlotName(int i);
TSTR GetSubTexmapTVName(int i);
BOOL SetDlgThing(ParamDlg* dlg);
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs() { return 0; }
Animatable* SubAnim(int i) { return nil; }
TSTR SubAnimName(int i) { return ""; }
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
ULONG Requirements( int subMtlNum );
};
#endif //PL_ClothingMTL_H

View File

@ -0,0 +1,426 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//#include "plClothingMtl.h"
#include "../../AssetMan/PublicInterface/AssManBaseTypes.h"
#include "max.h"
class plClothingEditBox
{
protected:
int fCtrlID;
int fPBEditID;
plClothingEditBox() {};
void IGetText(IParamBlock2 *pb, HWND hCtrl)
{
// Get the previous value
const char *oldVal = pb->GetStr(fPBEditID);
if (!oldVal)
oldVal = "";
// Get the text from the edit and store it in the paramblock
int len = GetWindowTextLength(hCtrl)+1;
if (len > 1)
{
char *buf = TRACKED_NEW char[len];
GetWindowText(hCtrl, buf, len);
// If the old value is different from the current one, update
if (strcmp(oldVal, buf))
pb->SetValue(fPBEditID, 0, buf);
delete [] buf;
}
else
{
// If the old value wasn't empty, update
if (*oldVal != '\0')
pb->SetValue(fPBEditID, 0, "");
}
}
public:
plClothingEditBox(int ctrlID, int pbEditID) : fCtrlID(ctrlID), fPBEditID(pbEditID) {}
void UpdateText(IParamBlock2 *pb, HWND hWnd)
{
const char *str = pb->GetStr(fPBEditID);
SetDlgItemText(hWnd, fCtrlID, (str != nil ? str : ""));
}
BOOL ProcessMsg(IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// If this isn't a message we process, return
if (!(msg == WM_INITDIALOG || msg == WM_DESTROY ||
(msg == WM_COMMAND && LOWORD(wParam) == fCtrlID)))
return FALSE;
IParamBlock2 *pb = map->GetParamBlock();
// Initializing the dialog, set the text box
if (msg == WM_INITDIALOG)
{
UpdateText(pb, hWnd);
return FALSE;
}
// Being destroyed, but we may not have gotten the text from the edit box
// (EN_KILLFOCUS seems to be sent after the window isn't recieving any more messages)
if (msg == WM_DESTROY)
{
IGetText(pb, GetDlgItem(hWnd, fCtrlID));
return FALSE;
}
int notification = HIWORD(wParam);
HWND hCtrl = (HWND)lParam;
// Disable Max accelerators when the edit box gets focus
if (notification == EN_SETFOCUS)
{
//plMaxAccelerators::Disable();
DisableAccelerators();
return TRUE;
}
// The edit control is losing focus, get it's contents
else if (notification == EN_KILLFOCUS)
{
IGetText(pb, hCtrl);
//plMaxAccelerators::Enable();
EnableAccelerators();
return TRUE;
}
return FALSE;
}
};
class ClothingBasicDlgProc;
extern ClothingBasicDlgProc gClothingBasicDlgProc;
static ParamBlockDesc2 gClothingMtlPB
(
plClothingMtl::kBlkBasic, _T("Clothing"), IDS_PASS_BASIC, GetClothingMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI + P_CALLSETS_ON_LOAD, plClothingMtl::kRefBasic,
// UI
IDD_CLOTHING, IDS_PASS_BASIC, 0, 0, &gClothingBasicDlgProc,
plClothingMtl::kTileset, _T("tileset"), TYPE_INT, 0, 0,
p_default, 0,
end,
plClothingMtl::kTexmap, _T("texmap"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kDescription, _T("ItemDescription"), TYPE_STRING, 0, 0,
p_ui, TYPE_EDITBOX, IDC_CLOTHING_DESCRIPTION,
end,
plClothingMtl::kThumbnail, _T("Thumbnail"), TYPE_TEXMAP, 0, 0,
end,
plClothingMtl::kLayer, _T("Layer"), TYPE_INT, 0, 0,
p_default, plClothingElement::kLayerTint1,
end,
plClothingMtl::kTexmapSkin, _T("SkinLayer"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmap2, _T("TintLayer2"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kDefault, _T("Default"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_CLOTHING_DEFAULT,
p_default, 0,
end,
plClothingMtl::kCustomTextSpecs, _T("TextSpecs"), TYPE_STRING, 0, 0,
end,
plClothingMtl::kTexmapBase, _T("BaseLayer"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend1, _T("SkinBlend(1)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend2, _T("SkinBlend(2)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend3, _T("SkinBlend(3)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend4, _T("SkinBlend(4)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend5, _T("SkinBlend(5)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kTexmapSkinBlend6, _T("SkinBlend(6)"), TYPE_TEXMAP_TAB, plClothingMtl::kMaxTiles, 0, 0,
end,
plClothingMtl::kDefaultTint1, _T("DefaultTint1"), TYPE_RGBA, 0, 0,
p_ui, TYPE_COLORSWATCH, IDC_CLOTHING_TINT1,
p_default, Color(1,1,1),
end,
plClothingMtl::kDefaultTint2, _T("DefaultTint2"), TYPE_RGBA, 0, 0,
p_ui, TYPE_COLORSWATCH, IDC_CLOTHING_TINT2,
p_default, Color(1,1,1),
end,
plClothingMtl::kForcedAcc, _T("ForcedAcc"), TYPE_STRING, 0, 0,
p_ui, TYPE_EDITBOX, IDC_CLOTHING_FORCED_ACC,
end,
end
);
class ClothingBasicDlgProc : public ParamMap2UserDlgProc
{
protected:
plClothingEditBox fCustomText;
public:
ClothingBasicDlgProc() : fCustomText(IDC_CLOTHING_CUSTOM_TEXT_SPECS, plClothingMtl::kCustomTextSpecs) {}
~ClothingBasicDlgProc() {}
void UpdateDisplay(IParamMap2 *pmap)
{
HWND hWnd = pmap->GetHWnd();
IParamBlock2 *pb = pmap->GetParamBlock();
plClothingMtl *mtl = (plClothingMtl *)pb->GetOwner();
HWND cbox = NULL;
plPlasmaMAXLayer *layer;
PBBitmap *pbbm;
ICustButton *bmSelectBtn;
char buff[256];
// Setup the tiles
int i, j;
int layerSet = pb->GetInt(ParamID(plClothingMtl::kLayer));
int layerIdx = plClothingMtl::LayerToPBIdx[layerSet];
for (j = 0; j < plClothingMtl::kMaxTiles; j++)
{
layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(layerIdx), 0, j);
pbbm = (layer == nil ? nil : layer->GetPBBitmap());
bmSelectBtn = GetICustButton(GetDlgItem(hWnd, plClothingMtl::ButtonConstants[j]));
bmSelectBtn->SetText(pbbm ? (TCHAR*)pbbm->bi.Filename() : "(none)");
ReleaseICustButton(bmSelectBtn);
}
// And the thumbnail...
layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(plClothingMtl::kThumbnail));
if (layer == nil)
{
layer = TRACKED_NEW plLayerTex;
pb->SetValue(ParamID(plClothingMtl::kThumbnail), 0, layer);
}
pbbm = layer->GetPBBitmap();
if (pbbm)
{
bmSelectBtn = GetICustButton(GetDlgItem(hWnd, IDC_CLOTHING_THUMBNAIL));
bmSelectBtn->SetText((TCHAR*)pbbm->bi.Filename());
ReleaseICustButton(bmSelectBtn);
}
int setIdx = pb->GetInt(ParamID(plClothingMtl::kTileset));
ComboBox_SetCurSel(GetDlgItem(hWnd, IDC_CLOTHING_TILESET), setIdx);
ComboBox_SetCurSel(GetDlgItem(hWnd, IDC_CLOTHING_LAYER), pb->GetInt(ParamID(plClothingMtl::kLayer)));
mtl->InitTilesets();
plClothingTileset *tileset = mtl->fTilesets.Get(setIdx);
for (i = 0; i < tileset->fElements.GetCount(); i++)
{
plClothingElement *element = tileset->fElements.Get(i);
SendMessage(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i]),
WM_SETTEXT, NULL, (LPARAM)element->fName);
sprintf(buff, "(%d, %d)", element->fWidth, element->fHeight);
SendMessage(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i + 1]),
WM_SETTEXT, NULL, (LPARAM)buff);
ShowWindow(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i]), SW_SHOW);
ShowWindow(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i + 1]), SW_SHOW);
ShowWindow(GetDlgItem(hWnd, plClothingMtl::ButtonConstants[i]), SW_SHOW);
}
for (i = tileset->fElements.GetCount(); i < plClothingMtl::kMaxTiles; i++)
{
ShowWindow(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i]), SW_HIDE);
ShowWindow(GetDlgItem(hWnd, plClothingMtl::TextConstants[2 * i + 1]), SW_HIDE);
ShowWindow(GetDlgItem(hWnd, plClothingMtl::ButtonConstants[i]), SW_HIDE);
}
mtl->ReleaseTilesets();
fCustomText.UpdateText(pb, hWnd);
}
virtual void Update(TimeValue t, Interval& valid, IParamMap2* pmap) { UpdateDisplay(pmap); }
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Check if it is for our edit box
if (fCustomText.ProcessMsg(map, hWnd, msg, wParam, lParam))
return TRUE;
int id = LOWORD(wParam);
int code = HIWORD(wParam);
IParamBlock2 *pb = map->GetParamBlock();
plClothingMtl *mtl = (plClothingMtl *)pb->GetOwner();
HWND cbox = NULL;
plPlasmaMAXLayer *layer;
PBBitmap *pbbm;
ICustButton *bmSelectBtn;
int layerIdx = plClothingMtl::LayerToPBIdx[pb->GetInt(ParamID(plClothingMtl::kLayer))];
switch (msg)
{
case WM_INITDIALOG:
int j;
mtl->InitTilesets();
cbox = GetDlgItem(hWnd, IDC_CLOTHING_TILESET);
for (j = 0; j < mtl->fTilesets.GetCount(); j++)
SendMessage(cbox, CB_ADDSTRING, 0, (LPARAM)mtl->fTilesets.Get(j)->fName);
mtl->ReleaseTilesets();
cbox = GetDlgItem(hWnd, IDC_CLOTHING_LAYER);
for (j = 0; j < plClothingElement::kLayerMax; j++)
ComboBox_AddString(cbox, plClothingMtl::LayerStrings[j]);
return TRUE;
case WM_COMMAND:
if (id == IDC_CLOTHING_TILESET)
{
int setIdx = SendMessage(GetDlgItem(hWnd, id), CB_GETCURSEL, 0, 0);
pb->SetValue(plClothingMtl::kTileset, t, setIdx);
return TRUE;
}
if (id == IDC_CLOTHING_LAYER)
{
pb->SetValue(plClothingMtl::kLayer, t, ComboBox_GetCurSel(GetDlgItem(hWnd, id)));
return TRUE;
}
if (id == IDC_CLOTHING_THUMBNAIL)
{
layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(plClothingMtl::kThumbnail));
if (layer == nil)
return FALSE;
BitmapInfo bi;
bi.SetName(layer->GetPBBitmap() == nil ? "" : layer->GetPBBitmap()->bi.Name());
BOOL selectedNewBitmap = layer->HandleBitmapSelection();
if (selectedNewBitmap)
{
pbbm = layer->GetPBBitmap();
bmSelectBtn = GetICustButton(GetDlgItem(hWnd, IDC_CLOTHING_THUMBNAIL));
bmSelectBtn->SetText(pbbm != nil ? (TCHAR*)pbbm->bi.Filename() : "(none)");
ReleaseICustButton(bmSelectBtn);
}
return TRUE;
}
int buttonIdx = -1;
if (id == IDC_CLOTHING_TEXTURE1) buttonIdx = 0;
else if (id == IDC_CLOTHING_TEXTURE2) buttonIdx = 1;
else if (id == IDC_CLOTHING_TEXTURE3) buttonIdx = 2;
else if (id == IDC_CLOTHING_TEXTURE4) buttonIdx = 3;
if (buttonIdx != -1)
{
layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(layerIdx), 0, buttonIdx);
if (layer == nil)
{ // First time we've set a layer on this spot
layer = TRACKED_NEW plLayerTex;
pb->SetValue(ParamID(layerIdx), 0, layer, buttonIdx);
}
jvUniqueId oldId;
layer->GetBitmapAssetId(oldId);
BitmapInfo bi;
bi.SetName(layer->GetPBBitmap() == nil ? "" : layer->GetPBBitmap()->bi.Name());
BOOL selectedNewBitmap = layer->HandleBitmapSelection();
if (selectedNewBitmap)
{
// Check if it's ok, and undo if not.
hsBool choiceOk = true;
pbbm = layer->GetPBBitmap();
if (pbbm != nil)
{
mtl->InitTilesets();
plClothingTileset *tileset = mtl->fTilesets.Get(pb->GetInt(plClothingMtl::kTileset));
plClothingElement *element = tileset->fElements.Get(buttonIdx);
float targRatio = (float)element->fWidth / (float)element->fHeight;
float ratio = (float)pbbm->bi.Width() / (float)pbbm->bi.Height();
if (targRatio != ratio)
{
choiceOk = false;
hsMessageBox("That image's width/height ratio does not match the one for this tile. "
"Restoring the old selection.", "Invalid image", hsMessageBoxNormal);
}
else if (pbbm->bi.Width() < element->fWidth)
{
choiceOk = false;
hsMessageBox("The chosen image is too small for that tile slot. "
"Restoring the old selection.", "Invalid image", hsMessageBoxNormal);
}
mtl->ReleaseTilesets();
}
if (!choiceOk)
{
layer->SetBitmapAssetId(oldId);
layer->SetBitmap(&bi);
}
else
{
bmSelectBtn = GetICustButton(GetDlgItem(hWnd, plClothingMtl::ButtonConstants[buttonIdx]));
bmSelectBtn->SetText(pbbm != nil ? (TCHAR*)pbbm->bi.Filename() : "(none)");
ReleaseICustButton(bmSelectBtn);
}
}
}
return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
static ClothingBasicDlgProc gClothingBasicDlgProc;

View File

@ -0,0 +1,568 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plCompositeMtl.h"
#include "plPassMtl.h"
//#include "plCompositeMtlPB.h"
#include "plCompositeMtlDlg.h"
class plCompositeClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plCompositeMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_COMP_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return COMP_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaComposite"); }
HINSTANCE HInstance() { return hInstance; }
};
static plCompositeClassDesc plCompositeMtlDesc;
ClassDesc2* GetCompMtlDesc() { return &plCompositeMtlDesc; }
#include "plCompositeMtlPBDec.h"
const char *plCompositeMtl::BlendStrings[] = // Make sure these match up in order with the Blend enum (in the header)
{
"Vertex Alpha",
"Inverse Vtx Alpha",
"Vertex Illum Red",
"Inv. Vtx Illum Red",
"Vertex Illum Green",
"Inv. Vtx Illum Green",
"Vertex Illum Blue",
"Inv. Vtx Illum Blue"
};
plCompositeMtl::plCompositeMtl(BOOL loading) : fPassesPB(NULL)
{
plCompositeMtlDesc.MakeAutoParamBlocks(this);
if (!loading)
Reset();
int i;
for (i = 0; i < NSUBMTLS; i++)
{
plPassMtl *newMtl = TRACKED_NEW plPassMtl(false);
fPassesPB->SetValue(kCompPasses, 0, newMtl, i);
GetCOREInterface()->AssignNewName(fPassesPB->GetMtl(kCompPasses, 0, i));
}
}
void plCompositeMtl::Reset()
{
fIValid.SetEmpty();
}
ParamDlg* plCompositeMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fMtlDlg = TRACKED_NEW plCompositeMtlDlg(hwMtlEdit, imp, this);
return fMtlDlg;
}
void plCompositeMtl::SetParamDlg(ParamDlg *dlg)
{
fMtlDlg = (plCompositeMtlDlg*)dlg;
}
BOOL plCompositeMtl::SetDlgThing(ParamDlg* dlg)
{
if (dlg == fMtlDlg)
{
fMtlDlg->SetThing(this);
return TRUE;
}
return FALSE;
}
Interval plCompositeMtl::Validity(TimeValue t)
{
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
}
// The index for a face on a composite material is really just a bitmask for all the submaterials. This function only
// computes it... The mesh creator will ask it to be created if it's needed.
int plCompositeMtl::ComputeMaterialIndex(float opac[][2], int vertCount)
{
int index = 0;
int i;//, j;
int bitmask = 1;
for (i = NumSubMtls() - 1, bitmask <<= i; i >= 0; i--, bitmask >>= 1)
{
index |= bitmask;
/*
if (i == 0)
index |= bitmask; // it's not opaqued out, so include the base layer
else if (fPassesPB->GetInt(kCompOn, 0, i - 1)) // is the checkbox ticked? (ie, are we using it?)
{
bool transparent = true;
for (j = 0; j < vertCount; j++)
{
if (opac[j][i - 1] != 0.0)
transparent = false;
}
if (transparent)
continue; // totally transparent for this face, skip it
index |= bitmask; // include this material
bool opaque = true;
for (j = 0; j < vertCount; j++)
{
if (opac[j][i - 1] < 1.0)
opaque = false;
}
if (opaque && !((plPassMtlBase *)fPassesPB->GetMtl(kCompPasses, 0, i))->HasAlpha())
break; // This material is totally opaque, no sense including anything underneath it
}
*/
}
return index;
}
int plCompositeMtl::GetBlendStyle(int index)
{
return fPassesPB->GetInt(kCompBlend, 0, index - 1);
}
// Determines whether all materials are only blending on one channel (and possibly its inverse) and therefore
// it's ok to overwrite the vertex alpha exported for the span using this material.
// Returns: -1 if we use multiple sources, otherwise the source we all agree on
int plCompositeMtl::CanWriteAlpha()
{
int blend[3];
blend[0] = ((((plPassMtlBase *)GetSubMtl(0))->GetOutputBlend() == plPassMtlBase::kBlendNone) ? -1 : kCompBlendVertexAlpha);
blend[1] = (fPassesPB->GetInt(kCompOn, 0, 0) ? RemoveInverse(GetBlendStyle(1)) : -1);
blend[2] = (fPassesPB->GetInt(kCompOn, 0, 1) ? RemoveInverse(GetBlendStyle(2)) : -1);
int source = blend[0];
int i;
for (i = 1; i < 3; i++)
{
if (source < 0)
{
source = blend[i];
continue;
}
if (source >= 0 && blend[i] >= 0 && blend[i] != source)
return -1;
}
return source;
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plCompositeMtl::NumSubs()
{
return NumSubMtls();
}
TSTR plCompositeMtl::SubAnimName(int i)
{
return GetSubMtlSlotName(i);
}
Animatable* plCompositeMtl::SubAnim(int i)
{
return GetSubMtl(i);
}
int plCompositeMtl::NumRefs()
{
return 1;
}
RefTargetHandle plCompositeMtl::GetReference(int i)
{
if (i == kRefPasses)
return fPassesPB;
return NULL;
}
void plCompositeMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefPasses)
fPassesPB = (IParamBlock2 *)rtarg;
}
int plCompositeMtl::NumParamBlocks()
{
return 1;
}
IParamBlock2 *plCompositeMtl::GetParamBlock(int i)
{
if (i == kRefPasses)
return fPassesPB;
return NULL;
}
IParamBlock2 *plCompositeMtl::GetParamBlockByID(BlockID id)
{
if (fPassesPB->ID() == id)
return fPassesPB;
return NULL;
}
RefResult plCompositeMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message )
{
switch (message)
{
case REFMSG_CHANGE:
fIValid.SetEmpty();
if (hTarget == fPassesPB)
{
ParamID changingParam = fPassesPB->LastNotifyParamID();
fPassesPB->GetDesc()->InvalidateUI(changingParam);
}
break;
}
return REF_SUCCEED;
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plCompositeMtl::NumSubMtls()
{
// return fPassesPB->GetInt(kMultCount);
return NSUBMTLS;
}
Mtl *plCompositeMtl::GetSubMtl(int i)
{
if (i < NumSubMtls())
return fPassesPB->GetMtl(kCompPasses, 0, i);
return NULL;
}
void plCompositeMtl::SetSubMtl(int i, Mtl *m)
{
if (i < NumSubMtls())
fPassesPB->SetValue(kCompPasses, 0, m, i);
}
TSTR plCompositeMtl::GetSubMtlSlotName(int i)
{
TSTR str;
str.printf("Pass %d", i+1);
return str;
}
TSTR plCompositeMtl::GetSubMtlTVName(int i)
{
return GetSubMtlSlotName(i);
}
/*===========================================================================*\
| Standard IO
\*===========================================================================*/
#define MTL_HDR_CHUNK 0x4000
IOResult plCompositeMtl::Save(ISave *isave)
{
IOResult res;
isave->BeginChunk(MTL_HDR_CHUNK);
res = MtlBase::Save(isave);
if (res!=IO_OK) return res;
isave->EndChunk();
return IO_OK;
}
IOResult plCompositeMtl::Load(ILoad *iload)
{
IOResult res;
int id;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(id = iload->CurChunkID())
{
case MTL_HDR_CHUNK:
res = MtlBase::Load(iload);
break;
}
iload->CloseChunk();
if (res!=IO_OK)
return res;
}
return IO_OK;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plCompositeMtl::Clone(RemapDir &remap)
{
plCompositeMtl *mnew = TRACKED_NEW plCompositeMtl(FALSE);
*((MtlBase*)mnew) = *((MtlBase*)this);
mnew->ReplaceReference(kRefPasses, remap.CloneRef(fPassesPB));
mnew->fIValid.SetEmpty();
BaseClone(this, mnew, remap);
return (RefTargetHandle)mnew;
}
void plCompositeMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plCompositeMtl::Update(TimeValue t, Interval& valid)
{
if (!fIValid.InInterval(t))
{
fIValid.SetInfinite();
// fPassesPB->GetValue(kMtlLayLayer1On, t, fMapOn[0], fIValid);
for (int i = 0; i < NumSubMtls(); i++)
{
if (GetSubMtl(i))
GetSubMtl(i)->Update(t, fIValid);
}
}
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plCompositeMtl::SetAmbient(Color c, TimeValue t) {}
void plCompositeMtl::SetDiffuse(Color c, TimeValue t) {}
void plCompositeMtl::SetSpecular(Color c, TimeValue t) {}
void plCompositeMtl::SetShininess(float v, TimeValue t) {}
Color plCompositeMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plCompositeMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plCompositeMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plCompositeMtl::GetXParency(int mtlNum, BOOL backFace) { return 0.0f; }
float plCompositeMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plCompositeMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plCompositeMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plCompositeMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
//sc.GetBGColor(backColor, backTrans);
backColor.Black();
backTrans.White();
Point3 vtxIllum, vtxAlpha;
plPassMtl::GetInterpVtxValue(MAP_ALPHA, sc, vtxAlpha);
plPassMtl::GetInterpVtxValue(MAP_SHADING, sc, vtxIllum);
int count = NumSubMtls();
for (int i = 0; i < count; i++)
{
if (i > 0 && fPassesPB->GetInt(kCompOn, 0, i - 1) == 0) // Material is unchecked, skip it.
continue;
Mtl *mtl = GetSubMtl(i);
if (mtl == NULL || mtl->ClassID() != PASS_MTL_CLASS_ID)
continue;
float opacity;
if (i == 0)
{
opacity = 1.0f;
}
else
{
int blendMethod = fPassesPB->GetInt(kCompBlend, 0, i - 1);
switch(blendMethod)
{
case kCompBlendVertexAlpha:
case kCompBlendInverseVtxAlpha:
opacity = vtxAlpha.x;
break;
case kCompBlendVertexIllumRed:
case kCompBlendInverseVtxIllumRed:
opacity = vtxIllum.x;
break;
case kCompBlendVertexIllumGreen:
case kCompBlendInverseVtxIllumGreen:
opacity = vtxIllum.y;
break;
case kCompBlendVertexIllumBlue:
case kCompBlendInverseVtxIllumBlue:
opacity = vtxIllum.z;
break;
default:
opacity = 1.0f;
break;
}
if (IsInverseBlend(blendMethod))
opacity = 1 - opacity;
}
plPassMtl *passMtl = (plPassMtl*)mtl;
passMtl->ShadeWithBackground(sc, backColor, false); // Don't include the vtx alpha, that's OUR job
float currTrans = (1 - (1 - sc.out.t.r) * opacity);
backTrans *= currTrans;
backColor = backColor * currTrans + sc.out.c * opacity;
}
sc.out.t = backTrans;
sc.out.c = backColor;
}
float plCompositeMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plCompositeMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
/*
void plCompositeMtl::SetNumSubMtls(int num)
{
TimeValue t = GetCOREInterface()->GetTime();
int curNum = fPassesPB->GetInt(kMultCount);
fPassesPB->SetValue(kMultCount, 0, num);
fPassesPB->SetCount(kMultPasses, num);
fPassesPB->SetCount(kMultOn, num);
for (int i = curNum; i < num; i++)
{
plPassMtl *newMtl = TRACKED_NEW plPassMtl(false);
fPassesPB->SetValue(kMultPasses, t, newMtl, i);
fPassesPB->SetValue(kMultOn, t, TRUE, i);
GetCOREInterface()->AssignNewName(fPassesPB->GetMtl(kMultPasses, t, i));
}
}
*/
void plCompositeMtl::SetOpacityVal(float *target, UVVert *alpha, UVVert *illum, int method)
{
if (method == kCompBlendVertexAlpha || method == kCompBlendInverseVtxAlpha)
{
if (alpha == NULL)
*target = 1.0f;
else
*target = alpha->x;
}
else if (method == kCompBlendVertexIllumRed || method == kCompBlendInverseVtxIllumRed)
{
if (illum == NULL)
*target = 1.0f;
else
*target = illum->x;
}
else if (method == kCompBlendVertexIllumGreen || method == kCompBlendInverseVtxIllumGreen)
{
if (illum == NULL)
*target = 1.0f;
else
*target = illum->y;
}
else if (method == kCompBlendVertexIllumBlue || method == kCompBlendInverseVtxIllumBlue)
{
if (illum == NULL)
*target = 1.0f;
else
*target = illum->z;
}
else
{
*target = 1.0f;
}
if (method == kCompBlendInverseVtxAlpha ||
method == kCompBlendInverseVtxIllumRed ||
method == kCompBlendInverseVtxIllumGreen ||
method == kCompBlendInverseVtxIllumBlue)
{
*target = 1.0f - *target;
}
}
/*
int plCompositeMtl::UVChannelsNeeded(bool makeAlphaLayer)
{
if (makeAlphaLayer)
return 1;
// Otherwise, we do have vertex alpha... can we get by without taking up a UV channel?
int channels = 0;
int i;
for (i = 0; i < NumSubMtls() - 1; i++)
{
if (!fPassesPB->GetInt(kCompOn, 0, i))
continue; // The material is unchecked, no need to see if it needs a channel
int method = fPassesPB->GetInt(kCompBlend, 0, i);
if (!(method == kCompBlendVertexAlpha || method1 == kCompBlendInverseVtxAlpha))
{
channels = 1;
break;
}
}
return channels;
}
*/

View File

@ -0,0 +1,154 @@
/*==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/>.
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==*/
#ifndef __PLCOMPMTL__H
#define __PLCOMPMTL__H
#include "Max.h"
#include "../resource.h"
#include "istdplug.h"
#include "iparamb2.h"
#include "iparamm2.h"
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;
#define COMP_MTL_CLASS_ID Class_ID(0x237c422d, 0x64ab6371)
class plCompositeMtlDlg;
class plCompositeMtl : public Mtl
{
protected:
IParamBlock2 *fPassesPB;
Interval fIValid;
plCompositeMtlDlg *fMtlDlg;
public:
enum
{
kCompPasses,
kCompOn,
kCompBlend,
kCompUVChannels,
kCompLayerCounts
};
// Make sure to pair up each blend mode with an inverse after it
// (This way we check for an inverse blend by doing an odd/even check.)
enum BlendMethod // These should match up in order with the blend strings
{
kCompBlendVertexAlpha,
kCompBlendInverseVtxAlpha,
kCompBlendVertexIllumRed,
kCompBlendInverseVtxIllumRed,
kCompBlendVertexIllumGreen,
kCompBlendInverseVtxIllumGreen,
kCompBlendVertexIllumBlue,
kCompBlendInverseVtxIllumBlue,
kCompNumBlendMethods
};
static const char *BlendStrings[];
enum { kRefPasses };
enum { kBlkPasses };
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void Reset();
void NotifyChanged();
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
// Shade and displacement calculation
void Shade(ShadeContext& sc);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
// SubTexmap access methods
int NumSubMtls();
Mtl* GetSubMtl(int i);
void SetSubMtl(int i, Mtl *m);
TSTR GetSubMtlSlotName(int i);
TSTR GetSubMtlTVName(int i);
BOOL SetDlgThing(ParamDlg* dlg);
plCompositeMtl(BOOL loading);
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
//From Animatable
Class_ID ClassID() { return COMP_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_COMP_MTL); }
RefTargetHandle Clone(RemapDir &remap);
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
void DeleteThis() { delete this; }
void SetParamDlg(ParamDlg *dlg);
int ComputeMaterialIndex(float opac[][2], int vertCount);
int GetBlendStyle(int index);
int CanWriteAlpha();
bool IsInverseBlend(int blend) const { return blend & 1; }
int RemoveInverse(int blend) { return blend - (blend & 1); }
//void SetNumSubMtls(int num);
void SetOpacityVal(float *pt, UVVert *alphas, UVVert *illums, int method);
//DllExport int UVChannelsNeeded(bool makeAlphaLayer);
};
#endif // __PLCOMPMTL__H

View File

@ -0,0 +1,277 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "max.h"
#include "MaxIcon.h"
#include "resource.h"
#include "plCompositeMtl.h"
//#include "plCompositeMtlPB.h"
//#include "plMaxLayer.h"
#include "plCompositeMtlDlg.h"
struct LayerID
{
int layerID;
int activeID;
int blendID;
};
static LayerID kLayerID[] =
{
{ IDC_TEX1, 0, 0 },
{ IDC_TEX2, IDC_TEXON2, IDC_COMBO2 },
{ IDC_TEX3, IDC_TEXON3, IDC_COMBO3 }
};
//-----------------------------------------------------------------------------
// Constructor and destructor
//-----------------------------------------------------------------------------
plCompositeMtlDlg::plCompositeMtlDlg(HWND hwMtlEdit, IMtlParams *imp, plCompositeMtl *m)
{
fDADMgr.Init(this);
fhMtlEdit = hwMtlEdit;
fhRollup = NULL;
fMtl = m;
fPBlock = fMtl->GetParamBlockByID(plCompositeMtl::kBlkPasses);
ip = imp;
valid = FALSE;
for (int i = 0; i < NSUBMTLS; i++)
fLayerBtns[i] = NULL;
curTime = imp->GetTime();
fhRollup = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_COMPOSITE),
ForwardProc,
"Composite Parameters",
(LPARAM)this);
}
plCompositeMtlDlg::~plCompositeMtlDlg()
{
fMtl->SetParamDlg(NULL);
for (int i = 0; i < NSUBMTLS; i++)
{
ReleaseICustButton(fLayerBtns[i]);
fLayerBtns[i] = NULL;
}
SetWindowLong(fhRollup, GWL_USERDATA, NULL);
ip->DeleteRollupPage(fhRollup);
fhRollup = NULL;
}
//-----------------------------------------------------------------------------
// Functions inheirited from ParamDlg
//-----------------------------------------------------------------------------
void plCompositeMtlDlg::SetThing(ReferenceTarget *m)
{
assert(m->SuperClassID() == MATERIAL_CLASS_ID);
assert(m->ClassID() == COMP_MTL_CLASS_ID);
// Bad?
if (fMtl)
fMtl->SetParamDlg(NULL);
fMtl = (plCompositeMtl *)m;
if (fMtl)
fMtl->SetParamDlg(this);
LoadDialog();
IUpdateMtlDisplay();
}
void plCompositeMtlDlg::SetTime(TimeValue t)
{
if (t != curTime)
{
curTime = t;
Interval v;
fMtl->Update(ip->GetTime(),v);
LoadDialog();
IUpdateMtlDisplay();
}
}
void plCompositeMtlDlg::ReloadDialog()
{
Interval v;
fMtl->Update(ip->GetTime(), v);
LoadDialog();
}
void plCompositeMtlDlg::ActivateDlg(BOOL onOff)
{
}
int plCompositeMtlDlg::FindSubMtlFromHWND(HWND hwnd)
{
for (int i = 0; i < NSUBMTLS; i++)
{
if (hwnd == fLayerBtns[i]->GetHwnd())
return i;
}
return -1;
}
BOOL plCompositeMtlDlg::ForwardProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
plCompositeMtlDlg *theDlg;
if (msg == WM_INITDIALOG)
{
theDlg = (plCompositeMtlDlg*)lParam;
theDlg->fhRollup = hDlg;
SetWindowLong(hDlg, GWL_USERDATA, lParam);
}
else
{
if ((theDlg = (plCompositeMtlDlg *)GetWindowLong(hDlg, GWL_USERDATA)) == NULL)
return FALSE;
}
return theDlg->LayerPanelProc(hDlg,msg,wParam,lParam);
}
//----------------------------------------------------------------------------
// Layer panel processor
//----------------------------------------------------------------------------
BOOL plCompositeMtlDlg::LayerPanelProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
int id = LOWORD(wParam);
int code = HIWORD(wParam);
int i;
switch (msg)
{
case WM_INITDIALOG:
{
for (i = 0; i < NSUBMTLS; i++)
{
fLayerBtns[i] = GetICustButton(GetDlgItem(hDlg, kLayerID[i].layerID));
fLayerBtns[i]->SetDADMgr(&fDADMgr);
if (i > 0) // the first material doesn't get one, nyah nyah!
{
HWND cbox = NULL;
int j;
for (j = 0; j < plCompositeMtl::kCompNumBlendMethods; j++)
{
cbox = GetDlgItem(hDlg, kLayerID[i].blendID);
SendMessage(cbox, CB_ADDSTRING, 0, (LPARAM)plCompositeMtl::BlendStrings[j]);
}
SendMessage(cbox, CB_SETCURSEL, 0, 0);
}
}
// TEMP testing
UpdateLayerDisplay();
IUpdateMtlDisplay();
}
return TRUE;
case WM_DESTROY:
for (i = 0; i < NSUBMTLS; i++)
{
ReleaseICustButton(fLayerBtns[i]);
fLayerBtns[i] = NULL;
}
break;
case WM_COMMAND:
{
for (i = 0; i < NSUBMTLS; i++)
{
if (id == kLayerID[i].activeID)
{
bool checked = SendMessage(GetDlgItem(hDlg, id), BM_GETCHECK, 0, 0) == BST_CHECKED;
fPBlock->SetValue(plCompositeMtl::kCompOn, curTime, checked, i - 1);
return TRUE;
}
if (id == kLayerID[i].layerID)
{
PostMessage(fhMtlEdit, WM_SUB_MTL_BUTTON, i, (LPARAM)fMtl);
return TRUE;
}
if (id == kLayerID[i].blendID)
{
fPBlock->SetValue(plCompositeMtl::kCompBlend, curTime, SendMessage(GetDlgItem(hDlg, id), CB_GETCURSEL, 0, 0), i - 1);
return TRUE;
}
}
}
// IUpdateMtlDisplay();
break;
}
return FALSE;
}
void plCompositeMtlDlg::UpdateLayerDisplay()
{
int i;
for (i = 0; i < NSUBMTLS; i++)
{
Mtl *m = fPBlock->GetMtl(plCompositeMtl::kCompPasses, curTime, i);
TSTR nm;
if (m)
nm = m->GetName();
else
nm = "None";
fLayerBtns[i]->SetText(nm.data());
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].layerID), SW_SHOW);
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].activeID), SW_SHOW);
if (i > 0)
{
int check = (fPBlock->GetInt(plCompositeMtl::kCompOn, curTime, i - 1) == 0 ? BST_UNCHECKED : BST_CHECKED);
SendMessage(GetDlgItem(fhRollup, kLayerID[i].activeID), BM_SETCHECK, (WPARAM)check, 0);
int selection = fPBlock->GetInt(plCompositeMtl::kCompBlend, curTime, i - 1);
SendMessage(GetDlgItem(fhRollup, kLayerID[i].blendID), CB_SETCURSEL, (WPARAM)selection, 0);
}
}
}
void plCompositeMtlDlg::LoadDialog()
{
if (fMtl)
{
fPBlock = fMtl->GetParamBlockByID(plCompositeMtl::kBlkPasses);
if (fhRollup)
UpdateLayerDisplay();
}
}

View File

@ -0,0 +1,86 @@
/*==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/>.
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==*/
#ifndef PL_COMPMTLDLG_H
#define PL_COMPMTLDLG_H
#define NSUBMTLS 3
class plCompositeMtlDlg : public ParamDlg
{
protected:
IParamBlock2 *fPBlock;
HWND fhMtlEdit; // Window handle of the materials editor dialog
HWND fhRollup; // Our rollup panel
IMtlParams *ip;
plCompositeMtl *fMtl; // current mtl being edited.
TimeValue curTime;
int isActive;
BOOL valid;
// int offset;
ICustButton *fLayerBtns[NSUBMTLS];
MtlDADMgr fDADMgr; // For drag-drop sub-materials
public:
// Constructor and destructor
plCompositeMtlDlg(HWND hwMtlEdit, IMtlParams *imp, plCompositeMtl *m);
~plCompositeMtlDlg();
// Functions inherited from ParamDLg:
Class_ID ClassID() { return COMP_MTL_CLASS_ID; }
void SetThing(ReferenceTarget *m);
ReferenceTarget* GetThing() { return (ReferenceTarget*)fMtl; }
void SetTime(TimeValue t);
void ReloadDialog();
void ActivateDlg(BOOL onOff);
void DeleteThis() { delete this; }
int FindSubMtlFromHWND(HWND hw);
static BOOL CALLBACK ForwardProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL LayerPanelProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void UpdateLayerDisplay();
void LoadDialog();
/*
// Lower-level crap
void Invalidate(); // Called by ParamMtl
BOOL IsActive() { return isActive; }
private:
void ClampOffset();
void SetNumMats();
void UpdateLayers();
void UpdateControlFor(int np);
void VScroll(int code, short int cpos );
*/
protected:
void IUpdateMtlDisplay() { if (ip) ip->MtlChanged(); }
};
#endif

View File

@ -0,0 +1,65 @@
/*==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/>.
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==*/
#ifndef PL_COMPOSITE_MTL_PB_H
#define PL_COMPOSITE_MTL_PB_H
enum
{
kCompPasses,
kCompOn,
kCompBlend,
kCompUVChannels,
kCompLayerCounts
};
// Make sure to pair up each blend mode with an inverse after it
// (This way we check for an inverse blend by doing an odd/even check.)
enum BlendMethod // These should match up in order with the blend strings
{
kCompBlendVertexAlpha,
kCompBlendInverseVtxAlpha,
kCompBlendVertexIllumRed,
kCompBlendInverseVtxIllumRed,
kCompBlendVertexIllumGreen,
kCompBlendInverseVtxIllumGreen,
kCompBlendVertexIllumBlue,
kCompBlendInverseVtxIllumBlue,
kCompNumBlendMethods
};
static char *BlendStrings[] = // Make sure these match up in order with the Blend enum
{
"Vertex Alpha",
"Inverse Vtx Alpha",
"Vertex Illum Red",
"Inv. Vtx Illum Red",
"Vertex Illum Green",
"Inv. Vtx Illum Green",
"Vertex Illum Blue",
"Inv. Vtx Illum Blue"
};
#endif //PL_COMPOSITE_MTL_PB_H

View File

@ -0,0 +1,51 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plCompositeMtl.h"
//#include "plCompositeMtlPB.h"
ClassDesc2* GetCompMtlDesc();
static ParamBlockDesc2 gCompositeMtlPB
(
plCompositeMtl::kBlkPasses, _T("composite"), 0, GetCompMtlDesc(),
P_AUTO_CONSTRUCT, plCompositeMtl::kRefPasses,
plCompositeMtl::kCompPasses, _T("passes"), TYPE_MTL_TAB, 3, 0, 0,
end,
plCompositeMtl::kCompOn, _T("passOn"), TYPE_BOOL_TAB, 2, 0, 0,
p_default, TRUE,
end,
plCompositeMtl::kCompBlend, _T("BlendMethod"), TYPE_INT_TAB, 2, 0, 0,
p_default, 0,
end,
plCompositeMtl::kCompUVChannels, _T("UVChannels"), TYPE_INT_TAB, 2, 0, 0,
p_default, 0,
end,
plCompositeMtl::kCompLayerCounts, _T("LayerCounts"), TYPE_INT_TAB, 3, 0, 0,
p_default, 0,
end,
end
);

View File

@ -0,0 +1,784 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plDecalMtl.h"
#include "resource.h"
//extern ClassDesc2* GetMaxLayerDesc();
#include "Shaders.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "plPassBaseParamIDs.h"
#include "plDecalMtlBasicPB.h"
#include "plDecalMtlLayersPB.h"
#include "iparamm2.h"
#include "Layers/plLayerTex.h"
#include "Layers/plStaticEnvLayer.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
extern HINSTANCE hInstance;
class plDecalMtlClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plDecalMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_DECAL_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return DECAL_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaMaterial"); }
HINSTANCE HInstance() { return hInstance; }
};
static plDecalMtlClassDesc plDecalMtlDesc;
ClassDesc2* GetDecalMtlDesc() { return &plDecalMtlDesc; }
// For initializing paramblock descriptor
ParamBlockDesc2 *GetDecalBasicPB();
ParamBlockDesc2 *GetDecalAdvPB();
ParamBlockDesc2 *GetDecalLayersPB();
#include "plDecalMtlAdvPBDec.h"
#include "plDecalMtlBasicPBDec.h"
#include "plDecalMtlLayersPBDec.h"
#include "plDecalMtlAnimPBDec.h"
plDecalMtl::plDecalMtl(BOOL loading) : plPassMtlBase( loading )
{
plDecalMtlDesc.MakeAutoParamBlocks( this );
fLayersPB->SetValue( kDecalLayBase, 0, TRACKED_NEW plLayerTex );
fLayersPB->SetValue( kDecalLayTop, 0, TRACKED_NEW plLayerTex );
// If we do this later (like, when the dialog loads) something blows up,
// somewhere in Max. It didn't in 4, it does in 7. This seems to fix it.
if (!loading)
IVerifyStealthPresent(ENTIRE_ANIMATION_NAME);
}
ParamDlg* plDecalMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fIMtlParams = imp;
IAutoMParamDlg* masterDlg = plDecalMtlDesc.CreateParamDlgs(hwMtlEdit, imp, this);
return (ParamDlg*)masterDlg;
}
BOOL plDecalMtl::SetDlgThing(ParamDlg* dlg)
{
return FALSE;
}
Interval plDecalMtl::Validity(TimeValue t)
{
#if 0 // mf horse
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
#else // mf horse
const char* name = GetName();
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
Interval v = FOREVER;
fBasicPB->GetValidity(t, v);
fAdvPB->GetValidity(t, v);
if( fLayersPB->GetTexmap(kDecalLayBase) )
v &= fLayersPB->GetTexmap(kDecalLayBase)->Validity(t);
if( fLayersPB->GetTexmap(kDecalLayTop) )
v &= fLayersPB->GetTexmap(kDecalLayTop)->Validity(t);
return v;
#endif // mf horse
}
//// GetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
RefTargetHandle plDecalMtl::GetReference( int i )
{
switch( i )
{
case kRefBasic: return fBasicPB;
case kRefAdv: return fAdvPB;
case kRefLayers: return fLayersPB;
case kRefAnim: return fAnimPB;
}
return plPassMtlBase::GetReference( i );
}
//// SetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
void plDecalMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefBasic)
fBasicPB = (IParamBlock2 *)rtarg;
else if (i == kRefAdv)
fAdvPB = (IParamBlock2 *)rtarg;
else if (i == kRefLayers)
fLayersPB = (IParamBlock2 *)rtarg;
else if (i == kRefAnim)
fAnimPB = (IParamBlock2 *)rtarg;
else
plPassMtlBase::SetReference( i, rtarg );
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plDecalMtl::NumSubs()
{
return 6;
}
TSTR plDecalMtl::SubAnimName(int i)
{
switch (i)
{
case 0: return fBasicPB->GetLocalName();
case 1: return fAdvPB->GetLocalName();
case 2: return fLayersPB->GetLocalName();
case 3: return fAnimPB->GetLocalName();
case 4: return "Base Layer";
case 5: return "Top Layer";
}
return "";
}
Animatable* plDecalMtl::SubAnim(int i)
{
switch (i)
{
case 0: return fBasicPB;
case 1: return fAdvPB;
case 2: return fLayersPB;
case 3: return fAnimPB;
case 4: return fLayersPB->GetTexmap(kDecalLayBase);
case 5:
if (fLayersPB->GetInt(kDecalLayTopOn))
return fLayersPB->GetTexmap(kDecalLayTop);
break;
}
return NULL;
}
int plDecalMtl::NumParamBlocks()
{
return 4;
}
IParamBlock2* plDecalMtl::GetParamBlock(int i)
{
return (IParamBlock2*)GetReference(i);
}
IParamBlock2* plDecalMtl::GetParamBlockByID(BlockID id)
{
if (fBasicPB->ID() == id)
return fBasicPB;
else if (fAdvPB->ID() == id)
return fAdvPB;
else if (fLayersPB->ID() == id)
return fLayersPB;
else if (fAnimPB->ID() == id)
return fAnimPB;
return NULL;
}
RefResult plDecalMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
return plPassMtlBase::NotifyRefChanged( changeInt, hTarget, partID, message );
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plDecalMtl::NumSubTexmaps()
{
return 2;
}
Texmap* plDecalMtl::GetSubTexmap(int i)
{
if (i == 0)
return fLayersPB->GetTexmap(kDecalLayBase);
else if (i == 1)
return fLayersPB->GetTexmap(kDecalLayTop);
return NULL;
}
void plDecalMtl::SetSubTexmap(int i, Texmap *m)
{
if (i == 0)
fLayersPB->SetValue(kDecalLayBase, 0, m);
else if (i == 1)
fLayersPB->SetValue(kDecalLayTop, 0, m);
}
TSTR plDecalMtl::GetSubTexmapSlotName(int i)
{
if (i == 0)
return "Base";
else if (i == 1)
return "Top";
return "";
}
TSTR plDecalMtl::GetSubTexmapTVName(int i)
{
return GetSubTexmapSlotName(i);
}
int plDecalMtl::SubTexmapOn(int i)
{
if (i == 0)
return 1;
else if (i == 1 && fLayersPB->GetInt(kDecalLayTopOn))
return 1;
return 0;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plDecalMtl::Clone(RemapDir &remap)
{
plDecalMtl *mnew = TRACKED_NEW plDecalMtl(FALSE);
plPassMtlBase::ICloneBase( mnew, remap );
return (RefTargetHandle)mnew;
}
void plDecalMtl::ICloneRefs( plPassMtlBase *target, RemapDir &remap )
{
target->ReplaceReference(kRefBasic, remap.CloneRef(fBasicPB));
target->ReplaceReference(kRefAdv, remap.CloneRef(fAdvPB));
target->ReplaceReference(kRefLayers, remap.CloneRef(fLayersPB));
target->ReplaceReference(kRefAnim, remap.CloneRef(fAnimPB));
}
void plDecalMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plDecalMtl::Update(TimeValue t, Interval& valid)
{
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
if (!fIValid.InInterval(t))
{
fIValid.SetInfinite();
if( fLayersPB->GetTexmap(kDecalLayBase) )
fLayersPB->GetTexmap(kDecalLayBase)->Update(t, fIValid);
if( fLayersPB->GetTexmap(kDecalLayTop) )
fLayersPB->GetTexmap(kDecalLayTop)->Update(t, fIValid);
// fLayersPB->GetValue(kMtlLayLayer1On, t, fMapOn[0], fIValid);
/*
for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
fSubTexmap[i]->Update(t,fIValid);
}
*/
}
// Our wonderful way of version handling--if the runtimeColor is (-1,-1,-1), we know it's
// just been initialized, so set it to the static color (this lets us do the right thing for
// loading old paramBlocks)
if( fBasicPB )
{
Color run = fBasicPB->GetColor( kDecalBasRunColor, 0 );
if( run == Color(-1,-1,-1) )
{
fBasicPB->SetValue( kDecalBasRunColor, 0, fBasicPB->GetColor( kDecalBasColor, 0 ) );
}
// Also, if shineStr is anything other than -1, then it must be an old paramblock and we need
// to convert to our new specColor (we know this because the original valid range was 0-100)
int shine = fBasicPB->GetInt( kDecalBasShineStr, 0 );
if( shine != -1 )
{
fBasicPB->SetValue( kDecalBasSpecColor, 0, Color( (float)shine / 100.f, (float)shine / 100.f, (float)shine / 100.f ) );
fBasicPB->SetValue( kDecalBasShineStr, 0, (int)-1 );
}
}
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plDecalMtl::SetAmbient(Color c, TimeValue t) {}
void plDecalMtl::SetDiffuse(Color c, TimeValue t) {}
void plDecalMtl::SetSpecular(Color c, TimeValue t) {}
void plDecalMtl::SetShininess(float v, TimeValue t) {}
Color plDecalMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plDecalMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plDecalMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plDecalMtl::GetXParency(int mtlNum, BOOL backFace)
{
int opacity = fBasicPB->GetInt( kDecalBasOpacity, 0 );
float alpha = 1.0f - ( (float)opacity / 100.0f );
return alpha;
}
float plDecalMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plDecalMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plDecalMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/////////////////////////////////////////////////////////////////
void plDecalMtl::SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb)
{
#if 0
if (texHandleValid.InInterval(t)) {
mtl->texture.SetCount(numTexHandlesUsed);
for (int i=0; i<numTexHandlesUsed; i++) {
if (texHandle[i]) {
mtl->texture[i].textHandle = texHandle[i]->GetHandle();
Texmap *tx = (*maps)[useSubForTex[i]].map;
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[i], tx );
SetTexOps(mtl,i,texOpsType[i]);
}
}
return;
}
#endif
#if 0 // WTF?!?!?!?
Texmap *tx[2];
int diffChan = stdIDToChannel[ ID_DI ];
int opacChan = stdIDToChannel[ ID_OP ];
tx[0] = (*maps)[diffChan].IsActive()?(*maps)[diffChan].map:NULL;
tx[1] = (*maps)[opacChan].IsActive()?(*maps)[opacChan].map:NULL;
#endif
int nsupport = cb.NumberTexturesSupported();
#if 0
BITMAPINFO *bmi[NTEXHANDLES];
int nmaps=0;
for (int i=0; i<NTEXHANDLES; i++) {
if (tx[i]) nmaps ++;
bmi[i] = NULL;
}
mtl->texture.SetCount(nmaps);
if (nmaps==0)
return;
for (i=0; i<nmaps; i++)
mtl->texture[i].textHandle = NULL;
texHandleValid.SetInfinite();
Interval valid;
BOOL needDecal = FALSE;
int ntx = 0;
int op;
int forceW = 0;
int forceH = 0;
if (tx[0]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[0], tx[0]);
TextureInfo &ti = mtl->texture[0];
if (ti.tiling[0]==GW_TEX_NO_TILING||ti.tiling[1]==GW_TEX_NO_TILING)
needDecal = TRUE;
op = needDecal?TXOP_ALPHABLEND:TXOP_MODULATE;
bmi[0] = tx[0]->GetVPDisplayDIB(t,cb,valid,FALSE);
if (bmi[0]) {
texHandleValid &= valid;
useSubForTex[0] = diffChan;
ntx = 1;
forceW = bmi[0]->bmiHeader.biWidth;
forceH = bmi[0]->bmiHeader.biHeight;
}
}
if (tx[1]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[ntx], tx[1]);
if (nsupport>ntx) {
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlpha(bmi[1], (*maps)[opacChan].amount, GetOpacity(t),ntx?whiteCol:pShader->GetDiffuseClr(t));
texHandle[ntx] = cb.MakeHandle(bmi[1]);
bmi[1] = NULL;
mtl->texture[ntx].textHandle = texHandle[ntx]->GetHandle();
SetTexOps(mtl,ntx,TXOP_OPACITY);
useSubForTex[ntx] = opacChan;
ntx++;
}
}
else {
if (!needDecal) {
TextureInfo ti;
// if (SameUV(mtl->texture[0],mtl->texture[1])) {
// Not really correct to combine channels for different UV's but what the heck.
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE, forceW, forceH);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlphaInto(bmi[1], bmi[0], (*maps)[opacChan].amount, GetOpacity(t));
op = TXOP_OPACITY;
free(bmi[1]);
bmi[1] = NULL;
}
// }
}
}
}
if (bmi[0]) {
texHandle[0] = cb.MakeHandle(bmi[0]);
bmi[0] = NULL;
mtl->texture[0].textHandle = texHandle[0]->GetHandle();
SetTexOps(mtl,0,op);
}
mtl->texture.SetCount(ntx);
numTexHandlesUsed = ntx;
#endif
}
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plDecalMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
sc.GetBGColor(backColor, backTrans);
ShadeWithBackground(sc, backColor);
}
//// Requirements ////////////////////////////////////////////////////////////
// Tells MAX what we need to render ourselves properly, such as translucency,
// two-sidedness, etc. Flags are in imtl.h in the MAX SDK.
ULONG plDecalMtl::Requirements( int subMtlNum )
{
ULONG req = 0;
req = Mtl::Requirements( subMtlNum );
// Uncomment this to get the background color fed to our ShadeWithBackground()
// (slower processing tho)
// req |= MTLREQ_BGCOL;
req |= MTLREQ_UV;
int blendType = fLayersPB->GetInt( kDecalLayOutputBlend );
if( blendType == kBlendAdd )
req |= MTLREQ_ADDITIVE_TRANSP | MTLREQ_TRANSP;
else if( blendType == kBlendAlpha )
req |= MTLREQ_TRANSP;
else if( fBasicPB->GetInt( kDecalBasOpacity, 0 ) != 100 )
req |= MTLREQ_TRANSP;
if( fAdvPB->GetInt( kPBAdvTwoSided ) )
req |= MTLREQ_2SIDE;
return req;
}
void plDecalMtl::ShadeWithBackground(ShadeContext &sc, Color background)
{
#if 1
// old
#if 0
Color lightCol,rescol, diffIllum0;
RGBA mval;
Point3 N0,P;
BOOL bumped = FALSE;
int i;
if (gbufID)
sc.SetGBufferID(gbufID);
if (sc.mode == SCMODE_SHADOW) {
float opac = 0.0;
for (i=0; i < NumSubTexmaps(); i++) {
if (SubTexmapOn(i)) {
hsMaxLayerBase *hsmLay = (hsMaxLayerBase *)GetSubTexmap(i);
opac += hsmLay->GetOpacity(t);
}
}
float f = 1.0f - opac;
sc.out.t = Color(f,f,f);
return;
}
N0 = sc.Normal();
P = sc.P();
#endif
TimeValue t = sc.CurTime();
Color color(0, 0, 0);
float alpha = 0.0;
// Evaluate Base layer
Texmap *map = fLayersPB->GetTexmap(kDecalLayBase);
if (map && ( map->ClassID() == LAYER_TEX_CLASS_ID
|| map->ClassID() == STATIC_ENV_LAYER_CLASS_ID ) )
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
color = evalColor;
alpha = evalColor.a;
}
// Evaluate Top layer, if it's on
if (fLayersPB->GetInt(kDecalLayTopOn))
{
Texmap *map = fLayersPB->GetTexmap(kDecalLayTop);
if (map && ( map->ClassID() == LAYER_TEX_CLASS_ID
|| map->ClassID() == STATIC_ENV_LAYER_CLASS_ID ) )
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
// Blend layers
int blendType = fLayersPB->GetInt(kDecalLayBlend);
switch (blendType)
{
case kBlendAdd:
color += evalColor * evalColor.a;
break;
case kBlendAlpha:
color = (1.0f - evalColor.a) * color + evalColor.a * evalColor;
alpha = 1 - (1 - evalColor.a) * (1 - alpha);
break;
case kBlendMult:
color *= evalColor;
break;
default: // No blend...
color = evalColor;
alpha = 1.0;
break;
}
}
}
#if 1
AColor black;
black.Black();
AColor white;
white.White();
SIllumParams ip;
if (fBasicPB->GetInt(kDecalBasEmissive))
{
// Emissive objects don't get shaded
ip.diffIllum = fBasicPB->GetColor(kDecalBasColorAmb, t) * color;
ip.diffIllum.ClampMinMax();
ip.specIllum = black;
}
else
{
//
// Shading setup
//
// Setup the parameters for the shader
ip.amb = fBasicPB->GetColor(kDecalBasColorAmb, t);
ip.diff = fBasicPB->GetColor(kDecalBasColor, t) * color;
ip.diffIllum = black;
ip.specIllum = black;
ip.N = sc.Normal();
ip.V = sc.V();
//
// Specularity
//
if (fBasicPB->GetInt(kDecalBasUseSpec, t))
{
ip.sh_str = 1.f;
ip.spec = fBasicPB->GetColor( kDecalBasSpecColor, t );
ip.ph_exp = (float)pow(2.0f,float(fBasicPB->GetInt(kDecalBasShine, t)) / 10.0f);
ip.shine = float(fBasicPB->GetInt(kDecalBasShine, t)) / 100.0f;
}
else
{
ip.sh_str = 0;
ip.ph_exp = 0;
ip.shine = 0;
ip.spec = black;
}
ip.softThresh = 0;
//
// Do the shading
Shader *myShader = GetShader(SHADER_BLINN);
myShader->Illum(sc, ip);
// Override shader parameters
if (fAdvPB->GetInt(kPBAdvNoShade))
{
ip.diffIllum = black;
ip.specIllum = black;
}
if (fAdvPB->GetInt(kPBAdvWhite))
{
ip.diffIllum = white;
ip.specIllum = black;
}
ip.diffIllum.ClampMinMax();
ip.specIllum.ClampMinMax();
ip.diffIllum = ip.amb * sc.ambientLight + ip.diff * ip.diffIllum;
}
// AColor returnColor = AColor(opac * ip.diffIllum + ip.specIllum, opac)
#endif
// Get opacity and combine with alpha
float opac = float(fBasicPB->GetInt(kDecalBasOpacity, t)) / 100.0f;
alpha *= opac;
// MAX will do the additive/alpha/no blending for us based on what Requirements()
// we tell it. However, since MAX's formula is bgnd*sc.out.t + sc.out.c,
// we have to multiply our output color by the alpha.
// If we ever need a more complicated blending function, you can request the
// background color via Requirements() (otherwise it's just black) and then do
// the blending yourself; however, if the transparency isn't set, the shadows
// will be opaque, so be careful.
Color outC = ip.diffIllum + ip.specIllum;
sc.out.c = ( outC * alpha );
sc.out.t = Color( 1.f - alpha, 1.f - alpha, 1.f - alpha );
#endif
}
float plDecalMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plDecalMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
bool plDecalMtl::HasAlpha()
{
return ((plLayerTex *)fLayersPB->GetTexmap(kDecalLayBase))->HasAlpha();
}
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
int plDecalMtl::GetBasicWire() { return fAdvPB->GetInt(kPBAdvWire); }
int plDecalMtl::GetMeshOutlines() { return fAdvPB->GetInt(kPBAdvMeshOutlines); }
int plDecalMtl::GetTwoSided() { return fAdvPB->GetInt(kPBAdvTwoSided); }
int plDecalMtl::GetSoftShadow() { return fAdvPB->GetInt(kPBAdvSoftShadow); }
int plDecalMtl::GetNoProj() { return fAdvPB->GetInt(kPBAdvNoProj); }
int plDecalMtl::GetVertexShade() { return fAdvPB->GetInt(kPBAdvVertexShade); }
int plDecalMtl::GetNoShade() { return fAdvPB->GetInt(kPBAdvNoShade); }
int plDecalMtl::GetNoFog() { return fAdvPB->GetInt(kPBAdvNoFog); }
int plDecalMtl::GetWhite() { return fAdvPB->GetInt(kPBAdvWhite); }
int plDecalMtl::GetZOnly() { return fAdvPB->GetInt(kPBAdvZOnly); }
int plDecalMtl::GetZClear() { return fAdvPB->GetInt(kPBAdvZClear); }
int plDecalMtl::GetZNoRead() { return fAdvPB->GetInt(kPBAdvZNoRead); }
int plDecalMtl::GetZNoWrite() { return fAdvPB->GetInt(kPBAdvZNoWrite); }
int plDecalMtl::GetZInc() { return fAdvPB->GetInt(kPBAdvZInc); }
int plDecalMtl::GetAlphaTestHigh() { return fAdvPB->GetInt(kPBAdvAlphaTestHigh); }
// Animation block
char * plDecalMtl::GetAnimName() { return fAnimPB->GetStr(kPBAnimName); }
int plDecalMtl::GetAutoStart() { return fAnimPB->GetInt(kPBAnimAutoStart); }
int plDecalMtl::GetLoop() { return fAnimPB->GetInt(kPBAnimLoop); }
char * plDecalMtl::GetAnimLoopName() { return fAnimPB->GetStr(kPBAnimLoopName); }
int plDecalMtl::GetEaseInType() { return fAnimPB->GetInt(kPBAnimEaseInType); }
float plDecalMtl::GetEaseInNormLength() { return fAnimPB->GetFloat(kPBAnimEaseInLength); }
float plDecalMtl::GetEaseInMinLength() { return fAnimPB->GetFloat(kPBAnimEaseInMin); }
float plDecalMtl::GetEaseInMaxLength() { return fAnimPB->GetFloat(kPBAnimEaseInMax); }
int plDecalMtl::GetEaseOutType() { return fAnimPB->GetInt(kPBAnimEaseOutType); }
float plDecalMtl::GetEaseOutNormLength() { return fAnimPB->GetFloat(kPBAnimEaseOutLength); }
float plDecalMtl::GetEaseOutMinLength() { return fAnimPB->GetFloat(kPBAnimEaseOutMin); }
float plDecalMtl::GetEaseOutMaxLength() { return fAnimPB->GetFloat(kPBAnimEaseOutMax); }
int plDecalMtl::GetUseGlobal() { return fAnimPB->GetInt(ParamID(kPBAnimUseGlobal)); }
char * plDecalMtl::GetGlobalVarName() { return fAnimPB->GetStr(ParamID(kPBAnimGlobalName)); }
// Basic block
int plDecalMtl::GetColorLock() { return fBasicPB->GetInt(kDecalBasColorLock); }
Color plDecalMtl::GetAmbColor() { return fBasicPB->GetColor(kDecalBasColorAmb); }
Color plDecalMtl::GetColor() { return fBasicPB->GetColor(kDecalBasColor); }
int plDecalMtl::GetOpacity() { return fBasicPB->GetInt(kDecalBasOpacity); }
int plDecalMtl::GetEmissive() { return fBasicPB->GetInt(kDecalBasEmissive); }
int plDecalMtl::GetUseSpec() { return fBasicPB->GetInt(kDecalBasUseSpec); }
int plDecalMtl::GetShine() { return fBasicPB->GetInt(kDecalBasShine); }
Color plDecalMtl::GetSpecularColor() { return fBasicPB->GetColor(kDecalBasSpecColor); }
Control *plDecalMtl::GetPreshadeColorController() { return fBasicPB->GetController(ParamID(kDecalBasColor)); }
Control *plDecalMtl::GetAmbColorController() { return fBasicPB->GetController(ParamID(kDecalBasColorAmb)); }
Control *plDecalMtl::GetOpacityController() { return fBasicPB->GetController(ParamID(kDecalBasOpacity)); }
Control *plDecalMtl::GetSpecularColorController() { return fBasicPB->GetController(ParamID(kDecalBasSpecColor)); }
int plDecalMtl::GetDiffuseColorLock() { return fBasicPB->GetInt(kDecalBasDiffuseLock); }
Color plDecalMtl::GetRuntimeColor() { return fBasicPB->GetColor(kDecalBasRunColor); }
Control *plDecalMtl::GetRuntimeColorController() { return fBasicPB->GetController(ParamID(kDecalBasRunColor)); }
// Layer block
Texmap *plDecalMtl::GetBaseLayer() { return fLayersPB->GetTexmap(kDecalLayBase); }
int plDecalMtl::GetTopLayerOn() { return fLayersPB->GetInt(kDecalLayTopOn); }
Texmap *plDecalMtl::GetTopLayer() { return fLayersPB->GetTexmap(kDecalLayTop); }
int plDecalMtl::GetLayerBlend() { return fLayersPB->GetInt(kDecalLayBlend); }
int plDecalMtl::GetOutputAlpha() { return fLayersPB->GetInt(kDecalLayOutputAlpha); }
int plDecalMtl::GetOutputBlend() { return fLayersPB->GetInt(kDecalLayOutputBlend); }

View File

@ -0,0 +1,193 @@
/*==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/>.
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==*/
#ifndef PL_DECALMTL_H
#define PL_DECALMTL_H
#include "Max.h"
#include "iparamb2.h"
#include "../resource.h"
#include "plPassMtlBase.h"
#define DECAL_MTL_CLASS_ID Class_ID(0x691d2257, 0x419d629e)
extern TCHAR *GetString(int id);
class plDecalMtl : public plPassMtlBase
{
protected:
virtual void ICloneRefs( plPassMtlBase *target, RemapDir &remap );
public:
enum
{
kRefBasic,
kRefLayers,
kRefAdv,
kRefAnim,
};
enum Blocks
{
kBlkBasic,
kBlkLayers,
kBlkAdv,
kBlkAnim,
};
plDecalMtl(BOOL loading);
void DeleteThis() { delete this; }
//From Animatable
Class_ID ClassID() { return DECAL_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_DECAL_MTL); }
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void NotifyChanged();
BOOL SupportsMultiMapsInViewport() { return FALSE; }
void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);
// Shade and displacement calculation
void Shade(ShadeContext& sc);
void ShadeWithBackground(ShadeContext &sc, Color background);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
virtual RefTargetHandle GetReference( int i );
virtual void SetReference( int i, RefTargetHandle rtarg );
// SubTexmap access methods
int NumSubTexmaps();
Texmap* GetSubTexmap(int i);
void SetSubTexmap(int i, Texmap *m);
TSTR GetSubTexmapSlotName(int i);
TSTR GetSubTexmapTVName(int i);
int SubTexmapOn(int i);
BOOL SetDlgThing(ParamDlg* dlg);
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// void SetParamDlg(ParamDlg *dlg);
// void SetNumSubTexmaps(int num);
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
ULONG Requirements( int subMtlNum );
virtual bool HasAlpha();
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
virtual int GetBasicWire();
virtual int GetMeshOutlines();
virtual int GetTwoSided();
virtual int GetSoftShadow();
virtual int GetNoProj();
virtual int GetVertexShade();
virtual int GetNoShade();
virtual int GetNoFog();
virtual int GetWhite();
virtual int GetZOnly();
virtual int GetZClear();
virtual int GetZNoRead();
virtual int GetZNoWrite();
virtual int GetZInc();
virtual int GetAlphaTestHigh();
// Animation block
virtual char * GetAnimName();
virtual int GetAutoStart();
virtual int GetLoop();
virtual char * GetAnimLoopName();
virtual int GetEaseInType();
virtual float GetEaseInMinLength();
virtual float GetEaseInMaxLength();
virtual float GetEaseInNormLength();
virtual int GetEaseOutType();
virtual float GetEaseOutMinLength();
virtual float GetEaseOutMaxLength();
virtual float GetEaseOutNormLength();
virtual int GetUseGlobal();
virtual char * GetGlobalVarName();
// Basic block
virtual int GetColorLock();
virtual Color GetAmbColor();
virtual Color GetColor();
virtual int GetOpacity();
virtual int GetEmissive();
virtual int GetUseSpec();
virtual int GetShine();
virtual Color GetSpecularColor();
virtual Control *GetPreshadeColorController();
virtual Control *GetAmbColorController();
virtual Control *GetOpacityController();
virtual Control *GetSpecularColorController();
virtual int GetDiffuseColorLock();
virtual Color GetRuntimeColor();
virtual Control *GetRuntimeColorController();
// Layer block
virtual Texmap *GetBaseLayer();
virtual int GetTopLayerOn();
virtual Texmap *GetTopLayer();
virtual int GetLayerBlend();
virtual int GetOutputAlpha();
virtual int GetOutputBlend();
};
#endif //PL_DECALMTL_H

View File

@ -0,0 +1,67 @@
/*==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/>.
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==*/
#ifndef PL_DECALMTLADVPB_H
#define PL_DECALMTLADVPB_H
// Param ID's
enum
{
// Specular
kDecalAdvUseSpec, // Not used anymore, feel free to replace with new fields as necessary
kDecalAdvSpecType, // ditto
kDecalAdvShine, // ...
kDecalAdvShineStr, // ...
// Misc
kDecalAdvWire,
kDecalAdvMeshOutlines,
kDecalAdvTwoSided,
// Shading
kDecalAdvSoftShadow,
kDecalAdvNoProj,
kDecalAdvVertexShade,
kDecalAdvNoShade,
kDecalAdvNoFog,
kDecalAdvWhite,
// Z
kDecalAdvZOnly,
kDecalAdvZClear,
kDecalAdvZNoRead,
kDecalAdvZNoWrite,
kDecalAdvZInc,
};
// Specular types
enum
{
kSpecTypeAlpha,
kSpecTypeColor,
kSpecTypeHighlight
};
#endif //PL_DECALMTLADVPB_H

View File

@ -0,0 +1,95 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plDecalMtl.h"
#include "plPassBaseParamIDs.h"
using namespace plPassBaseParamIDs;
static ParamBlockDesc2 gDecalAdvPB
(
plDecalMtl::kBlkAdv, _T("advanced"), IDS_PASS_ADV, GetDecalMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI, plDecalMtl::kRefAdv,
// UI
IDD_PASS_ADV, IDS_PASS_ADV, 0, APPENDROLL_CLOSED, NULL,
// Misc Properties
kPBAdvWire, _T("basicWire"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_WIRE,
end,
kPBAdvMeshOutlines, _T("meshOutlines"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_MESHOUTLINES,
end,
kPBAdvTwoSided, _T("twoSided"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_TWOSIDED,
end,
// Shade properties
kPBAdvSoftShadow, _T("softShadow"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_SOFTSHADOW,
end,
kPBAdvNoProj, _T("noProj"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NO_PROJ,
end,
kPBAdvVertexShade, _T("vertexShade"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_VERTEXSHADE,
end,
kPBAdvNoShade, _T("noShade"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NOSHADE,
end,
kPBAdvNoFog, _T("noFog"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NO_FOG,
end,
kPBAdvWhite, _T("white"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_WHITE,
end,
// Z Properties
kPBAdvZOnly, _T("zOnly"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZONLY,
end,
kPBAdvZClear, _T("zClear"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZCLEAR,
end,
kPBAdvZNoRead, _T("zNoRead"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZNOREAD,
end,
kPBAdvZNoWrite, _T("zNoWrite"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZNOWRITE,
p_default, TRUE,
end,
kPBAdvZInc, _T("zInc"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_INC,
p_default, TRUE,
end,
kPBAdvAlphaTestHigh, _T("aTestHigh"), TYPE_BOOL, 0, 0,
p_default, FALSE,
end,
end
);
ParamBlockDesc2 *GetDecalAdvPB() { return &gDecalAdvPB; }

View File

@ -0,0 +1,47 @@
/*==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/>.
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==*/
#ifndef PL_DECALMTLANIMPB_H
#define PL_DECALMTLANIMPB_H
enum
{
kDecalAnimName,
kDecalAnimAutoStart,
kDecalAnimLoop,
kDecalAnimLoopName,
kDecalEaseInType, // Not used, but reserved
kDecalEaseOutType, //
kDecalEaseInLength, //
kDecalEaseOutLength, //
kDecalEaseInMin, //
kDecalEaseInMax, //
kDecalEaseOutMin, //
kDecalEaseOutMax, //
kDecalAnimUseGlobal, //
kDecalAnimGlobalName, //
};
#endif

View File

@ -0,0 +1,93 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plDecalMtl.h"
#include "plPassBaseParamIDs.h"
#include "resource.h"
#include "iparamm2.h"
#include "plPassAnimDlgProc.h"
#include "plAnimStealthNode.h"
using namespace plPassBaseParamIDs;
static ParamBlockDesc2 gDecalAnimPB
(
plDecalMtl::kBlkAnim, _T("anim"), IDS_PASS_ANIM, GetDecalMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI + P_CALLSETS_ON_LOAD, plDecalMtl::kRefAnim,
// UI
IDD_PASS_ANIM, IDS_PASS_ANIM, 0, 0, &plPassAnimDlgProc::Get(),
#ifdef MCN_UPGRADE_OLD_ANIM_BLOCKS
// THE FOLLOWING ARE ALL OLD PARAMETERS AND SHOULD NO LONGER BE USED. The only reason
// they're here is so we can convert old paramBlocks into the new plAnimStealthNode format
kPBAnimName, _T("animName"), TYPE_STRING, 0, 0,
end,
kPBAnimAutoStart, _T("autoStart"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoop, _T("loop"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoopName, _T("loopName"), TYPE_STRING, 0, 0,
end,
// Anim Ease
kPBAnimEaseInType, _T("easeInType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseInLength, _T("easeInLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMin, _T("easeInMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMax, _T("easeInMax"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutType, _T("easeOutType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseOutLength, _T("easeOutLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMin, _T("easeOutMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMax, _T("easeOutMax"), TYPE_FLOAT, 0, 0,
end,
#endif // MCN_UPGRADE_OLD_ANIM_BLOCKS
kPBAnimUseGlobal, _T("UseGlobal"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_MTL_USE_GLOBAL,
end,
kPBAnimGlobalName, _T("GlobalName"), TYPE_STRING, 0, 0,
p_default, _T(""),
end,
kPBAnimStealthNodes, _T( "testing" ), TYPE_REFTARG_TAB, 0, 0, 0,
p_accessor, &plStealthNodeAccessor::GetInstance(),
end,
end
);
ParamBlockDesc2 *GetDecalAnimPB() { return &gDecalAnimPB; }

View File

@ -0,0 +1,52 @@
/*==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/>.
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==*/
#ifndef PL_DECALMTLBASICPB_H
#define PL_DECALMTLBASICPB_H
// Param ID's
enum
{
kDecalBasColorLock,
kDecalBasColorAmb,
kDecalBasColor,
kDecalBasOpacity,
kDecalBasEmissive,
// Specular
kDecalBasUseSpec,
kDecalBasShine,
kDecalBasShineStr,
// New color stuff
kDecalBasDiffuseLock,
kDecalBasRunColor,
kDecalBasSpecColor
};
#endif //PL_DECALMTLBASICPB_H

View File

@ -0,0 +1,236 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plDecalMtl.h"
#include "plDecalMtlBasicPB.h"
#include "resource.h"
#include "iparamm2.h"
class DecalBasicPBAccessor;
extern DecalBasicPBAccessor basicAccessor;
class DecalBasicDlgProc;
extern DecalBasicDlgProc gDecalBasicDlgProc;
static ParamBlockDesc2 gDecalBasicPB
(
plDecalMtl::kBlkBasic, _T("basic"), IDS_PASS_BASIC, GetDecalMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI, plDecalMtl::kRefBasic,
// UI
IDD_PASS_BASIC, IDS_PASS_BASIC, 0, 0, &gDecalBasicDlgProc,
// Color
kDecalBasColorLock, _T("colorLock"), TYPE_BOOL, 0, 0,
p_ui, TYPE_CHECKBUTTON, IDC_LOCK_AD,
p_accessor, &basicAccessor,
end,
kDecalBasColorAmb, _T("ambColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_AMB,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_COLOR_AMB,
p_accessor, &basicAccessor,
end,
kDecalBasColor, _T("color"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_COLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_COLOR,
p_default, Color(1,1,1),
p_accessor, &basicAccessor,
end,
kDecalBasRunColor, _T("runtimeColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_RUNCOLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_RUNCOLOR,
p_default, Color(1,1,1),
p_accessor, &basicAccessor,
end,
kDecalBasDiffuseLock, _T("diffuseLock"), TYPE_BOOL, 0, 0,
p_ui, TYPE_CHECKBUTTON, IDC_LOCK_COLORS,
p_accessor, &basicAccessor,
p_default, TRUE,
end,
// Opacity
kDecalBasOpacity, _T("opacity"), TYPE_INT, P_ANIMATABLE, IDS_BASIC_OPAC,
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_TR_EDIT, IDC_TR_SPIN, 0.4,
p_range, 0, 100,
p_default, 100,
end,
kDecalBasEmissive, _T("emissive"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_LAYER_EMISSIVE_CB,
end,
// Specularity
kDecalBasUseSpec, _T("useSpec"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_SPECULAR,
p_enable_ctrls, 2, kDecalBasShine, kDecalBasShineStr,
end,
kDecalBasShine, _T("shine"), TYPE_INT, 0, 0,
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_SH_EDIT, IDC_SH_SPIN, 0.4,
p_range, 0, 100,
end,
kDecalBasSpecColor, _T("specularColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_SPECCOLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_SPECCOLOR,
p_default, Color(0,0,0),
end,
// OBSOLETE--here so we can upgrade it to color if necessary
kDecalBasShineStr, _T("shineStr"), TYPE_INT, 0, 0,
p_range, -1, 100,
p_default, -1,
end,
end
);
ParamBlockDesc2 *GetDecalBasicPB() { return &gDecalBasicPB; }
class DecalBasicPBAccessor : public PBAccessor
{
bool fColorLocked;
public:
DecalBasicPBAccessor() : fColorLocked( false ) {}
void Set(PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)
{
plDecalMtl* mtl = (plDecalMtl*)owner;
IParamBlock2 *pb = mtl->GetParamBlockByID(plDecalMtl::kBlkBasic);
switch (id)
{
case kDecalBasColorLock:
if (val.i)
pb->SetValue(kDecalBasColor, t, pb->GetColor(kDecalBasColorAmb, t));
break;
case kDecalBasDiffuseLock:
if (val.i)
pb->SetValue(kDecalBasRunColor, t, pb->GetColor(kDecalBasColor, t));
break;
case kDecalBasColor:
case kDecalBasColorAmb:
case kDecalBasRunColor:
ISyncLockedColors( id, pb, val, t );
break;
}
}
void Get(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid)
{
}
void ISyncLockedColors( ParamID settingID, IParamBlock2 *pb, PB2Value &val, TimeValue t )
{
int i, numToSet = 0;
ParamID toSet[ 2 ];
if( fColorLocked )
return;
fColorLocked = true;
if( settingID == kDecalBasColorAmb && pb->GetInt( kDecalBasColorLock, t ) )
{
toSet[ numToSet++ ] = kDecalBasColor;
if( pb->GetInt( kDecalBasDiffuseLock, t ) )
toSet[ numToSet++ ] = kDecalBasRunColor;
}
else if( settingID == kDecalBasRunColor && pb->GetInt( kDecalBasDiffuseLock, t ) )
{
toSet[ numToSet++ ] = kDecalBasColor;
if( pb->GetInt( kDecalBasColorLock, t ) )
toSet[ numToSet++ ] = kDecalBasColorAmb;
}
else if( settingID == kDecalBasColor )
{
if( pb->GetInt( kDecalBasColorLock, t ) )
toSet[ numToSet++ ] = kDecalBasColorAmb;
if( pb->GetInt( kDecalBasDiffuseLock, t ) )
toSet[ numToSet++ ] = kDecalBasRunColor;
}
for( i = 0; i < numToSet; i++ )
{
pb->SetValue( toSet[ i ], t, *val.p );
pb->GetMap()->Invalidate( toSet[ i ] );
}
fColorLocked = false;
}
};
static DecalBasicPBAccessor basicAccessor;
class DecalBasicDlgProc : public ParamMap2UserDlgProc
{
#if 1
protected:
HIMAGELIST hLockButtons;
void LoadLockButtons()
{
static bool loaded = false;
if (loaded)
return;
loaded = true;
HINSTANCE hInst = hInstance;
hLockButtons = ImageList_Create(16, 15, TRUE, 2, 0);
HBITMAP hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BUTTONS));
HBITMAP hMask = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_MASKBUTTONS));
ImageList_Add(hLockButtons, hBitmap, hMask);
DeleteObject(hBitmap);
DeleteObject(hMask);
}
void ISetLock(HWND hButton)
{
LoadLockButtons();
ICustButton *iBut = GetICustButton(hButton);
iBut->SetImage(hLockButtons,0,1,0,1,16,15);
iBut->SetType(CBT_CHECK);
ReleaseICustButton(iBut);
}
public:
DecalBasicDlgProc() : hLockButtons(NULL) {}
~DecalBasicDlgProc() { if (hLockButtons) ImageList_Destroy(hLockButtons); }
#endif
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
IParamBlock2 *pb = map->GetParamBlock();
switch (msg)
{
case WM_INITDIALOG:
{
ISetLock(GetDlgItem(hWnd, IDC_LOCK_AD));
ISetLock(GetDlgItem(hWnd, IDC_LOCK_COLORS));
}
return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
static DecalBasicDlgProc gDecalBasicDlgProc;

View File

@ -0,0 +1,40 @@
/*==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/>.
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==*/
#ifndef PL_DECALMTLLAYERSPB_H
#define PL_DECALMTLLAYERSPB_H
enum
{
// Layers
kDecalLayBase,
kDecalLayOutputBlend,
kDecalLayTopOn,
kDecalLayTop,
kDecalLayBlend,
kDecalLayOutputAlpha,
};
#endif //PL_DECALMTLLAYERSPB_H

View File

@ -0,0 +1,87 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plDecalMtl.h"
#include "plDecalMtlLayersPB.h"
#include "resource.h"
#include "iparamm2.h"
#include "Layers/plLayerTex.h"
class DecalMtlLayersAccessor;
extern DecalMtlLayersAccessor gLayersAccessor;
class LayersDlgProc;
extern LayersDlgProc gLayersDlgProc;
static ParamBlockDesc2 gDecalMtlLayersPB
(
plDecalMtl::kBlkLayers, _T("layers"), IDS_PASS_LAYERS, GetDecalMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI, plDecalMtl::kRefLayers,
// UI
IDD_PASS_LAYERS, IDS_PASS_LAYERS, 0, 0, NULL,
kDecalLayBase, _T("baseLayer"), TYPE_TEXMAP, 0, IDS_BASIC_AMB,
p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER1,
p_subtexno, 0,
end,
kDecalLayOutputBlend, _T("outputBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_OUTPUTB_NONE, IDC_OUTPUTB_ALPHA, IDC_OUTPUTB_ADD,
p_vals, plPassMtlBase::kBlendNone, plPassMtlBase::kBlendAlpha, plPassMtlBase::kBlendAdd,
p_default, plPassMtlBase::kBlendNone,
end,
kDecalLayTopOn, _T("topLayerOn"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_TOP_ON,
p_default, FALSE,
p_enable_ctrls, 3, kDecalLayTop, kDecalLayBlend, kDecalLayOutputAlpha,
end,
kDecalLayTop, _T("topLayer"), TYPE_TEXMAP, 0, 0,
p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER2,
p_subtexno, 1,
end,
kDecalLayBlend, _T("layerBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_LAYER_ALPHA, IDC_LAYER_ADD, IDC_LAYER_MULTIPLY,
p_vals, plPassMtlBase::kBlendAlpha, plPassMtlBase::kBlendAdd, plPassMtlBase::kBlendMult,
p_default, plPassMtlBase::kBlendAdd,
end,
kDecalLayOutputAlpha, _T("ouputAlpha"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_OUTPUTA_DISCARD, IDC_OUTPUTA_ADD, IDC_OUTPUTA_MULT,
p_vals, plPassMtlBase::kAlphaDiscard, plPassMtlBase::kAlphaAdd, plPassMtlBase::kAlphaMultiply,
p_default, plPassMtlBase::kAlphaDiscard,
end,
end
);
ParamBlockDesc2 *GetDecalLayersPB() { return &gDecalMtlLayersPB; }

View File

@ -0,0 +1,370 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plMultipassMtl.h"
#include "plPassMtl.h"
#include "plMultipassMtlPB.h"
#include "plMultipassMtlDlg.h"
class plMultipassClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plMultipassMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_MULTI_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return MULTIMTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaMultipass"); }
HINSTANCE HInstance() { return hInstance; }
};
static plMultipassClassDesc plMultipassMtlDesc;
ClassDesc2* GetMultiMtlDesc() { return &plMultipassMtlDesc; }
#include "plMultipassMtlPB.cpp"
plMultipassMtl::plMultipassMtl(BOOL loading) : fPassesPB(NULL)
{
plMultipassMtlDesc.MakeAutoParamBlocks(this);
if (!loading)
Reset();
SetNumSubMtls(1);
}
void plMultipassMtl::Reset()
{
fIValid.SetEmpty();
}
ParamDlg* plMultipassMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fMtlDlg = TRACKED_NEW plMultipassMtlDlg(hwMtlEdit, imp, this);
return fMtlDlg;
}
void plMultipassMtl::SetParamDlg(ParamDlg *dlg)
{
fMtlDlg = (plMultipassMtlDlg*)dlg;
}
BOOL plMultipassMtl::SetDlgThing(ParamDlg* dlg)
{
if (dlg == fMtlDlg)
{
fMtlDlg->SetThing(this);
return TRUE;
}
return FALSE;
}
Interval plMultipassMtl::Validity(TimeValue t)
{
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plMultipassMtl::NumSubs()
{
return NumSubMtls();
}
TSTR plMultipassMtl::SubAnimName(int i)
{
return GetSubMtlSlotName(i);
}
Animatable* plMultipassMtl::SubAnim(int i)
{
return GetSubMtl(i);
}
int plMultipassMtl::NumRefs()
{
return 1;
}
RefTargetHandle plMultipassMtl::GetReference(int i)
{
if (i == kRefPasses)
return fPassesPB;
return NULL;
}
void plMultipassMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefPasses)
fPassesPB = (IParamBlock2 *)rtarg;
}
int plMultipassMtl::NumParamBlocks()
{
return 1;
}
IParamBlock2 *plMultipassMtl::GetParamBlock(int i)
{
if (i == kRefPasses)
return fPassesPB;
return NULL;
}
IParamBlock2 *plMultipassMtl::GetParamBlockByID(BlockID id)
{
if (fPassesPB->ID() == id)
return fPassesPB;
return NULL;
}
RefResult plMultipassMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message )
{
switch (message)
{
case REFMSG_CHANGE:
fIValid.SetEmpty();
if (hTarget == fPassesPB)
{
ParamID changingParam = fPassesPB->LastNotifyParamID();
fPassesPB->GetDesc()->InvalidateUI(changingParam);
}
break;
}
return REF_SUCCEED;
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plMultipassMtl::NumSubMtls()
{
return fPassesPB->GetInt(kMultCount);
}
Mtl *plMultipassMtl::GetSubMtl(int i)
{
if (i < NumSubMtls())
return fPassesPB->GetMtl(kMultPasses, 0, i);
return NULL;
}
void plMultipassMtl::SetSubMtl(int i, Mtl *m)
{
if (i < NumSubMtls())
fPassesPB->SetValue(kMultPasses, 0, m, i);
}
TSTR plMultipassMtl::GetSubMtlSlotName(int i)
{
TSTR str;
str.printf("Pass %d", i+1);
return str;
}
TSTR plMultipassMtl::GetSubMtlTVName(int i)
{
return GetSubMtlSlotName(i);
}
/*===========================================================================*\
| Standard IO
\*===========================================================================*/
#define MTL_HDR_CHUNK 0x4000
IOResult plMultipassMtl::Save(ISave *isave)
{
IOResult res;
isave->BeginChunk(MTL_HDR_CHUNK);
res = MtlBase::Save(isave);
if (res!=IO_OK) return res;
isave->EndChunk();
return IO_OK;
}
IOResult plMultipassMtl::Load(ILoad *iload)
{
IOResult res;
int id;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(id = iload->CurChunkID())
{
case MTL_HDR_CHUNK:
res = MtlBase::Load(iload);
break;
}
iload->CloseChunk();
if (res!=IO_OK)
return res;
}
return IO_OK;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plMultipassMtl::Clone(RemapDir &remap)
{
plMultipassMtl *mnew = TRACKED_NEW plMultipassMtl(FALSE);
*((MtlBase*)mnew) = *((MtlBase*)this);
mnew->ReplaceReference(kRefPasses, remap.CloneRef(fPassesPB));
mnew->fIValid.SetEmpty();
BaseClone(this, mnew, remap);
return (RefTargetHandle)mnew;
}
void plMultipassMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plMultipassMtl::Update(TimeValue t, Interval& valid)
{
if (!fIValid.InInterval(t))
{
fIValid.SetInfinite();
// fPassesPB->GetValue(kMtlLayLayer1On, t, fMapOn[0], fIValid);
for (int i = 0; i < NumSubMtls(); i++)
{
if (GetSubMtl(i))
GetSubMtl(i)->Update(t, fIValid);
}
}
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plMultipassMtl::SetAmbient(Color c, TimeValue t) {}
void plMultipassMtl::SetDiffuse(Color c, TimeValue t) {}
void plMultipassMtl::SetSpecular(Color c, TimeValue t) {}
void plMultipassMtl::SetShininess(float v, TimeValue t) {}
Color plMultipassMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plMultipassMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plMultipassMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plMultipassMtl::GetXParency(int mtlNum, BOOL backFace) { return 0.0f; }
float plMultipassMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plMultipassMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plMultipassMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plMultipassMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
backColor.Black();
backTrans.White();
int count = NumSubMtls();
for (int i = 0; i < count; i++)
{
if (fPassesPB->GetInt(kMultOn, 0, i) == 0)
continue;
// Call each pass' shade function with the previous color
Mtl *mtl = GetSubMtl(i);
//backTrans = Color(0,0,0);
if (mtl->ClassID() == PASS_MTL_CLASS_ID)
{
plPassMtl *passMtl = (plPassMtl*)mtl;
passMtl->ShadeWithBackground(sc, backColor);
backTrans *= sc.out.t;
backColor = backColor * sc.out.t + sc.out.c;
}
}
sc.out.t = backTrans;
sc.out.c = backColor;
}
float plMultipassMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plMultipassMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
void plMultipassMtl::SetNumSubMtls(int num)
{
TimeValue t = GetCOREInterface()->GetTime();
int curNum = fPassesPB->GetInt(kMultCount);
fPassesPB->SetValue(kMultCount, 0, num);
fPassesPB->SetCount(kMultPasses, num);
fPassesPB->SetCount(kMultOn, num);
fPassesPB->SetCount(kMultLayerCounts, num);
for (int i = curNum; i < num; i++)
{
plPassMtl *newMtl = TRACKED_NEW plPassMtl(false);
fPassesPB->SetValue(kMultPasses, t, newMtl, i);
fPassesPB->SetValue(kMultOn, t, TRUE, i);
GetCOREInterface()->AssignNewName(fPassesPB->GetMtl(kMultPasses, t, i));
}
}

View File

@ -0,0 +1,120 @@
/*==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/>.
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==*/
#ifndef __PLMAXMTL__H
#define __PLMAXMTL__H
#include "Max.h"
#include "../resource.h"
#include "istdplug.h"
#include "iparamb2.h"
#include "iparamm2.h"
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;
#define MULTIMTL_CLASS_ID Class_ID(0x3f687a, 0x28c62bd7)
class plMultipassMtlDlg;
class plMultipassMtl : public Mtl
{
protected:
IParamBlock2 *fPassesPB;
Interval fIValid;
plMultipassMtlDlg *fMtlDlg;
public:
enum { kRefPasses };
enum { kBlkPasses };
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void Reset();
void NotifyChanged();
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
// Shade and displacement calculation
void Shade(ShadeContext& sc);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
// SubTexmap access methods
int NumSubMtls();
Mtl* GetSubMtl(int i);
void SetSubMtl(int i, Mtl *m);
TSTR GetSubMtlSlotName(int i);
TSTR GetSubMtlTVName(int i);
BOOL SetDlgThing(ParamDlg* dlg);
plMultipassMtl(BOOL loading);
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
//From Animatable
Class_ID ClassID() { return MULTIMTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_MULTI_MTL); }
RefTargetHandle Clone(RemapDir &remap);
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
void DeleteThis() { delete this; }
void SetParamDlg(ParamDlg *dlg);
void SetNumSubMtls(int num);
};
#endif // __PLMAXMTL__H

View File

@ -0,0 +1,326 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "max.h"
#include "MaxIcon.h"
#include "resource.h"
#include "plMultipassMtl.h"
#include "plMultipassMtlPB.h"
//#include "plMaxLayer.h"
#include "plMultipassMtlDlg.h"
struct LayerID
{
int layerID;
int activeID;
};
static LayerID kLayerID[] =
{
{ IDC_TEX1, IDC_TEXON1 },
{ IDC_TEX2, IDC_TEXON2 },
{ IDC_TEX3, IDC_TEXON3 },
{ IDC_TEX4, IDC_TEXON4 },
{ IDC_TEX5, IDC_TEXON5 },
{ IDC_TEX6, IDC_TEXON6 },
{ IDC_TEX7, IDC_TEXON7 },
{ IDC_TEX8, IDC_TEXON8 },
{ IDC_TEX9, IDC_TEXON9 },
{ IDC_TEX10, IDC_TEXON10 },
};
//-----------------------------------------------------------------------------
// Constructor and destructor
//-----------------------------------------------------------------------------
plMultipassMtlDlg::plMultipassMtlDlg(HWND hwMtlEdit, IMtlParams *imp, plMultipassMtl *m)
{
fDADMgr.Init(this);
fhMtlEdit = hwMtlEdit;
fhRollup = NULL;
fMtl = m;
fPBlock = fMtl->GetParamBlockByID(plMultipassMtl::kBlkPasses);
ip = imp;
valid = FALSE;
for (int i = 0; i < NSUBMTLS; i++)
fLayerBtns[i] = NULL;
curTime = imp->GetTime();
fhRollup = ip->AddRollupPage(
hInstance,
MAKEINTRESOURCE(IDD_MULTIPASS),
ForwardProc,
"Multipass Parameters",
(LPARAM)this);
}
plMultipassMtlDlg::~plMultipassMtlDlg()
{
fMtl->SetParamDlg(NULL);
for (int i = 0; i < NSUBMTLS; i++)
{
ReleaseICustButton(fLayerBtns[i]);
fLayerBtns[i] = NULL;
}
SetWindowLong(fhRollup, GWL_USERDATA, NULL);
ip->DeleteRollupPage(fhRollup);
fhRollup = NULL;
}
//-----------------------------------------------------------------------------
// Functions inheirited from ParamDlg
//-----------------------------------------------------------------------------
void plMultipassMtlDlg::SetThing(ReferenceTarget *m)
{
assert(m->SuperClassID() == MATERIAL_CLASS_ID);
assert(m->ClassID() == MULTIMTL_CLASS_ID);
// Bad?
if (fMtl)
fMtl->SetParamDlg(NULL);
fMtl = (plMultipassMtl *)m;
if (fMtl)
fMtl->SetParamDlg(this);
LoadDialog();
IUpdateMtlDisplay();
}
void plMultipassMtlDlg::SetTime(TimeValue t)
{
if (t != curTime)
{
curTime = t;
Interval v;
fMtl->Update(ip->GetTime(),v);
LoadDialog();
IUpdateMtlDisplay();
}
}
void plMultipassMtlDlg::ReloadDialog()
{
Interval v;
fMtl->Update(ip->GetTime(), v);
LoadDialog();
}
void plMultipassMtlDlg::ActivateDlg(BOOL onOff)
{
}
int plMultipassMtlDlg::FindSubMtlFromHWND(HWND hwnd)
{
for (int i = 0; i < NSUBMTLS; i++)
{
if (hwnd == fLayerBtns[i]->GetHwnd())
return i;
}
return -1;
}
BOOL plMultipassMtlDlg::ForwardProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
plMultipassMtlDlg *theDlg;
if (msg == WM_INITDIALOG)
{
theDlg = (plMultipassMtlDlg*)lParam;
theDlg->fhRollup = hDlg;
SetWindowLong(hDlg, GWL_USERDATA, lParam);
}
else
{
if ((theDlg = (plMultipassMtlDlg *)GetWindowLong(hDlg, GWL_USERDATA)) == NULL)
return FALSE;
}
return theDlg->LayerPanelProc(hDlg,msg,wParam,lParam);
}
//----------------------------------------------------------------------------
// Layer panel processor
//----------------------------------------------------------------------------
BOOL plMultipassMtlDlg::LayerPanelProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
int id = LOWORD(wParam);
int code = HIWORD(wParam);
int i;
switch (msg)
{
case WM_INITDIALOG:
{
int nLayers = fPBlock->GetInt(kMultCount);
for (i = 0; i < NSUBMTLS; i++)
{
fLayerBtns[i] = GetICustButton(GetDlgItem(hDlg, kLayerID[i].layerID));
fLayerBtns[i]->SetDADMgr(&fDADMgr);
/* if (i < nLayers)
{
SetCheckBox(hDlg, kLayerID[i].activeID, fPBlock->GetInt(kMtlLayerOn, curTime, i));
}
*/
fNumTexSpin = SetupIntSpinner(hDlg, IDC_LAYER_SPIN, IDC_LAYER_EDIT, 1, 10, nLayers);
}
// TEMP testing
UpdateLayerDisplay();
IUpdateMtlDisplay();
}
return TRUE;
case WM_DESTROY:
for (i = 0; i < NSUBMTLS; i++)
{
ReleaseICustButton(fLayerBtns[i]);
fLayerBtns[i] = NULL;
}
ReleaseISpinner(fNumTexSpin);
fNumTexSpin = NULL;
break;
case CC_SPINNER_CHANGE:
if (id == IDC_LAYER_SPIN && !code)
{
IGetSpinnerVal();
return TRUE;
}
break;
case CC_SPINNER_BUTTONUP:
if (id == IDC_LAYER_SPIN && code)
{
IGetSpinnerVal();
return TRUE;
}
break;
case WM_COMMAND:
{
for (i = 0; i < NSUBMTLS; i++)
{
if (id == kLayerID[i].activeID)
{
// fMtl->EnableMap(i,GetCheckBox(hwndDlg, id));
bool checked = SendMessage(GetDlgItem(hDlg, id), BM_GETCHECK, 0, 0) == BST_CHECKED;
fPBlock->SetValue(kMultOn, curTime, checked, i);
return TRUE;
}
if (id == kLayerID[i].layerID)
{
PostMessage(fhMtlEdit, WM_SUB_MTL_BUTTON, i, (LPARAM)fMtl);
return TRUE;
}
}
}
// IUpdateMtlDisplay();
break;
}
return FALSE;
}
void plMultipassMtlDlg::UpdateLayerDisplay()
{
int numlayers = fPBlock->GetInt(kMultCount);
fNumTexSpin->SetValue(numlayers, FALSE);
int i;
for (i = 0; i < numlayers && i < NSUBMTLS; i++)
{
Mtl *m = fPBlock->GetMtl(kMultPasses, curTime, i);
TSTR nm;
if (m)
nm = m->GetName();
else
nm = "None";
fLayerBtns[i]->SetText(nm.data());
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].layerID), SW_SHOW);
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].activeID), SW_SHOW);
SetCheckBox(fhRollup, kLayerID[i].activeID, fPBlock->GetInt(kMultOn, curTime, i));
}
for (i = numlayers; i < NSUBMTLS; i++)
{
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].layerID), SW_HIDE);
ShowWindow(GetDlgItem(fhRollup, kLayerID[i].activeID), SW_HIDE);
}
}
void plMultipassMtlDlg::LoadDialog()
{
if (fMtl)
{
fPBlock = fMtl->GetParamBlockByID(plMultipassMtl::kBlkPasses);
if (fhRollup)
UpdateLayerDisplay();
}
}
bool plMultipassMtlDlg::ISetNumLayers(int num)
{
if (num >= 1 && num <= NSUBMTLS)
{
fMtl->SetNumSubMtls(num);
UpdateLayerDisplay();
// IUpdateMtlDisplay();
return true;
}
return false;
}
void plMultipassMtlDlg::IGetSpinnerVal()
{
ISpinnerControl *spin = GetISpinner(GetDlgItem(fhRollup, IDC_LAYER_SPIN));
if (!spin)
return;
// If new number of layers is invalid, set to current num
if (!ISetNumLayers(spin->GetIVal()))
{
int nLayers = fPBlock->GetInt(kMultCount);
spin->SetValue(nLayers, FALSE);
}
ReleaseISpinner(spin);
}

View File

@ -0,0 +1,89 @@
/*==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/>.
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==*/
#ifndef PL_MAXMTLDLG_H
#define PL_MAXMTLDLG_H
#define NSUBMTLS 10
class plMultipassMtlDlg : public ParamDlg
{
protected:
IParamBlock2 *fPBlock;
HWND fhMtlEdit; // Window handle of the materials editor dialog
HWND fhRollup; // Our rollup panel
IMtlParams *ip;
plMultipassMtl *fMtl; // current mtl being edited.
TimeValue curTime;
int isActive;
BOOL valid;
// int offset;
ISpinnerControl *fNumTexSpin;
ICustButton *fLayerBtns[NSUBMTLS];
MtlDADMgr fDADMgr; // For drag-drop sub-materials
public:
// Constructor and destructor
plMultipassMtlDlg(HWND hwMtlEdit, IMtlParams *imp, plMultipassMtl *m);
~plMultipassMtlDlg();
// Functions inherited from ParamDLg:
Class_ID ClassID() { return MULTIMTL_CLASS_ID; }
void SetThing(ReferenceTarget *m);
ReferenceTarget* GetThing() { return (ReferenceTarget*)fMtl; }
void SetTime(TimeValue t);
void ReloadDialog();
void ActivateDlg(BOOL onOff);
void DeleteThis() { delete this; }
int FindSubMtlFromHWND(HWND hw);
static BOOL CALLBACK ForwardProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL LayerPanelProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
void UpdateLayerDisplay();
void LoadDialog();
/*
// Lower-level crap
void Invalidate(); // Called by ParamMtl
BOOL IsActive() { return isActive; }
private:
void ClampOffset();
void SetNumMats();
void UpdateLayers();
void UpdateControlFor(int np);
void VScroll(int code, short int cpos );
*/
protected:
void IUpdateMtlDisplay() { if (ip) ip->MtlChanged(); }
bool ISetNumLayers(int num);
void IGetSpinnerVal();
};
#endif

View File

@ -0,0 +1,50 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plMultipassMtl.h"
#include "plMultipassMtlPB.h"
ClassDesc2* GetMultiMtlDesc();
static ParamBlockDesc2 gMultipassMtlPB
(
plMultipassMtl::kBlkPasses, _T("multipass"), 0, GetMultiMtlDesc(),
P_AUTO_CONSTRUCT, plMultipassMtl::kRefPasses,
kMultCount, _T("numPasses"), TYPE_INT, 0, 0,
p_default, 0,
end,
kMultPasses, _T("passes"), TYPE_MTL_TAB, 0, 0, 0,
end,
kMultOn, _T("passOn"), TYPE_BOOL_TAB, 0, 0, 0,
p_default, TRUE,
end,
kMultLayerCounts, _T("LayerCounts"), TYPE_INT_TAB, 0, 0, 0,
p_default, 0,
end,
end
);

View File

@ -0,0 +1,37 @@
/*==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/>.
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==*/
#ifndef PL_MULTIPASS_MTL_PB_H
#define PL_MULTIPASS_MTL_PB_H
enum
{
kMultCount,
kMultPasses,
kMultOn,
kMultLayerCounts
};
#endif //PL_MULTIPASS_MTL_PB_H

View File

@ -0,0 +1,127 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plNoteTrackWatcher - Dummy object to watch for notetrack additions or //
// removals from the main material that owns it. //
// All of this is required because MAX will notify //
// an object's dependents about notetrack actions but //
// NOT the object itself, and the Add/DeleteNoteTrack //
// functions are non-virtual. ARRRGH! //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plNoteTrackWatcher.h"
#include "plPassMtlBase.h"
#include "iparamm2.h"
#include "resource.h"
//// Watcher Class Desc //////////////////////////////////////////////////////
plNoteTrackWatcher::plNoteTrackWatcher( plPassMtlBase *parentMtl ) : fParentMtl(nil)
{
fNoteTrackCount = parentMtl->NumNoteTracks();
MakeRefByID( FOREVER, kRefParentMtl, parentMtl );
}
plNoteTrackWatcher::~plNoteTrackWatcher()
{
if( fParentMtl != nil )
{
fParentMtl->fNTWatcher = nil;
DeleteReference( kRefParentMtl );
}
DeleteAllRefsFromMe();
}
BOOL plNoteTrackWatcher::IsRealDependency( ReferenceTarget *rtarg )
{
if( rtarg == fParentMtl )
return false;
return true;
}
int plNoteTrackWatcher::NumRefs()
{
return 1;
}
RefTargetHandle plNoteTrackWatcher::GetReference( int i )
{
if( i == kRefParentMtl )
return fParentMtl;
return nil;
}
void plNoteTrackWatcher::SetReference( int i, RefTargetHandle rtarg )
{
if( i == kRefParentMtl )
fParentMtl = (plPassMtlBase *)rtarg;
}
RefResult plNoteTrackWatcher::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
switch( message )
{
case REFMSG_SUBANIM_STRUCTURE_CHANGED:
if( hTarget == fParentMtl && fParentMtl != nil )
{
// Structure of parent material changed--did it gain or lose a notetrack?
int oldCount = fNoteTrackCount;
fNoteTrackCount = fParentMtl->NumNoteTracks();
if( oldCount != fNoteTrackCount )
{
// Is it an addition?
if( fNoteTrackCount > oldCount )
// Yes, notify parent.
fParentMtl->NoteTrackAdded();
else
// Deletion, also notify parent
fParentMtl->NoteTrackRemoved();
}
}
break;
case REFMSG_NODE_NAMECHANGE:
if( hTarget == fParentMtl )
{
fParentMtl->NameChanged();
}
break;
case REFMSG_TARGET_DELETED:
fParentMtl = nil;
break;
}
return REF_SUCCEED;
}

View File

@ -0,0 +1,88 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plNoteTrackWatcher - Dummy object to watch for notetrack additions or //
// removals from the main material that owns it. //
// All of this is required because MAX will notify //
// an object's dependents about notetrack actions but //
// NOT the object itself, and the Add/DeleteNoteTrack //
// functions are non-virtual. ARRRGH! //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plNoteTrackWatcher_h
#define _plNoteTrackWatcher_h
#include "Max.h"
#include "iparamb2.h"
#include "iparamm2.h"
#include "hsTypes.h"
extern TCHAR *GetString(int id);
extern HINSTANCE hInstance;
#define NTWATCHER_CLASSID Class_ID(0x313f531e, 0xa5f132f)
#define REFMSG_NOTETRACK_ADDED REFMSG_USER + 1
class plPassMtlBase;
class NoteTrack;
//// Class Def ///////////////////////////////////////////////////////////////
class plNoteTrackWatcher : public ReferenceMaker
{
protected:
plPassMtlBase *fParentMtl;
// For tracking notetrack additions to the parent
int fNoteTrackCount;
public:
enum Refs
{
kRefParentMtl = 0
};
plNoteTrackWatcher( plPassMtlBase *parentMtl );
virtual ~plNoteTrackWatcher();
void DeleteThis() { delete this; }
Class_ID ClassID() { return NTWATCHER_CLASSID; }
SClass_ID SuperClassID() { return REF_MAKER_CLASS_ID; }
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
RefResult NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget, PartID& partID, RefMessage message);
virtual BOOL IsRealDependency( ReferenceTarget *rtarg );
};
#endif //_plNoteTrackWatcher_h

View File

@ -0,0 +1,620 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plParticleMtl.h"
#include "resource.h"
//extern ClassDesc2* GetMaxLayerDesc();
#include "Shaders.h"
#include "iparamm2.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
#include "plBMSampler.h"
#include "stdmat.h"
#include "Layers/plLayerTex.h"
#include "Layers/plLayerTexBitmapPB.h"
extern HINSTANCE hInstance;
class plParticleMtlClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plParticleMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_PARTICLE_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return PARTICLE_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("ParticleMaterial"); }
HINSTANCE HInstance() { return hInstance; }
};
static plParticleMtlClassDesc plParticleMtlDesc;
ClassDesc2* GetParticleMtlDesc() { return &plParticleMtlDesc; }
// For initializing paramblock descriptor
ParamBlockDesc2 *GetParticlePB();
#include "plParticleMtlPBDec.h"
const char *plParticleMtl::NormalStrings[] = // Make sure these match up in order with the Normal enum (in the header)
{
"Normal: View Facing",
"Normal: Up",
"Normal: Nearest Light",
"Normal: From Center",
"Normal: Vel x Up x Vel",
"Emissive"
};
plParticleMtl::plParticleMtl(BOOL loading) : fBasicPB(NULL)//, fBM(NULL), fUVGen(NULL)
{
#if 0 // This wasn't working on load
// Initialize the paramblock descriptors only once
static bool descInit = false;
if (!descInit)
{
descInit = true;
GetParticlePB()->SetClassDesc(GetParticleMtlDesc());
}
#endif
plParticleMtlDesc.MakeAutoParamBlocks(this);
// if (!loading)
{
Reset();
plLayerTex *tex = TRACKED_NEW plLayerTex;
//tex->GetParamBlockByID(kBlkBasic)->SetValue(kBmpUseBitmap, 0, 1);
fBasicPB->SetValue(kTexmap, 0, tex);
}
//fUVGen = GetNewDefaultUVGen();
}
void plParticleMtl::Reset()
{
fIValid.SetEmpty();
}
ParamDlg* plParticleMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fIMtlParams = imp;
IAutoMParamDlg* masterDlg = plParticleMtlDesc.CreateParamDlgs(hwMtlEdit, imp, this);
return (ParamDlg*)masterDlg;
}
BOOL plParticleMtl::SetDlgThing(ParamDlg* dlg)
{
return FALSE;
}
Interval plParticleMtl::Validity(TimeValue t)
{
#if 0 // mf horse
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
#else // mf horse
const char* name = GetName();
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
Interval v = FOREVER;
fBasicPB->GetValidity(t, v);
return v;
#endif // mf horse
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plParticleMtl::NumSubs()
{
return 2;
}
TSTR plParticleMtl::SubAnimName(int i)
{
switch (i)
{
case 0: return fBasicPB->GetLocalName();
case 1: return "Texmap";
}
return "";
}
Animatable* plParticleMtl::SubAnim(int i)
{
switch (i)
{
case 0: return fBasicPB;
case 1: return fBasicPB->GetTexmap(kTexmap);
}
return NULL;
}
int plParticleMtl::NumRefs()
{
return 1;
}
RefTargetHandle plParticleMtl::GetReference(int i)
{
switch (i)
{
case kRefBasic: return fBasicPB;
}
return NULL;
}
void plParticleMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefBasic)
fBasicPB = (IParamBlock2 *)rtarg;
}
int plParticleMtl::NumParamBlocks()
{
return 1;
}
IParamBlock2* plParticleMtl::GetParamBlock(int i)
{
return (IParamBlock2*)GetReference(i);
}
IParamBlock2* plParticleMtl::GetParamBlockByID(BlockID id)
{
if (fBasicPB->ID() == id)
return fBasicPB;
return NULL;
}
RefResult plParticleMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
switch (message)
{
case REFMSG_CHANGE:
fIValid.SetEmpty();
// see if this message came from a changing parameter in the pblock,
// if so, limit rollout update to the changing item
if (hTarget == fBasicPB)
{
IParamBlock2 *pb = (IParamBlock2*)hTarget;
ParamID changingParam = pb->LastNotifyParamID();
pb->GetDesc()->InvalidateUI(changingParam);
// And let the SceneWatcher know that the material on some of it's
// referenced objects changed.
NotifyDependents(FOREVER, PART_ALL, REFMSG_USER_MAT);
}
break;
}
return REF_SUCCEED;
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plParticleMtl::NumSubTexmaps()
{
return 1;
}
Texmap* plParticleMtl::GetSubTexmap(int i)
{
if (i == 0)
return fBasicPB->GetTexmap(kTexmap);
return NULL;
}
void plParticleMtl::SetSubTexmap(int i, Texmap *m)
{
if (i == 0)
fBasicPB->SetValue(kTexmap, 0, m);
}
TSTR plParticleMtl::GetSubTexmapSlotName(int i)
{
if (i == 0)
return "Texmap";
return "";
}
TSTR plParticleMtl::GetSubTexmapTVName(int i)
{
return GetSubTexmapSlotName(i);
}
/*===========================================================================*\
| Standard IO
\*===========================================================================*/
#define MTL_HDR_CHUNK 0x4000
IOResult plParticleMtl::Save(ISave *isave)
{
IOResult res;
isave->BeginChunk(MTL_HDR_CHUNK);
res = MtlBase::Save(isave);
if (res!=IO_OK) return res;
isave->EndChunk();
return IO_OK;
}
IOResult plParticleMtl::Load(ILoad *iload)
{
IOResult res;
int id;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(id = iload->CurChunkID())
{
case MTL_HDR_CHUNK:
res = MtlBase::Load(iload);
break;
}
iload->CloseChunk();
if (res!=IO_OK)
return res;
}
return IO_OK;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plParticleMtl::Clone(RemapDir &remap)
{
plParticleMtl *mnew = TRACKED_NEW plParticleMtl(FALSE);
*((MtlBase*)mnew) = *((MtlBase*)this);
mnew->ReplaceReference(kRefBasic, remap.CloneRef(fBasicPB));
BaseClone(this, mnew, remap);
mnew->fIValid.SetEmpty();
return (RefTargetHandle)mnew;
}
void plParticleMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plParticleMtl::Update(TimeValue t, Interval& valid)
{
//StdUVGen *gen = (StdUVGen *)fUVGen;
//gen->SetUScl(1.0f, t);
//gen->SetVScl(1.0f, t);
//gen->Update(t, fIValid);
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plParticleMtl::SetAmbient(Color c, TimeValue t) {}
void plParticleMtl::SetDiffuse(Color c, TimeValue t) {}
void plParticleMtl::SetSpecular(Color c, TimeValue t) {}
void plParticleMtl::SetShininess(float v, TimeValue t) {}
Color plParticleMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plParticleMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plParticleMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plParticleMtl::GetXParency(int mtlNum, BOOL backFace)
{
int opacity = fBasicPB->GetInt( kOpacity, 0 );
float alpha = 1.0f - ( (float)opacity / 100.0f );
return alpha;
}
float plParticleMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plParticleMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plParticleMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/////////////////////////////////////////////////////////////////
void plParticleMtl::SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb)
{
#if 0
if (texHandleValid.InInterval(t)) {
mtl->texture.SetCount(numTexHandlesUsed);
for (int i=0; i<numTexHandlesUsed; i++) {
if (texHandle[i]) {
mtl->texture[i].textHandle = texHandle[i]->GetHandle();
Texmap *tx = (*maps)[useSubForTex[i]].map;
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[i], tx );
SetTexOps(mtl,i,texOpsType[i]);
}
}
return;
}
#endif
#if 0 // WTF?!?!?!?
Texmap *tx[2];
int diffChan = stdIDToChannel[ ID_DI ];
int opacChan = stdIDToChannel[ ID_OP ];
tx[0] = (*maps)[diffChan].IsActive()?(*maps)[diffChan].map:NULL;
tx[1] = (*maps)[opacChan].IsActive()?(*maps)[opacChan].map:NULL;
#endif
int nsupport = cb.NumberTexturesSupported();
#if 0
BITMAPINFO *bmi[NTEXHANDLES];
int nmaps=0;
for (int i=0; i<NTEXHANDLES; i++) {
if (tx[i]) nmaps ++;
bmi[i] = NULL;
}
mtl->texture.SetCount(nmaps);
if (nmaps==0)
return;
for (i=0; i<nmaps; i++)
mtl->texture[i].textHandle = NULL;
texHandleValid.SetInfinite();
Interval valid;
BOOL needDecal = FALSE;
int ntx = 0;
int op;
int forceW = 0;
int forceH = 0;
if (tx[0]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[0], tx[0]);
TextureInfo &ti = mtl->texture[0];
if (ti.tiling[0]==GW_TEX_NO_TILING||ti.tiling[1]==GW_TEX_NO_TILING)
needDecal = TRUE;
op = needDecal?TXOP_ALPHABLEND:TXOP_MODULATE;
bmi[0] = tx[0]->GetVPDisplayDIB(t,cb,valid,FALSE);
if (bmi[0]) {
texHandleValid &= valid;
useSubForTex[0] = diffChan;
ntx = 1;
forceW = bmi[0]->bmiHeader.biWidth;
forceH = bmi[0]->bmiHeader.biHeight;
}
}
if (tx[1]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[ntx], tx[1]);
if (nsupport>ntx) {
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlpha(bmi[1], (*maps)[opacChan].amount, GetOpacity(t),ntx?whiteCol:pShader->GetDiffuseClr(t));
texHandle[ntx] = cb.MakeHandle(bmi[1]);
bmi[1] = NULL;
mtl->texture[ntx].textHandle = texHandle[ntx]->GetHandle();
SetTexOps(mtl,ntx,TXOP_OPACITY);
useSubForTex[ntx] = opacChan;
ntx++;
}
}
else {
if (!needDecal) {
TextureInfo ti;
// if (SameUV(mtl->texture[0],mtl->texture[1])) {
// Not really correct to combine channels for different UV's but what the heck.
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE, forceW, forceH);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlphaInto(bmi[1], bmi[0], (*maps)[opacChan].amount, GetOpacity(t));
op = TXOP_OPACITY;
free(bmi[1]);
bmi[1] = NULL;
}
// }
}
}
}
if (bmi[0]) {
texHandle[0] = cb.MakeHandle(bmi[0]);
bmi[0] = NULL;
mtl->texture[0].textHandle = texHandle[0]->GetHandle();
SetTexOps(mtl,0,op);
}
mtl->texture.SetCount(ntx);
numTexHandlesUsed = ntx;
#endif
}
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plParticleMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
sc.GetBGColor(backColor, backTrans);
ShadeWithBackground(sc, backColor);
}
//// Requirements ////////////////////////////////////////////////////////////
// Tells MAX what we need to render ourselves properly, such as translucency,
// two-sidedness, etc. Flags are in imtl.h in the MAX SDK.
ULONG plParticleMtl::Requirements( int subMtlNum )
{
ULONG req = 0;
req = Mtl::Requirements( subMtlNum );
// Uncomment this to get the background color fed to our ShadeWithBackground()
// (slower processing tho)
// req |= MTLREQ_BGCOL;
int blendType = fBasicPB->GetInt( kBlend );
if( blendType == kBlendAdd )
req |= MTLREQ_ADDITIVE_TRANSP | MTLREQ_TRANSP;
else if( blendType == kBlendAlpha )
req |= MTLREQ_TRANSP;
else if( fBasicPB->GetInt( kOpacity, 0 ) != 100 )
req |= MTLREQ_TRANSP;
return req;
}
void plParticleMtl::ShadeWithBackground(ShadeContext &sc, Color background)
{
#if 1
TimeValue t = sc.CurTime();
Color color(0, 0, 0);
float alpha = 0.0;
// Evaluate Base layer
Texmap *map = fBasicPB->GetTexmap(kTexmap);
if (map && map->ClassID() == LAYER_TEX_CLASS_ID)
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
color = evalColor;
alpha = evalColor.a;
}
#if 1
AColor black;
black.Black();
AColor white;
white.White();
SIllumParams ip;
if( fBasicPB->GetInt( kNormal ) == kEmissive )
{
// Emissive objects don't get shaded
ip.diffIllum = fBasicPB->GetColor(kColorAmb, t) * color;
ip.diffIllum.ClampMinMax();
ip.specIllum = black;
}
else
{
//
// Shading setup
//
// Setup the parameters for the shader
ip.amb = black;
ip.diff = fBasicPB->GetColor(kColor, t) * color;
ip.spec = white;
ip.diffIllum = black;
ip.specIllum = black;
ip.N = sc.Normal();
ip.V = sc.V();
//
// Specularity
//
ip.sh_str = 0;
ip.ph_exp = 0;
ip.shine = 0;
ip.softThresh = 0;
// Do the shading
Shader *myShader = GetShader(SHADER_BLINN);
myShader->Illum(sc, ip);
ip.diffIllum.ClampMinMax();
ip.specIllum.ClampMinMax();
ip.diffIllum = ip.amb * sc.ambientLight + ip.diff * ip.diffIllum;
}
// AColor returnColor = AColor(opac * ip.diffIllum + ip.specIllum, opac)
#endif
// Get opacity and combine with alpha
float opac = float(fBasicPB->GetInt(kOpacity, t)) / 100.0f;
//float opac = 1.0f;
alpha *= opac;
// MAX will do the additive/alpha/no blending for us based on what Requirements()
// we tell it. However, since MAX's formula is bgnd*sc.out.t + sc.out.c,
// we have to multiply our output color by the alpha.
// If we ever need a more complicated blending function, you can request the
// background color via Requirements() (otherwise it's just black) and then do
// the blending yourself; however, if the transparency isn't set, the shadows
// will be opaque, so be careful.
Color outC = ip.diffIllum + ip.specIllum;
sc.out.c = ( outC * alpha );
sc.out.t = Color( 1.f - alpha, 1.f - alpha, 1.f - alpha );
#endif
}
float plParticleMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plParticleMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
Control *plParticleMtl::GetAmbColorController() { return fBasicPB->GetController(ParamID(kColorAmb)); }
Control *plParticleMtl::GetColorController() { return fBasicPB->GetController(ParamID(kColor)); }
Control *plParticleMtl::GetOpacityController() { return fBasicPB->GetController(ParamID(kOpacity)); }
Control *plParticleMtl::GetWidthController() { return fBasicPB->GetController(ParamID(kWidth)); }
Control *plParticleMtl::GetHeightController() { return fBasicPB->GetController(ParamID(kHeight)); }

View File

@ -0,0 +1,182 @@
/*==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/>.
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==*/
#ifndef PL_PARTICLEMTL_H
#define PL_PARTICLEMTL_H
#include "Max.h"
//#include "istdplug.h"
#include "iparamb2.h"
//#include "iparamm2.h"
#include "../resource.h"
class Bitmap;
#define PARTICLE_MTL_CLASS_ID Class_ID(0x26df05ff, 0x60660749)
extern TCHAR *GetString(int id);
class plParticleMtl : public Mtl
{
protected:
IParamBlock2 *fBasicPB;
Interval fIValid;
public:
IMtlParams *fIMtlParams;
enum
{
kRefBasic,
};
enum
{
kBlkBasic,
};
enum // Param block indicies
{
kOpacity,
kColor,
kWidth,
kHeight,
kXTiles,
kYTiles,
kNormal,
kBlend,
kOrientation,
kBitmap,
kTexmap,
kColorAmb,
kNoFilter
};
enum
{
kBlendNone,
kBlendAlpha,
kBlendAdd
};
enum
{
kOrientVelocity,
kOrientUp,
kOrientVelStretch,
kOrientVelFlow
};
enum
{
kNormalViewFacing,
kNormalUp,
kNormalNearestLight,
kNormalFromCenter,
kNormalVelUpVel,
kEmissive,
kNumNormalOptions
};
static const char *NormalStrings[];
plParticleMtl(BOOL loading);
void DeleteThis() { delete this; }
//From Animatable
Class_ID ClassID() { return PARTICLE_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_PARTICLE_MTL); }
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void Reset();
void NotifyChanged();
BOOL SupportsMultiMapsInViewport() { return FALSE; }
void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);
// Shade and displacement calculation
void Shade(ShadeContext& sc);
void ShadeWithBackground(ShadeContext &sc, Color background);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
// SubTexmap access methods
int NumSubTexmaps();
Texmap* GetSubTexmap(int i);
void SetSubTexmap(int i, Texmap *m);
TSTR GetSubTexmapSlotName(int i);
TSTR GetSubTexmapTVName(int i);
BOOL SetDlgThing(ParamDlg* dlg);
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumRefs();
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// void SetParamDlg(ParamDlg *dlg);
// void SetNumSubTexmaps(int num);
DllExport Control *GetAmbColorController();
DllExport Control *GetColorController();
DllExport Control *GetOpacityController();
DllExport Control *GetWidthController();
DllExport Control *GetHeightController();
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
ULONG Requirements( int subMtlNum );
};
#endif //PL_PARTICLEMTL_H

View File

@ -0,0 +1,234 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plParticleMtl.h"
class PartMtlPBAccessor;
extern PartMtlPBAccessor partMtl_accessor;
class ParticleBasicDlgProc;
extern ParticleBasicDlgProc gParticleBasicDlgProc;
#define PL_PARTICLE_MTL_MIN_TILES 1
#define PL_PARTICLE_MTL_MAX_TILES 16
static ParamBlockDesc2 gParticleMtlPB
(
plParticleMtl::kBlkBasic, _T("particle"), IDS_PASS_BASIC, GetParticleMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI + P_CALLSETS_ON_LOAD, plParticleMtl::kRefBasic,
// UI
IDD_PARTICLE, IDS_PASS_BASIC, 0, 0, &gParticleBasicDlgProc,
plParticleMtl::kOpacity, _T("opacity"), TYPE_INT, P_ANIMATABLE, IDS_PARTICLE_OPACITY,
p_default, 100,
p_range, 0, 100,
p_ui, TYPE_SPINNER, EDITTYPE_INT,
IDC_PARTICLE_OPACITY, IDC_PARTICLE_OPACITY_SPIN, 1.0,
end,
plParticleMtl::kColorAmb, _T("ambColor"), TYPE_RGBA, P_ANIMATABLE, IDS_PARTICLE_AMB_COLOR,
p_ui, TYPE_COLORSWATCH, IDC_PARTICLE_AMB_COLOR,
p_default, Color(0,0,0),
end,
plParticleMtl::kColor, _T("color"), TYPE_RGBA, P_ANIMATABLE, IDS_PARTICLE_COLOR,
p_ui, TYPE_COLORSWATCH, IDC_PARTICLE_COLOR,
p_default, Color(1,1,1),
end,
plParticleMtl::kWidth, _T("width"), TYPE_FLOAT, P_ANIMATABLE, IDS_PARTICLE_WIDTH,
p_default, 1.0,
p_range, 0.01, 10.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_PARTICLE_WIDTH, IDC_PARTICLE_WIDTH_SPIN, 1.0,
end,
plParticleMtl::kHeight, _T("height"), TYPE_FLOAT, P_ANIMATABLE, IDS_PARTICLE_HEIGHT,
p_default, 1.0,
p_range, 0.01, 10.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_PARTICLE_HEIGHT, IDC_PARTICLE_HEIGHT_SPIN, 1.0,
end,
plParticleMtl::kXTiles, _T("xTiling"), TYPE_INT, 0, 0,
p_default, 1,
p_range, PL_PARTICLE_MTL_MIN_TILES, PL_PARTICLE_MTL_MAX_TILES,
p_ui, TYPE_SPINNER, EDITTYPE_POS_INT,
IDC_PARTICLE_XTILE, IDC_PARTICLE_XTILE_SPIN, 1.0,
p_accessor, &partMtl_accessor,
end,
plParticleMtl::kYTiles, _T("yTiling"), TYPE_INT, 0, 0,
p_default, 1,
p_range, PL_PARTICLE_MTL_MIN_TILES, PL_PARTICLE_MTL_MAX_TILES,
p_ui, TYPE_SPINNER, EDITTYPE_POS_INT,
IDC_PARTICLE_YTILE, IDC_PARTICLE_YTILE_SPIN, 1.0,
p_accessor, &partMtl_accessor,
end,
plParticleMtl::kNormal, _T("normal"), TYPE_INT, 0, 0,
p_default, 0,
end,
plParticleMtl::kBlend, _T("texBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 2, IDC_PARTICLE_BLEND_ALPHA, IDC_PARTICLE_BLEND_ADD,
p_vals, plParticleMtl::kBlendAlpha, plParticleMtl::kBlendAdd,
p_default, plParticleMtl::kBlendAlpha,
end,
plParticleMtl::kOrientation, _T("layerBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 4, IDC_PARTICLE_ORIENT_VELOCITY, IDC_PARTICLE_ORIENT_UP, IDC_PARTICLE_ORIENT_VELSTRETCH, IDC_PARTICLE_ORIENT_VELFLOW,
p_vals, plParticleMtl::kOrientVelocity, plParticleMtl::kOrientUp, plParticleMtl::kOrientVelStretch, plParticleMtl::kOrientVelFlow,
p_default, plParticleMtl::kOrientVelocity,
end,
plParticleMtl::kBitmap, _T("bitmap"), TYPE_BITMAP, P_SHORT_LABELS, 0,
///p_ui, TYPE_BITMAPBUTTON, IDC_PARTICLE_TEXTURE,
//p_accessor, &partMtl_accessor,
end,
plParticleMtl::kTexmap, _T("texmap"), TYPE_TEXMAP, 0, 0,
// p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER2,
end,
plParticleMtl::kNoFilter, _T("noFilter"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_PARTICLE_NOFILTER,
p_default, FALSE,
end,
end
);
class PartMtlPBAccessor : public PBAccessor
{
public:
void Set(PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)
{
plParticleMtl* mtl = (plParticleMtl *)owner;
//plLayerTex *layer;
switch (id)
{
case plParticleMtl::kBitmap:
break;
case plParticleMtl::kXTiles:
case plParticleMtl::kYTiles:
if (val.i < PL_PARTICLE_MTL_MIN_TILES)
val.i = PL_PARTICLE_MTL_MIN_TILES;
if (val.i > PL_PARTICLE_MTL_MAX_TILES)
val.i = PL_PARTICLE_MTL_MAX_TILES;
break;
}
}
void Get(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid)
{
}
};
static PartMtlPBAccessor partMtl_accessor;
class ParticleBasicDlgProc : public ParamMap2UserDlgProc
{
public:
ParticleBasicDlgProc() {}
~ParticleBasicDlgProc() {}
void UpdateDisplay(IParamMap2 *pmap)
{
HWND hWnd = pmap->GetHWnd();
IParamBlock2 *pb = pmap->GetParamBlock();
HWND cbox = GetDlgItem(hWnd, IDC_PARTICLE_NORMAL);
plPlasmaMAXLayer *layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(plParticleMtl::kTexmap));
PBBitmap *pbbm;
ICustButton *bmSelectBtn;
SendMessage(cbox, CB_SETCURSEL, pb->GetInt(plParticleMtl::kNormal), 0);
pbbm = (layer == nil ? nil : layer->GetPBBitmap());
bmSelectBtn = GetICustButton(GetDlgItem(hWnd,IDC_PARTICLE_TEXTURE));
bmSelectBtn->SetText(pbbm ? (TCHAR*)pbbm->bi.Filename() : "(none)");
ReleaseICustButton(bmSelectBtn);
}
virtual void Update(TimeValue t, Interval& valid, IParamMap2* pmap) { UpdateDisplay(pmap); }
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int id = LOWORD(wParam);
int code = HIWORD(wParam);
IParamBlock2 *pb = map->GetParamBlock();
HWND cbox = NULL;
plPlasmaMAXLayer *layer = (plPlasmaMAXLayer *)pb->GetTexmap(ParamID(plParticleMtl::kTexmap));
switch (msg)
{
case WM_INITDIALOG:
int j;
for (j = 0; j < plParticleMtl::kNumNormalOptions; j++)
{
cbox = GetDlgItem(hWnd, IDC_PARTICLE_NORMAL);
SendMessage(cbox, CB_ADDSTRING, 0, (LPARAM)plParticleMtl::NormalStrings[j]);
}
UpdateDisplay(map);
return TRUE;
case WM_COMMAND:
if (id == IDC_PARTICLE_NORMAL)
{
pb->SetValue(plParticleMtl::kNormal, t, SendMessage(GetDlgItem(hWnd, id), CB_GETCURSEL, 0, 0));
return TRUE;
}
else if (id == IDC_PARTICLE_TEXTURE)
{
if (layer == nil)
return FALSE;
layer->HandleBitmapSelection();
UpdateDisplay(map);
return TRUE;
}
else if (id == IDC_PARTICLE_NOFILTER)
{
if (!layer)
return FALSE;
if( pb->GetInt(plParticleMtl::kNoFilter) )
{
layer->GetParamBlockByID( plLayerTex::kBlkBitmap )->SetValue(kBmpNoFilter, t, 1);
}
else
{
layer->GetParamBlockByID( plLayerTex::kBlkBitmap )->SetValue(kBmpNoFilter, t, 0);
}
return TRUE;
}
break;
}
return FALSE;
}
void DeleteThis() {}
};
static ParticleBasicDlgProc gParticleBasicDlgProc;

View File

@ -0,0 +1,305 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plPassAnimDlgProc - Base Animation Dlg Proc for plPassMtlBase //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plPassAnimDlgProc.h"
#include "plPassBaseParamIDs.h"
#include "../MaxComponent/plNotetrackAnim.h"
#include "resource.h"
#include "iparamm2.h"
#include "plAnimStealthNode.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "../MaxComponent/plAnimComponent.h"
#include "../MaxExport/plErrorMsg.h"
const char *kPassNameNone = ENTIRE_ANIMATION_NAME;
#include "plAnimStealthNode.h"
using namespace plPassBaseParamIDs;
plPassAnimDlgProc::plPassAnimDlgProc()
{
fCurrParamMap = nil;
fInitingNames = false;
}
plPassAnimDlgProc::~plPassAnimDlgProc()
{
if( fCurrParamMap != nil )
{
plPassMtlBase *mtl = (plPassMtlBase *)( fCurrParamMap->GetParamBlock()->GetOwner() );
mtl->RegisterChangeCallback( this );
}
}
plPassAnimDlgProc &plPassAnimDlgProc::Get( void )
{
static plPassAnimDlgProc instance;
return instance;
}
void plPassAnimDlgProc::Update(TimeValue t, Interval& valid, IParamMap2* pmap)
{
/* plAnimStealthNode *testStealth = (plAnimStealthNode *)pmap->GetParamBlock()->GetINode( (ParamID)kPBAnimTESTING );
if( testStealth != nil )
{
IParamBlock2 *pb = testStealth->GetParamBlockByID( plAnimStealthNode::kBlockPB );
if( pb && pb->GetMap() && pb->GetMap()->GetUserDlgProc() )
pb->GetMap()->GetUserDlgProc()->Update( t, valid, pmap );
}
*/
HWND hWnd = pmap->GetHWnd();
IParamBlock2 *pb = pmap->GetParamBlock();
plAnimComponentProc::SetBoxToAgeGlobal(GetDlgItem(hWnd, IDC_MTL_GLOBAL_NAME), pb->GetStr(ParamID(kPBAnimGlobalName)));
}
BOOL plPassAnimDlgProc::DlgProc(TimeValue t, IParamMap2 *pMap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if( fCurrParamMap != pMap )
{
if( fCurrParamMap != nil )
{
plPassMtlBase *mtl = (plPassMtlBase *)( fCurrParamMap->GetParamBlock()->GetOwner() );
mtl->UnregisterChangeCallback( this );
}
fCurrParamMap = pMap;
if( fCurrParamMap != nil )
{
plPassMtlBase *mtl = (plPassMtlBase *)( fCurrParamMap->GetParamBlock()->GetOwner() );
mtl->RegisterChangeCallback( this );
}
}
IParamBlock2 *pb = pMap->GetParamBlock();
plPassMtlBase *mtl = (plPassMtlBase*)pb->GetOwner();
HWND gWnd = GetDlgItem(hWnd, IDC_MTL_GLOBAL_NAME);
char buff[512];
switch (msg)
{
case WM_DESTROY:
if( fCurrParamMap != nil )
{
plPassMtlBase *mtl = (plPassMtlBase *)( fCurrParamMap->GetParamBlock()->GetOwner() );
mtl->RegisterChangeCallback( this );
fCurrParamMap = nil;
}
break;
case WM_INITDIALOG:
{
fhWnd = hWnd;
fCurrStealth = nil;
IInitControls(mtl, pb);
plAnimComponentProc::FillAgeGlobalComboBox(gWnd, pb->GetStr(ParamID(kPBAnimGlobalName)));
plAnimComponentProc::SetBoxToAgeGlobal(gWnd, pb->GetStr(ParamID(kPBAnimGlobalName)));
IEnableGlobal(hWnd, pb->GetInt( (ParamID)kPBAnimUseGlobal ) );
bool stopPoints = false;
if( DoesHaveStopPoints( pb->GetOwner() ) )
{
stopPoints = true;
break;
}
IEnableEaseStopPoints( pMap, stopPoints );
}
return TRUE;
case WM_COMMAND:
// Anim name selection changed
if (LOWORD(wParam) == IDC_NAMES && HIWORD(wParam) == CBN_SELCHANGE)
{
IUpdateSegmentSel( pMap );
return TRUE;
}
// Refresh clicked
else if (LOWORD(wParam) == IDC_REFRESH_ANIMS && HIWORD(wParam) == BN_CLICKED)
{
IInitControls(mtl, pb);
return TRUE;
}
else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_MTL_GLOBAL_NAME)
{
ComboBox_GetLBText(gWnd, ComboBox_GetCurSel(gWnd), buff);
pb->SetValue(ParamID(kPBAnimGlobalName), 0, _T(buff));
}
else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_MTL_USE_GLOBAL)
{
IEnableGlobal(hWnd, pb->GetInt( (ParamID)kPBAnimUseGlobal ) );
}
break;
}
return FALSE;
}
void plPassAnimDlgProc::SegmentListChanged( void )
{
if( fCurrParamMap != nil )
ILoadNames( fCurrParamMap->GetParamBlock() );
}
void plPassAnimDlgProc::IUpdateSegmentSel( IParamMap2 *thisMap, hsBool clear )
{
plAnimStealthNode *newStealth;
HWND hAnims = GetDlgItem( fhWnd, IDC_NAMES );
// Get current selection
if( clear )
newStealth = nil;
else
{
int sel = SendDlgItemMessage( fhWnd, IDC_NAMES, CB_GETCURSEL, 0, 0 );
if( sel == CB_ERR )
{
// Somehow we don't have a selection...fine, just destroy
newStealth = nil;
}
else
{
newStealth = (plAnimStealthNode *)SendDlgItemMessage( fhWnd, IDC_NAMES, CB_GETITEMDATA, sel, 0 );
}
}
// Did we really not change?
if( newStealth == fCurrStealth )
return;
if( fCurrStealth != nil && newStealth != nil )
{
fCurrStealth->SwitchDlg( newStealth );
}
else
{
// Destroy the old
if( fCurrStealth != nil )
fCurrStealth->ReleaseDlg();
// Show the new
if( newStealth != nil )
IExposeStealthNode( newStealth, thisMap );
}
// And update!
fCurrStealth = newStealth;
}
void plPassAnimDlgProc::IExposeStealthNode( HelperObject *node, IParamMap2 *thisMap )
{
if( node->ClassID() != ANIMSTEALTH_CLASSID )
return;
// Get our stealth pointer
plAnimStealthNode *stealth = (plAnimStealthNode *)node;
// Create the paramMap-based dialog for us
IParamBlock2 *pb = thisMap->GetParamBlock();
plPassMtlBase *mtl = (plPassMtlBase *)pb->GetOwner();
if( !stealth->CreateAndEmbedDlg( thisMap, mtl->fIMtlParams, GetDlgItem( fhWnd, IDC_PLACEHOLDER ) ) )
{
}
}
void plPassAnimDlgProc::SetThing(ReferenceTarget *m)
{
plPassMtlBase *mtl = (plPassMtlBase*)m;
IInitControls(mtl, mtl->fAnimPB );
}
void plPassAnimDlgProc::IInitControls(Animatable *anim, IParamBlock2 *pb)
{
ILoadNames( pb );
IEnableGlobal( fhWnd, pb->GetInt( ParamID( kPBAnimUseGlobal ) ) );
}
void plPassAnimDlgProc::ILoadNames(IParamBlock2 *pb )
{
// The following is to prevent IGetNumStealths() from re-calling us
if( fInitingNames )
return;
fInitingNames = true;
HWND hAnims = GetDlgItem(fhWnd, IDC_NAMES);
SendMessage(hAnims, CB_RESETCONTENT, 0, 0);
plPassMtlBase *mtl = (plPassMtlBase *)pb->GetOwner();
// Loop through our stealth nodes and add them all to the combo,
// since that's what we're selecting...erm, yeah
int i, count = mtl->IGetNumStealths( true );
for( i = 0; i < count; i++ )
{
plAnimStealthNode *stealth = mtl->IGetStealth( i, false );
if( stealth != nil )
{
int idx = SendMessage( hAnims, CB_ADDSTRING, 0, (LPARAM)stealth->GetSegmentName() );
SendMessage( hAnims, CB_SETITEMDATA, idx, (LPARAM)stealth );
}
}
SendMessage( hAnims, CB_SETCURSEL, 0, 0 );
IUpdateSegmentSel( pb->GetMap() );
fInitingNames = false;
}
void plPassAnimDlgProc::IEnableGlobal(HWND hWnd, hsBool enable)
{
Edit_Enable(GetDlgItem(hWnd, IDC_MTL_GLOBAL_NAME), enable);
ComboBox_Enable(GetDlgItem(hWnd, IDC_NAMES), !enable);
HWND stealthWnd = ( fCurrStealth != nil ) ? fCurrStealth->GetWinDlg() : nil;
if( stealthWnd != nil )
EnableWindow( stealthWnd, !enable );
}
void plPassAnimDlgProc::IEnableEaseStopPoints( IParamMap2 *pm, bool enable )
{
pm->Enable( (ParamID)kPBAnimEaseInMin, enable );
pm->Enable( (ParamID)kPBAnimEaseInMax, enable );
pm->Enable( (ParamID)kPBAnimEaseOutMin, enable );
pm->Enable( (ParamID)kPBAnimEaseOutMax, enable );
}

View File

@ -0,0 +1,84 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plPassAnimDlgProc - Base Animation Dlg Proc for plPassMtlBase //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plPassAnimDlgProc_h
#define _plPassAnimDlgProc_h
#include "plPassMtlBase.h"
#include "iparamm2.h"
class plAnimStealthNode;
class IParamMap2;
class plPassAnimDlgProc : public ParamMap2UserDlgProc, public plMtlChangeCallback
{
protected:
// Combo itemdata values
enum
{
kName, // Name of an animation/loop
kDefault, // Default combo value
kInvalid, // Invalid entry (couldn't find)
};
plAnimStealthNode *fCurrStealth;
IParamMap2 *fCurrParamMap;
bool fInitingNames;
HWND fhWnd;
public:
plPassAnimDlgProc();
virtual ~plPassAnimDlgProc();
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void DeleteThis() {}
void SetThing(ReferenceTarget *m);
virtual void Update(TimeValue t, Interval& valid, IParamMap2* pmap);
void SegmentListChanged( void );
static plPassAnimDlgProc &Get( void );
protected:
// Set all the controls to their stored value
void IInitControls(Animatable *anim, IParamBlock2 *pb);
void IEnableGlobal(HWND hWnd, hsBool enable);
void ILoadNames( IParamBlock2 *pb );
void IExposeStealthNode( HelperObject *stealth, IParamMap2 *thisMap );
void IUpdateSegmentSel( IParamMap2 *thisMap, hsBool clear = false );
void IEnableEaseStopPoints( IParamMap2 *pm, bool enable );
};
#endif //_plPassAnimDlgProc_h

View File

@ -0,0 +1,100 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plPassBaseParamIDs - Common ParamIDs for all plPassMtlBase-derived mtls //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plPassBaseParamIDs_h
#define _plPassBaseParamIDs_h
#define MCN_UPGRADE_OLD_ANIM_BLOCKS
namespace plPassBaseParamIDs
{
enum AdvancedIDs
{
// Specular
kPBAdvUseSpec, // Not used anymore, feel free to replace with new fields as necessary
kPBAdvSpecType, // ditto
kPBAdvShine, // ...
kPBAdvShineStr, // ...
// Misc
kPBAdvWire,
kPBAdvMeshOutlines,
kPBAdvTwoSided,
// Shading
kPBAdvSoftShadow,
kPBAdvNoProj,
kPBAdvVertexShade,
kPBAdvNoShade,
kPBAdvNoFog,
kPBAdvWhite,
// Z
kPBAdvZOnly,
kPBAdvZClear,
kPBAdvZNoRead,
kPBAdvZNoWrite,
kPBAdvZInc,
// Alpha test
kPBAdvAlphaTestHigh
};
enum SpecularTypes
{
kSpecTypeAlpha,
kSpecTypeColor,
kSpecTypeHighlight
};
enum AnimationIDs
{
kPBAnimName,
kPBAnimAutoStart,
kPBAnimLoop,
kPBAnimLoopName,
kPBAnimEaseInType,
kPBAnimEaseOutType,
kPBAnimEaseInLength,
kPBAnimEaseOutLength,
kPBAnimEaseInMin,
kPBAnimEaseInMax,
kPBAnimEaseOutMin,
kPBAnimEaseOutMax,
kPBAnimUseGlobal,
kPBAnimGlobalName,
kPBAnimStealthNodes
};
}
#endif //_plPassBaseParamIDs_h

View File

@ -0,0 +1,846 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plPassMtl.h"
#include "resource.h"
//extern ClassDesc2* GetMaxLayerDesc();
#include "Shaders.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "plPassBaseParamIDs.h"
#include "plPassMtlBasicPB.h"
#include "plPassMtlLayersPB.h"
#include "iparamm2.h"
#include "Layers/plLayerTex.h"
#include "Layers/plStaticEnvLayer.h"
#include "hsBitVector.h"
extern HINSTANCE hInstance;
class plPassMtlClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void* Create(BOOL loading) { return TRACKED_NEW plPassMtl(loading); }
const TCHAR* ClassName() { return GetString(IDS_PASS_MTL); }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
Class_ID ClassID() { return PASS_MTL_CLASS_ID; }
const TCHAR* Category() { return NULL; }
const TCHAR* InternalName() { return _T("PlasmaMaterial"); }
HINSTANCE HInstance() { return hInstance; }
};
static plPassMtlClassDesc plPassMtlDesc;
ClassDesc2* GetPassMtlDesc() { return &plPassMtlDesc; }
// For initializing paramblock descriptor
ParamBlockDesc2 *GetPassBasicPB();
ParamBlockDesc2 *GetPassAdvPB();
ParamBlockDesc2 *GetPassLayersPB();
#include "plPassMtlAdvPBDec.h"
#include "plPassMtlBasicPBDec.h"
#include "plPassMtlLayersPBDec.h"
#include "plPassMtlAnimPBDec.h"
#include "plAnimStealthNode.h"
plPassMtl::plPassMtl(BOOL loading) : plPassMtlBase( loading )
{
plPassMtlDesc.MakeAutoParamBlocks( this );
fLayersPB->SetValue( kPassLayBase, 0, TRACKED_NEW plLayerTex );
fLayersPB->SetValue( kPassLayTop, 0, TRACKED_NEW plLayerTex );
// If we do this later (like, when the dialog loads) something blows up,
// somewhere in Max. It didn't in 4, it does in 7. This seems to fix it.
if (!loading)
IVerifyStealthPresent(ENTIRE_ANIMATION_NAME);
}
plPassMtl::~plPassMtl()
{
}
ParamDlg* plPassMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
{
fIMtlParams = imp;
IAutoMParamDlg* masterDlg = plPassMtlDesc.CreateParamDlgs(hwMtlEdit, imp, this);
return (ParamDlg*)masterDlg;
}
BOOL plPassMtl::SetDlgThing(ParamDlg* dlg)
{
return FALSE;
}
Interval plPassMtl::Validity(TimeValue t)
{
#if 0 // mf horse
Interval valid = FOREVER;
/* for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
valid &= fSubTexmap[i]->Validity(t);
}
*/
// float u;
// fPBlock->GetValue(pb_spin,t,u,valid);
return valid;
#else // mf horse
const char* name = GetName();
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
Interval v = FOREVER;
fBasicPB->GetValidity(t, v);
fAdvPB->GetValidity(t, v);
if( fLayersPB->GetTexmap(kPassLayBase) )
v &= fLayersPB->GetTexmap(kPassLayBase)->Validity(t);
if( fLayersPB->GetTexmap(kPassLayTop) )
v &= fLayersPB->GetTexmap(kPassLayTop)->Validity(t);
return v;
#endif // mf horse
}
//// GetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
RefTargetHandle plPassMtl::GetReference( int i )
{
switch( i )
{
case kRefBasic: return fBasicPB;
case kRefAdv: return fAdvPB;
case kRefLayers: return fLayersPB;
case kRefAnim: return fAnimPB;
}
return plPassMtlBase::GetReference( i );
}
//// SetReference ////////////////////////////////////////////////////////////
// Note: need to overload because MAX for some reason writes out the
// references by their INDEX. ARRRRGH!
void plPassMtl::SetReference(int i, RefTargetHandle rtarg)
{
if (i == kRefBasic)
fBasicPB = (IParamBlock2 *)rtarg;
else if (i == kRefAdv)
fAdvPB = (IParamBlock2 *)rtarg;
else if (i == kRefLayers)
fLayersPB = (IParamBlock2 *)rtarg;
else if (i == kRefAnim)
fAnimPB = (IParamBlock2 *)rtarg;
else
plPassMtlBase::SetReference( i, rtarg );
}
/*===========================================================================*\
| Subanim & References support
\*===========================================================================*/
int plPassMtl::NumSubs()
{
return 6;
}
TSTR plPassMtl::SubAnimName(int i)
{
switch (i)
{
case 0: return fBasicPB->GetLocalName();
case 1: return fAdvPB->GetLocalName();
case 2: return fLayersPB->GetLocalName();
case 3: return fAnimPB->GetLocalName();
case 4: return "Base Layer";
case 5: return "Top Layer";
}
return "";
}
Animatable* plPassMtl::SubAnim(int i)
{
switch (i)
{
case 0: return fBasicPB;
case 1: return fAdvPB;
case 2: return fLayersPB;
case 3: return fAnimPB;
case 4: return fLayersPB->GetTexmap(kPassLayBase);
case 5:
if (fLayersPB->GetInt(kPassLayTopOn))
return fLayersPB->GetTexmap(kPassLayTop);
break;
}
return NULL;
}
int plPassMtl::NumParamBlocks()
{
return 4;
}
IParamBlock2* plPassMtl::GetParamBlock(int i)
{
return (IParamBlock2*)GetReference(i);
}
IParamBlock2* plPassMtl::GetParamBlockByID(BlockID id)
{
if (fBasicPB->ID() == id)
return fBasicPB;
else if (fAdvPB->ID() == id)
return fAdvPB;
else if (fLayersPB->ID() == id)
return fLayersPB;
else if (fAnimPB->ID() == id)
return fAnimPB;
return NULL;
}
RefResult plPassMtl::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message)
{
return plPassMtlBase::NotifyRefChanged( changeInt, hTarget, partID, message );
}
////////////////////////////////////////////////////////////////////////////////
// Subtexmap access
int plPassMtl::NumSubTexmaps()
{
return 2;
}
Texmap* plPassMtl::GetSubTexmap(int i)
{
if (i == 0)
return fLayersPB->GetTexmap(kPassLayBase);
else if (i == 1)
return fLayersPB->GetTexmap(kPassLayTop);
return NULL;
}
void plPassMtl::SetSubTexmap(int i, Texmap *m)
{
if (i == 0)
fLayersPB->SetValue(kPassLayBase, 0, m);
else if (i == 1)
fLayersPB->SetValue(kPassLayTop, 0, m);
}
TSTR plPassMtl::GetSubTexmapSlotName(int i)
{
if (i == 0)
return "Base";
else if (i == 1)
return "Top";
return "";
}
TSTR plPassMtl::GetSubTexmapTVName(int i)
{
return GetSubTexmapSlotName(i);
}
int plPassMtl::SubTexmapOn(int i)
{
if (i == 0)
return 1;
else if (i == 1 && fLayersPB->GetInt(kPassLayTopOn))
return 1;
return 0;
}
/*===========================================================================*\
| Updating and cloning
\*===========================================================================*/
RefTargetHandle plPassMtl::Clone(RemapDir &remap)
{
plPassMtl *mnew = TRACKED_NEW plPassMtl(FALSE);
plPassMtlBase::ICloneBase( mnew, remap );
return (RefTargetHandle)mnew;
}
void plPassMtl::ICloneRefs( plPassMtlBase *target, RemapDir &remap )
{
target->ReplaceReference(kRefBasic, remap.CloneRef(fBasicPB));
target->ReplaceReference(kRefAdv, remap.CloneRef(fAdvPB));
target->ReplaceReference(kRefLayers, remap.CloneRef(fLayersPB));
target->ReplaceReference(kRefAnim, remap.CloneRef(fAnimPB));
}
void plPassMtl::NotifyChanged()
{
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void plPassMtl::Update(TimeValue t, Interval& valid)
{
// mf horse - Hacking in something like real validity checking
// to get material animations working. No warranty, this is just
// better than nothing.
if (!fIValid.InInterval(t))
{
fIValid.SetInfinite();
if( fLayersPB->GetTexmap(kPassLayBase) )
fLayersPB->GetTexmap(kPassLayBase)->Update(t, fIValid);
if( fLayersPB->GetTexmap(kPassLayTop) )
fLayersPB->GetTexmap(kPassLayTop)->Update(t, fIValid);
// fLayersPB->GetValue(kMtlLayLayer1On, t, fMapOn[0], fIValid);
/*
for (int i = 0; i < fSubTexmap.Count(); i++)
{
if (fSubTexmap[i])
fSubTexmap[i]->Update(t,fIValid);
}
*/
}
// Our wonderful way of version handling--if the runtimeColor is (-1,-1,-1), we know it's
// just been initialized, so set it to the static color (this lets us do the right thing for
// loading old paramBlocks)
if( fBasicPB )
{
Color run = fBasicPB->GetColor( kPassBasRunColor, 0 );
if( run == Color(-1,-1,-1) )
{
fBasicPB->SetValue( kPassBasRunColor, 0, fBasicPB->GetColor( kPassBasColor, 0 ) );
}
// Also, if shineStr is anything other than -1, then it must be an old paramblock and we need
// to convert to our new specColor (we know this because the original valid range was 0-100)
int shine = fBasicPB->GetInt( kPassBasShineStr, 0 );
if( shine != -1 )
{
fBasicPB->SetValue( kPassBasSpecColor, 0, Color( (float)shine / 100.f, (float)shine / 100.f, (float)shine / 100.f ) );
fBasicPB->SetValue( kPassBasShineStr, 0, (int)-1 );
}
}
valid &= fIValid;
}
/*===========================================================================*\
| Determine the characteristics of the material
\*===========================================================================*/
void plPassMtl::SetAmbient(Color c, TimeValue t) {}
void plPassMtl::SetDiffuse(Color c, TimeValue t) {}
void plPassMtl::SetSpecular(Color c, TimeValue t) {}
void plPassMtl::SetShininess(float v, TimeValue t) {}
Color plPassMtl::GetAmbient(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plPassMtl::GetDiffuse(int mtlNum, BOOL backFace) { return Color(0,0,0); }
Color plPassMtl::GetSpecular(int mtlNum, BOOL backFace) { return Color(0,0,0); }
float plPassMtl::GetXParency(int mtlNum, BOOL backFace)
{
int opacity = fBasicPB->GetInt( kPassBasOpacity, 0 );
float alpha = 1.0f - ( (float)opacity / 100.0f );
return alpha;
}
float plPassMtl::GetShininess(int mtlNum, BOOL backFace) { return 0.0f; }
float plPassMtl::GetShinStr(int mtlNum, BOOL backFace) { return 0.0f; }
float plPassMtl::WireSize(int mtlNum, BOOL backFace) { return 0.0f; }
/////////////////////////////////////////////////////////////////
void plPassMtl::SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb)
{
#if 0
if (texHandleValid.InInterval(t)) {
mtl->texture.SetCount(numTexHandlesUsed);
for (int i=0; i<numTexHandlesUsed; i++) {
if (texHandle[i]) {
mtl->texture[i].textHandle = texHandle[i]->GetHandle();
Texmap *tx = (*maps)[useSubForTex[i]].map;
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[i], tx );
SetTexOps(mtl,i,texOpsType[i]);
}
}
return;
}
#endif
#if 0 // WTF?!?!?!?
Texmap *tx[2];
int diffChan = stdIDToChannel[ ID_DI ];
int opacChan = stdIDToChannel[ ID_OP ];
tx[0] = (*maps)[diffChan].IsActive()?(*maps)[diffChan].map:NULL;
tx[1] = (*maps)[opacChan].IsActive()?(*maps)[opacChan].map:NULL;
#endif
int nsupport = cb.NumberTexturesSupported();
#if 0
BITMAPINFO *bmi[NTEXHANDLES];
int nmaps=0;
for (int i=0; i<NTEXHANDLES; i++) {
if (tx[i]) nmaps ++;
bmi[i] = NULL;
}
mtl->texture.SetCount(nmaps);
if (nmaps==0)
return;
for (i=0; i<nmaps; i++)
mtl->texture[i].textHandle = NULL;
texHandleValid.SetInfinite();
Interval valid;
BOOL needDecal = FALSE;
int ntx = 0;
int op;
int forceW = 0;
int forceH = 0;
if (tx[0]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[0], tx[0]);
TextureInfo &ti = mtl->texture[0];
if (ti.tiling[0]==GW_TEX_NO_TILING||ti.tiling[1]==GW_TEX_NO_TILING)
needDecal = TRUE;
op = needDecal?TXOP_ALPHABLEND:TXOP_MODULATE;
bmi[0] = tx[0]->GetVPDisplayDIB(t,cb,valid,FALSE);
if (bmi[0]) {
texHandleValid &= valid;
useSubForTex[0] = diffChan;
ntx = 1;
forceW = bmi[0]->bmiHeader.biWidth;
forceH = bmi[0]->bmiHeader.biHeight;
}
}
if (tx[1]) {
cb.GetGfxTexInfoFromTexmap(t, mtl->texture[ntx], tx[1]);
if (nsupport>ntx) {
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlpha(bmi[1], (*maps)[opacChan].amount, GetOpacity(t),ntx?whiteCol:pShader->GetDiffuseClr(t));
texHandle[ntx] = cb.MakeHandle(bmi[1]);
bmi[1] = NULL;
mtl->texture[ntx].textHandle = texHandle[ntx]->GetHandle();
SetTexOps(mtl,ntx,TXOP_OPACITY);
useSubForTex[ntx] = opacChan;
ntx++;
}
}
else {
if (!needDecal) {
TextureInfo ti;
// if (SameUV(mtl->texture[0],mtl->texture[1])) {
// Not really correct to combine channels for different UV's but what the heck.
bmi[1] = tx[1]->GetVPDisplayDIB(t,cb,valid,TRUE, forceW, forceH);
if (bmi[1]) {
texHandleValid &= valid;
StuffAlphaInto(bmi[1], bmi[0], (*maps)[opacChan].amount, GetOpacity(t));
op = TXOP_OPACITY;
free(bmi[1]);
bmi[1] = NULL;
}
// }
}
}
}
if (bmi[0]) {
texHandle[0] = cb.MakeHandle(bmi[0]);
bmi[0] = NULL;
mtl->texture[0].textHandle = texHandle[0]->GetHandle();
SetTexOps(mtl,0,op);
}
mtl->texture.SetCount(ntx);
numTexHandlesUsed = ntx;
#endif
}
/*===========================================================================*\
| Actual shading takes place
\*===========================================================================*/
void plPassMtl::GetInterpVtxValue(int channel, ShadeContext &sc, Point3 &val)
{
Mesh *mesh = sc.globContext->GetRenderInstance(sc.NodeID())->mesh;
if (mesh != nil)
{
Face *maxFace = &mesh->faces[ sc.FaceNumber() ];
UVVert *map = mesh->mapVerts(channel);
if (map != nil)
{
Point3 p0 = map[maxFace->getVert( 0 )];
Point3 p1 = map[maxFace->getVert( 1 )];
Point3 p2 = map[maxFace->getVert( 2 )];
Point3 interp = sc.BarycentricCoords();
val.x = interp.x * p0.x + interp.y * p1.x + interp.z * p2.x;
val.y = interp.x * p0.y + interp.y * p1.y + interp.z * p2.y;
val.z = interp.x * p0.z + interp.y * p1.z + interp.z * p2.z;
return;
}
}
// No value defined... set default.
if (channel == MAP_SHADING)
val.x = val.y = val.z = 0.0f;
else
val.x = val.y = val.z = 1.0f;
}
void plPassMtl::Shade(ShadeContext& sc)
{
// Get the background color
Color backColor, backTrans;
sc.GetBGColor(backColor, backTrans);
ShadeWithBackground(sc, backColor);
}
//// Requirements ////////////////////////////////////////////////////////////
// Tells MAX what we need to render ourselves properly, such as translucency,
// two-sidedness, etc. Flags are in imtl.h in the MAX SDK.
ULONG plPassMtl::Requirements( int subMtlNum )
{
ULONG req = 0;
req = Mtl::Requirements( subMtlNum );
// Uncomment this to get the background color fed to our ShadeWithBackground()
// (slower processing tho)
//req |= MTLREQ_BGCOL;
req |= MTLREQ_UV;
int blendType = fLayersPB->GetInt( kPassLayOutputBlend );
if( blendType == kBlendAdd )
req |= MTLREQ_ADDITIVE_TRANSP | MTLREQ_TRANSP;
else if( blendType == kBlendAlpha )
req |= MTLREQ_TRANSP;
else if( fBasicPB->GetInt( kPassBasOpacity, 0 ) != 100 )
req |= MTLREQ_TRANSP;
if( fAdvPB->GetInt( kPBAdvTwoSided ) )
req |= MTLREQ_2SIDE;
if (req & MTLREQ_FACEMAP)
{
int i = 0;
}
return req;
}
void plPassMtl::ShadeWithBackground(ShadeContext &sc, Color background, bool useVtxAlpha /* = true */)
{
#if 1
// old
#if 0
Color lightCol,rescol, diffIllum0;
RGBA mval;
Point3 N0,P;
BOOL bumped = FALSE;
int i;
if (gbufID)
sc.SetGBufferID(gbufID);
if (sc.mode == SCMODE_SHADOW) {
float opac = 0.0;
for (i=0; i < NumSubTexmaps(); i++) {
if (SubTexmapOn(i)) {
hsMaxLayerBase *hsmLay = (hsMaxLayerBase *)GetSubTexmap(i);
opac += hsmLay->GetOpacity(t);
}
}
float f = 1.0f - opac;
sc.out.t = Color(f,f,f);
return;
}
N0 = sc.Normal();
P = sc.P();
#endif
TimeValue t = sc.CurTime();
Color color(0, 0, 0);
float alpha = 0.0;
// Evaluate Base layer
Texmap *map = fLayersPB->GetTexmap(kPassLayBase);
if (map && ( map->ClassID() == LAYER_TEX_CLASS_ID
|| map->ClassID() == STATIC_ENV_LAYER_CLASS_ID ) )
{
plLayerTex *layer = (plLayerTex*)map;
AColor evalColor = layer->EvalColor(sc);
color = evalColor;
alpha = evalColor.a;
}
// Evaluate Top layer, if it's on
if (fLayersPB->GetInt(kPassLayTopOn))
{
Texmap *map = fLayersPB->GetTexmap(kPassLayTop);
if (map && ( map->ClassID() == LAYER_TEX_CLASS_ID
|| map->ClassID() == STATIC_ENV_LAYER_CLASS_ID
|| map->ClassID() == ANGLE_ATTEN_LAYER_CLASS_ID) )
{
plPlasmaMAXLayer *layer = (plPlasmaMAXLayer*)map;
AColor evalColor = layer->EvalColor(sc);
// Blend layers
if( !layer->DiscardColor() )
{
int blendType = fLayersPB->GetInt(kPassLayBlend);
switch (blendType)
{
case kBlendAdd:
color += evalColor * evalColor.a;
break;
case kBlendAlpha:
color = (1.0f - evalColor.a) * color + evalColor.a * evalColor;
break;
case kBlendMult:
color *= evalColor;
break;
default: // No blend...
color = evalColor;
break;
}
}
if( !layer->DiscardAlpha() )
{
int alphaType = fLayersPB->GetInt(kPassLayOutputBlend);
switch( alphaType )
{
case kAlphaMultiply:
alpha *= evalColor.a;
break;
case kAlphaAdd:
alpha += evalColor.a;
break;
case kAlphaDiscard:
default:
break;
}
}
}
}
#if 1
AColor black;
black.Black();
AColor white;
white.White();
SIllumParams ip;
if (fBasicPB->GetInt(kPassBasEmissive))
{
// Emissive objects don't get shaded
ip.diffIllum = fBasicPB->GetColor(kPassBasColorAmb, t) * color;
ip.diffIllum.ClampMinMax();
ip.specIllum = black;
}
else
{
//
// Shading setup
//
// Setup the parameters for the shader
ip.amb = fBasicPB->GetColor(kPassBasColorAmb, t);
ip.diff = fBasicPB->GetColor(kPassBasColor, t) * color;
ip.diffIllum = black;
ip.specIllum = black;
ip.N = sc.Normal();
ip.V = sc.V();
//
// Specularity
//
if (fBasicPB->GetInt(kPassBasUseSpec, t))
{
ip.sh_str = 1.f;
ip.spec = fBasicPB->GetColor( kPassBasSpecColor, t );
ip.ph_exp = (float)pow(2.0f,float(fBasicPB->GetInt(kPassBasShine, t)) / 10.0f);
ip.shine = float(fBasicPB->GetInt(kPassBasShine, t)) / 100.0f;
}
else
{
ip.spec = black;
ip.sh_str = 0;
ip.ph_exp = 0;
ip.shine = 0;
}
ip.softThresh = 0;
//
// Do the shading
Shader *myShader = GetShader(SHADER_BLINN);
myShader->Illum(sc, ip);
// Override shader parameters
if (fAdvPB->GetInt(kPBAdvNoShade))
{
ip.diffIllum = black;
ip.specIllum = black;
}
if (fAdvPB->GetInt(kPBAdvWhite))
{
ip.diffIllum = white;
ip.specIllum = black;
}
ip.specIllum.ClampMinMax();
ip.diffIllum = ip.amb * sc.ambientLight + ip.diff * ip.diffIllum;
ip.diffIllum.ClampMinMax();
}
// AColor returnColor = AColor(opac * ip.diffIllum + ip.specIllum, opac)
#endif
// Get opacity and combine with alpha
float opac = float(fBasicPB->GetInt(kPassBasOpacity, t)) / 100.0f;
alpha *= opac;
float vtxAlpha = 1.0f;
if (useVtxAlpha && GetOutputBlend() == plPassMtlBase::kBlendAlpha)
{
Point3 p;
GetInterpVtxValue(MAP_ALPHA, sc, p);
vtxAlpha = p.x;
}
alpha *= vtxAlpha;
// MAX will do the additive/alpha/no blending for us based on what Requirements()
// we tell it. However, since MAX's formula is bgnd*sc.out.t + sc.out.c,
// we have to multiply our output color by the alpha.
// If we ever need a more complicated blending function, you can request the
// background color via Requirements() (otherwise it's just black) and then do
// the blending yourself; however, if the transparency isn't set, the shadows
// will be opaque, so be careful.
Color outC = ip.diffIllum + ip.specIllum;
sc.out.c = ( outC * alpha );
sc.out.t = Color( 1.f - alpha, 1.f - alpha, 1.f - alpha );
#endif
}
float plPassMtl::EvalDisplacement(ShadeContext& sc)
{
return 0.0f;
}
Interval plPassMtl::DisplacementValidity(TimeValue t)
{
Interval iv;
iv.SetInfinite();
return iv;
}
bool plPassMtl::HasAlpha()
{
return ((plLayerTex *)fLayersPB->GetTexmap(kPassLayBase))->HasAlpha();
}
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
int plPassMtl::GetBasicWire() { return fAdvPB->GetInt(kPBAdvWire); }
int plPassMtl::GetMeshOutlines() { return fAdvPB->GetInt(kPBAdvMeshOutlines); }
int plPassMtl::GetTwoSided() { return fAdvPB->GetInt(kPBAdvTwoSided); }
int plPassMtl::GetSoftShadow() { return fAdvPB->GetInt(kPBAdvSoftShadow); }
int plPassMtl::GetNoProj() { return fAdvPB->GetInt(kPBAdvNoProj); }
int plPassMtl::GetVertexShade() { return fAdvPB->GetInt(kPBAdvVertexShade); }
int plPassMtl::GetNoShade() { return fAdvPB->GetInt(kPBAdvNoShade); }
int plPassMtl::GetNoFog() { return fAdvPB->GetInt(kPBAdvNoFog); }
int plPassMtl::GetWhite() { return fAdvPB->GetInt(kPBAdvWhite); }
int plPassMtl::GetZOnly() { return fAdvPB->GetInt(kPBAdvZOnly); }
int plPassMtl::GetZClear() { return fAdvPB->GetInt(kPBAdvZClear); }
int plPassMtl::GetZNoRead() { return fAdvPB->GetInt(kPBAdvZNoRead); }
int plPassMtl::GetZNoWrite() { return fAdvPB->GetInt(kPBAdvZNoWrite); }
int plPassMtl::GetZInc() { return fAdvPB->GetInt(kPBAdvZInc); }
int plPassMtl::GetAlphaTestHigh() { return fAdvPB->GetInt(kPBAdvAlphaTestHigh); }
// Animation block
char * plPassMtl::GetAnimName() { return fAnimPB->GetStr(kPBAnimName); }
int plPassMtl::GetAutoStart() { return fAnimPB->GetInt(kPBAnimAutoStart); }
int plPassMtl::GetLoop() { return fAnimPB->GetInt(kPBAnimLoop); }
char * plPassMtl::GetAnimLoopName() { return fAnimPB->GetStr(kPBAnimLoopName); }
int plPassMtl::GetEaseInType() { return fAnimPB->GetInt(kPBAnimEaseInType); }
float plPassMtl::GetEaseInNormLength() { return fAnimPB->GetFloat(kPBAnimEaseInLength); }
float plPassMtl::GetEaseInMinLength() { return fAnimPB->GetFloat(kPBAnimEaseInMin); }
float plPassMtl::GetEaseInMaxLength() { return fAnimPB->GetFloat(kPBAnimEaseInMax); }
int plPassMtl::GetEaseOutType() { return fAnimPB->GetInt(kPBAnimEaseOutType); }
float plPassMtl::GetEaseOutNormLength() { return fAnimPB->GetFloat(kPBAnimEaseOutLength); }
float plPassMtl::GetEaseOutMinLength() { return fAnimPB->GetFloat(kPBAnimEaseOutMin); }
float plPassMtl::GetEaseOutMaxLength() { return fAnimPB->GetFloat(kPBAnimEaseOutMax); }
int plPassMtl::GetUseGlobal() { return fAnimPB->GetInt(ParamID(kPBAnimUseGlobal)); }
char * plPassMtl::GetGlobalVarName() { return fAnimPB->GetStr(ParamID(kPBAnimGlobalName)); }
// Basic block
int plPassMtl::GetColorLock() { return fBasicPB->GetInt(kPassBasColorLock); }
Color plPassMtl::GetAmbColor() { return fBasicPB->GetColor(kPassBasColorAmb); }
Color plPassMtl::GetColor() { return fBasicPB->GetColor(kPassBasColor); }
int plPassMtl::GetOpacity() { return fBasicPB->GetInt(kPassBasOpacity); }
int plPassMtl::GetEmissive() { return fBasicPB->GetInt(kPassBasEmissive); }
int plPassMtl::GetUseSpec() { return fBasicPB->GetInt(kPassBasUseSpec); }
int plPassMtl::GetShine() { return fBasicPB->GetInt(kPassBasShine); }
Color plPassMtl::GetSpecularColor() { return fBasicPB->GetColor(kPassBasSpecColor); }
int plPassMtl::GetDiffuseColorLock() { return fBasicPB->GetInt(kPassBasDiffuseLock); }
Color plPassMtl::GetRuntimeColor() { return fBasicPB->GetColor(kPassBasRunColor); }
Control *plPassMtl::GetPreshadeColorController() { return fBasicPB->GetController(ParamID(kPassBasColor)); }
Control *plPassMtl::GetAmbColorController() { return fBasicPB->GetController(ParamID(kPassBasColorAmb)); }
Control *plPassMtl::GetOpacityController() { return fBasicPB->GetController(ParamID(kPassBasOpacity)); }
Control *plPassMtl::GetSpecularColorController() { return fBasicPB->GetController(ParamID(kPassBasSpecColor)); }
Control *plPassMtl::GetRuntimeColorController() { return fBasicPB->GetController(ParamID(kPassBasRunColor)); }
// Layer block
Texmap *plPassMtl::GetBaseLayer() { return fLayersPB->GetTexmap(kPassLayBase); }
int plPassMtl::GetTopLayerOn() { return fLayersPB->GetInt(kPassLayTopOn); }
Texmap *plPassMtl::GetTopLayer() { return fLayersPB->GetTexmap(kPassLayTop); }
int plPassMtl::GetLayerBlend() { return fLayersPB->GetInt(kPassLayBlend); }
int plPassMtl::GetOutputAlpha() { return fLayersPB->GetInt(kPassLayOutputAlpha); }
int plPassMtl::GetOutputBlend() { return fLayersPB->GetInt(kPassLayOutputBlend); }

View File

@ -0,0 +1,197 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTL_H
#define PL_PASSMTL_H
#include "Max.h"
//#include "istdplug.h"
#include "iparamb2.h"
//#include "iparamm2.h"
#include "../resource.h"
#include "plPassMtlBase.h"
#include "hsTemplates.h"
#define PASS_MTL_CLASS_ID Class_ID(0x42b6718f, 0x2d579b35)
extern TCHAR *GetString(int id);
class plPassMtl : public plPassMtlBase
{
protected:
virtual void ICloneRefs( plPassMtlBase *target, RemapDir &remap );
public:
enum RefIDs
{
kRefBasic,
kRefAdv,
kRefLayers,
kRefAnim,
};
enum Blocks
{
kBlkBasic,
kBlkAdv,
kBlkLayers,
kBlkAnim,
};
plPassMtl(BOOL loading);
virtual ~plPassMtl();
void DeleteThis() { delete this; }
//From Animatable
Class_ID ClassID() { return PASS_MTL_CLASS_ID; }
SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
void GetClassName(TSTR& s) { s = GetString(IDS_PASS_MTL); }
ParamDlg *CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
void Update(TimeValue t, Interval& valid);
Interval Validity(TimeValue t);
void NotifyChanged();
BOOL SupportsMultiMapsInViewport() { return FALSE; }
void SetupGfxMultiMaps(TimeValue t, Material *mtl, MtlMakerCallback &cb);
// Shade and displacement calculation
static void GetInterpVtxValue(int channel, ShadeContext &sc, Point3 &interpVal);
void Shade(ShadeContext& sc);
void ShadeWithBackground(ShadeContext &sc, Color background, bool useVtxAlpha = true);
float EvalDisplacement(ShadeContext& sc);
Interval DisplacementValidity(TimeValue t);
virtual RefTargetHandle GetReference( int i );
virtual void SetReference( int i, RefTargetHandle rtarg );
// SubTexmap access methods
int NumSubTexmaps();
Texmap* GetSubTexmap(int i);
void SetSubTexmap(int i, Texmap *m);
TSTR GetSubTexmapSlotName(int i);
TSTR GetSubTexmapTVName(int i);
int SubTexmapOn(int i);
BOOL SetDlgThing(ParamDlg* dlg);
RefTargetHandle Clone( RemapDir &remap );
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
PartID& partID, RefMessage message);
int NumSubs();
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
int NumParamBlocks();
IParamBlock2* GetParamBlock(int i);
IParamBlock2* GetParamBlockByID(BlockID id);
// void SetParamDlg(ParamDlg *dlg);
// void SetNumSubTexmaps(int num);
// From MtlBase and Mtl
void SetAmbient(Color c, TimeValue t);
void SetDiffuse(Color c, TimeValue t);
void SetSpecular(Color c, TimeValue t);
void SetShininess(float v, TimeValue t);
Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE);
Color GetDiffuse(int mtlNum=0, BOOL backFace=FALSE);
Color GetSpecular(int mtlNum=0, BOOL backFace=FALSE);
float GetXParency(int mtlNum=0, BOOL backFace=FALSE);
float GetShininess(int mtlNum=0, BOOL backFace=FALSE);
float GetShinStr(int mtlNum=0, BOOL backFace=FALSE);
float WireSize(int mtlNum=0, BOOL backFace=FALSE);
ULONG Requirements( int subMtlNum );
virtual bool HasAlpha();
// Massive list of inherited accessor functions for ParamBlock data
// Advanced Block
virtual int GetBasicWire();
virtual int GetMeshOutlines();
virtual int GetTwoSided();
virtual int GetSoftShadow();
virtual int GetNoProj();
virtual int GetVertexShade();
virtual int GetNoShade();
virtual int GetNoFog();
virtual int GetWhite();
virtual int GetZOnly();
virtual int GetZClear();
virtual int GetZNoRead();
virtual int GetZNoWrite();
virtual int GetZInc();
virtual int GetAlphaTestHigh();
// Animation block
virtual char * GetAnimName();
virtual int GetAutoStart();
virtual int GetLoop();
virtual char * GetAnimLoopName();
virtual int GetEaseInType();
virtual float GetEaseInMinLength();
virtual float GetEaseInMaxLength();
virtual float GetEaseInNormLength();
virtual int GetEaseOutType();
virtual float GetEaseOutMinLength();
virtual float GetEaseOutMaxLength();
virtual float GetEaseOutNormLength();
virtual int GetUseGlobal();
virtual char * GetGlobalVarName();
// Basic block
virtual int GetColorLock();
virtual Color GetAmbColor();
virtual Color GetColor();
virtual int GetOpacity();
virtual int GetEmissive();
virtual int GetUseSpec();
virtual int GetShine();
virtual Color GetSpecularColor();
virtual Control *GetPreshadeColorController();
virtual Control *GetAmbColorController();
virtual Control *GetOpacityController();
virtual Control *GetSpecularColorController();
virtual int GetDiffuseColorLock();
virtual Color GetRuntimeColor();
virtual Control *GetRuntimeColorController();
// Layer block
virtual Texmap *GetBaseLayer();
virtual int GetTopLayerOn();
virtual Texmap *GetTopLayer();
virtual int GetLayerBlend();
virtual int GetOutputAlpha();
virtual int GetOutputBlend();
};
#endif //PL_PASSMTL_H

View File

@ -0,0 +1,59 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTLADVPB_H
#define PL_PASSMTLADVPB_H
// Param ID's
enum
{
// Specular
kPassAdvUseSpec, // Not used anymore, feel free to replace with new fields as necessary
kPassAdvSpecType, // ditto
kPassAdvShine, // ...
kPassAdvShineStr, // ...
// Misc
kPassAdvWire,
kPassAdvMeshOutlines,
kPassAdvTwoSided,
// Shading
kPassAdvSoftShadow,
kPassAdvNoProj,
kPassAdvVertexShade,
kPassAdvNoShade,
kPassAdvNoFog,
kPassAdvWhite,
// Z
kPassAdvZOnly,
kPassAdvZClear,
kPassAdvZNoRead,
kPassAdvZNoWrite,
kPassAdvZInc,
};
#endif //PL_PASSMTLADVPB_H

View File

@ -0,0 +1,94 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plPassMtl.h"
#include "plPassBaseParamIDs.h"
using namespace plPassBaseParamIDs;
static ParamBlockDesc2 gPassAdvPB
(
plPassMtl::kBlkAdv, _T("advanced"), IDS_PASS_ADV, GetPassMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI, plPassMtl::kRefAdv,
// UI
IDD_PASS_ADV, IDS_PASS_ADV, 0, APPENDROLL_CLOSED, NULL,
// Misc Properties
kPBAdvWire, _T("basicWire"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_WIRE,
end,
kPBAdvMeshOutlines, _T("meshOutlines"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_MESHOUTLINES,
end,
kPBAdvTwoSided, _T("twoSided"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_MISC_TWOSIDED,
end,
// Shade properties
kPBAdvSoftShadow, _T("softShadow"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_SOFTSHADOW,
end,
kPBAdvNoProj, _T("noProj"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NO_PROJ,
end,
kPBAdvVertexShade, _T("vertexShade"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_VERTEXSHADE,
end,
kPBAdvNoShade, _T("noShade"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NOSHADE,
end,
kPBAdvNoFog, _T("noFog"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_NO_FOG,
end,
kPBAdvWhite, _T("white"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_WHITE,
end,
// Z Properties
kPBAdvZOnly, _T("zOnly"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZONLY,
end,
kPBAdvZClear, _T("zClear"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZCLEAR,
end,
kPBAdvZNoRead, _T("zNoRead"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZNOREAD,
end,
kPBAdvZNoWrite, _T("zNoWrite"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_ZNOWRITE,
end,
kPBAdvZInc, _T("zInc"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_Z_INC,
end,
kPBAdvAlphaTestHigh, _T("aTestHigh"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_ALPHA_TEST_HIGH,
p_default, FALSE,
end,
end
);
ParamBlockDesc2 *GetPassAdvPB() { return &gPassAdvPB; }

View File

@ -0,0 +1,85 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTLANIMPB_H
#define PL_PASSMTLANIMPB_H
enum { kPassAnimMain, kPassAnimEase };
#define WM_ROLLOUT_OPEN WM_USER+1
class plAnimEaseDlgProc : public ParamMap2UserDlgProc
{
protected:
void EnableStopPoints(IParamMap2 *pm, bool enable)
{
pm->Enable(kPassEaseInMin, enable);
pm->Enable(kPassEaseInMax, enable);
pm->Enable(kPassEaseOutMin, enable);
pm->Enable(kPassEaseOutMax, enable);
}
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
IParamBlock2 *pb = map->GetParamBlock();
bool stopPoints = false;
if (DoesHaveStopPoints(pb->GetOwner()))
{
stopPoints = true;
break;
}
EnableStopPoints(map, stopPoints);
// If we're doing an ease, set the ease rollup to open
// if (pb->GetInt(kPassEaseInType) != plAnimEaseTypes::kNoEase ||
// pb->GetInt(kPassEaseOutType) != plAnimEaseTypes::kNoEase)
// PostMessage(hWnd, WM_ROLLOUT_OPEN, 0, 0);
}
return TRUE;
// Max doesn't know about the rollup until after WM_CREATE, so we get
// around it by posting a message
//case WM_ROLLOUT_OPEN:
// {
// IRollupWindow *rollup = GetCOREInterface(MTLEDIT_INTERFACE)->GetCommandPanelRollup();
// int idx = rollup->GetPanelIndex(hWnd);
// rollup->SetPanelOpen(idx, TRUE);
// }
// return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
#endif

View File

@ -0,0 +1,95 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plPassMtl.h"
#include "plPassBaseParamIDs.h"
#include "resource.h"
#include "iparamm2.h"
#include "plPassAnimDlgProc.h"
#include "plAnimStealthNode.h"
using namespace plPassBaseParamIDs;
static ParamBlockDesc2 gPassAnimPB
(
plPassMtl::kBlkAnim, _T("anim"), IDS_PASS_ANIM, GetPassMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI + P_CALLSETS_ON_LOAD, plPassMtl::kRefAnim,
// UI
IDD_PASS_ANIM, IDS_PASS_ANIM, 0, 0, &plPassAnimDlgProc::Get(),
#ifdef MCN_UPGRADE_OLD_ANIM_BLOCKS
// THE FOLLOWING ARE ALL OLD PARAMETERS AND SHOULD NO LONGER BE USED. The only reason
// they're here is so we can convert old paramBlocks into the new plAnimStealthNode format
kPBAnimName, _T("animName"), TYPE_STRING, 0, 0,
end,
kPBAnimAutoStart, _T("autoStart"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoop, _T("loop"), TYPE_BOOL, 0, 0,
end,
kPBAnimLoopName, _T("loopName"), TYPE_STRING, 0, 0,
end,
// Anim Ease
kPBAnimEaseInType, _T("easeInType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseInLength, _T("easeInLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMin, _T("easeInMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseInMax, _T("easeInMax"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutType, _T("easeOutType"), TYPE_INT, 0, 0,
end,
kPBAnimEaseOutLength, _T("easeOutLength"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMin, _T("easeOutMin"), TYPE_FLOAT, 0, 0,
end,
kPBAnimEaseOutMax, _T("easeOutMax"), TYPE_FLOAT, 0, 0,
end,
#endif // MCN_UPGRADE_OLD_ANIM_BLOCKS
kPBAnimUseGlobal, _T("UseGlobal"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_MTL_USE_GLOBAL,
end,
kPBAnimGlobalName, _T("GlobalName"), TYPE_STRING, 0, 0,
p_default, _T(""),
end,
kPBAnimStealthNodes, _T( "testing" ), TYPE_REFTARG_TAB, 0, 0, 0,
p_accessor, &plStealthNodeAccessor::GetInstance(),
end,
end
);
ParamBlockDesc2 *GetPassAnimPB() { return &gPassAnimPB; }

View File

@ -0,0 +1,660 @@
/*==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/>.
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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plPassMtlBase - Base class for all Plasma MAX materials //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "hsBitVector.h"
#include "Max.h"
#include "iparamb2.h"
#include "notify.h"
#include "notetrck.h"
#include "plPassMtlBase.h"
#include "plPassBaseParamIDs.h"
#include "plNoteTrackWatcher.h"
#include "plAnimStealthNode.h"
#include "../MaxComponent/plMaxAnimUtils.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
// For converting from a MAX Mtl
#include "plPassMtl.h"
#include "plBumpMtl.h"
#include "plDecalMtl.h"
using namespace plPassBaseParamIDs;
IMtlParams *plPassMtlBase::fIMtlParams = nil;
//// plPostLoadHandler ///////////////////////////////////////////////////////
// Small class to keep track of all the materials to update after load
class plPostLoadHandler
{
static bool fLoading;
static hsTArray<plPassMtlBase *> fPostLoads;
public:
static bool IsLoading() { return fLoading; }
static void PostLoadFixupFunction( void *param, NotifyInfo *info )
{
fLoading = false;
for( int i = 0; i < fPostLoads.GetCount(); i++ )
fPostLoads[ i ]->PostLoadAnimPBFixup();
fPostLoads.Reset();
UnRegisterNotification( PostLoadFixupFunction, param, NOTIFY_FILE_POST_OPEN );
UnRegisterNotification( PostLoadFixupFunction, param, NOTIFY_FILE_POST_MERGE );
}
static void AddPostLoad( plPassMtlBase *mtl )
{
fLoading = true;
if( fPostLoads.GetCount() == 0 )
{
RegisterNotification( PostLoadFixupFunction, mtl, NOTIFY_FILE_POST_OPEN );
RegisterNotification( PostLoadFixupFunction, mtl, NOTIFY_FILE_POST_MERGE );
}
mtl->SetLoadingFlag( true );
fPostLoads.Append( mtl );
}
static void RemovePostLoad( plPassMtlBase *mtl )
{
for( int i = 0; i < fPostLoads.GetCount(); i++ )
{
if( fPostLoads[ i ] == mtl )
{
fPostLoads.Remove( i );
break;
}
}
}
};
hsTArray<plPassMtlBase *> plPostLoadHandler::fPostLoads;
bool plPostLoadHandler::fLoading = false;
plPassMtlBase::plPassMtlBase( BOOL loading ) : fNTWatcher( nil ), fBasicPB(NULL), fAdvPB(NULL), fLayersPB(NULL), fAnimPB(NULL),
fLoading( loading )
{
fNTWatcher = TRACKED_NEW plNoteTrackWatcher( this );
Reset();
}
plPassMtlBase::~plPassMtlBase()
{
if( fLoading )
plPostLoadHandler::RemovePostLoad( this );
// Force the watcher's parent pointer to nil, otherwise the de-ref will attempt to re-delete us
fNTWatcher->SetReference( plNoteTrackWatcher::kRefParentMtl, nil );
delete fNTWatcher;
fNTWatcher = nil;
// Manually delete our notetrack refs, otherwise there'll be hell to pay
for( int i = 0; i < fNotetracks.GetCount(); i++ )
{
if( fNotetracks[ i ] != nil )
DeleteReference( kRefNotetracks + i );
}
}
void plPassMtlBase::Reset( void )
{
fIValid.SetEmpty();
}
//// Stealth Accessors ///////////////////////////////////////////////////////
int plPassMtlBase::GetNumStealths( void )
{
return IGetNumStealths( true );
}
plAnimStealthNode *plPassMtlBase::GetStealth( int index )
{
return IGetStealth( index, false );
}
int plPassMtlBase::IGetNumStealths( hsBool update )
{
if( update )
IUpdateAnimNodes();
return fAnimPB->Count( (ParamID)kPBAnimStealthNodes );
}
plAnimStealthNode *plPassMtlBase::IGetStealth( int index, hsBool update )
{
if( update )
IUpdateAnimNodes();
return (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, index );
}
plAnimStealthNode *plPassMtlBase::IFindStealth( const char *segmentName )
{
int i;
for( i = 0; i < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); i++ )
{
plAnimStealthNode *node = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, i );
const char *name = node->GetSegmentName();
if( node != nil && strcmp( name, segmentName ) == 0 )
{
return node;
}
}
return nil;
}
//// IVerifyStealthPresent ///////////////////////////////////////////////////
// Ensures that we have a stealth for the given segment.
plAnimStealthNode *plPassMtlBase::IVerifyStealthPresent( const char *animName )
{
// If we're in the middle of loading, don't check
if (plPostLoadHandler::IsLoading())
return nil;
plAnimStealthNode *stealth = IFindStealth( animName );
if( stealth == nil )
{
// New segment, add a new stealth node
stealth = (plAnimStealthNode *)GetCOREInterface()->CreateInstance( HELPER_CLASS_ID, ANIMSTEALTH_CLASSID );
INode *node = GetCOREInterface()->CreateObjectNode( stealth );
stealth->SetSegment( ( strcmp(animName, ENTIRE_ANIMATION_NAME) != 0 ) ? animName : nil );
stealth->SetNodeName( GetName() );
node->Freeze( true );
// Skip the attach, since we might not find a valid INode. This will leave the node attached to the scene
// root, which is fine. Since we just care about it being SOMEWHERE in the scene hierarchy
/*
if( fAnimPB->Count( (ParamID)kPBAnimStealthNodes ) > 0 )
{
plAnimStealthNode *first = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, 0 );
first->GetINode()->AttachChild( node );
}
*/
fAnimPB->Append( (ParamID)kPBAnimStealthNodes, 1, (ReferenceTarget **)&stealth );
const char *realName = stealth->GetSegmentName();
fStealthsChanged = true;
}
else
{
// Exists already, we're ok
stealth->SetParentMtl( this );
}
return stealth;
}
//// Change Callbacks ////////////////////////////////////////////////////////
void plPassMtlBase::RegisterChangeCallback( plMtlChangeCallback *callback )
{
if( fChangeCallbacks.Find( callback ) == fChangeCallbacks.kMissingIndex )
fChangeCallbacks.Append( callback );
}
void plPassMtlBase::UnregisterChangeCallback( plMtlChangeCallback *callback )
{
int idx = fChangeCallbacks.Find( callback );
if( idx != fChangeCallbacks.kMissingIndex )
fChangeCallbacks.Remove( idx );
}
//// IUpdateAnimNodes ////////////////////////////////////////////////////////
// Updates the list of stealth nodes in the anim paramBlock to match our
// list of anim segments.
void plPassMtlBase::IUpdateAnimNodes( void )
{
// Our beautiful hack, to make sure we don't update until we actually are loaded
if( fLoading )
return;
SegmentMap *segMap = GetAnimSegmentMap( this, nil );
hsTArray<plAnimStealthNode *> goodNodes;
// Keep track of whether we change anything
fStealthsChanged = false;
// Verify one for "entire animation"
plAnimStealthNode *stealth = IVerifyStealthPresent( ENTIRE_ANIMATION_NAME );
goodNodes.Append( stealth );
// Verify segment nodes
if( segMap != nil )
{
for( SegmentMap::iterator i = segMap->begin(); i != segMap->end(); i++ )
{
SegmentSpec *spec = (*i).second;
if( spec->fType == SegmentSpec::kAnim )
{
plAnimStealthNode *stealth = IVerifyStealthPresent( spec->fName );
goodNodes.Append( stealth );
}
}
DeleteSegmentMap( segMap );
}
// Remove nodes that no longer have segments
int idx;
for( idx = 0; idx < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); )
{
plAnimStealthNode *node = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, idx );
if( node != nil && goodNodes.Find( node ) == goodNodes.kMissingIndex )
{
fAnimPB->Delete( (ParamID)kPBAnimStealthNodes, idx, 1 );
// GetCOREInterface()->DeleteNode( node->GetINode() );
fStealthsChanged = true;
}
else
idx++;
}
if( fStealthsChanged )
{
// Yup, our list of stealths got updated. Notify everyone of such.
for( idx = 0; idx < fChangeCallbacks.GetCount(); idx++ )
fChangeCallbacks[ idx ]->SegmentListChanged();
}
}
//// NameChanged /////////////////////////////////////////////////////////////
// Notify from NTWatcher so we can update the names of our stealth nodes
void plPassMtlBase::NameChanged( void )
{
for( int idx = 0; idx < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); idx++ )
{
plAnimStealthNode *node = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, idx );
if( node != nil )
node->SetNodeName( GetName() );
}
}
//// NoteTrackAdded/Removed //////////////////////////////////////////////////
// Notifies from NTWatcher so we can update our list of stealths
void plPassMtlBase::NoteTrackAdded( void )
{
int i;
// Make a ref to our new notetrack
for( i = 0; i < NumNoteTracks(); i++ )
{
NoteTrack *track = GetNoteTrack( i );
if( fNotetracks.Find( track ) == fNotetracks.kMissingIndex )
{
MakeRefByID( FOREVER, kRefNotetracks + fNotetracks.GetCount(), track );
break;
}
}
for( i = 0; i < fChangeCallbacks.GetCount(); i++ )
fChangeCallbacks[ i ]->NoteTrackListChanged();
IUpdateAnimNodes();
}
void plPassMtlBase::NoteTrackRemoved( void )
{
int i;
hsBitVector stillThere;
// Make a ref to our new notetrack
for( i = 0; i < NumNoteTracks(); i++ )
{
NoteTrack *track = GetNoteTrack( i );
int idx = fNotetracks.Find( track );
if( idx != fNotetracks.kMissingIndex )
stillThere.Set( idx );
}
for( i = 0; i < fNotetracks.GetCount(); i++ )
{
if( !stillThere.IsBitSet( i ) && fNotetracks[ i ] != nil )
{
// DeleteReference( kRefNotetracks + i );
SetReference( kRefNotetracks + i, nil );
}
}
for( i = 0; i < fChangeCallbacks.GetCount(); i++ )
fChangeCallbacks[ i ]->NoteTrackListChanged();
IUpdateAnimNodes();
}
//////////////////////////////////////////////////////////////////////////////
//// MAX Ref Stuff ///////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// NumRefs /////////////////////////////////////////////////////////////////
int plPassMtlBase::NumRefs()
{
return 4 + fNotetracks.GetCount();
}
//// GetReference ////////////////////////////////////////////////////////////
RefTargetHandle plPassMtlBase::GetReference( int i )
{
if( i >= kRefNotetracks && i < kRefNotetracks + fNotetracks.GetCount() )
return fNotetracks[ i - kRefNotetracks ];
return NULL;
}
//// SetReference ////////////////////////////////////////////////////////////
void plPassMtlBase::SetReference(int i, RefTargetHandle rtarg)
{
if( i >= kRefNotetracks )
{
fNotetracks.ExpandAndZero(i - kRefNotetracks + 1);
fNotetracks[i - kRefNotetracks] = (NoteTrack*)rtarg;
}
}
//// NotifyRefChanged ////////////////////////////////////////////////////////
RefResult plPassMtlBase::NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget,
PartID &partID, RefMessage message )
{
switch( message )
{
case REFMSG_CHANGE:
fIValid.SetEmpty();
// see if this message came from a changing parameter in the pblock,
// if so, limit rollout update to the changing item
if (hTarget == fBasicPB || hTarget == fAdvPB || hTarget == fLayersPB || hTarget == fAnimPB)
{
IParamBlock2 *pb = (IParamBlock2*)hTarget;
ParamID changingParam = pb->LastNotifyParamID();
pb->GetDesc()->InvalidateUI( changingParam );
// And let the SceneWatcher know that the material on some of it's
// referenced objects changed.
NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_MAT );
}
else
{
// Was it a notetrack ref?
if( fNotetracks.Find( (NoteTrack *)hTarget ) != fNotetracks.kMissingIndex )
{
// Yup, so update our notetrack list
IUpdateAnimNodes();
}
}
break;
case REFMSG_TARGET_DELETED:
NoteTrackRemoved();
break;
}
return REF_SUCCEED;
}
//////////////////////////////////////////////////////////////////////////////
//// Standard IO (or non-standard, as the case may be) ///////////////////////
//////////////////////////////////////////////////////////////////////////////
//// PostLoadAnimPBFixup /////////////////////////////////////////////////////
// Takes the old version of the anim paramblock and translates it into the
// new version.
// Note that there's an interesting (?) side effect of this: for new materials,
// we'll incorrectly detect them as the "old" format and fix-up them as well.
// This means that we'll end up with the same defaults for (Entire Animation)
// that we had for the old materials. We can easily change the defaults by
// changing the defaults for the old paramblock though.
// Also, we go ahead and re-work the stealth parent pointers here, since it
// appears to be the ONLY time we can do it and have it reliably work. ARRGH!
//
// History of the options that we CAN'T do and why (and hence why this):
// - ParamBlock accessor doesn't work. For some reason, the accessor isn't
// always called on load, even with P_CALLSETS_ON_LOAD specified
// - Doing it on Load() doesn't work, because neither the ParamBlocks are
// guaranteed to be fully loaded (with their tabs filled) nor are the
// notetracks necessarily attached yet
// - Notetracks can also possibly be attached BEFORE load, which doesn't
// do us a damned bit of good, so we need to make sure we're fully
// loaded before we run this function. Unfortunately, the only time
// we're guaranteed THAT is by a FILE_POST_OPEN notify. (post-load
// callbacks don't work because they're called right after our object
// is loaded but not necessarily before the notetracks are attached)
void plPassMtlBase::PostLoadAnimPBFixup( void )
{
SetLoadingFlag( false );
#ifdef MCN_UPGRADE_OLD_ANIM_BLOCKS
if( fAnimPB->Count( (ParamID)kPBAnimStealthNodes ) == 0 )
{
// Yup, old style. So our update process looks like this:
// 1) Create stealths for all our segments as we are now
// 2) Set the parameters on all of them to our old defaults (no autostart,
// loop on entire, no ease).
// 3) Copy the old paramblock values to the single stealth indicated by
// the old PB
// Step 1...
IUpdateAnimNodes();
// Step 2...
for( int i = 0; i < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); i++ )
{
plAnimStealthNode *node = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, i );
const char *name = node->GetSegmentName();
node->SetAutoStart( false );
node->SetLoop( true, ENTIRE_ANIMATION_NAME );
node->SetEaseIn( plAnimEaseTypes::kNoEase, 1.f, 1.f, 1.f );
node->SetEaseOut( plAnimEaseTypes::kNoEase, 1.f, 1.f, 1.f );
}
// Step 3...
const char *oldSel = (const char *)fAnimPB->GetStr( (ParamID)kPBAnimName );
if( oldSel == nil )
oldSel = ENTIRE_ANIMATION_NAME;
plAnimStealthNode *myNew = IFindStealth( oldSel );
if( myNew != nil )
{
#pragma warning( push ) // Forcing value to bool true or false (go figure, i'm even explicitly casting)
#pragma warning( disable:4800 ) // Forcing value to bool true or false (go figure, i'm even explicitly casting)
myNew->SetAutoStart( (bool)fAnimPB->GetInt( (ParamID)kPBAnimAutoStart ) );
myNew->SetLoop( (bool)fAnimPB->GetInt( (ParamID)kPBAnimLoop ),
(char *)fAnimPB->GetStr( (ParamID)kPBAnimLoopName ) );
myNew->SetEaseIn( (UInt8)fAnimPB->GetInt( (ParamID)kPBAnimEaseInType ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseInLength ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseInMin ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseInMax ) );
myNew->SetEaseOut( (UInt8)fAnimPB->GetInt( (ParamID)kPBAnimEaseOutType ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseOutLength ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseOutMin ),
(hsScalar)fAnimPB->GetFloat( (ParamID)kPBAnimEaseOutMax ) );
#pragma warning( pop )
}
}
#endif // MCN_UPGRADE_OLD_ANIM_BLOCKS
// Make sure the parent is set tho. Note: we have to do this because, for some *(#$&(* reason,
// when we're loading a file, MAX can somehow add the stealths to our tab list WITHOUT calling
// the accessor for it (and the tab is empty on the CallSetsOnLoad() pass, for some reason).
for( int i = 0; i < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); i++ )
{
plAnimStealthNode *node = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, i );
node->SetParentMtl( this );
}
}
#define MTL_HDR_CHUNK 0x4000
//// Load ////////////////////////////////////////////////////////////////////
// Our actual MAX load function
IOResult plPassMtlBase::Load(ILoad *iload)
{
plPostLoadHandler::AddPostLoad( this );
IOResult res;
int id;
while (IO_OK==(res=iload->OpenChunk()))
{
switch(id = iload->CurChunkID())
{
case MTL_HDR_CHUNK:
res = MtlBase::Load(iload);
break;
}
iload->CloseChunk();
if (res!=IO_OK)
return res;
}
return IO_OK;
}
//// Save ////////////////////////////////////////////////////////////////////
// The MAX flip-side
IOResult plPassMtlBase::Save(ISave *isave)
{
IOResult res;
isave->BeginChunk(MTL_HDR_CHUNK);
res = MtlBase::Save(isave);
if (res!=IO_OK) return res;
isave->EndChunk();
return IO_OK;
}
//// ICloneBase //////////////////////////////////////////////////////////////
void plPassMtlBase::ICloneBase( plPassMtlBase *target, RemapDir &remap )
{
*((MtlBase*)target) = *((MtlBase*)this);
ICloneRefs( target, remap );
for( int idx = 0; idx < fAnimPB->Count( (ParamID)kPBAnimStealthNodes ); idx++ )
{
IParamBlock2 *pb = target->fAnimPB;
plAnimStealthNode *stealth = (plAnimStealthNode *)fAnimPB->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, idx );
pb->SetValue( (ParamID)kPBAnimStealthNodes, 0, remap.CloneRef( stealth ), idx );
stealth = (plAnimStealthNode *)pb->GetReferenceTarget( (ParamID)kPBAnimStealthNodes, 0, idx );
INode *node = GetCOREInterface()->CreateObjectNode( stealth );
stealth->SetNodeName( GetName() );
node->Freeze( true );
}
BaseClone(this, target, remap);
target->fIValid.SetEmpty();
}
//// ConvertToPassMtl ////////////////////////////////////////////////////////
// Static convert to our plPassMtlBase type, if possible
plPassMtlBase *plPassMtlBase::ConvertToPassMtl( Mtl *mtl )
{
if( mtl == nil )
return nil;
if( mtl->ClassID() == PASS_MTL_CLASS_ID
|| mtl->ClassID() == BUMP_MTL_CLASS_ID
|| mtl->ClassID() == DECAL_MTL_CLASS_ID )
{
return (plPassMtlBase *)mtl;
}
return nil;
}
//// SetupProperties /////////////////////////////////////////////////////////
hsBool plPassMtlBase::SetupProperties( plMaxNode *node, plErrorMsg *pErrMsg )
{
hsBool ret = true;
// Call SetupProperties on all our animStealths if we have any
int i, count = IGetNumStealths();
for( i = 0; i < count; i++ )
{
if( !IGetStealth( i, false )->SetupProperties( node, pErrMsg ) )
ret = false;
}
return ret;
}
//// ConvertDeInit ///////////////////////////////////////////////////////////
hsBool plPassMtlBase::ConvertDeInit( plMaxNode *node, plErrorMsg *pErrMsg )
{
hsBool ret = true;
// Call ConvertDeInit on all our animStealths if we have any
int i, count = IGetNumStealths();
for( i = 0; i < count; i++ )
{
if( !IGetStealth( i, false )->ConvertDeInit( node, pErrMsg ) )
ret = false;
}
return ret;
}

View File

@ -0,0 +1,285 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTLBASE_H
#define PL_PASSMTLBASE_H
#include "hsTemplates.h"
#include "Max.h"
#include "iparamb2.h"
#include "../../PubUtilLib/plInterp/plAnimEaseTypes.h"
class plNoteTrackWatcher;
class plMtlChangeCallback;
class plAnimStealthNode;
class NoteTrack;
class plPassAnimDlgProc;
class plStealthNodeAccessor;
class plMaxNode;
class plErrorMsg;
class plPassMtlBase : public Mtl
{
protected:
friend class plPassAnimDlgProc;
friend class plStealthNodeAccessor;
friend class plNoteTrackWatcher;
plNoteTrackWatcher *fNTWatcher;
IParamBlock2 *fBasicPB;
IParamBlock2 *fAdvPB;
IParamBlock2 *fLayersPB;
IParamBlock2 *fAnimPB;
Interval fIValid;
hsBool fLoading;
hsTArray<NoteTrack *> fNotetracks;
hsBool fStealthsChanged;
hsTArray<plMtlChangeCallback *> fChangeCallbacks;
void IUpdateAnimNodes( void );
plAnimStealthNode *IFindStealth( const char *animName );
plAnimStealthNode *IVerifyStealthPresent( const char *animName );
int IGetNumStealths( hsBool update = true );
plAnimStealthNode *IGetStealth( int index, hsBool update = true );
void ICloneBase( plPassMtlBase *target, RemapDir &remap );
virtual void ICloneRefs( plPassMtlBase *target, RemapDir &remap ) = 0;
public:
// mcn note: as far as I can tell, this is always the same pointer passed around to everyone.
// So since we have trouble getting it all the time, just store the first version we get and
// use that forever and ever
static IMtlParams *fIMtlParams;
plPassMtlBase( BOOL loading );
virtual ~plPassMtlBase();
virtual bool HasAlpha() = 0;
enum Refs
{
//kRefBasic, // Can't do this, long ago they were different in the "derived" classes,
//kRefAdv, // and even tho MAX says it doesn't write refs out by their index, it does
//kRefLayers,
//kRefAnim,
kRefNotetracks = 4 // MUST BE THE LAST REF ID SPECIFIED
};
void SetLoadingFlag( hsBool f ) { fLoading = f; }
void PostLoadAnimPBFixup( void );
void RegisterChangeCallback( plMtlChangeCallback *callback );
void UnregisterChangeCallback( plMtlChangeCallback *callback );
// Change notifys from our ntWatcher
virtual void NoteTrackAdded( void );
virtual void NoteTrackRemoved( void );
virtual void NameChanged( void );
// Loading/Saving
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
virtual void Reset( void );
int NumRefs();
virtual RefTargetHandle GetReference( int i );
virtual void SetReference( int i, RefTargetHandle rtarg );
RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget, PartID &partID, RefMessage message );
// Convert time, called on the setupProps pass for each material applied to a node in the scene
virtual hsBool SetupProperties( plMaxNode *node, plErrorMsg *pErrMsg );
virtual hsBool ConvertDeInit( plMaxNode *node, plErrorMsg *pErrMsg );
int GetNumStealths( void );
plAnimStealthNode *GetStealth( int index );
// Static convert to our plPassMtlBase type, if possible
static plPassMtlBase *ConvertToPassMtl( Mtl *mtl );
// Blend types
enum
{
kBlendNone,
kBlendAlpha,
kBlendAdd,
kBlendMult
};
// Alpha blend types
enum
{
kAlphaDiscard,
kAlphaMultiply,
kAlphaAdd
};
// Advanced Block
virtual int GetBasicWire() = 0;
virtual int GetMeshOutlines() = 0;
virtual int GetTwoSided() = 0;
virtual int GetSoftShadow() = 0;
virtual int GetNoProj() = 0;
virtual int GetVertexShade() = 0;
virtual int GetNoShade() = 0;
virtual int GetNoFog() = 0;
virtual int GetWhite() = 0;
virtual int GetZOnly() = 0;
virtual int GetZClear() = 0;
virtual int GetZNoRead() = 0;
virtual int GetZNoWrite() = 0;
virtual int GetZInc() = 0;
virtual int GetAlphaTestHigh() = 0;
// Animation block
virtual char * GetAnimName() = 0;
virtual int GetAutoStart() = 0;
virtual int GetLoop() = 0;
virtual char * GetAnimLoopName() = 0;
virtual int GetEaseInType() { return plAnimEaseTypes::kNoEase; }
virtual float GetEaseInMinLength() { return 1; }
virtual float GetEaseInMaxLength() { return 1; }
virtual float GetEaseInNormLength() { return 1; }
virtual int GetEaseOutType() { return plAnimEaseTypes::kNoEase; }
virtual float GetEaseOutMinLength() { return 1; }
virtual float GetEaseOutMaxLength() { return 1; }
virtual float GetEaseOutNormLength() { return 1; }
virtual char * GetGlobalVarName() { return NULL; }
virtual int GetUseGlobal() { return 0; }
// Basic block
virtual int GetColorLock() = 0;
virtual Color GetAmbColor() = 0;
virtual Color GetColor() = 0;
virtual int GetOpacity() = 0;
virtual int GetEmissive() = 0;
virtual int GetUseSpec() = 0;
virtual int GetShine() = 0;
virtual Color GetSpecularColor() = 0;
virtual int GetDiffuseColorLock() = 0;
virtual Color GetRuntimeColor() = 0;
virtual Control *GetPreshadeColorController() = 0;
virtual Control *GetAmbColorController() = 0;
virtual Control *GetOpacityController() = 0;
virtual Control *GetSpecularColorController() = 0;
virtual Control *GetRuntimeColorController() = 0;
// Layer block
virtual Texmap *GetBaseLayer() = 0;
virtual int GetTopLayerOn() = 0;
virtual Texmap *GetTopLayer() = 0;
virtual int GetLayerBlend() = 0;
virtual int GetOutputAlpha() = 0;
virtual int GetOutputBlend() = 0;
};
// Make sure min is less than normal, which is less than max
class plEaseAccessor : public PBAccessor
{
protected:
bool fDoingUpdate;
int fBlockID;
int fEaseInMinID, fEaseInMaxID, fEaseInNormID, fEaseOutMinID, fEaseOutMaxID, fEaseOutNormID;
void AdjustMin(IParamBlock2 *pb, ParamID minID, ParamID normalID, ParamID maxID, float value)
{
if (value > pb->GetFloat(normalID))
{
pb->SetValue(normalID, 0, value);
if (value > pb->GetFloat(maxID))
pb->SetValue(maxID, 0, value);
}
}
void AdjustNormal(IParamBlock2 *pb, ParamID minID, ParamID normalID, ParamID maxID, float value)
{
if (value < pb->GetFloat(minID))
pb->SetValue(minID, 0, value);
if (value > pb->GetFloat(maxID))
pb->SetValue(maxID, 0, value);
}
void AdjustMax(IParamBlock2 *pb, ParamID minID, ParamID normalID, ParamID maxID, float value)
{
if (value < pb->GetFloat(normalID))
{
pb->SetValue(normalID, 0, value);
if (value < pb->GetFloat(minID))
pb->SetValue(minID, 0, value);
}
}
public:
plEaseAccessor(int blockID, int easeInMinID, int easeInMaxID, int easeInNormID,
int easeOutMinID, int easeOutMaxID, int easeOutNormID)
{
fDoingUpdate = false;
fBlockID = blockID;
fEaseInMinID = easeInMinID; fEaseInMaxID = easeInMaxID; fEaseInNormID = easeInNormID;
fEaseOutMinID = easeOutMinID; fEaseOutMaxID = easeOutMaxID; fEaseOutNormID = easeOutNormID;
}
void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)
{
if (fDoingUpdate)
return;
fDoingUpdate = true;
IParamBlock2 *pb = owner->GetParamBlockByID(fBlockID);
if (id == fEaseInMinID)
AdjustMin(pb, fEaseInMinID, fEaseInNormID, fEaseInMaxID, v.f);
else if (id == fEaseInNormID)
AdjustNormal(pb, fEaseInMinID, fEaseInNormID, fEaseInMaxID, v.f);
else if (id == fEaseInMaxID)
AdjustMax(pb, fEaseInMinID, fEaseInNormID, fEaseInMaxID, v.f);
else if (id == fEaseOutMinID)
AdjustMin(pb, fEaseOutMinID, fEaseOutNormID, fEaseOutMaxID, v.f);
else if (id == fEaseOutNormID)
AdjustNormal(pb, fEaseOutMinID, fEaseOutNormID, fEaseOutMaxID, v.f);
else if (id == fEaseOutMaxID)
AdjustMax(pb, fEaseOutMinID, fEaseOutNormID, fEaseOutMaxID, v.f);
fDoingUpdate = false;
}
};
//// plMtlChangeCallback /////////////////////////////////////////////////////
// Interface class for receiving info about when things change on a material.
class plMtlChangeCallback
{
public:
virtual void NoteTrackListChanged( void ) { ; }
virtual void SegmentListChanged( void ) { ; }
};
#endif // PL_PASSMTLBASE_H

View File

@ -0,0 +1,52 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTLBASICPB_H
#define PL_PASSMTLBASICPB_H
// Param ID's
enum
{
kPassBasColorLock,
kPassBasColorAmb,
kPassBasColor,
kPassBasOpacity,
kPassBasEmissive,
// Specular
kPassBasUseSpec,
kPassBasShine,
kPassBasShineStr,
// New color stuff
kPassBasDiffuseLock,
kPassBasRunColor,
kPassBasSpecColor
};
#endif //PL_PASSMTLBASICPB_H

View File

@ -0,0 +1,240 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plPassMtl.h"
#include "plPassMtlBasicPB.h"
#include "resource.h"
#include "iparamm2.h"
class PassBasicPBAccessor;
extern PassBasicPBAccessor basicAccessor;
class PassBasicDlgProc;
extern PassBasicDlgProc gPassBasicDlgProc;
static ParamBlockDesc2 gPassBasicPB
(
plPassMtl::kBlkBasic, _T("basic"), IDS_PASS_BASIC, GetPassMtlDesc(),//NULL,
P_AUTO_CONSTRUCT + P_AUTO_UI, plPassMtl::kRefBasic,
// UI
IDD_PASS_BASIC, IDS_PASS_BASIC, 0, 0, &gPassBasicDlgProc,
// Color
kPassBasColorLock, _T("colorLock"), TYPE_BOOL, 0, 0,
p_ui, TYPE_CHECKBUTTON, IDC_LOCK_AD,
p_accessor, &basicAccessor,
end,
kPassBasColorAmb, _T("ambColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_AMB,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_COLOR_AMB,
p_accessor, &basicAccessor,
end,
kPassBasColor, _T("color"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_COLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_COLOR,
p_default, Color(1,1,1),
p_accessor, &basicAccessor,
end,
kPassBasRunColor, _T("runtimeColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_RUNCOLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_RUNCOLOR,
p_default, Color(-1,-1,-1),
p_accessor, &basicAccessor,
end,
kPassBasDiffuseLock, _T("diffuseLock"), TYPE_BOOL, 0, 0,
p_ui, TYPE_CHECKBUTTON, IDC_LOCK_COLORS,
p_accessor, &basicAccessor,
p_default, TRUE,
end,
// Opacity
kPassBasOpacity, _T("opacity"), TYPE_INT, P_ANIMATABLE, IDS_BASIC_OPAC,
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_TR_EDIT, IDC_TR_SPIN, 0.4,
p_range, 0, 100,
p_default, 100,
end,
kPassBasEmissive, _T("emissive"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_LAYER_EMISSIVE_CB,
end,
// Specularity
kPassBasUseSpec, _T("useSpec"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_SHADE_SPECULAR,
p_enable_ctrls, 2, kPassBasShine, kPassBasSpecColor,
end,
kPassBasShine, _T("shine"), TYPE_INT, 0, 0,
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_SH_EDIT, IDC_SH_SPIN, 0.4,
p_range, 0, 100,
end,
kPassBasSpecColor, _T("specularColor"), TYPE_RGBA, P_ANIMATABLE, IDS_BASIC_SPECCOLOR,
p_ui, TYPE_COLORSWATCH, IDC_LAYER_SPECCOLOR,
p_default, Color(0,0,0),
end,
// OBSOLETE--here so we can upgrade it to color if necessary
kPassBasShineStr, _T("shineStr"), TYPE_INT, 0, 0,
p_range, -1, 100,
p_default, -1,
end,
end
);
ParamBlockDesc2 *GetPassBasicPB() { return &gPassBasicPB; }
class PassBasicPBAccessor : public PBAccessor
{
bool fColorLocked;
public:
PassBasicPBAccessor() : fColorLocked( false ) {}
void Set(PB2Value& val, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)
{
plPassMtl* mtl = (plPassMtl*)owner;
IParamBlock2 *pb = mtl->GetParamBlockByID(plPassMtl::kBlkBasic);
switch (id)
{
case kPassBasColorLock:
if (val.i)
pb->SetValue(kPassBasColor, t, pb->GetColor(kPassBasColorAmb, t));
break;
case kPassBasDiffuseLock:
if (val.i)
pb->SetValue(kPassBasRunColor, t, pb->GetColor(kPassBasColor, t));
break;
case kPassBasColor:
case kPassBasColorAmb:
case kPassBasRunColor:
ISyncLockedColors( id, pb, val, t );
break;
}
}
void Get(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t, Interval &valid)
{
}
void ISyncLockedColors( ParamID settingID, IParamBlock2 *pb, PB2Value &val, TimeValue t )
{
int i, numToSet = 0;
ParamID toSet[ 2 ];
if( fColorLocked )
return;
fColorLocked = true;
if( settingID == kPassBasColorAmb && pb->GetInt( kPassBasColorLock, t ) )
{
toSet[ numToSet++ ] = kPassBasColor;
if( pb->GetInt( kPassBasDiffuseLock, t ) )
toSet[ numToSet++ ] = kPassBasRunColor;
}
else if( settingID == kPassBasRunColor && pb->GetInt( kPassBasDiffuseLock, t ) )
{
toSet[ numToSet++ ] = kPassBasColor;
if( pb->GetInt( kPassBasColorLock, t ) )
toSet[ numToSet++ ] = kPassBasColorAmb;
}
else if( settingID == kPassBasColor )
{
if( pb->GetInt( kPassBasColorLock, t ) )
toSet[ numToSet++ ] = kPassBasColorAmb;
if( pb->GetInt( kPassBasDiffuseLock, t ) )
toSet[ numToSet++ ] = kPassBasRunColor;
}
for( i = 0; i < numToSet; i++ )
{
pb->SetValue( toSet[ i ], t, *val.p );
if( pb->GetMap() )
pb->GetMap()->Invalidate( toSet[ i ] );
}
fColorLocked = false;
}
};
static PassBasicPBAccessor basicAccessor;
class PassBasicDlgProc : public ParamMap2UserDlgProc
{
#if 1
protected:
HIMAGELIST hLockButtons;
void LoadLockButtons()
{
static bool loaded = false;
if (loaded)
return;
loaded = true;
HINSTANCE hInst = hInstance;
hLockButtons = ImageList_Create(16, 15, TRUE, 2, 0);
HBITMAP hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BUTTONS));
HBITMAP hMask = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_MASKBUTTONS));
ImageList_Add(hLockButtons, hBitmap, hMask);
DeleteObject(hBitmap);
DeleteObject(hMask);
}
void ISetLock(HWND hButton)
{
LoadLockButtons();
ICustButton *iBut = GetICustButton(hButton);
iBut->SetImage(hLockButtons,0,1,0,1,16,15);
iBut->SetType(CBT_CHECK);
ReleaseICustButton(iBut);
}
public:
PassBasicDlgProc() : hLockButtons(NULL) {}
~PassBasicDlgProc() { if (hLockButtons) ImageList_Destroy(hLockButtons); }
#endif
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
IParamBlock2 *pb = map->GetParamBlock();
switch (msg)
{
case WM_INITDIALOG:
{
ISetLock(GetDlgItem(hWnd, IDC_LOCK_AD));
ISetLock(GetDlgItem(hWnd, IDC_LOCK_COLORS));
}
return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
static PassBasicDlgProc gPassBasicDlgProc;

View File

@ -0,0 +1,41 @@
/*==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/>.
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==*/
#ifndef PL_PASSMTLLAYERSPB_H
#define PL_PASSMTLLAYERSPB_H
enum
{
// Layers
kPassLayBase,
kPassLayTopOn,
kPassLayTop,
kPassLayBlend,
kPassLayOutputBlend,
kPassLayOutputAlpha,
};
#endif //PL_PASSMTLLAYERSPB_H

View File

@ -0,0 +1,86 @@
/*==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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plPassMtl.h"
#include "plPassMtlLayersPB.h"
#include "resource.h"
#include "iparamm2.h"
#include "Layers/plLayerTex.h"
class PassMtlLayersAccessor;
extern PassMtlLayersAccessor gLayersAccessor;
class LayersDlgProc;
extern LayersDlgProc gLayersDlgProc;
static ParamBlockDesc2 gPassMtlLayersPB
(
plPassMtl::kBlkLayers, _T("layers"), IDS_PASS_LAYERS, GetPassMtlDesc(),
P_AUTO_CONSTRUCT + P_AUTO_UI, plPassMtl::kRefLayers,
// UI
IDD_PASS_LAYERS, IDS_PASS_LAYERS, 0, 0, NULL,
kPassLayBase, _T("baseLayer"), TYPE_TEXMAP, 0, IDS_BASIC_AMB,
p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER1,
p_subtexno, 0,
end,
kPassLayTopOn, _T("topLayerOn"), TYPE_BOOL, 0, 0,
p_ui, TYPE_SINGLECHEKBOX, IDC_TOP_ON,
p_default, FALSE,
p_enable_ctrls, 3, kPassLayTop, kPassLayBlend, kPassLayOutputAlpha,
end,
kPassLayTop, _T("topLayer"), TYPE_TEXMAP, 0, 0,
p_ui, TYPE_TEXMAPBUTTON, IDC_LAYER2,
p_subtexno, 1,
end,
kPassLayBlend, _T("layerBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_LAYER_ALPHA, IDC_LAYER_ADD, IDC_LAYER_MULTIPLY,
p_vals, plPassMtlBase::kBlendAlpha, plPassMtlBase::kBlendAdd, plPassMtlBase::kBlendMult,
p_default, plPassMtlBase::kBlendAdd,
end,
kPassLayOutputAlpha, _T("ouputAlpha"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_OUTPUTA_DISCARD, IDC_OUTPUTA_ADD, IDC_OUTPUTA_MULT,
p_vals, plPassMtlBase::kAlphaDiscard, plPassMtlBase::kAlphaAdd, plPassMtlBase::kAlphaMultiply,
p_default, plPassMtlBase::kAlphaDiscard,
end,
kPassLayOutputBlend, _T("outputBlend"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 3, IDC_OUTPUTB_NONE, IDC_OUTPUTB_ALPHA, IDC_OUTPUTB_ADD,
p_vals, plPassMtlBase::kBlendNone, plPassMtlBase::kBlendAlpha, plPassMtlBase::kBlendAdd,
p_default, plPassMtlBase::kBlendNone,
end,
end
);
ParamBlockDesc2 *GetPassLayersPB() { return &gPassMtlLayersPB; }