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