Blender  V3.3
gpu_py_matrix.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
15 #include <Python.h>
16 
17 #include "BLI_utildefines.h"
18 
19 #include "../mathutils/mathutils.h"
20 
21 #include "../generic/py_capi_utils.h"
22 
23 #define USE_GPU_PY_MATRIX_API
24 #include "GPU_matrix.h"
25 #undef USE_GPU_PY_MATRIX_API
26 
27 #include "gpu_py_matrix.h" /* own include */
28 
29 /* -------------------------------------------------------------------- */
34 {
35  if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) {
36  PyErr_SetString(
37  PyExc_RuntimeError,
38  "Maximum model-view stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
39  return false;
40  }
41  return true;
42 }
43 
45 {
46  if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) {
47  PyErr_SetString(
48  PyExc_RuntimeError,
49  "Maximum projection stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
50  return false;
51  }
52  return true;
53 }
54 
56 {
58  PyErr_SetString(PyExc_RuntimeError, "Minimum model-view stack depth reached");
59  return false;
60  }
61  return true;
62 }
63 
65 {
67  PyErr_SetString(PyExc_RuntimeError, "Minimum projection stack depth reached");
68  return false;
69  }
70  return true;
71 }
72 
75 /* -------------------------------------------------------------------- */
79 PyDoc_STRVAR(pygpu_matrix_push_doc,
80  ".. function:: push()\n"
81  "\n"
82  " Add to the model-view matrix stack.\n");
83 static PyObject *pygpu_matrix_push(PyObject *UNUSED(self))
84 {
86  return NULL;
87  }
89  Py_RETURN_NONE;
90 }
91 
92 PyDoc_STRVAR(pygpu_matrix_pop_doc,
93  ".. function:: pop()\n"
94  "\n"
95  " Remove the last model-view matrix from the stack.\n");
96 static PyObject *pygpu_matrix_pop(PyObject *UNUSED(self))
97 {
99  return NULL;
100  }
101  GPU_matrix_pop();
102  Py_RETURN_NONE;
103 }
104 
105 PyDoc_STRVAR(pygpu_matrix_push_projection_doc,
106  ".. function:: push_projection()\n"
107  "\n"
108  " Add to the projection matrix stack.\n");
109 static PyObject *pygpu_matrix_push_projection(PyObject *UNUSED(self))
110 {
112  return NULL;
113  }
115  Py_RETURN_NONE;
116 }
117 
118 PyDoc_STRVAR(pygpu_matrix_pop_projection_doc,
119  ".. function:: pop_projection()\n"
120  "\n"
121  " Remove the last projection matrix from the stack.\n");
122 static PyObject *pygpu_matrix_pop_projection(PyObject *UNUSED(self))
123 {
125  return NULL;
126  }
128  Py_RETURN_NONE;
129 }
130 
133 /* -------------------------------------------------------------------- */
140 typedef struct {
141  PyObject_HEAD /* Required Python macro. */
142  int type;
143  int level;
145 
146 enum {
149 };
150 
152 static PyObject *pygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args);
153 
155  {"__enter__", (PyCFunction)pygpu_matrix_stack_context_enter, METH_NOARGS},
156  {"__exit__", (PyCFunction)pygpu_matrix_stack_context_exit, METH_VARARGS},
157  {NULL},
158 };
159 
160 static PyTypeObject PyGPUMatrixStackContext_Type = {
161  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUMatrixStackContext",
162  .tp_basicsize = sizeof(BPyGPU_MatrixStackContext),
163  .tp_flags = Py_TPFLAGS_DEFAULT,
165 };
166 
168 {
169  /* sanity - should never happen */
170  if (self->level != -1) {
171  PyErr_SetString(PyExc_RuntimeError, "Already in use");
172  return NULL;
173  }
174 
175  if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
177  return NULL;
178  }
179  GPU_matrix_push();
181  }
182  else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
184  return NULL;
185  }
188  }
189  else {
191  }
192  Py_RETURN_NONE;
193 }
194 
196  PyObject *UNUSED(args))
197 {
198  /* sanity - should never happen */
199  if (self->level == -1) {
200  fprintf(stderr, "Not yet in use\n");
201  goto finally;
202  }
203 
204  if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
205  const int level = GPU_matrix_stack_level_get_model_view();
206  if (level != self->level) {
207  fprintf(stderr, "Level push/pop mismatch, expected %d, got %d\n", self->level, level);
208  }
209  if (level != 0) {
210  GPU_matrix_pop();
211  }
212  }
213  else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
214  const int level = GPU_matrix_stack_level_get_projection();
215  if (level != self->level) {
216  fprintf(stderr, "Level push/pop mismatch, expected %d, got %d", self->level, level);
217  }
218  if (level != 0) {
220  }
221  }
222  else {
224  }
225 finally:
226  Py_RETURN_NONE;
227 }
228 
229 static PyObject *pygpu_matrix_push_pop_impl(int type)
230 {
233  ret->type = type;
234  ret->level = -1;
235  return (PyObject *)ret;
236 }
237 
239  pygpu_matrix_push_pop_doc,
240  ".. function:: push_pop()\n"
241  "\n"
242  " Context manager to ensure balanced push/pop calls, even in the case of an error.\n");
243 static PyObject *pygpu_matrix_push_pop(PyObject *UNUSED(self))
244 {
246 }
247 
249  pygpu_matrix_push_pop_projection_doc,
250  ".. function:: push_pop_projection()\n"
251  "\n"
252  " Context manager to ensure balanced push/pop calls, even in the case of an error.\n");
253 static PyObject *pygpu_matrix_push_pop_projection(PyObject *UNUSED(self))
254 {
256 }
257 
260 /* -------------------------------------------------------------------- */
264 PyDoc_STRVAR(pygpu_matrix_multiply_matrix_doc,
265  ".. function:: multiply_matrix(matrix)\n"
266  "\n"
267  " Multiply the current stack matrix.\n"
268  "\n"
269  " :param matrix: A 4x4 matrix.\n"
270  " :type matrix: :class:`mathutils.Matrix`\n");
271 static PyObject *pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value)
272 {
273  MatrixObject *pymat;
274  if (!Matrix_Parse4x4(value, &pymat)) {
275  return NULL;
276  }
277  GPU_matrix_mul(pymat->matrix);
278  Py_RETURN_NONE;
279 }
280 
281 PyDoc_STRVAR(pygpu_matrix_scale_doc,
282  ".. function:: scale(scale)\n"
283  "\n"
284  " Scale the current stack matrix.\n"
285  "\n"
286  " :param scale: Scale the current stack matrix.\n"
287  " :type scale: sequence of 2 or 3 floats\n");
288 static PyObject *pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value)
289 {
290  float scale[3];
291  int len;
292  if ((len = mathutils_array_parse(
293  scale, 2, 3, value, "gpu.matrix.scale(): invalid vector arg")) == -1) {
294  return NULL;
295  }
296  if (len == 2) {
297  GPU_matrix_scale_2fv(scale);
298  }
299  else {
300  GPU_matrix_scale_3fv(scale);
301  }
302  Py_RETURN_NONE;
303 }
304 
305 PyDoc_STRVAR(pygpu_matrix_scale_uniform_doc,
306  ".. function:: scale_uniform(scale)\n"
307  "\n"
308  " :param scale: Scale the current stack matrix.\n"
309  " :type scale: float\n");
310 static PyObject *pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value)
311 {
312  float scalar;
313  if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
314  PyErr_Format(PyExc_TypeError, "expected a number, not %.200s", Py_TYPE(value)->tp_name);
315  return NULL;
316  }
317  GPU_matrix_scale_1f(scalar);
318  Py_RETURN_NONE;
319 }
320 
321 PyDoc_STRVAR(pygpu_matrix_translate_doc,
322  ".. function:: translate(offset)\n"
323  "\n"
324  " Scale the current stack matrix.\n"
325  "\n"
326  " :param offset: Translate the current stack matrix.\n"
327  " :type offset: sequence of 2 or 3 floats\n");
328 static PyObject *pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value)
329 {
330  float offset[3];
331  int len;
332  if ((len = mathutils_array_parse(
333  offset, 2, 3, value, "gpu.matrix.translate(): invalid vector arg")) == -1) {
334  return NULL;
335  }
336  if (len == 2) {
338  }
339  else {
341  }
342  Py_RETURN_NONE;
343 }
344 
347 /* -------------------------------------------------------------------- */
351 PyDoc_STRVAR(pygpu_matrix_reset_doc,
352  ".. function:: reset()\n"
353  "\n"
354  " Empty stack and set to identity.\n");
355 static PyObject *pygpu_matrix_reset(PyObject *UNUSED(self))
356 {
358  Py_RETURN_NONE;
359 }
360 
361 PyDoc_STRVAR(pygpu_matrix_load_identity_doc,
362  ".. function:: load_identity()\n"
363  "\n"
364  " Empty stack and set to identity.\n");
365 static PyObject *pygpu_matrix_load_identity(PyObject *UNUSED(self))
366 {
368  Py_RETURN_NONE;
369 }
370 
371 PyDoc_STRVAR(pygpu_matrix_load_matrix_doc,
372  ".. function:: load_matrix(matrix)\n"
373  "\n"
374  " Load a matrix into the stack.\n"
375  "\n"
376  " :param matrix: A 4x4 matrix.\n"
377  " :type matrix: :class:`mathutils.Matrix`\n");
378 static PyObject *pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value)
379 {
380  MatrixObject *pymat;
381  if (!Matrix_Parse4x4(value, &pymat)) {
382  return NULL;
383  }
384  GPU_matrix_set(pymat->matrix);
385  Py_RETURN_NONE;
386 }
387 
388 PyDoc_STRVAR(pygpu_matrix_load_projection_matrix_doc,
389  ".. function:: load_projection_matrix(matrix)\n"
390  "\n"
391  " Load a projection matrix into the stack.\n"
392  "\n"
393  " :param matrix: A 4x4 matrix.\n"
394  " :type matrix: :class:`mathutils.Matrix`\n");
395 static PyObject *pygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value)
396 {
397  MatrixObject *pymat;
398  if (!Matrix_Parse4x4(value, &pymat)) {
399  return NULL;
400  }
401  GPU_matrix_projection_set(pymat->matrix);
402  Py_RETURN_NONE;
403 }
404 
407 /* -------------------------------------------------------------------- */
411 PyDoc_STRVAR(pygpu_matrix_get_projection_matrix_doc,
412  ".. function:: get_projection_matrix()\n"
413  "\n"
414  " Return a copy of the projection matrix.\n"
415  "\n"
416  " :return: A 4x4 projection matrix.\n"
417  " :rtype: :class:`mathutils.Matrix`\n");
418 static PyObject *pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self))
419 {
420  float matrix[4][4];
422  return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL);
423 }
424 
425 PyDoc_STRVAR(pygpu_matrix_get_model_view_matrix_doc,
426  ".. function:: get_model_view_matrix()\n"
427  "\n"
428  " Return a copy of the model-view matrix.\n"
429  "\n"
430  " :return: A 4x4 view matrix.\n"
431  " :rtype: :class:`mathutils.Matrix`\n");
432 static PyObject *pygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self))
433 {
434  float matrix[4][4];
436  return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL);
437 }
438 
439 PyDoc_STRVAR(pygpu_matrix_get_normal_matrix_doc,
440  ".. function:: get_normal_matrix()\n"
441  "\n"
442  " Return a copy of the normal matrix.\n"
443  "\n"
444  " :return: A 3x3 normal matrix.\n"
445  " :rtype: :class:`mathutils.Matrix`\n");
446 static PyObject *pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self))
447 {
448  float matrix[3][3];
449  GPU_matrix_normal_get(matrix);
450  return Matrix_CreatePyObject(&matrix[0][0], 3, 3, NULL);
451 }
452 
455 /* -------------------------------------------------------------------- */
459 static struct PyMethodDef pygpu_matrix__tp_methods[] = {
460  /* Manage Stack */
461  {"push", (PyCFunction)pygpu_matrix_push, METH_NOARGS, pygpu_matrix_push_doc},
462  {"pop", (PyCFunction)pygpu_matrix_pop, METH_NOARGS, pygpu_matrix_pop_doc},
463 
464  {"push_projection",
465  (PyCFunction)pygpu_matrix_push_projection,
466  METH_NOARGS,
467  pygpu_matrix_push_projection_doc},
468  {"pop_projection",
469  (PyCFunction)pygpu_matrix_pop_projection,
470  METH_NOARGS,
471  pygpu_matrix_pop_projection_doc},
472 
473  /* Stack (Context Manager) */
474  {"push_pop", (PyCFunction)pygpu_matrix_push_pop, METH_NOARGS, pygpu_matrix_push_pop_doc},
475  {"push_pop_projection",
477  METH_NOARGS,
478  pygpu_matrix_push_pop_projection_doc},
479 
480  /* Manipulate State */
481  {"multiply_matrix",
482  (PyCFunction)pygpu_matrix_multiply_matrix,
483  METH_O,
484  pygpu_matrix_multiply_matrix_doc},
485  {"scale", (PyCFunction)pygpu_matrix_scale, METH_O, pygpu_matrix_scale_doc},
486  {"scale_uniform",
487  (PyCFunction)pygpu_matrix_scale_uniform,
488  METH_O,
489  pygpu_matrix_scale_uniform_doc},
490  {"translate", (PyCFunction)pygpu_matrix_translate, METH_O, pygpu_matrix_translate_doc},
491 
492 /* TODO */
493 #if 0
494  {"rotate", (PyCFunction)pygpu_matrix_rotate, METH_O, pygpu_matrix_rotate_doc},
495  {"rotate_axis", (PyCFunction)pygpu_matrix_rotate_axis, METH_O, pygpu_matrix_rotate_axis_doc},
496  {"look_at", (PyCFunction)pygpu_matrix_look_at, METH_O, pygpu_matrix_look_at_doc},
497 #endif
498 
499  /* Write State */
500  {"reset", (PyCFunction)pygpu_matrix_reset, METH_NOARGS, pygpu_matrix_reset_doc},
501  {"load_identity",
502  (PyCFunction)pygpu_matrix_load_identity,
503  METH_NOARGS,
504  pygpu_matrix_load_identity_doc},
505  {"load_matrix", (PyCFunction)pygpu_matrix_load_matrix, METH_O, pygpu_matrix_load_matrix_doc},
506  {"load_projection_matrix",
508  METH_O,
509  pygpu_matrix_load_projection_matrix_doc},
510 
511  /* Read State */
512  {"get_projection_matrix",
514  METH_NOARGS,
515  pygpu_matrix_get_projection_matrix_doc},
516  {"get_model_view_matrix",
518  METH_NOARGS,
519  pygpu_matrix_get_model_view_matrix_doc},
520  {"get_normal_matrix",
521  (PyCFunction)pygpu_matrix_get_normal_matrix,
522  METH_NOARGS,
523  pygpu_matrix_get_normal_matrix_doc},
524 
525  {NULL, NULL, 0, NULL},
526 };
527 
528 PyDoc_STRVAR(pygpu_matrix__tp_doc, "This module provides access to the matrix stack.");
529 static PyModuleDef pygpu_matrix_module_def = {
530  PyModuleDef_HEAD_INIT,
531  .m_name = "gpu.matrix",
532  .m_doc = pygpu_matrix__tp_doc,
533  .m_methods = pygpu_matrix__tp_methods,
534 };
535 
536 PyObject *bpygpu_matrix_init(void)
537 {
538  PyObject *submodule;
539 
540  submodule = PyModule_Create(&pygpu_matrix_module_def);
541 
542  if (PyType_Ready(&PyGPUMatrixStackContext_Type) < 0) {
543  return NULL;
544  }
545 
546  return submodule;
547 }
548 
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define STRINGIFY(x)
#define UNUSED(x)
_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
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:126
#define GPU_matrix_normal_get(x)
Definition: GPU_matrix.h:231
void GPU_matrix_translate_2fv(const float vec[2])
Definition: gpu_matrix.cc:183
#define GPU_matrix_model_view_get(x)
Definition: GPU_matrix.h:227
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:140
void GPU_matrix_scale_2fv(const float vec[2])
Definition: gpu_matrix.cc:226
#define GPU_matrix_set(x)
Definition: GPU_matrix.h:225
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:224
void GPU_matrix_scale_3fv(const float vec[3])
Definition: gpu_matrix.cc:241
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:119
void GPU_matrix_scale_1f(float factor)
Definition: gpu_matrix.cc:209
#define GPU_matrix_projection_get(x)
Definition: GPU_matrix.h:228
void GPU_matrix_reset(void)
Definition: gpu_matrix.cc:86
#define GPU_matrix_projection_set(x)
Definition: GPU_matrix.h:226
void GPU_matrix_translate_3fv(const float vec[3])
Definition: gpu_matrix.cc:204
void GPU_matrix_identity_set(void)
Definition: gpu_matrix.cc:168
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:133
PyObject * self
Definition: bpy_driver.c:165
int len
Definition: draw_manager.c:108
int GPU_matrix_stack_level_get_projection()
Definition: gpu_matrix.cc:675
int GPU_matrix_stack_level_get_model_view()
Definition: gpu_matrix.cc:669
static PyObject * pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value)
static PyObject * pygpu_matrix_pop(PyObject *UNUSED(self))
Definition: gpu_py_matrix.c:96
static bool pygpu_stack_is_pop_model_view_ok_or_error(void)
Definition: gpu_py_matrix.c:55
static PyObject * pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self))
static PyObject * pygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self))
PyDoc_STRVAR(pygpu_matrix_push_doc, ".. function:: push()\n" "\n" " Add to the model-view matrix stack.\n")
static PyObject * pygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args)
static bool pygpu_stack_is_push_projection_ok_or_error(void)
Definition: gpu_py_matrix.c:44
static PyObject * pygpu_matrix_push_projection(PyObject *UNUSED(self))
static PyObject * pygpu_matrix_push_pop_impl(int type)
static bool pygpu_stack_is_pop_projection_ok_or_error(void)
Definition: gpu_py_matrix.c:64
static PyObject * pygpu_matrix_load_identity(PyObject *UNUSED(self))
static PyMethodDef pygpu_matrix_stack_context__tp_methods[]
static PyObject * pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value)
static PyObject * pygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value)
static PyObject * pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value)
static bool pygpu_stack_is_push_model_view_ok_or_error(void)
Definition: gpu_py_matrix.c:33
static PyObject * pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value)
static struct PyMethodDef pygpu_matrix__tp_methods[]
static PyObject * pygpu_matrix_push_pop(PyObject *UNUSED(self))
PyObject * bpygpu_matrix_init(void)
static PyModuleDef pygpu_matrix_module_def
static PyObject * pygpu_matrix_push_pop_projection(PyObject *UNUSED(self))
@ PYGPU_MATRIX_TYPE_MODEL_VIEW
@ PYGPU_MATRIX_TYPE_PROJECTION
static PyTypeObject PyGPUMatrixStackContext_Type
static PyObject * pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self))
static PyObject * pygpu_matrix_pop_projection(PyObject *UNUSED(self))
static PyObject * pygpu_matrix_push(PyObject *UNUSED(self))
Definition: gpu_py_matrix.c:83
static PyObject * pygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self)
static PyObject * pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value)
static PyObject * pygpu_matrix_reset(PyObject *UNUSED(self))
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:98
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
int Matrix_Parse4x4(PyObject *o, void *p)
return ret
PyObject_HEAD int type