initial commit
[liquidmodel] / src / assman.c
1 #include <string.h>
2 #include "opengl.h"
3 #include "assman.h"
4 #include "sdr.h"
5 #include "imago2.h"
6 #include "assfile.h"
7 #include "rbtree.h"
8 #include "util.h"
9
10 struct asset {
11         int type;
12         char *name;
13         unsigned int id;
14 };
15
16 static struct rbtree *rb;
17
18 static size_t io_read(void *buf, size_t bytes, void *uptr);
19 static long io_seek(long offs, int whence, void *uptr);
20 static void del_rbnode(struct rbnode *rb, void *cls);
21
22 int init_assman(void)
23 {
24         if(!(rb = rb_create(RB_KEY_STRING))) {
25                 return -1;
26         }
27         rb_set_delete_func(rb, del_rbnode, 0);
28         return 0;
29 }
30
31 void destroy_assman(void)
32 {
33         rb_free(rb);
34         rb = 0;
35 }
36
37 unsigned int get_tex2d(const char *fname)
38 {
39         unsigned int id;
40         struct img_pixmap pixmap;
41         struct img_io io;
42
43         if((id = lookup_asset(fname))) {
44                 return id;
45         }
46
47         if(!(io.uptr = ass_fopen(fname, "rb"))) {
48                 fprintf(stderr, "failed to open image: %s\n", fname);
49                 return 0;
50         }
51         io.read = io_read;
52         io.write = 0;
53         io.seek = io_seek;
54
55         img_init(&pixmap);
56         if(img_read(&pixmap, &io) == -1) {
57                 fprintf(stderr, "failed to read image file: %s\n", fname);
58                 ass_fclose(io.uptr);
59                 return 0;
60         }
61         ass_fclose(io.uptr);
62
63         if(!(id = img_gltexture(&pixmap))) {
64                 fprintf(stderr, "failed to create OpenGL texture from: %s\n", fname);
65         }
66         img_destroy(&pixmap);
67
68         if(id) {
69                 printf("loaded 2D texture: %s\n", fname);
70                 add_asset(fname, ASS_TEX, id);
71         }
72         return id;
73 }
74
75 unsigned int get_texcube(const char *fname)
76 {
77         return 0;       /* TODO */
78 }
79
80 static unsigned int load_sdr(const char *fname, unsigned int type)
81 {
82         unsigned int sdr;
83         long sz;
84         char *buf;
85         struct assfile *fp;
86
87         if(!(fp = ass_fopen(fname, "rb"))) {
88                 fprintf(stderr, "failed to load vertex shader: %s\n", fname);
89                 return 0;
90         }
91         ass_fseek(fp, 0, SEEK_END);
92         sz = ass_ftell(fp);
93         ass_fseek(fp, 0, SEEK_SET);
94
95         buf = malloc_nf(sz + 1);
96         if(ass_fread(buf, 1, sz, fp) < sz) {
97                 fprintf(stderr, "failed to read vertex shader: %s\n", fname);
98                 free(buf);
99                 ass_fclose(fp);
100                 return 0;
101         }
102         buf[sz] = 0;
103         ass_fclose(fp);
104
105         switch(type) {
106         case GL_VERTEX_SHADER:
107                 printf("vertex shader %s ", fname);
108                 fflush(stdout);
109                 sdr = create_vertex_shader(buf);
110                 break;
111
112         case GL_FRAGMENT_SHADER:
113                 printf("pixel shader %s ", fname);
114                 fflush(stdout);
115                 sdr = create_pixel_shader(buf);
116                 break;
117
118         default:
119                 fprintf(stderr, "unknown shader type (%d) %s\n", type, fname);
120                 return 0;
121         }
122         free(buf);
123
124         return sdr;
125 }
126
127 unsigned int get_vsdr(const char *fname)
128 {
129         unsigned int sdr;
130
131         if((sdr = lookup_asset(fname))) {
132                 return sdr;
133         }
134
135         if((sdr = load_sdr(fname, GL_VERTEX_SHADER))) {
136                 add_asset(fname, ASS_SDR, sdr);
137         }
138         return sdr;
139 }
140
141 unsigned int get_psdr(const char *fname)
142 {
143         unsigned int sdr;
144
145         if((sdr = lookup_asset(fname))) {
146                 return sdr;
147         }
148
149         if((sdr = load_sdr(fname, GL_FRAGMENT_SHADER))) {
150                 add_asset(fname, ASS_SDR, sdr);
151         }
152         return sdr;
153 }
154
155 unsigned int get_sdrprog(const char *vfname, const char *pfname)
156 {
157         unsigned int vsdr, psdr, prog;
158         char *progname;
159
160         progname = alloca(strlen(vfname) + strlen(pfname) + 2);
161         sprintf(progname, "%s,%s", vfname, pfname);
162
163         if((prog = lookup_asset(progname))) {
164                 return prog;
165         }
166
167         if(!(vsdr = get_vsdr(vfname)) || !(psdr = get_psdr(pfname))) {
168                 return 0;
169         }
170         if(!(prog = create_program_link(vsdr, psdr, 0))) {
171                 return 0;
172         }
173         add_asset(progname, ASS_PROG, prog);
174         return prog;
175 }
176
177 int add_asset(const char *name, int type, unsigned int id)
178 {
179         struct asset *ass;
180
181         ass = malloc_nf(sizeof *ass);
182         ass->type = type;
183         ass->name = strdup_nf(name);
184         ass->id = id;
185
186         if(rb_insert(rb, (char*)ass->name, ass) == -1) {
187                 return -1;
188         }
189         return 0;
190 }
191
192 unsigned int lookup_asset(const char *name)
193 {
194         struct rbnode *n;
195
196         if(!(n = rb_find(rb, (char*)name))) {
197                 return 0;
198         }
199         return ((struct asset*)n->data)->id;
200 }
201
202 unsigned int load_sdrprog(const char *vfname, const char *pfname)
203 {
204         unsigned int vsdr, psdr, prog;
205
206         if(!(vsdr = load_sdr(vfname, GL_VERTEX_SHADER)) || !(psdr = load_sdr(pfname, GL_FRAGMENT_SHADER))) {
207                 return 0;
208         }
209         if(!(prog = create_program_link(vsdr, psdr, 0))) {
210                 return 0;
211         }
212         return prog;
213 }
214
215 static size_t io_read(void *buf, size_t bytes, void *uptr)
216 {
217         return ass_fread(buf, 1, bytes, uptr);
218 }
219
220 static long io_seek(long offs, int whence, void *uptr)
221 {
222         return ass_fseek(uptr, offs, whence);
223 }
224
225 static void del_rbnode(struct rbnode *rb, void *cls)
226 {
227         struct asset *ass = rb->data;
228
229         free(ass->name);
230
231         switch(ass->type) {
232         case ASS_TEX:
233                 glDeleteTextures(1, &ass->id);
234                 break;
235
236         case ASS_SDR:
237                 glDeleteShader(ass->id);
238                 break;
239
240         case ASS_PROG:
241                 glDeleteProgram(ass->id);
242                 break;
243         }
244 }