libresman

view examples/imgthumbs/src/thumbs.c @ 26:6b9974a8bdae

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