1 /**********************************************************************
2  *<
3 	FILE:			Wood.cpp
4 
5 	DESCRIPTION:	Wood 3D Texture map.
6 
7 	CREATED BY:		Suryan Stalin
8 
9 	HISTORY:		Modified from Marble.cpp by adding IPAS wood stuff
10 
11  *>	Copyright (c) 1994, All Rights Reserved.
12  **********************************************************************/
13 
14 
15 //Includes
16 #include "mtlhdr.h"
17 #include "woodres.h"
18 #include "iparamm2.h"
19 #include "stdmat.h"
20 #include "wooddent.h"
21 #include "wood.h"
22 #include "macrorec.h"
23 
24 
25 // JBW: IDs for ParamBlock2 blocks and parameters
26 // Parameter and ParamBlock IDs
27 enum { wood_params, };  // pblock ID
28 // dents_params param IDs
29 enum
30 {
31 	wood_map1,wood_map2,wood_color1,wood_color2,
32 	wood_map1_on, wood_map2_on, // main grad params
33 
34 	wood_thickness,wood_rnoise, wood_anoise,
35 	wood_coords,
36 //	wood_seed
37 
38 };
39 
40 //externs
41 extern		HINSTANCE			hInstance;
42 
43 ParamDlg *Wood::xyzGenDlg;
44 
45 //Globals
46 static		WoodClassDesc		woodCD;
47 static		int					subTexId[NSUBTEX] = { IDC_WOOD_TEX1, IDC_WOOD_TEX2 };
48 static		ParamBlockDescID	pbdesc[] =	{
49 											{	TYPE_FLOAT, NULL, TRUE,wood_thickness }, 	// size
50 											{	TYPE_FLOAT, NULL, TRUE,wood_rnoise }, 	// r1
51 											{	TYPE_FLOAT, NULL, TRUE,wood_anoise }, 	// r2
52 											{	TYPE_RGBA, NULL, TRUE,wood_color1 },  // col1
53 											{	TYPE_RGBA, NULL, TRUE,wood_color2 }   // col2
54 											};
55 static		int					nameID[] =	{	IDS_DS_WOODSIZE,
56 												IDS_DS_WOODR1,
57 												IDS_DS_WOODR2,
58 												IDS_DS_COLOR1,
59 												IDS_DS_COLOR2
60 											};
61 static		int					colID[2] =	{ IDC_WOOD_COL1, IDC_WOOD_COL2 };
62 static		Class_ID			woodClassID(WOOD_CLASS_ID,0);
63 static		float				noiseTable[NOISE_DIM+1][NOISE_DIM+1][NOISE_DIM+1];
64 static      int					noiseInited = 0;
65 // Array of old versions
66 static ParamVersionDesc versions[1] = {
67 	ParamVersionDesc(pbdesc,5,1)
68 	};
69 // per instance gradient block
70 static ParamBlockDesc2 wood_param_blk ( wood_params, _T("parameters"),  0, &woodCD, P_AUTO_CONSTRUCT + P_AUTO_UI, 1,
71 	//rollout
72 	IDD_WOOD, IDS_DS_WOOD_PARAMS, 0, 0, NULL,
73 	// params
74 	wood_map1,		_T("map1"),		TYPE_TEXMAP,			P_OWNERS_REF,	IDS_PW_MAP1,
75 		p_refno,		2,
76 		p_subtexno,		0,
77 		p_ui,			TYPE_TEXMAPBUTTON, IDC_WOOD_TEX1,
78 		end,
79 	wood_map2,		_T("map2"),		TYPE_TEXMAP,			P_OWNERS_REF,	IDS_PW_MAP2,
80 		p_refno,		3,
81 		p_subtexno,		1,
82 		p_ui,			TYPE_TEXMAPBUTTON, IDC_WOOD_TEX2,
83 		end,
84 	wood_color1,	 _T("color1"),	TYPE_RGBA,				P_ANIMATABLE,	IDS_DS_COLOR1,
85 		p_default,		Color(0,0,0),
86 		p_ui,			TYPE_COLORSWATCH, IDC_WOOD_COL1,
87 		end,
88 	wood_color2,	 _T("color2"),	TYPE_RGBA,				P_ANIMATABLE,	IDS_DS_COLOR2,
89 		p_default,		Color(1,1,1),
90 		p_ui,			TYPE_COLORSWATCH, IDC_WOOD_COL2,
91 		end,
92 	wood_map1_on,	_T("map1Enabled"), TYPE_BOOL,			0,				IDS_PW_MAP1ENABLE,
93 		p_default,		TRUE,
94 		p_ui,			TYPE_SINGLECHEKBOX, IDC_MAPON1,
95 		end,
96 	wood_map2_on,	_T("map2Enabled"), TYPE_BOOL,			0,				IDS_PW_MAP2ENABLE,
97 		p_default,		TRUE,
98 		p_ui,			TYPE_SINGLECHEKBOX, IDC_MAPON2,
99 		end,
100 
101 	wood_thickness,	_T("thickness"),   TYPE_FLOAT,			P_ANIMATABLE,	IDS_DS_WOODSIZE,
102 		p_default,		7.0,
103 		p_range,		0.0, 999999999.0,
104 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT,  IDC_WOODSIZE_EDIT, IDC_WOODSIZE_SPIN, .1f,
105 		end,
106 	wood_rnoise,	_T("radialNoise"),   TYPE_FLOAT,			P_ANIMATABLE,	IDS_DS_WOODR1,
107 		p_default,		1.0,
108 		p_range,		0.0, 100.0,
109 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT,  IDC_R1_EDIT, IDC_R1_SPIN, .1f,
110 		end,
111 	wood_anoise,	_T("axialNoise"),   TYPE_FLOAT,			P_ANIMATABLE,	IDS_DS_WOODR2,
112 		p_default,		1.0f,
113 		p_range,		0.0, 100.0f,
114 		p_ui, 			TYPE_SPINNER, EDITTYPE_FLOAT,   IDC_R2_EDIT, IDC_R2_SPIN, .1f,
115 		end,
116 	wood_coords,		_T("coords"),	TYPE_REFTARG,		P_OWNERS_REF,	IDS_DS_COORDINATES,
117 		p_refno,		0,
118 		end,
119 //	wood_seed,	_T("seed"),   TYPE_INT,			0,	IDS_PW_SEED,
120 //		p_default,		65432,
121 //		p_range,		0, 99999999,
122 //		p_ui, 			TYPE_SPINNER, EDITTYPE_INT,   IDC_WOODSEED_EDIT, IDC_WOODSEED_SPIN, 1.0f,
123 //		end,
124 
125 	end
126 );
127 
128 //Class Implementations
129 
130 //dialog stuff to get the Set Ref button
131 class WoodDlgProc : public ParamMap2UserDlgProc {
132 //public ParamMapUserDlgProc {
133 	public:
134 		Wood *wood;
WoodDlgProc(Wood * m)135 		WoodDlgProc(Wood *m) {wood = m;}
136 		INT_PTR DlgProc(TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
DeleteThis()137 		void DeleteThis() {delete this;}
SetThing(ReferenceTarget * m)138 		void SetThing(ReferenceTarget *m) {
139 			wood = (Wood*)m;
140 			}
141 	};
142 
143 
144 
DlgProc(TimeValue t,IParamMap2 * map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)145 INT_PTR WoodDlgProc::DlgProc(
146 		TimeValue t,IParamMap2 *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
147 	{
148 	switch (msg) {
149 		case WM_COMMAND:
150 			switch (LOWORD(wParam))
151 				{
152 				case IDC_WOOD_SWAP:
153 					{
154 					wood->SwapInputs();
155 					}
156 				}
157 			break;
158 		}
159 	return FALSE;
160 	}
161 
162 
163 //  Wood
Wood()164 Wood::Wood()
165 	{
166 #ifdef SHOW_3DMAPS_WITH_2D
167 	texHandle = NULL;
168 #endif
169 	Param1 = FALSE;
170 	subTex[0] = subTex[1] = NULL;
171 	pblock = NULL;
172 	xyzGen = NULL;
173 	seed = 0;
174 	InitNoise();
175 	woodCD.MakeAutoParamBlocks(this);	// make and intialize paramblock2
176 	Init();
177 	rollScroll=0;
178 	vers = 0;
179 	}
180 
181 #define IN_TO_M(x) (x / 39.370079f)
182 
Init()183 void Wood::Init()
184 	{
185 	if (xyzGen) xyzGen->Reset();
186 	else ReplaceReference( 0, GetNewDefaultXYZGen());
187 	ivalid.SetEmpty();
188 	SetColor(0, Color(0.79f,0.69f,0.27f), TimeValue(0));
189 	SetColor(1, Color(0.51f,0.32f,0.05f), TimeValue(0));
190     RegisterDistanceDefault(_T("Wood Params"), _T("Size"), 7.0f, IN_TO_M(7.0f));
191     float size = GetDistanceDefault(_T("Wood Params"), _T("Size"));
192     SetSize(size, TimeValue(0));
193 	SetR1(1.0f, TimeValue(0));
194 	SetR2(1.0f, TimeValue(0));
195 	for (int i=0; i<NSUBTEX; i++) mapOn[i] = TRUE;
196 	}
197 
Reset()198 void Wood::Reset()
199 	{
200 	woodCD.Reset(this, TRUE); // reset pb2 params
201 	DeleteReference(2);
202 	DeleteReference(3);
203 	Init();
204 	}
205 
206 #ifdef SHOW_3DMAPS_WITH_2D
GetActiveTexHandle(TimeValue t,TexHandleMaker & thmaker)207 DWORD_PTR Wood::GetActiveTexHandle(TimeValue t, TexHandleMaker& thmaker) {
208 	if (texHandle) {
209 		if (texHandleValid.InInterval(t))
210 			return texHandle->GetHandle();
211 		else DiscardTexHandle();
212 		}
213 	texHandle = thmaker.MakeHandle(GetVPDisplayDIB(t,thmaker,texHandleValid));
214 	return texHandle->GetHandle();
215 	}
216 #endif
217 
218 
NotifyChanged()219 void Wood::NotifyChanged()
220 {
221 	NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
222 }
223 
ClassID()224 Class_ID Wood::ClassID()
225 {
226 	return woodClassID;
227 }
228 
Clone(RemapDir & remap)229 RefTargetHandle Wood::Clone(RemapDir &remap)
230 {
231 	Wood *mnew = new Wood();
232 	*((MtlBase*)mnew) = *((MtlBase*)this);  // copy superclass stuff
233 	mnew->ReplaceReference(0,remap.CloneRef(xyzGen));
234 	mnew->ReplaceReference(1,remap.CloneRef(pblock));
235 	mnew->col[0] = col[0];
236 	mnew->col[1] = col[1];
237 	mnew->r1 = r1;
238 	mnew->r2 = r2;
239 	mnew->size = size;
240 //	mnew->seed = seed;
241 //	mnew->InitNoise();
242 	mnew->ivalid.SetEmpty();
243 	for (int i = 0; i<NSUBTEX; i++) {
244 		mnew->subTex[i] = NULL;
245 		if (subTex[i])
246 			mnew->ReplaceReference(i+2,remap.CloneRef(subTex[i]));
247 		mnew->mapOn[i] = mapOn[i];
248 		}
249 	BaseClone(this, mnew, remap);
250 	return (RefTargetHandle)mnew;
251 }
252 
CreateParamDlg(HWND hwMtlEdit,IMtlParams * imp)253 ParamDlg* Wood::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp)
254 {
255 	// create the rollout dialogs
256 	xyzGenDlg = xyzGen->CreateParamDlg(hwMtlEdit, imp);
257 	IAutoMParamDlg* masterDlg = woodCD.CreateParamDlgs(hwMtlEdit, imp, this);
258 // add the secondary dialogs to the master
259 	masterDlg->AddDlg(xyzGenDlg);
260 //attach a dlg proc to handle the swap button
261 	wood_param_blk.SetUserDlgProc(new WoodDlgProc(this));
262 
263 	return masterDlg;
264 
265 }
266 
SetDlgThing(ParamDlg * dlg)267 BOOL Wood::SetDlgThing(ParamDlg* dlg)
268 {
269 	// PW: set the appropriate 'thing' sub-object for each
270 	// secondary dialog
271 	if (dlg == xyzGenDlg)
272 		xyzGenDlg->SetThing(xyzGen);
273 	else
274 		return FALSE;
275 	return TRUE;
276 }
277 
ReadSXPData(TCHAR * name,void * sxpdata)278 void Wood::ReadSXPData(TCHAR *name, void *sxpdata)
279 {
280 	WoodState *state = (WoodState*)sxpdata;
281 	if (state->version==WOOD_VERS) {
282 		SetColor(0, ColrFromCol24(state->col1),0);
283 		SetColor(1, ColrFromCol24(state->col2),0);
284 		SetR1(state->r1,0);
285 		SetR2(state->r2,0);
286 		SetSize(state->size,0);
287 		}
288 }
289 
Update(TimeValue t,Interval & valid)290 void Wood::Update(TimeValue t, Interval& valid)
291 {
292 
293 /*	if (Param1)
294 		{
295 		pblock->SetValue(wood_map1_on,t,mapOn[0]);
296 		pblock->SetValue(wood_map2_on,t,mapOn[1]);
297 		pblock->SetValue(wood_seed,t,seed);
298 		Param1 = FALSE;
299 		}
300 */
301 
302 	if (!ivalid.InInterval(t)) {
303 		ivalid.SetInfinite();
304 		xyzGen->Update(t,ivalid);
305 		pblock->GetValue( wood_color1, t, col[0], ivalid );
306 		col[0].ClampMinMax();
307 		pblock->GetValue( wood_color2, t, col[1], ivalid );
308 		col[1].ClampMinMax();
309 		pblock->GetValue( wood_rnoise, t, r1, ivalid );
310 		pblock->GetValue( wood_anoise, t, r2, ivalid );
311 		pblock->GetValue( wood_thickness, t, size, ivalid );
312 		pblock->GetValue( wood_map1_on, t, mapOn[0], ivalid );
313 		pblock->GetValue( wood_map2_on, t, mapOn[1], ivalid );
314 
315 //		int rseed =-9876545;
316 //		pblock->GetValue( wood_seed, t, rseed, ivalid );
317 //		if (rseed != seed)
318 //			{
319 //			seed = rseed;
320 //			InitNoise();
321 //			}
322 //		else seed = rseed;
323 //
324 		for (int i=0; i<NSUBTEX; i++) {
325 			if (subTex[i])
326 				subTex[i]->Update(t,ivalid);
327 			}
328 		}
329 	valid &= ivalid;
330 }
331 
332 
SetColor(int i,Color c,TimeValue t)333 void Wood:: SetColor(int i, Color c, TimeValue t)
334 {
335 //    col[i] = c;
336 	col[i].r = c.r;
337 	col[i].g = c.g;
338 	col[i].b = c.b;
339 	pblock->SetValue( i==0?wood_color1:wood_color2, t, c);
340 }
341 
SwapInputs()342 void Wood::SwapInputs()
343 {
344 	Color t = col[0]; col[0] = col[1]; col[1] = t;
345 	Texmap *x = subTex[0];  subTex[0] = subTex[1];  subTex[1] = x;
346 	pblock->SwapControllers(wood_color1,0,wood_color2,0);
347 	wood_param_blk.InvalidateUI(wood_color1);
348 	wood_param_blk.InvalidateUI(wood_color2);
349 	wood_param_blk.InvalidateUI(wood_map1);
350 	wood_param_blk.InvalidateUI(wood_map2);
351 	macroRec->FunctionCall(_T("swap"), 2, 0, mr_prop, _T("color1"), mr_reftarg, this, mr_prop, _T("color2"), mr_reftarg, this);
352 	macroRec->FunctionCall(_T("swap"), 2, 0, mr_prop, _T("map1"), mr_reftarg, this, mr_prop, _T("map2"), mr_reftarg, this);
353 
354 }
355 
SetR1(float f,TimeValue t)356 void Wood::SetR1(float f, TimeValue t)
357 {
358 	r1 = f;
359 	pblock->SetValue( wood_rnoise, t, f);
360 }
361 
SetR2(float f,TimeValue t)362 void Wood::SetR2(float f, TimeValue t)
363 {
364 	r2 = f;
365 	pblock->SetValue( wood_anoise, t, f);
366 }
367 
SetSize(float f,TimeValue t)368 void Wood::SetSize(float f, TimeValue t)
369 {
370 	size = f;
371 	pblock->SetValue( wood_thickness, t, f);
372 }
373 
GetReference(int i)374 RefTargetHandle Wood::GetReference(int i)
375 {
376 	switch(i) {
377 		case 0: return xyzGen;
378 		case 1:	return pblock ;
379 		default:return subTex[i-2];
380 		}
381 }
382 
SetReference(int i,RefTargetHandle rtarg)383 void Wood::SetReference(int i, RefTargetHandle rtarg)
384 {
385 	switch(i) {
386 		case 0: xyzGen = (XYZGen *)rtarg; break;
387 		case 1:	pblock = (IParamBlock2 *)rtarg; break;
388 		default: subTex[i-2] = (Texmap *)rtarg; break;
389 		}
390 }
391 
SetSubTexmap(int i,Texmap * m)392 void Wood::SetSubTexmap(int i, Texmap *m)
393 {
394 	ReplaceReference(i+2,m);
395 	if (i==0)
396 		{
397 		wood_param_blk.InvalidateUI(wood_map1);
398 		ivalid.SetEmpty();
399 		}
400 	else if (i==1)
401 		{
402 		wood_param_blk.InvalidateUI(wood_map2);
403 		ivalid.SetEmpty();
404 		}
405 
406 }
407 
GetSubTexmapSlotName(int i)408 TSTR Wood::GetSubTexmapSlotName(int i)
409 {
410 	switch(i) {
411 		case 0:  return TSTR(GetString(IDS_DS_COLOR1));
412 		case 1:  return TSTR(GetString(IDS_DS_COLOR2));
413 		default: return TSTR(_T(""));
414 		}
415 }
416 
SubAnim(int i)417 Animatable* Wood::SubAnim(int i)
418 {
419 	switch (i) {
420 		case 0: return xyzGen;
421 		case 1: return pblock;
422 		default: return subTex[i-2];
423 		}
424 }
425 
SubAnimName(int i)426 TSTR Wood::SubAnimName(int i)
427 {
428 	switch (i) {
429 		case 0: return TSTR(GetString(IDS_DS_COORDINATES));
430 		case 1: return TSTR(GetString(IDS_DS_PARAMETERS));
431 		default: return GetSubTexmapTVName(i-2);
432 		}
433 }
434 
435 
NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget,PartID & partID,RefMessage message)436 RefResult Wood::NotifyRefChanged(	Interval changeInt, RefTargetHandle hTarget,
437 									PartID& partID, RefMessage message )
438 {
439 	switch (message) {
440 		case REFMSG_CHANGE:
441 			ivalid.SetEmpty();
442 			if (hTarget == pblock )
443 				{
444 			// see if this message came from a changing parameter in the pblock,
445 			// if so, limit rollout update to the changing item and update any active viewport texture
446 				ParamID changing_param = pblock->LastNotifyParamID();
447 //			if (hTarget != xyzGen  && hTarget != pblock )
448 				wood_param_blk.InvalidateUI(changing_param);
449 			// notify our dependents that we've changed
450 				// NotifyChanged();  //DS this is redundant
451 #ifdef SHOW_3DMAPS_WITH_2D
452 				if (changing_param != -1)
453 					DiscardTexHandle();
454 #endif
455 				}
456 			if (hTarget == xyzGen )
457 				{
458 #ifdef SHOW_3DMAPS_WITH_2D
459 				DiscardTexHandle();
460 #endif
461 				// NotifyChanged();  //DS this is redundant
462 				}
463 
464 			break;
465 		}
466 	return(REF_SUCCEED);
467 }
468 
469 #define MAPOFF_CHUNK 0x1000
470 #define PARAM2_CHUNK 0x1010
471 
Save(ISave * isave)472 IOResult Wood::Save(ISave *isave)
473 {
474 //	ULONG nb;
475 	IOResult res;
476 	// Save common stuff
477 	isave->BeginChunk(MTL_HDR_CHUNK);
478 	res = MtlBase::Save(isave);
479 	if (res!=IO_OK) return res;
480 	isave->EndChunk();
481 
482 //	isave->BeginChunk(WOOD_NOISE_CHUNK);
483 //	isave->Write(&seed,sizeof(int),&nb);
484 //	isave->EndChunk();
485 
486 	isave->BeginChunk(PARAM2_CHUNK);
487 	isave->EndChunk();
488 
489 	return IO_OK;
490 }
491 
492 class WoodPostLoad : public PostLoadCallback
493 {
494 	public:
495 		Wood *chk;
WoodPostLoad(Wood * b)496 		WoodPostLoad(Wood *b) {chk=b;}
proc(ILoad * iload)497 		void proc(ILoad *iload) {
498 			if (chk->vers<1) {
499 				if (chk->pblock)
500 					chk->pblock->RescaleParam(wood_thickness, 0, 100.0f);
501 //					ScaleFloatController(chk->pblock, PB_SIZE, 100.0f);
502 //				iload->SetObsolete();
503 				}
504 			delete this;
505 			}
506 };
507 
508 //watje
509 
510 class Wood2PostLoadCallback:public  PostLoadCallback
511 {
512 public:
513 	Wood      *s;
514 	int Param1;
Wood2PostLoadCallback(Wood * r,BOOL b)515 	Wood2PostLoadCallback(Wood *r, BOOL b) {s=r;Param1 = b;}
516 	void proc(ILoad *iload);
517 };
518 
proc(ILoad * iload)519 void Wood2PostLoadCallback::proc(ILoad *iload)
520 {
521 	if (Param1)
522 		{
523 		TimeValue t  = 0;
524 		s->pblock->SetValue(wood_map1_on,t,s->mapOn[0]);
525 		s->pblock->SetValue(wood_map2_on,t,s->mapOn[1]);
526 //		s->pblock->SetValue(wood_seed,t,s->seed);
527 		Param1 = FALSE;
528 		}
529 
530 //	Interval ivalid;
531 //	s->pblock->GetValue( wood_seed, 0, s->seed, ivalid );
532 //	s->InitNoise();
533 
534 	delete this;
535 }
536 
537 
Load(ILoad * iload)538 IOResult Wood::Load(ILoad *iload)
539 {
540 //	ULONG		nb;
541 	IOResult res;
542 	int id;
543 	vers = 0;
544 	Param1 = TRUE;
545 
546 	while (IO_OK==(res=iload->OpenChunk()))
547 	{
548 		switch(id = iload->CurChunkID())
549 		{
550 			case MTL_HDR_CHUNK:
551 				res = MtlBase::Load(iload);
552 				break;
553 			case WOODVERS1_CHUNK:
554 				vers = 1;
555 
556 				break;
557 			case MAPOFF_CHUNK+0:
558 			case MAPOFF_CHUNK+1:
559 				mapOn[id-MAPOFF_CHUNK] = 0;
560 				break;
561 
562 #if 0
563 			case WOOD_NOISE_CHUNK:
564 				iload->Read(&seed,sizeof(int),&nb);
565 //				InitNoise();
566 				break;
567 #endif
568 			case PARAM2_CHUNK:
569 				Param1 = FALSE;
570 				break;
571 
572 
573 		}
574 		iload->CloseChunk();
575 		if (res!=IO_OK)
576 			return res;
577 	}
578 	if (Param1)
579 		{
580 		ParamBlock2PLCB* plcb = new ParamBlock2PLCB(versions, 1, &wood_param_blk, this, 1);
581 		iload->RegisterPostLoadCallback(plcb);
582 		}
583 	Wood2PostLoadCallback* wood2plcb = new Wood2PostLoadCallback(this,Param1);
584 	iload->RegisterPostLoadCallback(wood2plcb);
585 
586 	return IO_OK;
587 }
588 
InitNoise()589 void Wood::InitNoise()
590 {
591 //	if(!seed)
592 //		seed = rand()+1;
593 	if (!noiseInited) {
594 		noiseInited = 1;
595 		srand(65432);
596 		int i, j, k, ii, jj, kk;
597 		for (i=0; i<=NOISE_DIM; i++)
598 			for (j=0; j<=NOISE_DIM; j++)
599 				for (k=0; k<=NOISE_DIM; k++)
600 				{
601 					noiseTable[i][j][k] = (float)(rand()&0x7FFF);
602 					ii = (i==NOISE_DIM)?0:i;
603 					jj = (j==NOISE_DIM)?0:j;
604 					kk = (k==NOISE_DIM)?0:k;
605 					noiseTable[i][j][k] = noiseTable[ii][jj][kk];
606 				}
607 		}
608 }
609 
WoodNoise(float x)610 float Wood::WoodNoise(float x)
611 {
612    int ix;
613    double fx, mx;
614    double n0, n1;
615    mx = fmod((double)x, FNOISE_DIM);
616    if (mx<0) mx += FNOISE_DIM;
617    ix = (int)mx;
618    fx = fmod(mx, 1.0);
619    n0 = noiseTable[ix][0][0];
620    n1 = noiseTable[ix+1][0][0];
621 
622    return (float)((n0+fx*(n1-n0))/32768.0);
623 }
624 
625 /*
626 float noise(float x, float y, float z)
627 {
628    int ix, iy, iz;
629    float fx, fy, fz, mx, my, mz;
630    float n, n00, n01, n10, n11, n0, n1;
631    mx = fmod(x, FNOISE_DIM); if (mx<0) mx += FNOISE_DIM;
632    my = fmod(y, FNOISE_DIM); if (my<0) my += FNOISE_DIM;
633    mz = fmod(z, FNOISE_DIM); if (mz<0) mz += FNOISE_DIM;
634    ix = (int)mx;
635    iy = (int)my;
636    iz = (int)mz;
637    fx = fmod(mx, 1.0);
638    fy = fmod(my, 1.0);
639    fz = fmod(mz, 1.0);
640    n = noise_table[ix][iy][iz];
641    n00 = n + fx*(noise_table[ix+1][iy][iz]-n);
642    n = noise_table[ix][iy][iz+1];
643    n01 = n + fx*(noise_table[ix+1][iy][iz+1]-n);
644    n = noise_table[ix][iy+1][iz];
645    n10 = n + fx*(noise_table[ix+1][iy+1][iz]-n);
646    n = noise_table[ix][iy+1][iz+1];
647    n11 = n + fx*(noise_table[ix+1][iy+1][iz+1]-n);
648    n0 = n00 + fy*(n10-n00);
649    n1 = n01 + fy*(n11-n01);
650    return(((float)(n0+fz*(n1-n0)))/32768.0);
651 }
652 
653 */
654 
LerpColor(RGBA * c,RGBA * a,RGBA * b,float f)655 void Wood::LerpColor(RGBA *c, RGBA *a, RGBA *b, float f)
656 {
657    int alph, ialph;
658 
659    if (f>1.0) f = 1.0f;
660    alph = (int)(4096*f);
661    ialph = 4096-alph;
662 
663    c->r = (float)(((int)(ialph*a->r + alph*b->r)*255)>>12);
664    c->g = (float)(((int)(ialph*a->g + alph*b->g)*255)>>12);
665    c->b = (float)(((int)(ialph*a->b + alph*b->b)*255)>>12);
666 
667    c->r /= 255.0f;
668    c->g /= 255.0f;
669    c->b /= 255.0f;
670 
671 }
672 
673 /* smooth step function with hermite interpolation*/
SmoothStep(float x0,float x1,float v)674 float Wood::SmoothStep(float x0, float x1, float v)
675 {
676    if (v<=x0) return(0.0f);
677    else if (v>=x1) return(1.0f);
678    else {
679       float u = (v-x0)/(x1-x0);
680       return(u*u*(3-2*u));
681    }
682 }
683 
WoodFunc(Point3 p)684 float Wood::WoodFunc(Point3 p) {
685 	float r;
686 	float px = p.x/size;
687 	float py = p.y/size;
688 	float pz = p.z/size;
689 	px += WoodNoise(px)*r1;
690 	py += WoodNoise(py)*r1;
691 	pz += WoodNoise(pz)*r1;
692 	r = (float) sqrt(py*py+pz*pz);
693 	r += WoodNoise(r)+r2*WoodNoise(px/4.0f);
694 	r = (float)fmod((double)r, 1.0); /* be periodic */
695 	r = SmoothStep(0.0f, 0.8f, r) - SmoothStep(0.83f, 1.0f, r);
696 	return(r);
697 	}
698 
699 static AColor black(0.0f,0.0f,0.0f,0.0f);
700 
EvalColor(ShadeContext & sc)701 RGBA Wood::EvalColor(ShadeContext& sc)
702 {
703 	Point3	p,dp;
704 	RGBA	c;
705 	if (!sc.doMaps) return black;
706 	if (gbufID) sc.SetGBufferID(gbufID);
707 
708 	xyzGen->GetXYZ(sc,p,dp);
709 	if (size==0.0f) size=.0001f;
710 //	p *= FACT/size;
711 
712 	float d = WoodFunc(p);
713 
714 	if (d<=.0005f)
715 		return  (mapOn[0]&&subTex[0]) ? subTex[0]->EvalColor(sc): col[0];
716 	else
717 		if (d>=.9995)
718 			return  (mapOn[1]&&subTex[1]) ? subTex[1]->EvalColor(sc): col[1];
719 	RGBA c0 = (mapOn[0]&&subTex[0]) ? subTex[0]->EvalColor(sc): col[0];
720 	RGBA c1 = (mapOn[1]&&subTex[1]) ? subTex[1]->EvalColor(sc): col[1];
721 	c = (1.0f-d)*c0 + d*c1;
722 	return c;
723 }
724 
EvalNormalPerturb(ShadeContext & sc)725 Point3 Wood::EvalNormalPerturb(ShadeContext& sc)
726 {
727 	float del,d;
728 	Point3 p,dp;
729 
730 	if (!sc.doMaps) return Point3(0,0,0);
731 	if (gbufID) sc.SetGBufferID(gbufID);
732 	xyzGen->GetXYZ(sc,p,dp);
733 	if (size==0.0f) size=.0001f;
734 //	p *= FACT/size;
735 
736 	d = WoodFunc(p);
737 //	del = 20.0f;
738 	del = 0.1f;
739 	Point3 np;
740 	Point3 M[3];
741 	xyzGen->GetBumpDP(sc,M);
742     np.x = (WoodFunc(p+del*M[0]) - d)/del;
743 	np.y = (WoodFunc(p+del*M[1]) - d)/del;
744 	np.z = (WoodFunc(p+del*M[2]) - d)/del;
745 //	return np*100.0f;
746 	np = sc.VectorFromNoScale(np,REF_OBJECT);
747 	Texmap *sub0 = mapOn[0]?subTex[0]:NULL;
748 	Texmap *sub1 = mapOn[1]?subTex[1]:NULL;
749 	if (sub0||sub1) {
750 		// d((1-k)*a + k*b ) = dk*(b-a) + k*(db-da) + da
751 		float a,b;
752 		Point3 da,db;
753 		if (sub0) { 	a = sub0->EvalMono(sc); 	da = sub0->EvalNormalPerturb(sc);		}
754 		else {	 a = Intens(col[0]);	 da = Point3(0.0f,0.0f,0.0f);		 }
755 		if (sub1) { 	b = sub1->EvalMono(sc); 	db = sub1->EvalNormalPerturb(sc);	}
756 		else {	 b = Intens(col[1]);	 db= Point3(0.0f,0.0f,0.0f);		 }
757 		np = (b-a)*np + d*(db-da) + da;
758 		}
759 	else
760 		np *= Intens(col[1])-Intens(col[0]);
761 	return np;
762 	}
763 
764 //WoodClassDesc
ClassID()765 Class_ID WoodClassDesc::ClassID()
766 {
767 	return woodClassID;
768 }
GetWoodDesc()769 ClassDesc* GetWoodDesc()		{ return &woodCD;  }
770 
771