libresman

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