c3program: can specify uniform order
[simavr] / examples / shared / libc3 / src / c3program.c
1 /*
2         c3program.c
3
4         Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
5
6         This file is part of libc3.
7
8         libc3 is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         libc3 is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with libc3.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <fcntl.h>
29
30 #include "c3program.h"
31
32 c3program_p
33 c3program_new(
34                 const char * name,
35                 const char ** uniforms )
36 {
37         c3program_p p = malloc(sizeof(*p));
38         memset(p, 0, sizeof(*p));
39         p->name = str_new(name);
40
41         /* Allow specifying uniform names to make sure they are in
42          * the specified order in the array, this allow direct indexing
43          * instead of doign string lookup
44          */
45         if (uniforms) {
46                 for (int ui = 0; uniforms[ui]; ui++) {
47                         c3program_param_t pa = {
48                                 .name = str_new(uniforms[ui]),
49                                 .program = p,
50                                 .index = p->params.count,
51                         };
52                         c3program_param_array_add(&p->params, pa);
53                 }
54         }
55         return p;
56 }
57
58 void
59 c3program_dispose(
60                 c3program_p p)
61 {
62         c3program_purge(p);
63         for (int pi = 0; pi < p->params.count; pi++) {
64                 c3program_param_p pa = &p->params.e[pi];
65                 str_free(pa->name);
66         }
67         c3program_param_array_free(&p->params);
68         str_free(p->name);
69         str_free(p->log);
70         free(p);
71 }
72
73 void
74 c3program_purge(
75                 c3program_p p)
76 {
77         for (int si = 0; si < p->shaders.count; si++) {
78                 c3shader_p s = &p->shaders.e[si];
79                 str_free(s->name);
80                 str_free(s->shader);
81         }
82         c3shader_array_free(&p->shaders);
83 }
84
85 c3program_param_p
86 c3program_locate_param(
87                 c3program_p p,
88                 const char * name )
89 {
90         for (int pi = 0; pi < p->params.count; pi++)
91                 if (!strcmp(p->params.e[pi].name->str, name))
92                         return &p->params.e[pi];
93         return NULL;
94 }
95
96 int
97 c3program_load_shader(
98                 c3program_p p,
99                 uint32_t        type,
100                 const char * header,
101                 const char * filename,
102                 uint16_t flags)
103 {
104         struct stat st;
105         str_p pgm = NULL;
106
107         if (stat(filename, &st))
108                 goto error;
109         int fd = open(filename, O_RDONLY);
110         if (fd == -1)
111                 goto error;
112
113         int hlen = header ? strlen(header) : 0;
114         pgm = str_alloc(st.st_size + hlen);
115         if (header)
116                 strcpy(pgm->str, header);
117
118         if (read(fd, pgm->str + hlen, st.st_size) != st.st_size)
119                 goto error;
120         close(fd);
121         pgm->str[pgm->len] = 0; // zero terminate it
122
123         c3shader_t s = {
124                 .type = type,
125                 .name = str_new(filename),
126                 .shader = pgm,
127         };
128         c3shader_array_add(&p->shaders, s);
129
130         if (flags & C3_PROGRAM_LOAD_UNIFORM) {
131                 char * cur = pgm->str;
132                 char * l;
133
134                 while ((l = strsep(&cur, "\r\n")) != NULL) {
135                         while (*l && *l <= ' ')
136                                 l++;
137                         str_p line = str_new(l);
138                         if (cur) // fix the endline after strsep
139                                 *(cur-1) = '\n';
140                         if (strncmp(line->str, "uniform", 7))
141                                 continue;
142                         // printf("UNI: %s\n", line->str);
143
144                         char * sep = line->str;
145                         char * uniform = strsep(&sep, " \t");
146                         char * unitype = strsep(&sep, " \t");
147                         char * uniname = strsep(&sep, " \t");
148                         /*
149                          * found a parameter, extract it's type & name
150                          */
151                         if (uniform && unitype && uniname) {
152                                 // trim semicolons etc
153                                 char *cl = uniname;
154                                 while (isalpha(*cl) || *cl == '_')
155                                         cl++;
156                                 *cl = 0;
157                                 str_p name = str_new(uniname);
158                                 for (int pi = 0; pi < p->params.count && uniform; pi++)
159                                         if (!str_cmp(name, p->params.e[pi].name)) {
160                                                 if (!p->params.e[pi].type)
161                                                         p->params.e[pi].type = str_new(unitype);
162                                                 uniform = NULL; // already there
163                                         }
164                                 if (uniform) {
165                                         c3program_param_t pa = {
166                                                         .type = str_new(unitype),
167                                                         .name = name,
168                                                         .program = p,
169                                                         .index = p->params.count,
170                                         };
171                                         c3program_param_array_add(&p->params, pa);
172                                         if (p->verbose)
173                                                 printf("%s %s: new parameter '%s' '%s'\n", __func__,
174                                                         p->name->str, unitype, uniname);
175                                 } else
176                                         str_free(name);
177                         }
178                         str_free(line);
179                 }
180         }
181         return p->shaders.count - 1;
182
183 error:
184         if (fd != -1)
185                 close(fd);
186         if (pgm)
187                 str_free(pgm);
188         fprintf(stderr, "%s: %s: %s\n", __func__, filename, strerror(errno));
189         return -1;
190
191 }