forked from bartvdbraak/blender
386122ada6
This commit extends the technique of dynamic linked list to the logic system to eliminate as much as possible temporaries, map lookup or full scan. The logic engine is now free of memory allocation, which is an important stability factor. The overhead of the logic system is reduced by a factor between 3 and 6 depending on the logic setup. This is the speed-up you can expect on a logic setup using simple bricks. Heavy bricks like python controllers and ray sensors will still take about the same time to execute so the speed up will be less important. The core of the logic engine has been much reworked but the functionality is still the same except for one thing: the priority system on the execution of controllers. The exact same remark applies to actuators but I'll explain for controllers only: Previously, it was possible, with the "executePriority" attribute to set a controller to run before any other controllers in the game. Other than that, the sequential execution of controllers, as defined in Blender was guaranteed by default. With the new system, the sequential execution of controllers is still guaranteed but only within the controllers of one object. the user can no longer set a controller to run before any other controllers in the game. The "executePriority" attribute controls the execution of controllers within one object. The priority is a small number starting from 0 for the first controller and incrementing for each controller. If this missing feature is a must, a special method can be implemented to set a controller to run before all other controllers. Other improvements: - Systematic use of reference in parameter passing to avoid unnecessary data copy - Use pre increment in iterator instead of post increment to avoid temporary allocation - Use const char* instead of STR_String whenever possible to avoid temporary allocation - Fix reference counting bugs (memory leak) - Fix a crash in certain cases of state switching and object deletion - Minor speed up in property sensor - Removal of objects during the game is a lot faster
975 lines
22 KiB
C++
975 lines
22 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(
|
|
PyTypeObject *T
|
|
)
|
|
: PyObjectPlus(T),
|
|
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,
|
|
bool skin,
|
|
int lightlayer)
|
|
{
|
|
RAS_IPolyMaterial::Initialize(
|
|
data->texname[0],
|
|
data->matname,
|
|
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::ReleaseMaterial()
|
|
{
|
|
if (mBlenderShader)
|
|
mBlenderShader->ReloadMaterial();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
//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);
|
|
}
|
|
|
|
//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)
|
|
{
|
|
if (!mMaterial->mapping[i].uvCoName.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;
|
|
obj->Release(); /* FindValue() AddRef's */
|
|
|
|
obj->Release();
|
|
|
|
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[] = {
|
|
//KX_PYATTRIBUTE_TODO("shader"),
|
|
//KX_PYATTRIBUTE_TODO("materialIndex"),
|
|
//KX_PYATTRIBUTE_TODO("blending"),
|
|
{ NULL } //Sentinel
|
|
};
|
|
|
|
PyTypeObject KX_BlenderMaterial::Type = {
|
|
#if (PY_VERSION_HEX >= 0x02060000)
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
#else
|
|
/* python 2.5 and below */
|
|
PyObject_HEAD_INIT( NULL ) /* required py macro */
|
|
0, /* ob_size */
|
|
#endif
|
|
"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;
|
|
}
|
|
|