blender/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
Benoit Bolsee d11a5bbef2 BGE: Support mesh modifiers in the game engine.
Realtime modifiers applied on mesh objects will be supported in 
the game engine with the following limitations:

- Only real time modifiers are supported (basically all of them!)
- Virtual modifiers resulting from parenting are not supported: 
  armature, curve, lattice. You can still use these modifiers 
  (armature is really not recommended) but in non parent mode. 
  The BGE has it's own parenting capability for armature.
- Modifiers are computed on the host (using blender modifier
  stack).
- Modifiers are statically evaluated: any possible time dependency
  in the modifiers is not supported (don't know enough about
  modifiers to be more specific).
- Modifiers are reevaluated if the underlying mesh is deformed
  due to shape action or armature action. Beware that this is 
  very CPU intensive; modifiers should really be used for static
  objects only.
- Physics is still based on the original mesh: if you have a 
  mirror modifier, the physic shape will be limited to one half
  of the resulting object. Therefore, the modifiers should 
  preferably be used on graphic objects.
- Scripts have no access to the modified mesh. 
- Modifiers that are based on objects interaction (boolean,..)
  will not be dependent on the objects position in the GE.
  What you see in the 3D view is what you get in the GE regardless
  on the object position, velocity, etc.

Besides that, the feature is compatible with all the BGE features
that affect meshes: armature action, shape action, relace mesh, 
VideoTexture, add object, dupligroup.

Known problems:
- This feature is a bit hacky: the BGE uses the derived mesh draw 
  functions to display the object. This drawing method is a
  bit slow and is not 100% compatible with the BGE. There may
  be some problems in multi-texture mode: the multi-texture
  coordinates are not sent to the GPU. 
  Texface and GLSL on the other hand should be fully supported.
- Culling is still based on the extend of the original mesh. 
  If you have a modifer that extends the size of the mesh, 
  the object may disappear while still in the view frustrum.
- Derived mesh is not shared between replicas.
  The derived mesh is allocated and computed for each object
  with modifiers, regardless if they are static replicas.
- Display list are not created on objects with modifiers.
  
I should be able to fix the above problems before release.
However, the feature is already useful for game development.
Once you are ready to release the game, you can apply the modifiers
to get back display list support and mesh sharing capability.

MSVC, scons, Cmake, makefile updated.

Enjoy
/benoit
2009-04-21 11:01:09 +00:00

945 lines
21 KiB
C++

// ------------------------------------
// ...
// ------------------------------------
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "GL/glew.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"
// ------------------------------------
#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(
KX_Scene *scene,
BL_Material *data,
bool skin,
int lightlayer,
PyTypeObject *T
)
: PyObjectPlus(T),
RAS_IPolyMaterial(
STR_String( data->texname[0] ),
STR_String( data->matname ), // needed for physics!
data->materialindex,
data->tile,
data->tilexrep[0],
data->tileyrep[0],
data->mode,
data->transp,
((data->ras_mode &ALPHA)!=0),
((data->ras_mode &ZSORT)!=0),
lightlayer
),
mMaterial(data),
mShader(0),
mBlenderShader(0),
mScene(scene),
mUserDefBlend(0),
mModified(0),
mConstructed(false),
mPass(0)
{
// --------------------------------
// 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;
// figure max
int enabled = mMaterial->num_enabled;
int max = BL_Texture::GetMaxUnits();
mMaterial->num_enabled = enabled>=max?max:enabled;
// 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; i<mMaterial->num_enabled; i++) {
m_multimode +=
( mMaterial->flag[i] +
mMaterial->blend_mode[i]
);
}
m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(COLLIDER|USE_LIGHT));
}
KX_BlenderMaterial::~KX_BlenderMaterial()
{
// cleanup work
if (mConstructed)
// clean only if material was actually used
OnExit();
}
MTFace* KX_BlenderMaterial::GetMTFace(void) const
{
// fonts on polys
MT_assert(mMaterial->tface);
return mMaterial->tface;
}
unsigned int* KX_BlenderMaterial::GetMCol(void) const
{
// fonts on polys
return mMaterial->rgb;
}
void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const
{
if (mMaterial) {
*rgba++ = (unsigned char) (mMaterial->matcolor[0]*255.0);
*rgba++ = (unsigned char) (mMaterial->matcolor[1]*255.0);
*rgba++ = (unsigned char) (mMaterial->matcolor[2]*255.0);
*rgba++ = (unsigned char) (mMaterial->matcolor[3]*255.0);
} else
RAS_IPolyMaterial::GetMaterialRGBAColor(rgba);
}
Material *KX_BlenderMaterial::GetBlenderMaterial() const
{
return mMaterial->material;
}
Scene* KX_BlenderMaterial::GetBlenderScene() const
{
return mScene->GetBlenderScene();
}
void KX_BlenderMaterial::OnConstruction()
{
if (mConstructed)
// when material are reused between objects
return;
if(mMaterial->glslmat)
SetBlenderGLSLShader();
// for each unique material...
int i;
for(i=0; i<mMaterial->num_enabled; i++) {
if( mMaterial->mapping[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("<<i<<") in "<<
mMaterial->matname<< ", image will not be available");
}
else {
if( mMaterial->img[i] ) {
if( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
spit("unable to initialize image("<<i<<") in "<<
mMaterial->matname<< ", image will not be available");
}
}
}
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; i<mMaterial->num_enabled; i++) {
BL_Texture::ActivateUnit(i);
mTextures[i].DeleteTex();
mTextures[i].DisableUnit();
}
if( mMaterial->tface )
GPU_set_tpage(mMaterial->tface);
}
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->SetBlendingMode(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; i<mMaterial->num_enabled; i++) {
if(!mTextures[i].Ok()) continue;
mTextures[i].ActivateTexture();
mTextures[0].SetMapping(mMaterial->mapping[i].mapping);
}
if(!mUserDefBlend) {
ras->SetBlendingMode(mMaterial->transp);
}
else {
ras->SetBlendingMode(TF_SOLID);
ras->SetBlendingMode(-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->SetBlendingMode(TF_SOLID);
// frame cleanup.
if(mLastBlenderShader) {
mLastBlenderShader->SetProg(false);
mLastBlenderShader= NULL;
}
else
BL_Texture::DisableAllTextures();
return;
}
if(!mBlenderShader->Equals(mLastBlenderShader)) {
ras->SetBlendingMode(mMaterial->transp);
if(mLastBlenderShader)
mLastBlenderShader->SetProg(false);
else
BL_Texture::DisableAllTextures();
mBlenderShader->SetProg(true, ras->GetTime());
mLastBlenderShader= mBlenderShader;
}
}
void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras)
{
BL_Texture::DisableAllTextures();
if( !enable ) {
ras->SetBlendingMode(TF_SOLID);
return;
}
BL_Texture::ActivateFirst();
if( mMaterial->IdMode == DEFAULT_BLENDER ) {
ras->SetBlendingMode(mMaterial->transp);
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->SetBlendingMode(mMaterial->transp);
}
return;
}
int mode = 0,i=0;
for(i=0; (i<mMaterial->num_enabled && i<MAXTEX); i++) {
if( !mTextures[i].Ok() ) continue;
mTextures[i].ActivateTexture();
mTextures[i].setTexEnv(mMaterial);
mode = mMaterial->mapping[i].mapping;
if(mode &USEOBJ)
setObjectMatrixData(i, ras);
else
mTextures[i].SetMapping(mode);
if(!(mode &USEOBJ))
setTexMatrixData( i );
}
if(!mUserDefBlend) {
ras->SetBlendingMode(mMaterial->transp);
}
else {
ras->SetBlendingMode(TF_SOLID);
ras->SetBlendingMode(-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<KX_BlenderMaterial*>(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
tmp->setShaderData(false, rasty);
if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
rasty->SetCullFace(false);
else
rasty->SetCullFace(true);
if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
(rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
{
if((mMaterial->ras_mode &WIRE)!=0)
rasty->SetCullFace(false);
rasty->SetLines(true);
}
else
rasty->SetLines(false);
}
ActivatGLMaterials(rasty);
ActivateTexGen(rasty);
}
void
KX_BlenderMaterial::ActivateBlenderShaders(
RAS_IRasterizer* rasty,
TCachingInfo& cachingInfo)const
{
KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(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
tmp->setBlenderShaderData(false, rasty);
if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
rasty->SetCullFace(false);
else
rasty->SetCullFace(true);
if (((mMaterial->ras_mode & WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
(rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
{
if((mMaterial->ras_mode &WIRE)!=0)
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<KX_BlenderMaterial*>(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
tmp->setTexData( false,rasty);
if(mMaterial->mode & RAS_IRasterizer::KX_TWOSIDE)
rasty->SetCullFace(false);
else
rasty->SetCullFace(true);
if (((mMaterial->ras_mode &WIRE)!=0) || (mMaterial->mode & RAS_IRasterizer::KX_LINES) ||
(rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME))
{
if((mMaterial->ras_mode &WIRE)!=0)
rasty->SetCullFace(false);
rasty->SetLines(true);
}
else
rasty->SetLines(false);
}
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 blendmode;
mBlenderShader->Update(ms, rasty);
/* we do blend modes here, because they can change per object
* with the same material due to obcolor/obalpha */
blendmode = mBlenderShader->GetBlendMode();
if((blendmode == TF_SOLID || blendmode == TF_ALPHA) && mMaterial->transp != TF_SOLID)
blendmode = mMaterial->transp;
rasty->SetBlendingMode(blendmode);
}
}
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->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; i<mMaterial->num_enabled; i++) {
int mode = mMaterial->mapping[i].mapping;
if (mode &USECUSTOMUV)
{
STR_String str = mMaterial->mapping[i].uvCoName;
if (!str.IsEmpty())
ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV2, i);
continue;
}
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_UV1, 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);
}
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[] = {
{ NULL } //Sentinel
};
PyTypeObject KX_BlenderMaterial::Type = {
PyObject_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,
py_base_getattro,
py_base_setattro,
0,0,0,0,0,0,0,0,0,
Methods
};
PyParentObject KX_BlenderMaterial::Parents[] = {
&KX_BlenderMaterial::Type,
&PyObjectPlus::Type,
NULL
};
PyObject* KX_BlenderMaterial::py_getattro(PyObject *attr)
{
py_getattro_up(PyObjectPlus);
}
PyObject* KX_BlenderMaterial::py_getattro_dict() {
py_getattro_dict_up(PyObjectPlus);
}
int KX_BlenderMaterial::py_setattro(PyObject *attr, PyObject *pyvalue)
{
return PyObjectPlus::py_setattro(attr, pyvalue);
}
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;
}
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;
}
void KX_BlenderMaterial::SetBlenderGLSLShader(void)
{
if(!mBlenderShader)
mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer);
if(!mBlenderShader->Ok()) {
delete mBlenderShader;
mBlenderShader = 0;
}
}
KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
{
return PyInt_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 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( GameLogic.src, GameLogic.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;
}