2 // ------------------------------------
4 // ------------------------------------
11 #include "KX_BlenderMaterial.h"
12 #include "BL_Material.h"
15 #include "KX_GameObject.h"
16 #include "KX_MeshProxy.h"
18 #include "MT_Vector3.h"
19 #include "MT_Vector4.h"
20 #include "MT_Matrix4x4.h"
22 #include "RAS_MeshObject.h"
23 #include "RAS_IRasterizer.h"
24 #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
27 #include "BDR_drawmesh.h"
30 #include "STR_HashedString.h"
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"
38 // ------------------------------------
39 #define spit(x) std::cout << x << std::endl;
41 BL_Shader *KX_BlenderMaterial::mLastShader = NULL;
42 BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL;
44 //static PyObject *gTextureDict = 0;
46 KX_BlenderMaterial::KX_BlenderMaterial(
56 STR_String( data->texname[0] ),
57 STR_String( data->matname ), // needed for physics!
63 ((data->ras_mode &ALPHA)!=0),
64 ((data->ras_mode &ZSORT)!=0),
66 ((data->ras_mode &TRIANGLE)!=0),
79 // --------------------------------
80 // RAS_IPolyMaterial variables...
81 m_flag |=RAS_BLENDERMAT;
82 m_flag |=(mMaterial->IdMode>=ONETEX)?RAS_MULTITEX:0;
83 m_flag |=(mMaterial->ras_mode & USE_LIGHT)!=0?RAS_MULTILIGHT:0;
86 int enabled = mMaterial->num_enabled;
87 int max = BL_Texture::GetMaxUnits();
88 mMaterial->num_enabled = enabled>=max?max:enabled;
90 // test the sum of the various modes for equality
91 // so we can ether accept or reject this material
92 // as being equal, this is rather important to
93 // prevent material bleeding
94 for(int i=0; i<mMaterial->num_enabled; i++) {
96 ( mMaterial->flag[i] +
97 mMaterial->blend_mode[i]
100 m_multimode += mMaterial->IdMode+mMaterial->ras_mode;
104 KX_BlenderMaterial::~KX_BlenderMaterial()
108 // clean only if material was actually used
113 MTFace* KX_BlenderMaterial::GetMTFace(void) const
116 MT_assert(mMaterial->tface);
117 return mMaterial->tface;
120 unsigned int* KX_BlenderMaterial::GetMCol(void) const
123 return mMaterial->rgb;
126 void KX_BlenderMaterial::OnConstruction()
129 // when material are reused between objects
132 if(mMaterial->glslmat)
133 SetBlenderGLSLShader();
135 // for each unique material...
137 for(i=0; i<mMaterial->num_enabled; i++) {
138 if( mMaterial->mapping[i].mapping & USEENV ) {
139 if(!GLEW_ARB_texture_cube_map) {
140 spit("CubeMap textures not supported");
143 if(!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) )
144 spit("unable to initialize image("<<i<<") in "<<
145 mMaterial->matname<< ", image will not be available");
149 if( mMaterial->img[i] ) {
150 if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
151 spit("unable to initialize image("<<i<<") in "<<
152 mMaterial->matname<< ", image will not be available");
162 void KX_BlenderMaterial::EndFrame()
164 if(mLastBlenderShader) {
165 mLastBlenderShader->SetProg(false);
166 mLastBlenderShader = NULL;
170 mLastShader->SetProg(false);
175 void KX_BlenderMaterial::OnExit()
178 //note, the shader here is allocated, per unique material
179 //and this function is called per face
180 if(mShader == mLastShader) {
181 mShader->SetProg(false);
189 if( mBlenderShader ) {
190 if(mBlenderShader == mLastBlenderShader) {
191 mBlenderShader->SetProg(false);
192 mLastBlenderShader = NULL;
195 delete mBlenderShader;
199 BL_Texture::ActivateFirst();
200 for(int i=0; i<mMaterial->num_enabled; i++) {
201 BL_Texture::ActivateUnit(i);
202 mTextures[i].DeleteTex();
203 mTextures[i].DisableUnit();
206 if( mMaterial->tface )
207 set_tpage(mMaterial->tface);
211 void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras)
213 MT_assert(GLEW_ARB_shader_objects && mShader);
216 if( !enable || !mShader->Ok() ) {
218 if(mShader == mLastShader) {
219 mShader->SetProg(false);
223 ras->SetBlendingMode(TF_SOLID);
224 BL_Texture::DisableAllTextures();
228 BL_Texture::DisableAllTextures();
229 mShader->SetProg(true);
230 mLastShader = mShader;
232 BL_Texture::ActivateFirst();
234 mShader->ApplyShader();
236 // for each enabled unit
237 for(i=0; i<mMaterial->num_enabled; i++) {
238 if(!mTextures[i].Ok()) continue;
239 mTextures[i].ActivateTexture();
240 mTextures[0].SetMapping(mMaterial->mapping[i].mapping);
244 ras->SetBlendingMode(mMaterial->transp);
247 ras->SetBlendingMode(TF_SOLID);
248 ras->SetBlendingMode(-1); // indicates custom mode
250 // tested to be valid enums
252 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
256 void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras)
258 if( !enable || !mBlenderShader->Ok() ) {
260 if(mLastBlenderShader) {
261 mLastBlenderShader->SetProg(false);
262 mLastBlenderShader= NULL;
265 ras->SetBlendingMode(TF_SOLID);
266 BL_Texture::DisableAllTextures();
270 if(!mBlenderShader->Equals(mLastBlenderShader)) {
271 ras->SetBlendingMode(mMaterial->transp);
272 BL_Texture::DisableAllTextures();
274 if(mLastBlenderShader)
275 mLastBlenderShader->SetProg(false);
277 mBlenderShader->SetProg(true);
278 mLastBlenderShader= mBlenderShader;
282 void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
284 BL_Texture::DisableAllTextures();
287 ras->SetBlendingMode(TF_SOLID);
291 BL_Texture::ActivateFirst();
293 if( mMaterial->IdMode == DEFAULT_BLENDER ) {
294 ras->SetBlendingMode(mMaterial->transp);
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);
310 for(i=0; (i<mMaterial->num_enabled && i<MAXTEX); i++) {
311 if( !mTextures[i].Ok() ) continue;
313 mTextures[i].ActivateTexture();
314 mTextures[i].setTexEnv(mMaterial);
315 mode = mMaterial->mapping[i].mapping;
318 setObjectMatrixData(i, ras);
320 mTextures[i].SetMapping(mode);
323 setTexMatrixData( i );
327 ras->SetBlendingMode(mMaterial->transp);
330 ras->SetBlendingMode(TF_SOLID);
331 ras->SetBlendingMode(-1); // indicates custom mode
334 glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
339 KX_BlenderMaterial::ActivatShaders(
340 RAS_IRasterizer* rasty,
341 TCachingInfo& cachingInfo)const
343 KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
346 if(tmp->mMaterial->IsShared())
349 if(mLastBlenderShader) {
350 mLastBlenderShader->SetProg(false);
351 mLastBlenderShader= NULL;
354 if (GetCachingInfo() != cachingInfo) {
357 tmp->setShaderData( false, rasty);
359 cachingInfo = GetCachingInfo();
361 if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
362 tmp->setShaderData( true, rasty);
364 tmp->setShaderData( false, rasty);
366 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
367 rasty->SetCullFace(false);
369 rasty->SetCullFace(true);
371 if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
373 if((mMaterial->ras_mode &WIRE)!=0)
374 rasty->SetCullFace(false);
375 rasty->SetLines(true);
378 rasty->SetLines(false);
381 ActivatGLMaterials(rasty);
382 ActivateTexGen(rasty);
386 KX_BlenderMaterial::ActivateBlenderShaders(
387 RAS_IRasterizer* rasty,
388 TCachingInfo& cachingInfo)const
390 KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
393 mLastShader->SetProg(false);
398 if(tmp->mMaterial->IsShared())
401 if (GetCachingInfo() != cachingInfo) {
403 tmp->setBlenderShaderData(false, rasty);
405 cachingInfo = GetCachingInfo();
407 if(rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
408 tmp->setBlenderShaderData(true, rasty);
409 rasty->EnableTextures(true);
412 tmp->setBlenderShaderData(false, rasty);
413 rasty->EnableTextures(false);
416 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
417 rasty->SetCullFace(false);
419 rasty->SetCullFace(true);
421 if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
423 if((mMaterial->ras_mode &WIRE)!=0)
424 rasty->SetCullFace(false);
425 rasty->SetLines(true);
428 rasty->SetLines(false);
431 ActivatGLMaterials(rasty);
432 mBlenderShader->SetAttribs(rasty, mMaterial);
436 KX_BlenderMaterial::ActivateMat(
437 RAS_IRasterizer* rasty,
438 TCachingInfo& cachingInfo
441 KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
444 mLastShader->SetProg(false);
448 if(mLastBlenderShader) {
449 mLastBlenderShader->SetProg(false);
450 mLastBlenderShader= NULL;
453 if (GetCachingInfo() != cachingInfo) {
455 tmp->setTexData( false,rasty );
457 cachingInfo = GetCachingInfo();
459 if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED)
460 tmp->setTexData( true,rasty );
462 tmp->setTexData( false,rasty);
464 if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
465 rasty->SetCullFace(false);
467 rasty->SetCullFace(true);
469 if (((mMaterial->ras_mode &WIRE)!=0) || mMaterial->mode & RAS_IRasterizer::KX_LINES)
471 if((mMaterial->ras_mode &WIRE)!=0)
472 rasty->SetCullFace(false);
473 rasty->SetLines(true);
476 rasty->SetLines(false);
479 ActivatGLMaterials(rasty);
480 ActivateTexGen(rasty);
484 KX_BlenderMaterial::Activate(
485 RAS_IRasterizer* rasty,
486 TCachingInfo& cachingInfo
490 if( GLEW_ARB_shader_objects && ( mShader && mShader->Ok() ) ) {
491 if( (mPass++) < mShader->getNumPass() ) {
492 ActivatShaders(rasty, cachingInfo);
497 if(mShader == mLastShader) {
498 mShader->SetProg(false);
506 else if( GLEW_ARB_shader_objects && ( mBlenderShader && mBlenderShader->Ok() ) ) {
507 if( (mPass++) == 0 ) {
508 ActivateBlenderShaders(rasty, cachingInfo);
522 ActivateMat(rasty, cachingInfo);
534 bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const
536 if(!RAS_IPolyMaterial::UsesLighting(rasty))
539 if(mShader && mShader->Ok());
540 else if(mBlenderShader && mBlenderShader->Ok())
546 void KX_BlenderMaterial::ActivateMeshSlot(const KX_MeshSlot & ms, RAS_IRasterizer* rasty) const
548 if(mShader && GLEW_ARB_shader_objects) {
549 mShader->Update(ms, rasty);
551 else if(mBlenderShader && GLEW_ARB_shader_objects) {
554 mBlenderShader->Update(ms, rasty);
556 /* we do blend modes here, because they can change per object
557 * with the same material due to obcolor */
558 blendmode = mBlenderShader->GetBlendMode();
559 if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID)
560 blendmode = mMaterial->transp;
562 rasty->SetBlendingMode(blendmode);
566 void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
568 if(mShader || !mBlenderShader) {
569 rasty->SetSpecularity(
570 mMaterial->speccolor[0]*mMaterial->spec_f,
571 mMaterial->speccolor[1]*mMaterial->spec_f,
572 mMaterial->speccolor[2]*mMaterial->spec_f,
576 rasty->SetShinyness( mMaterial->hard );
579 mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit,
580 mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
581 mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
585 mMaterial->matcolor[0]*mMaterial->emit,
586 mMaterial->matcolor[1]*mMaterial->emit,
587 mMaterial->matcolor[2]*mMaterial->emit,
590 rasty->SetAmbient(mMaterial->amb);
593 if (mMaterial->material)
594 rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
598 void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
600 if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
601 ras->SetAttribNum(0);
602 if(mShader && GLEW_ARB_shader_objects) {
603 if(mShader->GetAttribute() == BL_Shader::SHD_TANGENT) {
604 ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0);
605 ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1);
606 ras->SetAttribNum(2);
610 ras->SetTexCoordNum(mMaterial->num_enabled);
612 for(int i=0; i<mMaterial->num_enabled; i++) {
613 int mode = mMaterial->mapping[i].mapping;
615 if (mode &USECUSTOMUV)
617 STR_String str = mMaterial->mapping[i].uvCoName;
619 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i);
623 if( mode &(USEREFL|USEOBJ))
624 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i);
625 else if(mode &USEORCO)
626 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i);
627 else if(mode &USENORM)
628 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i);
630 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV1, i);
631 else if(mode &USETANG)
632 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i);
634 ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i);
637 ras->EnableTextures(true);
640 ras->EnableTextures(false);
643 void KX_BlenderMaterial::setTexMatrixData(int i)
645 glMatrixMode(GL_TEXTURE);
648 if( GLEW_ARB_texture_cube_map &&
649 mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB &&
650 mMaterial->mapping[i].mapping & USEREFL) {
652 mMaterial->mapping[i].scale[0],
653 -mMaterial->mapping[i].scale[1],
654 -mMaterial->mapping[i].scale[2]
660 mMaterial->mapping[i].scale[0],
661 mMaterial->mapping[i].scale[1],
662 mMaterial->mapping[i].scale[2]
666 mMaterial->mapping[i].offsets[0],
667 mMaterial->mapping[i].offsets[1],
668 mMaterial->mapping[i].offsets[2]
671 glMatrixMode(GL_MODELVIEW);
675 static void GetProjPlane(BL_Material *mat, int index,int num, float*param)
677 param[0]=param[1]=param[2]=param[3]=0.f;
678 if( mat->mapping[index].projplane[num] == PROJX )
680 else if( mat->mapping[index].projplane[num] == PROJY )
682 else if( mat->mapping[index].projplane[num] == PROJZ)
686 void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras)
690 mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame);
694 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
695 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
696 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
698 GLenum plane = GL_EYE_PLANE;
701 float proj[4]= {0.f,0.f,0.f,0.f};
702 GetProjPlane(mMaterial, i, 0, proj);
703 glTexGenfv(GL_S, plane, proj);
705 GetProjPlane(mMaterial, i, 1, proj);
706 glTexGenfv(GL_T, plane, proj);
708 GetProjPlane(mMaterial, i, 2, proj);
709 glTexGenfv(GL_R, plane, proj);
711 glEnable(GL_TEXTURE_GEN_S);
712 glEnable(GL_TEXTURE_GEN_T);
713 glEnable(GL_TEXTURE_GEN_R);
716 ras->GetViewMatrix(mvmat);
718 glMatrixMode(GL_TEXTURE);
721 mMaterial->mapping[i].scale[0],
722 mMaterial->mapping[i].scale[1],
723 mMaterial->mapping[i].scale[2]
726 MT_Point3 pos = obj->NodeGetWorldPosition();
727 MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f);
728 MT_Vector4 t = mvmat*matmul;
730 glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) );
732 glMatrixMode(GL_MODELVIEW);
736 // ------------------------------------
737 void KX_BlenderMaterial::UpdateIPO(
747 // only works one deep now
748 mMaterial->speccolor[0] = (float)(specrgb)[0];
749 mMaterial->speccolor[1] = (float)(specrgb)[1];
750 mMaterial->speccolor[2] = (float)(specrgb)[2];
751 mMaterial->matcolor[0] = (float)(rgba[0]);
752 mMaterial->matcolor[1] = (float)(rgba[1]);
753 mMaterial->matcolor[2] = (float)(rgba[2]);
754 mMaterial->alpha = (float)(alpha);
755 mMaterial->hard = (float)(hard);
756 mMaterial->emit = (float)(emit);
757 mMaterial->spec_f = (float)(spec);
761 PyMethodDef KX_BlenderMaterial::Methods[] =
763 KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
764 KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
765 KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
766 {NULL,NULL} //Sentinel
770 PyTypeObject KX_BlenderMaterial::Type = {
771 PyObject_HEAD_INIT(&PyType_Type)
773 "KX_BlenderMaterial",
774 sizeof(KX_BlenderMaterial),
786 PyParentObject KX_BlenderMaterial::Parents[] = {
788 &KX_BlenderMaterial::Type,
793 PyObject* KX_BlenderMaterial::_getattr(const STR_String& attr)
795 _getattr_up(PyObjectPlus);
798 int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue)
800 return PyObjectPlus::_setattr(attr, pyvalue);
804 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
806 if( !GLEW_ARB_fragment_shader) {
808 spit("Fragment shaders not supported");
814 if( !GLEW_ARB_vertex_shader) {
816 spit("Vertex shaders not supported");
822 if(!GLEW_ARB_shader_objects) {
824 spit("GLSL not supported");
829 // returns Py_None on error
830 // the calling script will need to check
832 if(!mShader && !mModified) {
833 mShader = new BL_Shader();
837 if(mShader && !mShader->GetError()) {
838 mMaterial->SetSharedMaterial(true);
843 // decref all references to the object
845 // We will then go back to fixed functionality
848 if(mShader->ob_refcnt > 1) {
859 PyErr_Format(PyExc_ValueError, "GLSL Error");
864 void KX_BlenderMaterial::SetBlenderGLSLShader(void)
867 mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer);
869 if(!mBlenderShader->Ok()) {
870 delete mBlenderShader;
874 m_flag |= RAS_BLENDERGLSL;
877 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
879 return PyInt_FromLong( mMaterial->material_index );
882 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" )
884 // TODO: enable python switching
888 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)")
890 // TODO: enable python switching
894 static unsigned int GL_array[11] = {
898 GL_ONE_MINUS_SRC_COLOR,
900 GL_ONE_MINUS_DST_COLOR,
902 GL_ONE_MINUS_SRC_ALPHA,
904 GL_ONE_MINUS_DST_ALPHA,
905 GL_SRC_ALPHA_SATURATE
908 KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( GameLogic.src, GameLogic.dest)")
911 if(PyArg_ParseTuple(args, "ii", &b[0], &b[1]))
913 bool value_found[2] = {false, false};
914 for(int i=0; i<11; i++)
916 if(b[0] == GL_array[i]) {
917 value_found[0] = true;
918 mBlendFunc[0] = b[0];
920 if(b[1] == GL_array[i]) {
921 value_found[1] = true;
922 mBlendFunc[1] = b[1];
924 if(value_found[0] && value_found[1]) break;
926 if(!value_found[0] || !value_found[1]) {
927 PyErr_Format(PyExc_ValueError, "invalid enum.");
930 mUserDefBlend = true;