Py BGE API
[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_BucketManager.h"
23 #include "RAS_MeshObject.h"
24 #include "RAS_IRasterizer.h"
25 #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
26
27 #include "GPU_draw.h"
28
29 #include "STR_HashedString.h"
30
31 // ------------------------------------
32 #include "DNA_object_types.h"
33 #include "DNA_material_types.h"
34 #include "DNA_image_types.h"
35 #include "DNA_meshdata_types.h"
36 #include "BKE_mesh.h"
37 // ------------------------------------
38 #define spit(x) std::cout << x << std::endl;
39
40 BL_Shader *KX_BlenderMaterial::mLastShader = NULL;
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         PyTypeObject *T
51         )
52 :       PyObjectPlus(T),
53         RAS_IPolyMaterial(
54                 STR_String( data->texname[0] ),
55                 STR_String( data->matname ), // needed for physics!
56                 data->tile,
57                 data->tilexrep[0],
58                 data->tileyrep[0],
59                 data->mode,
60                 data->transp,
61                 ((data->ras_mode &ALPHA)!=0),
62                 ((data->ras_mode &ZSORT)!=0),
63                 lightlayer
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->glslmat)? RAS_BLENDERGLSL: 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 & ~(COLLIDER|USE_LIGHT));
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         // for each unique material...
133         int i;
134         for(i=0; i<mMaterial->num_enabled; i++) {
135                 if( mMaterial->mapping[i].mapping & USEENV ) {
136                         if(!GLEW_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
154         mBlendFunc[0] =0;
155         mBlendFunc[1] =0;
156         mConstructed = true;
157 }
158
159 void KX_BlenderMaterial::EndFrame()
160 {
161         if(mLastBlenderShader) {
162                 mLastBlenderShader->SetProg(false);
163                 mLastBlenderShader = NULL;
164         }
165
166         if(mLastShader) {
167                 mLastShader->SetProg(false);
168                 mLastShader = NULL;
169         }
170 }
171
172 void KX_BlenderMaterial::OnExit()
173 {
174         if( mShader ) {
175                 //note, the shader here is allocated, per unique material
176                 //and this function is called per face
177                 if(mShader == mLastShader) {
178                         mShader->SetProg(false);
179                         mLastShader = NULL;
180                 }
181
182                 delete mShader;
183                 mShader = 0;
184         }
185
186         if( mBlenderShader ) {
187                 if(mBlenderShader == mLastBlenderShader) {
188                         mBlenderShader->SetProg(false);
189                         mLastBlenderShader = NULL;
190                 }
191
192                 delete mBlenderShader;
193                 mBlenderShader = 0;
194         }
195
196         BL_Texture::ActivateFirst();
197         for(int i=0; i<mMaterial->num_enabled; i++) {
198                 BL_Texture::ActivateUnit(i);
199                 mTextures[i].DeleteTex();
200                 mTextures[i].DisableUnit();
201         }
202
203         if( mMaterial->tface ) 
204                 GPU_set_tpage(mMaterial->tface);
205 }
206
207
208 void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
209 {
210         MT_assert(GLEW_ARB_shader_objects && mShader);
211
212         int i;
213         if( !enable || !mShader->Ok() ) {
214                 // frame cleanup.
215                 if(mShader == mLastShader) {
216                         mShader->SetProg(false);
217                         mLastShader = NULL;
218                 }
219
220                 ras->SetBlendingMode(TF_SOLID);
221                 BL_Texture::DisableAllTextures();
222                 return;
223         }
224
225         BL_Texture::DisableAllTextures();
226         mShader->SetProg(true);
227         mLastShader = mShader;
228         
229         BL_Texture::ActivateFirst();
230
231         mShader->ApplyShader();
232
233         // for each enabled unit
234         for(i=0; i<mMaterial->num_enabled; i++) {
235                 if(!mTextures[i].Ok()) continue;
236                 mTextures[i].ActivateTexture();
237                 mTextures[0].SetMapping(mMaterial->mapping[i].mapping);
238         }
239
240         if(!mUserDefBlend) {
241                 ras->SetBlendingMode(mMaterial->transp);
242         }
243         else {
244                 ras->SetBlendingMode(TF_SOLID);
245                 ras->SetBlendingMode(-1); // indicates custom mode
246
247                 // tested to be valid enums
248                 glEnable(GL_BLEND);
249                 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
250         }
251 }
252
253 void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras)
254 {
255         if( !enable || !mBlenderShader->Ok() ) {
256                 ras->SetBlendingMode(TF_SOLID);
257
258                 // frame cleanup.
259                 if(mLastBlenderShader) {
260                         mLastBlenderShader->SetProg(false);
261                         mLastBlenderShader= NULL;
262                 }
263                 else
264                         BL_Texture::DisableAllTextures();
265
266                 return;
267         }
268
269         if(!mBlenderShader->Equals(mLastBlenderShader)) {
270                 ras->SetBlendingMode(mMaterial->transp);
271
272                 if(mLastBlenderShader)
273                         mLastBlenderShader->SetProg(false);
274                 else
275                         BL_Texture::DisableAllTextures();
276
277                 mBlenderShader->SetProg(true, ras->GetTime());
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                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
373                 {               
374                         if((mMaterial->ras_mode &WIRE)!=0) 
375                                 rasty->SetCullFace(false);
376                         rasty->SetLines(true);
377                 }
378                 else
379                         rasty->SetLines(false);
380         }
381
382         ActivatGLMaterials(rasty);
383         ActivateTexGen(rasty);
384 }
385
386 void
387 KX_BlenderMaterial::ActivateBlenderShaders(
388         RAS_IRasterizer* rasty, 
389         TCachingInfo& cachingInfo)const
390 {
391         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
392
393         if(mLastShader) {
394                 mLastShader->SetProg(false);
395                 mLastShader= NULL;
396         }
397
398         if (GetCachingInfo() != cachingInfo) {
399                 if (!cachingInfo)
400                         tmp->setBlenderShaderData(false, rasty);
401                 
402                 cachingInfo = GetCachingInfo();
403         
404                 if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
405                         tmp->setBlenderShaderData(true, rasty);
406                 else
407                         tmp->setBlenderShaderData(false, rasty);
408
409                 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
410                         rasty->SetCullFace(false);
411                 else
412                         rasty->SetCullFace(true);
413
414                 if (((mMaterial->ras_mode & WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
415                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
416                 {               
417                         if((mMaterial->ras_mode &WIRE)!=0) 
418                                 rasty->SetCullFace(false);
419                         rasty->SetLines(true);
420                 }
421                 else
422                         rasty->SetLines(false);
423
424                 ActivatGLMaterials(rasty);
425                 mBlenderShader->SetAttribs(rasty, mMaterial);
426         }
427 }
428
429 void
430 KX_BlenderMaterial::ActivateMat( 
431         RAS_IRasterizer* rasty,  
432         TCachingInfo& cachingInfo
433         )const
434 {
435         KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
436
437         if(mLastShader) {
438                 mLastShader->SetProg(false);
439                 mLastShader= NULL;
440         }
441
442         if(mLastBlenderShader) {
443                 mLastBlenderShader->SetProg(false);
444                 mLastBlenderShader= NULL;
445         }
446
447         if (GetCachingInfo() != cachingInfo) {
448                 if (!cachingInfo) 
449                         tmp->setTexData( false,rasty );
450                 
451                 cachingInfo = GetCachingInfo();
452
453                 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
454                         tmp->setTexData( true,rasty  );
455                 else
456                         tmp->setTexData( false,rasty);
457
458                 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
459                         rasty->SetCullFace(false);
460                 else
461                         rasty->SetCullFace(true);
462
463                 if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
464                     (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
465                 {               
466                         if((mMaterial->ras_mode &WIRE)!=0) 
467                                 rasty->SetCullFace(false);
468                         rasty->SetLines(true);
469                 }
470                 else
471                         rasty->SetLines(false);
472         }
473
474         ActivatGLMaterials(rasty);
475         ActivateTexGen(rasty);
476 }
477
478 bool 
479 KX_BlenderMaterial::Activate( 
480         RAS_IRasterizer* rasty,  
481         TCachingInfo& cachingInfo
482         )const
483 {
484         if(GLEW_ARB_shader_objects && (mShader && mShader->Ok())) {
485                 if((mPass++) < mShader->getNumPass() ) {
486                         ActivatShaders(rasty, cachingInfo);
487                         return true;
488                 }
489                 else {
490                         if(mShader == mLastShader) {
491                                 mShader->SetProg(false);
492                                 mLastShader = NULL;
493                         }
494                         mPass = 0;
495                         return false;
496                 }
497         }
498         else if( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) {
499                 if(mPass++ == 0) {
500                         ActivateBlenderShaders(rasty, cachingInfo);
501                         return true;
502                 }
503                 else {
504                         mPass = 0;
505                         return false;
506                 }
507         }
508         else {
509                 if(mPass++ == 0) {
510                         ActivateMat(rasty, cachingInfo);
511                         return true;
512                 }
513                 else {
514                         mPass = 0;
515                         return false;
516                 }
517         }
518 }
519
520 bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const
521 {
522         if(!RAS_IPolyMaterial::UsesLighting(rasty))
523                 return false;
524
525         if(mShader && mShader->Ok())
526                 return true;
527         else if(mBlenderShader && mBlenderShader->Ok())
528                 return false;
529         else
530                 return true;
531 }
532
533 void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const
534 {
535         if(mShader && GLEW_ARB_shader_objects) {
536                 mShader->Update(ms, rasty);
537         }
538         else if(mBlenderShader && GLEW_ARB_shader_objects) {
539                 int blendmode;
540
541                 mBlenderShader->Update(ms, rasty);
542
543                 /* we do blend modes here, because they can change per object
544                  * with the same material due to obcolor/obalpha */
545                 blendmode = mBlenderShader->GetBlendMode();
546                 if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID)
547                         blendmode = mMaterial->transp;
548
549                 rasty->SetBlendingMode(blendmode);
550         }
551 }
552
553 void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
554 {
555         if(mShader || !mBlenderShader) {
556                 rasty->SetSpecularity(
557                         mMaterial->speccolor[0]*mMaterial->spec_f,
558                         mMaterial->speccolor[1]*mMaterial->spec_f,
559                         mMaterial->speccolor[2]*mMaterial->spec_f,
560                         mMaterial->spec_f
561                 );
562
563                 rasty->SetShinyness( mMaterial->hard );
564
565                 rasty->SetDiffuse(
566                         mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, 
567                         mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
568                         mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
569                         1.0f);
570
571                 rasty->SetEmissive(     
572                         mMaterial->matcolor[0]*mMaterial->emit,
573                         mMaterial->matcolor[1]*mMaterial->emit,
574                         mMaterial->matcolor[2]*mMaterial->emit,
575                         1.0 );
576
577                 rasty->SetAmbient(mMaterial->amb);
578         }
579
580         if (mMaterial->material)
581                 rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
582 }
583
584
585 void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
586 {
587         if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
588                 ras->SetAttribNum(0);
589                 if(mShader && GLEW_ARB_shader_objects) {
590                         if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT) {
591                                 ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0);
592                                 ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1);
593                                 ras->SetAttribNum(2);
594                         }
595                 }
596
597                 ras->SetTexCoordNum(mMaterial->num_enabled);
598
599                 for(int i=0; i<mMaterial->num_enabled; i++) {
600                         int mode = mMaterial->mapping[i].mapping;
601
602                         if (mode &USECUSTOMUV)
603                         {
604                                 STR_String str = mMaterial->mapping[i].uvCoName;
605                                 if (!str.IsEmpty())
606                                         ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i);
607                                 continue;
608                         }
609
610                         if( mode &(USEREFL|USEOBJ))
611                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i);
612                         else if(mode &USEORCO)
613                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
614                         else if(mode &USENORM)
615                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i);
616                         else if(mode &USEUV)
617                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV1, i);
618                         else if(mode &USETANG)
619                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i);
620                         else 
621                                 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
622                 }
623         }
624 }
625
626 void KX_BlenderMaterial::setTexMatrixData(int i)
627 {
628         glMatrixMode(GL_TEXTURE);
629         glLoadIdentity();
630
631         if( GLEW_ARB_texture_cube_map && 
632                 mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB && 
633                 mMaterial->mapping[i].mapping & USEREFL) {
634                 glScalef( 
635                         mMaterial->mapping[i].scale[0], 
636                         -mMaterial->mapping[i].scale[1], 
637                         -mMaterial->mapping[i].scale[2]
638                 );
639         }
640         else
641         {
642                 glScalef( 
643                         mMaterial->mapping[i].scale[0], 
644                         mMaterial->mapping[i].scale[1], 
645                         mMaterial->mapping[i].scale[2]
646                 );
647         }
648         glTranslatef(
649                 mMaterial->mapping[i].offsets[0],
650                 mMaterial->mapping[i].offsets[1], 
651                 mMaterial->mapping[i].offsets[2]
652         );
653
654         glMatrixMode(GL_MODELVIEW);
655
656 }
657
658 static void GetProjPlane(BL_Material *mat, int index,int num, float*param)
659 {
660         param[0]=param[1]=param[2]=param[3]=0.f;
661         if( mat->mapping[index].projplane[num] == PROJX )
662                 param[0] = 1.f;
663         else if( mat->mapping[index].projplane[num] == PROJY )
664                 param[1] = 1.f;
665         else if( mat->mapping[index].projplane[num] == PROJZ)
666                 param[2] = 1.f;
667 }
668
669 void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
670 {
671         KX_GameObject *obj = 
672                 (KX_GameObject*)
673                 mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame);
674
675         if(!obj) return;
676
677         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
678         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
679         glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
680
681         GLenum plane = GL_EYE_PLANE;
682
683         // figure plane gen
684         float proj[4]= {0.f,0.f,0.f,0.f};
685         GetProjPlane(mMaterial, i, 0, proj);
686         glTexGenfv(GL_S, plane, proj);
687         
688         GetProjPlane(mMaterial, i, 1, proj);
689         glTexGenfv(GL_T, plane, proj);
690
691         GetProjPlane(mMaterial, i, 2, proj);
692         glTexGenfv(GL_R, plane, proj);
693
694         glEnable(GL_TEXTURE_GEN_S);
695         glEnable(GL_TEXTURE_GEN_T);
696         glEnable(GL_TEXTURE_GEN_R);
697
698         const MT_Matrix4x4& mvmat = ras->GetViewMatrix();
699
700         glMatrixMode(GL_TEXTURE);
701         glLoadIdentity();
702         glScalef( 
703                 mMaterial->mapping[i].scale[0], 
704                 mMaterial->mapping[i].scale[1], 
705                 mMaterial->mapping[i].scale[2]
706         );
707
708         MT_Point3 pos = obj->NodeGetWorldPosition();
709         MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f);
710         MT_Vector4 t = mvmat*matmul;
711
712         glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) );
713
714         glMatrixMode(GL_MODELVIEW);
715
716 }
717
718 // ------------------------------------
719 void KX_BlenderMaterial::UpdateIPO(
720         MT_Vector4 rgba,
721         MT_Vector3 specrgb,
722         MT_Scalar hard,
723         MT_Scalar spec,
724         MT_Scalar ref,
725         MT_Scalar emit,
726         MT_Scalar alpha
727         )
728 {
729         // only works one deep now
730         mMaterial->speccolor[0] = (float)(specrgb)[0];
731         mMaterial->speccolor[1] = (float)(specrgb)[1];
732         mMaterial->speccolor[2] = (float)(specrgb)[2];
733         mMaterial->matcolor[0]  = (float)(rgba[0]);
734         mMaterial->matcolor[1]  = (float)(rgba[1]);
735         mMaterial->matcolor[2]  = (float)(rgba[2]);
736         mMaterial->alpha                = (float)(alpha);
737         mMaterial->hard                 = (float)(hard);
738         mMaterial->emit                 = (float)(emit);
739         mMaterial->spec_f               = (float)(spec);
740 }
741
742
743 PyMethodDef KX_BlenderMaterial::Methods[] = 
744 {
745         KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
746         KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
747         KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
748         {NULL,NULL} //Sentinel
749 };
750
751 PyAttributeDef KX_BlenderMaterial::Attributes[] = {
752         { NULL }        //Sentinel
753 };
754
755 PyTypeObject KX_BlenderMaterial::Type = {
756         PyObject_HEAD_INIT(&PyType_Type)
757                 0,
758                 "KX_BlenderMaterial",
759                 sizeof(KX_BlenderMaterial),
760                 0,
761                 PyDestructor,
762                 0,
763                 __getattr,
764                 __setattr,
765                 0,
766                 __repr,
767                 0
768 };
769
770
771 PyParentObject KX_BlenderMaterial::Parents[] = {
772         &PyObjectPlus::Type,
773         &KX_BlenderMaterial::Type,
774         NULL
775 };
776
777
778 PyObject* KX_BlenderMaterial::_getattr(const char *attr)
779 {
780         _getattr_up(PyObjectPlus);
781 }
782
783 int KX_BlenderMaterial::_setattr(const char *attr, PyObject *pyvalue)
784 {
785         return PyObjectPlus::_setattr(attr, pyvalue);
786 }
787
788
789 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
790 {
791         if( !GLEW_ARB_fragment_shader) {
792                 if(!mModified)
793                         spit("Fragment shaders not supported");
794         
795                 mModified = true;
796                 Py_RETURN_NONE;
797         }
798
799         if( !GLEW_ARB_vertex_shader) {
800                 if(!mModified)
801                         spit("Vertex shaders not supported");
802
803                 mModified = true;
804                 Py_RETURN_NONE;
805         }
806
807         if(!GLEW_ARB_shader_objects)  {
808                 if(!mModified)
809                         spit("GLSL not supported");
810                 mModified = true;
811                 Py_RETURN_NONE;
812         }
813         else {
814                 // returns Py_None on error
815                 // the calling script will need to check
816
817                 if(!mShader && !mModified) {
818                         mShader = new BL_Shader();
819                         mModified = true;
820                 }
821
822                 if(mShader && !mShader->GetError()) {
823                         m_flag &= ~RAS_BLENDERGLSL;
824                         mMaterial->SetSharedMaterial(true);
825                         mScene->GetBucketManager()->ReleaseDisplayLists(this);
826                         Py_INCREF(mShader);
827                         return mShader;
828                 }else
829                 {
830                         // decref all references to the object
831                         // then delete it!
832                         // We will then go back to fixed functionality
833                         // for this material
834                         if(mShader) {
835                                 if(mShader->ob_refcnt > 1) {
836                                         Py_DECREF(mShader);
837                                 }
838                                 else {
839                                         delete mShader;
840                                         mShader=0;
841                                 }
842                         }
843                 }
844                 Py_RETURN_NONE;
845         }
846         PyErr_Format(PyExc_ValueError, "GLSL Error");
847         return NULL;
848 }
849
850
851 void KX_BlenderMaterial::SetBlenderGLSLShader(void)
852 {
853         if(!mBlenderShader)
854                 mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer);
855
856         if(!mBlenderShader->Ok()) {
857                 delete mBlenderShader;
858                 mBlenderShader = 0;
859         }
860 }
861
862 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
863 {
864         return PyInt_FromLong( mMaterial->material_index );
865 }
866
867 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" )
868 {
869         // TODO: enable python switching
870         return NULL;
871 }
872
873 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)")
874 {
875         // TODO: enable python switching
876         return NULL;
877 }
878
879 static unsigned int GL_array[11] = {
880         GL_ZERO,
881         GL_ONE,
882         GL_SRC_COLOR,
883         GL_ONE_MINUS_SRC_COLOR,
884         GL_DST_COLOR,
885         GL_ONE_MINUS_DST_COLOR,
886         GL_SRC_ALPHA,
887         GL_ONE_MINUS_SRC_ALPHA,
888         GL_DST_ALPHA,
889         GL_ONE_MINUS_DST_ALPHA,
890         GL_SRC_ALPHA_SATURATE
891 };
892
893 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.src, GameLogic.dest)")
894 {
895         unsigned int b[2];
896         if(PyArg_ParseTuple(args, "ii", &b[0], &b[1]))
897         {
898                 bool value_found[2] = {false, false};
899                 for(int i=0; i<11; i++)
900                 {
901                         if(b[0] == GL_array[i]) {
902                                 value_found[0] = true;
903                                 mBlendFunc[0] = b[0];
904                         }
905                         if(b[1] == GL_array[i]) {
906                                 value_found[1] = true;
907                                 mBlendFunc[1] = b[1];
908                         }
909                         if(value_found[0] && value_found[1]) break;
910                 }
911                 if(!value_found[0] || !value_found[1]) {
912                         PyErr_Format(PyExc_ValueError, "invalid enum.");
913                         return NULL;
914                 }
915                 mUserDefBlend = true;
916                 Py_RETURN_NONE;
917         }
918         return NULL;
919 }
920