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