commit 520edea668a1044786efc326dc85241a47600f9c Author: Carsten Haitzler Date: Sun Aug 1 22:14:11 1999 +0000 adding imlib2 code in.. NOT a lib yet... :) but playable code and loader system SVN revision: 27 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..df9dbbb --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +INSTALL = install + +SRCS = rend.c ximage.c scale.c main.c rgba.c image.c color.c grab.c \ + blend.c file.c +OBJS = $(SRCS:.c=.o) +BINDIR = /usr/local/bin +BIN = imlib2 +LIBS = -L/usr/X11R6/lib/ -lX11 -lXext -ldl + +CFLAGS = -O -g -mpentium -mcpu=pentium -march=pentium + +imlib2: $(OBJS) + $(RM) $@ + $(CC) -o $@ $(OBJS) $(LIBS) + $(CC) loader_png.c -o png.so -Wl,-soname -Wl,png.so -shared -lpng -lz -lm + +clean:: + $(RM) $(BIN) *.CKP *.ln *.BAK *.bak *.o *.so core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"* + +c.o: + $(CC) $(CFLAGS) -I/usr/X11R6/include -c $< -o $@ +load.o: + $(CC) $(CFLAGS) -I/usr/X11R6/include -c $< -o $@ + +install:: + $(INSTALL) $(BIN) $(BINDIR) + diff --git a/README b/README new file mode 100644 index 0000000..dd4b969 --- /dev/null +++ b/README @@ -0,0 +1,63 @@ +Imlib 2.0 pre pre pre pre alpha toy code... + +WARNING! + +this isn't even a library yet - it's a single program thats modularised to +become a librayr once it's all debugged. + +what you DO have here is: + +color allocation & adjustment code - if in 8bbp or less it will cose the +larges colorcube it can that fits in your available colormap space - right +now the code uses the default colormap, but if you look at color.c carefully +you'll see the code will not be hard to change (have prefercnes as to size +of colorcube etc.) + +does alpha blending onto any X drawable with any colormap. +does ``high quality'' rendering with dithering available for all modes up to +16bpp (1bpp, 8bpp, 15bpp, 16bpp). + +probably has nasty endianess problems. + +has VERY VERY VERY fast rendering code. +has anti-aliased scaling up and down code. + +has a modularised loader system (works right now - but still possible +changes might have to be made) +simple to get this going: +mkdir ~/.loaders +mkdir ~/.loaders/image +cp png.so ~/.loaders/image + +you just installed the png loader - it's theonly one i've written and it +isnt very good (comments in code - load.c) but it works. +the laoder system automagically updates yhe loaders were you to dump new +files there or overwrite the old ones to any program RUNTIME will pick up +the new code.. :) you dont even have to restart the program.. OOH what joy :) +the image caching is all there and the pixmap caching backend is there too. +there is nothign to generate pixmaps yet - that has yet to come (it will use +the rendering code in rend.c). + +things that still need to be worked on: +* colormodifiers (to do gamma etc. correction - need to develop a new system +wherby i can uniquely tag pixmaps with a colormodifier ID for caching +properly). +* border scaling - you know - like E does now for buttons etc. +* saving functions +* image manipulation funcitons (flip, rotate, scale etc of original data) +* nice api for the actual library with context-like system (the api you see +here is actually going to be the internal api for imlib - a level down from +what api the user actually gets to see & use - all access to image data will +be goverend by going thru the api too rather than just snarfing structure +memebrs) +* a new name for imlib2.0 - 2.0 just sounds boring :) +* more loader / saver modules for jpeg, ppm, pgm, pgm, xpm, tiff etc... +* RGBA drawing area - basically a RGBA buffer with RGBA buffer ops written +(copyarea, poasteimage, fillrect, drawline, drawtext etc. so you can have a +little virtual RGBA framebuffer - also will include rectangle os ineterst +updating mechanism (so anly the parts of the RGBA buffer that were drawn to +are drawn and updated to the scren). +* more flim! + + + diff --git a/blend.c b/blend.c new file mode 100644 index 0000000..3d4dcbc --- /dev/null +++ b/blend.c @@ -0,0 +1,54 @@ +#include "common.h" +#include "blend.h" + +void +BlendRGBAToRGBA(DATA32 *src, int src_jump, DATA32 *dst, int dst_jump, + int w, int h) +{ + int x, y; + DATA32 *p1, *p2; + + for (y = 0; y < h; y++) + { + DATA8 a, nr, ng, nb, r, g, b, rr, gg, bb; + int tmp; + + p1 = src + (y * (w + src_jump)); + p2 = dst + (y * (w + dst_jump)); + for (x = 0; x < w; x++) + { + a = (*p1 >> 24) & 0xff; + if (a < 255) + { +#if 1 + r = 255 - a; + *p2 = + ((((*p1 & 0x00ff00ff) * a) >> 8) & 0x00ff00ff) + + ((((*p1 >> 8) & 0x00ff00ff) * a) & 0xff00ff00) + + ((((*p2 & 0x00ff00ff) * r) >> 8) & 0x00ff00ff) + + ((((*p2 >> 8) & 0x00ff00ff) * r) & 0xff00ff00); +#else + r = (*p1 ) & 0xff; + g = (*p1 >> 8 ) & 0xff; + b = (*p1 >> 16) & 0xff; + + rr = (*p2 ) & 0xff; + gg = (*p2 >> 8 ) & 0xff; + bb = (*p2 >> 16) & 0xff; + + tmp = (r - rr) * a; + nr = rr + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (g - gg) * a; + ng = gg + ((tmp + (tmp >> 8) + 0x80) >> 8); + tmp = (b - bb) * a; + nb = bb + ((tmp + (tmp >> 8) + 0x80) >> 8); + *p2 = ((nb & 0xff) << 16) | ((ng & 0xff) << 8) | (nr & 0xff); +#endif + } + else + *p2 = *p1; + p1++; + p2++; + } + } +} diff --git a/blend.h b/blend.h new file mode 100644 index 0000000..25a03a5 --- /dev/null +++ b/blend.h @@ -0,0 +1,6 @@ +#ifndef __BLEND +#define __BLEND 1 +void +BlendRGBAToRGBA(DATA32 *src, int src_jump, DATA32 *dst, int dst_jump, + int w, int h); +#endif diff --git a/color.c b/color.c new file mode 100644 index 0000000..cedc14f --- /dev/null +++ b/color.c @@ -0,0 +1,298 @@ +#include +#include +#include "common.h" +#include "color.h" + +/* FIXME: DATA32 must become DATA8 */ +DATA8 _dither_color_lut[256]; +DATA8 _pal_type = 0; + +void +AllocColorTable(Display *d, Colormap cmap) +{ + if (AllocColors332(d, cmap)) + return; + if (AllocColors232(d, cmap)) + return; + if (AllocColors222(d, cmap)) + return; + if (AllocColors221(d, cmap)) + return; + if (AllocColors121(d, cmap)) + return; + if (AllocColors111(d, cmap)) + return; + if (AllocColors1(d, cmap)) + return; +} + +char +AllocColors332(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 8; r++) + { + for (g = 0; g < 8; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + int val; + + val = (r << 5) | (r << 2) | (r >> 1); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 5) | (g << 2) | (g >> 1); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 0; + return 1; +} + +char +AllocColors232(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 4; r++) + { + for (g = 0; g < 8; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + int val; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 5) | (g << 2) | (g >> 1); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 1; + return 1; +} + +char +AllocColors222(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 4; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 4; b++) + { + XColor xcl; + int val; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 6) | (b << 4) | (b << 2) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 2; + return 1; +} + +char +AllocColors221(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 4; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + int val; + + val = (r << 6) | (r << 4) | (r << 2) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 3; + return 1; +} + +char +AllocColors121(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 2; r++) + { + for (g = 0; g < 4; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + int val; + + val = (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r << 2) | (r << 1) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 6) | (g << 4) | (g << 2) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 4; + return 1; +} + +char +AllocColors111(Display *d, Colormap cmap) +{ + int r, g, b, i = 0; + + for (r = 0; r < 2; r++) + { + for (g = 0; g < 2; g++) + { + for (b = 0; b < 2; b++) + { + XColor xcl; + int val; + + val = (r << 7) | (r << 6) | (r << 5) | (r << 4) | (r << 3) | (r << 2) | (r << 1) | (r); + xcl.red = (unsigned short)((val << 8) | (val)); + val = (g << 7) | (g << 6) | (g << 5) | (g << 4) | (g << 3) | (g << 2) | (g << 1) | (g); + xcl.green = (unsigned short)((val << 8) | (val)); + val = (b << 7) | (b << 6) | (b << 5) | (b << 4) | (b << 3) | (b << 2) | (b << 1) | (b); + xcl.blue = (unsigned short)((val << 8) | (val)); + if (!XAllocColor(d, cmap, &xcl)) + { + unsigned long pixels[256]; + int j; + + if (i > 0) + { + for(j = 0; j < i; j++) + pixels[j] = (unsigned long) _dither_color_lut[j]; + XFreeColors(d, cmap, pixels, i, 0); + } + return 0; + } + _dither_color_lut[i] = xcl.pixel; + i++; + } + } + } + _pal_type = 5; + return 1; +} + +char +AllocColors1(Display *d, Colormap cmap) +{ + XColor xcl; + + xcl.red = (unsigned short)(0x0000); + xcl.green = (unsigned short)(0x0000); + xcl.blue = (unsigned short)(0x0000); + XAllocColor(d, cmap, &xcl); + _dither_color_lut[0] = xcl.pixel; + xcl.red = (unsigned short)(0xffff); + xcl.green = (unsigned short)(0xffff); + xcl.blue = (unsigned short)(0xffff); + XAllocColor(d, cmap, &xcl); + _dither_color_lut[1] = xcl.pixel; + _pal_type = 6; + return 1; +} diff --git a/color.h b/color.h new file mode 100644 index 0000000..7f1b166 --- /dev/null +++ b/color.h @@ -0,0 +1,23 @@ +#ifndef __COLOR +#define __COLOR 1 +/* FIXME: DATA32 must become DATA8 */ +extern DATA8 _dither_color_lut[256]; +extern DATA8 _pal_type; + +void +AllocColorTable(Display *d, Colormap cmap); +char +AllocColors332(Display *d, Colormap cmap); +char +AllocColors232(Display *d, Colormap cmap); +char +AllocColors222(Display *d, Colormap cmap); +char +AllocColors221(Display *d, Colormap cmap); +char +AllocColors121(Display *d, Colormap cmap); +char +AllocColors111(Display *d, Colormap cmap); +char +AllocColors1(Display *d, Colormap cmap); +#endif diff --git a/common.h b/common.h new file mode 100644 index 0000000..a51121f --- /dev/null +++ b/common.h @@ -0,0 +1,13 @@ +#ifndef __COMMON +#define __COMMON 1 + +#include +#include +#include + +#define DATA64 unsigned long long +#define DATA32 unsigned int +#define DATA16 unsigned short +#define DATA8 unsigned char + +#endif diff --git a/file.c b/file.c new file mode 100644 index 0000000..fe9df61 --- /dev/null +++ b/file.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "file.h" + +static void FileFieldWord(char *s, int num, char *wd); + +char * +FileExtension(char *file) +{ + char *p; + + p = strrchr(file, '.'); + if (p != NULL) + return(p + 1); + return(""); +} + +int +FileExists(char *s) +{ + struct stat st; + + if ((!s) || (!*s)) + return(0); + if (stat(s, &st) < 0) + return(0); + return(1); +} + +int +FileIsFile(char *s) +{ + struct stat st; + + if ((!s) || (!*s)) + return(0); + if (stat(s, &st) < 0) + return(0); + if (S_ISREG(st.st_mode)) + return(1); + return(0); +} + +int +FileIsDir(char *s) +{ + struct stat st; + + if ((!s) || (!*s)) + return(0); + if (stat(s, &st) < 0) + return(0); + if (S_ISDIR(st.st_mode)) + return(1); + return(0); +} + +char ** +FileDir(char *dir, int *num) +{ + int i, dirlen; + int done = 0; + DIR *dirp; + char **names; + struct dirent *dp; + + if ((!dir) || (!*dir)) + return(0); + dirp = opendir(dir); + if (!dirp) + { + *num = 0; + return(NULL); + } + /* count # of entries in dir (worst case) */ + for (dirlen = 0; (dp = readdir(dirp)) != NULL; dirlen++); + if (!dirlen) + { + closedir(dirp); + *num = dirlen; + return(NULL); + } + names = (char **)malloc(dirlen * sizeof(char *)); + + if (!names) + return(NULL); + + rewinddir(dirp); + for (i = 0; i < dirlen;) + { + dp = readdir(dirp); + if (!dp) + break; + if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) + { + names[i] = strdup(dp->d_name); + i++; + } + } + + if (i < dirlen) + dirlen = i; /* dir got shorter... */ + closedir(dirp); + *num = dirlen; + /* do a simple bubble sort here to alphanumberic it */ + while (!done) + { + done = 1; + for (i = 0; i < dirlen - 1; i++) + { + if (strcmp(names[i], names[i + 1]) > 0) + { + char *tmp; + + tmp = names[i]; + names[i] = names[i + 1]; + names[i + 1] = tmp; + done = 0; + } + } + } + return(names); +} + +void +FileFreeDirList(char **l, int num) +{ + if (!l) + return; + while (num--) + if (l[num]) + free(l[num]); + free(l); + return; +} + +void +FileDel(char *s) +{ + if ((!s) || (!*s)) + return; + unlink(s); + return; +} + +time_t +FileModDate(char *s) +{ + struct stat st; + + if ((!s) || (!*s)) + return(0); + if (!stat(s, &st) < 0) + return(0); + if (st.st_mtime > st.st_ctime) + { + return(st.st_mtime); + } + else + return(st.st_ctime); + return(0); +} + +char * +FileHomeDir(int uid) +{ + static int usr_uid = -1; + static char *usr_s = NULL; + char *s; + struct passwd *pwd; + + s = getenv("HOME"); + if (s) + return strdup(s); + if (usr_uid < 0) + usr_uid = getuid(); + if ((uid == usr_uid) && (usr_s)) + { + return(strdup(usr_s)); + } + pwd = getpwuid(uid); + if (pwd) + { + s = strdup(pwd->pw_dir); + if (uid == usr_uid) + usr_s = strdup(s); + return(s); + } + return NULL; +} + +/* gets word number [num] in the string [s] and copies it into [wd] */ +/* wd is NULL terminated. If word [num] does not exist wd = "" */ +/* NB: this function now handles quotes so for a line: */ +/* Hello to "Welcome sir - may I Help" Shub Foo */ +/* Word 1 = Hello */ +/* Word 2 = to */ +/* Word 3 = Welcome sir - may I Help */ +/* Word 4 = Shub */ +/* word 5 = Foo */ + +char * +FileField(char *s, int field) +{ + char buf[4096]; + + buf[0] = 0; + FileFieldWord(s, field + 1, buf); + if (buf[0]) + { + if ((!strcmp(buf, "NULL")) || + (!strcmp(buf, "(null)"))) + return(NULL); + return(strdup(buf)); + } + return(NULL); +} + + + + + + + + + + +static void +FileFieldWord(char *s, int num, char *wd) +{ + char *cur, *start, *end; + int count, inword, inquote, len; + + if (!s) + return; + if (!wd) + return; + *wd = 0; + if (num <= 0) + return; + cur = s; + count = 0; + inword = 0; + inquote = 0; + start = NULL; + end = NULL; + while ((*cur) && (count < num)) + { + if (inword) + { + if (inquote) + { + if (*cur == '"') + { + inquote = 0; + inword = 0; + end = cur; + count++; + } + } + else + { + if (isspace(*cur)) + { + end = cur; + inword = 0; + count++; + } + } + } + else + { + if (!isspace(*cur)) + { + if (*cur == '"') + { + inquote = 1; + start = cur + 1; + } + else + start = cur; + inword = 1; + } + } + if (count == num) + break; + cur++; + } + if (!start) + return; + if (!end) + end = cur; + if (end <= start) + return; + len = (int)(end - start); + if (len > 4000) + len = 4000; + if (len > 0) + { + strncpy(wd, start, len); + wd[len] = 0; + } + return; +} + diff --git a/file.h b/file.h new file mode 100644 index 0000000..8edb306 --- /dev/null +++ b/file.h @@ -0,0 +1,13 @@ +#ifndef __FILE +#define __FILE 1 +char *FileExtension(char *file); +int FileExists(char *s); +int FileIsFile(char *s); +int FileIsDir(char *s); +char **FileDir(char *dir, int *num); +void FileFreeDirList(char **l, int num); +void FileDel(char *s); +time_t FileModDate(char *s); +char *FileHomeDir(int uid); +char *FileField(char *s, int field); +#endif diff --git a/grab.c b/grab.c new file mode 100644 index 0000000..3c3f806 --- /dev/null +++ b/grab.c @@ -0,0 +1,537 @@ +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "grab.h" + +static char _x_err = 0; + +static void +Tmp_HandleXError(Display * d, XErrorEvent * ev) +{ + d = NULL; + ev = NULL; + _x_err = 1; +} + +DATA32 * +GrabDrawableToRGBA(Display *d, Drawable p, Pixmap m, Visual *v, Colormap cm, + int depth, int x, int y, int w, int h, char domask) +{ + XErrorHandler prev_erh = NULL; + XWindowAttributes xatt, ratt; + char is_pixmap = 0, created_mask = 0, is_shm = 0, is_mshm = 0; + int i, pixel, mpixel; + int src_x, src_y, src_w, src_h, ow, oh, ox, oy; + int width, height, clipx, clipy, inx, iny; + XShmSegmentInfo shminfo, mshminfo; + XImage *xim = NULL, *mxim = NULL; + static char x_does_shm = -1; + DATA32 *data, *ptr; + DATA8 rtab[256], gtab[256], btab[256]; + XColor cols[256]; + + ox = x; + oy = y; + ow = w; + oh = h; + /* FIXME: hmm - need to co-ordinate this with the app */ + XGrabServer(d); + prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError); + _x_err = 0; + /* lets see if its a pixmap or not */ + XGetWindowAttributes(d, p, &xatt); + XSync(d, False); + if (_x_err) + is_pixmap = 1; + /* reset our error handler */ + XSetErrorHandler((XErrorHandler) prev_erh); + if (is_pixmap) + { + Window dw; + + XGetGeometry(d, p, &dw, &src_x, &src_y, + (unsigned int *)&src_w, (unsigned int *)&src_h, + (unsigned int *)&src_x, (unsigned int *)&xatt.depth); + src_x = 0; + src_y = 0; + } + else + { + Window dw; + XGetWindowAttributes(d, xatt.root, &ratt); + XTranslateCoordinates(d, p, xatt.root, 0, 0, &src_x, &src_y, &dw); + if ((xatt.map_state != IsViewable) && + (xatt.backing_store == NotUseful)) + { + XUngrabServer(d); + return NULL; + } + } + + /* clip to the drawable tree and screen */ + clipx = 0; + clipy = 0; + width = xatt.width - x; + height = xatt.height - y; + if (width > w) + width = w; + if (height > h) + height = h; + + if (!is_pixmap) + { + if ((src_x + x + width) > ratt.width) + width = ratt.width - (src_x + x); + if ((src_y + y + height) > ratt.height) + height = ratt.height - (src_y + y); + } + if (x < 0) + { + clipx = -x; + width += x; + x = 0; + } + if (y < 0) + { + clipy = -y; + height += y; + y = 0; + } + if (!is_pixmap) + { + if ((src_x + x) < 0) + { + clipx -= (src_x + x); + width += (src_x + x); + x = -src_x; + } + if ((src_y + y) < 0) + { + clipy -= (src_y + y); + height += (src_y + y); + y = -src_y; + } + } + if ((width <= 0) || (height <= 0)) + { + XUngrabServer(d); + return NULL; + } + w = width; + h = height; + if ((!is_pixmap) && (domask) && (!m)) + { + int ord, rect_no = 0; + XRectangle *r = NULL; + + r = XShapeGetRectangles(d, p, ShapeBounding, &rect_no, &ord); + if (r) + { + if (!((rect_no == 1) && + (r[0].x == 0) && (r[0].y == 0) && + (r[0].width == xatt.width) && (r[0].height == xatt.height))) + { + XGCValues gcv; + GC gc; + + created_mask = 1; + m = XCreatePixmap(d, p, w, h, 1); + gcv.foreground = 0; + gc = XCreateGC(d, m, GCForeground, &gcv); + XFillRectangle(d, m, gc, 0, 0, w, h); + XSetForeground(d, gc, 1); + for (i = 0; i < rect_no; i++) + XFillRectangle(d, m, gc, + r[i].x - x, r[i].y - y, + r[i].width, r[i].height); + XFreeGC(d, gc); + } + XFree(r); + } + } + /* Create an Ximage (shared or not) */ + if (x_does_shm < 0) + { + if (XShmQueryExtension(d)) + x_does_shm = 1; + else + x_does_shm = 0; + } + prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError); + _x_err = 0; + if (x_does_shm) + { + xim = XShmCreateImage(d, v, xatt.depth, ZPixmap, NULL, + &shminfo, w, h); + if (!xim) + xim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + else + { + XSync(d, False); + if (_x_err) + { + XDestroyImage(xim); + xim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + _x_err = 0; + } + else + { + shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * + xim->height, IPC_CREAT | 0666); + if (shminfo.shmid < 0) + { + XDestroyImage(xim); + xim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + } + else + { + shminfo.shmaddr = xim->data = shmat(shminfo.shmid, 0, 0); + if (xim->data != (char *)-1) + { + shminfo.readOnly = False; + XShmAttach(d, &shminfo); + is_shm = 1; + } + else + { + shmctl(shminfo.shmid, IPC_RMID, 0); + XDestroyImage(xim); + xim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + } + } + } + } + } + else + xim = XGetImage(d, p, x, y, w, h, 0xffffffff, ZPixmap); + if (is_shm) + { + XShmGetImage(d, p, xim, x, y, 0xffffffff); + XSync(d, False); + if (_x_err) + { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + XDestroyImage(xim); + xim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + is_shm = 0; + } + } + XSetErrorHandler((XErrorHandler) prev_erh); + if ((m) && (domask)) + { + prev_erh = XSetErrorHandler((XErrorHandler) Tmp_HandleXError); + _x_err = 0; + if (x_does_shm) + { + mxim = XShmCreateImage(d, v, 1, ZPixmap, NULL, + &mshminfo, w, h); + if (!mxim) + mxim = XGetImage(d, p, 0, 0, w, h, + 0xffffffff, ZPixmap); + else + { + XSync(d, False); + if (_x_err) + { + XDestroyImage(mxim); + xim = XGetImage(d, p, 0, 0, w, h, + 0xffffffff, ZPixmap); + _x_err = 0; + } + else + { + mshminfo.shmid = shmget(IPC_PRIVATE, + mxim->bytes_per_line * + mxim->height, IPC_CREAT | 0666); + if (mshminfo.shmid < 0) + { + XDestroyImage(mxim); + mxim = XGetImage(d, p, 0, 0, w, h, + 0xffffffff, ZPixmap); + } + else + { + mshminfo.shmaddr = xim->data = + shmat(mshminfo.shmid, 0, 0); + if (mxim->data != (char *)-1) + { + mshminfo.readOnly = False; + XShmAttach(d, &mshminfo); + is_mshm = 1; + } + else + { + shmctl(mshminfo.shmid, IPC_RMID, 0); + XDestroyImage(mxim); + mxim = XGetImage(d, p, x, y, w, h, + 0xffffffff, ZPixmap); + } + } + } + } + } + else + mxim = XGetImage(d, m, 0, 0, w, h, 0xffffffff, ZPixmap); + if (is_mshm) + { + XShmGetImage(d, p, mxim, 0, 0, 0xffffffff); + XSync(d, False); + if (_x_err) + { + shmdt(mshminfo.shmaddr); + shmctl(mshminfo.shmid, IPC_RMID, 0); + XDestroyImage(mxim); + mxim = XGetImage(d, p, 0, 0, w, h, + 0xffffffff, ZPixmap); + is_mshm = 0; + } + XSetErrorHandler((XErrorHandler) prev_erh); + } + } + if ((is_shm) || (is_mshm)) + { + XSync(d, False); + XUngrabServer(d); + XSync(d, False); + } + else + XUngrabServer(d); + + if ((xatt.depth == 1) && (!cm) && (is_pixmap)) + { + rtab[0] = 0; + gtab[0] = 0; + btab[0] = 0; + rtab[1] = 255; + gtab[1] = 255; + btab[1] = 255; + } + else if (xatt.depth <= 8) + { + if ((!is_pixmap) && (!cm)) + { + cm = xatt.colormap; + if (cm == None) + cm = ratt.colormap; + } + else + cm = ratt.colormap; + + for (i = 0; i < (1 << xatt.depth); i++) + { + cols[i].pixel = i; + cols[i].flags = DoRed | DoGreen | DoBlue; + } + XQueryColors(d, cm, cols, 1 << xatt.depth); + for (i = 0; i < (1 << xatt.depth); i++) + { + rtab[i] = cols[i].red >> 8; + gtab[i] = cols[i].green >> 8; + btab[i] = cols[i].blue >> 8; + } + } + data = malloc(ow * oh * sizeof(DATA32)); + if (data) + { + inx = x - ox; + iny = y - oy; + /* go thru the XImage and convert */ + switch (depth) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + if (mxim) + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + mpixel = XGetPixel(mxim, x, y); + *ptr++ = (0xff000000 >> (mpixel << 31)) | + (btab[pixel & 0xff] << 16) | + (gtab[pixel & 0xff] << 8) | + (rtab[pixel & 0xff]); + + } + } + } + else + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = 0xff000000 | + (btab[pixel & 0xff] << 16) | + (gtab[pixel & 0xff] << 8) | + (rtab[pixel & 0xff]); + } + } + } + break; + case 16: + if (mxim) + { + for (y = 0; y < h; y++) + { + DATA8 r, g, b; + + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + r = (pixel >> 8) & 0xf8; + g = (pixel >> 3) & 0xfc; + b = (pixel << 3) & 0xf8; + mpixel = XGetPixel(mxim, x, y); + *ptr++ = (0xff000000 >> (mpixel << 31)) | + (b << 16) | + (g << 8) | + (r); + } + } + } + else + { + for (y = 0; y < h; y++) + { + DATA8 r, g, b; + + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + r = (pixel >> 8) & 0xf8; + g = (pixel >> 3) & 0xfc; + b = (pixel << 3) & 0xf8; + *ptr++ = 0xff000000 | + (b << 16) | + (g << 8) | + (r); + } + } + } + break; + case 15: + if (mxim) + { + for (y = 0; y < h; y++) + { + DATA8 r, g, b; + + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + r = (pixel >> 7) & 0xf8; + g = (pixel >> 2) & 0xf8; + b = (pixel << 3) & 0xf8; + mpixel = XGetPixel(mxim, x, y); + *ptr++ = (0xff000000 >> (mpixel << 31)) | + (b << 16) | + (g << 8) | + (r); + } + } + } + else + { + for (y = 0; y < h; y++) + { + DATA8 r, g, b; + + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + r = (pixel >> 7) & 0xf8; + g = (pixel >> 2) & 0xf8; + b = (pixel << 3) & 0xf8; + *ptr++ = 0xff000000 | + (b << 16) | + (g << 8) | + (r); + } + } + } + break; + case 24: + case 32: + if (mxim) + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + mpixel = XGetPixel(mxim, x, y); + *ptr++ = (0xff000000 >> (mpixel << 31)) | + ((pixel & 0x000000ff) << 16) | + ((pixel & 0x0000ff00)) | + ((pixel & 0x00ff0000) >> 16); + } + } + } + else + { + for (y = 0; y < h; y++) + { + ptr = data + ((y + iny) * ow) + inx; + for (x = 0; x < w; x++) + { + pixel = XGetPixel(xim, x, y); + *ptr++ = 0xff000000 | + ((pixel & 0x000000ff) << 16) | + ((pixel & 0x0000ff00)) | + ((pixel & 0x00ff0000) >> 16); + } + } + } + break; + default: + break; + } + } + /* destroy the Ximage */ + if (is_shm) + { + XSync(d, False); + XShmDetach(d, &shminfo); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + } + if ((is_mshm) && (mxim)) + { + XShmDetach(d, &mshminfo); + shmdt(mshminfo.shmaddr); + shmctl(mshminfo.shmid, IPC_RMID, 0); + } + XDestroyImage(xim); + if (created_mask) + XFreePixmap(d, m); + if (mxim) + XDestroyImage(mxim); + return data; +} diff --git a/grab.h b/grab.h new file mode 100644 index 0000000..1cc109c --- /dev/null +++ b/grab.h @@ -0,0 +1,6 @@ +#ifndef __GRAB +#define __GRAB 1 +DATA32 * +GrabDrawableToRGBA(Display *d, Drawable p, Pixmap m, Visual *v, Colormap cm, + int depth, int x, int y, int w, int h, char domask); +#endif diff --git a/image.c b/image.c new file mode 100644 index 0000000..d823339 --- /dev/null +++ b/image.c @@ -0,0 +1,679 @@ +#include "common.h" +#include +#include +#include +#include +#include +#include +#include "image.h" +#include "file.h" + +static ImlibImage *images = NULL; +static ImlibImagePixmap *pixmaps = NULL; +static ImlibLoader *loaders = NULL; +static int cache_size = 4096 * 1024; + +void +SetCacheSize(int size) +{ + cache_size = size; + CleanupImageCache(); + CleanupImagePixmapCache(); +} + +int +GetCacheSize(void) +{ + return cache_size; +} + +ImlibImage * +ProduceImage(void) +{ + ImlibImage *im; + + im = malloc(sizeof(ImlibImage)); + im->data = NULL; + im->file = NULL; + im->moddate = 0; + im->flags = F_NONE; + im->border.left = 0; + im->border.right = 0; + im->border.top = 0; + im->border.bottom = 0; + im->references = 0; + im->w = 0; + im->h = 0; + im->loader = NULL; + im->next = NULL; + return im; +} + +void +ConsumeImage(ImlibImage *im) +{ + if (im->file) + free(im->file); + if (im->data) + free(im->data); + if (im->format) + free(im->format); + free(im); +} + +ImlibImage * +FindCachedImage(char *file) +{ + ImlibImage *im, *previous_im; + + im = images; + previous_im = NULL; + /* go through the images list */ + while (im) + { + /* if the filenames match */ + if (!strcmp(file, im->file)) + { + /* move the image to the head of the pixmap list */ + if (previous_im) + { + previous_im->next = im->next; + im->next = images; + images = im; + } + /* return it */ + return im; + } + previous_im = im; + im = im->next; + } + return NULL; +} + +void +AddImageToCache(ImlibImage *im) +{ + im->next = images; + images = im; +} + +void +RemoveImageFromCache(ImlibImage *im) +{ + ImlibImage *current_im, *previous_im; + + current_im = images; + previous_im = NULL; + while (current_im) + { + if (im == current_im) + { + if (previous_im) + previous_im->next = im->next; + else + images = im->next; + return; + } + current_im = current_im->next; + } +} + +int +CurrentCacheSize(void) +{ + ImlibImage *im; + ImlibImagePixmap *ip; + int current_cache = 0; + + im = images; + while(im) + { + if (im->references == 0) + { + if (!(IMAGE_IS_VALID(im))) + { + RemoveImageFromCache(im); + ConsumeImage(im); + } + else + current_cache += im->w * im->h * sizeof(DATA32); + } + im = im->next; + } + ip = pixmaps; + while(ip) + { + if (ip->references == 0) + { + if (!(IMAGE_IS_VALID(ip->image))) + { + RemoveImagePixmapFromCache(ip); + ConsumeImagePixmap(ip); + } + else + { + if (ip->pixmap) + { + if (ip->depth < 8) + current_cache += ip->w * ip->h * (ip->depth / 8); + else if (ip->depth == 8) + current_cache += ip->w * ip->h; + else if (ip->depth <= 16) + current_cache += ip->w * ip->h * 2; + else if (ip->depth <= 32) + current_cache += ip->w * ip->h * 4; + } + if (ip->mask) + current_cache += ip->w * ip->h / 8; + } + } + ip = ip->next; + } +} + +void +CleanupImageCache(void) +{ + ImlibImage *im, *im_last; + int current_cache; + char operation = 1; + + current_cache = CurrentCacheSize(); + while ((current_cache > cache_size) || (operation)); + { + im_last = NULL; + operation = 0; + im = images; + while(im) + { + if (im->references <= 0) + im_last = im; + im = im->next; + } + if (im_last) + { + RemoveImageFromCache(im_last); + ConsumeImage(im_last); + operation = 1; + } + current_cache = CurrentCacheSize(); + } +} + +ImlibImagePixmap * +ProduceImagePixmap(void) +{ + ImlibImagePixmap *ip; + + ip = malloc(sizeof(ImlibImagePixmap)); + ip->w = 0; + ip->h = 0; + ip->pixmap = 0; + ip->mask = 0; + ip->display = NULL; + ip->visual = NULL; + ip->depth = 0; + ip->mode_count = 0; + ip->image = NULL; + ip->references = 0; + ip->next = NULL; + return ip; +} + +void +ConsumeImagePixmap(ImlibImagePixmap *ip) +{ + if (ip->pixmap) + XFreePixmap(ip->display, ip->pixmap); + if (ip->mask) + XFreePixmap(ip->display, ip->mask); + free(ip); +} + +ImlibImagePixmap * +FindCachedImagePixmap(ImlibImage *im, int w, int h, Display *d, Visual *v, + int depth, int mode_count) +{ + ImlibImagePixmap *ip, *previous_ip; + + ip = pixmaps; + previous_ip = NULL; + /* go through the pixmap list */ + while (ip) + { + /* if all the pixmap attributes match */ + if ((ip->w == w) && (ip->h == h) && (ip->depth == depth) && + (ip->visual == v) && (ip->display == d) && + (ip->mode_count == mode_count)) + { + /* move the pixmap to the head of the pixmap list */ + if (previous_ip) + { + previous_ip->next = ip->next; + ip->next = pixmaps; + pixmaps = ip; + } + /* return it */ + return ip; + } + previous_ip = ip; + ip = ip->next; + } + return NULL; +} + +void +AddImagePixmapToCache(ImlibImagePixmap *ip) +{ + ip->next = pixmaps; + pixmaps = ip; +} + +void +RemoveImagePixmapFromCache(ImlibImagePixmap *ip) +{ + ImlibImagePixmap *current_ip, *previous_ip; + + current_ip = pixmaps; + previous_ip = NULL; + while (current_ip) + { + if (ip == current_ip) + { + if (previous_ip) + previous_ip->next = ip->next; + else + pixmaps = ip->next; + return; + } + current_ip = current_ip->next; + } +} + +void +CleanupImagePixmapCache() +{ + ImlibImagePixmap *ip, *ip_last; + int current_cache; + char operation = 1; + + current_cache = CurrentCacheSize(); + while ((current_cache > cache_size) || (operation)); + { + ip_last = NULL; + operation = 0; + ip = pixmaps; + while(ip) + { + if (ip->references <= 0) + ip_last = ip; + ip = ip->next; + } + if (ip_last) + { + RemoveImagePixmapFromCache(ip_last); + ConsumeImagePixmap(ip_last); + operation = 1; + } + current_cache = CurrentCacheSize(); + } +} + +ImlibLoader * +ProduceLoader(char *file) +{ + ImlibLoader *l; + void (*l_formats)(ImlibLoader *l) ; + + l = malloc(sizeof(ImlibLoader)); + l->num_formats = 0; + l->formats = NULL; + l->handle = dlopen(file, RTLD_NOW); + if (!l->handle) + { + free(l); + return NULL; + } + l->load = dlsym(l->handle, "load"); + l->save = dlsym(l->handle, "save"); + l_formats = dlsym(l->handle, "formats"); + if ((!(l->load)) || (!(l->save)) || (!(l_formats))) + { + dlclose(l->handle); + free(l); + return NULL; + } + l_formats(l); + l->file = strdup(file); + l->next = NULL; + return l; +} + +char ** +ListLoaders(int *num_ret) +{ + char **list = NULL, **l, s[4096], *home; + int num, i, pi = 0; + + *num_ret = 0; + home = FileHomeDir(getuid()); + sprintf(s, "%s/.loaders/image/", home); + l = FileDir(s, &num); + if (num > 0) + { + *num_ret += num; + list = malloc(sizeof(char *) * *num_ret); + for (i = 0; i < num; i++) + { + sprintf(s, "%s/.loaders/image/%s", home, l[i]); + list[i] = strdup(s); + } + pi = i; + FileFreeDirList(l, num); + } + sprintf(s, "/usr/lib/loaders/image/"); + l = FileDir(s, &num); + if (num > 0) + { + *num_ret += num; + list = realloc(list, sizeof(char *) * *num_ret); + for (i = 0; i < num; i++) + { + sprintf(s, "/usr/lib/loaders/image/%s", l[i]); + list[pi + i] = strdup(s); + } + FileFreeDirList(l, num); + free(home); + } + return list; +} + +void +ConsumeLoader(ImlibLoader *l) +{ + if (l->file) + free(l->file); + if (l->handle) + dlclose(l->handle); + if (l->formats) + { + int i; + + for (i = 0; i < l->num_formats; i++) + free(l->formats[i]); + free(l->formats); + } + free(l); +} + +void +RescanLoaders(void) +{ + static time_t last_scan_time = 0; + static time_t last_modified_home_time = 0; + static time_t last_modified_system_time = 0; + time_t current_time; + char s[4096], *home; + char do_reload = 0; + + /* dont stat the dir and rescan if we checked in the last 5 seconds */ + current_time = time(NULL); + if ((current_time - last_scan_time) < 5) + return; + /* ok - was the system loaders dir contents modified ? */ + last_scan_time = current_time; + if (FileIsDir("/usr/lib/loaders/image/")) + { + current_time = FileModDate("/usr/lib/loaders/image/"); + if (current_time > last_modified_system_time) + { + /* yup - set the "do_reload" flag */ + do_reload = 1; + last_modified_system_time = current_time; + } + } + /* ok - was the users own loaders dir contents modified ? */ + home = FileHomeDir(getuid()); + sprintf(s, "%s/.loaders/image/", home); + free(home); + if (FileIsDir(s)) + { + current_time = FileModDate(s); + if (current_time > last_modified_home_time) + { + /* yup - set the "do_reload" flag */ + do_reload = 1; + last_modified_home_time = current_time; + } + } + /* if we dont ned to reload the loaders - get out now */ + if (!do_reload) + return; + RemoveAllLoaders(); + LoadAllLoaders(); +} + +void +RemoveAllLoaders(void) +{ + ImlibLoader *l, *il; + + l = loaders; + while(l) + { + il = l; + l = l->next; + ConsumeLoader(il); + } + loaders = NULL; +} + +void +LoadAllLoaders(void) +{ + int i, num; + char **list; + + list = ListLoaders(&num); + if (!list) + return; + + for (i = num - 1; i >= 0; i--) + { + ImlibLoader *l; + + l = ProduceLoader(list[i]); + if (l) + { + l->next = loaders; + loaders = l; + } + if (list[i]) + free(list[i]); + } + free(list); +} + +ImlibLoader * +FindBestLoaderForFile(char *file) +{ + char *extension, *lower; + ImlibLoader *l = NULL; + + /* use the file extension for a "best guess" as to what loader to try */ + /* first at any rate */ + extension = strdup(FileExtension(file)); + /* change the extensiont o all lwoer case as all "types" are listed as */ + /* lower case strings fromt he loader that represent all the possible */ + /* extensions that file format could have */ + lower = extension; + while (*lower) + { + *lower = tolower(*lower); + lower++; + } + /* go through the loaders - first loader that claims to handle that */ + /* image type (extension wise) wins as a first guess to use - NOTE */ + /* this is an OPTIMISATION - it is possible the file has no extension */ + /* or has an unrecognised one but still is loadable by a loader. */ + /* if thkis initial loader failes to load the load mechanism will */ + /* systematically go from most recently used to least recently used */ + /* loader until one succeeds - or none are left and all have failed */ + /* and only if all fail does the laod fail. the lao9der that does */ + /* succeed gets it way tot he head of the list so it's going */ + /* to be used first next time in this search mechanims - this */ + /* assumes you tend to laod a few image types and ones generally */ + /* of the same format */ + l = loaders; + while (l) + { + int i; + + for (i = 0; i < l->num_formats; i++) + { + if (!strcmp(l->formats[i], extension)) + { + free(extension); + return l; + } + } + l = l->next; + } + free(extension); + return l; +} + +ImlibImage * +LoadImage(char *file) +{ + ImlibImage *im; + ImlibLoader *best_loader; + + /* see if we alreayd have the image cached */ + im = FindCachedImage(file); + /* if we found a cached image and we shoudl always check that it is */ + /* accurate to the disk conents if they changed since we last loaded */ + /* and that it is still a valid image */ + if ((im) && (IMAGE_IS_VALID(im)) && (IMAGE_ALWAYS_CHECK_DISK(im))) + { + time_t current_modified_time; + + current_modified_time = FileModDate(file); + /* if the file on disk is newer than the cached one */ + if (current_modified_time > im->moddate) + { + /* invalidate image */ + im->flags &= F_INVALID; + } + else + { + /* image is ok to re-use - program is just being stupid loading */ + /* the same data twice */ + im->references++; + return im; + } + } + /* either image in cache is invalid or we dont even have it in cache */ + /* so produce a new one and load an image into that */ + im = ProduceImage(); + im->file = strdup(file); + im->moddate = FileModDate(file); + /* ok - just check all our loaders are up to date */ + RescanLoaders(); + /* take a guess by extension on the best loader to use */ + best_loader = FindBestLoaderForFile(file); + if (best_loader) + best_loader->load(im); + /* width is still 0 - the laoder didnt manage to do anything */ + if (im->w == 0) + { + ImlibLoader *l, *previous_l = NULL; + l = loaders; + /* run through all loaders and try load until one succeeds */ + while ((l) && (im->w == 0)) + { + /* if its not the best loader that alreayd failed - try load */ + if (l != best_loader) + l->load(im); + /* if it failed - advance */ + if (im->w == 0) + { + previous_l = l; + l = l->next; + } + } + /* if we have a loader then its the loader that succeeded */ + /* move the successful loader to the head of the list */ + /* as long as it's not alreayd at the head of the list */ + if ((l) && (previous_l)) + { + im->loader = l; + previous_l->next = l->next; + l->next = loaders; + loaders = l; + } + } + else + im->loader = best_loader; + /* all loaders have been tried and they all failed. free the skeleton */ + /* image struct we had and return NULL */ + if (im->w == 0) + { + ConsumeImage(im); + return NULL; + } +#if 0 + /* FIXME: need to turn this png loading function into a loader andf then */ + /* remove the below stuff */ + im->data = RGBA_Load(file, &(im->w), &(im->h)); + im->flags = F_HAS_ALPHA; +#endif + + + /* the laod succeeded - make sure the image is refernenced then add */ + /* it to our cache */ + im->references = 1; + AddImageToCache(im); + return im; +} + +ImlibImagePixmap * +FindImlibImagePixmapByID(Display *d, Pixmap p) +{ + ImlibImagePixmap *ip; + + ip = pixmaps; + /* go through the pixmap list */ + while (ip) + { + /* if all the pixmap ID & Display match */ + if ((ip->pixmap == p) && (ip->display == d)) + return ip; + ip = ip->next; + } + return NULL; +} + +void +FreeImage(ImlibImage *im) +{ + if (im->references > 0) + { + im->references--; + CleanupImageCache(); + } +} + +void +FreePixmap(Display *d, Pixmap p) +{ + ImlibImagePixmap *ip; + + ip = FindImlibImagePixmapByID(d, p); + if (ip->references > 0) + { + ip->references--; + CleanupImagePixmapCache(); + } +} + diff --git a/image.h b/image.h new file mode 100644 index 0000000..757440f --- /dev/null +++ b/image.h @@ -0,0 +1,97 @@ +#ifndef __IMAGE +# define __IMAGE 1 + +typedef enum _iflags Iflags; +typedef struct _imlibimage ImlibImage; +typedef struct _imlibimagepixmap ImlibImagePixmap; +typedef struct _imlibborder ImlibBorder; +typedef struct _imlibloader ImlibLoader; + +enum _iflags +{ + F_NONE = 0, + F_HAS_ALPHA = (1 << 0), + F_UNLOADED = (1 << 1), + F_UNCACHEABLE = (1 << 2), + F_ALWAYS_CHECK_DISK = (1 << 3), + F_INVALID = (1 << 4) +}; + +struct _imlibborder +{ + int left, right, top, bottom; +}; + +struct _imlibimage +{ + char *file; + int w, h; + DATA32 *data; + Iflags flags; + time_t moddate; + ImlibBorder border; + int references; + ImlibLoader *loader; + ImlibImage *next; + char *format; +}; + +struct _imlibimagepixmap +{ + int w, h; + Pixmap pixmap, mask; + Display *display; + Visual *visual; + int depth; + int mode_count; + ImlibImage *image; + int references; + ImlibImagePixmap *next; +}; + +struct _imlibloader +{ + char *file; + int num_formats; + char **formats; + void *handle; + char (*load)(ImlibImage *im); + char (*save)(ImlibImage *im); + ImlibLoader *next; +}; + +void SetCacheSize(int size); +int GetCacheSize(void); +ImlibImage *ProduceImage(void); +void ConsumeImage(ImlibImage *im); +ImlibImage *FindCachedImage(char *file); +void AddImageToCache(ImlibImage *im); +void RemoveImageFromCache(ImlibImage *im); +void CleanupImageCache(void); +ImlibImagePixmap *ProduceImagePixmap(void); +void ConsumeImagePixmap(ImlibImagePixmap *ip); +ImlibImagePixmap *FindCachedImagePixmap(ImlibImage *im, int w, int h, + Display *d, Visual *v, + int depth, int mode_count); +void AddImagePixmapToCache(ImlibImagePixmap *ip); +void RemoveImagePixmapFromCache(ImlibImagePixmap *ip); +void CleanupImagePixmapCache(); +ImlibLoader *ProduceLoader(char *file); +char **ListLoaders(int *num_ret); +void ConsumeLoader(ImlibLoader *l); +void RescanLoaders(void); +void RemoveAllLoaders(void); +void LoadAllLoaders(void); +ImlibLoader *FindBestLoaderForFile(char *file); +ImlibImage *LoadImage(char *file); +ImlibImagePixmap *FindImlibImagePixmapByID(Display *d, Pixmap p); +void FreeImage(ImlibImage *im); +void FreePixmap(Display *d, Pixmap p); + +# define IMAGE_HAS_ALPHA(im) (im->flags & F_HAS_ALPHA) +# define IMAGE_IS_UNLOADED(im) (im->flags & F_UNLOADED) +# define IMAGE_IS_UNCACHEABLE(im) (im->flags & F_UNCACHEABLE) +# define IMAGE_ALWAYS_CHECK_DISK(im) (im->flags & F_ALWAYS_CHECK_DISK) +# define IMAGE_IS_VALID(im) (!(im->flags & F_INVALID)) + +#endif diff --git a/loader_png.c b/loader_png.c new file mode 100644 index 0000000..d77785b --- /dev/null +++ b/loader_png.c @@ -0,0 +1,162 @@ +#include "common.h" +#include +#include +#include +#include +#include "image.h" +#include + +/* this is a quick sample png loader module... nioce and small isnt it? */ + +/* PNG stuff */ +#define PNG_BYTES_TO_CHECK 4 + +static void * +_load_PNG (int *ww, int *hh, FILE *f) +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned char *data, **lines; + int i, bit_depth, color_type, interlace_type; + unsigned char buf[PNG_BYTES_TO_CHECK]; + int w, h; + + fread(buf, 1, PNG_BYTES_TO_CHECK, f); + if (!png_check_sig(buf, PNG_BYTES_TO_CHECK)) + { + rewind(f); + return NULL; + } + rewind(f); + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + rewind(f); + return NULL; + } + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + rewind(f); + return NULL; + } + if (setjmp(png_ptr->jmpbuf)) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + rewind(f); + return NULL; + } + png_init_io(png_ptr, f); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *)(&w), (png_uint_32 *)(&h), + &bit_depth, &color_type, &interlace_type, + NULL, NULL); + /* Palette -> RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_expand(png_ptr); + /* 16bit color -> 8bit color */ + png_set_strip_16(png_ptr); + /* pack all pixels to byte boundaires */ + png_set_packing(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + *ww = w; + *hh = h; + data = malloc(w * h * 4); + lines = (unsigned char **)malloc(h * sizeof(unsigned char *)); + for (i = 0; i < h; i++) + lines[i] = data + (i * w * 4); + png_read_image(png_ptr, lines); + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + free(lines); + return data; +} + +DATA32 * +RGBA_Load(char *file, int *w, int *h) +{ + FILE *f; + DATA32 *data; + + f = fopen(file, "r"); + data = (DATA32 *)_load_PNG(w, h, f); + fclose(f); + return data; +} + +char +load (ImlibImage *im) +{ + int w, h; + DATA32 *data; + + /* alreayd data in this image - dont load it again */ + if (im->data) + return 0; + /* ok - this is not 100% right. */ + /* what I SHOULD be doing is checking the im->loader value - if it's */ + /* set and im->data is NULL - then I do the SECOND loading phase. */ + /* this Is optional - but an OPTIMISED loader (like all loaders should */ + /* if the format allows it) has 2 loading phases. the first time the */ + /* loader is called If it can withotu performance penalty, read the */ + /* image header - glean ingormation like width, height, if the image */ + /* has an alpha channel or not - etc. If this information can be gathered */ + /* now without haveing to also decode the image data, and if it is */ + /* possible for the image data to later in a second load / phase, to be */ + /* loaded separately withotu significant penalty, then the loader */ + /* shoudl delay imge data decoding until it is actually needed in the */ + /* second load phase. if it is unable to do this, or the author does */ + /* not have time to do it properly, then ALL data, including image data */ + /* should be decoded on the first phase. The loader, if it does this */ + /* shoudl ignore the image laod if the data memebr is not NULL */ + /* the below code for now just does a one phase load */ + data = RGBA_Load(im->file, &w, &h); + if (data) + { + im->data = data; + im->flags = F_HAS_ALPHA; + /* setting the width to somthign > 0 means you managed to load */ + /* the image */ + im->w = w; + im->h = h; + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + im->format = strdup("png"); + /* success - retrun 1 */ + return 1; + } + /* failure to load... return 0 */ + return 0; +} + +char +save (ImlibImage *im) +{ + /* if we cant do this - just return 0 */ + return 0; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats (ImlibLoader *l) +{ + char *list_formats[] = + { "png" }; + int num_formats = 1; + int i; + + l->formats = malloc(sizeof(char *) * num_formats); + for (i = 0; i < num_formats; i++) + l->formats[i] = strdup(list_formats[i]); +} + diff --git a/main.c b/main.c new file mode 100644 index 0000000..442e14e --- /dev/null +++ b/main.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "image.h" +#include "rend.h" +#include "rgba.h" + + +Display *disp; + +int main (int argc, char **argv) +{ + Window win; + int i, j; + ImlibImage *im; + Visual *vis; + int depth; + int sec1, usec1, sec2, usec2; + int pixels = 0; + struct timeval timev; + double sec; + char *file; + + int root = 0; + int scale = 0; + int w = -1; + int h = -1; + int aa = 0; + int dith = 0; + int loop = 1; + int blend = 0; + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-root")) + root = 1; + else if (!strcmp(argv[i], "-smooth")) + aa = 1; + else if (!strcmp(argv[i], "-blend")) + blend = 1; + else if (!strcmp(argv[i], "-dither")) + dith = 1; + else if (!strcmp(argv[i], "-scale")) + scale = 1; + else if (!strcmp(argv[i], "-noloop")) + loop = 0; + else if (!strcmp(argv[i], "-size")) + { + i++; + w = atoi(argv[i++]); + h = atoi(argv[i]); + } + else + file = argv[i]; + } + printf("init\n"); + RGBA_init(); + disp = XOpenDisplay(NULL); + printf("load\n"); + im = LoadImage(file); + if (!im) + printf("load fialed\n"); + if (w < 0) + { + w = im->w; + h = im->h; + } + if (root) + win = DefaultRootWindow(disp); + else + { + win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0, 0, w, h, 0, 0, 0); + XMapWindow(disp, win); + } + if (scale) + { + Window d; + int dd; + + XGetGeometry(disp, win, &d, &dd, &dd, &w, &h, &dd, &dd); + } + vis = DefaultVisual(disp, DefaultScreen(disp)); + depth = DefaultDepth(disp, DefaultScreen(disp)); + if (depth == 8) + AllocColorTable(disp, DefaultColormap(disp, DefaultScreen(disp))); + XSync(disp, False); + printf("rend\n"); + gettimeofday(&timev,NULL); + sec1=(int)timev.tv_sec; /* and stores it so we can time outselves */ + usec1=(int)timev.tv_usec; /* we will use this to vary speed of rot */ + SetMaxXImageCount(disp, 5); + if (loop) + { + for (i = 0; i < w; i++) + { + static Pixmap m = 0; + + if (m) + XFreePixmap(disp, m); + m = 0; + /* + if (((w - i) > 0) && ((((w - i) * h) / w) > 0)) + m = XCreatePixmap(disp, win, (w - i), ((w - i) * h) / w, 1); + */ RenderImage(disp, im, + win, m, + vis, + DefaultColormap(disp, DefaultScreen(disp)), + depth, + 0, 0, im->w, im->h, + 0, 0, w - i, ((w - i) * h) / w, + (char)aa, (char)dith, (char)blend, 0 + ); + if (m) + { + XShapeCombineMask(disp, win, ShapeBounding, 0, 0, m, ShapeSet); + } + pixels += (w - i) * (((w - i) * h) / w); + } + } + else + { + RenderImage(disp, im, + win, 0, + vis, + DefaultColormap(disp, DefaultScreen(disp)), + depth, + 0, 0, im->w, im->h, + 0, 0, w, h, + (char)aa, (char)dith, (char)blend, 0 + ); + pixels += (w) * (h); + } + gettimeofday(&timev,NULL); + sec2=(int)timev.tv_sec; /* and stores it so we can time outselves */ + usec2=(int)timev.tv_usec; /* we will use this to vary speed of rot */ + printf("done\n"); + i = sec2 - sec1; + j = usec2 - usec1; + while (j < 0) + { + i++; + j += 1000000; + } + sec = (double)i + ((double)j / 1000000); + printf("%3.3f sec\n", sec); + printf("%3.3f Mpixels / sec\n", (double)(pixels) / (sec * 1000000)); + return 0; +} diff --git a/rend.c b/rend.c new file mode 100644 index 0000000..c24d0a2 --- /dev/null +++ b/rend.c @@ -0,0 +1,424 @@ +#include +#include +#include "common.h" +#include "scale.h" +#include "image.h" +#include "ximage.h" +#include "rend.h" +#include "rgba.h" +#include "image.h" +#include "color.h" +#include "grab.h" +#include "blend.h" + +/* size of the lines per segment we scale / render at a time */ +#define LINESIZE 16 + +/* useful macro */ +#define CLIP(x, y, w, h, xx, yy, ww, hh) \ +if (x < xx) {w += x; x = xx;} \ +if (y < yy) {h += y; y = xx;} \ +if ((x + w) > ww) {w = ww - x;} \ +if ((y + h) > hh) {h = hh - y;} + +void +RenderImage(Display *d, ImlibImage *im, + Drawable w, Drawable m, + Visual *v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + char anitalias, char hiq, char blend, char dither_mask) +{ + XImage *xim, *mxim; + DATA32 *buf = NULL, *pointer, *back = NULL; + int y, h, hh, jump; + static GC gc = 0; + static GC gcm = 0; + XGCValues gcv; + DATA32 **ypoints = NULL; + int *xpoints = NULL; + int *yapoints = NULL; + int *xapoints = NULL; + int scw, sch; + int psx, psy, psw, psh; + char xup = 0, yup = 0; + char shm = 0; + + /* dont do anything if we have a 0 widht or height image to render */ + if ((dw <= 0) || (dh <= 0)) + return; + /* if the input rect size < 0 dont render either */ + if ((sw <= 0) || (sh <= 0)) + return; + /* if the output is too big (8k arbitary limit here) dont bother */ + if ((dw > 8192) || (dh > 8192)) + return; + /* clip the source rect to be within the actual image */ + psx = sx; + psy = sy; + psw = sw; + psh = sh; + CLIP(sx, sy, sw, sh, 0, 0, im->w, im->h); + /* clip output coords to clipped input coords */ + if (psx != sx) + dx = (dx * sx) / psx; + if (psy != sy) + dy = (dy * sy) / psy; + if (psw != sw) + dw = (dw * sw) / psw; + if (psh != sh) + dh = (dh * sh) / psh; + /* do a second check to see if we now have invalid coords */ + /* dont do anything if we have a 0 widht or height image to render */ + if ((dw <= 0) || (dh <= 0)) + return; + /* if the input rect size < 0 dont render either */ + if ((sw <= 0) || (sh <= 0)) + return; + /* if the output is too big (8k arbitary limit here) dont bother */ + if ((dw > 8192) || (dh > 8192)) + return; + /* calculate the scaling factors of width and height for a whole image */ + scw = dw * im->w / sw; + sch = dh * im->h / sh; + /* if we are scaling the image at all make a scaling buffer */ + if (!((sw == dw) && (sh == dh))) + { + /* need to calculate ypoitns and xpoints array */ + ypoints = CalcYPoints(im->data, im->w, im->h, sch, im->border.top, im->border.bottom); + if (!ypoints) + return; + xpoints = CalcXPoints(im->w, scw, im->border.left, im->border.right); + if (!xpoints) + { + free(ypoints); + return; + } + /* calculate aliasing counts */ + if (anitalias) + { + yapoints = CalcApoints(im->h, sch, im->border.top, im->border.bottom); + if (!yapoints) + { + free(ypoints); + free(xpoints); + return; + } + xapoints = CalcApoints(im->w, scw, im->border.left, im->border.right); + if (!xapoints) + { + free(yapoints); + free(ypoints); + free(xpoints); + return; + } + } + } + if ((blend) && (IMAGE_HAS_ALPHA(im))) + back = GrabDrawableToRGBA(d, w, 0, v, cm, depth, dx, dy, dw, dh, 0); + /* get a new XImage - or get one from the cached list */ + xim = ProduceXImage(d, v, depth, dw, dh, &shm); + if (!xim) + { + if (anitalias) + { + free(xapoints); + free(yapoints); + } + free(ypoints); + free(xpoints); + if (back) + free(back); + return; + } + /* do a double check in 24/32bpp */ + if ((xim->bits_per_pixel == 32) && (depth == 24)) + depth = 32; + if (m) + { + mxim = ProduceXImage(d, v, 1, dw, dh, &shm); + if (!mxim) + { + ConsumeXImage(d, xim); + if (anitalias) + { + free(xapoints); + free(yapoints); + } + free(ypoints); + free(xpoints); + if (back) + free(back); + return; + } + } + /* if we are scaling the image at all make a scaling buffer */ + if (!((sw == dw) && (sh == dh))) + { + /* allocate a buffer to render scaled RGBA data into */ + buf = malloc(dw * LINESIZE * sizeof(int)); + if (!buf) + { + ConsumeXImage(d, xim); + if (m) + ConsumeXImage(d, mxim); + if (anitalias) + { + free(xapoints); + free(yapoints); + } + free(ypoints); + free(xpoints); + if (back) + free(back); + return; + } + } + /* setup h */ + h = dh; + /* set our scaling up in x / y dir flags */ + if (dw > sw) + xup = 1; + if (dh > sh) + yup = 1; + /* scale in LINESIZE Y chunks and convert to depth*/ + for (y = 0; y < dh; y += LINESIZE) + { + hh = LINESIZE; + if (h < LINESIZE) + hh = h; + /* if we're scaling it */ + if (buf) + { + /* scale the imagedata for this LINESIZE lines chunk of image data */ + if (anitalias) + { + if (IMAGE_HAS_ALPHA(im)) + ScaleAARGBA(ypoints, xpoints, buf, xapoints, yapoints, xup, yup, dx, dy + y, 0, 0, dw, hh, dw, im->w); + else + ScaleAARGB(ypoints, xpoints, buf, xapoints, yapoints, xup, yup, dx, dy + y, 0, 0, dw, hh, dw, im->w); + } + else + ScaleSampleRGBA(ypoints, xpoints, buf, dx, dy + y, 0, 0, dw, hh, dw); + jump = 0; + pointer = buf; + } + else + { + jump = im->w - sw; + pointer = im->data + ((y + sy) * im->w) + sx; + } + /* if we have a back buffer - we're blending to the bg */ + if (back) + { + BlendRGBAToRGBA(pointer, jump, back + (y * dw), 0, dw, hh); + pointer = back + (y * dw); + jump = 0; + } + /* once scaled... convert chunk to bit depth into XImage bufer */ + /* NB - the order here may be random - but I chose it to select most */ + /* common depths first */ + if (depth == 16) + { + if (hiq) + RGBA_to_RGB565_dither(pointer, jump, + ((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))), + (xim->bytes_per_line / sizeof(DATA16)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB565_fast(pointer, jump, + ((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))), + (xim->bytes_per_line / sizeof(DATA16)) - dw, + dw, hh, dx, dy + y); + } + /* FIXME: need to handle different RGB ordering */ + else if (depth == 24) + { + RGBA_to_RGB888_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * xim->bytes_per_line), + xim->bytes_per_line - (dw * 3), + dw, hh, dx, dy + y); + } + else if (depth == 32) + { + RGBA_to_RGB8888_fast(pointer, jump, + ((DATA32 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA32))), + (xim->bytes_per_line / sizeof(DATA32)) - dw, + dw, hh, dx, dy + y); + } + else if (depth == 8) + { + if (_pal_type == 0) + { + if (hiq) + RGBA_to_RGB332_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB332_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 1) + { + if (hiq) + RGBA_to_RGB232_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB232_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 2) + { + if (hiq) + RGBA_to_RGB222_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB222_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 3) + { + if (hiq) + RGBA_to_RGB221_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB221_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 4) + { + if (hiq) + RGBA_to_RGB121_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB121_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 5) + { + if (hiq) + RGBA_to_RGB111_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB111_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + else if (_pal_type == 6) + { + if (hiq) + RGBA_to_RGB1_dither(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB1_fast(pointer, jump, + ((DATA8 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA8))), + (xim->bytes_per_line / sizeof(DATA8)) - dw, + dw, hh, dx, dy + y); + } + } + else if (depth == 15) + { + if (hiq) + RGBA_to_RGB555_dither(pointer, jump, + ((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))), + (xim->bytes_per_line / sizeof(DATA16)) - dw, + dw, hh, dx, dy + y); + else + RGBA_to_RGB555_fast(pointer, jump, + ((DATA16 *)xim->data) + (y * (xim->bytes_per_line / sizeof(DATA16))), + (xim->bytes_per_line / sizeof(DATA16)) - dw, + dw, hh, dx, dy + y); + } + if (m) + { + memset(((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)), + 0x0, mxim->bytes_per_line * hh); + if (dither_mask) + RGBA_to_A1_dither(pointer, jump, + ((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)), + (mxim->bytes_per_line) - (dw >> 3), + dw, hh, dx, dy + y); + else + RGBA_to_A1_fast(pointer, jump, + ((DATA8 *)mxim->data) + (y * (mxim->bytes_per_line)), + (mxim->bytes_per_line) - (dw >> 3), + dw, hh, dx, dy + y); + } + /* FIXME: have to add code to generate mask if asked for */ + h -= LINESIZE; + } + /* free up our buffers and poit tables */ + if (buf) + { + free(buf); + free(ypoints); + free(xpoints); + } + if (anitalias) + { + free(yapoints); + free(xapoints); + } + if (back) + free(back); + /* if we didnt have a gc... create it */ + if (!gc) + { + gcv.graphics_exposures = False; + gc = XCreateGC(d, w, GCGraphicsExposures, &gcv); + } + if (m) + { + if (!gcm) + { + gcv.graphics_exposures = False; + gcm = XCreateGC(d, m, GCGraphicsExposures, &gcv); + } + /* write the mask */ + if (shm) + /* write shm XImage */ + XShmPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh, False); + /* write regular XImage */ + else + XPutImage(d, m, gcm, mxim, 0, 0, dx, dy, dw, dh); + } + /* write the image */ + if (shm) + /* write shm XImage */ + XShmPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh, False); + /* write regular XImage */ + else + XPutImage(d, w, gc, xim, 0, 0, dx, dy, dw, dh); + /* free the XImage and put onto our free list */ + /* wait for the write to be done */ + if (shm) + XSync(d, False); + ConsumeXImage(d, xim); + if (m) + ConsumeXImage(d, mxim); +} + diff --git a/rend.h b/rend.h new file mode 100644 index 0000000..5d32af2 --- /dev/null +++ b/rend.h @@ -0,0 +1,10 @@ +#ifndef __REND +#define __REND 1 +void +RenderImage(Display *d, ImlibImage *im, + Drawable w, Drawable m, + Visual *v, Colormap cm, int depth, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + char anitalias, char hiq, char blend, char dither_mask); +#endif diff --git a/rgba.c b/rgba.c new file mode 100644 index 0000000..06de837 --- /dev/null +++ b/rgba.c @@ -0,0 +1,2797 @@ +#include "common.h" +#include "rgba.h" + +#define IS_ALIGNED_64(val) (!((val) & 0x7)) +#define IS_ALIGNED_32(val) (!((val) & 0x3)) +#define IS_ALIGNED_16(val) (!((val) & 0x1)) + +#define IS_MULTIPLE_2(val) (!((val) & 0x1)) +#define IS_MULTIPLE_4(val) (!((val) & 0x3)) + +/* for PPC / Motorola / SPARC, not x86, ALPHA */ +/*#define __BIG_ENDIAN__*/ +/* for data in ABGR memory model */ + +/* NOTES: */ +/* x86: RGBA in byte order = ABGR when read as an int (in register/int) */ + +/* internal static functions */ +static void *_load_PNG (int *ww, int *hh, FILE *f); + +/* lookup table to see what color index to use */ +extern DATA8 _dither_color_lut[256]; + +/* using DATA32 - major speedup for aligned memory reads */ + +/* 48Kb of static data (lookup tabel for dithering) */ +static DATA16 _dither_r565_44[4][4][256]; +static DATA16 _dither_g565_44[4][4][256]; +static DATA16 _dither_b565_44[4][4][256]; +/* another 48Kb of static data (lookup table for dithering) */ +static DATA16 _dither_r555_44[4][4][256]; +static DATA16 _dither_g555_44[4][4][256]; +static DATA16 _dither_b555_44[4][4][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r332_88[8][8][256]; +static DATA8 _dither_g332_88[8][8][256]; +static DATA8 _dither_b332_88[8][8][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r232_88[8][8][256]; +static DATA8 _dither_g232_88[8][8][256]; +static DATA8 _dither_b232_88[8][8][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r222_88[8][8][256]; +static DATA8 _dither_g222_88[8][8][256]; +static DATA8 _dither_b222_88[8][8][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r221_88[8][8][256]; +static DATA8 _dither_g221_88[8][8][256]; +static DATA8 _dither_b221_88[8][8][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r121_88[8][8][256]; +static DATA8 _dither_g121_88[8][8][256]; +static DATA8 _dither_b121_88[8][8][256]; +/* another 24Kb of static data (lookup table for dithering) */ +static DATA8 _dither_r111_88[8][8][256]; +static DATA8 _dither_g111_88[8][8][256]; +static DATA8 _dither_b111_88[8][8][256]; +/* another 8Kb of static data (lookup table for dithering) */ +static DATA8 _dither_1_88[8][8][256]; + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB565 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB565 conversion */ +#define WRITE1_RGBA_RGB565(src, dest) \ +*dest = ((*src << 8) & 0xf800) | \ + ((*src >> 5) & 0x7e0) | \ + ((*src >> 19) & 0x1f); dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] << 8) & 0xf800) | \ + ((src[1] >> 5) & 0x7e0) | \ + ((src[1] >> 19) & 0x1f) | \ + ((src[0] << 24) & 0xf8000000) | \ + ((src[0] << 11) & 0x7e00000) | \ + ((src[0] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB565(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] << 8) & 0xf800) | \ + ((src[0] >> 5) & 0x7e0) | \ + ((src[0] >> 19) & 0x1f) | \ + ((src[1] << 24) & 0xf8000000) | \ + ((src[1] << 11) & 0x7e00000) | \ + ((src[1] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB565 conversion */ +#define DITHER_RGBA_565_LUT_R(num) \ +(_dither_r565_44[(x + num) & 0x3][y & 0x3][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_565_LUT_G(num) \ +(_dither_g565_44[(x + num) & 0x3][y & 0x3][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_565_LUT_B(num) \ +(_dither_b565_44[(x + num) & 0x3][y & 0x3][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB565_DITHER(src, dest) \ +*dest = (DITHER_RGBA_565_LUT_R(0)) | \ + (DITHER_RGBA_565_LUT_G(0)) | \ + (DITHER_RGBA_565_LUT_B(0)); dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_565_LUT_R(1))) | \ + ((DITHER_RGBA_565_LUT_G(1))) | \ + ((DITHER_RGBA_565_LUT_B(1))) | \ + ((DITHER_RGBA_565_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_565_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_565_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB565_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_565_LUT_R(0))) | \ + ((DITHER_RGBA_565_LUT_G(0))) | \ + ((DITHER_RGBA_565_LUT_B(0))) | \ + ((DITHER_RGBA_565_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_565_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_565_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB555 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB555 conversion */ +#define WRITE1_RGBA_RGB555(src, dest) \ +*dest = ((*src << 7) & 0x7c00) | \ + ((*src >> 6) & 0x3e0) | \ + ((*src >> 19) & 0x1f); dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[1] << 7) & 0x7c00) | \ + ((src[1] >> 6) & 0x3e0) | \ + ((src[1] >> 19) & 0x1f) | \ + ((src[0] << 23) & 0x7c000000) | \ + ((src[0] << 10) & 0x3e00000) | \ + ((src[0] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB555(src, dest) \ +{ \ + *((DATA32 *)dest) = ((src[0] << 7) & 0x7c00) | \ + ((src[0] >> 6) & 0x3e0) | \ + ((src[0] >> 19) & 0x1f) | \ + ((src[1] << 23) & 0x7c000000) | \ + ((src[1] << 10) & 0x3e00000) | \ + ((src[1] >> 3) & 0x1f0000); \ + dest += 2; src += 2; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB555 conversion */ +#define DITHER_RGBA_555_LUT_R(num) \ +(_dither_r555_44[(x + num) & 0x3][y & 0x3][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_555_LUT_G(num) \ +(_dither_g555_44[(x + num) & 0x3][y & 0x3][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_555_LUT_B(num) \ +(_dither_b555_44[(x + num) & 0x3][y & 0x3][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB555_DITHER(src, dest) \ +*dest = (DITHER_RGBA_555_LUT_R(0)) | \ + (DITHER_RGBA_555_LUT_G(0)) | \ + (DITHER_RGBA_555_LUT_B(0)); dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_555_LUT_R(1))) | \ + ((DITHER_RGBA_555_LUT_G(1))) | \ + ((DITHER_RGBA_555_LUT_B(1))) | \ + ((DITHER_RGBA_555_LUT_R(0) << 16)) | \ + ((DITHER_RGBA_555_LUT_G(0) << 16)) | \ + ((DITHER_RGBA_555_LUT_B(0) << 16)); \ + dest += 2; src += 2; \ +} +#else +#define WRITE2_RGBA_RGB555_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = ((DITHER_RGBA_555_LUT_R(0))) | \ + ((DITHER_RGBA_555_LUT_G(0))) | \ + ((DITHER_RGBA_555_LUT_B(0))) | \ + ((DITHER_RGBA_555_LUT_R(1) << 16)) | \ + ((DITHER_RGBA_555_LUT_G(1) << 16)) | \ + ((DITHER_RGBA_555_LUT_B(1) << 16)); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB332 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB332 conversion */ +#define WRITE1_RGBA_RGB332(src, dest) \ +*dest = _dither_color_lut[((*src >> 22) & 0x03) | \ + ((*src >> 11) & 0x1c) | \ + ((*src) & 0xe0)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB332(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] >> 22) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1]) & 0xe0)]) | \ + (_dither_color_lut[((src[0] >> 22) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0] & 0xe0)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB332(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] >> 22) & 0x03) | \ + ((src[3] >> 11) & 0x1c) | \ + ((src[3]) & 0xe0)]) | \ + (_dither_color_lut[((src[2] >> 22) & 0x03) | \ + ((src[2] >> 11) & 0x1c) | \ + ((src[2]) & 0xe0)] << 8) | \ + (_dither_color_lut[((src[1] >> 22) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1]) & 0xe0)] << 16) | \ + (_dither_color_lut[((src[0] >> 22) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0]) & 0xe0)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB332(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] >> 22) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0]) & 0xe0)]) | \ + (_dither_color_lut[((src[1] >> 22) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1]) & 0xe0)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB332(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] >> 22) & 0x03) | \ + ((src[0] >> 11) & 0x1c) | \ + ((src[0]) & 0xe0)]) | \ + (_dither_color_lut[((src[1] >> 22) & 0x03) | \ + ((src[1] >> 11) & 0x1c) | \ + ((src[1]) & 0xe0)] << 8) | \ + (_dither_color_lut[((src[2] >> 22) & 0x03) | \ + ((src[2] >> 11) & 0x1c) | \ + ((src[2]) & 0xe0)] << 16) | \ + (_dither_color_lut[((src[3] >> 22) & 0x03) | \ + ((src[3] >> 11) & 0x1c) | \ + ((src[3]) & 0xe0)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB332 conversion */ +#define DITHER_RGBA_332_LUT_R(num) \ +(_dither_r332_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_332_LUT_G(num) \ +(_dither_g332_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_332_LUT_B(num) \ +(_dither_b332_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB332_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_332_LUT_R(0)) | \ + (DITHER_RGBA_332_LUT_G(0)) | \ + (DITHER_RGBA_332_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(3))) | \ + ((DITHER_RGBA_332_LUT_G(3))) | \ + ((DITHER_RGBA_332_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(2))) | \ + ((DITHER_RGBA_332_LUT_G(2))) | \ + ((DITHER_RGBA_332_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(2))) | \ + ((DITHER_RGBA_332_LUT_G(2))) | \ + ((DITHER_RGBA_332_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(3))) | \ + ((DITHER_RGBA_332_LUT_G(3))) | \ + ((DITHER_RGBA_332_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB332_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_332_LUT_R(0))) | \ + ((DITHER_RGBA_332_LUT_G(0))) | \ + ((DITHER_RGBA_332_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_332_LUT_R(1))) | \ + ((DITHER_RGBA_332_LUT_G(1))) | \ + ((DITHER_RGBA_332_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB232 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB232 conversion */ +#define RGB232_BSHIFT >> 22 +#define RGB232_GSHIFT >> 11 +#define RGB232_RSHIFT >> 1 +#define RGB232_BMASK & 0x03 +#define RGB232_GMASK & 0x1c +#define RGB232_RMASK & 0x60 + +#define WRITE1_RGBA_RGB232(src, dest) \ +*dest = _dither_color_lut[((*src RGB232_BSHIFT) RGB232_BMASK) | \ + ((*src RGB232_GSHIFT) RGB232_GMASK) | \ + ((*src RGB232_RSHIFT) RGB232_RMASK)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB232(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB232(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[3] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[3] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[2] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[2] RGB232_RSHIFT) RGB232_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB232(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB232(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[0] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[0] RGB232_RSHIFT) RGB232_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[1] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[1] RGB232_RSHIFT) RGB232_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[2] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[2] RGB232_RSHIFT) RGB232_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB232_BSHIFT) RGB232_BMASK) | \ + ((src[3] RGB232_GSHIFT) RGB232_GMASK) | \ + ((src[3] RGB232_RSHIFT) RGB232_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB232 conversion */ +#define DITHER_RGBA_232_LUT_R(num) \ +(_dither_r232_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_232_LUT_G(num) \ +(_dither_g232_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_232_LUT_B(num) \ +(_dither_b232_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB232_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_232_LUT_R(0)) | \ + (DITHER_RGBA_232_LUT_G(0)) | \ + (DITHER_RGBA_232_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(3))) | \ + ((DITHER_RGBA_232_LUT_G(3))) | \ + ((DITHER_RGBA_232_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(2))) | \ + ((DITHER_RGBA_232_LUT_G(2))) | \ + ((DITHER_RGBA_232_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(2))) | \ + ((DITHER_RGBA_232_LUT_G(2))) | \ + ((DITHER_RGBA_232_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(3))) | \ + ((DITHER_RGBA_232_LUT_G(3))) | \ + ((DITHER_RGBA_232_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB232_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_232_LUT_R(0))) | \ + ((DITHER_RGBA_232_LUT_G(0))) | \ + ((DITHER_RGBA_232_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_232_LUT_R(1))) | \ + ((DITHER_RGBA_232_LUT_G(1))) | \ + ((DITHER_RGBA_232_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB222 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB222 conversion */ +#define RGB222_BSHIFT >> 22 +#define RGB222_GSHIFT >> 12 +#define RGB222_RSHIFT >> 2 +#define RGB222_BMASK & 0x03 +#define RGB222_GMASK & 0x0c +#define RGB222_RMASK & 0x30 + +#define WRITE1_RGBA_RGB222(src, dest) \ +*dest = _dither_color_lut[((*src RGB222_BSHIFT) RGB222_BMASK) | \ + ((*src RGB222_GSHIFT) RGB222_GMASK) | \ + ((*src RGB222_RSHIFT) RGB222_RMASK)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB222(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB222(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[3] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[3] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[2] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[2] RGB222_RSHIFT) RGB222_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB222(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB222(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[0] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[0] RGB222_RSHIFT) RGB222_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[1] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[1] RGB222_RSHIFT) RGB222_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[2] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[2] RGB222_RSHIFT) RGB222_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB222_BSHIFT) RGB222_BMASK) | \ + ((src[3] RGB222_GSHIFT) RGB222_GMASK) | \ + ((src[3] RGB222_RSHIFT) RGB222_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB222 conversion */ +#define DITHER_RGBA_222_LUT_R(num) \ +(_dither_r222_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_222_LUT_G(num) \ +(_dither_g222_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_222_LUT_B(num) \ +(_dither_b222_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB222_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_222_LUT_R(0)) | \ + (DITHER_RGBA_222_LUT_G(0)) | \ + (DITHER_RGBA_222_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(3))) | \ + ((DITHER_RGBA_222_LUT_G(3))) | \ + ((DITHER_RGBA_222_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(2))) | \ + ((DITHER_RGBA_222_LUT_G(2))) | \ + ((DITHER_RGBA_222_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(2))) | \ + ((DITHER_RGBA_222_LUT_G(2))) | \ + ((DITHER_RGBA_222_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(3))) | \ + ((DITHER_RGBA_222_LUT_G(3))) | \ + ((DITHER_RGBA_222_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB222_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_222_LUT_R(0))) | \ + ((DITHER_RGBA_222_LUT_G(0))) | \ + ((DITHER_RGBA_222_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_222_LUT_R(1))) | \ + ((DITHER_RGBA_222_LUT_G(1))) | \ + ((DITHER_RGBA_222_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB221 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB221 conversion */ +#define RGB221_BSHIFT >> 23 +#define RGB221_GSHIFT >> 13 +#define RGB221_RSHIFT >> 3 +#define RGB221_BMASK & 0x01 +#define RGB221_GMASK & 0x06 +#define RGB221_RMASK & 0x18 + +#define WRITE1_RGBA_RGB221(src, dest) \ +*dest = _dither_color_lut[((*src RGB221_BSHIFT) RGB221_BMASK) | \ + ((*src RGB221_GSHIFT) RGB221_GMASK) | \ + ((*src RGB221_RSHIFT) RGB221_RMASK)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB221(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB221(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[3] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[3] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[2] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[2] RGB221_RSHIFT) RGB221_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB221(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB221(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[0] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[0] RGB221_RSHIFT) RGB221_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[1] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[1] RGB221_RSHIFT) RGB221_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[2] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[2] RGB221_RSHIFT) RGB221_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB221_BSHIFT) RGB221_BMASK) | \ + ((src[3] RGB221_GSHIFT) RGB221_GMASK) | \ + ((src[3] RGB221_RSHIFT) RGB221_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB221 conversion */ +#define DITHER_RGBA_221_LUT_R(num) \ +(_dither_r221_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_221_LUT_G(num) \ +(_dither_g221_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_221_LUT_B(num) \ +(_dither_b221_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB221_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_221_LUT_R(0)) | \ + (DITHER_RGBA_221_LUT_G(0)) | \ + (DITHER_RGBA_221_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(3))) | \ + ((DITHER_RGBA_221_LUT_G(3))) | \ + ((DITHER_RGBA_221_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(2))) | \ + ((DITHER_RGBA_221_LUT_G(2))) | \ + ((DITHER_RGBA_221_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(2))) | \ + ((DITHER_RGBA_221_LUT_G(2))) | \ + ((DITHER_RGBA_221_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(3))) | \ + ((DITHER_RGBA_221_LUT_G(3))) | \ + ((DITHER_RGBA_221_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB221_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_221_LUT_R(0))) | \ + ((DITHER_RGBA_221_LUT_G(0))) | \ + ((DITHER_RGBA_221_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_221_LUT_R(1))) | \ + ((DITHER_RGBA_221_LUT_G(1))) | \ + ((DITHER_RGBA_221_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB121 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB121 conversion */ +#define RGB121_BSHIFT >> 23 +#define RGB121_GSHIFT >> 13 +#define RGB121_RSHIFT >> 4 +#define RGB121_BMASK & 0x01 +#define RGB121_GMASK & 0x06 +#define RGB121_RMASK & 0x08 + +#define WRITE1_RGBA_RGB121(src, dest) \ +*dest = _dither_color_lut[((*src RGB121_BSHIFT) RGB121_BMASK) | \ + ((*src RGB121_GSHIFT) RGB121_GMASK) | \ + ((*src RGB121_RSHIFT) RGB121_RMASK)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB121(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB121(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[3] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[3] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[2] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[2] RGB121_RSHIFT) RGB121_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB121(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB121(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[0] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[0] RGB121_RSHIFT) RGB121_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[1] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[1] RGB121_RSHIFT) RGB121_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[2] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[2] RGB121_RSHIFT) RGB121_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB121_BSHIFT) RGB121_BMASK) | \ + ((src[3] RGB121_GSHIFT) RGB121_GMASK) | \ + ((src[3] RGB121_RSHIFT) RGB121_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB121 conversion */ +#define DITHER_RGBA_121_LUT_R(num) \ +(_dither_r121_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_121_LUT_G(num) \ +(_dither_g121_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_121_LUT_B(num) \ +(_dither_b121_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB121_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_121_LUT_R(0)) | \ + (DITHER_RGBA_121_LUT_G(0)) | \ + (DITHER_RGBA_121_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(3))) | \ + ((DITHER_RGBA_121_LUT_G(3))) | \ + ((DITHER_RGBA_121_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(2))) | \ + ((DITHER_RGBA_121_LUT_G(2))) | \ + ((DITHER_RGBA_121_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(2))) | \ + ((DITHER_RGBA_121_LUT_G(2))) | \ + ((DITHER_RGBA_121_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(3))) | \ + ((DITHER_RGBA_121_LUT_G(3))) | \ + ((DITHER_RGBA_121_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB121_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_121_LUT_R(0))) | \ + ((DITHER_RGBA_121_LUT_G(0))) | \ + ((DITHER_RGBA_121_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_121_LUT_R(1))) | \ + ((DITHER_RGBA_121_LUT_G(1))) | \ + ((DITHER_RGBA_121_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB111 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB111 conversion */ +#define RGB111_BSHIFT >> 23 +#define RGB111_GSHIFT >> 14 +#define RGB111_RSHIFT >> 5 +#define RGB111_BMASK & 0x01 +#define RGB111_GMASK & 0x02 +#define RGB111_RMASK & 0x30 + +#define WRITE1_RGBA_RGB111(src, dest) \ +*dest = _dither_color_lut[((*src RGB111_BSHIFT) RGB111_BMASK) | \ + ((*src RGB111_GSHIFT) RGB111_GMASK) | \ + ((*src RGB111_RSHIFT) RGB111_RMASK)]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE2_RGBA_RGB111(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB111(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[3] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[3] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[3] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[2] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[2] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[2] RGB111_RSHIFT) RGB111_RMASK)] << 8) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 16) | \ + (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#else +#define WRITE2_RGBA_RGB111(src, dest) \ +{ \ + *((DATA16 *)dest) = (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 8); \ + dest += 2; src += 2; \ +} +#define WRITE4_RGBA_RGB111(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((src[0] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[0] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[0] RGB111_RSHIFT) RGB111_RMASK)]) | \ + (_dither_color_lut[((src[1] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[1] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[1] RGB111_RSHIFT) RGB111_RMASK)] << 8) | \ + (_dither_color_lut[((src[2] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[2] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[2] RGB111_RSHIFT) RGB111_RMASK)] << 16) | \ + (_dither_color_lut[((src[3] RGB111_BSHIFT) RGB111_BMASK) | \ + ((src[3] RGB111_GSHIFT) RGB111_GMASK) | \ + ((src[3] RGB111_RSHIFT) RGB111_RMASK)] << 24); \ + dest += 4; src += 4; \ +} +#endif +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB111 conversion */ +#define DITHER_RGBA_111_LUT_R(num) \ +(_dither_r111_88[(x + num) & 0x7][y & 0x7][(src[num] >> 0 ) & 0xff]) +#define DITHER_RGBA_111_LUT_G(num) \ +(_dither_g111_88[(x + num) & 0x7][y & 0x7][(src[num] >> 8) & 0xff]) +#define DITHER_RGBA_111_LUT_B(num) \ +(_dither_b111_88[(x + num) & 0x7][y & 0x7][(src[num] >> 16) & 0xff]) + +#define WRITE1_RGBA_RGB111_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_111_LUT_R(0)) | \ + (DITHER_RGBA_111_LUT_G(0)) | \ + (DITHER_RGBA_111_LUT_B(0))]; dest++; src++ +#ifdef __BIG_ENDIAN__ +#define WRITE4_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(3))) | \ + ((DITHER_RGBA_111_LUT_G(3))) | \ + ((DITHER_RGBA_111_LUT_B(3)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(2))) | \ + ((DITHER_RGBA_111_LUT_G(2))) | \ + ((DITHER_RGBA_111_LUT_B(2)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))] << 8); \ + dest += 2; src += 2; \ +} +#else +#define WRITE4_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 8) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(2))) | \ + ((DITHER_RGBA_111_LUT_G(2))) | \ + ((DITHER_RGBA_111_LUT_B(2)))] << 16) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(3))) | \ + ((DITHER_RGBA_111_LUT_G(3))) | \ + ((DITHER_RGBA_111_LUT_B(3)))] << 24); \ + dest += 4; src += 4; \ +} +#define WRITE2_RGBA_RGB111_DITHER(src, dest) \ +{ \ + *((DATA32 *)dest) = (_dither_color_lut[((DITHER_RGBA_111_LUT_R(0))) | \ + ((DITHER_RGBA_111_LUT_G(0))) | \ + ((DITHER_RGBA_111_LUT_B(0)))]) | \ + (_dither_color_lut[((DITHER_RGBA_111_LUT_R(1))) | \ + ((DITHER_RGBA_111_LUT_G(1))) | \ + ((DITHER_RGBA_111_LUT_B(1)))] << 8); \ + dest += 2; src += 2; \ +} +#endif + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB1 (mono B&W) */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB1 conversion */ + +#define WRITE1_RGBA_RGB1(src, dest) \ +*dest = _dither_color_lut[((((*src >> 0) & 0xff) + \ + ((*src >> 8) & 0xff) + \ + ((*src >> 16) & 0xff)) / 3) >> 7]; dest++; src++ +/*****************************************************************************/ +/* MACROS for dithered RGBA -> RGB1 conversion */ +#define DITHER_RGBA_1_LUT(num) \ +(_dither_1_88[(x + num) & 0x7][y & 0x7][((((*src >> 0) & 0xff) + \ + ((*src >> 8) & 0xff) + \ + ((*src >> 16) & 0xff)) / 3)]) + +#define WRITE1_RGBA_RGB1_DITHER(src, dest) \ +*dest = _dither_color_lut[(DITHER_RGBA_1_LUT(0))]; dest++; src++ + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> A1 (mono B&W - alpha mas) */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> A1 conversion */ + +#define WRITE1_RGBA_A1(src, dest) \ +*dest |= ((*src & 0x80000000) >> (31 - (x & 0x7))); \ +if ((x & 0x7) == 0x7) dest++; \ +src++ + +/*****************************************************************************/ +/* MACROS for dithered RGBA -> A1 conversion */ +#define DITHER_RGBA_A1_LUT(num) \ +(_dither_1_88[(x + num) & 0x7][y & 0x7][(src[num] >> 24)]) + +#define WRITE1_RGBA_A1_DITHER(src, dest) \ +*dest |= (DITHER_RGBA_A1_LUT(0)) << (x & 0x7); \ +if ((x & 0x7) == 0x7) dest++; \ +src++; + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB8888 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB8888 conversion */ +#define WRITE1_RGBA_RGB8888(src, dest) \ +*dest = ((*src >> 16) & 0x0000ff) | \ + ((*src << 0) & 0x00ff00) | \ + ((*src << 16) & 0xff0000); dest++; src++; + +/*****************************************************************************/ +/* Actual rendering routines */ +/* RGBA -> RGB888 */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MACROS for plain RGBA -> RGB888 conversion */ +#define WRITE1_RGBA_RGB888(src, dest) \ +*dest = ((*src >> 16) & 0xff); dest++; \ +*dest = ((*src >> 8) & 0xff); dest++; \ +*dest = ((*src >> 0) & 0xff); dest++; src++; + +/* Palette mode stuff */ + +void +RGBA_init(void) +{ + /* the famous dither matrix */ + DATA8 _dither_44[4][4] = + { + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2} + }; + DATA8 _dither_88[8][8] = + { + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } + }; + int i, x, y; + + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + _dither_r565_44[x][y][i] = ((i + 8) & 0xf8) << 8; + else + _dither_r565_44[x][y][i] = (i & 0xf8) << 8; + + if ((_dither_44[x][y] < ((i & 0x3) << 1)) && (i < (256 - 4))) + _dither_g565_44[x][y][i] = (((i + 4) & 0xfc) << 8) >> 5; + else + _dither_g565_44[x][y][i] = ((i & 0xfc) << 8) >> 5; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + _dither_b565_44[x][y][i] = (((i + 8) & 0xf8) << 16) >> 19; + else + _dither_b565_44[x][y][i] = ((i & 0xf8) << 16) >> 19; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + _dither_r555_44[x][y][i] = (((i + 8) & 0xf8) << 8) >> 1; + else + _dither_r555_44[x][y][i] = ((i & 0xf8) << 8) >> 1; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + _dither_g555_44[x][y][i] = (((i + 8) & 0xf8) << 8) >> 6; + else + _dither_g555_44[x][y][i] = ((i & 0xf8) << 8) >> 6; + + if ((_dither_44[x][y] < (i & 0x7)) && (i < (256 - 8))) + _dither_b555_44[x][y][i] = (((i + 8) & 0xf8) << 16) >> 19; + else + _dither_b555_44[x][y][i] = ((i & 0xf8) << 16) >> 19; + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < ((i & 0x1f) << 1)) && (i < (256 - 32))) + _dither_r332_88[x][y][i] = ((i + 32) & 0xe0); + else + _dither_r332_88[x][y][i] = (i & 0xe0); + + if ((_dither_88[x][y] < ((i & 0x1f) << 1)) && (i < (256 - 32))) + _dither_g332_88[x][y][i] = (((i + 32) >> 3)& 0x1c); + else + _dither_g332_88[x][y][i] = ((i >> 3) & 0x1c); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_b332_88[x][y][i] = (((i + 64) >> 6)& 0x03); + else + _dither_b332_88[x][y][i] = ((i >> 6) & 0x03); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_r232_88[x][y][i] = (((i + 64) >> 1) & 0x60); + else + _dither_r232_88[x][y][i] = ((i >> 1) & 0x60); + + if ((_dither_88[x][y] < ((i & 0x1f) << 1)) && (i < (256 - 32))) + _dither_g232_88[x][y][i] = (((i + 32) >> 3)& 0x1c); + else + _dither_g232_88[x][y][i] = ((i >> 3) & 0x1c); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_b232_88[x][y][i] = (((i + 64) >> 6)& 0x03); + else + _dither_b232_88[x][y][i] = ((i >> 6) & 0x03); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_r222_88[x][y][i] = (((i + 64) >> 2) & 0x30); + else + _dither_r222_88[x][y][i] = ((i >> 2) & 0x30); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_g222_88[x][y][i] = (((i + 64) >> 4)& 0x0c); + else + _dither_g222_88[x][y][i] = ((i >> 4) & 0x0c); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_b222_88[x][y][i] = (((i + 64) >> 6)& 0x03); + else + _dither_b222_88[x][y][i] = ((i >> 6) & 0x03); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_r221_88[x][y][i] = (((i + 64) >> 3) & 0x18); + else + _dither_r221_88[x][y][i] = ((i >> 3) & 0x18); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_g221_88[x][y][i] = (((i + 64) >> 5) & 0x06); + else + _dither_g221_88[x][y][i] = ((i >> 5) & 0x06); + + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_b221_88[x][y][i] = (((i + 128) >> 7) & 0x01); + else + _dither_b221_88[x][y][i] = ((i >> 7) & 0x01); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_r121_88[x][y][i] = (((i + 128) >> 4) & 0x08); + else + _dither_r121_88[x][y][i] = ((i >> 4) & 0x08); + + if ((_dither_88[x][y] < (i & 0x3f)) && (i < (256 - 64))) + _dither_g121_88[x][y][i] = (((i + 64) >> 5) & 0x06); + else + _dither_g121_88[x][y][i] = ((i >> 5) & 0x06); + + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_b121_88[x][y][i] = (((i + 128) >> 7) & 0x01); + else + _dither_b121_88[x][y][i] = ((i >> 7) & 0x01); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_r111_88[x][y][i] = (((i + 128) >> 5) & 0x04); + else + _dither_r111_88[x][y][i] = ((i >> 5) & 0x04); + + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_g111_88[x][y][i] = (((i + 128) >> 6) & 0x02); + else + _dither_g111_88[x][y][i] = ((i >> 6) & 0x02); + + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_b111_88[x][y][i] = (((i + 128) >> 7) & 0x01); + else + _dither_b111_88[x][y][i] = ((i >> 7) & 0x01); + } + } + } + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + for (i = 0; i < 256; i++) + { + if ((_dither_88[x][y] < ((i & 0x7f) >> 1)) && (i < (256 - 128))) + _dither_1_88[x][y][i] = (((i + 128) >> 7) & 0x01); + else + _dither_1_88[x][y][i] = ((i >> 7) & 0x01); + } + } + } +} + +void +RGBA_to_RGB565_fast(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB565(src, dest); + WRITE1_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB565(src, dest); + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB565(src, dest); + WRITE1_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB565(src, dest); + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB565(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB565_dither(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + WRITE1_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB565_DITHER(src, dest); + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + WRITE1_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB565_DITHER(src, dest); + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB565_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB555_fast(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB555(src, dest); + WRITE1_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB555(src, dest); + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB555(src, dest); + WRITE1_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = 0; y < h; y++) + { + WRITE1_RGBA_RGB555(src, dest); + for (x = 0; x < w; x+=2) + WRITE2_RGBA_RGB555(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB555_dither(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_2(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + WRITE1_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + else + { + if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB555_DITHER(src, dest); + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + WRITE1_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w--; + for (y = dy; y < h; y++) + { + x = dx - 1; + WRITE1_RGBA_RGB555_DITHER(src, dest); + for (x = dx; x < w; x+=2) + WRITE2_RGBA_RGB555_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB332_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + WRITE2_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + WRITE2_RGBA_RGB332(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB332(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB332(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB332_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + WRITE2_RGBA_RGB332_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB332_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB332_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB232_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + WRITE2_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + WRITE2_RGBA_RGB232(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB232(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB232(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB232_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + WRITE2_RGBA_RGB232_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB232_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB232_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB222_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + WRITE2_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + WRITE2_RGBA_RGB222(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB222(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB222(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB222_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + WRITE2_RGBA_RGB222_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB222_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB222_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB221_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + WRITE2_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + WRITE2_RGBA_RGB221(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB221(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB221(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB221_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + WRITE2_RGBA_RGB221_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB221_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB221_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB121_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + WRITE2_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + WRITE2_RGBA_RGB121(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB121(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB121(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB121_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + WRITE2_RGBA_RGB121_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB121_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB121_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB111_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + WRITE2_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = 0; y < h; y++) + { + for (x = 0; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + if (x < w) + { + if (IS_MULTIPLE_4((width - x))) + { + for (; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + else if (IS_MULTIPLE_2((width - x))) + { + w = width - 2 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + WRITE2_RGBA_RGB111(src, dest); + src += src_jump; + dest += dest_jump; + } + else + { + w = width - 3 - x; + for (; x < w; x+=4) + WRITE4_RGBA_RGB111(src, dest); + for (; x < width; x++) + { + WRITE1_RGBA_RGB111(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB111_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + if (IS_ALIGNED_32((int)dest)) + { + if (IS_MULTIPLE_4(width)) + { + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else if (IS_MULTIPLE_2(width)) + { + w-=2; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + WRITE2_RGBA_RGB111_DITHER(src, dest); + src += src_jump; + dest += dest_jump; + } + } + else + { + w-=3; + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x+=4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + else + { + for (y = dy; y < h; y++) + { + w = width + dx; + for (x = dx; ((x < w) && (!(IS_ALIGNED_32((int)dest)))); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + if (x < w) + { + w = (width + dx) - (3 + x); + for (; x < w; x+=4) + WRITE4_RGBA_RGB111_DITHER(src, dest); + for (; x < (width + dx); x++) + { + WRITE1_RGBA_RGB111_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + } + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB1_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_RGB1(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB1_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x++) + { + WRITE1_RGBA_RGB1_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_A1_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_A1(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_A1_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width + dx; + h = height + dy; + + for (y = dy; y < h; y++) + { + for (x = dx; x < w; x++) + { + WRITE1_RGBA_A1_DITHER(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB8888_fast(DATA32 *src , int src_jump, + DATA32 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_RGB8888(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + +void +RGBA_to_RGB888_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy) +{ + int x, y, w, h; + + w = width; + h = height; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + WRITE1_RGBA_RGB888(src, dest); + } + src += src_jump; + dest += dest_jump; + } + return; + dx = 0; + dy = 0; +} + diff --git a/rgba.h b/rgba.h new file mode 100644 index 0000000..04aeb93 --- /dev/null +++ b/rgba.h @@ -0,0 +1,71 @@ +#ifndef __RGBA +#define __RGBA 1 + +void RGBA_init(void); +void RGBA_to_RGB565_fast(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB565_dither(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB555_fast(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB555_dither(DATA32 *src , int src_jump, + DATA16 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB332_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB332_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB232_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB232_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB222_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB222_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB221_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB221_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB121_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB121_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB111_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB111_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB1_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB1_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_A1_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_A1_dither(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB8888_fast(DATA32 *src , int src_jump, + DATA32 *dest, int dest_jump, + int width, int height, int dx, int dy); +void RGBA_to_RGB888_fast(DATA32 *src , int src_jump, + DATA8 *dest, int dest_jump, + int width, int height, int dx, int dy); +#endif diff --git a/scale.c b/scale.c new file mode 100644 index 0000000..a0c2e0a --- /dev/null +++ b/scale.c @@ -0,0 +1,872 @@ +#include "common.h" +#include "scale.h" + +#define R_VAL(x) (((x) & 0x000000ff)) +#define G_VAL(x) (((x) & 0x0000ff00) >> 8) +#define B_VAL(x) (((x) & 0x00ff0000) >> 16) +#define A_VAL(x) (((x) & 0xff000000) >> 24) +#define RGBA_COMPOSE(r, g, b, a) ((a) << 24) | ((b) << 16) | ((g) << 8) | (r) +#define INV_XAP (255 - xapoints[x]) +#define XAP (xapoints[x]) +#define INV_YAP (255 - yapoints[dyy + y]) +#define YAP (yapoints[dyy + y]) + +DATA32 ** +CalcYPoints(DATA32 *src, int sw, int sh, int dh, int b1, int b2) +{ + DATA32 **p; + int i, j = 0; + int val, inc; + + p = malloc(dh * sizeof(DATA32 *)); + if (dh < (b1 + b2)) + { + if (dh < b1) + { + b1 = dh; + b2 = 0; + } + else + b2 = dh - b1; + } + val = 0; + inc = 1 << 16; + for (i = 0; i < b1; i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + if (dh > (b1 + b2)) + { + val = (b1 << 16); + inc = ((sh - b1 - b2) << 16) / (dh - b1 - b2); + for (i = 0; i < (dh - b1 - b2); i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + } + val = (sh - b2) << 16; + inc = 1 << 16; + for (i = 0; i < b2; i++) + { + p[j++] = src + ((val >> 16) * sw); + val += inc; + } + return p; +} + +int * +CalcXPoints(int sw, int dw, int b1, int b2) +{ + int *p, i, j = 0; + int val, inc; + + p = malloc(dw * sizeof(int)); + if (dw < (b1 + b2)) + { + if (dw < b1) + { + b1 = dw; + b2 = 0; + } + else + b2 = dw - b1; + } + val = 0; + inc = 1 << 16; + for (i = 0; i < b1; i++) + { + p[j++] = (val >> 16); + val += inc; + } + if (dw > (b1 + b2)) + { + val = (b1 << 16); + inc = ((sw - b1 - b2) << 16) / (dw - b1 - b2); + for (i = 0; i < (dw - b1 - b2); i++) + { + p[j++] = (val >> 16); + val += inc; + } + } + val = (sw - b2) << 16; + inc = 1 << 16; + for (i = 0; i < b2; i++) + { + p[j++] = (val >> 16); + val += inc; + } + return p; +} + +int * +CalcApoints(int s, int d, int b1, int b2) +{ + int *p, i, v, j = 0; + + p = malloc(d * sizeof(int)); + if (d < (b1 + b2)) + { + if (d < b1) + { + b1 = d; + b2 = 0; + } + else + b2 = d - b1; + } + /* scaling up */ + if (d > s) + { + int val, inc; + + for (i = 0; i < b1; i++) + p[j++] = 0; + if (d > (b1 + b2)) + { + int ss, dd; + + ss = s - b1 - b2; + dd = d - b1 - b2; + val = 0; + inc = (ss << 16) / dd; + for (i = 0; i < dd; i++) + { + p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); + if (((val >> 16) + b1) >= (s - 1)) + p[j - 1] = 0; + val += inc; + } + } + for (i = 0; i < b2; i++) + p[j++] = 0; + } + /* scaling down */ + else + { + for (i = 0; i < b1; i++) + p[j++] = 1; + if (d > (b1 + b2)) + { + int ss, dd; + + ss = s - b1 - b2; + dd = d - b1 - b2; + for (i = 0; i < dd; i++) + { + v = (((i + 1) * ss) / dd) - ((i * ss) / dd); + if (v != 1) + { + if (((((i + 1) * ss) / dd) + b1) >= s) + v = s - (((i * ss) / dd) + b1) - 1; + p[j++] = v; + } + else + p[j++] = v; + if (p[j - 1] < 1) + p[j - 1] = 1; + } + } + for (i = 0; i < b2; i++) + p[j++] = 1; + } + return p; +} + +/* scale by pixel sampling only */ +void +ScaleSampleRGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow) +{ + DATA32 *sptr, *dptr; + int x, y, end; + + /* whats the last pixel ont he line so we stop there */ + end = dxx + dw; + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* get the pointer to the start of the destination scanline */ + dptr = dest + dx + ((y + dy) * dow); + /* calculate the source line we'll scan from */ + sptr = ypoints[dyy + y]; + /* go thru the scanline and copy across */ + for (x = dxx; x < end; x++) + *dptr++ = sptr[xpoints[x]]; + } +} + +/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/ + +/* scale by area sampling */ +void +ScaleAARGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int *xapoints, int *yapoints, char xup, char yup, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow) +{ + DATA32 *sptr, *ssptr, *dptr; + int x, y, i, j, end; + + end = dxx + dw; + /* scaling up both ways */ + if ((xup) && (yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int rr = 0, gg = 0, bb = 0, aa = 0; + DATA32 pix; + + if (YAP > 0) + { + if (XAP > 0) + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + rr = R_VAL(pix) * INV_XAP; + gg = G_VAL(pix) * INV_XAP; + bb = B_VAL(pix) * INV_XAP; + aa = A_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + rr += R_VAL(pix) * XAP; + gg += G_VAL(pix) * XAP; + bb += B_VAL(pix) * XAP; + aa += A_VAL(pix) * XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + a = ((aa * YAP) + (a * INV_YAP)) >> 16; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + } + else + { + if (XAP > 0) + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if ((xup) && (!yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int rr = 0, gg = 0, bb = 0, aa = 0; + int count; + DATA32 pix; + + if (XAP > 0) + { + if (YAP > 1) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + pix = ssptr[xpoints[x]]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + } + count = j; + r = r * INV_XAP / count; + g = g * INV_XAP / count; + b = b * INV_XAP / count; + a = a * INV_XAP / count; + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + pix = ssptr[xpoints[x] + 1]; + rr += R_VAL(pix); + gg += G_VAL(pix); + bb += B_VAL(pix); + aa += A_VAL(pix); + } + count = j; + r = (r + ((rr * XAP) / count)) >> 8; + g = (g + ((gg * XAP) / count)) >> 8; + b = (b + ((bb * XAP) / count)) >> 8; + a = (a + ((aa * XAP) / count)) >> 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + a = A_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + a += A_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + } + else + { + if (YAP > 1) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j *sow); + pix = ssptr[xpoints[x]]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + } + count = j; + r /= count; + g /= count; + b /= count; + a /= count; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down horizontally */ + else if ((!xup) && (yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int rr = 0, gg = 0, bb = 0, aa = 0; + int count; + DATA32 pix; + + if (YAP > 0) + { + if (XAP > 1) + { + ssptr = ypoints[dyy + y]; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + } + count = i; + r = r * INV_YAP / count; + g = g * INV_YAP / count; + b = b * INV_YAP / count; + a = a * INV_YAP / count; + ssptr = ypoints[dyy + y] + sow; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + rr += R_VAL(pix); + gg += G_VAL(pix); + bb += B_VAL(pix); + aa += A_VAL(pix); + } + count = i; + r = (r + ((rr * YAP) / count)) >> 8; + g = (g + ((gg * YAP) / count)) >> 8; + b = (b + ((bb * YAP) / count)) >> 8; + a = (a + ((aa * YAP) / count)) >> 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + a = A_VAL(pix) * INV_YAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + a += A_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + a >>= 8; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + } + else + { + if (XAP > 1) + { + ssptr = ypoints[dyy + y]; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + } + count = i; + r /= count; + g /= count; + b /= count; + a /= count; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down horizontally & vertically */ + else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0, a = 0; + int count; + DATA32 pix; + + if ((XAP > 1) || (YAP > 1)) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + a += A_VAL(pix); + } + } + count = (i * j); + r /= count; + g /= count; + b /= count; + a /= count; + pix = RGBA_COMPOSE(r, g, b, a); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } +} + +/* scale by area sampling - IGNORE the ALPHA byte*/ +void +ScaleAARGB(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int *xapoints, int *yapoints, char xup, char yup, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow) +{ + DATA32 *sptr, *ssptr, *dptr; + int x, y, i, j, end; + + end = dxx + dw; + /* scaling up both ways */ + if ((xup) && (yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + DATA32 pix; + + if (YAP > 0) + { + if (XAP > 0) + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + rr = R_VAL(pix) * INV_XAP; + gg = G_VAL(pix) * INV_XAP; + bb = B_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + rr += R_VAL(pix) * XAP; + gg += G_VAL(pix) * XAP; + bb += B_VAL(pix) * XAP; + r = ((rr * YAP) + (r * INV_YAP)) >> 16; + g = ((gg * YAP) + (g * INV_YAP)) >> 16; + b = ((bb * YAP) + (b * INV_YAP)) >> 16; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + } + else + { + if (XAP > 0) + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x] ]; + } + } + } + } + /* if we're scaling down vertically */ + else if ((xup) && (!yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + int count; + DATA32 pix; + + if (XAP > 0) + { + if (YAP > 1) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + pix = ssptr[xpoints[x]]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + } + count = j; + r = r * INV_XAP / count; + g = g * INV_XAP / count; + b = b * INV_XAP / count; + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + pix = ssptr[xpoints[x] + 1]; + rr += R_VAL(pix); + gg += G_VAL(pix); + bb += B_VAL(pix); + } + count = j; + r = (r + ((rr * XAP) / count)) >> 8; + g = (g + ((gg * XAP) / count)) >> 8; + b = (b + ((bb * XAP) / count)) >> 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_XAP; + g = G_VAL(pix) * INV_XAP; + b = B_VAL(pix) * INV_XAP; + pix = ssptr[xpoints[x] + 1]; + r += R_VAL(pix) * XAP; + g += G_VAL(pix) * XAP; + b += B_VAL(pix) * XAP; + r >>= 8; + g >>= 8; + b >>= 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + } + else + { + if (YAP > 1) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j *sow); + pix = ssptr[xpoints[x]]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + } + count = j; + r /= count; + g /= count; + b /= count; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down horizontally */ + else if ((!xup) && (yup)) + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int rr = 0, gg = 0, bb = 0; + int count; + DATA32 pix; + + if (YAP > 0) + { + if (XAP > 1) + { + ssptr = ypoints[dyy + y]; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + } + count = i; + r = r * INV_YAP / count; + g = g * INV_YAP / count; + b = b * INV_YAP / count; + ssptr = ypoints[dyy + y] + sow; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + rr += R_VAL(pix); + gg += G_VAL(pix); + bb += B_VAL(pix); + } + count = i; + r = (r + ((rr * YAP) / count)) >> 8; + g = (g + ((gg * YAP) / count)) >> 8; + b = (b + ((bb * YAP) / count)) >> 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + { + ssptr = ypoints[dyy + y]; + pix = ssptr[xpoints[x]]; + r = R_VAL(pix) * INV_YAP; + g = G_VAL(pix) * INV_YAP; + b = B_VAL(pix) * INV_YAP; + ssptr += sow; + pix = ssptr[xpoints[x]]; + r += R_VAL(pix) * YAP; + g += G_VAL(pix) * YAP; + b += B_VAL(pix) * YAP; + r >>= 8; + g >>= 8; + b >>= 8; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + } + else + { + if (XAP > 1) + { + ssptr = ypoints[dyy + y]; + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + } + count = i; + r /= count; + g /= count; + b /= count; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } + } + /* if we're scaling down horizontally & vertically */ + else + { + /* go through every scanline in the output buffer */ + for (y = 0; y < dh; y++) + { + /* calculate the source line we'll scan from */ + dptr = dest + dx + ((y + dy) * dow); + sptr = ypoints[dyy + y]; + for (x = dxx; x < end; x++) + { + int r = 0, g = 0, b = 0; + int count; + DATA32 pix; + + if ((XAP > 1) || (YAP > 1)) + { + for (j = 0; j < YAP; j++) + { + ssptr = ypoints[dyy + y] + (j * sow); + for (i = 0; i < XAP; i++) + { + pix = ssptr[xpoints[x] + i]; + r += R_VAL(pix); + g += G_VAL(pix); + b += B_VAL(pix); + } + } + count = (i * j); + r /= count; + g /= count; + b /= count; + pix = RGBA_COMPOSE(r, g, b, 0xff); + *dptr++ = pix; + } + else + *dptr++ = sptr[xpoints[x]]; + } + } + } +} + diff --git a/scale.h b/scale.h new file mode 100644 index 0000000..619b33f --- /dev/null +++ b/scale.h @@ -0,0 +1,21 @@ +#ifndef __SCALE +#define __SCALE 1 + +DATA32 ** +CalcYPoints(DATA32 *src, int sw, int sh, int dh, int b1, int b2); +int * +CalcXPoints(int sw, int dw, int b1, int b2); +int * +CalcApoints(int s, int d, int b1, int b2); +void +ScaleSampleRGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow); +void +ScaleAARGBA(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int *xapoints, int *yapoints, char xup, char yup, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow); +void +ScaleAARGB(DATA32 **ypoints, int *xpoints, DATA32 *dest, + int *xapoints, int *yapoints, char xup, char yup, + int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow); +#endif diff --git a/test_images/im.png b/test_images/im.png new file mode 100644 index 0000000..08668bd Binary files /dev/null and b/test_images/im.png differ diff --git a/test_images/im_rgb.png b/test_images/im_rgb.png new file mode 100644 index 0000000..0d30b4e Binary files /dev/null and b/test_images/im_rgb.png differ diff --git a/ximage.c b/ximage.c new file mode 100644 index 0000000..f01293c --- /dev/null +++ b/ximage.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include "common.h" +#include "ximage.h" + +/* static private variables */ +static char x_does_shm = -1; +static int list_num = 0; +static XImage **list_xim = NULL; +static XShmSegmentInfo **list_si = NULL; +static Display **list_d = NULL; +static char *list_used = NULL; +static int list_mem_use = 0; +static int list_max_mem = 1024 * 1024 * 1024; +static int list_max_count = 1; + +/* temporary X error catcher we use later */ +static char _x_err = 0; + +/* the fucntion we use for catching the error */ +static void +TmpXError(Display * d, XErrorEvent * ev) +{ + _x_err = 1; +} + +void +SetMaxXImageCount(Display *d, int num) +{ + list_max_count = num; + FlushXImage(d); +} + +int +GetMaxXImageCount(Display *d) +{ + return list_max_count; +} + +void +SetMaxXImageTotalSize(Display *d, int num) +{ + list_max_mem = num; + FlushXImage(d); +} + +int +GetMaxXImageTotalSize(Display *d) +{ + return list_max_mem; +} + +void +FlushXImage(Display *d) +{ + int i; + XImage *xim; + char did_free = 1; + + while (((list_mem_use > list_max_mem) || (list_num > list_max_count)) && + (did_free)) + { + did_free = 0; + for (i = 0; i < list_num; i++) + { + if (list_used[i] == 0) + { + int j; + + xim = list_xim[i]; + list_mem_use -= xim->bytes_per_line * xim->height; + if (list_si[i]) + XShmDetach(d, list_si[i]); + XDestroyImage(xim); + if (list_si[i]) + { + shmdt(list_si[i]->shmaddr); + shmctl(list_si[i]->shmid, IPC_RMID, 0); + free(list_si[i]); + } + list_num--; + for (j = i; j < list_num; j++) + { + list_xim[j] = list_xim[j + 1]; + list_si[j] = list_si[j + 1]; + list_used[j] = list_used[j + 1]; + list_d[j] = list_d[j + 1]; + } + list_xim = realloc(list_xim, sizeof(XImage *) * list_num); + list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num); + list_used = realloc(list_used, sizeof(char) * list_num); + list_d = realloc(list_d, sizeof(Display *) * list_num); + did_free = 1; + } + } + } +} + +/* free (consume == opposite of produce) the XImage (mark as unused) */ +void +ConsumeXImage(Display *d, XImage *xim) +{ + int i; + + /* march through the XImage list */ + for (i = 0; i < list_num; i++) + { + /* find a match */ + if (list_xim[i] == xim) + { + /* we have a match = mark as unused */ + list_used[i] = 0; + /* flush the XImage list to get rud of stuff we dont want */ + FlushXImage(d); + /* return */ + return; + } + } +} + +/* create a new XImage or find it on our list of currently available ones so */ +/* we dont need to create a new one */ +XImage * +ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared) +{ + XImage *xim; + int i; + + /* if we havent check the shm extension before - see if its there */ + if (x_does_shm < 0) + { + /* if its there set dose_xhm flag */ + if (XShmQueryExtension(d)) + x_does_shm = 1; + /* clear the flag - no shm at all */ + else + x_does_shm = 0; + } + /* find a cached XImage (to avoid server to & fro) that is big enough */ + /* for our needs and the right depth */ + *shared = 0; + /* go thru the current image list */ + for (i = 0; i < list_num; i++) + { + /* if the image has the same depth, width and height - recycle it */ + /* as long as its not used */ + if ((list_xim[i]->bits_per_pixel == depth) && + (list_xim[i]->width >= w) && + (list_xim[i]->height >= h) && +/* (list_d[i] == d) &&*/ + (!list_used[i])) + { + /* mark it as used */ + list_used[i] = 1; + /* if its shared set shared flag */ + if (list_si[i]) + *shared = 1; + /* return it */ + return list_xim[i]; + } + } + /* can't find a usable XImage on the cache - create one */ + /* add the new XImage to the XImage cache */ + list_num++; + list_xim = realloc(list_xim, sizeof(XImage *) * list_num); + list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num); + list_used = realloc(list_used, sizeof(char) * list_num); + list_d = realloc(list_d, sizeof(Display *) * list_num); + list_si[list_num - 1] = malloc(sizeof(XShmSegmentInfo)); + + /* work on making a shared image */ + xim = NULL; + /* if the server does shm */ + if (x_does_shm) + { + /* try create an shm image */ + xim = XShmCreateImage(d, v, depth, ZPixmap, NULL, + list_si[list_num - 1], w, h); + /* if it succeeds */ + if (xim) + { + /* add to list */ + list_xim[list_num - 1] = xim; + /* get an shm id of this image */ + list_si[list_num - 1]->shmid = + shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, + IPC_CREAT | 0777); + /* if the get succeeds */ + if (list_si[list_num - 1]->shmid != -1) + { + /* set the params for the shm segment */ + list_si[list_num - 1]->readOnly = False; + list_si[list_num - 1]->shmaddr = xim->data = + shmat(list_si[list_num - 1]->shmid, 0, 0); + /* get the shm addr for this data chunk */ + if (xim->data != (char *)-1) + { + XErrorHandler ph; + + /* setup a temporary error handler */ + _x_err = 0; + ph = XSetErrorHandler((XErrorHandler) TmpXError); + /* ask X to attach to the shared mem segment */ + XShmAttach(d, list_si[list_num - 1]); + /* wait for X to reply and do this */ + XSync(d, False); + /* reset the error handler */ + XSetErrorHandler((XErrorHandler) ph); + /* if we attached without an error we're set */ + if (!_x_err) + { + /* mark the image as used */ + list_used[list_num - 1] = 1; + /* incrument our memory count */ + list_mem_use += xim->bytes_per_line * xim->height; + /* set shared flag */ + *shared = 1; + } + /* attach by X failed... must be remote client */ + else + { + /* flag shm foevere to not work - remote */ + x_does_shm = 0; + /* destroy our previous image */ + XDestroyImage(xim); + /* detach */ + shmdt(list_si[list_num - 1]->shmaddr); + /* remove the shm id */ + shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0); + /* flag out xim as NULL */ + xim = NULL; + } + } + /* get failed - out of shm id's or shm segment too big ? */ + else + { + /* destroy previous image */ + XDestroyImage(xim); + /* remove the shm id we created */ + shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0); + /* flag xim as NULL */ + xim = NULL; + } + } + /* couldnt create SHM image ? */ + else + { + /* destroy previous image */ + XDestroyImage(xim); + /* flag xim as NULL */ + xim = NULL; + } + } + } + /* ok if xim == NULL it all failed - fall back to XImages */ + if (!xim) + { + /* get rid of out shm info struct */ + free(list_si[list_num - 1]); + /* flag it as NULL ot indicate a normal XImage */ + list_si[list_num - 1] = NULL; + /* create a normal ximage */ + xim = XCreateImage(d, v, depth, ZPixmap, 0, NULL, w, h, 32, 0); + /* allocate data for it */ + xim->data = malloc(xim->bytes_per_line * xim->height); + /* add xim to our list */ + list_xim[list_num - 1] = xim; + /* incriment our memory count */ + list_mem_use += xim->bytes_per_line * xim->height; + /* mark image as used */ + list_used[list_num - 1] = 1; + /* remember what display that XImage was for */ + list_d[list_num - 1] = d; + } + /* flush unused images from the image list */ + FlushXImage(d); + /* return out image */ + return xim; +} diff --git a/ximage.h b/ximage.h new file mode 100644 index 0000000..51406a8 --- /dev/null +++ b/ximage.h @@ -0,0 +1,10 @@ +#ifndef __XIMAGE +#define __XIMAGE 1 +void SetMaxXImageCount(Display *d, int num); +int GetMaxXImageCount(Display *d); +void SetMaxXImageTotalSize(Display *d, int num); +int GetMaxXImageTotalSize(Display *d); +void FlushXImage(Display *d); +void ConsumeXImage(Display *d, XImage *xim); +XImage *ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared); +#endif