diff options
author | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-01-05 01:33:53 +0000 |
---|---|---|
committer | ennewalker <ennewalker@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-01-05 01:33:53 +0000 |
commit | 62f7040f14b39e67042be98f951575fbc819e84e (patch) | |
tree | d4fa0598a1bee1d34fff81e2c150de08c2256753 /crawl-ref/source/guic-x11.cc | |
parent | 19155f1f85058ef9d65d11e60c63cc69c36d4e8a (diff) | |
download | crawl-ref-62f7040f14b39e67042be98f951575fbc819e84e.tar.gz crawl-ref-62f7040f14b39e67042be98f951575fbc819e84e.zip |
Tiles!
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3194 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/guic-x11.cc')
-rw-r--r-- | crawl-ref/source/guic-x11.cc | 1052 |
1 files changed, 1052 insertions, 0 deletions
diff --git a/crawl-ref/source/guic-x11.cc b/crawl-ref/source/guic-x11.cc new file mode 100644 index 0000000000..cbf2f045ab --- /dev/null +++ b/crawl-ref/source/guic-x11.cc @@ -0,0 +1,1052 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <X11/Xlib.h> +#include <X11/X.h> +#include <X11/Xutil.h> +#include <X11/Xlocale.h> +#include <X11/keysym.h> +#include <X11/keysymdef.h> +#include <X11/Xmd.h> + +#if DEBUG +#define ASSERT(p) {if (!(p)) printf( __FILE__, __LINE__);} +#else +#define ASSERT(p) ((void) 0) +#endif + +#include "guic.h" + +static Display *display; +static int screen; +static GC term_gc[MAX_TERM_COL]; +static GC map_gc[MAX_MAP_COL]; +static unsigned long term_pix[MAX_TERM_COL]; +static unsigned long map_pix[MAX_MAP_COL]; +static unsigned long pix_transparent; +static unsigned long pix_hilite; +static unsigned long pix_black; +static unsigned long pix_rimcolor; +static int x11_byte_per_pixel_ximage(); +static unsigned long create_pixel(unsigned int red, unsigned int green, + unsigned int blue); +static XImage *read_png(const char *fname); + +/*******************************************************/ +void WinClass::SysInit() +{ + win = (Window)NULL; +} + +void WinClass::SysDeinit() +{} + +void RegionClass::SysInit() +{ + font = NULL; +} + +void RegionClass::SysDeinit() +{ + if (font != NULL && !font_copied) XFreeFont(display, font); +} + +void TextRegionClass::SysInit(int x, int y, int cx, int cy) +{} + +void TextRegionClass::SysDeinit() +{} + +void TileRegionClass::SysInit(int mx0, int my0, int dx0, int dy0) +{} + +void TileRegionClass::SysDeinit() +{} + +void MapRegionClass::SysInit(int x, int y, int o_x, int o_y) +{} + +void MapRegionClass::SysDeinit() +{} + +void RegionClass::init_font(const char *name){ + /*** Large part of this routine was copied from Hengband ***/ + int ascent, descent, width; + + font = XLoadQueryFont(display, name); + if (!font) + { + fprintf(stderr,"Error! Can't load font %s\n",name); + exit(1); + } + width = font->max_bounds.width; + ascent = font->ascent; + descent = font->descent; + + int i; + for (i=0;i<MAX_TERM_COL;i++) + XSetFont(display, term_gc[i], font->fid); + + fx = dx = width; + fy = dy = ascent + descent; + asc = ascent; + font_copied = false; +} + +void RegionClass::copy_font(RegionClass *r) +{ + fx = r->fx; + fy = r->fy; + dx = r->dx; + dy = r->dy; + asc = r->asc; + font = r->font; + font_copied = true; +} + +void RegionClass::sys_flush() +{ + XFlush(display); +} + +void RegionClass::init_backbuf() +{ +} + +void TextRegionClass::init_backbuf() +{ +} + +void TileRegionClass::init_backbuf() +{ + int x, y; + + backbuf = ImgCreateSimple(mx*dx, my*dy); + for (x = 0; x < mx*dx; x++) + for (y = 0; y < my*dy; y++) + XPutPixel(backbuf, x, y, pix_black); +} + +void TileRegionClass::resize_backbuf() +{ + if (backbuf != NULL) ImgDestroy(backbuf); + init_backbuf(); +} + +void RegionClass::resize_backbuf() +{ + if (backbuf != NULL) ImgDestroy(backbuf); + init_backbuf(); +} + +void MapRegionClass::init_backbuf() +{ + int x, y; + backbuf = ImgCreateSimple(mx*dx, my*dy); + for (x = 0; x < mx*dx; x++) + for (y = 0; y < my*dy; y++) + XPutPixel(backbuf, x, y, pix_black); +} + +void MapRegionClass::resize_backbuf() +{ + if (backbuf != NULL) + ImgDestroy(backbuf); + init_backbuf(); +} + +void TextRegionClass::draw_string(int x, int y, unsigned char *buf, + int len, int col) +{ + XFillRectangle(display, win->win, term_gc[col>>4], + x*dx+ox, y*dy+oy, dx * len, dy); + XDrawString(display, win->win, term_gc[col&0x0f], x*dx+ox, y*dy+asc+oy, + (char *)&cbuf[y*mx+x], len); +} + +void TextRegionClass::draw_cursor(int x, int y) +{ + if(!flag)return; + + XDrawString(display, win->win, term_gc[0x0f], x*dx+ox, y*dy+asc+oy, + "_", 1); + sys_flush(); +} + +void TextRegionClass::erase_cursor() +{ + WinClass *w = win; + + int x0 = cursor_x; + int y0 = cursor_y; + int width = 1; + int adrs = y0 * mx + x0; + int col = abuf[adrs]; + int x1 = x0;; + if(!flag)return; + + XFillRectangle(display, w->win, term_gc[col>>4], + x1*dx + ox, y0*dy +oy, dx*width, dy); + + XDrawString(display, w->win, + term_gc[col&0x0f], x0*dx+ ox, y0*dy+asc+ oy, + (char *)&cbuf[adrs], width ); +} + + +void WinClass::clear() +{ + fillrect(0, 0, wx, wy, PIX_BLACK); + XFlush(display); +} + +void RegionClass::clear() +{ + fillrect(0, 0, wx, wy, PIX_BLACK); + XFlush(display); +} + +void TileRegionClass::clear() +{ + RegionClass::clear(); +} + +void MapRegionClass::clear() +{ + int i; + + for (i=0; i<mx2*my2; i++) + { + mbuf[i]=PIX_BLACK; + } + + RegionClass::clear(); +} + +void TextRegionClass::clear() +{ + int i; + + for (i=0; i<mx*my; i++) + { + cbuf[i]=' '; + abuf[i]=0; + } + + RegionClass::clear(); +} + +void WinClass::create(char *name) +{ + + if (!win) + { + win = XCreateSimpleWindow(display, RootWindow(display,screen), + 10,10, wx, wy, 0, + BlackPixel(display,screen), BlackPixel(display,screen)); + + XMapWindow(display, win); + XSelectInput(display, win, ExposureMask | KeyPressMask + | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | + LeaveWindowMask | EnterWindowMask | StructureNotifyMask ); + move(ox, oy); + } + else + resize(0,0); + + clear(); +} + +void WinClass::move() +{ + XMoveWindow(display, win, ox, oy); +} + +void WinClass::resize() +{ + XResizeWindow(display, win, wx, wy); +} + +void TileRegionClass::redraw(int x1, int y1, int x2, int y2) +{ + int wwx = x2-x1+1; + int wwy = y2-y1+1; + + if (x1<0) + { + wwx += x1; + x1 = 0; + } + + if (y1<0) + { + wwy += y1; + y1 = 0; + } + + if (x2 >= mx*dx) + { + wwx -= x2-mx*dx+1; + } + + if (y2 >= my*dy) + { + wwy -= y2-my*dy+1; + } + + XPutImage(display, win->win, term_gc[0], + backbuf, x1, y1, x1+ox, y1+oy, wwx, wwy); +} + +void MapRegionClass::redraw(int x1, int y1, int x2, int y2) +{ + if (!flag) + return; + + XPutImage(display, win->win, term_gc[0], + backbuf, x1*dx, y1*dy, + x1*dx+ox, y1*dy+oy, + (x2-x1+1)*dx, (y2-y1+1)*dy); +} + +void MapRegionClass::draw_data(unsigned char *buf){ + int x, y, xx, yy; + static int px = 0; + static int py = 0; + + if (!flag) + return; + + for(yy=0;yy<dy*2;yy++) + { + XPutPixel(backbuf, px*dx+dx/2, yy, map_pix[MAP_BLACK]); + } + for(xx=0;xx<dx*2;xx++) + { + XPutPixel(backbuf, xx, py*dy+dy/2, map_pix[MAP_BLACK]); + } + + for (y = 0; y < my; y++) + { + unsigned char *ptr = + &buf[x_margin + (y_margin + y)*(mx2 + x_margin*2)]; + for (x = 0; x < mx; x++) + { + int col = ptr[x]; + // Hack :remember player position + if (col == MAP_WHITE) + { + px = x; + py = y; + } + if(col != get_col(x, y) || force_redraw) + { + for(xx=0; xx<dx; xx++) + for(yy=0; yy<dy; yy++) + XPutPixel(backbuf, x*dx+xx, y*dy+yy, map_pix[col]); + + set_col(col, x, y); + } + } + } + for(yy=0;yy<dy*2;yy++) + { + XPutPixel(backbuf, px*dx+dx/2, yy, map_pix[MAP_WHITE]); + } + for(xx=0;xx<dx*2;xx++) + { + XPutPixel(backbuf, xx, py*dy+dy/2, map_pix[MAP_WHITE]); + } + + redraw(); + XFlush(display); + force_redraw = false; +} + +/* XXXXX + * img_type related + */ + +bool ImgIsTransparentAt(img_type img, int x, int y) +{ + ASSERT(x>=0); + ASSERT(y>=0); + ASSERT(x<(img->width)); + ASSERT(y<(img->height)); + + return (pix_transparent == XGetPixel(img, x, y)) ? true:false; +} + +void ImgSetTransparentPix(img_type img) +{ + pix_transparent = XGetPixel(img, 0, 0); +} + +void ImgDestroy(img_type img) +{ + XDestroyImage(img); +} + +img_type ImgCreateSimple(int wx, int wy) +{ + if (wx ==0 || wy == 0) return NULL; + char *buf = (char *)malloc(x11_byte_per_pixel_ximage()* wx * wy); + + img_type res= XCreateImage(display, DefaultVisual(display, screen), + DefaultDepth(display, screen), + ZPixmap, 0, buf, wx, wy, 8, 0); + return(res); +} + +img_type ImgLoadFile(const char *name) +{ + return read_png(name); +} + +void ImgClear(img_type img) +{ + int x,y; + ASSERT(img != NULL); + for(y=0;y<img->height;y++) + for(x=0;x<img->width;x++) + XPutPixel(img, x, y, pix_transparent); +} + +// Copy internal image to another internal image +void ImgCopy(img_type src, int sx, int sy, int wx, int wy, + img_type dest, int dx, int dy, int copy) +{ + int x, y; + int bpp = src->bytes_per_line / src->width; + int bpl_s = src->bytes_per_line; + int bpl_d = dest->bytes_per_line; + + ASSERT(sx>=0); + ASSERT(sy>=0); + ASSERT(sx+wx<=(src->width)); + ASSERT(sy+wy<=(src->height)); + ASSERT(dx>=0); + ASSERT(dy>=0); + ASSERT(dx+wx<=(dest->width)); + ASSERT(dy+wy<=(dest->height)); + + if(copy==1) + { + char *p_src = (char *)(src->data + bpl_s * sy + sx * bpp); + char *p_dest = (char *)(dest->data + bpl_d * dy + dx * bpp); + + for(y=0;y<wy;y++){ + memcpy(p_dest, p_src, wx * bpp); + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=1) + { + CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp); + CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=2) + { + CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp); + CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + else if(bpp<=4) + { + CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp); + CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + +} + +// Copy internal image to another internal image +void ImgCopyH(img_type src, int sx, int sy, int wx, int wy, + img_type dest, int dx, int dy, int copy) +{ + int x, y; + int bpp = src->bytes_per_line / src->width; + int bpl_s = src->bytes_per_line; + int bpl_d = dest->bytes_per_line; + + ASSERT(sx>=0); + ASSERT(sy>=0); + ASSERT(sx+wx<=(src->width)); + ASSERT(sy+wy<=(src->height)); + ASSERT(dx>=0); + ASSERT(dy>=0); + ASSERT(dx+wx<=(dest->width)); + ASSERT(dy+wy<=(dest->height)); + + if(copy==1) + { + char *p_src = (char *)(src->data + bpl_s * sy + sx * bpp); + char *p_dest = (char *)(dest->data + bpl_d * dy + dx * bpp); + + for(y=0;y<wy;y++){ + memcpy(p_dest, p_src, wx * bpp); + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=1) + { + CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp); + CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + + else if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=2) + { + CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp); + CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + + else if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + else if(bpp<=4) + { + CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp); + CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + + else if(p_src[x] != pix_transparent) + p_dest[x] = p_src[x]; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + +} + + +// Copy internal image to another internal image +void ImgCopyMasked(img_type src, int sx, int sy, int wx, int wy, + img_type dest, int dx, int dy, char *mask) +{ + int x, y, count; + int bpp = src->bytes_per_line / src->width; + int bpl_s = src->bytes_per_line; + int bpl_d = dest->bytes_per_line; + ASSERT(sx>=0); + ASSERT(sy>=0); + ASSERT(sx+wx<=(src->width)); + ASSERT(sy+wy<=(src->height)); + ASSERT(dx>=0); + ASSERT(dy>=0); + ASSERT(dx+wx<=(dest->width)); + ASSERT(dy+wy<=(dest->height)); + + + count = 0; + + if(bpp<=1) + { + CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp); + CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + count++; + } + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=2) + { + CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp); + CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + count++; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + else if(bpp<=4) + { + CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp); + CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + count++; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + +} + +// Copy internal image to another internal image +void ImgCopyMaskedH(img_type src, int sx, int sy, int wx, int wy, + img_type dest, int dx, int dy, char *mask) +{ + int x, y, count; + int bpp = src->bytes_per_line / src->width; + int bpl_s = src->bytes_per_line; + int bpl_d = dest->bytes_per_line; + ASSERT(sx>=0); + ASSERT(sy>=0); + ASSERT(sx+wx<=(src->width)); + ASSERT(sy+wy<=(src->height)); + ASSERT(dx>=0); + ASSERT(dy>=0); + ASSERT(dx+wx<=(dest->width)); + ASSERT(dy+wy<=(dest->height)); + + + count = 0; + + if(bpp<=1) + { + CARD8 *p_src = (CARD8 *)(src->data + bpl_s * sy + sx * bpp); + CARD8 *p_dest = (CARD8 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + else if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + + count++; + } + p_src += bpl_s; + p_dest += bpl_d; + } + } + else if(bpp<=2) + { + CARD16 *p_src = (CARD16 *)(src->data + bpl_s * sy + sx * bpp); + CARD16 *p_dest = (CARD16 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + else if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + count++; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + else if(bpp<=4) + { + CARD32 *p_src = (CARD32 *)(src->data + bpl_s * sy + sx * bpp); + CARD32 *p_dest = (CARD32 *)(dest->data + bpl_d * dy + dx * bpp); + for(y=0;y<wy;y++){ + for(x=0;x<wx;x++){ + //X11 specific + if(p_src[x] == pix_rimcolor) + p_dest[x] = pix_hilite; + else if(p_src[x] != pix_transparent && mask[count]==0) + p_dest[x] = p_src[x]; + count++; + } + p_src += bpl_s/bpp; + p_dest += bpl_d/bpp; + } + } + +} + +void TileRegionClass::DrawPanel(int left, int top, int width, int height) +{ + framerect(left, top , left + width, top + height, PIX_WHITE); + framerect(left + 1, top + 1, left + width, top + height, PIX_DARKGREY); + fillrect (left + 1, top + 1, left + width - 1, top + height -1, PIX_LIGHTGREY); +} + +void RegionClass::framerect(int left, int top, int right, int bottom, + int color) +{ + XDrawRectangle(display, win->win, term_gc[color&0xf], + ox+left, oy+top, right-left, bottom-top); +} + +void TileRegionClass::framerect(int left, int top, int right, int bottom, + int color) +{ + int x,y; + int pix = term_pix[color]; + + for (x=left; x<=right; x++){ + XPutPixel(backbuf, x, top, pix); + XPutPixel(backbuf, x, bottom, pix); + } + + for (y=top+1; y< bottom; y++){ + XPutPixel(backbuf, left, y, pix); + XPutPixel(backbuf, right, y, pix); + } +} + +void WinClass::fillrect(int left, int top, int right, int bottom, + int color) +{ + XFillRectangle(display, win, term_gc[color&0xf], + top, left, right-left+1, bottom-top+1); +} + +void RegionClass::fillrect(int left, int top, int right, int bottom, + int color) +{ + XFillRectangle(display, win->win, term_gc[color&0xf], + ox+left, oy+top, right-left, bottom-top); +} + +void TileRegionClass::fillrect(int left, int top, int right, int bottom, + int color) +{ + int x,y; + int pix = term_pix[color]; + + ASSERT(left>=0); + ASSERT(top>=0); + ASSERT(right<mx); + ASSERT(bottom<my); + + for (x=left; x<=right; x++){ + for (y=top; y<= bottom; y++){ + XPutPixel(backbuf, x, y, pix); + }} +} + +/********************************************/ + +bool GuicInit(Display **d, int *s) +{ + int i; + setlocale(LC_ALL, ""); + display= XOpenDisplay(""); + if (!display) + { + fprintf(stderr,"Cannot open display\n"); + return false; + } + screen=DefaultScreen(display); + + *d = display; + *s = screen; + + // for text display + for(i=0;i<MAX_TERM_COL;i++) + { + const int *c = term_colors[i]; + term_pix[i] = create_pixel(c[0],c[1],c[2]); + term_gc[i]= XCreateGC(display,RootWindow(display,screen),0,0); + XSetForeground(display,term_gc[i], term_pix[i]); + } + // for text display + for(i=0;i<MAX_MAP_COL;i++) + { + const int *c = map_colors[i]; + map_pix[i] = create_pixel(c[0],c[1],c[2]); + map_gc[i]= XCreateGC(display,RootWindow(display,screen),0,0); + XSetForeground(display, map_gc[i], map_pix[i]); + } + + // for Image manipulation + pix_black = term_pix[PIX_BLACK] ; + pix_hilite = term_pix[PIX_LIGHTMAGENTA] ; + pix_rimcolor = create_pixel(1,1,1); + + return true; +} + +void GuicDeinit() +{ + int i; + + for(i=0;i<MAX_TERM_COL;i++) + XFreeGC(display,term_gc[i]); + + for(i=0;i<MAX_MAP_COL;i++) + XFreeGC(display,map_gc[i]); + + XCloseDisplay(display); +} + +static int x11_byte_per_pixel_ximage() +{ + int i = 1; + int j = (DefaultDepth(display, screen) - 1) >> 2; + while (j >>= 1) i <<= 1; + return i; +} + +unsigned long create_pixel(unsigned int red, unsigned int green, + unsigned int blue) +{ + Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(display)); + XColor xcolour; + + xcolour.red = red * 256; + xcolour.green = green * 256; + xcolour.blue = blue * 256; + xcolour.flags = DoRed | DoGreen | DoBlue; + + XAllocColor(display, cmap, &xcolour); + return (xcolour.pixel); +} + +/* + Copied from pngtopnm.c and modified by M.Itakura + (mostly omitted and added a few lines) + only color paletted image is handled +*/ + +/* +** pngtopnm.c - +** read a Portable Network Graphics file and produce a portable anymap +** +** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de> +** and Willem van Schaik <willem@schaik.com> +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +** +** modeled after giftopnm by David Koblas and +** with lots of bits pasted from libpng.txt by Guy Eric Schalnat +*/ + +#define VERSION "2.37.1 (3 July 1998)" + +#include "png.h" + +#define pm_message printf +#define pm_error(x) {fprintf(stderr,x);return NULL;} + +# define TRUE 1 +# define FALSE 0 +# define NONE 0 + +#define SIG_CHECK_SIZE 4 + +XImage *read_png (const char *fname) +{ + char sig_buf [SIG_CHECK_SIZE]; + png_struct *png_ptr; + png_info *info_ptr; + png_byte **png_image; + png_byte *png_pixel; + unsigned int x, y; + int linesize; + png_uint_16 c; + unsigned int i; + + //X11 + XImage *res; + unsigned long pix_table[256]; + + + FILE *ifp = fopen(fname,"r"); + + if(!ifp) { fprintf(stderr, "File not found: %s", fname); return NULL; } + + if (fread (sig_buf, 1, SIG_CHECK_SIZE, ifp) != SIG_CHECK_SIZE) + pm_error ("input file empty or too short"); + if (png_sig_cmp ((unsigned char *)sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE) != 0) + pm_error ("input file not a PNG file"); + + png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + pm_error ("cannot allocate LIBPNG structure"); + } + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL) { + png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + pm_error ("cannot allocate LIBPNG structures"); + } + + if (setjmp (png_ptr->jmpbuf)) { + png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + free (png_ptr); + free (info_ptr); + pm_error ("setjmp returns error condition"); + } + + png_init_io (png_ptr, ifp); + png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE); + png_read_info (png_ptr, info_ptr); + + + + png_image = (png_byte **)malloc (info_ptr->height * sizeof (png_byte*)); + if (png_image == NULL) { + free (png_ptr); + free (info_ptr); + pm_error ("couldn't alloc space for image"); + } + + if (info_ptr->bit_depth == 16) + linesize = 2 * info_ptr->width; + else + linesize = info_ptr->width; + + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + linesize *= 2; + else + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB) + linesize *= 3; + else + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + linesize *= 4; + + for (y = 0 ; y < info_ptr->height ; y++) { + png_image[y] = (png_byte *)malloc (linesize); + if (png_image[y] == NULL) { + for (x = 0 ; x < y ; x++) + free (png_image[x]); + free (png_image); + free (png_ptr); + free (info_ptr); + pm_error ("couldn't alloc space for image"); + } + } + + if (info_ptr->bit_depth < 8) + png_set_packing (png_ptr); + + /* sBIT handling is very tricky. If we are extracting only the image, we + can use the sBIT info for grayscale and color images, if the three + values agree. If we extract the transparency/alpha mask, sBIT is + irrelevant for trans and valid for alpha. If we mix both, the + multiplication may result in values that require the normal bit depth, + so we will use the sBIT info only for transparency, if we know that only + solid and fully transparent is used */ + + if (info_ptr->valid & PNG_INFO_sBIT) { + + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (info_ptr->sig_bit.red != info_ptr->sig_bit.green || + info_ptr->sig_bit.red != info_ptr->sig_bit.blue) ) { + pm_message ("different bit depths for color channels not supported"); + pm_message ("writing file with %d bit resolution", info_ptr->bit_depth); + } else + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) && + (info_ptr->sig_bit.red < 255)) { + for (i = 0 ; i < info_ptr->num_palette ; i++) { + info_ptr->palette[i].red >>= (8 - info_ptr->sig_bit.red); + info_ptr->palette[i].green >>= (8 - info_ptr->sig_bit.green); + info_ptr->palette[i].blue >>= (8 - info_ptr->sig_bit.blue); + } + + } else + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) && + (info_ptr->sig_bit.gray < info_ptr->bit_depth)) { + png_set_shift (png_ptr, &(info_ptr->sig_bit)); + } + + + } + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { +//X11 + for (i = 0 ; i < info_ptr->num_palette ; i++) + pix_table[i] = create_pixel(info_ptr->palette[i].red, + info_ptr->palette[i].green, info_ptr->palette[i].blue); + } + else + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + for (i = 0 ; i < 256 ; i++) +//X11 + pix_table[i] = create_pixel(i, i, i); + } + + png_read_image (png_ptr, png_image); + png_read_end (png_ptr, info_ptr); + + res = ImgCreateSimple(info_ptr->width, info_ptr->height); + + for (y = 0 ; y < info_ptr->height ; y++) { + png_pixel = png_image[y]; + for (x = 0 ; x < info_ptr->width ; x++) { + c = *png_pixel; + png_pixel++; + XPutPixel(res, x, y, pix_table[c]); + } + } + + for (y = 0 ; y < info_ptr->height ; y++) + free (png_image[y]); + free (png_image); + free (png_ptr); + free (info_ptr); + + fclose(ifp); + return res; +} |