/* * render.c -- enfle rendering engine * (C)Copyright 1998, 99 by Hiroshi Takekawa * This file is part of Enfle. * * Last Modified: Mon Oct 2 22:13:58 2000. * $Id: render.c,v 1.32 2000/10/02 15:39:30 sian Exp $ * * Enfle is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Enfle is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "enfle.h" #include "browse.h" #include "cmrender.h" #include "quantize.h" /* #define QUICK_ACCELERATION_HACK */ #undef QUICK_ACCELERATION_HACK static XImage * create_ximage(Info *info, Binfo *binfo) { return XCreateImage(info->disp, info->visual, info->depth, ZPixmap, 0, NULL, info->xwidth, info->xheight, 8, 0); } static void * allocate_ximage(Info *info) { return calloc(1, info->xdata_size); } void render_destroy_ximage(XImage *ximage) { XDestroyImage(ximage); } void render_free_ximage(Info *info, Binfo *binfo) { free(info->xdata); } XImage * render_image(Info *info, Binfo *binfo, Image *p, int f) { XImage *ximage; int width = p->width; int height = p->height; int depth = info->depth; int i, j; unsigned char *xdata; #if 0 fprintf(stderr, "render_image() called with f = %d\n", f); #endif if (!f) { info->xwidth = width + p->left; info->xheight = height + p->top; if (info->swidth) info->xwidth = info->mswidth; if (info->sheight) info->xheight = info->msheight; if ((ximage = create_ximage(info, binfo)) == NULL) { fprintf(stderr, "create_ximage() failed\n"); exit(1); } info->xdata_size = ximage->bytes_per_line * ximage->height; if (info->xdata != NULL) render_free_ximage(info, binfo); if ((info->xdata = allocate_ximage(info)) == NULL) { fprintf(stderr, "No enough memory xdata(%dx%d, depth = %d) %d bytes\n", width, height, info->depth, info->xdata_size); exit(1); } memset(info->xdata, p->background.index, info->xdata_size); } else { if ((ximage = create_ximage(info, binfo)) == NULL) { fprintf(stderr, "create_ximage() failed\n"); exit(1); } } ximage->data = xdata = info->xdata; #ifdef DEBUG fprintf(stderr, "type = %d default depth = %d\n", p->type, depth); fprintf(stderr, "(XImage's)bits_per_pixel = %d byte_order: %s bitmap_bit_order: %s\n", ximage->bits_per_pixel, (ximage->byte_order == LSBFirst) ? "LSBFirst" : "MSBFirst", (ximage->bitmap_bit_order == LSBFirst) ? "LSBFirst" : "MSBFirst"); #endif /* expansion is done in browse.c */ #ifdef SHAPE if (p->transparent_disposal == _SHAPE) { XImage *xmask; GC gc; XGCValues gcv; if (p->mask == NULL) image_create_mask(p); xmask = XCreateImage(info->disp, info->visual, 1, XYBitmap, 0, p->mask, p->width, p->height, 8, 0); xmask->byte_order = MSBFirst; xmask->bitmap_bit_order = MSBFirst; p->pixmask = XCreatePixmap(info->disp, info->win, p->left + p->width, p->top + p->height, 1); gcv.foreground = 0; gcv.background = 1; gc = XCreateGC(info->disp, p->pixmask, GCBackground | GCForeground, &gcv); XFillRectangle(info->disp, p->pixmask, gc, 0, 0, p->left + p->width, p->top + p->height); XPutImage(info->disp, p->pixmask, gc, xmask, 0, 0, p->left, p->top, p->width, p->height); XFreeGC(info->disp, gc); XShapeCombineMask(info->disp, info->win, ShapeBounding, 0, 0, p->pixmask, ShapeSet); XDestroyImage(xmask); /* p->mask already freed by XDestroyImage() */ p->mask = NULL; } #endif /* reduction */ if (!info->if_quantize) { switch (p->type) { case _RGB24: if (depth == 16 && !image_reduce(p, _RGB16)) { fprintf(stderr, "render_image: FATAL: image_reduce: returns 0\n"); exit(1); } else if (depth == 15 && !image_reduce(p, _RGB15)) { fprintf(stderr, "render_image: FATAL: image_reduce: returns 0\n"); exit(1); } break; default: break; } } else { if (p->ncolors > 256) { /* image quantization */ unsigned char *q, pal[256 * 3]; #ifdef DEBUG fprintf(stderr, "quantizing..\n"); #endif if ((q = quantize(p->image, pal, width, height, 8)) == NULL) return NULL; #ifdef DEBUG fprintf(stderr, "Ok.\n"); #endif for (i = 0; i < 256; i++) for (j = 0; j < 3; j++) p->colormap[i][j] = pal[i * 3 + j]; free(p->image); p->image = q; p->type = _INDEX; p->bytes_per_line = p->width; p->ncolors = 256; } } /* rendering */ switch (p->type) { case _MONO: case _GRAY: /* cannot reach here */ fprintf(stderr, "Internal error, cannot rendering\n"); exit(1); case _RGB16: if (depth != 16 && depth != 15) { /* cannot reach here */ fprintf(stderr, "Internal error, cannot rendering\n"); exit(1); } if (ximage->bits_per_pixel == 16) { /* acceleration code */ ximage->data = xdata = p->image; } else { fprintf(stderr, "I have no code for bits_per_pixel = %d\n", ximage->bits_per_pixel); exit(1); } break; case _INDEX: { int f; /* colormapped image rendering */ f = render_image_colormap(info, p, xdata, ximage->bits_per_pixel, ximage->bytes_per_line); if (f) { fprintf(stderr, "enfle: render_image: FATAL: %s\n", cmrender_err[f]); exit(1); } } break; case _RGB24: if (depth != 24) { fprintf(stderr, "I have no code to render _RGB24 for depth %d\n", depth); exit(1); } if (ximage->bits_per_pixel == 24) { #if 0 free(xdata); info->xdata = NULL; #endif /* acceleration code */ ximage->data = xdata = p->image; } else if (ximage->bits_per_pixel == 32) { #ifdef QUICK_ACCELERATION_HACK free(xdata); info->xdata = NULL; /* acceleration code */ ximage->data = xdata = p->image; ximage->bits_per_pixel = 24; ximage->bytes_per_line = width * 3; ximage->byte_order = MSBFirst; #else unsigned char *s = p->image; unsigned char *d = xdata + ximage->bytes_per_line * p->top + p->left * 4; unsigned char *dn; if (p->transparent_disposal == _DONOTHING) { if (ximage->byte_order == LSBFirst) { for (j = 0; j < height; j++) { dn = d + ximage->bytes_per_line; for (i = 0; i < width; i++) { d[3] = 0; d[2] = *s++; d[1] = *s++; d[0] = *s++; d += 4; } d = dn; } } else { for (j = 0; j < height; j++) { dn = d + ximage->bytes_per_line; for (i = 0; i < width; i++) { d[0] = 0; d[1] = *s++; d[2] = *s++; d[3] = *s++; d += 4; } d = dn; } } } else { /* transparent */ if (ximage->byte_order == LSBFirst) { for (j = 0; j < height; j++) { dn = d + ximage->bytes_per_line; for (i = 0; i < width; i++) { if (s[0] != p->transparent.red || s[1] != p->transparent.green || s[2] != p->transparent.blue) { d[3] = 0; d[2] = *s++; d[1] = *s++; d[0] = *s++; } else s += 3; d += 4; } d = dn; } } else { for (j = 0; j < height; j++) { dn = d + ximage->bytes_per_line; for (i = 0; i < width; i++) { if (s[0] != p->transparent.red || s[1] != p->transparent.green || s[2] != p->transparent.blue) { d[0] = 0; d[1] = *s++; d[2] = *s++; d[3] = *s++; } else s += 3; d += 4; } d = dn; } } } #endif } else { fprintf(stderr, "I have no code for bits_per_pixel = %d\n", ximage->bits_per_pixel); exit(1); } break; default: break; } return ximage; }