forked from bartvdbraak/blender
85c58bfa8a
also, disabled the asynchronous logicbrick update, it reportedly causes jitter.
1056 lines
25 KiB
C++
1056 lines
25 KiB
C++
|
|
// ------------------------------------
|
|
// ...
|
|
// ------------------------------------
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#endif // WIN32
|
|
#ifdef __APPLE__
|
|
#define GL_GLEXT_LEGACY 1
|
|
#include <OpenGL/gl.h>
|
|
#include <OpenGL/glu.h>
|
|
#else
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#endif
|
|
|
|
#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_MeshObject.h"
|
|
#include "RAS_IRasterizer.h"
|
|
#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
|
|
#include "RAS_OpenGLRasterizer/ARB_multitexture.h"
|
|
|
|
extern "C" {
|
|
#include "BDR_drawmesh.h"
|
|
}
|
|
|
|
#include "STR_HashedString.h"
|
|
|
|
// ------------------------------------
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "BKE_mesh.h"
|
|
// ------------------------------------
|
|
using namespace bgl;
|
|
#define spit(x) std::cout << x << std::endl;
|
|
|
|
//static PyObject *gTextureDict = 0;
|
|
|
|
KX_BlenderMaterial::KX_BlenderMaterial(
|
|
KX_Scene *scene,
|
|
BL_Material *data,
|
|
bool skin,
|
|
int lightlayer,
|
|
void *clientobject,
|
|
PyTypeObject *T
|
|
)
|
|
: PyObjectPlus(T),
|
|
RAS_IPolyMaterial(
|
|
STR_String( data->texname[0] ),
|
|
STR_String( data->matname ), // needed for physics!
|
|
data->tile,
|
|
data->tilexrep[0],
|
|
data->tileyrep[0],
|
|
data->mode,
|
|
((data->ras_mode &TRANSP)!=0),
|
|
((data->ras_mode &ZSORT)!=0),
|
|
lightlayer,
|
|
((data->ras_mode &TRIANGLE)!=0),
|
|
clientobject
|
|
),
|
|
mMaterial(data),
|
|
mShader(0),
|
|
mScene(scene),
|
|
mUserDefBlend(0),
|
|
mModified(0),
|
|
mPass(0)
|
|
|
|
{
|
|
///RAS_EXT_support._ARB_multitexture == true if were here
|
|
|
|
// --------------------------------
|
|
// 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;
|
|
|
|
// figure max
|
|
#ifdef GL_ARB_multitexture
|
|
int enabled = mMaterial->num_enabled;
|
|
mMaterial->num_enabled = enabled>=bgl::max_texture_units?bgl::max_texture_units:enabled;
|
|
#else
|
|
mMaterial->num_enabled=0;
|
|
#endif
|
|
|
|
m_enabled = mMaterial->num_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;
|
|
|
|
}
|
|
|
|
|
|
KX_BlenderMaterial::~KX_BlenderMaterial()
|
|
{
|
|
// cleanup work
|
|
OnExit();
|
|
}
|
|
|
|
|
|
TFace* KX_BlenderMaterial::GetTFace(void) const
|
|
{
|
|
// fonts on polys
|
|
MT_assert(mMaterial->tface);
|
|
return mMaterial->tface;
|
|
}
|
|
|
|
void KX_BlenderMaterial::OnConstruction()
|
|
{
|
|
// for each unique material...
|
|
#ifdef GL_ARB_multitexture
|
|
/* will be used to switch textures
|
|
if(!gTextureDict)
|
|
gTextureDict = PyDict_New();
|
|
*/
|
|
int i;
|
|
for(i=0; i<mMaterial->num_enabled; i++) {
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if( mMaterial->mapping[i].mapping & USEENV ) {
|
|
if(!RAS_EXT_support._ARB_texture_cube_map) {
|
|
spit("CubeMap textures not supported");
|
|
continue;
|
|
}
|
|
if(!mTextures[i].InitCubeMap( mMaterial->cubemap[i] ) )
|
|
spit("unable to initialize image("<<i<<") in "<<
|
|
mMaterial->matname<< ", image will not be available");
|
|
}
|
|
|
|
else {
|
|
#endif//GL_ARB_texture_cube_map
|
|
if( mMaterial->img[i] ) {
|
|
if( ! mTextures[i].InitFromImage(mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 ))
|
|
spit("unable to initialize image("<<i<<") in "<<
|
|
mMaterial->matname<< ", image will not be available");
|
|
}
|
|
#ifdef GL_ARB_texture_cube_map
|
|
}
|
|
#endif//GL_ARB_texture_cube_map
|
|
/*PyDict_SetItemString(gTextureDict, mTextures[i].GetName().Ptr(), PyInt_FromLong(mTextures[i]));*/
|
|
}
|
|
#endif//GL_ARB_multitexture
|
|
|
|
mBlendFunc[0] =0;
|
|
mBlendFunc[1] =0;
|
|
}
|
|
|
|
void KX_BlenderMaterial::OnExit()
|
|
{
|
|
#ifdef GL_ARB_multitexture
|
|
|
|
#ifdef GL_ARB_shader_objects
|
|
if( RAS_EXT_support._ARB_shader_objects && mShader ) {
|
|
//note, the shader here is allocated, per unique material
|
|
//and this function is called per face
|
|
bgl::blUseProgramObjectARB(0);
|
|
delete mShader;
|
|
mShader = 0;
|
|
}
|
|
#endif //GL_ARB_shader_objects
|
|
|
|
for(int i=0; i<mMaterial->num_enabled; i++) {
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
|
|
mTextures[i].DeleteTex();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if(RAS_EXT_support._ARB_texture_cube_map)
|
|
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
#endif//GL_ARB_texture_cube_map
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
glDisable(GL_TEXTURE_GEN_R);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
}
|
|
|
|
/*if (gTextureDict) {
|
|
PyDict_Clear(gTextureDict);
|
|
Py_DECREF(gTextureDict);
|
|
gTextureDict = 0;
|
|
}*/
|
|
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if(RAS_EXT_support._ARB_texture_cube_map)
|
|
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
#endif//GL_ARB_texture_cube_map
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
#endif//GL_ARB_multitexture
|
|
|
|
// make sure multi texture units
|
|
// revert back to blender...
|
|
// --
|
|
if( mMaterial->tface )
|
|
set_tpage(mMaterial->tface);
|
|
}
|
|
|
|
|
|
void KX_BlenderMaterial::DisableTexData()
|
|
{
|
|
glDisable(GL_BLEND);
|
|
#ifdef GL_ARB_multitexture
|
|
int i=(MAXTEX>=bgl::max_texture_units?bgl::max_texture_units:MAXTEX)-1;
|
|
for(; i>=0; i--) {
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if(RAS_EXT_support._ARB_texture_cube_map)
|
|
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
#endif//GL_ARB_texture_cube_map
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
glDisable(GL_TEXTURE_GEN_R);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
}
|
|
#endif//GL_ARB_multitexture
|
|
}
|
|
|
|
|
|
void KX_BlenderMaterial::setShaderData( bool enable )
|
|
{
|
|
#ifdef GL_ARB_multitexture
|
|
#ifdef GL_ARB_shader_objects
|
|
|
|
MT_assert(RAS_EXT_support._ARB_shader_objects && mShader);
|
|
|
|
int i;
|
|
if( !enable || !mShader->Ok() ) {
|
|
// frame cleanup.
|
|
bgl::blUseProgramObjectARB( 0 );
|
|
DisableTexData();
|
|
return;
|
|
}
|
|
|
|
DisableTexData();
|
|
bgl::blUseProgramObjectARB( mShader->GetProg() );
|
|
|
|
// for each enabled unit
|
|
for(i=0; i<mMaterial->num_enabled; i++) {
|
|
|
|
const uSampler *samp = mShader->getSampler(i);
|
|
if( samp->loc == -1 || samp->glTexture == 0 ) continue;
|
|
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if( mMaterial->mapping[i].mapping &USEENV ) {
|
|
glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, samp->glTexture /* mTextures[i]*/ );
|
|
glEnable( GL_TEXTURE_CUBE_MAP_ARB );
|
|
}
|
|
else {
|
|
#endif//GL_ARB_texture_cube_map
|
|
glBindTexture( GL_TEXTURE_2D, samp->glTexture /*mTextures[i]*/ );
|
|
glEnable( GL_TEXTURE_2D );
|
|
#ifdef GL_ARB_texture_cube_map
|
|
}
|
|
#endif//GL_ARB_texture_cube_map
|
|
// use a sampler
|
|
bgl::blUniform1iARB(samp->loc, i );
|
|
}
|
|
|
|
if(!mUserDefBlend) {
|
|
setDefaultBlending();
|
|
}else
|
|
{
|
|
glEnable(GL_BLEND);
|
|
// tested to be valid enums
|
|
glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
|
|
}
|
|
|
|
#endif//GL_ARB_shader_objects
|
|
#endif//GL_ARB_multitexture
|
|
}
|
|
|
|
|
|
void KX_BlenderMaterial::setTexData( bool enable )
|
|
{
|
|
#ifdef GL_ARB_multitexture
|
|
int i;
|
|
|
|
#ifdef GL_ARB_shader_objects
|
|
if(RAS_EXT_support._ARB_shader_objects) {
|
|
// switch back to fixed func
|
|
bgl::blUseProgramObjectARB( 0 );
|
|
}
|
|
#endif//GL_ARB_shader_objects
|
|
|
|
if( !enable ) {
|
|
// frame cleanup.
|
|
DisableTexData();
|
|
return;
|
|
}
|
|
|
|
DisableTexData();
|
|
|
|
if( mMaterial->IdMode == DEFAULT_BLENDER ) {
|
|
setDefaultBlending();
|
|
return;
|
|
}
|
|
|
|
if( mMaterial->IdMode == TEXFACE ) {
|
|
|
|
// no material connected to the object
|
|
if( mTextures[0] ) {
|
|
if( !mTextures[0].Ok() ) return;
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB);
|
|
glBindTexture( GL_TEXTURE_2D, mTextures[0] );
|
|
glEnable(GL_TEXTURE_2D);
|
|
setTextureEnvironment( -1 ); // modulate
|
|
setEnvMap( (mMaterial->mapping[0].mapping &USEREFL)!=0 );
|
|
setDefaultBlending();
|
|
}
|
|
return;
|
|
}
|
|
|
|
int lastblend = 0;
|
|
|
|
// for each enabled unit
|
|
for(i=0; (i<mMaterial->num_enabled); i++) {
|
|
if( !mTextures[i].Ok() ) continue;
|
|
|
|
bgl::blActiveTextureARB(GL_TEXTURE0_ARB+i);
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
// use environment maps
|
|
if( mMaterial->mapping[i].mapping &USEENV && RAS_EXT_support._ARB_texture_cube_map ) {
|
|
glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, mTextures[i] );
|
|
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
setTextureEnvironment( i );
|
|
|
|
if( mMaterial->mapping[i].mapping &USEREFL )
|
|
setEnvMap( true, true );
|
|
else if(mMaterial->mapping[i].mapping &USEOBJ)
|
|
setObjectMatrixData(i);
|
|
else
|
|
setTexMatrixData( i );
|
|
}
|
|
// 2d textures
|
|
else {
|
|
#endif//GL_ARB_texture_cube_map
|
|
glBindTexture( GL_TEXTURE_2D, mTextures[i] );
|
|
glEnable( GL_TEXTURE_2D );
|
|
setTextureEnvironment( i );
|
|
|
|
if( mMaterial->mapping[i].mapping &USEREFL ){
|
|
setEnvMap( true );
|
|
}
|
|
else if(mMaterial->mapping[i].mapping &USEOBJ){
|
|
setObjectMatrixData(i);
|
|
}
|
|
else {
|
|
setTexMatrixData( i );
|
|
}
|
|
|
|
#ifdef GL_ARB_texture_cube_map
|
|
}
|
|
#endif//GL_ARB_texture_cube_map
|
|
}
|
|
if(!mUserDefBlend) {
|
|
setDefaultBlending();
|
|
}else
|
|
{
|
|
glEnable(GL_BLEND);
|
|
// tested to be valid enums
|
|
glBlendFunc(mBlendFunc[0], mBlendFunc[1]);
|
|
}
|
|
|
|
#endif//GL_ARB_multitexture
|
|
}
|
|
|
|
void
|
|
KX_BlenderMaterial::ActivatShaders(
|
|
RAS_IRasterizer* rasty,
|
|
TCachingInfo& cachingInfo)const
|
|
{
|
|
if (GetCachingInfo() != cachingInfo) {
|
|
KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
|
|
|
|
if (!cachingInfo)
|
|
tmp->setShaderData( false );
|
|
|
|
cachingInfo = GetCachingInfo();
|
|
|
|
if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED ) {
|
|
tmp->setShaderData( true );
|
|
rasty->EnableTextures(true);
|
|
}
|
|
else {
|
|
tmp->setShaderData( false );
|
|
rasty->EnableTextures(false);
|
|
}
|
|
|
|
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->SetLines(true);
|
|
else
|
|
rasty->SetLines(false);
|
|
}
|
|
|
|
// shaders have access to the variables set here
|
|
// via builtin GLSL variables
|
|
// eg: gl_FrontMaterial.diffuse
|
|
// --
|
|
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
|
|
);
|
|
|
|
// Lagan's patch...
|
|
// added material factor
|
|
rasty->SetAmbient(mMaterial->amb);
|
|
|
|
if (mMaterial->material)
|
|
rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
|
|
}
|
|
|
|
void
|
|
KX_BlenderMaterial::ActivateMat(
|
|
RAS_IRasterizer* rasty,
|
|
TCachingInfo& cachingInfo
|
|
)const
|
|
{
|
|
if (GetCachingInfo() != cachingInfo) {
|
|
KX_BlenderMaterial *tmp = const_cast<KX_BlenderMaterial*>(this);
|
|
|
|
if (!cachingInfo)
|
|
tmp->setTexData( false );
|
|
|
|
cachingInfo = GetCachingInfo();
|
|
|
|
if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) {
|
|
tmp->setTexData( true );
|
|
rasty->EnableTextures(true);
|
|
}
|
|
else{
|
|
tmp->setTexData( false );
|
|
rasty->EnableTextures(false);
|
|
}
|
|
|
|
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->SetLines(true);
|
|
else
|
|
rasty->SetLines(false);
|
|
}
|
|
|
|
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
|
|
);
|
|
|
|
// Lagan's patch...
|
|
// added material factor
|
|
rasty->SetAmbient(mMaterial->amb);
|
|
|
|
if (mMaterial->material)
|
|
rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
|
|
}
|
|
|
|
bool
|
|
KX_BlenderMaterial::Activate(
|
|
RAS_IRasterizer* rasty,
|
|
TCachingInfo& cachingInfo
|
|
)const
|
|
{
|
|
bool dopass = false;
|
|
#ifdef GL_ARB_shader_objects
|
|
if( RAS_EXT_support._ARB_shader_objects &&
|
|
( mShader && mShader->Ok() ) ) {
|
|
|
|
if( (mPass++) < mShader->getNumPass() ) {
|
|
ActivatShaders(rasty, cachingInfo);
|
|
dopass = true;
|
|
return dopass;
|
|
}
|
|
else {
|
|
bgl::blUseProgramObjectARB( 0 );
|
|
mPass = 0;
|
|
dopass = false;
|
|
return dopass;
|
|
}
|
|
}
|
|
else {
|
|
#endif//GL_ARB_shader_objects
|
|
switch (mPass++)
|
|
{
|
|
case 0:
|
|
ActivateMat(rasty, cachingInfo);
|
|
dopass = true;
|
|
break;
|
|
default:
|
|
mPass = 0;
|
|
dopass = false;
|
|
break;
|
|
}
|
|
#ifdef GL_ARB_shader_objects
|
|
}
|
|
#endif//GL_ARB_shader_objects
|
|
return dopass;
|
|
}
|
|
|
|
void KX_BlenderMaterial::setTextureEnvironment( int textureIndex )
|
|
{
|
|
#ifndef GL_ARB_texture_env_combine
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
return;
|
|
#else
|
|
if(textureIndex == -1 || !RAS_EXT_support._ARB_texture_env_combine){
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
|
|
return;
|
|
}
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
|
|
|
GLfloat blend_operand = GL_SRC_COLOR;
|
|
GLfloat blend_operand_prev = GL_SRC_COLOR;
|
|
|
|
GLenum combiner = GL_COMBINE_RGB_ARB;
|
|
GLenum source0 = GL_SOURCE0_RGB_ARB;
|
|
GLenum source1 = GL_SOURCE1_RGB_ARB;
|
|
GLenum source2 = GL_SOURCE2_RGB_ARB;
|
|
GLenum op0 = GL_OPERAND0_RGB_ARB;
|
|
GLenum op1 = GL_OPERAND1_RGB_ARB;
|
|
GLenum op2 = GL_OPERAND2_RGB_ARB;
|
|
GLfloat alphaOp = GL_SRC_ALPHA;
|
|
|
|
// switch to alpha combiners
|
|
if( (mMaterial->flag[textureIndex] &TEXALPHA) ) {
|
|
combiner = GL_COMBINE_ALPHA_ARB;
|
|
source0 = GL_SOURCE0_ALPHA_ARB;
|
|
source1 = GL_SOURCE1_ALPHA_ARB;
|
|
source2 = GL_SOURCE2_ALPHA_ARB;
|
|
op0 = GL_OPERAND0_ALPHA_ARB;
|
|
op1 = GL_OPERAND1_ALPHA_ARB;
|
|
op2 = GL_OPERAND2_ALPHA_ARB;
|
|
blend_operand = GL_SRC_ALPHA;
|
|
|
|
// invert
|
|
if(mMaterial->flag[textureIndex] &TEXNEG) {
|
|
blend_operand_prev = GL_ONE_MINUS_SRC_ALPHA;
|
|
blend_operand = GL_ONE_MINUS_SRC_ALPHA;
|
|
}
|
|
}
|
|
else {
|
|
if(mMaterial->flag[textureIndex] &TEXNEG) {
|
|
blend_operand_prev=GL_ONE_MINUS_SRC_COLOR;
|
|
blend_operand = GL_ONE_MINUS_SRC_COLOR;
|
|
}
|
|
}
|
|
bool using_alpha = false;
|
|
|
|
if(mMaterial->flag[textureIndex] &USEALPHA){
|
|
alphaOp = GL_ONE_MINUS_SRC_ALPHA;
|
|
using_alpha=true;
|
|
}
|
|
else if(mMaterial->flag[textureIndex] &USENEGALPHA){
|
|
alphaOp = GL_SRC_ALPHA;
|
|
using_alpha = true;
|
|
}
|
|
|
|
switch( mMaterial->blend_mode[textureIndex] ) {
|
|
case BLEND_MIX:
|
|
{
|
|
// ------------------------------
|
|
if(!using_alpha) {
|
|
GLfloat base_col[4];
|
|
base_col[0] = base_col[1] = base_col[2] = 0.f;
|
|
base_col[3] = 1.f-mMaterial->color_blend[textureIndex];
|
|
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,base_col );
|
|
}
|
|
glTexEnvf( GL_TEXTURE_ENV, combiner, GL_INTERPOLATE_ARB);
|
|
glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB);
|
|
glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
|
|
glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
|
|
if(!using_alpha)
|
|
glTexEnvf( GL_TEXTURE_ENV, source2, GL_CONSTANT_ARB );
|
|
else
|
|
glTexEnvf( GL_TEXTURE_ENV, source2, GL_TEXTURE );
|
|
|
|
glTexEnvf( GL_TEXTURE_ENV, op2, alphaOp);
|
|
}break;
|
|
case BLEND_MUL:
|
|
{
|
|
// ------------------------------
|
|
glTexEnvf( GL_TEXTURE_ENV, combiner, GL_MODULATE);
|
|
glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB);
|
|
glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev);
|
|
glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
|
|
if(using_alpha)
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
|
|
else
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
|
|
}break;
|
|
case BLEND_ADD:
|
|
{
|
|
// ------------------------------
|
|
glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD_SIGNED_ARB);
|
|
glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
|
|
glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
|
|
glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
|
|
if(using_alpha)
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
|
|
else
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
|
|
}break;
|
|
case BLEND_SUB:
|
|
{
|
|
// ------------------------------
|
|
glTexEnvf( GL_TEXTURE_ENV, combiner, GL_SUBTRACT_ARB);
|
|
glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
|
|
glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
|
|
glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
|
|
}break;
|
|
case BLEND_SCR:
|
|
{
|
|
// ------------------------------
|
|
glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD);
|
|
glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB );
|
|
glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev );
|
|
glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE );
|
|
if(using_alpha)
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp);
|
|
else
|
|
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
|
|
} break;
|
|
}
|
|
glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
|
|
#endif //!GL_ARB_texture_env_combine
|
|
}
|
|
|
|
bool KX_BlenderMaterial::setDefaultBlending()
|
|
{
|
|
if( mMaterial->transp &TF_ADD) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
return true;
|
|
}
|
|
|
|
if( mMaterial->transp & TF_ALPHA ) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
return true;
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
return false;
|
|
}
|
|
|
|
void KX_BlenderMaterial::setEnvMap(bool val, bool cube)
|
|
{
|
|
#ifdef GL_ARB_texture_cube_map
|
|
if( cube && RAS_EXT_support._ARB_texture_cube_map )
|
|
{
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB );
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
|
|
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable(GL_TEXTURE_GEN_R);
|
|
}
|
|
else {
|
|
#endif//GL_ARB_texture_cube_map
|
|
if( val ) {
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable(GL_TEXTURE_GEN_R);
|
|
}
|
|
else {
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
glDisable(GL_TEXTURE_GEN_R);
|
|
}
|
|
#ifdef GL_ARB_texture_cube_map
|
|
}
|
|
#endif//GL_ARB_texture_cube_map
|
|
}
|
|
|
|
|
|
void KX_BlenderMaterial::setTexMatrixData(int i)
|
|
{
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
|
|
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)
|
|
{
|
|
// will work without cubemaps
|
|
// but a cubemap will look the best
|
|
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);
|
|
|
|
float matr[16];
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, matr);
|
|
MT_Matrix4x4 mvmat(matr);
|
|
|
|
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 ),
|
|
// KX_PYMETHODTABLE( KX_BlenderMaterial, getTexture ),
|
|
// KX_PYMETHODTABLE( KX_BlenderMaterial, setTexture ),
|
|
|
|
{NULL,NULL} //Sentinel
|
|
};
|
|
|
|
|
|
PyTypeObject KX_BlenderMaterial::Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0,
|
|
"KX_BlenderMaterial",
|
|
sizeof(KX_BlenderMaterial),
|
|
0,
|
|
PyDestructor,
|
|
0,
|
|
__getattr,
|
|
__setattr,
|
|
0,
|
|
__repr,
|
|
0
|
|
};
|
|
|
|
|
|
PyParentObject KX_BlenderMaterial::Parents[] = {
|
|
&PyObjectPlus::Type,
|
|
&KX_BlenderMaterial::Type,
|
|
NULL
|
|
};
|
|
|
|
|
|
PyObject* KX_BlenderMaterial::_getattr(const STR_String& attr)
|
|
{
|
|
// nodda ?
|
|
_getattr_up(PyObjectPlus);
|
|
}
|
|
|
|
int KX_BlenderMaterial::_setattr(const STR_String& attr, PyObject *pyvalue)
|
|
{
|
|
return PyObjectPlus::_setattr(attr, pyvalue);
|
|
}
|
|
|
|
|
|
KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
|
|
{
|
|
#ifdef GL_ARB_fragment_shader
|
|
if( !RAS_EXT_support._ARB_fragment_shader) {
|
|
if(!mModified)
|
|
spit("Fragment shaders not supported");
|
|
|
|
mModified = true;
|
|
Py_Return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef GL_ARB_vertex_shader
|
|
if( !RAS_EXT_support._ARB_vertex_shader) {
|
|
if(!mModified)
|
|
spit("Vertex shaders not supported");
|
|
|
|
mModified = true;
|
|
Py_Return;
|
|
}
|
|
#endif
|
|
|
|
#ifdef GL_ARB_shader_objects
|
|
if(!RAS_EXT_support._ARB_shader_objects) {
|
|
if(!mModified)
|
|
spit("GLSL not supported");
|
|
mModified = true;
|
|
Py_Return;
|
|
}
|
|
else {
|
|
// returns Py_None on error
|
|
// the calling script will need to check
|
|
|
|
if(!mShader && !mModified) {
|
|
mShader = new BL_Shader();
|
|
for(int i= 0; i<mMaterial->num_enabled; i++) {
|
|
if(mMaterial->mapping[i].mapping & USEENV )
|
|
mShader->InitializeSampler(SAMP_CUBE, i, 0, mTextures[i]);
|
|
else
|
|
mShader->InitializeSampler(SAMP_2D, i, 0, mTextures[i]);
|
|
}
|
|
mModified = true;
|
|
}
|
|
|
|
if(mShader && !mShader->GetError()) {
|
|
Py_INCREF(mShader);
|
|
return mShader;
|
|
}else
|
|
{
|
|
// decref all references to the object
|
|
// then delete it!
|
|
// We will then go back to fixed functionality
|
|
// for this material
|
|
if(mShader) {
|
|
if(mShader->ob_refcnt > 1) {
|
|
Py_DECREF(mShader);
|
|
}
|
|
else {
|
|
delete mShader;
|
|
mShader=0;
|
|
}
|
|
}
|
|
}
|
|
Py_Return;
|
|
}
|
|
PyErr_Format(PyExc_ValueError, "GLSL Error");
|
|
return NULL;
|
|
|
|
#else
|
|
Py_Return;
|
|
#endif//GL_ARB_shader_objects
|
|
}
|
|
|
|
KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()")
|
|
{
|
|
return PyInt_FromLong( mMaterial->material_index );
|
|
}
|
|
|
|
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", &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_Format(PyExc_ValueError, "invalid enum.");
|
|
return NULL;
|
|
}
|
|
mUserDefBlend = true;
|
|
Py_Return;
|
|
}
|
|
return NULL;
|
|
}
|
|
|