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.
812 lines
26 KiB
812 lines
26 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "HeadSpin.h" |
|
#include "hsWindows.h" |
|
#include "../resource.h" |
|
|
|
#include "MaxMain/MaxCompat.h" |
|
#include <iparamm2.h> |
|
#include <istdplug.h> |
|
#include <stdmat.h> |
|
#pragma hdrstop |
|
|
|
#include "plDecalMtl.h" |
|
|
|
#include "../Shaders.h" |
|
#include "MaxComponent/plMaxAnimUtils.h" |
|
|
|
#include "plPassBaseParamIDs.h" |
|
#include "plDecalMtlBasicPB.h" |
|
#include "plDecalMtlLayersPB.h" |
|
|
|
#include "../Layers/plLayerTex.h" |
|
#include "../Layers/plStaticEnvLayer.h" |
|
#include "MaxMain/plPlasmaRefMsgs.h" |
|
#include "MaxMain/MaxCompat.h" |
|
|
|
extern HINSTANCE hInstance; |
|
|
|
class plDecalMtlClassDesc : public ClassDesc2 |
|
{ |
|
public: |
|
int IsPublic() { return TRUE; } |
|
void* Create(BOOL loading) { return 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, new plLayerTex ); |
|
fLayersPB->SetValue( kDecalLayTop, 0, 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); |
|
} |
|
|
|
void plDecalMtl::GetClassName(TSTR& s) |
|
{ |
|
s = GetString(IDS_DECAL_MTL); |
|
} |
|
|
|
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 = 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 |
|
const char * plDecalMtl::GetAnimName() { return fAnimPB->GetStr(kPBAnimName); } |
|
int plDecalMtl::GetAutoStart() { return fAnimPB->GetInt(kPBAnimAutoStart); } |
|
int plDecalMtl::GetLoop() { return fAnimPB->GetInt(kPBAnimLoop); } |
|
const 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)); } |
|
const 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 GetParamBlock2Controller(fBasicPB, ParamID(kDecalBasColor)); } |
|
Control *plDecalMtl::GetAmbColorController() { return GetParamBlock2Controller(fBasicPB, ParamID(kDecalBasColorAmb)); } |
|
Control *plDecalMtl::GetOpacityController() { return GetParamBlock2Controller(fBasicPB, ParamID(kDecalBasOpacity)); } |
|
Control *plDecalMtl::GetSpecularColorController() { return GetParamBlock2Controller(fBasicPB, ParamID(kDecalBasSpecColor)); } |
|
int plDecalMtl::GetDiffuseColorLock() { return fBasicPB->GetInt(kDecalBasDiffuseLock); } |
|
Color plDecalMtl::GetRuntimeColor() { return fBasicPB->GetColor(kDecalBasRunColor); } |
|
Control *plDecalMtl::GetRuntimeColorController() { return GetParamBlock2Controller(fBasicPB, 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); } |
|
|
|
|