Blender  V2.93
gpu_py_element.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
24 #include <Python.h>
25 
26 #include "GPU_index_buffer.h"
27 
28 #include "BLI_math.h"
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "../generic/py_capi_utils.h"
33 #include "../generic/python_utildefines.h"
34 
35 #include "gpu_py.h"
36 #include "gpu_py_element.h" /* own include */
37 
38 /* -------------------------------------------------------------------- */
42 static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
43 {
45 
46  const char *error_prefix = "IndexBuf.__new__";
47  bool ok = true;
48 
50  PyObject *seq;
51 
52  uint verts_per_prim;
53  uint index_len;
54  GPUIndexBufBuilder builder;
55 
56  static const char *_keywords[] = {"type", "seq", NULL};
57  static _PyArg_Parser _parser = {"$O&O:IndexBuf.__new__", _keywords, 0};
58  if (!_PyArg_ParseTupleAndKeywordsFast(
59  args, kwds, &_parser, PyC_ParseStringEnum, &prim_type, &seq)) {
60  return NULL;
61  }
62 
63  verts_per_prim = GPU_indexbuf_primitive_len(prim_type.value_found);
64  if (verts_per_prim == -1) {
65  PyErr_Format(PyExc_ValueError,
66  "The argument 'type' must be "
67  "'POINTS', 'LINES', 'TRIS' or 'LINES_ADJ'");
68  return NULL;
69  }
70 
71  if (PyObject_CheckBuffer(seq)) {
72  Py_buffer pybuffer;
73 
74  if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_FORMAT | PyBUF_ND) == -1) {
75  /* PyObject_GetBuffer already handles error messages. */
76  return NULL;
77  }
78 
79  if (pybuffer.ndim != 1 && pybuffer.shape[1] != verts_per_prim) {
80  PyErr_Format(PyExc_ValueError, "Each primitive must exactly %d indices", verts_per_prim);
81  return NULL;
82  }
83 
84  if (pybuffer.itemsize != 4 ||
86  PyErr_Format(PyExc_ValueError, "Each index must be an 4-bytes integer value");
87  return NULL;
88  }
89 
90  index_len = pybuffer.shape[0];
91  if (pybuffer.ndim != 1) {
92  index_len *= pybuffer.shape[1];
93  }
94 
95  /* The `vertex_len` parameter is only used for asserts in the Debug build. */
96  /* Not very useful in python since scripts are often tested in Release build. */
97  /* Use `INT_MAX` instead of the actual number of vertices. */
98  GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
99 
100 #if 0
101  uint *buf = pybuffer.buf;
102  for (uint i = index_len; i--; buf++) {
103  GPU_indexbuf_add_generic_vert(&builder, *buf);
104  }
105 #else
106  memcpy(builder.data, pybuffer.buf, index_len * sizeof(*builder.data));
107  builder.index_len = index_len;
108 #endif
109  PyBuffer_Release(&pybuffer);
110  }
111  else {
112  PyObject *seq_fast = PySequence_Fast(seq, error_prefix);
113 
114  if (seq_fast == NULL) {
115  return false;
116  }
117 
118  const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
119 
120  PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
121 
122  index_len = seq_len * verts_per_prim;
123 
124  /* The `vertex_len` parameter is only used for asserts in the Debug build. */
125  /* Not very useful in python since scripts are often tested in Release build. */
126  /* Use `INT_MAX` instead of the actual number of vertices. */
127  GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
128 
129  if (verts_per_prim == 1) {
130  for (uint i = 0; i < seq_len; i++) {
131  GPU_indexbuf_add_generic_vert(&builder, PyC_Long_AsU32(seq_items[i]));
132  }
133  }
134  else {
135  int values[4];
136  for (uint i = 0; i < seq_len; i++) {
137  PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
138  if (seq_fast_item == NULL) {
139  PyErr_Format(PyExc_TypeError,
140  "%s: expected a sequence, got %s",
141  error_prefix,
142  Py_TYPE(seq_items[i])->tp_name);
143  ok = false;
144  goto finally;
145  }
146 
147  ok = PyC_AsArray_FAST(
148  values, seq_fast_item, verts_per_prim, &PyLong_Type, false, error_prefix) == 0;
149 
150  if (ok) {
151  for (uint j = 0; j < verts_per_prim; j++) {
152  GPU_indexbuf_add_generic_vert(&builder, values[j]);
153  }
154  }
155  Py_DECREF(seq_fast_item);
156  }
157  }
158 
159  if (PyErr_Occurred()) {
160  ok = false;
161  }
162 
163  finally:
164 
165  Py_DECREF(seq_fast);
166  }
167 
168  if (ok == false) {
169  MEM_freeN(builder.data);
170  return NULL;
171  }
172 
174 }
175 
177 {
178  GPU_indexbuf_discard(self->elem);
179  Py_TYPE(self)->tp_free(self);
180 }
181 
182 PyDoc_STRVAR(pygpu_IndexBuf__tp_doc,
183  ".. class:: GPUIndexBuf(type, seq)\n"
184  "\n"
185  " Contains an index buffer.\n"
186  "\n"
187  " :arg type: The primitive type this index buffer is composed of.\n"
188  " Possible values are `POINTS`, `LINES`, `TRIS` and `LINE_STRIP_ADJ`.\n"
189  " :type type: str\n"
190  " :param seq: Indices this index buffer will contain.\n"
191  " Whether a 1D or 2D sequence is required depends on the type.\n"
192  " Optionally the sequence can support the buffer protocol.\n"
193  " :type seq: 1D or 2D sequence\n");
194 PyTypeObject BPyGPUIndexBuf_Type = {
195  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUIndexBuf",
196  .tp_basicsize = sizeof(BPyGPUIndexBuf),
197  .tp_dealloc = (destructor)pygpu_IndexBuf__tp_dealloc,
198  .tp_flags = Py_TPFLAGS_DEFAULT,
199  .tp_doc = pygpu_IndexBuf__tp_doc,
200  .tp_new = pygpu_IndexBuf__tp_new,
201 };
202 
205 /* -------------------------------------------------------------------- */
210 {
211  BPyGPUIndexBuf *self;
212 
213  self = PyObject_New(BPyGPUIndexBuf, &BPyGPUIndexBuf_Type);
214  self->elem = elem;
215 
216  return (PyObject *)self;
217 }
218 
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
struct GPUIndexBuf GPUIndexBuf
int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v)
void GPU_indexbuf_discard(GPUIndexBuf *elem)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
@ GPU_PRIM_NONE
Definition: GPU_primitive.h:47
Read Guarded memory(de)allocation.
PyObject * self
Definition: bpy_driver.c:185
struct PyC_StringEnumItems bpygpu_primtype_items[]
Definition: gpu_py.c:38
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition: gpu_py.h:28
static void pygpu_IndexBuf__tp_dealloc(BPyGPUIndexBuf *self)
PyObject * BPyGPUIndexBuf_CreatePyObject(GPUIndexBuf *elem)
PyDoc_STRVAR(pygpu_IndexBuf__tp_doc, ".. class:: GPUIndexBuf(type, seq)\n" "\n" " Contains an index buffer.\n" "\n" " :arg type: The primitive type this index buffer is composed of.\n" " Possible values are `POINTS`, `LINES`, `TRIS` and `LINE_STRIP_ADJ`.\n" " :type type: str\n" " :param seq: Indices this index buffer will contain.\n" " Whether a 1D or 2D sequence is required depends on the type.\n" " Optionally the sequence can support the buffer protocol.\n" " :type seq: 1D or 2D sequence\n")
PyTypeObject BPyGPUIndexBuf_Type
static PyObject * pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
struct BPyGPUIndexBuf BPyGPUIndexBuf
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
char PyC_StructFmt_type_from_str(const char *typestr)
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_AsArray_FAST(void *array, PyObject *value_fast, const Py_ssize_t length, const PyTypeObject *type, const bool is_double, const char *error_prefix)
Definition: py_capi_utils.c:59
uint32_t PyC_Long_AsU32(PyObject *value)
bool PyC_StructFmt_type_is_float_any(char format)