Game Engine: alpha blending and sorting
[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., 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 #include "RAS_MaterialBucket.h"
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #ifdef WIN32
36 #pragma warning (disable:4786)
37 #include <windows.h>
38 #endif // WIN32
39
40 #include "RAS_Polygon.h"
41 #include "RAS_TexVert.h"
42 #include "RAS_IRasterizer.h"
43 #include "RAS_IRenderTools.h"
44 #include "RAS_MeshObject.h"
45 #include "RAS_Deformer.h"       // __NLA
46
47
48
49 KX_VertexIndex::KX_VertexIndex(int size)
50 {
51         m_size = size;
52 }
53
54
55
56 void KX_VertexIndex::SetIndex(short loc,unsigned int index)
57 {
58         m_indexarray[loc]=index;
59 }
60
61 bool KX_MeshSlot::Less(const KX_MeshSlot& lhs) const
62 {
63         bool result = ((m_mesh < lhs.m_mesh ) ||
64                 ((m_mesh == lhs.m_mesh)&&(m_OpenGLMatrix < lhs.m_OpenGLMatrix)));
65         
66         return result;
67 }
68
69 KX_MeshSlot::~KX_MeshSlot()
70 {
71         if (m_DisplayList)
72                 m_DisplayList->Release();
73 }
74
75
76 RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat)
77         :m_bModified(true)
78 {
79         m_material = mat;
80 }
81
82
83
84 RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const
85
86         return m_material;
87 }
88
89
90         
91 void RAS_MaterialBucket::SetMeshSlot(KX_MeshSlot& ms)
92 {
93         m_meshSlots.insert(ms);
94 }
95
96
97
98 void RAS_MaterialBucket::RemoveMeshSlot(KX_MeshSlot& ms)
99 {
100         T_MeshSlotList::iterator it = m_meshSlots.find(ms);
101
102         if (!(it == m_meshSlots.end()))
103                 m_meshSlots.erase(it);
104                         
105 }
106
107
108
109 void RAS_MaterialBucket::MarkVisibleMeshSlot(KX_MeshSlot& ms,
110                                                                                          bool visible,
111                                                                                          bool color,
112                                                                                          const MT_Vector4& rgbavec)
113 {
114         T_MeshSlotList::iterator it = m_meshSlots.find(ms);
115                         
116         assert (!(it == m_meshSlots.end())); 
117         (*it).m_bVisible = visible;
118         (*it).m_bObjectColor = color;
119         (*it).m_RGBAcolor= rgbavec;
120 }
121
122 bool RAS_MaterialBucket::IsAlpha() const
123 {       
124         return (m_material->IsAlpha());
125 }
126
127 bool RAS_MaterialBucket::IsZSort() const
128 {       
129         return (m_material->IsZSort());
130 }
131
132
133
134 void RAS_MaterialBucket::StartFrame()
135 {
136 }
137
138
139
140 void RAS_MaterialBucket::EndFrame()
141 {
142 }
143
144 unsigned int RAS_MaterialBucket::NumMeshSlots()
145 {
146         return m_meshSlots.size();
147 }
148
149 RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msBegin()
150 {
151         return m_meshSlots.begin();
152 }
153
154 RAS_MaterialBucket::T_MeshSlotList::iterator RAS_MaterialBucket::msEnd()
155 {
156         return m_meshSlots.end();
157 }
158
159 bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
160         RAS_IRenderTools *rendertools, RAS_IRasterizer::DrawMode &drawmode)
161 {
162         rendertools->SetViewMat(cameratrans);
163
164         if (!rasty->SetMaterial(*m_material))
165                 return false;
166         
167         if (m_material->UsesLighting(rasty))
168                 rendertools->ProcessLighting(RAS_IRenderTools::RAS_LIGHT_OBJECT_LAYER/*m_material->GetLightLayer()*/);
169         else
170                 rendertools->ProcessLighting(-1);
171
172         if(rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID)
173                 drawmode = RAS_IRasterizer::KX_MODE_LINES;
174         else if(m_material->UsesTriangles())
175                 drawmode = RAS_IRasterizer::KX_MODE_TRIANGLES;
176         else
177                 drawmode = RAS_IRasterizer::KX_MODE_QUADS;
178         
179         return true;
180 }
181
182 void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty,
183         RAS_IRenderTools* rendertools, const KX_MeshSlot &ms, RAS_IRasterizer::DrawMode drawmode)
184 {
185         if (!ms.m_bVisible)
186                 return;
187         
188         m_material->ActivateMeshSlot(ms, rasty);
189
190         /* __NLA Do the deformation */
191         if (ms.m_pDeformer)
192         {
193                 ms.m_pDeformer->Apply(m_material);
194         //      KX_ReInstanceShapeFromMesh(ms.m_mesh); // Recompute the physics mesh. (Can't call KX_* from RAS_)
195         }
196         /* End __NLA */
197         
198         if (rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID)
199                 ms.m_mesh->SortPolygons(cameratrans*MT_Transform(ms.m_OpenGLMatrix));
200
201         rendertools->PushMatrix();
202         rendertools->applyTransform(rasty,ms.m_OpenGLMatrix,m_material->GetDrawingMode());
203
204         if(rasty->QueryLists())
205         {
206                 if(ms.m_DisplayList)
207                         ms.m_DisplayList->SetModified(ms.m_mesh->MeshModified());
208         }
209
210         // verify if we can use display list, not for deformed object, and
211         // also don't create a new display list when drawing shadow buffers,
212         // then it won't have texture coordinates for actual drawing
213         KX_ListSlot **displaylist;
214         if(ms.m_pDeformer)
215                 displaylist = 0;
216         else if(!ms.m_DisplayList && rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW)
217                 displaylist = 0;
218         else
219                 displaylist = &ms.m_DisplayList;
220
221         // Use the text-specific IndexPrimitives for text faces
222         if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT)
223         {
224                 rasty->IndexPrimitives_3DText(
225                                 ms.m_mesh->GetVertexCache(m_material), 
226                                 ms.m_mesh->GetIndexCache(m_material), 
227                                 drawmode,
228                                 m_material,
229                                 rendertools, // needed for textprinting on polys
230                                 ms.m_bObjectColor,
231                                 ms.m_RGBAcolor);
232         }
233
234         // for using glMultiTexCoord
235         else if((m_material->GetFlag() & RAS_MULTITEX))
236         {
237                 rasty->IndexPrimitivesMulti(
238                                 ms.m_mesh->GetVertexCache(m_material), 
239                                 ms.m_mesh->GetIndexCache(m_material), 
240                                 drawmode,
241                                 ms.m_bObjectColor,
242                                 ms.m_RGBAcolor,
243                                 displaylist);
244         }
245
246         // Use the normal IndexPrimitives
247         else
248         {
249                 rasty->IndexPrimitives(
250                                 ms.m_mesh->GetVertexCache(m_material), 
251                                 ms.m_mesh->GetIndexCache(m_material), 
252                                 drawmode,
253                                 ms.m_bObjectColor,
254                                 ms.m_RGBAcolor,
255                                 displaylist);
256         }
257
258         if(rasty->QueryLists()) {
259                 if(ms.m_DisplayList)
260                         ms.m_mesh->SetMeshModified(false);
261         }
262
263         rendertools->PopMatrix();
264 }
265
266 void RAS_MaterialBucket::Render(const MT_Transform& cameratrans,
267                                                                 RAS_IRasterizer* rasty,
268                                                                 RAS_IRenderTools* rendertools)
269 {
270         if (m_meshSlots.begin()== m_meshSlots.end())
271                 return;
272                 
273         //rendertools->SetViewMat(cameratrans);
274
275         //rasty->SetMaterial(*m_material);
276         
277         RAS_IRasterizer::DrawMode drawmode;
278         for (T_MeshSlotList::const_iterator it = m_meshSlots.begin();
279         ! (it == m_meshSlots.end()); ++it)
280         {
281                 rendertools->SetClientObject((*it).m_clientObj);
282                 while (ActivateMaterial(cameratrans, rasty, rendertools, drawmode)) {
283                         RenderMeshSlot(cameratrans, rasty, rendertools, *it, drawmode);
284                 }
285         }
286         // to reset the eventual GL_CW mode
287         rendertools->SetClientObject(NULL);
288 }
289
290