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