1 /**********************************************************************
2 *<
3 FILE: MASK.CPP
4
5 DESCRIPTION: MASK Composite.
6
7 CREATED BY: Dan Silva
8
9 HISTORY:12/2/98 Updated to Param Block 2 Peter Watje
10
11 *> Copyright (c) 1994, All Rights Reserved.
12 **********************************************************************/
13
14 #include "mtlhdr.h"
15 #include "mtlres.h"
16 #include "mtlresOverride.h"
17
18 extern HINSTANCE hInstance;
19 #include "iparamm2.h"
20
21
22
23 #define NSUBTEX 2 // number of texture map slots
24
25 static Class_ID maskClassID(MASK_CLASS_ID,0);
26
27 static int subTexId[NSUBTEX] = { IDC_MASK_MAP, IDC_MASK_MASK };
28
29 //--------------------------------------------------------------
30 // Mask: A Composite texture map
31 //--------------------------------------------------------------
32 class Mask: public Texmap {
33 Texmap* subTex[NSUBTEX]; // refs
34 Interval ivalid;
35 BOOL rollScroll;
36 public:
37 BOOL Param1;
38 Mask();
39 BOOL mapOn[NSUBTEX];
40 BOOL invertMask;
41
42 IParamBlock2 *pblock; // ref #2
43 ParamDlg* CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
44 void Update(TimeValue t, Interval& valid);
45 void Init();
46 void Reset();
Validity(TimeValue t)47 Interval Validity(TimeValue t) { Interval v; Update(t,v); return ivalid; }
48
49 void NotifyChanged();
50
51 // Evaluate the color of map for the context.
52 AColor EvalColor(ShadeContext& sc);
53 float EvalMono(ShadeContext& sc);
54 AColor EvalFunction(ShadeContext& sc, float u, float v, float du, float dv);
55
56 // For Bump mapping, need a perturbation to apply to a normal.
57 // Leave it up to the Texmap to determine how to do this.
58 Point3 EvalNormalPerturb(ShadeContext& sc);
59
60 // Methods to access texture maps of material
NumSubTexmaps()61 int NumSubTexmaps() { return NSUBTEX; }
GetSubTexmap(int i)62 Texmap* GetSubTexmap(int i) { return subTex[i]; }
63 void SetSubTexmap(int i, Texmap *m);
64 TSTR GetSubTexmapSlotName(int i);
65
ClassID()66 Class_ID ClassID() { return maskClassID; }
SuperClassID()67 SClass_ID SuperClassID() { return TEXMAP_CLASS_ID; }
GetClassName(TSTR & s)68 void GetClassName(TSTR& s) { s= GetString(IDS_DS_MASK); }
DeleteThis()69 void DeleteThis() { delete this; }
70
NumSubs()71 int NumSubs() { return NSUBTEX+1; }
72 Animatable* SubAnim(int i);
73 TSTR SubAnimName(int i);
SubNumToRefNum(int subNum)74 int SubNumToRefNum(int subNum) { return subNum; }
75
76 // From ref
NumRefs()77 int NumRefs() { return NSUBTEX+1; }
78 RefTargetHandle GetReference(int i);
79 void SetReference(int i, RefTargetHandle rtarg);
80
81 RefTargetHandle Clone(RemapDir &remap = DefaultRemapDir());
82 RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget,
83 PartID& partID, RefMessage message );
84
85 // IO
86 IOResult Save(ISave *isave);
87 IOResult Load(ILoad *iload);
88
89 // JBW: direct ParamBlock access is added
NumParamBlocks()90 int NumParamBlocks() { return 1; } // return number of ParamBlocks in this instance
GetParamBlock(int i)91 IParamBlock2* GetParamBlock(int i) { return pblock; } // return i'th ParamBlock
GetParamBlockByID(BlockID id)92 IParamBlock2* GetParamBlockByID(BlockID id) { return (pblock->ID() == id) ? pblock : NULL; } // return id'd ParamBlock
93
94 bool IsLocalOutputMeaningful( ShadeContext& sc );
95 };
96
97 class MaskClassDesc:public ClassDesc2 {
98 public:
IsPublic()99 int IsPublic() { return GetAppID() != kAPP_VIZR; }
Create(BOOL loading)100 void * Create(BOOL loading) { return new Mask; }
ClassName()101 const TCHAR * ClassName() { return GetString(IDS_DS_MASK_CDESC); } // mjm - 2.3.99
SuperClassID()102 SClass_ID SuperClassID() { return TEXMAP_CLASS_ID; }
ClassID()103 Class_ID ClassID() { return maskClassID; }
Category()104 const TCHAR* Category() { return TEXMAP_CAT_COMP; }
105 // PW: new descriptor data accessors added. Note that the
106 // internal name is hardwired since it must not be localized.
InternalName()107 const TCHAR* InternalName() { return _T("maskTex"); } // returns fixed parsable name (scripter-visible name)
HInstance()108 HINSTANCE HInstance() { return hInstance; } // returns owning module handle
109
110 };
111
112 static MaskClassDesc maskCD;
113
GetMaskDesc()114 ClassDesc* GetMaskDesc() { return &maskCD; }
115
116 enum { mask_params, }; // pblock ID
117 // mask_params param IDs
118 enum
119 {
120 mask_map1, mask_map2,
121 mask_map1_on, mask_map2_on, // main grad params
122 mask_invert
123 };
124
125 // per instance gradient block
126 static ParamBlockDesc2 mask_param_blk ( mask_params, _T("parameters"), 0, &maskCD, P_AUTO_CONSTRUCT + P_AUTO_UI, 2,
127 //rollout
128 IDD_MASK, IDS_MASKPARMS, 0, 0, NULL,
129 // params
130 mask_map1, _T("map"), TYPE_TEXMAP, P_OWNERS_REF, IDS_DS_MAP,
131 p_refno, 0,
132 p_subtexno, 0,
133 p_ui, TYPE_TEXMAPBUTTON, IDC_MASK_MAP,
134 end,
135 mask_map2, _T("mask"), TYPE_TEXMAP, P_OWNERS_REF, IDS_DS_MASK,
136 p_refno, 1,
137 p_subtexno, 1,
138 p_ui, TYPE_TEXMAPBUTTON, IDC_MASK_MASK,
139 end,
140 mask_map1_on, _T("mapEnabled"), TYPE_BOOL, 0, IDS_JW_MAP1ENABLE,
141 p_default, TRUE,
142 p_ui, TYPE_SINGLECHEKBOX, IDC_MAPON1,
143 end,
144 mask_map2_on, _T("maskEnabled"), TYPE_BOOL, 0, IDS_JW_MAP2ENABLE,
145 p_default, TRUE,
146 p_ui, TYPE_SINGLECHEKBOX, IDC_MAPON2,
147 end,
148 mask_invert, _T("maskInverted"), TYPE_BOOL, 0, IDS_PW_INVERT,
149 p_default, FALSE,
150 p_ui, TYPE_SINGLECHEKBOX, IDC_INVERT_MASK,
151 end,
152 end
153 );
154
155
156 //-----------------------------------------------------------------------------
157 // Mask
158 //-----------------------------------------------------------------------------
159
160
Init()161 void Mask::Init() {
162 ivalid.SetEmpty();
163 invertMask = 0;
164 }
165
Reset()166 void Mask::Reset() {
167 for (int i=0; i<NSUBTEX; i++) {
168 DeleteReference(i); // get rid of maps
169 mapOn[i] = 1;
170 }
171 maskCD.Reset(this, TRUE); // reset all pb2's
172 Init();
173 }
174
NotifyChanged()175 void Mask::NotifyChanged() {
176 NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
177 }
178
Mask()179 Mask::Mask() {
180 Param1 = FALSE;
181 mapOn[0] = mapOn[1] = 1;
182 for (int i=0; i<NSUBTEX; i++) subTex[i] = NULL;
183 pblock = NULL;
184 maskCD.MakeAutoParamBlocks(this); // make and intialize paramblock2
185 Init();
186 rollScroll=0;
187 }
188
189
190 static AColor white(1.0f,1.0f,1.0f,1.0f);
191
EvalColor(ShadeContext & sc)192 AColor Mask::EvalColor(ShadeContext& sc) {
193 if (gbufID) sc.SetGBufferID(gbufID);
194 float m = 1.0f;
195 if (subTex[1]&&mapOn[1]) {
196 m = subTex[1]->EvalMono(sc);
197 if (invertMask) m = 1.0f-m;
198 }
199 AColor c0 = subTex[0]&&mapOn[0]? subTex[0]->EvalColor(sc): white;
200 if(m==1.0f)
201 return c0;
202 else
203 return m*c0;
204 }
205
EvalMono(ShadeContext & sc)206 float Mask::EvalMono(ShadeContext& sc) {
207 if (gbufID) sc.SetGBufferID(gbufID);
208 float m = 1.0f;
209 if (subTex[1]&&mapOn[1]) {
210 m = subTex[1]->EvalMono(sc);
211 if (invertMask) m = 1.0f-m;
212 }
213 float c0 = subTex[0]&&mapOn[0]? subTex[0]->EvalMono(sc): 1.0f;
214 return m*c0;
215 }
216
EvalNormalPerturb(ShadeContext & sc)217 Point3 Mask::EvalNormalPerturb(ShadeContext& sc) {
218 if (gbufID) sc.SetGBufferID(gbufID);
219 float m = 1.0f;
220 if (subTex[1]&&mapOn[1]) {
221 m = subTex[1]->EvalMono(sc);
222 if (invertMask) m = 1.0f-m;
223 }
224 Point3 p0 = subTex[0]&&mapOn[0]? subTex[0]->EvalNormalPerturb(sc): Point3(0.0f,0.0f,0.0f);
225 return m*p0;
226 }
227
Clone(RemapDir & remap)228 RefTargetHandle Mask::Clone(RemapDir &remap) {
229 Mask *mnew = new Mask();
230 *((MtlBase*)mnew) = *((MtlBase*)this); // copy superclass stuff
231 mnew->ReplaceReference(2,remap.CloneRef(pblock));
232 mnew->ivalid.SetEmpty();
233 for (int i = 0; i<NSUBTEX; i++) {
234 mnew->subTex[i] = NULL;
235 if (subTex[i])
236 mnew->ReplaceReference(i,remap.CloneRef(subTex[i]));
237 mnew->mapOn[i] = mapOn[i];
238 mnew->invertMask = invertMask;
239 }
240 BaseClone(this, mnew, remap);
241 return (RefTargetHandle)mnew;
242 }
243
CreateParamDlg(HWND hwMtlEdit,IMtlParams * imp)244 ParamDlg* Mask::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp) {
245 IAutoMParamDlg* masterDlg = maskCD.CreateParamDlgs(hwMtlEdit, imp, this);
246 //attach a dlg proc to handle the swap button
247 // add the secondary dialogs to the master
248 return masterDlg;
249
250 }
251
Update(TimeValue t,Interval & valid)252 void Mask::Update(TimeValue t, Interval& valid) {
253
254 if (Param1)
255 {
256 pblock->SetValue( mask_map1_on, 0, mapOn[0]);
257 pblock->SetValue( mask_map2_on, 0, mapOn[1]);
258 pblock->SetValue( mask_invert, 0, invertMask);
259 Param1 = FALSE;
260 }
261
262 if (!ivalid.InInterval(t)) {
263
264 ivalid.SetInfinite();
265
266 pblock->GetValue( mask_map1_on, t, mapOn[0], ivalid);
267 pblock->GetValue( mask_map2_on, t, mapOn[1], ivalid);
268 pblock->GetValue( mask_invert, t, invertMask, ivalid);
269
270 for (int i=0; i<NSUBTEX; i++) {
271 if (subTex[i])
272 subTex[i]->Update(t,ivalid);
273 }
274 }
275 valid &= ivalid;
276 }
277
GetReference(int i)278 RefTargetHandle Mask::GetReference(int i) {
279 if (i <2 )
280 return subTex[i];
281 else return pblock;
282 }
283
SetReference(int i,RefTargetHandle rtarg)284 void Mask::SetReference(int i, RefTargetHandle rtarg) {
285 if (i < 2)
286 subTex[i] = (Texmap *)rtarg;
287 else pblock = (IParamBlock2 *)rtarg;
288 }
289
SetSubTexmap(int i,Texmap * m)290 void Mask::SetSubTexmap(int i, Texmap *m) {
291 ReplaceReference(i,m);
292 if (i==0)
293 {
294 mask_param_blk.InvalidateUI(mask_map1);
295 ivalid.SetEmpty();
296 }
297 else if (i==1)
298 {
299 mask_param_blk.InvalidateUI(mask_map2);
300 ivalid.SetEmpty();
301 }
302
303 }
304
GetSubTexmapSlotName(int i)305 TSTR Mask::GetSubTexmapSlotName(int i) {
306 switch(i) {
307 case 0: return TSTR(GetString(IDS_DS_MAP));
308 case 1: return TSTR(GetString(IDS_DS_MASK));
309 default: return TSTR(_T(""));
310 }
311 }
312
SubAnim(int i)313 Animatable* Mask::SubAnim(int i) {
314 if (i < 2)
315 return subTex[i];
316 else return pblock;
317 }
318
SubAnimName(int i)319 TSTR Mask::SubAnimName(int i) {
320 if (i< 2)
321 return GetSubTexmapTVName(i);
322 else return TSTR(_T(""));
323 }
324
NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget,PartID & partID,RefMessage message)325 RefResult Mask::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
326 PartID& partID, RefMessage message ) {
327 switch (message) {
328 case REFMSG_CHANGE:
329 ivalid.SetEmpty();
330 if (hTarget == pblock)
331 {
332 //if (paramDlg&&!paramDlg->isActive)
333 ParamID changing_param = pblock->LastNotifyParamID();
334 mask_param_blk.InvalidateUI(changing_param);
335 }
336
337 // if (paramDlg)
338 // paramDlg->Invalidate();
339 break;
340
341 }
342 return(REF_SUCCEED);
343 }
344
345
346 #define MTL_HDR_CHUNK 0x4000
347 #define MAPOFF_CHUNK 0x1000
348 #define INVERT_MASK_CHUNK 0x2000
349 #define PARAM2_CHUNK 0x2010
350
Save(ISave * isave)351 IOResult Mask::Save(ISave *isave) {
352 IOResult res;
353 // Save common stuff
354 isave->BeginChunk(MTL_HDR_CHUNK);
355 res = MtlBase::Save(isave);
356 if (res!=IO_OK) return res;
357 isave->EndChunk();
358
359 isave->BeginChunk(PARAM2_CHUNK);
360 isave->EndChunk();
361 return IO_OK;
362 }
363
364
365 //watje
366 class MaskPostLoadCallback:public PostLoadCallback
367 {
368 public:
369 Mask *s;
370 int loadedChecks;
MaskPostLoadCallback(Mask * r,BOOL b)371 MaskPostLoadCallback(Mask *r, BOOL b) {s=r;loadedChecks = b;}
372 void proc(ILoad *iload);
373 };
374
proc(ILoad * iload)375 void MaskPostLoadCallback::proc(ILoad *iload)
376 {
377 if (loadedChecks)
378 {
379 s->pblock->SetValue( mask_map1_on, 0, s->mapOn[0]);
380 s->pblock->SetValue( mask_map2_on, 0, s->mapOn[1]);
381 s->pblock->SetValue( mask_invert, 0, s->invertMask);
382 }
383 delete this;
384 }
385
386
Load(ILoad * iload)387 IOResult Mask::Load(ILoad *iload) {
388 // ULONG nb;
389 IOResult res;
390 int id;
391 // BOOL loadedChecks = FALSE;
392 Param1 = TRUE;
393 while (IO_OK==(res=iload->OpenChunk())) {
394 switch(id = iload->CurChunkID()) {
395 case MTL_HDR_CHUNK:
396 res = MtlBase::Load(iload);
397 break;
398 case MAPOFF_CHUNK+0:
399 case MAPOFF_CHUNK+1:
400 mapOn[id-MAPOFF_CHUNK] = 0;
401 break;
402 case INVERT_MASK_CHUNK:
403 invertMask = 1;
404 break;
405 case PARAM2_CHUNK:
406 Param1 = FALSE;
407 break;
408 }
409 iload->CloseChunk();
410 if (res!=IO_OK)
411 return res;
412 }
413
414 // MaskPostLoadCallback* maskplcb = new MaskPostLoadCallback(this,loadedChecks);
415 // iload->RegisterPostLoadCallback(maskplcb);
416
417 return IO_OK;
418 }
419
420
421 //������������������������������������������������������������������������
422 // This map is not meaningful unless all of its submaps are on.
423 //
IsLocalOutputMeaningful(ShadeContext & sc)424 bool Mask::IsLocalOutputMeaningful( ShadeContext& sc )
425 {
426 for ( int i = 0; i < NumSubTexmaps(); i++ )
427 {
428 if ( SubTexmapOn( i ) && ( GetSubTexmap( i ) != NULL ) )
429 return true;
430 }
431
432 return false;
433 }
434