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