forked from bartvdbraak/blender
1015 lines
24 KiB
C++
1015 lines
24 KiB
C++
/*
|
|
* ***** 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 "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"
|
|
// ------------------------------------
|
|
#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; i<BL_Texture::GetMaxUnits(); i++) {
|
|
m_multimode += (mMaterial->flag[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; i<BL_Texture::GetMaxUnits(); 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");
|
|
}
|
|
/* 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("<<i<<") in "<<
|
|
mMaterial->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; i<BL_Texture::GetMaxUnits(); i++) {
|
|
if (!mTextures[i].Ok()) continue;
|
|
BL_Texture::ActivateUnit(i);
|
|
mTextures[i].DeleteTex();
|
|
mTextures[i].DisableUnit();
|
|
}
|
|
|
|
/* used to call with 'mMaterial->tface' 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; i<BL_Texture::GetMaxUnits(); i++) {
|
|
if (!mTextures[i].Ok()) continue;
|
|
mTextures[i].ActivateTexture();
|
|
mTextures[0].SetMapping(mMaterial->mapping[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; i<BL_Texture::GetMaxUnits(); 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->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<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 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<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 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<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 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 (ELEM(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; i<BL_Texture::GetMaxUnits(); i++) {
|
|
int mode = mMaterial->mapping[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<KX_Scene *>(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<KX_BlenderMaterial*>(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<KX_BlenderMaterial*>(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<KX_BlenderMaterial*>(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<KX_BlenderMaterial*>(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
|