diff --git a/ChangeLog b/ChangeLog index 61f757241..303aa0da5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2005-03-27 mallum,,, + + * Makefile: + * cltr-photo-grid.c: (cltr_photo_grid_cell_new), + (ctrl_photo_grid_get_zoomed_coords), (cltr_photo_grid_navigate), + (cltr_photo_grid_activate_cell), (cltr_photo_grid_populate), + (cltr_photo_grid_redraw), (cltr_photo_grid_new): + * cltr-photo-grid.h: + * cltr.c: (cltr_dispatch_x_event), (cltr_init), (test_idle_cb), + (main): + * cltr.h: + Add a very hacky threaded image loader. + * pixbuf.c: (pixel_set_vals), pixbuf.h: + Add copy func ( unused as yet ) + 2005-03-25 mallum,,, * cltr-photo-grid.c: (cltr_photo_grid_cell_new), diff --git a/Makefile b/Makefile index 01f2a8a80..450e0647e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -LIBS=-lpng -lGL -ljpeg -L/usr/X11R6/lib -lX11 `pkg-config --libs pangoft2 pango glib-2.0` -CFLAGS=`pkg-config --cflags pangoft2 pango glib-2.0` +LIBS=-lpng -lGL -ljpeg -L/usr/X11R6/lib -lX11 `pkg-config --libs pangoft2 pango glib-2.0 gthread-2.0` +CFLAGS=`pkg-config --cflags pangoft2 pango glib-2.0 gthread-2.0` .c.o: $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c diff --git a/cltr-photo-grid.c b/cltr-photo-grid.c index 7d176d248..973e45fc7 100644 --- a/cltr-photo-grid.c +++ b/cltr-photo-grid.c @@ -1,5 +1,8 @@ #include "cltr-photo-grid.h" +/* this likely shouldn'y go here */ +static GMutex *Mutex_GRID = NULL; + ClutterPhotoGridCell* cltr_photo_grid_cell_new(ClutterPhotoGrid *grid, Pixbuf *pixb, @@ -39,6 +42,9 @@ cltr_photo_grid_cell_new(ClutterPhotoGrid *grid, cell->angle = 6.0 - (rand()%12); + cell->anim_step = 15; + cell->state = CLTR_PHOTO_GRID_CELL_STATE_APPEARING; + return cell; } @@ -83,6 +89,29 @@ ctrl_photo_grid_get_zoomed_coords(ClutterPhotoGrid *grid, *ty = (float)grid->cell_height * (grid->zoom_max) * y * -1.0; } +gboolean +cltr_photo_grid_idle_cb(gpointer data) +{ + ClutterPhotoGrid *grid = (ClutterPhotoGrid *)data; + + cltr_photo_grid_redraw(grid); + + switch(grid->state) + { + case CLTR_PHOTO_GRID_STATE_LOADING: + case CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE: + case CLTR_PHOTO_GRID_STATE_ZOOM_IN: + case CLTR_PHOTO_GRID_STATE_ZOOM_OUT: + case CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE: + return TRUE; + case CLTR_PHOTO_GRID_STATE_ZOOMED: + case CLTR_PHOTO_GRID_STATE_BROWSE: + default: + return FALSE; /* no need for rapid updates now */ + } +} + + void cltr_photo_grid_navigate(ClutterPhotoGrid *grid, CltrDirection direction) @@ -121,6 +150,8 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid, grid->view_min_y = grid->view_max_y ; grid->anim_step = 0; zoom = grid->zoom_max; + + g_idle_add(cltr_photo_grid_idle_cb, grid); } ctrl_photo_grid_cell_to_coords(grid, grid->cell_active, &x, &y); @@ -130,6 +161,8 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid, &grid->view_max_y); CLTR_DBG("x: %f, y: %f", grid->view_max_x , grid->view_max_y); + + cltr_photo_grid_redraw(grid); } } @@ -139,6 +172,8 @@ cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid) if (grid->state == CLTR_PHOTO_GRID_STATE_BROWSE) { grid->state = CLTR_PHOTO_GRID_STATE_ZOOM_IN; + + g_idle_add(cltr_photo_grid_idle_cb, grid); } else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED) { @@ -146,38 +181,54 @@ cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid) /* reset - zoomed moving will have reset */ grid->view_min_x = 0.0; grid->view_min_y = 0.0; + + g_idle_add(cltr_photo_grid_idle_cb, grid); } /* que a draw ? */ } -void -cltr_photo_grid_populate(ClutterPhotoGrid *grid, - const gchar *imgs_path) +gpointer +cltr_photo_grid_populate(gpointer data) { - GDir *dir; - GError *error; - const gchar *entry = NULL; - gchar *fullpath = NULL; - int n_pixb = 0, i =0; - GList *cell_item; - ClutterFont *font = NULL; + ClutterPhotoGrid *grid = (ClutterPhotoGrid *)data; + GDir *dir; + GError *error; + const gchar *entry = NULL; + gchar *fullpath = NULL; + int n_pixb = 0, i =0; + ClutterFont *font = NULL; font = font_new("Sans Bold 96"); - if ((dir = g_dir_open (imgs_path, 0, &error)) == NULL) + if ((dir = g_dir_open (grid->img_path, 0, &error)) == NULL) { /* handle this much better */ - fprintf(stderr, "failed to open '%s'\n", imgs_path); - return; + fprintf(stderr, "failed to open '%s'\n", grid->img_path); + return NULL; } - while((entry = g_dir_read_name (dir)) != NULL) + while ((entry = g_dir_read_name (dir)) != NULL) + { + if (!strcasecmp(&entry[strlen(entry)-4], ".png") + || !strcasecmp(&entry[strlen(entry)-4], ".jpg") + || !strcasecmp(&entry[strlen(entry)-5], ".jpeg")) + n_pixb++; + } + + CLTR_DBG("estamited %i pixb's\n", n_pixb); + + grid->texs = util_malloc0(sizeof(GLuint)*n_pixb); + glGenTextures(n_pixb, grid->texs); + + g_dir_rewind (dir); + + while ((entry = g_dir_read_name (dir)) != NULL) { Pixbuf *pixb = NULL; - fullpath = g_strconcat(imgs_path, "/", entry, NULL); - + fullpath = g_strconcat(grid->img_path, "/", entry, NULL); + pixb = pixbuf_new_from_file(fullpath); if (pixb) @@ -187,12 +238,47 @@ cltr_photo_grid_populate(ClutterPhotoGrid *grid, cell = cltr_photo_grid_cell_new(grid, pixb, entry); - g_snprintf(&buf[0], 24, "%i", n_pixb); + g_snprintf(&buf[0], 24, "%i", i); font_draw(font, cell->pixb, buf, 10, 10); + cell->texref = grid->texs[i]; + + g_mutex_lock(Mutex_GRID); + + glBindTexture(GL_TEXTURE_2D, cell->texref); + + CLTR_GLERR(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + CLTR_GLERR(); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + grid->tex_w, + grid->tex_h, + 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8, + grid->tex_data); + + CLTR_GLERR(); + + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + (GLsizei)cell->pixb->width, + (GLsizei)cell->pixb->height, + GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, + cell->pixb->data); + + CLTR_GLERR(); + + g_mutex_unlock(Mutex_GRID); + cltr_photo_grid_append_cell(grid, cell); - n_pixb++; + i++; } g_free(fullpath); @@ -200,49 +286,17 @@ cltr_photo_grid_populate(ClutterPhotoGrid *grid, g_dir_close (dir); + g_mutex_lock(Mutex_GRID); + grid->cell_active = g_list_first(grid->cells_tail); - /* Set up textures */ + grid->state = CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE; - grid->texs = util_malloc0(sizeof(GLuint)*n_pixb); - glGenTextures(n_pixb, grid->texs); + g_mutex_unlock(Mutex_GRID); - cell_item = g_list_first(grid->cells_tail); + cltr_photo_grid_redraw(grid); - do - { - ClutterPhotoGridCell *cell = (ClutterPhotoGridCell *)cell_item->data; - - glBindTexture(GL_TEXTURE_2D, grid->texs[i]); - - CLTR_DBG("loading texture %i", i); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - grid->tex_w, - grid->tex_h, - 0, GL_RGBA, - GL_UNSIGNED_INT_8_8_8_8, - grid->tex_data); - - CLTR_GLERR(); - - glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, - (GLsizei)cell->pixb->width, - (GLsizei)cell->pixb->height, - GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, - cell->pixb->data); - - CLTR_GLERR(); - - i++; - } - while ( (cell_item = g_list_next(cell_item)) != NULL ); + return NULL; } void @@ -252,11 +306,21 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) GList *cell_item; float zoom, trans_x, trans_y; + /* CLTR_MARK();*/ + glPushMatrix(); glClear(GL_COLOR_BUFFER_BIT); glClearColor( 0.6, 0.6, 0.62, 1.0); + + if (grid->cells_tail == NULL) + { + glPopMatrix(); + glXSwapBuffers(CltrCntx.xdpy, grid->parent->xwin); + return; + } + glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); @@ -273,7 +337,9 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) trans_x = grid->view_min_x; trans_y = grid->view_min_y; - if (grid->state != CLTR_PHOTO_GRID_STATE_BROWSE) + if (grid->state != CLTR_PHOTO_GRID_STATE_BROWSE + && grid->state != CLTR_PHOTO_GRID_STATE_LOADING + && grid->state != CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE) { /* Assume zoomed in */ zoom = grid->zoom_max; @@ -309,8 +375,9 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) { zoom = grid->zoom_min; grid->anim_step = 0; + trans_x = grid->view_min_x; + trans_y = grid->view_min_y; grid->state = CLTR_PHOTO_GRID_STATE_BROWSE; - } else { @@ -320,12 +387,6 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) zoom = grid->zoom_min + (grid->zoom_max - grid->zoom_min) * f; trans_x = (grid->view_max_x - grid->view_min_x) * f; trans_y = (grid->view_max_y - grid->view_min_y) * f; - -#if 0 - zoom = grid->zoom_min - + (( (grid->zoom_max - grid->zoom_min) / grid->anim_n_steps ) - * (grid->anim_n_steps - grid->anim_step) ); -#endif } } else if (grid->state == CLTR_PHOTO_GRID_STATE_ZOOMED_MOVE) @@ -372,6 +433,23 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) thumb_w = (pixb->width / grid->n_cols); thumb_h = (pixb->height / grid->n_rows); + if (cell->state == CLTR_PHOTO_GRID_CELL_STATE_APPEARING) + { + cell->anim_step -= 4; + + if (cell->anim_step <= 0) + { + cell->state = CLTR_PHOTO_GRID_CELL_STATE_STATIC; + } + else + { + thumb_w = thumb_w + cell->anim_step; + thumb_h = thumb_h + cell->anim_step; + } + + cell->anim_step = 0; + } + ew_border = thumb_w/8; ns_border = thumb_h/8; @@ -397,8 +475,9 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) /* Translate origin to rotation point ( photo center ) */ glTranslatef( x1 + ((x2-x1)/2), y1 + ((y2-y1)/2), 0.0); - /* Rotate around Z axis */ - glRotatef ( cell->angle, 0.0, 0.0, 1.0); + if (cell->state != CLTR_PHOTO_GRID_CELL_STATE_APPEARING) + /* Rotate around Z axis */ + glRotatef ( cell->angle, 0.0, 0.0, 1.0); /* Border - why need tex disabled ? */ glDisable(GL_TEXTURE_2D); @@ -416,7 +495,9 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) glEnable(GL_TEXTURE_2D); glEnable(GL_SMOOTH); - glBindTexture(GL_TEXTURE_2D, grid->texs[i]); + g_mutex_lock(Mutex_GRID); + + glBindTexture(GL_TEXTURE_2D, cell->texref); /* if (cell == grid->cell_active @@ -440,6 +521,8 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) glEnd (); } + g_mutex_unlock(Mutex_GRID); + /* back to regular non translated matrix */ glPopMatrix(); @@ -471,18 +554,29 @@ cltr_photo_grid_redraw(ClutterPhotoGrid *grid) glXSwapBuffers(CltrCntx.xdpy, grid->parent->xwin); + g_mutex_lock(Mutex_GRID); + + /* Hack, so final item get painted via threaded load */ + if (grid->state == CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE) + grid->state = CLTR_PHOTO_GRID_STATE_BROWSE; + + g_mutex_unlock(Mutex_GRID); + } ClutterPhotoGrid* cltr_photo_grid_new(ClutterWindow *win, int n_cols, int n_rows, - const gchar *imgs_path) + const gchar *img_path) { ClutterPhotoGrid *grid = NULL; + GThread *loader_thread; grid = util_malloc0(sizeof(ClutterPhotoGrid)); + grid->img_path = strdup(img_path); + grid->width = win->width; grid->height = win->height; grid->n_cols = n_cols; @@ -492,7 +586,7 @@ cltr_photo_grid_new(ClutterWindow *win, grid->cell_width = grid->width / n_cols; grid->cell_height = grid->height / n_rows; - grid->state = CLTR_PHOTO_GRID_STATE_BROWSE; + grid->state = CLTR_PHOTO_GRID_STATE_LOADING; grid->anim_n_steps = 50; /* value needs to be calced dep on rows */ grid->anim_step = 0; @@ -516,10 +610,14 @@ cltr_photo_grid_new(ClutterWindow *win, grid->tex_data = malloc (grid->tex_w * grid->tex_h * 4); - /* Load */ - cltr_photo_grid_populate(grid, imgs_path); + Mutex_GRID = g_mutex_new(); - grid->cell_active = g_list_first(grid->cells_tail); + /* Load */ + + loader_thread = g_thread_create (cltr_photo_grid_populate, + (gpointer)grid, + TRUE, + NULL); /* ctrl_photo_grid_cell_to_coords(grid, grid->cell_active, &x, &y); @@ -530,7 +628,8 @@ cltr_photo_grid_new(ClutterWindow *win, &grid->view_max_x, &grid->view_max_y); */ - cltr_photo_grid_redraw(grid); + + g_idle_add(cltr_photo_grid_idle_cb, grid); return grid; } diff --git a/cltr-photo-grid.h b/cltr-photo-grid.h index 38ca3200a..00b51aab1 100644 --- a/cltr-photo-grid.h +++ b/cltr-photo-grid.h @@ -9,6 +9,8 @@ typedef struct ClutterPhotoGridCell ClutterPhotoGridCell; typedef enum ClutterPhotoGridState { + CLTR_PHOTO_GRID_STATE_LOADING , + CLTR_PHOTO_GRID_STATE_LOAD_COMPLETE , CLTR_PHOTO_GRID_STATE_BROWSE , CLTR_PHOTO_GRID_STATE_ZOOM_IN , CLTR_PHOTO_GRID_STATE_ZOOMED , @@ -17,10 +19,23 @@ typedef enum ClutterPhotoGridState } ClutterPhotoGridState; +typedef enum ClutterPhotoGridCellState +{ + CLTR_PHOTO_GRID_CELL_STATE_APPEARING, + CLTR_PHOTO_GRID_CELL_STATE_STATIC, +} +ClutterPhotoGridCellState; + + struct ClutterPhotoGridCell { Pixbuf *pixb; float angle; + GLuint texref; + + gint anim_step; + + ClutterPhotoGridCellState state; }; struct ClutterPhotoGrid @@ -33,6 +48,8 @@ struct ClutterPhotoGrid /* ****** */ + gchar *img_path; + int n_rows; int n_cols; @@ -75,9 +92,8 @@ cltr_photo_grid_navigate(ClutterPhotoGrid *grid, void /* bleh badly named */ cltr_photo_grid_activate_cell(ClutterPhotoGrid *grid); -void -cltr_photo_grid_populate(ClutterPhotoGrid *grid, - const gchar *imgs_path) ; +gpointer +cltr_photo_grid_populate(gpointer data) ; void cltr_photo_grid_redraw(ClutterPhotoGrid *grid); diff --git a/cltr.c b/cltr.c index 4dcf0643d..a675710a3 100644 --- a/cltr.c +++ b/cltr.c @@ -62,6 +62,12 @@ static const GSourceFuncs x_event_funcs = { NULL }; +void +cltr_dispatch_expose(XExposeEvent *xexpev) +{ + cltr_photo_grid_redraw(Grid); +} + void cltr_dispatch_keypress(XKeyEvent *xkeyev) { @@ -107,7 +113,8 @@ cltr_dispatch_x_event (XEvent *xevent, CLTR_DBG("Map Notify Event"); break; case Expose: - CLTR_DBG("Expose"); + CLTR_DBG("Expose"); /* TODO COMPRESS */ + cltr_dispatch_expose(&xevent->xexpose); break; case KeyPress: CLTR_DBG("KeyPress"); @@ -136,10 +143,8 @@ cltr_init(int *argc, char ***argv) GSource *source; CltrXEventSource *display_source; - /* Not just yet .. g_thread_init (NULL); - XInitThreads (); - */ + // XInitThreads (); if ((CltrCntx.xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL) { @@ -281,15 +286,6 @@ test_idle_cb(gpointer data) } -gboolean -idle_cb(gpointer data) -{ - ClutterPhotoGrid *grid = (ClutterPhotoGrid *)data; - - cltr_photo_grid_redraw(grid); - - return TRUE; -} int main(int argc, char **argv) @@ -312,9 +308,11 @@ main(int argc, char **argv) Grid = grid; /* laaaaaazy globals */ - cltr_photo_grid_redraw(grid); + // cltr_photo_grid_redraw(grid); - g_idle_add(idle_cb, grid); + // g_idle_add(idle_cb, grid); + + // g_timeout_add (10, idle_cb, grid); // g_idle_add(test_idle_cb, (gpointer)win->xwin); diff --git a/cltr.h b/cltr.h index aa89808bb..da8395e5f 100644 --- a/cltr.h +++ b/cltr.h @@ -29,7 +29,7 @@ GLenum err = glGetError (); /* Roundtrip */ \ if (err != GL_NO_ERROR) \ { \ - g_printerr (__FILE__ ": GL Error: %i [at %s:%d]\n", \ + g_printerr (__FILE__ ": GL Error: %x [at %s:%d]\n", \ err, __func__, __LINE__); \ } \ } diff --git a/pixbuf.c b/pixbuf.c index edd3b7ec7..30c991dbf 100644 --- a/pixbuf.c +++ b/pixbuf.c @@ -538,6 +538,31 @@ pixel_set_vals(PixbufPixel *p, p->r = r; p->g = g; p->b = b; p->a = a; } +void +pixbuf_copy(Pixbuf *src_pixb, + Pixbuf *dst_pixb, + int srcx, + int srcy, + int srcw, + int srch, + int dstx, + int dsty) +{ + int j, *sp, *dp; + + sp = src_pixb->data + (srcy * src_pixb->width) + srcx; + dp = dst_pixb->data + (dsty * dst_pixb->width) + dstx; + + while (srch--) + { + j = srcw; + while (j--) + *dp++ = *sp++; + dp += (dst_pixb->width - srcw); + sp += (src_pixb->width - srcw); + } +} + Pixbuf * pixbuf_scale_down(Pixbuf *pixb, int new_width, diff --git a/pixbuf.h b/pixbuf.h index 80608b9ba..9c81ff641 100644 --- a/pixbuf.h +++ b/pixbuf.h @@ -59,6 +59,16 @@ pixel_set_vals(PixbufPixel *p, const unsigned char b, const unsigned char a); +void +pixbuf_copy(Pixbuf *src_pixb, + Pixbuf *dst_pixb, + int srcx, + int srcy, + int srcw, + int srch, + int dstx, + int dsty); + Pixbuf* pixbuf_scale_down(Pixbuf *pixb, int new_width,