1 /**********************************************************************
2 *<
3 FILE: multi.cpp
4
5 DESCRIPTION: Composite material
6
7 CREATED BY: Dan Silva
8
9 HISTORY: UPdated to Param2 1/11/98 Peter Watje
10
11 Modified to handle sparse arrays without having to have all the
12 intervening nulls. 6/19/00 Dan Silva
13
14 *> Copyright (c) 1994, All Rights Reserved.
15 **********************************************************************/
16 #include "buildver.h"
17 #include "mtlhdr.h"
18 #include "mtlres.h"
19 #include "mtlresOverride.h"
20 #include "stdmat.h"
21 #include "iparamm2.h"
22 // begin - ke/mjm - 03.16.00 - merge reshading code
23 //#include "iReshade.h"
24 // end - ke/mjm - 03.16.00 - merge reshading code
25 #include "macrorec.h"
26 #include "gport.h"
27
28 #include "3dsmaxport.h"
29
30 extern HINSTANCE hInstance;
31
32
33 //###########################################################################
34 // pblock conversions for maxscript mtl id fixes
35
36 class MultiIDDimension : public ParamDimension
37 {
38 public:
DimensionType()39 DimType DimensionType() { return DIM_CUSTOM; }
Convert(float value)40 float Convert(float value) { return value+1; };
UnConvert(float value)41 float UnConvert(float value) { return value-1; };
42 };
43
44 static MultiIDDimension theMultiIDDim;
45
46
47
48 // use hash-table for lookup speed
49 #define USE_HASHING 1
50
51 //###########################################################################
52 // hash-table template class (taken straight from pview)
53 // modified:
54 // -1 is reserved for "empty key value" instead of 0
55 // start with hash table size of 10 instead of 100
56 // add "clean" member to clear out keys, but not free the list
57 #if USE_HASHING
58
59 static int exponentialPrimes[] =
60 {2, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749,
61 65521, 131071, 262139, 524287, 1048573, 2097143};
62
63 #define N_PRIMES (sizeof(exponentialPrimes) / sizeof(int))
64
findPrimeForSize(int size)65 static int findPrimeForSize(int size)
66 {
67 for (int i = 0; i < N_PRIMES; i++)
68 {
69 if (exponentialPrimes[i] > size)
70 return exponentialPrimes[i];
71 }
72
73 return size + 1;
74 }
75
76 #define UNUSED_KEY -1
77
78 template <class K, class V> class MyHashTable
79 {
80 protected:
81
82 struct Association
83 {
84 K key;
85 V value;
86 };
87
88 Association *ht;
89 int htSize;
90 int nElements;
91
FindPosition(K key)92 int FindPosition(K key)
93 {
94 int index;
95 K indexedObject;
96
97 index = ((DWORD) key) % htSize;
98 while (((indexedObject = ht[index].key) != UNUSED_KEY) && (key != indexedObject))
99 {
100 index++;
101 if (index >= htSize)
102 index = 0;
103 }
104 return index;
105 }
106
GrowTo(int newSize)107 void GrowTo(int newSize)
108 {
109 Association *oldHt = ht;
110 int oldSize = htSize;
111
112 ht = new Association[newSize];
113 memset(ht, 0, newSize * sizeof(Association));
114 for (int x = 0; x < newSize; x++ ) // init to -1's (unused slot)
115 ht[x].key = UNUSED_KEY;
116 htSize = newSize;
117
118 if (oldHt != NULL)
119 {
120 for (int i = 0; i < oldSize; i++)
121 {
122 if (oldHt[i].key != UNUSED_KEY)
123 AddAssociation(oldHt[i].key, oldHt[i].value);
124 }
125 delete[] oldHt;
126 }
127 }
128
129 public:
130
MyHashTable(int size=10)131 MyHashTable(int size = 10)
132 {
133 ht = NULL;
134 Initialize(size);
135 }
136
~MyHashTable()137 ~MyHashTable()
138 {
139 if (ht != NULL)
140 delete[] ht;
141 }
142
Clear()143 void Clear()
144 {
145 if (ht != NULL)
146 delete[] ht;
147 ht = NULL;
148 htSize = 0;
149 nElements = 0;
150 }
151
Clean()152 void Clean()
153 {
154 memset(ht, 0, htSize * sizeof(Association));
155 for (int x = 0; x < htSize; x++ ) // init to -1's (unused slot)
156 ht[x].key = -1;
157 nElements = 0; // 4/13/01 11:37am --MQM-- oops, need this!
158 }
159
Initialize(int size=100)160 void Initialize(int size = 100)
161 {
162 Clear();
163 GrowTo(findPrimeForSize(size * 4));
164 }
165
AddAssociation(K key,V & value)166 int AddAssociation(K key, V &value)
167 {
168 int index;
169
170 if (nElements >= (htSize / 2))
171 GrowTo(findPrimeForSize(htSize * 2 + 8));
172
173 index = FindPosition(key);
174 if (ht[index].key == UNUSED_KEY)
175 {
176 ht[index].key = key;
177 ht[index].value = value;
178 nElements++;
179 return -1 - index;
180 }
181
182 return index;
183 }
184
GetIndex(K key)185 int GetIndex(K key)
186 {
187 int index = FindPosition(key);
188 if (ht[index].key != UNUSED_KEY)
189 return index;
190 else
191 return -1;
192 }
193
operator [](const int i) const194 V& operator[](const int i) const
195 {
196 return ht[i].value;
197 }
198
GetNextAssociation(int & hashIndex,K * keyP,V * valueP)199 bool GetNextAssociation(int &hashIndex, K* keyP, V* valueP)
200 {
201 for (int i = hashIndex; i < htSize; i++)
202 {
203 if (ht[i].key != UNUSED_KEY)
204 {
205 hashIndex = i + 1;
206 *keyP = ht[i].key;
207 *valueP = ht[i].value;
208 return true;
209 }
210 }
211
212 return false;
213 }
214
Count(void)215 inline int Count(void)
216 {
217 return nElements;
218 }
219 };
220
221 #endif
222 //###########################################################################
223
224 #define NSUBMTLS 10
225 static Class_ID multiClassID(MULTI_CLASS_ID,0);
226
227 class Multi;
228 class MultiDlg;
229 class DelSubRestore;
230
231
232 #define PBLOCK_REF 0
233 #define MTL_REF 1
234
235 class MultiDlg: public ParamDlg {
236 public:
237 HWND hwmedit; // window handle of the materials editor dialog
238 HFONT hFont;
239 IMtlParams *ip;
240 Multi *theMtl; // current mtl being edited.
241 HWND hPanelBasic; // Rollup pane
242 HWND hScroll;
243 TimeValue curTime;
244 int isActive;
245 BOOL valid;
246 ICustButton *iBut[NSUBMTLS];
247 ICustEdit *iName[NSUBMTLS];
248 ICustEdit *iIndex[NSUBMTLS];
249 BOOL isDup[NSUBMTLS];
250 MtlDADMgr dadMgr;
251
252 MultiDlg(HWND hwMtlEdit, IMtlParams *imp, Multi *m);
253 ~MultiDlg();
254 INT_PTR BasicPanelProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
255 void VScroll(int code, short int cpos );
256 void DrawPStampBlackBorder(HDC hdc, Rect &rect);
257 void DrawPStampHilite( int i, BOOL on);
258 void DrawPStampHilite(HDC hdc, BOOL on, Rect &rect );
259 void DrawPStamp(HDC hdc, Rect &rect, int i );
260 void RemovePStampHilite();
261 void DrawDupIndicators();
262 void SetIsDup(int i);
263 void SelectMtl(int i);
264 void UpdateSubMtlNames();
265 void UpdateColorSwatches();
266 void UpdatePStamp(int i);
267 void LoadDialog(BOOL draw); // stuff params into dialog
Invalidate()268 void Invalidate() {
269 valid = FALSE;
270 Rect rect;
271 rect.left = rect.top = 0;
272 rect.right = rect.bottom = 10;
273 InvalidateRect(hPanelBasic,&rect,FALSE);
274 }
275 void ReloadDialog();
UpdateMtlDisplay()276 void UpdateMtlDisplay() { ip->MtlChanged(); }
ActivateDlg(BOOL onOff)277 void ActivateDlg(BOOL onOff) {}
278 void SetNumMats(HWND hWnd);
279 void DragAndDrop(int ifrom, int ito);
280 int SubMtlNumFromNameID(int id);
281
282 // methods inherited from ParamDlg:
ClassID()283 Class_ID ClassID() {return multiClassID; }
284 void SetThing(ReferenceTarget *m);
GetThing()285 ReferenceTarget* GetThing() { return (ReferenceTarget *)theMtl; }
DeleteThis()286 void DeleteThis() { delete this; }
287 void SetTime(TimeValue t);
288 int FindSubMtlFromHWND(HWND hw);
289 };
290
291
292 // Parameter block indices
293 #define PB_THRESH 0
294 #define PB_WIDTH 1
295
296 //-----------------------------------------------------------------------------
297 // Multi
298 //-----------------------------------------------------------------------------
299
300 // JBW: IDs for ParamBlock2 blocks and parameters
301 // Parameter and ParamBlock IDs
302
303 enum { multi_params, }; // pblock ID
304
305 enum // multi_params param IDs
306 {
307 multi_mtls,
308 multi_ons,
309 multi_names,
310 multi_ids,
311 };
312
313
314 class Multi : public MultiMtl, public IReshading
315 {
316 friend class MultiDlg;
317 friend class SetNumMtlsRestore;
318 friend class DelSubRestore;
319 friend class AddMtlsRestore;
320 friend class SetSubRestore;
321
322 // Animatable parameters
323 Interval ivalid;
324 ReshadeRequirements mReshadeRQ; // mjm - 06.02.00
325 MultiDlg *paramDlg;
326 int offset;
327 int selected;
328
329 public:
330
331 NameTab subNames;
332 Tab<Mtl *> subMtl;
333
334 #if USE_HASHING
335 // allow fast conversions for sub-material id --> actual submaterial slot #
336 // (use int for the key, instead of short int, since -1 is reserved in the table)
337 MyHashTable< int, int > hashTab;
338 int hashTabDirty;
339 #endif
340
341 // Tab<BOOL> mapOn;
342
343 BOOL Param1;
344 BOOL ignoreNotify;
345 IParamBlock2 *pblock; // ref #0
346 int maxMtlId; // current max material id used in the list...needs to be updated when anything changes
347
348 BOOL loadingOld;
349 void AddMtl(ReferenceTarget *rt = NULL, int id=0, TCHAR *name=0);
350 void DeleteSelMtl();
351 void SortMtls( CompareFnc cmp );
352 void SortMtlsByName();
353 void SortMtlsByID();
354 void SortMtlsBySlotName();
355 BOOL AnyDupIDs();
356 // BOOL IsIDDup( int k );
357 void SetNumSubMtls( int n );
358 // void SetNSubMtls( int num );
359 void GetSubMtlName( int mtlid, TSTR &s );
360 void SetSubMtlAndName( int mtlid, Mtl *m, TSTR &subMtlName );
361 void RemoveMtl (int mtlid);
362 void ClampOffset();
363 Sampler* GetPixelSampler(int mtlNum, BOOL backFace );
364
SetAmbient(Color c,TimeValue t)365 void SetAmbient( Color c, TimeValue t ) {}
SetDiffuse(Color c,TimeValue t)366 void SetDiffuse( Color c, TimeValue t ) {}
SetSpecular(Color c,TimeValue t)367 void SetSpecular( Color c, TimeValue t ) {}
SetShininess(float v,TimeValue t)368 void SetShininess( float v, TimeValue t ) {}
369 void SetThresh( float v, TimeValue t);
370 void SetWidth( float v, TimeValue t);
371
372 Mtl * UseMtl();
373 Color GetAmbient( int mtlNum = 0, BOOL backFace = FALSE );
374 Color GetDiffuse( int mtlNum = 0, BOOL backFace = FALSE );
375 Color GetSpecular( int mtlNum = 0, BOOL backFace = FALSE );
376 float GetXParency( int mtlNum = 0, BOOL backFace = FALSE );
377 float GetShininess( int mtlNum = 0, BOOL backFace = FALSE );
378 float GetShinStr( int mtlNum = 0, BOOL backFace = FALSE );
379 float WireSize( int mtlNum = 0, BOOL backFace = FALSE );
380
381 Multi( BOOL loading, BOOL createDefaultSubMtls = TRUE ); // mjm - 10.11.99 - added createDefaultSubMtls parameter
382 ~Multi();
SetParamDlg(MultiDlg * pd)383 void SetParamDlg( MultiDlg *pd ) { paramDlg = pd; }
384 ParamDlg * CreateParamDlg( HWND hwMtlEdit, IMtlParams *imp );
385 void Shade( ShadeContext &sc );
386 float EvalDisplacement( ShadeContext &sc );
387 Interval DisplacementValidity( TimeValue t );
388 void Update( TimeValue t, Interval &valid );
389 void Init();
390 void Reset();
391 Interval Validity( TimeValue t );
392 void NotifyChanged();
393
ClassID()394 Class_ID ClassID() { return multiClassID; }
SuperClassID()395 SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
396 #ifndef GAME_VER // orb 08-21-2001 Fixing Defect 302554
GetClassName(TSTR & s)397 void GetClassName( TSTR &s ) { s = GetString(IDS_RB_MULTISUBOBJECT); }
398 #else
GetClassName(TSTR & s)399 void GetClassName( TSTR &s ) { s = GetString(IDS_RB_MULTISUBOBJECT_GMAX); }
400 #endif // GAME_VER
401
DeleteThis()402 void DeleteThis() { delete this; }
403
404
405 // Methods to access sub-materials of meta-materials
406
407 #if USE_HASHING
UpdateHashTable()408 void UpdateHashTable()
409 {
410 int count; // # of sub-materials to search
411 int id; // id of the sub material
412 Interval iv; // and interval
413 int i; // loop var
414
415 // wipe values in the table
416 hashTab.Clean();
417
418 // search through all our slots for the MAXIMUM id #
419 maxMtlId = -1; // start with max set to -1
420 count = subMtl.Count();
421 for ( i = 0; i < count; i++ )
422 {
423 // grab the id value from the param block (slow)
424 pblock->GetValue( multi_ids, 0, id, iv, i );
425 if ( id > maxMtlId )
426 maxMtlId = id;
427
428 // add to hash map
429 hashTab.AddAssociation( id, i );
430 }
431
432 // hash table not dirty anymore
433 hashTabDirty = 0;
434 }
435 #endif
436
MaxSubMtlID()437 int MaxSubMtlID()
438 {
439 #if USE_HASHING
440 if ( hashTabDirty )
441 UpdateHashTable();
442
443 return maxMtlId ;
444 #else
445 int mx; // max id # found
446 int count; // # of sub-materials to search
447 int id; // id of the sub material
448 Interval iv; // and interval
449 int i; // loop var
450
451 // search through all our slots for the MAXIMUM id #
452 mx = -1; // start with max set to -1
453 count = subMtl.Count();
454 for ( i = 0; i < count; i++ )
455 {
456 // grab the id value from the param block (slow)
457 pblock->GetValue( multi_ids, 0, id, iv, i );
458 if ( id > mx )
459 mx = id;
460 }
461
462 // return maximum id# found
463 return mx;
464 #endif
465 }
466
NumSubMtls()467 int NumSubMtls()
468 {
469 #if USE_HASHING
470 if ( hashTabDirty )
471 UpdateHashTable();
472
473 return maxMtlId + 1; // why does this return the max id and not count?????
474 #else
475 return MaxSubMtlID() + 1; // was - return subMtl.Count();
476 #endif
477 }
478
FindSubMtl(int i)479 int FindSubMtl( int i )
480 {
481 #if USE_HASHING
482 // rebuild hash table if dirty
483 if ( hashTabDirty )
484 UpdateHashTable();
485
486 // use hash table to find the index find the value associated with the material id key
487 int idx = hashTab.GetIndex( i );
488 if ( idx == -1 )
489 return -1;
490 else
491 return hashTab[idx]; // value
492 #else
493 int j; // loop var
494 int id; // id of sub material in loop
495 Interval iv; // and interval
496
497 // find a specific sub-material 'i'
498 // this should be in a table instead!
499 for ( j = 0; j < subMtl.Count(); j++ )
500 {
501 pblock->GetValue( multi_ids, 0, id, iv, j );
502 if ( id == i )
503 return j;
504 }
505 return -1;
506 #endif
507 }
508
FindSubMtlMod(int mtlid)509 int FindSubMtlMod( int mtlid )
510 {
511 #if USE_HASHING
512 // rebuild hash table if dirty
513 if ( hashTabDirty )
514 UpdateHashTable();
515
516 // bail out if no materials
517 if ( maxMtlId == -1 )
518 return -1;
519
520 // take care of wraparound.
521 // note: we need the UpdateHashTable() above to recalculate maxMtlId
522 if ( mtlid > maxMtlId )
523 mtlid = mtlid % ( maxMtlId + 1 );
524
525 // use hash table to find the index find the value associated with the material id key
526 int idx = hashTab.GetIndex( mtlid );
527 if ( idx == -1 )
528 return -1;
529 else
530 return hashTab[idx]; // value
531 #else
532 if ( maxMtlId == -1 )
533 return -1;
534 if ( mtlid > maxMtlId )
535 mtlid = mtlid % ( maxMtlId + 1 );
536 return FindSubMtl( mtlid ); // IS THIS GOING TO SLOW THINGS DOWN?
537 #endif
538 }
539
GetSubMtl(int i)540 Mtl * GetSubMtl( int i )
541 {
542 #if USE_HASHING
543 // rebuild hash table if dirty
544 if ( hashTabDirty )
545 UpdateHashTable();
546
547 // get the submaterial ptr
548 int idx = hashTab.GetIndex( i );
549 return ( idx == -1 ) ? NULL : subMtl[ hashTab[idx] ]; // 4/13/01 4:44pm --MQM-- from subMtl[idx] to subMtl[ hashTab[idx] ]
550 #else
551 int j = FindSubMtl( i );
552 return ( j >= 0 ) ? subMtl[j] : NULL;
553 #endif
554 }
555
556
557 void SetSubMtl( int i, Mtl *m );
558 TSTR GetSubMtlSlotName( int i );
IsMultiMtl()559 BOOL IsMultiMtl() { return TRUE; }
560
NumSubs()561 int NumSubs() { return subMtl.Count(); }
562 Animatable * SubAnim( int i );
563 TSTR SubAnimName( int i );
SubNumToRefNum(int subNum)564 int SubNumToRefNum( int subNum ) { return subNum+1; }
565
566 // From ref
NumRefs()567 int NumRefs() { return loadingOld ? subMtl.Count()+1 : subMtl.Count()+1; }
568 RefTargetHandle GetReference( int i );
569 void SetReference( int i, RefTargetHandle rtarg );
570 int RemapRefOnLoad( int iref ) ;
571
572 RefTargetHandle Clone( RemapDir &remap = DefaultRemapDir() );
573 RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget, PartID &partID, RefMessage message );
574
575 // IO
576 IOResult Save( ISave *isave );
577 IOResult Load( ILoad *iload );
578
579 // JBW: direct ParamBlock access is added
NumParamBlocks()580 int NumParamBlocks() { return 1; } // return number of ParamBlocks in this instance
GetParamBlock(int i)581 IParamBlock2 * GetParamBlock( int i ) { return pblock; } // return i'th ParamBlock
GetParamBlockByID(BlockID id)582 IParamBlock2 * GetParamBlockByID( BlockID id ) { return ( pblock->ID() == id ) ? pblock : NULL; } // return id'd ParamBlock
583
584 // begin - ke/mjm - 03.16.00 - merge reshading code
SupportsRenderElements()585 BOOL SupportsRenderElements() { return TRUE; }
586 // BOOL SupportsReShading(ShadeContext& sc);
GetReshadeRequirements()587 ReshadeRequirements GetReshadeRequirements() { return mReshadeRQ; } // mjm - 06.02.00
588 void PreShade( ShadeContext &sc, IReshadeFragment *pFrag);
589 void PostShade( ShadeContext &sc, IReshadeFragment *pFrag, int &nextTexIndex, IllumParams *ip );
590 // end - ke/mjm - 03.16.00 - merge reshading code
591
592 // From Mtl
593 bool IsOutputConst( ShadeContext &sc, int stdID );
594 bool EvalColorStdChannel( ShadeContext &sc, int stdID, Color &outClr );
595 bool EvalMonoStdChannel( ShadeContext &sc, int stdID, float &outVal );
596
597 void * GetInterface( ULONG id );
598 };
599
600
601 int numMultis = 0;
602 class MultiClassDesc:public ClassDesc2 {
603 public:
IsPublic()604 int IsPublic() { return GetAppID() != kAPP_VIZR; }
Create(BOOL loading)605 void * Create(BOOL loading) { return new Multi(loading); }
606 #ifndef GAME_VER // orb 08-21-2001 Fixing Defect 302554
ClassName()607 const TCHAR * ClassName() { return GetString(IDS_RB_MULTISUBOBJECT_CDESC); } // mjm - 2.3.99
608 #else
ClassName()609 const TCHAR * ClassName() { return GetString(IDS_RB_MULTISUBOBJECT_CDESC_GMAX); } // mjm - 2.3.99
610 #endif //GAME_VER
SuperClassID()611 SClass_ID SuperClassID() { return MATERIAL_CLASS_ID; }
ClassID()612 Class_ID ClassID() { return multiClassID; }
Category()613 const TCHAR* Category() { return _T(""); }
614 // PW: new descriptor data accessors added. Note that the
615 // internal name is hardwired since it must not be localized.
InternalName()616 const TCHAR* InternalName() { return _T("multiSubMaterial"); } // returns fixed parsable name (scripter-visible name)
HInstance()617 HINSTANCE HInstance() { return hInstance; } // returns owning module handle
618
619 };
620
621 static MultiClassDesc multiCD;
622
GetMultiDesc()623 ClassDesc* GetMultiDesc() {
624 return &multiCD;
625 }
626
627
628 // per instance param block
629 static ParamBlockDesc2 multi_param_blk ( multi_params, _T("parameters"), 0, &multiCD, P_AUTO_CONSTRUCT + P_AUTO_UI, PBLOCK_REF,
630 //rollout
631 IDD_MULTI, IDS_DS_MULTI_PARAMS, 0, 0, NULL,
632 // params
633 multi_mtls, _T("materialList"), TYPE_MTL_TAB, 10, P_OWNERS_REF + P_VARIABLE_SIZE, IDS_RB_MATERIAL2,
634 p_refno, MTL_REF,
635 end,
636 multi_ons, _T("mapEnabled"), TYPE_BOOL_TAB, 10, P_VARIABLE_SIZE, IDS_JW_MAP1ENABLE,
637 p_default, TRUE,
638 end,
639 multi_names, _T("names"), TYPE_STRING_TAB, 10, P_VARIABLE_SIZE, IDS_DS_MAP,
640 end,
641 multi_ids, _T("materialIDList"), TYPE_INT_TAB, 10, P_VARIABLE_SIZE, IDS_DS_INDEX,
642 p_dim, &theMultiIDDim, // 4/24/01 3:33pm --MQM-- add ParameterDimension function to fix maxscript #'s
643 end,
644 end
645 );
646
647
PanelDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)648 static INT_PTR CALLBACK PanelDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
649 MultiDlg *theDlg;
650 if (msg==WM_INITDIALOG) {
651 theDlg = (MultiDlg*)lParam;
652 theDlg->hPanelBasic = hwndDlg;
653 DLSetWindowLongPtr(hwndDlg, lParam);
654 }
655 else {
656 if ( (theDlg = DLGetWindowLongPtr<MultiDlg *>(hwndDlg) ) == NULL )
657 return FALSE;
658 }
659 theDlg->isActive = 1;
660 int res = theDlg->BasicPanelProc(hwndDlg,msg,wParam,lParam);
661 theDlg->isActive = 0;
662 return res;
663 }
664
665
FindSubMtlFromHWND(HWND hw)666 int MultiDlg::FindSubMtlFromHWND(HWND hw) {
667 for (int i=0; i<NSUBMTLS; i++) {
668 if (hw == iBut[i]->GetHwnd()) {
669 int j = i+theMtl->offset;
670 int id;
671 Interval iv;
672 theMtl->pblock->GetValue(multi_ids,0,id,iv,j);
673 return id;
674 }
675 }
676 return -1;
677 }
678
DragAndDrop(int ifrom,int ito)679 void MultiDlg::DragAndDrop(int ifrom, int ito) {
680 theMtl->CopySubMtl(hPanelBasic,ifrom+theMtl->offset, ito+theMtl->offset);
681 theMtl->NotifyChanged();
682 UpdateMtlDisplay();
683 }
684
685 //-------------------------------------------------------------------
686
MultiDlg(HWND hwMtlEdit,IMtlParams * imp,Multi * m)687 MultiDlg::MultiDlg(HWND hwMtlEdit, IMtlParams *imp, Multi *m) {
688 dadMgr.Init(this);
689 hwmedit = hwMtlEdit;
690 ip = imp;
691 hPanelBasic = NULL;
692 theMtl = m;
693 isActive = 0;
694 valid = FALSE;
695 theMtl->ClampOffset();
696 for (int i=0; i<NSUBMTLS; i++) {
697 iBut[i] = NULL;
698 iName[i] = NULL;
699 iIndex[i] = NULL;
700 isDup[i] = FALSE;
701 }
702 hFont = CreateFont(14,0,0,0,FW_BOLD,0,0,0,0,0,0,0, VARIABLE_PITCH | FF_SWISS, _T(""));
703 hPanelBasic = ip->AddRollupPage(
704 hInstance,
705 MAKEINTRESOURCE(IDD_MULTI),
706 PanelDlgProc,
707 GetString(IDS_DS_MULTI_PARAMS),
708 (LPARAM)this );
709 curTime = imp->GetTime();
710 }
711
ReloadDialog()712 void MultiDlg::ReloadDialog() {
713 Interval valid;
714 theMtl->Update(curTime,valid);
715 LoadDialog(FALSE);
716 }
717
SetTime(TimeValue t)718 void MultiDlg::SetTime(TimeValue t) {
719 if (t!=curTime) {
720 Interval valid;
721 curTime = t;
722 theMtl->Update(curTime,valid);
723 // Since nothing is time varying, can skip this
724 //InvalidateRect(hPanelBasic,NULL,0);
725 }
726 }
727
~MultiDlg()728 MultiDlg::~MultiDlg() {
729 theMtl->SetParamDlg(NULL);
730 DLSetWindowLongPtr(hPanelBasic, NULL);
731 hPanelBasic = NULL;
732 for (int i=0; i<NSUBMTLS; i++) {
733 ReleaseICustButton(iBut[i]);
734 ReleaseICustEdit(iName[i]);
735 ReleaseICustEdit(iIndex[i]);
736 iBut[i] = NULL;
737 iName[i] = NULL;
738 iIndex[i] = NULL;
739 }
740 DeleteObject(hFont);
741 }
742
743
744 static int subMtlId[NSUBMTLS] = {
745 IDC_MULTI_MTL0,
746 IDC_MULTI_MTL1,
747 IDC_MULTI_MTL2,
748 IDC_MULTI_MTL3,
749 IDC_MULTI_MTL4,
750 IDC_MULTI_MTL5,
751 IDC_MULTI_MTL6,
752 IDC_MULTI_MTL7,
753 IDC_MULTI_MTL8,
754 IDC_MULTI_MTL9
755 };
756
757
758 static int subNameId[NSUBMTLS] = {
759 IDC_MTL_NAME0,
760 IDC_MTL_NAME1,
761 IDC_MTL_NAME2,
762 IDC_MTL_NAME3,
763 IDC_MTL_NAME4,
764 IDC_MTL_NAME5,
765 IDC_MTL_NAME6,
766 IDC_MTL_NAME7,
767 IDC_MTL_NAME8,
768 IDC_MTL_NAME9
769 };
770
771 static int subIndex[NSUBMTLS] = {
772 IDC_MTL_ID0,
773 IDC_MTL_ID1,
774 IDC_MTL_ID2,
775 IDC_MTL_ID3,
776 IDC_MTL_ID4,
777 IDC_MTL_ID5,
778 IDC_MTL_ID6,
779 IDC_MTL_ID7,
780 IDC_MTL_ID8,
781 IDC_MTL_ID9
782 };
783
784
785 static int mapOnIDs[] = {
786 IDC_MAPON1,
787 IDC_MAPON2,
788 IDC_MAPON3,
789 IDC_MAPON4,
790 IDC_MAPON5,
791 IDC_MAPON6,
792 IDC_MAPON7,
793 IDC_MAPON8,
794 IDC_MAPON9,
795 IDC_MAPON10,
796 };
797 /*
798 static int numIDs[] = {
799 IDC_MULT_NUM1,
800 IDC_MULT_NUM2,
801 IDC_MULT_NUM3,
802 IDC_MULT_NUM4,
803 IDC_MULT_NUM5,
804 IDC_MULT_NUM6,
805 IDC_MULT_NUM7,
806 IDC_MULT_NUM8,
807 IDC_MULT_NUM9,
808 IDC_MULT_NUM10,
809 };
810 */
811
812 static int mtlPStampIDs[] = {
813 IDC_PSTAMP1,
814 IDC_PSTAMP2,
815 IDC_PSTAMP3,
816 IDC_PSTAMP4,
817 IDC_PSTAMP5,
818 IDC_PSTAMP6,
819 IDC_PSTAMP7,
820 IDC_PSTAMP8,
821 IDC_PSTAMP9,
822 IDC_PSTAMP10,
823 };
824
825 static int indexIDs[] = {
826 IDC_MTL_ID0,
827 IDC_MTL_ID1,
828 IDC_MTL_ID2,
829 IDC_MTL_ID3,
830 IDC_MTL_ID4,
831 IDC_MTL_ID5,
832 IDC_MTL_ID6,
833 IDC_MTL_ID7,
834 IDC_MTL_ID8,
835 IDC_MTL_ID9
836 };
837
SubMtlNumFromPStampID(int id)838 static int SubMtlNumFromPStampID(int id) {
839 for (int i=0; i<NSUBMTLS; i++) {
840 if (mtlPStampIDs[i]==id) return i;
841 }
842 return 0;
843 }
844
845
SubMtlNumFromNameID(int id)846 int MultiDlg::SubMtlNumFromNameID(int id) {
847 for (int i=0; i<NSUBMTLS; i++) {
848 if (subNameId[i]==id) return i;
849 }
850 return 0;
851 }
852
853
SubMtlNumIndexID(int id)854 static int SubMtlNumIndexID(int id) {
855 for (int i=0; i<NSUBMTLS; i++) {
856 if (indexIDs[i]==id) return i;
857 }
858 return 0;
859 }
860
RemovePStampHilite()861 void MultiDlg::RemovePStampHilite() {
862 for (int i=0; i<NSUBMTLS; i++) {
863 DrawPStampHilite( i, FALSE);
864 }
865 // if (theMtl->selected>=0)
866 // DrawPStampHilite( theMtl->selected-theMtl->offset, FALSE);
867 }
868
VScroll(int code,short int cpos)869 void MultiDlg::VScroll(int code, short int cpos ) {
870 for (int i=0; i<NSUBMTLS; i++) {
871 if (iIndex[i]->HasFocus()||iName[i]->HasFocus())
872 SetFocus(NULL);
873 }
874 RemovePStampHilite();
875 switch (code) {
876 case SB_LINEUP: theMtl->offset--; break;
877 case SB_LINEDOWN: theMtl->offset++; break;
878 case SB_PAGEUP: theMtl->offset -= NSUBMTLS; break;
879 case SB_PAGEDOWN: theMtl->offset += NSUBMTLS; break;
880
881 case SB_THUMBPOSITION:
882 case SB_THUMBTRACK:
883 theMtl->offset = cpos;
884 break;
885 }
886
887 theMtl->ClampOffset();
888 UpdateSubMtlNames();
889 }
890
891 #define DORECT(x) Rectangle( hdc, rect.left-(x), rect.top-(x), rect.right+(x), rect.bottom+(x) )
892
DrawPStampBlackBorder(HDC hdc,Rect & rect)893 void MultiDlg::DrawPStampBlackBorder(HDC hdc, Rect &rect) {
894 SelectObject( hdc, GetStockObject( NULL_BRUSH ) );
895 SelectObject(hdc,GetStockObject(BLACK_PEN));
896 DORECT(0);
897 }
898
DrawPStampHilite(HDC hdc,BOOL on,Rect & rect)899 void MultiDlg::DrawPStampHilite(HDC hdc, BOOL on, Rect &rect) {
900 SelectObject( hdc, GetStockObject( NULL_BRUSH ) );
901 HPEN hGray = CreatePen( PS_SOLID, 0, GetCustSysColor( COLOR_BTNFACE ) );
902 SelectObject(hdc, hGray);
903 if (on) SelectObject(hdc, GetStockObject(WHITE_PEN));
904 DORECT(1);
905 if (on) SelectObject(hdc, GetStockObject(BLACK_PEN));
906 DORECT(2);
907 DeleteObject( hGray);
908 }
909
DrawPStampHilite(int i,BOOL on)910 void MultiDlg::DrawPStampHilite( int i, BOOL on) {
911 HWND hwStamp = GetDlgItem(hPanelBasic, mtlPStampIDs[i]);
912 HDC hdc = GetDC(hwStamp);
913 Rect rect;
914 GetClientRect(hwStamp,&rect);
915 DrawPStampHilite(hdc, on, rect);
916 }
917
DrawDupIndicators()918 void MultiDlg::DrawDupIndicators() {
919 Rect rp;
920 GetWindowRect(hPanelBasic, &rp);
921 HDC hdc = GetDC(hPanelBasic);
922 HPEN hGray = CreatePen( PS_SOLID, 0, GetCustSysColor( COLOR_BTNFACE));
923 HPEN hRed = CreatePen( PS_SOLID, 0, RGB(255,0,0));
924 SelectObject( hdc, GetStockObject( NULL_BRUSH ) );
925 for (int i=0; i<NSUBMTLS; i++) {
926 Rect rect;
927 HWND hw = iIndex[i]->GetHwnd();
928 GetWindowRect( hw, &rect );
929 rect.left -= rp.left; rect.right -= rp.left;
930 rect.top -= rp.top; rect.bottom -= rp.top;
931 SelectObject(hdc, isDup[i]? hRed: hGray);
932 DORECT(1);
933 DORECT(2);
934 }
935 DeleteObject( hGray);
936 DeleteObject( hRed);
937 ReleaseDC(hPanelBasic,hdc);
938 }
939
SetIsDup(int i)940 void MultiDlg::SetIsDup(int i) {
941 if (i>=0&&i<NSUBMTLS)
942 isDup[i] = TRUE;
943 }
944
DrawPStamp(HDC hdc,Rect & rect,int i)945 void MultiDlg::DrawPStamp(HDC hdc, Rect &rect, int i ) {
946 i += theMtl->offset;
947 if (i>=theMtl->subMtl.Count())
948 return;
949 Mtl *m = theMtl->subMtl[i];
950 if (m==NULL) {
951 HBRUSH hOldbrush = (HBRUSH)SelectObject(hdc,GetCustSysColorBrush(COLOR_BTNFACE));
952 DORECT(0);
953 SelectObject(hdc,hOldbrush);
954 }
955 else {
956 PStamp *ps = m->GetPStamp(PS_TINY);
957 if (!ps)
958 ps = m->CreatePStamp(PS_TINY,TRUE);
959 int w = ps->Width();
960 int h = ps->Height();
961 int scanw = ByteWidth(w);
962 int nb = scanw*h;
963 UBYTE *workImg = new UBYTE[nb];
964 ps->GetImage(workImg);
965
966 GetGPort()->DisplayMap(hdc, rect, 0, 0, workImg, scanw);
967 delete workImg;
968
969 /*
970 int h = rect.bottom-rect.top;
971 int w = rect.right-rect.left;
972 if (w>h) w = h;
973 if (h>w) h = w;
974 int scanw = ByteWidth(w);
975 int nb = scanw*h;
976 UBYTE *workImg = new UBYTE[nb];
977
978 // Need to put this into Interface with separate w,h
979 GetCOREInterface()->Execute(I_EXEC_RENDER_MTL_SAMPLE,(ULONG_PTR)m, (ULONG_PTR)w, (ULONG_PTR)workImg);
980 GetGPort()->DisplayMap(hdc, rect, 0, 0, workImg, scanw);
981 delete workImg;
982 */
983 }
984 DrawPStampBlackBorder(hdc, rect);
985 if (i==theMtl->selected) {
986 DrawPStampHilite(hdc, TRUE, rect);
987 }
988 }
989
SelectMtl(int i)990 void MultiDlg::SelectMtl(int i) {
991 if (theMtl->selected>=0)
992 DrawPStampHilite(theMtl->selected-theMtl->offset,FALSE);
993 theMtl->selected = i+theMtl->offset;
994 if (i>=0)
995 DrawPStampHilite(i, TRUE);
996 }
997
PStampWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)998 LRESULT CALLBACK PStampWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
999 {
1000 LONG_PTR id = SubMtlNumFromPStampID(GetWindowLongPtr(hwnd,GWLP_ID));
1001 HWND hwParent = GetParent(hwnd);
1002 MultiDlg *theDlg = DLGetWindowLongPtr<MultiDlg *>(hwParent);
1003 if (theDlg==NULL) return FALSE;
1004
1005 switch (msg) {
1006 case WM_COMMAND:
1007 case WM_MOUSEMOVE:
1008 case WM_CREATE:
1009 case WM_DESTROY:
1010 break;
1011
1012 case WM_LBUTTONUP:
1013 theDlg->SelectMtl( id );
1014 break;
1015
1016 case WM_PAINT:
1017 {
1018 PAINTSTRUCT ps;
1019 Rect rect;
1020 HDC hdc = BeginPaint( hwnd, &ps );
1021 if (!IsRectEmpty(&ps.rcPaint)) {
1022 GetClientRect( hwnd, &rect );
1023 theDlg->DrawPStamp( hdc, rect, id ) ;
1024 }
1025 EndPaint( hwnd, &ps );
1026 }
1027 break;
1028 }
1029 return DefWindowProc(hwnd,msg,wParam,lParam);
1030 }
1031
1032
DupMsgWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1033 LRESULT CALLBACK DupMsgWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1034 {
1035 switch (msg) {
1036 case WM_PAINT:
1037 {
1038 PAINTSTRUCT ps;
1039 Rect rect;
1040 HDC hdc = BeginPaint( hwnd, &ps );
1041 if (!IsRectEmpty(&ps.rcPaint)) {
1042 SetTextColor(hdc, RGB(255,0,0));
1043 SetBkMode(hdc, TRANSPARENT);
1044 TCHAR buf[256];
1045 GetWindowText(hwnd,buf,sizeof(buf));
1046 DLTextOut(hdc, 0, 0, buf);
1047 }
1048 EndPaint( hwnd, &ps );
1049 }
1050 break;
1051 default:
1052 break;
1053 }
1054 return DefWindowProc(hwnd,msg,wParam,lParam);
1055 }
1056
1057 static BOOL ignoreKillFocus = FALSE;
1058
BasicPanelProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)1059 INT_PTR MultiDlg::BasicPanelProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) {
1060 int id = LOWORD(wParam);
1061 int code = HIWORD(wParam);
1062 switch (msg) {
1063 case WM_INITDIALOG: {
1064 hScroll = GetDlgItem(hwndDlg,IDC_MULTI_SCROLL);
1065 SetScrollRange(hScroll,SB_CTL,0,theMtl->subMtl.Count()-NSUBMTLS,FALSE);
1066 SetScrollPos(hScroll,SB_CTL,theMtl->offset,TRUE);
1067 EnableWindow(hScroll,theMtl->subMtl.Count()>NSUBMTLS);
1068 SendDlgItemMessage(hwndDlg,IDC_DUP_IDS,WM_SETFONT,(WPARAM)hFont,TRUE);
1069 ShowWindow(GetDlgItem(hwndDlg,IDC_DUP_IDS),theMtl->AnyDupIDs()?SW_SHOW:SW_HIDE);
1070 for (int i=0; i<NSUBMTLS; i++) {
1071 iBut[i] = GetICustButton(GetDlgItem(hwndDlg,subMtlId[i]));
1072 iBut[i]->SetDADMgr(&dadMgr);
1073 iName[i] = GetICustEdit( GetDlgItem(hwndDlg,subNameId[i]));
1074 iName[i]->SetLeading(2); //??
1075 iIndex[i] = GetICustEdit(GetDlgItem(hwndDlg,subIndex[i]));
1076 iIndex[i]->SetLeading(2); //??
1077 iIndex[i]->WantReturn(TRUE);
1078 if (i+theMtl->offset<theMtl->subMtl.Count()) {
1079 TCHAR *name;
1080 int id;
1081 Interval iv;
1082 theMtl->pblock->GetValue(multi_names,0,name,iv,i+theMtl->offset);
1083 iName[i]->SetText(name);
1084 theMtl->pblock->GetValue(multi_ids,0,id,iv,i+theMtl->offset); //??????
1085 iIndex[i]->SetText(id+1); //?????
1086
1087 // iName[i]->SetText(theMtl->subNames[i+theMtl->offset]);
1088 }
1089 // TSTR buf;
1090 // buf.printf("%d:",i+theMtl->offset+1);
1091 // SetDlgItemText(hwndDlg,numIDs[i],buf);
1092 int onCount = theMtl->pblock->Count(multi_ons);
1093 if (i-theMtl->offset<onCount)
1094 {
1095 int on;
1096 Interval iv;
1097 theMtl->pblock->GetValue(multi_ons,0,on,iv,i+theMtl->offset);
1098 SetCheckBox(hwndDlg, mapOnIDs[i], on);
1099 }
1100 // if (i-theMtl->offset<theMtl->mapOn.Count())
1101 // SetCheckBox(hwndDlg, mapOnIDs[i], theMtl->mapOn[i+theMtl->offset]);
1102
1103 HWND hwnd = GetDlgItem(hwndDlg, mtlPStampIDs[i]);
1104 DLSetWindowLongPtr( hwnd, PStampWndProc);
1105 DLSetWindowLongPtr( hwnd, this);
1106
1107 hwnd = GetDlgItem(hwndDlg, IDC_DUP_IDS);
1108 DLSetWindowLongPtr( hwnd, DupMsgWndProc);
1109
1110 }
1111 DrawDupIndicators();
1112 }
1113 return TRUE;
1114 case WM_VSCROLL:
1115 VScroll(LOWORD(wParam),(short int)HIWORD(wParam));
1116 break;
1117
1118 case WM_COMMAND:
1119 switch (id) {
1120 case IDC_MULTI_MTL0:
1121 case IDC_MULTI_MTL1:
1122 case IDC_MULTI_MTL2:
1123 case IDC_MULTI_MTL3:
1124 case IDC_MULTI_MTL4:
1125 case IDC_MULTI_MTL5:
1126 case IDC_MULTI_MTL6:
1127 case IDC_MULTI_MTL7:
1128 case IDC_MULTI_MTL8:
1129 case IDC_MULTI_MTL9: {
1130 int i = id-IDC_MULTI_MTL0 + theMtl->offset;
1131 if (i < theMtl->subMtl.Count()) {
1132 int mtlid;
1133 Interval iv;
1134 theMtl->pblock->GetValue(multi_ids,0,mtlid,iv,i);
1135 PostMessage(hwmedit,WM_SUB_MTL_BUTTON, mtlid ,(LPARAM)theMtl);
1136 }
1137 }
1138 break;
1139
1140 case IDC_MAPON1:
1141 case IDC_MAPON2:
1142 case IDC_MAPON3:
1143 case IDC_MAPON4:
1144 case IDC_MAPON5:
1145 case IDC_MAPON6:
1146 case IDC_MAPON7:
1147 case IDC_MAPON8:
1148 case IDC_MAPON9:
1149 case IDC_MAPON10:
1150 // theMtl->mapOn[id-IDC_MAPON1+theMtl->offset] = GetCheckBox(hwndDlg, id);
1151 {
1152 int on = GetCheckBox(hwndDlg, id);
1153 Interval iv;
1154 theMtl->pblock->SetValue(multi_ons,0,on,id-IDC_MAPON1+theMtl->offset);
1155
1156 theMtl->NotifyChanged();
1157 break;
1158 }
1159
1160 case IDC_MULTI_SETNUM:
1161 SetNumMats(hwndDlg);
1162 break;
1163
1164 case IDC_MULTI_ADD:
1165 if ( theMtl->MaxSubMtlID() >= 1000 ) // 4/24/01 1:50pm --MQM-- don't allow new materials when id's are above 1000
1166 break;
1167 RemovePStampHilite();
1168 theHold.Begin();
1169 theMtl->AddMtl();
1170 theHold.Accept(GetString(IDS_DS_ADD_SUBMTL));
1171 UpdateSubMtlNames();
1172 UpdateMtlDisplay();
1173 break;
1174
1175 case IDC_MULTI_DELETE:
1176 if ( theMtl->subMtl.Count() == 1 ) // 4/12/01 11:10am --MQM-- don't let the user delete the last material
1177 break;
1178 RemovePStampHilite();
1179 theHold.Begin();
1180 theMtl->DeleteSelMtl();
1181 theHold.Accept(GetString(IDS_DS_DELSUBMAT));
1182 theMtl->UpdateHashTable(); // 4/10/01 11:57am --MQM-- force update before redisplay
1183 UpdateSubMtlNames();
1184 UpdateMtlDisplay();
1185 break;
1186
1187 case IDC_MULTI_SORT:
1188 RemovePStampHilite();
1189 theMtl->SortMtlsByID();
1190 UpdateSubMtlNames();
1191 UpdateMtlDisplay();
1192 break;
1193
1194 case IDC_MULTI_ALPHASORT:
1195 RemovePStampHilite();
1196 theMtl->SortMtlsByName();
1197 UpdateSubMtlNames();
1198 UpdateMtlDisplay();
1199 break;
1200
1201 case IDC_MULTI_NAMESORT:
1202 RemovePStampHilite();
1203 theMtl->SortMtlsBySlotName();
1204 UpdateSubMtlNames();
1205 UpdateMtlDisplay();
1206 break;
1207
1208
1209 case IDC_MTL_NAME0:
1210 case IDC_MTL_NAME1:
1211 case IDC_MTL_NAME2:
1212 case IDC_MTL_NAME3:
1213 case IDC_MTL_NAME4:
1214 case IDC_MTL_NAME5:
1215 case IDC_MTL_NAME6:
1216 case IDC_MTL_NAME7:
1217 case IDC_MTL_NAME8:
1218 case IDC_MTL_NAME9:
1219 if (HIWORD(wParam)==EN_CHANGE) {
1220 TCHAR buf[200];
1221 int n = SubMtlNumFromNameID(id);
1222 iName[n]->GetText(buf,199);
1223 // theMtl->subNames.SetName(n+theMtl->offset, buf);
1224 theMtl->pblock->SetValue(multi_names,0,buf,n+theMtl->offset);
1225 #if USE_HASHING
1226 // theMtl->UpdateHashTable();
1227 theMtl->hashTabDirty = 1;
1228 #endif
1229 }
1230 break;
1231
1232 case IDC_MTL_ID0:
1233 case IDC_MTL_ID1:
1234 case IDC_MTL_ID2:
1235 case IDC_MTL_ID3:
1236 case IDC_MTL_ID4:
1237 case IDC_MTL_ID5:
1238 case IDC_MTL_ID6:
1239 case IDC_MTL_ID7:
1240 case IDC_MTL_ID8:
1241 case IDC_MTL_ID9:
1242
1243 // if user exits from this material ID box, or the control was
1244 // changed by someone else, take care of updating the value in the pblock
1245 if ( ( HIWORD(wParam)==EN_KILLFOCUS && !ignoreKillFocus ) ||
1246 HIWORD(wParam)==EN_CHANGE )
1247 {
1248 int n = SubMtlNumIndexID( id );
1249 if ( HIWORD(wParam)==EN_KILLFOCUS || iIndex[n]->GotReturn() )
1250 {
1251 // get the old ID from the pblock for comparison purposes
1252 Interval iv;
1253 int oldMtlId;
1254 theMtl->pblock->GetValue( multi_ids, 0, oldMtlId, iv, n+theMtl->offset );
1255
1256 // and grab the new ID from the edit control
1257 int newMtlId = iIndex[n]->GetInt()-1;
1258
1259 // ignore notify messages
1260 theMtl->ignoreNotify = TRUE;
1261
1262 // if the new ID is different than the old one, set it in the pblock
1263 if ( newMtlId != oldMtlId )
1264 {
1265 // disable the macro recorder, since it will spit out the WRONG id#
1266 macroRec->Disable();
1267
1268 #if USE_HASHING
1269 // id has changed, we need to recompute hash table!!!
1270 theMtl->hashTabDirty = 1;
1271 #endif
1272 // set the new ID value in the pblock
1273 theMtl->pblock->SetValue( multi_ids, 0, newMtlId, n+theMtl->offset );
1274
1275 // now turn the macro recorder back on, and spit out the "correct" material id
1276 // it was getting it directly from the pblock, so we need to add +1 to it!
1277 macroRec->Enable();
1278 macroRecorder->Assign(mr_index, mr_prop, _T("materialIDList"), mr_reftarg, theMtl, mr_int, n+theMtl->offset+1 , mr_int, newMtlId+1 );
1279 }
1280
1281 // turn back on notify
1282 theMtl->ignoreNotify = FALSE;
1283
1284 // check for duplicate id's
1285 ShowWindow( GetDlgItem(hwndDlg,IDC_DUP_IDS), theMtl->AnyDupIDs() ? SW_SHOW : SW_HIDE );
1286 DrawDupIndicators();
1287
1288 /*
1289 if (theMtl->IsIDDup(n)) {
1290 TCHAR msg[128];
1291 wsprintf(msg,GetString(IDS_DUP_WARNING), newMtlId+1);
1292 ignoreKillFocus = TRUE;
1293 MessageBox(NULL, msg, GetString(IDS_RB_MULTISUBOBJECT), MB_TASKMODAL);
1294 ignoreKillFocus = FALSE;
1295 }
1296 */
1297 }
1298 }
1299 break;
1300
1301 }
1302 break;
1303 case WM_PAINT:
1304 if (!valid) {
1305 valid = TRUE;
1306 ReloadDialog();
1307 }
1308 {
1309 PAINTSTRUCT ps;
1310 Rect rect;
1311 HDC hdc = BeginPaint( hwndDlg, &ps );
1312 if (!IsRectEmpty(&ps.rcPaint)) {
1313 DrawDupIndicators();
1314 }
1315 EndPaint( hwndDlg, &ps );
1316 }
1317 return FALSE;
1318 case WM_CLOSE:
1319 break;
1320 case WM_DESTROY:
1321 break;
1322
1323
1324 case CC_COLOR_BUTTONDOWN:
1325 theHold.Begin();
1326 break;
1327 case CC_COLOR_BUTTONUP:
1328 if (HIWORD(wParam)) theHold.Accept(GetString(IDS_DS_PARAMCHG));
1329 else theHold.Cancel();
1330 break;
1331
1332 case CC_COLOR_CHANGE: {
1333 if (HIWORD(wParam)) theHold.Begin();
1334 int i = LOWORD(wParam)-IDC_MULTI_COLOR1+theMtl->offset;
1335 IColorSwatch *cs = (IColorSwatch*)lParam;
1336 if (i>=0 && i<theMtl->subMtl.Count()&&theMtl->subMtl[i]) {
1337 theMtl->subMtl[i]->SetDiffuse(
1338 Color(cs->GetColor()),curTime);
1339 }
1340 UpdateColorSwatches();
1341 if (HIWORD(wParam)) {
1342 theHold.Accept(GetString(IDS_DS_PARAMCHG));
1343 UpdateMtlDisplay();
1344 }
1345 break;
1346 }
1347
1348 case WM_CUSTEDIT_ENTER: {
1349 // mask keyboard input for sub material id#'s
1350 for (int x=0; x<NSUBMTLS; x++) { // check all the controls
1351 if (subIndex[x] == id) { // this control is the one
1352 int val = iIndex[x]->GetInt();
1353 if (val<1) // restrict to 1..1000
1354 val=1;
1355 else if (val>1000)
1356 val=1000;
1357 iIndex[x]->SetText(val);
1358 }
1359 }
1360 UpdateMtlDisplay();
1361 break;
1362 }
1363
1364 case CC_SPINNER_BUTTONUP:
1365 UpdateMtlDisplay();
1366 break;
1367
1368 }
1369 return FALSE;
1370 }
1371
BasicPanelDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)1372 static INT_PTR CALLBACK BasicPanelDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
1373 MultiDlg *theDlg;
1374 if (msg==WM_INITDIALOG) {
1375 theDlg = (MultiDlg*)lParam;
1376 theDlg->hPanelBasic = hwndDlg;
1377 DLSetWindowLongPtr(hwndDlg, lParam);
1378 }
1379 else {
1380 if ( (theDlg = DLGetWindowLongPtr<MultiDlg *>(hwndDlg) ) == NULL )
1381 return FALSE;
1382 }
1383 theDlg->isActive = 1;
1384 int res = theDlg->BasicPanelProc(hwndDlg,msg,wParam,lParam);
1385 theDlg->isActive = 0;
1386 return res;
1387 }
1388
UpdateColorSwatches()1389 void MultiDlg::UpdateColorSwatches() {
1390
1391 for (int i=0; i<theMtl->subMtl.Count()-theMtl->offset && i<NSUBMTLS; i++) {
1392 Mtl *m = theMtl->subMtl[i+theMtl->offset];
1393
1394 TSTR nm, label;
1395 if (m) nm = m->GetFullName();
1396 else nm = GetString(IDS_DS_NONE);
1397 if (m) {
1398 IColorSwatch *cs = GetIColorSwatch(GetDlgItem(hPanelBasic,IDC_MULTI_COLOR1+i),
1399 m->GetDiffuse(),nm);
1400 cs->SetColor(m->GetDiffuse());
1401 ReleaseIColorSwatch(cs);
1402 }
1403 }
1404
1405 }
1406
UpdatePStamp(int i)1407 void MultiDlg::UpdatePStamp( int i ) {
1408 HWND hPStamp = GetDlgItem( hPanelBasic, mtlPStampIDs[i] );
1409 InvalidateRect(hPStamp, NULL, FALSE);
1410 }
1411
UpdateSubMtlNames()1412 void MultiDlg::UpdateSubMtlNames() {
1413 IColorSwatch *cs;
1414 int ct = theMtl->pblock->Count(multi_names);
1415
1416 if (theMtl->selected<0)
1417 theMtl->selected = theMtl->subMtl.Count()-1;
1418
1419 ShowWindow(GetDlgItem(hPanelBasic,IDC_DUP_IDS),theMtl->AnyDupIDs()?SW_SHOW:SW_HIDE);
1420 DrawDupIndicators();
1421
1422 int i;
1423 for (i=0; i<theMtl->subMtl.Count()-theMtl->offset && i<NSUBMTLS; i++) {
1424 Mtl *m = theMtl->subMtl[i+theMtl->offset];
1425 TSTR nm, label;
1426 if (m)
1427 nm = m->GetFullName();
1428 else
1429 nm = GetString(IDS_DS_NONE);
1430
1431 HWND hx = GetDlgItem(hPanelBasic, IDC_PSTAMP1);
1432 ShowWindow(GetDlgItem(hPanelBasic, IDC_MULTI_MTL0+i), SW_SHOW);
1433 ShowWindow(GetDlgItem(hPanelBasic, IDC_MULTI_COLOR1+i), SW_SHOW);
1434
1435 if ((m==NULL)||(m->IsMultiMtl()||m->NumSubMtls()>0))
1436 EnableWindow(GetDlgItem(hPanelBasic, IDC_MULTI_COLOR1+i), FALSE);
1437 else
1438 EnableWindow(GetDlgItem(hPanelBasic, IDC_MULTI_COLOR1+i), TRUE);
1439 ShowWindow(GetDlgItem(hPanelBasic, subNameId[i]), SW_SHOW);
1440 ShowWindow(GetDlgItem(hPanelBasic,mapOnIDs[i]),SW_SHOW);
1441 ShowWindow(GetDlgItem(hPanelBasic,subIndex[i]),SW_SHOW);
1442 ShowWindow(GetDlgItem(hPanelBasic,mtlPStampIDs[i]),SW_SHOW);
1443
1444 int on;
1445 Interval iv;
1446
1447 if ((i+theMtl->offset)<ct)
1448 {
1449 theMtl->pblock->GetValue(multi_ons,0,on,iv,i+theMtl->offset);
1450
1451 SetCheckBox(hPanelBasic, mapOnIDs[i], on);
1452 }
1453 // SetCheckBox(hPanelBasic, mapOnIDs[i], theMtl->mapOn[i+theMtl->offset]);
1454
1455 // SetDlgItemText(hPanelBasic, IDC_MULTI_MTL0+i, nm.data());
1456 iBut[i]->SetText(nm.data());
1457
1458 if (m) {
1459 cs = GetIColorSwatch(GetDlgItem(hPanelBasic,IDC_MULTI_COLOR1+i),
1460 m->GetDiffuse(),nm);
1461 cs->SetColor(m->GetDiffuse());
1462 ReleaseIColorSwatch(cs);
1463 }
1464
1465 TCHAR *name;
1466 Interval niv;
1467 if ((i+theMtl->offset)<ct)
1468 {
1469 theMtl->pblock->GetValue(multi_names,0,name,niv,i+theMtl->offset);
1470 if (name) {
1471 TCHAR buf[256];
1472 iName[i]->GetText(buf,255);
1473 if (_tcscmp(name,buf))
1474 iName[i]->SetText(name);
1475 }
1476 else iName[i]->SetText(_T(""));
1477 int theid;
1478 theMtl->pblock->GetValue(multi_ids,0,theid,niv,i+theMtl->offset);
1479 iIndex[i]->SetText(theid+1); //?????
1480 }
1481 // TSTR buf;
1482 // buf.printf("%d:",i+theMtl->offset+1);
1483 // SetDlgItemText(hPanelBasic,numIDs[i],buf);
1484
1485 HWND hwps = GetDlgItem(hPanelBasic,mtlPStampIDs[i]);
1486 InvalidateRect(hwps, NULL, FALSE);
1487 }
1488 for ( ; i<NSUBMTLS; i++) {
1489 ShowWindow(GetDlgItem(hPanelBasic, IDC_MULTI_MTL0+i), SW_HIDE);
1490 ShowWindow(GetDlgItem(hPanelBasic, IDC_MULTI_COLOR1+i), SW_HIDE);
1491 ShowWindow(GetDlgItem(hPanelBasic, subNameId[i]), SW_HIDE);
1492 ShowWindow(GetDlgItem(hPanelBasic,mapOnIDs[i]),SW_HIDE);
1493 ShowWindow(GetDlgItem(hPanelBasic,subIndex[i]),SW_HIDE);
1494 ShowWindow(GetDlgItem(hPanelBasic,mtlPStampIDs[i]),SW_HIDE);
1495 // TSTR buf;
1496 // SetDlgItemText(hPanelBasic,numIDs[i],buf);
1497 }
1498 TSTR buf;
1499 buf.printf(_T("%d"),theMtl->subMtl.Count());
1500 SetDlgItemText(hPanelBasic,IDC_MULTI_NUMMATS,buf);
1501 SetScrollRange(hScroll,SB_CTL,0,theMtl->subMtl.Count()-NSUBMTLS,FALSE);
1502 SetScrollPos(hScroll,SB_CTL,theMtl->offset,TRUE);
1503 EnableWindow(hScroll,theMtl->subMtl.Count()>NSUBMTLS);
1504 }
1505
LoadDialog(BOOL draw)1506 void MultiDlg::LoadDialog(BOOL draw) {
1507 if (theMtl) {
1508 Interval valid;
1509 theMtl->Update(curTime,valid);
1510 UpdateSubMtlNames();
1511 }
1512 }
1513
SetThing(ReferenceTarget * m)1514 void MultiDlg::SetThing(ReferenceTarget *m) {
1515 assert (m->ClassID()==multiClassID);
1516 assert (m->SuperClassID()==MATERIAL_CLASS_ID);
1517 RemovePStampHilite();
1518 if (theMtl) theMtl->paramDlg = NULL;
1519 theMtl = (Multi *)m;
1520 if (theMtl) theMtl->paramDlg = this;
1521 LoadDialog(TRUE);
1522 }
1523
1524 static int addNum = 5;
1525
NumMatsDlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)1526 static INT_PTR CALLBACK NumMatsDlgProc(
1527 HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1528 {
1529 switch (msg) {
1530 case WM_INITDIALOG: {
1531 ISpinnerControl *spin =
1532 SetupIntSpinner(
1533 hWnd,IDC_MULTI_NUMMATSSPIN,IDC_MULTI_NUMMATS,
1534 1,1000,(int)lParam);
1535 ReleaseISpinner(spin);
1536 CenterWindow(hWnd,GetParent(hWnd));
1537 break;
1538 }
1539
1540 case WM_COMMAND:
1541 switch (LOWORD(wParam)) {
1542 case IDOK: {
1543 ISpinnerControl *spin =
1544 GetISpinner(GetDlgItem(hWnd,IDC_MULTI_NUMMATSSPIN));
1545 EndDialog(hWnd,spin->GetIVal());
1546 ReleaseISpinner(spin);
1547 break;
1548 }
1549
1550 case IDCANCEL:
1551 EndDialog(hWnd,-1);
1552 break;
1553 }
1554 break;
1555
1556 default:
1557 return FALSE;
1558 }
1559 return TRUE;
1560 }
1561
SetNumMats(HWND hWnd)1562 void MultiDlg::SetNumMats(HWND hWnd)
1563 {
1564 int res = DialogBoxParam(
1565 hInstance,
1566 MAKEINTRESOURCE(IDD_MULTI_SETNUM),
1567 hPanelBasic,
1568 NumMatsDlgProc,
1569 (LPARAM)theMtl->subMtl.Count());
1570 if (res>=0) {
1571 if (res<=0) res = 1;
1572 if (res>1000) res = 1000;
1573 if (res==theMtl->subMtl.Count())
1574 return;
1575 RemovePStampHilite();
1576 HCURSOR c = SetCursor(LoadCursor(NULL,IDC_WAIT));
1577 theHold.Begin();
1578 theMtl->SetNumSubMtls(res);
1579 theHold.Accept(GetString(IDS_DS_SET_NSUB));
1580 SetCursor(c);
1581 UpdateSubMtlNames();
1582 UpdateMtlDisplay();
1583 }
1584 }
1585
1586
1587
1588 //-----------------------------------------------------------------------------
1589 // Multi
1590 //-----------------------------------------------------------------------------
1591
1592
1593
1594 static ParamBlockDesc pbdesc[] = {
1595 { TYPE_FLOAT, NULL, TRUE } }; // blend
1596
Init()1597 void Multi::Init() {
1598 ivalid.SetEmpty();
1599 offset = 0;
1600 maxMtlId = -1;
1601 hashTabDirty = 1;
1602 #if USE_HASHING
1603 hashTab.Initialize( 10 );
1604 #endif
1605 }
1606
Reset()1607 void Multi::Reset() {
1608 Init();
1609 // multiCD.Reset(this, TRUE); // reset all pb2's <-- 4/10/01 11:27am --MQM-- this line not needed
1610 // for (int i=0; i<subMtl.Count(); i++)
1611 // DeleteReference(i+1);
1612 SetNumSubMtls(NSUBMTLS);
1613 for (int i=0; i<subMtl.Count(); i++) {
1614 HoldSuspend hs; // LAM - 6/12/04 - defect 571821
1615 ReferenceTarget* mtl = (ReferenceTarget*)GetStdMtl2Desc()->Create();
1616 hs.Resume();
1617 ReplaceReference(i+1, mtl);
1618 GetCOREInterface()->AssignNewName(subMtl[i]);
1619 pblock->SetValue(multi_ids,0,i,i);
1620 }
1621 }
1622
GetInterface(ULONG id)1623 void* Multi::GetInterface(ULONG id)
1624 {
1625 if( id == IID_IReshading )
1626 return (IReshading*)( this );
1627 else if ( id == IID_IValidityToken )
1628 return (IValidityToken*)( this );
1629 else
1630 return MultiMtl::GetInterface(id);
1631 }
1632
NotifyChanged()1633 void Multi::NotifyChanged() {
1634 ivalid.SetEmpty();
1635 NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
1636 }
1637
Multi(BOOL loading,BOOL createDefaultSubMtls)1638 Multi::Multi(BOOL loading, BOOL createDefaultSubMtls) : mReshadeRQ(RR_None) // mjm - 06.02.00 // mjm - 10.11.99 - added createDefaultSubMtls parameter
1639 {
1640 paramDlg = NULL;
1641 Param1 = FALSE;
1642 ignoreNotify = FALSE;
1643 selected = -1;
1644
1645 /*
1646 subMtl.SetCount(NSUBMTLS);
1647 for (int i=0; i<NSUBMTLS; i++) subMtl[i] = NULL;
1648 */
1649 pblock = NULL;
1650
1651 loadingOld = FALSE;
1652 multiCD.MakeAutoParamBlocks(this); // make and intialize paramblock2
1653 Init();
1654
1655 if (!loading && createDefaultSubMtls) // mjm - 10.11.99
1656 SetNumSubMtls(NSUBMTLS);
1657
1658 pblock->DefineParamAlias(_T("material1"), multi_mtls, 0); // JBW 5/24/99, add alias for base material to support macroRecording
1659 }
1660
~Multi()1661 Multi::~Multi() {
1662
1663 }
1664
UseMtl()1665 Mtl *Multi::UseMtl() {
1666 Mtl* m = NULL;
1667 for (int i=0; i<subMtl.Count(); i++) if (subMtl[i]) { m = subMtl[i]; break; }
1668 return m;
1669 }
1670
ClampOffset()1671 void Multi::ClampOffset()
1672 {
1673 if (offset>subMtl.Count()-NSUBMTLS) {
1674 offset=subMtl.Count()-NSUBMTLS;
1675 }
1676 if (offset<0) offset = 0;
1677 }
1678
1679 // These allow the real-time renderer to display a material appearance.
GetAmbient(int mtlNum,BOOL backFace)1680 Color Multi::GetAmbient(int mtlNum, BOOL backFace) {
1681 int j = FindSubMtlMod(mtlNum);
1682 if(j<0)
1683 return Color(0.f,0.f,0.f);
1684 if (subMtl[j]) return subMtl[j]->GetAmbient(mtlNum,backFace);
1685 return UseMtl()?UseMtl()->GetAmbient(mtlNum,backFace):Color(0,0,0);
1686 }
1687
GetDiffuse(int mtlNum,BOOL backFace)1688 Color Multi::GetDiffuse(int mtlNum, BOOL backFace){
1689 int j = FindSubMtlMod(mtlNum);
1690 if(j<0)
1691 return Color(0.f,0.f,0.f);
1692 if (subMtl[j]) return subMtl[j]->GetDiffuse(mtlNum,backFace);
1693 return UseMtl()?UseMtl()->GetDiffuse():Color(0,0,0);
1694 }
1695
GetSpecular(int mtlNum,BOOL backFace)1696 Color Multi::GetSpecular(int mtlNum, BOOL backFace){
1697 int j = FindSubMtlMod(mtlNum);
1698 if(j<0)
1699 return Color(0.f,0.f,0.f);
1700 if (subMtl[j]) return subMtl[j]->GetSpecular(mtlNum,backFace);
1701 return UseMtl()?UseMtl()->GetSpecular():Color(0,0,0);
1702 }
1703
GetXParency(int mtlNum,BOOL backFace)1704 float Multi::GetXParency(int mtlNum, BOOL backFace) {
1705 int j = FindSubMtlMod(mtlNum);
1706 if(j<0)
1707 return 0.0f;
1708 if (subMtl[j]) return subMtl[j]->GetXParency(mtlNum,backFace);
1709 return UseMtl()?UseMtl()->GetXParency():0.0f;
1710 }
1711
GetShininess(int mtlNum,BOOL backFace)1712 float Multi::GetShininess(int mtlNum, BOOL backFace) {
1713 int j = FindSubMtlMod(mtlNum);
1714 if(j<0)
1715 return 0.0f;
1716 if (subMtl[j]) return subMtl[j]->GetShininess(mtlNum,backFace);
1717 return UseMtl()?UseMtl()->GetShininess():0.0f;
1718 }
1719
GetShinStr(int mtlNum,BOOL backFace)1720 float Multi::GetShinStr(int mtlNum, BOOL backFace) {
1721 int j = FindSubMtlMod(mtlNum);
1722 if(j<0)
1723 return 0.0f;
1724 if (subMtl[j]) return subMtl[j]->GetShinStr(mtlNum,backFace);
1725 return UseMtl()?UseMtl()->GetShinStr():0.0f;
1726 }
1727
WireSize(int mtlNum,BOOL backFace)1728 float Multi::WireSize(int mtlNum, BOOL backFace) {
1729 int j = FindSubMtlMod(mtlNum);
1730 if(j<0)
1731 return 0.0f;
1732 if (subMtl[j]) return subMtl[j]->WireSize(mtlNum,backFace);
1733 return UseMtl()?UseMtl()->WireSize():0.0f;
1734 }
1735
Clone(RemapDir & remap)1736 RefTargetHandle Multi::Clone(RemapDir &remap) {
1737 Multi *mnew = new Multi(FALSE, FALSE); // mjm - 10.11.99 - don't create default subMtls
1738 *((MtlBase*)mnew) = *((MtlBase*)this); // copy superclass stuff
1739 mnew->ivalid.SetEmpty();
1740 int nsub = subMtl.Count();
1741 mnew->subMtl.SetCount(nsub);
1742 // mnew->mapOn.SetCount(nsub);
1743 // mnew->subNames.SetSize(nsub);
1744 mnew->offset = offset;
1745 for (int i = 0; i<nsub; i++)
1746 mnew->subMtl[i] = NULL;
1747 mnew->ReplaceReference(PBLOCK_REF,remap.CloneRef(pblock));
1748 mnew->pblock->SetCount(multi_mtls, nsub);
1749 mnew->pblock->SetCount(multi_ons, nsub);
1750 mnew->pblock->SetCount(multi_names, nsub);
1751 mnew->pblock->SetCount(multi_ids, nsub);
1752
1753 for (int i = 0; i<nsub; i++)
1754 {
1755 if (subMtl[i]) {
1756 mnew->ReplaceReference(i+1,remap.CloneRef(subMtl[i]));
1757 // mnew->pblock->SetValue(multi_mtls,0,mnew->subMtl[i],i);
1758 }
1759 // mnew->mapOn[i] = mapOn[i];
1760 }
1761 #if USE_HASHING
1762 // mnew->UpdateHashTable();
1763 mnew->hashTabDirty = 1; // MQM 3/5/01 - 11:44am - faster?
1764 #endif
1765 BaseClone(this, mnew, remap);
1766 return (RefTargetHandle)mnew;
1767 }
1768
1769
CreateParamDlg(HWND hwMtlEdit,IMtlParams * imp)1770 ParamDlg* Multi::CreateParamDlg(HWND hwMtlEdit, IMtlParams *imp) {
1771 MultiDlg *dm = new MultiDlg(hwMtlEdit, imp, this);
1772 dm->LoadDialog(TRUE);
1773 SetParamDlg(dm);
1774 return dm;
1775 }
1776
Update(TimeValue t,Interval & valid)1777 void Multi::Update( TimeValue t, Interval &valid )
1778 {
1779 int count; // num sub materials
1780 int id; // id of current sub mat
1781 Interval iv; // current interval
1782 int i; // loop var
1783
1784 // update all submaterials
1785 if ( !ivalid.InInterval( t ) )
1786 {
1787 //#if USE_HASHING
1788 // hashTab.Clean();
1789 //#endif
1790
1791 ivalid.SetInfinite();
1792
1793 // loop through and update all sub materials
1794 maxMtlId = -1;
1795 count = subMtl.Count();
1796 for ( i = 0; i < count; i++ )
1797 {
1798 // tell sub material to update
1799 if ( subMtl[i] )
1800 subMtl[i]->Update( t, ivalid );
1801
1802 // get the material id from the sub material
1803 pblock->GetValue( multi_ids, 0, id, iv, i );
1804 if ( id > maxMtlId )
1805 maxMtlId = id; // UPDATE - cache max id#
1806
1807 //#if USE_HASHING
1808 // hashTab.AddAssociation( id, i );
1809 //#endif
1810 }
1811 }
1812 valid &= ivalid;
1813 }
1814
Validity(TimeValue t)1815 Interval Multi::Validity(TimeValue t) {
1816 Interval valid;
1817 Update(t,valid);
1818 return ivalid;
1819 }
1820
GetSubMtlName(int mtlid,TSTR & s)1821 void Multi::GetSubMtlName(int mtlid, TSTR &s) {
1822 TCHAR *name;
1823 int j = FindSubMtl(mtlid);
1824 if (j>=0) {
1825 Interval iv;
1826 pblock->GetValue(multi_names,0,name,iv,j);
1827 s = name;
1828 }
1829 else
1830 s = _T("");
1831 }
1832
1833
1834
1835 struct sortEl{
1836 int i;
1837 Mtl *mtl;
1838 BOOL on;
1839 int mtlid;
1840 TCHAR name[100];
1841 };
1842
cmpIDs(const void * arg1,const void * arg2)1843 static int __cdecl cmpIDs( const void *arg1, const void *arg2 ) {
1844 sortEl *s1 = (sortEl *)arg1;
1845 sortEl *s2 = (sortEl *)arg2;
1846 int id1 = s1->mtlid;
1847 int id2 = s2->mtlid;
1848 return id2<id1? 1: id1<id2? -1:0;
1849 }
1850
cmpNames(const void * arg1,const void * arg2)1851 static int __cdecl cmpNames( const void *arg1, const void *arg2 ) {
1852 sortEl *s1 = (sortEl *)arg1;
1853 sortEl *s2 = (sortEl *)arg2;
1854 int id1 = s1->mtlid;
1855 int id2 = s2->mtlid;
1856 Mtl * m1 = s1->mtl;
1857 Mtl * m2 = s2->mtl;
1858 if (m1&&m2) {
1859 int res = _tcsicmp(m1->GetFullName(), m2->GetFullName());
1860 if (res == 0) goto useid;
1861 return res;
1862 }
1863 if (m1) return -1;
1864 if (m2) return 1;
1865 useid:
1866 return id2<id1? 1: id1<id2? -1:0;
1867 }
1868
cmpSlotNames(const void * arg1,const void * arg2)1869 static int __cdecl cmpSlotNames( const void *arg1, const void *arg2 ) {
1870 sortEl *s1 = (sortEl *)arg1;
1871 sortEl *s2 = (sortEl *)arg2;
1872 int id1 = s1->mtlid;
1873 int id2 = s2->mtlid;
1874 int res = _tcsicmp(s1->name, s2->name);
1875 if (res != 0)
1876 return res;
1877 return id2<id1? 1: id1<id2? -1:0;
1878 }
1879
SortMtlsByName()1880 void Multi::SortMtlsByName() {
1881 SortMtls(cmpNames);
1882 }
1883
SortMtlsByID()1884 void Multi::SortMtlsByID() {
1885 SortMtls(cmpIDs);
1886 }
1887
SortMtlsBySlotName()1888 void Multi::SortMtlsBySlotName() {
1889 SortMtls(cmpSlotNames);
1890 }
1891
AnyDupIDs()1892 BOOL Multi::AnyDupIDs() {
1893 if (paramDlg == NULL)
1894 return 0;
1895 for (int j=0; j<NSUBMTLS; j++)
1896 paramDlg->isDup[j] = FALSE;
1897 Tab<sortEl> sortlist;
1898 int n = subMtl.Count();
1899 sortlist.SetCount(n);
1900 for (int i=0; i<n; i++) {
1901 sortEl &s = sortlist[i];
1902 s.i = i;
1903 Interval iv;
1904 pblock->GetValue(multi_ids,0, s.mtlid,iv,i);
1905 }
1906 sortlist.Sort(cmpIDs);
1907 int lastid = -999;
1908 int lastIndex = -1;
1909 BOOL anyDups = FALSE;
1910 for ( int i=0; i<n; i++) {
1911 sortEl &s = sortlist[i];
1912 int id = s.mtlid;
1913 int indx = s.i;
1914 if (id==lastid) {
1915 anyDups = TRUE;
1916 paramDlg->SetIsDup(lastIndex-offset);
1917 paramDlg->SetIsDup(s.i-offset);
1918 }
1919 lastid = id;
1920 lastIndex = s.i;
1921 }
1922 return anyDups;
1923 }
1924
SortMtls(CompareFnc cmp)1925 void Multi::SortMtls(CompareFnc cmp) {
1926 Tab<sortEl> sortlist;
1927 int n = subMtl.Count();
1928 sortlist.SetCount(n);
1929 for (int i=0; i<n; i++) {
1930 sortEl s;
1931 Interval iv;
1932 pblock->GetValue(multi_ids,0, s.mtlid,iv,i);
1933 pblock->GetValue(multi_mtls, 0, s.mtl,iv,i);
1934 pblock->GetValue(multi_ons, 0, s.on,iv,i);
1935 TCHAR *name;
1936 pblock->GetValue(multi_names,0,name,iv,i);
1937 if (name)
1938 _tcscpy(s.name,name);
1939 else s.name[0] = 0;
1940
1941 sortlist[i] = s;
1942 if (subMtl[i]) subMtl[i]->SetAFlag(A_LOCK_TARGET);
1943 }
1944 sortlist.Sort(cmp);
1945 for ( int i=0; i<n; i++) {
1946 sortEl &s = sortlist[i];
1947 pblock->SetValue(multi_ids,0,s.mtlid,i);
1948 pblock->SetValue(multi_mtls,0,s.mtl,i);
1949 pblock->SetValue(multi_ons,0,s.on,i);
1950 pblock->SetValue(multi_names,0,s.name,i);
1951 subMtl[i] = s.mtl;
1952 }
1953 for ( int i=0; i<n; i++) {
1954 if (subMtl[i]) subMtl[i]->ClearAFlag(A_LOCK_TARGET);
1955 }
1956 #if USE_HASHING
1957 hashTabDirty = 1; // MQM 3/5/01 - 11:45am - faster?
1958 // UpdateHashTable();
1959 #endif
1960 NotifyChanged();
1961 }
1962
1963
1964
1965 class DelSubRestore: public RestoreObj {
1966 Multi *mtl;
1967 SingleRefMaker subm;
1968 int nsub;
1969 TSTR name;
1970 BOOL on;
1971 int id;
1972 public:
DelSubRestore()1973 DelSubRestore() { }
1974 DelSubRestore(Multi *m, int i);
~DelSubRestore()1975 ~DelSubRestore(){}
1976 void Restore(int isUndo);
1977 void Redo();
Description()1978 TSTR Description() {
1979 TCHAR buf[100];
1980 _stprintf(buf,_T("DelSubMtlRestore"));
1981 return(TSTR(buf));
1982 }
1983 };
1984
DelSubRestore(Multi * m,int i)1985 DelSubRestore::DelSubRestore(Multi *m, int i) {
1986 theHold.Suspend();
1987 nsub = i;
1988 mtl = m;
1989 subm.SetRef(m->subMtl[i]);
1990 Interval iv;
1991 mtl->pblock->GetValue(multi_ids,0,id,iv,i);
1992 mtl->pblock->GetValue(multi_ons,0,on,iv,i);
1993 TCHAR *pname;
1994 mtl->pblock->GetValue(multi_names,0,pname,iv,i);
1995 name = pname;
1996 theHold.Resume();
1997 }
1998
Restore(int isUndo)1999 void DelSubRestore::Restore(int isUndo) {
2000 if (isUndo) {
2001 Mtl *foo = NULL;
2002 if (mtl->paramDlg)
2003 mtl->paramDlg->RemovePStampHilite();
2004 mtl->subMtl.Insert(nsub, 1, &foo);
2005 Mtl *sm = (Mtl *)subm.GetRef();
2006 mtl->ReplaceReference(nsub+1, sm);
2007 mtl->pblock->Insert(multi_mtls, nsub, 1, &sm);
2008 mtl->pblock->Insert(multi_ons, nsub, 1, &on);
2009 TCHAR *pname = name.data();
2010 mtl->pblock->Insert(multi_names, nsub, 1, &pname);
2011 mtl->pblock->Insert(multi_ids, nsub, 1, &id);
2012 mtl->selected = nsub;
2013 #if USE_HASHING
2014 mtl->hashTabDirty = 1; // MQM 3/5/01 - 11:45am - faster?
2015 // mtl->UpdateHashTable();
2016 #endif
2017 mtl->NotifyChanged();
2018 }
2019 }
2020
Redo()2021 void DelSubRestore::Redo() {
2022 if (mtl->paramDlg)
2023 mtl->paramDlg->RemovePStampHilite();
2024 mtl->ReplaceReference(nsub+1, NULL);
2025 mtl->subMtl.Delete(nsub, 1);
2026 mtl->pblock->Delete(multi_mtls, nsub, 1);
2027 mtl->pblock->Delete(multi_ons, nsub, 1);
2028 mtl->pblock->Delete(multi_names, nsub, 1);
2029 mtl->pblock->Delete(multi_ids, nsub, 1);
2030 if (mtl->selected>=mtl->subMtl.Count())
2031 mtl->selected = mtl->subMtl.Count() -1;
2032 #if USE_HASHING
2033 mtl->hashTabDirty = 1; // MQM 3/5/01 - 11:45am - faster?
2034 // mtl->UpdateHashTable();
2035 #endif
2036 mtl->NotifyChanged();
2037 }
2038
2039 class AddMtlsRestore : public RestoreObj {
2040 public:
2041 Multi *m;
2042 int num;
2043 SingleRefMaker *subm;
2044 TSTR *_name;
2045 int *_id;
2046
2047
AddMtlsRestore(Multi * mul,int n)2048 AddMtlsRestore(Multi *mul, int n) {
2049 m = mul;
2050 num = n;
2051
2052 subm = new SingleRefMaker[n];
2053 _name = new TSTR[n];
2054 _id = new int[num];
2055 }
2056
~AddMtlsRestore()2057 ~AddMtlsRestore() {
2058 delete [] subm;
2059 delete []_name;
2060 delete [] _id;
2061 }
2062
2063 //Used to store all the missing data for all the materials being added
2064 //At creation time, only n and num can be set.
SetMissingFields(Multi * mul,int n)2065 void SetMissingFields(Multi *mul, int n)
2066 {
2067 theHold.Suspend();
2068
2069 for(int i=0;i<num;i++)
2070 {
2071 subm[i].SetRef(mul->subMtl[n+i]);
2072 Interval iv;
2073 mul->pblock->GetValue(multi_ids,0,_id[i],iv,n+i);
2074 TCHAR *pname;
2075 mul->pblock->GetValue(multi_names,0,pname,iv,n+i);
2076 _name[i] = pname;
2077 }
2078 theHold.Resume();
2079 }
2080
Restore(int isUndo)2081 void Restore(int isUndo) {
2082 for (int i=0; i<num; i++) {
2083 m->selected = m->subMtl.Count()-1;
2084 m->DeleteSelMtl();
2085 }
2086 }
Redo()2087 void Redo() {
2088 for (int i=0; i<num; i++)
2089 {
2090 m->AddMtl(subm[i].GetRef(),_id[i],_name[i]);
2091 }
2092 m->offset = m->subMtl.Count()-NSUBMTLS;
2093 m->ClampOffset();
2094 }
Description()2095 TSTR Description() {
2096 TCHAR buf[100];
2097 _stprintf(buf,_T("AddMtlsRestore"));
2098 return(TSTR(buf));
2099 }
2100 };
2101
AddMtl(ReferenceTarget * rt,int id,TCHAR * name)2102 void Multi::AddMtl(ReferenceTarget *rt, int id, TCHAR *name) {
2103 SuspendSetKeyMode();
2104
2105 AddMtlsRestore *undoData=NULL;
2106
2107 if (theHold.Holding())
2108 theHold.Put( undoData = new AddMtlsRestore(this,1));
2109 theHold.Suspend();
2110 int n = subMtl.Count()+1;
2111 int maxid = MaxSubMtlID();
2112 subMtl.SetCount(n);
2113
2114 subMtl[n-1] = NULL; // orb 08-24-2001 Fixing Defects 307753 & 306999
2115
2116 #if USE_HASHING
2117 if(rt!=NULL)
2118 maxMtlId++; // 5/2/01 1:26pm --MQM-- moved from #if block below to fix callback/out-of-sync problems
2119 #endif
2120 macroRec->Disable(); // DS 10/13/00
2121 pblock->SetCount(multi_ons, n);
2122 pblock->SetCount(multi_names, n);
2123 pblock->SetCount(multi_ids, n);
2124 macroRec->Enable(); // DS 10/13/00
2125 pblock->SetCount(multi_mtls, n);
2126 n--;
2127
2128 pblock->SetValue(multi_ons,0,TRUE,n);
2129
2130 if(rt)
2131 {
2132 pblock->SetValue(multi_ids,0,id,n);
2133 pblock->SetValue(multi_names,0,name,n);
2134 ReplaceReference(n+1,rt);
2135 }
2136 else
2137 {
2138 pblock->SetValue(multi_ids,0,maxid+1,n);
2139 pblock->SetValue(multi_names,0,_T(""),n); // LAM 11/21/00
2140 HoldSuspend hs; // LAM - 6/12/04 - defect 571821
2141 ReferenceTarget* mtl = (ReferenceTarget*)GetStdMtl2Desc()->Create();
2142 hs.Resume();
2143 ReplaceReference(n+1,mtl);
2144 GetCOREInterface()->AssignNewName(subMtl[n]);
2145 }
2146
2147 if(undoData)
2148 undoData->SetMissingFields(this,n);
2149
2150 NotifyChanged();
2151 theHold.Resume();
2152 #if USE_HASHING
2153 if ( hashTabDirty )
2154 UpdateHashTable();
2155 else
2156 hashTab.AddAssociation( maxMtlId, n );
2157 #endif
2158 ResumeSetKeyMode();
2159 }
2160
SetNumSubMtls(int num)2161 void Multi::SetNumSubMtls(int num) {
2162 int n = num-subMtl.Count();
2163 if (n>0) {
2164
2165 int startOffset = subMtl.Count();
2166
2167 AddMtlsRestore *undoData=NULL;
2168 if (theHold.Holding())
2169 theHold.Put(undoData = new AddMtlsRestore(this,n));
2170
2171 theHold.Suspend();
2172 for (int i=0; i<n; i++)
2173 AddMtl();
2174
2175 if(undoData)
2176 undoData->SetMissingFields(this,startOffset);
2177
2178 theHold.Resume();
2179 }
2180 else if (n<=0) {
2181 n = -n;
2182 for (int i=0; i<n; i++) {
2183 if(subMtl.Count()==1) //az: #502733 fix - don't let delete the last material
2184 break;
2185 selected = subMtl.Count()-1;
2186 DeleteSelMtl();
2187 }
2188 selected = subMtl.Count()-1;
2189 }
2190 offset = subMtl.Count()-NSUBMTLS;
2191 ClampOffset();
2192 #if USE_HASHING
2193 hashTabDirty = 1; // MQM 3/5/01 - 11:45am - faster?
2194 // UpdateHashTable(); // clean up when removing mats
2195 #endif
2196 }
2197
DeleteSelMtl()2198 void Multi::DeleteSelMtl() {
2199 if (selected>=0&&selected<subMtl.Count()) {
2200 if (theHold.Holding())
2201 theHold.Put(new DelSubRestore(this, selected));
2202 theHold.Suspend();
2203 ReplaceReference(selected+1, NULL);
2204 subMtl.Delete(selected, 1);
2205 macroRec->Disable(); // DS 10/13/00
2206 pblock->Delete(multi_ons, selected, 1);
2207 pblock->Delete(multi_names, selected, 1);
2208 pblock->Delete(multi_ids, selected, 1);
2209 macroRec->Enable(); // DS 10/13/00
2210 pblock->Delete(multi_mtls, selected, 1);
2211 if (selected>=subMtl.Count())
2212 selected = subMtl.Count() -1;
2213 #if USE_HASHING
2214 hashTabDirty = 1; // MQM 3/5/01 - 11:46am - faster?
2215 // UpdateHashTable();
2216 #endif
2217 ClampOffset();
2218 NotifyChanged();
2219 theHold.Resume();
2220 }
2221 }
2222
2223
2224 //need to remap references since we added a paramblock
RemapRefOnLoad(int iref)2225 int Multi::RemapRefOnLoad(int iref)
2226 {
2227 if (Param1) iref += 1;
2228 return iref;
2229 }
2230
GetReference(int i)2231 RefTargetHandle Multi::GetReference(int i) {
2232 if (loadingOld) {
2233 // russom - September 7, 2005 - 653392
2234 // Check index against size of subMtl
2235 if (i==0)
2236 return NULL;
2237 else if ((i-1) < subMtl.Count() )
2238 return subMtl[i-1];
2239 else
2240 return NULL;
2241 }
2242 else
2243 {
2244 // russom - September 7, 2005 - 653392
2245 // Check index against size of subMtl
2246 if (i==PBLOCK_REF)
2247 return pblock;
2248 else if ((i-1) < subMtl.Count() )
2249 return subMtl[i-1];
2250 else
2251 return NULL;
2252 }
2253 }
2254
SetReference(int i,RefTargetHandle rtarg)2255 void Multi::SetReference(int i, RefTargetHandle rtarg) {
2256 if ((i-1)>=subMtl.Count()) {
2257 int n = subMtl.Count();
2258 SetNumSubMtls(i+1);
2259 // subMtl.SetCount(i+1);
2260 // for (int j=n; j<=i; j++) // mjm - 10,11.99
2261 // subMtl[j] = NULL; // mjm - 10,11.99 - default subMtl created in SetNumSubMtls()
2262 }
2263 if (loadingOld) {
2264 if (i==0|| (rtarg&&!IsMtl(rtarg)))
2265 { } //pblock = (IParamBlock *)rtarg;
2266 else
2267 subMtl[i-1] = (Mtl *)rtarg;
2268 }
2269 else
2270 {
2271 if (i==PBLOCK_REF) pblock = (IParamBlock2 *)rtarg;
2272 else subMtl[i-1] = (Mtl *)rtarg;
2273 }
2274 }
2275
2276
2277
2278 class SetSubRestore: public RestoreObj {
2279 Multi *multi;
2280 Mtl *mtl;
2281 SingleRefMaker subold;
2282 SingleRefMaker subnew;
2283 int nsub;
2284 int mtlid;
2285 TSTR oldnm;
2286 TSTR newnm;
2287 BOOL doname;
2288 public:
SetSubRestore()2289 SetSubRestore() { }
SetSubRestore(Multi * m,int i,Mtl * mt,int mid,TCHAR * newName=NULL)2290 SetSubRestore(Multi *m, int i, Mtl *mt, int mid, TCHAR *newName=NULL) {
2291 multi = m;
2292 nsub = i;
2293 mtl = mt;
2294 mtlid = mid;
2295 doname = FALSE;
2296 if (newName) {
2297 doname = TRUE;
2298 newnm = newName;
2299 if (nsub>=0) {
2300 TCHAR *pname;
2301 Interval niv;
2302 multi->pblock->GetValue(multi_names,0,pname,niv,nsub);
2303 oldnm = pname;
2304 }
2305 }
2306 theHold.Suspend();
2307 if (i>=0)
2308 subold.SetRef(multi->subMtl[i]);
2309 subnew.SetRef(mt);
2310 theHold.Resume();
2311 }
~SetSubRestore()2312 ~SetSubRestore(){}
Restore(int isUndo)2313 void Restore(int isUndo) {
2314 if (nsub>=0) {
2315 Mtl *sm = (Mtl *)subold.GetRef();
2316 multi->ReplaceReference(nsub+1, sm);
2317 if (doname) {
2318 TCHAR *pname = oldnm.data();
2319 multi->pblock->SetValue(multi_names,0,pname,nsub);
2320 }
2321 }
2322 else {
2323 int n = multi->subMtl.Count();
2324 multi->SetNumSubMtls(n-1);
2325 }
2326 if (multi->paramDlg)
2327 multi->paramDlg->UpdateSubMtlNames();
2328 }
Redo()2329 void Redo() {
2330 Mtl *sm = (Mtl *)subnew.GetRef();
2331 multi->SetSubMtlAndName(mtlid,sm,newnm);
2332 if (doname)
2333 multi->SetSubMtlAndName(mtlid,sm,newnm);
2334 else
2335 multi->SetSubMtl(mtlid,sm);
2336 }
Description()2337 TSTR Description() {
2338 TCHAR buf[100];
2339 _stprintf(buf,_T("SetSubMtlRestore"));
2340 return(TSTR(buf));
2341 }
2342 };
2343
SetSubMtlAndName(int mtlid,Mtl * m,TSTR & nm)2344 void Multi::SetSubMtlAndName(int mtlid, Mtl *m, TSTR &nm) {
2345 int j = FindSubMtl(mtlid);
2346 if (theHold.Holding())
2347 theHold.Put(new SetSubRestore(this,j,m,mtlid,nm.data()));
2348 theHold.Suspend();
2349 if (j>=0) {
2350 ReplaceReference(j+1,m);
2351 TCHAR *pname = nm.data();
2352 pblock->SetValue(multi_names,0,pname,j);
2353 }
2354 else {
2355 int n = subMtl.Count();
2356 SetNumSubMtls(n+1);
2357 ReplaceReference(n+1,m);
2358 // set the n-th mtl to have mtlid for its mtl ID.
2359 pblock->SetValue(multi_ids,0,mtlid,n);
2360 pblock->SetValue(multi_names,0,nm.data(),n);
2361 #if USE_HASHING
2362 if ( mtlid > maxMtlId ) // 5/22/01 3:31pm --MQM-- bug #252504, NumSubMtls() getting called but maxMtlId not updated
2363 maxMtlId = mtlid;
2364 hashTabDirty = 1; // MQM 3/5/01 - 11:47am - faster?
2365 #endif
2366 }
2367 if (paramDlg)
2368 paramDlg->UpdateSubMtlNames();
2369 #if USE_HASHING
2370 // UpdateHashTable();
2371 #endif
2372 theHold.Resume();
2373 }
2374
RemoveMtl(int mtlid)2375 void Multi::RemoveMtl(int mtlid)
2376 {
2377 int found = FindSubMtl(mtlid);
2378 if (found >= 0 && (subMtl.Count()>1)) {
2379 selected = found;
2380 DeleteSelMtl();
2381 selected = subMtl.Count()-1;
2382 if(paramDlg){
2383 paramDlg->RemovePStampHilite();
2384 paramDlg->Invalidate();
2385 paramDlg->UpdateMtlDisplay();
2386 }
2387 }
2388 }
2389
SetSubMtl(int i,Mtl * m)2390 void Multi::SetSubMtl(int i, Mtl *m) {
2391 int j = FindSubMtl(i);
2392 if (theHold.Holding())
2393 theHold.Put(new SetSubRestore(this,j,m,i));
2394 theHold.Suspend();
2395 if (j>=0) {
2396 ReplaceReference(j+1,m);
2397 }
2398 else {
2399 int n = subMtl.Count();
2400 SetNumSubMtls(n+1);
2401 ReplaceReference(n+1,m);
2402 // set the n-th mtl to have i for its mtlID.
2403 pblock->SetValue(multi_ids,0,i,n);
2404 #if USE_HASHING
2405 if ( i > maxMtlId ) // 5/22/01 3:31pm --MQM-- bug #252504, NumSubMtls() getting called but maxMtlId not updated
2406 maxMtlId = i;
2407 hashTabDirty = 1; // MQM 3/5/01 - 11:47am - faster?
2408 #endif
2409 }
2410 if (paramDlg)
2411 paramDlg->UpdateSubMtlNames();
2412 #if USE_HASHING
2413 // UpdateHashTable();
2414 #endif
2415 theHold.Resume();
2416 }
2417
GetSubMtlSlotName(int i)2418 TSTR Multi::GetSubMtlSlotName(int i) {
2419 TSTR s;
2420 TCHAR *name;
2421 Interval iv;
2422
2423 int j = FindSubMtl(i);
2424 if (j>=0) {
2425 pblock->GetValue(multi_names,0,name,iv,j);
2426 if (name)
2427 s.printf("(%d) %s",i+1,name);
2428 else
2429 s.printf("(%d)",i+1);
2430 }
2431
2432 else
2433 s.printf("(%d)",i+1);
2434 return s;
2435 }
2436
SubAnim(int i)2437 Animatable* Multi::SubAnim(int i) {
2438 // if (i==PBLOCK_REF) return pblock;
2439 // else return subMtl[i-1];
2440 return subMtl[i];
2441 }
2442
SubAnimName(int i)2443 TSTR Multi::SubAnimName(int i) {
2444 // return GetSubMtlTVName(i);
2445 TCHAR *name;
2446 Interval iv;
2447 int id;
2448 pblock->GetValue(multi_names,0,name,iv,i);
2449 pblock->GetValue(multi_ids,0,id,iv,i);
2450 TSTR s;
2451 if (name)
2452 s.printf("(%d) %s",id+1,name);
2453 else
2454 s.printf("(%d)",id+1);
2455 TSTR nm;
2456 if (subMtl[i])
2457 nm.printf(_T("%s: %s"), s.data(), subMtl[i]->GetFullName().data() );
2458 else
2459 nm.printf(_T("%s: None"), s.data());
2460 return nm;
2461 }
2462
NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget,PartID & partID,RefMessage message)2463 RefResult Multi::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget,
2464 PartID& partID, RefMessage message ) {
2465 switch (message) {
2466 case REFMSG_CHANGE:
2467 if (ignoreNotify)
2468 return REF_SUCCEED; // succeed????
2469 // return REF_STOP;
2470 ivalid.SetEmpty();
2471 if (hTarget == pblock){
2472 ParamID changing_param = pblock->LastNotifyParamID();
2473 multi_param_blk.InvalidateUI(changing_param);
2474 if( (changing_param == multi_ons )
2475 ||(changing_param == multi_ids ))
2476 mReshadeRQ = RR_NeedReshade;
2477
2478 // 6/1/01 10:58am --MQM--
2479 // maxscript or other has changed a sub-mtl id
2480 if ( changing_param == multi_ids )
2481 {
2482 // hash table is now dirty, since the
2483 // max mtl id may be different now
2484 hashTabDirty = 1;
2485 }
2486
2487 // > 10/29/02 - 12:21pm --MQM--
2488 // if the dialog is open, update it to
2489 // reflect the changes. this used to be in
2490 // the "if ( changing_param == multi_ids )" above,
2491 // but we need to update for names, etc.
2492 if ( paramDlg != NULL )
2493 paramDlg->Invalidate();
2494 }
2495
2496 if (IsMtl(hTarget)) {
2497 int n = subMtl.Count();
2498 for (int i=0; i<n; i++) {
2499 if (subMtl[i] && ((Mtl *)hTarget==subMtl[i])) {
2500 if( paramDlg!=NULL ) {
2501 paramDlg->UpdatePStamp(i);
2502 }
2503
2504 subMtl[i]->DiscardPStamp(PS_TINY);
2505 IReshading* r = static_cast<IReshading*>(subMtl[i]->GetInterface(IID_IReshading));
2506 mReshadeRQ = r == NULL ? RR_None : r->GetReshadeRequirements();
2507 break;
2508 }
2509 }
2510 }
2511
2512 // following by JBW 45/21/99 to allow scripter-setting of submtl counts (any count change updates others)
2513 if ( pblock )
2514 {
2515 int newCount = -1;
2516
2517 if ( pblock->LastNotifyParamID() == multi_ons &&
2518 pblock->Count( multi_ons ) != subMtl.Count() )
2519 {
2520 newCount = pblock->Count( multi_ons );
2521 }
2522 else if ( pblock->LastNotifyParamID() == multi_names &&
2523 pblock->Count( multi_names ) != subMtl.Count() )
2524 {
2525 newCount = pblock->Count( multi_names );
2526 }
2527 else if ( pblock->LastNotifyParamID() == multi_ids &&
2528 pblock->Count( multi_ids ) != subMtl.Count() )
2529 {
2530 newCount=pblock->Count( multi_ids );
2531 }
2532 else if ( pblock->LastNotifyParamID() == multi_mtls &&
2533 pblock->Count( multi_mtls ) != subMtl.Count() )
2534 {
2535 newCount=pblock->Count( multi_mtls );
2536 }
2537
2538 // count has changed
2539 if ( newCount != -1 )
2540 {
2541 // > 6/12/02 - 1:51pm --MQM--
2542 // don't allow 0 count...maxscript was allowing this, but we don't want it anymore
2543 if ( newCount == 0 )
2544 newCount = 1;
2545
2546 ignoreNotify = TRUE;
2547 pblock->SetCount( pblock->LastNotifyParamID(), subMtl.Count() ); // to make DelSubRestore happy
2548 SetNumSubMtls( newCount );
2549 mReshadeRQ = RR_NeedReshade;
2550 if ( paramDlg != NULL )
2551 {
2552 paramDlg->RemovePStampHilite();
2553 paramDlg->Invalidate();
2554 paramDlg->UpdateMtlDisplay();
2555 }
2556 ignoreNotify = FALSE;
2557 }
2558 }
2559
2560
2561 if (hTarget != NULL) {
2562 switch (hTarget->SuperClassID()) {
2563 case MATERIAL_CLASS_ID: {
2564 IReshading* r = static_cast<IReshading*>(hTarget->GetInterface(IID_IReshading));
2565 mReshadeRQ = r == NULL ? RR_None : r->GetReshadeRequirements();
2566 } break;
2567 }
2568 }
2569 break;
2570
2571 case REFMSG_SUBANIM_STRUCTURE_CHANGED:
2572 if( hTarget != this )
2573 return REF_SUCCEED;
2574
2575 mReshadeRQ = RR_NeedPreshade;
2576 NotifyChanged();
2577 break;
2578
2579 // case REFMSG_SUSPEND_STRUCTURE_CHANGED:
2580 // ignoreNotify = TRUE;
2581 // break;
2582 //
2583 // case REFMSG_RESUME_STRUCTURE_CHANGED:
2584 // ignoreNotify = FALSE;
2585 // break;
2586
2587 case REFMSG_GET_PARAM_DIM:
2588 {
2589 GetParamDim *gpd = (GetParamDim*)partID;
2590 switch ( gpd->index ) // 4/24/01 3:22pm --MQM-- fix for maxscript #'s to match
2591 {
2592 case multi_mtls:
2593 case multi_ons:
2594 case multi_names:
2595 gpd->dim = defaultDim;
2596 break;
2597
2598 case multi_ids:
2599 gpd->dim = &theMultiIDDim;
2600 break;
2601 }
2602 return REF_STOP;
2603 }
2604
2605 case REFMSG_GET_PARAM_NAME: {
2606 GetParamName *gpn = (GetParamName*)partID;
2607 return REF_STOP;
2608 }
2609 }
2610 return(REF_SUCCEED);
2611 }
2612
2613
Clamp(Color & c)2614 inline void Clamp(Color &c) {
2615 if (c.r > 1.0f) c.r = 1.0f;
2616 if (c.g > 1.0f) c.g = 1.0f;
2617 if (c.b > 1.0f) c.b = 1.0f;
2618 }
2619
2620 static Color black(0,0,0);
2621
GetPixelSampler(int mtlNum,BOOL backFace)2622 Sampler* Multi::GetPixelSampler(int mtlNum, BOOL backFace )
2623 {
2624 int j = FindSubMtlMod( mtlNum );
2625 Mtl* subM = (j>=0)? subMtl[j] : NULL;
2626 if ( subM )
2627 return subM->GetPixelSampler( mtlNum, backFace );
2628 return NULL;
2629 }
2630
PreShade(ShadeContext & sc,IReshadeFragment * pFrag)2631 void Multi::PreShade(ShadeContext& sc, IReshadeFragment* pFrag)
2632 {
2633 IReshading* pReshading;
2634 int mtlnum = sc.mtlNum, ct = subMtl.Count();
2635 // NOTE: preshade each submaterial to allow user to switch among them during reshading
2636 if (ct)
2637 {
2638 int j = FindSubMtlMod(mtlnum);
2639 Mtl* subm = (j>=0)?subMtl[j]:NULL;
2640 if ( subm )
2641 {
2642 // store sub-material number and preshade it
2643 pFrag->AddIntChannel(mtlnum);
2644 pReshading = (IReshading*)(subm->GetInterface(IID_IReshading));
2645 if( pReshading )
2646 pReshading->PreShade(sc, pFrag);
2647
2648 }
2649 else
2650 {
2651 // -1 indicates no submaterial used
2652 pFrag->AddIntChannel(-1);
2653 }
2654 }
2655 else
2656 {
2657 // -1 indicates no submaterial used
2658 pFrag->AddIntChannel(-1);
2659 }
2660 }
2661
PostShade(ShadeContext & sc,IReshadeFragment * pFrag,int & nextTexIndex,IllumParams *)2662 void Multi::PostShade(ShadeContext& sc, IReshadeFragment* pFrag, int& nextTexIndex, IllumParams*)
2663 {
2664 int mtlnum = pFrag->GetIntChannel(nextTexIndex++);
2665 if (mtlnum == -1)
2666 {
2667 // no submaterial was used
2668 sc.out.c.Black();
2669 sc.out.t.Black();
2670 return;
2671 }
2672
2673 // submaterial used, let it postshade
2674 int j = FindSubMtlMod(mtlnum);
2675 Mtl *subm = NULL;
2676
2677 IReshading* pReshading;
2678 if (j>=0) {
2679 subm = subMtl[j];
2680 if (subm) {
2681 // always shade to skip
2682 pReshading = (IReshading*)(subm->GetInterface(IID_IReshading));
2683 if( pReshading )
2684 pReshading->PostShade(sc, pFrag, nextTexIndex);
2685
2686 int on;
2687 // then see if it's on
2688 pblock->GetValue(multi_ons,0,on,FOREVER,j);
2689 if (!on)
2690 subm = NULL;
2691 }// if subm
2692 } // j >= 0
2693
2694 // black for no or off material
2695 if (!subm){
2696 sc.out.c.Black();
2697 sc.out.t.Black();
2698 }
2699 }
2700
2701
2702
2703 // if this function changes, please also check SupportsReShading, PreShade and PostShade
2704 // end - ke/mjm - 03.16.00 - merge reshading code
2705 // [attilas|29.5.2000] if this function changes, please also check EvalColorStdChannel
Shade(ShadeContext & sc)2706 void Multi::Shade(ShadeContext& sc) {
2707 if (gbufID) sc.SetGBufferID(gbufID);
2708 int mtlnum = sc.mtlNum, ct = subMtl.Count();
2709 if (ct)
2710 {
2711
2712 // if (mtlnum < 0) mtlnum = 0;
2713 // if (mtlnum >= ct) mtlnum = mtlnum % ct;
2714 // Mtl* subm = subMtl[mtlnum];
2715
2716 int j = FindSubMtlMod(mtlnum);
2717 if (j<0)
2718 return;
2719 Mtl* subm = subMtl[j];
2720 int on;
2721 Interval iv;
2722 pblock->GetValue(multi_ons,0,on,iv,j);
2723 if (subm&&on)
2724 subm->Shade(sc); //no handling for render elements needed
2725 }
2726 }
2727
EvalDisplacement(ShadeContext & sc)2728 float Multi::EvalDisplacement( ShadeContext& sc )
2729 {
2730 if ( subMtl.Count() )
2731 {
2732 // find the submaterial
2733 int j = FindSubMtlMod( sc.mtlNum );
2734 if ( j < 0 ) // bail out now if material doesn't exist
2735 return 0.0f;
2736 Mtl* subm = subMtl[j];
2737
2738 int on;
2739 Interval iv;
2740 pblock->GetValue( multi_ons, 0, on, iv, j );
2741 if ( subm&&on )
2742 return subm->EvalDisplacement( sc );
2743 }
2744
2745 return 0.0f;
2746 }
2747
DisplacementValidity(TimeValue t)2748 Interval Multi::DisplacementValidity(TimeValue t){
2749 int ct = subMtl.Count();
2750 Interval iv;
2751 iv.SetInfinite();
2752 for (int i=0; i<ct; i++) {
2753 Mtl* subm = subMtl[i];
2754 int on;
2755 Interval iv;
2756 pblock->GetValue(multi_ons,0,on,iv,i);
2757 if (subm&&on)
2758 iv &= subm->DisplacementValidity(t);
2759 }
2760 return iv;
2761 }
2762
2763 #define MTL_HDR_CHUNK 0x4000
2764 #define MULTI_NUM_OLD 0x4001
2765 #define MULTI_NUM 0x4002
2766 #define MULTI_NAMES 0x4010
2767 #define MAPOFF_CHUNK 0x1000
2768 #define PARAM2_CHUNK 0x4003
2769 #define PARAM2_NEW_CHUNK 0x4005 // Started saving this 6/19/00 to indicate the new array structure
2770
Save(ISave * isave)2771 IOResult Multi::Save(ISave *isave) {
2772 IOResult res;
2773 ULONG nb;
2774 isave->BeginChunk(MTL_HDR_CHUNK);
2775 res = MtlBase::Save(isave);
2776 if (res!=IO_OK) return res;
2777 isave->EndChunk();
2778
2779 isave->BeginChunk(PARAM2_NEW_CHUNK);
2780 isave->EndChunk();
2781
2782 //int numSubs = NSUBMTLS;
2783 int numSubs = subMtl.Count();
2784 isave->BeginChunk(MULTI_NUM);
2785 isave->Write(&numSubs,sizeof(numSubs),&nb);
2786 isave->EndChunk();
2787
2788
2789 // isave->BeginChunk(MULTI_NAMES);
2790 // subNames.Save(isave);
2791 // isave->EndChunk();
2792
2793 /*
2794 for (int i=0; i<subMtl.Count(); i++) {
2795 if (mapOn[i]==0) {
2796 isave->BeginChunk(MAPOFF_CHUNK+i);
2797 isave->EndChunk();
2798 }
2799 }
2800 */
2801
2802 return IO_OK;
2803 }
2804
2805
2806 //2-18-96
2807 class MultiPostLoad : public PostLoadCallback {
2808 public:
2809 Multi *m;
MultiPostLoad(Multi * b)2810 MultiPostLoad(Multi *b) {m=b;}
proc(ILoad * iload)2811 void proc(ILoad *iload) {
2812 m->loadingOld = FALSE;
2813 delete this;
2814 }
2815 };
2816
2817 //watje
2818 class Multi2PostLoadCallback:public PostLoadCallback
2819 {
2820 public:
2821 Multi *s;
2822 Tab<BOOL> ons;
2823 // NameTab subNames;
2824
2825 int Param1,oldArray;
Multi2PostLoadCallback(Multi * r,BOOL b,Tab<BOOL> bl,BOOL oldA)2826 Multi2PostLoadCallback(Multi *r, BOOL b, Tab<BOOL> bl, BOOL oldA/*, NameTab sNames*/) {s=r;Param1 = b;ons = bl; oldArray = oldA; /*subNames = sNames;*/}
2827
2828 // 420314 : CR
2829 // Need to make the priority higher. The tables need to be fixed up as soon as posible.
2830 // If Update() gets called before the PLCB has run, this will cause crashes
2831 // I picked the highest number. Since most object PLCB have 5, I think 4 could have done the same job
2832 // just wanted to be safe.
Priority()2833 int Priority() { return 1; }
2834 void proc(ILoad *iload);
2835 };
2836
proc(ILoad * iload)2837 void Multi2PostLoadCallback::proc(ILoad *iload)
2838 {
2839 if (Param1)
2840 {
2841 s->pblock->SetCount(multi_ons,ons.Count());
2842 s->pblock->SetCount(multi_names,ons.Count());
2843 s->pblock->SetCount(multi_mtls,ons.Count());
2844 s->pblock->SetCount(multi_ids,ons.Count());
2845 for (int i=0; i<s->subMtl.Count(); i++) {
2846 s->pblock->SetValue(multi_ons,0,ons[i],i);
2847 if (s->subNames[i])
2848 s->pblock->SetValue(multi_names,0,s->subNames[i],i);
2849 s->pblock->SetValue(multi_ids,0,i,i);
2850 }
2851 }
2852 else
2853 {
2854 if (s->pblock->Count(multi_mtls) != s->subMtl.Count())
2855 {
2856 s->pblock->SetCount(multi_mtls,s->subMtl.Count());
2857 s->pblock->SetCount(multi_names,s->subMtl.Count());
2858 s->pblock->SetCount(multi_ons,s->subMtl.Count());
2859 }
2860 if (oldArray) {
2861 s->pblock->SetCount(multi_ids,s->subMtl.Count());
2862 for (int i=0; i<s->pblock->Count(multi_mtls); i++) {
2863 s->pblock->SetValue(multi_ids,0,i,i);
2864 }
2865 }
2866 }
2867
2868 #if USE_HASHING
2869 s->hashTabDirty = 1; // MQM 3/5/01 - 11:47am - faster?
2870 // s->UpdateHashTable();
2871 #endif
2872
2873 delete this;
2874 }
2875
Load(ILoad * iload)2876 IOResult Multi::Load(ILoad *iload) {
2877 ULONG nb;
2878 IOResult res;
2879 Param1 = TRUE;
2880 BOOL oldArray = TRUE;
2881
2882 Tab<BOOL>mapOn;
2883 // NameTab subNames;
2884
2885
2886 while (IO_OK==(res=iload->OpenChunk())) {
2887 int id = iload->CurChunkID();
2888
2889 if (id>=MAPOFF_CHUNK&&id<=MAPOFF_CHUNK+0x1000) {
2890 mapOn[id-MAPOFF_CHUNK] = FALSE;
2891 }
2892 else
2893
2894 switch(id) {
2895 case MTL_HDR_CHUNK:
2896 res = MtlBase::Load(iload);
2897 break;
2898 case MULTI_NUM_OLD:
2899 iload->SetObsolete();
2900 iload->RegisterPostLoadCallback(new MultiPostLoad(this));
2901 loadingOld = TRUE;
2902 case MULTI_NUM: {
2903 int numSubs;
2904 iload->Read(&numSubs,sizeof(numSubs),&nb);
2905 subMtl.SetCount(numSubs);
2906 mapOn.SetCount(numSubs);
2907 subNames.SetSize(numSubs);
2908
2909 for (int i=0; i<numSubs; i++) {
2910 subMtl[i] = NULL;
2911 mapOn[i] = TRUE;
2912 }
2913 }
2914 break;
2915 case MULTI_NAMES:
2916 res = subNames.Load(iload);
2917 subNames.SetSize(subMtl.Count());
2918 break;
2919 case PARAM2_NEW_CHUNK:
2920 oldArray = FALSE;
2921 // fall thru...
2922 case PARAM2_CHUNK:
2923 Param1 = FALSE;
2924 break;
2925 }
2926 iload->CloseChunk();
2927 if (res!=IO_OK)
2928 return res;
2929 }
2930
2931 Multi2PostLoadCallback* multiplcb = new Multi2PostLoadCallback(this,Param1,mapOn,oldArray);
2932 iload->RegisterPostLoadCallback(multiplcb);
2933 return IO_OK;
2934 }
2935
2936 //������������������������������������������������������������������������
2937 // Returns true if the submaterial specified in the shade context is constant
2938
IsOutputConst(ShadeContext & sc,int stdID)2939 bool Multi::IsOutputConst
2940 (
2941 ShadeContext& sc, // describes context of evaluation
2942 int stdID // must be ID_AM, ect
2943 )
2944 {
2945 int mtlnum = sc.mtlNum, ct = subMtl.Count();
2946 if (ct)
2947 {
2948 // if (mtlnum < 0)
2949 // mtlnum = 0;
2950 // if (mtlnum >= ct)
2951 // mtlnum = mtlnum % ct;
2952 // Mtl* subm = subMtl[mtlnum];
2953
2954 int j = FindSubMtlMod(mtlnum);
2955 if (j >= 0) {
2956 Mtl* subm = subMtl[j];
2957
2958 int on;
2959 Interval iv;
2960 pblock->GetValue(multi_ons,0,on,iv,j);
2961 if ( subm && on )
2962 return subm->IsOutputConst( sc, stdID );
2963 }
2964 }
2965 return true;
2966 }
2967
2968 //������������������������������������������������������������������������
2969 // Evaluates the material on a single texmap channel.
2970 // For a mono channel, the value is copied in all 3 components of the
2971 // output color.
2972 //
EvalColorStdChannel(ShadeContext & sc,int stdID,Color & outClr)2973 bool Multi::EvalColorStdChannel
2974 (
2975 ShadeContext& sc, // describes context of evaluation
2976 int stdID, // must be ID_AM, ect
2977 Color& outClr // output var
2978 )
2979 {
2980 int mtlnum = sc.mtlNum, ct = subMtl.Count();
2981 if (ct)
2982 {
2983 // if (mtlnum < 0)
2984 // mtlnum = 0;
2985 // if (mtlnum >= ct)
2986 // mtlnum = mtlnum % ct;
2987 // Mtl* subm = subMtl[mtlnum];
2988
2989 int j = FindSubMtlMod(mtlnum);
2990 if (j >= 0) {
2991 Mtl* subm = subMtl[j];
2992
2993 int on;
2994 Interval iv;
2995 pblock->GetValue(multi_ons,0,on,iv,j);
2996 if ( subm && on )
2997 return subm->EvalColorStdChannel( sc, stdID, outClr );
2998 }
2999 }
3000 return false;
3001 }
3002
3003 //������������������������������������������������������������������������
3004 // Evaluates the material on a single texmap channel.
3005 //
EvalMonoStdChannel(ShadeContext & sc,int stdID,float & outVal)3006 bool Multi::EvalMonoStdChannel
3007 (
3008 ShadeContext& sc, // describes context of evaluation
3009 int stdID, // must be ID_AM, ect
3010 float& outVal // output var
3011 )
3012 {
3013 int mtlnum = sc.mtlNum, ct = subMtl.Count();
3014 if (ct)
3015 {
3016 // if (mtlnum < 0)
3017 // mtlnum = 0;
3018 // if (mtlnum >= ct)
3019 // mtlnum = mtlnum % ct;
3020 // Mtl* subm = subMtl[mtlnum];
3021
3022 int j = FindSubMtlMod(mtlnum);
3023 Mtl* subm = j>=0?subMtl[j]:NULL;
3024
3025 int on;
3026 Interval iv;
3027 pblock->GetValue(multi_ons,0,on,iv,j);
3028 if ( subm && on )
3029 return subm->EvalMonoStdChannel( sc, stdID, outVal );
3030 }
3031 return false;
3032 }
3033
3034
3035
3036
3037
3038 /*
3039
3040 class SetNumMtlsRestore : public RestoreObj {
3041 public:
3042 Multi *multi;
3043 Tab<Mtl*> undo, redo;
3044 // Tab<BOOL> undoMO, redoMO;
3045 SetNumMtlsRestore(Multi *m) {
3046 multi = m;
3047 undo = multi->subMtl;
3048 // undoMO = multi->mapOn;
3049 }
3050
3051 void Restore(int isUndo) {
3052 if (isUndo) {
3053 redo = multi->subMtl;
3054 // redoMO = multi->mapOn;
3055 }
3056 multi->subMtl = undo;
3057 // multi->mapOn = undoMO;
3058 }
3059 void Redo() {
3060 multi->subMtl = redo;
3061 // multi->mapOn = redoMO;
3062 }
3063 };
3064
3065 void Multi::SetNumSubMtls(int n)
3066 {
3067 int ct = subMtl.Count();
3068 if (n!=ct) {
3069 if (n<ct) {
3070 for (int i=n; i<ct; i++) {
3071 if (subMtl[i])
3072 subMtl[i]->DeactivateMapsInTree();
3073 ReplaceReference(i+1,NULL);
3074 }
3075 }
3076 subMtl.SetCount(n);
3077 // subNames.SetSize(n);
3078 // mapOn.SetCount(n);
3079 // pblock->SetCount(multi_mtls,n);
3080 if (n>ct) {
3081 for (int i=ct; i<subMtl.Count(); i++) {
3082 subMtl[i] = NULL;
3083 ReplaceReference(i+1,(ReferenceTarget*)GetStdMtl2Desc()->Create());
3084 GetCOREInterface()->AssignNewName(subMtl[i]);
3085
3086 // pblock->SetValue(multi_ons,0,TRUE,i);
3087 // mapOn[i] = TRUE;
3088 }
3089 //have to do this sepperate because setvalue causes an update and all the references are not in place yet
3090 macroRec->Disable(); // JBW 4/21/99, just record on count change
3091 pblock->SetCount(multi_ons,n);
3092 pblock->SetCount(multi_names,n);
3093 pblock->SetCount(multi_ids,n);
3094 macroRec->Enable();
3095 pblock->SetCount(multi_mtls,n);
3096 for (int i=ct; i<subMtl.Count(); i++) {
3097 pblock->SetValue(multi_ons,0,TRUE,i);
3098 pblock->SetValue(multi_ids,0,i,i);
3099 // mapOn[i] = TRUE;
3100 }
3101
3102 }
3103 else
3104 {
3105 macroRec->Disable(); // JBW 4/21/99, just record on count change
3106 pblock->SetCount(multi_ons,n);
3107 pblock->SetCount(multi_names,n);
3108 pblock->SetCount(multi_ids,n);
3109 macroRec->Enable();
3110 pblock->SetCount(multi_mtls,n);
3111
3112 }
3113
3114 ClampOffset();
3115 NotifyChanged();
3116 if (paramDlg&&!paramDlg->isActive) {
3117 paramDlg->ReloadDialog();
3118 paramDlg->UpdateMtlDisplay(); // DS 9/2/99
3119 }
3120 }
3121 }
3122
3123 */
3124