doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / gameengine / Rasterizer / RAS_MaterialBucket.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #include "RAS_MaterialBucket.h"
30
31 #if defined(WIN32) && !defined(FREE_WINDOWS)
32 #pragma warning (disable:4786)
33 #endif
34
35 #ifdef WIN32
36 #include <windows.h>
37 #endif // WIN32
38
39 #include "RAS_Polygon.h"
40 #include "RAS_TexVert.h"
41 #include "RAS_IRasterizer.h"
42 #include "RAS_IRenderTools.h"
43 #include "RAS_MeshObject.h"
44 #include "RAS_Deformer.h"       // __NLA
45
46 /* mesh slot */
47
48 RAS_MeshSlot::RAS_MeshSlot() : SG_QList()
49 {
50         m_clientObj = NULL;
51         m_pDeformer = NULL;
52         m_OpenGLMatrix = NULL;
53         m_mesh = NULL;
54         m_bucket = NULL;
55         m_bVisible = false;
56         m_bCulled = true;
57         m_bObjectColor = false;
58         m_RGBAcolor = MT_Vector4(0.0, 0.0, 0.0, 0.0);
59         m_DisplayList = NULL;
60         m_bDisplayList = true;
61         m_joinSlot = NULL;
62         m_pDerivedMesh = NULL;
63 }
64
65 RAS_MeshSlot::~RAS_MeshSlot()
66 {
67         RAS_DisplayArrayList::iterator it;
68
69 #ifdef USE_SPLIT
70         Split(true);
71
72         while(m_joinedSlots.size())
73                 m_joinedSlots.front()->Split(true);
74 #endif
75
76         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
77                 (*it)->m_users--;
78                 if((*it)->m_users == 0)
79                         delete *it;
80         }
81
82         if (m_DisplayList) {
83                 m_DisplayList->Release();
84                 m_DisplayList = NULL;
85         }
86 }
87
88 RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) : SG_QList()
89 {
90         RAS_DisplayArrayList::iterator it;
91
92         m_clientObj = NULL;
93         m_pDeformer = NULL;
94         m_pDerivedMesh = NULL;
95         m_OpenGLMatrix = NULL;
96         m_mesh = slot.m_mesh;
97         m_bucket = slot.m_bucket;
98         m_bVisible = slot.m_bVisible;
99         m_bCulled = slot.m_bCulled;
100         m_bObjectColor = slot.m_bObjectColor;
101         m_RGBAcolor = slot.m_RGBAcolor;
102         m_DisplayList = NULL;
103         m_bDisplayList = slot.m_bDisplayList;
104         m_joinSlot = NULL;
105         m_currentArray = slot.m_currentArray;
106         m_displayArrays = slot.m_displayArrays;
107         m_joinedSlots = slot.m_joinedSlots;
108
109         m_startarray = slot.m_startarray;
110         m_startvertex = slot.m_startvertex;
111         m_startindex = slot.m_startindex;
112         m_endarray = slot.m_endarray;
113         m_endvertex = slot.m_endvertex;
114         m_endindex = slot.m_endindex;
115
116         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
117                 // don't copy display arrays for now because it breaks python 
118                 // access to vertices, but we'll need a solution if we want to
119                 // join display arrays for reducing draw calls.
120                 //*it = new RAS_DisplayArray(**it);
121                 //(*it)->m_users = 1;
122
123                 (*it)->m_users++;
124         }
125 }
126
127 void RAS_MeshSlot::init(RAS_MaterialBucket *bucket, int numverts)
128 {
129         m_bucket = bucket;
130
131         SetDisplayArray(numverts);
132
133         m_startarray = 0;
134         m_startvertex = 0;
135         m_startindex = 0;
136         m_endarray = 0;
137         m_endvertex = 0;
138         m_endindex = 0;
139 }
140
141 void RAS_MeshSlot::begin(RAS_MeshSlot::iterator& it)
142 {
143         int startvertex, endvertex;
144         int startindex, endindex;
145
146         it.array = (m_displayArrays.size() > 0)? m_displayArrays[m_startarray]: NULL;
147
148         if(it.array == NULL || it.array->m_index.size() == 0 || it.array->m_vertex.size() == 0) {
149                 it.array = NULL;
150                 it.vertex = NULL;
151                 it.index = NULL;
152                 it.startvertex = 0;
153                 it.endvertex = 0;
154                 it.totindex = 0;
155         }
156         else {
157                 startvertex = m_startvertex;
158                 endvertex = (m_startarray == m_endarray)? m_endvertex: it.array->m_vertex.size();
159                 startindex = m_startindex;
160                 endindex = (m_startarray == m_endarray)? m_endindex: it.array->m_index.size();
161
162                 it.vertex = &it.array->m_vertex[0];
163                 it.index = &it.array->m_index[startindex];
164                 it.startvertex = startvertex;
165                 it.endvertex = endvertex;
166                 it.totindex = endindex-startindex;
167                 it.arraynum = m_startarray;
168         }
169 }
170
171 void RAS_MeshSlot::next(RAS_MeshSlot::iterator& it)
172 {
173         int startvertex, endvertex;
174         int startindex, endindex;
175
176         if(it.arraynum == (size_t)m_endarray) {
177                 it.array = NULL;
178                 it.vertex = NULL;
179                 it.index = NULL;
180                 it.startvertex = 0;
181                 it.endvertex = 0;
182                 it.totindex = 0;
183         }
184         else {
185                 it.arraynum++;
186                 it.array = m_displayArrays[it.arraynum];
187
188                 startindex = 0;
189                 endindex = (it.arraynum == (size_t)m_endarray)? m_endindex: it.array->m_index.size();
190                 startvertex = 0;
191                 endvertex = (it.arraynum == (size_t)m_endarray)? m_endvertex: it.array->m_vertex.size();
192
193                 it.vertex = &it.array->m_vertex[0];
194                 it.index = &it.array->m_index[startindex];
195                 it.startvertex = startvertex;
196                 it.endvertex = endvertex;
197                 it.totindex = endindex-startindex;
198         }
199 }
200
201 bool RAS_MeshSlot::end(RAS_MeshSlot::iterator& it)
202 {
203         return (it.array == NULL);
204 }
205
206 RAS_DisplayArray *RAS_MeshSlot::CurrentDisplayArray()
207 {
208         return m_currentArray;
209 }
210
211 void RAS_MeshSlot::SetDisplayArray(int numverts)
212 {
213         RAS_DisplayArrayList::iterator it;
214         RAS_DisplayArray *darray = NULL;
215         
216         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
217                 darray = *it;
218
219                 if(darray->m_type == numverts) {
220                         if(darray->m_index.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_INDEX)
221                                 darray = NULL;
222                         else if(darray->m_vertex.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_VERTEX)
223                                 darray = NULL;
224                         else
225                                 break;
226                 }
227                 else
228                         darray = NULL;
229         }
230
231         if(!darray) {
232                 darray = new RAS_DisplayArray();
233                 darray->m_users = 1;
234
235                 if(numverts == 2) darray->m_type = RAS_DisplayArray::LINE;
236                 else if(numverts == 3) darray->m_type = RAS_DisplayArray::TRIANGLE;
237                 else darray->m_type = RAS_DisplayArray::QUAD;
238
239                 m_displayArrays.push_back(darray);
240
241                 if(numverts == 2)
242                         darray->m_type = RAS_DisplayArray::LINE;
243                 else if(numverts == 3)
244                         darray->m_type = RAS_DisplayArray::TRIANGLE;
245                 else if(numverts == 4)
246                         darray->m_type = RAS_DisplayArray::QUAD;
247                 
248                 m_endarray = m_displayArrays.size()-1;
249                 m_endvertex = 0;
250                 m_endindex = 0;
251         }
252
253         m_currentArray = darray;
254 }
255
256 void RAS_MeshSlot::AddPolygon(int numverts)
257 {
258         SetDisplayArray(numverts);
259 }
260
261 int RAS_MeshSlot::AddVertex(const RAS_TexVert& tv)
262 {
263         RAS_DisplayArray *darray;
264         int offset;
265         
266         darray = m_currentArray;
267         darray->m_vertex.push_back(tv);
268         offset = darray->m_vertex.size()-1;
269
270         if(darray == m_displayArrays[m_endarray])
271                 m_endvertex++;
272
273         return offset;
274 }
275
276 void RAS_MeshSlot::AddPolygonVertex(int offset)
277 {
278         RAS_DisplayArray *darray;
279
280         darray = m_currentArray;
281         darray->m_index.push_back(offset);
282
283         if(darray == m_displayArrays[m_endarray])
284                 m_endindex++;
285 }
286
287 void RAS_MeshSlot::SetDeformer(RAS_Deformer* deformer)
288 {
289         if (deformer && m_pDeformer != deformer) {
290                 RAS_DisplayArrayList::iterator it;
291                 if (deformer->ShareVertexArray()) {
292                         // this deformer uses the base vertex array, first release the current ones
293                         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
294                                 (*it)->m_users--;
295                                 if((*it)->m_users == 0)
296                                         delete *it;
297                         }
298                         m_displayArrays.clear();
299                         // then hook to the base ones
300                         RAS_MeshMaterial *mmat = m_mesh->GetMeshMaterial(m_bucket->GetPolyMaterial());
301                         if (mmat && mmat->m_baseslot) {
302                                 m_displayArrays = mmat->m_baseslot->m_displayArrays;
303                                 for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
304                                         (*it)->m_users++;
305                                 }
306                         }
307                 }
308                 else {
309                         // no sharing
310                         // we create local copy of RAS_DisplayArray when we have a deformer:
311                         // this way we can avoid conflict between the vertex cache of duplicates
312                         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
313                                 if (deformer->UseVertexArray()) {
314                                         // the deformer makes use of vertex array, make sure we have our local copy
315                                         if ((*it)->m_users > 1) {
316                                                 // only need to copy if there are other users
317                                                 // note that this is the usual case as vertex arrays are held by the material base slot
318                                                 RAS_DisplayArray *newarray = new RAS_DisplayArray(*(*it));
319                                                 newarray->m_users = 1;
320                                                 (*it)->m_users--;
321                                                 *it = newarray;
322                                         }
323                                 } else {
324                                         // the deformer is not using vertex array (Modifier), release them
325                                         (*it)->m_users--;
326                                         if((*it)->m_users == 0)
327                                                 delete *it;
328                                 }
329                         }
330                         if (!deformer->UseVertexArray()) {
331                                 m_displayArrays.clear();
332                                 m_startarray = 0;
333                                 m_startvertex = 0;
334                                 m_startindex = 0;
335                                 m_endarray = 0;
336                                 m_endvertex = 0;
337                                 m_endindex = 0;
338                         }
339                 }
340         }
341         m_pDeformer = deformer;
342 }
343
344 bool RAS_MeshSlot::Equals(RAS_MeshSlot *target)
345 {
346         if(!m_OpenGLMatrix || !target->m_OpenGLMatrix)
347                 return false;
348         if(m_pDeformer || target->m_pDeformer)
349                 return false;
350         if(m_bVisible != target->m_bVisible)
351                 return false;
352         if(m_bObjectColor != target->m_bObjectColor)
353                 return false;
354         if(m_bObjectColor && !(m_RGBAcolor == target->m_RGBAcolor))
355                 return false;
356         
357         return true;
358 }
359
360 bool RAS_MeshSlot::Join(RAS_MeshSlot *target, MT_Scalar distance)
361 {
362         RAS_DisplayArrayList::iterator it;
363         iterator mit;
364         size_t i;
365
366         // verify if we can join
367         if(m_joinSlot || m_joinedSlots.size() || target->m_joinSlot)
368                 return false;
369
370         if(!Equals(target))
371                 return false;
372         
373         MT_Vector3 co(&m_OpenGLMatrix[12]);
374         MT_Vector3 targetco(&target->m_OpenGLMatrix[12]);
375
376         if((co - targetco).length() > distance)
377                 return false;
378
379         MT_Matrix4x4 mat(m_OpenGLMatrix);
380         MT_Matrix4x4 targetmat(target->m_OpenGLMatrix);
381         targetmat.invert();
382
383         MT_Matrix4x4 transform = targetmat*mat;
384         
385         // m_mesh, clientobj
386         m_joinSlot = target;
387         m_joinInvTransform = transform;
388         m_joinInvTransform.invert();
389         target->m_joinedSlots.push_back(this);
390
391         MT_Matrix4x4 ntransform = m_joinInvTransform.transposed();
392         ntransform[0][3]= ntransform[1][3]= ntransform[2][3]= 0.0f;
393
394         for(begin(mit); !end(mit); next(mit))
395                 for(i=mit.startvertex; i<mit.endvertex; i++)
396                         mit.vertex[i].Transform(transform, ntransform);
397         
398         /* We know we'll need a list at least this big, reserve in advance */
399         target->m_displayArrays.reserve(target->m_displayArrays.size() + m_displayArrays.size());
400
401         for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
402                 target->m_displayArrays.push_back(*it);
403                 target->m_endarray++;
404                 target->m_endvertex = target->m_displayArrays.back()->m_vertex.size();
405                 target->m_endindex = target->m_displayArrays.back()->m_index.size();
406         }
407
408         if (m_DisplayList) {
409                 m_DisplayList->Release();
410                 m_DisplayList = NULL;
411         }
412         if (target->m_DisplayList) {
413                 target->m_DisplayList->Release();
414                 target->m_DisplayList = NULL;
415         }
416         
417         return true;
418 #if 0
419         return false;
420 #endif
421 }
422
423 bool RAS_MeshSlot::Split(bool force)
424 {
425         list<RAS_MeshSlot*>::iterator jit;
426         RAS_MeshSlot *target = m_joinSlot;
427         RAS_DisplayArrayList::iterator it, jt;
428         iterator mit;
429         size_t i, found0 = 0, found1 = 0;
430
431         if(target && (force || !Equals(target))) {
432                 m_joinSlot = NULL;
433
434                 for(jit=target->m_joinedSlots.begin(); jit!=target->m_joinedSlots.end(); jit++) {
435                         if(*jit == this) {
436                                 target->m_joinedSlots.erase(jit);
437                                 found0 = 1;
438                                 break;
439                         }
440                 }
441
442                 if(!found0)
443                         abort();
444
445                 for(it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) {
446                         found1 = 0;
447                         for(jt=target->m_displayArrays.begin(); jt!=target->m_displayArrays.end(); jt++) {
448                                 if(*jt == *it) {
449                                         target->m_displayArrays.erase(jt);
450                                         target->m_endarray--;
451                                         found1 = 1;
452                                         break;
453                                 }
454                         }
455
456                         if(!found1)
457                                 abort();
458                 }
459
460                 if(target->m_displayArrays.size()) {
461                         target->m_endvertex = target->m_displayArrays.back()->m_vertex.size();
462                         target->m_endindex = target->m_displayArrays.back()->m_index.size();
463                 }
464                 else {
465                         target->m_endvertex = 0;
466                         target->m_endindex = 0;
467                 }
468
469                 MT_Matrix4x4 ntransform = m_joinInvTransform.inverse().transposed();
470                 ntransform[0][3]= ntransform[1][3]= ntransform[2][3]= 0.0f;
471
472                 for(begin(mit); !end(mit); next(mit))
473                         for(i=mit.startvertex; i<mit.endvertex; i++)
474                                 mit.vertex[i].Transform(m_joinInvTransform, ntransform);
475
476                 if (target->m_DisplayList) {
477                         target->m_DisplayList->Release();
478                         target->m_DisplayList = NULL;
479                 }
480
481                 return true;
482         }
483
484         return false;
485 }
486
487
488 #ifdef USE_SPLIT        
489 bool RAS_MeshSlot::IsCulled()
490 {
491         if(m_joinSlot)
492                 return true;
493         if(!m_bCulled)
494                 return false;
495         list<RAS_MeshSlot*>::iterator it;
496         for(it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++)
497                 if(!(*it)->m_bCulled)
498                         return false;
499         return true;
500 }
501 #endif  
502
503 /* material bucket sorting */
504
505 struct RAS_MaterialBucket::less
506 {
507         bool operator()(const RAS_MaterialBucket* x, const RAS_MaterialBucket* y) const 
508         { 
509                 return *x->GetPolyMaterial() < *y->GetPolyMaterial(); 
510         }
511 };
512
513 /* material bucket */
514
515 RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat)
516 {
517         m_material = mat;
518 }
519
520 RAS_MaterialBucket::~RAS_MaterialBucket()
521 {
522 }
523
524 RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const
525
526         return m_material;
527 }
528
529 bool RAS_MaterialBucket::IsAlpha() const
530 {       
531         return (m_material->IsAlpha());
532 }
533
534 bool RAS_MaterialBucket::IsZSort() const
535 {       
536         return (m_material->IsZSort());
537 }
538
539 RAS_MeshSlot* RAS_MaterialBucket::AddMesh(int numverts)
540 {
541         RAS_MeshSlot *ms;
542
543         m_meshSlots.push_back(RAS_MeshSlot());
544         
545         ms = &m_meshSlots.back();
546         ms->init(this, numverts);
547
548         return ms;
549 }
550
551 RAS_MeshSlot* RAS_MaterialBucket::CopyMesh(RAS_MeshSlot *ms)
552 {
553         m_meshSlots.push_back(RAS_MeshSlot(*ms));
554         
555         return &m_meshSlots.back();
556 }
557
558 void RAS_MaterialBucket::RemoveMesh(RAS_MeshSlot* ms)
559 {
560         list<RAS_MeshSlot>::iterator it;
561
562         for(it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++) {
563                 if(&*it == ms) {
564                         m_meshSlots.erase(it);
565                         return;
566                 }
567         }
568 }
569
570 list<RAS_MeshSlot>::iterator RAS_MaterialBucket::msBegin()
571 {
572         return m_meshSlots.begin();
573 }
574
575 list<RAS_MeshSlot>::iterator RAS_MaterialBucket::msEnd()
576 {
577         return m_meshSlots.end();
578 }
579
580 bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
581         RAS_IRenderTools *rendertools)
582 {
583         bool uselights;
584
585         if(!rasty->SetMaterial(*m_material))
586                 return false;
587         
588         uselights= m_material->UsesLighting(rasty);
589         rendertools->ProcessLighting(rasty, uselights, cameratrans);
590         
591         return true;
592 }
593
594 void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
595         RAS_IRenderTools* rendertools, RAS_MeshSlot &ms)
596 {
597         m_material->ActivateMeshSlot(ms, rasty);
598
599         if (ms.m_pDeformer)
600         {
601                 ms.m_pDeformer->Apply(m_material);
602         //      KX_ReInstanceShapeFromMesh(ms.m_mesh); // Recompute the physics mesh. (Can't call KX_* from RAS_)
603         }
604         
605         if(IsZSort() && rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
606                 ms.m_mesh->SortPolygons(ms, cameratrans*MT_Transform(ms.m_OpenGLMatrix));
607
608         rendertools->PushMatrix();
609         if (!ms.m_pDeformer || !ms.m_pDeformer->SkipVertexTransform())
610         {
611                 rendertools->applyTransform(rasty,ms.m_OpenGLMatrix,m_material->GetDrawingMode());
612         }
613
614         if(rasty->QueryLists())
615                 if(ms.m_DisplayList)
616                         ms.m_DisplayList->SetModified(ms.m_mesh->MeshModified());
617
618         // verify if we can use display list, not for deformed object, and
619         // also don't create a new display list when drawing shadow buffers,
620         // then it won't have texture coordinates for actual drawing. also
621         // for zsort we can't make a display list, since the polygon order
622         // changes all the time.
623         if(ms.m_pDeformer && ms.m_pDeformer->IsDynamic())
624                 ms.m_bDisplayList = false;
625         else if(!ms.m_DisplayList && rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW)
626                 ms.m_bDisplayList = false;
627         else if (IsZSort())
628                 ms.m_bDisplayList = false;
629         else if(m_material->UsesObjectColor() && ms.m_bObjectColor)
630                 ms.m_bDisplayList = false;
631         else
632                 ms.m_bDisplayList = true;
633
634         // for text drawing using faces
635         if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT)
636                 rasty->IndexPrimitives_3DText(ms, m_material, rendertools);
637         // for multitexturing
638         else if((m_material->GetFlag() & (RAS_MULTITEX|RAS_BLENDERGLSL)))
639                 rasty->IndexPrimitivesMulti(ms);
640         // use normal IndexPrimitives
641         else
642                 rasty->IndexPrimitives(ms);
643
644         if(rasty->QueryLists())
645                 if(ms.m_DisplayList)
646                         ms.m_mesh->SetMeshModified(false);
647
648         rendertools->PopMatrix();
649 }
650
651 void RAS_MaterialBucket::Optimize(MT_Scalar distance)
652 {
653         /* TODO: still have to check before this works correct:
654          * - lightlayer, frontface, text, billboard
655          * - make it work with physics */
656         
657 #if 0
658         list<RAS_MeshSlot>::iterator it;
659         list<RAS_MeshSlot>::iterator jt;
660
661         // greed joining on all following buckets
662         for(it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++)
663                 for(jt=it, jt++; jt!=m_meshSlots.end(); jt++)
664                         jt->Join(&*it, distance);
665 #endif
666 }
667