blender/source/gameengine/Ketsji/BL_Shader.cpp
Brecht Van Lommel 272a91f754 Merge of apricot branch game engine changes into trunk, excluding GLSL.
GLEW
====

Added the GLEW opengl extension library into extern/, always compiled
into Blender now. This is much nicer than doing this kind of extension
management manually, and will be used in the game engine, for GLSL, and
other opengl extensions.

* According to the GLEW website it works on Windows, Linux, Mac OS X,
  FreeBSD, Irix, and Solaris. There might still be platform specific
  issues due to this commit, so let me know and I'll look into it.
* This means also that all extensions will now always be compiled in,
  regardless of the glext.h on the platform where compilation happens.

Game Engine
===========

Refactoring of the use of opengl extensions and other drawing code
in the game engine, and cleaning up some hacks related to GLSL
integration. These changes will be merged into trunk too after this.

The game engine graphics demos & apricot level survived my tests,
but this could use some good testing of course.

For users: please test with the options "Generate Display Lists" and
"Vertex Arrays" enabled, these should be the fastest and are supposed
to be "unreliable", but if that's the case that's probably due to bugs
that can be fixed.

* The game engine now also uses GLEW for extensions, replacing the
  custom opengl extensions code that was there. Removes a lot of
  #ifdef's, but the runtime checks stay of course.
* Removed the WITHOUT_GLEXT environment variable. This was added to
  work around a specific bug and only disabled multitexturing anyway.
  It might also have caused a slowdown since it was retrieving the
  environment variable for every vertex in immediate mode (bug #13680).

* Refactored the code to allow drawing skinned meshes with vertex
  arrays too, removing some specific immediate mode drawing functions
  for this that only did extra normal calculation. Now it always splits
  vertices of flat faces instead.
* Refactored normal recalculation with some minor optimizations,
  required for the above change.
* Removed some outdated code behind the __NLA_OLDDEFORM #ifdef.
* Fixed various bugs in setting of multitexture coordinates and vertex
  attributes for vertex arrays. These were not being enabled/disabled
  correct according to the opengl spec, leading to crashes. Also tangent
  attributes used an immediate mode call for vertex arrays, which can't
  work.
* Fixed use of uninitialized variable in RAS_TexVert.
* Exporting skinned meshes was doing O(n^2) lookups for vertices and
  deform weights, now uses same trick as regular meshes.
2008-06-17 10:27:34 +00:00

1408 lines
28 KiB
C++

#include "GL/glew.h"
#include <iostream>
#include "BL_Shader.h"
#include "BL_Material.h"
#include "MT_assert.h"
#include "MT_Matrix4x4.h"
#include "MT_Matrix3x3.h"
#include "KX_PyMath.h"
#include "MEM_guardedalloc.h"
#include "RAS_GLExtensionManager.h"
#include "RAS_MeshObject.h"
#include "RAS_IRasterizer.h"
#define spit(x) std::cout << x << std::endl;
#define SORT_UNIFORMS 1
#define UNIFORM_MAX_LEN sizeof(float)*16
#define MAX_LOG_LEN 262144 // bounds
BL_Uniform::BL_Uniform(int data_size)
: mLoc(-1),
mDirty(true),
mType(UNI_NONE),
mTranspose(0),
mDataLen(data_size)
{
#ifdef SORT_UNIFORMS
MT_assert((int)mDataLen <= UNIFORM_MAX_LEN);
mData = (void*)MEM_mallocN(mDataLen, "shader-uniform-alloc");
#endif
}
BL_Uniform::~BL_Uniform()
{
#ifdef SORT_UNIFORMS
if(mData) {
MEM_freeN(mData);
mData=0;
}
#endif
}
void BL_Uniform::Apply(class BL_Shader *shader)
{
#ifdef SORT_UNIFORMS
MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
if(!mDirty)
return;
switch(mType)
{
case UNI_FLOAT: {
float *f = (float*)mData;
glUniform1fARB(mLoc,(GLfloat)*f);
}break;
case UNI_INT: {
int *f = (int*)mData;
glUniform1iARB(mLoc, (GLint)*f);
}break;
case UNI_FLOAT2: {
float *f = (float*)mData;
glUniform2fvARB(mLoc,1, (GLfloat*)f);
}break;
case UNI_FLOAT3: {
float *f = (float*)mData;
glUniform3fvARB(mLoc,1,(GLfloat*)f);
}break;
case UNI_FLOAT4: {
float *f = (float*)mData;
glUniform4fvARB(mLoc,1,(GLfloat*)f);
}break;
case UNI_INT2: {
int *f = (int*)mData;
glUniform2ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_INT3: {
int *f = (int*)mData;
glUniform3ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_INT4: {
int *f = (int*)mData;
glUniform4ivARB(mLoc,1,(GLint*)f);
}break;
case UNI_MAT4: {
float *f = (float*)mData;
glUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
}break;
case UNI_MAT3: {
float *f = (float*)mData;
glUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
}break;
}
mDirty = false;
#endif
}
void BL_Uniform::SetData(int location, int type,bool transpose)
{
#ifdef SORT_UNIFORMS
mType = type;
mLoc = location;
mDirty = true;
#endif
}
const bool BL_Shader::Ok()const
{
return (mShader !=0 && mOk && mUse);
}
BL_Shader::BL_Shader(PyTypeObject *T)
: PyObjectPlus(T),
mShader(0),
mPass(1),
mOk(0),
mUse(0),
mAttr(0),
vertProg(""),
fragProg(""),
mError(0),
mDirty(true)
{
// if !GLEW_ARB_shader_objects this class will not be used
//for (int i=0; i<MAXTEX; i++) {
// mSampler[i] = BL_Sampler();
//}
}
BL_Shader::~BL_Shader()
{
//for (int i=0; i<MAXTEX; i++){
// if(mSampler[i].mOwn) {
// if(mSampler[i].mTexture)
// mSampler[i].mTexture->DeleteTex();
// }
//}
ClearUniforms();
if( mShader ) {
glDeleteObjectARB(mShader);
mShader = 0;
}
vertProg = 0;
fragProg = 0;
mOk = 0;
glUseProgramObjectARB(0);
}
void BL_Shader::ClearUniforms()
{
BL_UniformVec::iterator it = mUniforms.begin();
while(it != mUniforms.end()){
delete (*it);
it++;
}
mUniforms.clear();
BL_UniformVecDef::iterator itp = mPreDef.begin();
while(itp != mPreDef.end()) {
delete (*itp);
itp++;
}
mPreDef.clear();
}
BL_Uniform *BL_Shader::FindUniform(const int location)
{
#ifdef SORT_UNIFORMS
BL_UniformVec::iterator it = mUniforms.begin();
while(it != mUniforms.end()) {
if((*it)->GetLocation() == location)
return (*it);
it++;
}
#endif
return 0;
}
void BL_Shader::SetUniformfv(int location, int type, float *param,int size, bool transpose)
{
#ifdef SORT_UNIFORMS
BL_Uniform *uni= FindUniform(location);
if(uni) {
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
}
else {
uni = new BL_Uniform(size);
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
mUniforms.push_back(uni);
}
mDirty = true;
#endif
}
void BL_Shader::SetUniformiv(int location, int type, int *param,int size, bool transpose)
{
#ifdef SORT_UNIFORMS
BL_Uniform *uni= FindUniform(location);
if(uni) {
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
}
else {
uni = new BL_Uniform(size);
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
mUniforms.push_back(uni);
}
mDirty = true;
#endif
}
void BL_Shader::ApplyShader()
{
#ifdef SORT_UNIFORMS
if(!mDirty)
return;
for(unsigned int i=0; i<mUniforms.size(); i++)
mUniforms[i]->Apply(this);
mDirty = false;
#endif
}
void BL_Shader::UnloadShader()
{
//
}
bool BL_Shader::LinkProgram()
{
int vertlen = 0, fraglen=0, proglen=0;
int vertstatus=0, fragstatus=0, progstatus=0;
unsigned int tmpVert=0, tmpFrag=0, tmpProg=0;
int char_len=0;
char *logInf =0;
if(mError)
goto programError;
if(!vertProg || !fragProg){
spit("Invalid GLSL sources");
return false;
}
if( !GLEW_ARB_fragment_shader) {
spit("Fragment shaders not supported");
return false;
}
if( !GLEW_ARB_vertex_shader) {
spit("Vertex shaders not supported");
return false;
}
// -- vertex shader ------------------
tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
glCompileShaderARB(tmpVert);
glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen);
// print info if any
if( vertlen > 0 && vertlen < MAX_LOG_LEN){
logInf = (char*)MEM_mallocN(vertlen, "vert-log");
glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
if(char_len >0) {
spit("---- Vertex Shader Error ----");
spit(logInf);
}
MEM_freeN(logInf);
logInf=0;
}
// check for compile errors
glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus);
if(!vertstatus) {
spit("---- Vertex shader failed to compile ----");
goto programError;
}
// -- fragment shader ----------------
tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
glShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0);
glCompileShaderARB(tmpFrag);
glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen);
if(fraglen >0 && fraglen < MAX_LOG_LEN){
logInf = (char*)MEM_mallocN(fraglen, "frag-log");
glGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf);
if(char_len >0) {
spit("---- Fragment Shader Error ----");
spit(logInf);
}
MEM_freeN(logInf);
logInf=0;
}
glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus);
if(!fragstatus){
spit("---- Fragment shader failed to compile ----");
goto programError;
}
// -- program ------------------------
// set compiled vert/frag shader & link
tmpProg = glCreateProgramObjectARB();
glAttachObjectARB(tmpProg, tmpVert);
glAttachObjectARB(tmpProg, tmpFrag);
glLinkProgramARB(tmpProg);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen);
glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus);
if(proglen > 0 && proglen < MAX_LOG_LEN) {
logInf = (char*)MEM_mallocN(proglen, "prog-log");
glGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf);
if(char_len >0) {
spit("---- GLSL Program ----");
spit(logInf);
}
MEM_freeN(logInf);
logInf=0;
}
if(!progstatus){
spit("---- GLSL program failed to link ----");
goto programError;
}
// set
mShader = tmpProg;
glDeleteObjectARB(tmpVert);
glDeleteObjectARB(tmpFrag);
mOk = 1;
mError = 0;
return true;
programError:
if(tmpVert) {
glDeleteObjectARB(tmpVert);
tmpVert=0;
}
if(tmpFrag) {
glDeleteObjectARB(tmpFrag);
tmpFrag=0;
}
if(tmpProg) {
glDeleteObjectARB(tmpProg);
tmpProg=0;
}
mOk = 0;
mUse = 0;
mError = 1;
return false;
}
const char *BL_Shader::GetVertPtr()
{
return vertProg?vertProg:0;
}
const char *BL_Shader::GetFragPtr()
{
return fragProg?fragProg:0;
}
void BL_Shader::SetVertPtr( char *vert )
{
vertProg = vert;
}
void BL_Shader::SetFragPtr( char *frag )
{
fragProg = frag;
}
unsigned int BL_Shader::GetProg()
{
return mShader;
}
//
//const BL_Sampler* BL_Shader::GetSampler(int i)
//{
// MT_assert(i<=MAXTEX);
// return &mSampler[i];
//}
void BL_Shader::SetSampler(int loc, int unit)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
glUniform1iARB(loc, unit);
}
}
//
//void BL_Shader::InitializeSampler(int unit, BL_Texture* texture)
//{
// MT_assert(unit<=MAXTEX);
// mSampler[unit].mTexture = texture;
// mSampler[unit].mLoc =-1;
// mSampler[unit].mOwn = 0;
//}
void BL_Shader::SetProg(bool enable)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
if( mShader != 0 && mOk && enable) {
glUseProgramObjectARB(mShader);
}
else {
glUseProgramObjectARB(0);
}
}
}
void BL_Shader::Update( const KX_MeshSlot & ms, RAS_IRasterizer* rasty )
{
if(!Ok() || !mPreDef.size())
return;
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
MT_Matrix4x4 model;
model.setValue(ms.m_OpenGLMatrix);
MT_Matrix4x4 view;
rasty->GetViewMatrix(view);
if(mAttr==SHD_TANGENT)
ms.m_mesh->SetMeshModified(true);
BL_UniformVecDef::iterator it;
for(it = mPreDef.begin(); it!= mPreDef.end(); it++)
{
BL_DefUniform *uni = (*it);
if(uni->mLoc == -1) continue;
switch (uni->mType)
{
case MODELMATRIX:
{
SetUniform(uni->mLoc, model);
break;
}
case MODELMATRIX_TRANSPOSE:
{
SetUniform(uni->mLoc, model, true);
break;
}
case MODELMATRIX_INVERSE:
{
model.invert();
SetUniform(uni->mLoc, model);
break;
}
case MODELMATRIX_INVERSETRANSPOSE:
{
model.invert();
SetUniform(uni->mLoc, model, true);
break;
}
case MODELVIEWMATRIX:
{
SetUniform(uni->mLoc, view*model);
break;
}
case MODELVIEWMATRIX_TRANSPOSE:
{
MT_Matrix4x4 mat(view*model);
SetUniform(uni->mLoc, mat, true);
break;
}
case MODELVIEWMATRIX_INVERSE:
{
MT_Matrix4x4 mat(view*model);
mat.invert();
SetUniform(uni->mLoc, mat);
break;
}
case MODELVIEWMATRIX_INVERSETRANSPOSE:
{
MT_Matrix4x4 mat(view*model);
mat.invert();
SetUniform(uni->mLoc, mat, true);
break;
}
case CAM_POS:
{
MT_Point3 pos(rasty->GetCameraPosition());
SetUniform(uni->mLoc, pos);
break;
}
case VIEWMATRIX:
{
SetUniform(uni->mLoc, view);
break;
}
case VIEWMATRIX_TRANSPOSE:
{
SetUniform(uni->mLoc, view, true);
break;
}
case VIEWMATRIX_INVERSE:
{
view.invert();
SetUniform(uni->mLoc, view);
break;
}
case VIEWMATRIX_INVERSETRANSPOSE:
{
view.invert();
SetUniform(uni->mLoc, view, true);
break;
}
case CONSTANT_TIMER:
{
SetUniform(uni->mLoc, (float)rasty->GetTime());
break;
}
default:
break;
}
}
}
}
int BL_Shader::GetAttribLocation(const STR_String& name)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
return glGetAttribLocationARB(mShader, name.ReadPtr());
}
return -1;
}
void BL_Shader::BindAttribute(const STR_String& attr, int loc)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
glBindAttribLocationARB(mShader, loc, attr.ReadPtr());
}
}
int BL_Shader::GetUniformLocation(const STR_String& name)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
MT_assert(mShader!=0);
int location = glGetUniformLocationARB(mShader, name.ReadPtr());
if(location == -1)
spit("Invalid uniform value: " << name.ReadPtr() << ".");
return location;
}
return -1;
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple2& vec)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
float value[2];
vec.getValue(value);
glUniform2fvARB(uniform, 1, value);
}
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple3& vec)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
float value[3];
vec.getValue(value);
glUniform3fvARB(uniform, 1, value);
}
}
void BL_Shader::SetUniform(int uniform, const MT_Tuple4& vec)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
float value[4];
vec.getValue(value);
glUniform4fvARB(uniform, 1, value);
}
}
void BL_Shader::SetUniform(int uniform, const unsigned int& val)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
glUniform1iARB(uniform, val);
}
}
void BL_Shader::SetUniform(int uniform, const int val)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
glUniform1iARB(uniform, val);
}
}
void BL_Shader::SetUniform(int uniform, const float& val)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
glUniform1fARB(uniform, val);
}
}
void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
float value[16];
vec.getValue(value);
glUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
}
}
void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
float value[9];
value[0] = (float)vec[0][0]; value[1] = (float)vec[1][0]; value[2] = (float)vec[2][0];
value[3] = (float)vec[0][1]; value[4] = (float)vec[1][1]; value[5] = (float)vec[2][1];
value[6] = (float)vec[0][2]; value[7] = (float)vec[1][2]; value[7] = (float)vec[2][2];
glUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
}
}
void BL_Shader::SetUniform(int uniform, const float* val, int len)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
if(len == 2)
glUniform2fvARB(uniform, 1,(GLfloat*)val);
else if (len == 3)
glUniform3fvARB(uniform, 1,(GLfloat*)val);
else if (len == 4)
glUniform4fvARB(uniform, 1,(GLfloat*)val);
else
MT_assert(0);
}
}
void BL_Shader::SetUniform(int uniform, const int* val, int len)
{
if( GLEW_ARB_fragment_shader &&
GLEW_ARB_vertex_shader &&
GLEW_ARB_shader_objects
)
{
if(len == 2)
glUniform2ivARB(uniform, 1, (GLint*)val);
else if (len == 3)
glUniform3ivARB(uniform, 1, (GLint*)val);
else if (len == 4)
glUniform4ivARB(uniform, 1, (GLint*)val);
else
MT_assert(0);
}
}
PyObject* BL_Shader::_getattr(const STR_String& attr)
{
_getattr_up(PyObjectPlus);
}
PyMethodDef BL_Shader::Methods[] =
{
// creation
KX_PYMETHODTABLE( BL_Shader, setSource ),
KX_PYMETHODTABLE( BL_Shader, delSource ),
KX_PYMETHODTABLE( BL_Shader, getVertexProg ),
KX_PYMETHODTABLE( BL_Shader, getFragmentProg ),
KX_PYMETHODTABLE( BL_Shader, setNumberOfPasses ),
KX_PYMETHODTABLE( BL_Shader, validate),
/// access functions
KX_PYMETHODTABLE( BL_Shader, isValid),
KX_PYMETHODTABLE( BL_Shader, setUniform1f ),
KX_PYMETHODTABLE( BL_Shader, setUniform2f ),
KX_PYMETHODTABLE( BL_Shader, setUniform3f ),
KX_PYMETHODTABLE( BL_Shader, setUniform4f ),
KX_PYMETHODTABLE( BL_Shader, setUniform1i ),
KX_PYMETHODTABLE( BL_Shader, setUniform2i ),
KX_PYMETHODTABLE( BL_Shader, setUniform3i ),
KX_PYMETHODTABLE( BL_Shader, setUniform4i ),
KX_PYMETHODTABLE( BL_Shader, setAttrib ),
KX_PYMETHODTABLE( BL_Shader, setUniformfv ),
KX_PYMETHODTABLE( BL_Shader, setUniformiv ),
KX_PYMETHODTABLE( BL_Shader, setUniformDef ),
KX_PYMETHODTABLE( BL_Shader, setSampler ),
KX_PYMETHODTABLE( BL_Shader, setUniformMatrix4 ),
KX_PYMETHODTABLE( BL_Shader, setUniformMatrix3 ),
{NULL,NULL} //Sentinel
};
PyTypeObject BL_Shader::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"BL_Shader",
sizeof(BL_Shader),
0,
PyDestructor,
0,
__getattr,
__setattr,
0,
__repr,
0
};
PyParentObject BL_Shader::Parents[] = {
&PyObjectPlus::Type,
&BL_Shader::Type,
NULL
};
KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" )
{
if(mShader !=0 && mOk )
{
// already set...
Py_Return;
}
char *v,*f;
int apply=0;
if( PyArg_ParseTuple(args, "ssi", &v, &f, &apply) )
{
vertProg = v;
fragProg = f;
if( LinkProgram() ) {
glUseProgramObjectARB( mShader );
mUse = apply!=0;
Py_Return;
}
vertProg = 0;
fragProg = 0;
mUse = 0;
Py_Return;
}
Py_Return;
}
KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" )
{
ClearUniforms();
glUseProgramObjectARB(0);
glDeleteObjectARB(mShader);
mShader = 0;
mOk = 0;
mUse = 0;
Py_Return;
}
KX_PYMETHODDEF_DOC( BL_Shader, isValid, "isValid()" )
{
return PyInt_FromLong( ( mShader !=0 && mOk ) );
}
KX_PYMETHODDEF_DOC( BL_Shader, getVertexProg ,"getVertexProg( )" )
{
return PyString_FromString(vertProg?vertProg:"");
}
KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg ,"getFragmentProg( )" )
{
return PyString_FromString(fragProg?fragProg:"");
}
KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
if(mShader==0) {
PyErr_Format(PyExc_TypeError, "invalid shader object");
return NULL;
}
int stat = 0;
glValidateProgramARB(mShader);
glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat);
if(stat > 0 && stat < MAX_LOG_LEN) {
int char_len=0;
char *logInf = (char*)MEM_mallocN(stat, "validate-log");
glGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf);
if(char_len >0) {
spit("---- GLSL Validation ----");
spit(logInf);
}
MEM_freeN(logInf);
logInf=0;
}
Py_Return;
}
KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int index=-1;
if(PyArg_ParseTuple(args, "si", &uniform, &index))
{
int loc = GetUniformLocation(uniform);
if(loc != -1) {
if(index >= MAXTEX && index < 0)
spit("Invalid texture sample index: " << index);
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT, &index, (sizeof(int)) );
#else
SetUniform(loc, index);
#endif
//if(index <= MAXTEX)
// mSampler[index].mLoc = loc;
//else
// spit("Invalid texture sample index: " << index);
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )" )
{
int pass = 1;
if(!PyArg_ParseTuple(args, "i", &pass))
return NULL;
mPass = 1;
Py_Return;
}
/// access functions
KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
float value=0;
if(PyArg_ParseTuple(args, "sf", &uniform, &value ))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT, &value, sizeof(float));
#else
SetUniform( loc, (float)value );
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f , "setUniform2f(name, fx, fy)")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
float array[2]={ 0,0 };
if(PyArg_ParseTuple(args, "sff", &uniform, &array[0],&array[1] ))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array, (sizeof(float)*2) );
#else
SetUniform(loc, array, 2);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
float array[3]={0,0,0};
if(PyArg_ParseTuple(args, "sfff", &uniform, &array[0],&array[1],&array[2]))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array, (sizeof(float)*3) );
#else
SetUniform(loc, array, 3);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
float array[4]={0,0,0,0};
if(PyArg_ParseTuple(args, "sffff", &uniform, &array[0],&array[1],&array[2], &array[3]))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array, (sizeof(float)*4) );
#else
SetUniform(loc, array, 4);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int value=0;
if(PyArg_ParseTuple(args, "si", &uniform, &value ))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT, &value, sizeof(int));
#else
SetUniform(loc, (int)value);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i , "setUniform2i(name, ix, iy)")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int array[2]={ 0,0 };
if(PyArg_ParseTuple(args, "sii", &uniform, &array[0],&array[1] ))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT2, array, sizeof(int)*2);
#else
SetUniform(loc, array, 2);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int array[3]={0,0,0};
if(PyArg_ParseTuple(args, "siii", &uniform, &array[0],&array[1],&array[2]))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT3, array, sizeof(int)*3);
#else
SetUniform(loc, array, 3);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int array[4]={0,0,0, 0};
if(PyArg_ParseTuple(args, "siiii", &uniform, &array[0],&array[1],&array[2], &array[3] ))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT4, array, sizeof(int)*4);
#else
SetUniform(loc, array, 4);
#endif
}
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv , "setUniformfv( float (list2 or list3 or list4) )")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char*uniform = "";
PyObject *listPtr =0;
float array_data[4] = {0.f,0.f,0.f,0.f};
if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
if(PySequence_Check(listPtr))
{
unsigned int list_size = PySequence_Size(listPtr);
for(unsigned int i=0; (i<list_size && i<4); i++)
{
PyObject *item = PySequence_GetItem(listPtr, i);
array_data[i] = (float)PyFloat_AsDouble(item);
Py_DECREF(item);
}
switch(list_size)
{
case 2:
{
float array2[2] = { array_data[0],array_data[1] };
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array2, sizeof(float)*2);
#else
SetUniform(loc, array2, 2);
#endif
Py_Return;
} break;
case 3:
{
float array3[3] = { array_data[0],array_data[1],array_data[2] };
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array3, sizeof(float)*3);
#else
SetUniform(loc, array3, 3);
#endif
Py_Return;
}break;
case 4:
{
float array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array4, sizeof(float)*4);
#else
SetUniform(loc, array4, 4);
#endif
Py_Return;
}break;
default:
{
PyErr_Format(PyExc_TypeError, "Invalid list size");
return NULL;
}break;
}
}
}
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( int (list2 or list3 or list4) )")
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char*uniform = "";
PyObject *listPtr =0;
int array_data[4] = {0,0,0,0};
if(PyArg_ParseTuple(args, "sO", &uniform, &listPtr))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
if(PySequence_Check(listPtr))
{
unsigned int list_size = PySequence_Size(listPtr);
for(unsigned int i=0; (i<list_size && i<4); i++)
{
PyObject *item = PySequence_GetItem(listPtr, i);
array_data[i] = PyInt_AsLong(item);
Py_DECREF(item);
}
switch(list_size)
{
case 2:
{
int array2[2] = { array_data[0],array_data[1]};
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int)*2);
#else
SetUniform(loc, array2, 2);
#endif
Py_Return;
} break;
case 3:
{
int array3[3] = { array_data[0],array_data[1],array_data[2] };
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int)*3);
#else
SetUniform(loc, array3, 3);
#endif
Py_Return;
}break;
case 4:
{
int array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int)*4);
#else
SetUniform(loc, array4, 4);
#endif
Py_Return;
}break;
default:
{
PyErr_Format(PyExc_TypeError, "Invalid list size");
return NULL;
}break;
}
}
}
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4,
"setUniformMatrix4(uniform-name, mat-4x4, transpose(row-major=true, col-major=false)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
float matr[16] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};
char *uniform="";
PyObject *matrix=0;
int transp=1; // MT_ is row major so transpose by default....
if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
if (PyObject_IsMT_Matrix(matrix, 4))
{
MT_Matrix4x4 mat;
if (PyMatTo(matrix, mat))
{
#ifdef SORT_UNIFORMS
mat.getValue(matr);
SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float)*16), (transp!=0) );
#else
SetUniform(loc,mat,(transp!=0));
#endif
Py_Return;
}
}
}
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
"setUniformMatrix3(uniform-name, list[3x3], transpose(row-major=true, col-major=false)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
float matr[9] = {
1,0,0,
0,1,0,
0,0,1,
};
char *uniform="";
PyObject *matrix=0;
int transp=1; // MT_ is row major so transpose by default....
if(PyArg_ParseTuple(args, "sO|i",&uniform, &matrix,&transp))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
if (PyObject_IsMT_Matrix(matrix, 3))
{
MT_Matrix3x3 mat;
if (PyMatTo(matrix, mat))
{
#ifdef SORT_UNIFORMS
mat.getValue(matr);
SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float)*9), (transp!=0) );
#else
SetUniform(loc,mat,(transp!=0));
#endif
Py_Return;
}
}
}
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
int attr=0;
if(PyArg_ParseTuple(args, "i", &attr )) {
if(mShader==0) {
PyErr_Format(PyExc_ValueError, "invalid shader object");
return NULL;
}
mAttr=SHD_TANGENT;
glUseProgramObjectARB(mShader);
glBindAttribLocationARB(mShader, mAttr, "Tangent");
Py_Return;
}
return NULL;
}
KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" )
{
if(mError) {
Py_INCREF(Py_None);
return Py_None;
}
char *uniform="";
int nloc=0;
if(PyArg_ParseTuple(args, "si",&uniform, &nloc))
{
int loc = GetUniformLocation(uniform);
if(loc != -1)
{
bool defined = false;
BL_UniformVecDef::iterator it = mPreDef.begin();
while(it != mPreDef.end()) {
if((*it)->mLoc == loc) {
defined = true;
break;
}
it++;
}
if(defined)
{
Py_Return;
}
BL_DefUniform *uni = new BL_DefUniform();
uni->mLoc = loc;
uni->mType = nloc;
uni->mFlag = 0;
mPreDef.push_back(uni);
Py_Return;
}
}
return NULL;
}
// eof