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