/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ /** \file gameengine/Ketsji/KX_BlenderMaterial.cpp * \ingroup ketsji */ #include "glew-mx.h" #include "KX_BlenderMaterial.h" #include "BL_Material.h" #include "KX_Scene.h" #include "KX_Light.h" #include "KX_GameObject.h" #include "KX_MeshProxy.h" #include "MT_Vector3.h" #include "MT_Vector4.h" #include "MT_Matrix4x4.h" #include "RAS_BucketManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" #include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" #include "GPU_draw.h" #include "STR_HashedString.h" // ------------------------------------ #include "DNA_object_types.h" #include "DNA_material_types.h" #include "DNA_image_types.h" #include "DNA_meshdata_types.h" #include "BKE_mesh.h" // ------------------------------------ #include "BLI_utildefines.h" #define spit(x) std::cout << x << std::endl; BL_Shader *KX_BlenderMaterial::mLastShader = NULL; BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; //static PyObject *gTextureDict = 0; KX_BlenderMaterial::KX_BlenderMaterial() : PyObjectPlus(), RAS_IPolyMaterial(), mMaterial(NULL), mShader(0), mBlenderShader(0), mScene(NULL), mUserDefBlend(0), mModified(0), mConstructed(false), mPass(0) { } void KX_BlenderMaterial::Initialize( KX_Scene *scene, BL_Material *data, GameSettings *game, int lightlayer) { RAS_IPolyMaterial::Initialize( data->texname[0], data->matname, data->materialindex, data->tile, data->tilexrep[0], data->tileyrep[0], data->alphablend, ((data->ras_mode &ALPHA)!=0), ((data->ras_mode &ZSORT)!=0), ((data->ras_mode &USE_LIGHT)!=0), ((data->ras_mode &TEX)), game ); mMaterial = data; mShader = 0; mBlenderShader = 0; mScene = scene; mUserDefBlend = 0; mModified = 0; mConstructed = false; mPass = 0; mLightLayer = lightlayer; // -------------------------------- // RAS_IPolyMaterial variables... m_flag |= RAS_BLENDERMAT; m_flag |= (mMaterial->IdMode>=ONETEX)? RAS_MULTITEX: 0; m_flag |= ((mMaterial->ras_mode & USE_LIGHT)!=0)? RAS_MULTILIGHT: 0; m_flag |= (mMaterial->glslmat)? RAS_BLENDERGLSL: 0; m_flag |= ((mMaterial->ras_mode & CAST_SHADOW)!=0)? RAS_CASTSHADOW: 0; m_flag |= ((mMaterial->ras_mode & ONLY_SHADOW)!=0)? RAS_ONLYSHADOW: 0; // test the sum of the various modes for equality // so we can ether accept or reject this material // as being equal, this is rather important to // prevent material bleeding for (int i=0; iflag[i] + mMaterial->blend_mode[i]); } m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(USE_LIGHT)); } KX_BlenderMaterial::~KX_BlenderMaterial() { // cleanup work if (mConstructed) // clean only if material was actually used OnExit(); } MTFace* KX_BlenderMaterial::GetMTFace() const { // fonts on polys return &mMaterial->tface; } unsigned int* KX_BlenderMaterial::GetMCol() const { // fonts on polys return mMaterial->rgb; } void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const { if (mMaterial) { *rgba++ = (unsigned char)(mMaterial->matcolor[0] * 255.0f); *rgba++ = (unsigned char)(mMaterial->matcolor[1] * 255.0f); *rgba++ = (unsigned char)(mMaterial->matcolor[2] * 255.0f); *rgba++ = (unsigned char)(mMaterial->matcolor[3] * 255.0f); } else RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); } Material *KX_BlenderMaterial::GetBlenderMaterial() const { return mMaterial->material; } Image *KX_BlenderMaterial::GetBlenderImage() const { return mMaterial->tface.tpage; } Scene* KX_BlenderMaterial::GetBlenderScene() const { return mScene->GetBlenderScene(); } void KX_BlenderMaterial::ReleaseMaterial() { if (mBlenderShader) mBlenderShader->ReloadMaterial(); } void KX_BlenderMaterial::InitTextures() { // for each unique material... int i; for (i=0; imapping[i].mapping & USEENV ) { if (!GLEW_ARB_texture_cube_map) { spit("CubeMap textures not supported"); continue; } if (!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) ) spit("unable to initialize image("<matname<< ", image will not be available"); } /* If we're using glsl materials, the textures are handled by bf_gpu, so don't load them twice! * However, if we're using a custom shader, then we still need to load the textures ourselves. */ else if (!mMaterial->glslmat || mShader) { if ( mMaterial->img[i] ) { if ( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 )) spit("unable to initialize image("<matname<< ", image will not be available"); } } } } void KX_BlenderMaterial::OnConstruction() { if (mConstructed) // when material are reused between objects return; if (mMaterial->glslmat) SetBlenderGLSLShader(); InitTextures(); mBlendFunc[0] =0; mBlendFunc[1] =0; mConstructed = true; } void KX_BlenderMaterial::EndFrame() { if (mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader = NULL; } if (mLastShader) { mLastShader->SetProg(false); mLastShader = NULL; } } void KX_BlenderMaterial::OnExit() { if ( mShader ) { //note, the shader here is allocated, per unique material //and this function is called per face if (mShader == mLastShader) { mShader->SetProg(false); mLastShader = NULL; } delete mShader; mShader = 0; } if ( mBlenderShader ) { if (mBlenderShader == mLastBlenderShader) { mBlenderShader->SetProg(false); mLastBlenderShader = NULL; } delete mBlenderShader; mBlenderShader = 0; } BL_Texture::ActivateFirst(); for (int i=0; itface' but this can be a freed array, * see: [#30493], so just call with NULL, this is best since it clears * the 'lastface' pointer in GPU too - campbell */ GPU_set_tpage(NULL, 1, mMaterial->alphablend); } void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) { MT_assert(GLEW_ARB_shader_objects && mShader); int i; if ( !enable || !mShader->Ok() ) { // frame cleanup. if (mShader == mLastShader) { mShader->SetProg(false); mLastShader = NULL; } ras->SetAlphaBlend(TF_SOLID); BL_Texture::DisableAllTextures(); return; } BL_Texture::DisableAllTextures(); mShader->SetProg(true); mLastShader = mShader; BL_Texture::ActivateFirst(); mShader->ApplyShader(); // for each enabled unit for (i=0; imapping[i].mapping); } if (!mUserDefBlend) { ras->SetAlphaBlend(mMaterial->alphablend); } else { ras->SetAlphaBlend(TF_SOLID); ras->SetAlphaBlend(-1); // indicates custom mode // tested to be valid enums glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); } } void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras) { if ( !enable || !mBlenderShader->Ok() ) { ras->SetAlphaBlend(TF_SOLID); // frame cleanup. if (mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; } else BL_Texture::DisableAllTextures(); return; } if (!mBlenderShader->Equals(mLastBlenderShader)) { ras->SetAlphaBlend(mMaterial->alphablend); if (mLastBlenderShader) mLastBlenderShader->SetProg(false); else BL_Texture::DisableAllTextures(); mBlenderShader->SetProg(true, ras->GetTime(), ras); mLastBlenderShader= mBlenderShader; } } void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) { BL_Texture::DisableAllTextures(); if ( !enable ) { ras->SetAlphaBlend(TF_SOLID); return; } BL_Texture::ActivateFirst(); if ( mMaterial->IdMode == DEFAULT_BLENDER ) { ras->SetAlphaBlend(mMaterial->alphablend); return; } if ( mMaterial->IdMode == TEXFACE ) { // no material connected to the object if ( mTextures[0].Ok() ) { mTextures[0].ActivateTexture(); mTextures[0].setTexEnv(0, true); mTextures[0].SetMapping(mMaterial->mapping[0].mapping); ras->SetAlphaBlend(mMaterial->alphablend); } return; } int mode = 0,i=0; for (i=0; imapping[i].mapping; if (mode &USEOBJ) setObjectMatrixData(i, ras); else mTextures[i].SetMapping(mode); if (!(mode &USEOBJ)) setTexMatrixData( i ); } if (!mUserDefBlend) { ras->SetAlphaBlend(mMaterial->alphablend); } else { ras->SetAlphaBlend(TF_SOLID); ras->SetAlphaBlend(-1); // indicates custom mode glEnable(GL_BLEND); glBlendFunc(mBlendFunc[0], mBlendFunc[1]); } } void KX_BlenderMaterial::ActivatShaders( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo)const { KX_BlenderMaterial *tmp = const_cast(this); // reset... if (tmp->mMaterial->IsShared()) cachingInfo =0; if (mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; } if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) tmp->setShaderData(false, rasty); cachingInfo = GetCachingInfo(); if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) tmp->setShaderData(true, rasty); else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) tmp->setShaderData(true, rasty); else tmp->setShaderData(false, rasty); if (mMaterial->ras_mode &TWOSIDED) rasty->SetCullFace(false); else rasty->SetCullFace(true); if ((mMaterial->ras_mode &WIRE) || (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if (mMaterial->ras_mode &WIRE) rasty->SetCullFace(false); rasty->SetLines(true); } else rasty->SetLines(false); ActivatGLMaterials(rasty); ActivateTexGen(rasty); } //ActivatGLMaterials(rasty); //ActivateTexGen(rasty); } void KX_BlenderMaterial::ActivateBlenderShaders( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo)const { KX_BlenderMaterial *tmp = const_cast(this); if (mLastShader) { mLastShader->SetProg(false); mLastShader= NULL; } if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) tmp->setBlenderShaderData(false, rasty); cachingInfo = GetCachingInfo(); if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) tmp->setBlenderShaderData(true, rasty); else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) tmp->setBlenderShaderData(true, rasty); else tmp->setBlenderShaderData(false, rasty); if (mMaterial->ras_mode &TWOSIDED) rasty->SetCullFace(false); else rasty->SetCullFace(true); if ((mMaterial->ras_mode &WIRE) || (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if (mMaterial->ras_mode &WIRE) rasty->SetCullFace(false); rasty->SetLines(true); } else rasty->SetLines(false); ActivatGLMaterials(rasty); mBlenderShader->SetAttribs(rasty, mMaterial); } } void KX_BlenderMaterial::ActivateMat( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo )const { KX_BlenderMaterial *tmp = const_cast(this); if (mLastShader) { mLastShader->SetProg(false); mLastShader= NULL; } if (mLastBlenderShader) { mLastBlenderShader->SetProg(false); mLastBlenderShader= NULL; } if (GetCachingInfo() != cachingInfo) { if (!cachingInfo) tmp->setTexData( false,rasty ); cachingInfo = GetCachingInfo(); if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) tmp->setTexData( true,rasty ); else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) tmp->setTexData(true, rasty); else tmp->setTexData( false,rasty); if (mMaterial->ras_mode &TWOSIDED) rasty->SetCullFace(false); else rasty->SetCullFace(true); if ((mMaterial->ras_mode &WIRE) || (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) { if (mMaterial->ras_mode &WIRE) rasty->SetCullFace(false); rasty->SetLines(true); } else rasty->SetLines(false); ActivatGLMaterials(rasty); ActivateTexGen(rasty); } //ActivatGLMaterials(rasty); //ActivateTexGen(rasty); } bool KX_BlenderMaterial::Activate( RAS_IRasterizer* rasty, TCachingInfo& cachingInfo )const { if (GLEW_ARB_shader_objects && (mShader && mShader->Ok())) { if ((mPass++) < mShader->getNumPass() ) { ActivatShaders(rasty, cachingInfo); return true; } else { if (mShader == mLastShader) { mShader->SetProg(false); mLastShader = NULL; } mPass = 0; return false; } } else if ( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) { if (mPass++ == 0) { ActivateBlenderShaders(rasty, cachingInfo); return true; } else { mPass = 0; return false; } } else { if (mPass++ == 0) { ActivateMat(rasty, cachingInfo); return true; } else { mPass = 0; return false; } } } bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const { if (!RAS_IPolyMaterial::UsesLighting(rasty)) return false; if (mShader && mShader->Ok()) return true; else if (mBlenderShader && mBlenderShader->Ok()) return false; else return true; } void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const { if (mShader && GLEW_ARB_shader_objects) { mShader->Update(ms, rasty); } else if (mBlenderShader && GLEW_ARB_shader_objects) { int alphablend; mBlenderShader->Update(ms, rasty); /* we do blend modes here, because they can change per object * with the same material due to obcolor/obalpha */ alphablend = mBlenderShader->GetAlphaBlend(); if (ELEM3(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) alphablend = mMaterial->alphablend; rasty->SetAlphaBlend(alphablend); } } void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const { if (mShader || !mBlenderShader) { rasty->SetSpecularity( mMaterial->speccolor[0]*mMaterial->spec_f, mMaterial->speccolor[1]*mMaterial->spec_f, mMaterial->speccolor[2]*mMaterial->spec_f, mMaterial->spec_f ); rasty->SetShinyness( mMaterial->hard ); rasty->SetDiffuse( mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit, mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit, 1.0f); rasty->SetEmissive( mMaterial->matcolor[0]*mMaterial->emit, mMaterial->matcolor[1]*mMaterial->emit, mMaterial->matcolor[2]*mMaterial->emit, 1.0 ); rasty->SetAmbient(mMaterial->amb); } if (mMaterial->material) rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0); } void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const { if (ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED || (ras->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !ras->GetUsingOverrideShader())) { ras->SetAttribNum(0); if (mShader && GLEW_ARB_shader_objects) { if (mShader->GetAttribute() == BL_Shader::SHD_TANGENT) { ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0); ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1); ras->SetAttribNum(2); } } ras->SetTexCoordNum(mMaterial->num_enabled); for (int i=0; imapping[i].mapping; if ( mode &(USEREFL|USEOBJ)) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i); else if (mode &USEORCO) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i); else if (mode &USENORM) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i); else if (mode &USEUV) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV, i); else if (mode &USETANG) ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i); else ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); } } } void KX_BlenderMaterial::setTexMatrixData(int i) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); if ( GLEW_ARB_texture_cube_map && mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB && mMaterial->mapping[i].mapping & USEREFL) { glScalef( mMaterial->mapping[i].scale[0], -mMaterial->mapping[i].scale[1], -mMaterial->mapping[i].scale[2] ); } else { glScalef( mMaterial->mapping[i].scale[0], mMaterial->mapping[i].scale[1], mMaterial->mapping[i].scale[2] ); } glTranslatef( mMaterial->mapping[i].offsets[0], mMaterial->mapping[i].offsets[1], mMaterial->mapping[i].offsets[2] ); glMatrixMode(GL_MODELVIEW); } static void GetProjPlane(BL_Material *mat, int index,int num, float*param) { param[0]=param[1]=param[2]=param[3]=0.f; if ( mat->mapping[index].projplane[num] == PROJX ) param[0] = 1.f; else if ( mat->mapping[index].projplane[num] == PROJY ) param[1] = 1.f; else if ( mat->mapping[index].projplane[num] == PROJZ) param[2] = 1.f; } void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras) { KX_GameObject *obj = (KX_GameObject*) mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame); if (!obj) return; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); GLenum plane = GL_EYE_PLANE; // figure plane gen float proj[4] = {0.f,0.f,0.f,0.f}; GetProjPlane(mMaterial, i, 0, proj); glTexGenfv(GL_S, plane, proj); GetProjPlane(mMaterial, i, 1, proj); glTexGenfv(GL_T, plane, proj); GetProjPlane(mMaterial, i, 2, proj); glTexGenfv(GL_R, plane, proj); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); const MT_Matrix4x4& mvmat = ras->GetViewMatrix(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef( mMaterial->mapping[i].scale[0], mMaterial->mapping[i].scale[1], mMaterial->mapping[i].scale[2] ); MT_Point3 pos = obj->NodeGetWorldPosition(); MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f); MT_Vector4 t = mvmat*matmul; glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) ); glMatrixMode(GL_MODELVIEW); } // ------------------------------------ void KX_BlenderMaterial::UpdateIPO( MT_Vector4 rgba, MT_Vector3 specrgb, MT_Scalar hard, MT_Scalar spec, MT_Scalar ref, MT_Scalar emit, MT_Scalar alpha ) { // only works one deep now mMaterial->speccolor[0] = (float)(specrgb)[0]; mMaterial->speccolor[1] = (float)(specrgb)[1]; mMaterial->speccolor[2] = (float)(specrgb)[2]; mMaterial->matcolor[0] = (float)(rgba[0]); mMaterial->matcolor[1] = (float)(rgba[1]); mMaterial->matcolor[2] = (float)(rgba[2]); mMaterial->alpha = (float)(alpha); mMaterial->hard = (float)(hard); mMaterial->emit = (float)(emit); mMaterial->spec_f = (float)(spec); mMaterial->ref = (float)(ref); } void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val) { mScene= static_cast(val); OnConstruction(); } void KX_BlenderMaterial::SetBlenderGLSLShader() { if (!mBlenderShader) mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, mLightLayer); if (!mBlenderShader->Ok()) { delete mBlenderShader; mBlenderShader = 0; } } #ifdef WITH_PYTHON PyMethodDef KX_BlenderMaterial::Methods[] = { KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ), KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ), KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ), {NULL,NULL} //Sentinel }; PyAttributeDef KX_BlenderMaterial::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader), KX_PYATTRIBUTE_RO_FUNCTION("material_index", KX_BlenderMaterial, pyattr_get_materialIndex), KX_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending), { NULL } //Sentinel }; PyTypeObject KX_BlenderMaterial::Type = { PyVarObject_HEAD_INIT(NULL, 0) "KX_BlenderMaterial", sizeof(PyObjectPlus_Proxy), 0, py_base_dealloc, 0, 0, 0, 0, py_base_repr, 0,0,0,0,0,0,0,0,0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 0,0,0,0,0,0,0, Methods, 0, 0, &PyObjectPlus::Type, 0,0,0,0,0,0, py_base_new }; PyObject *KX_BlenderMaterial::pyattr_get_shader(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial* self = static_cast(self_v); return self->PygetShader(NULL, NULL); } PyObject *KX_BlenderMaterial::pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial* self = static_cast(self_v); return PyLong_FromLong(self->GetMaterialIndex()); } PyObject *KX_BlenderMaterial::pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial* self = static_cast(self_v); unsigned int* bfunc = self->getBlendFunc(); return Py_BuildValue("(ll)", (long int)bfunc[0], (long int)bfunc[1]); } int KX_BlenderMaterial::pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial* self = static_cast(self_v); PyObject *obj = self->PysetBlending(value, NULL); if (obj) { Py_DECREF(obj); return 0; } return -1; } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") { if ( !GLEW_ARB_fragment_shader) { if (!mModified) spit("Fragment shaders not supported"); mModified = true; Py_RETURN_NONE; } if ( !GLEW_ARB_vertex_shader) { if (!mModified) spit("Vertex shaders not supported"); mModified = true; Py_RETURN_NONE; } if (!GLEW_ARB_shader_objects) { if (!mModified) spit("GLSL not supported"); mModified = true; Py_RETURN_NONE; } else { // returns Py_None on error // the calling script will need to check if (!mShader && !mModified) { mShader = new BL_Shader(); mModified = true; // Using a custom shader, make sure to initialize textures InitTextures(); } if (mShader && !mShader->GetError()) { m_flag &= ~RAS_BLENDERGLSL; mMaterial->SetSharedMaterial(true); mScene->GetBucketManager()->ReleaseDisplayLists(this); return mShader->GetProxy(); } else { // decref all references to the object // then delete it! // We will then go back to fixed functionality // for this material if (mShader) { delete mShader; /* will handle python de-referencing */ mShader=0; } } Py_RETURN_NONE; } PyErr_SetString(PyExc_ValueError, "material.getShader(): KX_BlenderMaterial, GLSL Error"); return NULL; } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") { return PyLong_FromLong(GetMaterialIndex()); } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" ) { // TODO: enable python switching return NULL; } KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)") { // TODO: enable python switching return NULL; } static const unsigned int GL_array[11] = { GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA_SATURATE }; KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( bge.logic.src, bge.logic.dest)") { unsigned int b[2]; if (PyArg_ParseTuple(args, "ii:setBlending", &b[0], &b[1])) { bool value_found[2] = {false, false}; for (int i=0; i<11; i++) { if (b[0] == GL_array[i]) { value_found[0] = true; mBlendFunc[0] = b[0]; } if (b[1] == GL_array[i]) { value_found[1] = true; mBlendFunc[1] = b[1]; } if (value_found[0] && value_found[1]) break; } if (!value_found[0] || !value_found[1]) { PyErr_SetString(PyExc_ValueError, "material.setBlending(int, int): KX_BlenderMaterial, invalid enum."); return NULL; } mUserDefBlend = true; Py_RETURN_NONE; } return NULL; } #endif // WITH_PYTHON