Minor Fixes:
[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         short newnormal[3];
258         
259         newnormal[0]=(short)((normal[0])*32767.0);
260         newnormal[1]=(short)((normal[1])*32767.0);
261         newnormal[2]=(short)((normal[2])*32767.0);
262         
263         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
264         
265         int numverts = ao->m_VertexArrayCache1[vtxarray]->size();//m_VertexArrayCount[vtxarray];
266         RAS_TexVert newvert(xyz,uv,rgbacolor,newnormal, 0);
267 #define KX_FIND_SHARED_VERTICES
268 #ifdef KX_FIND_SHARED_VERTICES
269         
270         for (std::vector<RAS_MatArrayIndex>::iterator it = m_xyz_index_to_vertex_index_mapping[orgindex].begin();
271              it != m_xyz_index_to_vertex_index_mapping[orgindex].end();
272              it++)
273         {
274                 if ((*it).m_arrayindex1 == ao->m_index1 &&
275                         (*it).m_array == vtxarray && 
276                         *(*it).m_matid == *mat &&
277                         (*ao->m_VertexArrayCache1[vtxarray])[(*it).m_index].closeTo(&newvert)
278                         )
279                 {
280                         return (*it).m_index;
281                 }
282         }
283 #endif // KX_FIND_SHARED_VERTICES
284         
285         // no vertex found, add one
286         ao->m_VertexArrayCache1[vtxarray]->push_back(newvert);
287         //      printf("(%f,%f,%f) ",xyz[0],xyz[1],xyz[2]);
288         RAS_MatArrayIndex idx;
289         idx.m_arrayindex1 = ao->m_index1;
290         idx.m_array = vtxarray;
291         idx.m_index = numverts;
292         idx.m_matid = mat;
293         m_xyz_index_to_vertex_index_mapping[orgindex].push_back(idx); 
294         
295         return numverts;
296 }
297
298
299
300 const vecVertexArray& RAS_MeshObject::GetVertexCache (RAS_IPolyMaterial* mat)
301 {
302         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
303
304         return ao->m_VertexArrayCache1;
305 }
306
307
308
309 int RAS_MeshObject::GetVertexArrayLength(RAS_IPolyMaterial* mat)
310 {
311         int len = 0;
312
313         const vecVertexArray & vertexvec = GetVertexCache(mat);
314         vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
315         
316         for (; it != vertexvec.end(); ++it)
317         {
318                 len += (*it)->size();
319         }
320
321         return len;
322 }
323
324         
325
326 RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid,
327                                                                            unsigned int index)
328 {
329         RAS_TexVert* vertex = NULL;
330         
331         RAS_MaterialBucket* bucket = GetMaterialBucket(matid);
332         if (bucket)
333         {
334                 RAS_IPolyMaterial* mat = bucket->GetPolyMaterial();
335                 if (mat)
336                 {
337                         const vecVertexArray & vertexvec = GetVertexCache(mat);
338                         vector<KX_VertexArray*>::const_iterator it = vertexvec.begin();
339                         
340                         for (unsigned int len = 0; it != vertexvec.end(); ++it)
341                         {
342                                 if (index < len + (*it)->size())
343                                 {
344                                         vertex = &(*(*it))[index-len];
345                                         break;
346                                 }
347                                 else
348                                 {
349                                         len += (*it)->size();
350                                 }
351                         }
352                 }
353         }
354         
355         return vertex;
356 }
357
358
359
360 const vecIndexArrays& RAS_MeshObject::GetIndexCache (RAS_IPolyMaterial* mat)
361 {
362         KX_ArrayOptimizer* ao = GetArrayOptimizer(mat);//*(m_matVertexArrays[*mat]);
363
364         return ao->m_IndexArrayCache1;
365 }
366
367
368
369 KX_ArrayOptimizer* RAS_MeshObject::GetArrayOptimizer(RAS_IPolyMaterial* polymat)
370 {
371         KX_ArrayOptimizer** aop = (m_matVertexArrayS[*polymat]);
372
373         if (aop)
374                 return *aop;
375         
376         int numelements = m_matVertexArrayS.size();
377         m_sortedMaterials.push_back(polymat);
378                 
379         KX_ArrayOptimizer* ao = new KX_ArrayOptimizer(numelements);
380         m_matVertexArrayS.insert(*polymat,ao);
381         
382         return ao;
383 }
384
385
386
387 void RAS_MeshObject::Bucketize(double* oglmatrix,
388                                                            void* clientobj,
389                                                            bool useObjectColor,
390                                                            const MT_Vector4& rgbavec)
391 {
392         KX_MeshSlot ms;
393         ms.m_clientObj = clientobj;
394         ms.m_mesh = this;
395         ms.m_OpenGLMatrix = oglmatrix;
396         ms.m_bObjectColor = useObjectColor;
397         ms.m_RGBAcolor = rgbavec;
398         
399         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
400         {
401                 RAS_MaterialBucket* bucket = *it;
402                 bucket->SchedulePolygons(0);
403 //              KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
404                 bucket->SetMeshSlot(ms);
405         }
406
407 }
408
409
410
411 void RAS_MeshObject::MarkVisible(double* oglmatrix,
412                                                                  void* clientobj,
413                                                                  bool visible,
414                                                                  bool useObjectColor,
415                                                                  const MT_Vector4& rgbavec)
416 {
417         KX_MeshSlot ms;
418         ms.m_clientObj = clientobj;
419         ms.m_mesh = this;
420         ms.m_OpenGLMatrix = oglmatrix;
421         ms.m_RGBAcolor = rgbavec;
422         ms.m_bObjectColor= useObjectColor;
423
424         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
425         {
426                 RAS_MaterialBucket* bucket = *it;
427                 bucket->SchedulePolygons(0);
428 //              KX_ArrayOptimizer* oa = GetArrayOptimizer(bucket->GetPolyMaterial());
429                 bucket->MarkVisibleMeshSlot(ms,visible,useObjectColor,rgbavec);
430         }
431 }
432
433
434
435 void RAS_MeshObject::RemoveFromBuckets(double* oglmatrix,
436                                                                            void* clientobj)
437 {
438         KX_MeshSlot ms;
439         ms.m_clientObj = clientobj;
440         ms.m_mesh = this;
441         ms.m_OpenGLMatrix = oglmatrix;
442
443         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
444         {
445                 RAS_MaterialBucket* bucket = *it;
446 //              RAS_IPolyMaterial* polymat = bucket->GetPolyMaterial();
447                 bucket->SchedulePolygons(0);
448                 //KX_ArrayOptimizer* oa = GetArrayOptimizer(polymat);
449                 bucket->RemoveMeshSlot(ms);
450         }
451
452 }
453
454
455
456 /*
457  * RAS_MeshObject::GetVertex returns the vertex located somewhere in the vertexpool
458  * it is the clients responsibility to make sure the array and index are valid
459  */
460 RAS_TexVert* RAS_MeshObject::GetVertex(short array,
461                                                                            short index,
462                                                                            RAS_IPolyMaterial* polymat)
463 {
464          KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);//*(m_matVertexArrays[*polymat]);
465         return &((*(ao->m_VertexArrayCache1)[array])[index]);
466 }
467
468
469
470 void RAS_MeshObject::ClearArrayData()
471 {
472         for (unsigned int i=0;i<m_matVertexArrayS.size();i++)
473         {
474                 KX_ArrayOptimizer** ao = m_matVertexArrayS.at(i);
475                 if (ao)
476                         delete *ao;
477         }
478 }
479
480
481
482 /**
483  * RAS_MeshObject::CreateNewVertices creates vertices within sorted pools of vertices that share same material
484 */
485 int     RAS_MeshObject::FindVertexArray(int numverts,
486                                                                         RAS_IPolyMaterial* polymat)
487 {
488 //      bool found=false;
489         int array=-1;
490         
491         KX_ArrayOptimizer* ao = GetArrayOptimizer(polymat);
492
493         for (unsigned int i=0;i<ao->m_VertexArrayCache1.size();i++)
494         {
495                 if ( (ao->m_TriangleArrayCount[i] + (numverts-2)) < BUCKET_MAX_TRIANGLES) 
496                 {
497                          if((ao->m_VertexArrayCache1[i]->size()+numverts < BUCKET_MAX_INDICES))
498                                 {
499                                         array = i;
500                                         ao->m_TriangleArrayCount[array]+=numverts-2;
501                                         break;
502                                 }
503                 }
504         }
505
506         if (array == -1)
507         {
508                 array = ao->m_VertexArrayCache1.size();
509                 vector<RAS_TexVert>* va = new vector<RAS_TexVert>;
510                 ao->m_VertexArrayCache1.push_back(va);
511                 KX_IndexArray *ia = new KX_IndexArray();
512                 ao->m_IndexArrayCache1.push_back(ia);
513                 ao->m_TriangleArrayCount.push_back(numverts-2);
514         }
515
516         return array;
517 }
518
519
520
521
522 //void RAS_MeshObject::Transform(const MT_Transform& trans)
523 //{
524         //m_trans.translate(MT_Vector3(0,0,1));//.operator *=(trans);
525         
526 //      for (int i=0;i<m_Polygons.size();i++)
527 //      {
528 //              m_Polygons[i]->Transform(trans);
529 //      }
530 //}
531
532
533 /*
534 void RAS_MeshObject::RelativeTransform(const MT_Vector3& vec)
535 {
536         for (int i=0;i<m_Polygons.size();i++)
537         {
538                 m_Polygons[i]->RelativeTransform(vec);
539         }
540 }
541 */
542
543
544
545 void RAS_MeshObject::UpdateMaterialList()
546 {
547         m_materials.clear();
548         unsigned int numpolys = m_Polygons.size();
549         // for all polygons, find out which material they use, and add it to the set of materials
550         for (unsigned int i=0;i<numpolys;i++)
551         {
552                 m_materials.insert(m_Polygons[i]->GetMaterial());
553         }
554 }
555
556 RAS_MeshObject::polygonSlot::polygonSlot(const MT_Vector3 &pnorm, const MT_Scalar &pval, RAS_MeshObject *mesh, RAS_Polygon* poly) :
557                         m_poly(poly)
558 {
559         const KX_VertexIndex &base = m_poly->GetIndexBase();
560         RAS_TexVert *vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[0], poly->GetMaterial()->GetPolyMaterial());
561         m_z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
562         
563         for( unsigned int i = 1; i < m_poly->VertexCount(); i++)
564         {
565                 vert = mesh->GetVertex(base.m_vtxarray, base.m_indexarray[i], poly->GetMaterial()->GetPolyMaterial());
566                 float z = MT_dot(pnorm, vert->getLocalXYZ()) + pval;
567                 if (z < m_z)
568                         m_z = z;
569         }
570 }
571
572 void RAS_MeshObject::SortPolygons(const MT_Transform &transform)
573 {
574         // Extract camera Z plane...
575         const MT_Vector3 pnorm(transform.getBasis()[2]);
576         const MT_Scalar pval = transform.getOrigin()[2];
577         
578         unsigned int numpolys = m_Polygons.size();
579         std::multiset<polygonSlot, backtofront> alphapolyset;
580         std::multiset<polygonSlot, fronttoback> solidpolyset;
581         
582         for (unsigned int p = 0; p < numpolys; p++)
583         {
584                 RAS_Polygon* poly = m_Polygons[p];
585                 if (poly->IsVisible())
586                 {
587                         if (poly->GetMaterial()->GetPolyMaterial()->IsTransparant())
588                         {
589                                 alphapolyset.insert(polygonSlot(pnorm, pval, this, poly));
590                         } else {
591                                 solidpolyset.insert(polygonSlot(pnorm, pval, this, poly));
592                         }
593                 }
594         }
595         
596         // Clear current array data.
597         for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
598         {
599                 vector<KX_IndexArray*> *indexcache = &GetArrayOptimizer((*it)->GetPolyMaterial())->m_IndexArrayCache1;
600                 for (vector<KX_IndexArray*>::iterator iit = indexcache->begin(); iit != indexcache->end(); ++iit)
601                         (*iit)->clear();
602         }
603
604         std::multiset<polygonSlot, fronttoback>::iterator sit = solidpolyset.begin();
605         for (; sit != solidpolyset.end(); ++sit)
606                 SchedulePoly((*sit).m_poly->GetVertexIndexBase(), (*sit).m_poly->VertexCount(), (*sit).m_poly->GetMaterial()->GetPolyMaterial());
607         
608         std::multiset<polygonSlot, backtofront>::iterator ait = alphapolyset.begin();
609         for (; ait != alphapolyset.end(); ++ait)
610                 SchedulePoly((*ait).m_poly->GetVertexIndexBase(), (*ait).m_poly->VertexCount(), (*ait).m_poly->GetMaterial()->GetPolyMaterial());
611 }
612
613 void RAS_MeshObject::SchedulePolygons(const MT_Transform &transform, int drawingmode,RAS_IRasterizer* rasty)
614 {
615 //      int nummaterials = m_materials.size();
616         int i;
617
618         if (m_bModified)
619         {
620                 for (RAS_MaterialBucket::Set::iterator it = m_materials.begin();it!=m_materials.end();++it)
621                 {
622                         RAS_MaterialBucket* bucket = *it;
623
624                         bucket->SchedulePolygons(drawingmode);
625                         if (bucket->GetPolyMaterial()->IsZSort())
626                                 m_zsort = true;
627                 }
628
629                 int numpolys = m_Polygons.size();
630                 
631                 if ((rasty->GetDrawingMode() > RAS_IRasterizer::KX_BOUNDINGBOX) && 
632                         (rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID))
633                 {
634                         for (i=0;i<numpolys;i++)
635                         {
636                                 RAS_Polygon* poly = m_Polygons[i];
637                                 if (poly->IsVisible())
638                                         ScheduleWireframePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetEdgeCode()
639                                         ,poly->GetMaterial()->GetPolyMaterial());
640                                 
641                         }
642                 }
643                 else
644                 {
645                         if (!m_zsort)
646                         {
647                                 for (i=0;i<numpolys;i++)
648                                 {
649                                         RAS_Polygon* poly = m_Polygons[i];
650                                         if (poly->IsVisible())
651                                         {
652                                                 SchedulePoly(poly->GetVertexIndexBase(),poly->VertexCount(),poly->GetMaterial()->GetPolyMaterial());
653                                         }
654                                 }
655                         }
656                 }
657
658                 m_bModified = false;
659         } 
660         
661         if (m_zsort && rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
662         {
663                 SortPolygons(transform);
664         }
665 }