1 /*===========================================================================*\
2  |    File: Splat.cpp
3  |
4  | Purpose: A 3D Map for creating splatd surface textures.
5  |          This is a port of the 3D Studio/DOS SXP by Dan Silva.
6  |
7  | History: Mark Meier, Began 02/03/97.
8  |          MM, Last Change 02/03/97.
9  |			Updated to Param Block2 by Peter Watje 12/1/1998
10  |			MM, 02/99, Bug fix.
11 \*===========================================================================*/
12 /*===========================================================================*\
13  | Include Files
14 \*===========================================================================*/
15 #include "procmaps.h"
16 #include "iparamm2.h"
17 #include "resource.h"
18 #include "resourceOverride.h"
19 #include "macrorec.h"
20 
21 /*===========================================================================*\
22  | Miscellaneous Defines
23 \*===========================================================================*/
24 
25 #define SHOW_3DMAPS_WITH_2D
26 
27 // The unique ClassID
28 static Class_ID splatClassID(SPLAT_CLASS_ID, 0);
29 
30 // This is the number of colors used
31 #define NUM_COLORS 2
32 
33 // This is the number of sub-texmaps used
34 #define NUM_SUB_TEXMAPS 2
35 
36 // This is the version number of the IPAS SXP files that can be read
37 #define SPLAT_SXP_VERSION 0xE041
38 
39 #define EPSILON 0.02f
40 
41 struct Col24 {
42 	ULONG r, g, b;
43 };
44 
ColorFromCol24(Col24 a)45 static Color ColorFromCol24(Col24 a) {
46 	Color c;
47 	c.r = (float)a.r/255.0f;
48 	c.g = (float)a.g/255.0f;
49 	c.b = (float)a.b/255.0f;
50 	return c;
51 }
52 
53 #pragma pack(1)
54 struct SplatState {
55 	ulong version;
56 	float size, thresh;
57 	int init;
58 	Col24 col1, col2;
59 	float strength;
60 };
61 #pragma pack()
62 
63 // These are various resource IDs
64 static int colID[2] = { IDC_COL1, IDC_COL2 };
65 static int subTexId[NUM_SUB_TEXMAPS] = { IDC_TEX1, IDC_TEX2 };
66 static int mapOnId[NUM_SUB_TEXMAPS] = { IDC_MAPON1, IDC_MAPON2 };
67 
68 // Forward references
69 //class Splat;
70 //class SplatDlgProc;
71 
72 /*===========================================================================*\
73  | Splat 3D Texture Map Plug-In Class
74 \*===========================================================================*/
75 class Splat : public Tex3D {
76 	// This allows the class that manages the UI to access the private
77 	// data members of this class.
78 //	friend class SplatDlg;
79 
80 	// This is the function that actually computes the speckling.
81 	float splatter(Point3 p);
82 
83 	// These are the current colors from the color swatch controls.
84 	Color col[NUM_COLORS];
85 
86 	// These are the parameters managed by the parameter map
87 	float size;
88 	float thresh;
89 	int iter;
90 	Point3 col1, col2;
91 
92 	// This points to the XYZGen instance used to handle the
93 	// 'Coordinates' rollup in the materials editor.
94 	// This is reference #0 of this class.
95 	XYZGen *xyzGen;
96 	// These are the sub-texmaps.  If these are set by the user
97 	// then the color of our texture is affected by the sub-texmaps
98 	// and not the color swatches.
99 	// These are reference #2 and #3 of this class.
100 	Texmap *subTex[NUM_SUB_TEXMAPS];
101 	// Indicates if a sub-texmap is to be used or not
102 	// This holds the validity interval of the texmap.
103 	Interval texValidity;
104 	// This is the version of the texture loaded from disk.
105 	int fileVersion;
106 	// This points to the ParamDlg instance used to manage the UI
107 //	SplatDlg *paramDlg;
108 
109 #ifdef SHOW_3DMAPS_WITH_2D
110 	TexHandle *texHandle;
111 	Interval texHandleValid;
112 #endif
113 
114 	public:
115 		static ParamDlg* xyzGenDlg;
116 	// This is the parameter block which manages the data for the
117 	// spinner and color swatch controls.
118 	// This is reference #1 of this class.
119 		IParamBlock2 *pblock;
120 		BOOL mapOn[NUM_SUB_TEXMAPS];
121 		// --- Methods inherited from Animatable ---
ClassID()122 		Class_ID ClassID() { return splatClassID; }
SuperClassID()123 		SClass_ID SuperClassID() { return TEXMAP_CLASS_ID; }
GetClassName(TSTR & s)124 		void GetClassName(TSTR& s) { s= GetString(IDS_DS_SPLAT); }
DeleteThis()125 		void DeleteThis() { delete this; }
126 
127 		// We have 4 sub-animatables.  These are the xyzGen,
128 		// the pblock, and the two sub-texmaps
NumSubs()129 		int NumSubs() { return 2+NUM_SUB_TEXMAPS; }
130 		Animatable* SubAnim(int i);
131 		TSTR SubAnimName(int i);
SubNumToRefNum(int subNum)132 		int SubNumToRefNum(int subNum) { return subNum; }
133 
134 		// --- Methods inherited from ReferenceMaker ---
135 		// We have 4 references.  These are the xyzGen,
136 		// the pblock, and the two sub-texmaps
NumRefs()137  		int NumRefs() { return 2+NUM_SUB_TEXMAPS; }
138 		RefTargetHandle GetReference(int i);
139 		void SetReference(int i, RefTargetHandle rtarg);
140 		RefResult NotifyRefChanged(Interval changeInt,
141 			RefTargetHandle hTarget, PartID& partID, RefMessage message);
142 		IOResult Save(ISave *isave);
143 		IOResult Load(ILoad *iload);
144 
145 		// --- Methods inherited from ReferenceTarget ---
146 		RefTargetHandle Clone(RemapDir &remap = DefaultRemapDir());
147 
148 		// --- Methods inherited from MtlBase ---
LocalRequirements(int subMtlNum)149 		ULONG LocalRequirements(int subMtlNum) {
150 			return xyzGen->Requirements(subMtlNum);
151 		}
LocalMappingsRequired(int subMtlNum,BitArray & mapreq,BitArray & bumpreq)152 		void LocalMappingsRequired(int subMtlNum, BitArray & mapreq, BitArray &bumpreq) {
153 			xyzGen->MappingsRequired(subMtlNum,mapreq,bumpreq);
154 		}
155 		void Update(TimeValue t, Interval& ivalid);
156 		void Init();
157 		void Reset();
158 		Interval Validity(TimeValue t);
159 		ParamDlg* CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp);
NumSubTexmaps()160 		int NumSubTexmaps() { return NUM_SUB_TEXMAPS; }
161 		Texmap* GetSubTexmap(int i);
162 		void SetSubTexmap(int i, Texmap *m);
163 		TSTR GetSubTexmapSlotName(int i);
164 
165 		// --- Methods inherited from Texmap ---
GetTheXYZGen()166 		XYZGen *GetTheXYZGen() { return xyzGen; }
167 		RGBA EvalColor(ShadeContext& sc);
168 		Point3 EvalNormalPerturb(ShadeContext& sc);
169 
170 		// --- Methods inherited from Tex3D ---
171 		void ReadSXPData(TCHAR *name, void *sxpdata);
172 
173 		// --- Methods of Splat ---
174 		Splat();
~Splat()175 		~Splat() {
176 #ifdef SHOW_3DMAPS_WITH_2D
177 			DiscardTexHandle();
178 #endif
179 			}
180 		void SwapInputs();
181 		void NotifyChanged();
182 		void SetSize(float f, TimeValue t);
183 		void SetThresh(float f, TimeValue t);
184 		void SetIter(int i, TimeValue t);
185 		void SetColor(int i, Color c, TimeValue t);
186 		void ClampFloat(float &f, float min, float max);
187 		void ClampInt(int &i, int min, int max);
188 
189 #ifdef SHOW_3DMAPS_WITH_2D
DiscardTexHandle()190 		void DiscardTexHandle() {
191 			if (texHandle) {
192 				texHandle->DeleteThis();
193 				texHandle = NULL;
194 				}
195 			}
SupportTexDisplay()196 		BOOL SupportTexDisplay() { return TRUE; }
ActivateTexDisplay(BOOL onoff)197 		void ActivateTexDisplay(BOOL onoff) {
198 			if (!onoff) DiscardTexHandle();
199 			}
200 		DWORD_PTR GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker);
201 #endif SHOW_3DMAPS_WITH_2D
202 
203 
204 // JBW: direct ParamBlock access is added
NumParamBlocks()205 		int	NumParamBlocks() { return 1; }					// return number of ParamBlocks in this instance
GetParamBlock(int i)206 		IParamBlock2* GetParamBlock(int i) { return pblock; } // return i'th ParamBlock
GetParamBlockByID(BlockID id)207 		IParamBlock2* GetParamBlockByID(BlockID id) { return (pblock->ID() == id) ? pblock : NULL; } // return id'd ParamBlock
208 		BOOL SetDlgThing(ParamDlg* dlg);
209 
IsLocalOutputMeaningful(ShadeContext & sc)210 		bool IsLocalOutputMeaningful( ShadeContext& sc ) { return true; }
211 };
212 
213 // This is the Class Descriptor for the Splat 3D Texture plug-in
214 class SplatClassDesc : public ClassDesc2 {
215 	public:
IsPublic()216 		int 			IsPublic() { return GetAppID() != kAPP_VIZR; }
Create(BOOL loading)217 		void *			Create(BOOL loading) { 	return new Splat; }
ClassName()218 		const TCHAR *	ClassName() { return GetString(IDS_DS_SPLAT_CDESC); } // mjm - 2.3.99
SuperClassID()219 		SClass_ID		SuperClassID() { return TEXMAP_CLASS_ID; }
ClassID()220 		Class_ID 		ClassID() { return splatClassID; }
Category()221 		const TCHAR* 	Category() { return TEXMAP_CAT_3D; }
222 // JBW: new descriptor data accessors added.  Note that the
223 //      internal name is hardwired since it must not be localized.
InternalName()224 		const TCHAR*	InternalName() { return _T("splat"); }	// returns fixed parsable name (scripter-visible name)
HInstance()225 		HINSTANCE		HInstance() { return hInstance; }			// returns owning module handle
226 };
227 static SplatClassDesc splatCD;
GetSplatDesc()228 ClassDesc *GetSplatDesc() { return &splatCD; }
229 ParamDlg* Splat::xyzGenDlg;
230 
231 /*===========================================================================*\
232  | Class to Manage the User Interface in the Materials Editor
233 \*===========================================================================*/
234 /*
235 class SplatDlg: public ParamDlg {
236 	public:
237 		// This is our UI rollup page window handle in the materials editor
238 		HWND hParamDlg;
239 		// Window handle of the materials editor dialog itself
240 		HWND hMedit;
241 		// Interface for calling methods provided by MAX
242 		IMtlParams *ip;
243 		// The current Splat being edited.
244 		Splat *theTex;
245 		// Parameter Map for handling UI controls
246 		IParamMap *pmap;
247 		// Custom buttons for texture maps
248 		ICustButton *iCustButton[NUM_SUB_TEXMAPS];
249 		// Custom conrols for the colors
250 		IColorSwatch *cs[NUM_COLORS];
251 		// This is used inside the SetTime method to only update the UI
252 		// controls when the time slider has changed
253 		TimeValue curTime;
254 		// Point to the XYZGenDlg we use
255 		ParamDlg *xyzGenDlg;
256 		BOOL valid;
257 		BOOL isActive;
258 		TexDADMgr dadMgr;
259 
260 		// --- Methods inherited from ParamDlg ---
261 		Class_ID ClassID();
262 		void SetThing(ReferenceTarget *m);
263 		ReferenceTarget* GetThing();
264 		void SetTime(TimeValue t);
265 		int FindSubTexFromHWND(HWND hw);
266 		void ReloadDialog();
267 		void ActivateDlg(BOOL onOff);
268 		void DeleteThis() { delete this; }
269 
270 		// --- SplatDlg Methods ---
271 		SplatDlg(HWND hwMtlEdit, IMtlParams *imp, Splat *m);
272 		~SplatDlg();
273 		INT_PTR PanelProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
274 		void UpdateSubTexNames();
275 		void LoadDialog();
276 		void UpdateMtlDisplay() { ip->MtlChanged(); }
277 		void Invalidate();
278 };
279 */
280 /*===========================================================================*\
281  | Parameter Map Related Data and Methods
282 \*===========================================================================*/
283 // Parameter block indices
284 /*
285 #define PB_SIZE		0
286 #define PB_THRESH	1
287 #define PB_ITER		2
288 #define PB_COL1		3
289 #define PB_COL2		4
290 */
291 // Spinner limits
292 #define MIN_SIZE 0.001f
293 #define MAX_SIZE 999999999.0f
294 
295 #define MIN_THRESH 0.0f
296 #define MAX_THRESH 1.0f
297 
298 #define MIN_ITER 1
299 #define MAX_ITER 10
300 
301 // Paramter block version number
302 #define SPLAT_PB_VERSION 2
303 
304 
305 enum { splat_params };  // pblock ID
306 // grad_params param IDs
307 enum
308 {
309 	splat_size,splat_iteration,splat_threshold,
310 	splat_color1, splat_color2,
311 	splat_map1, splat_map2,
312 	splat_mapon1,splat_mapon2,
313 	splat_coords,	  // access for UVW mapping
314 };
315 
316 
317 static ParamBlockDesc2 splat_param_blk ( splat_params, _T("parameters"),  0, &splatCD, P_AUTO_CONSTRUCT + P_AUTO_UI, 1,
318 	//rollout
319 	IDD_SPLAT, IDS_DS_SPLAT_PARAMS, 0, 0, NULL,
320 	// params
321 
322 
323 	splat_size,	_T("size"),   TYPE_FLOAT,			P_ANIMATABLE,	IDS_DS_SIZE,
324 		p_default,		40.f,
325 		p_range,		MIN_SIZE, MAX_SIZE,
326 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT, IDC_SIZE_EDIT,IDC_SIZE_SPIN, 0.1f,
327 		end,
328 	splat_iteration,	_T("iterations"),   TYPE_INT,		P_ANIMATABLE,	IDS_DS_ITER,
329 		p_default,		4,
330 		p_range,		MIN_ITER, MAX_ITER,
331 		p_ui, 			TYPE_SPINNER, EDITTYPE_INT, IDC_ITER_EDIT,IDC_ITER_SPIN, 1.f,
332 		end,
333 	splat_threshold,	_T("threshold"),   TYPE_FLOAT,			P_ANIMATABLE,	IDS_DS_THRESH,
334 		p_default,		0.2f,
335 		p_range,		MIN_THRESH, MAX_THRESH,
336 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT, IDC_THRESH_EDIT,IDC_THRESH_SPIN, 0.1f,
337 		end,
338 	splat_color1,	 _T("color1"),	TYPE_RGBA,				P_ANIMATABLE,	IDS_DS_COL1,
339 		p_default,		Color(0.7f, 0.8f, 0.8f),
340 		p_ui,			TYPE_COLORSWATCH, IDC_COL1,
341 		end,
342 	splat_color2,	 _T("color2"),	TYPE_RGBA,				P_ANIMATABLE,	IDS_DS_COL2,
343 		p_default,		Color(0.2f, 0.5f, 1.0f),
344 		p_ui,			TYPE_COLORSWATCH, IDC_COL2,
345 		end,
346 	splat_map1,		_T("map1"),		TYPE_TEXMAP,			P_OWNERS_REF,	IDS_PW_MAP1,
347 		p_refno,		2,
348 		p_subtexno,		0,
349 		p_ui,			TYPE_TEXMAPBUTTON, IDC_TEX1,
350 		end,
351 	splat_map2,		_T("map2"),		TYPE_TEXMAP,			P_OWNERS_REF,	IDS_PW_MAP2,
352 		p_refno,		3,
353 		p_subtexno,		1,
354 		p_ui,			TYPE_TEXMAPBUTTON, IDC_TEX2,
355 		end,
356 	splat_mapon1,	_T("map1On"), TYPE_BOOL,			0,				IDS_PW_MAPON1,
357 		p_default,		TRUE,
358 		p_ui,			TYPE_SINGLECHEKBOX, IDC_MAPON1,
359 		end,
360 	splat_mapon2,	_T("map2On"), TYPE_BOOL,			0,				IDS_PW_MAPON2,
361 		p_default,		TRUE,
362 		p_ui,			TYPE_SINGLECHEKBOX, IDC_MAPON2,
363 		end,
364 	splat_coords,		_T("coords"),	TYPE_REFTARG,		P_OWNERS_REF,	IDS_PW_COORDINATES,
365 		p_refno,		0,
366 		end,
367 
368 	end
369 );
370 
371 /*
372 // Array of parameter descriptors
373 static ParamUIDesc paramDesc[] = {
374 	ParamUIDesc(
375 		PB_SIZE,
376 		EDITTYPE_FLOAT,
377 		IDC_SIZE_EDIT,IDC_SIZE_SPIN,
378 		MIN_SIZE, MAX_SIZE,
379 		SPIN_AUTOSCALE),
380 
381 	ParamUIDesc(
382 		PB_THRESH,
383 		EDITTYPE_FLOAT,
384 		IDC_THRESH_EDIT,IDC_THRESH_SPIN,
385 		MIN_THRESH, MAX_THRESH,
386 		SPIN_AUTOSCALE),
387 
388 	ParamUIDesc(
389 		PB_ITER,
390 		EDITTYPE_INT,
391 		IDC_ITER_EDIT,IDC_ITER_SPIN,
392 		MIN_ITER, MAX_ITER,
393 		SPIN_AUTOSCALE),
394 
395 	ParamUIDesc(PB_COL1, TYPE_COLORSWATCH, IDC_COL1),
396 	ParamUIDesc(PB_COL2, TYPE_COLORSWATCH, IDC_COL2)
397 };
398 */
399 // The number of descriptors in the paramDesc array
400 #define PARAMDESC_LENGTH 5
401 
402 // Parameter block parameters
403 static ParamBlockDescID pbdesc[] = {
404 	{ TYPE_FLOAT, NULL, TRUE, splat_size }, // size
405 	{ TYPE_FLOAT, NULL, TRUE, splat_threshold }, // thresh
406 	{ TYPE_INT,   NULL, TRUE, splat_iteration }, // iter
407 	{ TYPE_RGBA,  NULL, TRUE, splat_color1 }, // color 1
408 	{ TYPE_RGBA,  NULL, TRUE, splat_color2 }  // color 2
409 };
410 // The number of parameters in the parameter block
411 #define PB_LENGTH 5
412 
413 static ParamVersionDesc versions[] = {
414 	ParamVersionDesc(pbdesc,5,1)	// Version 1 params
415 	};
416 
417 // The names of the parameters in the parameter block
418 static int nameIDs[] = { IDS_DS_SIZE, IDS_DS_THRESH, IDS_DS_ITER, IDS_DS_COL1, IDS_DS_COL2 };
419 /*
420 // This is the class that allows the sub-map buttons to be processed.
421 class SplatDlgProc : public ParamMapUserDlgProc {
422 	public:
423 		SplatDlg *theDlg;
424 		SplatDlgProc(SplatDlg *s) { theDlg = s; }
425 		INT_PTR DlgProc(TimeValue t, IParamMap *map,
426 			HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
427 		void DeleteThis() { delete this; }
428 };
429 
430 // This is the dialog proc to process the texmap buttons
431 INT_PTR SplatDlgProc::DlgProc(TimeValue t, IParamMap *map,
432 	HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
433 	theDlg->isActive = TRUE;
434 	BOOL res = theDlg->PanelProc(hWnd, msg, wParam, lParam);
435 	theDlg->isActive = FALSE;
436 	return res;
437 }
438 
439 INT_PTR SplatDlg::PanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
440 	int id = LOWORD(wParam);
441 	int code = HIWORD(wParam);
442     switch (msg) {
443 		case WM_INITDIALOG: {
444 			for (int i = 0; i < NUM_COLORS; i++)
445    				cs[i] = GetIColorSwatch(GetDlgItem(hParamDlg, colID[i]),
446    					theTex->col[i], theTex->GetSubTexmapSlotName(i).data());
447 			for (i = 0; i < NUM_SUB_TEXMAPS; i++) {
448 				iCustButton[i] = GetICustButton(GetDlgItem(hWnd, subTexId[i]));
449 				iCustButton[i]->SetDADMgr(&dadMgr);
450 				SetCheckBox(hWnd, mapOnId[i], theTex->mapOn[i]);
451 			}
452 			return TRUE;
453 		}
454 		break;
455 
456 		case WM_COMMAND:
457 		    switch (id) {
458 				case IDC_TEX1:
459 					PostMessage(hMedit, WM_TEXMAP_BUTTON, 0, (LPARAM)theTex);
460 					break;
461 
462 				case IDC_TEX2:
463 					PostMessage(hMedit, WM_TEXMAP_BUTTON, 1, (LPARAM)theTex);
464 					break;
465 
466 				case IDC_SWAP: {
467 					theTex->SwapInputs();
468 					IParamBlock *pb = (IParamBlock *)pmap->GetParamBlock();
469 					pb->SetValue(PB_COL1, curTime, theTex->col[0]);
470 					pb->SetValue(PB_COL2, curTime, theTex->col[1]);
471 					pmap->Invalidate();
472 					UpdateSubTexNames();
473 					UpdateMtlDisplay();
474 					theTex->NotifyChanged();
475 					}
476 					break;
477 
478 				case IDC_MAPON1:
479 					theTex->mapOn[0] = GetCheckBox(hWnd, id);
480 					theTex->NotifyChanged();
481 					UpdateMtlDisplay();
482 					break;
483 
484 				case IDC_MAPON2:
485 					theTex->mapOn[1] = GetCheckBox(hWnd, id);
486 					theTex->NotifyChanged();
487 					UpdateMtlDisplay();
488 					break;
489 			}
490 			break;
491 
492 		case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE:
493 			ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
494 			return FALSE;
495 
496 		case WM_PAINT:
497 			if (!valid) {
498 				valid = TRUE;
499 				ReloadDialog();
500 			}
501 			break;
502 
503 		case WM_CLOSE:
504 			break;
505 
506 		case WM_DESTROY:
507 			break;
508    	}
509 	return FALSE;
510 }
511 */
512 /*===========================================================================*\
513  | SplatDlg Methods
514 \*===========================================================================*/
515 // --- SplatDlg Methods ---
516 // Constructor.
517 // This is called from within the Splat::CreateParamDlg method.  That
518 // method is passed the handle to the materials editor dialog, and an
519 // interface for calling methods of MAX.  These are passed in here and stored.
520 /*
521 SplatDlg::SplatDlg(HWND hwMtlEdit, IMtlParams *imp, Splat *m) {
522 	dadMgr.Init(this);
523 	hMedit = hwMtlEdit;
524 	ip = imp;
525 	theTex = m;
526     valid = FALSE;
527     isActive = FALSE;
528 	curTime = ip->GetTime();
529 
530 	// This call allocates a new instance of the XYZGen class
531 	xyzGenDlg = theTex->xyzGen->CreateParamDlg(hMedit, imp);
532 
533 	// Creates a parameter map to handle the display of texture map
534 	// parameters in the material editor
535 	pmap = CreateMParamMap(paramDesc, PARAMDESC_LENGTH,
536 		theTex->pblock, ip, hInstance, MAKEINTRESOURCE(IDD_SPLAT),
537 		GetString(IDS_DS_SPLAT_PARAMS), 0);
538 
539 	// Save the window handle of the rollup page
540 	hParamDlg = pmap->GetHWnd();
541 
542 	// Establish the dialog proc to handle the custom button controls
543 	pmap->SetUserDlgProc(new SplatDlgProc(this));
544 }
545 
546 // Destructor.
547 // This is called after the user changes to another sample slot in
548 // the materials editor that does not contain a Splat texture.
549 // Note that it is not called if they do go to another Splat -- in
550 // that case, the parameters in the rollup page are updated, but
551 // the entire page is not deleted.  This is accomplished by simply
552 // changing the parameter block pointer (done inside SplatDlg::SetThing()).
553 SplatDlg::~SplatDlg() {
554 	theTex->paramDlg = NULL;
555 	for (int i = 0; i < NUM_SUB_TEXMAPS; i++) {
556 		ReleaseICustButton(iCustButton[i]);
557 		iCustButton[i] = NULL;
558 	}
559 	// Delete the XYZGen class we created
560 	xyzGenDlg->DeleteThis();
561 	// Delete the parameter map
562 	DestroyMParamMap(pmap);
563 	pmap = NULL;
564 }
565 
566 // This is called by the DADMgr
567 int SplatDlg::FindSubTexFromHWND(HWND hw) {
568 	for (int i=0; i<NUM_SUB_TEXMAPS; i++) {
569 		if (hw == iCustButton[i]->GetHwnd()) return i;
570 		}
571 	return -1;
572 	}
573 
574 
575 // This is called when the dialog is loaded to set the names of the
576 // textures displayed
577 void SplatDlg::UpdateSubTexNames() {
578 	for (int i = 0; i < NUM_SUB_TEXMAPS; i++) {
579 		TSTR nm;
580 		Texmap *m = theTex->subTex[i];
581 		if (m)
582 			nm = m->GetFullName();
583 		else
584 			nm = GetString(IDS_DS_NONE);
585 		iCustButton[i]->SetText(nm.data());
586 	}
587 }
588 
589 // Update the dialog display with the values of the texture we are
590 // currently editing.
591 void SplatDlg::LoadDialog() {
592 	if (theTex) {
593 		Interval ivalid;
594 		theTex->Update(curTime, ivalid);
595 
596 		ISpinnerControl *spin = (ISpinnerControl *)
597 			GetISpinner(GetDlgItem(hParamDlg, IDC_SIZE_SPIN));
598 		spin->SetValue(theTex->size, FALSE);
599 		ReleaseISpinner(spin);
600 		spin = (ISpinnerControl *)
601 			GetISpinner(GetDlgItem(hParamDlg, IDC_THRESH_SPIN));
602 		spin->SetValue(theTex->thresh, FALSE);
603 		ReleaseISpinner(spin);
604 		spin = (ISpinnerControl *)
605 			GetISpinner(GetDlgItem(hParamDlg, IDC_ITER_SPIN));
606 		spin->SetValue(theTex->iter, FALSE);
607 		ReleaseISpinner(spin);
608 
609 		cs[0]->SetColor(theTex->col[0]);
610 		cs[1]->SetColor(theTex->col[1]);
611 
612 		UpdateSubTexNames();
613 	}
614 }
615 
616 // This method invalidates the rollup page so it will get redrawn
617 void SplatDlg::Invalidate() {
618 	InvalidateRect(hParamDlg, NULL, FALSE);
619 	valid = FALSE;
620 }
621 
622 // --- Methods inherited from ParamDlg ---
623 // Returns the Class_ID of the plug-in this dialog manages
624 Class_ID SplatDlg::ClassID() {
625 	return splatClassID;
626 }
627 
628 // This sets the current texture being edited to the texture passed
629 void SplatDlg::SetThing(ReferenceTarget *m) {
630 	assert(m->ClassID() == splatClassID);
631 	assert(m->SuperClassID() == TEXMAP_CLASS_ID);
632 	if (theTex)
633 		theTex->paramDlg = NULL;
634 
635 	// Set the pointer to the texmap being edited to the one passed.
636 	theTex = (Splat *)m;
637 
638 	// Point the parameter map parameter block pointer at the
639 	// one that is now being edited.
640 	pmap->SetParamBlock(theTex->pblock);
641 	if (theTex)
642 		theTex->paramDlg = this;
643 
644 	// Let the XYZGen set the new one being edited
645 	xyzGenDlg->SetThing(theTex->xyzGen);
646 
647 	// Update the dialog display with the values of the new texmap.
648 	LoadDialog();
649 }
650 
651 // This returns the current texture being edited
652 ReferenceTarget *SplatDlg::GetThing() {
653 	return (ReferenceTarget *)theTex;
654 }
655 
656 // This method is called when the current time has changed.
657 // This gives the developer an opportunity to update any user
658 // interface data that may need adjusting due to the change in time.
659 void SplatDlg::SetTime(TimeValue t) {
660 	Interval ivalid;
661 	if (t != curTime) {
662 		xyzGenDlg->SetTime(t);
663 		curTime = t;
664 		theTex->Update(curTime, ivalid);
665 		LoadDialog();
666 		InvalidateRect(hParamDlg, NULL, 0);
667 	}
668 }
669 
670 // This method should place values into all the parameter dialog's controls,
671 // edit fields etc.
672 void SplatDlg::ReloadDialog() {
673 	Interval ivalid;
674 	theTex->Update(curTime, ivalid);
675 	LoadDialog();
676 }
677 
678 // This method is called when the dialog box becomes active or inactive.
679 void SplatDlg::ActivateDlg(BOOL onOff) {
680 	for (int i = 0; i < NUM_COLORS; i++) {
681 		cs[i]->Activate(onOff);
682 	}
683 }
684 */
685 //dialog stuff to get the Set Ref button
686 class SplatDlgProc : public ParamMap2UserDlgProc {
687 //public ParamMapUserDlgProc {
688 	public:
689 		Splat *splat;
SplatDlgProc(Splat * m)690 		SplatDlgProc(Splat *m) {splat = m;}
691 		INT_PTR DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
DeleteThis()692 		void DeleteThis() {delete this;}
693 	};
694 
695 
696 
DlgProc(TimeValue t,IParamMap2 * map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)697 INT_PTR SplatDlgProc::DlgProc(
698 		TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
699 	{
700 	switch (msg) {
701 		case WM_COMMAND:
702 			switch (LOWORD(wParam))
703 				{
704 				case IDC_SWAP:
705 					{
706 					splat = (Splat*)map->GetParamBlock()->GetOwner();
707 
708 					splat->SwapInputs();
709 					}
710 				break;
711 				}
712 			break;
713 		}
714 	return FALSE;
715 	}
716 
717 /*===========================================================================*\
718  | Splat Methods
719 \*===========================================================================*/
720 // --- Methods inherited from Animatable ---
721 // This method returns a pointer to the 'i-th' sub-anim.
SubAnim(int i)722 Animatable* Splat::SubAnim(int i) {
723 	switch (i) {
724 		case 0: return xyzGen;
725 		case 1: return pblock;
726 		default: return subTex[i-2];
727 	}
728 }
729 
730 // This method returns the name of the 'i-th' sub-anim to appear in track view.
SubAnimName(int i)731 TSTR Splat::SubAnimName(int i) {
732 	switch (i) {
733 		case 0: return GetString(IDS_DS_COORDS);
734 		case 1: return GetString(IDS_DS_PARAMETERS);
735 		default: return GetSubTexmapTVName(i-2);
736 	}
737 }
738 
739 // --- Methods inherited from ReferenceMaker ---
740 // Return the 'i-th' reference
GetReference(int i)741 RefTargetHandle Splat::GetReference(int i) {
742 	switch(i) {
743 		case 0: return xyzGen;
744 		case 1:	return pblock ;
745 		default:return subTex[i-2];
746 	}
747 }
748 
749 // Save the 'i-th' reference
SetReference(int i,RefTargetHandle rtarg)750 void Splat::SetReference(int i, RefTargetHandle rtarg) {
751 	switch(i) {
752 		case 0: xyzGen = (XYZGen *)rtarg; break;
753 		case 1:	pblock = (IParamBlock2 *)rtarg; break;
754 		default: subTex[i-2] = (Texmap *)rtarg; break;
755 	}
756 }
757 
758 // This method is responsible for responding to the change notification
759 // messages sent by the texmap dependants.
NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget,PartID & partID,RefMessage message)760 RefResult Splat::NotifyRefChanged(Interval changeInt,
761 	RefTargetHandle hTarget, PartID& partID, RefMessage message ) {
762 	switch (message) {
763 		case REFMSG_CHANGE:
764 			// One of the texmap dependants have changed.  We set our
765 			// validity interval to empty and invalidate the dialog
766 			// so it gets redrawn.
767 //			texValidity.SetEmpty();
768 //			if (hTarget != xyzGen) {
769 //				if (paramDlg)
770 //					paramDlg->pmap->Invalidate();
771 //				}
772 			texValidity.SetEmpty();
773 			if (hTarget == pblock)
774 				{
775 
776 				ParamID changing_param = pblock->LastNotifyParamID();
777 				splat_param_blk.InvalidateUI(changing_param);
778 #ifdef SHOW_3DMAPS_WITH_2D
779 				if (changing_param != -1)
780 					DiscardTexHandle();
781 #endif
782 				}
783 #ifdef SHOW_3DMAPS_WITH_2D
784 			else if (hTarget == xyzGen)
785 				{
786 				DiscardTexHandle();
787 				}
788 #endif
789 
790 			break;
791 /*
792 		case REFMSG_GET_PARAM_DIM: {
793 			// This returns the 'dimension' of the parameter.  This is
794 			// the type and order of magnitude of the parameter.
795 			GetParamDim *gpd = (GetParamDim *)partID;
796 			switch (gpd->index) {
797 				case PB_SIZE:	gpd->dim =  stdWorldDim; break;
798 				case PB_THRESH:
799 				case PB_ITER:
800 					gpd->dim = defaultDim; break;
801 				case PB_COL1:
802 				case PB_COL2: gpd->dim = stdColor255Dim; break;
803 			}
804 			return REF_STOP;
805 		}
806 
807 		case REFMSG_GET_PARAM_NAME: {
808 			// This returns the name that will appear in track view
809 			// of the parameter.
810 			GetParamName *gpn = (GetParamName *)partID;
811 			gpn->name = GetString(nameIDs[gpn->index]);
812 			return REF_STOP;
813 		}
814 */
815 	}
816 	return(REF_SUCCEED);
817 }
818 
819 // Load/Save Chunk IDs
820 #define MTL_HDR_CHUNK			0x4000
821 #define SPLAT_VERS1_CHUNK		0x4001
822 #define MAPOFF_CHUNK			0x1000
823 #define PARAM2_CHUNK			0x1010
824 
825 // This is called by the system to allow the plug-in to save its data
Save(ISave * isave)826 IOResult Splat::Save(ISave *isave) {
827 	IOResult res;
828 
829 	// Save the common stuff from the base class
830 	isave->BeginChunk(MTL_HDR_CHUNK);
831 	res = MtlBase::Save(isave);
832 	if (res != IO_OK)
833 		return res;
834 	isave->EndChunk();
835 	isave->BeginChunk(PARAM2_CHUNK);
836 	isave->EndChunk();
837 /*
838 	// Save a version number chunk
839 	isave->BeginChunk(SPLAT_VERS1_CHUNK);
840 	isave->EndChunk();
841 	// Save the on/off status of the sub-texmaps
842 	for (int i = 0; i < NUM_SUB_TEXMAPS; i++) {
843 		if (mapOn[i] == 0) {
844 			isave->BeginChunk(MAPOFF_CHUNK+i);
845 			isave->EndChunk();
846 		}
847 	}
848 */
849 	return IO_OK;
850 }
851 
852 class SplatPostLoad : public PostLoadCallback {
853 	public:
854 		Splat *n;
855 		BOOL Param1;
SplatPostLoad(Splat * ns,BOOL b)856 		SplatPostLoad(Splat *ns, BOOL b) {n = ns; Param1 = b;}
proc(ILoad * iload)857 		void proc(ILoad *iload) {
858 			if (Param1)
859 				{
860 				n->pblock->SetValue( splat_mapon1, 0, n->mapOn[0]);
861 				n->pblock->SetValue( splat_mapon2, 0, n->mapOn[1]);
862 				}
863 			delete this;
864 
865 
866 			}
867 	};
868 
869 
870 
871 // This is called by the system to allow the plug-in to load its data
Load(ILoad * iload)872 IOResult Splat::Load(ILoad *iload) {
873 	IOResult res;
874 	int id;
875 	fileVersion = 0;
876 	BOOL Param1 = TRUE;
877 	while (IO_OK == (res = iload->OpenChunk())) {
878 		switch(id = iload->CurChunkID())  {
879 			case MTL_HDR_CHUNK:
880 				// Load the common stuff from the base class
881 				res = MtlBase::Load(iload);
882 				break;
883 			case SPLAT_VERS1_CHUNK:
884 				// Set the version number
885 				fileVersion = 1;
886 				break;
887 			case PARAM2_CHUNK:
888 				// Set the version number
889 				Param1 = FALSE;;
890 				break;
891 			case MAPOFF_CHUNK+0:
892 			case MAPOFF_CHUNK+1:
893 				// Set the sub-texmap on/off settings
894 				mapOn[id-MAPOFF_CHUNK] = 0;
895 				break;
896 		}
897 		iload->CloseChunk();
898 		if (res != IO_OK)
899 			return res;
900 	}
901 	// JBW: register old version ParamBlock to ParamBlock2 converter
902 	ParamBlock2PLCB* plcb = new ParamBlock2PLCB(versions, 1, &splat_param_blk, this, 1);
903 	iload->RegisterPostLoadCallback(plcb);
904 
905 	iload->RegisterPostLoadCallback(new SplatPostLoad(this,Param1));
906 	return IO_OK;
907 }
908 
909 // --- Methods inherited from ReferenceTarget ---
910 // This method is called to have the plug-in clone itself.
Clone(RemapDir & remap)911 RefTargetHandle Splat::Clone(RemapDir &remap) {
912 	// Create a new instance of the plug-in class
913 	Splat *newSplat = new Splat();
914 
915 	// Copy superclass stuff
916 	*((MtlBase *)newSplat) = *((MtlBase *)this);
917 
918 	// Clone the items we reference
919 	newSplat->ReplaceReference(0, remap.CloneRef(xyzGen));
920 	newSplat->ReplaceReference(1, remap.CloneRef(pblock));
921 	newSplat->col[0] = col[0];
922 	newSplat->col[1] = col[1];
923 	newSplat->size = size;
924 	newSplat->thresh = thresh;
925 	newSplat->iter = iter;
926 	newSplat->texValidity.SetEmpty();
927 	for (int i = 0; i < NUM_SUB_TEXMAPS; i++) {
928 		newSplat->subTex[i] = NULL;
929 		newSplat->mapOn[i] = mapOn[i];
930 		if (subTex[i])
931 			newSplat->ReplaceReference(i+2, remap.CloneRef(subTex[i]));
932 	}
933 	BaseClone(this, newSplat, remap);
934 	// Return the new cloned texture
935 	return (RefTargetHandle)newSplat;
936 }
937 
938 // --- Methods inherited from MtlBase ---
939 // This method is called to return the validity interval of the texmap.
Validity(TimeValue t)940 Interval Splat::Validity(TimeValue t) {
941 	Interval v;
942 	// Calling Update() sets texValidity.
943 	Update(t, v);
944 	return texValidity;
945 }
946 
947 #define IN_TO_M(x) (x / 39.370079f)
948 
949 // This method is called to reset the texmap back to its default values.
Init()950 void Splat::Init() {
951 	// Reset the XYZGen or allocate a new one
952 	if (xyzGen)
953 		xyzGen->Reset();
954 	else
955 		ReplaceReference(0, GetNewDefaultXYZGen());
956 
957 	// Set the inital parameters
958 	SetColor(0, Color(0.7f, 0.8f, 0.8f), TimeValue(0));
959 	SetColor(1, Color(0.2f, 0.5f, 1.0f), TimeValue(0));
960 
961     RegisterDistanceDefault(_T("Splat Params"), _T("Size"), 40.0f, IN_TO_M(40.0f));
962     float size = GetDistanceDefault(_T("Splat Params"), _T("Size"));
963     SetSize(size, TimeValue(0));
964 
965 	SetThresh(0.2f, TimeValue(0));
966 	SetIter(4, TimeValue(0));
967 
968 	// Set the validity interval of the texture to empty
969 	texValidity.SetEmpty();
970 }
971 
Reset()972 void Splat::Reset() {
973 	splatCD.Reset(this, TRUE);	// reset all pb2's
974 	DeleteReference(2);
975 	DeleteReference(3);
976 	Init();
977 	}
978 
Splat()979 Splat::Splat() {
980 #ifdef SHOW_3DMAPS_WITH_2D
981 	texHandle = NULL;
982 #endif
983 	subTex[0] = subTex[1] = NULL;
984 	pblock = NULL;
985 	xyzGen = NULL;
986 //	paramDlg = NULL;
987 	mapOn[0] = mapOn[1] = 1;
988 	splatCD.MakeAutoParamBlocks(this);	// make and intialize paramblock2
989 	Init();
990 	fileVersion = 0;
991 }
992 
993 // This method gets called when the material or texture is to be displayed
994 // in the material editor parameters area.
CreateParamDlg(HWND hwMtlEdit,IMtlParams * imp)995 ParamDlg* Splat::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp) {
996 	// Allocate a new instance of ParamDlg to manage the UI.  This will
997 	// create the rollup page in the materials editor.
998 //	SplatDlg *splatDlg = new SplatDlg(hwMtlEdit, imp, this);
999 	// Update the dialog display with the proper values of the texture.
1000 //	splatDlg->LoadDialog();
1001 //	paramDlg = splatDlg;
1002 //	return splatDlg;
1003 
1004 	xyzGenDlg = xyzGen->CreateParamDlg(hwMtlEdit, imp);
1005 	IAutoMParamDlg* masterDlg = splatCD.CreateParamDlgs(hwMtlEdit, imp, this);
1006 	// add the secondary dialogs to the master
1007 	masterDlg->AddDlg(xyzGenDlg);
1008 	splat_param_blk.SetUserDlgProc(new SplatDlgProc(this));
1009 
1010 	return masterDlg;
1011 
1012 }
1013 
1014 #ifdef SHOW_3DMAPS_WITH_2D
GetActiveTexHandle(TimeValue t,TexHandleMaker & thmaker)1015 DWORD_PTR Splat::GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker) {
1016 	if (texHandle) {
1017 		if (texHandleValid.InInterval(t))
1018 			return texHandle->GetHandle();
1019 		else DiscardTexHandle();
1020 		}
1021 	texHandle = thmaker.MakeHandle(GetVPDisplayDIB(t,thmaker,texHandleValid));
1022 	return texHandle->GetHandle();
1023 	}
1024 #endif
1025 
SetDlgThing(ParamDlg * dlg)1026 BOOL Splat::SetDlgThing(ParamDlg* dlg)
1027 {
1028 	// JBW: set the appropriate 'thing' sub-object for each
1029 	// secondary dialog
1030 	if ((xyzGenDlg!= NULL) && (dlg == xyzGenDlg))
1031 		xyzGenDlg->SetThing(xyzGen);
1032 	else
1033 		return FALSE;
1034 	return TRUE;
1035 }
1036 // This method is called before rendering begins to allow the plug-in
1037 // to evaluate anything prior to the render so it can store this information.
Update(TimeValue t,Interval & ivalid)1038 void Splat::Update(TimeValue t, Interval& ivalid) {
1039 	if (!texValidity.InInterval(t)) {
1040 		texValidity.SetInfinite();
1041 		xyzGen->Update(t, texValidity);
1042 //		pblock->GetValue(PB_COL1, t, col[0], texValidity);
1043 		pblock->GetValue(splat_color1, t, col[0], texValidity);
1044 		col[0].ClampMinMax();
1045 //		pblock->GetValue(PB_COL2, t, col[1], texValidity);
1046 		pblock->GetValue(splat_color2, t, col[1], texValidity);
1047 		col[1].ClampMinMax();
1048 //		pblock->GetValue(PB_SIZE, t, size, texValidity);
1049 		pblock->GetValue(splat_size, t, size, texValidity);
1050 		ClampFloat(size, MIN_SIZE, MAX_SIZE);
1051 //		pblock->GetValue(PB_THRESH, t, thresh, texValidity);
1052 		pblock->GetValue(splat_threshold, t, thresh, texValidity);
1053 		ClampFloat(thresh, MIN_THRESH, MAX_THRESH);
1054 //		pblock->GetValue(PB_ITER, t, iter, texValidity);
1055 		pblock->GetValue(splat_iteration, t, iter, texValidity);
1056 		pblock->GetValue(splat_mapon1, t, mapOn[0], texValidity);
1057 		pblock->GetValue(splat_mapon2, t, mapOn[1], texValidity);
1058 		ClampInt(iter, (int) MIN_ITER, (int) MAX_ITER);
1059 		for (int i = 0; i < NUM_SUB_TEXMAPS; i++) {
1060 			if (subTex[i])
1061 				subTex[i]->Update(t, texValidity);
1062 		}
1063 	}
1064 	ivalid &= texValidity;
1065 }
1066 
ClampFloat(float & f,float min,float max)1067 void Splat::ClampFloat(float &f, float min, float max) {
1068 	if (f < min) f = min;
1069 	else if (f > max) f = max;
1070 }
1071 
ClampInt(int & i,int min,int max)1072 void Splat::ClampInt(int &i, int min, int max) {
1073 	if (i < min) i = min;
1074 	else if (i > max) i = max;
1075 }
1076 
1077 // Returns a pointer to the 'i-th' sub-texmap managed by this texture.
GetSubTexmap(int i)1078 Texmap *Splat::GetSubTexmap(int i) {
1079 	return subTex[i];
1080 }
1081 
1082 // Stores the 'i-th' sub-texmap managed by the material or texture.
SetSubTexmap(int i,Texmap * m)1083 void Splat::SetSubTexmap(int i, Texmap *m) {
1084 	ReplaceReference(i+2, m);
1085 
1086 	if (i==0)
1087 		{
1088 		splat_param_blk.InvalidateUI(splat_map1);
1089 		texValidity.SetEmpty();
1090 		}
1091 	else if (i==1)
1092 		{
1093 		splat_param_blk.InvalidateUI(splat_map2);
1094 		texValidity.SetEmpty();
1095 		}
1096 
1097 //	if (paramDlg)
1098 //		paramDlg->UpdateSubTexNames();
1099 }
1100 
1101 // This name appears in the materials editor dialog when editing the
1102 // 'i-th' sub-map.
GetSubTexmapSlotName(int i)1103 TSTR Splat::GetSubTexmapSlotName(int i) {
1104 	switch(i) {
1105 		case 0:  return GetString(IDS_DS_COL1);
1106 		case 1:  return GetString(IDS_DS_COL2);
1107 		default: return TSTR(_T(""));
1108 	}
1109 }
1110 
1111 // --- Methods inherited from Texmap ---
EvalColor(ShadeContext & sc)1112 RGBA Splat::EvalColor(ShadeContext& sc) {
1113 	// After being evaluated, if a map or material has a non-zero gbufID,
1114 	// it should call ShadeContext::SetGBuffer() to store it into
1115 	// the shade context.
1116 	if (gbufID)
1117 		sc.SetGBufferID(gbufID);
1118 
1119 	// Use the XYZGen instance to get a transformed point from the
1120 	// ShadeContext.
1121 	Point3 p, dp;
1122 	xyzGen->GetXYZ(sc, p, dp);
1123 	if (size == 0.0f)
1124 		size = 0.0001f;
1125 
1126 	float d = splatter(p);
1127 
1128 	// If we have sub-texmaps and they are enabled, get the colors from
1129 	// the sub-texmaps, otherwise get them from the color swatch
1130 	RGBA c0 = (mapOn[0]&&subTex[0]) ? subTex[0]->EvalColor(sc): col[0];
1131 	RGBA c1 = (mapOn[1]&&subTex[1]) ? subTex[1]->EvalColor(sc): col[1];
1132 
1133 	// Composite the colors together and return the result.
1134 	return (1.0f-d)*c0 + d*c1;
1135 }
1136 
EvalNormalPerturb(ShadeContext & sc)1137 Point3 Splat::EvalNormalPerturb(ShadeContext& sc) {
1138 	float del, d, f;
1139 	Point3 p, dp, np;
1140 
1141 	if (gbufID)
1142 		sc.SetGBufferID(gbufID);
1143 
1144 	xyzGen->GetXYZ(sc, p, dp);
1145 
1146 	d = splatter(p);
1147 	del = 0.1f;
1148 //	float strength = (abs((int)col[1].r-(int)col[0].r)+
1149 //				abs((int)col[1].g-(int)col[0].g)+
1150 //				abs((int)col[1].b-(int)col[0].b)); ///100.0f; // 756.0f
1151 
1152 //	f = strength/del;
1153 	f = 1.0f/del;
1154 	Point3 M[3];
1155 	xyzGen->GetBumpDP(sc,M);
1156     np.x = f*(splatter(p+del*M[0]) - d);
1157 	np.y = f*(splatter(p+del*M[1]) - d);
1158 	np.z = f*(splatter(p+del*M[2]) - d);
1159 
1160 	np = sc.VectorFromNoScale(np,REF_OBJECT);
1161 	Texmap *sub0 = mapOn[0]?subTex[0]:NULL;
1162 	Texmap *sub1 = mapOn[1]?subTex[1]:NULL;
1163 	if (sub0||sub1) {
1164 		// d((1-k)*a + k*b ) = dk*(b-a) + k*(db-da) + da
1165 		float a,b;
1166 		Point3 da,db;
1167 		if (sub0) {
1168 			a = sub0->EvalMono(sc);
1169 			da = sub0->EvalNormalPerturb(sc);
1170 			}
1171 		else {
1172 			a = Intens(col[0]);
1173 			da = Point3(0.0f,0.0f,0.0f);
1174 			}
1175 		if (sub1) {
1176 			b = sub1->EvalMono(sc);
1177 			db = sub1->EvalNormalPerturb(sc);
1178 			}
1179 		else {
1180 			b = Intens(col[1]);
1181 			db= Point3(0.0f,0.0f,0.0f);
1182 			}
1183 		np = (b-a)*np + d*(db-da) + da;
1184 		}
1185 	else
1186 		np *= Intens(col[1])-Intens(col[0]);
1187 	return np;
1188 	}
1189 
1190 // --- Methods inherited from Tex3D ---
ReadSXPData(TCHAR * name,void * sxpdata)1191 void Splat::ReadSXPData(TCHAR *name, void *sxpdata) {
1192 	SplatState *state = (SplatState*)sxpdata;
1193 	if (state != NULL && (state->version == SPLAT_SXP_VERSION)) {
1194 		SetColor(0, ColorFromCol24(state->col1), TimeValue(0));
1195 		SetColor(1, ColorFromCol24(state->col2), TimeValue(0));
1196 		SetSize(state->size, TimeValue(0));
1197 		SetThresh(state->thresh, TimeValue(0));
1198 	}
1199 }
1200 
1201 // --- Methods of Splat ---
1202 
splatter(Point3 p)1203 float Splat::splatter(Point3 p) {
1204 	float fact, ss, q[3], t;
1205 
1206 	q[0] = p[0]/size;
1207 	q[1] = p[1]/size;
1208 	q[2] = p[2]/size;
1209 	fact = 1.0f;
1210 	for (int i = 0; i < iter; i++) {
1211 		t = NOISE(q);
1212 		if (t > 1.0)
1213 			t = 1.0f;
1214 		ss = smoothstep(thresh-EPSILON, thresh+EPSILON, t);
1215 		fact *= ss;
1216 		q[0] *= 2.0f;	q[1] *= 2.0f;	q[2] *= 2.0f;
1217 	}
1218 	return(1.0f-fact);
1219 }
1220 
NotifyChanged()1221 void Splat::NotifyChanged() {
1222 	NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
1223 }
1224 
SwapInputs()1225 void Splat::SwapInputs() {
1226 	Color t = col[0]; col[0] = col[1]; col[1] = t;
1227 	Texmap *x = subTex[0];  subTex[0] = subTex[1];  subTex[1] = x;
1228 //	pblock->SwapControllers(PB_COL1, PB_COL2);
1229 	pblock->SwapControllers(splat_color1,0, splat_color2,0);
1230 	splat_param_blk.InvalidateUI(splat_color1);
1231 	splat_param_blk.InvalidateUI(splat_color2);
1232 	splat_param_blk.InvalidateUI(splat_map1);
1233 	splat_param_blk.InvalidateUI(splat_map2);
1234 	macroRec->FunctionCall(_T("swap"), 2, 0, mr_prop, _T("color1"), mr_reftarg, this, mr_prop, _T("color2"), mr_reftarg, this);
1235 	macroRec->FunctionCall(_T("swap"), 2, 0, mr_prop, _T("map1"), mr_reftarg, this, mr_prop, _T("map2"), mr_reftarg, this);
1236 }
1237 
SetColor(int i,Color c,TimeValue t)1238 void Splat::SetColor(int i, Color c, TimeValue t) {
1239     col[i] = c;
1240 //	pblock->SetValue((i == 0) ? PB_COL1 : PB_COL2, t, c);
1241 	pblock->SetValue((i == 0) ? splat_color1 : splat_color2, t, c);
1242 }
1243 
SetSize(float f,TimeValue t)1244 void Splat::SetSize(float f, TimeValue t) {
1245 	size = f;
1246 //	pblock->SetValue(PB_SIZE, t, f);
1247 	pblock->SetValue(splat_size, t, f);
1248 }
1249 
SetThresh(float f,TimeValue t)1250 void Splat::SetThresh(float f, TimeValue t) {
1251 	thresh = f;
1252 	if (thresh < EPSILON)
1253 		thresh = EPSILON;
1254 	if (thresh > 1.0f-EPSILON)
1255 		thresh = 1.0f-EPSILON;
1256 //	pblock->SetValue(PB_THRESH, t, thresh);
1257 	pblock->SetValue(splat_threshold, t, thresh);
1258 }
1259 
SetIter(int i,TimeValue t)1260 void Splat::SetIter(int i, TimeValue t) {
1261 	iter = i;
1262 //	pblock->SetValue(PB_ITER, t, i);
1263 	pblock->SetValue(splat_iteration, t, i);
1264 }
1265 
1266