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