mirror of
https://github.com/brl/mutter.git
synced 2024-11-29 19:40:43 -05:00
470 lines
9.2 KiB
C
470 lines
9.2 KiB
C
#include "cltr.h"
|
|
|
|
float Zoom = 0.1;
|
|
|
|
typedef struct ClutterMainContext ClutterMainContext;
|
|
|
|
struct ClutterMainContext
|
|
{
|
|
Display *xdpy;
|
|
Window xwin_root;
|
|
int xscreen;
|
|
GC xgc;
|
|
GLXContext gl_context;
|
|
};
|
|
|
|
typedef struct ClutterWindow ClutterWindow;
|
|
|
|
struct ClutterWindow
|
|
{
|
|
Window xwin;
|
|
int width;
|
|
int height;
|
|
};
|
|
|
|
ClutterMainContext CltrCntx;
|
|
|
|
int
|
|
cltr_init(int *argc, char ***argv)
|
|
{
|
|
int gl_attributes[] =
|
|
{
|
|
GLX_RGBA,
|
|
GLX_DOUBLEBUFFER,
|
|
GLX_RED_SIZE, 1,
|
|
GLX_GREEN_SIZE, 1,
|
|
GLX_BLUE_SIZE, 1,
|
|
0
|
|
};
|
|
|
|
XVisualInfo *vinfo;
|
|
|
|
if ((CltrCntx.xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CltrCntx.xscreen = DefaultScreen(CltrCntx.xdpy);
|
|
CltrCntx.xwin_root = RootWindow(CltrCntx.xdpy, CltrCntx.xscreen);
|
|
|
|
if ((vinfo = glXChooseVisual(CltrCntx.xdpy,
|
|
CltrCntx.xscreen,
|
|
gl_attributes)) == NULL)
|
|
{
|
|
fprintf(stderr, "Unable to find visual\n");
|
|
return 0;
|
|
}
|
|
|
|
CltrCntx.gl_context = glXCreateContext(CltrCntx.xdpy, vinfo, 0, True);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
ClutterWindow*
|
|
cltr_window_new(int width, int height)
|
|
{
|
|
ClutterWindow *win;
|
|
|
|
win = util_malloc0(sizeof(ClutterWindow));
|
|
|
|
win->width = width;
|
|
win->height = height;
|
|
|
|
win->xwin = XCreateSimpleWindow(CltrCntx.xdpy,
|
|
CltrCntx.xwin_root,
|
|
0, 0,
|
|
width, height,
|
|
0, 0, WhitePixel(CltrCntx.xdpy,
|
|
CltrCntx.xscreen));
|
|
|
|
glXMakeCurrent(CltrCntx.xdpy, win->xwin, CltrCntx.gl_context);
|
|
|
|
glViewport (0, 0, width, height);
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glLoadIdentity ();
|
|
glClearColor (0xff, 0xff, 0xff, 0xff);
|
|
glClearDepth (1.0f);
|
|
|
|
glDisable (GL_DEPTH_TEST);
|
|
glDepthMask (GL_FALSE);
|
|
glDisable (GL_CULL_FACE);
|
|
glShadeModel (GL_FLAT);
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
glLoadIdentity ();
|
|
glOrtho (0, width, height, 0, -1, 1);
|
|
|
|
glMatrixMode (GL_PROJECTION);
|
|
|
|
/* likely better somewhere elese */
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
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);
|
|
|
|
return win;
|
|
}
|
|
|
|
void
|
|
cltr_main_loop()
|
|
{
|
|
XEvent xev;
|
|
|
|
for (;;)
|
|
{
|
|
XNextEvent(CltrCntx.xdpy, &xev);
|
|
}
|
|
}
|
|
|
|
/* xxxxxxxxxxxxx */
|
|
|
|
typedef struct ClutterPhotoGrid ClutterPhotoGrid;
|
|
|
|
typedef struct ClutterPhotoGridCell ClutterPhotoGridCell;
|
|
|
|
typedef enum ClutterPhotoGridState
|
|
{
|
|
CLTR_PHOTO_GRID_STATE_BROWSE,
|
|
CLTR_PHOTO_GRID_STATE_ZOOM_IN,
|
|
CLTR_PHOTO_GRID_STATE_ZOOMED,
|
|
CLTR_PHOTO_GRID_STATE_ZOOM_OUT,
|
|
}
|
|
ClutterPhotoGridState;
|
|
|
|
struct ClutterPhotoGrid
|
|
{
|
|
/* XXX should be base widget stuff */
|
|
int x,y;
|
|
int width;
|
|
int height;
|
|
ClutterWindow *parent;
|
|
|
|
/* ****** */
|
|
|
|
int n_rows;
|
|
int n_cols;
|
|
|
|
int cell_width;
|
|
int cell_height;
|
|
|
|
GList *cells_tail;
|
|
|
|
int tex_w;
|
|
int tex_h;
|
|
int *tex_data;
|
|
GLuint *texs;
|
|
|
|
ClutterPhotoGridState state;
|
|
};
|
|
|
|
void
|
|
cltr_photo_grid_append_cell(ClutterPhotoGrid *grid,
|
|
Pixbuf *pixb,
|
|
const gchar *filename)
|
|
{
|
|
int neww = 0, newh = 0;
|
|
|
|
int maxw = grid->width, maxh = grid->height;
|
|
|
|
Pixbuf *pixb_scaled = NULL;
|
|
|
|
if (pixb->width > pixb->height) /* landscape */
|
|
{
|
|
if (pixb->width > maxw)
|
|
{
|
|
neww = maxw;
|
|
newh = (neww * pixb->height) / pixb->width;
|
|
}
|
|
}
|
|
else /* portrait */
|
|
{
|
|
if (pixb->height > maxh)
|
|
{
|
|
newh = maxh;
|
|
neww = (newh * pixb->width) / pixb->height;
|
|
}
|
|
}
|
|
|
|
if (neww || newh)
|
|
{
|
|
pixb_scaled = pixbuf_scale_down(pixb, neww, newh);
|
|
pixbuf_unref(pixb);
|
|
}
|
|
else pixb_scaled = pixb;
|
|
|
|
grid->cells_tail = g_list_append(grid->cells_tail, pixb_scaled);
|
|
|
|
CLTR_DBG ("loaded %s at %ix%i", filename, neww, newh);
|
|
}
|
|
|
|
void
|
|
cltr_photo_grid_populate(ClutterPhotoGrid *grid,
|
|
const char *imgs_path)
|
|
{
|
|
GDir *dir;
|
|
GError *error;
|
|
const gchar *entry = NULL;
|
|
gchar *fullpath = NULL;
|
|
int n_pixb = 0, i =0;
|
|
GList *cell;
|
|
|
|
if ((dir = g_dir_open (imgs_path, 0, &error)) == NULL)
|
|
{
|
|
/* handle this much better */
|
|
fprintf(stderr, "failed to open '%s'\n", imgs_path);
|
|
return;
|
|
}
|
|
|
|
while((entry = g_dir_read_name (dir)) != NULL)
|
|
{
|
|
Pixbuf *pixb = NULL;
|
|
fullpath = g_strconcat(imgs_path, "/", entry, NULL);
|
|
|
|
pixb = pixbuf_new_from_file(fullpath);
|
|
|
|
if (pixb)
|
|
{
|
|
cltr_photo_grid_append_cell(grid, pixb, entry);
|
|
n_pixb++;
|
|
}
|
|
|
|
g_free(fullpath);
|
|
}
|
|
|
|
g_dir_close (dir);
|
|
|
|
/* Set up textures */
|
|
|
|
grid->texs = util_malloc0(sizeof(GLuint)*n_pixb);
|
|
glGenTextures(n_pixb, grid->texs);
|
|
|
|
cell = g_list_first(grid->cells_tail);
|
|
|
|
do
|
|
{
|
|
Pixbuf *tpixb = (Pixbuf *)cell->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);
|
|
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
|
|
(GLsizei)tpixb->width,
|
|
(GLsizei)tpixb->height,
|
|
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
|
tpixb->data);
|
|
|
|
i++;
|
|
}
|
|
while ( (cell = g_list_next(cell)) != NULL );
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
void
|
|
cltr_photo_grid_redraw(ClutterPhotoGrid *grid)
|
|
{
|
|
int x = 0, y = 0, rows = grid->n_rows, cols = 0, i =0;
|
|
GList *cell;
|
|
|
|
glClearColor( 0.0, 0.0, 0.0, 1.0);
|
|
glClear (GL_COLOR_BUFFER_BIT);
|
|
|
|
/*
|
|
|
|
glTranslatef( 0.0, 0.0, 0.1);
|
|
*/
|
|
|
|
glLoadIdentity ();
|
|
glScalef( Zoom, Zoom, Zoom);
|
|
|
|
Zoom += 0.01;
|
|
|
|
cell = g_list_first(grid->cells_tail);
|
|
|
|
while (rows--)
|
|
{
|
|
cols = grid->n_cols;
|
|
x = 0;
|
|
while (cols--)
|
|
{
|
|
Pixbuf *pixb = NULL;
|
|
float tx, ty;
|
|
int x1, x2, y1, y2, thumb_w, thumb_h;
|
|
int ns_border, ew_border;
|
|
|
|
pixb = (Pixbuf *)cell->data;
|
|
|
|
thumb_w = (pixb->width / grid->n_cols);
|
|
thumb_h = (pixb->height / grid->n_rows);
|
|
|
|
ew_border = thumb_w/4;
|
|
ns_border = thumb_h/4;
|
|
|
|
thumb_w -= (2 * ew_border);
|
|
thumb_h -= (2 * ns_border);
|
|
|
|
x1 = x + ew_border;
|
|
y1 = y + ns_border;
|
|
|
|
x2 = x1 + thumb_w;
|
|
y2 = y1 + thumb_h;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, grid->texs[i]);
|
|
|
|
/*
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
|
|
(GLsizei)pixb->width,
|
|
(GLsizei)pixb->height,
|
|
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
|
pixb->data);
|
|
*/
|
|
tx = (float) pixb->width / grid->tex_w;
|
|
ty = (float) pixb->height / grid->tex_h;
|
|
|
|
glBegin (GL_QUADS);
|
|
glTexCoord2f (tx, ty); glVertex2i (x2, y2);
|
|
glTexCoord2f (0, ty); glVertex2i (x1, y2);
|
|
glTexCoord2f (0, 0); glVertex2i (x1, y1);
|
|
glTexCoord2f (tx, 0); glVertex2i (x2, y1);
|
|
glEnd ();
|
|
|
|
cell = g_list_next(cell);
|
|
|
|
if (!cell)
|
|
goto finish;
|
|
|
|
x += grid->cell_width;
|
|
i++;
|
|
}
|
|
y += grid->cell_height;
|
|
}
|
|
|
|
finish:
|
|
glXSwapBuffers(CltrCntx.xdpy, grid->parent->xwin);
|
|
|
|
}
|
|
|
|
ClutterPhotoGrid*
|
|
cltr_photo_grid_new(ClutterWindow *win,
|
|
int n_cols,
|
|
int n_rows,
|
|
const char *imgs_path)
|
|
{
|
|
ClutterPhotoGrid *grid = NULL;
|
|
|
|
grid = util_malloc0(sizeof(ClutterPhotoGrid));
|
|
|
|
grid->width = win->width;
|
|
grid->height = win->height;
|
|
grid->n_cols = n_cols;
|
|
grid->n_rows = n_rows;
|
|
grid->parent = win;
|
|
|
|
grid->cell_width = grid->width / n_cols;
|
|
grid->cell_height = grid->height / n_rows;
|
|
|
|
/* Below needs to go else where */
|
|
|
|
grid->tex_w = 1024;
|
|
grid->tex_h = 512;
|
|
|
|
grid->tex_data = malloc (grid->tex_w * grid->tex_h * 4);
|
|
|
|
/*
|
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
|
|
grid->tex_w, grid->tex_h,
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, grid->tex_data);
|
|
*/
|
|
|
|
/* Load */
|
|
cltr_photo_grid_populate(grid, imgs_path);
|
|
|
|
cltr_photo_grid_redraw(grid);
|
|
|
|
return grid;
|
|
}
|
|
|
|
static Bool
|
|
get_xevent_timed(Display *dpy,
|
|
XEvent *event_return,
|
|
struct timeval *tv)
|
|
{
|
|
if (tv->tv_usec == 0 && tv->tv_sec == 0)
|
|
{
|
|
XNextEvent(dpy, event_return);
|
|
return True;
|
|
}
|
|
|
|
XFlush(dpy);
|
|
|
|
if (XPending(dpy) == 0)
|
|
{
|
|
int fd = ConnectionNumber(dpy);
|
|
fd_set readset;
|
|
FD_ZERO(&readset);
|
|
FD_SET(fd, &readset);
|
|
|
|
if (select(fd+1, &readset, NULL, NULL, tv) == 0)
|
|
return False;
|
|
else {
|
|
XNextEvent(dpy, event_return);
|
|
return True;
|
|
}
|
|
|
|
} else {
|
|
XNextEvent(dpy, event_return);
|
|
return True;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
ClutterPhotoGrid *grid = NULL;
|
|
ClutterWindow *win = NULL;
|
|
|
|
cltr_init(&argc, &argv);
|
|
|
|
win = cltr_window_new(640, 480);
|
|
|
|
grid = cltr_photo_grid_new(win, 3, 3, argv[1]);
|
|
|
|
cltr_photo_grid_redraw(grid);
|
|
|
|
XFlush(CltrCntx.xdpy);
|
|
|
|
XMapWindow(CltrCntx.xdpy, grid->parent->xwin);
|
|
|
|
{
|
|
for (;;)
|
|
{
|
|
cltr_photo_grid_redraw(grid);
|
|
XFlush(CltrCntx.xdpy);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|