c978b908a6ad79aa5271a7c1273deb97d99cc783
[blender.git] / source / gameengine / Rasterizer / RAS_OpenGLRasterizer / RAS_StorageIM.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 #include "RAS_StorageIM.h"
29 #include "RAS_MaterialBucket.h"
30 #include "RAS_IPolygonMaterial.h"
31
32 #include "glew-mx.h"
33 #include "GPU_draw.h"
34 #include "GPU_extensions.h"
35 #include "GPU_material.h"
36
37 extern "C"{
38         #include "BKE_DerivedMesh.h"
39 }
40
41 RAS_StorageIM::RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
42         m_drawingmode(RAS_IRasterizer::KX_TEXTURED),
43         m_texco_num(texco_num),
44         m_attrib_num(attrib_num),
45         m_texco(texco),
46         m_attrib(attrib),
47         m_attrib_layer(attrib_layer)
48 {
49 }
50 RAS_StorageIM::~RAS_StorageIM()
51 {
52 }
53
54 bool RAS_StorageIM::Init()
55 {
56         return true;
57 }
58 void RAS_StorageIM::Exit()
59 {
60 }
61
62 void RAS_StorageIM::IndexPrimitives(RAS_MeshSlot& ms)
63 {
64         IndexPrimitivesInternal(ms, false);
65 }
66
67 void RAS_StorageIM::IndexPrimitivesMulti(class RAS_MeshSlot& ms)
68 {
69         IndexPrimitivesInternal(ms, true);
70 }
71
72 void RAS_StorageIM::TexCoord(const RAS_TexVert &tv)
73 {
74         int unit;
75
76         if (GLEW_ARB_multitexture) {
77                 for (unit = 0; unit < *m_texco_num; unit++) {
78                         switch (m_texco[unit]) {
79                                 case RAS_IRasterizer::RAS_TEXCO_ORCO:
80                                 case RAS_IRasterizer::RAS_TEXCO_GLOB:
81                                         glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getXYZ());
82                                         break;
83                                 case RAS_IRasterizer::RAS_TEXCO_UV:
84                                         glMultiTexCoord2fvARB(GL_TEXTURE0_ARB + unit, tv.getUV(unit));
85                                         break;
86                                 case RAS_IRasterizer::RAS_TEXCO_NORM:
87                                         glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getNormal());
88                                         break;
89                                 case RAS_IRasterizer::RAS_TEXTANGENT:
90                                         glMultiTexCoord4fvARB(GL_TEXTURE0_ARB + unit, tv.getTangent());
91                                         break;
92                                 default:
93                                         break;
94                         }
95                 }
96         }
97
98         if (GLEW_ARB_vertex_program) {
99                 for (unit = 0; unit < *m_attrib_num; unit++) {
100                         switch (m_attrib[unit]) {
101                                 case RAS_IRasterizer::RAS_TEXCO_ORCO:
102                                 case RAS_IRasterizer::RAS_TEXCO_GLOB:
103                                         glVertexAttrib3fvARB(unit, tv.getXYZ());
104                                         break;
105                                 case RAS_IRasterizer::RAS_TEXCO_UV:
106                                         glVertexAttrib2fvARB(unit, tv.getUV(m_attrib_layer[unit]));
107                                         break;
108                                 case RAS_IRasterizer::RAS_TEXCO_NORM:
109                                         glVertexAttrib3fvARB(unit, tv.getNormal());
110                                         break;
111                                 case RAS_IRasterizer::RAS_TEXTANGENT:
112                                         glVertexAttrib4fvARB(unit, tv.getTangent());
113                                         break;
114                                 case RAS_IRasterizer::RAS_TEXCO_VCOL:
115                                         glVertexAttrib4ubvARB(unit, tv.getRGBA());
116                                         break;
117                                 default:
118                                         break;
119                         }
120                 }
121         }
122
123 }
124
125 void RAS_StorageIM::SetCullFace(bool enable)
126 {
127         if (enable)
128                 glEnable(GL_CULL_FACE);
129         else
130                 glDisable(GL_CULL_FACE);
131 }
132
133 static bool current_wireframe;
134 static RAS_MaterialBucket *current_bucket;
135 static RAS_IPolyMaterial *current_polymat;
136 static RAS_MeshSlot *current_ms;
137 static RAS_MeshObject *current_mesh;
138 static int current_blmat_nr;
139 static GPUVertexAttribs current_gpu_attribs;
140 static Image *current_image;
141 static int CheckMaterialDM(int matnr, void *attribs)
142 {
143         // only draw the current material
144         if (matnr != current_blmat_nr)
145                 return 0;
146         GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs;
147         if (gattribs)
148                 memcpy(gattribs, &current_gpu_attribs, sizeof(GPUVertexAttribs));
149         return 1;
150 }
151
152 /*
153 static int CheckTexfaceDM(void *mcol, int index)
154 {
155
156         // index is the original face index, retrieve the polygon
157         RAS_Polygon* polygon = (index >= 0 && index < current_mesh->NumPolygons()) ?
158                 current_mesh->GetPolygon(index) : NULL;
159         if (polygon && polygon->GetMaterial() == current_bucket) {
160                 // must handle color.
161                 if (current_wireframe)
162                         return 2;
163                 if (current_ms->m_bObjectColor) {
164                         MT_Vector4& rgba = current_ms->m_RGBAcolor;
165                         glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
166                         // don't use mcol
167                         return 2;
168                 }
169                 if (!mcol) {
170                         // we have to set the color from the material
171                         unsigned char rgba[4];
172                         current_polymat->GetMaterialRGBAColor(rgba);
173                         glColor4ubv((const GLubyte *)rgba);
174                         return 2;
175                 }
176                 return 1;
177         }
178         return 0;
179 }
180 */
181
182 static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
183 {
184
185         // index is the original face index, retrieve the polygon
186         if (matnr == current_blmat_nr &&
187                 (mtexpoly == NULL || mtexpoly->tpage == current_image)) {
188                 // must handle color.
189                 if (current_wireframe)
190                         return DM_DRAW_OPTION_NO_MCOL;
191                 if (current_ms->m_bObjectColor) {
192                         MT_Vector4& rgba = current_ms->m_RGBAcolor;
193                         glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
194                         // don't use mcol
195                         return DM_DRAW_OPTION_NO_MCOL;
196                 }
197                 if (!has_mcol) {
198                         // we have to set the color from the material
199                         unsigned char rgba[4];
200                         current_polymat->GetMaterialRGBAColor(rgba);
201                         glColor4ubv((const GLubyte *)rgba);
202                         return DM_DRAW_OPTION_NO_MCOL;
203                 }
204                 return DM_DRAW_OPTION_NORMAL;
205         }
206         return DM_DRAW_OPTION_SKIP;
207 }
208
209 void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
210
211         bool obcolor = ms.m_bObjectColor;
212         bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME;
213         MT_Vector4& rgba = ms.m_RGBAcolor;
214         RAS_MeshSlot::iterator it;
215
216         if (ms.m_pDerivedMesh) {
217                 // mesh data is in derived mesh, 
218                 current_bucket = ms.m_bucket;
219                 current_polymat = current_bucket->GetPolyMaterial();
220                 current_ms = &ms;
221                 current_mesh = ms.m_mesh;
222                 current_wireframe = wireframe;
223                 // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */
224
225                 // handle two-side
226                 if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL)
227                         this->SetCullFace(true);
228                 else
229                         this->SetCullFace(false);
230
231                 if (current_polymat->GetFlag() & RAS_BLENDERGLSL) {
232                         // GetMaterialIndex return the original mface material index, 
233                         // increment by 1 to match what derived mesh is doing
234                         current_blmat_nr = current_polymat->GetMaterialIndex()+1;
235                         // For GLSL we need to retrieve the GPU material attribute
236                         Material* blmat = current_polymat->GetBlenderMaterial();
237                         Scene* blscene = current_polymat->GetBlenderScene();
238                         if (!wireframe && blscene && blmat)
239                                 GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat), &current_gpu_attribs);
240                         else
241                                 memset(&current_gpu_attribs, 0, sizeof(current_gpu_attribs));
242                         // DM draw can mess up blending mode, restore at the end
243                         int current_blend_mode = GPU_get_material_alpha_blend();
244                         ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM);
245                         GPU_set_material_alpha_blend(current_blend_mode);
246                 } else {
247                         //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
248                         current_blmat_nr = current_polymat->GetMaterialIndex();
249                         current_image = current_polymat->GetBlenderImage();
250                         ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV);
251                 }
252                 return;
253         }
254         // iterate over display arrays, each containing an index + vertex array
255         for (ms.begin(it); !ms.end(it); ms.next(it)) {
256                 RAS_TexVert *vertex;
257                 size_t i, j, numvert;
258                 
259                 numvert = it.array->m_type;
260
261                 if (it.array->m_type == RAS_DisplayArray::LINE) {
262                         // line drawing
263                         glBegin(GL_LINES);
264
265                         for (i = 0; i < it.totindex; i += 2)
266                         {
267                                 vertex = &it.vertex[it.index[i]];
268                                 glVertex3fv(vertex->getXYZ());
269
270                                 vertex = &it.vertex[it.index[i+1]];
271                                 glVertex3fv(vertex->getXYZ());
272                         }
273
274                         glEnd();
275                 }
276                 else {
277                         // triangle and quad drawing
278                         if (it.array->m_type == RAS_DisplayArray::TRIANGLE)
279                                 glBegin(GL_TRIANGLES);
280                         else
281                                 glBegin(GL_QUADS);
282
283                         for (i = 0; i < it.totindex; i += numvert)
284                         {
285                                 if (obcolor)
286                                         glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
287
288                                 for (j = 0; j < numvert; j++) {
289                                         vertex = &it.vertex[it.index[i+j]];
290
291                                         if (!wireframe) {
292                                                 if (!obcolor)
293                                                         glColor4ubv((const GLubyte *)(vertex->getRGBA()));
294
295                                                 glNormal3fv(vertex->getNormal());
296
297                                                 if (multi)
298                                                         TexCoord(*vertex);
299                                                 else
300                                                         glTexCoord2fv(vertex->getUV(0));
301                                         }
302
303                                         glVertex3fv(vertex->getXYZ());
304                                 }
305                         }
306
307                         glEnd();
308                 }
309         }
310 }