Ghost Context Refactor
[blender-staging.git] / source / gameengine / Ketsji / KX_BlenderMaterial.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  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file gameengine/Ketsji/KX_BlenderMaterial.cpp
22  *  \ingroup ketsji
23  */
24
25 #include "glew-mx.h"
26
27 #include "KX_BlenderMaterial.h"
28 #include "BL_Material.h"
29 #include "KX_Scene.h"
30 #include "KX_Light.h"
31 #include "KX_GameObject.h"
32 #include "KX_MeshProxy.h"
33
34 #include "MT_Vector3.h"
35 #include "MT_Vector4.h"
36 #include "MT_Matrix4x4.h"
37
38 #include "RAS_BucketManager.h"
39 #include "RAS_MeshObject.h"
40 #include "RAS_IRasterizer.h"
41 #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
42
43 #include "GPU_draw.h"
44
45 #include "STR_HashedString.h"
46
47 // ------------------------------------
48 #include "DNA_object_types.h"
49 #include "DNA_material_types.h"
50 #include "DNA_image_types.h"
51 #include "DNA_meshdata_types.h"
52 #include "BKE_mesh.h"
53 // ------------------------------------
54 #include "BLI_utildefines.h"
55
56 #define spit(x) std::cout << x << std::endl;
57
58 BL_Shader *KX_BlenderMaterial::mLastShader = NULL;
59 BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL;
60
61 //static PyObject *gTextureDict = 0;
62
63 KX_BlenderMaterial::KX_BlenderMaterial()
64 :       PyObjectPlus(),
65         RAS_IPolyMaterial(),
66         mMaterial(NULL),
67         mShader(0),
68         mBlenderShader(0),
69         mScene(NULL),
70         mUserDefBlend(0),
71         mModified(0),
72         mConstructed(false),
73         mPass(0)
74 {
75 }
76
77 void KX_BlenderMaterial::Initialize(
78         KX_Scene *scene,
79         BL_Material *data,
80         GameSettings *game,
81         int lightlayer)
82 {
83         RAS_IPolyMaterial::Initialize(
84                 data->texname[0],
85                 data->matname,
86                 data->materialindex,
87                 data->tile,
88                 data->tilexrep[0],
89                 data->tileyrep[0],
90                 data->alphablend,
91                 ((data->ras_mode &ALPHA)!=0),
92                 ((data->ras_mode &ZSORT)!=0),
93                 ((data->ras_mode &USE_LIGHT)!=0),
94                 ((data->ras_mode &TEX)),
95                 game
96         );
97         mMaterial = data;
98         mShader = 0;
99         mBlenderShader = 0;
100         mScene = scene;
101         mUserDefBlend = 0;
102         mModified = 0;
103         mConstructed = false;
104         mPass = 0;
105         mLightLayer = lightlayer;
106         // --------------------------------
107         // RAS_IPolyMaterial variables...
108         m_flag |= RAS_BLENDERMAT;
109         m_flag |= (mMaterial->IdMode>=ONETEX)? RAS_MULTITEX: 0;
110         m_flag |= ((mMaterial->ras_mode & USE_LIGHT)!=0)? RAS_MULTILIGHT: 0;
111         m_flag |= (mMaterial->glslmat)? RAS_BLENDERGLSL: 0;
112         m_flag |= ((mMaterial->ras_mode & CAST_SHADOW)!=0)? RAS_CASTSHADOW: 0;
113         m_flag |= ((mMaterial->ras_mode & ONLY_SHADOW)!=0)? RAS_ONLYSHADOW: 0;
114
115         // test the sum of the various modes for equality
116         // so we can ether accept or reject this material
117         // as being equal, this is rather important to
118         // prevent material bleeding
119         for (int i=0; i<BL_Texture::GetMaxUnits(); i++) {
120                 m_multimode     += (mMaterial->flag[i] + mMaterial->blend_mode[i]);
121         }
122         m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(USE_LIGHT));
123 }
124
125 KX_BlenderMaterial::~KX_BlenderMaterial()
126 {
127         // cleanup work
128         if (mConstructed)
129                 // clean only if material was actually used
130                 OnExit();
131 }
132
133 MTFace* KX_BlenderMaterial::GetMTFace() const
134 {
135         // fonts on polys
136         return &mMaterial->tface;
137 }
138
139 unsigned int* KX_BlenderMaterial::GetMCol() const
140 {
141         // fonts on polys
142         return mMaterial->rgb;
143 }
144
145 void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const
146 {
147         if (mMaterial) {
148                 *rgba++ = (unsigned char)(mMaterial->matcolor[0] * 255.0f);
149                 *rgba++ = (unsigned char)(mMaterial->matcolor[1] * 255.0f);
150                 *rgba++ = (unsigned char)(mMaterial->matcolor[2] * 255.0f);
151                 *rgba++ = (unsigned char)(mMaterial->matcolor[3] * 255.0f);
152         } else
153                 RAS_IPolyMaterial::GetMaterialRGBAColor(rgba);
154 }
155
156 Material *KX_BlenderMaterial::GetBlenderMaterial() const
157 {
158         return mMaterial->material;
159 }
160
161 Image *KX_BlenderMaterial::GetBlenderImage() const
162 {
163         return mMaterial->tface.tpage;
164 }
165
166 Scene* KX_BlenderMaterial::GetBlenderScene() const
167 {
168         return mScene->GetBlenderScene();
169 }
170
171 void KX_BlenderMaterial::ReleaseMaterial()
172 {
173         if (mBlenderShader)
174                 mBlenderShader->ReloadMaterial();
175 }
176
177 void KX_BlenderMaterial::InitTextures()
178 {
179         // for each unique material...
180         int i;
181         for (i=0; i<BL_Texture::GetMaxUnits(); i++) {
182                 if ( mMaterial->mapping[i].mapping & USEENV ) {
183                         if (!GLEW_ARB_texture_cube_map) {
184                                 spit("CubeMap textures not supported");
185                                 continue;
186                         }
187                         if (!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) )
188                                 spit("unable to initialize image("<<i<<") in "<<
189                                      mMaterial->matname<< ", image will not be available");
190                 }
191                 /* If we're using glsl materials, the textures are handled by bf_gpu, so don't load them twice!
192                  * However, if we're using a custom shader, then we still need to load the textures ourselves. */
193                 else if (!mMaterial->glslmat || mShader) {
194                         if ( mMaterial->img[i] ) {
195                                 if ( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
196                                         spit("unable to initialize image("<<i<<") in "<< 
197                                                 mMaterial->matname<< ", image will not be available");
198                         }
199                 }
200         }
201 }
202
203 void KX_BlenderMaterial::OnConstruction()
204 {
205         if (mConstructed)
206                 // when material are reused between objects
207                 return;
208         
209         if (mMaterial->glslmat)
210                 SetBlenderGLSLShader();
211
212         InitTextures();
213
214         mBlendFunc[0] =0;
215         mBlendFunc[1] =0;
216         mConstructed = true;
217 }
218
219 void KX_BlenderMaterial::EndFrame()
220 {
221         if (mLastBlenderShader) {
222                 mLastBlenderShader->SetProg(false);
223                 mLastBlenderShader = NULL;
224         }
225
226         if (mLastShader) {
227                 mLastShader->SetProg(false);
228                 mLastShader = NULL;
229         }
230 }
231
232 void KX_BlenderMaterial::OnExit()
233 {
234         if ( mShader ) {
235                 //note, the shader here is allocated, per unique material
236                 //and this function is called per face
237                 if (mShader == mLastShader) {
238                         mShader->SetProg(false);
239                         mLastShader = NULL;
240                 }
241
242                 delete mShader;
243                 mShader = 0;
244         }
245
246         if ( mBlenderShader ) {
247                 if (mBlenderShader == mLastBlenderShader) {
248                         mBlenderShader->SetProg(false);
249                         mLastBlenderShader = NULL;
250                 }
251
252                 delete mBlenderShader;
253                 mBlenderShader = 0;
254         }
255
256         BL_Texture::ActivateFirst();
257         for (int i=0; i<BL_Texture::GetMaxUnits(); i++) {
258                 if (!mTextures[i].Ok()) continue;
259                 BL_Texture::ActivateUnit(i);
260                 mTextures[i].DeleteTex();
261                 mTextures[i].DisableUnit();
262         }
263
264         /* used to call with 'mMaterial->tface' but this can be a freed array,
265          * see: [#30493], so just call with NULL, this is best since it clears
266          * the 'lastface' pointer in GPU too - campbell */
267         GPU_set_tpage(NULL, 1, mMaterial->alphablend);
268 }
269
270
271 void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
272 {
273         MT_assert(GLEW_ARB_shader_objects && mShader);
274
275         int i;
276         if ( !enable || !mShader->Ok() ) {
277                 // frame cleanup.
278                 if (mShader == mLastShader) {
279                         mShader->SetProg(false);
280                         mLastShader = NULL;
281                 }
282
283                 ras->SetAlphaBlend(TF_SOLID);
284                 BL_Texture::DisableAllTextures();
285                 return;
286         }
287
288         BL_Texture::DisableAllTextures();
289         mShader->SetProg(true);
290         mLastShader = mShader;
291         
292         BL_Texture::ActivateFirst();
293
294         mShader->ApplyShader();
295
296         // for each enabled unit
297         for (i=0; i<BL_Texture::GetMaxUnits(); i++) {
298                 if (!mTextures[i].Ok()) continue;
299                 mTextures[i].ActivateTexture();
300                 mTextures[0].SetMapping(mMaterial->mapping[i].mapping);
301         }
302
303         if (!mUserDefBlend) {
304                 ras->SetAlphaBlend(mMaterial->alphablend);
305         }
306         else {
307                 ras->SetAlphaBlend(TF_SOLID);
308                 ras->SetAlphaBlend(-1); // indicates custom mode
309
310                 // tested to be valid enums
311                 glEnable(GL_BLEND);
312                 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
313         }
314 }
315
316 void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras)
317 {
318         if ( !enable || !mBlenderShader->Ok() ) {
319                 ras->SetAlphaBlend(TF_SOLID);
320
321                 // frame cleanup.
322                 if (mLastBlenderShader) {
323                         mLastBlenderShader->SetProg(false);
324                         mLastBlenderShader= NULL;
325                 }
326                 else
327                         BL_Texture::DisableAllTextures();
328
329                 return;
330         }
331
332         if (!mBlenderShader->Equals(mLastBlenderShader)) {
333                 ras->SetAlphaBlend(mMaterial->alphablend);
334
335                 if (mLastBlenderShader)
336                         mLastBlenderShader->SetProg(false);
337                 else
338                         BL_Texture::DisableAllTextures();
339
340                 mBlenderShader->SetProg(true, ras->GetTime(), ras);
341                 mLastBlenderShader= mBlenderShader;
342         }
343 }
344
345 void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
346 {
347         BL_Texture::DisableAllTextures();
348
349         if ( !enable ) {
350                 ras->SetAlphaBlend(TF_SOLID);
351                 return;
352         }
353
354         BL_Texture::ActivateFirst();
355
356         if ( mMaterial->IdMode == DEFAULT_BLENDER ) {
357                 ras->SetAlphaBlend(mMaterial->alphablend);
358                 return;
359         }
360
361         if ( mMaterial->IdMode == TEXFACE ) {
362                 // no material connected to the object
363                 if ( mTextures[0].Ok() ) {
364                         mTextures[0].ActivateTexture();
365                         mTextures[0].setTexEnv(0, true);
366                         mTextures[0].SetMapping(mMaterial->mapping[0].mapping);
367                         ras->SetAlphaBlend(mMaterial->alphablend);
368                 }
369                 return;
370         }
371
372         int mode = 0,i=0;
373         for (i=0; i<BL_Texture::GetMaxUnits(); i++) {
374                 if ( !mTextures[i].Ok() ) continue;
375
376                 mTextures[i].ActivateTexture();
377                 mTextures[i].setTexEnv(mMaterial);
378                 mode = mMaterial->mapping[i].mapping;
379
380                 if (mode &USEOBJ)
381                         setObjectMatrixData(i, ras);
382                 else
383                         mTextures[i].SetMapping(mode);
384                 
385                 if (!(mode &USEOBJ))
386                         setTexMatrixData( i );
387         }
388
389         if (!mUserDefBlend) {
390                 ras->SetAlphaBlend(mMaterial->alphablend);
391         }
392         else {
393                 ras->SetAlphaBlend(TF_SOLID);
394                 ras->SetAlphaBlend(-1); // indicates custom mode
395
396                 glEnable(GL_BLEND);
397                 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
398         }
399 }
400
401 void
402 KX_BlenderMaterial::ActivatShaders(
403         RAS_IRasterizer* rasty, 
404         TCachingInfo& cachingInfo)const
405 {
406         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
407
408         // reset... 
409         if (tmp->mMaterial->IsShared()) 
410                 cachingInfo =0;
411
412         if (mLastBlenderShader) {
413                 mLastBlenderShader->SetProg(false);
414                 mLastBlenderShader= NULL;
415         }
416
417         if (GetCachingInfo() != cachingInfo) {
418
419                 if (!cachingInfo)
420                         tmp->setShaderData(false, rasty);
421                 
422                 cachingInfo = GetCachingInfo();
423         
424                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
425                         tmp->setShaderData(true, rasty);
426                 else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader())
427                         tmp->setShaderData(true, rasty);
428                 else
429                         tmp->setShaderData(false, rasty);
430
431                 if (mMaterial->ras_mode &TWOSIDED)
432                         rasty->SetCullFace(false);
433                 else
434                         rasty->SetCullFace(true);
435
436                 if ((mMaterial->ras_mode &WIRE) ||
437                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
438                 {
439                         if (mMaterial->ras_mode &WIRE) 
440                                 rasty->SetCullFace(false);
441                         rasty->SetLines(true);
442                 }
443                 else
444                         rasty->SetLines(false);
445                 ActivatGLMaterials(rasty);
446                 ActivateTexGen(rasty);
447         }
448
449         //ActivatGLMaterials(rasty);
450         //ActivateTexGen(rasty);
451 }
452
453 void
454 KX_BlenderMaterial::ActivateBlenderShaders(
455         RAS_IRasterizer* rasty, 
456         TCachingInfo& cachingInfo)const
457 {
458         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
459
460         if (mLastShader) {
461                 mLastShader->SetProg(false);
462                 mLastShader= NULL;
463         }
464
465         if (GetCachingInfo() != cachingInfo) {
466                 if (!cachingInfo)
467                         tmp->setBlenderShaderData(false, rasty);
468                 
469                 cachingInfo = GetCachingInfo();
470         
471                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
472                         tmp->setBlenderShaderData(true, rasty);
473                 else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader())
474                         tmp->setBlenderShaderData(true, rasty);
475                 else
476                         tmp->setBlenderShaderData(false, rasty);
477
478                 if (mMaterial->ras_mode &TWOSIDED)
479                         rasty->SetCullFace(false);
480                 else
481                         rasty->SetCullFace(true);
482
483                 if ((mMaterial->ras_mode &WIRE) ||
484                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
485                 {
486                         if (mMaterial->ras_mode &WIRE) 
487                                 rasty->SetCullFace(false);
488                         rasty->SetLines(true);
489                 }
490                 else
491                         rasty->SetLines(false);
492
493                 ActivatGLMaterials(rasty);
494                 mBlenderShader->SetAttribs(rasty, mMaterial);
495         }
496 }
497
498 void
499 KX_BlenderMaterial::ActivateMat( 
500         RAS_IRasterizer* rasty,  
501         TCachingInfo& cachingInfo
502         )const
503 {
504         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
505
506         if (mLastShader) {
507                 mLastShader->SetProg(false);
508                 mLastShader= NULL;
509         }
510
511         if (mLastBlenderShader) {
512                 mLastBlenderShader->SetProg(false);
513                 mLastBlenderShader= NULL;
514         }
515
516         if (GetCachingInfo() != cachingInfo) {
517                 if (!cachingInfo) 
518                         tmp->setTexData( false,rasty );
519                 
520                 cachingInfo = GetCachingInfo();
521
522                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
523                         tmp->setTexData( true,rasty  );
524                 else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader())
525                         tmp->setTexData(true, rasty);
526                 else
527                         tmp->setTexData( false,rasty);
528
529                 if (mMaterial->ras_mode &TWOSIDED)
530                         rasty->SetCullFace(false);
531                 else
532                         rasty->SetCullFace(true);
533
534                 if ((mMaterial->ras_mode &WIRE) ||
535                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
536                 {
537                         if (mMaterial->ras_mode &WIRE) 
538                                 rasty->SetCullFace(false);
539                         rasty->SetLines(true);
540                 }
541                 else
542                         rasty->SetLines(false);
543                 ActivatGLMaterials(rasty);
544                 ActivateTexGen(rasty);
545         }
546
547         //ActivatGLMaterials(rasty);
548         //ActivateTexGen(rasty);
549 }
550
551 bool 
552 KX_BlenderMaterial::Activate( 
553         RAS_IRasterizer* rasty,  
554         TCachingInfo& cachingInfo
555         )const
556 {
557         if (GLEW_ARB_shader_objects && (mShader && mShader->Ok())) {
558                 if ((mPass++) < mShader->getNumPass() ) {
559                         ActivatShaders(rasty, cachingInfo);
560                         return true;
561                 }
562                 else {
563                         if (mShader == mLastShader) {
564                                 mShader->SetProg(false);
565                                 mLastShader = NULL;
566                         }
567                         mPass = 0;
568                         return false;
569                 }
570         }
571         else if ( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) {
572                 if (mPass++ == 0) {
573                         ActivateBlenderShaders(rasty, cachingInfo);
574                         return true;
575                 }
576                 else {
577                         mPass = 0;
578                         return false;
579                 }
580         }
581         else {
582                 if (mPass++ == 0) {
583                         ActivateMat(rasty, cachingInfo);
584                         return true;
585                 }
586                 else {
587                         mPass = 0;
588                         return false;
589                 }
590         }
591 }
592
593 bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const
594 {
595         if (!RAS_IPolyMaterial::UsesLighting(rasty))
596                 return false;
597
598         if (mShader && mShader->Ok())
599                 return true;
600         else if (mBlenderShader && mBlenderShader->Ok())
601                 return false;
602         else
603                 return true;
604 }
605
606 void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const
607 {
608         if (mShader && GLEW_ARB_shader_objects) {
609                 mShader->Update(ms, rasty);
610         }
611         else if (mBlenderShader && GLEW_ARB_shader_objects) {
612                 int alphablend;
613
614                 mBlenderShader->Update(ms, rasty);
615
616                 /* we do blend modes here, because they can change per object
617                  * with the same material due to obcolor/obalpha */
618                 alphablend = mBlenderShader->GetAlphaBlend();
619                 if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID)
620                         alphablend = mMaterial->alphablend;
621
622                 rasty->SetAlphaBlend(alphablend);
623         }
624 }
625
626 void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
627 {
628         if (mShader || !mBlenderShader) {
629                 rasty->SetSpecularity(
630                         mMaterial->speccolor[0]*mMaterial->spec_f,
631                         mMaterial->speccolor[1]*mMaterial->spec_f,
632                         mMaterial->speccolor[2]*mMaterial->spec_f,
633                         mMaterial->spec_f
634                 );
635
636                 rasty->SetShinyness( mMaterial->hard );
637
638                 rasty->SetDiffuse(
639                         mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, 
640                         mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
641                         mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
642                         1.0f);
643
644                 rasty->SetEmissive(
645                         mMaterial->matcolor[0]*mMaterial->emit,
646                         mMaterial->matcolor[1]*mMaterial->emit,
647                         mMaterial->matcolor[2]*mMaterial->emit,
648                         1.0 );
649
650                 rasty->SetAmbient(mMaterial->amb);
651         }
652
653         if (mMaterial->material)
654                 rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
655 }
656
657
658 void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
659 {
660         if (ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED || 
661                 (ras->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !ras->GetUsingOverrideShader())) {
662                 ras->SetAttribNum(0);
663                 if (mShader && GLEW_ARB_shader_objects) {
664                         if (mShader->GetAttribute() == BL_Shader::SHD_TANGENT) {
665                                 ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0);
666                                 ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1);
667                                 ras->SetAttribNum(2);
668                         }
669                 }
670
671                 ras->SetTexCoordNum(mMaterial->num_enabled);
672
673                 for (int i=0; i<BL_Texture::GetMaxUnits(); i++) {
674                         int mode = mMaterial->mapping[i].mapping;
675
676                         if ( mode &(USEREFL|USEOBJ))
677                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i);
678                         else if (mode &USEORCO)
679                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
680                         else if (mode &USENORM)
681                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i);
682                         else if (mode &USEUV)
683                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV, i);
684                         else if (mode &USETANG)
685                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i);
686                         else 
687                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
688                 }
689         }
690 }
691
692 void KX_BlenderMaterial::setTexMatrixData(int i)
693 {
694         glMatrixMode(GL_TEXTURE);
695         glLoadIdentity();
696
697         if ( GLEW_ARB_texture_cube_map && 
698                 mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB && 
699                 mMaterial->mapping[i].mapping & USEREFL) {
700                 glScalef( 
701                         mMaterial->mapping[i].scale[0], 
702                         -mMaterial->mapping[i].scale[1], 
703                         -mMaterial->mapping[i].scale[2]
704                 );
705         }
706         else
707         {
708                 glScalef( 
709                         mMaterial->mapping[i].scale[0], 
710                         mMaterial->mapping[i].scale[1], 
711                         mMaterial->mapping[i].scale[2]
712                 );
713         }
714         glTranslatef(
715                 mMaterial->mapping[i].offsets[0],
716                 mMaterial->mapping[i].offsets[1], 
717                 mMaterial->mapping[i].offsets[2]
718         );
719
720         glMatrixMode(GL_MODELVIEW);
721
722 }
723
724 static void GetProjPlane(BL_Material *mat, int index,int num, float*param)
725 {
726         param[0]=param[1]=param[2]=param[3]=0.f;
727         if ( mat->mapping[index].projplane[num] == PROJX )
728                 param[0] = 1.f;
729         else if ( mat->mapping[index].projplane[num] == PROJY )
730                 param[1] = 1.f;
731         else if ( mat->mapping[index].projplane[num] == PROJZ)
732                 param[2] = 1.f;
733 }
734
735 void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
736 {
737         KX_GameObject *obj = 
738                 (KX_GameObject*)
739                 mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame);
740
741         if (!obj) return;
742
743         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
744         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
745         glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
746
747         GLenum plane = GL_EYE_PLANE;
748
749         // figure plane gen
750         float proj[4] = {0.f,0.f,0.f,0.f};
751         GetProjPlane(mMaterial, i, 0, proj);
752         glTexGenfv(GL_S, plane, proj);
753         
754         GetProjPlane(mMaterial, i, 1, proj);
755         glTexGenfv(GL_T, plane, proj);
756
757         GetProjPlane(mMaterial, i, 2, proj);
758         glTexGenfv(GL_R, plane, proj);
759
760         glEnable(GL_TEXTURE_GEN_S);
761         glEnable(GL_TEXTURE_GEN_T);
762         glEnable(GL_TEXTURE_GEN_R);
763
764         const MT_Matrix4x4& mvmat = ras->GetViewMatrix();
765
766         glMatrixMode(GL_TEXTURE);
767         glLoadIdentity();
768         glScalef( 
769                 mMaterial->mapping[i].scale[0], 
770                 mMaterial->mapping[i].scale[1], 
771                 mMaterial->mapping[i].scale[2]
772         );
773
774         MT_Point3 pos = obj->NodeGetWorldPosition();
775         MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f);
776         MT_Vector4 t = mvmat*matmul;
777
778         glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) );
779
780         glMatrixMode(GL_MODELVIEW);
781
782 }
783
784 // ------------------------------------
785 void KX_BlenderMaterial::UpdateIPO(
786         MT_Vector4 rgba,
787         MT_Vector3 specrgb,
788         MT_Scalar hard,
789         MT_Scalar spec,
790         MT_Scalar ref,
791         MT_Scalar emit,
792         MT_Scalar alpha
793         )
794 {
795         // only works one deep now
796         mMaterial->speccolor[0] = (float)(specrgb)[0];
797         mMaterial->speccolor[1] = (float)(specrgb)[1];
798         mMaterial->speccolor[2] = (float)(specrgb)[2];
799         mMaterial->matcolor[0]  = (float)(rgba[0]);
800         mMaterial->matcolor[1]  = (float)(rgba[1]);
801         mMaterial->matcolor[2]  = (float)(rgba[2]);
802         mMaterial->alpha                = (float)(alpha);
803         mMaterial->hard                 = (float)(hard);
804         mMaterial->emit                 = (float)(emit);
805         mMaterial->spec_f               = (float)(spec);
806         mMaterial->ref                  = (float)(ref);
807 }
808
809 void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val)
810 {
811         mScene= static_cast<KX_Scene *>(val);
812
813         OnConstruction();
814 }
815
816 void KX_BlenderMaterial::SetBlenderGLSLShader()
817 {
818         if (!mBlenderShader)
819                 mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, mLightLayer);
820
821         if (!mBlenderShader->Ok()) {
822                 delete mBlenderShader;
823                 mBlenderShader = 0;
824         }
825 }
826
827 #ifdef WITH_PYTHON
828
829 PyMethodDef KX_BlenderMaterial::Methods[] = 
830 {
831         KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
832         KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
833         KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
834         {NULL,NULL} //Sentinel
835 };
836
837 PyAttributeDef KX_BlenderMaterial::Attributes[] = {
838         KX_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader),
839         KX_PYATTRIBUTE_RO_FUNCTION("material_index", KX_BlenderMaterial, pyattr_get_materialIndex),
840         KX_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending),
841         { NULL }        //Sentinel
842 };
843
844 PyTypeObject KX_BlenderMaterial::Type = {
845         PyVarObject_HEAD_INIT(NULL, 0)
846         "KX_BlenderMaterial",
847         sizeof(PyObjectPlus_Proxy),
848         0,
849         py_base_dealloc,
850         0,
851         0,
852         0,
853         0,
854         py_base_repr,
855         0,0,0,0,0,0,0,0,0,
856         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
857         0,0,0,0,0,0,0,
858         Methods,
859         0,
860         0,
861         &PyObjectPlus::Type,
862         0,0,0,0,0,0,
863         py_base_new
864 };
865
866 PyObject *KX_BlenderMaterial::pyattr_get_shader(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
867 {
868         KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v);
869         return self->PygetShader(NULL, NULL);
870 }
871
872 PyObject *KX_BlenderMaterial::pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
873 {
874         KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v);
875         return PyLong_FromLong(self->GetMaterialIndex());
876 }
877
878 PyObject *KX_BlenderMaterial::pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
879 {
880         KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v);
881         unsigned int* bfunc = self->getBlendFunc();
882         return Py_BuildValue("(ll)", (long int)bfunc[0], (long int)bfunc[1]);
883 }
884
885 int KX_BlenderMaterial::pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
886 {
887         KX_BlenderMaterial* self = static_cast<KX_BlenderMaterial*>(self_v);
888         PyObject *obj = self->PysetBlending(value, NULL);
889         if (obj)
890         {
891                 Py_DECREF(obj);
892                 return 0;
893         }
894         return -1;
895 }
896
897 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
898 {
899         if ( !GLEW_ARB_fragment_shader) {
900                 if (!mModified)
901                         spit("Fragment shaders not supported");
902         
903                 mModified = true;
904                 Py_RETURN_NONE;
905         }
906
907         if ( !GLEW_ARB_vertex_shader) {
908                 if (!mModified)
909                         spit("Vertex shaders not supported");
910
911                 mModified = true;
912                 Py_RETURN_NONE;
913         }
914
915         if (!GLEW_ARB_shader_objects) {
916                 if (!mModified)
917                         spit("GLSL not supported");
918                 mModified = true;
919                 Py_RETURN_NONE;
920         }
921         else {
922                 // returns Py_None on error
923                 // the calling script will need to check
924
925                 if (!mShader && !mModified) {
926                         mShader = new BL_Shader();
927                         mModified = true;
928
929                         // Using a custom shader, make sure to initialize textures
930                         InitTextures();
931                 }
932
933                 if (mShader && !mShader->GetError()) {
934                         m_flag &= ~RAS_BLENDERGLSL;
935                         mMaterial->SetSharedMaterial(true);
936                         mScene->GetBucketManager()->ReleaseDisplayLists(this);
937                         return mShader->GetProxy();
938                 }
939                 else {
940                         // decref all references to the object
941                         // then delete it!
942                         // We will then go back to fixed functionality
943                         // for this material
944                         if (mShader) {
945                                 delete mShader; /* will handle python de-referencing */
946                                 mShader=0;
947                         }
948                 }
949                 Py_RETURN_NONE;
950         }
951         PyErr_SetString(PyExc_ValueError, "material.getShader(): KX_BlenderMaterial, GLSL Error");
952         return NULL;
953 }
954
955 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
956 {
957         return PyLong_FromLong(GetMaterialIndex());
958 }
959
960 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" )
961 {
962         // TODO: enable python switching
963         return NULL;
964 }
965
966 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)")
967 {
968         // TODO: enable python switching
969         return NULL;
970 }
971
972 static const unsigned int GL_array[11] = {
973         GL_ZERO,
974         GL_ONE,
975         GL_SRC_COLOR,
976         GL_ONE_MINUS_SRC_COLOR,
977         GL_DST_COLOR,
978         GL_ONE_MINUS_DST_COLOR,
979         GL_SRC_ALPHA,
980         GL_ONE_MINUS_SRC_ALPHA,
981         GL_DST_ALPHA,
982         GL_ONE_MINUS_DST_ALPHA,
983         GL_SRC_ALPHA_SATURATE
984 };
985
986 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( bge.logic.src, bge.logic.dest)")
987 {
988         unsigned int b[2];
989         if (PyArg_ParseTuple(args, "ii:setBlending", &b[0], &b[1]))
990         {
991                 bool value_found[2] = {false, false};
992                 for (int i=0; i<11; i++)
993                 {
994                         if (b[0] == GL_array[i]) {
995                                 value_found[0] = true;
996                                 mBlendFunc[0] = b[0];
997                         }
998                         if (b[1] == GL_array[i]) {
999                                 value_found[1] = true;
1000                                 mBlendFunc[1] = b[1];
1001                         }
1002                         if (value_found[0] && value_found[1]) break;
1003                 }
1004                 if (!value_found[0] || !value_found[1]) {
1005                         PyErr_SetString(PyExc_ValueError, "material.setBlending(int, int): KX_BlenderMaterial, invalid enum.");
1006                         return NULL;
1007                 }
1008                 mUserDefBlend = true;
1009                 Py_RETURN_NONE;
1010         }
1011         return NULL;
1012 }
1013
1014 #endif // WITH_PYTHON