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