Blender  V2.93
gpu_py_matrix.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 
29 #include <Python.h>
30 
31 #include "BLI_utildefines.h"
32 
33 #include "../mathutils/mathutils.h"
34 
35 #include "../generic/py_capi_utils.h"
36 
37 #define USE_GPU_PY_MATRIX_API
38 #include "GPU_matrix.h"
39 #undef USE_GPU_PY_MATRIX_API
40 
41 #include "gpu_py_matrix.h" /* own include */
42 
43 /* -------------------------------------------------------------------- */
48 {
49  if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) {
50  PyErr_SetString(
51  PyExc_RuntimeError,
52  "Maximum model-view stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
53  return false;
54  }
55  return true;
56 }
57 
59 {
60  if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) {
61  PyErr_SetString(
62  PyExc_RuntimeError,
63  "Maximum projection stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached");
64  return false;
65  }
66  return true;
67 }
68 
70 {
72  PyErr_SetString(PyExc_RuntimeError, "Minimum model-view stack depth reached");
73  return false;
74  }
75  return true;
76 }
77 
79 {
81  PyErr_SetString(PyExc_RuntimeError, "Minimum projection stack depth reached");
82  return false;
83  }
84  return true;
85 }
86 
89 /* -------------------------------------------------------------------- */
93 PyDoc_STRVAR(pygpu_matrix_push_doc,
94  ".. function:: push()\n"
95  "\n"
96  " Add to the model-view matrix stack.\n");
97 static PyObject *pygpu_matrix_push(PyObject *UNUSED(self))
98 {
100  return NULL;
101  }
102  GPU_matrix_push();
103  Py_RETURN_NONE;
104 }
105 
106 PyDoc_STRVAR(pygpu_matrix_pop_doc,
107  ".. function:: pop()\n"
108  "\n"
109  " Remove the last model-view matrix from the stack.\n");
110 static PyObject *pygpu_matrix_pop(PyObject *UNUSED(self))
111 {
113  return NULL;
114  }
115  GPU_matrix_pop();
116  Py_RETURN_NONE;
117 }
118 
119 PyDoc_STRVAR(pygpu_matrix_push_projection_doc,
120  ".. function:: push_projection()\n"
121  "\n"
122  " Add to the projection matrix stack.\n");
123 static PyObject *pygpu_matrix_push_projection(PyObject *UNUSED(self))
124 {
126  return NULL;
127  }
129  Py_RETURN_NONE;
130 }
131 
132 PyDoc_STRVAR(pygpu_matrix_pop_projection_doc,
133  ".. function:: pop_projection()\n"
134  "\n"
135  " Remove the last projection matrix from the stack.\n");
136 static PyObject *pygpu_matrix_pop_projection(PyObject *UNUSED(self))
137 {
139  return NULL;
140  }
142  Py_RETURN_NONE;
143 }
144 
147 /* -------------------------------------------------------------------- */
154 typedef struct {
155  PyObject_HEAD /* required python macro */
156  int type;
157  int level;
159 
160 enum {
163 };
164 
166 static PyObject *pygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args);
167 
169  {"__enter__", (PyCFunction)pygpu_matrix_stack_context_enter, METH_NOARGS},
170  {"__exit__", (PyCFunction)pygpu_matrix_stack_context_exit, METH_VARARGS},
171  {NULL},
172 };
173 
174 static PyTypeObject PyGPUMatrixStackContext_Type = {
175  PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUMatrixStackContext",
176  .tp_basicsize = sizeof(BPyGPU_MatrixStackContext),
177  .tp_flags = Py_TPFLAGS_DEFAULT,
179 };
180 
182 {
183  /* sanity - should never happen */
184  if (self->level != -1) {
185  PyErr_SetString(PyExc_RuntimeError, "Already in use");
186  return NULL;
187  }
188 
189  if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
191  return NULL;
192  }
193  GPU_matrix_push();
195  }
196  else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
198  return NULL;
199  }
202  }
203  else {
205  }
206  Py_RETURN_NONE;
207 }
208 
210  PyObject *UNUSED(args))
211 {
212  /* sanity - should never happen */
213  if (self->level == -1) {
214  fprintf(stderr, "Not yet in use\n");
215  goto finally;
216  }
217 
218  if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) {
219  const int level = GPU_matrix_stack_level_get_model_view();
220  if (level != self->level) {
221  fprintf(stderr, "Level push/pop mismatch, expected %d, got %d\n", self->level, level);
222  }
223  if (level != 0) {
224  GPU_matrix_pop();
225  }
226  }
227  else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) {
228  const int level = GPU_matrix_stack_level_get_projection();
229  if (level != self->level) {
230  fprintf(stderr, "Level push/pop mismatch, expected %d, got %d", self->level, level);
231  }
232  if (level != 0) {
234  }
235  }
236  else {
238  }
239 finally:
240  Py_RETURN_NONE;
241 }
242 
243 static PyObject *pygpu_matrix_push_pop_impl(int type)
244 {
247  ret->type = type;
248  ret->level = -1;
249  return (PyObject *)ret;
250 }
251 
253  pygpu_matrix_push_pop_doc,
254  ".. function:: push_pop()\n"
255  "\n"
256  " Context manager to ensure balanced push/pop calls, even in the case of an error.\n");
257 static PyObject *pygpu_matrix_push_pop(PyObject *UNUSED(self))
258 {
260 }
261 
263  pygpu_matrix_push_pop_projection_doc,
264  ".. function:: push_pop_projection()\n"
265  "\n"
266  " Context manager to ensure balanced push/pop calls, even in the case of an error.\n");
267 static PyObject *pygpu_matrix_push_pop_projection(PyObject *UNUSED(self))
268 {
270 }
271 
274 /* -------------------------------------------------------------------- */
278 PyDoc_STRVAR(pygpu_matrix_multiply_matrix_doc,
279  ".. function:: multiply_matrix(matrix)\n"
280  "\n"
281  " Multiply the current stack matrix.\n"
282  "\n"
283  " :param matrix: A 4x4 matrix.\n"
284  " :type matrix: :class:`mathutils.Matrix`\n");
285 static PyObject *pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value)
286 {
287  MatrixObject *pymat;
288  if (!Matrix_Parse4x4(value, &pymat)) {
289  return NULL;
290  }
291  GPU_matrix_mul(pymat->matrix);
292  Py_RETURN_NONE;
293 }
294 
295 PyDoc_STRVAR(pygpu_matrix_scale_doc,
296  ".. function:: scale(scale)\n"
297  "\n"
298  " Scale the current stack matrix.\n"
299  "\n"
300  " :param scale: Scale the current stack matrix.\n"
301  " :type scale: sequence of 2 or 3 floats\n");
302 static PyObject *pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value)
303 {
304  float scale[3];
305  int len;
306  if ((len = mathutils_array_parse(
307  scale, 2, 3, value, "gpu.matrix.scale(): invalid vector arg")) == -1) {
308  return NULL;
309  }
310  if (len == 2) {
311  GPU_matrix_scale_2fv(scale);
312  }
313  else {
314  GPU_matrix_scale_3fv(scale);
315  }
316  Py_RETURN_NONE;
317 }
318 
319 PyDoc_STRVAR(pygpu_matrix_scale_uniform_doc,
320  ".. function:: scale_uniform(scale)\n"
321  "\n"
322  " :param scale: Scale the current stack matrix.\n"
323  " :type scale: float\n");
324 static PyObject *pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value)
325 {
326  float scalar;
327  if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
328  PyErr_Format(PyExc_TypeError, "expected a number, not %.200s", Py_TYPE(value)->tp_name);
329  return NULL;
330  }
331  GPU_matrix_scale_1f(scalar);
332  Py_RETURN_NONE;
333 }
334 
335 PyDoc_STRVAR(pygpu_matrix_translate_doc,
336  ".. function:: translate(offset)\n"
337  "\n"
338  " Scale the current stack matrix.\n"
339  "\n"
340  " :param offset: Translate the current stack matrix.\n"
341  " :type offset: sequence of 2 or 3 floats\n");
342 static PyObject *pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value)
343 {
344  float offset[3];
345  int len;
346  if ((len = mathutils_array_parse(
347  offset, 2, 3, value, "gpu.matrix.translate(): invalid vector arg")) == -1) {
348  return NULL;
349  }
350  if (len == 2) {
351  GPU_matrix_translate_2fv(offset);
352  }
353  else {
354  GPU_matrix_translate_3fv(offset);
355  }
356  Py_RETURN_NONE;
357 }
358 
361 /* -------------------------------------------------------------------- */
365 PyDoc_STRVAR(pygpu_matrix_reset_doc,
366  ".. function:: reset()\n"
367  "\n"
368  " Empty stack and set to identity.\n");
369 static PyObject *pygpu_matrix_reset(PyObject *UNUSED(self))
370 {
372  Py_RETURN_NONE;
373 }
374 
375 PyDoc_STRVAR(pygpu_matrix_load_identity_doc,
376  ".. function:: load_identity()\n"
377  "\n"
378  " Empty stack and set to identity.\n");
379 static PyObject *pygpu_matrix_load_identity(PyObject *UNUSED(self))
380 {
382  Py_RETURN_NONE;
383 }
384 
385 PyDoc_STRVAR(pygpu_matrix_load_matrix_doc,
386  ".. function:: load_matrix(matrix)\n"
387  "\n"
388  " Load a matrix into the stack.\n"
389  "\n"
390  " :param matrix: A 4x4 matrix.\n"
391  " :type matrix: :class:`mathutils.Matrix`\n");
392 static PyObject *pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value)
393 {
394  MatrixObject *pymat;
395  if (!Matrix_Parse4x4(value, &pymat)) {
396  return NULL;
397  }
398  GPU_matrix_set(pymat->matrix);
399  Py_RETURN_NONE;
400 }
401 
402 PyDoc_STRVAR(pygpu_matrix_load_projection_matrix_doc,
403  ".. function:: load_projection_matrix(matrix)\n"
404  "\n"
405  " Load a projection matrix into the stack.\n"
406  "\n"
407  " :param matrix: A 4x4 matrix.\n"
408  " :type matrix: :class:`mathutils.Matrix`\n");
409 static PyObject *pygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value)
410 {
411  MatrixObject *pymat;
412  if (!Matrix_Parse4x4(value, &pymat)) {
413  return NULL;
414  }
415  GPU_matrix_projection_set(pymat->matrix);
416  Py_RETURN_NONE;
417 }
418 
421 /* -------------------------------------------------------------------- */
425 PyDoc_STRVAR(pygpu_matrix_get_projection_matrix_doc,
426  ".. function:: get_projection_matrix()\n"
427  "\n"
428  " Return a copy of the projection matrix.\n"
429  "\n"
430  " :return: A 4x4 projection matrix.\n"
431  " :rtype: :class:`mathutils.Matrix`\n");
432 static PyObject *pygpu_matrix_get_projection_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_model_view_matrix_doc,
440  ".. function:: get_model_view_matrix()\n"
441  "\n"
442  " Return a copy of the model-view matrix.\n"
443  "\n"
444  " :return: A 4x4 view matrix.\n"
445  " :rtype: :class:`mathutils.Matrix`\n");
446 static PyObject *pygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self))
447 {
448  float matrix[4][4];
450  return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL);
451 }
452 
453 PyDoc_STRVAR(pygpu_matrix_get_normal_matrix_doc,
454  ".. function:: get_normal_matrix()\n"
455  "\n"
456  " Return a copy of the normal matrix.\n"
457  "\n"
458  " :return: A 3x3 normal matrix.\n"
459  " :rtype: :class:`mathutils.Matrix`\n");
460 static PyObject *pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self))
461 {
462  float matrix[3][3];
463  GPU_matrix_normal_get(matrix);
464  return Matrix_CreatePyObject(&matrix[0][0], 3, 3, NULL);
465 }
466 
469 /* -------------------------------------------------------------------- */
473 static struct PyMethodDef pygpu_matrix__tp_methods[] = {
474  /* Manage Stack */
475  {"push", (PyCFunction)pygpu_matrix_push, METH_NOARGS, pygpu_matrix_push_doc},
476  {"pop", (PyCFunction)pygpu_matrix_pop, METH_NOARGS, pygpu_matrix_pop_doc},
477 
478  {"push_projection",
479  (PyCFunction)pygpu_matrix_push_projection,
480  METH_NOARGS,
481  pygpu_matrix_push_projection_doc},
482  {"pop_projection",
483  (PyCFunction)pygpu_matrix_pop_projection,
484  METH_NOARGS,
485  pygpu_matrix_pop_projection_doc},
486 
487  /* Stack (Context Manager) */
488  {"push_pop", (PyCFunction)pygpu_matrix_push_pop, METH_NOARGS, pygpu_matrix_push_pop_doc},
489  {"push_pop_projection",
491  METH_NOARGS,
492  pygpu_matrix_push_pop_projection_doc},
493 
494  /* Manipulate State */
495  {"multiply_matrix",
496  (PyCFunction)pygpu_matrix_multiply_matrix,
497  METH_O,
498  pygpu_matrix_multiply_matrix_doc},
499  {"scale", (PyCFunction)pygpu_matrix_scale, METH_O, pygpu_matrix_scale_doc},
500  {"scale_uniform",
501  (PyCFunction)pygpu_matrix_scale_uniform,
502  METH_O,
503  pygpu_matrix_scale_uniform_doc},
504  {"translate", (PyCFunction)pygpu_matrix_translate, METH_O, pygpu_matrix_translate_doc},
505 
506 /* TODO */
507 #if 0
508  {"rotate", (PyCFunction)pygpu_matrix_rotate, METH_O, pygpu_matrix_rotate_doc},
509  {"rotate_axis", (PyCFunction)pygpu_matrix_rotate_axis, METH_O, pygpu_matrix_rotate_axis_doc},
510  {"look_at", (PyCFunction)pygpu_matrix_look_at, METH_O, pygpu_matrix_look_at_doc},
511 #endif
512 
513  /* Write State */
514  {"reset", (PyCFunction)pygpu_matrix_reset, METH_NOARGS, pygpu_matrix_reset_doc},
515  {"load_identity",
516  (PyCFunction)pygpu_matrix_load_identity,
517  METH_NOARGS,
518  pygpu_matrix_load_identity_doc},
519  {"load_matrix", (PyCFunction)pygpu_matrix_load_matrix, METH_O, pygpu_matrix_load_matrix_doc},
520  {"load_projection_matrix",
522  METH_O,
523  pygpu_matrix_load_projection_matrix_doc},
524 
525  /* Read State */
526  {"get_projection_matrix",
528  METH_NOARGS,
529  pygpu_matrix_get_projection_matrix_doc},
530  {"get_model_view_matrix",
532  METH_NOARGS,
533  pygpu_matrix_get_model_view_matrix_doc},
534  {"get_normal_matrix",
535  (PyCFunction)pygpu_matrix_get_normal_matrix,
536  METH_NOARGS,
537  pygpu_matrix_get_normal_matrix_doc},
538 
539  {NULL, NULL, 0, NULL},
540 };
541 
542 PyDoc_STRVAR(pygpu_matrix__tp_doc, "This module provides access to the matrix stack.");
543 static PyModuleDef pygpu_matrix_module_def = {
544  PyModuleDef_HEAD_INIT,
545  .m_name = "gpu.matrix",
546  .m_doc = pygpu_matrix__tp_doc,
547  .m_methods = pygpu_matrix__tp_methods,
548 };
549 
550 PyObject *bpygpu_matrix_init(void)
551 {
552  PyObject *submodule;
553 
554  submodule = PyModule_Create(&pygpu_matrix_module_def);
555 
556  if (PyType_Ready(&PyGPUMatrixStackContext_Type) < 0) {
557  return NULL;
558  }
559 
560  return submodule;
561 }
562 
#define BLI_assert_unreachable()
Definition: BLI_assert.h:96
#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:142
#define GPU_matrix_normal_get(x)
Definition: GPU_matrix.h:230
void GPU_matrix_translate_2fv(const float vec[2])
Definition: gpu_matrix.cc:199
#define GPU_matrix_model_view_get(x)
Definition: GPU_matrix.h:226
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:156
void GPU_matrix_scale_2fv(const float vec[2])
Definition: gpu_matrix.cc:242
#define GPU_matrix_set(x)
Definition: GPU_matrix.h:224
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:223
void GPU_matrix_scale_3fv(const float vec[3])
Definition: gpu_matrix.cc:257
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:135
void GPU_matrix_scale_1f(float factor)
Definition: gpu_matrix.cc:225
#define GPU_matrix_projection_get(x)
Definition: GPU_matrix.h:227
void GPU_matrix_reset(void)
Definition: gpu_matrix.cc:102
#define GPU_matrix_projection_set(x)
Definition: GPU_matrix.h:225
void GPU_matrix_translate_3fv(const float vec[3])
Definition: gpu_matrix.cc:220
void GPU_matrix_identity_set(void)
Definition: gpu_matrix.cc:184
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:149
PyObject * self
Definition: bpy_driver.c:185
int GPU_matrix_stack_level_get_projection(void)
Definition: gpu_matrix.cc:709
int GPU_matrix_stack_level_get_model_view(void)
Definition: gpu_matrix.cc:703
static PyObject * pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value)
static PyObject * pygpu_matrix_pop(PyObject *UNUSED(self))
static bool pygpu_stack_is_pop_model_view_ok_or_error(void)
Definition: gpu_py_matrix.c:69
static PyObject * pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self))
static PyObject * pygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self))
@ PYGPU_MATRIX_TYPE_MODEL_VIEW
@ PYGPU_MATRIX_TYPE_PROJECTION
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:58
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:78
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:47
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))
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:97
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))
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:118
int Matrix_Parse4x4(PyObject *o, void *p)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort num_col, const ushort num_row, PyTypeObject *base_type)
return ret
PyObject_HEAD int type
uint len