libc3: Update
[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 simavr.
7
8         simavr 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         simavr 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 simavr.  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 {
36         c3program_p p = malloc(sizeof(*p));
37         memset(p, 0, sizeof(*p));
38         p->name = str_new(name);
39         return p;
40 }
41
42 void
43 c3program_dispose(
44                 c3program_p p)
45 {
46         c3program_purge(p);
47         for (int pi = 0; pi < p->params.count; pi++) {
48                 c3program_param_p pa = &p->params.e[pi];
49                 str_free(pa->name);
50         }
51         c3program_param_array_free(&p->params);
52         str_free(p->name);
53         str_free(p->log);
54         free(p);
55 }
56
57 void
58 c3program_purge(
59                 c3program_p p)
60 {
61         for (int si = 0; si < p->shaders.count; si++) {
62                 c3shader_p s = &p->shaders.e[si];
63                 str_free(s->name);
64                 str_free(s->shader);
65         }
66         c3shader_array_free(&p->shaders);
67 }
68
69 int
70 c3program_load_shader(
71                 c3program_p p,
72                 uint32_t        type,
73                 const char * header,
74                 const char * filename,
75                 uint16_t flags)
76 {
77         struct stat st;
78         str_p pgm = NULL;
79
80         if (stat(filename, &st))
81                 goto error;
82         int fd = open(filename, O_RDONLY);
83         if (fd == -1)
84                 goto error;
85
86         int hlen = header ? strlen(header) : 0;
87         pgm = str_alloc(st.st_size + hlen);
88         if (header)
89                 strcpy(pgm->str, header);
90
91         if (read(fd, pgm->str + hlen, st.st_size) != st.st_size)
92                 goto error;
93         close(fd);
94         pgm->str[pgm->len] = 0; // zero terminate it
95
96         c3shader_t s = {
97                 .type = type,
98                 .name = str_new(filename),
99                 .shader = pgm,
100         };
101         c3shader_array_add(&p->shaders, s);
102
103         if (flags & C3_PROGRAM_LOAD_UNIFORM) {
104                 char * cur = pgm->str;
105                 char * l;
106
107                 while ((l = strsep(&cur, "\r\n")) != NULL) {
108                         while (*l && *l <= ' ')
109                                 l++;
110                         str_p line = str_new(l);
111                         if (cur) // fix the endline after strsep
112                                 *(cur-1) = '\n';
113                         if (strncmp(line->str, "uniform", 7))
114                                 continue;
115                         // printf("UNI: %s\n", line->str);
116
117                         char * sep = line->str;
118                         char * uniform = strsep(&sep, " \t");
119                         char * unitype = strsep(&sep, " \t");
120                         char * uniname = strsep(&sep, " \t");
121                         /*
122                          * found a parameter, extract it's type & name
123                          */
124                         if (uniform && unitype && uniname) {
125                                 // trim semicolons etc
126                                 char *cl = uniname;
127                                 while (isalpha(*cl) || *cl == '_')
128                                         cl++;
129                                 *cl = 0;
130                                 str_p name = str_new(uniname);
131                                 for (int pi = 0; pi < p->params.count && uniform; pi++)
132                                         if (!str_cmp(name, p->params.e[pi].name))
133                                                 uniform = NULL; // already there
134                                 if (uniform) {
135                                         c3program_param_t pa = {
136                                                         .type = str_new(unitype),
137                                                         .name = name,
138                                                         .program = p,
139                                         };
140                                         c3program_param_array_add(&p->params, pa);
141                                         printf("%s %s: new parameter '%s' '%s'\n", __func__,
142                                                         p->name->str, unitype, uniname);
143                                 } else
144                                         str_free(name);
145                         }
146                         str_free(line);
147                 }
148         }
149         return p->shaders.count - 1;
150
151 error:
152         if (fd != -1)
153                 close(fd);
154         if (pgm)
155                 str_free(pgm);
156         fprintf(stderr, "%s: %s: %s\n", __func__, filename, strerror(errno));
157         return -1;
158
159 }