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