Blender  V3.3
gpu_py_element.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
10 #include <Python.h>
11 
12 #include "GPU_index_buffer.h"
13 
14 #include "BLI_math.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include "../generic/py_capi_utils.h"
19 
20 #include "gpu_py.h"
21 #include "gpu_py_element.h" /* own include */
22 
23 /* -------------------------------------------------------------------- */
27 static PyObject *pygpu_IndexBuf__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
28 {
30 
31  const char *error_prefix = "IndexBuf.__new__";
32  bool ok = true;
33 
35  PyObject *seq;
36 
37  uint verts_per_prim;
38  uint index_len;
39  GPUIndexBufBuilder builder;
40 
41  static const char *_keywords[] = {"type", "seq", NULL};
42  static _PyArg_Parser _parser = {
43  "$O" /* `type` */
44  "&O" /* `seq` */
45  ":IndexBuf.__new__",
46  _keywords,
47  0,
48  };
49  if (!_PyArg_ParseTupleAndKeywordsFast(
50  args, kwds, &_parser, PyC_ParseStringEnum, &prim_type, &seq)) {
51  return NULL;
52  }
53 
54  verts_per_prim = GPU_indexbuf_primitive_len(prim_type.value_found);
55  if (verts_per_prim == -1) {
56  PyErr_Format(PyExc_ValueError,
57  "The argument 'type' must be "
58  "'POINTS', 'LINES', 'TRIS' or 'LINES_ADJ'");
59  return NULL;
60  }
61 
62  if (PyObject_CheckBuffer(seq)) {
63  Py_buffer pybuffer;
64 
65  if (PyObject_GetBuffer(seq, &pybuffer, PyBUF_FORMAT | PyBUF_ND) == -1) {
66  /* PyObject_GetBuffer already handles error messages. */
67  return NULL;
68  }
69 
70  if (pybuffer.ndim != 1 && pybuffer.shape[1] != verts_per_prim) {
71  PyErr_Format(PyExc_ValueError, "Each primitive must exactly %d indices", verts_per_prim);
72  PyBuffer_Release(&pybuffer);
73  return NULL;
74  }
75 
76  if (pybuffer.itemsize != 4 ||
78  PyErr_Format(PyExc_ValueError, "Each index must be an 4-bytes integer value");
79  PyBuffer_Release(&pybuffer);
80  return NULL;
81  }
82 
83  index_len = pybuffer.shape[0];
84  if (pybuffer.ndim != 1) {
85  index_len *= pybuffer.shape[1];
86  }
87 
88  /* The `vertex_len` parameter is only used for asserts in the Debug build. */
89  /* Not very useful in python since scripts are often tested in Release build. */
90  /* Use `INT_MAX` instead of the actual number of vertices. */
91  GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
92 
93  uint *buf = pybuffer.buf;
94  for (uint i = index_len; i--; buf++) {
95  GPU_indexbuf_add_generic_vert(&builder, *buf);
96  }
97 
98  PyBuffer_Release(&pybuffer);
99  }
100  else {
101  PyObject *seq_fast = PySequence_Fast(seq, error_prefix);
102 
103  if (seq_fast == NULL) {
104  return false;
105  }
106 
107  const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast);
108 
109  PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast);
110 
111  index_len = seq_len * verts_per_prim;
112 
113  /* The `vertex_len` parameter is only used for asserts in the Debug build. */
114  /* Not very useful in python since scripts are often tested in Release build. */
115  /* Use `INT_MAX` instead of the actual number of vertices. */
116  GPU_indexbuf_init(&builder, prim_type.value_found, index_len, INT_MAX);
117 
118  if (verts_per_prim == 1) {
119  for (uint i = 0; i < seq_len; i++) {
120  GPU_indexbuf_add_generic_vert(&builder, PyC_Long_AsU32(seq_items[i]));
121  }
122  }
123  else {
124  int values[4];
125  for (uint i = 0; i < seq_len; i++) {
126  PyObject *seq_fast_item = PySequence_Fast(seq_items[i], error_prefix);
127  if (seq_fast_item == NULL) {
128  PyErr_Format(PyExc_TypeError,
129  "%s: expected a sequence, got %s",
130  error_prefix,
131  Py_TYPE(seq_items[i])->tp_name);
132  ok = false;
133  goto finally;
134  }
135 
136  ok = PyC_AsArray_FAST(values,
137  sizeof(*values),
138  seq_fast_item,
139  verts_per_prim,
140  &PyLong_Type,
141  error_prefix) == 0;
142 
143  if (ok) {
144  for (uint j = 0; j < verts_per_prim; j++) {
145  GPU_indexbuf_add_generic_vert(&builder, values[j]);
146  }
147  }
148  Py_DECREF(seq_fast_item);
149  }
150  }
151 
152  if (PyErr_Occurred()) {
153  ok = false;
154  }
155 
156  finally:
157 
158  Py_DECREF(seq_fast);
159  }
160 
161  if (ok == false) {
162  MEM_freeN(builder.data);
163  return NULL;
164  }
165 
167 }
168 
170 {
171  GPU_indexbuf_discard(self->elem);
172  Py_TYPE(self)->tp_free(self);
173 }
174 
175 PyDoc_STRVAR(pygpu_IndexBuf__tp_doc,
176  ".. class:: GPUIndexBuf(type, seq)\n"
177  "\n"
178  " Contains an index buffer.\n"
179  "\n"
180  " :arg type: The primitive type this index buffer is composed of.\n"
181  " Possible values are `POINTS`, `LINES`, `TRIS` and `LINE_STRIP_ADJ`.\n"
182  " :type type: str\n"
183  " :param seq: Indices this index buffer will contain.\n"
184  " Whether a 1D or 2D sequence is required depends on the type.\n"
185  " Optionally the sequence can support the buffer protocol.\n"
186  " :type seq: 1D or 2D sequence\n");
187 PyTypeObject BPyGPUIndexBuf_Type = {
188  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUIndexBuf",
189  .tp_basicsize = sizeof(BPyGPUIndexBuf),
190  .tp_dealloc = (destructor)pygpu_IndexBuf__tp_dealloc,
191  .tp_flags = Py_TPFLAGS_DEFAULT,
192  .tp_doc = pygpu_IndexBuf__tp_doc,
193  .tp_new = pygpu_IndexBuf__tp_new,
194 };
195 
198 /* -------------------------------------------------------------------- */
203 {
204  BPyGPUIndexBuf *self;
205 
206  self = PyObject_New(BPyGPUIndexBuf, &BPyGPUIndexBuf_Type);
207  self->elem = elem;
208 
209  return (PyObject *)self;
210 }
211 
unsigned int uint
Definition: BLI_sys_types.h:67
#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:33
Read Guarded memory(de)allocation.
PyObject * self
Definition: bpy_driver.c:165
struct PyC_StringEnumItems bpygpu_primtype_items[]
Definition: gpu_py.c:24
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
Definition: gpu_py.h:14
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:27
char PyC_StructFmt_type_from_str(const char *typestr)
int PyC_ParseStringEnum(PyObject *o, void *p)
uint32_t PyC_Long_AsU32(PyObject *value)
int PyC_AsArray_FAST(void *array, const size_t array_item_size, PyObject *value_fast, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
Definition: py_capi_utils.c:45
bool PyC_StructFmt_type_is_float_any(char format)