aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/gfx_tools.c
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gfx/gfx_tools.c')
-rw-r--r--engines/sci/gfx/gfx_tools.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/engines/sci/gfx/gfx_tools.c b/engines/sci/gfx/gfx_tools.c
new file mode 100644
index 0000000000..b82627c896
--- /dev/null
+++ b/engines/sci/gfx/gfx_tools.c
@@ -0,0 +1,465 @@
+/***************************************************************************
+ 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) <jameson@linuxgames.com>
+
+***************************************************************************/
+
+#include <sci_memory.h>
+#include <gfx_tools.h>
+
+/* set optimisations for Win32: */
+#ifdef _WIN32
+# include <memory.h>
+# 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;
+}