3c50900c6886becb828b33a0ae6c07c5399348f2
[blender.git] / source / blender / python / gpu / gpu_py_shader.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file blender/python/gpu/gpu_py_shader.c
22  *  \ingroup bpygpu
23  *
24  * - Use ``bpygpu_`` for local API.
25  * - Use ``BPyGPU`` for public API.
26  */
27
28 #include <Python.h>
29
30 #include "BLI_utildefines.h"
31
32 #include "GPU_shader.h"
33 #include "GPU_shader_interface.h"
34
35 #include "../generic/py_capi_utils.h"
36 #include "../generic/python_utildefines.h"
37 #include "../mathutils/mathutils.h"
38
39 #include "gpu_py.h"
40 #include "gpu_py_shader.h" /* own include */
41 #include "gpu_py_vertex_format.h"
42
43
44  /* -------------------------------------------------------------------- */
45
46  /** \name Enum Conversion.
47  * \{ */
48
49 static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p)
50 {
51         Py_ssize_t mode_id_len;
52         const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len);
53         if (mode_id == NULL) {
54                 PyErr_Format(PyExc_ValueError,
55                              "expected a string, got %s",
56                              Py_TYPE(o)->tp_name);
57                 return 0;
58         }
59 #define MATCH_ID(id) \
60         if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \
61                 if (STREQ(mode_id, STRINGIFY(id))) { \
62                         mode = GPU_SHADER_##id; \
63                         goto success; \
64                 } \
65         } ((void)0)
66
67         GPUBuiltinShader mode;
68         MATCH_ID(2D_UNIFORM_COLOR);
69         MATCH_ID(2D_FLAT_COLOR);
70         MATCH_ID(2D_SMOOTH_COLOR);
71         MATCH_ID(2D_IMAGE);
72         MATCH_ID(3D_UNIFORM_COLOR);
73         MATCH_ID(3D_FLAT_COLOR);
74         MATCH_ID(3D_SMOOTH_COLOR);
75
76 #undef MATCH_ID
77         PyErr_Format(PyExc_ValueError,
78                      "unknown type literal: '%s'",
79                      mode_id);
80         return 0;
81
82 success:
83         (*(GPUBuiltinShader *)p) = mode;
84         return 1;
85 }
86
87 static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix)
88 {
89         int uniform = GPU_shader_get_uniform(shader, name);
90
91         if (uniform == -1) {
92                 PyErr_Format(PyExc_ValueError, "%s: uniform %.32s %.32s not found", error_prefix, name);
93         }
94
95         return uniform;
96 }
97
98 /** \} */
99
100
101 /* -------------------------------------------------------------------- */
102
103 /** \name Shader Type
104  * \{ */
105
106 static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
107 {
108         struct {
109                 const char *vertexcode;
110                 const char *fragcode;
111                 const char *geocode;
112                 const char *libcode;
113                 const char *defines;
114         } params = {0};
115
116         static const char *_keywords[] = {
117                 "vertexcode", "fragcode", "geocode",
118                 "libcode", "defines", NULL};
119
120         static _PyArg_Parser _parser = {"ss|$sss:GPUShader.__new__", _keywords, 0};
121         if (!bpygpu_is_initialized() ||
122             !_PyArg_ParseTupleAndKeywordsFast(
123                 args, kwds, &_parser,
124                 &params.vertexcode, &params.fragcode, &params.geocode,
125                 &params.libcode, &params.defines))
126         {
127                 return NULL;
128         }
129
130         GPUShader *shader = GPU_shader_create(
131                 params.vertexcode,
132                 params.fragcode,
133                 params.geocode,
134                 params.libcode,
135                 params.defines,
136                 NULL);
137
138         if (shader == NULL) {
139                 PyErr_SetString(PyExc_Exception,
140                                 "Shader Compile Error, see console for more details");
141                 return NULL;
142         }
143
144         return BPyGPUShader_CreatePyObject(shader, false);
145 }
146
147 PyDoc_STRVAR(bpygpu_shader_bind_doc,
148 ".. method:: bind()\n"
149 "\n"
150 "   Bind the shader object. Required to be able to change uniforms of this shader.\n"
151 );
152 static PyObject *bpygpu_shader_bind(BPyGPUShader *self)
153 {
154         GPU_shader_bind(self->shader);
155         Py_RETURN_NONE;
156 }
157
158 PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc,
159 ".. method:: uniform_from_name(name)\n"
160 "\n"
161 "   Get uniform location by name.\n"
162 "\n"
163 "   :param name: Name of the uniform variable whose location is to be queried.\n"
164 "   :type name: `str`\n"
165 "   :return: Location of the uniform variable.\n"
166 "   :rtype: `int`\n"
167 );
168 static PyObject *bpygpu_shader_uniform_from_name(
169         BPyGPUShader *self, PyObject *arg)
170 {
171         const char *name = PyUnicode_AsUTF8(arg);
172         if (name == NULL) {
173                 return NULL;
174         }
175
176         int uniform = bpygpu_uniform_location_get(
177                 self->shader, name, "GPUShader.get_uniform");
178
179         if (uniform == -1) {
180                 return NULL;
181         }
182
183         return PyLong_FromLong(uniform);
184 }
185
186 PyDoc_STRVAR(bpygpu_shader_uniform_block_from_name_doc,
187 ".. method:: uniform_block_from_name(name)\n"
188 "\n"
189 "   Get uniform block location by name.\n"
190 "\n"
191 "   :param name: Name of the uniform block variable whose location is to be queried.\n"
192 "   :type name: `str`\n"
193 "   :return: The location of the uniform block variable.\n"
194 "   :rtype: `int`\n"
195 );
196 static PyObject *bpygpu_shader_uniform_block_from_name(
197         BPyGPUShader *self, PyObject *arg)
198 {
199         const char *name = PyUnicode_AsUTF8(arg);
200         if (name == NULL) {
201                 return NULL;
202         }
203
204         int uniform = GPU_shader_get_uniform_block(self->shader, name);
205
206         if (uniform == -1) {
207                 PyErr_Format(PyExc_ValueError,
208                              "GPUShader.get_uniform_block: uniform %.32s not found", name);
209                 return NULL;
210         }
211
212         return PyLong_FromLong(uniform);
213 }
214
215 static bool bpygpu_shader_uniform_vector_imp(
216         PyObject *args, int elem_size,
217         int *r_location, int *r_length, int *r_count, Py_buffer *r_pybuffer)
218 {
219         PyObject *buffer;
220
221         *r_count = 1;
222         if (!PyArg_ParseTuple(
223                 args, "iOi|i:GPUShader.uniform_vector_*",
224                 r_location, &buffer, r_length, r_count))
225         {
226                 return false;
227         }
228
229         if (PyObject_GetBuffer(buffer, r_pybuffer, PyBUF_SIMPLE) == -1) {
230                 /* PyObject_GetBuffer raise a PyExc_BufferError */
231                 return false;
232         }
233
234         if (r_pybuffer->len != (*r_length * *r_count * elem_size)) {
235                 PyErr_SetString(
236                         PyExc_BufferError,
237                         "GPUShader.uniform_vector_*: buffer size does not match.");
238                 return false;
239         }
240
241         return true;
242 }
243
244 PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc,
245 ".. method:: uniform_vector_float(location, buffer, length, count)\n"
246 "\n"
247 "   Set the buffer to fill the uniform.\n"
248 "\n"
249 "   :param location: Location of the uniform variable to be modified.\n"
250 "   :type location: int\n"
251 "   :param buffer:  The data that should be set. Can support the buffer protocol.\n"
252 "   :type buffer: sequence of floats\n"
253 "   :param length: Size of the uniform data type:\n"
254 "\n"
255 "      - 1: float\n"
256 "      - 2: vec2 or float[2]\n"
257 "      - 3: vec3 or float[3]\n"
258 "      - 4: vec4 or float[4]\n"
259 "      - 9: mat3\n"
260 "      - 16: mat4\n"
261 "\n"
262 "   :type length: int\n"
263 "   :param count: Specifies the number of elements, vector or matrices that are to be modified.\n"
264 "   :type count: int\n"
265 );
266 static PyObject *bpygpu_shader_uniform_vector_float(
267         BPyGPUShader *self, PyObject *args)
268 {
269         int location, length, count;
270
271         Py_buffer pybuffer;
272
273         if (!bpygpu_shader_uniform_vector_imp(
274                 args, sizeof(float),
275                 &location, &length, &count, &pybuffer))
276         {
277                 return NULL;
278         }
279
280         GPU_shader_uniform_vector(
281                 self->shader, location, length,
282                 count, pybuffer.buf);
283
284         PyBuffer_Release(&pybuffer);
285
286         Py_RETURN_NONE;
287 }
288
289 PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc,
290 ".. method:: uniform_vector_int(location, buffer, length, count)\n"
291 "\n"
292 "   See GPUShader.uniform_vector_float(...) description.\n"
293 );
294 static PyObject *bpygpu_shader_uniform_vector_int(
295         BPyGPUShader *self, PyObject *args)
296 {
297         int location, length, count;
298
299         Py_buffer pybuffer;
300
301         if (!bpygpu_shader_uniform_vector_imp(
302                 args, sizeof(int),
303                 &location, &length, &count, &pybuffer))
304         {
305                 return NULL;
306         }
307
308         GPU_shader_uniform_vector_int(
309                 self->shader, location, length,
310                 count, pybuffer.buf);
311
312         PyBuffer_Release(&pybuffer);
313
314         Py_RETURN_NONE;
315 }
316
317 PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc,
318 ".. method:: uniform_bool(name, seq)\n"
319 "\n"
320 "   Specify the value of a uniform variable for the current program object.\n"
321 "\n"
322 "   :param name: Name of the uniform variable whose value is to be changed.\n"
323 "   :type name: str\n"
324 "   :param seq: Value that will be used to update the specified uniform variable.\n"
325 "   :type seq: sequence of bools\n"
326 );
327 static PyObject *bpygpu_shader_uniform_bool(
328         BPyGPUShader *self, PyObject *args)
329 {
330         const char *error_prefix = "GPUShader.uniform_bool";
331
332         struct {
333                 const char *id;
334                 PyObject *seq;
335         } params;
336
337         if (!PyArg_ParseTuple(
338                 args, "sO:GPUShader.uniform_bool",
339                 &params.id, &params.seq))
340         {
341                 return NULL;
342         }
343
344         int values[4];
345         int length;
346         int ret;
347         {
348                 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
349                 if (seq_fast == NULL) {
350                         PyErr_Format(PyExc_TypeError,
351                                      "%s: expected a sequence, got %s",
352                                      error_prefix, Py_TYPE(params.seq)->tp_name);
353                         ret = -1;
354                 }
355                 else {
356                         length = PySequence_Fast_GET_SIZE(seq_fast);
357                         if (length == 0 || length > 4) {
358                                 PyErr_Format(PyExc_TypeError,
359                                              "%s: invalid sequence length. expected 1..4, got %d",
360                                              error_prefix, length);
361                                 ret = -1;
362                         }
363                         else {
364                                 ret = PyC_AsArray_FAST(
365                                         values, seq_fast, length, &PyLong_Type,
366                                         false, error_prefix);
367                         }
368                         Py_DECREF(seq_fast);
369                 }
370         }
371         if (ret == -1) {
372                 return NULL;
373         }
374
375         const int location = bpygpu_uniform_location_get(
376                 self->shader, params.id, error_prefix);
377
378         if (location == -1) {
379                 return NULL;
380         }
381
382         GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
383
384         Py_RETURN_NONE;
385 }
386
387 PyDoc_STRVAR(bpygpu_shader_uniform_float_doc,
388 ".. method:: uniform_float(name, value)\n"
389 "\n"
390 "   Specify the value of a uniform variable for the current program object.\n"
391 "\n"
392 "   :param name: Name of the uniform variable whose value is to be changed.\n"
393 "   :type name: str\n"
394 "   :param value: Value that will be used to update the specified uniform variable.\n"
395 "   :type value: single number or sequence of numbers\n"
396 );
397 static PyObject *bpygpu_shader_uniform_float(
398         BPyGPUShader *self, PyObject *args)
399 {
400         const char *error_prefix = "GPUShader.uniform_float";
401
402         struct {
403                 const char *id;
404                 PyObject *seq;
405         } params;
406
407         if (!PyArg_ParseTuple(
408                 args, "sO:GPUShader.uniform_float",
409                 &params.id, &params.seq))
410         {
411                 return NULL;
412         }
413
414         float values[16];
415         int length;
416
417         if (PyFloat_Check(params.seq)) {
418                 values[0] = (float)PyFloat_AsDouble(params.seq);
419                 length = 1;
420         }
421         else if (PyLong_Check(params.seq)) {
422                 values[0] = (float)PyLong_AsDouble(params.seq);
423                 length = 1;
424         }
425         else if (MatrixObject_Check(params.seq)) {
426                 MatrixObject *mat = (MatrixObject *)params.seq;
427                 if (BaseMath_ReadCallback(mat) == -1) {
428                         return NULL;
429                 }
430                 if ((mat->num_row != mat->num_col) || !ELEM(mat->num_row, 3, 4)) {
431                         PyErr_SetString(PyExc_ValueError,
432                                         "Expected 3x3 or 4x4 matrix");
433                         return NULL;
434                 }
435                 length = mat->num_row * mat->num_col;
436                 memcpy(values, mat->matrix, sizeof(float) * length);
437         }
438         else {
439                 length = mathutils_array_parse(values, 2, 16, params.seq, "");
440                 if (length == -1) {
441                         return NULL;
442                 }
443         }
444
445         if (!ELEM(length, 1, 2, 3, 4, 9, 16)) {
446                 PyErr_SetString(PyExc_TypeError,
447                                 "Expected a single float or a sequence of floats of length 1..4, 9 or 16.");
448                 return NULL;
449         }
450
451         const int location = bpygpu_uniform_location_get(
452                 self->shader, params.id, error_prefix);
453
454         if (location == -1) {
455                 return NULL;
456         }
457
458         GPU_shader_uniform_vector(self->shader, location, length, 1, values);
459
460         Py_RETURN_NONE;
461 }
462
463 PyDoc_STRVAR(bpygpu_shader_uniform_int_doc,
464 ".. method:: uniform_int(name, seq)\n"
465 "\n"
466 "   Specify the value of a uniform variable for the current program object.\n"
467 "\n"
468 "   :param name: name of the uniform variable whose value is to be changed.\n"
469 "   :type name: str\n"
470 "   :param seq: Value that will be used to update the specified uniform variable.\n"
471 "   :type seq: sequence of numbers\n"
472 );
473 static PyObject *bpygpu_shader_uniform_int(
474         BPyGPUShader *self, PyObject *args)
475 {
476         const char *error_prefix = "GPUShader.uniform_int";
477
478         struct {
479                 const char *id;
480                 PyObject *seq;
481         } params;
482
483         if (!PyArg_ParseTuple(
484                 args, "sO:GPUShader.uniform_int",
485                 &params.id, &params.seq))
486         {
487                 return NULL;
488         }
489
490         int values[4];
491         int length;
492         int ret;
493
494         if (PyLong_Check(params.seq)) {
495                 values[0] = PyC_Long_AsI32(params.seq);
496                 length = 1;
497                 ret = 0;
498         }
499         else {
500                 PyObject *seq_fast = PySequence_Fast(params.seq, error_prefix);
501                 if (seq_fast == NULL) {
502                         PyErr_Format(PyExc_TypeError,
503                                      "%s: expected a sequence, got %s",
504                                      error_prefix, Py_TYPE(params.seq)->tp_name);
505                         ret = -1;
506                 }
507                 else {
508                         length = PySequence_Fast_GET_SIZE(seq_fast);
509                         if (length == 0 || length > 4) {
510                                 PyErr_Format(PyExc_TypeError,
511                                              "%s: invalid sequence length. expected 1..4, got %d",
512                                              error_prefix, length);
513                                 ret = -1;
514                         }
515                         else {
516                                 ret = PyC_AsArray_FAST(
517                                         values, seq_fast, length, &PyLong_Type,
518                                         false, error_prefix);
519                         }
520                         Py_DECREF(seq_fast);
521                 }
522         }
523         if (ret == -1) {
524                 return NULL;
525         }
526
527         const int location = bpygpu_uniform_location_get(
528                 self->shader, params.id, error_prefix);
529
530         if (location == -1) {
531                 return NULL;
532         }
533
534         GPU_shader_uniform_vector_int(self->shader, location, length, 1, values);
535
536         Py_RETURN_NONE;
537 }
538
539 PyDoc_STRVAR(bpygpu_shader_attr_from_name_doc,
540 ".. method:: attr_from_name(name)\n"
541 "\n"
542 "   Get attribute location by name.\n"
543 "\n"
544 "   :param name: The name of the attribute variable whose location is to be queried.\n"
545 "   :type name: str\n"
546 "   :return: The location of an attribute variable.\n"
547 "   :rtype: int\n"
548 );
549 static PyObject *bpygpu_shader_attr_from_name(
550         BPyGPUShader *self, PyObject *arg)
551 {
552         const char *name = PyUnicode_AsUTF8(arg);
553         if (name == NULL) {
554                 return NULL;
555         }
556
557         int attr = GPU_shader_get_attribute(self->shader, name);
558
559         if (attr == -1) {
560                 PyErr_Format(PyExc_ValueError,
561                              "GPUShader.attr_from_name: attribute %.32s not found", name);
562                 return NULL;
563         }
564
565         return PyLong_FromLong(attr);
566 }
567
568 PyDoc_STRVAR(bpygpu_shader_calc_format_doc,
569 ".. method:: calc_format()\n"
570 "\n"
571 "   Build a new format based on the attributes of the shader.\n"
572 "\n"
573 "   :return: vertex attribute format for the shader\n"
574 "   :rtype: GPUVertFormat\n"
575 );
576 static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
577 {
578         BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
579         GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader));
580         return (PyObject *)ret;
581 }
582
583 static struct PyMethodDef bpygpu_shader_methods[] = {
584         {"bind", (PyCFunction)bpygpu_shader_bind,
585          METH_NOARGS, bpygpu_shader_bind_doc},
586         {"uniform_from_name",
587          (PyCFunction)bpygpu_shader_uniform_from_name,
588          METH_O, bpygpu_shader_uniform_from_name_doc},
589         {"uniform_block_from_name",
590          (PyCFunction)bpygpu_shader_uniform_block_from_name,
591          METH_O, bpygpu_shader_uniform_block_from_name_doc},
592         {"uniform_vector_float",
593          (PyCFunction)bpygpu_shader_uniform_vector_float,
594          METH_VARARGS, bpygpu_shader_uniform_vector_float_doc},
595         {"uniform_vector_int",
596          (PyCFunction)bpygpu_shader_uniform_vector_int,
597          METH_VARARGS, bpygpu_shader_uniform_vector_int_doc},
598         {"uniform_bool",
599          (PyCFunction)bpygpu_shader_uniform_bool,
600          METH_VARARGS, bpygpu_shader_uniform_bool_doc},
601         {"uniform_float",
602          (PyCFunction)bpygpu_shader_uniform_float,
603          METH_VARARGS, bpygpu_shader_uniform_float_doc},
604         {"uniform_int",
605          (PyCFunction)bpygpu_shader_uniform_int,
606          METH_VARARGS, bpygpu_shader_uniform_int_doc},
607         {"attr_from_name",
608          (PyCFunction)bpygpu_shader_attr_from_name,
609          METH_O, bpygpu_shader_attr_from_name_doc},
610         {"format_calc",
611          (PyCFunction)bpygpu_shader_calc_format,
612          METH_NOARGS, bpygpu_shader_calc_format_doc},
613         {NULL, NULL, 0, NULL}
614 };
615
616 PyDoc_STRVAR(bpygpu_shader_program_doc,
617 "The name of the program object for use by the OpenGL API (read-only).\n\n:type: int"
618 );
619 static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure))
620 {
621         return PyLong_FromLong(GPU_shader_get_program(self->shader));
622 }
623
624 static PyGetSetDef bpygpu_shader_getseters[] = {
625         {(char *)"program",
626          (getter)bpygpu_shader_program_get, (setter)NULL,
627          bpygpu_shader_program_doc, NULL},
628         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
629 };
630
631
632 static void bpygpu_shader_dealloc(BPyGPUShader *self)
633 {
634         if (self->is_builtin == false) {
635                 GPU_shader_free(self->shader);
636         }
637         Py_TYPE(self)->tp_free((PyObject *)self);
638 }
639
640
641 PyDoc_STRVAR(bpygpu_shader_doc,
642 ".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n"
643 "\n"
644 "   GPUShader combines multiple GLSL shaders into a program used for drawing.\n"
645 "   It must contain a vertex and fragment shaders, with an optional geometry shader.\n"
646 "\n"
647 "   The GLSL #version directive is automatically included at the top of shaders, and set to 330.\n"
648 "   Some preprocessor directives are automatically added according to the Operating System or availability:\n"
649 "   ``GPU_ATI``, ``GPU_NVIDIA`` and ``GPU_INTEL``.\n"
650 "\n"
651 "   The following extensions are enabled by default if supported by the GPU:\n"
652 "   ``GL_ARB_texture_gather`` and ``GL_ARB_texture_query_lod``.\n"
653 "\n"
654 "   To debug shaders, use the --debug-gpu-shaders command line option"
655 "   to see full GLSL shader compilation and linking errors.\n"
656 "\n"
657 "   :param vertexcode: Vertex shader code.\n"
658 "   :type vertexcode: str\n"
659 "   :param fragcode: Fragment shader code.\n"
660 "   :type value: str\n"
661 "   :param geocode: Geometry shader code.\n"
662 "   :type value: str\n"
663 "   :param libcode: Code with functions and presets to be shared between shaders.\n"
664 "   :type value: str\n"
665 "   :param defines: Preprocessor directives.\n"
666 "   :type value: str\n"
667 );
668 PyTypeObject BPyGPUShader_Type = {
669         PyVarObject_HEAD_INIT(NULL, 0)
670         .tp_name = "GPUShader",
671         .tp_basicsize = sizeof(BPyGPUShader),
672         .tp_dealloc = (destructor)bpygpu_shader_dealloc,
673         .tp_flags = Py_TPFLAGS_DEFAULT,
674         .tp_doc = bpygpu_shader_doc,
675         .tp_methods = bpygpu_shader_methods,
676         .tp_getset = bpygpu_shader_getseters,
677         .tp_new = bpygpu_shader_new,
678 };
679
680 /** \} */
681
682
683 /* -------------------------------------------------------------------- */
684
685 /** \name gpu.shader Module API
686  * \{ */
687
688 PyDoc_STRVAR(bpygpu_shader_unbind_doc,
689 ".. function:: unbind()\n"
690 "\n"
691 "   Unbind the bound shader object.\n"
692 );
693 static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self))
694 {
695         GPU_shader_unbind();
696         Py_RETURN_NONE;
697 }
698
699 PyDoc_STRVAR(bpygpu_shader_from_builtin_doc,
700 ".. function:: from_builtin(shader_name)\n"
701 "\n"
702 "   Shaders that are embedded in the blender internal code.\n"
703 "   They all read the uniform 'mat4 ModelViewProjectionMatrix', which can be edited by the 'gpu.matrix' module.\n"
704 "   For more details, you can check the shader code with the function 'gpu.shader.code_from_builtin';\n"
705 "\n"
706 "   :param shader_name: One of these builtin shader names: {\n"
707 "       '2D_UNIFORM_COLOR',\n"
708 "       '2D_FLAT_COLOR',\n"
709 "       '2D_SMOOTH_COLOR',\n"
710 "       '2D_IMAGE',\n"
711 "       '3D_UNIFORM_COLOR',\n"
712 "       '3D_FLAT_COLOR',\n"
713 "       '3D_SMOOTH_COLOR'}\n"
714 "   :type shader_name: str\n"
715 "   :return: Shader object corresponding to the given name.\n"
716 "   :rtype: :class:`bpy.types.GPUShader`\n"
717 );
718 static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg)
719 {
720         GPUBuiltinShader shader_id;
721
722         if (!bpygpu_is_initialized() ||
723             !bpygpu_ParseBultinShaderEnum(arg, &shader_id))
724         {
725                 return NULL;
726         }
727
728         GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
729
730         return BPyGPUShader_CreatePyObject(shader, true);
731 }
732
733 PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc,
734 ".. function:: code_from_builtin(shader_name)\n"
735 "\n"
736 "   Exposes the internal shader code for query.\n"
737 "\n"
738 "   :param shader_name: One of these builtin shader names: {\n"
739 "       '2D_UNIFORM_COLOR',\n"
740 "       '2D_FLAT_COLOR',\n"
741 "       '2D_SMOOTH_COLOR',\n"
742 "       '2D_IMAGE',\n"
743 "       '3D_UNIFORM_COLOR',\n"
744 "       '3D_FLAT_COLOR',\n"
745 "       '3D_SMOOTH_COLOR'}\n"
746 "   :type shader_name: str\n"
747 "   :return: Vertex, fragment and geometry shader codes.\n"
748 "   :rtype: dict\n"
749 );
750 static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg)
751 {
752         GPUBuiltinShader shader_id;
753
754         const char *vert;
755         const char *frag;
756         const char *geom;
757         const char *defines;
758
759         PyObject *item, *r_dict;
760
761         if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) {
762                 return NULL;
763         }
764
765         GPU_shader_get_builtin_shader_code(
766                 shader_id, &vert, &frag, &geom, &defines);
767
768         r_dict = PyDict_New();
769
770         PyDict_SetItemString(r_dict, "vertex_shader", item = PyUnicode_FromString(vert));
771         Py_DECREF(item);
772
773         PyDict_SetItemString(r_dict, "fragment_shader", item = PyUnicode_FromString(frag));
774         Py_DECREF(item);
775
776         if (geom) {
777                 PyDict_SetItemString(r_dict, "geometry_shader", item = PyUnicode_FromString(geom));
778                 Py_DECREF(item);
779         }
780         if (defines) {
781                 PyDict_SetItemString(r_dict, "defines", item = PyUnicode_FromString(defines));
782                 Py_DECREF(item);
783         }
784         return r_dict;
785 }
786
787 static struct PyMethodDef bpygpu_shader_module_methods[] = {
788         {"unbind",
789          (PyCFunction)bpygpu_shader_unbind,
790          METH_NOARGS, bpygpu_shader_unbind_doc},
791         {"from_builtin",
792          (PyCFunction)bpygpu_shader_from_builtin,
793          METH_O, bpygpu_shader_from_builtin_doc},
794         {"code_from_builtin",
795          (PyCFunction)bpygpu_shader_code_from_builtin,
796          METH_O, bpygpu_shader_code_from_builtin_doc},
797         {NULL, NULL, 0, NULL}
798 };
799
800 PyDoc_STRVAR(bpygpu_shader_module_doc,
801 "This module provides access to GPUShader internal functions."
802 );
803 static PyModuleDef BPyGPU_shader_module_def = {
804         PyModuleDef_HEAD_INIT,
805         .m_name = "gpu.shader",
806         .m_doc = bpygpu_shader_module_doc,
807         .m_methods = bpygpu_shader_module_methods,
808 };
809
810 /** \} */
811
812
813 /* -------------------------------------------------------------------- */
814
815 /** \name Public API
816  * \{ */
817
818 PyObject *BPyGPUShader_CreatePyObject(GPUShader *shader, bool is_builtin)
819 {
820         BPyGPUShader *self;
821
822         self = PyObject_New(BPyGPUShader, &BPyGPUShader_Type);
823         self->shader = shader;
824         self->is_builtin = is_builtin;
825
826         return (PyObject *)self;
827 }
828
829 PyObject *BPyInit_gpu_shader(void)
830 {
831         PyObject *submodule;
832
833         submodule = PyModule_Create(&BPyGPU_shader_module_def);
834
835         return submodule;
836 }
837
838 /** \} */