libresman

view examples/imgthumbs/src/thumbs.c @ 20:c6073bf9fd38

finally! async loading works. Now on to inotify...
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 12 Feb 2014 16:02:12 +0200
parents 711698580eb0
children fe0dbdfbe403
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);
26 if(!texman) {
27 texman = resman_create();
28 resman_set_load_func(texman, load_res_texture, 0);
29 resman_set_done_func(texman, done_res_texture, 0);
30 resman_set_destroy_func(texman, free_res_texture, 0);
31 }
33 if(!(dir = opendir(dirpath))) {
34 fprintf(stderr, "failed to open directory: %s: %s\n", dirpath, strerror(errno));
35 return 0;
36 }
38 while((dent = readdir(dir))) {
39 struct img_pixmap img;
40 struct thumbnail *node;
42 if(!(node = malloc(sizeof *node))) {
43 perror("failed to allocate thumbnail list node");
44 continue;
45 }
46 memset(node, 0, sizeof *node);
48 if(!(node->fname = malloc(strlen(dirpath) + strlen(dent->d_name) + 2))) {
49 free(node);
50 continue;
51 }
52 strcpy(node->fname, dirpath);
53 if(dirpath[strlen(dirpath) - 1] != '/') {
54 strcat(node->fname, "/");
55 }
56 strcat(node->fname, dent->d_name);
58 node->aspect = 1.0;
60 if(dbg_load_async) {
61 resman_lookup(texman, node->fname, node);
62 } else {
63 img_init(&img);
64 if(img_load(&img, node->fname) == -1) {
65 img_destroy(&img);
66 free(node->fname);
67 free(node);
68 continue;
69 }
71 printf("loaded image: %s\n", node->fname);
73 node->aspect = (float)img.width / (float)img.height;
75 glGenTextures(1, &node->tex);
76 glBindTexture(GL_TEXTURE_2D, node->tex);
77 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
79 glTexImage2D(GL_TEXTURE_2D, 0, img_glintfmt(&img), img.width, img.height, 0, img_glfmt(&img), img_gltype(&img), img.pixels);
80 img_destroy(&img);
82 node->prev = list;
83 node->next = list->next;
84 if(list->next) list->next->prev = node;
85 list->next = node;
86 }
87 node->list = list;
88 }
89 closedir(dir);
91 return list;
92 }
94 void free_thumbs(struct thumbnail *thumbs)
95 {
96 if(!thumbs) return;
98 while(thumbs) {
99 struct thumbnail *tmp = thumbs;
100 thumbs = thumbs->next;
102 free(tmp->fname);
103 free(tmp);
104 }
105 }
108 void update_thumbs(void)
109 {
110 resman_poll(texman);
111 }
113 void draw_thumbs(struct thumbnail *thumbs, float thumb_sz, float start_y)
114 {
115 int vp[4];
116 float gap = thumb_sz / 4.0;
117 float x = gap;
118 float y = gap + start_y;
119 float view_aspect;
121 glGetIntegerv(GL_VIEWPORT, vp);
122 view_aspect = (float)(vp[2] - vp[0]) / (float)(vp[3] - vp[1]);
124 glMatrixMode(GL_PROJECTION);
125 glPushMatrix();
126 glLoadIdentity();
127 glOrtho(0, 1, 1.0 / view_aspect, 0, -1, 1);
129 glMatrixMode(GL_MODELVIEW);
131 thumbs = thumbs->next; /* skip dummy node */
132 while(thumbs) {
133 glPushMatrix();
134 glTranslatef(x, y, 0);
136 glScalef(thumb_sz, thumb_sz, 1);
138 glBegin(GL_QUADS);
139 glColor3f(0.25, 0.25, 0.25);
140 glTexCoord2f(0, 0); glVertex2f(0, 0);
141 glTexCoord2f(1, 0); glVertex2f(1, 0);
142 glTexCoord2f(1, 1); glVertex2f(1, 1);
143 glTexCoord2f(0, 1); glVertex2f(0, 1);
144 glEnd();
146 if(thumbs->tex) {
147 if(thumbs->aspect >= 1.0) {
148 glTranslatef(0, 0.5 - 0.5 / thumbs->aspect, 0);
149 glScalef(1, 1.0 / thumbs->aspect, 1);
150 } else {
151 glTranslatef(0.5 - thumbs->aspect / 2.0, 0, 0);
152 glScalef(thumbs->aspect, 1, 1);
153 }
155 if(glIsTexture(thumbs->tex)) {
156 glEnable(GL_TEXTURE_2D);
157 glBindTexture(GL_TEXTURE_2D, thumbs->tex);
159 glBegin(GL_QUADS);
160 glColor3f(1, 1, 1);
161 glTexCoord2f(0, 0); glVertex2f(0, 0);
162 glTexCoord2f(1, 0); glVertex2f(1, 0);
163 glTexCoord2f(1, 1); glVertex2f(1, 1);
164 glTexCoord2f(0, 1); glVertex2f(0, 1);
165 glEnd();
166 } else {
167 fprintf(stderr, "invalid texture: %u\n", thumbs->tex);
168 }
170 glPopMatrix();
171 glDisable(GL_TEXTURE_2D);
172 }
174 thumbs->layout_pos[0] = x;
175 thumbs->layout_pos[1] = y;
176 thumbs->layout_size[0] = thumb_sz;
177 thumbs->layout_size[1] = thumb_sz;
179 x += thumb_sz + gap;
180 if(x >= 1.0 - thumb_sz) {
181 x = gap;
182 y += thumb_sz + gap;
183 }
185 thumbs = thumbs->next;
186 }
188 glMatrixMode(GL_PROJECTION);
189 glPopMatrix();
190 glMatrixMode(GL_MODELVIEW);
191 }
193 static int load_res_texture(const char *fname, int id, void *cls)
194 {
195 struct thumbnail *rdata = resman_get_res_data(texman, id);
197 assert(rdata);
198 if(!rdata->img) {
199 if(!(rdata->img = img_create())) {
200 return -1;
201 }
202 }
204 if(img_load(rdata->img, fname) == -1) {
205 img_free(rdata->img);
206 rdata->img = 0;
207 return -1;
208 }
209 rdata->aspect = (float)rdata->img->width / (float)rdata->img->height;
211 /* set the resource's data to the loaded image, so that we can use
212 * it in the done callback */
213 resman_set_res_data(texman, id, rdata);
214 return 0;
215 }
217 static int done_res_texture(int id, void *cls)
218 {
219 struct thumbnail *thumb = resman_get_res_data(texman, id);
220 int load_result = resman_get_res_result(texman, id);
222 if(load_result == -1) {
223 /* returning -1 will remove this resource, the free_res_texture
224 * destroy handler will be called, which will remove the node
225 * from the list
226 */
227 return -1;
228 }
230 if(resman_get_res_result(texman, id) != 0 || !thumb) {
231 fprintf(stderr, "failed to load resource %d (%s)\n", id, resman_get_res_name(texman, id));
232 } else {
233 printf("done loading resource %d (%s)\n", id, resman_get_res_name(texman, id));
234 }
236 if(!thumb->tex) {
237 glGenTextures(1, &thumb->tex);
238 }
239 glBindTexture(GL_TEXTURE_2D, thumb->tex);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
242 glTexImage2D(GL_TEXTURE_2D, 0, img_glintfmt(thumb->img),
243 thumb->img->width, thumb->img->height, 0, img_glfmt(thumb->img),
244 img_gltype(thumb->img), thumb->img->pixels);
246 /* and add it to the list of thumbnails */
247 thumb->prev = thumb->list;
248 thumb->next = thumb->list->next;
249 if(thumb->list->next) thumb->list->next->prev = thumb;
250 thumb->list->next = thumb;
251 return 0;
252 }
254 static void free_res_texture(int id, void *cls)
255 {
256 struct thumbnail *thumb = resman_get_res_data(texman, id);
258 printf("deleting thumb %d: %s\n", id, thumb->fname);
260 if(thumb) {
261 if(thumb->tex) {
262 glDeleteTextures(1, &thumb->tex);
263 }
264 if(thumb->img) {
265 img_free(thumb->img);
266 }
267 }
269 /* remove from the list */
270 if(thumb->prev) {
271 thumb->prev->next = thumb->next;
272 }
273 if(thumb->next) {
274 thumb->next->prev = thumb->prev;
275 }
276 free(thumb);
277 }