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
12 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);
}