rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@1
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <string.h>
|
nuclear@1
|
4 #include <errno.h>
|
nuclear@11
|
5 #include <assert.h>
|
nuclear@1
|
6 #include <dirent.h>
|
nuclear@1
|
7 #include <imago2.h>
|
nuclear@1
|
8 #include "opengl.h"
|
nuclear@1
|
9 #include "thumbs.h"
|
nuclear@11
|
10 #include "resman.h"
|
nuclear@1
|
11
|
nuclear@11
|
12 static int load_res_texture(const char *fname, int id, void *cls);
|
nuclear@11
|
13 static int done_res_texture(int id, void *cls);
|
nuclear@11
|
14 static void free_res_texture(int id, void *cls);
|
nuclear@11
|
15
|
nuclear@20
|
16 struct resman *texman;
|
nuclear@20
|
17 int dbg_load_async = 1;
|
nuclear@11
|
18
|
nuclear@1
|
19 struct thumbnail *create_thumbs(const char *dirpath)
|
nuclear@1
|
20 {
|
nuclear@1
|
21 DIR *dir;
|
nuclear@1
|
22 struct dirent *dent;
|
nuclear@13
|
23 /* allocate dummy head node */
|
nuclear@13
|
24 struct thumbnail *list = calloc(1, sizeof *list);
|
nuclear@21
|
25 char *env;
|
nuclear@21
|
26
|
nuclear@21
|
27 if((env = getenv("RESMAN_LOAD_ASYNC"))) {
|
nuclear@21
|
28 dbg_load_async = atoi(env);
|
nuclear@21
|
29 }
|
nuclear@1
|
30
|
nuclear@11
|
31 if(!texman) {
|
nuclear@11
|
32 texman = resman_create();
|
nuclear@11
|
33 resman_set_load_func(texman, load_res_texture, 0);
|
nuclear@11
|
34 resman_set_done_func(texman, done_res_texture, 0);
|
nuclear@11
|
35 resman_set_destroy_func(texman, free_res_texture, 0);
|
nuclear@2
|
36 }
|
nuclear@2
|
37
|
nuclear@1
|
38 if(!(dir = opendir(dirpath))) {
|
nuclear@1
|
39 fprintf(stderr, "failed to open directory: %s: %s\n", dirpath, strerror(errno));
|
nuclear@1
|
40 return 0;
|
nuclear@1
|
41 }
|
nuclear@1
|
42
|
nuclear@1
|
43 while((dent = readdir(dir))) {
|
nuclear@18
|
44 struct img_pixmap img;
|
nuclear@1
|
45 struct thumbnail *node;
|
nuclear@1
|
46
|
nuclear@1
|
47 if(!(node = malloc(sizeof *node))) {
|
nuclear@1
|
48 perror("failed to allocate thumbnail list node");
|
nuclear@1
|
49 continue;
|
nuclear@1
|
50 }
|
nuclear@11
|
51 memset(node, 0, sizeof *node);
|
nuclear@1
|
52
|
nuclear@1
|
53 if(!(node->fname = malloc(strlen(dirpath) + strlen(dent->d_name) + 2))) {
|
nuclear@1
|
54 free(node);
|
nuclear@1
|
55 continue;
|
nuclear@1
|
56 }
|
nuclear@1
|
57 strcpy(node->fname, dirpath);
|
nuclear@1
|
58 if(dirpath[strlen(dirpath) - 1] != '/') {
|
nuclear@1
|
59 strcat(node->fname, "/");
|
nuclear@1
|
60 }
|
nuclear@1
|
61 strcat(node->fname, dent->d_name);
|
nuclear@1
|
62
|
nuclear@16
|
63 node->aspect = 1.0;
|
nuclear@11
|
64
|
nuclear@20
|
65 if(dbg_load_async) {
|
nuclear@20
|
66 resman_lookup(texman, node->fname, node);
|
nuclear@20
|
67 } else {
|
nuclear@20
|
68 img_init(&img);
|
nuclear@20
|
69 if(img_load(&img, node->fname) == -1) {
|
nuclear@20
|
70 img_destroy(&img);
|
nuclear@20
|
71 free(node->fname);
|
nuclear@20
|
72 free(node);
|
nuclear@20
|
73 continue;
|
nuclear@20
|
74 }
|
nuclear@20
|
75
|
nuclear@20
|
76 printf("loaded image: %s\n", node->fname);
|
nuclear@20
|
77
|
nuclear@20
|
78 node->aspect = (float)img.width / (float)img.height;
|
nuclear@20
|
79
|
nuclear@20
|
80 glGenTextures(1, &node->tex);
|
nuclear@20
|
81 glBindTexture(GL_TEXTURE_2D, node->tex);
|
nuclear@20
|
82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@20
|
83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@20
|
84 glTexImage2D(GL_TEXTURE_2D, 0, img_glintfmt(&img), img.width, img.height, 0, img_glfmt(&img), img_gltype(&img), img.pixels);
|
nuclear@18
|
85 img_destroy(&img);
|
nuclear@20
|
86
|
nuclear@20
|
87 node->prev = list;
|
nuclear@20
|
88 node->next = list->next;
|
nuclear@20
|
89 if(list->next) list->next->prev = node;
|
nuclear@20
|
90 list->next = node;
|
nuclear@1
|
91 }
|
nuclear@20
|
92 node->list = list;
|
nuclear@21
|
93 node->load_count = 0;
|
nuclear@1
|
94 }
|
nuclear@1
|
95 closedir(dir);
|
nuclear@1
|
96
|
nuclear@1
|
97 return list;
|
nuclear@1
|
98 }
|
nuclear@1
|
99
|
nuclear@1
|
100 void free_thumbs(struct thumbnail *thumbs)
|
nuclear@1
|
101 {
|
nuclear@1
|
102 if(!thumbs) return;
|
nuclear@1
|
103
|
nuclear@1
|
104 while(thumbs) {
|
nuclear@1
|
105 struct thumbnail *tmp = thumbs;
|
nuclear@1
|
106 thumbs = thumbs->next;
|
nuclear@1
|
107
|
nuclear@1
|
108 free(tmp->fname);
|
nuclear@1
|
109 free(tmp);
|
nuclear@1
|
110 }
|
nuclear@1
|
111 }
|
nuclear@1
|
112
|
nuclear@1
|
113
|
nuclear@11
|
114 void update_thumbs(void)
|
nuclear@11
|
115 {
|
nuclear@11
|
116 resman_poll(texman);
|
nuclear@11
|
117 }
|
nuclear@11
|
118
|
nuclear@1
|
119 void draw_thumbs(struct thumbnail *thumbs, float thumb_sz, float start_y)
|
nuclear@1
|
120 {
|
nuclear@1
|
121 int vp[4];
|
nuclear@1
|
122 float gap = thumb_sz / 4.0;
|
nuclear@1
|
123 float x = gap;
|
nuclear@1
|
124 float y = gap + start_y;
|
nuclear@1
|
125 float view_aspect;
|
nuclear@1
|
126
|
nuclear@1
|
127 glGetIntegerv(GL_VIEWPORT, vp);
|
nuclear@14
|
128 view_aspect = (float)(vp[2] - vp[0]) / (float)(vp[3] - vp[1]);
|
nuclear@1
|
129
|
nuclear@1
|
130 glMatrixMode(GL_PROJECTION);
|
nuclear@1
|
131 glPushMatrix();
|
nuclear@1
|
132 glLoadIdentity();
|
nuclear@1
|
133 glOrtho(0, 1, 1.0 / view_aspect, 0, -1, 1);
|
nuclear@1
|
134
|
nuclear@1
|
135 glMatrixMode(GL_MODELVIEW);
|
nuclear@1
|
136
|
nuclear@13
|
137 thumbs = thumbs->next; /* skip dummy node */
|
nuclear@1
|
138 while(thumbs) {
|
nuclear@1
|
139 glPushMatrix();
|
nuclear@1
|
140 glTranslatef(x, y, 0);
|
nuclear@1
|
141
|
nuclear@1
|
142 glScalef(thumb_sz, thumb_sz, 1);
|
nuclear@1
|
143
|
nuclear@1
|
144 glBegin(GL_QUADS);
|
nuclear@1
|
145 glColor3f(0.25, 0.25, 0.25);
|
nuclear@1
|
146 glTexCoord2f(0, 0); glVertex2f(0, 0);
|
nuclear@1
|
147 glTexCoord2f(1, 0); glVertex2f(1, 0);
|
nuclear@1
|
148 glTexCoord2f(1, 1); glVertex2f(1, 1);
|
nuclear@1
|
149 glTexCoord2f(0, 1); glVertex2f(0, 1);
|
nuclear@1
|
150 glEnd();
|
nuclear@1
|
151
|
nuclear@12
|
152 if(thumbs->tex) {
|
nuclear@12
|
153 if(thumbs->aspect >= 1.0) {
|
nuclear@12
|
154 glTranslatef(0, 0.5 - 0.5 / thumbs->aspect, 0);
|
nuclear@12
|
155 glScalef(1, 1.0 / thumbs->aspect, 1);
|
nuclear@12
|
156 } else {
|
nuclear@12
|
157 glTranslatef(0.5 - thumbs->aspect / 2.0, 0, 0);
|
nuclear@12
|
158 glScalef(thumbs->aspect, 1, 1);
|
nuclear@12
|
159 }
|
nuclear@12
|
160
|
nuclear@12
|
161 if(glIsTexture(thumbs->tex)) {
|
nuclear@12
|
162 glEnable(GL_TEXTURE_2D);
|
nuclear@12
|
163 glBindTexture(GL_TEXTURE_2D, thumbs->tex);
|
nuclear@12
|
164
|
nuclear@12
|
165 glBegin(GL_QUADS);
|
nuclear@12
|
166 glColor3f(1, 1, 1);
|
nuclear@12
|
167 glTexCoord2f(0, 0); glVertex2f(0, 0);
|
nuclear@12
|
168 glTexCoord2f(1, 0); glVertex2f(1, 0);
|
nuclear@12
|
169 glTexCoord2f(1, 1); glVertex2f(1, 1);
|
nuclear@12
|
170 glTexCoord2f(0, 1); glVertex2f(0, 1);
|
nuclear@12
|
171 glEnd();
|
nuclear@12
|
172 } else {
|
nuclear@12
|
173 fprintf(stderr, "invalid texture: %u\n", thumbs->tex);
|
nuclear@12
|
174 }
|
nuclear@12
|
175
|
nuclear@12
|
176 glPopMatrix();
|
nuclear@12
|
177 glDisable(GL_TEXTURE_2D);
|
nuclear@1
|
178 }
|
nuclear@1
|
179
|
nuclear@1
|
180 thumbs->layout_pos[0] = x;
|
nuclear@1
|
181 thumbs->layout_pos[1] = y;
|
nuclear@1
|
182 thumbs->layout_size[0] = thumb_sz;
|
nuclear@1
|
183 thumbs->layout_size[1] = thumb_sz;
|
nuclear@1
|
184
|
nuclear@1
|
185 x += thumb_sz + gap;
|
nuclear@1
|
186 if(x >= 1.0 - thumb_sz) {
|
nuclear@1
|
187 x = gap;
|
nuclear@1
|
188 y += thumb_sz + gap;
|
nuclear@1
|
189 }
|
nuclear@1
|
190
|
nuclear@1
|
191 thumbs = thumbs->next;
|
nuclear@1
|
192 }
|
nuclear@1
|
193
|
nuclear@1
|
194 glMatrixMode(GL_PROJECTION);
|
nuclear@1
|
195 glPopMatrix();
|
nuclear@1
|
196 glMatrixMode(GL_MODELVIEW);
|
nuclear@1
|
197 }
|
nuclear@11
|
198
|
nuclear@11
|
199 static int load_res_texture(const char *fname, int id, void *cls)
|
nuclear@11
|
200 {
|
nuclear@12
|
201 struct thumbnail *rdata = resman_get_res_data(texman, id);
|
nuclear@11
|
202
|
nuclear@11
|
203 assert(rdata);
|
nuclear@11
|
204 if(!rdata->img) {
|
nuclear@11
|
205 if(!(rdata->img = img_create())) {
|
nuclear@11
|
206 return -1;
|
nuclear@11
|
207 }
|
nuclear@11
|
208 }
|
nuclear@11
|
209
|
nuclear@12
|
210 if(img_load(rdata->img, fname) == -1) {
|
nuclear@11
|
211 img_free(rdata->img);
|
nuclear@13
|
212 rdata->img = 0;
|
nuclear@11
|
213 return -1;
|
nuclear@11
|
214 }
|
nuclear@11
|
215 rdata->aspect = (float)rdata->img->width / (float)rdata->img->height;
|
nuclear@11
|
216
|
nuclear@11
|
217 /* set the resource's data to the loaded image, so that we can use
|
nuclear@11
|
218 * it in the done callback */
|
nuclear@12
|
219 resman_set_res_data(texman, id, rdata);
|
nuclear@11
|
220 return 0;
|
nuclear@11
|
221 }
|
nuclear@11
|
222
|
nuclear@11
|
223 static int done_res_texture(int id, void *cls)
|
nuclear@11
|
224 {
|
nuclear@20
|
225 struct thumbnail *thumb = resman_get_res_data(texman, id);
|
nuclear@13
|
226 int load_result = resman_get_res_result(texman, id);
|
nuclear@11
|
227
|
nuclear@13
|
228 if(load_result == -1) {
|
nuclear@13
|
229 /* returning -1 will remove this resource, the free_res_texture
|
nuclear@13
|
230 * destroy handler will be called, which will remove the node
|
nuclear@13
|
231 * from the list
|
nuclear@13
|
232 */
|
nuclear@13
|
233 return -1;
|
nuclear@13
|
234 }
|
nuclear@11
|
235
|
nuclear@20
|
236 if(resman_get_res_result(texman, id) != 0 || !thumb) {
|
nuclear@12
|
237 fprintf(stderr, "failed to load resource %d (%s)\n", id, resman_get_res_name(texman, id));
|
nuclear@11
|
238 } else {
|
nuclear@12
|
239 printf("done loading resource %d (%s)\n", id, resman_get_res_name(texman, id));
|
nuclear@11
|
240 }
|
nuclear@11
|
241
|
nuclear@20
|
242 if(!thumb->tex) {
|
nuclear@20
|
243 glGenTextures(1, &thumb->tex);
|
nuclear@11
|
244 }
|
nuclear@20
|
245 glBindTexture(GL_TEXTURE_2D, thumb->tex);
|
nuclear@11
|
246 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@11
|
247 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@20
|
248 glTexImage2D(GL_TEXTURE_2D, 0, img_glintfmt(thumb->img),
|
nuclear@20
|
249 thumb->img->width, thumb->img->height, 0, img_glfmt(thumb->img),
|
nuclear@20
|
250 img_gltype(thumb->img), thumb->img->pixels);
|
nuclear@20
|
251
|
nuclear@21
|
252 /* and add it to the list of thumbnails (if it's the first loading) */
|
nuclear@21
|
253 if(resman_get_res_load_count(texman, id) == 0) {
|
nuclear@21
|
254 thumb->prev = thumb->list;
|
nuclear@21
|
255 thumb->next = thumb->list->next;
|
nuclear@21
|
256 if(thumb->list->next) thumb->list->next->prev = thumb;
|
nuclear@21
|
257 thumb->list->next = thumb;
|
nuclear@21
|
258 }
|
nuclear@11
|
259 return 0;
|
nuclear@11
|
260 }
|
nuclear@11
|
261
|
nuclear@11
|
262 static void free_res_texture(int id, void *cls)
|
nuclear@11
|
263 {
|
nuclear@13
|
264 struct thumbnail *thumb = resman_get_res_data(texman, id);
|
nuclear@11
|
265
|
nuclear@14
|
266 printf("deleting thumb %d: %s\n", id, thumb->fname);
|
nuclear@14
|
267
|
nuclear@13
|
268 if(thumb) {
|
nuclear@13
|
269 if(thumb->tex) {
|
nuclear@13
|
270 glDeleteTextures(1, &thumb->tex);
|
nuclear@11
|
271 }
|
nuclear@13
|
272 if(thumb->img) {
|
nuclear@13
|
273 img_free(thumb->img);
|
nuclear@11
|
274 }
|
nuclear@11
|
275 }
|
nuclear@13
|
276
|
nuclear@13
|
277 /* remove from the list */
|
nuclear@13
|
278 if(thumb->prev) {
|
nuclear@13
|
279 thumb->prev->next = thumb->next;
|
nuclear@13
|
280 }
|
nuclear@13
|
281 if(thumb->next) {
|
nuclear@13
|
282 thumb->next->prev = thumb->prev;
|
nuclear@13
|
283 }
|
nuclear@13
|
284 free(thumb);
|
nuclear@11
|
285 }
|