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