forked from bartvdbraak/blender
82c845425f
Any GLSL materials loaded after lights are LibLoaded will now use the lights in heir shaders. This includes materials loaded from the same scene as the LibLoaded lights. We could later add a new flag to LibLoad to recompile all existing shaders, but this commit should offer a lot more flexibility as is.
1014 lines
24 KiB
C++
1014 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;
|
|
|
|
// 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(void) const
|
|
{
|
|
// fonts on polys
|
|
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.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 (ELEM3(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID)
|
|
alphablend = mMaterial->alphablend;
|
|
|
|
rasty->SetAlphaBlend(alphablend);
|
|
}
|
|
}
|
|
|
|
void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
|
|
{
|
|
if (mShader || !mBlenderShader) {
|
|
rasty->SetSpecularity(
|
|
mMaterial->speccolor[0]*mMaterial->spec_f,
|
|
mMaterial->speccolor[1]*mMaterial->spec_f,
|
|
mMaterial->speccolor[2]*mMaterial->spec_f,
|
|
mMaterial->spec_f
|
|
);
|
|
|
|
rasty->SetShinyness( mMaterial->hard );
|
|
|
|
rasty->SetDiffuse(
|
|
mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit,
|
|
mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit,
|
|
mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit,
|
|
1.0f);
|
|
|
|
rasty->SetEmissive(
|
|
mMaterial->matcolor[0]*mMaterial->emit,
|
|
mMaterial->matcolor[1]*mMaterial->emit,
|
|
mMaterial->matcolor[2]*mMaterial->emit,
|
|
1.0 );
|
|
|
|
rasty->SetAmbient(mMaterial->amb);
|
|
}
|
|
|
|
if (mMaterial->material)
|
|
rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
|
|
}
|
|
|
|
|
|
void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const
|
|
{
|
|
if (ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED ||
|
|
(ras->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !ras->GetUsingOverrideShader())) {
|
|
ras->SetAttribNum(0);
|
|
if (mShader && GLEW_ARB_shader_objects) {
|
|
if (mShader->GetAttribute() == BL_Shader::SHD_TANGENT) {
|
|
ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0);
|
|
ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1);
|
|
ras->SetAttribNum(2);
|
|
}
|
|
}
|
|
|
|
ras->SetTexCoordNum(mMaterial->num_enabled);
|
|
|
|
for (int i=0; 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 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
|