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