libresman

view examples/imgthumbs/src/thumbs.c @ 17:43a9fe4a80ee

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 11 Feb 2014 18:48:24 +0200
parents 0a789208498d 2fcd1fbb0d18
children 711698580eb0
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 #define DBG_SYNC
14 #ifndef GL_COMPRESSED_RGB
15 #define GL_COMPRESSED_RGB 0x84ed
16 #endif
18 struct resman *texman;
19 struct thumbnail *dbg;
21 static int load_res_texture(const char *fname, int id, void *cls);
22 static int done_res_texture(int id, void *cls);
23 static void free_res_texture(int id, void *cls);
26 struct thumbnail *create_thumbs(const char *dirpath)
27 {
28 DIR *dir;
29 struct dirent *dent;
30 /* allocate dummy head node */
31 struct thumbnail *list = calloc(1, sizeof *list);
32 dbg = list;
34 if(!texman) {
35 texman = resman_create();
36 resman_set_load_func(texman, load_res_texture, 0);
37 resman_set_done_func(texman, done_res_texture, 0);
38 resman_set_destroy_func(texman, free_res_texture, 0);
39 }
41 if(!(dir = opendir(dirpath))) {
42 fprintf(stderr, "failed to open directory: %s: %s\n", dirpath, strerror(errno));
43 return 0;
44 }
46 while((dent = readdir(dir))) {
47 #ifdef DBG_SYNC
48 int xsz, ysz;
49 unsigned char *pixels;
50 #endif
51 struct thumbnail *node;
53 if(!(node = malloc(sizeof *node))) {
54 perror("failed to allocate thumbnail list node");
55 continue;
56 }
57 memset(node, 0, sizeof *node);
59 if(!(node->fname = malloc(strlen(dirpath) + strlen(dent->d_name) + 2))) {
60 free(node);
61 continue;
62 }
63 strcpy(node->fname, dirpath);
64 if(dirpath[strlen(dirpath) - 1] != '/') {
65 strcat(node->fname, "/");
66 }
67 strcat(node->fname, dent->d_name);
69 node->aspect = 1.0;
71 #ifndef DBG_SYNC
72 resman_lookup(texman, node->fname, node);
73 #else
74 if(!(pixels = img_load_pixels(node->fname, &xsz, &ysz, IMG_FMT_RGBA32))) {
75 free(node->fname);
76 free(node);
77 continue;
78 }
80 printf("loaded image: %s\n", node->fname);
82 glGenTextures(1, &node->tex);
83 glBindTexture(GL_TEXTURE_2D, node->tex);
84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
86 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
87 img_free_pixels(pixels);
89 node->aspect = (float)xsz / (float)ysz;
90 #endif
92 node->next = list->next;
93 node->prev = list;
94 list->next = node;
95 }
96 closedir(dir);
98 return list;
99 }
101 void free_thumbs(struct thumbnail *thumbs)
102 {
103 if(!thumbs) return;
105 while(thumbs) {
106 struct thumbnail *tmp = thumbs;
107 thumbs = thumbs->next;
109 free(tmp->fname);
110 free(tmp);
111 }
112 }
115 void update_thumbs(void)
116 {
117 resman_poll(texman);
118 }
120 void draw_thumbs(struct thumbnail *thumbs, float thumb_sz, float start_y)
121 {
122 int vp[4];
123 float gap = thumb_sz / 4.0;
124 float x = gap;
125 float y = gap + start_y;
126 float view_aspect;
128 glGetIntegerv(GL_VIEWPORT, vp);
129 view_aspect = (float)(vp[2] - vp[0]) / (float)(vp[3] - vp[1]);
131 glMatrixMode(GL_PROJECTION);
132 glPushMatrix();
133 glLoadIdentity();
134 glOrtho(0, 1, 1.0 / view_aspect, 0, -1, 1);
136 glMatrixMode(GL_MODELVIEW);
138 thumbs = thumbs->next; /* skip dummy node */
139 while(thumbs) {
140 printf("drawing thumb: %s\n", thumbs->fname);
141 glPushMatrix();
142 glTranslatef(x, y, 0);
144 glScalef(thumb_sz, thumb_sz, 1);
146 glBegin(GL_QUADS);
147 glColor3f(0.25, 0.25, 0.25);
148 glTexCoord2f(0, 0); glVertex2f(0, 0);
149 glTexCoord2f(1, 0); glVertex2f(1, 0);
150 glTexCoord2f(1, 1); glVertex2f(1, 1);
151 glTexCoord2f(0, 1); glVertex2f(0, 1);
152 glEnd();
154 if(thumbs->tex) {
155 if(thumbs->aspect >= 1.0) {
156 glTranslatef(0, 0.5 - 0.5 / thumbs->aspect, 0);
157 glScalef(1, 1.0 / thumbs->aspect, 1);
158 } else {
159 glTranslatef(0.5 - thumbs->aspect / 2.0, 0, 0);
160 glScalef(thumbs->aspect, 1, 1);
161 }
163 if(glIsTexture(thumbs->tex)) {
164 glEnable(GL_TEXTURE_2D);
165 glBindTexture(GL_TEXTURE_2D, thumbs->tex);
167 glBegin(GL_QUADS);
168 glColor3f(1, 1, 1);
169 glTexCoord2f(0, 0); glVertex2f(0, 0);
170 glTexCoord2f(1, 0); glVertex2f(1, 0);
171 glTexCoord2f(1, 1); glVertex2f(1, 1);
172 glTexCoord2f(0, 1); glVertex2f(0, 1);
173 glEnd();
174 } else {
175 fprintf(stderr, "invalid texture: %u\n", thumbs->tex);
176 }
178 glPopMatrix();
179 glDisable(GL_TEXTURE_2D);
180 }
182 thumbs->layout_pos[0] = x;
183 thumbs->layout_pos[1] = y;
184 thumbs->layout_size[0] = thumb_sz;
185 thumbs->layout_size[1] = thumb_sz;
187 x += thumb_sz + gap;
188 if(x >= 1.0 - thumb_sz) {
189 x = gap;
190 y += thumb_sz + gap;
191 }
193 thumbs = thumbs->next;
194 }
196 glMatrixMode(GL_PROJECTION);
197 glPopMatrix();
198 glMatrixMode(GL_MODELVIEW);
199 }
201 static int load_res_texture(const char *fname, int id, void *cls)
202 {
203 struct thumbnail *rdata = resman_get_res_data(texman, id);
205 assert(rdata);
206 if(!rdata->img) {
207 if(!(rdata->img = img_create())) {
208 return -1;
209 }
210 }
212 if(img_load(rdata->img, fname) == -1) {
213 img_free(rdata->img);
214 rdata->img = 0;
215 return -1;
216 }
217 rdata->aspect = (float)rdata->img->width / (float)rdata->img->height;
219 /* set the resource's data to the loaded image, so that we can use
220 * it in the done callback */
221 resman_set_res_data(texman, id, rdata);
222 return 0;
223 }
225 static int done_res_texture(int id, void *cls)
226 {
227 struct thumbnail *rdata = resman_get_res_data(texman, id);
228 int load_result = resman_get_res_result(texman, id);
230 if(load_result == -1) {
231 /* returning -1 will remove this resource, the free_res_texture
232 * destroy handler will be called, which will remove the node
233 * from the list
234 */
235 return -1;
236 }
238 if(resman_get_res_result(texman, id) != 0 || !rdata) {
239 fprintf(stderr, "failed to load resource %d (%s)\n", id, resman_get_res_name(texman, id));
240 } else {
241 printf("done loading resource %d (%s)\n", id, resman_get_res_name(texman, id));
242 }
244 if(!rdata->tex) {
245 glGenTextures(1, &rdata->tex);
246 }
247 glBindTexture(GL_TEXTURE_2D, rdata->tex);
248 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
250 glTexImage2D(GL_TEXTURE_2D, 0, img_glintfmt(rdata->img),
251 rdata->img->width, rdata->img->height, 0, img_glfmt(rdata->img),
252 img_gltype(rdata->img), rdata->img->pixels);
253 return 0;
254 }
256 static void free_res_texture(int id, void *cls)
257 {
258 struct thumbnail *thumb = resman_get_res_data(texman, id);
260 printf("deleting thumb %d: %s\n", id, thumb->fname);
262 if(thumb) {
263 if(thumb->tex) {
264 glDeleteTextures(1, &thumb->tex);
265 }
266 if(thumb->img) {
267 img_free(thumb->img);
268 }
269 }
271 /* remove from the list */
272 if(thumb->prev) {
273 thumb->prev->next = thumb->next;
274 }
275 if(thumb->next) {
276 thumb->next->prev = thumb->prev;
277 }
278 free(thumb);
279 }