mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 03:22:04 +00:00
Initial Import
This commit is contained in:
commit
aa2146acd3
15
Makefile
Normal file
15
Makefile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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`
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
|
||||||
|
|
||||||
|
OBJS=cltr.o pixbuf.o util.o fonts.o
|
||||||
|
|
||||||
|
clutter: $(OBJS)
|
||||||
|
$(CC) -g -Wall -o $@ $(OBJS) $(LIBS)
|
||||||
|
|
||||||
|
$(OBJS): pixbuf.h util.h fonts.h cltr.h
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr *.o clutter test
|
349
cltr-list.c
Normal file
349
cltr-list.c
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
#include "pixbuf.h"
|
||||||
|
#include "fonts.h"
|
||||||
|
|
||||||
|
#define TEX_W 1024 /* must be > than frame_w & power of 2 */
|
||||||
|
#define TEX_H 1024
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WINW 640
|
||||||
|
#define WINH 480
|
||||||
|
|
||||||
|
#define NBOXITEMS 10
|
||||||
|
|
||||||
|
#define NUMRECTS 4
|
||||||
|
#define MAXSCALE 2
|
||||||
|
#define MAXDIST (WINH)
|
||||||
|
#define MAXH (WINH/NUMRECTS)
|
||||||
|
#define MAXW (WINW - 20)
|
||||||
|
|
||||||
|
#ifndef ABS
|
||||||
|
#define ABS(a) ((a > 0) ? (a) : -1 * (a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct TableWidget TableWidget;
|
||||||
|
|
||||||
|
typedef struct TableWidgetCell TableWidgetCell;
|
||||||
|
|
||||||
|
int ScrollDir = 1;
|
||||||
|
|
||||||
|
struct TableWidget
|
||||||
|
{
|
||||||
|
int x,y,width,height;
|
||||||
|
|
||||||
|
TableWidgetCell *cells, *active_cell;
|
||||||
|
|
||||||
|
int active_cell_y;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TableWidgetCell
|
||||||
|
{
|
||||||
|
XRectangle rect;
|
||||||
|
TableWidgetCell *next, *prev;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Display *xdpy;
|
||||||
|
Window xwin;
|
||||||
|
XEvent xevent;
|
||||||
|
GC xgc;
|
||||||
|
Pixbuf *pix, *pix_orig;
|
||||||
|
|
||||||
|
float
|
||||||
|
distfunc(TableWidget *table, int d)
|
||||||
|
{
|
||||||
|
/* printf("returning %f\n", (exp((float)d/MAXDIST)/exp(1.0))); */
|
||||||
|
int maxdist = table->height;
|
||||||
|
|
||||||
|
d = (maxdist-ABS(d)) ;
|
||||||
|
return ( exp( (float)d/maxdist * 2.0 ) / exp(2.0) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TableWidgetCell*
|
||||||
|
table_cell_new()
|
||||||
|
{
|
||||||
|
TableWidgetCell *cell = NULL;
|
||||||
|
|
||||||
|
cell = malloc(sizeof(TableWidgetCell));
|
||||||
|
memset(cell, 0, sizeof(TableWidgetCell));
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableWidget*
|
||||||
|
table_new(int n_items)
|
||||||
|
{
|
||||||
|
TableWidget *table = NULL;
|
||||||
|
TableWidgetCell *last = NULL, *cell = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
table = malloc(sizeof(TableWidget));
|
||||||
|
memset(table, 0, sizeof(TableWidget));
|
||||||
|
|
||||||
|
table->width = WINW;
|
||||||
|
table->height = WINH;
|
||||||
|
|
||||||
|
table->active_cell_y = 100;
|
||||||
|
|
||||||
|
for (i=0; i<n_items; i++)
|
||||||
|
{
|
||||||
|
cell = table_cell_new();
|
||||||
|
if (last)
|
||||||
|
{
|
||||||
|
last->next = cell;
|
||||||
|
cell->prev = last;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
table->cells = table->active_cell = cell;
|
||||||
|
|
||||||
|
last = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->cells->rect.y = table->active_cell_y;
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
table_redraw(TableWidget *table)
|
||||||
|
{
|
||||||
|
TableWidgetCell *cur = table->cells;
|
||||||
|
int last = table->cells->rect.y;
|
||||||
|
|
||||||
|
glClearColor( 0.0, 0.0, 0.0, 1.0);
|
||||||
|
glClear (GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
cur->rect.y = last;
|
||||||
|
|
||||||
|
if (cur->rect.y+cur->rect.height >= 0)
|
||||||
|
{
|
||||||
|
cur->rect.width = MAXW * distfunc(table, cur->rect.y - table->active_cell_y);
|
||||||
|
cur->rect.height = MAXH * distfunc(table, cur->rect.y - table->active_cell_y);
|
||||||
|
|
||||||
|
cur->rect.x = (WINW - cur->rect.width)/6;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = cur->rect.y + cur->rect.height;
|
||||||
|
|
||||||
|
if (last > 0 && cur->rect.y < WINH) /* crappy clip */
|
||||||
|
{
|
||||||
|
float tx = 1.0, ty = 1.0, sx, sy;
|
||||||
|
int x1 = cur->rect.x, x2 = cur->rect.x + cur->rect.width;
|
||||||
|
int y1 = cur->rect.y, y2 = cur->rect.y + cur->rect.height;
|
||||||
|
|
||||||
|
tx = (float) pix->width / TEX_W;
|
||||||
|
ty = (float) pix->height / 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 ();
|
||||||
|
|
||||||
|
/* draw with X primitives
|
||||||
|
XDrawRectangle(xdpy, xwin, xgc,
|
||||||
|
cur->rect.x, cur->rect.y,
|
||||||
|
cur->rect.width, cur->rect.height);
|
||||||
|
|
||||||
|
XDrawLine(xdpy, xwin, xgc,
|
||||||
|
cur->rect.x, cur->rect.y,
|
||||||
|
cur->rect.x + cur->rect.width,
|
||||||
|
cur->rect.y + cur->rect.height);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
glXSwapBuffers(xdpy, xwin);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
table_scroll_down(TableWidget *table)
|
||||||
|
{
|
||||||
|
TableWidgetCell *next_active = table->active_cell->next;
|
||||||
|
|
||||||
|
if (!next_active)
|
||||||
|
{
|
||||||
|
ScrollDir = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (next_active->rect.y > table->active_cell_y)
|
||||||
|
{
|
||||||
|
table->cells->rect.y--;
|
||||||
|
table_redraw(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
table->active_cell = next_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
table_scroll_up(TableWidget *table)
|
||||||
|
{
|
||||||
|
TableWidgetCell *next_active = table->active_cell->prev;
|
||||||
|
|
||||||
|
if (!next_active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (next_active->rect.y < table->active_cell_y)
|
||||||
|
{
|
||||||
|
table->cells->rect.y++;
|
||||||
|
table_redraw(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
table->active_cell = next_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
TableWidget *table;
|
||||||
|
int i, j, last, offset=0;
|
||||||
|
XGCValues gcvals;
|
||||||
|
ClutterFont *font = NULL;
|
||||||
|
|
||||||
|
/* GL */
|
||||||
|
GLXContext context; /* OpenGL context */
|
||||||
|
GLubyte *texture_data = NULL;
|
||||||
|
XVisualInfo *vinfo;
|
||||||
|
static int attributes[] =
|
||||||
|
{
|
||||||
|
GLX_RGBA,
|
||||||
|
GLX_DOUBLEBUFFER,
|
||||||
|
GLX_RED_SIZE, 1,
|
||||||
|
GLX_GREEN_SIZE, 1,
|
||||||
|
GLX_BLUE_SIZE, 1,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ((xdpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: Cant open display\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((vinfo = glXChooseVisual(xdpy, DefaultScreen(xdpy), attributes)) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to find visual\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
xwin = XCreateSimpleWindow(xdpy,
|
||||||
|
RootWindow(xdpy, DefaultScreen(xdpy)),
|
||||||
|
0, 0,
|
||||||
|
WINW, WINH,
|
||||||
|
0, 0, WhitePixel(xdpy, DefaultScreen(xdpy)));
|
||||||
|
|
||||||
|
gcvals.foreground = BlackPixel(xdpy, DefaultScreen(xdpy));
|
||||||
|
gcvals.background = WhitePixel(xdpy, DefaultScreen(xdpy));
|
||||||
|
gcvals.line_width = 1;
|
||||||
|
|
||||||
|
xgc = XCreateGC(xdpy, RootWindow(xdpy, DefaultScreen(xdpy)),
|
||||||
|
GCForeground|GCBackground|GCLineWidth,
|
||||||
|
&gcvals);
|
||||||
|
|
||||||
|
context = glXCreateContext(xdpy, vinfo, 0, True);
|
||||||
|
glXMakeCurrent(xdpy, xwin, context);
|
||||||
|
|
||||||
|
glViewport (0, 0, WINW, WINH);
|
||||||
|
glMatrixMode (GL_MODELVIEW);
|
||||||
|
glLoadIdentity ();
|
||||||
|
glClearColor (0, 0, 0, 0);
|
||||||
|
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);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
glMatrixMode (GL_PROJECTION);
|
||||||
|
glLoadIdentity ();
|
||||||
|
glOrtho (0, WINW, WINH, 0, -1, 1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
texture_data = malloc (TEX_W * TEX_H * 4);
|
||||||
|
|
||||||
|
for (i=0; i < (TEX_W * TEX_H * 4); i++)
|
||||||
|
texture_data[i] = rand()%255;
|
||||||
|
|
||||||
|
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
|
||||||
|
TEX_W, TEX_H,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||||
|
|
||||||
|
pix_orig = pixbuf_new_from_file(argv[1]);
|
||||||
|
|
||||||
|
if (!pix_orig)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "image load failed\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pix = pixbuf_scale_down(pix_orig, 100, 100);
|
||||||
|
|
||||||
|
/*
|
||||||
|
font = font_new("Sans Bold 48");
|
||||||
|
|
||||||
|
font_draw(font, pix, "Hello World\nlove matmoo", 0, 0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
|
||||||
|
(GLsizei)pix->width,
|
||||||
|
(GLsizei)pix->height,
|
||||||
|
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
|
||||||
|
pix->data);
|
||||||
|
|
||||||
|
table = table_new(NBOXITEMS);
|
||||||
|
|
||||||
|
table_redraw(table);
|
||||||
|
|
||||||
|
XMapWindow(xdpy, xwin);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
// XNextEvent(xdpy, &ev);
|
||||||
|
// XClearWindow(xdpy, xwin);
|
||||||
|
table_redraw(table);
|
||||||
|
ScrollDir ? table_scroll_down(table) : table_scroll_up(table);
|
||||||
|
|
||||||
|
// scroll_to_next();
|
||||||
|
XFlush(xdpy);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
469
cltr.c
Normal file
469
cltr.c
Normal file
@ -0,0 +1,469 @@
|
|||||||
|
#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;
|
||||||
|
}
|
45
cltr.h
Normal file
45
cltr.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef _HAVE_CLTR_H
|
||||||
|
#define _HAVE_CLTR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "pixbuf.h"
|
||||||
|
#include "fonts.h"
|
||||||
|
|
||||||
|
#define CLTR_WANT_DEBUG 1
|
||||||
|
|
||||||
|
#if (CLTR_WANT_DEBUG)
|
||||||
|
|
||||||
|
#define CLTR_DBG(x, a...) \
|
||||||
|
g_printerr ( __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
|
||||||
|
|
||||||
|
#define CLTR_GLERR() \
|
||||||
|
{ \
|
||||||
|
GLenum err = glGetError (); /* Roundtrip */ \
|
||||||
|
if (err != GL_NO_ERROR) \
|
||||||
|
{ \
|
||||||
|
const GLubyte *message = gluErrorString (err); \
|
||||||
|
g_printerr (__FILE__ ": GL Error: %s [at %s:%d]\n", \
|
||||||
|
__func__, __LINE__); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define CLTR_DBG(x, a...) do {} while (0)
|
||||||
|
#define CLTR_GLERR() do {} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
173
fonts.c
Normal file
173
fonts.c
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "fonts.h"
|
||||||
|
|
||||||
|
ClutterFont*
|
||||||
|
font_new (const char *face)
|
||||||
|
{
|
||||||
|
ClutterFont *font;
|
||||||
|
PangoFontDescription *desc;
|
||||||
|
|
||||||
|
font = util_malloc0(sizeof(ClutterFont));
|
||||||
|
|
||||||
|
font->font_map = pango_ft2_font_map_new ();
|
||||||
|
|
||||||
|
pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (font->font_map),
|
||||||
|
96., 96.);
|
||||||
|
|
||||||
|
desc = pango_font_description_from_string (face);
|
||||||
|
|
||||||
|
font->context
|
||||||
|
= pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (font->font_map));
|
||||||
|
|
||||||
|
pango_context_set_font_description (font->context, desc);
|
||||||
|
|
||||||
|
pango_font_description_free (desc);
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int
|
||||||
|
decoration_get_title_width (LmcDecoration *decoration)
|
||||||
|
{
|
||||||
|
int title_space;
|
||||||
|
int width;
|
||||||
|
|
||||||
|
title_space = (decoration->window_width
|
||||||
|
+ lmc_theme->border_info.left
|
||||||
|
+ lmc_theme->border_info.right
|
||||||
|
- lmc_theme->border_info.left_unscaled
|
||||||
|
- lmc_theme->border_info.right_unscaled);
|
||||||
|
title_space = MAX (title_space, 0);
|
||||||
|
|
||||||
|
pango_layout_get_pixel_size (decoration->layout, &width, NULL);
|
||||||
|
|
||||||
|
return MIN (width + TITLE_RIGHT_PAD, title_space);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_layout_bitmap (PangoLayout *layout,
|
||||||
|
FT_Bitmap *bitmap,
|
||||||
|
PangoRectangle *ink)
|
||||||
|
{
|
||||||
|
PangoRectangle ink_rect;
|
||||||
|
|
||||||
|
pango_layout_get_extents (layout, &ink_rect, NULL);
|
||||||
|
|
||||||
|
/* XXX why the >> 10 */
|
||||||
|
ink->x = ink_rect.x >> 10;
|
||||||
|
ink->width = ((ink_rect.x + ink_rect.width + 1023) >> 10) - ink->x;
|
||||||
|
ink->y = ink_rect.y >> 10;
|
||||||
|
ink->height = ((ink_rect.y + ink_rect.height + 1023) >> 10) - ink->y;
|
||||||
|
|
||||||
|
if (ink->width == 0)
|
||||||
|
ink->width = 1;
|
||||||
|
if (ink->height == 0)
|
||||||
|
ink->height = 1;
|
||||||
|
|
||||||
|
bitmap->width = ink->width;
|
||||||
|
bitmap->pitch = (bitmap->width + 3) & ~3;
|
||||||
|
bitmap->rows = ink->height;
|
||||||
|
bitmap->buffer = malloc (bitmap->pitch * bitmap->rows);
|
||||||
|
bitmap->num_grays = 256;
|
||||||
|
bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
|
||||||
|
|
||||||
|
printf("FT_Bitmap is %ix%i\n", bitmap->width, bitmap->rows);
|
||||||
|
|
||||||
|
memset (bitmap->buffer, 0, bitmap->pitch * bitmap->rows);
|
||||||
|
|
||||||
|
pango_ft2_render_layout (bitmap, layout, - ink->x, - ink->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_layout_on_pixbuf (PangoLayout *layout,
|
||||||
|
Pixbuf *pixb,
|
||||||
|
const PixbufPixel *color,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int clip_x,
|
||||||
|
int clip_y,
|
||||||
|
int clip_width,
|
||||||
|
int clip_height)
|
||||||
|
{
|
||||||
|
PangoRectangle ink;
|
||||||
|
FT_Bitmap bitmap;
|
||||||
|
int i, j;
|
||||||
|
unsigned char *layout_bits;
|
||||||
|
|
||||||
|
get_layout_bitmap (layout, &bitmap, &ink);
|
||||||
|
|
||||||
|
layout_bits = bitmap.buffer;
|
||||||
|
|
||||||
|
for (j = y + ink.y; j < y + ink.y + ink.height; j++)
|
||||||
|
{
|
||||||
|
if (j >= clip_y && j < clip_y + clip_height)
|
||||||
|
{
|
||||||
|
int start_x, end_x;
|
||||||
|
|
||||||
|
start_x = MAX (x + ink.x, clip_x);
|
||||||
|
end_x = MIN (x + ink.x + ink.width, clip_x + clip_width);
|
||||||
|
|
||||||
|
if (start_x < end_x)
|
||||||
|
{
|
||||||
|
unsigned char *b = layout_bits + (start_x - (x + ink.x));
|
||||||
|
|
||||||
|
for (i = start_x ; i < end_x; i++)
|
||||||
|
{
|
||||||
|
PixbufPixel pixel;
|
||||||
|
int tr1, tg1, tb1, tr2, tg2, tb2;
|
||||||
|
int a = (*b * color->a + 0x80) >> 8;
|
||||||
|
|
||||||
|
pixbuf_get_pixel (pixb, i, j, &pixel);
|
||||||
|
|
||||||
|
tr1 = (255 - a) * pixel.r + 0x80;
|
||||||
|
tr2 = a * color->r + 0x80;
|
||||||
|
pixel.r = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8);
|
||||||
|
tg1 = (255 - a) * pixel.g + 0x80;
|
||||||
|
tg2 = a * color->g + 0x80;
|
||||||
|
pixel.g = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8);
|
||||||
|
tb1 = (255 - a) * pixel.b + 0x80;
|
||||||
|
tb2 = a * color->b + 0x80;
|
||||||
|
pixel.b = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8);
|
||||||
|
|
||||||
|
pixbuf_set_pixel (pixb, i, j, &pixel);
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_bits += bitmap.pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (bitmap.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
font_draw(ClutterFont *font,
|
||||||
|
Pixbuf *pixb,
|
||||||
|
const char *text,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
int layout_width, layout_height;
|
||||||
|
PangoLayout *layout;
|
||||||
|
PixbufPixel p = { 0xff,0,0,0x80 };
|
||||||
|
|
||||||
|
layout = pango_layout_new (font->context);
|
||||||
|
|
||||||
|
pango_layout_set_text (layout, text, -1);
|
||||||
|
|
||||||
|
pango_layout_get_pixel_size (layout,
|
||||||
|
&layout_width, &layout_height);
|
||||||
|
|
||||||
|
printf("%s() %ix%i\n", __func__, layout_width, layout_height);
|
||||||
|
|
||||||
|
/* cant rely on just clip - need to set layout width too */
|
||||||
|
|
||||||
|
draw_layout_on_pixbuf (layout, pixb, &p, x, y,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
pixb->width - x,
|
||||||
|
pixb->height - y);
|
||||||
|
}
|
31
fonts.h
Normal file
31
fonts.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef _HAVE_FONTS_H
|
||||||
|
#define _HAVE_FONTS_H
|
||||||
|
|
||||||
|
#include <pango/pangoft2.h>
|
||||||
|
|
||||||
|
#include "pixbuf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* Code based on stuff found in luminocity */
|
||||||
|
|
||||||
|
typedef struct ClutterFont ClutterFont;
|
||||||
|
|
||||||
|
struct ClutterFont
|
||||||
|
{
|
||||||
|
PangoFontMap *font_map;
|
||||||
|
PangoContext *context;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClutterFont*
|
||||||
|
font_new (const char *face);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
font_draw(ClutterFont *font,
|
||||||
|
Pixbuf *pixb,
|
||||||
|
const char *text,
|
||||||
|
int x,
|
||||||
|
int y);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
614
pixbuf.c
Normal file
614
pixbuf.c
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <string.h> /* For memset() */
|
||||||
|
#include <unistd.h> /* For read() */
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h> /* For mmap()/munmap() */
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
#include <jpeglib.h>
|
||||||
|
|
||||||
|
#include "pixbuf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int*
|
||||||
|
load_png_file( const char *file,
|
||||||
|
int *width,
|
||||||
|
int *height)
|
||||||
|
{
|
||||||
|
FILE *fd;
|
||||||
|
/* GLubyte *data; */
|
||||||
|
int *data;
|
||||||
|
unsigned char header[8];
|
||||||
|
int bit_depth, color_type;
|
||||||
|
png_uint_32 png_width, png_height, i, rowbytes;
|
||||||
|
png_structp png_ptr;
|
||||||
|
png_infop info_ptr;
|
||||||
|
png_bytep *row_pointers;
|
||||||
|
|
||||||
|
if ((fd = fopen( file, "rb" )) == NULL) return NULL;
|
||||||
|
|
||||||
|
/* check header etc */
|
||||||
|
|
||||||
|
fread(header, 1, 8, fd);
|
||||||
|
|
||||||
|
if (!png_check_sig(header, 8))
|
||||||
|
{
|
||||||
|
fclose(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (!png_ptr)
|
||||||
|
{
|
||||||
|
fclose(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if (!info_ptr)
|
||||||
|
{
|
||||||
|
png_destroy_read_struct( &png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||||
|
fclose(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp( png_ptr->jmpbuf ) )
|
||||||
|
{
|
||||||
|
png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io( png_ptr, fd );
|
||||||
|
|
||||||
|
png_set_sig_bytes( png_ptr, 8);
|
||||||
|
png_read_info( png_ptr, info_ptr);
|
||||||
|
|
||||||
|
png_get_IHDR( png_ptr, info_ptr,
|
||||||
|
&png_width, &png_height, &bit_depth,
|
||||||
|
&color_type, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
*width = (int) png_width;
|
||||||
|
*height = (int) png_height;
|
||||||
|
|
||||||
|
/* Tranform to req 8888 */
|
||||||
|
|
||||||
|
if (bit_depth == 16 ) png_set_strip_16(png_ptr); /* 16 -> 8 */
|
||||||
|
|
||||||
|
if (bit_depth < 8) png_set_packing(png_ptr); /* 1,2,4 -> 8 */
|
||||||
|
|
||||||
|
if (( color_type == PNG_COLOR_TYPE_GRAY ) ||
|
||||||
|
( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ))
|
||||||
|
png_set_gray_to_rgb(png_ptr);
|
||||||
|
|
||||||
|
if (( color_type == PNG_COLOR_TYPE_GRAY ) ||
|
||||||
|
( color_type == PNG_COLOR_TYPE_RGB ))
|
||||||
|
png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); /* req 1.2.7 */
|
||||||
|
|
||||||
|
if (( color_type == PNG_COLOR_TYPE_PALETTE )||
|
||||||
|
( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS )))
|
||||||
|
png_set_expand(png_ptr);
|
||||||
|
|
||||||
|
png_read_update_info( png_ptr, info_ptr);
|
||||||
|
|
||||||
|
/* Now load the actual data */
|
||||||
|
|
||||||
|
rowbytes = png_get_rowbytes( png_ptr, info_ptr);
|
||||||
|
|
||||||
|
data = (int *) malloc( (rowbytes*(*height + 1)));
|
||||||
|
|
||||||
|
row_pointers = (png_bytep *) malloc( (*height)*sizeof(png_bytep));
|
||||||
|
|
||||||
|
if (( data == NULL ) || ( row_pointers == NULL ))
|
||||||
|
{
|
||||||
|
png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
|
||||||
|
if (data) free(data);
|
||||||
|
if (row_pointers) free(row_pointers);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < *height; i++ )
|
||||||
|
row_pointers[i] = (png_bytep) data + i*rowbytes;
|
||||||
|
|
||||||
|
png_read_image( png_ptr, row_pointers );
|
||||||
|
png_read_end( png_ptr, NULL);
|
||||||
|
|
||||||
|
free(row_pointers);
|
||||||
|
png_destroy_read_struct( &png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct local_error_mgr
|
||||||
|
{
|
||||||
|
struct jpeg_error_mgr pub; /* "public" fields */
|
||||||
|
jmp_buf setjmp_buffer; /* for return to caller */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct local_error_mgr * local_error_ptr;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_jpeg_error_exit (j_common_ptr cinfo)
|
||||||
|
{
|
||||||
|
local_error_ptr err = (local_error_ptr) cinfo->err;
|
||||||
|
(*cinfo->err->output_message) (cinfo);
|
||||||
|
longjmp(err->setjmp_buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int*
|
||||||
|
load_jpg_file( const char *file,
|
||||||
|
int *width,
|
||||||
|
int *height)
|
||||||
|
{
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
struct local_error_mgr jerr;
|
||||||
|
FILE *infile; /* source file */
|
||||||
|
JSAMPLE *buffer; /* Output row buffer */
|
||||||
|
int row_stride; /* physical row width in output buffer */
|
||||||
|
|
||||||
|
int *data = NULL, *d = NULL;
|
||||||
|
|
||||||
|
if ((infile = fopen(file, "rb")) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = _jpeg_error_exit;
|
||||||
|
|
||||||
|
if (setjmp(jerr.setjmp_buffer)) {
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_create_decompress(&cinfo);
|
||||||
|
jpeg_stdio_src(&cinfo, infile);
|
||||||
|
jpeg_read_header(&cinfo, TRUE);
|
||||||
|
|
||||||
|
cinfo.do_fancy_upsampling = FALSE;
|
||||||
|
cinfo.do_block_smoothing = FALSE;
|
||||||
|
cinfo.out_color_space = JCS_RGB;
|
||||||
|
cinfo.scale_num = 1;
|
||||||
|
|
||||||
|
jpeg_start_decompress(&cinfo);
|
||||||
|
|
||||||
|
if( cinfo.output_components != 3 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
fprintf( stderr, "mbpixbuf: jpegs with %d channles not supported\n",
|
||||||
|
cinfo.output_components );
|
||||||
|
*/
|
||||||
|
jpeg_finish_decompress(&cinfo);
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = cinfo.output_width;
|
||||||
|
*height = cinfo.output_height;
|
||||||
|
|
||||||
|
d = data = malloc(*width * *height * 4 );
|
||||||
|
|
||||||
|
row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
|
buffer = malloc( sizeof(JSAMPLE)*row_stride );
|
||||||
|
|
||||||
|
while (cinfo.output_scanline < cinfo.output_height)
|
||||||
|
{
|
||||||
|
int off = 0;
|
||||||
|
|
||||||
|
jpeg_read_scanlines(&cinfo, &buffer, 1);
|
||||||
|
|
||||||
|
while (off < row_stride)
|
||||||
|
{
|
||||||
|
/* XXX Endianess */
|
||||||
|
*d++ =
|
||||||
|
(buffer[off] << 24) | /* RGBA */
|
||||||
|
(buffer[off+1] << 16) |
|
||||||
|
(buffer[off+2] << 8) |
|
||||||
|
(0xff << 0);
|
||||||
|
off += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_finish_decompress(&cinfo);
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
|
||||||
|
if (buffer) free(buffer);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* X pcx code, based on usplash code by paul coden */
|
||||||
|
/* http://courses.ece.uiuc.edu/ece390/books/labmanual/graphics-pcx.html */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char manufacturer;
|
||||||
|
unsigned char version;
|
||||||
|
unsigned char encoding;
|
||||||
|
unsigned char bits_per_pixel;
|
||||||
|
unsigned short xmin;
|
||||||
|
unsigned short ymin;
|
||||||
|
unsigned short xmax;
|
||||||
|
unsigned short ymax;
|
||||||
|
unsigned short xdpi;
|
||||||
|
unsigned short ydpi;
|
||||||
|
unsigned char colourmap[48];
|
||||||
|
unsigned char reserved;
|
||||||
|
unsigned char planes;
|
||||||
|
unsigned short scanline_length;
|
||||||
|
unsigned short palette_info;
|
||||||
|
unsigned short xsize;
|
||||||
|
unsigned short ysize;
|
||||||
|
unsigned char fill[54];
|
||||||
|
unsigned char data[0];
|
||||||
|
} pcx;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PCX_ZSOFT = 10,
|
||||||
|
PCX_RLE = 1,
|
||||||
|
PCX_WITH_PALETTE = 2,
|
||||||
|
PCX_COLOUR_MAP_LENGTH = 769
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Reads the first 128 bytes of a PCX headers, from an file
|
||||||
|
** descriptor, into memory.
|
||||||
|
** RETURN zero on success.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pcx_read_header(pcx *header, int fd)
|
||||||
|
{
|
||||||
|
if(!lseek(fd, 0, SEEK_SET))
|
||||||
|
if(read(fd, header, sizeof(pcx)) == sizeof(pcx))
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Does the file descriptor point to a PCX file, which is of a
|
||||||
|
** suitable colour-depth (8-bit) for us to use?
|
||||||
|
** RETURN zero on success.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pcx_is_suitable(int fd)
|
||||||
|
{
|
||||||
|
pcx header;
|
||||||
|
if(!pcx_read_header(&header, fd))
|
||||||
|
if(header.manufacturer == PCX_ZSOFT
|
||||||
|
/* && header.version >= PCX_WITH_PALETTE && */
|
||||||
|
&& header.encoding == PCX_RLE
|
||||||
|
&& header.planes == 3 /* 24bpp */
|
||||||
|
&& header.bits_per_pixel == 8 ) /* why not 24 from gimp */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Takes a raw PCX RLE stream and decompresses it into the destination
|
||||||
|
** buffer, which must be big enough!
|
||||||
|
** RETURN zero on success
|
||||||
|
**
|
||||||
|
** PCX images are RLE (Run Length Encoded as follows:
|
||||||
|
** if(top two bits are set) // >= 0xc0
|
||||||
|
** use bottom six bit (& 0x3f) as RLE count for next byte;
|
||||||
|
** else // < 0xc0
|
||||||
|
** copy one byte normally;
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pcx_raw_decode24(int *dest,
|
||||||
|
unsigned char *src,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int x, y, i, count;
|
||||||
|
int *d = dest;
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
memset(dest, 0xff, height * width * 4);
|
||||||
|
|
||||||
|
for(y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
d = dest + (y * width);
|
||||||
|
/* RGB */
|
||||||
|
for(x = 0; x < width;)
|
||||||
|
if(*src < 0xc0)
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*p = *src++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = *src++ & 0x3f;
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*p = *src++;
|
||||||
|
x += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d = dest + (y * width);
|
||||||
|
|
||||||
|
/* RGB */
|
||||||
|
for(x = 0; x < width;)
|
||||||
|
if(*src < 0xc0)
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*(p+1) = *src++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = *src++ & 0x3f;
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*(p+1) = *src++;
|
||||||
|
}
|
||||||
|
x += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = dest + (y * width);
|
||||||
|
|
||||||
|
/* RGB */
|
||||||
|
for(x = 0; x < width;)
|
||||||
|
if(*src < 0xc0)
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*(p+2) = *src++ ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = *src++ & 0x3f;
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
p = (unsigned char *)d++;
|
||||||
|
*(p+2) = *src++;
|
||||||
|
}
|
||||||
|
x += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int*
|
||||||
|
load_pcx_file (const char *filename,
|
||||||
|
int *width,
|
||||||
|
int *height)
|
||||||
|
{
|
||||||
|
int *data;
|
||||||
|
int fd, file_length;
|
||||||
|
pcx *header;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
if((fd = open(filename, O_RDONLY)) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Test file */
|
||||||
|
if(pcx_is_suitable(fd))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get file size */
|
||||||
|
if (fstat(fd, &st))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
file_length = st.st_size;
|
||||||
|
|
||||||
|
/* mmap the pcx file into our header */
|
||||||
|
header = mmap(NULL, file_length, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
if (header == MAP_FAILED)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Get the width and height of the image */
|
||||||
|
*width = header->xmax - header->xmin + 1;
|
||||||
|
*height = header->ymax - header->ymin + 1;
|
||||||
|
|
||||||
|
/* Allocate enough room for the data and colourmap*/
|
||||||
|
data = malloc(*width * *height * 4);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
munmap(header, file_length);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode the data */
|
||||||
|
pcx_raw_decode24(data, header->data, *width, *height);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
munmap(header, file_length);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Pixbuf*
|
||||||
|
pixbuf_new(int width, int height)
|
||||||
|
{
|
||||||
|
Pixbuf *pixb;
|
||||||
|
|
||||||
|
pixb = util_malloc0(sizeof(Pixbuf));
|
||||||
|
|
||||||
|
pixb->width = width;
|
||||||
|
pixb->height = height;
|
||||||
|
pixb->bytes_per_pixel = 4;
|
||||||
|
pixb->channels = 4;
|
||||||
|
pixb->bytes_per_line = pixb->bytes_per_pixel * pixb->width;
|
||||||
|
pixb->data = malloc(pixb->bytes_per_line * pixb->height);
|
||||||
|
|
||||||
|
/* memset ? */
|
||||||
|
|
||||||
|
return pixb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_unref(Pixbuf *pixb)
|
||||||
|
{
|
||||||
|
pixb->refcnt--;
|
||||||
|
|
||||||
|
if (pixb->refcnt < 0)
|
||||||
|
{
|
||||||
|
free(pixb->data);
|
||||||
|
free(pixb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pixbuf*
|
||||||
|
pixbuf_new_from_file(const char *filename)
|
||||||
|
{
|
||||||
|
Pixbuf *pixb;
|
||||||
|
|
||||||
|
pixb = util_malloc0(sizeof(Pixbuf));
|
||||||
|
|
||||||
|
if (!strcasecmp(&filename[strlen(filename)-4], ".png"))
|
||||||
|
pixb->data =load_png_file(filename, &pixb->width, &pixb->height);
|
||||||
|
else if (!strcasecmp(&filename[strlen(filename)-4], ".jpg")
|
||||||
|
|| !strcasecmp(&filename[strlen(filename)-5], ".jpeg"))
|
||||||
|
pixb->data = load_jpg_file( filename, &pixb->width, &pixb->height);
|
||||||
|
else if (!strcasecmp(&filename[strlen(filename)-4], ".pcx"))
|
||||||
|
pixb->data = load_pcx_file( filename, &pixb->width, &pixb->height);
|
||||||
|
|
||||||
|
if (pixb->data == NULL)
|
||||||
|
{
|
||||||
|
free (pixb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixb->bytes_per_pixel = 4;
|
||||||
|
pixb->channels = 4;
|
||||||
|
pixb->bytes_per_line = pixb->bytes_per_pixel * pixb->width;
|
||||||
|
|
||||||
|
return pixb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_set_pixel(Pixbuf *pixb, int x, int y, PixbufPixel *p)
|
||||||
|
{
|
||||||
|
int *offset = pixb->data + ( y * pixb->width) + x;
|
||||||
|
|
||||||
|
/* ARGB_32 MSB */
|
||||||
|
|
||||||
|
*offset = (p->r << 0) | (p->g << 8) | (p->b << 16) | (p->a << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_get_pixel(Pixbuf *pixb, int x, int y, PixbufPixel *p)
|
||||||
|
{
|
||||||
|
int *offset = pixb->data + ( y * pixb->width) + x;
|
||||||
|
|
||||||
|
/* ARGB_32 MSB */
|
||||||
|
|
||||||
|
p->r = *offset & 0xff;
|
||||||
|
p->g = (*offset >> 8) & 0xff;
|
||||||
|
p->b = (*offset >> 16) & 0xff;
|
||||||
|
p->a = (*offset >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void /* XXX could be DEFINE */
|
||||||
|
pixel_set_vals(PixbufPixel *p,
|
||||||
|
const unsigned char r,
|
||||||
|
const unsigned char g,
|
||||||
|
const unsigned char b,
|
||||||
|
const unsigned char a)
|
||||||
|
{
|
||||||
|
p->r = r; p->g = g; p->b = b; p->a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pixbuf *
|
||||||
|
pixbuf_scale_down(Pixbuf *pixb,
|
||||||
|
int new_width,
|
||||||
|
int new_height)
|
||||||
|
{
|
||||||
|
Pixbuf *pixb_scaled;
|
||||||
|
int *xsample, *ysample, *dest, *src, *srcy;
|
||||||
|
int i, x, y, r, g, b, a, nb_samples, xrange, yrange, rx, ry;
|
||||||
|
|
||||||
|
if ( new_width > pixb->width || new_height > pixb->height)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pixb_scaled = pixbuf_new(new_width, new_height);
|
||||||
|
|
||||||
|
xsample = malloc( (new_width+1) * sizeof(int));
|
||||||
|
ysample = malloc( (new_height+1) * sizeof(int));
|
||||||
|
|
||||||
|
for ( i = 0; i <= new_width; i++ )
|
||||||
|
xsample[i] = i * pixb->width / new_width;
|
||||||
|
|
||||||
|
for ( i = 0; i <= new_height; i++ )
|
||||||
|
ysample[i] = i * pixb->height / new_height * pixb->width;
|
||||||
|
|
||||||
|
dest = pixb_scaled->data;
|
||||||
|
|
||||||
|
/* scan output image */
|
||||||
|
for ( y = 0; y < new_height; y++ )
|
||||||
|
{
|
||||||
|
yrange = ( ysample[y+1] - ysample[y] ) / pixb->width;
|
||||||
|
for ( x = 0; x < new_width; x++)
|
||||||
|
{
|
||||||
|
xrange = xsample[x+1] - xsample[x];
|
||||||
|
srcy = pixb->data + ( ysample[y] + xsample[x] );
|
||||||
|
|
||||||
|
/* average R,G,B,A values on sub-rectangle of source image */
|
||||||
|
nb_samples = xrange * yrange;
|
||||||
|
|
||||||
|
if ( nb_samples > 1 )
|
||||||
|
{
|
||||||
|
r = 0; g = 0; b = 0; a = 0;
|
||||||
|
for ( ry = 0; ry < yrange; ry++ )
|
||||||
|
{
|
||||||
|
src = srcy;
|
||||||
|
for ( rx = 0; rx < xrange; rx++ )
|
||||||
|
{
|
||||||
|
/* average R,G,B,A values */
|
||||||
|
r += *src & 0xff;
|
||||||
|
g += ((*src) >> 8) & 0xff;
|
||||||
|
b += ((*src) >> 16) & 0xff;
|
||||||
|
a += ((*src) >> 24) & 0xff;
|
||||||
|
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcy += pixb->width;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest++ =
|
||||||
|
((unsigned char)(r/nb_samples) << 0) |
|
||||||
|
((unsigned char)(g/nb_samples) << 8) |
|
||||||
|
((unsigned char)(b/nb_samples) << 16) |
|
||||||
|
((unsigned char)(a/nb_samples) << 24);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dest++ = *srcy++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
free( xsample );
|
||||||
|
free( ysample );
|
||||||
|
|
||||||
|
return pixb_scaled;
|
||||||
|
}
|
67
pixbuf.h
Normal file
67
pixbuf.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef _HAVE_PIXBUF_H
|
||||||
|
#define _HAVE_PIXBUF_H
|
||||||
|
|
||||||
|
typedef struct Pixbuf Pixbuf;
|
||||||
|
typedef struct PixbufPixel PixbufPixel;
|
||||||
|
|
||||||
|
typedef enum PixbufFormat
|
||||||
|
{
|
||||||
|
PB_FMT_RGBA
|
||||||
|
}
|
||||||
|
PixbufFormat;
|
||||||
|
|
||||||
|
struct PixbufPixel
|
||||||
|
{
|
||||||
|
unsigned char r,g,b,a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Pixbuf
|
||||||
|
{
|
||||||
|
int *data;
|
||||||
|
int bytes_per_pixel; /* bits per pixel = bpp << 3 */
|
||||||
|
int channels; /* 4 with alpha */
|
||||||
|
int width, height;
|
||||||
|
int bytes_per_line; /* ( width * bpp ) */
|
||||||
|
|
||||||
|
int refcnt; /* starts at 0 */
|
||||||
|
|
||||||
|
void *meta; /* for jpeg meta text ? to a hash ? */
|
||||||
|
|
||||||
|
/* Possibles */
|
||||||
|
|
||||||
|
int rmask, gmask, bmask, amask; /* Masks - good for packed formats > */
|
||||||
|
int has_alpha; /* Rather than channels ? */
|
||||||
|
|
||||||
|
|
||||||
|
/* PixbufFormat format; like GL format */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Pixbuf*
|
||||||
|
pixbuf_new_from_file(const char *filename);
|
||||||
|
|
||||||
|
Pixbuf*
|
||||||
|
pixbuf_new(int width, int height);
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_unref(Pixbuf *pixb);
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_set_pixel(Pixbuf *pixb, int x, int y, PixbufPixel *p);
|
||||||
|
|
||||||
|
void
|
||||||
|
pixbuf_get_pixel(Pixbuf *pixbuf, int x, int y, PixbufPixel *p);
|
||||||
|
|
||||||
|
void
|
||||||
|
pixel_set_vals(PixbufPixel *p,
|
||||||
|
const unsigned char r,
|
||||||
|
const unsigned char g,
|
||||||
|
const unsigned char b,
|
||||||
|
const unsigned char a);
|
||||||
|
|
||||||
|
Pixbuf*
|
||||||
|
pixbuf_scale_down(Pixbuf *pixb,
|
||||||
|
int new_width,
|
||||||
|
int new_height);
|
||||||
|
|
||||||
|
#endif
|
26
util.c
Normal file
26
util.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* misc utility code */
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
util_malloc0(int size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = malloc(size);
|
||||||
|
memset(p, 0, size);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
util_next_p2 ( int a )
|
||||||
|
{
|
||||||
|
int rval=1;
|
||||||
|
while(rval < a)
|
||||||
|
rval <<= 1;
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user