You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
492 lines
11 KiB
492 lines
11 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
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 "plAngleAttenLayer.h" |
|
|
|
#include "iparamb2.h" |
|
#include "iparamm2.h" |
|
#include "stdmat.h" |
|
|
|
#include "plBMSampler.h" |
|
#include "../MaxMain/plPlasmaRefMsgs.h" |
|
|
|
class plAngleAttenLayerClassDesc : public ClassDesc2 |
|
{ |
|
public: |
|
int IsPublic() { return TRUE; } |
|
void* Create(BOOL loading = FALSE) { return TRACKED_NEW plAngleAttenLayer(); } |
|
const TCHAR* ClassName() { return GetString(IDS_ANGLE_ATTEN_LAYER); } |
|
SClass_ID SuperClassID() { return TEXMAP_CLASS_ID; } |
|
Class_ID ClassID() { return ANGLE_ATTEN_LAYER_CLASS_ID; } |
|
const TCHAR* Category() { return TEXMAP_CAT_COLMOD; } |
|
const TCHAR* InternalName() { return _T("PlasmaAngleAttenLayer"); } |
|
HINSTANCE HInstance() { return hInstance; } |
|
}; |
|
static plAngleAttenLayerClassDesc plAngleAttenLayerDesc; |
|
ClassDesc2* GetAngleAttenLayerDesc() { return &plAngleAttenLayerDesc; } |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
//// ParamBlock Definition //////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
|
|
static const float kDefTransp0 = 60.f; |
|
static const float kDefOpaque0 = 90.f; |
|
static const float kDefTransp1 = 30.f; |
|
static const float kDefOpaque1 = 0.f; |
|
|
|
static ParamBlockDesc2 gAngleAttenParamBlk |
|
( |
|
plAngleAttenLayer::kBlkAngles, _T("angles"), 0, GetAngleAttenLayerDesc(),//NULL, |
|
P_AUTO_CONSTRUCT + P_AUTO_UI, plAngleAttenLayer::kRefAngles, |
|
|
|
IDD_ANGLE_ATTEN_LAYER, IDS_ANGLE_ATTEN_LAYER_PROPS, 0, 0, nil, |
|
|
|
// Texture size |
|
plAngleAttenLayer::kTranspAngle0, _T("transp0"), TYPE_FLOAT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_TRANSP_ANGLE_0, IDC_TRANSP_ANGLE_0_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0.0, 180.0, |
|
p_default, kDefTransp0, |
|
end, |
|
|
|
plAngleAttenLayer::kOpaqueAngle0, _T("opaque0"), TYPE_FLOAT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_OPAQUE_ANGLE_0, IDC_OPAQUE_ANGLE_0_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0.0, 180.0, |
|
p_default, kDefOpaque0, |
|
end, |
|
|
|
plAngleAttenLayer::kDoubleFade, _T("doubleFade"), TYPE_BOOL, 0, 0, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_DOUBLE_FADE, |
|
p_enable_ctrls, 2, plAngleAttenLayer::kOpaqueAngle1, plAngleAttenLayer::kTranspAngle1, |
|
p_default, false, |
|
end, |
|
|
|
plAngleAttenLayer::kOpaqueAngle1, _T("opaque1"), TYPE_FLOAT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_OPAQUE_ANGLE_1, IDC_OPAQUE_ANGLE_1_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0.0, 180.0, |
|
p_default, kDefTransp1, |
|
end, |
|
|
|
plAngleAttenLayer::kTranspAngle1, _T("transp1"), TYPE_FLOAT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_TRANSP_ANGLE_1, IDC_TRANSP_ANGLE_1_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0.0, 180.0, |
|
p_default, kDefOpaque1, |
|
end, |
|
|
|
plAngleAttenLayer::kReflect, _T("reflect"), TYPE_BOOL, 0, 0, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_REFLECT, |
|
p_default, false, |
|
end, |
|
|
|
plAngleAttenLayer::kLoClamp, _T("loClamp"), TYPE_INT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_LO_CLAMP, IDC_LO_CLAMP_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0, 100, |
|
p_default, 0, |
|
end, |
|
|
|
plAngleAttenLayer::kHiClamp, _T("hiClamp"), TYPE_INT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_HI_CLAMP, IDC_HI_CLAMP_SPIN, SPIN_AUTOSCALE, |
|
p_range, 0, 100, |
|
p_default, 100, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plAngleAttenLayer::plAngleAttenLayer() : |
|
fParmsPB(NULL), |
|
fIValid(NEVER), |
|
fCosTransp0(0), |
|
fCosOpaque0(0), |
|
fCosTransp1(0), |
|
fCosOpaque1(0), |
|
fCosinesCached(false) |
|
{ |
|
plAngleAttenLayerDesc.MakeAutoParamBlocks(this); |
|
} |
|
|
|
plAngleAttenLayer::~plAngleAttenLayer() |
|
{ |
|
} |
|
|
|
//From MtlBase |
|
void plAngleAttenLayer::Reset() |
|
{ |
|
GetAngleAttenLayerDesc()->Reset(this, TRUE); // reset all pb2's |
|
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); |
|
|
|
fIValid.SetEmpty(); |
|
} |
|
|
|
void plAngleAttenLayer::Update(TimeValue t, Interval& valid) |
|
{ |
|
if (!fIValid.InInterval(t)) |
|
{ |
|
fIValid.SetInfinite(); |
|
|
|
} |
|
|
|
valid &= fIValid; |
|
} |
|
|
|
Interval plAngleAttenLayer::Validity(TimeValue t) |
|
{ |
|
//TODO: Update fIValid here |
|
|
|
Interval v = FOREVER; |
|
return v; |
|
} |
|
|
|
ParamDlg* plAngleAttenLayer::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp) |
|
{ |
|
IAutoMParamDlg* masterDlg = plAngleAttenLayerDesc.CreateParamDlgs(hwMtlEdit, imp, this); |
|
|
|
return masterDlg; |
|
} |
|
|
|
BOOL plAngleAttenLayer::SetDlgThing(ParamDlg* dlg) |
|
{ |
|
return FALSE; |
|
} |
|
|
|
int plAngleAttenLayer::NumRefs() |
|
{ |
|
return 1; |
|
} |
|
|
|
//From ReferenceMaker |
|
RefTargetHandle plAngleAttenLayer::GetReference(int i) |
|
{ |
|
switch (i) |
|
{ |
|
case kRefAngles: return fParmsPB; |
|
default: return NULL; |
|
} |
|
} |
|
|
|
void plAngleAttenLayer::SetReference(int i, RefTargetHandle rtarg) |
|
{ |
|
Interval garbage; |
|
|
|
switch (i) |
|
{ |
|
case kRefAngles: |
|
fParmsPB = (IParamBlock2 *)rtarg; |
|
break; |
|
} |
|
} |
|
|
|
int plAngleAttenLayer::NumParamBlocks() |
|
{ |
|
return 1; |
|
} |
|
|
|
IParamBlock2* plAngleAttenLayer::GetParamBlock(int i) |
|
{ |
|
switch (i) |
|
{ |
|
case 0: return fParmsPB; |
|
default: return NULL; |
|
} |
|
} |
|
|
|
IParamBlock2* plAngleAttenLayer::GetParamBlockByID(BlockID id) |
|
{ |
|
if (fParmsPB->ID() == id) |
|
return fParmsPB; |
|
else |
|
return NULL; |
|
} |
|
|
|
//From ReferenceTarget |
|
RefTargetHandle plAngleAttenLayer::Clone(RemapDir &remap) |
|
{ |
|
plAngleAttenLayer *mnew = TRACKED_NEW plAngleAttenLayer(); |
|
*((MtlBase*)mnew) = *((MtlBase*)this); // copy superclass stuff |
|
mnew->ReplaceReference(kRefAngles, remap.CloneRef(fParmsPB)); |
|
BaseClone(this, mnew, remap); |
|
return (RefTargetHandle)mnew; |
|
} |
|
|
|
int plAngleAttenLayer::NumSubs() |
|
{ |
|
return 1; |
|
} |
|
|
|
Animatable* plAngleAttenLayer::SubAnim(int i) |
|
{ |
|
//TODO: Return 'i-th' sub-anim |
|
switch (i) |
|
{ |
|
case kRefAngles: return fParmsPB; |
|
default: return NULL; |
|
} |
|
} |
|
|
|
TSTR plAngleAttenLayer::SubAnimName(int i) |
|
{ |
|
switch (i) |
|
{ |
|
case kRefAngles: return "Angles"; |
|
default: return ""; |
|
} |
|
} |
|
|
|
RefResult plAngleAttenLayer::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, |
|
PartID& partID, RefMessage message) |
|
{ |
|
switch (message) |
|
{ |
|
case REFMSG_CHANGE: |
|
{ |
|
fIValid.SetEmpty(); |
|
|
|
if (hTarget == fParmsPB) |
|
{ |
|
// see if this message came from a changing parameter in the pblock, |
|
// if so, limit rollout update to the changing item |
|
ParamID changingParam = fParmsPB->LastNotifyParamID(); |
|
fParmsPB->GetDesc()->InvalidateUI(changingParam); |
|
|
|
if (changingParam != -1) |
|
IChanged(); |
|
} |
|
} |
|
break; |
|
|
|
} |
|
|
|
return REF_SUCCEED; |
|
} |
|
|
|
void plAngleAttenLayer::IChanged() |
|
{ |
|
// Cut and paste insanity from DynamicTextLayer. |
|
// Texture wasn't getting updated in the viewports, and this fixes it. |
|
// Don't know if it's the right way though. |
|
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); |
|
|
|
// And this is so the SceneWatcher gets notified that the material on some of it's |
|
// referenced objects changed. |
|
NotifyDependents(FOREVER, PART_ALL, REFMSG_USER_MAT); |
|
|
|
ICacheCosines(); |
|
} |
|
|
|
void plAngleAttenLayer::ICacheCosines() |
|
{ |
|
fCosTransp0 = cosf(DegToRad(fParmsPB->GetFloat(kTranspAngle0))); |
|
fCosOpaque0 = cosf(DegToRad(fParmsPB->GetFloat(kOpaqueAngle0))); |
|
|
|
if( fParmsPB->GetInt(kDoubleFade) ) |
|
{ |
|
fCosTransp1 = cosf(DegToRad(fParmsPB->GetFloat(kTranspAngle1))); |
|
fCosOpaque1 = cosf(DegToRad(fParmsPB->GetFloat(kOpaqueAngle1))); |
|
} |
|
else |
|
{ |
|
fCosTransp1 = fCosOpaque1 = 0; |
|
} |
|
fCosinesCached = true; |
|
} |
|
|
|
#define TEX_HDR_CHUNK 0x5000 |
|
|
|
IOResult plAngleAttenLayer::Save(ISave *isave) |
|
{ |
|
IOResult res; |
|
|
|
isave->BeginChunk(TEX_HDR_CHUNK); |
|
res = MtlBase::Save(isave); |
|
if (res != IO_OK) |
|
return res; |
|
isave->EndChunk(); |
|
|
|
return IO_OK; |
|
} |
|
|
|
IOResult plAngleAttenLayer::Load(ILoad *iload) |
|
{ |
|
IOResult res; |
|
while (IO_OK == (res = iload->OpenChunk())) |
|
{ |
|
if (iload->CurChunkID() == TEX_HDR_CHUNK) |
|
{ |
|
res = MtlBase::Load(iload); |
|
} |
|
iload->CloseChunk(); |
|
if (res != IO_OK) |
|
return res; |
|
} |
|
|
|
return IO_OK; |
|
} |
|
|
|
|
|
AColor plAngleAttenLayer::EvalColor(ShadeContext& sc) |
|
{ |
|
if( !sc.doMaps ) |
|
return AColor(0.0f, 0.0f, 0.0f, 1.0f); |
|
|
|
AColor color; |
|
if (sc.GetCache(this, color)) |
|
return color; |
|
|
|
if( !fCosinesCached ) |
|
ICacheCosines(); |
|
|
|
if (gbufID) |
|
sc.SetGBufferID(gbufID); |
|
|
|
// Evaluate the Bitmap |
|
|
|
Point3 normal = sc.Normal(); |
|
|
|
if( fParmsPB->GetInt(kReflect) ) |
|
{ |
|
normal = sc.ReflectVector(); |
|
} |
|
float dotZ = normal.z; |
|
|
|
float alpha = 1.f; |
|
if( fCosTransp0 != fCosOpaque0 ) |
|
{ |
|
float a = (dotZ - fCosTransp0) / (fCosOpaque0 - fCosTransp0); |
|
if( a < 0 ) |
|
a = 0; |
|
else if( a > 1.f ) |
|
a = 1.f; |
|
alpha *= a; |
|
} |
|
if( fParmsPB->GetInt(kDoubleFade) && (fCosTransp1 != fCosOpaque1) ) |
|
{ |
|
float a = (dotZ - fCosTransp1) / (fCosOpaque1 - fCosTransp1); |
|
if( a < 0 ) |
|
a = 0; |
|
else if( a > 1.f ) |
|
a = 1.f; |
|
if( fCosTransp0 < fCosTransp1 ) |
|
{ |
|
if( fCosTransp0 > fCosOpaque0 ) |
|
alpha += a; |
|
else |
|
alpha *= a; |
|
} |
|
else |
|
{ |
|
if( fCosTransp0 < fCosOpaque0 ) |
|
alpha += a; |
|
else |
|
alpha *= a; |
|
} |
|
} |
|
color = AColor(1.f, 1.f, 1.f, alpha); |
|
|
|
sc.PutCache(this, color); |
|
return color; |
|
} |
|
|
|
float plAngleAttenLayer::EvalMono(ShadeContext& sc) |
|
{ |
|
return Intens(EvalColor(sc)); |
|
} |
|
|
|
Point3 plAngleAttenLayer::EvalNormalPerturb(ShadeContext& sc) |
|
{ |
|
// Return the perturbation to apply to a normal for bump mapping |
|
return Point3(0, 0, 0); |
|
} |
|
|
|
ULONG plAngleAttenLayer::LocalRequirements(int subMtlNum) |
|
{ |
|
return MTLREQ_VIEW_DEP | MTLREQ_TRANSP; |
|
} |
|
|
|
void plAngleAttenLayer::ActivateTexDisplay(BOOL onoff) |
|
{ |
|
} |
|
|
|
BITMAPINFO *plAngleAttenLayer::GetVPDisplayDIB(TimeValue t, TexHandleMaker& thmaker, Interval &valid, BOOL mono, BOOL forceW, BOOL forceH) |
|
{ |
|
return nil; |
|
// FIXME |
|
} |
|
|
|
DWORD plAngleAttenLayer::GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker) |
|
{ |
|
return 0; |
|
} |
|
|
|
const char *plAngleAttenLayer::GetTextureName( int which ) |
|
{ |
|
return NULL; |
|
} |
|
|
|
int plAngleAttenLayer::GetLoClamp() |
|
{ |
|
return fParmsPB->GetInt(kLoClamp); |
|
} |
|
|
|
int plAngleAttenLayer::GetHiClamp() |
|
{ |
|
return fParmsPB->GetInt(kHiClamp); |
|
} |
|
|
|
Box3 plAngleAttenLayer::GetFade() |
|
{ |
|
Point3 pmin, pmax; |
|
|
|
pmin.x = fParmsPB->GetFloat(kTranspAngle0); |
|
pmin.y = fParmsPB->GetFloat(kOpaqueAngle0); |
|
if( pmin.x < pmin.y ) |
|
pmin.z = -1.f; |
|
else if( pmin.x > pmin.y ) |
|
pmin.z = 1.f; |
|
else |
|
pmin.z = 0; |
|
|
|
if( fParmsPB->GetInt(kDoubleFade) ) |
|
{ |
|
pmax.x = fParmsPB->GetFloat(kTranspAngle1); |
|
pmax.y = fParmsPB->GetFloat(kOpaqueAngle1); |
|
if( pmax.x < pmax.y ) |
|
pmax.z = -1.f; |
|
else if( pmax.x > pmax.y ) |
|
pmax.z = 1.f; |
|
else |
|
pmax.z = 0; |
|
} |
|
else |
|
{ |
|
pmax.x = pmax.y = pmax.z = 0; |
|
} |
|
return Box3(pmin, pmax); |
|
|
|
} |
|
|
|
BOOL plAngleAttenLayer::Reflect() |
|
{ |
|
return fParmsPB->GetInt(kReflect); |
|
} |