# HG changeset patch # User John Tsiombikas # Date 1391131044 -7200 # Node ID 469ce01809bc5f837fa97ee971cbe496cf813476 # Parent 61d7ff6da54b9e6e66f661617f4af6cebbb3e401 rudimentary imgthumbs "example program". doesn't use libresman yet diff -r 61d7ff6da54b -r 469ce01809bc .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,17 @@ +\.o$ +\.swp$ +\.d$ +^libresman.so +^libresman.a +\.jpg$ +\.png$ +\.gif$ +\.tga$ +\.jpeg$ +\.targa$ +\.tif$ +\.bmp$ +\.ppm$ +\.pnm$ +\.xpm$ +\.rgba$ diff -r 61d7ff6da54b -r 469ce01809bc examples/imgthumbs/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/imgthumbs/Makefile Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,19 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +bin = imgthumbs + +CFLAGS = -pedantic -Wall -g -I../../src +LDFLAGS = $(libgl) -limago + +ifeq ($(shell uname -s), Darwin) + libgl = -framework OpenGL -framework GLUT +else + libgl = -lGL -lGLU -lglut +endif + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 61d7ff6da54b -r 469ce01809bc examples/imgthumbs/src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/imgthumbs/src/main.c Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,232 @@ +#include +#include +#include +#include "opengl.h" +#include "resman.h" +#include "thumbs.h" + +static int init(void); +static void cleanup(void); +static void display(void); +/*static void idle(void);*/ +static void reshape(int x, int y); +static void keyb(unsigned char key, int x, int y); +static void mouse(int bn, int st, int x, int y); +static void motion(int x, int y); +static struct thumbnail *find_thumb(int x, int y); + +const char *path = "."; +struct resman *texman; +int win_width, win_height; +float win_aspect; +float pan_x, pan_y; +float show_pan_x, show_pan_y; +float show_zoom = 1.0; +float thumbs_size = 0.25; + +struct thumbnail *thumbs, *show_thumb; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + + if(argv[1]) { + path = argv[1]; + } + + glutInitWindowSize(800, 600); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("imgthumbs"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutMouseFunc(mouse); + glutMotionFunc(motion); + + if(init() == -1) { + return 1; + } + atexit(cleanup); + + glutMainLoop(); + return 0; +} + +static int init(void) +{ + thumbs = create_thumbs(path); + return 0; +} + +static void cleanup(void) +{ + free_thumbs(thumbs); +} + +static void display(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if(show_thumb) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, show_thumb->tex); + + glScalef(show_zoom, show_zoom, 1); + glTranslatef(2.0 * show_pan_x, 2.0 * show_pan_y, 0); + if(show_thumb->aspect >= 1.0) { + glScalef(1, 1.0 / show_thumb->aspect, 1); + } else { + glScalef(show_thumb->aspect, 1, 1); + } + + glBegin(GL_QUADS); + glColor3f(1, 1, 1); + glTexCoord2f(0, 0); glVertex2f(-1, -1); + glTexCoord2f(1, 0); glVertex2f(1, -1); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(-1, 1); + glEnd(); + + glDisable(GL_TEXTURE_2D); + } else { + draw_thumbs(thumbs, thumbs_size, pan_y); + } + + glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + +/* +static void idle(void) +{ + glutPostRedisplay(); +} +*/ + +static void reshape(int x, int y) +{ + win_aspect = (float)x / (float)y; + + glViewport(0, 0, x, y); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, 1.0 / win_aspect, -1.0 / win_aspect, -1, 1); + + win_width = x; + win_height = y; +} + +static void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 27: + exit(0); + + case ' ': + show_zoom = 1.0; + thumbs_size = 0.25; + pan_x = pan_y = show_pan_x = show_pan_y = 0; + glutPostRedisplay(); + break; + } +} + +static int bnstate[32]; +static int prev_x, prev_y; +static int click_x[32], click_y[32]; + +static void mouse(int bn, int st, int x, int y) +{ + int bidx = bn - GLUT_LEFT_BUTTON; + int state = st == GLUT_DOWN ? 1 : 0; + + bnstate[bidx] = state; + + prev_x = x; + prev_y = y; + + if(state) { + click_x[bidx] = x; + click_y[bidx] = y; + } else { + int is_drag = abs(x - click_x[bidx]) > 3 || abs(y - click_y[bidx]) > 3; + + if(bidx == 0) { + if(!show_thumb) { + if(!is_drag) { + struct thumbnail *sel = find_thumb(x, y); + if(sel) { + show_thumb = sel; + show_pan_x = show_pan_y = 0; + glutPostRedisplay(); + } + } + } + } else { + if(!is_drag) { + show_thumb = 0; + glutPostRedisplay(); + } + } + } +} + +static void motion(int x, int y) +{ + int dx = x - prev_x; + int dy = y - prev_y; + prev_x = x; + prev_y = y; + + if(!dx && !dy) return; + + if(bnstate[0]) { + float fdx = dx / (float)win_width; + float fdy = dy / (float)win_height / win_aspect; + + if(show_thumb) { + show_pan_x += fdx / show_zoom; + show_pan_y += fdy / show_zoom; + } else { + pan_x += fdx; + pan_y += fdy; + } + glutPostRedisplay(); + } + + if(bnstate[2]) { + if(show_thumb) { + show_zoom -= dy * 0.0075; + if(show_zoom <= 0) show_zoom = 0; + } else { + thumbs_size -= dy * 0.005; + if(thumbs_size <= 0.01) thumbs_size = 0.01; + } + glutPostRedisplay(); + } +} + +static struct thumbnail *find_thumb(int x, int y) +{ + float fx = (float)x / (float)win_width; + float fy = (float)y / (float)win_height / win_aspect; + struct thumbnail *node; + + node = thumbs; + while(node) { + float nx = node->layout_pos[0]; + float ny = node->layout_pos[1]; + + if(fx >= nx && fx < nx + node->layout_size[0] && + fy >= ny && fy < ny + node->layout_size[1]) { + return node; + } + node = node->next; + } + return 0; +} diff -r 61d7ff6da54b -r 469ce01809bc examples/imgthumbs/src/opengl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/imgthumbs/src/opengl.h Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,10 @@ +#ifndef OPENGL_H_ +#define OPENGL_H_ + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#endif /* OPENGL_H_ */ diff -r 61d7ff6da54b -r 469ce01809bc examples/imgthumbs/src/thumbs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/imgthumbs/src/thumbs.c Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include "opengl.h" +#include "thumbs.h" + +struct thumbnail *create_thumbs(const char *dirpath) +{ + DIR *dir; + struct dirent *dent; + struct thumbnail *list = 0; + + if(!(dir = opendir(dirpath))) { + fprintf(stderr, "failed to open directory: %s: %s\n", dirpath, strerror(errno)); + return 0; + } + + while((dent = readdir(dir))) { + int xsz, ysz; + unsigned char *pixels; + struct thumbnail *node; + + if(!(node = malloc(sizeof *node))) { + perror("failed to allocate thumbnail list node"); + continue; + } + + if(!(node->fname = malloc(strlen(dirpath) + strlen(dent->d_name) + 2))) { + free(node); + continue; + } + strcpy(node->fname, dirpath); + if(dirpath[strlen(dirpath) - 1] != '/') { + strcat(node->fname, "/"); + } + strcat(node->fname, dent->d_name); + + if(!(pixels = img_load_pixels(node->fname, &xsz, &ysz, IMG_FMT_RGBA32))) { + free(node->fname); + free(node); + continue; + } + + printf("loaded image: %s\n", node->fname); + + glGenTextures(1, &node->tex); + glBindTexture(GL_TEXTURE_2D, node->tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + img_free_pixels(pixels); + + node->aspect = (float)xsz / (float)ysz; + + node->next = list; + list = node; + } + closedir(dir); + + return list; +} + +void free_thumbs(struct thumbnail *thumbs) +{ + if(!thumbs) return; + + while(thumbs) { + struct thumbnail *tmp = thumbs; + thumbs = thumbs->next; + + free(tmp->fname); + free(tmp); + } +} + + +void draw_thumbs(struct thumbnail *thumbs, float thumb_sz, float start_y) +{ + int vp[4]; + float gap = thumb_sz / 4.0; + float x = gap; + float y = gap + start_y; + float view_aspect; + + glGetIntegerv(GL_VIEWPORT, vp); + view_aspect = (float)(vp[2] - vp[0]) / (vp[3] - vp[1]); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, 1, 1.0 / view_aspect, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + + while(thumbs) { + + glPushMatrix(); + glTranslatef(x, y, 0); + + glScalef(thumb_sz, thumb_sz, 1); + + glBegin(GL_QUADS); + glColor3f(0.25, 0.25, 0.25); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(1, 0); glVertex2f(1, 0); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(0, 1); + glEnd(); + + if(thumbs->aspect >= 1.0) { + glTranslatef(0, 0.5 - 0.5 / thumbs->aspect, 0); + glScalef(1, 1.0 / thumbs->aspect, 1); + } else { + glTranslatef(0.5 - thumbs->aspect / 2.0, 0, 0); + glScalef(thumbs->aspect, 1, 1); + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, thumbs->tex); + + glBegin(GL_QUADS); + glColor3f(1, 1, 1); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(1, 0); glVertex2f(1, 0); + glTexCoord2f(1, 1); glVertex2f(1, 1); + glTexCoord2f(0, 1); glVertex2f(0, 1); + glEnd(); + + glPopMatrix(); + glDisable(GL_TEXTURE_2D); + + thumbs->layout_pos[0] = x; + thumbs->layout_pos[1] = y; + thumbs->layout_size[0] = thumb_sz; + thumbs->layout_size[1] = thumb_sz; + + x += thumb_sz + gap; + if(x >= 1.0 - thumb_sz) { + x = gap; + y += thumb_sz + gap; + } + + thumbs = thumbs->next; + } + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); +} diff -r 61d7ff6da54b -r 469ce01809bc examples/imgthumbs/src/thumbs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/imgthumbs/src/thumbs.h Fri Jan 31 03:17:24 2014 +0200 @@ -0,0 +1,21 @@ +#ifndef THUMBS_H_ +#define THUMBS_H_ + + +struct thumbnail { + char *fname; + unsigned int tex; + float aspect; + + float layout_pos[2]; + float layout_size[2]; + + struct thumbnail *next; +}; + +struct thumbnail *create_thumbs(const char *dirpath); +void free_thumbs(struct thumbnail *thumbs); + +void draw_thumbs(struct thumbnail *thumbs, float thumb_sz, float start_y); + +#endif /* THUMBS_H_ */ diff -r 61d7ff6da54b -r 469ce01809bc src/resman.h --- a/src/resman.h Wed Jan 29 08:17:31 2014 +0200 +++ b/src/resman.h Fri Jan 31 03:17:24 2014 +0200 @@ -1,53 +1,31 @@ #ifndef RESOURCE_MANAGER_H_ #define RESOURCE_MANAGER_H_ -/* TODO API */ - -/* usage example: -int texload(const char *fname, void *cls) -{ - // open image, parse data ... -} - -struct resman rman; - -resman_init(&rman); -resman_set_load_func(&rman, texload, 0); -resman_set_done_func(&rman, texload_done, 0); -... - -struct texture *tex; -struct resman_job *rjob; - -rjob = resman_get(&rman, "tex.png", 0); -... -resman_wait_job(&rman, rjob); -tex = resman_get_job_data(rjob); -resman_free_job(&rman, rjob); - -... -resman_destroy(&rman); -*/ - struct resman; -typedef int (*resman_load_func_t)(const char *fname, void *cls); -typedef void (*resman_done_func_t)(int status, void *cls); - - int resman_init(struct resman *rman); void resman_destroy(struct resman *rman); /* The load callback will be called to load a data file. It may be called in the * context of a different loading thread. */ -void resman_set_load_func(struct resman *rman, resman_load_func_t func, void *cls); +/*void resman_set_load_func(struct resman *rman, resman_load_func_t func, void *cls);*/ /* The "done" callback will be called in the context of the main thread, whenever a * file was sucessfully loaded, or an error occured. * It's first argument (status) is set to whatever the load function returned, and its - * closure pointer is the closure + * closure pointer is the closure ... */ -void resman_set_done_func(struct resman *rman, resman_done_func_t func); +/*void resman_set_done_func(struct resman *rman, resman_done_func_t func);*/ + + +int resman_lookup(struct resman *rman, const char *fname, void *cls); +void resman_wait(struct resman *rman, int id); + +int resman_poll(struct resman *rman); + +void resman_set_res_data(struct resman *rman, int res_id, void *data); +void *resman_get_res_data(struct resman *rman, int res_id); + #endif /* RESOURCE_MANAGER_H_ */