Merged 15170:15635 from trunk (no conflicts or even merges)
[blender.git] / source / gameengine / Rasterizer / RAS_BucketManager.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #ifdef WIN32
34 // don't show these anoying STL warnings
35 #pragma warning (disable:4786)
36 #endif
37
38 #include "GEN_Map.h"
39 #include "RAS_MaterialBucket.h"
40 #include "STR_HashedString.h"
41 #include "RAS_MeshObject.h"
42 #define KX_NUM_MATERIALBUCKETS 100
43 #include "RAS_IRasterizer.h"
44 #include "RAS_IRenderTools.h"
45
46 #include "RAS_BucketManager.h"
47
48 #include <set>
49
50 RAS_BucketManager::RAS_BucketManager()
51 {
52
53 }
54
55 RAS_BucketManager::~RAS_BucketManager()
56 {
57                 RAS_BucketManagerClearAll();
58 }
59
60 /**
61  * struct alphamesh holds a mesh, (m_ms) it's depth, (m_z) and the bucket it came from (m_bucket.)
62  */
63 struct RAS_BucketManager::alphamesh
64 {
65 public:
66         MT_Scalar m_z;
67         RAS_MaterialBucket::T_MeshSlotList::iterator m_ms;
68         RAS_MaterialBucket *m_bucket;
69         alphamesh(MT_Scalar z, RAS_MaterialBucket::T_MeshSlotList::iterator &ms, RAS_MaterialBucket *bucket) :
70                 m_z(z),
71                 m_ms(ms),
72                 m_bucket(bucket)
73         {}
74 };
75
76 struct RAS_BucketManager::backtofront
77 {
78         bool operator()(const alphamesh &a, const alphamesh &b)
79         {
80                 return a.m_z < b.m_z;
81         }
82 };
83         
84
85 void RAS_BucketManager::RenderAlphaBuckets(
86         const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
87 {
88         BucketList::iterator bit;
89         std::multiset<alphamesh, backtofront> alphameshset;
90         RAS_MaterialBucket::T_MeshSlotList::iterator mit;
91         
92         /* Camera's near plane equation: cam_norm.dot(point) + cam_origin */
93         const MT_Vector3 cam_norm(cameratrans.getBasis()[2]);
94         const MT_Scalar cam_origin = cameratrans.getOrigin()[2];
95         for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit)
96         {
97                 (*bit)->ClearScheduledPolygons();
98                 for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit)
99                 {
100                         if ((*mit).m_bVisible)
101                         {
102                                 MT_Point3 pos((*mit).m_OpenGLMatrix[12], (*mit).m_OpenGLMatrix[13], (*mit).m_OpenGLMatrix[14]);
103                                 alphameshset.insert(alphamesh(MT_dot(cam_norm, pos) + cam_origin, mit, *bit));
104                         }
105                 }
106         }
107         
108         // It shouldn't be strictly necessary to disable depth writes; but
109         // it is needed for compatibility.
110         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED);
111
112         RAS_IRasterizer::DrawMode drawingmode;
113         std::multiset< alphamesh, backtofront>::iterator msit = alphameshset.begin();
114         for (; msit != alphameshset.end(); ++msit)
115         {
116                 rendertools->SetClientObject((*(*msit).m_ms).m_clientObj);
117                 while ((*msit).m_bucket->ActivateMaterial(cameratrans, rasty, rendertools, drawingmode))
118                         (*msit).m_bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *(*msit).m_ms, drawingmode);
119         }
120         
121         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
122 }
123
124 void RAS_BucketManager::Renderbuckets(
125         const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
126 {
127         BucketList::iterator bucket;
128         
129         rasty->EnableTextures(false);
130         rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
131         
132         // beginning each frame, clear (texture/material) caching information
133         rasty->ClearCachingInfo();
134
135         RAS_MaterialBucket::StartFrame();
136         for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket)
137         {
138                 (*bucket)->ClearScheduledPolygons();
139         }
140         
141         for (bucket = m_MaterialBuckets.begin(); bucket != m_MaterialBuckets.end(); ++bucket)
142         {
143                 RAS_IPolyMaterial *tmp = (*bucket)->GetPolyMaterial();
144                 if(tmp->IsZSort() || tmp->GetFlag() &RAS_FORCEALPHA )
145                         rasty->SetAlphaTest(true);
146                 else
147                         rasty->SetAlphaTest(false);
148
149                 (*bucket)->Render(cameratrans,rasty,rendertools);
150         }
151         rasty->SetAlphaTest(false);
152
153         RenderAlphaBuckets(cameratrans, rasty, rendertools);    
154         RAS_MaterialBucket::EndFrame();
155 }
156
157 RAS_MaterialBucket* RAS_BucketManager::RAS_BucketManagerFindBucket(RAS_IPolyMaterial * material, bool &bucketCreated)
158 {
159         bucketCreated = false;
160         BucketList::iterator it;
161         for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++)
162         {
163                 if (*(*it)->GetPolyMaterial() == *material)
164                         return *it;
165         }
166         
167         for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
168         {
169                 if (*(*it)->GetPolyMaterial() == *material)
170                         return *it;
171         }
172         
173         RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material);
174         bucketCreated = true;
175         if (bucket->IsTransparant())
176                 m_AlphaBuckets.push_back(bucket);
177         else
178                 m_MaterialBuckets.push_back(bucket);
179         
180         return bucket;
181 }
182
183 void RAS_BucketManager::RAS_BucketManagerClearAll()
184 {
185         BucketList::iterator it;
186         for (it = m_MaterialBuckets.begin(); it != m_MaterialBuckets.end(); it++)
187         {
188                 delete (*it);
189         }
190         for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++)
191         {
192                 delete(*it);
193         }
194         
195         m_MaterialBuckets.clear();
196         m_AlphaBuckets.clear();
197 }