diff options
author | Mitchell Stokes <mogurijin@gmail.com> | 2011-05-14 10:32:25 +0400 |
---|---|---|
committer | Mitchell Stokes <mogurijin@gmail.com> | 2011-05-14 10:32:25 +0400 |
commit | 99113b8541d89e9da36385e146a400d39efcdbc9 (patch) | |
tree | 523e869f90697c0203f11985ed99d8180675d0fa /source | |
parent | d25be80320c7157cb61e5a57de13a9d6f2a4cf7f (diff) |
These two files didn't get added when I created a branch from my working copy.
Diffstat (limited to 'source')
-rw-r--r-- | source/gameengine/Ketsji/KX_PythonShaders.cpp | 492 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_PythonShaders.h | 101 |
2 files changed, 593 insertions, 0 deletions
diff --git a/source/gameengine/Ketsji/KX_PythonShaders.cpp b/source/gameengine/Ketsji/KX_PythonShaders.cpp new file mode 100644 index 00000000000..86d43b8153a --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonShaders.cpp @@ -0,0 +1,492 @@ +/** + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Init bge.shaders + */ + +#ifndef DISABLE_PYTHON +#include "KX_PythonInit.h" +#include "PyObjectPlus.h" +#include "KX_PythonSeq.h" +#include "KX_PythonShaders.h" +#include "KX_BlenderMaterial.h" +#include "BL_BlenderShader.h" +#include "DNA_material_types.h" +#include "BLI_listbase.h" + +/** + * The Shader type + */ + +KX_PythonShader::KX_PythonShader() + : PyObjectPlus(), + m_vert(""), + m_geom(""), + m_frag(""), + m_mat(NULL) +{ +} + +KX_PythonShader::KX_PythonShader(KX_BlenderMaterial *material) + : PyObjectPlus(), + m_mat(material) +{ + char vert[64000]="", geom[64000]="", frag[64000]=""; + material->GetBlenderShader()->GetSources(vert, geom, frag); + + m_vert = vert; + m_geom = geom; + m_frag = frag; + + CustomUniform *cu = static_cast<CustomUniform*>(material->GetBlenderMaterial()->csi.uniforms.first); + + while (cu) + { + m_uniforms.push_back(new KX_PythonUniform(cu)); + cu = cu->next; + } +} + +KX_PythonShader::~KX_PythonShader() +{ + // XXX This probably needs more attention... + m_uniforms.clear(); +} + +PyObject *KX_PythonShader::py_shader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + KX_PythonShader* pyshader = new KX_PythonShader(); + return pyshader->GetProxy(); +} + +PyTypeObject KX_PythonShader::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "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_shader_new +}; + +PyMethodDef KX_PythonShader::Methods[] = { + KX_PYMETHODTABLE_O(KX_PythonShader, addUniform), + {NULL} //Sentinel +}; + +PyAttributeDef KX_PythonShader::Attributes[] = { + KX_PYATTRIBUTE_RW_FUNCTION("vertex", KX_PythonShader, pyattr_get_source, pyattr_set_source), + KX_PYATTRIBUTE_RW_FUNCTION("geometry", KX_PythonShader, pyattr_get_source, pyattr_set_source), + KX_PYATTRIBUTE_RW_FUNCTION("fragment", KX_PythonShader, pyattr_get_source, pyattr_set_source), + KX_PYATTRIBUTE_RO_FUNCTION("uniforms", KX_PythonShader, pyattr_get_uniforms), + {NULL} //Sentinel +}; + +PyObject* KX_PythonShader::pyattr_get_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PythonShader *self = static_cast<KX_PythonShader*>(self_v); + + if (!strcmp(attrdef->m_name, "vertex")) + return PyUnicode_FromString(self->m_vert.Ptr()); + else if (!strcmp(attrdef->m_name, "geometry")) + return PyUnicode_FromString(self->m_geom.Ptr()); + else if (!strcmp(attrdef->m_name, "fragment")) + return PyUnicode_FromString(self->m_frag.Ptr()); + else + /* Should never happen */ + PyErr_SetString(PyExc_SystemError, "invalid attribute, internal error"); + + Py_RETURN_NONE; +} + +int KX_PythonShader::pyattr_set_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_PythonShader *self = static_cast<KX_PythonShader*>(self_v); + + PyObject* bytes = PyUnicode_AsASCIIString(value); + char* source = PyBytes_AsString(bytes); + + if (!strcmp(attrdef->m_name, "vertex")) + { + self->m_vert = source; + + if (self->m_mat) + self->m_mat->GetBlenderShader()->SetSources(source, NULL, NULL); + } + else if (!strcmp(attrdef->m_name, "geometry")) + { + self->m_geom = source; + + if (self->m_mat) + self->m_mat->GetBlenderShader()->SetSources(NULL, source, NULL); + } + else if (!strcmp(attrdef->m_name, "fragment")) + { + self->m_frag = source; + + if (self->m_mat) + self->m_mat->GetBlenderShader()->SetSources(NULL, NULL, source); + } + else + { + /* Should never happen */ + PyErr_SetString(PyExc_SystemError, "invalid type, internal error"); + Py_DECREF(bytes); + return PY_SET_ATTR_FAIL; + } + + Py_DECREF(bytes); + return PY_SET_ATTR_SUCCESS; +} + +PyObject* KX_PythonShader::pyattr_get_uniforms(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PythonShader* self = static_cast<KX_PythonShader*>(self_v); + return KX_PythonSeq_CreatePyObject(self->m_proxy, KX_PYGENSEQ_SHADER_TYPE_UNIFORMS); + +} + +KX_PYMETHODDEF_DOC_O(KX_PythonShader, addUniform, + "addUniform(uniform) -- Adds the uniform to the shader's uniform list") +{ + if (!PyType_IsSubtype(&KX_PythonUniform::Type, Py_TYPE(value))) + return NULL; + + KX_PythonUniform *uniform = static_cast<KX_PythonUniform*>BGE_PROXY_REF(value); + + BLI_addhead(&m_mat->GetBlenderMaterial()->csi.uniforms, uniform->GetCustomUniform()); + m_uniforms.push_back(uniform); + + Py_RETURN_NONE; +} + +/** + * The Uniform type + */ + +KX_PythonUniform::KX_PythonUniform(char* name, short type, int size) + : PyObjectPlus(), + m_name(name), + m_type(type), + m_size(size), + m_cu(NULL), + m_owns_cu(true) +{ + m_cu = (CustomUniform*)malloc(sizeof(CustomUniform)); + m_cu->next = m_cu->prev = NULL; + + strcpy(m_cu->name, name); + m_cu->type = type; + m_cu->size = size; + + m_cu->data = 0; + + switch (m_cu->type) + { + case MA_UNF_FLOAT: + *(float*)&m_cu->data = 0.f; + break; + case MA_UNF_VEC2: + case MA_UNF_VEC3: + case MA_UNF_VEC4: + m_cu->data = calloc(m_size, sizeof(float)); + break; + case MA_UNF_INT: + *(int*)&m_cu->data = 0; + break; + case MA_UNF_IVEC2: + case MA_UNF_IVEC3: + case MA_UNF_IVEC4: + m_cu->data = calloc(m_size, sizeof(int)); + default: + m_cu->data = NULL; + } + + m_data = m_cu->data; + +} + +KX_PythonUniform::KX_PythonUniform(CustomUniform *cu) + : PyObjectPlus(), + m_cu(cu), + m_owns_cu(false) +{ + m_name = cu->name; + m_type = cu->type; + m_size = cu->size; + m_data = cu->data; +} + + +KX_PythonUniform::~KX_PythonUniform() +{ + if (m_owns_cu) + free(m_cu); +} + +PyObject *KX_PythonUniform::py_uniform_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *name; + short type_const; + int size; + + if (!PyArg_ParseTuple(args, "sh:Uniform", &name, &type_const)) { + PyErr_SetString(PyExc_ValueError, "wrong number of arguments. Please use Uniform(name, type)"); + return NULL; + } + + switch(type_const) + { + case MA_UNF_FLOAT: + case MA_UNF_INT: + case MA_UNF_SAMPLER2D: + size = 1; + break; + case MA_UNF_VEC2: + case MA_UNF_IVEC2: + size = 2; + break; + case MA_UNF_VEC3: + case MA_UNF_IVEC3: + size = 3; + break; + case MA_UNF_VEC4: + case MA_UNF_IVEC4: + size = 4; + break; + default: + PyErr_SetString(PyExc_ValueError, "the supplied type is unsupported"); + return NULL; + } + + KX_PythonUniform* pyuniform = new KX_PythonUniform(name, type_const, size); + return pyuniform->GetProxy(); +} + +PyTypeObject KX_PythonUniform::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "Uniform", + 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_uniform_new +}; + +PyMethodDef KX_PythonUniform::Methods[] = { + {NULL} //Sentinel +}; + +PyAttributeDef KX_PythonUniform::Attributes[] = { + KX_PYATTRIBUTE_STRING_RO("name", KX_PythonUniform, m_name), + KX_PYATTRIBUTE_SHORT_RO("type", KX_PythonUniform, m_type), + KX_PYATTRIBUTE_RW_FUNCTION("value", KX_PythonUniform, pyattr_get_value, pyattr_set_value), + {NULL} //Sentinel +}; + +PyObject *KX_PythonUniform::pyattr_get_value(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_PythonUniform *self = static_cast<KX_PythonUniform*>(self_v); + + if (!self->m_data) + Py_RETURN_NONE; + + switch(self->m_type) + { + case MA_UNF_FLOAT: + { + float val = *(float*)(&self->m_data); + return PyFloat_FromDouble(val); + } + case MA_UNF_VEC2: + case MA_UNF_VEC3: + case MA_UNF_VEC4: + { + float* val = static_cast<float*>(self->m_data); + PyObject* ret = PyList_New(self->m_size); + + for (int i=0; i<self->m_size; ++i) + { + PyList_SetItem(ret, i, PyFloat_FromDouble(val[i])); + } + + return ret; + + } + case MA_UNF_INT: + { + int val = *(int*)&self->m_data; + return PyLong_FromLong(val); + } + case MA_UNF_IVEC2: + case MA_UNF_IVEC3: + case MA_UNF_IVEC4: + { + int* val = static_cast<int*>(self->m_data); + PyObject* ret = PyList_New(self->m_size); + + for (int i=0; i<self->m_size; ++i) + { + PyList_SetItem(ret, i, PyLong_FromLong(val[i])); + } + + return ret; + } + case MA_UNF_SAMPLER2D: + return PyLong_FromLong(((Tex*)self->m_data)->ima->bindcode); + default: + // Should never happen + PyErr_SetString(PyExc_AttributeError, "invalid type for uniform, internal error"); + return NULL; + } +} + +int KX_PythonUniform::pyattr_set_value(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_PythonUniform *self = static_cast<KX_PythonUniform*>(self_v); + + switch(self->m_type) + { + case MA_UNF_FLOAT: + { + if (!PyFloat_Check(value)) + { + PyErr_SetString(PyExc_ValueError, "float uniform type requires a float value"); + return PY_SET_ATTR_FAIL; + } + + *(float*)(&self->m_data) = PyFloat_AsDouble(value); + if (self->m_cu) + self->m_cu->data = self->m_data; + return PY_SET_ATTR_SUCCESS; + } + case MA_UNF_VEC2: + case MA_UNF_VEC3: + case MA_UNF_VEC4: + { + if (!PySequence_Check(value)) + { + PyErr_SetString(PyExc_ValueError, "vector uniform types require a sequence of floats"); + return PY_SET_ATTR_FAIL; + } + + if (PySequence_Size(value) != self->m_size) + { + PyErr_SetString(PyExc_ValueError, "not enough values in the sequence"); + return PY_SET_ATTR_FAIL; + } + + for (int i=0; i<self->m_size; ++i) + { + PyObject* val = PySequence_Fast_GET_ITEM(value, i); + if (!PyFloat_Check(val)) + { + PyErr_SetString(PyExc_ValueError, "vector uniform types require a sequence of floats"); + return PY_SET_ATTR_FAIL; + } + ((float*)self->m_data)[i] = PyFloat_AsDouble(val); + } + + return PY_SET_ATTR_SUCCESS; + } + case MA_UNF_INT: + { + if (!PyLong_Check(value)) + { + PyErr_SetString(PyExc_ValueError, "integer uniform type requires an integer value"); + return PY_SET_ATTR_FAIL; + } + + *(int*)&self->m_data = PyLong_AsLong(value); + if (self->m_cu) + self->m_cu->data = self->m_data; + return PY_SET_ATTR_SUCCESS; + } + case MA_UNF_IVEC2: + case MA_UNF_IVEC3: + case MA_UNF_IVEC4: + { + if (!PySequence_Check(value)) + { + PyErr_SetString(PyExc_ValueError, "integer vector uniform types require a sequence of integers"); + return PY_SET_ATTR_FAIL; + } + + if (PySequence_Size(value) != self->m_size) + { + PyErr_SetString(PyExc_ValueError, "not enough values in the sequence"); + return PY_SET_ATTR_FAIL; + } + + for (int i=0; i<self->m_size; ++i) + { + PyObject* val = PySequence_Fast_GET_ITEM(value, i); + if (!PyLong_Check(val)) + { + PyErr_SetString(PyExc_ValueError, "integer vector uniform types require a sequence of integers"); + return PY_SET_ATTR_FAIL; + } + ((int*)self->m_data)[i] = PyLong_AsLong(val); + } + + return PY_SET_ATTR_SUCCESS; + } + case MA_UNF_SAMPLER2D: + PyErr_SetString(PyExc_AttributeError, "Sampler2D value is read-only"); + return PY_SET_ATTR_FAIL; + default: + // Should never happen + PyErr_SetString(PyExc_AttributeError, "invalid type for uniform, internal error"); + return PY_SET_ATTR_FAIL; + } +} + +#endif // ndef DISABLE_PYTHON
\ No newline at end of file diff --git a/source/gameengine/Ketsji/KX_PythonShaders.h b/source/gameengine/Ketsji/KX_PythonShaders.h new file mode 100644 index 00000000000..3c48bafbadb --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonShaders.h @@ -0,0 +1,101 @@ +/** + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Init bge.shaders + */ + +#ifndef __KX_PYSHADERS +#define __KX_PYSHADERS +#ifndef DISABLE_PYTHON + +#include "PyObjectPlus.h" + +typedef std::vector<class KX_PythonUniform *> UniformList; + +class KX_PythonShader: public PyObjectPlus +{ + Py_Header; + +private: + STR_String m_vert, m_geom, m_frag; + class KX_BlenderMaterial *m_mat; + UniformList m_uniforms; + +public: + KX_PythonShader(); + KX_PythonShader(class KX_BlenderMaterial *material); + ~KX_PythonShader(); + + STR_String& GetVertex() { return m_vert; } + STR_String& GetGeometry() { return m_geom; } + STR_String& GetFragment() { return m_frag; } + + UniformList& GetUniforms() { return m_uniforms; } + + static PyObject* py_shader_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + + KX_PYMETHOD_DOC_O(KX_PythonShader, addUniform); + + static PyObject* pyattr_get_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_uniforms(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); +}; + +class KX_PythonUniform: public PyObjectPlus +{ + Py_Header; + +private: + STR_String m_name; + short m_type; + int m_size; + void *m_data; + + struct CustomUniform *m_cu; + bool m_owns_cu; // This is so uniforms created in Python can clean up after themselves + +public: + KX_PythonUniform(char* name, short type, int size); + KX_PythonUniform(struct CustomUniform *cu); + ~KX_PythonUniform(); + + STR_String& GetName() {return m_name;} + struct CustomUniform *GetCustomUniform() {return m_cu;} + + virtual PyObject* py_repr(void) + { + return PyUnicode_FromString(GetName().ReadPtr()); + } + + static PyObject* py_uniform_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + + static PyObject* pyattr_get_value(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_value(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +}; + +#endif //ndef DISABLE_PYTHON +#endif // __KX_PYSHADERS
\ No newline at end of file |