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