4f767e37e8
Reviewers: lordloki, youle, campbellbarton, sergey, kupoman, moguri, panzergame Reviewed By: panzergame Projects: #game_engine Differential Revision: https://developer.blender.org/D1397
1438 lines
31 KiB
C++
1438 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_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 (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
|