38 if (!
self->batch->shader) {
39 PyErr_SetString(PyExc_RuntimeError,
"batch does not have any program assigned to it");
55 const char *exc_str_missing_arg =
"GPUBatch.__new__() missing required argument '%s' (pos %d)";
61 static const char *_keywords[] = {
"type",
"buf",
"elem",
nullptr};
62 static _PyArg_Parser _parser = {
72 if (!_PyArg_ParseTupleAndKeywordsFast(args,
87 PyErr_WarnEx(PyExc_DeprecationWarning,
88 "'LINE_LOOP' is deprecated. Please use 'LINE_STRIP' and close the segment.",
93 PyExc_DeprecationWarning,
94 "'TRI_FAN' is deprecated. Please use 'TRI_STRIP' or 'TRIS' and try modifying your "
95 "vertices or indices to match the topology.",
99 if (py_vertbuf ==
nullptr) {
100 PyErr_Format(PyExc_TypeError, exc_str_missing_arg, _keywords[1], 2);
106 py_indexbuf ? py_indexbuf->
elem :
nullptr);
110#ifdef USE_GPU_PY_REFERENCES
111 ret->references = PyList_New(py_indexbuf ? 2 : 1);
112 PyList_SET_ITEM(
ret->references, 0, (PyObject *)py_vertbuf);
113 Py_INCREF(py_vertbuf);
115 if (py_indexbuf !=
nullptr) {
116 PyList_SET_ITEM(
ret->references, 1, (PyObject *)py_indexbuf);
117 Py_INCREF(py_indexbuf);
121 PyObject_GC_Track(
ret);
124 return (PyObject *)
ret;
129 pygpu_batch_vertbuf_add_doc,
".. method:: vertbuf_add(buf)\n"
131" Add another vertex buffer to the Batch.\n"
132" It is not possible to add more vertices to the batch using this method.\n"
133" Instead it can be used to add more attributes to the existing vertices.\n"
134" A good use case would be when you have a separate\n"
135" vertex buffer for vertex positions and vertex normals.\n"
138" :arg buf: The vertex buffer that will be added to the batch.\n"
139" :type buf: :class:`gpu.types.GPUVertBuf`\n"
144 PyErr_Format(PyExc_TypeError,
"Expected a GPUVertBuf, got %s", Py_TYPE(py_buf)->tp_name);
150 PyErr_Format(PyExc_TypeError,
151 "Expected %d length, got %d",
164#ifdef USE_GPU_PY_REFERENCES
166 PyList_Append(
self->references, (PyObject *)py_buf);
175 pygpu_batch_program_set_doc,
176 ".. method:: program_set(program)\n"
178 " Assign a shader to this batch that will be used for drawing when not overwritten later.\n"
179 " Note: This method has to be called in the draw context that the batch will be drawn in.\n"
180 " This function does not need to be called when you always\n"
181 " set the shader when calling :meth:`gpu.types.GPUBatch.draw`.\n"
183 " :arg program: The program/shader the batch will use in future draw calls.\n"
184 " :type program: :class:`gpu.types.GPUShader`\n");
187 static bool deprecation_warning_issued =
false;
190 if (!deprecation_warning_issued) {
191 PyErr_WarnEx(PyExc_DeprecationWarning,
192 "Calls to GPUBatch.program_set are deprecated."
193 "Please set the shader via the 'program' parameter when calling "
194 "GPUBatch.draw/draw_instanced/draw_range.",
196 deprecation_warning_issued =
true;
200 PyErr_Format(PyExc_TypeError,
"Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name);
207#ifdef USE_GPU_PY_REFERENCES
209 int i = PyList_GET_SIZE(
self->references);
211 PyObject *py_shader_test = PyList_GET_ITEM(
self->references,
i);
213 PyList_SET_ITEM(
self->references,
i, (PyObject *)py_shader);
214 Py_INCREF(py_shader);
221 PyList_Append(
self->references, (PyObject *)py_shader);
234 if (!
batch->shader) {
249 if ((
format.stride % 4) != 0) {
250 return "For POLYLINE shaders, only 4-byte aligned formats are supported";
253 int pos_attr_id = -1;
254 int col_attr_id = -1;
255 for (
uint a_idx = 0; a_idx <
format.attr_len; a_idx++) {
257 if ((a->
offset % 4) != 0) {
258 return "For POLYLINE shaders, only 4-byte aligned attributes are supported";
261 if (pos_attr_id == -1 &&
name ==
"pos") {
263 return "For POLYLINE shaders, the 'pos' attribute needs to be 'F32'";
266 return "For POLYLINE shaders, the 'pos' attribute must use the 'FLOAT' fetch type";
270 else if (col_attr_id == -1 &&
name ==
"color") {
272 return "For POLYLINE shaders, the 'color' attribute needs to be 'F32' or 'U8'";
276 if (pos_attr_id != -1 && col_attr_id != -1) {
286 pygpu_batch_draw_doc,
287 ".. method:: draw(shader=None)\n"
289 " Run the drawing shader with the parameters assigned to the batch.\n"
291 " :arg shader: Shader that performs the drawing operations.\n"
292 " If ``None`` is passed, the last shader set to this batch will run.\n"
293 " :type program: :class:`gpu.types.GPUShader`\n");
296 static bool deprecation_warning_issued =
false;
300 if (!PyArg_ParseTuple(args,
"|O!:GPUBatch.draw", &
BPyGPUShader_Type, &py_shader)) {
303 if (py_shader ==
nullptr) {
304 if (!deprecation_warning_issued) {
307 PyErr_WarnEx(PyExc_DeprecationWarning,
308 "Calling GPUBatch.draw without specifying a shader is deprecated. "
309 "Please provide a valid GPUShader as the 'shader' parameter.",
311 deprecation_warning_issued =
true;
318 else if (
self->batch->shader != py_shader->
shader) {
330 if (line_width > 1.0f || use_linesmooth) {
332 PyErr_WarnEx(PyExc_DeprecationWarning,
333 "Calling GPUBatch.draw to draw wide or smooth lines with "
334 "GPU_SHADER_3D_FLAT_COLOR is deprecated. "
335 "Use GPU_SHADER_3D_POLYLINE_FLAT_COLOR instead.",
339 PyErr_WarnEx(PyExc_DeprecationWarning,
340 "Calling GPUBatch.draw to draw wide or smooth lines with "
341 "GPU_SHADER_3D_SMOOTH_COLOR is deprecated. "
342 "Use GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR instead.",
346 PyErr_WarnEx(PyExc_DeprecationWarning,
347 "Calling GPUBatch.draw to draw wide or smooth lines with "
348 "GPU_SHADER_3D_UNIFORM_COLOR is deprecated. "
349 "Use GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR instead.",
360 PyErr_WarnEx(PyExc_DeprecationWarning,
361 "Calling GPUBatch.draw to draw points with "
362 "GPU_SHADER_3D_FLAT_COLOR is deprecated. "
363 "Use GPU_SHADER_3D_POINT_FLAT_COLOR instead.",
367 PyErr_WarnEx(PyExc_DeprecationWarning,
368 "Calling GPUBatch.draw to draw points with "
369 "GPU_SHADER_3D_SMOOTH_COLOR is deprecated. "
370 "Use GPU_SHADER_3D_POINT_FLAT_COLOR instead.",
374 PyErr_WarnEx(PyExc_DeprecationWarning,
375 "Calling GPUBatch.draw to draw points with "
376 "GPU_SHADER_3D_UNIFORM_COLOR is deprecated. "
377 "Use GPU_SHADER_3D_POINT_SMOOTH_COLOR instead.",
383 PyErr_SetString(PyExc_RuntimeError,
error);
393 pygpu_batch_draw_instanced_doc,
394 ".. method:: draw_instanced(program, *, instance_start=0, instance_count=0)\n"
396 " Draw multiple instances of the drawing program with the parameters assigned\n"
397 " to the batch. In the vertex shader, ``gl_InstanceID`` will contain the instance\n"
398 " number being drawn.\n"
400 " :arg program: Program that performs the drawing operations.\n"
401 " :type program: :class:`gpu.types.GPUShader`\n"
402 " :arg instance_start: Number of the first instance to draw.\n"
403 " :type instance_start: int\n"
404 " :arg instance_count: Number of instances to draw. When not provided or set to 0\n"
405 " the number of instances will be determined by the number of rows in the first\n"
407 " :type instance_count: int\n");
411 int instance_start = 0;
412 int instance_count = 0;
414 static const char *_keywords[] = {
"program",
"instance_start",
"instance_count",
nullptr};
415 static _PyArg_Parser _parser = {
421 ":GPUBatch.draw_instanced",
425 if (!_PyArg_ParseTupleAndKeywordsFast(
426 args, kw, &_parser, &
BPyGPUShader_Type, &py_program, &instance_start, &instance_count))
438 pygpu_batch_draw_range_doc,
439 ".. method:: draw_range(program, *, elem_start=0, elem_count=0)\n"
441 " Run the drawing program with the parameters assigned to the batch. "
442 "Only draw the ``elem_count`` elements of the index buffer starting at ``elem_start``.\n"
444 " :arg program: Program that performs the drawing operations.\n"
445 " :type program: :class:`gpu.types.GPUShader`\n"
446 " :arg elem_start: First index to draw. When not provided or set to 0 drawing\n"
447 " will start from the first element of the index buffer.\n"
448 " :type elem_start: int\n"
449 " :arg elem_count: Number of elements of the index buffer to draw. When not\n"
450 " provided or set to 0 all elements from ``elem_start`` to the end of the\n"
451 " index buffer will be drawn.\n"
452 " :type elem_count: int\n");
459 static const char *_keywords[] = {
"program",
"elem_start",
"elem_count",
nullptr};
460 static _PyArg_Parser _parser = {
466 ":GPUBatch.draw_range",
470 if (!_PyArg_ParseTupleAndKeywordsFast(
501# pragma clang diagnostic push
502# pragma clang diagnostic ignored "-Wcast-function-type"
504# pragma GCC diagnostic push
505# pragma GCC diagnostic ignored "-Wcast-function-type"
512 {
"draw", (PyCFunction)
pygpu_batch_draw, METH_VARARGS, pygpu_batch_draw_doc},
515 METH_VARARGS | METH_KEYWORDS,
516 pygpu_batch_draw_instanced_doc},
519 METH_VARARGS | METH_KEYWORDS,
520 pygpu_batch_draw_range_doc},
523 {
nullptr,
nullptr, 0,
nullptr},
528# pragma clang diagnostic pop
530# pragma GCC diagnostic pop
534#ifdef USE_GPU_PY_REFERENCES
538 Py_VISIT(
self->references);
544 Py_CLEAR(
self->references);
550 return self->references !=
nullptr;
559#ifdef USE_GPU_PY_REFERENCES
560 PyObject_GC_UnTrack(
self);
561 if (
self->references) {
563 Py_XDECREF(
self->references);
573 ".. class:: GPUBatch(type, buf, elem=None)\n"
575 " Reusable container for drawable geometry.\n"
577 " :arg type: The primitive type of geometry to be drawn.\n"
578 " Possible values are ``POINTS``, ``LINES``, ``TRIS``, ``LINE_STRIP``, ``LINE_LOOP``, "
579 "``TRI_STRIP``, ``TRI_FAN``, ``LINES_ADJ``, ``TRIS_ADJ`` and ``LINE_STRIP_ADJ``.\n"
581 " :arg buf: Vertex buffer containing all or some of the attributes required for drawing.\n"
582 " :type buf: :class:`gpu.types.GPUVertBuf`\n"
583 " :arg elem: An optional index buffer.\n"
584 " :type elem: :class:`gpu.types.GPUIndexBuf`\n");
586 PyVarObject_HEAD_INIT(
nullptr, 0)
605#ifdef USE_GPU_PY_REFERENCES
606 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
611#ifdef USE_GPU_PY_REFERENCES
637#ifdef USE_GPU_PY_REFERENCES
663#ifdef USE_GPU_PY_REFERENCES
665 self->references =
nullptr;
672 return (PyObject *)
self;
677#undef BPY_GPU_BATCH_CHECK_OBJ
static constexpr int GPU_BATCH_VBO_MAX_LEN
void GPU_batch_discard(blender::gpu::Batch *batch)
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
void GPU_batch_draw_instance_range(blender::gpu::Batch *batch, int instance_first, int instance_count)
int GPU_batch_vertbuf_add(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
void GPU_batch_draw(blender::gpu::Batch *batch)
void GPU_batch_draw_range(blender::gpu::Batch *batch, int vertex_first, int vertex_count)
void GPU_batch_set_shader(blender::gpu::Batch *batch, blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
blender::gpu::Shader * GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
@ GPU_SHADER_3D_SMOOTH_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_FLAT_COLOR
bool GPU_line_smooth_get()
float GPU_line_width_get()
uint GPU_vertbuf_get_vertex_len(const blender::gpu::VertBuf *verts)
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
PyC_StringEnumItems bpygpu_primtype_items[]
#define BPYGPU_IS_INIT_OR_ERROR_OBJ
static PyObject * pygpu_batch_draw(BPyGPUBatch *self, PyObject *args)
static int pygpu_batch__tp_clear(BPyGPUBatch *self)
PyObject * BPyGPUBatch_CreatePyObject(blender::gpu::Batch *batch)
static PyObject * pygpu_batch_program_use_begin(BPyGPUBatch *self)
static int pygpu_batch__tp_traverse(BPyGPUBatch *self, visitproc visit, void *arg)
static PyObject * pygpu_batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader)
static PyObject * pygpu_batch__tp_new(PyTypeObject *, PyObject *args, PyObject *kwds)
static PyObject * pygpu_batch_program_use_end(BPyGPUBatch *self)
static void pygpu_batch__tp_dealloc(BPyGPUBatch *self)
static bool pygpu_batch_is_program_or_error(BPyGPUBatch *self)
static PyObject * pygpu_batch_draw_instanced(BPyGPUBatch *self, PyObject *args, PyObject *kw)
static PyMethodDef pygpu_batch__tp_methods[]
static PyObject * pygpu_batch_draw_range(BPyGPUBatch *self, PyObject *args, PyObject *kw)
static int pygpu_batch__tp_is_gc(BPyGPUBatch *self)
static const char * pygpu_shader_check_compatibility(blender::gpu::Batch *batch)
PyTypeObject BPyGPUBatch_Type
PyDoc_STRVAR(pygpu_batch_vertbuf_add_doc, ".. method:: vertbuf_add(buf)\n" "\n" " Add another vertex buffer to the Batch.\n" " It is not possible to add more vertices to the batch using this method.\n" " Instead it can be used to add more attributes to the existing vertices.\n" " A good use case would be when you have a separate\n" " vertex buffer for vertex positions and vertex normals.\n" " Current a batch can have at most " STRINGIFY(GPU_BATCH_VBO_MAX_LEN) " vertex buffers.\n" "\n" " :arg buf: The vertex buffer that will be added to the batch.\n" " :type buf: :class:`gpu.types.GPUVertBuf`\n")
static PyObject * pygpu_batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf)
#define USE_GPU_PY_REFERENCES
PyTypeObject BPyGPUIndexBuf_Type
bool bpygpu_shader_is_polyline(blender::gpu::Shader *shader)
PyTypeObject BPyGPUShader_Type
#define BPyGPUShader_Check(v)
PyTypeObject BPyGPUVertBuf_Type
#define BPyGPUVertBuf_Check(v)
static void error(const char *str)
int PyC_ParseStringEnum(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
PyObject_VAR_HEAD blender::gpu::IndexBuf * elem
PyObject_VAR_HEAD blender::gpu::Shader * shader
PyObject_VAR_HEAD blender::gpu::VertBuf * buf
GPUVertFetchMode fetch_mode() const
GPUVertCompType comp_type() const
struct GPUVertAttr::Type type