Merged 15170:15635 from trunk (no conflicts or even merges)
[blender.git] / source / gameengine / Rasterizer / RAS_MeshObject.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include "RAS_MeshObject.h"
34 #include "RAS_IRasterizer.h"
35 #include "MT_MinMax.h"
36 #include "MT_Point3.h"
37
38
39 STR_String RAS_MeshObject::s_emptyname = "";
40
41
42
43 KX_ArrayOptimizer::~KX_ArrayOptimizer()
44 {
45         for (vector<KX_VertexArray*>::iterator itv = m_VertexArrayCache1.begin();
46         !(itv == m_VertexArrayCache1.end());++itv)
47         {
48                 delete (*itv);
49         }
50
51         for (vector<KX_IndexArray*>::iterator iti = m_IndexArrayCache1.begin();
52         !(iti == m_IndexArrayCache1.end());++iti)
53         {
54                 delete (*iti);
55         }
56         
57         m_TriangleArrayCount.clear();
58         m_VertexArrayCache1.clear();
59         m_IndexArrayCache1.clear();
60
61
62 }
63
64
65
66 RAS_MeshObject::RAS_MeshObject(Mesh* mesh, int lightlayer)
67         : m_bModified(true),
68         m_lightlayer(lightlayer),
69         m_zsort(false),
70         m_MeshMod(true),
71         m_mesh(mesh),
72         m_class(0)
73 {
74 }
75
76
77 bool RAS_MeshObject::MeshModified()
78 {
79         return m_MeshMod;
80 }
81
82         
83 RAS_MeshObject::~RAS_MeshObject()
84 {
85         for (vector<RAS_Polygon*>::iterator it=m_Polygons.begin();!(it==m_Polygons.end());it++)
86         {
87                 delete (*it);
88         }
89
90         ClearArrayData();
91 }
92
93
94
95 unsigned int RAS_MeshObject::GetLightLayer()
96 {
97         return m_lightlayer;
98 }
99
100
101
102 int RAS_MeshObject::NumMaterials()
103 {
104         return m_materials.size();
105 }
106
107 const STR_String& RAS_MeshObject::GetMaterialName(unsigned int matid)
108
109         RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
110         
111         return bucket?bucket->GetPolyMaterial()->GetMaterialName():s_emptyname;
112 }
113
114 RAS_MaterialBucket* RAS_MeshObject::GetMaterialBucket(unsigned int matid)
115 {
116         if (m_materials.size() > 0 && (matid < m_materials.size()))
117         {
118                 RAS_MaterialBucket::Set::const_iterator it = m_materials.begin();
119                 while (matid--) ++it;
120                 return *it;
121         }
122
123         return NULL;
124 }
125
126
127
128 int RAS_MeshObject::NumPolygons()
129 {
130         return m_Polygons.size();
131 }
132
133
134
135 RAS_Polygon* RAS_MeshObject::GetPolygon(int num)
136 {
137         return m_Polygons[num];
138 }
139
140         
141         
142 RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetFirstMaterial()
143 {
144         return m_materials.begin();
145 }
146
147
148
149 RAS_MaterialBucket::Set::iterator RAS_MeshObject::GetLastMaterial()
150 {
151         return m_materials.end();
152 }
153
154
155
156 void RAS_MeshObject::SetName(STR_String name)
157 {
158         m_name = name;
159 }
160
161
162
163 const STR_String& RAS_MeshObject::GetName()
164 {
165         return m_name;
166 }
167
168
169
170 const STR_String& RAS_MeshObject::GetTextureName(unsigned int matid)
171
172         RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
173         
174         return bucket?bucket->GetPolyMaterial()->GetTextureName():s_emptyname;
175 }
176
177
178
179 void RAS_MeshObject::AddPolygon(RAS_Polygon* poly)
180 {
181         m_Polygons.push_back(poly);
182 }
183
184
185
186 void RAS_MeshObject::DebugColor(unsigned int abgr)
187 {
188 /*
189         int numpolys = NumPolygons();
190         for (int i=0;i<numpolys;i++)
191         {
192                 RAS_Polygon* poly = m_polygons[i];
193                 for (int v=0;v<poly->VertexCount();v++)
194                 {
195                 RAS_TexVert* vtx = poly->GetVertex(v);
196                 vtx->setDebugRGBA(abgr);
197                 }
198         }
199         */
200
201         m_debugcolor = abgr;    
202 }
203
204
205
206 void RAS_MeshObject::SchedulePoly(const KX_VertexIndex& idx,
207                                                                   int numverts,
208                                                                   RAS_IPolyMaterial* mat)
209 {
210         //int indexpos = m_IndexArrayCount[idx.m_vtxarray];
211         //m_IndexArrayCount[idx.m_vtxarray] = indexpos + 3;
212         
213         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
214         ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[0]);
215         ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[1]);
216         ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[2]);
217         if (!mat->UsesTriangles()) //if (!m_bUseTriangles)
218         {       
219                 //m_IndexArrayCount[idx.m_vtxarray] = indexpos+4;
220                 ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(idx.m_indexarray[3]);
221         }
222 }
223
224
225
226 void RAS_MeshObject::ScheduleWireframePoly(const KX_VertexIndex& idx,
227                                                                                    int numverts,
228                                                                                    int edgecode,
229                                                                                    RAS_IPolyMaterial* mat)
230 {
231         //int indexpos = m_IndexArrayCount[idx.m_vtxarray];
232         int edgetrace = 1<<(numverts-1);
233         bool drawedge = (edgecode & edgetrace)!=0;
234         edgetrace = 1;
235         int prevvert = idx.m_indexarray[numverts-1];
236         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
237         
238         for (int v = 0; v < numverts; v++)
239         {
240                 unsigned int curvert = idx.m_indexarray[v];
241                 if (drawedge)
242                 {
243                         ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(prevvert);
244                         ao->m_IndexArrayCache1[idx.m_vtxarray]->push_back(curvert);
245                 }
246                 prevvert = curvert;
247                 drawedge = (edgecode & edgetrace)!=0;
248                 edgetrace*=2;
249         }
250         //m_IndexArrayCount[idx.m_vtxarray] = indexpos;
251 }
252
253 int RAS_MeshObject::FindOrAddVertex(int vtxarray,
254                                                                         const MT_Point3& xyz,
255                                                                         const MT_Point2& uv,
256                                                                         const MT_Point2& uv2,
257                                                                         const MT_Vector4& tangent,
258                                                                         const unsigned int rgbacolor,
259                                                                         const MT_Vector3& normal,
260                                                                         bool flat,
261                                                                         RAS_IPolyMaterial* mat,
262                                                                         int origindex)
263 {
264         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
265         
266         int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray];
267         RAS_TexVert newvert(xyz,uv,uv2,tangent,rgbacolor,normal, flat? TV_CALCFACENORMAL: 0,origindex);
268
269 #define KX_FIND_SHARED_VERTICES
270 #ifdef KX_FIND_SHARED_VERTICES
271         if(!flat) {
272                 for (std::vector<RAS_MatArrayIndex>::iterator it = m_xyz_index_to_vertex_index_mapping[origindex].begin();
273                          it != m_xyz_index_to_vertex_index_mapping[origindex].end();
274                          it++)
275                 {
276                         if ((*it).m_arrayindex1 == ao->m_index1 &&
277                                 (*it).m_array == vtxarray && 
278                                 *(*it).m_matid == *mat &&
279                                 (*ao->m_VertexArrayCache1[vtxarray])[(*it).m_index].closeTo(&newvert)
280                                 )
281                         {
282                                 return (*it).m_index;
283                         }
284                 }
285         }
286 #endif // KX_FIND_SHARED_VERTICES
287         
288         // no vertex found, add one
289         ao->m_VertexArrayCache1[vtxarray]->push_back(newvert);
290         //      printf("(%f,%f,%f) ",xyz[0],xyz[1],xyz[2]);
291         RAS_MatArrayIndex idx;
292         idx.m_arrayindex1 = ao->m_index1;
293         idx.m_array = vtxarray;
294         idx.m_index = numverts;
295         idx.m_matid = mat;
296         m_xyz_index_to_vertex_index_mapping[origindex].push_back(idx); 
297         
298         return numverts;
299 }
300
301 vecVertexArray& RAS_MeshObject::GetVertexCache (RAS_IPolyMaterial* mat)
302 {
303         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
304
305         return ao->m_VertexArrayCache1;
306 }
307
308 int RAS_MeshObject::GetVertexArrayLength(RAS_IPolyMaterial* mat)
309 {
310         int len = 0;
311
312         const vecVertexArray & vertexvec = GetVertexCache(mat);
313         vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
314         
315         for (; it != vertexvec.end(); ++it)
316         {
317                 len += (*it)->size();
318         }
319
320         return len;
321 }
322
323         
324
325 RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid,
326                                                                            unsigned int index)
327 {
328         RAS_TexVert* vertex = NULL;
329         
330         RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
331         if (bucket)
332         {
333                 RAS_IPolyMaterial* mat = bucket->GetPolyMaterial();
334                 if (mat)
335                 {
336                         const vecVertexArray & vertexvec = GetVertexCache(mat);
337                         vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
338                         
339                         for (unsigned int len = 0; it != vertexvec.end(); ++it)
340                         {
341                                 if (index < len + (*it)->size())
342                                 {
343                                         vertex = &(*(*it))[index-len];
344                                         break;
345                                 }
346                                 else
347                                 {
348                                         len += (*it)->size();
349                                 }
350                         }
351                 }
352         }
353         
354         return vertex;
355 }
356
357
358
359 const vecIndexArrays& RAS_MeshObject::GetIndexCache (RAS_IPolyMaterial* mat)
360 {
361         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);
362
363         return ao->m_IndexArrayCache1;
364 }
365
366
367
368 KX_ArrayOptimizer* RAS_MeshObject::GetArrayOptimizer(RAS_IPolyMaterial* polymat)
369 {
370         KX_ArrayOptimizer** aop = m_matVertexArrayS[polymat];
371
372         if(aop)
373                 return *aop;
374         
375         // didn't find array, but an array might already exist
376         // for a material equal to this one
377         for(int i=0;i<m_matVertexArrayS.size();i++) {
378                 RAS_IPolyMaterial *mat = (RAS_IPolyMaterial*)(m_matVertexArrayS.getKey(i)->getValue());
379                 if(*mat == *polymat) {
380                         m_matVertexArrayS.insert(polymat, *m_matVertexArrayS.at(i));
381                         return *m_matVertexArrayS.at(i);
382                 }
383         }
384
385         // create new array
386         int numelements = m_matVertexArrayS.size();
387         m_sortedMaterials.push_back(polymat);
388
389         KX_ArrayOptimizer* ao = new KX_ArrayOptimizer(numelements);
390         m_matVertexArrayS.insert(polymat, ao);
391         
392         return ao;
393 }
394
395
396
397 void RAS_MeshObject::Bucketize(double* oglmatrix,
398                                                            void* clientobj,
399                                                            bool useObjectColor,
400                                                            const MT_Vector4& rgbavec)
401 {
402         KX_MeshSlot ms;
403         ms.m_clientObj = clientobj;
404         ms.m_mesh = this;
405         ms.m_OpenGLMatrix = oglmatrix;
406         ms.m_bObjectColor = useObjectColor;
407         ms.m_RGBAcolor = rgbavec;
408         
409         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
410         {
411                 RAS_MaterialBucket* bucket = *it;
412                 bucket->SchedulePolygons(0);
413 //              KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
414                 bucket->SetMeshSlot(ms);
415         }
416
417 }
418
419
420
421 void RAS_MeshObject::MarkVisible(double* oglmatrix,
422                                                                  void* clientobj,
423                                                                  bool visible,
424                                                                  bool useObjectColor,
425                                                                  const MT_Vector4& rgbavec)
426 {
427         KX_MeshSlot ms;
428         ms.m_clientObj = clientobj;
429         ms.m_mesh = this;
430         ms.m_OpenGLMatrix = oglmatrix;
431         ms.m_RGBAcolor = rgbavec;
432         ms.m_bObjectColor= useObjectColor;
433
434         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
435         {
436                 RAS_MaterialBucket* bucket = *it;
437                 bucket->SchedulePolygons(0);
438 //              KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
439                 bucket->MarkVisibleMeshSlot(ms,visible,useObjectColor,rgbavec);
440         }
441 }
442
443
444 void RAS_MeshObject::RemoveFromBuckets(double* oglmatrix,
445                                                                            void* clientobj)
446 {
447         KX_MeshSlot ms;
448         ms.m_clientObj = clientobj;
449         ms.m_mesh = this;
450         ms.m_OpenGLMatrix = oglmatrix;
451
452         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
453         {
454                 RAS_MaterialBucket* bucket = *it;
455 //              RAS_IPolyMaterial* polymat = bucket->GetPolyMaterial();
456                 bucket->SchedulePolygons(0);
457                 //KX_ArrayOptimizer* oa = GetArrayOptimizer(polymat);
458                 bucket->RemoveMeshSlot(ms);
459         }
460
461 }
462
463
464
465 /*
466  * RAS_MeshObject::GetVertex returns the vertex located somewhere in the vertexpool
467  * it is the clients responsibility to make sure the array and index are valid
468  */
469 RAS_TexVert* RAS_MeshObject::GetVertex(short array,
470                                                                            unsigned int index,
471                                                                            RAS_IPolyMaterial* polymat)
472 {
473          KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);
474         return &((*(ao->m_VertexArrayCache1)[array])[index]);
475 }
476
477
478
479 void RAS_MeshObject::ClearArrayData()
480 {
481         for (int i=0;i<m_matVertexArrayS.size();i++) {
482                 KX_ArrayOptimizer** ao = m_matVertexArrayS.at(i);
483
484                 // we have duplicate entries, only free once
485                 for(int j=i+1;j<m_matVertexArrayS.size();j++) {
486                         if(ao == m_matVertexArrayS.at(j)) {
487                                 ao = NULL;
488                                 break;
489                         }
490                 }
491
492                 if (ao)
493                         delete *ao;
494         }
495 }
496
497
498
499 /**
500  * RAS_MeshObject::CreateNewVertices creates vertices within sorted pools of vertices that share same material
501 */
502 int     RAS_MeshObject::FindVertexArray(int numverts,
503                                                                         RAS_IPolyMaterial* polymat)
504 {
505 //      bool found=false;
506         int array=-1;
507         
508         KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);
509
510         for (unsigned int i=0;i<ao->m_VertexArrayCache1.size();i++)
511         {
512                 if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES) 
513                 {
514                         if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES))
515                         {
516                                 array = i;
517                                 ao->m_TriangleArrayCount[array]+=numverts-2;
518                                 break;
519                         }
520                 }
521         }
522
523         if (array == -1)
524         {
525                 array = ao->m_VertexArrayCache1.size();
526                 vector<RAS_TexVert>* va = new vector<RAS_TexVert>;
527                 ao->m_VertexArrayCache1.push_back(va);
528                 KX_IndexArray *ia = new KX_IndexArray();
529                 ao->m_IndexArrayCache1.push_back(ia);
530                 ao->m_TriangleArrayCount.push_back(numverts-2);
531         }
532
533         return array;
534 }
535
536
537
538
539 //void RAS_MeshObject::Transform(const MT_Transform& trans)
540 //{
541         //m_trans.translate(MT_Vector3(0,0,1));//.operator *=(trans);
542         
543 //      for (int i=0;i<m_Polygons.size();i++)
544 //      {
545 //              m_Polygons[i]->Transform(trans);
546 //      }
547 //}
548
549
550 /*
551 void RAS_MeshObject::RelativeTransform(const MT_Vector3& vec)
552 {
553         for (int i=0;i<m_Polygons.size();i++)
554         {
555                 m_Polygons[i]->RelativeTransform(vec);
556         }
557 }
558 */
559
560
561
562 void RAS_MeshObject::UpdateMaterialList()
563 {
564         m_materials.clear();
565         unsigned int numpolys = m_Polygons.size();
566         // for all polygons, find out which material they use, and add it to the set of materials
567         for (unsigned int i=0;i<numpolys;i++)
568         {
569                 m_materials.insert(m_Polygons[i]->GetMaterial());
570         }
571 }
572
573 struct RAS_MeshObject::polygonSlot
574 {
575         float        m_z;
576         RAS_Polygon *m_poly;
577                 
578         polygonSlot(float z, RAS_Polygon* poly) :
579                 m_z(z),
580                 m_poly(poly)
581         {}
582         /**
583          * pnorm and pval form the plane equation that the distance from is used to
584          * sort against.
585          */
586         polygonSlot(const MT_Vector3 &pnorm, const MT_Scalar &pval, RAS_MeshObject *mesh, RAS_Polygon* poly) :
587                         m_poly(poly)
588         {
589                 const KX_VertexIndex &base = m_poly->GetIndexBase();
590                 RAS_TexVert *vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[0], poly->GetMaterial()->GetPolyMaterial());
591                 m_z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
592                 
593                 for(int i = 1; i < m_poly->VertexCount(); i++)
594                 {
595                         vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[i], poly->GetMaterial()->GetPolyMaterial());
596                         float z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
597                         m_z += z;
598                 }
599                 m_z /= m_poly->VertexCount();
600         }
601 };
602         
603 struct RAS_MeshObject::backtofront
604 {
605         bool operator()(const polygonSlot &a, const polygonSlot &b) const
606         {
607                 return a.m_z < b.m_z;
608         }
609 };
610
611 struct RAS_MeshObject::fronttoback
612 {
613         bool operator()(const polygonSlot &a, const polygonSlot &b) const
614         {
615                 return a.m_z > b.m_z;
616         }
617 };
618
619
620 void RAS_MeshObject::SortPolygons(const MT_Transform &transform)
621 {
622         if (!m_zsort)
623                 return;
624                 
625         // Extract camera Z plane...
626         const MT_Vector3 pnorm(transform.getBasis()[2]);
627         const MT_Scalar pval = transform.getOrigin()[2];
628         
629         unsigned int numpolys = m_Polygons.size();
630         std::multiset<polygonSlot, backtofront> alphapolyset;
631         std::multiset<polygonSlot, fronttoback> solidpolyset;
632         
633         for (unsigned int p = 0; p < numpolys; p++)
634         {
635                 RAS_Polygon* poly = m_Polygons[p];
636                 if (poly->IsVisible())
637                 {
638                         if (poly->GetMaterial()->GetPolyMaterial()->IsTransparant())
639                         {
640                                 alphapolyset.insert(polygonSlot(pnorm, pval, this, poly));
641                         } else {
642                                 solidpolyset.insert(polygonSlot(pnorm, pval, this, poly));
643                         }
644                 }
645         }
646         
647         // Clear current array data.
648         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
649         {
650                 vector<KX_IndexArray*> *indexcache = &GetArrayOptimizer((*it)->GetPolyMaterial())->m_IndexArrayCache1;
651                 for (vector<KX_IndexArray*>::iterator iit = indexcache->begin(); iit != indexcache->end(); ++iit)
652                         (*iit)->clear();
653         }
654
655         std::multiset<polygonSlot, fronttoback>::iterator sit = solidpolyset.begin();
656         for (; sit != solidpolyset.end(); ++sit)
657                 SchedulePoly((*sit).m_poly->GetVertexIndexBase(), (*sit).m_poly->VertexCount(), (*sit).m_poly->GetMaterial()->GetPolyMaterial());
658         
659         std::multiset<polygonSlot, backtofront>::iterator ait = alphapolyset.begin();
660         for (; ait != alphapolyset.end(); ++ait)
661                 SchedulePoly((*ait).m_poly->GetVertexIndexBase(), (*ait).m_poly->VertexCount(), (*ait).m_poly->GetMaterial()->GetPolyMaterial());
662 }
663
664
665 void RAS_MeshObject::SchedulePolygons(const MT_Transform &transform, int drawingmode)
666 {
667 //      int nummaterials = m_materials.size();
668         int i;
669
670         if (m_bModified)
671         {
672                 for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
673                 {
674                         RAS_MaterialBucket* bucket = *it;
675
676                         bucket->SchedulePolygons(drawingmode);
677                         if (bucket->GetPolyMaterial()->IsZSort())
678                                 m_zsort = true;
679                 }
680
681                 int numpolys = m_Polygons.size();
682                 
683                 if ((drawingmode > RAS_IRasterizer::KX_BOUNDINGBOX) && 
684                         (drawingmode < RAS_IRasterizer::KX_SOLID))
685                 {
686                         for (i=0;i<numpolys;i++)
687                         {
688                                 RAS_Polygon* poly = m_Polygons[i];
689                                 if (poly->IsVisible())
690                                         ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode()
691                                         ,poly->GetMaterial()->GetPolyMaterial());
692                                 
693                         }
694                         m_zsort = false;
695                 }
696                 else
697                 {
698                         if (!m_zsort)
699                         {
700                                 for (i=0;i<numpolys;i++)
701                                 {
702                                         RAS_Polygon* poly = m_Polygons[i];
703                                         if (poly->IsVisible())
704                                         {
705                                                 SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetMaterial()->GetPolyMaterial());
706                                         }
707                                 }
708                         }
709                 }
710
711                 m_bModified = false;
712
713                 m_MeshMod = true;
714         } 
715 }