blender/source/gameengine/Ketsji/BL_Shader.cpp
Mitchell Stokes 964107fbce BGE code cleanup: Removing RAS_GLExtensionManager.
This class did nothing but print out extensions if they were found.
Instead, the code from bge.logic.PrintGLInfo() is now printed as the
Rasterizer is initialized. This gives better information, and it removes
some GL code from KX_PythonInit.cpp (the PrintGLInfo method now calls
the Rasterizer to print the information).

Differential Revision: https://developer.blender.org/D438
2015-12-07 19:25:12 -08:00

1437 lines
31 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/BL_Shader.cpp
* \ingroup ketsji
*/
#include "glew-mx.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_MeshObject.h"
#include "RAS_IRasterizer.h"
#define spit(x) std::cout << x << std::endl;
#define SORT_UNIFORMS 1
#define UNIFORM_MAX_LEN (int)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 = NULL;
}
#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
}
bool BL_Shader::Ok()const
{
return (mShader != 0 && mOk && mUse);
}
BL_Shader::BL_Shader()
:
PyObjectPlus(),
mShader(0),
mPass(1),
mOk(0),
mUse(0),
mAttr(0),
vertProg(NULL),
fragProg(NULL),
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 = NULL;
fragProg = NULL;
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 NULL;
}
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 = NULL;
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 : NULL;
}
const char *BL_Shader::GetFragPtr()
{
return fragProg ? fragProg : NULL;
}
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 RAS_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);
const MT_Matrix4x4 &view = rasty->GetViewMatrix();
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:
{
MT_Matrix4x4 viewinv = view;
viewinv.invert();
SetUniform(uni->mLoc, view);
break;
}
case VIEWMATRIX_INVERSETRANSPOSE:
{
MT_Matrix4x4 viewinv = view;
viewinv.invert();
SetUniform(uni->mLoc, view, true);
break;
}
case CONSTANT_TIMER:
{
SetUniform(uni->mLoc, (float)rasty->GetTime());
break;
}
default:
break;
}
}
}
}
int BL_Shader::GetAttribLocation(const char *name)
{
if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
return glGetAttribLocationARB(mShader, name);
}
return -1;
}
void BL_Shader::BindAttribute(const char *attr, int loc)
{
if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glBindAttribLocationARB(mShader, loc, attr);
}
}
int BL_Shader::GetUniformLocation(const char *name)
{
if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
MT_assert(mShader != 0);
int location = glGetUniformLocationARB(mShader, name);
if (location == -1) {
spit("Invalid uniform value: " << name << ".");
}
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];
// note: getValue gives back column major as needed by OpenGL
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[8] = (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);
}
}
}
#ifdef WITH_PYTHON
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
};
PyAttributeDef BL_Shader::Attributes[] = {
{NULL} //Sentinel
};
PyTypeObject BL_Shader::Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"BL_Shader",
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
};
KX_PYMETHODDEF_DOC(BL_Shader, setSource, " setSource(vertexProgram, fragmentProgram)")
{
if (mShader != 0 && mOk) {
// already set...
Py_RETURN_NONE;
}
char *v, *f;
int apply = 0;
if (PyArg_ParseTuple(args, "ssi:setSource", &v, &f, &apply)) {
vertProg = v;
fragProg = f;
if (LinkProgram()) {
glUseProgramObjectARB(mShader);
mUse = apply != 0;
Py_RETURN_NONE;
}
vertProg = NULL;
fragProg = NULL;
mUse = 0;
Py_RETURN_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, delSource, "delSource( )")
{
ClearUniforms();
glUseProgramObjectARB(0);
glDeleteObjectARB(mShader);
mShader = 0;
mOk = 0;
mUse = 0;
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, isValid, "isValid()")
{
return PyBool_FromLong((mShader != 0 && mOk));
}
KX_PYMETHODDEF_DOC(BL_Shader, getVertexProg, "getVertexProg( )")
{
return PyUnicode_FromString(vertProg ? vertProg : "");
}
KX_PYMETHODDEF_DOC(BL_Shader, getFragmentProg, "getFragmentProg( )")
{
return PyUnicode_FromString(fragProg ? fragProg : "");
}
KX_PYMETHODDEF_DOC(BL_Shader, validate, "validate()")
{
if (mError) {
Py_RETURN_NONE;
}
if (mShader == 0) {
PyErr_SetString(PyExc_TypeError, "shader.validate(): BL_Shader, 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 = NULL;
}
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, setSampler, "setSampler(name, index)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int index = -1;
if (PyArg_ParseTuple(args, "si:setSampler", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )")
{
int pass = 1;
if (!PyArg_ParseTuple(args, "i:setNumberOfPasses", &pass)) {
return NULL;
}
mPass = 1;
Py_RETURN_NONE;
}
/// access functions
KX_PYMETHODDEF_DOC(BL_Shader, setUniform1f, "setUniform1f(name, fx)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
float value = 0.0f;
if (PyArg_ParseTuple(args, "sf:setUniform1f", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
float array[2] = {0.0f, 0.0f};
if (PyArg_ParseTuple(args, "sff:setUniform2f", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
float array[3] = {0.0f, 0.0f, 0.0f};
if (PyArg_ParseTuple(args, "sfff:setUniform3f", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
float array[4] = {0.0f, 0.0f, 0.0f, 0.0f};
if (PyArg_ParseTuple(args, "sffff:setUniform4f", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int value = 0;
if (PyArg_ParseTuple(args, "si:setUniform1i", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int array[2] = {0, 0};
if (PyArg_ParseTuple(args, "sii:setUniform2i", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int array[3] = {0, 0, 0};
if (PyArg_ParseTuple(args, "siii:setUniform3i", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int array[4] = {0, 0, 0, 0};
if (PyArg_ParseTuple(args, "siiii:setUniform4i", &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_NONE;
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 or list4))")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform = "";
PyObject *listPtr = NULL;
float array_data[4] = {0.0f, 0.0f, 0.0f, 0.0f};
if (PyArg_ParseTuple(args, "sO:setUniformfv", &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_NONE;
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_NONE;
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_NONE;
break;
}
default:
{
PyErr_SetString(PyExc_TypeError,
"shader.setUniform4i(name, ix,iy,iz, iw): BL_Shader. invalid list size");
return NULL;
break;
}
}
}
}
}
return NULL;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 or list3 or list4))")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform = "";
PyObject *listPtr = NULL;
int array_data[4] = {0, 0, 0, 0};
if (!PyArg_ParseTuple(args, "sO:setUniformiv", &uniform, &listPtr)) {
return NULL;
}
int loc = GetUniformLocation(uniform);
if (loc == -1) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformiv(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
if (!PySequence_Check(listPtr)) {
PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument is not a sequence");
return NULL;
}
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] = PyLong_AsLong(item);
Py_DECREF(item);
}
if (PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformiv(...): BL_Shader, one or more values in the list is not an int");
return NULL;
}
// Sanity checks done!
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_NONE;
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_NONE;
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_NONE;
break;
}
default:
{
PyErr_SetString(PyExc_TypeError,
"shader.setUniformiv(...): BL_Shader, second argument, invalid list size, expected an int "
"list between 2 and 4");
return NULL;
break;
}
}
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4,
"setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)")
{
if (mError) {
Py_RETURN_NONE;
}
float matr[16] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
const char *uniform;
PyObject *matrix = NULL;
int transp = 0; // python use column major by default, so no transpose....
if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix4", &uniform, &matrix, &transp)) {
return NULL;
}
int loc = GetUniformLocation(uniform);
if (loc == -1) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformMatrix4(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
MT_Matrix4x4 mat;
if (!PyMatTo(matrix, mat)) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformMatrix4(...): BL_Shader, second argument cannot be converted into a 4x4 matrix");
return NULL;
}
// Sanity checks done!
#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_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix3,
"setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)")
{
if (mError) {
Py_RETURN_NONE;
}
float matr[9] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
const char *uniform;
PyObject *matrix = NULL;
int transp = 0; // python use column major by default, so no transpose....
if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3", &uniform, &matrix, &transp)) {
return NULL;
}
int loc = GetUniformLocation(uniform);
if (loc == -1) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformMatrix3(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
MT_Matrix3x3 mat;
if (!PyMatTo(matrix, mat)) {
PyErr_SetString(PyExc_TypeError,
"shader.setUniformMatrix3(...): BL_Shader, second argument cannot be converted into a 3x3 matrix");
return NULL;
}
#ifdef SORT_UNIFORMS
mat.getValue3x3(matr);
SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float) * 9), (transp != 0));
#else
SetUniform(loc, mat, (transp != 0));
#endif
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, setAttrib, "setAttrib(enum)")
{
if (mError) {
Py_RETURN_NONE;
}
int attr = 0;
if (!PyArg_ParseTuple(args, "i:setAttrib", &attr)) {
return NULL;
}
attr = SHD_TANGENT; // user input is ignored for now, there is only 1 attr
if (mShader == 0) {
PyErr_SetString(PyExc_ValueError, "shader.setAttrib() BL_Shader, invalid shader object");
return NULL;
}
mAttr = attr;
glUseProgramObjectARB(mShader);
glBindAttribLocationARB(mShader, mAttr, "Tangent");
Py_RETURN_NONE;
}
KX_PYMETHODDEF_DOC(BL_Shader, setUniformDef, "setUniformDef(name, enum)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
int nloc = 0;
if (PyArg_ParseTuple(args, "si:setUniformDef", &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_NONE;
}
BL_DefUniform *uni = new BL_DefUniform();
uni->mLoc = loc;
uni->mType = nloc;
uni->mFlag = 0;
mPreDef.push_back(uni);
Py_RETURN_NONE;
}
}
return NULL;
}
#endif // WITH_PYTHON
// eof