diff options
22 files changed, 1726 insertions, 1000 deletions
diff --git a/doc/python_api/examples/gpu.offscreen.1.py b/doc/python_api/examples/gpu.types.GPUOffScreen.py index bb34603bd23..a1b38837278 100644 --- a/doc/python_api/examples/gpu.offscreen.1.py +++ b/doc/python_api/examples/gpu.types.GPUOffScreen.py @@ -42,7 +42,7 @@ class OffScreenDraw(bpy.types.Operator): aspect_ratio = scene.render.resolution_x / scene.render.resolution_y try: - offscreen = gpu.offscreen.new(512, int(512 / aspect_ratio)) + offscreen = gpu.types.GPUOffScreen(512, int(512 / aspect_ratio)) except Exception as e: print(e) offscreen = None @@ -52,7 +52,7 @@ class OffScreenDraw(bpy.types.Operator): @staticmethod def _update_offscreen(context, offscreen): scene = context.scene - render_layer = context.render_layer + view_layer = context.view_layer render = scene.render camera = scene.camera diff --git a/doc/python_api/rst/gpu.rst b/doc/python_api/rst/gpu.rst deleted file mode 100644 index d4860da4770..00000000000 --- a/doc/python_api/rst/gpu.rst +++ /dev/null @@ -1,20 +0,0 @@ -******************* -GPU functions (gpu) -******************* - -.. module:: gpu - -Functions for GPU offscreen rendering, matrix stacks and selection. - -Submodules: - -.. toctree:: - :maxdepth: 1 - - gpu.offscreen.rst - - -Intro -===== - -Module to provide functions concerning the GPU implementation in Blender. diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 9b58f7b3888..edfa2c4a95b 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -235,7 +235,9 @@ else: "bpy.utils.previews", "bpy_extras", "gpu", - "gpu.offscreen", + "gpu.types", + "gpu.matrix", + "gpu.select", "idprop.types", "mathutils", "mathutils.bvhtree", @@ -1822,7 +1824,10 @@ def write_rst_importable_modules(basepath): # C_modules "aud": "Audio System", "blf": "Font Drawing", - "gpu.offscreen": "GPU Off-Screen Buffer", + "gpu": "GPU Shader Module", + "gpu.types": "GPU Types", + "gpu.matrix": "GPU Matrix", + "gpu.select": "GPU Select", "bmesh": "BMesh Module", "bmesh.types": "BMesh Types", "bmesh.utils": "BMesh Utilities", @@ -1865,7 +1870,6 @@ def copy_handwritten_rsts(basepath): # TODO put this docs in Blender's code and use import as per modules above handwritten_modules = [ "bgl", # "Blender OpenGl wrapper" - "gpu", # "GPU Shader Module" "bmesh.ops", # generated by rst_from_bmesh_opdefines.py # includes... diff --git a/source/blender/python/gpu/CMakeLists.txt b/source/blender/python/gpu/CMakeLists.txt index 141a36bbcc2..bf317a4ebc5 100644 --- a/source/blender/python/gpu/CMakeLists.txt +++ b/source/blender/python/gpu/CMakeLists.txt @@ -35,10 +35,22 @@ set(INC_SYS set(SRC gpu_py_api.c + gpu_py_batch.c + gpu_py_matrix.c + gpu_py_offscreen.c + gpu_py_select.c gpu_py_types.c + gpu_py_vertex_buffer.c + gpu_py_vertex_format.c gpu_py_api.h + gpu_py_batch.h + gpu_py_matrix.h + gpu_py_offscreen.h + gpu_py_select.h gpu_py_types.h + gpu_py_vertex_buffer.h + gpu_py_vertex_format.h ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c index 53285b372d8..fc1e7390ffe 100644 --- a/source/blender/python/gpu/gpu_py_api.c +++ b/source/blender/python/gpu/gpu_py_api.c @@ -19,31 +19,44 @@ */ /** \file blender/python/gpu/gpu_py_api.c - * \ingroup pygpu + * \ingroup bpygpu * * Experimental Python API, not considered public yet (called '_gpu'), * we may re-expose as public later. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. */ #include <Python.h> -#include "GPU_batch.h" -#include "GPU_vertex_format.h" - -#include "gpu_py_api.h" -#include "gpu_py_types.h" - #include "BLI_utildefines.h" #include "../generic/python_utildefines.h" +#include "gpu_py_matrix.h" +#include "gpu_py_select.h" +#include "gpu_py_types.h" + +#include "gpu_py_api.h" /* own include */ + PyDoc_STRVAR(GPU_doc, -"This module provides access to gpu drawing functions." +"This module to provide functions concerning the GPU implementation in Blender." +"\n\n" +"Submodules:\n" +"\n" +".. toctree::\n" +" :maxdepth: 1\n" +"\n" +" gpu.types.rst\n" +" gpu.matrix.rst\n" +" gpu.select.rst\n" +"\n" ); static struct PyModuleDef GPU_module_def = { PyModuleDef_HEAD_INIT, - .m_name = "_gpu", /* m_name */ - .m_doc = GPU_doc, /* m_doc */ + .m_name = "gpu", + .m_doc = GPU_doc, }; PyObject *BPyInit_gpu(void) @@ -54,10 +67,17 @@ PyObject *BPyInit_gpu(void) mod = PyModule_Create(&GPU_module_def); - /* _gpu.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_gpu_types())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); + PyModule_AddObject(mod, "matrix", (submodule = BPyInit_gpu_matrix())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + Py_INCREF(submodule); + + PyModule_AddObject(mod, "select", (submodule = BPyInit_gpu_select())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + Py_INCREF(submodule); + return mod; } diff --git a/source/blender/python/gpu/gpu_py_api.h b/source/blender/python/gpu/gpu_py_api.h index 387bfcab950..20eafb3d140 100644 --- a/source/blender/python/gpu/gpu_py_api.h +++ b/source/blender/python/gpu/gpu_py_api.h @@ -18,13 +18,13 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __GPU_PY_API_H__ -#define __GPU_PY_API_H__ - /** \file blender/python/gpu/gpu_py_api.h - * \ingroup pygpu + * \ingroup bpygpu */ +#ifndef __GPU_PY_API_H__ +#define __GPU_PY_API_H__ + PyObject *BPyInit_gpu(void); #endif /* __GPU_PY_API_H__ */ diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c new file mode 100644 index 00000000000..dfc95e2a996 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -0,0 +1,414 @@ +/* + * ***** 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. + * + * Copyright 2015, Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_batch.c + * \ingroup bpygpu + * + * This file defines the offscreen functionalities of the 'gpu' module + * used for off-screen OpenGL rendering. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_library.h" + +#include "GPU_batch.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu_py_vertex_buffer.h" +#include "gpu_py_batch.h" /* own include */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertBatch Type + * \{ */ + +static int bpygpu_ParsePrimType(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 == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GPU_PRIM_##id; \ + goto success; \ + } \ + } ((void)0) + + GPUPrimType mode; + MATCH_ID(POINTS); + MATCH_ID(LINES); + MATCH_ID(TRIS); + MATCH_ID(LINE_STRIP); + MATCH_ID(LINE_LOOP); + MATCH_ID(TRI_STRIP); + MATCH_ID(TRI_FAN); + MATCH_ID(LINE_STRIP_ADJ); + +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(GPUPrimType *)p) = mode; + return 1; +} + +static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + const char * const keywords[] = {"type", "buf", NULL}; + + struct { + GPUPrimType type_id; + BPyGPUVertBuf *py_buf; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "$O&O!:GPUBatch.__new__", (char **)keywords, + bpygpu_ParsePrimType, ¶ms.type_id, + &BPyGPUVertBuf_Type, ¶ms.py_buf)) + { + return NULL; + } + + GPUBatch *batch = GPU_batch_create(params.type_id, params.py_buf->buf, NULL); + BPyGPUBatch *ret = (BPyGPUBatch *)BPyGPUBatch_CreatePyObject(batch); + +#ifdef USE_GPU_PY_REFERENCES + ret->references = PyList_New(1); + PyList_SET_ITEM(ret->references, 0, (PyObject *)params.py_buf); + Py_INCREF(params.py_buf); + PyObject_GC_Track(ret); +#endif + + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygpu_VertBatch_vertbuf_add_doc, +"TODO" +); +static PyObject *bpygpu_VertBatch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf) +{ + if (!BPyGPUVertBuf_Check(py_buf)) { + PyErr_Format(PyExc_TypeError, + "Expected a GPUVertBuf, got %s", + Py_TYPE(py_buf)->tp_name); + return NULL; + } + + if (self->batch->verts[0]->vertex_len != py_buf->buf->vertex_len) { + PyErr_Format(PyExc_TypeError, + "Expected %d length, got %d", + self->batch->verts[0]->vertex_len, py_buf->buf->vertex_len); + return NULL; + } + +#ifdef USE_GPU_PY_REFERENCES + /* Hold user */ + PyList_Append(self->references, (PyObject *)py_buf); +#endif + + GPU_batch_vertbuf_add(self->batch, py_buf->buf); + Py_RETURN_NONE; +} + +/* Currently magic number from Py perspective. */ +PyDoc_STRVAR(bpygpu_VertBatch_program_set_builtin_doc, +"TODO" +); +static PyObject *bpygpu_VertBatch_program_set_builtin(BPyGPUBatch *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", NULL}; + + struct { + const char *shader; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "s:program_set_builtin", (char **)kwlist, + ¶ms.shader)) + { + return NULL; + } + + GPUBuiltinShader shader; + +#define MATCH_ID(id) \ + if (STREQ(params.shader, STRINGIFY(id))) { \ + shader = GPU_SHADER_##id; \ + goto success; \ + } ((void)0) + + MATCH_ID(2D_FLAT_COLOR); + MATCH_ID(2D_SMOOTH_COLOR); + MATCH_ID(2D_UNIFORM_COLOR); + + MATCH_ID(3D_FLAT_COLOR); + MATCH_ID(3D_SMOOTH_COLOR); + MATCH_ID(3D_UNIFORM_COLOR); + +#undef MATCH_ID + + PyErr_SetString(PyExc_ValueError, + "shader name not known"); + return NULL; + +success: + GPU_batch_program_set_builtin(self->batch, shader); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_VertBatch_uniform_bool(BPyGPUBatch *self, PyObject *args) +{ + struct { + const char *id; + bool values[1]; + } params; + + if (!PyArg_ParseTuple( + args, "sO&:uniform_bool", + ¶ms.id, + PyC_ParseBool, ¶ms.values[0])) + { + return NULL; + } + + GPU_batch_uniform_1b(self->batch, params.id, params.values[0]); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_VertBatch_uniform_i32(BPyGPUBatch *self, PyObject *args) +{ + struct { + const char *id; + int values[1]; + } params; + + if (!PyArg_ParseTuple( + args, "si:uniform_i32", + ¶ms.id, + ¶ms.values[0])) + { + return NULL; + } + + GPU_batch_uniform_1i(self->batch, params.id, params.values[0]); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_VertBatch_uniform_f32(BPyGPUBatch *self, PyObject *args) +{ + struct { + const char *id; + float values[4]; + } params; + + if (!PyArg_ParseTuple( + args, "sf|fff:uniform_f32", + ¶ms.id, + ¶ms.values[0], ¶ms.values[1], ¶ms.values[2], ¶ms.values[3])) + { + return NULL; + } + + switch (PyTuple_GET_SIZE(args)) { + case 2: GPU_batch_uniform_1f(self->batch, params.id, params.values[0]); break; + case 3: GPU_batch_uniform_2f(self->batch, params.id, UNPACK2(params.values)); break; + case 4: GPU_batch_uniform_3f(self->batch, params.id, UNPACK3(params.values)); break; + case 5: GPU_batch_uniform_4f(self->batch, params.id, UNPACK4(params.values)); break; + default: + BLI_assert(0); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_VertBatch_draw_doc, +"TODO" +); +static PyObject *bpygpu_VertBatch_draw(BPyGPUBatch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GPU_batch_draw(self->batch); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_VertBatch_program_use_begin(BPyGPUBatch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GPU_batch_program_use_begin(self->batch); + Py_RETURN_NONE; +} + +static PyObject *bpygpu_VertBatch_program_use_end(BPyGPUBatch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GPU_batch_program_use_end(self->batch); + Py_RETURN_NONE; +} + +static struct PyMethodDef bpygpu_VertBatch_methods[] = { + {"vertbuf_add", (PyCFunction)bpygpu_VertBatch_vertbuf_add, + METH_O, bpygpu_VertBatch_vertbuf_add_doc}, + {"program_set_builtin", (PyCFunction)bpygpu_VertBatch_program_set_builtin, + METH_VARARGS | METH_KEYWORDS, bpygpu_VertBatch_program_set_builtin_doc}, + {"uniform_bool", (PyCFunction)bpygpu_VertBatch_uniform_bool, + METH_VARARGS, NULL}, + {"uniform_i32", (PyCFunction)bpygpu_VertBatch_uniform_i32, + METH_VARARGS, NULL}, + {"uniform_f32", (PyCFunction)bpygpu_VertBatch_uniform_f32, + METH_VARARGS, NULL}, + {"draw", (PyCFunction) bpygpu_VertBatch_draw, + METH_NOARGS, bpygpu_VertBatch_draw_doc}, + {"program_use_begin", (PyCFunction)bpygpu_VertBatch_program_use_begin, + METH_NOARGS, ""}, + {"program_use_end", (PyCFunction)bpygpu_VertBatch_program_use_end, + METH_NOARGS, ""}, + {NULL, NULL, 0, NULL} +}; + +#ifdef USE_GPU_PY_REFERENCES + +static int bpygpu_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg) +{ + Py_VISIT(self->references); + return 0; +} + +static int bpygpu_Batch_clear(BPyGPUBatch *self) +{ + Py_CLEAR(self->references); + return 0; +} + +#endif + +static void bpygpu_Batch_dealloc(BPyGPUBatch *self) +{ + GPU_batch_discard(self->batch); + +#ifdef USE_GPU_PY_REFERENCES + if (self->references) { + PyObject_GC_UnTrack(self); + bpygpu_Batch_clear(self); + Py_XDECREF(self->references); + } +#endif + + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(py_gpu_batch_doc, +"GPUBatch(type, buf)\n" +"\n" +"Contains VAOs + VBOs + Shader representing a drawable entity." +"\n" +" :param type: One of these primitive types: {\n" +" \"GPU_PRIM_POINTS\",\n" +" \"GPU_PRIM_LINES\",\n" +" \"GPU_PRIM_TRIS\",\n" +" \"GPU_PRIM_LINE_STRIP\",\n" +" \"GPU_PRIM_LINE_LOOP\",\n" +" \"GPU_PRIM_TRI_STRIP\",\n" +" \"GPU_PRIM_TRI_FAN\",\n" +" \"GPU_PRIM_LINES_ADJ\",\n" +" \"GPU_PRIM_TRIS_ADJ\",\n" +" \"GPU_PRIM_LINE_STRIP_ADJ\",\n" +" \"GPU_PRIM_NONE\n" +" }.\n" +" :type type: str`\n" +" :param buf: Vertex buffer.\n" +" :type buf: GPUVertBuf`\n" +); +PyTypeObject BPyGPUBatch_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUBatch", + .tp_basicsize = sizeof(BPyGPUBatch), + .tp_dealloc = (destructor)bpygpu_Batch_dealloc, +#ifdef USE_GPU_PY_REFERENCES + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_doc = py_gpu_batch_doc, + .tp_traverse = (traverseproc)bpygpu_Batch_traverse, + .tp_clear = (inquiry)bpygpu_Batch_clear, +#else + .tp_flags = Py_TPFLAGS_DEFAULT, +#endif + .tp_methods = bpygpu_VertBatch_methods, + .tp_new = bpygpu_Batch_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API +* \{ */ + +PyObject *BPyGPUBatch_CreatePyObject(GPUBatch *batch) +{ + BPyGPUBatch *self; + +#ifdef USE_GPU_PY_REFERENCES + self = (BPyGPUBatch *)_PyObject_GC_New(&BPyGPUBatch_Type); + self->references = NULL; +#else + self = PyObject_New(BPyGPUBatch, &BPyGPUBatch_Type); +#endif + + self->batch = batch; + + return (PyObject *)self; +} + +/** \} */ + +#undef BPY_GPU_BATCH_CHECK_OBJ diff --git a/source/blender/python/gpu/gpu_py_batch.h b/source/blender/python/gpu/gpu_py_batch.h new file mode 100644 index 00000000000..c77574428db --- /dev/null +++ b/source/blender/python/gpu/gpu_py_batch.h @@ -0,0 +1,48 @@ +/* + * ***** 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_batch.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_BATCH_H__ +#define __GPU_PY_BATCH_H__ + +#include "BLI_compiler_attrs.h" + +#define USE_GPU_PY_REFERENCES + +extern PyTypeObject BPyGPUBatch_Type; + +#define BPyGPUBatch_Check(v) (Py_TYPE(v) == &BPyGPUBatch_Type) + +typedef struct BPyGPUBatch { + PyObject_VAR_HEAD + /* The batch is owned, we may support thin wrapped batches later. */ + struct GPUBatch *batch; +#ifdef USE_GPU_PY_REFERENCES + /* Just to keep a user to prevent freeing buf's we're using */ + PyObject *references; +#endif +} BPyGPUBatch; + +PyObject *BPyGPUBatch_CreatePyObject(struct GPUBatch *batch) ATTR_NONNULL(1); + +#endif /* __GPU_PY_BATCH_H__ */ diff --git a/source/blender/python/intern/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c index 2ab6fd864eb..f378c0203a2 100644 --- a/source/blender/python/intern/gpu_py_matrix.c +++ b/source/blender/python/gpu/gpu_py_matrix.c @@ -18,13 +18,16 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/gpu_py_matrix.c - * \ingroup pythonintern +/** \file blender/python/gpu/gpu_py_matrix.c + * \ingroup bpygpu * * This file defines the gpu.matrix stack API. * * \warning While these functions attempt to ensure correct stack usage. * Mixing Python and C functions may still crash on invalid use. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. */ #include <Python.h> @@ -36,17 +39,17 @@ #include "../generic/py_capi_utils.h" -#include "gpu.h" - #define USE_GPU_PY_MATRIX_API #include "GPU_matrix.h" #undef USE_GPU_PY_MATRIX_API +#include "gpu_py_matrix.h" /* own include */ + /* -------------------------------------------------------------------- */ /** \name Helper Functions * \{ */ -static bool pygpu_stack_is_push_model_view_ok_or_error(void) +static bool bpygpu_stack_is_push_model_view_ok_or_error(void) { if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) { PyErr_SetString(PyExc_RuntimeError, @@ -56,7 +59,7 @@ static bool pygpu_stack_is_push_model_view_ok_or_error(void) return true; } -static bool pygpu_stack_is_push_projection_ok_or_error(void) +static bool bpygpu_stack_is_push_projection_ok_or_error(void) { if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) { PyErr_SetString(PyExc_RuntimeError, @@ -66,7 +69,7 @@ static bool pygpu_stack_is_push_projection_ok_or_error(void) return true; } -static bool pygpu_stack_is_pop_model_view_ok_or_error(void) +static bool bpygpu_stack_is_pop_model_view_ok_or_error(void) { if (GPU_matrix_stack_level_get_model_view() == 0) { PyErr_SetString(PyExc_RuntimeError, @@ -76,7 +79,7 @@ static bool pygpu_stack_is_pop_model_view_ok_or_error(void) return true; } -static bool pygpu_stack_is_pop_projection_ok_or_error(void) +static bool bpygpu_stack_is_pop_projection_ok_or_error(void) { if (GPU_matrix_stack_level_get_projection() == 0) { PyErr_SetString(PyExc_RuntimeError, @@ -92,56 +95,56 @@ static bool pygpu_stack_is_pop_projection_ok_or_error(void) /** \name Manage Stack * \{ */ -PyDoc_STRVAR(pygpu_matrix_push_doc, +PyDoc_STRVAR(bpygpu_matrix_push_doc, "push()\n" "\n" " Add to the model-view matrix stack.\n" ); -static PyObject *pygpu_matrix_push(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_push(PyObject *UNUSED(self)) { - if (!pygpu_stack_is_push_model_view_ok_or_error()) { + if (!bpygpu_stack_is_push_model_view_ok_or_error()) { return NULL; } GPU_matrix_push(); Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_pop_doc, +PyDoc_STRVAR(bpygpu_matrix_pop_doc, "pop()\n" "\n" " Remove the last model-view matrix from the stack.\n" ); -static PyObject *pygpu_matrix_pop(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_pop(PyObject *UNUSED(self)) { - if (!pygpu_stack_is_pop_model_view_ok_or_error()) { + if (!bpygpu_stack_is_pop_model_view_ok_or_error()) { return NULL; } GPU_matrix_pop(); Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_push_projection_doc, +PyDoc_STRVAR(bpygpu_matrix_push_projection_doc, "push_projection()\n" "\n" " Add to the projection matrix stack.\n" ); -static PyObject *pygpu_matrix_push_projection(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_push_projection(PyObject *UNUSED(self)) { - if (!pygpu_stack_is_push_projection_ok_or_error()) { + if (!bpygpu_stack_is_push_projection_ok_or_error()) { return NULL; } GPU_matrix_push_projection(); Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_pop_projection_doc, +PyDoc_STRVAR(bpygpu_matrix_pop_projection_doc, "pop_projection()\n" "\n" " Remove the last projection matrix from the stack.\n" ); -static PyObject *pygpu_matrix_pop_projection(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_pop_projection(PyObject *UNUSED(self)) { - if (!pygpu_stack_is_pop_projection_ok_or_error()) { + if (!bpygpu_stack_is_pop_projection_ok_or_error()) { return NULL; } GPU_matrix_pop_projection(); @@ -161,31 +164,31 @@ typedef struct { PyObject_HEAD /* required python macro */ int type; int level; -} BPy_GPU_MatrixStackContext; +} BPyGPU_MatrixStackContext; enum { PYGPU_MATRIX_TYPE_MODEL_VIEW = 1, PYGPU_MATRIX_TYPE_PROJECTION = 2, }; -static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *self); -static PyObject *pygpu_matrix_stack_context_exit(BPy_GPU_MatrixStackContext *self, PyObject *args); +static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self); +static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args); -static PyMethodDef pygpu_matrix_stack_context_methods[] = { - {"__enter__", (PyCFunction)pygpu_matrix_stack_context_enter, METH_NOARGS}, - {"__exit__", (PyCFunction)pygpu_matrix_stack_context_exit, METH_VARARGS}, +static PyMethodDef bpygpu_matrix_stack_context_methods[] = { + {"__enter__", (PyCFunction)bpygpu_matrix_stack_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpygpu_matrix_stack_context_exit, METH_VARARGS}, {NULL} }; -static PyTypeObject pygpu_matrix_stack_context_Type = { +static PyTypeObject BPyGPU_matrix_stack_context_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "GPUMatrixStackContext", - .tp_basicsize = sizeof(BPy_GPU_MatrixStackContext), + .tp_basicsize = sizeof(BPyGPU_MatrixStackContext), .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_methods = pygpu_matrix_stack_context_methods, + .tp_methods = bpygpu_matrix_stack_context_methods, }; -static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *self) +static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self) { /* sanity - should never happen */ if (self->level != -1) { @@ -194,14 +197,14 @@ static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *se } if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { - if (!pygpu_stack_is_push_model_view_ok_or_error()) { + if (!bpygpu_stack_is_push_model_view_ok_or_error()) { return NULL; } GPU_matrix_push(); self->level = GPU_matrix_stack_level_get_model_view(); } else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { - if (!pygpu_stack_is_push_projection_ok_or_error()) { + if (!bpygpu_stack_is_push_projection_ok_or_error()) { return NULL; } GPU_matrix_push_projection(); @@ -213,7 +216,7 @@ static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *se Py_RETURN_NONE; } -static PyObject *pygpu_matrix_stack_context_exit(BPy_GPU_MatrixStackContext *self, PyObject *UNUSED(args)) +static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *UNUSED(args)) { /* sanity - should never happen */ if (self->level == -1) { @@ -246,32 +249,32 @@ finally: Py_RETURN_NONE; } -static PyObject *pygpu_matrix_push_pop_impl(int type) +static PyObject *bpygpu_matrix_push_pop_impl(int type) { - BPy_GPU_MatrixStackContext *ret = PyObject_New(BPy_GPU_MatrixStackContext, &pygpu_matrix_stack_context_Type); + BPyGPU_MatrixStackContext *ret = PyObject_New(BPyGPU_MatrixStackContext, &BPyGPU_matrix_stack_context_Type); ret->type = type; ret->level = -1; return (PyObject *)ret; } -PyDoc_STRVAR(pygpu_matrix_push_pop_doc, +PyDoc_STRVAR(bpygpu_matrix_push_pop_doc, "push_pop()\n" "\n" " Context manager to ensure balanced push/pop calls, even in the case of an error.\n" ); -static PyObject *pygpu_matrix_push_pop(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_push_pop(PyObject *UNUSED(self)) { - return pygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); + return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); } -PyDoc_STRVAR(pygpu_matrix_push_pop_projection_doc, +PyDoc_STRVAR(bpygpu_matrix_push_pop_projection_doc, "push_pop_projection()\n" "\n" " Context manager to ensure balanced push/pop calls, even in the case of an error.\n" ); -static PyObject *pygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) { - return pygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); + return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); } /** \} */ @@ -280,7 +283,7 @@ static PyObject *pygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) /** \name Manipulate State * \{ */ -PyDoc_STRVAR(pygpu_matrix_multiply_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_multiply_matrix_doc, "multiply_matrix(matrix)\n" "\n" " Multiply the current stack matrix.\n" @@ -288,7 +291,7 @@ PyDoc_STRVAR(pygpu_matrix_multiply_matrix_doc, " :param matrix: A 4x4 matrix.\n" " :type matrix: :class:`mathutils.Matrix`\n" ); -static PyObject *pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) { MatrixObject *pymat; if (!Matrix_Parse4x4(value, &pymat)) { @@ -298,7 +301,7 @@ static PyObject *pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject * Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_scale_doc, +PyDoc_STRVAR(bpygpu_matrix_scale_doc, "scale(scale)\n" "\n" " Scale the current stack matrix.\n" @@ -306,7 +309,7 @@ PyDoc_STRVAR(pygpu_matrix_scale_doc, " :param scale: Scale the current stack matrix.\n" " :type scale: sequence of 2 or 3 floats\n" ); -static PyObject *pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) { float scale[3]; int len; @@ -322,13 +325,13 @@ static PyObject *pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_scale_uniform_doc, +PyDoc_STRVAR(bpygpu_matrix_scale_uniform_doc, "scale_uniform(scale)\n" "\n" " :param scale: Scale the current stack matrix.\n" " :type scale: sequence of 2 or 3 floats\n" ); -static PyObject *pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) { float scalar; if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { @@ -341,7 +344,7 @@ static PyObject *pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *va Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_translate_doc, +PyDoc_STRVAR(bpygpu_matrix_translate_doc, "translate(offset)\n" "\n" " Scale the current stack matrix.\n" @@ -349,7 +352,7 @@ PyDoc_STRVAR(pygpu_matrix_translate_doc, " :param offset: Translate the current stack matrix.\n" " :type offset: sequence of 2 or 3 floats\n" ); -static PyObject *pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) { float offset[3]; int len; @@ -371,29 +374,29 @@ static PyObject *pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) /** \name Write State * \{ */ -PyDoc_STRVAR(pygpu_matrix_reset_doc, +PyDoc_STRVAR(bpygpu_matrix_reset_doc, "reset()\n" "\n" " Empty stack and set to identity.\n" ); -static PyObject *pygpu_matrix_reset(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_reset(PyObject *UNUSED(self)) { GPU_matrix_reset(); Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_load_identity_doc, +PyDoc_STRVAR(bpygpu_matrix_load_identity_doc, "load_identity()\n" "\n" " Empty stack and set to identity.\n" ); -static PyObject *pygpu_matrix_load_identity(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_load_identity(PyObject *UNUSED(self)) { GPU_matrix_identity_set(); Py_RETURN_NONE; } -PyDoc_STRVAR(pygpu_matrix_load_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_load_matrix_doc, "load_matrix(matrix)\n" "\n" " Load a matrix into the stack.\n" @@ -401,7 +404,7 @@ PyDoc_STRVAR(pygpu_matrix_load_matrix_doc, " :param matrix: A 4x4 matrix.\n" " :type matrix: :class:`mathutils.Matrix`\n" ); -static PyObject *pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) { MatrixObject *pymat; if (!Matrix_Parse4x4(value, &pymat)) { @@ -417,7 +420,7 @@ static PyObject *pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *valu /** \name Read State * \{ */ -PyDoc_STRVAR(pygpu_matrix_get_projection_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_get_projection_matrix_doc, "get_projection_matrix()\n" "\n" " Return a copy of the projection matrix.\n" @@ -425,7 +428,7 @@ PyDoc_STRVAR(pygpu_matrix_get_projection_matrix_doc, " :return: A 4x4 projection matrix.\n" " :rtype: :class:`mathutils.Matrix`\n" ); -static PyObject *pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) { float matrix[4][4]; GPU_matrix_model_view_get(matrix); @@ -433,7 +436,7 @@ static PyObject *pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) } -PyDoc_STRVAR(pygpu_matrix_get_modal_view_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_get_modal_view_matrix_doc, "get_view_matrix()\n" "\n" " Return a copy of the view matrix.\n" @@ -441,14 +444,14 @@ PyDoc_STRVAR(pygpu_matrix_get_modal_view_matrix_doc, " :return: A 4x4 view matrix.\n" " :rtype: :class:`mathutils.Matrix`\n" ); -static PyObject *pygpu_matrix_get_modal_view_matrix(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_get_modal_view_matrix(PyObject *UNUSED(self)) { float matrix[4][4]; GPU_matrix_projection_get(matrix); return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); } -PyDoc_STRVAR(pygpu_matrix_get_normal_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_get_normal_matrix_doc, "get_normal_matrix()\n" "\n" " Return a copy of the normal matrix.\n" @@ -456,7 +459,7 @@ PyDoc_STRVAR(pygpu_matrix_get_normal_matrix_doc, " :return: A 3x3 normal matrix.\n" " :rtype: :class:`mathutils.Matrix`\n" ); -static PyObject *pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) +static PyObject *bpygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) { float matrix[3][3]; GPU_matrix_normal_get(matrix); @@ -469,80 +472,80 @@ static PyObject *pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) /** \name Module * \{ */ -static struct PyMethodDef BPy_GPU_matrix_methods[] = { +static struct PyMethodDef bpygpu_matrix_methods[] = { /* Manage Stack */ - {"push", (PyCFunction)pygpu_matrix_push, - METH_NOARGS, pygpu_matrix_push_doc}, - {"pop", (PyCFunction)pygpu_matrix_pop, - METH_NOARGS, pygpu_matrix_pop_doc}, + {"push", (PyCFunction)bpygpu_matrix_push, + METH_NOARGS, bpygpu_matrix_push_doc}, + {"pop", (PyCFunction)bpygpu_matrix_pop, + METH_NOARGS, bpygpu_matrix_pop_doc}, - {"push_projection", (PyCFunction)pygpu_matrix_push_projection, - METH_NOARGS, pygpu_matrix_push_projection_doc}, - {"pop_projection", (PyCFunction)pygpu_matrix_pop_projection, - METH_NOARGS, pygpu_matrix_pop_projection_doc}, + {"push_projection", (PyCFunction)bpygpu_matrix_push_projection, + METH_NOARGS, bpygpu_matrix_push_projection_doc}, + {"pop_projection", (PyCFunction)bpygpu_matrix_pop_projection, + METH_NOARGS, bpygpu_matrix_pop_projection_doc}, /* Stack (Context Manager) */ - {"push_pop", (PyCFunction)pygpu_matrix_push_pop, - METH_NOARGS, pygpu_matrix_push_pop_doc}, - {"push_pop_projection", (PyCFunction)pygpu_matrix_push_pop_projection, - METH_NOARGS, pygpu_matrix_push_pop_projection_doc}, + {"push_pop", (PyCFunction)bpygpu_matrix_push_pop, + METH_NOARGS, bpygpu_matrix_push_pop_doc}, + {"push_pop_projection", (PyCFunction)bpygpu_matrix_push_pop_projection, + METH_NOARGS, bpygpu_matrix_push_pop_projection_doc}, /* Manipulate State */ - {"multiply_matrix", (PyCFunction)pygpu_matrix_multiply_matrix, - METH_O, pygpu_matrix_multiply_matrix_doc}, - {"scale", (PyCFunction)pygpu_matrix_scale, - METH_O, pygpu_matrix_scale_doc}, - {"scale_uniform", (PyCFunction)pygpu_matrix_scale_uniform, - METH_O, pygpu_matrix_scale_uniform_doc}, - {"translate", (PyCFunction)pygpu_matrix_translate, - METH_O, pygpu_matrix_translate_doc}, + {"multiply_matrix", (PyCFunction)bpygpu_matrix_multiply_matrix, + METH_O, bpygpu_matrix_multiply_matrix_doc}, + {"scale", (PyCFunction)bpygpu_matrix_scale, + METH_O, bpygpu_matrix_scale_doc}, + {"scale_uniform", (PyCFunction)bpygpu_matrix_scale_uniform, + METH_O, bpygpu_matrix_scale_uniform_doc}, + {"translate", (PyCFunction)bpygpu_matrix_translate, + METH_O, bpygpu_matrix_translate_doc}, /* TODO */ #if 0 - {"rotate", (PyCFunction)pygpu_matrix_rotate, - METH_O, pygpu_matrix_rotate_doc}, - {"rotate_axis", (PyCFunction)pygpu_matrix_rotate_axis, - METH_O, pygpu_matrix_rotate_axis_doc}, - {"look_at", (PyCFunction)pygpu_matrix_look_at, - METH_O, pygpu_matrix_look_at_doc}, + {"rotate", (PyCFunction)bpygpu_matrix_rotate, + METH_O, bpygpu_matrix_rotate_doc}, + {"rotate_axis", (PyCFunction)bpygpu_matrix_rotate_axis, + METH_O, bpygpu_matrix_rotate_axis_doc}, + {"look_at", (PyCFunction)bpygpu_matrix_look_at, + METH_O, bpygpu_matrix_look_at_doc}, #endif /* Write State */ - {"reset", (PyCFunction)pygpu_matrix_reset, - METH_NOARGS, pygpu_matrix_reset_doc}, - {"load_identity", (PyCFunction)pygpu_matrix_load_identity, - METH_NOARGS, pygpu_matrix_load_identity_doc}, - {"load_matrix", (PyCFunction)pygpu_matrix_load_matrix, - METH_O, pygpu_matrix_load_matrix_doc}, + {"reset", (PyCFunction)bpygpu_matrix_reset, + METH_NOARGS, bpygpu_matrix_reset_doc}, + {"load_identity", (PyCFunction)bpygpu_matrix_load_identity, + METH_NOARGS, bpygpu_matrix_load_identity_doc}, + {"load_matrix", (PyCFunction)bpygpu_matrix_load_matrix, + METH_O, bpygpu_matrix_load_matrix_doc}, /* Read State */ - {"get_projection_matrix", (PyCFunction)pygpu_matrix_get_projection_matrix, - METH_NOARGS, pygpu_matrix_get_projection_matrix_doc}, - {"get_model_view_matrix", (PyCFunction)pygpu_matrix_get_modal_view_matrix, - METH_NOARGS, pygpu_matrix_get_modal_view_matrix_doc}, - {"get_normal_matrix", (PyCFunction)pygpu_matrix_get_normal_matrix, - METH_NOARGS, pygpu_matrix_get_normal_matrix_doc}, + {"get_projection_matrix", (PyCFunction)bpygpu_matrix_get_projection_matrix, + METH_NOARGS, bpygpu_matrix_get_projection_matrix_doc}, + {"get_model_view_matrix", (PyCFunction)bpygpu_matrix_get_modal_view_matrix, + METH_NOARGS, bpygpu_matrix_get_modal_view_matrix_doc}, + {"get_normal_matrix", (PyCFunction)bpygpu_matrix_get_normal_matrix, + METH_NOARGS, bpygpu_matrix_get_normal_matrix_doc}, {NULL, NULL, 0, NULL} }; -PyDoc_STRVAR(BPy_GPU_matrix_doc, +PyDoc_STRVAR(bpygpu_matrix_doc, "This module provides access to the matrix stack." ); -static PyModuleDef BPy_GPU_matrix_module_def = { +static PyModuleDef BPyGPU_matrix_module_def = { PyModuleDef_HEAD_INIT, .m_name = "gpu.matrix", - .m_doc = BPy_GPU_matrix_doc, - .m_methods = BPy_GPU_matrix_methods, + .m_doc = bpygpu_matrix_doc, + .m_methods = bpygpu_matrix_methods, }; PyObject *BPyInit_gpu_matrix(void) { PyObject *submodule; - submodule = PyModule_Create(&BPy_GPU_matrix_module_def); + submodule = PyModule_Create(&BPyGPU_matrix_module_def); - if (PyType_Ready(&pygpu_matrix_stack_context_Type) < 0) { + if (PyType_Ready(&BPyGPU_matrix_stack_context_Type) < 0) { return NULL; } diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/gpu/gpu_py_matrix.h index 92841db9027..7bd6318611d 100644 --- a/source/blender/python/intern/gpu.h +++ b/source/blender/python/gpu/gpu_py_matrix.h @@ -15,29 +15,16 @@ * 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) 2005 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Benoit Bolsee. - * * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/gpu.h - * \ingroup pythonintern - * - * Initializes the gpu Python module. +/** \file blender/python/gpu/gpu_py_matrix.h + * \ingroup bpygpu */ -#ifndef __GPU_H__ -#define __GPU_H__ - -PyObject *GPU_initPython(void); +#ifndef __GPU_PY_MATRIX_H__ +#define __GPU_PY_MATRIX_H__ -PyObject *BPyInit_gpu_offscreen(void); PyObject *BPyInit_gpu_matrix(void); -PyObject *BPyInit_gpu_select(void); -#endif /* __GPU_H__ */ +#endif /* __GPU_PY_MATRIX_H__ */ diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c new file mode 100644 index 00000000000..36d03240786 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -0,0 +1,336 @@ +/* + * ***** 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. + * + * Copyright 2015, Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gpu/gpu_py_offscreen.c + * \ingroup bpygpu + * + * This file defines the offscreen functionalities of the 'gpu' module + * used for off-screen OpenGL rendering. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_scene.h" + +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +#include "../editors/include/ED_view3d.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu_py_offscreen.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name GPUOffscreen Type + * \{ */ + +static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"width", "height", "samples", NULL}; + + GPUOffScreen *ofs; + int width, height, samples = 0; + char err_out[256]; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "ii|i:new", (char **)(kwlist), + &width, &height, &samples)) + { + return NULL; + } + + ofs = GPU_offscreen_create(width, height, samples, true, false, err_out); + + if (ofs == NULL) { + PyErr_Format(PyExc_RuntimeError, + "gpu.offscreen.new(...) failed with '%s'", + err_out[0] ? err_out : "unknown error"); + return NULL; + } + + return BPyGPUOffScreen_CreatePyObject(ofs); +} + +static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs) +{ + if (UNLIKELY(bpygpu_ofs->ofs == NULL)) { + PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid"); + return -1; + } + return 0; +} + +#define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu) { \ + if (UNLIKELY(bpygpu_offscreen_valid_check(bpygpu) == -1)) { \ + return NULL; \ + } \ +} ((void)0) + +PyDoc_STRVAR(bpygpu_offscreen_width_doc, "Texture width.\n\n:type: int"); +static PyObject *bpygpu_offscreen_width_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_width(self->ofs)); +} + +PyDoc_STRVAR(bpygpu_offscreen_height_doc, "Texture height.\n\n:type: int"); +static PyObject *bpygpu_offscreen_height_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + return PyLong_FromLong(GPU_offscreen_height(self->ofs)); +} + +PyDoc_STRVAR(bpygpu_offscreen_color_texture_doc, "Color texture.\n\n:type: int"); +static PyObject *bpygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + GPUTexture *texture = GPU_offscreen_color_texture(self->ofs); + return PyLong_FromLong(GPU_texture_opengl_bindcode(texture)); +} + +PyDoc_STRVAR(bpygpu_offscreen_bind_doc, +"bind(save=True)\n" +"\n" +" Bind the offscreen object.\n" +"\n" +" :param save: save OpenGL current states.\n" +" :type save: bool\n" +); +static PyObject *bpygpu_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"save", NULL}; + bool save = true; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "|O&:bind", (char **)(kwlist), + PyC_ParseBool, &save)) + { + return NULL; + } + + GPU_offscreen_bind(self->ofs, save); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_offscreen_unbind_doc, +"unbind(restore=True)\n" +"\n" +" Unbind the offscreen object.\n" +"\n" +" :param restore: restore OpenGL previous states.\n" +" :type restore: bool\n" +); +static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"restore", NULL}; + bool restore = true; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "|O&:unbind", (char **)(kwlist), + PyC_ParseBool, &restore)) + { + return NULL; + } + + GPU_offscreen_unbind(self->ofs, restore); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_offscreen_draw_view3d_doc, +"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" +"\n" +" Draw the 3d viewport in the offscreen object.\n" +"\n" +" :param scene: Scene to draw.\n" +" :type scene: :class:`bpy.types.Scene`\n" +" :param view3d: 3D View to get the drawing settings from.\n" +" :type view3d: :class:`bpy.types.SpaceView3D`\n" +" :param region: Region of the 3D View.\n" +" :type region: :class:`bpy.types.Region`\n" +" :param modelview_matrix: ModelView Matrix.\n" +" :type modelview_matrix: :class:`mathutils.Matrix`\n" +" :param projection_matrix: Projection Matrix.\n" +" :type projection_matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"scene", "view_layer", "view3d", "region", "projection_matrix", "modelview_matrix", NULL}; + + MatrixObject *py_mat_modelview, *py_mat_projection; + PyObject *py_scene, *py_view_layer, *py_region, *py_view3d; + + struct Depsgraph *depsgraph; + struct Scene *scene; + struct ViewLayer *view_layer; + View3D *v3d; + ARegion *ar; + struct RV3DMatrixStore *rv3d_mats; + + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OOOOO&O&:draw_view3d", (char **)(kwlist), + &py_scene, &py_view_layer, &py_view3d, &py_region, + Matrix_Parse4x4, &py_mat_projection, + Matrix_Parse4x4, &py_mat_modelview) || + (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || + !(view_layer = PyC_RNA_AsPointer(py_view_layer, "ViewLayer")) || + !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || + !(ar = PyC_RNA_AsPointer(py_region, "Region")))) + { + return NULL; + } + + BLI_assert(BKE_id_is_in_gobal_main(&scene->id)); + + depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); + + rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata); + + GPU_offscreen_bind(self->ofs, true); /* bind */ + + ED_view3d_draw_offscreen(depsgraph, + scene, + v3d->shading.type, + v3d, + ar, + GPU_offscreen_width(self->ofs), + GPU_offscreen_height(self->ofs), + (float(*)[4])py_mat_modelview->matrix, + (float(*)[4])py_mat_projection->matrix, + false, + true, + "", + NULL, + self->ofs, + NULL); + + GPU_offscreen_unbind(self->ofs, true); /* unbind */ + + ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats); + MEM_freeN(rv3d_mats); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygpu_offscreen_free_doc, +"free()\n" +"\n" +" Free the offscreen object\n" +" The framebuffer, texture and render objects will no longer be accessible.\n" +); +static PyObject *bpygpu_offscreen_free(BPyGPUOffScreen *self) +{ + BPY_GPU_OFFSCREEN_CHECK_OBJ(self); + + GPU_offscreen_free(self->ofs); + self->ofs = NULL; + Py_RETURN_NONE; +} + +static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self) +{ + if (self->ofs) + GPU_offscreen_free(self->ofs); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyGetSetDef bpygpu_offscreen_getseters[] = { + {(char *)"color_texture", (getter)bpygpu_offscreen_color_texture_get, (setter)NULL, bpygpu_offscreen_color_texture_doc, NULL}, + {(char *)"width", (getter)bpygpu_offscreen_width_get, (setter)NULL, bpygpu_offscreen_width_doc, NULL}, + {(char *)"height", (getter)bpygpu_offscreen_height_get, (setter)NULL, bpygpu_offscreen_height_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +static struct PyMethodDef bpygpu_offscreen_methods[] = { + {"bind", (PyCFunction)bpygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_bind_doc}, + {"unbind", (PyCFunction)bpygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_unbind_doc}, + {"draw_view3d", (PyCFunction)bpygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, bpygpu_offscreen_draw_view3d_doc}, + {"free", (PyCFunction)bpygpu_offscreen_free, METH_NOARGS, bpygpu_offscreen_free_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(bpygpu_offscreen_doc, +"GPUOffScreen(width, height, samples=0)\n" +"\n" +" This object gives access to off screen buffers.\n" +"\n" +" :param width: Horizontal dimension of the buffer.\n" +" :type width: `int`\n" +" :param height: Vertical dimension of the buffer.\n" +" :type height: `int`\n" +" :param samples: OpenGL samples to use for MSAA or zero to disable.\n" +" :type samples: `int`\n" +); +PyTypeObject BPyGPUOffScreen_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUOffScreen", + .tp_basicsize = sizeof(BPyGPUOffScreen), + .tp_dealloc = (destructor)BPyGPUOffScreen__tp_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = bpygpu_offscreen_doc, + .tp_methods = bpygpu_offscreen_methods, + .tp_getset = bpygpu_offscreen_getseters, + .tp_new = bpygpu_offscreen_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs) +{ + BPyGPUOffScreen *self; + + self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type); + self->ofs = ofs; + + return (PyObject *)self; +} + +/** \} */ + +#undef BPY_GPU_OFFSCREEN_CHECK_OBJ diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h new file mode 100644 index 00000000000..8b94671b82c --- /dev/null +++ b/source/blender/python/gpu/gpu_py_offscreen.h @@ -0,0 +1,41 @@ +/* + * ***** 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_offscreen.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_OFFSCREEN_H__ +#define __GPU_PY_OFFSCREEN_H__ + +#include "BLI_compiler_attrs.h" + +extern PyTypeObject BPyGPUOffScreen_Type; + +#define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type) + +typedef struct BPyGPUOffScreen { + PyObject_HEAD + struct GPUOffScreen *ofs; +} BPyGPUOffScreen; + +PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1); + +#endif /* __GPU_PY_OFFSCREEN_H__ */ diff --git a/source/blender/python/intern/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c index fcdcce24935..56b8b904464 100644 --- a/source/blender/python/intern/gpu_py_select.c +++ b/source/blender/python/gpu/gpu_py_select.c @@ -18,13 +18,16 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/python/intern/gpu_py_select.c - * \ingroup pythonintern +/** \file blender/python/gpu/gpu_py_select.c + * \ingroup bpygpu * * This file defines the gpu.select API. * * \note Currently only used for gizmo selection, * will need to add begin/end and a way to access the hits. + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. */ #include <Python.h> @@ -33,15 +36,15 @@ #include "../generic/py_capi_utils.h" -#include "gpu.h" - #include "GPU_select.h" +#include "gpu_py_select.h" /* own include */ + /* -------------------------------------------------------------------- */ /** \name Methods * \{ */ -PyDoc_STRVAR(pygpu_select_load_id_doc, +PyDoc_STRVAR(bpygpu_select_load_id_doc, "load_id(id)\n" "\n" " Set the selection ID.\n" @@ -49,7 +52,7 @@ PyDoc_STRVAR(pygpu_select_load_id_doc, " :param id: Number (32-bit unsigned int).\n" " :type select: int\n" ); -static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) +static PyObject *bpygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) { uint id; if ((id = PyC_Long_AsU32(value)) == (uint)-1) { @@ -64,27 +67,27 @@ static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) /** \name Module * \{ */ -static struct PyMethodDef BPy_GPU_select_methods[] = { +static struct PyMethodDef bpygpu_select_methods[] = { /* Manage Stack */ - {"load_id", (PyCFunction)pygpu_select_load_id, METH_O, pygpu_select_load_id_doc}, + {"load_id", (PyCFunction)bpygpu_select_load_id, METH_O, bpygpu_select_load_id_doc}, {NULL, NULL, 0, NULL} }; -PyDoc_STRVAR(BPy_GPU_select_doc, +PyDoc_STRVAR(bpygpu_select_doc, "This module provides access to selection." ); -static PyModuleDef BPy_GPU_select_module_def = { +static PyModuleDef BPyGPU_select_module_def = { PyModuleDef_HEAD_INIT, .m_name = "gpu.select", - .m_doc = BPy_GPU_select_doc, - .m_methods = BPy_GPU_select_methods, + .m_doc = bpygpu_select_doc, + .m_methods = bpygpu_select_methods, }; PyObject *BPyInit_gpu_select(void) { PyObject *submodule; - submodule = PyModule_Create(&BPy_GPU_select_module_def); + submodule = PyModule_Create(&BPyGPU_select_module_def); return submodule; } diff --git a/source/blender/python/gpu/gpu_py_select.h b/source/blender/python/gpu/gpu_py_select.h new file mode 100644 index 00000000000..af39f8c070e --- /dev/null +++ b/source/blender/python/gpu/gpu_py_select.h @@ -0,0 +1,30 @@ +/* + * ***** 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_api.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_SELECT_H__ +#define __GPU_PY_SELECT_H__ + +PyObject *BPyInit_gpu_select(void); + +#endif /* __GPU_PY_SELECT_H__ */ diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c index 4e564fdf849..62694189ce3 100644 --- a/source/blender/python/gpu/gpu_py_types.c +++ b/source/blender/python/gpu/gpu_py_types.c @@ -19,7 +19,7 @@ */ /** \file blender/python/gpu/gpu_py_types.c - * \ingroup pygpu + * \ingroup bpygpu * * - Use ``bpygpu_`` for local API. * - Use ``BPyGPU`` for public API. @@ -27,751 +27,27 @@ #include <Python.h> -#include "GPU_batch.h" -#include "GPU_vertex_format.h" - -#include "BLI_math.h" - -#include "MEM_guardedalloc.h" - #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" #include "gpu_py_types.h" /* own include */ -#ifdef __BIG_ENDIAN__ - /* big endian */ -# define MAKE_ID2(c, d) ((c) << 8 | (d)) -# define MAKE_ID3(a, b, c) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 ) -# define MAKE_ID4(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) ) -#else - /* little endian */ -# define MAKE_ID2(c, d) ((d) << 8 | (c)) -# define MAKE_ID3(a, b, c) ( (int)(c) << 16 | (b) << 8 | (a) ) -# define MAKE_ID4(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) ) -#endif - -/* -------------------------------------------------------------------- */ - -/** \name Enum Conversion - * - * Use with PyArg_ParseTuple's "O&" formatting. - * \{ */ - -static int bpygpu_ParseVertCompType(PyObject *o, void *p) -{ - Py_ssize_t comp_type_id_len; - const char *comp_type_id = _PyUnicode_AsStringAndSize(o, &comp_type_id_len); - if (comp_type_id == NULL) { - PyErr_Format(PyExc_ValueError, - "expected a string, got %s", - Py_TYPE(o)->tp_name); - return 0; - } - - GPUVertCompType comp_type; - if (comp_type_id_len == 2) { - switch (*((ushort *)comp_type_id)) { - case MAKE_ID2('I', '8'): { comp_type = GPU_COMP_I8; goto success; } - case MAKE_ID2('U', '8'): { comp_type = GPU_COMP_U8; goto success; } - } - } - else if (comp_type_id_len == 3) { - switch (*((uint *)comp_type_id)) { - case MAKE_ID3('I', '1', '6'): { comp_type = GPU_COMP_I16; goto success; } - case MAKE_ID3('U', '1', '6'): { comp_type = GPU_COMP_U16; goto success; } - case MAKE_ID3('I', '3', '2'): { comp_type = GPU_COMP_I32; goto success; } - case MAKE_ID3('U', '3', '2'): { comp_type = GPU_COMP_U32; goto success; } - case MAKE_ID3('F', '3', '2'): { comp_type = GPU_COMP_F32; goto success; } - case MAKE_ID3('I', '1', '0'): { comp_type = GPU_COMP_I10; goto success; } - } - } - - PyErr_Format(PyExc_ValueError, - "unknown type literal: '%s'", - comp_type_id); - return 0; - -success: - *((GPUVertCompType *)p) = comp_type; - return 1; -} - -static int bpygpu_ParseVertFetchMode(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 == strlen(STRINGIFY(id))) { \ - if (STREQ(mode_id, STRINGIFY(id))) { \ - mode = GPU_FETCH_##id; \ - goto success; \ - } \ - } ((void)0) - - GPUVertFetchMode mode; - MATCH_ID(FLOAT); - MATCH_ID(INT); - MATCH_ID(INT_TO_FLOAT_UNIT); - MATCH_ID(INT_TO_FLOAT); -#undef MATCH_ID - PyErr_Format(PyExc_ValueError, - "unknown type literal: '%s'", - mode_id); - return 0; - -success: - (*(GPUVertFetchMode *)p) = mode; - return 1; -} - -static int bpygpu_ParsePrimType(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 == strlen(STRINGIFY(id))) { \ - if (STREQ(mode_id, STRINGIFY(id))) { \ - mode = GPU_PRIM_##id; \ - goto success; \ - } \ - } ((void)0) - - GPUPrimType mode; - MATCH_ID(POINTS); - MATCH_ID(LINES); - MATCH_ID(TRIS); - MATCH_ID(LINE_STRIP); - MATCH_ID(LINE_LOOP); - MATCH_ID(TRI_STRIP); - MATCH_ID(TRI_FAN); - MATCH_ID(LINE_STRIP_ADJ); - -#undef MATCH_ID - PyErr_Format(PyExc_ValueError, - "unknown type literal: '%s'", - mode_id); - return 0; - -success: - (*(GPUPrimType *)p) = mode; - return 1; -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Utility Functions - * \{ */ - -#define PY_AS_NATIVE_SWITCH(attr) \ - switch (attr->comp_type) { \ - case GPU_COMP_I8: { PY_AS_NATIVE(int8_t, PyC_Long_AsI8); break; } \ - case GPU_COMP_U8: { PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); break; } \ - case GPU_COMP_I16: { PY_AS_NATIVE(int16_t, PyC_Long_AsI16); break; } \ - case GPU_COMP_U16: { PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); break; } \ - case GPU_COMP_I32: { PY_AS_NATIVE(int32_t, PyC_Long_AsI32); break; } \ - case GPU_COMP_U32: { PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); break; } \ - case GPU_COMP_F32: { PY_AS_NATIVE(float, PyFloat_AsDouble); break; } \ - default: \ - BLI_assert(0); \ - } ((void)0) - -/* No error checking, callers must run PyErr_Occurred */ -static void fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr) -{ -#define PY_AS_NATIVE(ty_dst, py_as_native) \ -{ \ - ty_dst *data_dst = data_dst_void; \ - *data_dst = py_as_native(py_src); \ -} ((void)0) - - PY_AS_NATIVE_SWITCH(attr); - -#undef PY_AS_NATIVE -} - -/* No error checking, callers must run PyErr_Occurred */ -static void fill_format_tuple(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr) -{ - const uint len = attr->comp_len; - -/** - * Args are constants, so range checks will be optimized out if they're nop's. - */ -#define PY_AS_NATIVE(ty_dst, py_as_native) \ - ty_dst *data_dst = data_dst_void; \ - for (uint i = 0; i < len; i++) { \ - data_dst[i] = py_as_native(PyTuple_GET_ITEM(py_src, i)); \ - } ((void)0) - - PY_AS_NATIVE_SWITCH(attr); - -#undef PY_AS_NATIVE -} - -#undef PY_AS_NATIVE_SWITCH -#undef WARN_TYPE_LIMIT_PUSH -#undef WARN_TYPE_LIMIT_POP - -static bool bpygpu_vertbuf_fill_impl( - GPUVertBuf *vbo, - uint data_id, PyObject *seq) -{ - bool ok = true; - const GPUVertAttr *attr = &vbo->format.attribs[data_id]; - - GPUVertBufRaw data_step; - GPU_vertbuf_attr_get_raw_data(vbo, data_id, &data_step); - - PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill"); - if (seq_fast == NULL) { - goto finally; - } - - const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast); - - if (seq_len != vbo->vertex_len) { - PyErr_Format(PyExc_ValueError, - "Expected a sequence of size %d, got %d", - vbo->vertex_len, seq_len); - } - - PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); - - if (attr->comp_len == 1) { - for (uint i = 0; i < seq_len; i++) { - uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); - PyObject *item = seq_items[i]; - fill_format_elem(data, item, attr); - } - } - else { - for (uint i = 0; i < seq_len; i++) { - uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); - PyObject *item = seq_items[i]; - if (!PyTuple_CheckExact(item)) { - PyErr_Format(PyExc_ValueError, - "expected a tuple, got %s", - Py_TYPE(item)->tp_name); - ok = false; - goto finally; - } - if (PyTuple_GET_SIZE(item) != attr->comp_len) { - PyErr_Format(PyExc_ValueError, - "expected a tuple of size %d, got %d", - attr->comp_len, PyTuple_GET_SIZE(item)); - ok = false; - goto finally; - } - - /* May trigger error, check below */ - fill_format_tuple(data, item, attr); - } - } - - if (PyErr_Occurred()) { - ok = false; - } - -finally: - - Py_DECREF(seq_fast); - return ok; -} - -/* handy, but not used just now */ -#if 0 -static int bpygpu_find_id(const GPUVertFormat *fmt, const char *id) -{ - for (int i = 0; i < fmt->attr_len; i++) { - for (uint j = 0; j < fmt->name_len; j++) { - if (STREQ(fmt->attribs[i].name[j], id)) { - return i; - } - } - } - return -1; -} -#endif - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name VertFormat Type - * \{ */ - -static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) -{ - if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) { - PyErr_SetString(PyExc_TypeError, - "VertFormat(): takes no arguments"); - return NULL; - } - - BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); - - return (PyObject *)ret; -} - -PyDoc_STRVAR(bpygpu_VertFormat_attr_add_doc, -"TODO" -); -static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"id", "comp_type", "len", "fetch_mode", NULL}; - - struct { - const char *id; - GPUVertCompType comp_type; - uint len; - GPUVertFetchMode fetch_mode; - } params; - - if (self->fmt.attr_len == GPU_VERT_ATTR_MAX_LEN) { - PyErr_SetString(PyExc_ValueError, "Maxumum attr reached " STRINGIFY(GPU_VERT_ATTR_MAX_LEN)); - return NULL; - } - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "$sO&IO&:attr_add", (char **)kwlist, - ¶ms.id, - bpygpu_ParseVertCompType, ¶ms.comp_type, - ¶ms.len, - bpygpu_ParseVertFetchMode, ¶ms.fetch_mode)) - { - return NULL; - } - - uint attr_id = GPU_vertformat_attr_add(&self->fmt, params.id, params.comp_type, params.len, params.fetch_mode); - return PyLong_FromLong(attr_id); -} - -static struct PyMethodDef bpygpu_VertFormat_methods[] = { - {"attr_add", (PyCFunction)bpygpu_VertFormat_attr_add, - METH_VARARGS | METH_KEYWORDS, bpygpu_VertFormat_attr_add_doc}, - {NULL, NULL, 0, NULL} -}; - - -static void bpygpu_VertFormat_dealloc(BPyGPUVertFormat *self) -{ - Py_TYPE(self)->tp_free(self); -} - -PyTypeObject BPyGPUVertFormat_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "GPUVertFormat", - .tp_basicsize = sizeof(BPyGPUVertFormat), - .tp_dealloc = (destructor)bpygpu_VertFormat_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_methods = bpygpu_VertFormat_methods, - .tp_new = bpygpu_VertFormat_new, -}; - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name VertBuf Type - * \{ */ - -static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) -{ - const char * const keywords[] = {"len", "format", NULL}; - - struct { - BPyGPUVertFormat *py_fmt; - uint len; - } params; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, - "$IO!:GPUVertBuf.__new__", (char **)keywords, - ¶ms.len, - &BPyGPUVertFormat_Type, ¶ms.py_fmt)) - { - return NULL; - } - - struct GPUVertBuf *vbo = GPU_vertbuf_create_with_format(¶ms.py_fmt->fmt); - - GPU_vertbuf_data_alloc(vbo, params.len); - - return BPyGPUVertBuf_CreatePyObject(vbo); -} - -PyDoc_STRVAR(bpygpu_VertBuf_fill_doc, -"TODO" -); -static PyObject *bpygpu_VertBuf_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"id", "data", NULL}; - - struct { - uint id; - PyObject *py_seq_data; - } params; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "$IO:fill", (char **)kwlist, - ¶ms.id, - ¶ms.py_seq_data)) - { - return NULL; - } - - if (params.id >= self->buf->format.attr_len) { - PyErr_Format(PyExc_ValueError, - "Format id %d out of range", - params.id); - return NULL; - } - - if (self->buf->data == NULL) { - PyErr_SetString(PyExc_ValueError, - "Can't fill, static buffer already in use"); - return NULL; - } - - if (!bpygpu_vertbuf_fill_impl(self->buf, params.id, params.py_seq_data)) { - return NULL; - } - Py_RETURN_NONE; -} - -static struct PyMethodDef bpygpu_VertBuf_methods[] = { - {"fill", (PyCFunction) bpygpu_VertBuf_fill, - METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_fill_doc}, - {NULL, NULL, 0, NULL} -}; - -static void bpygpu_VertBuf_dealloc(BPyGPUVertBuf *self) -{ - GPU_vertbuf_discard(self->buf); - Py_TYPE(self)->tp_free(self); -} - -PyTypeObject BPyGPUVertBuf_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "GPUVertBuf", - .tp_basicsize = sizeof(BPyGPUVertBuf), - .tp_dealloc = (destructor)bpygpu_VertBuf_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_methods = bpygpu_VertBuf_methods, - .tp_new = bpygpu_VertBuf_new, -}; - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name VertBatch Type - * \{ */ - -static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) -{ - const char * const keywords[] = {"type", "buf", NULL}; - - struct { - GPUPrimType type_id; - BPyGPUVertBuf *py_buf; - } params; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, - "$O&O!:GPUBatch.__new__", (char **)keywords, - bpygpu_ParsePrimType, ¶ms.type_id, - &BPyGPUVertBuf_Type, ¶ms.py_buf)) - { - return NULL; - } - - GPUBatch *batch = GPU_batch_create(params.type_id, params.py_buf->buf, NULL); - BPyGPUBatch *ret = (BPyGPUBatch *)BPyGPUBatch_CreatePyObject(batch); - -#ifdef USE_GPU_PY_REFERENCES - ret->references = PyList_New(1); - PyList_SET_ITEM(ret->references, 0, (PyObject *)params.py_buf); - Py_INCREF(params.py_buf); - PyObject_GC_Track(ret); -#endif - - return (PyObject *)ret; -} - -PyDoc_STRVAR(bpygpu_VertBatch_vertbuf_add_doc, -"TODO" -); -static PyObject *bpygpu_VertBatch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf) -{ - if (!BPyGPUVertBuf_Check(py_buf)) { - PyErr_Format(PyExc_TypeError, - "Expected a GPUVertBuf, got %s", - Py_TYPE(py_buf)->tp_name); - return NULL; - } - - if (self->batch->verts[0]->vertex_len != py_buf->buf->vertex_len) { - PyErr_Format(PyExc_TypeError, - "Expected %d length, got %d", - self->batch->verts[0]->vertex_len, py_buf->buf->vertex_len); - return NULL; - } - -#ifdef USE_GPU_PY_REFERENCES - /* Hold user */ - PyList_Append(self->references, (PyObject *)py_buf); -#endif - - GPU_batch_vertbuf_add(self->batch, py_buf->buf); - Py_RETURN_NONE; -} - -/* Currently magic number from Py perspective. */ -PyDoc_STRVAR(bpygpu_VertBatch_program_set_builtin_doc, -"TODO" -); -static PyObject *bpygpu_VertBatch_program_set_builtin(BPyGPUBatch *self, PyObject *args, PyObject *kwds) -{ - static const char *kwlist[] = {"id", NULL}; - - struct { - const char *shader; - } params; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "s:program_set_builtin", (char **)kwlist, - ¶ms.shader)) - { - return NULL; - } - - GPUBuiltinShader shader; - -#define MATCH_ID(id) \ - if (STREQ(params.shader, STRINGIFY(id))) { \ - shader = GPU_SHADER_##id; \ - goto success; \ - } ((void)0) - - MATCH_ID(2D_FLAT_COLOR); - MATCH_ID(2D_SMOOTH_COLOR); - MATCH_ID(2D_UNIFORM_COLOR); - - MATCH_ID(3D_FLAT_COLOR); - MATCH_ID(3D_SMOOTH_COLOR); - MATCH_ID(3D_UNIFORM_COLOR); - -#undef MATCH_ID - - PyErr_SetString(PyExc_ValueError, - "shader name not known"); - return NULL; - -success: - GPU_batch_program_set_builtin(self->batch, shader); - Py_RETURN_NONE; -} - -static PyObject *bpygpu_VertBatch_uniform_bool(BPyGPUBatch *self, PyObject *args) -{ - struct { - const char *id; - bool values[1]; - } params; - - if (!PyArg_ParseTuple( - args, "sO&:uniform_bool", - ¶ms.id, - PyC_ParseBool, ¶ms.values[0])) - { - return NULL; - } - - GPU_batch_uniform_1b(self->batch, params.id, params.values[0]); - Py_RETURN_NONE; -} - -static PyObject *bpygpu_VertBatch_uniform_i32(BPyGPUBatch *self, PyObject *args) -{ - struct { - const char *id; - int values[1]; - } params; - - if (!PyArg_ParseTuple( - args, "si:uniform_i32", - ¶ms.id, - ¶ms.values[0])) - { - return NULL; - } - - GPU_batch_uniform_1i(self->batch, params.id, params.values[0]); - Py_RETURN_NONE; -} - -static PyObject *bpygpu_VertBatch_uniform_f32(BPyGPUBatch *self, PyObject *args) -{ - struct { - const char *id; - float values[4]; - } params; - - if (!PyArg_ParseTuple( - args, "sf|fff:uniform_f32", - ¶ms.id, - ¶ms.values[0], ¶ms.values[1], ¶ms.values[2], ¶ms.values[3])) - { - return NULL; - } - - switch (PyTuple_GET_SIZE(args)) { - case 2: GPU_batch_uniform_1f(self->batch, params.id, params.values[0]); break; - case 3: GPU_batch_uniform_2f(self->batch, params.id, UNPACK2(params.values)); break; - case 4: GPU_batch_uniform_3f(self->batch, params.id, UNPACK3(params.values)); break; - case 5: GPU_batch_uniform_4f(self->batch, params.id, UNPACK4(params.values)); break; - default: - BLI_assert(0); - } - Py_RETURN_NONE; -} - -PyDoc_STRVAR(bpygpu_VertBatch_draw_doc, -"TODO" -); -static PyObject *bpygpu_VertBatch_draw(BPyGPUBatch *self) -{ - if (!glIsProgram(self->batch->program)) { - PyErr_SetString(PyExc_ValueError, - "batch program has not not set"); - } - GPU_batch_draw(self->batch); - Py_RETURN_NONE; -} - -static PyObject *bpygpu_VertBatch_program_use_begin(BPyGPUBatch *self) -{ - if (!glIsProgram(self->batch->program)) { - PyErr_SetString(PyExc_ValueError, - "batch program has not not set"); - } - GPU_batch_program_use_begin(self->batch); - Py_RETURN_NONE; -} - -static PyObject *bpygpu_VertBatch_program_use_end(BPyGPUBatch *self) -{ - if (!glIsProgram(self->batch->program)) { - PyErr_SetString(PyExc_ValueError, - "batch program has not not set"); - } - GPU_batch_program_use_end(self->batch); - Py_RETURN_NONE; -} - -static struct PyMethodDef bpygpu_VertBatch_methods[] = { - {"vertbuf_add", (PyCFunction)bpygpu_VertBatch_vertbuf_add, - METH_O, bpygpu_VertBatch_vertbuf_add_doc}, - {"program_set_builtin", (PyCFunction)bpygpu_VertBatch_program_set_builtin, - METH_VARARGS | METH_KEYWORDS, bpygpu_VertBatch_program_set_builtin_doc}, - {"uniform_bool", (PyCFunction)bpygpu_VertBatch_uniform_bool, - METH_VARARGS, NULL}, - {"uniform_i32", (PyCFunction)bpygpu_VertBatch_uniform_i32, - METH_VARARGS, NULL}, - {"uniform_f32", (PyCFunction)bpygpu_VertBatch_uniform_f32, - METH_VARARGS, NULL}, - {"draw", (PyCFunction) bpygpu_VertBatch_draw, - METH_NOARGS, bpygpu_VertBatch_draw_doc}, - {"program_use_begin", (PyCFunction)bpygpu_VertBatch_program_use_begin, - METH_NOARGS, ""}, - {"program_use_end", (PyCFunction)bpygpu_VertBatch_program_use_end, - METH_NOARGS, ""}, - {NULL, NULL, 0, NULL} -}; - -#ifdef USE_GPU_PY_REFERENCES - -static int bpygpu_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg) -{ - Py_VISIT(self->references); - return 0; -} - -static int bpygpu_Batch_clear(BPyGPUBatch *self) -{ - Py_CLEAR(self->references); - return 0; -} - -#endif - -static void bpygpu_Batch_dealloc(BPyGPUBatch *self) -{ - GPU_batch_discard(self->batch); - -#ifdef USE_GPU_PY_REFERENCES - if (self->references) { - PyObject_GC_UnTrack(self); - bpygpu_Batch_clear(self); - Py_XDECREF(self->references); - } -#endif - - Py_TYPE(self)->tp_free(self); -} - -PyTypeObject BPyGPUBatch_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "GPUBatch", - .tp_basicsize = sizeof(BPyGPUBatch), - .tp_dealloc = (destructor)bpygpu_Batch_dealloc, -#ifdef USE_GPU_PY_REFERENCES - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, - .tp_traverse = (traverseproc)bpygpu_Batch_traverse, - .tp_clear = (inquiry)bpygpu_Batch_clear, -#else - .tp_flags = Py_TPFLAGS_DEFAULT, -#endif - .tp_methods = bpygpu_VertBatch_methods, - .tp_new = bpygpu_Batch_new, -}; - /* -------------------------------------------------------------------- */ /** \name GPU Types Module * \{ */ -static struct PyModuleDef BPy_BM_types_module_def = { +static struct PyModuleDef BPyGPU_types_module_def = { PyModuleDef_HEAD_INIT, - .m_name = "_gpu.types", + .m_name = "gpu.types", }; PyObject *BPyInit_gpu_types(void) { PyObject *submodule; - submodule = PyModule_Create(&BPy_BM_types_module_def); + submodule = PyModule_Create(&BPyGPU_types_module_def); if (PyType_Ready(&BPyGPUVertFormat_Type) < 0) return NULL; @@ -779,6 +55,8 @@ PyObject *BPyInit_gpu_types(void) return NULL; if (PyType_Ready(&BPyGPUBatch_Type) < 0) return NULL; + if (PyType_Ready(&BPyGPUOffScreen_Type) < 0) + return NULL; #define MODULE_TYPE_ADD(s, t) \ PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t) @@ -786,6 +64,7 @@ PyObject *BPyInit_gpu_types(void) MODULE_TYPE_ADD(submodule, BPyGPUVertFormat_Type); MODULE_TYPE_ADD(submodule, BPyGPUVertBuf_Type); MODULE_TYPE_ADD(submodule, BPyGPUBatch_Type); + MODULE_TYPE_ADD(submodule, BPyGPUOffScreen_Type); #undef MODULE_TYPE_ADD @@ -793,53 +72,3 @@ PyObject *BPyInit_gpu_types(void) } /** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Public API - * \{ */ - -PyObject *BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt) -{ - BPyGPUVertFormat *self; - - self = PyObject_New(BPyGPUVertFormat, &BPyGPUVertFormat_Type); - if (fmt) { - self->fmt = *fmt; - } - else { - memset(&self->fmt, 0, sizeof(self->fmt)); - } - - return (PyObject *)self; -} - -PyObject *BPyGPUVertBuf_CreatePyObject(GPUVertBuf *buf) -{ - BPyGPUVertBuf *self; - - self = PyObject_New(BPyGPUVertBuf, &BPyGPUVertBuf_Type); - self->buf = buf; - - return (PyObject *)self; -} - - -PyObject *BPyGPUBatch_CreatePyObject(GPUBatch *batch) -{ - BPyGPUBatch *self; - -#ifdef USE_GPU_PY_REFERENCES - self = (BPyGPUBatch *)_PyObject_GC_New(&BPyGPUBatch_Type); - self->references = NULL; -#else - self = PyObject_New(BPyGPUBatch, &BPyGPUBatch_Type); -#endif - - self->batch = batch; - - return (PyObject *)self; -} - -/** \} */ diff --git a/source/blender/python/gpu/gpu_py_types.h b/source/blender/python/gpu/gpu_py_types.h index f736a8f749a..0b1a62b78e9 100644 --- a/source/blender/python/gpu/gpu_py_types.h +++ b/source/blender/python/gpu/gpu_py_types.h @@ -19,49 +19,17 @@ */ /** \file blender/python/gpu/gpu_py_types.h - * \ingroup pygpu + * \ingroup bpygpu */ #ifndef __GPU_PY_TYPES_H__ #define __GPU_PY_TYPES_H__ -#include "BLI_compiler_attrs.h" - -#define USE_GPU_PY_REFERENCES - -extern PyTypeObject BPyGPUVertFormat_Type; -extern PyTypeObject BPyGPUVertBuf_Type; -extern PyTypeObject BPyGPUBatch_Type; - -#define BPyGPUVertFormat_Check(v) (Py_TYPE(v) == &BPyGPUVertFormat_Type) -#define BPyGPUVertBuf_Check(v) (Py_TYPE(v) == &BPyGPUVertBuf_Type) -#define BPyGPUBatch_Check(v) (Py_TYPE(v) == &BPyGPUBatch_Type) - -typedef struct BPyGPUVertFormat { - PyObject_VAR_HEAD - struct GPUVertFormat fmt; -} BPyGPUVertFormat; - -typedef struct BPyGPUVertBuf { - PyObject_VAR_HEAD - /* The buf is owned, we may support thin wrapped batches later. */ - struct GPUVertBuf *buf; -} BPyGPUVertBuf; - -typedef struct BPyGPUBatch { - PyObject_VAR_HEAD - /* The batch is owned, we may support thin wrapped batches later. */ - struct GPUBatch *batch; -#ifdef USE_GPU_PY_REFERENCES - /* Just to keep a user to prevent freeing buf's we're using */ - PyObject *references; -#endif -} BPyGPUBatch; +#include "gpu_py_vertex_format.h" +#include "gpu_py_vertex_buffer.h" +#include "gpu_py_batch.h" +#include "gpu_py_offscreen.h" PyObject *BPyInit_gpu_types(void); -PyObject *BPyGPUVertFormat_CreatePyObject(struct GPUVertFormat *fmt); -PyObject *BPyGPUVertBuf_CreatePyObject(struct GPUVertBuf *vbo) ATTR_NONNULL(1); -PyObject *BPyGPUBatch_CreatePyObject(struct GPUBatch *batch) ATTR_NONNULL(1); - #endif /* __GPU_PY_TYPES_H__ */ diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c new file mode 100644 index 00000000000..cc67afa4342 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -0,0 +1,345 @@ +/* + * ***** 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_vertex_buffer.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "GPU_vertex_buffer.h" + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_vertex_format.h" +#include "gpu_py_vertex_buffer.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name Enum Conversion + * + * Use with PyArg_ParseTuple's "O&" formatting. + * \{ */ + +static int bpygpu_ParseVertFetchMode(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 == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GPU_FETCH_##id; \ + goto success; \ + } \ + } ((void)0) + + GPUVertFetchMode mode; + MATCH_ID(FLOAT); + MATCH_ID(INT); + MATCH_ID(INT_TO_FLOAT_UNIT); + MATCH_ID(INT_TO_FLOAT); +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(GPUVertFetchMode *)p) = mode; + return 1; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Utility Functions + * \{ */ + +#define PY_AS_NATIVE_SWITCH(attr) \ + switch (attr->comp_type) { \ + case GPU_COMP_I8: { PY_AS_NATIVE(int8_t, PyC_Long_AsI8); break; } \ + case GPU_COMP_U8: { PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); break; } \ + case GPU_COMP_I16: { PY_AS_NATIVE(int16_t, PyC_Long_AsI16); break; } \ + case GPU_COMP_U16: { PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); break; } \ + case GPU_COMP_I32: { PY_AS_NATIVE(int32_t, PyC_Long_AsI32); break; } \ + case GPU_COMP_U32: { PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); break; } \ + case GPU_COMP_F32: { PY_AS_NATIVE(float, PyFloat_AsDouble); break; } \ + default: \ + BLI_assert(0); \ + } ((void)0) + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_elem(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr) +{ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ +{ \ + ty_dst *data_dst = data_dst_void; \ + *data_dst = py_as_native(py_src); \ +} ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_tuple(void *data_dst_void, PyObject *py_src, const GPUVertAttr *attr) +{ + const uint len = attr->comp_len; + +/** + * Args are constants, so range checks will be optimized out if they're nop's. + */ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ + ty_dst *data_dst = data_dst_void; \ + for (uint i = 0; i < len; i++) { \ + data_dst[i] = py_as_native(PyTuple_GET_ITEM(py_src, i)); \ + } ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +#undef PY_AS_NATIVE_SWITCH +#undef WARN_TYPE_LIMIT_PUSH +#undef WARN_TYPE_LIMIT_POP + +static bool bpygpu_vertbuf_fill_impl( + GPUVertBuf *vbo, + uint data_id, PyObject *seq) +{ + bool ok = true; + const GPUVertAttr *attr = &vbo->format.attribs[data_id]; + + GPUVertBufRaw data_step; + GPU_vertbuf_attr_get_raw_data(vbo, data_id, &data_step); + + PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill"); + if (seq_fast == NULL) { + goto finally; + } + + const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast); + + if (seq_len != vbo->vertex_len) { + PyErr_Format(PyExc_ValueError, + "Expected a sequence of size %d, got %d", + vbo->vertex_len, seq_len); + } + + PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); + + if (attr->comp_len == 1) { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); + PyObject *item = seq_items[i]; + fill_format_elem(data, item, attr); + } + } + else { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GPU_vertbuf_raw_step(&data_step); + PyObject *item = seq_items[i]; + if (!PyTuple_CheckExact(item)) { + PyErr_Format(PyExc_ValueError, + "expected a tuple, got %s", + Py_TYPE(item)->tp_name); + ok = false; + goto finally; + } + if (PyTuple_GET_SIZE(item) != attr->comp_len) { + PyErr_Format(PyExc_ValueError, + "expected a tuple of size %d, got %d", + attr->comp_len, PyTuple_GET_SIZE(item)); + ok = false; + goto finally; + } + + /* May trigger error, check below */ + fill_format_tuple(data, item, attr); + } + } + + if (PyErr_Occurred()) { + ok = false; + } + +finally: + + Py_DECREF(seq_fast); + return ok; +} + +/* handy, but not used just now */ +#if 0 +static int bpygpu_find_id(const GPUVertFormat *fmt, const char *id) +{ + for (int i = 0; i < fmt->attr_len; i++) { + for (uint j = 0; j < fmt->name_len; j++) { + if (STREQ(fmt->attribs[i].name[j], id)) { + return i; + } + } + } + return -1; +} +#endif + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertBuf Type + * \{ */ + +static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + const char * const keywords[] = {"len", "format", NULL}; + + struct { + BPyGPUVertFormat *py_fmt; + uint len; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "$IO!:GPUVertBuf.__new__", (char **)keywords, + ¶ms.len, + &BPyGPUVertFormat_Type, ¶ms.py_fmt)) + { + return NULL; + } + + struct GPUVertBuf *vbo = GPU_vertbuf_create_with_format(¶ms.py_fmt->fmt); + + GPU_vertbuf_data_alloc(vbo, params.len); + + return BPyGPUVertBuf_CreatePyObject(vbo); +} + +PyDoc_STRVAR(bpygpu_VertBuf_fill_doc, +"TODO" +); +static PyObject *bpygpu_VertBuf_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", "data", NULL}; + + struct { + uint id; + PyObject *py_seq_data; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "$IO:fill", (char **)kwlist, + ¶ms.id, + ¶ms.py_seq_data)) + { + return NULL; + } + + if (params.id >= self->buf->format.attr_len) { + PyErr_Format(PyExc_ValueError, + "Format id %d out of range", + params.id); + return NULL; + } + + if (self->buf->data == NULL) { + PyErr_SetString(PyExc_ValueError, + "Can't fill, static buffer already in use"); + return NULL; + } + + if (!bpygpu_vertbuf_fill_impl(self->buf, params.id, params.py_seq_data)) { + return NULL; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef bpygpu_VertBuf_methods[] = { + {"fill", (PyCFunction) bpygpu_VertBuf_fill, + METH_VARARGS | METH_KEYWORDS, bpygpu_VertBuf_fill_doc}, + {NULL, NULL, 0, NULL} +}; + +static void bpygpu_VertBuf_dealloc(BPyGPUVertBuf *self) +{ + GPU_vertbuf_discard(self->buf); + Py_TYPE(self)->tp_free(self); +} + +PyDoc_STRVAR(py_gpu_vertex_buffer_doc, +"GPUVertBuf(len, format)\n" +"\n" +"Contains a VBO." +"\n" +" :param len: number of elements to allocate\n" +" :type type: int`\n" +" :param format: Vertex format.\n" +" :type buf: GPUVertFormat`\n" +); +PyTypeObject BPyGPUVertBuf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUVertBuf", + .tp_basicsize = sizeof(BPyGPUVertBuf), + .tp_dealloc = (destructor)bpygpu_VertBuf_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = py_gpu_vertex_buffer_doc, + .tp_methods = bpygpu_VertBuf_methods, + .tp_new = bpygpu_VertBuf_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUVertBuf_CreatePyObject(GPUVertBuf *buf) +{ + BPyGPUVertBuf *self; + + self = PyObject_New(BPyGPUVertBuf, &BPyGPUVertBuf_Type); + self->buf = buf; + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.h b/source/blender/python/gpu/gpu_py_vertex_buffer.h new file mode 100644 index 00000000000..6751956298c --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.h @@ -0,0 +1,42 @@ +/* + * ***** 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_vertex_buffer.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_VERTEX_BUFFER_H__ +#define __GPU_PY_VERTEX_BUFFER_H__ + +#include "BLI_compiler_attrs.h" + +extern PyTypeObject BPyGPUVertBuf_Type; + +#define BPyGPUVertBuf_Check(v) (Py_TYPE(v) == &BPyGPUVertBuf_Type) + +typedef struct BPyGPUVertBuf { + PyObject_VAR_HEAD + /* The buf is owned, we may support thin wrapped batches later. */ + struct GPUVertBuf *buf; +} BPyGPUVertBuf; + +PyObject *BPyGPUVertBuf_CreatePyObject(struct GPUVertBuf *vbo) ATTR_NONNULL(1); + +#endif /* __GPU_PY_VERTEX_BUFFER_H__ */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c new file mode 100644 index 00000000000..96ca4003dc9 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -0,0 +1,230 @@ +/* + * ***** 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_vertex_format.c + * \ingroup bpygpu + * + * - Use ``bpygpu_`` for local API. + * - Use ``BPyGPU`` for public API. + */ + +#include <Python.h> + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gpu_py_vertex_format.h" /* own include */ + +#ifdef __BIG_ENDIAN__ + /* big endian */ +# define MAKE_ID2(c, d) ((c) << 8 | (d)) +# define MAKE_ID3(a, b, c) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 ) +# define MAKE_ID4(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) ) +#else + /* little endian */ +# define MAKE_ID2(c, d) ((d) << 8 | (c)) +# define MAKE_ID3(a, b, c) ( (int)(c) << 16 | (b) << 8 | (a) ) +# define MAKE_ID4(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) ) +#endif + +/* -------------------------------------------------------------------- */ + +/** \name Enum Conversion + * + * Use with PyArg_ParseTuple's "O&" formatting. + * \{ */ + +static int bpygpu_ParseVertCompType(PyObject *o, void *p) +{ + Py_ssize_t comp_type_id_len; + const char *comp_type_id = _PyUnicode_AsStringAndSize(o, &comp_type_id_len); + if (comp_type_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } + + GPUVertCompType comp_type; + if (comp_type_id_len == 2) { + switch (*((ushort *)comp_type_id)) { + case MAKE_ID2('I', '8'): { comp_type = GPU_COMP_I8; goto success; } + case MAKE_ID2('U', '8'): { comp_type = GPU_COMP_U8; goto success; } + } + } + else if (comp_type_id_len == 3) { + switch (*((uint *)comp_type_id)) { + case MAKE_ID3('I', '1', '6'): { comp_type = GPU_COMP_I16; goto success; } + case MAKE_ID3('U', '1', '6'): { comp_type = GPU_COMP_U16; goto success; } + case MAKE_ID3('I', '3', '2'): { comp_type = GPU_COMP_I32; goto success; } + case MAKE_ID3('U', '3', '2'): { comp_type = GPU_COMP_U32; goto success; } + case MAKE_ID3('F', '3', '2'): { comp_type = GPU_COMP_F32; goto success; } + case MAKE_ID3('I', '1', '0'): { comp_type = GPU_COMP_I10; goto success; } + } + } + + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + comp_type_id); + return 0; + +success: + *((GPUVertCompType *)p) = comp_type; + return 1; +} + +static int bpygpu_ParseVertFetchMode(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 == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GPU_FETCH_##id; \ + goto success; \ + } \ + } ((void)0) + + GPUVertFetchMode mode; + MATCH_ID(FLOAT); + MATCH_ID(INT); + MATCH_ID(INT_TO_FLOAT_UNIT); + MATCH_ID(INT_TO_FLOAT); +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(GPUVertFetchMode *)p) = mode; + return 1; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertFormat Type + * \{ */ + +static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) { + PyErr_SetString(PyExc_TypeError, + "VertFormat(): takes no arguments"); + return NULL; + } + + BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); + + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygpu_VertFormat_attr_add_doc, +"TODO" +); +static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", "comp_type", "len", "fetch_mode", NULL}; + + struct { + const char *id; + GPUVertCompType comp_type; + uint len; + GPUVertFetchMode fetch_mode; + } params; + + if (self->fmt.attr_len == GPU_VERT_ATTR_MAX_LEN) { + PyErr_SetString(PyExc_ValueError, "Maxumum attr reached " STRINGIFY(GPU_VERT_ATTR_MAX_LEN)); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "$sO&IO&:attr_add", (char **)kwlist, + ¶ms.id, + bpygpu_ParseVertCompType, ¶ms.comp_type, + ¶ms.len, + bpygpu_ParseVertFetchMode, ¶ms.fetch_mode)) + { + return NULL; + } + + uint attr_id = GPU_vertformat_attr_add(&self->fmt, params.id, params.comp_type, params.len, params.fetch_mode); + return PyLong_FromLong(attr_id); +} + +static struct PyMethodDef bpygpu_VertFormat_methods[] = { + {"attr_add", (PyCFunction)bpygpu_VertFormat_attr_add, + METH_VARARGS | METH_KEYWORDS, bpygpu_VertFormat_attr_add_doc}, + {NULL, NULL, 0, NULL} +}; + + +static void bpygpu_VertFormat_dealloc(BPyGPUVertFormat *self) +{ + Py_TYPE(self)->tp_free(self); +} + +PyTypeObject BPyGPUVertFormat_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUVertFormat", + .tp_basicsize = sizeof(BPyGPUVertFormat), + .tp_dealloc = (destructor)bpygpu_VertFormat_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = bpygpu_VertFormat_methods, + .tp_new = bpygpu_VertFormat_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGPUVertFormat_CreatePyObject(GPUVertFormat *fmt) +{ + BPyGPUVertFormat *self; + + self = PyObject_New(BPyGPUVertFormat, &BPyGPUVertFormat_Type); + if (fmt) { + self->fmt = *fmt; + } + else { + memset(&self->fmt, 0, sizeof(self->fmt)); + } + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.h b/source/blender/python/gpu/gpu_py_vertex_format.h new file mode 100644 index 00000000000..5b0bf1addc2 --- /dev/null +++ b/source/blender/python/gpu/gpu_py_vertex_format.h @@ -0,0 +1,41 @@ +/* + * ***** 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_vertex_format.h + * \ingroup bpygpu + */ + +#ifndef __GPU_PY_VERTEX_FORMAT_H__ +#define __GPU_PY_VERTEX_FORMAT_H__ + +#include "GPU_vertex_format.h" + +extern PyTypeObject BPyGPUVertFormat_Type; + +#define BPyGPUVertFormat_Check(v) (Py_TYPE(v) == &BPyGPUVertFormat_Type) + +typedef struct BPyGPUVertFormat { + PyObject_VAR_HEAD + struct GPUVertFormat fmt; +} BPyGPUVertFormat; + +PyObject *BPyGPUVertFormat_CreatePyObject(struct GPUVertFormat *fmt); + +#endif /* __GPU_PY_VERTEX_FORMAT_H__ */ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 3255fb49667..1390b97af33 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -82,10 +82,6 @@ set(SRC bpy_traceback.c bpy_utils_previews.c bpy_utils_units.c - gpu.c - gpu_offscreen.c - gpu_py_matrix.c - gpu_py_select.c stubs.c bpy.h @@ -120,7 +116,6 @@ set(SRC bpy_traceback.h bpy_utils_previews.h bpy_utils_units.h - gpu.h ../BPY_extern.h ../BPY_extern_clog.h ) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 1276721e32f..3ba024de7c2 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -46,7 +46,6 @@ #include "RNA_types.h" #include "bpy.h" -#include "gpu.h" #include "bpy_rna.h" #include "bpy_path.h" #include "bpy_capi_utils.h" @@ -219,7 +218,6 @@ static struct _inittab bpy_internal_modules[] = { {"mathutils.kdtree", PyInit_mathutils_kdtree}, #endif {"_bpy_path", BPyInit__bpy_path}, - {"_gpu", BPyInit_gpu}, {"bgl", BPyInit_bgl}, {"blf", BPyInit_blf}, {"imbuf", BPyInit_imbuf}, @@ -235,7 +233,7 @@ static struct _inittab bpy_internal_modules[] = { #ifdef WITH_CYCLES {"_cycles", CCL_initPython}, #endif - {"gpu", GPU_initPython}, + {"gpu", BPyInit_gpu}, {"idprop", BPyInit_idprop}, {NULL, NULL} }; |