/*************************************************************************** gfx_tools.c Copyright (C) 2000 Christoph Reichenbach This program may be modified and copied freely according to the terms of the GNU general public license (GPL), as long as the above copyright notice and the licensing information contained herein are preserved. Please refer to www.gnu.org for licensing details. This work is provided AS IS, without warranty of any kind, expressed or implied, including but not limited to the warranties of merchantibility, noninfringement, and fitness for a specific purpose. The author will not be held liable for any damage caused by this work or derivatives of it. By using this source code, you agree to the licensing terms as stated above. Please contact the maintainer for bug reports or inquiries. Current Maintainer: Christoph Reichenbach (CR) ***************************************************************************/ #include "sci/include/sci_memory.h" #include "sci/include/gfx_tools.h" /* set optimisations for Win32: */ #ifdef _WIN32 # include # ifndef SATISFY_PURIFY # pragma intrinsic( memcpy, memset ) # endif #endif rect_t gfx_rect_fullscreen = {0, 0, 320, 200}; void gfx_clip_box_basic(rect_t *box, int maxx, int maxy) { if (box->x < 0) box->x = 0; if (box->y < 0) box->y = 0; if (box->x + box->xl > maxx) box->xl = maxx - box->x + 1; if (box->y + box->yl > maxy) box->yl = maxy - box->y + 1; } gfx_mode_t * gfx_new_mode(int xfact, int yfact, int bytespp, unsigned int red_mask, unsigned int green_mask, unsigned int blue_mask, unsigned int alpha_mask, int red_shift, int green_shift, int blue_shift, int alpha_shift, int palette, int flags) { gfx_mode_t *mode = (gfx_mode_t*)sci_malloc(sizeof(gfx_mode_t)); #ifdef SATISFY_PURIFY memset(mode, 0, sizeof(gfx_mode_t)); #endif mode->xfact = xfact; mode->yfact = yfact; mode->bytespp = bytespp; mode->red_mask = red_mask; mode->green_mask = green_mask; mode->blue_mask = blue_mask; mode->alpha_mask = alpha_mask; mode->red_shift = red_shift; mode->green_shift = green_shift; mode->blue_shift = blue_shift; mode->alpha_shift = alpha_shift; mode->flags = flags; if (palette) { mode->palette = (gfx_palette_t*)sci_malloc(sizeof(gfx_palette_t)); #ifdef SATISFY_PURIFY memset(mode->palette, 0, sizeof(gfx_palette_t)); #endif mode->palette->max_colors_nr = palette; mode->palette->colors = (gfx_palette_color_t*)sci_calloc(sizeof(gfx_palette_color_t), palette); /* Initialize with empty entries */ } else mode->palette = NULL; return mode; } void gfx_free_mode(gfx_mode_t *mode) { if (mode->palette) { free(mode->palette->colors); free(mode->palette); } free(mode); } void gfx_copy_pixmap_box_i(gfx_pixmap_t *dest, gfx_pixmap_t *src, rect_t box) { int width, height; int offset; if ((dest->index_xl != src->index_xl) || (dest->index_yl != src->index_yl)) return; gfx_clip_box_basic(&box, dest->index_xl, dest->index_yl); if (box.xl <= 0 || box.yl <= 0) return; height = box.yl; width = box.xl; offset = box.x + (box.y * dest->index_xl); while (height--) { memcpy(dest->index_data + offset, src->index_data + offset, width); offset += dest->index_xl; } } gfx_pixmap_t * gfx_clone_pixmap(gfx_pixmap_t *pxm, gfx_mode_t *mode) { gfx_pixmap_t *clone = (gfx_pixmap_t*)sci_malloc(sizeof(gfx_pixmap_t)); *clone = *pxm; clone->index_data = NULL; clone->colors = NULL; clone->data = NULL; gfx_pixmap_alloc_data(clone, mode); memcpy(clone->data, pxm->data, clone->data_size); if (clone->alpha_map) { clone->alpha_map = (byte *) sci_malloc(clone->xl * clone->yl); memcpy(clone->alpha_map, pxm->alpha_map, clone->xl * clone->yl); } return clone; } gfx_pixmap_t * gfx_new_pixmap(int xl, int yl, int resid, int loop, int cel) { gfx_pixmap_t *pxm = (gfx_pixmap_t*)sci_malloc(sizeof(gfx_pixmap_t)); #ifdef SATISFY_PURIFY memset(pxm, 0, sizeof(gfx_pixmap_t)); #endif pxm->alpha_map = NULL; pxm->data = NULL; pxm->internal.info = NULL; pxm->colors = NULL; pxm->internal.handle = 0; pxm->index_xl = xl; pxm->index_yl = yl; pxm->ID = resid; pxm->loop = loop; pxm->cel = cel; pxm->index_data = NULL; pxm->flags = 0; pxm->color_key = 0xff; return pxm; } void gfx_free_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm) { if (driver) { if (pxm->flags & GFX_PIXMAP_FLAG_INSTALLED) { if (driver->capabilities & GFX_CAPABILITY_PIXMAP_REGISTRY) driver->unregister_pixmap(driver, pxm); } if (driver->mode->palette && pxm->flags & GFX_PIXMAP_FLAG_PALETTE_ALLOCATED && !(pxm->flags & GFX_PIXMAP_FLAG_DONT_UNALLOCATE_PALETTE) && !(pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) { int i; int error = 0; GFXDEBUG("UNALLOCATING %d\n", pxm->colors_nr); for (i = 0; i < pxm->colors_nr; i++) if (gfx_free_color(driver->mode->palette, pxm->colors + i)) error++; if (error) { GFXWARN("%d errors occured while freeing %d colors of pixmap with ID %06x/%d/%d\n", error, pxm->colors_nr,pxm->ID, pxm->loop, pxm->cel); } } } if (pxm->index_data) free(pxm->index_data); if (pxm->alpha_map) free(pxm->alpha_map); if (pxm->data) free(pxm->data); if (pxm->colors && !(pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) free(pxm->colors); free(pxm); } gfx_pixmap_t * gfx_pixmap_alloc_index_data(gfx_pixmap_t *pixmap) { int size; if (pixmap->index_data) { GFXWARN("Attempt to allocate pixmap index data twice!\n"); return pixmap; } size = pixmap->index_xl * pixmap->index_yl; if (!size) size = 1; pixmap->index_data = (byte*)sci_malloc(size); memset(pixmap->index_data, 0, size); return pixmap; } gfx_pixmap_t * gfx_pixmap_free_index_data(gfx_pixmap_t *pixmap) { if (!pixmap->index_data) { GFXWARN("Attempt to free pixmap index data twice!\n"); return pixmap; } free(pixmap->index_data); pixmap->index_data = NULL; return pixmap; } gfx_pixmap_t * gfx_pixmap_alloc_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode) { int size; if (pixmap->data) { GFXWARN("Attempt to allocate pixmap data twice!\n"); return pixmap; } if (pixmap->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) { pixmap->xl = pixmap->index_xl; pixmap->yl = pixmap->index_yl; } else { pixmap->xl = pixmap->index_xl * mode->xfact; pixmap->yl = pixmap->index_yl * mode->yfact; } size = pixmap->xl * pixmap->yl * mode->bytespp; if (!size) size = 1; pixmap->data = (byte*)sci_malloc(pixmap->data_size = size); return pixmap; } gfx_pixmap_t * gfx_pixmap_free_data(gfx_pixmap_t *pixmap) { if (!pixmap->data) { GFXWARN("Attempt to free pixmap data twice!\n"); return pixmap; } free(pixmap->data); pixmap->data = NULL; return pixmap; } int gfx_alloc_color(gfx_palette_t *pal, gfx_pixmap_color_t *color) { int i; int dr, dg, db; /* deltas */ int bestdelta = 1 + ((0x100 * 0x100) * 3); int bestcolor = -1; int firstfree = -1; if (pal == NULL) return GFX_OK; if (pal->max_colors_nr <= 0) { GFXERROR("Palette has zero or less color entries!\n"); return GFX_ERROR; } if (color->global_index != GFX_COLOR_INDEX_UNMAPPED) { #if 0 GFXDEBUG("Attempt to allocate color twice: index 0x%d (%02x/%02x/%02x)!\n", color->global_index, color->r, color->g, color->b); #endif return GFX_OK; } for (i = 0; i < pal->max_colors_nr; i++) { gfx_palette_color_t *pal_color = pal->colors + i; if (pal_color->lockers) { int delta; dr = abs(pal_color->r - color->r); dg = abs(pal_color->g - color->g); db = abs(pal_color->b - color->b); if (dr == 0 && dg == 0 && db == 0) { color->global_index = i; return GFX_OK; } delta = (dr * dr) + (dg * dg) + (db * db); if (delta < bestdelta) { bestdelta = delta; bestcolor = i; } } else if (firstfree == -1) firstfree = i; } if (firstfree != -1) { pal->colors[firstfree].r = color->r; pal->colors[firstfree].g = color->g; pal->colors[firstfree].b = color->b; pal->colors[firstfree].lockers = 1; color->global_index = firstfree; return 42; /* positive value to indicate that this color still needs to be set */ } color->global_index = bestcolor; // GFXWARN("Out of palette colors- doing approximated mapping!\n"); return GFX_OK; } int gfx_free_color(gfx_palette_t *pal, gfx_pixmap_color_t *color) { gfx_palette_color_t *palette_color = pal->colors + color->global_index; if (!pal) return GFX_OK; if (color->global_index == GFX_COLOR_INDEX_UNMAPPED) { GFXWARN("Attempt to free unmapped color %02x/%02x/%02x!\n", color->r, color->g, color->b); BREAKPOINT(); return GFX_ERROR; } if (color->global_index >= pal->max_colors_nr) { GFXERROR("Attempt to free invalid color index %d (%02x/%02x/%02x)!\n", color->global_index, color->r, color->g, color->b); return GFX_ERROR; } if (!palette_color->lockers) { GFXERROR("Attempt to free unused color index %d (%02x/%02x/%02x)!\n", color->global_index, color->r, color->g, color->b); return GFX_ERROR; } if (palette_color->lockers != GFX_COLOR_SYSTEM) --(palette_color->lockers); color->global_index = GFX_COLOR_INDEX_UNMAPPED; return GFX_OK; } gfx_pixmap_t * gfx_pixmap_scale_index_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode) { byte *old_data, *new_data, *initial_new_data; byte *linestart; int linewidth; int xl, yl; int i, yc; int xfact = mode->xfact; int yfact = mode->yfact; if (xfact == 1 && yfact == 1) return pixmap; if (!pixmap) return NULL; if (pixmap->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) return pixmap; /* Already done */ old_data = pixmap->index_data; if (!old_data) { GFXERROR("Attempt to scale index data without index data!\n"); return pixmap; } xl = pixmap->index_xl; yl = pixmap->index_yl; linewidth = xfact * xl; initial_new_data = new_data = (byte *) sci_malloc(linewidth * yfact * yl); for (yc = 0; yc < yl; yc++) { linestart = new_data; if (xfact == 1) { memcpy(new_data, old_data, linewidth); new_data += linewidth; old_data += linewidth; } else for (i = 0; i < xl; i++) { byte fillc = *old_data++; memset(new_data, fillc, xfact); new_data += xfact; } for (i = 1; i < yfact; i++) { memcpy(new_data, linestart, linewidth); new_data += linewidth; } } free(pixmap->index_data); pixmap->index_data = initial_new_data; pixmap->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; pixmap->index_xl = linewidth; pixmap->index_yl *= yfact; return pixmap; }