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