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