4a923e6635608ce8358dc604fc5b5c68a00a7129
[blender.git] / source / blender / gpu / intern / gpu_codegen.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. The Blender
8  * Foundation also sells licenses for use in proprietary software under
9  * the Blender License.  See http://www.blender.org/BL/ for information
10  * about this.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The Original Code is Copyright (C) 2005 Blender Foundation.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): Brecht Van Lommel.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 /** \file blender/gpu/intern/gpu_codegen.c
32  *  \ingroup gpu
33  */
34
35
36 #include "GL/glew.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_customdata_types.h"
41 #include "DNA_image_types.h"
42 #include "DNA_material_types.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
46 #include "BLI_dynstr.h"
47 #include "BLI_ghash.h"
48 #include "BLI_heap.h"
49
50 #include "GPU_material.h"
51 #include "GPU_extensions.h"
52
53 #include "BLO_sys_types.h" // for intptr_t support
54
55 #include "gpu_codegen.h"
56
57 #include "node_util.h" /* For muting node stuff... */
58
59 #include <string.h>
60 #include <stdarg.h>
61
62 extern char datatoc_gpu_shader_material_glsl[];
63 extern char datatoc_gpu_shader_vertex_glsl[];
64
65 /* structs and defines */
66
67 static const char* GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
68         NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"};
69
70 /* GLSL code parsing for finding function definitions.
71  * These are stored in a hash for lookup when creating a material. */
72
73 static GHash *FUNCTION_HASH= NULL;
74 /*static char *FUNCTION_PROTOTYPES= NULL;
75 static GPUShader *FUNCTION_LIB= NULL;*/
76
77 static int gpu_str_prefix(const char *str, const char *prefix)
78 {
79         while(*str && *prefix) {
80                 if(*str != *prefix)
81                         return 0;
82
83                 str++;
84                 prefix++;
85         }
86         
87         return (*prefix == '\0');
88 }
89
90 static char *gpu_str_skip_token(char *str, char *token, int max)
91 {
92         int len = 0;
93
94         /* skip a variable/function name */
95         while(*str) {
96                 if(ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
97                         break;
98                 else {
99                         if(token && len < max-1) {
100                                 *token= *str;
101                                 token++;
102                                 len++;
103                         }
104                         str++;
105                 }
106         }
107
108         if(token)
109                 *token= '\0';
110
111         /* skip the next special characters:
112          * note the missing ')' */
113         while(*str) {
114                 if(ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r'))
115                         str++;
116                 else
117                         break;
118         }
119
120         return str;
121 }
122
123 static void gpu_parse_functions_string(GHash *hash, char *code)
124 {
125         GPUFunction *function;
126         int i, type, qual;
127
128         while((code = strstr(code, "void "))) {
129                 function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
130
131                 code = gpu_str_skip_token(code, NULL, 0);
132                 code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME);
133
134                 /* get parameters */
135                 while(*code && *code != ')') {
136                         /* test if it's an input or output */
137                         qual = FUNCTION_QUAL_IN;
138                         if(gpu_str_prefix(code, "out "))
139                                 qual = FUNCTION_QUAL_OUT;
140                         if(gpu_str_prefix(code, "inout "))
141                                 qual = FUNCTION_QUAL_INOUT;
142                         if((qual != FUNCTION_QUAL_IN) || gpu_str_prefix(code, "in "))
143                                 code = gpu_str_skip_token(code, NULL, 0);
144
145                         /* test for type */
146                         type= 0;
147                         for(i=1; i<=16; i++) {
148                                 if(GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
149                                         type= i;
150                                         break;
151                                 }
152                         }
153
154                         if(!type && gpu_str_prefix(code, "sampler2DShadow"))
155                                 type= GPU_SHADOW2D;
156                         if(!type && gpu_str_prefix(code, "sampler2D"))
157                                 type= GPU_TEX2D;
158
159                         if(type) {
160                                 /* add paramater */
161                                 code = gpu_str_skip_token(code, NULL, 0);
162                                 code = gpu_str_skip_token(code, NULL, 0);
163                                 function->paramqual[function->totparam]= qual;
164                                 function->paramtype[function->totparam]= type;
165                                 function->totparam++;
166                         }
167                         else {
168                                 fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name);
169                                 break;
170                         }
171                 }
172
173                 if(function->name[0] == '\0' || function->totparam == 0) {
174                         fprintf(stderr, "GPU functions parse error.\n");
175                         MEM_freeN(function);
176                         break;
177                 }
178
179                 BLI_ghash_insert(hash, function->name, function);
180         }
181 }
182
183 #if 0
184 static char *gpu_generate_function_prototyps(GHash *hash)
185 {
186         DynStr *ds = BLI_dynstr_new();
187         GHashIterator *ghi;
188         GPUFunction *function;
189         char *name, *prototypes;
190         int a;
191         
192         /* automatically generate function prototypes to add to the top of the
193          * generated code, to avoid have to add the actual code & recompile all */
194         ghi = BLI_ghashIterator_new(hash);
195
196         for(; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
197                 name = BLI_ghashIterator_getValue(ghi);
198                 function = BLI_ghashIterator_getValue(ghi);
199
200                 BLI_dynstr_appendf(ds, "void %s(", name);
201                 for(a=0; a<function->totparam; a++) {
202                         if(function->paramqual[a] == FUNCTION_QUAL_OUT)
203                                 BLI_dynstr_append(ds, "out ");
204                         else if(function->paramqual[a] == FUNCTION_QUAL_INOUT)
205                                 BLI_dynstr_append(ds, "inout ");
206
207                         if(function->paramtype[a] == GPU_TEX2D)
208                                 BLI_dynstr_append(ds, "sampler2D");
209                         else if(function->paramtype[a] == GPU_SHADOW2D)
210                                 BLI_dynstr_append(ds, "sampler2DShadow");
211                         else
212                                 BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]);
213                                 
214                         //BLI_dynstr_appendf(ds, " param%d", a);
215                         
216                         if(a != function->totparam-1)
217                                 BLI_dynstr_append(ds, ", ");
218                 }
219                 BLI_dynstr_append(ds, ");\n");
220         }
221
222         BLI_dynstr_append(ds, "\n");
223
224         prototypes = BLI_dynstr_get_cstring(ds);
225         BLI_dynstr_free(ds);
226
227         return prototypes;
228 }
229 #endif
230
231 GPUFunction *GPU_lookup_function(const char *name)
232 {
233         if(!FUNCTION_HASH) {
234                 FUNCTION_HASH = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "GPU_lookup_function gh");
235                 gpu_parse_functions_string(FUNCTION_HASH, datatoc_gpu_shader_material_glsl);
236                 /*FUNCTION_PROTOTYPES = gpu_generate_function_prototyps(FUNCTION_HASH);
237                 FUNCTION_LIB = GPU_shader_create_lib(datatoc_gpu_shader_material_glsl);*/
238         }
239
240         return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name);
241 }
242
243 void GPU_extensions_exit(void)
244 {
245         extern Material defmaterial;    // render module abuse...
246
247         if(defmaterial.gpumaterial.first)
248                 GPU_material_free(&defmaterial);
249
250         if(FUNCTION_HASH) {
251                 BLI_ghash_free(FUNCTION_HASH, NULL, (GHashValFreeFP)MEM_freeN);
252                 FUNCTION_HASH = NULL;
253         }
254         /*if(FUNCTION_PROTOTYPES) {
255                 MEM_freeN(FUNCTION_PROTOTYPES);
256                 FUNCTION_PROTOTYPES = NULL;
257         }*/
258         /*if(FUNCTION_LIB) {
259                 GPU_shader_free(FUNCTION_LIB);
260                 FUNCTION_LIB = NULL;
261         }*/
262 }
263
264 /* GLSL code generation */
265
266 static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id)
267 {
268         char name[1024];
269
270         BLI_snprintf(name, sizeof(name), "%s%d", tmp, id);
271
272         if (from == to) {
273                 BLI_dynstr_append(ds, name);
274         }
275         else if (to == GPU_FLOAT) {
276                 if (from == GPU_VEC4)
277                         BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name);
278                 else if (from == GPU_VEC3)
279                         BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name);
280                 else if (from == GPU_VEC2)
281                         BLI_dynstr_appendf(ds, "%s.r", name);
282         }
283         else if (to == GPU_VEC2) {
284                 if (from == GPU_VEC4)
285                         BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name);
286                 else if (from == GPU_VEC3)
287                         BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name);
288                 else if (from == GPU_FLOAT)
289                         BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
290         }
291         else if (to == GPU_VEC3) {
292                 if (from == GPU_VEC4)
293                         BLI_dynstr_appendf(ds, "%s.rgb", name);
294                 else if (from == GPU_VEC2)
295                         BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name);
296                 else if (from == GPU_FLOAT)
297                         BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name);
298         }
299         else {
300                 if (from == GPU_VEC3)
301                         BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name);
302                 else if (from == GPU_VEC2)
303                         BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
304                 else if (from == GPU_FLOAT)
305                         BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
306         }
307 }
308
309 static void codegen_print_datatype(DynStr *ds, int type, float *data)
310 {
311         int i;
312
313         BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
314
315         for(i=0; i<type; i++) {
316                 BLI_dynstr_appendf(ds, "%f", data[i]);
317                 if(i == type-1)
318                         BLI_dynstr_append(ds, ")");
319                 else
320                         BLI_dynstr_append(ds, ", ");
321         }
322 }
323
324 static int codegen_input_has_texture(GPUInput *input)
325 {
326         if (input->link)
327                 return 0;
328         else if(input->ima)
329                 return 1;
330         else
331                 return input->tex != NULL;
332 }
333
334 const char *GPU_builtin_name(GPUBuiltin builtin)
335 {
336         if(builtin == GPU_VIEW_MATRIX)
337                 return "unfviewmat";
338         else if(builtin == GPU_OBJECT_MATRIX)
339                 return "unfobmat";
340         else if(builtin == GPU_INVERSE_VIEW_MATRIX)
341                 return "unfinvviewmat";
342         else if(builtin == GPU_INVERSE_OBJECT_MATRIX)
343                 return "unfinvobmat";
344         else if(builtin == GPU_VIEW_POSITION)
345                 return "varposition";
346         else if(builtin == GPU_VIEW_NORMAL)
347                 return "varnormal";
348         else if(builtin == GPU_OBCOLOR)
349                 return "unfobcolor";
350         else
351                 return "";
352 }
353
354 static void codegen_set_unique_ids(ListBase *nodes)
355 {
356         GHash *bindhash, *definehash;
357         GPUNode *node;
358         GPUInput *input;
359         GPUOutput *output;
360         int id = 1, texid = 0;
361
362         bindhash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "codegen_set_unique_ids1 gh");
363         definehash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "codegen_set_unique_ids2 gh");
364
365         for (node=nodes->first; node; node=node->next) {
366                 for (input=node->inputs.first; input; input=input->next) {
367                         /* set id for unique names of uniform variables */
368                         input->id = id++;
369                         input->bindtex = 0;
370                         input->definetex = 0;
371
372                         /* set texid used for settings texture slot with multitexture */
373                         if (codegen_input_has_texture(input) &&
374                                 ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL))) {
375                                 if (input->link) {
376                                         /* input is texture from buffer, assign only one texid per
377                                            buffer to avoid sampling the same texture twice */
378                                         if (!BLI_ghash_haskey(bindhash, input->link)) {
379                                                 input->texid = texid++;
380                                                 input->bindtex = 1;
381                                                 BLI_ghash_insert(bindhash, input->link, SET_INT_IN_POINTER(input->texid));
382                                         }
383                                         else
384                                                 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->link));
385                                 }
386                                 else if(input->ima) {
387                                         /* input is texture from image, assign only one texid per
388                                            buffer to avoid sampling the same texture twice */
389                                         if (!BLI_ghash_haskey(bindhash, input->ima)) {
390                                                 input->texid = texid++;
391                                                 input->bindtex = 1;
392                                                 BLI_ghash_insert(bindhash, input->ima, SET_INT_IN_POINTER(input->texid));
393                                         }
394                                         else
395                                                 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->ima));
396                                 }
397                                 else {
398                                         if (!BLI_ghash_haskey(bindhash, input->tex)) {
399                                                 /* input is user created texture, check tex pointer */
400                                                 input->texid = texid++;
401                                                 input->bindtex = 1;
402                                                 BLI_ghash_insert(bindhash, input->tex, SET_INT_IN_POINTER(input->texid));
403                                         }
404                                         else
405                                                 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->tex));
406                                 }
407
408                                 /* make sure this pixel is defined exactly once */
409                                 if (input->source == GPU_SOURCE_TEX_PIXEL) {
410                                         if(input->ima) {
411                                                 if (!BLI_ghash_haskey(definehash, input->ima)) {
412                                                         input->definetex = 1;
413                                                         BLI_ghash_insert(definehash, input->ima, SET_INT_IN_POINTER(input->texid));
414                                                 }
415                                         }
416                                         else {
417                                                 if (!BLI_ghash_haskey(definehash, input->link)) {
418                                                         input->definetex = 1;
419                                                         BLI_ghash_insert(definehash, input->link, SET_INT_IN_POINTER(input->texid));
420                                                 }
421                                         }
422                                 }
423                         }
424                 }
425
426                 for (output=node->outputs.first; output; output=output->next)
427                         /* set id for unique names of tmp variables storing output */
428                         output->id = id++;
429         }
430
431         BLI_ghash_free(bindhash, NULL, NULL);
432         BLI_ghash_free(definehash, NULL, NULL);
433 }
434
435 static void codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
436 {
437         GPUNode *node;
438         GPUInput *input;
439         const char *name;
440         int builtins = 0;
441
442         /* print uniforms */
443         for (node=nodes->first; node; node=node->next) {
444                 for (input=node->inputs.first; input; input=input->next) {
445                         if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
446                                 /* create exactly one sampler for each texture */
447                                 if (codegen_input_has_texture(input) && input->bindtex)
448                                         BLI_dynstr_appendf(ds, "uniform %s samp%d;\n",
449                                                 (input->textype == GPU_TEX2D)? "sampler2D": "sampler2DShadow",
450                                                 input->texid);
451                         }
452                         else if(input->source == GPU_SOURCE_BUILTIN) {
453                                 /* only define each builting uniform/varying once */
454                                 if(!(builtins & input->builtin)) {
455                                         builtins |= input->builtin;
456                                         name = GPU_builtin_name(input->builtin);
457
458                                         if(gpu_str_prefix(name, "unf")) {
459                                                 BLI_dynstr_appendf(ds, "uniform %s %s;\n",
460                                                         GPU_DATATYPE_STR[input->type], name);
461                                         }
462                                         else {
463                                                 BLI_dynstr_appendf(ds, "varying %s %s;\n",
464                                                         GPU_DATATYPE_STR[input->type], name);
465                                         }
466                                 }
467                         }
468                         else if (input->source == GPU_SOURCE_VEC_UNIFORM) {
469                                 if(input->dynamicvec) {
470                                         /* only create uniforms for dynamic vectors */
471                                         BLI_dynstr_appendf(ds, "uniform %s unf%d;\n",
472                                                 GPU_DATATYPE_STR[input->type], input->id);
473                                 }
474                                 else {
475                                         /* for others use const so the compiler can do folding */
476                                         BLI_dynstr_appendf(ds, "const %s cons%d = ",
477                                                 GPU_DATATYPE_STR[input->type], input->id);
478                                         codegen_print_datatype(ds, input->type, input->vec);
479                                         BLI_dynstr_append(ds, ";\n");
480                                 }
481                         }
482                         else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
483                                 BLI_dynstr_appendf(ds, "varying %s var%d;\n",
484                                         GPU_DATATYPE_STR[input->type], input->attribid);
485                         }
486                 }
487         }
488
489         BLI_dynstr_append(ds, "\n");
490 }
491
492 static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
493 {
494         GPUNode *node;
495         GPUInput *input;
496         GPUOutput *output;
497
498         for (node=nodes->first; node; node=node->next) {
499                 /* load pixels from textures */
500                 for (input=node->inputs.first; input; input=input->next) {
501                         if (input->source == GPU_SOURCE_TEX_PIXEL) {
502                                 if (codegen_input_has_texture(input) && input->definetex) {
503                                         BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
504                                         BLI_dynstr_appendf(ds, "samp%d, gl_TexCoord[%d].st);\n",
505                                                 input->texid, input->texid);
506                                 }
507                         }
508                 }
509
510                 /* declare temporary variables for node output storage */
511                 for (output=node->outputs.first; output; output=output->next)
512                         BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
513                                 GPU_DATATYPE_STR[output->type], output->id);
514         }
515
516         BLI_dynstr_append(ds, "\n");
517 }
518
519 static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *finaloutput)
520 {
521         GPUNode *node;
522         GPUInput *input;
523         GPUOutput *output;
524
525         for (node=nodes->first; node; node=node->next) {
526                 BLI_dynstr_appendf(ds, "\t%s(", node->name);
527                 
528                 for (input=node->inputs.first; input; input=input->next) {
529                         if (input->source == GPU_SOURCE_TEX) {
530                                 BLI_dynstr_appendf(ds, "samp%d", input->texid);
531                                 if (input->link)
532                                         BLI_dynstr_appendf(ds, ", gl_TexCoord[%d].st", input->texid);
533                         }
534                         else if (input->source == GPU_SOURCE_TEX_PIXEL) {
535                                 if (input->link && input->link->output)
536                                         codegen_convert_datatype(ds, input->link->output->type, input->type,
537                                                 "tmp", input->link->output->id);
538                                 else
539                                         codegen_convert_datatype(ds, input->link->output->type, input->type,
540                                                 "tex", input->texid);
541                         }
542                         else if(input->source == GPU_SOURCE_BUILTIN)
543                                 BLI_dynstr_appendf(ds, "%s", GPU_builtin_name(input->builtin));
544                         else if(input->source == GPU_SOURCE_VEC_UNIFORM) {
545                                 if(input->dynamicvec)
546                                         BLI_dynstr_appendf(ds, "unf%d", input->id);
547                                 else
548                                         BLI_dynstr_appendf(ds, "cons%d", input->id);
549                         }
550                         else if (input->source == GPU_SOURCE_ATTRIB)
551                                 BLI_dynstr_appendf(ds, "var%d", input->attribid);
552
553                         BLI_dynstr_append(ds, ", ");
554                 }
555
556                 for (output=node->outputs.first; output; output=output->next) {
557                         BLI_dynstr_appendf(ds, "tmp%d", output->id);
558                         if (output->next)
559                                 BLI_dynstr_append(ds, ", ");
560                 }
561
562                 BLI_dynstr_append(ds, ");\n");
563         }
564
565         BLI_dynstr_append(ds, "\n\tgl_FragColor = ");
566         codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id);
567         BLI_dynstr_append(ds, ";\n");
568 }
569
570 static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const char *UNUSED(name))
571 {
572         DynStr *ds = BLI_dynstr_new();
573         char *code;
574
575         /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/
576
577         codegen_set_unique_ids(nodes);
578         codegen_print_uniforms_functions(ds, nodes);
579
580         //if(G.f & G_DEBUG)
581         //      BLI_dynstr_appendf(ds, "/* %s */\n", name);
582
583         BLI_dynstr_append(ds, "void main(void)\n");
584         BLI_dynstr_append(ds, "{\n");
585
586         codegen_declare_tmps(ds, nodes);
587         codegen_call_functions(ds, nodes, output);
588
589         BLI_dynstr_append(ds, "}\n");
590
591         /* create shader */
592         code = BLI_dynstr_get_cstring(ds);
593         BLI_dynstr_free(ds);
594
595         //if(G.f & G_DEBUG) printf("%s\n", code);
596
597         return code;
598 }
599
600 static char *code_generate_vertex(ListBase *nodes)
601 {
602         DynStr *ds = BLI_dynstr_new();
603         GPUNode *node;
604         GPUInput *input;
605         char *code;
606         
607         for (node=nodes->first; node; node=node->next) {
608                 for (input=node->inputs.first; input; input=input->next) {
609                         if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
610                                 BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
611                                         GPU_DATATYPE_STR[input->type], input->attribid);
612                                 BLI_dynstr_appendf(ds, "varying %s var%d;\n",
613                                         GPU_DATATYPE_STR[input->type], input->attribid);
614                         }
615                 }
616         }
617
618         BLI_dynstr_append(ds, "\n");
619         BLI_dynstr_append(ds, datatoc_gpu_shader_vertex_glsl);
620
621         for (node=nodes->first; node; node=node->next)
622                 for (input=node->inputs.first; input; input=input->next)
623                         if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
624                                 if(input->attribtype == CD_TANGENT) /* silly exception */
625                                 {
626                                         BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize((gl_ModelViewMatrix * vec4(att%d.xyz, 0)).xyz);\n", input->attribid, input->attribid);
627                                         BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid);
628                                 }
629                                 else
630                                         BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
631                         }
632
633         BLI_dynstr_append(ds, "}\n\n");
634
635         code = BLI_dynstr_get_cstring(ds);
636
637         BLI_dynstr_free(ds);
638
639         //if(G.f & G_DEBUG) printf("%s\n", code);
640
641         return code;
642 }
643
644 /* GPU pass binding/unbinding */
645
646 GPUShader *GPU_pass_shader(GPUPass *pass)
647 {
648         return pass->shader;
649 }
650
651 static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
652 {
653         GPUShader *shader = pass->shader;
654         GPUNode *node;
655         GPUInput *next, *input;
656         ListBase *inputs = &pass->inputs;
657         int extract, z;
658
659         memset(inputs, 0, sizeof(*inputs));
660
661         if(!shader)
662                 return;
663
664         GPU_shader_bind(shader);
665
666         for (node=nodes->first; node; node=node->next) {
667                 z = 0;
668                 for (input=node->inputs.first; input; input=next, z++) {
669                         next = input->next;
670
671                         /* attributes don't need to be bound, they already have
672                          * an id that the drawing functions will use */
673                         if(input->source == GPU_SOURCE_ATTRIB ||
674                            input->source == GPU_SOURCE_BUILTIN)
675                                 continue;
676
677                         if (input->ima || input->tex)
678                                 BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid);
679                         else
680                                 BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id);
681
682                         /* pass non-dynamic uniforms to opengl */
683                         extract = 0;
684
685                         if(input->ima || input->tex) {
686                                 if (input->bindtex)
687                                         extract = 1;
688                         }
689                         else if(input->dynamicvec)
690                                 extract = 1;
691
692                         if(extract)
693                                 input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
694
695                         /* extract nodes */
696                         if(extract) {
697                                 BLI_remlink(&node->inputs, input);
698                                 BLI_addtail(inputs, input);
699                         }
700                 }
701         }
702
703         GPU_shader_unbind(shader);
704 }
705
706 void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
707 {
708         GPUInput *input;
709         GPUShader *shader = pass->shader;
710         ListBase *inputs = &pass->inputs;
711
712         if (!shader)
713                 return;
714
715         GPU_shader_bind(shader);
716
717         /* now bind the textures */
718         for (input=inputs->first; input; input=input->next) {
719                 if (input->ima)
720                         input->tex = GPU_texture_from_blender(input->ima, input->iuser, time, mipmap);
721
722                 if(input->tex && input->bindtex) {
723                         GPU_texture_bind(input->tex, input->texid);
724                         GPU_shader_uniform_texture(shader, input->shaderloc, input->tex);
725                 }
726         }
727 }
728
729 void GPU_pass_update_uniforms(GPUPass *pass)
730 {
731         GPUInput *input;
732         GPUShader *shader = pass->shader;
733         ListBase *inputs = &pass->inputs;
734
735         if (!shader)
736                 return;
737
738         /* pass dynamic inputs to opengl, others were removed */
739         for (input=inputs->first; input; input=input->next)
740                 if(!(input->ima || input->tex))
741                         GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1,
742                                 input->dynamicvec);
743 }
744
745 void GPU_pass_unbind(GPUPass *pass)
746 {
747         GPUInput *input;
748         GPUShader *shader = pass->shader;
749         ListBase *inputs = &pass->inputs;
750
751         if (!shader)
752                 return;
753
754         for (input=inputs->first; input; input=input->next) {
755                 if(input->tex && input->bindtex)
756                         GPU_texture_unbind(input->tex);
757
758                 if (input->ima)
759                         input->tex = NULL;
760         }
761         
762         GPU_shader_unbind(shader);
763 }
764
765 /* Node Link Functions */
766
767 static GPUNodeLink *GPU_node_link_create(int type)
768 {
769         GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink");
770         link->type = type;
771         link->users++;
772
773         return link;
774 }
775
776 static void GPU_node_link_free(GPUNodeLink *link)
777 {
778         link->users--;
779
780         if (link->users < 0)
781                 fprintf(stderr, "GPU_node_link_free: negative refcount\n");
782         
783         if (link->users == 0) {
784                 if (link->output)
785                         link->output->link = NULL;
786                 MEM_freeN(link);
787         }
788 }
789
790 /* Node Functions */
791
792 static GPUNode *GPU_node_begin(const char *name)
793 {
794         GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode");
795
796         node->name= name;
797
798         return node;
799 }
800
801 static void GPU_node_end(GPUNode *UNUSED(node))
802 {
803         /* empty */
804 }
805
806 static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type)
807 {
808         GPUInput *input;
809         GPUNode *outnode;
810         const char *name;
811
812         if(link->output) {
813                 outnode = link->output->node;
814                 name = outnode->name;
815
816                 if(strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) {
817                         input = MEM_dupallocN(outnode->inputs.first);
818                         input->type = type;
819                         if(input->link)
820                                 input->link->users++;
821                         BLI_addtail(&node->inputs, input);
822                         return;
823                 }
824         }
825         
826         input = MEM_callocN(sizeof(GPUInput), "GPUInput");
827         input->node = node;
828
829         if(link->builtin) {
830                 /* builtin uniform */
831                 input->type = type;
832                 input->source = GPU_SOURCE_BUILTIN;
833                 input->builtin = link->builtin;
834
835                 MEM_freeN(link);
836         }
837         else if(link->output) {
838                 /* link to a node output */
839                 input->type = type;
840                 input->source = GPU_SOURCE_TEX_PIXEL;
841                 input->link = link;
842                 link->users++;
843         }
844         else if(link->dynamictex) {
845                 /* dynamic texture, GPUTexture is updated/deleted externally */
846                 input->type = type;
847                 input->source = GPU_SOURCE_TEX;
848
849                 input->tex = link->dynamictex;
850                 input->textarget = GL_TEXTURE_2D;
851                 input->textype = type;
852                 input->dynamictex = 1;
853                 input->dynamicdata = link->ptr2;
854                 MEM_freeN(link);
855         }
856         else if(link->texture) {
857                 /* small texture created on the fly, like for colorbands */
858                 input->type = GPU_VEC4;
859                 input->source = GPU_SOURCE_TEX;
860                 input->textype = type;
861
862                 //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL);
863                 input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL);
864                 input->textarget = GL_TEXTURE_2D;
865
866                 MEM_freeN(link->ptr1);
867                 MEM_freeN(link);
868         }
869         else if(link->image) {
870                 /* blender image */
871                 input->type = GPU_VEC4;
872                 input->source = GPU_SOURCE_TEX;
873
874                 input->ima = link->ptr1;
875                 input->iuser = link->ptr2;
876                 input->textarget = GL_TEXTURE_2D;
877                 input->textype = GPU_TEX2D;
878                 MEM_freeN(link);
879         }
880         else if(link->attribtype) {
881                 /* vertex attribute */
882                 input->type = type;
883                 input->source = GPU_SOURCE_ATTRIB;
884
885                 input->attribtype = link->attribtype;
886                 BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname));
887                 MEM_freeN(link);
888         }
889         else {
890                 /* uniform vector */
891                 input->type = type;
892                 input->source = GPU_SOURCE_VEC_UNIFORM;
893
894                 memcpy(input->vec, link->ptr1, type*sizeof(float));
895                 if(link->dynamic) {
896                         input->dynamicvec= link->ptr1;
897                         input->dynamictype= link->dynamictype;
898                         input->dynamicdata= link->ptr2;
899                 }
900                 MEM_freeN(link);
901         }
902
903         BLI_addtail(&node->inputs, input);
904 }
905
906 static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock)
907 {
908         GPUNodeLink *link;
909
910         if(sock->link) {
911                 gpu_node_input_link(node, sock->link, sock->type);
912         }
913         else {
914                 link = GPU_node_link_create(0);
915                 link->ptr1 = sock->vec;
916                 gpu_node_input_link(node, link, sock->type);
917         }
918 }
919
920 static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), GPUNodeLink **link)
921 {
922         GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput");
923
924         output->type = type;
925         output->node = node;
926
927         if (link) {
928                 *link = output->link = GPU_node_link_create(type);
929                 output->link->output = output;
930
931                 /* note: the caller owns the reference to the linkfer, GPUOutput
932                    merely points to it, and if the node is destroyed it will
933                    set that pointer to NULL */
934         }
935
936         BLI_addtail(&node->outputs, output);
937 }
938
939 static void GPU_inputs_free(ListBase *inputs)
940 {
941         GPUInput *input;
942
943         for(input=inputs->first; input; input=input->next) {
944                 if(input->link)
945                         GPU_node_link_free(input->link);
946                 else if(input->tex && !input->dynamictex)
947                         GPU_texture_free(input->tex);
948         }
949
950         BLI_freelistN(inputs);
951 }
952
953 static void GPU_node_free(GPUNode *node)
954 {
955         GPUOutput *output;
956
957         GPU_inputs_free(&node->inputs);
958
959         for (output=node->outputs.first; output; output=output->next)
960                 if (output->link) {
961                         output->link->output = NULL;
962                         GPU_node_link_free(output->link);
963                 }
964
965         BLI_freelistN(&node->outputs);
966         MEM_freeN(node);
967 }
968
969 static void GPU_nodes_free(ListBase *nodes)
970 {
971         GPUNode *node;
972
973         while (nodes->first) {
974                 node = nodes->first;
975                 BLI_remlink(nodes, node);
976                 GPU_node_free(node);
977         }
978 }
979
980 /* vertex attributes */
981
982 static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs)
983 {
984         GPUNode *node;
985         GPUInput *input;
986         int a;
987
988         /* convert attributes requested by node inputs to an array of layers,
989          * checking for duplicates and assigning id's starting from zero. */
990
991         memset(attribs, 0, sizeof(*attribs));
992
993         for(node=nodes->first; node; node=node->next) {
994                 for(input=node->inputs.first; input; input=input->next) {
995                         if(input->source == GPU_SOURCE_ATTRIB) {
996                                 for(a=0; a<attribs->totlayer; a++) {
997                                         if(attribs->layer[a].type == input->attribtype &&
998                                                 strcmp(attribs->layer[a].name, input->attribname) == 0)
999                                                 break;
1000                                 }
1001
1002                                 if(a == attribs->totlayer && a < GPU_MAX_ATTRIB) {
1003                                         input->attribid = attribs->totlayer++;
1004                                         input->attribfirst = 1;
1005
1006                                         attribs->layer[a].type = input->attribtype;
1007                                         attribs->layer[a].attribid = input->attribid;
1008                                         BLI_strncpy(attribs->layer[a].name, input->attribname,
1009                                                 sizeof(attribs->layer[a].name));
1010                                 }
1011                                 else
1012                                         input->attribid = attribs->layer[a].attribid;
1013                         }
1014                 }
1015         }
1016 }
1017
1018 static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
1019 {
1020         GPUNode *node;
1021         GPUInput *input;
1022         
1023         *builtin= 0;
1024
1025         for(node=nodes->first; node; node=node->next)
1026                 for(input=node->inputs.first; input; input=input->next)
1027                         if(input->source == GPU_SOURCE_BUILTIN)
1028                                 *builtin |= input->builtin;
1029 }
1030
1031 /* varargs linking  */
1032
1033 GPUNodeLink *GPU_attribute(int type, const char *name)
1034 {
1035         GPUNodeLink *link = GPU_node_link_create(0);
1036
1037         link->attribtype= type;
1038         link->attribname= name;
1039
1040         return link;
1041 }
1042
1043 GPUNodeLink *GPU_uniform(float *num)
1044 {
1045         GPUNodeLink *link = GPU_node_link_create(0);
1046
1047         link->ptr1= num;
1048         link->ptr2= NULL;
1049
1050         return link;
1051 }
1052
1053 GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data)
1054 {
1055         GPUNodeLink *link = GPU_node_link_create(0);
1056
1057         link->ptr1= num;
1058         link->ptr2= data;
1059         link->dynamic= 1;
1060         link->dynamictype = dynamictype;
1061
1062
1063         return link;
1064 }
1065
1066 GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser)
1067 {
1068         GPUNodeLink *link = GPU_node_link_create(0);
1069
1070         link->image= 1;
1071         link->ptr1= ima;
1072         link->ptr2= iuser;
1073
1074         return link;
1075 }
1076
1077 GPUNodeLink *GPU_texture(int size, float *pixels)
1078 {
1079         GPUNodeLink *link = GPU_node_link_create(0);
1080
1081         link->texture = 1;
1082         link->texturesize = size;
1083         link->ptr1= pixels;
1084
1085         return link;
1086 }
1087
1088 GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data)
1089 {
1090         GPUNodeLink *link = GPU_node_link_create(0);
1091
1092         link->dynamic = 1;
1093         link->dynamictex = tex;
1094         link->dynamictype = dynamictype;
1095         link->ptr2 = data;
1096
1097         return link;
1098 }
1099
1100 GPUNodeLink *GPU_socket(GPUNodeStack *sock)
1101 {
1102         GPUNodeLink *link = GPU_node_link_create(0);
1103
1104         link->socket= sock;
1105
1106         return link;
1107 }
1108
1109 GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
1110 {
1111         GPUNodeLink *link = GPU_node_link_create(0);
1112
1113         link->builtin= builtin;
1114
1115         return link;
1116 }
1117
1118 int GPU_link(GPUMaterial *mat, const char *name, ...)
1119 {
1120         GPUNode *node;
1121         GPUFunction *function;
1122         GPUNodeLink *link, **linkptr;
1123         va_list params;
1124         int i;
1125
1126         function = GPU_lookup_function(name);
1127         if(!function) {
1128                 fprintf(stderr, "GPU failed to find function %s\n", name);
1129                 return 0;
1130         }
1131
1132         node = GPU_node_begin(name);
1133
1134         va_start(params, name);
1135         for(i=0; i<function->totparam; i++) {
1136                 if(function->paramqual[i] != FUNCTION_QUAL_IN) {
1137                         linkptr= va_arg(params, GPUNodeLink**);
1138                         GPU_node_output(node, function->paramtype[i], "", linkptr);
1139                 }
1140                 else {
1141                         link= va_arg(params, GPUNodeLink*);
1142                         gpu_node_input_link(node, link, function->paramtype[i]);
1143                 }
1144         }
1145         va_end(params);
1146
1147         GPU_node_end(node);
1148
1149         gpu_material_add_node(mat, node);
1150
1151         return 1;
1152 }
1153
1154 int GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...)
1155 {
1156         GPUNode *node;
1157         GPUFunction *function;
1158         GPUNodeLink *link, **linkptr;
1159         va_list params;
1160         int i, totin, totout;
1161
1162         function = GPU_lookup_function(name);
1163         if(!function) {
1164                 fprintf(stderr, "GPU failed to find function %s\n", name);
1165                 return 0;
1166         }
1167
1168         node = GPU_node_begin(name);
1169         totin = 0;
1170         totout = 0;
1171
1172         if(in) {
1173                 for(i = 0; in[i].type != GPU_NONE; i++) {
1174                         gpu_node_input_socket(node, &in[i]);
1175                         totin++;
1176                 }
1177         }
1178         
1179         if(out) {
1180                 for(i = 0; out[i].type != GPU_NONE; i++) {
1181                         GPU_node_output(node, out[i].type, out[i].name, &out[i].link);
1182                         totout++;
1183                 }
1184         }
1185
1186         va_start(params, out);
1187         for(i=0; i<function->totparam; i++) {
1188                 if(function->paramqual[i] != FUNCTION_QUAL_IN) {
1189                         if(totout == 0) {
1190                                 linkptr= va_arg(params, GPUNodeLink**);
1191                                 GPU_node_output(node, function->paramtype[i], "", linkptr);
1192                         }
1193                         else
1194                                 totout--;
1195                 }
1196                 else {
1197                         if(totin == 0) {
1198                                 link= va_arg(params, GPUNodeLink*);
1199                                 if(link->socket)
1200                                         gpu_node_input_socket(node, link->socket);
1201                                 else
1202                                         gpu_node_input_link(node, link, function->paramtype[i]);
1203                         }
1204                         else
1205                                 totin--;
1206                 }
1207         }
1208         va_end(params);
1209
1210         GPU_node_end(node);
1211
1212         gpu_material_add_node(mat, node);
1213         
1214         return 1;
1215 }
1216
1217 int GPU_stack_link_mute(GPUMaterial *mat, const char *name, LinkInOutsMuteNode *mlnk)
1218 {
1219         GPUNode *node;
1220         GPUFunction *function;
1221         int i;
1222
1223         function = GPU_lookup_function(name);
1224         if(!function) {
1225                 fprintf(stderr, "GPU failed to find function %s\n", name);
1226                 return 0;
1227         }
1228
1229         for(i = 0; i < mlnk->num_outs; i++) {
1230                 node = GPU_node_begin(name);
1231                 gpu_node_input_socket(node, (GPUNodeStack*)mlnk->in);
1232                 GPU_node_output(node, ((GPUNodeStack*)mlnk->outs+i)->type, ((GPUNodeStack*)mlnk->outs+i)->name,
1233                                 &((GPUNodeStack*)mlnk->outs+i)->link);
1234                 GPU_node_end(node);
1235
1236                 gpu_material_add_node(mat, node);
1237         }
1238
1239         return 1;
1240 }
1241
1242 int GPU_link_changed(GPUNodeLink *link)
1243 {
1244         GPUNode *node;
1245         GPUInput *input;
1246         const char *name;
1247
1248         if(link->output) {
1249                 node = link->output->node;
1250                 name = node->name;
1251
1252                 if(strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) {
1253                         input = node->inputs.first;
1254                         return (input->link != NULL);
1255                 }
1256
1257                 return 1;
1258         }
1259         else
1260                 return 0;
1261 }
1262
1263 /* Pass create/free */
1264
1265 static void gpu_nodes_tag(GPUNodeLink *link)
1266 {
1267         GPUNode *node;
1268         GPUInput *input;
1269
1270         if(!link->output)
1271                 return;
1272
1273         node = link->output->node;
1274         if(node->tag)
1275                 return;
1276         
1277         node->tag= 1;
1278         for(input=node->inputs.first; input; input=input->next)
1279                 if(input->link)
1280                         gpu_nodes_tag(input->link);
1281 }
1282
1283 static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
1284 {
1285         GPUNode *node, *next;
1286
1287         for(node=nodes->first; node; node=node->next)
1288                 node->tag= 0;
1289
1290         gpu_nodes_tag(outlink);
1291
1292         for(node=nodes->first; node; node=next) {
1293                 next = node->next;
1294
1295                 if(!node->tag) {
1296                         BLI_remlink(nodes, node);
1297                         GPU_node_free(node);
1298                 }
1299         }
1300 }
1301
1302 GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, const char *name)
1303 {
1304         GPUShader *shader;
1305         GPUPass *pass;
1306         char *vertexcode, *fragmentcode;
1307
1308         /*if(!FUNCTION_LIB) {
1309                 GPU_nodes_free(nodes);
1310                 return NULL;
1311         }*/
1312
1313         /* prune unused nodes */
1314         gpu_nodes_prune(nodes, outlink);
1315
1316         gpu_nodes_get_vertex_attributes(nodes, attribs);
1317         gpu_nodes_get_builtin_flag(nodes, builtins);
1318
1319         /* generate code and compile with opengl */
1320         fragmentcode = code_generate_fragment(nodes, outlink->output, name);
1321         vertexcode = code_generate_vertex(nodes);
1322         shader = GPU_shader_create(vertexcode, fragmentcode, datatoc_gpu_shader_material_glsl); /*FUNCTION_LIB);*/
1323
1324         /* failed? */
1325         if (!shader) {
1326                 memset(attribs, 0, sizeof(*attribs));
1327                 memset(builtins, 0, sizeof(*builtins));
1328                 GPU_nodes_free(nodes);
1329                 return NULL;
1330         }
1331         
1332         /* create pass */
1333         pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
1334
1335         pass->output = outlink->output;
1336         pass->shader = shader;
1337         pass->fragmentcode = fragmentcode;
1338         pass->vertexcode = vertexcode;
1339         pass->libcode = datatoc_gpu_shader_material_glsl;
1340
1341         /* extract dynamic inputs and throw away nodes */
1342         GPU_nodes_extract_dynamic_inputs(pass, nodes);
1343         GPU_nodes_free(nodes);
1344
1345         return pass;
1346 }
1347
1348 void GPU_pass_free(GPUPass *pass)
1349 {
1350         GPU_shader_free(pass->shader);
1351         GPU_inputs_free(&pass->inputs);
1352         if (pass->fragmentcode)
1353                 MEM_freeN(pass->fragmentcode);
1354         if (pass->vertexcode)
1355                 MEM_freeN(pass->vertexcode);
1356         MEM_freeN(pass);
1357 }
1358