Improved OpenGL Shader Language support for game engine. The python interface is...
[blender.git] / source / gameengine / Ketsji / KX_BlenderMaterial.cpp
1
2 // ------------------------------------
3 // ...
4 // ------------------------------------
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #ifdef WIN32
10 #include <windows.h>
11 #endif // WIN32
12 #ifdef __APPLE__
13 #define GL_GLEXT_LEGACY 1
14 #include <OpenGL/gl.h>
15 #include <OpenGL/glu.h>
16 #else
17 #include <GL/gl.h>
18 #include <GL/glu.h>
19 #endif
20
21 #include "KX_BlenderMaterial.h"
22 #include "BL_Material.h"
23 #include "KX_Scene.h"
24 #include "KX_Light.h"
25 #include "KX_GameObject.h"
26 #include "KX_MeshProxy.h"
27
28 #include "MT_Vector3.h"
29 #include "MT_Vector4.h"
30 #include "MT_Matrix4x4.h"
31
32 #include "RAS_MeshObject.h"
33 #include "RAS_IRasterizer.h"
34 #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
35 #include "RAS_OpenGLRasterizer/ARB_multitexture.h"
36
37 extern "C" {
38 #include "BDR_drawmesh.h"
39 }
40
41 #include "STR_HashedString.h"
42
43 // ------------------------------------
44 #include "DNA_object_types.h"
45 #include "DNA_material_types.h"
46 #include "DNA_image_types.h"
47 #include "DNA_mesh_types.h"
48 #include "BKE_mesh.h"
49 // ------------------------------------
50 using namespace bgl;
51 #define spit(x) std::cout << x << std::endl;
52
53 //static PyObject *gTextureDict = 0;
54
55 KX_BlenderMaterial::KX_BlenderMaterial(
56     KX_Scene *scene,
57         BL_Material *data,
58         bool skin,
59         int lightlayer,
60         void *clientobject,
61         PyTypeObject *T
62         )
63 :       PyObjectPlus(T),
64         RAS_IPolyMaterial(
65                 STR_String( data->texname[0] ),
66                 STR_String( data->matname ), // needed for physics!
67                 data->tile,
68                 data->tilexrep[0],
69                 data->tileyrep[0],
70                 data->mode,
71                 ((data->ras_mode &TRANSP)!=0),
72                 ((data->ras_mode &ZSORT)!=0),
73                 lightlayer,
74                 ((data->ras_mode &TRIANGLE)!=0),
75                 clientobject
76         ),
77         mMaterial(data),
78         mShader(0),
79         mScene(scene),
80         mUserDefBlend(0),
81         mModified(0),
82         mPass(0)
83
84 {
85         ///RAS_EXT_support._ARB_multitexture == true if were here
86
87         // --------------------------------
88         // RAS_IPolyMaterial variables... 
89         m_flag |=RAS_BLENDERMAT;
90         m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0;
91         m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0;
92         
93         // figure max
94         int enabled = mMaterial->num_enabled;
95         int max = BL_Texture::GetMaxUnits();
96         mMaterial->num_enabled = enabled>=max?max:enabled;
97
98         // base class
99         m_enabled = mMaterial->num_enabled;
100
101         // test the sum of the various modes for equality
102         // so we can ether accept or reject this material 
103         // as being equal, this is rather important to 
104         // prevent material bleeding
105         for(int i=0; i<mMaterial->num_enabled; i++) {
106                 m_multimode     +=
107                         ( mMaterial->flag[i]    +
108                           mMaterial->blend_mode[i]
109                          );
110         }
111         m_multimode += mMaterial->IdMode+mMaterial->ras_mode;
112
113 }
114
115 KX_BlenderMaterial::~KX_BlenderMaterial()
116 {
117         // cleanup work
118         OnExit();
119 }
120
121
122 TFace* KX_BlenderMaterial::GetTFace(void) const 
123 {
124         // fonts on polys
125         MT_assert(mMaterial->tface);
126         return mMaterial->tface;
127 }
128
129 void KX_BlenderMaterial::OnConstruction()
130 {
131         // for each unique material...
132         int i;
133         for(i=0; i<mMaterial->num_enabled; i++) {
134                 BL_Texture::ActivateUnit(i);
135                 if( mMaterial->mapping[i].mapping & USEENV ) {
136                         if(!RAS_EXT_support._ARB_texture_cube_map) {
137                                 spit("CubeMap textures not supported");
138                                 continue;
139                         }
140                         if(!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) )
141                                 spit("unable to initialize image("<<i<<") in "<< 
142                                                 mMaterial->matname<< ", image will not be available");
143                 } 
144         
145                 else {
146                         if( mMaterial->img[i] ) {
147                                 if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
148                                         spit("unable to initialize image("<<i<<") in "<< 
149                                                  mMaterial->matname<< ", image will not be available");
150                         }
151                 }
152         }
153         mBlendFunc[0] =0;
154         mBlendFunc[1] =0;
155 }
156
157 void KX_BlenderMaterial::OnExit()
158 {
159         if( mShader ) {
160                  //note, the shader here is allocated, per unique material
161                  //and this function is called per face
162                 mShader->SetProg(0);
163                 delete mShader;
164                 mShader = 0;
165         }
166
167         BL_Texture::ActivateFirst();
168         for(int i=0; i<mMaterial->num_enabled; i++) {
169                 BL_Texture::ActivateUnit(i);
170                 mTextures[i].DeleteTex();
171                 mTextures[i].DisableUnit();
172         }
173
174         if( mMaterial->tface ) 
175                 set_tpage(mMaterial->tface);
176 }
177
178
179 void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
180 {
181         MT_assert(RAS_EXT_support._ARB_shader_objects && mShader);
182
183         int i;
184         if( !enable || !mShader->Ok() ) {
185                 // frame cleanup.
186                 mShader->SetProg(false);
187                 BL_Texture::DisableAllTextures();
188                 return;
189         }
190
191         BL_Texture::DisableAllTextures();
192         mShader->SetProg(true);
193         
194         BL_Texture::ActivateFirst();
195
196         // for each enabled unit
197         for(i=0; i<mMaterial->num_enabled; i++) {
198                 const uSampler *samp = mShader->getSampler(i);
199                 BL_Texture *tex = samp->gl_texture;
200                 if( samp->loc == -1 || !tex || !tex->Ok() ) 
201                         continue;
202                 tex->ActivateTexture();
203                 mShader->SetSampler(samp->loc, i);
204         }
205         if(!mUserDefBlend) {
206                 setDefaultBlending();
207         }else
208         {
209                 // tested to be valid enums
210                 glEnable(GL_BLEND);
211                 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
212         }
213 }
214
215
216 void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
217 {
218         if(RAS_EXT_support._ARB_shader_objects && mShader) 
219                 mShader->SetProg(false);
220
221         BL_Texture::DisableAllTextures();
222         if( !enable )
223                 return;
224
225         BL_Texture::ActivateFirst();
226
227         if( mMaterial->IdMode == DEFAULT_BLENDER ) {
228                 setDefaultBlending();
229                 return;
230         }
231
232         if( mMaterial->IdMode == TEXFACE ) {
233                 // no material connected to the object
234                 if( mTextures[0].Ok() ) {
235                         mTextures[0].ActivateTexture();
236                         mTextures[0].setTexEnv(0, true);
237                         mTextures[0].SetMapping(mMaterial->mapping[0].mapping);
238                         setDefaultBlending(); 
239                 }
240                 return;
241         }
242
243         int mode = 0,i=0;
244         for(i=0; (i<mMaterial->num_enabled); i++) {
245                 if( !mTextures[i].Ok() ) continue;
246
247                 mTextures[i].ActivateTexture();
248                 mTextures[i].setTexEnv(mMaterial);
249                 mode = mMaterial->mapping[i].mapping;
250
251                 if(mode &USEOBJ)
252                         setObjectMatrixData(i, ras);
253                 else
254                         mTextures[i].SetMapping(mode);
255                 
256                 if(!(mode &USEOBJ))
257                         setTexMatrixData( i );
258         }
259
260         if(!mUserDefBlend) {
261                 setDefaultBlending();
262         }
263         else {
264                 glEnable(GL_BLEND);
265                 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
266         }
267 }
268
269 void
270 KX_BlenderMaterial::ActivatShaders(
271         RAS_IRasterizer* rasty, 
272         TCachingInfo& cachingInfo)const
273 {
274         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
275         
276         // reset... 
277         if(tmp->mMaterial->IsShared()) 
278                 cachingInfo =0;
279         
280         if (GetCachingInfo() != cachingInfo) {
281
282                 if (!cachingInfo)
283                         tmp->setShaderData( false, rasty);
284                 
285                 cachingInfo = GetCachingInfo();
286         
287                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED ) {
288                         tmp->setShaderData( true, rasty);
289                         rasty->EnableTextures(true);
290                 }
291                 else {
292                         tmp->setShaderData( false, rasty);
293                         rasty->EnableTextures(false);
294                 }
295
296                 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
297                         rasty->SetCullFace(false);
298                 else
299                         rasty->SetCullFace(true);
300
301                 if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
302                         rasty->SetLines(true);
303                 else
304                         rasty->SetLines(false);
305         }
306         
307         // shaders have access to the variables set here
308         // via builtin GLSL variables
309         // eg: gl_FrontMaterial.diffuse
310         // --
311         rasty->SetSpecularity(
312                 mMaterial->speccolor[0]*mMaterial->spec_f,
313                 mMaterial->speccolor[1]*mMaterial->spec_f,
314                 mMaterial->speccolor[2]*mMaterial->spec_f,
315                 mMaterial->spec_f
316         );
317
318         rasty->SetShinyness( mMaterial->hard );
319
320         rasty->SetDiffuse(
321                 mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, 
322                 mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
323                 mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
324                 1.0f);
325
326         rasty->SetEmissive(     
327                 mMaterial->matcolor[0]*mMaterial->emit,
328                 mMaterial->matcolor[1]*mMaterial->emit,
329                 mMaterial->matcolor[2]*mMaterial->emit,
330                 1.0
331                 );
332
333         rasty->SetAmbient(mMaterial->amb);
334
335         if (mMaterial->material)
336                 rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
337
338         tmp->applyTexGen(rasty);
339
340 }
341
342 void
343 KX_BlenderMaterial::ActivateMat( 
344         RAS_IRasterizer* rasty,  
345         TCachingInfo& cachingInfo
346         )const
347 {
348         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
349         if (GetCachingInfo() != cachingInfo) {
350                 if (!cachingInfo) 
351                         tmp->setTexData( false,rasty );
352                 
353                 cachingInfo = GetCachingInfo();
354
355                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
356                         tmp->setTexData( true,rasty  );
357                         rasty->EnableTextures(true);
358                 }
359                 else{
360                         tmp->setTexData( false,rasty);
361                         rasty->EnableTextures(false);
362                 }
363
364                 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
365                         rasty->SetCullFace(false);
366                 else
367                         rasty->SetCullFace(true);
368
369                 if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
370                         rasty->SetLines(true);
371                 else
372                         rasty->SetLines(false);
373         }
374                 
375         rasty->SetSpecularity(
376                 mMaterial->speccolor[0]*mMaterial->spec_f,
377                 mMaterial->speccolor[1]*mMaterial->spec_f,
378                 mMaterial->speccolor[2]*mMaterial->spec_f,
379                 mMaterial->spec_f
380         );
381
382         rasty->SetShinyness( mMaterial->hard );
383
384         rasty->SetDiffuse(
385                 mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, 
386                 mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
387                 mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
388                 1.0f);
389
390         rasty->SetEmissive(     
391                 mMaterial->matcolor[0]*mMaterial->emit,
392                 mMaterial->matcolor[1]*mMaterial->emit,
393                 mMaterial->matcolor[2]*mMaterial->emit,
394                 1.0
395                 );
396         rasty->SetAmbient(mMaterial->amb);
397         if (mMaterial->material)
398                 rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
399
400         tmp->applyTexGen(rasty);
401 }
402
403
404 bool 
405 KX_BlenderMaterial::Activate( 
406         RAS_IRasterizer* rasty,  
407         TCachingInfo& cachingInfo
408         )const
409 {
410         bool dopass = false;
411         if( RAS_EXT_support._ARB_shader_objects && ( mShader && mShader->Ok() ) ) {
412                 if( (mPass++) < mShader->getNumPass() ) {
413                         ActivatShaders(rasty, cachingInfo);
414                         dopass = true;
415                         return dopass;
416                 }
417                 else {
418                         mShader->SetProg(false);
419                         mPass = 0;
420                         dopass = false;
421                         return dopass;
422                 }
423         }
424         else {
425                 switch (mPass++)
426                 {
427                         case 0:
428                                 ActivateMat(rasty, cachingInfo);
429                                 dopass = true;
430                                 break;
431                         default:
432                                 mPass = 0;
433                                 dopass = false;
434                                 break;
435                 }
436         }
437         return dopass;
438 }
439
440 void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const
441 {
442         if(mShader && RAS_EXT_support._ARB_shader_objects)
443                 mShader->Update(ms, rasty);
444 }
445
446
447 bool KX_BlenderMaterial::setDefaultBlending()
448 {
449         if( mMaterial->transp &TF_ADD) {
450                 glEnable(GL_BLEND);
451                 glBlendFunc(GL_ONE, GL_ONE);
452                 return true;
453         }
454         
455         if( mMaterial->transp & TF_ALPHA ) {
456                 glEnable(GL_BLEND);
457                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
458                 return true;
459         }
460         
461         glDisable(GL_BLEND);
462         return false;
463 }
464
465 void KX_BlenderMaterial::setTexMatrixData(int i)
466 {
467         glMatrixMode(GL_TEXTURE);
468         glLoadIdentity();
469
470         glScalef( 
471                 mMaterial->mapping[i].scale[0], 
472                 mMaterial->mapping[i].scale[1], 
473                 mMaterial->mapping[i].scale[2]
474         );
475         glTranslatef(
476                 mMaterial->mapping[i].offsets[0],
477                 mMaterial->mapping[i].offsets[1], 
478                 mMaterial->mapping[i].offsets[2]
479         );
480
481         glMatrixMode(GL_MODELVIEW);
482
483 }
484
485 static void GetProjPlane(BL_Material *mat, int index,int num, float*param)
486 {
487         param[0]=param[1]=param[2]=param[3]=0.f;
488         if( mat->mapping[index].projplane[num] == PROJX )
489                 param[0] = 1.f;
490         else if( mat->mapping[index].projplane[num] == PROJY )
491                 param[1] = 1.f;
492         else if( mat->mapping[index].projplane[num] == PROJZ)
493                 param[2] = 1.f;
494 }
495
496 void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
497 {
498         KX_GameObject *obj = 
499                 (KX_GameObject*)
500                 mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame);
501
502         if(!obj) return;
503
504         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
505         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
506         glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
507
508         GLenum plane = GL_EYE_PLANE;
509
510         // figure plane gen
511         float proj[4]= {0.f,0.f,0.f,0.f};
512         GetProjPlane(mMaterial, i, 0, proj);
513         glTexGenfv(GL_S, plane, proj);
514         
515         GetProjPlane(mMaterial, i, 1, proj);
516         glTexGenfv(GL_T, plane, proj);
517
518         GetProjPlane(mMaterial, i, 2, proj);
519         glTexGenfv(GL_R, plane, proj);
520
521         glEnable(GL_TEXTURE_GEN_S);
522         glEnable(GL_TEXTURE_GEN_T);
523         glEnable(GL_TEXTURE_GEN_R);
524
525         MT_Matrix4x4 mvmat;
526         ras->GetViewMatrix(mvmat);
527
528         glMatrixMode(GL_TEXTURE);
529         glLoadIdentity();
530         glScalef( 
531                 mMaterial->mapping[i].scale[0], 
532                 mMaterial->mapping[i].scale[1], 
533                 mMaterial->mapping[i].scale[2]
534         );
535
536         MT_Point3 pos = obj->NodeGetWorldPosition();
537         MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f);
538         MT_Vector4 t = mvmat*matmul;
539
540         glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) );
541
542         glMatrixMode(GL_MODELVIEW);
543
544 }
545
546 void KX_BlenderMaterial::applyTexGen(RAS_IRasterizer *ras)
547 {
548         if(mShader && RAS_EXT_support._ARB_shader_objects)
549                 if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT)
550                         ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT);
551
552         for(int i=0; i<mMaterial->num_enabled; i++) {
553                 int mode = mMaterial->mapping[i].mapping;
554                 
555                 if( mode &(USEREFL|USEOBJ))
556                         ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_GEN, i);
557                 else if(mode &USEORCO)
558                         ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
559                 else if(mode &USENORM)
560                         ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_NORM, i);
561                 else if(mode &USEUV)
562                         ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_UV1, i);
563                 else 
564                         ras->SetTexCoords(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
565         }
566 }
567
568
569 // ------------------------------------
570 void KX_BlenderMaterial::UpdateIPO(
571         MT_Vector4 rgba,
572         MT_Vector3 specrgb,
573         MT_Scalar hard,
574         MT_Scalar spec,
575         MT_Scalar ref,
576         MT_Scalar emit,
577         MT_Scalar alpha
578         )
579 {
580         // only works one deep now
581         mMaterial->speccolor[0] = (float)(specrgb)[0];
582         mMaterial->speccolor[1] = (float)(specrgb)[1];
583         mMaterial->speccolor[2] = (float)(specrgb)[2];
584         mMaterial->matcolor[0]  = (float)(rgba[0]);
585         mMaterial->matcolor[1]  = (float)(rgba[1]);
586         mMaterial->matcolor[2]  = (float)(rgba[2]);
587         mMaterial->alpha                = (float)(alpha);
588         mMaterial->hard                 = (float)(hard);
589         mMaterial->emit                 = (float)(emit);
590         mMaterial->spec_f               = (float)(spec);
591 }
592
593
594 PyMethodDef KX_BlenderMaterial::Methods[] = 
595 {
596         KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
597         KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
598         KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
599         {NULL,NULL} //Sentinel
600 };
601
602
603 PyTypeObject KX_BlenderMaterial::Type = {
604         PyObject_HEAD_INIT(&PyType_Type)
605                 0,
606                 "KX_BlenderMaterial",
607                 sizeof(KX_BlenderMaterial),
608                 0,
609                 PyDestructor,
610                 0,
611                 __getattr,
612                 __setattr,
613                 0,
614                 __repr,
615                 0
616 };
617
618
619 PyParentObject KX_BlenderMaterial::Parents[] = {
620         &PyObjectPlus::Type,
621         &KX_BlenderMaterial::Type,
622         NULL
623 };
624
625
626 PyObject* KX_BlenderMaterial::_getattr(const STR_String& attr)
627 {
628         // nodda ?
629         _getattr_up(PyObjectPlus);
630 }
631
632 int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue)
633 {
634         return PyObjectPlus::_setattr(attr, pyvalue);
635 }
636
637
638 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
639 {
640 #ifdef GL_ARB_fragment_shader
641         if( !RAS_EXT_support._ARB_fragment_shader) {
642                 if(!mModified)
643                         spit("Fragment shaders not supported");
644         
645                 mModified = true;
646                 Py_Return;
647         }
648 #endif
649
650 #ifdef GL_ARB_vertex_shader
651         if( !RAS_EXT_support._ARB_vertex_shader) {
652                 if(!mModified)
653                         spit("Vertex shaders not supported");
654
655                 mModified = true;
656                 Py_Return;
657         }
658 #endif
659
660 #ifdef GL_ARB_shader_objects
661         if(!RAS_EXT_support._ARB_shader_objects)  {
662                 if(!mModified)
663                         spit("GLSL not supported");
664                 mModified = true;
665                 Py_Return;
666         }
667         else {
668                 // returns Py_None on error
669                 // the calling script will need to check
670
671                 if(!mShader && !mModified) {
672                         mShader = new BL_Shader();
673                         for(int i= 0; i<mMaterial->num_enabled; i++) {
674                                 if(mMaterial->mapping[i].mapping & USEENV )
675                                         mShader->InitializeSampler(SAMP_CUBE, i, 0, &mTextures[i]);
676                                 else
677                                         mShader->InitializeSampler(SAMP_2D, i, 0, &mTextures[i]);
678                         }
679                         mModified = true;
680                 }
681
682                 if(mShader && !mShader->GetError()) {
683                         mMaterial->SetSharedMaterial(true);
684                         Py_INCREF(mShader);
685                         return mShader;
686                 }else
687                 {
688                         // decref all references to the object
689                         // then delete it!
690                         // We will then go back to fixed functionality
691                         // for this material
692                         if(mShader) {
693                                 if(mShader->ob_refcnt > 1) {
694                                         Py_DECREF(mShader);
695                                 }
696                                 else {
697                                         delete mShader;
698                                         mShader=0;
699                                 }
700                         }
701                 }
702                 Py_Return;
703         }
704         PyErr_Format(PyExc_ValueError, "GLSL Error");
705         return NULL;
706
707 #else
708         Py_Return;
709 #endif//GL_ARB_shader_objects
710 }
711
712
713 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
714 {
715         return PyInt_FromLong( mMaterial->material_index );
716 }
717
718 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" )
719 {
720         // TODO: enable python switching
721         return NULL;
722 }
723
724 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)")
725 {
726         // TODO: enable python switching
727         return NULL;
728 }
729
730 static unsigned int GL_array[11] = {
731         GL_ZERO,
732         GL_ONE,
733         GL_SRC_COLOR,
734         GL_ONE_MINUS_SRC_COLOR,
735         GL_DST_COLOR,
736         GL_ONE_MINUS_DST_COLOR,
737         GL_SRC_ALPHA,
738         GL_ONE_MINUS_SRC_ALPHA,
739         GL_DST_ALPHA,
740         GL_ONE_MINUS_DST_ALPHA,
741         GL_SRC_ALPHA_SATURATE
742 };
743
744 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.src, GameLogic.dest)")
745 {
746         unsigned int b[2];
747         if(PyArg_ParseTuple(args, "ii", &b[0], &b[1]))
748         {
749                 bool value_found[2] = {false, false};
750                 for(int i=0; i<11; i++)
751                 {
752                         if(b[0] == GL_array[i]) {
753                                 value_found[0] = true;
754                                 mBlendFunc[0] = b[0];
755                         }
756                         if(b[1] == GL_array[i]) {
757                                 value_found[1] = true;
758                                 mBlendFunc[1] = b[1];
759                         }
760                         if(value_found[0] && value_found[1]) break;
761                 }
762                 if(!value_found[0] || !value_found[1]) {
763                         PyErr_Format(PyExc_ValueError, "invalid enum.");
764                         return NULL;
765                 }
766                 mUserDefBlend = true;
767                 Py_Return;
768         }
769         return NULL;
770 }
771