893 lines
23 KiB
C
893 lines
23 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 blender/python/gpu/gpu_py_shader.c
|
|
* \ingroup bpygpu
|
|
*
|
|
* - Use ``bpygpu_`` for local API.
|
|
* - Use ``BPyGPU`` for public API.
|
|
*/
|
|
|
|
#include <Python.h>
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "GPU_shader.h"
|
|
#include "GPU_shader_interface.h"
|
|
|
|
#include "../generic/py_capi_utils.h"
|
|
#include "../generic/python_utildefines.h"
|
|
#include "../mathutils/mathutils.h"
|
|
|
|
#include "gpu_py_shader.h" /* own include */
|
|
#include "gpu_py_vertex_format.h"
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Enum Conversion.
|
|
* \{ */
|
|
|
|
static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p)
|
|
{
|
|
Py_ssize_t mode_id_len;
|
|
const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
|
|
if (mode_id == NULL) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"expected a string, got %s",
|
|
Py_TYPE(o)->tp_name);
|
|
return 0;
|
|
}
|
|
#define MATCH_ID(id) \
|
|
if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \
|
|
if (STREQ(mode_id, STRINGIFY(id))) { \
|
|
mode = GPU_SHADER_##id; \
|
|
goto success; \
|
|
} \
|
|
} ((void)0)
|
|
|
|
GPUBuiltinShader mode;
|
|
MATCH_ID(2D_UNIFORM_COLOR);
|
|
MATCH_ID(2D_FLAT_COLOR);
|
|
MATCH_ID(2D_SMOOTH_COLOR);
|
|
MATCH_ID(2D_IMAGE);
|
|
MATCH_ID(3D_UNIFORM_COLOR);
|
|
MATCH_ID(3D_FLAT_COLOR);
|
|
MATCH_ID(3D_SMOOTH_COLOR);
|
|
|
|
#undef MATCH_ID
|
|
PyErr_Format(PyExc_ValueError,
|
|
"unknown type literal: '%s'",
|
|
mode_id);
|
|
return 0;
|
|
|
|
success:
|
|
(*(GPUBuiltinShader *)p) = mode;
|
|
return 1;
|
|
}
|
|
|
|
static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix)
|
|
{
|
|
int uniform = GPU_shader_get_uniform(shader, name);
|
|
|
|
if (uniform == -1) {
|
|
PyErr_Format(PyExc_ValueError, "%s: uniform %.32s %.32s not found", error_prefix, name);
|
|
}
|
|
|
|
return uniform;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Shader Type
|
|
* \{ */
|
|
|
|
static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
|
|
{
|
|
struct {
|
|
const char *vertexcode;
|
|
const char *fragcode;
|
|
const char *geocode;
|
|
const char *libcode;
|
|
const char *defines;
|
|
} params = {0};
|
|
|
|
static const char *_keywords[] = {
|
|
"vertexcode", "fragcode", "geocode",
|
|
"libcode", "defines", NULL};
|
|
|
|
static _PyArg_Parser _parser = {"ss|$sss:GPUShader.__new__", _keywords, 0};
|
|
if (!_PyArg_ParseTupleAndKeywordsFast(
|
|
args, kwds, &_parser,
|
|
¶ms.vertexcode, ¶ms.fragcode, ¶ms.geocode,
|
|
¶ms.libcode, ¶ms.defines))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
GPUShader *shader = GPU_shader_create(
|
|
params.vertexcode,
|
|
params.fragcode,
|
|
params.geocode,
|
|
params.libcode,
|
|
params.defines,
|
|
NULL);
|
|
|
|
if (shader == NULL) {
|
|
PyErr_SetString(PyExc_Exception,
|
|
"Shader Compile Error, see console for more details");
|
|
return NULL;
|
|
}
|
|
|
|
return BPyGPUShader_CreatePyObject(shader, false);
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_bind_doc,
|
|
".. method:: bind()\n"
|
|
"\n"
|
|
" Bind the Shader object.\n"
|
|
);
|
|
static PyObject *bpygpu_shader_bind(BPyGPUShader *self)
|
|
{
|
|
GPU_shader_bind(self->shader);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_transform_feedback_enable_doc,
|
|
".. method:: transform_feedback_enable(vbo_id)\n"
|
|
"\n"
|
|
" Start transform feedback operation.\n"
|
|
"\n"
|
|
" :return: true if transform feedback was succesfully enabled.\n"
|
|
" :rtype: bool\n"
|
|
);
|
|
static PyObject *bpygpu_shader_transform_feedback_enable(
|
|
BPyGPUShader *self, PyObject *arg)
|
|
{
|
|
uint vbo_id;
|
|
if ((vbo_id = PyC_Long_AsU32(arg)) == (uint)-1) {
|
|
return NULL;
|
|
}
|
|
return PyBool_FromLong(GPU_shader_transform_feedback_enable(self->shader, vbo_id));
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_transform_feedback_disable_doc,
|
|
".. method:: transform_feedback_disable()\n"
|
|
"\n"
|
|
" Disable transform feedback.\n"
|
|
);
|
|
static PyObject *bpygpu_transform_feedback_disable(BPyGPUShader *self)
|
|
{
|
|
GPU_shader_transform_feedback_disable(self->shader);
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc,
|
|
".. method:: uniform_from_name(name)\n"
|
|
"\n"
|
|
" Get uniform location by name.\n"
|
|
"\n"
|
|
" :param name: name of the uniform variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :return: the location of the uniform variable.\n"
|
|
" :rtype: int\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_from_name(
|
|
BPyGPUShader *self, PyObject *arg)
|
|
{
|
|
const char *name = PyUnicode_AsUTF8(arg);
|
|
if (name == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
int uniform = bpygpu_uniform_location_get(
|
|
self->shader, name, "GPUShader.get_uniform");
|
|
|
|
if (uniform == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
return PyLong_FromLong(uniform);
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_block_from_name_doc,
|
|
".. method:: uniform_block_from_name(name)\n"
|
|
"\n"
|
|
" Get uniform block location by name.\n"
|
|
"\n"
|
|
" :param name: name of the uniform block variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :return: the location of the uniform block variable.\n"
|
|
" :rtype: int\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_block_from_name(
|
|
BPyGPUShader *self, PyObject *arg)
|
|
{
|
|
const char *name = PyUnicode_AsUTF8(arg);
|
|
if (name == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
int uniform = GPU_shader_get_uniform_block(self->shader, name);
|
|
|
|
if (uniform == -1) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"GPUShader.get_uniform_block: uniform %.32s not found", name);
|
|
return NULL;
|
|
}
|
|
|
|
return PyLong_FromLong(uniform);
|
|
}
|
|
|
|
static bool bpygpu_shader_uniform_vector_imp(
|
|
PyObject *args, int elem_size,
|
|
int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer)
|
|
{
|
|
PyObject *buffer;
|
|
|
|
*r_count = 1;
|
|
if (!PyArg_ParseTuple(
|
|
args, "iOi|i:GPUShader.uniform_vector_*",
|
|
r_location, &buffer, r_length, r_count))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) {
|
|
/* PyObject_GetBuffer raise a PyExc_BufferError */
|
|
return false;
|
|
}
|
|
|
|
if (r_pybuffer->len != (*r_length * *r_count * elem_size)) {
|
|
PyErr_SetString(
|
|
PyExc_BufferError,
|
|
"GPUShader.uniform_vector_*: buffer size does not match.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc,
|
|
".. method:: uniform_vector_float(location, buffer, length, count)\n"
|
|
"\n"
|
|
" Set the buffer to fill the uniform.\n"
|
|
"\n"
|
|
" :param location: location of the uniform variable to be modified.\n"
|
|
" :type location: int\n"
|
|
" :param buffer: buffer object with format float.\n"
|
|
" :type buffer: buffer object\n"
|
|
" :param length:\n"
|
|
" size of the uniform data type:\n"
|
|
"\n"
|
|
" - 1: float\n"
|
|
" - 2: vec2 or float[2]\n"
|
|
" - 3: vec3 or float[3]\n"
|
|
" - 4: vec4 or float[4]\n"
|
|
" - 9: mat3\n"
|
|
" - 16: mat4\n"
|
|
"\n"
|
|
" :type length: int\n"
|
|
" :param count: specifies the number of elements, vector or matrices that are to be modified.\n"
|
|
" :type count: int\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_vector_float(
|
|
BPyGPUShader *self, PyObject *args)
|
|
{
|
|
int location, length, count;
|
|
|
|
Py_buffer pybuffer;
|
|
|
|
if (!bpygpu_shader_uniform_vector_imp(
|
|
args, sizeof(float),
|
|
&location, &length, &count, &pybuffer))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_uniform_vector(
|
|
self->shader, location, length,
|
|
count, pybuffer.buf);
|
|
|
|
PyBuffer_Release(&pybuffer);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc,
|
|
".. method:: uniform_vector_int(location, buffer, length, count)\n"
|
|
"\n"
|
|
" See GPUShader.uniform_vector_float(...) description.\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_vector_int(
|
|
BPyGPUShader *self, PyObject *args)
|
|
{
|
|
int location, length, count;
|
|
|
|
Py_buffer pybuffer;
|
|
|
|
if (!bpygpu_shader_uniform_vector_imp(
|
|
args, sizeof(int),
|
|
&location, &length, &count, &pybuffer))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_uniform_vector_int(
|
|
self->shader, location, length,
|
|
count, pybuffer.buf);
|
|
|
|
PyBuffer_Release(&pybuffer);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc,
|
|
".. method:: uniform_bool(name, seq)\n"
|
|
"\n"
|
|
" Specify the value of a uniform variable for the current program object.\n"
|
|
"\n"
|
|
" :param name: name of the uniform variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :param seq: values that will be used to update the specified uniform variable.\n"
|
|
" :type seq: sequence of bools\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_bool(
|
|
BPyGPUShader *self, PyObject *args)
|
|
{
|
|
const char *error_prefix = "GPUShader.uniform_bool";
|
|
|
|
struct {
|
|
const char *id;
|
|
PyObject *seq;
|
|
} params;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, "sO:GPUShader.uniform_bool",
|
|
¶ms.id, ¶ms.seq))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int values[4];
|
|
int length;
|
|
int ret;
|
|
{
|
|
PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
|
|
if (seq_fast == NULL) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"%s: expected a sequence, got %s",
|
|
error_prefix, Py_TYPE(params.seq)->tp_name);
|
|
ret = -1;
|
|
}
|
|
else {
|
|
length = PySequence_Fast_GET_SIZE(seq_fast);
|
|
if (length == 0 || length > 4) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"%s: invalid sequence length. expected 1..4, got %d",
|
|
error_prefix, length);
|
|
ret = -1;
|
|
}
|
|
else {
|
|
ret = PyC_AsArray_FAST(
|
|
values, seq_fast, length, &PyLong_Type,
|
|
false, error_prefix);
|
|
}
|
|
Py_DECREF(seq_fast);
|
|
}
|
|
}
|
|
if (ret == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
const int location = bpygpu_uniform_location_get(
|
|
self->shader, params.id, error_prefix);
|
|
|
|
if (location == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_float_doc,
|
|
".. method:: uniform_float(name, value)\n"
|
|
"\n"
|
|
" Specify the value of a uniform variable for the current program object.\n"
|
|
"\n"
|
|
" :param name: name of the uniform variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :param value: values that will be used to update the specified uniform variable.\n"
|
|
" :type value: single number or sequence of numbers\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_float(
|
|
BPyGPUShader *self, PyObject *args)
|
|
{
|
|
const char *error_prefix = "GPUShader.uniform_float";
|
|
|
|
struct {
|
|
const char *id;
|
|
PyObject *seq;
|
|
} params;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, "sO:GPUShader.uniform_float",
|
|
¶ms.id, ¶ms.seq))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
float values[16];
|
|
int length;
|
|
|
|
if (PyFloat_Check(params.seq)) {
|
|
values[0] = (float)PyFloat_AsDouble(params.seq);
|
|
length = 1;
|
|
}
|
|
else if (PyLong_Check(params.seq)) {
|
|
values[0] = (float)PyLong_AsDouble(params.seq);
|
|
length = 1;
|
|
}
|
|
else if (MatrixObject_Check(params.seq)) {
|
|
MatrixObject *mat = (MatrixObject *)params.seq;
|
|
if (BaseMath_ReadCallback(mat) == -1) {
|
|
return NULL;
|
|
}
|
|
if ((mat->num_row != mat->num_col) || !ELEM(mat->num_row, 3, 4)) {
|
|
PyErr_SetString(PyExc_ValueError,
|
|
"Expected 3x3 or 4x4 matrix");
|
|
return NULL;
|
|
}
|
|
length = mat->num_row * mat->num_col;
|
|
memcpy(values, mat->matrix, sizeof(float) * length);
|
|
}
|
|
else {
|
|
length = mathutils_array_parse(values, 2, 16, params.seq, "");
|
|
if (length == -1) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!ELEM(length, 1, 2, 3, 4, 9, 16)) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Expected a single float or a sequence of floats of length 1..4, 9 or 16.");
|
|
return NULL;
|
|
}
|
|
|
|
const int location = bpygpu_uniform_location_get(
|
|
self->shader, params.id, error_prefix);
|
|
|
|
if (location == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_uniform_vector(self->shader, location, length, 1, values);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_uniform_int_doc,
|
|
".. method:: uniform_int(name, seq)\n"
|
|
"\n"
|
|
" Specify the value of a uniform variable for the current program object.\n"
|
|
"\n"
|
|
" :param name: name of the uniform variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :param seq: values that will be used to update the specified uniform variable.\n"
|
|
" :type seq: sequence of numbers\n"
|
|
);
|
|
static PyObject *bpygpu_shader_uniform_int(
|
|
BPyGPUShader *self, PyObject *args)
|
|
{
|
|
const char *error_prefix = "GPUShader.uniform_int";
|
|
|
|
struct {
|
|
const char *id;
|
|
PyObject *seq;
|
|
} params;
|
|
|
|
if (!PyArg_ParseTuple(
|
|
args, "sO:GPUShader.uniform_int",
|
|
¶ms.id, ¶ms.seq))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int values[4];
|
|
int length;
|
|
int ret;
|
|
|
|
if (PyLong_Check(params.seq)) {
|
|
values[0] = PyC_Long_AsI32(params.seq);
|
|
length = 1;
|
|
ret = 0;
|
|
}
|
|
else {
|
|
PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
|
|
if (seq_fast == NULL) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"%s: expected a sequence, got %s",
|
|
error_prefix, Py_TYPE(params.seq)->tp_name);
|
|
ret = -1;
|
|
}
|
|
else {
|
|
length = PySequence_Fast_GET_SIZE(seq_fast);
|
|
if (length == 0 || length > 4) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"%s: invalid sequence length. expected 1..4, got %d",
|
|
error_prefix, length);
|
|
ret = -1;
|
|
}
|
|
else {
|
|
ret = PyC_AsArray_FAST(
|
|
values, seq_fast, length, &PyLong_Type,
|
|
false, error_prefix);
|
|
}
|
|
Py_DECREF(seq_fast);
|
|
}
|
|
}
|
|
if (ret == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
const int location = bpygpu_uniform_location_get(
|
|
self->shader, params.id, error_prefix);
|
|
|
|
if (location == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_attr_from_name_doc,
|
|
".. method:: attr_from_name(name)\n"
|
|
"\n"
|
|
" Get attribute location by name.\n"
|
|
"\n"
|
|
" :param name: the name of the attribute variable whose location is to be queried.\n"
|
|
" :type name: str\n"
|
|
" :return: the location of an attribute variable.\n"
|
|
" :rtype: int\n"
|
|
);
|
|
static PyObject *bpygpu_shader_attr_from_name(
|
|
BPyGPUShader *self, PyObject *arg)
|
|
{
|
|
const char *name = PyUnicode_AsUTF8(arg);
|
|
if (name == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
int attr = GPU_shader_get_attribute(self->shader, name);
|
|
|
|
if (attr == -1) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"GPUShader.attr_from_name: attribute %.32s not found", name);
|
|
return NULL;
|
|
}
|
|
|
|
return PyLong_FromLong(attr);
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_calc_format_doc,
|
|
".. method:: calc_format()\n"
|
|
"\n"
|
|
" Build a new format based on the attributes of the shader.\n"
|
|
"\n"
|
|
" :return: vertex attribute format for the shader\n"
|
|
" :rtype: GPUVertFormat\n"
|
|
);
|
|
static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
|
|
{
|
|
BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
|
|
GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader));
|
|
return (PyObject *)ret;
|
|
}
|
|
|
|
static struct PyMethodDef bpygpu_shader_methods[] = {
|
|
{"bind", (PyCFunction)bpygpu_shader_bind,
|
|
METH_NOARGS, bpygpu_shader_bind_doc},
|
|
{"transform_feedback_enable",
|
|
(PyCFunction)bpygpu_shader_transform_feedback_enable,
|
|
METH_O, bpygpu_shader_transform_feedback_enable_doc},
|
|
{"transform_feedback_disable",
|
|
(PyCFunction)bpygpu_transform_feedback_disable,
|
|
METH_NOARGS, bpygpu_shader_transform_feedback_disable_doc},
|
|
{"uniform_from_name",
|
|
(PyCFunction)bpygpu_shader_uniform_from_name,
|
|
METH_O, bpygpu_shader_uniform_from_name_doc},
|
|
{"uniform_block_from_name",
|
|
(PyCFunction)bpygpu_shader_uniform_block_from_name,
|
|
METH_O, bpygpu_shader_uniform_block_from_name_doc},
|
|
{"uniform_vector_float",
|
|
(PyCFunction)bpygpu_shader_uniform_vector_float,
|
|
METH_VARARGS, bpygpu_shader_uniform_vector_float_doc},
|
|
{"uniform_vector_int",
|
|
(PyCFunction)bpygpu_shader_uniform_vector_int,
|
|
METH_VARARGS, bpygpu_shader_uniform_vector_int_doc},
|
|
{"uniform_bool",
|
|
(PyCFunction)bpygpu_shader_uniform_bool,
|
|
METH_VARARGS, bpygpu_shader_uniform_bool_doc},
|
|
{"uniform_float",
|
|
(PyCFunction)bpygpu_shader_uniform_float,
|
|
METH_VARARGS, bpygpu_shader_uniform_float_doc},
|
|
{"uniform_int",
|
|
(PyCFunction)bpygpu_shader_uniform_int,
|
|
METH_VARARGS, bpygpu_shader_uniform_int_doc},
|
|
{"attr_from_name",
|
|
(PyCFunction)bpygpu_shader_attr_from_name,
|
|
METH_O, bpygpu_shader_attr_from_name_doc},
|
|
{"format_calc",
|
|
(PyCFunction)bpygpu_shader_calc_format,
|
|
METH_NOARGS, bpygpu_shader_calc_format_doc},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_program_doc,
|
|
"The name of the program object for use by the OpenGL API (read-only).\n\n:type: int"
|
|
);
|
|
static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure))
|
|
{
|
|
return PyLong_FromLong(GPU_shader_get_program(self->shader));
|
|
}
|
|
|
|
static PyGetSetDef bpygpu_shader_getseters[] = {
|
|
{(char *)"program",
|
|
(getter)bpygpu_shader_program_get, (setter)NULL,
|
|
bpygpu_shader_program_doc, NULL},
|
|
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
|
|
};
|
|
|
|
|
|
static void bpygpu_shader_dealloc(BPyGPUShader *self)
|
|
{
|
|
if (self->is_builtin == false) {
|
|
GPU_shader_free(self->shader);
|
|
}
|
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
}
|
|
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_doc,
|
|
"GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n"
|
|
"\n"
|
|
"GPUShader combines multiple GLSL shaders into a program used for drawing.\n"
|
|
"It must contain a vertex and fragment shaders, with an optional geometry shader.\n"
|
|
"\n"
|
|
"The GLSL #version directive is automatically included at the top of shaders, and set to 330.\n"
|
|
"\n"
|
|
"Some preprocessor directives are automatically added according to the Operating System or availability.\n"
|
|
"\n"
|
|
"These are::\n"
|
|
"\n"
|
|
" \"#define GPU_ATI\\n\"\n"
|
|
" \"#define GPU_NVIDIA\\n\"\n"
|
|
" \"#define GPU_INTEL\\n\"\n"
|
|
"\n"
|
|
"The following extensions are enabled by default if supported by the GPU::\n"
|
|
"\n"
|
|
" \"#extension GL_ARB_texture_gather: enable\\n\"\n"
|
|
" \"#extension GL_ARB_texture_query_lod: enable\\n\"\n"
|
|
"\n"
|
|
"To debug shaders, use the --debug-gpu-shaders command line option"
|
|
" to see full GLSL shader compilation and linking errors.\n"
|
|
"\n"
|
|
" :param vertexcode: vertex Shader Code.\n"
|
|
" :type vertexcode: str\n"
|
|
" :param fragcode: fragment Shader Code.\n"
|
|
" :type value: str\n"
|
|
" :param geocode: geometry Shader Code.\n"
|
|
" :type value: str\n"
|
|
" :param libcode: code with functions and presets to be shared between shaders.\n"
|
|
" :type value: str\n"
|
|
" :param defines: preprocessor directives.\n"
|
|
" :type value: str\n"
|
|
);
|
|
PyTypeObject BPyGPUShader_Type = {
|
|
PyVarObject_HEAD_INIT(NULL, 0)
|
|
.tp_name = "GPUShader",
|
|
.tp_basicsize = sizeof(BPyGPUShader),
|
|
.tp_dealloc = (destructor)bpygpu_shader_dealloc,
|
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
|
.tp_doc = bpygpu_shader_doc,
|
|
.tp_methods = bpygpu_shader_methods,
|
|
.tp_getset = bpygpu_shader_getseters,
|
|
.tp_new = bpygpu_shader_new,
|
|
};
|
|
|
|
/** \} */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name gpu.shader Module API
|
|
* \{ */
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_unbind_doc,
|
|
".. function:: unbind()\n"
|
|
"\n"
|
|
" Unbind the bound shader object.\n"
|
|
);
|
|
static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self))
|
|
{
|
|
GPU_shader_unbind();
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_from_builtin_doc,
|
|
".. function:: from_builtin(shader_name)\n"
|
|
"\n"
|
|
"Shaders that are embedded in the blender internal code.\n"
|
|
"They all read the uniform 'mat4 ModelViewProjectionMatrix', which can be edited by the 'gpu.matrix' module.\n"
|
|
" '2D_UNIFORM_COLOR' (attribute: 'vec3 pos'; uniform: 'vec4 color');\n"
|
|
"\n"
|
|
" '2D_FLAT_COLOR' (attribute: 'vec4 color', 'vec3 pos');\n"
|
|
"\n"
|
|
" '2D_SMOOTH_COLOR' (attribute: 'vec4 color', 'vec3 pos');\n"
|
|
"\n"
|
|
" '2D_IMAGE' (attribute: 'vec2 texCoord', 'vec2 pos');\n"
|
|
"\n"
|
|
" '3D_UNIFORM_COLOR' (attribute: 'vec3 pos'; uniform: 'vec4 color');\n"
|
|
"\n"
|
|
" '3D_FLAT_COLOR' (attribute: 'vec4 color', 'vec3 pos');\n"
|
|
"\n"
|
|
" '3D_SMOOTH_COLOR (attribute: 'vec4 color', 'vec3 pos');\n"
|
|
"\n"
|
|
"For more details, you can check the shader code with the function 'gpu.shader.code_from_builtin';\n"
|
|
"\n"
|
|
" :param shader_name: One of these builtin shader names: {\n"
|
|
" '2D_UNIFORM_COLOR',\n"
|
|
" '2D_FLAT_COLOR',\n"
|
|
" '2D_SMOOTH_COLOR',\n"
|
|
" '2D_IMAGE',\n"
|
|
" '3D_UNIFORM_COLOR',\n"
|
|
" '3D_FLAT_COLOR',\n"
|
|
" '3D_SMOOTH_COLOR'}\n"
|
|
" :type shader_name: str\n"
|
|
" :return: the shader object\n"
|
|
" :rtype: bpy.types.GPUShader\n"
|
|
);
|
|
static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg)
|
|
{
|
|
GPUBuiltinShader shader_id;
|
|
|
|
if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
|
|
return NULL;
|
|
}
|
|
|
|
GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
|
|
|
|
return BPyGPUShader_CreatePyObject(shader, true);
|
|
}
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc,
|
|
".. function:: code_from_builtin(shader_name)\n"
|
|
"\n"
|
|
"Exposes the internal shader code for query.\n"
|
|
"\n"
|
|
" :param shader_name: One of these builtin shader names: {\n"
|
|
" '2D_UNIFORM_COLOR',\n"
|
|
" '2D_FLAT_COLOR',\n"
|
|
" '2D_SMOOTH_COLOR',\n"
|
|
" '2D_IMAGE',\n"
|
|
" '3D_UNIFORM_COLOR',\n"
|
|
" '3D_FLAT_COLOR',\n"
|
|
" '3D_SMOOTH_COLOR'}\n"
|
|
" :type shader_name: str\n"
|
|
" :return: vertex, fragment and geometry shader codes.\n"
|
|
" :rtype: dict\n"
|
|
);
|
|
static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg)
|
|
{
|
|
GPUBuiltinShader shader_id;
|
|
|
|
const char *vert;
|
|
const char *frag;
|
|
const char *geom;
|
|
const char *defines;
|
|
|
|
PyObject *item, *r_dict;
|
|
|
|
if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
|
|
return NULL;
|
|
}
|
|
|
|
GPU_shader_get_builtin_shader_code(
|
|
shader_id, &vert, &frag, &geom, &defines);
|
|
|
|
r_dict = PyDict_New();
|
|
|
|
PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert));
|
|
Py_DECREF(item);
|
|
|
|
PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag));
|
|
Py_DECREF(item);
|
|
|
|
if (geom) {
|
|
PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom));
|
|
Py_DECREF(item);
|
|
}
|
|
if (defines) {
|
|
PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines));
|
|
Py_DECREF(item);
|
|
}
|
|
return r_dict;
|
|
}
|
|
|
|
static struct PyMethodDef bpygpu_shader_module_methods[] = {
|
|
{"unbind",
|
|
(PyCFunction)bpygpu_shader_unbind,
|
|
METH_NOARGS, bpygpu_shader_unbind_doc},
|
|
{"from_builtin",
|
|
(PyCFunction)bpygpu_shader_from_builtin,
|
|
METH_O, bpygpu_shader_from_builtin_doc},
|
|
{"code_from_builtin",
|
|
(PyCFunction)bpygpu_shader_code_from_builtin,
|
|
METH_O, bpygpu_shader_code_from_builtin_doc},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
PyDoc_STRVAR(bpygpu_shader_module_doc,
|
|
"This module provides access to GPUShader internal functions."
|
|
);
|
|
static PyModuleDef BPyGPU_shader_module_def = {
|
|
PyModuleDef_HEAD_INIT,
|
|
.m_name = "gpu.shader",
|
|
.m_doc = bpygpu_shader_module_doc,
|
|
.m_methods = bpygpu_shader_module_methods,
|
|
};
|
|
|
|
/** \} */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Public API
|
|
* \{ */
|
|
|
|
PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
|
|
{
|
|
BPyGPUShader *self;
|
|
|
|
self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type);
|
|
self->shader = shader;
|
|
self->is_builtin = is_builtin;
|
|
|
|
return (PyObject *)self;
|
|
}
|
|
|
|
PyObject *BPyInit_gpu_shader(void)
|
|
{
|
|
PyObject *submodule;
|
|
|
|
submodule = PyModule_Create(&BPyGPU_shader_module_def);
|
|
|
|
return submodule;
|
|
}
|
|
|
|
/** \} */
|