From bc37ec4ce13e2742b3fcaa2d8cd2b3a6224c0c72 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 18 Mar 2009 13:24:47 +0000 Subject: Renamed resmgr.cpp -> gfx_resmgr.cpp Moved all files from gfx/resource/* to gfx/* svn-id: r39515 --- engines/sci/gfx/gfx_resmgr.cpp | 623 ++++++++++ engines/sci/gfx/picfill.cpp | 600 ++++++++++ engines/sci/gfx/res_cursor.cpp | 92 ++ engines/sci/gfx/res_font.cpp | 143 +++ engines/sci/gfx/res_pal.cpp | 147 +++ engines/sci/gfx/res_pic.cpp | 1881 +++++++++++++++++++++++++++++++ engines/sci/gfx/res_view0.cpp | 229 ++++ engines/sci/gfx/res_view1.cpp | 513 +++++++++ engines/sci/gfx/resmgr.cpp | 623 ---------- engines/sci/gfx/resource/picfill.cpp | 600 ---------- engines/sci/gfx/resource/res_cursor.cpp | 92 -- engines/sci/gfx/resource/res_font.cpp | 143 --- engines/sci/gfx/resource/res_pal.cpp | 147 --- engines/sci/gfx/resource/res_pic.cpp | 1881 ------------------------------- engines/sci/gfx/resource/res_view0.cpp | 229 ---- engines/sci/gfx/resource/res_view1.cpp | 513 --------- engines/sci/module.mk | 14 +- 17 files changed, 4235 insertions(+), 4235 deletions(-) create mode 100644 engines/sci/gfx/gfx_resmgr.cpp create mode 100644 engines/sci/gfx/picfill.cpp create mode 100644 engines/sci/gfx/res_cursor.cpp create mode 100644 engines/sci/gfx/res_font.cpp create mode 100644 engines/sci/gfx/res_pal.cpp create mode 100644 engines/sci/gfx/res_pic.cpp create mode 100644 engines/sci/gfx/res_view0.cpp create mode 100644 engines/sci/gfx/res_view1.cpp delete mode 100644 engines/sci/gfx/resmgr.cpp delete mode 100644 engines/sci/gfx/resource/picfill.cpp delete mode 100644 engines/sci/gfx/resource/res_cursor.cpp delete mode 100644 engines/sci/gfx/resource/res_font.cpp delete mode 100644 engines/sci/gfx/resource/res_pal.cpp delete mode 100644 engines/sci/gfx/resource/res_pic.cpp delete mode 100644 engines/sci/gfx/resource/res_view0.cpp delete mode 100644 engines/sci/gfx/resource/res_view1.cpp (limited to 'engines') diff --git a/engines/sci/gfx/gfx_resmgr.cpp b/engines/sci/gfx/gfx_resmgr.cpp new file mode 100644 index 0000000000..890e5842d2 --- /dev/null +++ b/engines/sci/gfx/gfx_resmgr.cpp @@ -0,0 +1,623 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// Resource manager core part + +// FIXME/TODO: The name "(Graphics) resource manager", and the associated +// filenames, are misleading. This should be renamed to "Graphics manager" +// or something like that. + +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" +#include "sci/gfx/gfx_driver.h" +#include "sci/gfx/gfx_resmgr.h" +#include "sci/gfx/gfx_state_internal.h" +#include "sci/gfx/font.h" + +#include "common/system.h" + +namespace Sci { + +// Invalid hash mode: Used to invalidate modified pics +#define MODE_INVALID -1 + +struct param_struct { + int args[4]; + gfx_driver_t *driver; +}; + +#define DRAW_PIC01(pic, picStyle, isSci1) \ + gfxr_draw_pic01((pic), flags, default_palette, res->size, res->data, (picStyle), res->id, (isSci1), state->static_palette); + +#define DRAW_PIC11(pic, picStyle) \ + gfxr_draw_pic11((pic), flags, default_palette, res->size, res->data, (picStyle), res->id, state->static_palette); + +/* Calculate a picture +** Parameters: (gfx_resstate_t *) state: The resource state, containing options and version information +** (gfxr_pic_t *) scaled_pic: The pic structure that is to be written to +** (gfxr_pic_t *) unscaled_pic: The pic structure the unscaled pic is to be written to, +** or NULL if it isn't needed. +** (int) flags: Pic drawing flags (interpreter dependant) +** (int) default_palette: The default palette to use for pic drawing (interpreter dependant) +** (int) nr: pic resource number +** Returns : (int) GFX_ERROR if the resource could not be found, GFX_OK otherwise +*/ +int calculatePic(gfx_resstate_t *state, gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, int flags, int default_palette, int nr) { + Resource *res = state->resManager->findResource(kResourceTypePic, nr, 0); + int need_unscaled = unscaled_pic != NULL; + gfxr_pic0_params_t style, basic_style; + + basic_style.line_mode = GFX_LINE_MODE_CORRECT; + basic_style.brush_mode = GFX_BRUSH_MODE_SCALED; + basic_style.pic_port_bounds = state->options->pic_port_bounds; + + style.line_mode = state->options->pic0_line_mode; + style.brush_mode = state->options->pic0_brush_mode; + style.pic_port_bounds = state->options->pic_port_bounds; + + if (!res || !res->data) + return GFX_ERROR; + + if (need_unscaled) { + if (state->version == SCI_VERSION_1_1) + DRAW_PIC11(unscaled_pic, &basic_style) + else + DRAW_PIC01(unscaled_pic, &basic_style, state->version >= SCI_VERSION_01_VGA) + } + + if (scaled_pic && scaled_pic->undithered_buffer) + memcpy(scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer, scaled_pic->undithered_buffer_size); + + if (state->version == SCI_VERSION_1_1) + DRAW_PIC11(scaled_pic, &style) + else + DRAW_PIC01(scaled_pic, &style, state->version >= SCI_VERSION_01_VGA) + + if (state->version < SCI_VERSION_01_VGA) { + if (need_unscaled) + gfxr_remove_artifacts_pic0(scaled_pic, unscaled_pic); + + if (!scaled_pic->undithered_buffer) + scaled_pic->undithered_buffer = sci_malloc(scaled_pic->undithered_buffer_size); + + memcpy(scaled_pic->undithered_buffer, scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer_size); + + gfxr_dither_pic0(scaled_pic, state->options->pic0_dither_mode, state->options->pic0_dither_pattern); + } + + // Mark default palettes + if (scaled_pic) + scaled_pic->visual_map->loop = default_palette; + + if (unscaled_pic) + unscaled_pic->visual_map->loop = default_palette; + + return GFX_OK; +} + +gfx_resstate_t *gfxr_new_resource_manager(int version, gfx_options_t *options, gfx_driver_t *driver, ResourceManager *resManager) { + gfx_resstate_t *state = new gfx_resstate_t(); + + state->version = version; + state->options = options; + state->driver = driver; + state->resManager = resManager; + state->static_palette = 0; + + state->tag_lock_counter = state->lock_counter = 0; + + return state; +} + +int GfxResManager::getOptionsHash(gfx_resource_type_t type) { + switch (type) { + case GFX_RESOURCE_TYPE_VIEW: + // This should never happen + error("getOptionsHash called on a VIEW resource"); + + case GFX_RESOURCE_TYPE_PIC: + if (_state->version >= SCI_VERSION_01_VGA) + return _state->options->pic_port_bounds.y; + else + return (_state->options->pic0_unscaled) ? 0x10000 : (_state->options->pic0_dither_mode << 12) + | (_state->options->pic0_dither_pattern << 8) | (_state->options->pic0_brush_mode << 4) + | (_state->options->pic0_line_mode); + + case GFX_RESOURCE_TYPE_FONT: + case GFX_RESOURCE_TYPE_CURSOR: + return 0; + + case GFX_RESOURCE_TYPES_NR: + default: + GFXERROR("Invalid resource type: %d\n", type); + return -1; + } +} + +#define FREEALL(freecmd, type) \ + if (resource->scaled_data.type) \ + freecmd(resource->scaled_data.type); \ + resource->scaled_data.type = NULL; \ + if (resource->unscaled_data.type) \ + freecmd(resource->unscaled_data.type); \ + resource->unscaled_data.type = NULL; + +void gfxr_free_resource(gfx_resource_t *resource, int type) { + if (!resource) + return; + + switch (type) { + + case GFX_RESOURCE_TYPE_VIEW: + FREEALL(gfxr_free_view, view); + break; + + case GFX_RESOURCE_TYPE_PIC: + FREEALL(gfxr_free_pic, pic); + break; + + case GFX_RESOURCE_TYPE_FONT: + FREEALL(gfxr_free_font, font); + break; + + case GFX_RESOURCE_TYPE_CURSOR: + FREEALL(gfx_free_pixmap, pointer); + break; + + default: + GFXWARN("Attempt to free invalid resource type %d\n", type); + } + + free(resource); +} + +void GfxResManager::freeAllResources() { + for (int type = 0; type < GFX_RESOURCE_TYPES_NR; ++type) { + for (IntResMap::iterator iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { + gfxr_free_resource(iter->_value, type); + iter->_value = 0; + } + } +} + +void GfxResManager::freeResManager() { + freeAllResources(); + delete _state; +} + +void GfxResManager::freeTaggedResources() { + // Current heuristics: free tagged views and old pics + + IntResMap::iterator iter; + int type; + const int tmp = _state->tag_lock_counter; + + type = GFX_RESOURCE_TYPE_VIEW; + for (iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { + gfx_resource_t *resource = iter->_value; + + if (resource) { + if (resource->lock_sequence_nr < tmp) { + gfxr_free_resource(resource, type); + iter->_value = 0; + } else { + resource->lock_sequence_nr = 0; + } + } + } + + type = GFX_RESOURCE_TYPE_PIC; + for (iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { + gfx_resource_t *resource = iter->_value; + + if (resource) { + if (resource->lock_sequence_nr < 0) { + gfxr_free_resource(resource, type); + iter->_value = 0; + } else { + resource->lock_sequence_nr--; + } + } + } + + _state->tag_lock_counter = 0; +} + +#define XLATE_AS_APPROPRIATE(key, entry) \ + if (maps & key) { \ + if (res->unscaled_data.pic&& (force || !res->unscaled_data.pic->entry->data)) { \ + if (key == GFX_MASK_VISUAL) \ + gfx_get_res_config(options, res->unscaled_data.pic->entry); \ + gfx_xlate_pixmap(res->unscaled_data.pic->entry, mode, filter); \ + } if (scaled && res->scaled_data.pic && (force || !res->scaled_data.pic->entry->data)) { \ + if (key == GFX_MASK_VISUAL) \ + gfx_get_res_config(options, res->scaled_data.pic->entry); \ + gfx_xlate_pixmap(res->scaled_data.pic->entry, mode, filter); \ + } \ + } + +static gfxr_pic_t *gfxr_pic_xlate_common(gfx_resource_t *res, int maps, int scaled, int force, gfx_mode_t *mode, + gfx_xlate_filter_t filter, int endianize, gfx_options_t *options) { + XLATE_AS_APPROPRIATE(GFX_MASK_VISUAL, visual_map); + XLATE_AS_APPROPRIATE(GFX_MASK_PRIORITY, priority_map); + XLATE_AS_APPROPRIATE(GFX_MASK_CONTROL, control_map); + + if (endianize && (maps & GFX_MASK_VISUAL) && res->scaled_data.pic->visual_map) + gfxr_endianness_adjust(res->scaled_data.pic->visual_map, mode); + + return scaled ? res->scaled_data.pic : res->unscaled_data.pic; +} +#undef XLATE_AS_APPROPRIATE + +gfxr_pic_t *GfxResManager::getPic(int num, int maps, int flags, int default_palette, bool scaled) { + gfxr_pic_t *npic = NULL; + IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_PIC]; + gfx_resource_t *res = NULL; + int hash = getOptionsHash(GFX_RESOURCE_TYPE_PIC); + int must_post_process_pic = 0; + int need_unscaled = (_state->driver->mode->xfact != 1 || _state->driver->mode->yfact != 1); + + hash |= (flags << 20) | ((default_palette & 0x7) << 28); + + res = resMap.contains(num) ? resMap[num] : NULL; + + if (!res || res->mode != hash) { + gfxr_pic_t *pic; + gfxr_pic_t *unscaled_pic = NULL; + + if (_state->options->pic0_unscaled) { + need_unscaled = 0; + pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); + } else + pic = gfxr_init_pic(_state->driver->mode, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); + if (!pic) { + GFXERROR("Failed to allocate scaled pic!\n"); + return NULL; + } + + gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); + + if (need_unscaled) { + unscaled_pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); + if (!unscaled_pic) { + GFXERROR("Failed to allocate unscaled pic!\n"); + return NULL; + } + gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); + } + if (calculatePic(_state, pic, unscaled_pic, flags, default_palette, num)) { + gfxr_free_pic(pic); + if (unscaled_pic) + gfxr_free_pic(unscaled_pic); + return NULL; + } + if (!res) { + res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); + res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num); + res->lock_sequence_nr = _state->options->buffer_pics_nr; + resMap[num] = res; + } else { + gfxr_free_pic(res->scaled_data.pic); + if (res->unscaled_data.pic) + gfxr_free_pic(res->unscaled_data.pic); + } + + res->mode = hash; + res->scaled_data.pic = pic; + res->unscaled_data.pic = unscaled_pic; + } else { + res->lock_sequence_nr = _state->options->buffer_pics_nr; // Update lock counter + } + + must_post_process_pic = res->scaled_data.pic->visual_map->data == NULL; + // If the pic was only just drawn, we'll have to endianness-adjust it now + + npic = gfxr_pic_xlate_common(res, maps, scaled || _state->options->pic0_unscaled, 0, _state->driver->mode, + _state->options->pic_xlate_filter, 0, _state->options); + + + if (must_post_process_pic) { + gfxr_endianness_adjust(npic->visual_map, _state->driver->mode); + } + + return npic; +} + +static void set_pic_id(gfx_resource_t *res, int id) { + if (res->scaled_data.pic) { + gfxr_pic_t *pic = res->scaled_data.pic; + pic->control_map->ID = id; + pic->priority_map->ID = id; + pic->visual_map->ID = id; + } + + if (res->unscaled_data.pic) { + gfxr_pic_t *pic = res->unscaled_data.pic; + pic->control_map->ID = id; + pic->priority_map->ID = id; + pic->visual_map->ID = id; + } +} + +static int get_pic_id(gfx_resource_t *res) { + if (res->scaled_data.pic) + return res->scaled_data.pic->visual_map->ID; + else + return res->unscaled_data.pic->visual_map->ID; +} + +static void _gfxr_unscale_pixmap_index_data(gfx_pixmap_t *pxm, gfx_mode_t *mode) { + int xmod = mode->xfact; // Step size horizontally + int ymod = pxm->index_width * mode->yfact; // Vertical step size + int maxpos = pxm->index_width * pxm->index_height; + int pos; + byte *dest = pxm->index_data; + + if (!(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)) + return; // It's not scaled! + + for (pos = 0; pos < maxpos; pos += ymod) { + int c; + + for (c = 0; c < pxm->index_width; c += xmod) + *dest++ = pxm->index_data[pos + c]; + // No overwrite since line and offset readers move much faster (proof by in-duction, trivial + // and left to the reader) + } + + pxm->index_width /= mode->xfact; + pxm->index_height /= mode->yfact; + pxm->flags &= ~GFX_PIXMAP_FLAG_SCALED_INDEX; +} + +gfxr_pic_t *GfxResManager::addToPic(int old_nr, int new_nr, int flags, int old_default_palette, int default_palette) { + IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_PIC]; + gfxr_pic_t *pic = NULL; + gfx_resource_t *res = NULL; + int hash = getOptionsHash(GFX_RESOURCE_TYPE_PIC); + int need_unscaled = !(_state->options->pic0_unscaled) && (_state->driver->mode->xfact != 1 || _state->driver->mode->yfact != 1); + + res = resMap.contains(old_nr) ? resMap[old_nr] : NULL; + + if (!res || (res->mode != MODE_INVALID && res->mode != hash)) { + // FIXME: the initialization of the GFX resource manager should + // be pushed up, and it shouldn't occur here + GfxResManager *_gfx = new GfxResManager(_state); + _gfx->getPic(old_nr, 0, flags, old_default_palette, 1); + delete _gfx; + + res = resMap.contains(old_nr) ? resMap[old_nr] : NULL; + + if (!res) { + GFXWARN("Attempt to add pic %d to non-existing pic %d\n", new_nr, old_nr); + return NULL; + } + } + + if (_state->options->pic0_unscaled) // Unscale priority map, if we scaled it earlier + _gfxr_unscale_pixmap_index_data(res->scaled_data.pic->priority_map, _state->driver->mode); + + // The following two operations are needed when returning scaled maps (which is always the case here) + res->lock_sequence_nr = _state->options->buffer_pics_nr; + calculatePic(_state, res->scaled_data.pic, need_unscaled ? res->unscaled_data.pic : NULL, + flags | DRAWPIC01_FLAG_OVERLAID_PIC, default_palette, new_nr); + + res->mode = MODE_INVALID; // Invalidate + + if (_state->options->pic0_unscaled) // Scale priority map again, if needed + res->scaled_data.pic->priority_map = gfx_pixmap_scale_index_data(res->scaled_data.pic->priority_map, _state->driver->mode); + { + int old_ID = get_pic_id(res); + set_pic_id(res, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, new_nr)); // To ensure that our graphical translation optoins work properly + pic = gfxr_pic_xlate_common(res, GFX_MASK_VISUAL, 1, 1, _state->driver->mode, _state->options->pic_xlate_filter, 1, _state->options); + set_pic_id(res, old_ID); + } + + return pic; +} + +gfxr_view_t *gfxr_draw_view11(int id, byte *resource, int size); + +gfxr_view_t *GfxResManager::getView(int nr, int *loop, int *cel, int palette) { + IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_VIEW]; + gfx_resource_t *res = NULL; + int hash = palette; + gfxr_view_t *view = NULL; + gfxr_loop_t *loop_data = NULL; + gfx_pixmap_t *cel_data = NULL; + + res = resMap.contains(nr) ? resMap[nr] : NULL; + + if (!res || res->mode != hash) { + Resource *viewRes = _state->resManager->findResource(kResourceTypeView, nr, 0); + if (!viewRes || !viewRes->data) + return NULL; + + int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); + + if (_state->version < SCI_VERSION_01) + view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, -1); + else if (_state->version == SCI_VERSION_01) + view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, palette); + else if (_state->version >= SCI_VERSION_01_VGA && _state->version <= SCI_VERSION_1_LATE) + view = gfxr_draw_view1(resid, viewRes->data, viewRes->size, _state->static_palette); + else if (_state->version >= SCI_VERSION_1_1) + view = gfxr_draw_view11(resid, viewRes->data, viewRes->size); + + if (_state->version >= SCI_VERSION_01_VGA) { + if (!view->palette) { + view->palette = new Palette(_state->static_palette->size()); + view->palette->name = "interpreter_get_view"; + } + + // Palettize view + for (unsigned i = 0; i < MIN(view->palette->size(), _state->static_palette->size()); i++) { + const PaletteEntry& vc = view->palette->getColor(i); + if (vc.r == 0 && vc.g == 0 && vc.b == 0) { + const PaletteEntry& sc = _state->static_palette->getColor(i); + view->palette->setColor(i, sc.r, sc.g, sc.b); + } + } + + } + + if (!res) { + res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.view = NULL; + res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); + res->lock_sequence_nr = _state->tag_lock_counter; + res->mode = hash; + resMap[nr] = res; + } else { + gfxr_free_view(res->unscaled_data.view); + } + + res->mode = hash; + res->unscaled_data.view = view; + + } else { + res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter + view = res->unscaled_data.view; + } + + *loop = CLIP(*loop, 0, view->loops_nr - 1); + + if (*loop < 0) { + GFXWARN("View %d has no loops\n", nr); + return NULL; + } + + loop_data = view->loops + (*loop); + if (loop_data == NULL) { + GFXWARN("Trying to load invalid loop %d of view %d\n", *loop, nr); + return NULL; + } + + *cel = CLIP(*cel, 0, loop_data->cels_nr - 1); + + if (*cel < 0) { + GFXWARN("View %d loop %d has no cels\n", nr, *loop); + return NULL; + } + + cel_data = loop_data->cels[*cel]; + if (loop_data == NULL) { + GFXWARN("Trying to load invalid view/loop/cel %d/%d/%d\n", nr, *loop, *cel); + return NULL; + } + + if (!cel_data->data) { + gfx_get_res_config(_state->options, cel_data); + gfx_xlate_pixmap(cel_data, _state->driver->mode, _state->options->view_xlate_filter); + gfxr_endianness_adjust(cel_data, _state->driver->mode); + } + + return view; +} + +gfx_bitmap_font_t *GfxResManager::getFont(int num, bool scaled) { + IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_FONT]; + gfx_resource_t *res = NULL; + int hash = getOptionsHash(GFX_RESOURCE_TYPE_FONT); + + res = resMap.contains(num) ? resMap[num] : NULL; + + if (!res || res->mode != hash) { + Resource *fontRes = _state->resManager->findResource(kResourceTypeFont, num, 0); + if (!fontRes || !fontRes->data) + return NULL; + + gfx_bitmap_font_t *font = gfxr_read_font(fontRes->id, fontRes->data, fontRes->size); + + if (!res) { + res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.font = NULL; + res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_FONT, num); + res->lock_sequence_nr = _state->tag_lock_counter; + res->mode = hash; + resMap[num] = res; + } else { + gfxr_free_font(res->unscaled_data.font); + } + + res->unscaled_data.font = font; + + return font; + } else { + res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter + if (res->unscaled_data.pointer) + return res->unscaled_data.font; + else + return res->scaled_data.font; + } +} + +gfx_pixmap_t *GfxResManager::getCursor(int num) { + IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_CURSOR]; + gfx_resource_t *res = NULL; + int hash = getOptionsHash(GFX_RESOURCE_TYPE_CURSOR); + + res = resMap.contains(num) ? resMap[num] : NULL; + + if (!res || res->mode != hash) { + Resource *cursorRes = _state->resManager->findResource(kResourceTypeCursor, num, 0); + if (!cursorRes || !cursorRes->data) + return NULL; + + if (_state->version >= SCI_VERSION_1_1) { + GFXWARN("Attempt to retrieve cursor in SCI1.1 or later\n"); + return NULL; + } + + gfx_pixmap_t *cursor = gfxr_draw_cursor(GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, num), + cursorRes->data, cursorRes->size, _state->version != SCI_VERSION_0); + + if (!cursor) + return NULL; + + if (!res) { + res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.pointer = NULL; + res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, num); + res->lock_sequence_nr = _state->tag_lock_counter; + res->mode = hash; + resMap[num] = res; + } else { + gfx_free_pixmap(res->unscaled_data.pointer); + } + gfx_get_res_config(_state->options, cursor); + gfx_xlate_pixmap(cursor, _state->driver->mode, _state->options->cursor_xlate_filter); + gfxr_endianness_adjust(cursor, _state->driver->mode); + + res->unscaled_data.pointer = cursor; + + return cursor; + } else { + res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter + return res->unscaled_data.pointer; + } +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/picfill.cpp b/engines/sci/gfx/picfill.cpp new file mode 100644 index 0000000000..eb0e8b36c2 --- /dev/null +++ b/engines/sci/gfx/picfill.cpp @@ -0,0 +1,600 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/gfx/gfx_resource.h" + +/* Generic pic filling code, to be included by sci_pic_0.c + * + * + * To use, define the following: + * AUXBUF_FILL: Name of the exported floodfill function + * AUXBUF_FILL_HELPER: Name of the helper function + * FILL_FUNCTION: Name of the exported floodfill function + * FILL_FUNCTION_RECURSIVE: Name of the helper function + * + * Define DRAW_SCALED to support scaled drawing, or leave it out for faster + * processing. + * + */ + +namespace Sci { + +#define CLIPMASK_HARD_BOUND 0x80 /* ensures that we don't re-fill filled stuff */ + +static void AUXBUF_FILL_HELPER(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, + int clipmask, int control, int sci_titlebar_size) { + int xl, xr; + int oldytotal = y * 320; +#ifdef DRAW_SCALED + unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x78; +#else + unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x84; +#endif + + do { + int ytotal = oldytotal + (320 * dy); + int xcont; + int state; + + y += dy; + + if (y < sci_titlebar_size || y > 199) + return; + + xl = old_xl; + if (!(pic->aux_map[ytotal + xl] & clipmask)) { // go left + while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) + --xl; + } else // go right and look for the first valid spot + while ((xl <= old_xr) && (pic->aux_map[ytotal + xl] & clipmask)) + ++xl; + + if (xl > old_xr) // No fillable strip above the last one + return; + + if ((ytotal + xl) < 0) { + fprintf(stderr, "AARGH-%d\n", __LINE__); + BREAKPOINT(); + } + + xr = xl; + while (xr < 320 && !(pic->aux_map[ytotal + xr] & clipmask)) { + pic->aux_map[ytotal + xr] |= fillmask; + ++xr; + } + + if ((ytotal + xr) > 64000) { + fprintf(stderr, "AARGH-%d\n", __LINE__); + BREAKPOINT(); + } + + --xr; + + if (xr < xl) + return; + + // Check whether we need to recurse on branches in the same direction + if ((y > sci_titlebar_size && dy < 0) || (y < 199 && dy > 0)) { + state = 0; + xcont = xr + 1; + while (xcont <= old_xr) { + if (pic->aux_map[ytotal + xcont] & clipmask) + state = 0; + else if (!state) { // recurse + state = 1; + AUXBUF_FILL_HELPER(pic, xcont, old_xr, y - dy, dy, clipmask, control, sci_titlebar_size); + } + ++xcont; + } + } + + // Check whether we need to recurse on backward branches: + // left + if (xl < old_xl - 1) { + state = 0; + for (xcont = old_xl - 1; xcont >= xl; xcont--) { + if (pic->aux_map[oldytotal + xcont] & clipmask) + state = xcont; + else if (state) { // recurse + AUXBUF_FILL_HELPER(pic, xcont, state, y, -dy, clipmask, control, sci_titlebar_size); + state = 0; + } + } + } + + // right + if (xr > old_xr + 1) { + state = 0; + for (xcont = old_xr + 1; xcont <= xr; xcont++) { + if (pic->aux_map[oldytotal + xcont] & clipmask) + state = xcont; + else if (state) { // recurse + AUXBUF_FILL_HELPER(pic, state, xcont, y, -dy, clipmask, control, sci_titlebar_size); + state = 0; + } + } + } + + if ((ytotal + xl) < 0) { + fprintf(stderr, "AARGH-%d\n", __LINE__); + BREAKPOINT() + } + if ((ytotal + xr + 1) > 64000) { + fprintf(stderr, "AARGH-%d\n", __LINE__); + BREAKPOINT(); + } + + if (control) + memset(pic->control_map->index_data + ytotal + xl, control, xr - xl + 1); + + oldytotal = ytotal; + old_xr = xr; + old_xl = xl; + + } while (1); +} + + +static void AUXBUF_FILL(gfxr_pic_t *pic, int x, int y, int clipmask, int control, int sci_titlebar_size) { + // Fills the aux buffer and the control map (if control != 0) + int xl, xr; + int ytotal = y * 320; +#ifdef DRAW_SCALED + unsigned const char fillmask = 0x78; +#else + unsigned const char fillmask = 0x4; +#endif + +#ifndef DRAW_SCALED + if (!control || !(clipmask & 4)) + return; // Without pic scaling, we only do this to fill the control map +#endif + + if (clipmask & 1) + clipmask = 1; // vis + else if (clipmask & 2) + clipmask = 2; // pri + else if (clipmask & 4) + clipmask = 4; // ctl + else return; + +#ifdef DRAW_SCALED + clipmask |= fillmask; // Bits 3-5 +#endif + + if (pic->aux_map[ytotal + x] & clipmask) + return; + + pic->aux_map[ytotal + x] |= fillmask; + + xl = x; + while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) { + --xl; + pic->aux_map[ytotal + xl] |= fillmask; + } + + xr = x; + while ((xr < 319) && !(pic->aux_map[ytotal + xr + 1] & clipmask)) { + ++xr; + pic->aux_map[ytotal + xr] |= fillmask; + } + + clipmask |= CLIPMASK_HARD_BOUND; // Guarantee clipping + + if (control) // Draw the same strip on the control map + memset(pic->control_map->index_data + ytotal + xl, control, xr - xl + 1); + + if (y > sci_titlebar_size) + AUXBUF_FILL_HELPER(pic, xl, xr, y, -1, clipmask, control, sci_titlebar_size); + + if (y < 199) + AUXBUF_FILL_HELPER(pic, xl, xr, y, + 1, clipmask, control, sci_titlebar_size); +} + + +#undef CLIPMASK_HARD_BOUND + + +#ifdef FILL_RECURSIVE_DEBUG +# define PRINT_DEBUG0(s) if (!fillmagc) fprintf(stderr, s) +# define PRINT_DEBUG1(s,p1) if (!fillmagc) fprintf(stderr, s, p1) +# define PRINT_DEBUG4(s,p1,p2,p3,p4) if (!fillmagc) fprintf(stderr, s, p1) +#else +# define PRINT_DEBUG0(s) +# define PRINT_DEBUG1(s,p1) +# define PRINT_DEBUG4(s,p1,p2,p3,p4) +#endif + +#ifdef DRAW_SCALED +# define SCALED_CHECK(x) (x) +# define IS_BOUNDARY(x, y, index) (((index) & legalmask) != legalcolor) +#else +# define SCALED_CHECK(x) 1 +# define IS_BOUNDARY(x, y, index) ( \ + (((x)+(y)) & 1)? /* figure out which part of the mask to use, to simulate dithering */ \ + ((((index)) & ((legalmask) )) != ((legalcolor) & ((legalmask)))) /* odd coordinate */ \ + : ((((index)) & ((legalmask) >> 8)) != ((legalcolor) & ((legalmask) >> 8))) /* even coordinate */ \ + ) +#endif + +static void FILL_FUNCTION_RECURSIVE(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, byte *bounds, + int legalcolor, int legalmask, int color, int priority, int drawenable, int sci_titlebar_size) { + int linewidth = pic->mode->xfact * 320; + int miny = pic->mode->yfact * sci_titlebar_size; + int maxy = pic->mode->yfact * 200; + int xl, xr; + int oldytotal = y * linewidth; +#ifdef DRAW_SCALED + int old_proj_y = -42; + int proj_y; + int proj_ytotal; + int proj_x; + int proj_xl_bound = 0; + int proj_xr_bound = 0; +#endif + + do { + int ytotal = oldytotal + (linewidth * dy); + int xcont; + int state; + + y += dy; + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillc) + return; + else if (!fillmagc) { + --fillc; + } +#endif + + if (y < miny || y >= maxy) { + PRINT_DEBUG0("ABRT on failed initial assertion!\n"); + return; + } +#ifdef DRAW_SCALED + proj_y = y / pic->mode->yfact; + + if (proj_y != old_proj_y) { + // First, find the projected coordinates, unless known already: + proj_ytotal = proj_y * 320; + proj_x = old_xl / pic->mode->xfact; + + proj_xl_bound = proj_x; + if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { + while (proj_xl_bound && pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT) + --proj_xl_bound; + } else { + while (proj_xl_bound < 319 && !(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT)) + ++proj_xl_bound; + + if (proj_xl_bound < 319) + ++proj_xl_bound; + } + + if (proj_xl_bound == 319 + && !(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { + PRINT_DEBUG0("ABRT because proj_xl_bound couldn't be found\n"); + return; + } + + proj_xr_bound = (proj_xl_bound > proj_x) ? proj_xl_bound : proj_x; + while ((proj_xr_bound < 319) + && pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT) + ++proj_xr_bound; + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillmagc) { + fprintf(stderr, "l%d: {%d,%d} | ", proj_y, proj_xl_bound, proj_xr_bound); + pic->aux_map[proj_y*320 + proj_xl_bound] |= 0x2; + pic->aux_map[proj_y*320 + proj_xr_bound] |= 0x2; + } +#endif + + proj_xl_bound *= pic->mode->xfact; + if (proj_xl_bound) + proj_xl_bound -= pic->mode->xfact - 1; + + if (proj_xr_bound < 319) + ++proj_xr_bound; + proj_xr_bound *= pic->mode->xfact; + proj_xr_bound += pic->mode->xfact - 1; + + old_proj_y = proj_y; + } +#else +# define proj_xl_bound 0 +# define proj_xr_bound 319 +#endif + + // Now we have the projected limits, get the real ones: + + xl = (old_xl > proj_xl_bound) ? old_xl : proj_xl_bound; + if (!IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl])) { // go left as far as possible + while (xl > proj_xl_bound && (!IS_BOUNDARY(xl - 1, y + 1, bounds[ytotal + xl - 1]))) + --xl; + } else // go right until the fillable area starts + while (xl < proj_xr_bound && (IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl]))) + ++xl; + + + PRINT_DEBUG1("<%d,", xl); + + if ((xl > proj_xr_bound) + || (xl > old_xr)) { + PRINT_DEBUG0("ABRT because xl > xr_bound\n"); + return; + } + + xr = (xl > old_xl) ? xl : old_xl; + while (xr < proj_xr_bound && (!IS_BOUNDARY(xr + 1, y + 1, bounds[ytotal + xr + 1]))) + ++xr; + + PRINT_DEBUG1("%d> -> ", xr); + + if (IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl])) { + PRINT_DEBUG0("ABRT because xl illegal\n"); + return; + } + +#ifdef DRAW_SCALED + PRINT_DEBUG4("[%d[%d,%d]%d]\n", proj_xl_bound, xl, xr, proj_xr_bound); + + if (xl < proj_xl_bound && xr - 3*pic->mode->xfact < proj_xl_bound) { + PRINT_DEBUG0("ABRT interval left of zone\n"); + return; + } + + if (xr > proj_xr_bound && xl + 3*pic->mode->xfact > proj_xr_bound) { + PRINT_DEBUG0("ABRT because interval right of zone\n"); + return; + } +#endif + + if (drawenable & GFX_MASK_VISUAL) + memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); + + if (drawenable & GFX_MASK_PRIORITY) + memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); + + + // Check whether we need to recurse on branches in the same direction + state = 0; + xcont = xr + 1; + while (xcont <= old_xr) { + if (IS_BOUNDARY(xcont, y + 1, bounds[ytotal + xcont])) + state = xcont; + else if (state) { // recurse + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BRANCH %d [%d,%d] l%d\n", dy, state, xcont, y - dy); + + FILL_FUNCTION_RECURSIVE(pic, state, xcont, y - dy, dy, bounds, legalcolor, + legalmask, color, priority, drawenable, sci_titlebar_size); + state = 0; + } + ++xcont; + } + + // Check whether we need to recurse on backward branches: + // left + if (xl < old_xl - 1) { + state = 0; + for (xcont = old_xl - 1; xcont >= xl; xcont--) { + if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) + state = xcont; + else if (state) { // recurse + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BACK-LEFT %d [%d,%d] l%d\n", -dy, state, xcont, y); + + FILL_FUNCTION_RECURSIVE(pic, xcont, state, y, -dy, bounds, + legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + state = 0; + } + } + } + + // right + if (xr > old_xr + 1) { + state = 0; + for (xcont = old_xr + 1; xcont <= xr; xcont++) { + if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) + state = xcont; + else if (state) { // recurse + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BACK-RIGHT %d [%d,%d] l%d\n", -dy, state, xcont, y); + + FILL_FUNCTION_RECURSIVE(pic, state, xcont, y, -dy, bounds, + legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + state = 0; + } + } + } + + oldytotal = ytotal; + old_xl = xl; + old_xr = xr; + + } while (1); +} + + +static void FILL_FUNCTION(gfxr_pic_t *pic, int x_320, int y_200, int color, int priority, int control, int drawenable, + int sci_titlebar_size) { + int linewidth = pic->mode->xfact * 320; + int x, y; + int xl, xr; + int ytotal; + int bitmask; + byte *bounds = NULL; + int legalcolor, legalmask; +#ifdef DRAW_SCALED + int min_x, min_y, max_x, max_y; +#endif + int original_drawenable = drawenable; // Backup, since we need the unmodified value + // for filling the aux and control map + + // Restrict drawenable not to restrict itself to zero + if (pic->control_map->index_data[y_200 * 320 + x_320] != 0) + drawenable &= ~GFX_MASK_CONTROL; + + if (color == 0xff) + drawenable &= ~GFX_MASK_VISUAL; + + if (priority == 0) { + drawenable &= ~GFX_MASK_PRIORITY; + original_drawenable &= ~GFX_MASK_PRIORITY; + } + + AUXBUF_FILL(pic, x_320, y_200, original_drawenable, (drawenable & GFX_MASK_CONTROL) ? control : 0, + sci_titlebar_size); + +#ifdef DRAW_SCALED + _gfxr_auxbuf_spread(pic, &min_x, &min_y, &max_x, &max_y); + + if (_gfxr_find_fill_point(pic, min_x, min_y, max_x, max_y, x_320, y_200, color, drawenable, &x, &y)) { + //GFXWARN("Could not find scaled fill point, but unscaled fill point was available!\n"); + drawenable &= GFX_MASK_PRIORITY; + if (!drawenable) + _gfxr_auxbuf_propagate_changes(pic, 0); + } +#else + x = x_320; + y = y_200; +#endif + + ytotal = y * linewidth; + + if (!drawenable) + return; + + if (drawenable & GFX_MASK_VISUAL) { + bounds = pic->visual_map->index_data; +#if 0 + // Code disabled, as removing it fixes qg1 pic.095 (unscaled). However, + // it MAY be of relevance to scaled pic drawing... + + if ((color & 0xf) == 0xf // When dithering with white, do more + // conservative checks + || (color & 0xf0) == 0xf0) + legalcolor = 0xff; + else + legalcolor = 0xf0; // Only check the second color +#endif +#ifdef DRAW_SCALED + legalcolor = 0xff; + legalmask = legalcolor; +#else + legalmask = 0x0ff0; + legalcolor = 0xff; +#endif + } else if (drawenable & GFX_MASK_PRIORITY) { + bounds = pic->priority_map->index_data; + legalcolor = 0; + legalmask = 0x0f0f; + } else { + legalcolor = 0; + legalmask = 0x0f0f; + } + + if (!bounds || IS_BOUNDARY(x, y, bounds[ytotal + x])) + return; + + if (bounds) { +#ifdef DRAW_SCALED + int proj_y = y_200; + int proj_ytotal = proj_y * 320; + int proj_x = x_320; + int proj_xl_bound; + int proj_xr_bound; + int proj_xl, proj_xr; + + ytotal = y * linewidth; + + proj_xl_bound = proj_x; + if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { + while (proj_xl_bound && SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT)) + --proj_xl_bound; + } else + while (proj_xl_bound < 319 && SCALED_CHECK(!(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT))) + ++proj_xl_bound; + + proj_xr_bound = (proj_xl_bound > proj_x) ? proj_xl_bound : proj_x; + while ((proj_xr_bound < 319) && SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT)) + ++proj_xr_bound; + + proj_xl = proj_xl_bound; + proj_xr = proj_xr_bound; + + proj_xl_bound *= pic->mode->xfact; + if (proj_xl_bound) + proj_xl_bound -= pic->mode->xfact - 1; + + if (proj_xr_bound < 319) + ++proj_xr_bound; + proj_xr_bound *= pic->mode->xfact; + proj_xr_bound += pic->mode->xfact - 1; +#endif + xl = x; + while (xl > proj_xl_bound && (!IS_BOUNDARY(xl - 1, y, bounds[ytotal + xl -1]))) + --xl; + + while (x < proj_xr_bound && (!IS_BOUNDARY(x + 1, y, bounds[ytotal + x + 1]))) + ++x; + xr = x; + + if (drawenable & GFX_MASK_VISUAL) + memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); + + if (drawenable & GFX_MASK_PRIORITY) + memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); + + FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, -1, bounds, legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, + 1, bounds, legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + } + + // Now finish the aux buffer + bitmask = drawenable & (((color != 0xff) ? 1 : 0) | ((priority) ? 2 : 0) | ((control) ? 4 : 0)); + +#ifdef DRAW_SCALED +# ifdef FILL_RECURSIVE_DEBUG + if (fillmagc) +# endif + _gfxr_auxbuf_propagate_changes(pic, bitmask); +#endif +} + +#undef SCALED_CHECK +#undef IS_BOUNDARY + +#ifndef DRAW_SCALED +# undef proj_xl_bound +# undef proj_xr_bound +#endif + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_cursor.cpp b/engines/sci/gfx/res_cursor.cpp new file mode 100644 index 0000000000..9a109f6ebf --- /dev/null +++ b/engines/sci/gfx/res_cursor.cpp @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* SCI cursor functions */ + +#include "sci/gfx/gfx_system.h" +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" + +namespace Sci { + +#define CURSOR_RESOURCE_SIZE 68 +#define CURSOR_SIZE 16 + +#define GFX_SCI01_CURSOR_COLORS_NR 3 +#define GFX_SCI0_CURSOR_COLORS_NR 2 + +#define GFX_CURSOR_TRANSPARENT 255 + +gfx_pixmap_color_t gfx_sci01_cursor_colors[GFX_SCI01_CURSOR_COLORS_NR] = { + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0xff, 0xff, 0xff}, + {GFX_COLOR_INDEX_UNMAPPED, 0xaa, 0xaa, 0xaa} +}; + +gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, bool isSci01) { + int colors[4] = {0, 1, GFX_CURSOR_TRANSPARENT, 1}; + int line; + byte *data; + gfx_pixmap_t *retval; + + if (isSci01) + colors[3] = 2; + + if (size != CURSOR_RESOURCE_SIZE) { + GFXERROR("Expected resource size of %d, but found %d\n", CURSOR_RESOURCE_SIZE, size); + return NULL; + } + + retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(CURSOR_SIZE, CURSOR_SIZE, id, 0, 0)); + // FIXME: don't copy palette + retval->palette = new Palette(gfx_sci01_cursor_colors, isSci01 ? GFX_SCI01_CURSOR_COLORS_NR : GFX_SCI0_CURSOR_COLORS_NR); + retval->palette->name = "cursor"; + retval->color_key = GFX_CURSOR_TRANSPARENT; + + if (isSci01) { + retval->xoffset = READ_LE_UINT16(resource); + retval->yoffset = READ_LE_UINT16(resource + 2); + } else if (resource[3]) // center + retval->xoffset = retval->yoffset = CURSOR_SIZE / 2; + else + retval->xoffset = retval->yoffset = 0; + + resource += 4; + + data = retval->index_data; + for (line = 0; line < 16; line++) { + int mask_a = READ_LE_UINT16(resource + (line << 1)); + int mask_b = READ_LE_UINT16(resource + 32 + (line << 1)); + int i; + + for (i = 0; i < 16; i++) { + int color_code = ((mask_a << i) & 0x8000) | (((mask_b << i) >> 1) & 0x4000); + *data++ = colors[color_code >> 14]; + } + } + return retval; +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_font.cpp b/engines/sci/gfx/res_font.cpp new file mode 100644 index 0000000000..c208fe16f0 --- /dev/null +++ b/engines/sci/gfx/res_font.cpp @@ -0,0 +1,143 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_system.h" +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" +#include "sci/gfx/font.h" + +namespace Sci { + +extern int font_counter; + +#define FONT_HEIGHT_OFFSET 4 +#define FONT_MAXCHAR_OFFSET 2 + +static int calc_char(byte *dest, int total_width, int total_height, byte *src, int size) { + int width = src[0]; + int height = src[1]; + int byte_width = (width + 7) >> 3; + int y; + + src += 2; + + if ((width >> 3) > total_width || height > total_height) { + GFXERROR("Weird character: width=%d/%d, height=%d/%d\n", width, total_width, height, total_height); + return GFX_ERROR; + } + + if (byte_width * height + 2 > size) { + GFXERROR("Character extends to %d of %d allowed bytes\n", byte_width * height + 2, size); + return GFX_ERROR; + } + + for (y = 0; y < height; y++) { + memcpy(dest, src, byte_width); + src += byte_width; + dest += total_width; + } + + return GFX_OK; +} + +gfx_bitmap_font_t *gfxr_read_font(int id, byte *resource, int size) { + gfx_bitmap_font_t *font = (gfx_bitmap_font_t*)sci_calloc(sizeof(gfx_bitmap_font_t), 1); + int chars_nr; + int max_width = 0, max_height; + int i; + + ++font_counter; + + if (size < 6) { + GFXERROR("Font %04x size is %d- this is a joke, right?\n", id, size); + gfxr_free_font(font); + return NULL; + } + + font->chars_nr = chars_nr = READ_LE_UINT16(resource + FONT_MAXCHAR_OFFSET); + font->line_height = max_height = READ_LE_UINT16(resource + FONT_HEIGHT_OFFSET); + + if (chars_nr < 0 || chars_nr > 256 || max_height < 0) { + if (chars_nr < 0 || chars_nr > 256) + GFXERROR("Font %04x: Invalid number of characters: %d\n", id, chars_nr); + if (max_height < 0) + GFXERROR("Font %04x: Invalid font height: %d\n", id, max_height); + gfxr_free_font(font); + return NULL; + } + + if (size < 6 + chars_nr * 2) { + GFXERROR("Font %04x: Insufficient space for %d characters in font\n", id, chars_nr); + gfxr_free_font(font); + return NULL; + } + + font->ID = id; + font->widths = (int*)sci_malloc(sizeof(int) * chars_nr); + + for (i = 0; i < chars_nr; i++) { + int offset = READ_LE_UINT16(resource + (i << 1) + 6); + + if (offset >= size) { + GFXERROR("Font %04x: Error: Character 0x%02x is at offset 0x%04x (beyond 0x%04x)\n", id, i, offset, size); + gfxr_free_font(font); + return NULL; + } + + if ((resource[offset]) > max_width) + max_width = resource[offset]; + if ((resource[offset + 1]) > max_height) + max_height = resource[offset + 1]; + + font->widths[i] = resource[offset]; + } + + font->height = max_height; + font->row_size = (max_width + 7) >> 3; + + if (font->row_size == 3) + font->row_size = 4; + + if (font->row_size > 4) + font->row_size = (font->row_size + 3) & ~3; + + font->char_size = font->row_size * max_height; + font->data = (byte *)sci_calloc(font->char_size, chars_nr); + + for (i = 0; i < chars_nr; i++) { + int offset = READ_LE_UINT16(resource + (i << 1) + 6); + + if (calc_char(font->data + (font->char_size * i), font->row_size, max_height, resource + offset, size - offset)) { + GFXERROR("Problem occured in font %04x, char %d/%d\n", id, i, chars_nr); + gfxr_free_font(font); + return NULL; + } + } + + return font; +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_pal.cpp b/engines/sci/gfx/res_pal.cpp new file mode 100644 index 0000000000..74fb8629b7 --- /dev/null +++ b/engines/sci/gfx/res_pal.cpp @@ -0,0 +1,147 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +/* SCI1 palette resource defrobnicator */ + +#include "common/file.h" +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_system.h" +#include "sci/gfx/gfx_resource.h" + +namespace Sci { + +#define MAX_COLORS 256 +#define PALETTE_START 260 +#define COLOR_OK 0x01 + +#define SCI_PAL_FORMAT_VARIABLE_FLAGS 0 +#define SCI_PAL_FORMAT_CONSTANT_FLAGS 1 + +Palette *gfxr_read_pal11(int id, byte *resource, int size) { + int start_color = resource[25]; + int format = resource[32]; + int entry_size = 0; + Palette *retval; + byte *pal_data = resource + 37; + int _colors_nr = READ_LE_UINT16(resource + 29); + int i; + + switch (format) { + case SCI_PAL_FORMAT_VARIABLE_FLAGS : + entry_size = 4; + break; + case SCI_PAL_FORMAT_CONSTANT_FLAGS : + entry_size = 3; + break; + } + + retval = new Palette(_colors_nr + start_color); + char buf[100]; + sprintf(buf, "read_pal11 (id %d)", id); + retval->name = buf; + + for (i = 0; i < start_color; i ++) { + retval->setColor(i, 0, 0, 0); + } + for (i = start_color; i < start_color + _colors_nr; i ++) { + switch (format) { + case SCI_PAL_FORMAT_CONSTANT_FLAGS: + retval->setColor(i, pal_data[0], pal_data[1], pal_data[2]); + break; + case SCI_PAL_FORMAT_VARIABLE_FLAGS: + retval->setColor(i, pal_data[1], pal_data[2], pal_data[3]); + break; + } + pal_data += entry_size; + } + + return retval; +} + +Palette *gfxr_read_pal1(int id, byte *resource, int size) { + int counter = 0; + int pos; + unsigned int colors[MAX_COLORS] = {0}; + + if (size < PALETTE_START + 4) { + GFXERROR("Palette resource too small in %04x\n", id); + return NULL; + } + + pos = PALETTE_START; + + while (pos < size/* && resource[pos] == COLOR_OK && counter < MAX_COLORS*/) { + int color = resource[pos] | (resource[pos + 1] << 8) | (resource[pos + 2] << 16) | (resource[pos + 3] << 24); + + pos += 4; + + colors[counter++] = color; + } + + if (counter < MAX_COLORS && resource[pos] != COLOR_OK) { + GFXERROR("Palette %04x uses unknown palette color prefix 0x%02x at offset 0x%04x\n", id, resource[pos], pos); + return NULL; + } + + if (counter < MAX_COLORS) { + GFXERROR("Palette %04x ends prematurely\n", id); + return NULL; + } + + Palette *retval = new Palette(counter); + char buf[100]; + sprintf(buf, "read_pal1 (id %d)", id); + retval->name = buf; + + for (pos = 0; pos < counter; pos++) { + unsigned int color = colors[pos]; + retval->setColor(pos, (color >> 8) & 0xff, (color >> 16) & 0xff, (color >> 24) & 0xff); + } + + return retval; +} + +Palette *gfxr_read_pal1_amiga(Common::File &file) { + int i; + Palette *retval = new Palette(32); + + for (i = 0; i < 32; i++) { + int b1, b2; + + b1 = file.readByte(); + b2 = file.readByte(); + + if (b1 == EOF || b2 == EOF) { + GFXERROR("Palette file ends prematurely\n"); + return NULL; + } + + retval->setColor(i, (b1 & 0xf) * 0x11, ((b2 & 0xf0) >> 4) * 0x11, (b2 & 0xf) * 0x11); + } + + return retval; +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_pic.cpp b/engines/sci/gfx/res_pic.cpp new file mode 100644 index 0000000000..f9f56e4ce9 --- /dev/null +++ b/engines/sci/gfx/res_pic.cpp @@ -0,0 +1,1881 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include // for time() to seed rand() via srand() +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" + +namespace Sci { + +#undef GFXR_DEBUG_PIC0 // Enable to debug pic0 messages +#undef FILL_RECURSIVE_DEBUG // Enable for verbose fill debugging + +#define GFXR_PIC0_PALETTE_SIZE 40 +#define GFXR_PIC0_NUM_PALETTES 4 + +#define INTERCOL(a, b) ((int) sqrt((((3.3 * (a))*(a)) + ((1.7 * (b))*(b))) / 5.0)) +// Macro for color interpolation + +#define SCI0_MAX_PALETTE 2 + +int sci0_palette = 0; + +// Copied from include/kernel.h +#define SCI0_PRIORITY_BAND_FIRST_14_ZONES(nr) ((((nr) == 0)? 0 : \ + ((first) + (((nr)-1) * (last - first)) / 14))) + +// Default color maps +gfx_pixmap_color_t gfx_sci0_image_colors[SCI0_MAX_PALETTE+1][GFX_SCI0_IMAGE_COLORS_NR] = { + {{GFX_COLOR_SYSTEM, 0x00, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0x00, 0xaa}, + {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0xaa}, + {GFX_COLOR_SYSTEM, 0xaa, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0x00, 0xaa}, + {GFX_COLOR_SYSTEM, 0xaa, 0x55, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0xaa, 0xaa}, + {GFX_COLOR_SYSTEM, 0x55, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0x55, 0xff}, + {GFX_COLOR_SYSTEM, 0x55, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0xff, 0xff}, + {GFX_COLOR_SYSTEM, 0xff, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0x55, 0xff}, + {GFX_COLOR_SYSTEM, 0xff, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0xff, 0xff}}, // "Normal" EGA + + + {{GFX_COLOR_SYSTEM, 0x00, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0x00, 0xff}, + {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0xaa}, + {GFX_COLOR_SYSTEM, 0xce, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0xbe, 0x71, 0xde}, + {GFX_COLOR_SYSTEM, 0x8d, 0x50, 0x00}, {GFX_COLOR_SYSTEM, 0xbe, 0xbe, 0xbe}, + {GFX_COLOR_SYSTEM, 0x55, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0x00, 0xbe, 0xff}, + {GFX_COLOR_SYSTEM, 0x00, 0xce, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0xff, 0xff}, + {GFX_COLOR_SYSTEM, 0xff, 0x9d, 0x8d}, {GFX_COLOR_SYSTEM, 0xff, 0x55, 0xff}, + {GFX_COLOR_SYSTEM, 0xff, 0xff, 0x00}, {GFX_COLOR_SYSTEM, 0xff, 0xff, 0xff}}, // AGI Amiga-ish + +// RGB and I intensities (former taken from the GIMP) +#define GR 30 +#define GG 59 +#define GB 11 +#define GI 15 + +#define FULL (GR+GG+GB+GI) + +#define CC(x) (((x)*255)/FULL),(((x)*255)/FULL),(((x)*255)/FULL) // Combines color intensities + + {{GFX_COLOR_SYSTEM, CC(0) }, {GFX_COLOR_SYSTEM, CC(GB) }, + {GFX_COLOR_SYSTEM, CC(GG) }, {GFX_COLOR_SYSTEM, CC(GB + GG) }, + {GFX_COLOR_SYSTEM, CC(GR) }, {GFX_COLOR_SYSTEM, CC(GB + GR) }, + {GFX_COLOR_SYSTEM, CC(GG + GR) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GR) }, + {GFX_COLOR_SYSTEM, CC(GI) }, {GFX_COLOR_SYSTEM, CC(GB + GI) }, + {GFX_COLOR_SYSTEM, CC(GG + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GI) }, + {GFX_COLOR_SYSTEM, CC(GR + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GR + GI) }, + {GFX_COLOR_SYSTEM, CC(GG + GR + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GR + GI) }} +}; // Grayscale + +#undef GR +#undef GG +#undef GB +#undef GI + +#undef FULL + +#undef C2 +#undef C3 +#undef C4 + +Palette* gfx_sci0_pic_colors = 0; // Initialized during initialization +Palette* gfx_sci0_image_pal[SCI0_MAX_PALETTE+1]; +Palette* embedded_view_pal = 0; + +#define SCI1_PALETTE_SIZE 1284 + +#ifdef FILL_RECURSIVE_DEBUG +/************************************/ +int fillc = 100000000; +int fillmagc = 30000000; +/************************************/ +#endif + +// Color mapping used while scaling embedded views. +gfx_pixmap_color_t embedded_view_colors[16] = { + {0x00, 0, 0, 0}, {0x11, 0, 0, 0}, {0x22, 0, 0, 0}, {0x33, 0, 0, 0}, + {0x44, 0, 0, 0}, {0x55, 0, 0, 0}, {0x66, 0, 0, 0}, {0x77, 0, 0, 0}, + {0x88, 0, 0, 0}, {0x99, 0, 0, 0}, {0xaa, 0, 0, 0}, {0xbb, 0, 0, 0}, + {0xcc, 0, 0, 0}, {0xdd, 0, 0, 0}, {0xee, 0, 0, 0}, {0xff, 0, 0, 0} +}; + +void gfxr_init_static_palette() { + if (!gfx_sci0_pic_colors) { + gfx_sci0_pic_colors = new Palette(256); + gfx_sci0_pic_colors->name = "gfx_sci0_pic_colors"; + for (int i = 0; i < 256; i++) { + byte r = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].r, + gfx_sci0_image_colors[sci0_palette][i >> 4].r); + byte g = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].g, + gfx_sci0_image_colors[sci0_palette][i >> 4].g); + byte b = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].b, + gfx_sci0_image_colors[sci0_palette][i >> 4].b); + gfx_sci0_pic_colors->setColor(i,r,g,b); + } + //warning("Uncomment me after fixing sci0_palette changes to reset me"); + //_gfxr_pic0_colors_initialized = 1; + + for (int i = 0; i <= SCI0_MAX_PALETTE; ++i) { + gfx_sci0_image_pal[i] = new Palette(gfx_sci0_image_colors[i], GFX_SCI0_IMAGE_COLORS_NR); + gfx_sci0_image_pal[i]->name = "gfx_sci0_image_pal[i]"; + } + + embedded_view_pal = new Palette(embedded_view_colors, 16); + embedded_view_pal->name = "embedded_view_pal"; + } +} + + +gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, int sci1) { + gfxr_pic_t *pic = (gfxr_pic_t*)sci_malloc(sizeof(gfxr_pic_t)); + + pic->mode = mode; + + pic->control_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, ID, 2, 0)); + + pic->priority_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(mode->xfact * 320, mode->yfact * 200, + ID, 1, 0)); + + + pic->visual_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * mode->xfact, + 200 * mode->yfact, ID, 0, 0)); + + // Initialize colors + if (!sci1) { + pic->ID = ID; + gfxr_init_static_palette(); + } + + pic->visual_map->palette = gfx_sci0_pic_colors->getref(); + pic->visual_map->color_key = GFX_PIXMAP_COLOR_KEY_NONE; + + pic->visual_map->flags = 0; + pic->priority_map->flags = 0; + pic->control_map->flags = 0; + if (mode->xfact > 1 || mode->yfact > 1) { + pic->visual_map->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + pic->priority_map->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + } + + pic->priority_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); + pic->control_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); + + pic->undithered_buffer_size = pic->visual_map->index_width * pic->visual_map->index_height; + pic->undithered_buffer = NULL; + pic->priorityTable = NULL; + + return pic; +} + +// Pic rendering operations + +void gfxr_clear_pic0(gfxr_pic_t *pic, int sci_titlebar_size) { + memset(pic->visual_map->index_data, 0x00, (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact)); + memset(pic->visual_map->index_data + (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact), + 0xff, pic->mode->xfact * 320 * pic->mode->yfact * (200 - sci_titlebar_size)); // white + memset(pic->priority_map->index_data + (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact), + 0x0, pic->mode->xfact * 320 * pic->mode->yfact * (200 - sci_titlebar_size)); + memset(pic->priority_map->index_data, 0x0a, sci_titlebar_size * (pic->mode->yfact * 320 * pic->mode->xfact)); + memset(pic->control_map->index_data, 0, GFXR_AUX_MAP_SIZE); + memset(pic->aux_map, 0, GFXR_AUX_MAP_SIZE); +} + + +//** Basic operations on the auxiliary buffer ** + +#define FRESH_PAINT 0x40 +// freshly filled or near to something that is + +#define LINEMACRO(startx, starty, deltalinear, deltanonlinear, linearvar, nonlinearvar, \ + linearend, nonlinearstart, linearmod, nonlinearmod, operation) \ + x = (startx); y = (starty); \ + incrNE = ((deltalinear) > 0)? (deltalinear) : -(deltalinear); \ + incrNE <<= 1; \ + deltanonlinear <<= 1; \ + incrE = ((deltanonlinear) > 0) ? -(deltanonlinear) : (deltanonlinear); \ + d = nonlinearstart-1; \ + while (linearvar != (linearend)) { \ + buffer[linewidth * y + x] operation color; \ +/* color ^= color2; color2 ^= color; color ^= color2; */ /* Swap colors */ \ + linearvar += linearmod; \ + if ((d+=incrE) < 0) { \ + d += incrNE; \ + nonlinearvar += nonlinearmod; \ + }; \ + }; \ + buffer[linewidth * y + x] operation color; + +static void _gfxr_auxbuf_line_draw(gfxr_pic_t *pic, rect_t line, int color, int color2, int sci_titlebar_size) { + int dx, dy, incrE, incrNE, d, finalx, finaly; + int x = line.x; + int y = line.y + sci_titlebar_size; + unsigned char *buffer = pic->aux_map; + int linewidth = 320; + + dx = line.width; + dy = line.height; + finalx = x + dx; + finaly = y + dy; + + dx = abs(dx); + dy = abs(dy); + + if (dx > dy) { + if (finalx < x) { + if (finaly < y) { // llu == left-left-up + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, -1, |=); + } else { // lld + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, 1, |=); + } + } else { // x1 >= x + if (finaly < y) { // rru + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, -1, |=); + } else { // rrd + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, 1, |=); + } + } + } else { // dx <= dy + if (finaly < y) { + if (finalx < x) { // luu + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, -1, |=); + } else { // ruu + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, 1, |=); + } + } else { // y1 >= y + if (finalx < x) { // ldd + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, -1, |=); + } else { // rdd + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, 1, |=); + } + } + } +} + +static void _gfxr_auxbuf_line_clear(gfxr_pic_t *pic, rect_t line, int color, int sci_titlebar_size) { + int dx, dy, incrE, incrNE, d, finalx, finaly; + int x = line.x; + int y = line.y + sci_titlebar_size; + unsigned char *buffer = pic->aux_map; + int linewidth = 320; + + dx = line.width; + dy = line.height; + finalx = x + dx; + finaly = y + dy; + + dx = abs(dx); + dy = abs(dy); + + if (dx > dy) { + if (finalx < x) { + if (finaly < y) { // llu == left-left-up + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, -1, &=); + } else { // lld + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, 1, &=); + } + } else { // x1 >= x + if (finaly < y) { // rru + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, -1, &=); + } else { // rrd + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, 1, &=); + } + } + } else { // dx <= dy + if (finaly < y) { + if (finalx < x) { // luu + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, -1, &=); + } else { // ruu + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, 1, &=); + } + } else { // y1 >= y + if (finalx < x) { // ldd + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, -1, &=); + } else { // rdd + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, 1, &=); + } + } + } +} + +#undef LINEMACRO + +#ifdef WITH_PIC_SCALING +static void _gfxr_auxbuf_propagate_changes(gfxr_pic_t *pic, int bitmask) { + // Propagates all filled bits into the planes described by bitmask + unsigned long *data = (unsigned long *)pic->aux_map; + unsigned long clearmask = 0x07070707; + unsigned long andmask = (bitmask << 3) | (bitmask << (3 + 8)) | (bitmask << (3 + 16)) | (bitmask << (3 + 24)); + + if (sizeof(unsigned long) == 8) { // UltraSparc, Alpha, newer MIPSens, etc + andmask |= (andmask << 32); + clearmask |= (clearmask << 32); + } + + for (int i = 0; i < GFXR_AUX_MAP_SIZE / sizeof(unsigned long); i++) { + unsigned long temp = *data & andmask; + temp >>= 3; + *data = (temp | *data) & clearmask; + ++data; + } +} +#endif + + +#if 0 +// Unreferenced - removed +static void _gfxr_auxbuf_tag_line(gfxr_pic_t *pic, int pos, int width) { + for (int i = 0; i < width; i++) + pic->aux_map[i+pos] |= FRESH_PAINT; +} + +// Unreferenced - removed +static void _gfxr_auxbuf_spread(gfxr_pic_t *pic, int *min_x, int *min_y, int *max_x, int *max_y) { + // Tries to spread by approximating the first derivation of the border function. + // Draws to the current and the last line, thus taking up to twice as long as neccessary. + // Other than that, it's O(n^2) + + int intervals_nr = 0, old_intervals_nr; + int x, y, i, pos = 10 * 320; + struct interval_struct { + int xl, xr, tag; + } intervals[2][160]; + + *max_x = *max_y = -1; + *min_x = *min_y = 320; + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillmagc) { + fprintf(stderr, "------------------------------------------------\n"); + fprintf(stderr, "LineID: "); + for (i = 0; i < 5; i++) + fprintf(stderr, " %d ", i); + fprintf(stderr, "\n"); + } +#endif + + for (y = 10; y < 200; y++) { + int ivi = y & 1; // InterVal Index: Current intervals; !ivi is the list of old ones + int old_intervals_start_offset = 0; + int width = 0; + + old_intervals_nr = intervals_nr; + intervals_nr = 0; + + for (x = 0; x < 321; x++) + if (x < 320 && pic->aux_map[pos+x] & 0x10) + width++; + else if (width) { // Found one interval + int xl = x - width; + int xr = x - 1; + int done = 0; + int found_interval = 0; + + intervals[ivi][intervals_nr].width = xl; + intervals[ivi][intervals_nr].tag = 0; + intervals[ivi][intervals_nr++].xr = xr; + + if (xl < *min_x) + *min_x = xl; + if (xr > *max_x) + *max_x = xr; + + i = old_intervals_start_offset; + while (!done && i < old_intervals_nr) { + if (intervals[!ivi][i].width > xr + 1) + done = 1; + + else if (intervals[!ivi][i].xr < xl - 1) { + int o_xl = intervals[!ivi][i].width; + int o_xr = intervals[!ivi][i].xr; + if (o_xr == o_xl && !intervals[!ivi][i].tag) { // thin bar + memcpy(intervals[ivi] + intervals_nr, intervals[ivi] + intervals_nr - 1, sizeof(struct interval_struct)); + memcpy(intervals[ivi] + intervals_nr - 1, intervals[!ivi] + i, sizeof(struct interval_struct)); + intervals[!ivi][i].tag = 1; + pic->aux_map[pos - 320 + o_xl] |= FRESH_PAINT; + ++intervals_nr; + } + + old_intervals_start_offset = i; + } else { + int k = i; + int old_xl = intervals[!ivi][i].width; + int dwidth_l = abs(old_xl - xl); + int old_xr, dwidth_r; + int write_left_width, write_right_width; + + intervals[!ivi][i].tag = 1; + while (k + 1 < old_intervals_nr && intervals[!ivi][k+1].width <= xr) { + ++k; + intervals[!ivi][i].tag = 1; + } + + old_xr = intervals[!ivi][k].xr; + dwidth_r = abs(old_xr - xr); + + // Current line + write_left_width = (dwidth_l > xl) ? xl : dwidth_l; + _gfxr_auxbuf_tag_line(pic, pos + xl - write_left_width, write_left_width); + + write_right_width = (dwidth_r + xr > 319) ? 320 - xr : dwidth_r; + _gfxr_auxbuf_tag_line(pic, pos + xr, write_right_width); + + if (xl - write_left_width < *min_x) + *min_x = xl - write_left_width; + if (xr + write_right_width > *max_x) + *max_x = xr + write_right_width; + + // Previous line + write_left_width = (dwidth_l > old_xl) ? old_xl : dwidth_l; + write_right_width = (dwidth_r + old_xr > 319) ? 320 - old_xr : dwidth_r; + + if (i == k) { // Only one predecessor interval + _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xl - write_left_width, write_left_width); + _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xr, write_right_width); + } else // Fill entire line + _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xl - write_left_width, old_xr - old_xl + + 1 + write_left_width + write_right_width); + + if (xl - write_left_width < *min_x) + *min_x = xl - write_left_width; + if (xr + write_right_width > *max_x) + *max_x = xr + write_right_width; + + found_interval = done = 1; + } + i++; + } + width = 0; + } + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillmagc && intervals_nr) { + fprintf(stderr, "AI L#%03d:", y); + for (int j = 0; j < intervals_nr; j++) + fprintf(stderr, "%c[%03d,%03d]", intervals[ivi][j].tag ? ' ' : '-', intervals[ivi][j].width, intervals[ivi][j].xr); + fprintf(stderr, "\n"); + } +#endif + + if (intervals_nr) { + if (y < *min_y) + *min_y = y; + *max_y = y; + } + + pos += 320; + } + + for (pos = 320 * 200 - 1; pos >= 320; pos--) + if (pic->aux_map[pos - 320] & 0x40) + pic->aux_map[pos] |= 0x40; + + if (*max_y < 199) + (*max_y)++; +} + +#endif + + +/*** Regular drawing operations ***/ + +#define PATTERN_FLAG_RECTANGLE 0x10 +#define PATTERN_FLAG_USE_PATTERN 0x20 + +#define PIC_OP_FIRST 0xf0 + +enum { + PIC_OP_SET_COLOR = 0xf0, + PIC_OP_DISABLE_VISUAL = 0xf1, + PIC_OP_SET_PRIORITY = 0xf2, + PIC_OP_DISABLE_PRIORITY = 0xf3, + PIC_OP_SHORT_PATTERNS = 0xf4, + PIC_OP_MEDIUM_LINES = 0xf5, + PIC_OP_LONG_LINES = 0xf6, + PIC_OP_SHORT_LINES = 0xf7, + PIC_OP_FILL = 0xf8, + PIC_OP_SET_PATTERN = 0xf9, + PIC_OP_ABSOLUTE_PATTERN = 0xfa, + PIC_OP_SET_CONTROL = 0xfb, + PIC_OP_DISABLE_CONTROL = 0xfc, + PIC_OP_MEDIUM_PATTERNS = 0xfd, + PIC_OP_OPX = 0xfe, + PIC_OP_TERMINATE = 0xff +}; + +enum { + PIC_SCI0_OPX_SET_PALETTE_ENTRIES = 0, + PIC_SCI0_OPX_SET_PALETTE = 1, + PIC_SCI0_OPX_MONO0 = 2, + PIC_SCI0_OPX_MONO1 = 3, + PIC_SCI0_OPX_MONO2 = 4, + PIC_SCI0_OPX_MONO3 = 5, + PIC_SCI0_OPX_MONO4 = 6, + PIC_SCI0_OPX_EMBEDDED_VIEW, + PIC_SCI0_OPX_SET_PRIORITY_TABLE +}; + +// We use this so we can keep OPX handling in one switch. +// We simply add this constant to the op number if we're running an SCI1 game, +// and offset the OPX constants below correspondingly. +#define SCI1_OP_OFFSET 42 + +enum { + PIC_SCI1_OPX_SET_PALETTE_ENTRIES = 0 + SCI1_OP_OFFSET, + PIC_SCI1_OPX_EMBEDDED_VIEW = 1 + SCI1_OP_OFFSET, + PIC_SCI1_OPX_SET_PALETTE = 2 + SCI1_OP_OFFSET, + PIC_SCI1_OPX_PRIORITY_TABLE_EQDIST = 3 + SCI1_OP_OFFSET, + PIC_SCI1_OPX_PRIORITY_TABLE_EXPLICIT = 4 + SCI1_OP_OFFSET +}; + + +#ifdef GFXR_DEBUG_PIC0 +#define p0printf sciprintf +#else +void do_nothing(...) { } +#define p0printf do_nothing +#endif + +enum { + ELLIPSE_SOLID, // Normal filled ellipse + ELLIPSE_OR // color ORred to the buffer +}; + +static void _gfxr_fill_ellipse(gfxr_pic_t *pic, byte *buffer, int linewidth, int x, int y, + int rad_x, int rad_y, int color, int fillstyle) { + int xx = 0, yy = rad_y; + int i, x_i, y_i; + int xr = 2 * rad_x * rad_x; + int yr = 2 * rad_y * rad_y; + + x_i = 1; + y_i = xr * rad_y - 1; + i = y_i >> 1; + + while (yy >= 0) { + int oldxx = xx; + int oldyy = yy; + + if (i >= 0) { + x_i += yr; + i -= x_i + 1; + ++xx; + } + + if (i < 0) { + y_i -= xr; + i += y_i - 1; + --yy; + } + + if (oldyy != yy) { + int j; + int offset0 = (y - oldyy) * linewidth; + int offset1 = (y + oldyy) * linewidth; + + offset0 += x - oldxx; + offset1 += x - oldxx; + + if (oldyy == 0) + offset1 = 0; // We never have to draw ellipses in the menu bar + + oldyy = yy; + + switch (fillstyle) { + + case ELLIPSE_SOLID: + memset(buffer + offset0, color, (oldxx << 1) + 1); + if (offset1) + memset(buffer + offset1, color, (oldxx << 1) + 1); + break; + + case ELLIPSE_OR: + for (j = 0; j < (oldxx << 1) + 1; j++) { + buffer[offset0 + j] |= color; + if (offset1) + buffer[offset1 + j] |= color; + } + break; + + default: + fprintf(stderr, "%s L%d: Invalid ellipse fill mode!\n", __FILE__, __LINE__); + return; + + } + } + } +} + +static void _gfxr_auxplot_brush(gfxr_pic_t *pic, byte *buffer, int yoffset, int offset, int plot, + int color, gfx_brush_mode_t brush_mode, int randseed) { + // yoffset 63680, offset 320, plot 1, color 34, brush_mode 0, randseed 432)*/ + // Auxplot: Used by plot_aux_pattern to plot to visual and priority + int xc, yc; + int line_width = 320 * pic->mode->xfact; + int full_offset = (yoffset * pic->mode->yfact + offset) * pic->mode->xfact; + + if (yoffset + offset >= 64000) { + BREAKPOINT(); + } + + switch (brush_mode) { + case GFX_BRUSH_MODE_SCALED: + if (plot) + for (yc = 0; yc < pic->mode->yfact; yc++) { + memset(buffer + full_offset, color, pic->mode->xfact); + full_offset += line_width; + } + break; + + case GFX_BRUSH_MODE_ELLIPSES: + if (plot) { + int x = offset * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); + int y = (yoffset / 320) * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); + + _gfxr_fill_ellipse(pic, buffer, line_width, x, y, pic->mode->xfact >> 1, pic->mode->yfact >> 1, color, ELLIPSE_SOLID); + } + break; + + case GFX_BRUSH_MODE_RANDOM_ELLIPSES: + if (plot) { + int x = offset * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); + int y = (yoffset / 320) * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); + int sizex = pic->mode->xfact >> 1; + int sizey = pic->mode->yfact >> 1; + + srand(randseed); + + x -= (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); + x += (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); + y -= (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); + y += (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); + sizex = (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); + sizey = (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); + + _gfxr_fill_ellipse(pic, buffer, line_width, x, y, pic->mode->xfact >> 1, pic->mode->yfact >> 1, + color, ELLIPSE_SOLID); + srand(time(NULL)); // Make sure we don't accidently forget to re-init the random number generator + } + break; + + case GFX_BRUSH_MODE_MORERANDOM: { + int mask = plot ? 7 : 1; + srand(randseed); + for (yc = 0; yc < pic->mode->yfact; yc++) { + for (xc = 0; xc < pic->mode->xfact; xc++) + if ((rand() & 7) < mask) + buffer[full_offset + xc] = color; + full_offset += line_width; + } + srand(time(NULL)); // Make sure we don't accidently forget to re-init the random number generator + } + break; + } +} + +#define PLOT_AUX_PATTERN_NO_RANDOM -1 + +static void _gfxr_plot_aux_pattern(gfxr_pic_t *pic, int x, int y, int size, int circle, int random, + int mask, int color, int priority, int control, gfx_brush_mode_t brush_mode, int map_nr) { + // Plots an appropriate pattern to the aux buffer and the control buffer, + // if mask & GFX_MASK_CONTROL + // random should be set to the random index, or -1 to disable + + // These circle offsets uniquely identify the circles used by Sierra: + int circle_data[][8] = { + {0}, + {1, 0}, + {2, 2, 1}, + {3, 3, 2, 1}, + {4, 4, 4, 3, 1}, + {5, 5, 4, 4, 3, 1}, + {6, 6, 6, 5, 5, 4, 2}, + {7, 7, 7, 6, 6, 5, 4, 2} + }; + + // 'Random' fill patterns, provided by Carl Muckenhoupt: + byte random_data[32] = { + 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, 0x82, 0x09, 0x0a, 0x22, + 0x12, 0x10, 0x42, 0x14, 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, + 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 + }; + + // 'Random' fill offsets, provided by Carl Muckenhoupt: + byte random_offset[128] = { + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, + 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, + 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, + 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, + 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, + 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, + 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, + 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 + }; + + int offset = 0, width = 0; + int yoffset = (y - size) * 320; + int i; + int random_index = 0; + gfx_pixmap_t *map = NULL; + + switch (map_nr) { + case GFX_MASK_VISUAL: + map = pic->visual_map; + break; + case GFX_MASK_PRIORITY: + map = pic->priority_map; + break; + default: + map = pic->control_map; + break; + } + + if (random >= 0) + random_index = random_offset[random]; + + if (!circle) { + offset = -size; + width = (size << 1) + 2; + } + + for (i = -size; i <= size; i++) { + int j; + int height; + + if (circle) { + offset = circle_data[size][abs(i)]; + height = width = (offset << 1) + 1; + offset = -offset; + } else + height = width - 1; + + if (random == PLOT_AUX_PATTERN_NO_RANDOM) { + + if (mask & map_nr) + memset(map->index_data + yoffset + offset + x, control, width); + + if (map_nr == GFX_MASK_CONTROL) + for (j = x; j < x + width; j++) + pic->aux_map[yoffset + offset + j] |= mask; + + } else { // Semi-Random! + for (j = 0; j < height; j++) { + if (random_data[random_index >> 3] & (0x80 >> (random_index & 7))) { + // The 'seemingly' random decision + if (mask & GFX_MASK_CONTROL) + pic->control_map->index_data[yoffset + x + offset + j] = control; + + pic->aux_map[yoffset + x + offset + j] |= mask; + + if (mask & GFX_MASK_VISUAL) + _gfxr_auxplot_brush(pic, pic->visual_map->index_data, yoffset, x + offset + j, + 1, color, brush_mode, random_index + x); + + if (mask & GFX_MASK_PRIORITY) + _gfxr_auxplot_brush(pic, pic->priority_map->index_data, yoffset, x + offset + j, + 1, priority, brush_mode, random_index + x); + + } else { + if (mask & GFX_MASK_VISUAL) + _gfxr_auxplot_brush(pic, pic->visual_map->index_data, yoffset, x + offset + j, + 0, color, brush_mode, random_index + x); + + if (mask & GFX_MASK_PRIORITY) + _gfxr_auxplot_brush(pic, pic->priority_map->index_data, yoffset, x + offset + j, + 0, priority, brush_mode, random_index + x); + } + random_index = (random_index + 1) & 0xff; + } + } + yoffset += 320; + } +} + +static void _gfxr_draw_pattern(gfxr_pic_t *pic, int x, int y, int color, int priority, int control, int drawenable, + int pattern_code, int pattern_size, int pattern_nr, gfx_brush_mode_t brush_mode, int sci_titlebar_size) { + int xsize = (pattern_size + 1) * pic->mode->xfact - 1; + int ysize = (pattern_size + 1) * pic->mode->yfact - 1; + int scaled_x, scaled_y; + rect_t boundaries; + int max_x = (pattern_code & PATTERN_FLAG_RECTANGLE) ? 318 : 319; // Rectangles' width is size+1 + + p0printf(stderr, "Pattern at (%d,%d) size %d, rand=%d, code=%02x\n", x, y, pattern_size, pattern_nr, pattern_code); + + y += sci_titlebar_size; + + if (x - pattern_size < 0) + x = pattern_size; + + if (y - pattern_size < sci_titlebar_size) + y = sci_titlebar_size + pattern_size; + + if (x + pattern_size > max_x) + x = max_x - pattern_size; + + if (y + pattern_size > 199) + y = 199 - pattern_size; + + scaled_x = x * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); + scaled_y = y * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); + + if (scaled_x < xsize) + scaled_x = xsize; + + if (scaled_y < ysize + sci_titlebar_size * pic->mode->yfact) + scaled_y = ysize + sci_titlebar_size * pic->mode->yfact; + + if (scaled_x > (320 * pic->mode->xfact) - 1 - xsize) + scaled_x = (320 * pic->mode->xfact) - 1 - xsize; + + if (scaled_y > (200 * pic->mode->yfact) - 1 - ysize) + scaled_y = (200 * pic->mode->yfact) - 1 - ysize; + + if (pattern_code & PATTERN_FLAG_RECTANGLE) { + // Rectangle + boundaries.x = scaled_x - xsize; + boundaries.y = scaled_y - ysize; + boundaries.width = ((xsize + 1) << 1) + 1; + boundaries.height = (ysize << 1) + 1; + + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 0, pattern_nr, drawenable, color, priority, + control, brush_mode, GFX_MASK_CONTROL); + } else { + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 0, PLOT_AUX_PATTERN_NO_RANDOM, drawenable, 0, 0, control, + GFX_BRUSH_MODE_SCALED, GFX_MASK_CONTROL); + + if (drawenable & GFX_MASK_VISUAL) + gfx_draw_box_pixmap_i(pic->visual_map, boundaries, color); + + if (drawenable & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(pic->priority_map, boundaries, priority); + } + + } else { + // Circle + + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, pattern_nr, drawenable, color, priority, + control, brush_mode, GFX_MASK_CONTROL); + } else { + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, + drawenable, 0, 0, control, GFX_BRUSH_MODE_SCALED, GFX_MASK_CONTROL); + + if (pic->mode->xfact == 1 && pic->mode->yfact == 1) { + if (drawenable & GFX_MASK_VISUAL) + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, + drawenable, 0, 0, color, GFX_BRUSH_MODE_SCALED, GFX_MASK_VISUAL); + + if (drawenable & GFX_MASK_PRIORITY) + _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, + drawenable, 0, 0, priority, GFX_BRUSH_MODE_SCALED, GFX_MASK_PRIORITY); + } else { + if (drawenable & GFX_MASK_VISUAL) + _gfxr_fill_ellipse(pic, pic->visual_map->index_data, 320 * pic->mode->xfact, + scaled_x, scaled_y, xsize, ysize, color, ELLIPSE_SOLID); + + if (drawenable & GFX_MASK_PRIORITY) + _gfxr_fill_ellipse(pic, pic->priority_map->index_data, 320 * pic->mode->xfact, + scaled_x, scaled_y, xsize, ysize, priority, ELLIPSE_SOLID); + } + } + } +} + +static void _gfxr_draw_subline(gfxr_pic_t *pic, int x, int y, int ex, int ey, int color, int priority, int drawenable) { + Common::Point start; + Common::Point end; + + start.x = x; + start.y = y; + end.x = ex; + end.y = ey; + + if (ex >= pic->visual_map->index_width || ey >= pic->visual_map->index_height || x < 0 || y < 0) { + fprintf(stderr, "While drawing pic0: INVALID LINE %d,%d,%d,%d\n", + start.x, start.y, end.x, end.y); + return; + } + + if (drawenable & GFX_MASK_VISUAL) + gfx_draw_line_pixmap_i(pic->visual_map, start, end, color); + + if (drawenable & GFX_MASK_PRIORITY) + gfx_draw_line_pixmap_i(pic->priority_map, start, end, priority); + +} + +static void _gfxr_draw_line(gfxr_pic_t *pic, int x, int y, int ex, int ey, int color, + int priority, int control, int drawenable, int line_mode, int cmd, int sci_titlebar_size) { + int scale_x = pic->mode->xfact; + int scale_y = pic->mode->yfact; + int xc, yc; + rect_t line; + int mask; + int partially_white = (drawenable & GFX_MASK_VISUAL) && (((color & 0xf0) == 0xf0) || ((color & 0x0f) == 0x0f)); + + line.x = x; + line.y = y; + line.width = ex - x; + line.height = ey - y; + + if (x > 319 || y > 199 || x < 0 || y < 0 || ex > 319 || ey > 199 || ex < 0 || ey < 0) { + GFXWARN("While building pic: Attempt to draw line (%d,%d) to (%d,%d): cmd was %d\n", x, y, ex, ey, cmd); + return; + } + + y += sci_titlebar_size; + ey += sci_titlebar_size; + + if (drawenable & GFX_MASK_CONTROL) { + p0printf(" ctl:%x", control); + gfx_draw_line_pixmap_i(pic->control_map, Common::Point(x, y), Common::Point(x + line.width, y + line.height), control); + } + + // Calculate everything that is changed to SOLID + mask = drawenable & (((color != 0xff) ? 1 : 0) | ((priority) ? 2 : 0) | ((control) ? 4 : 0)); + + if (mask) { + int mask2 = mask; + if (partially_white) + mask2 = mask &= ~GFX_MASK_VISUAL; + _gfxr_auxbuf_line_draw(pic, line, mask, mask2, sci_titlebar_size); + } + + // Calculate everything that is changed to TRANSPARENT + mask = drawenable & (((color == 0xff) ? 1 : 0) | ((!priority) ? 2 : 0) | ((!control) ? 4 : 0)); + + if (mask) + _gfxr_auxbuf_line_clear(pic, line, ~mask, sci_titlebar_size); + + x *= scale_x; + y *= scale_y; + ex *= scale_x; + ey *= scale_y; + + if (drawenable & GFX_MASK_VISUAL) + p0printf(" col:%02x", color); + + if (drawenable & GFX_MASK_PRIORITY) + p0printf(" pri:%x", priority); + + if (line_mode == GFX_LINE_MODE_FINE) { // Adjust lines to extend over the full visual + x = (x * ((320 + 1) * scale_x - 1)) / (320 * scale_x); + y = (y * ((200 + 1) * scale_y - 1)) / (200 * scale_y); + ex = (ex * ((320 + 1) * scale_x - 1)) / (320 * scale_x); + ey = (ey * ((200 + 1) * scale_y - 1)) / (200 * scale_y); + + _gfxr_draw_subline(pic, x, y, ex, ey, color, priority, drawenable); + } else { + if (x == ex && y == ey) { // Just one single point? + rect_t drawrect; + drawrect.x = x; + drawrect.y = y; + drawrect.width = scale_x; + drawrect.height = scale_y; + + if (drawenable & GFX_MASK_VISUAL) + gfx_draw_box_pixmap_i(pic->visual_map, drawrect, color); + + if (drawenable & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(pic->priority_map, drawrect, priority); + + } else { + int width = scale_x; + int height = scale_y; + int x_offset = 0; + int y_offset = 0; + + if (line_mode == GFX_LINE_MODE_FAST) { + width = (width + 1) >> 1; + height = (height + 1) >> 1; + x_offset = (width >> 1); + y_offset = (height >> 1); + } + + for (xc = 0; xc < width; xc++) + _gfxr_draw_subline(pic, x + xc + x_offset, y + y_offset, ex + xc + x_offset, ey + y_offset, + color, priority, drawenable); + + if (height > 0) + for (xc = 0; xc < width; xc++) + _gfxr_draw_subline(pic, x + xc + x_offset, y + height - 1 + y_offset, + ex + xc + x_offset, ey + height - 1 + y_offset, color, priority, drawenable); + + if (height > 1) { + for (yc = 1; yc < height - 1; yc++) + _gfxr_draw_subline(pic, x + x_offset, y + yc + y_offset, ex + x_offset, ey + yc + y_offset, + color, priority, drawenable); + if (width > 0) + for (yc = 1; yc < height - 1; yc++) + _gfxr_draw_subline(pic, x + width - 1 + x_offset, y + yc + y_offset, + ex + width - 1 + x_offset, ey + yc + y_offset, color, priority, drawenable); + } + } + } + + p0printf("\n"); +} + + +#define IS_FILL_BOUNDARY(x) (((x) & legalmask) != legalcolor) + +#ifdef WITH_PIC_SCALING + +#define TEST_POINT(xx, yy) \ + if (pic->aux_map[(yy) * 320 + (xx)] & FRESH_PAINT) { \ + mpos = (((yy) * 320 * pic->mode->yfact) + (xx)) * pic->mode->xfact; \ + for (iy = 0; iy < pic->mode->yfact; iy++) { \ + for (ix = 0; ix < pic->mode->xfact; ix++) { \ + if (!IS_FILL_BOUNDARY(test_map[mpos + ix])) { \ + *x = ix + (xx) * pic->mode->xfact; \ + *y = iy + (yy) * pic->mode->yfact; \ + return 0; \ + } \ + mpos += linewidth; \ + } \ + } \ + } + +static int _gfxr_find_fill_point(gfxr_pic_t *pic, int min_x, int min_y, int max_x, int max_y, int x_320, + int y_200, int color, int drawenable, int *x, int *y) { + // returns -1 on failure, 0 on success + int linewidth = pic->mode->xfact * 320; + int mpos, ix, iy; + int size_x = (max_x - min_x + 1) >> 1; + int size_y = (max_y - min_y + 1) >> 1; + int mid_x = min_x + size_x; + int mid_y = min_y + size_y; + int max_size = (size_x > size_y) ? size_x : size_y; + int size; + int legalcolor; + int legalmask; + byte *test_map; + *x = x_320 * pic->mode->xfact; + *y = y_200 * pic->mode->yfact; + + if (size_x < 0 || size_y < 0) + return 0; + + if (drawenable & GFX_MASK_VISUAL) { + test_map = pic->visual_map->index_data; + + if ((color & 0xf) == 0xf // When dithering with white, do more + // conservative checks + || (color & 0xf0) == 0xf0) + legalcolor = 0xff; + else + legalcolor = 0xf0; // Only check the second color + + legalmask = legalcolor; + } else if (drawenable & GFX_MASK_PRIORITY) { + test_map = pic->priority_map->index_data; + legalcolor = 0; + legalmask = 0xf; + } else return -3; + + TEST_POINT(x_320, y_200); // Most likely candidate + TEST_POINT(mid_x, mid_y); // Second most likely candidate + + for (size = 1; size <= max_size; size++) { + int i; + + if (size <= size_y) { + int limited_size = (size > size_x) ? size_x : size; + + for (i = mid_x - limited_size; i <= mid_x + limited_size; i++) { + TEST_POINT(i, mid_y - size); + TEST_POINT(i, mid_y + size); + } + } + + if (size <= size_x) { + int limited_size = (size - 1 > size_y) ? size_y : size - 1; + + for (i = mid_y - limited_size; i <= mid_y + limited_size; i++) { + TEST_POINT(mid_x - size, i); + TEST_POINT(mid_x + size, i); + } + } + } + + return -1; +} + +#undef TEST_POINT + +} // End of namespace Sci + +// Now include the actual filling code (with scaling support) +#define FILL_FUNCTION _gfxr_fill_any +#define FILL_FUNCTION_RECURSIVE _gfxr_fill_any_recursive +#define AUXBUF_FILL_HELPER _gfxr_auxbuf_fill_any_recursive +#define AUXBUF_FILL _gfxr_auxbuf_fill_any +#define DRAW_SCALED +# include "picfill.cpp" +#undef DRAW_SCALED +#undef AUXBUF_FILL +#undef AUXBUF_FILL_HELPER +#undef FILL_FUNCTION_RECURSIVE +#undef FILL_FUNCTION + +namespace Sci { + +#endif // defined(WITH_PIC_SCALING) + +} // End of namespace Sci + +// Include again, but this time without support for scaling +#define FILL_FUNCTION _gfxr_fill_1 +#define FILL_FUNCTION_RECURSIVE _gfxr_fill_1_recursive +#define AUXBUF_FILL_HELPER _gfxr_auxbuf_fill_1_recursive +#define AUXBUF_FILL _gfxr_auxbuf_fill_1 +# include "picfill.cpp" +#undef AUXBUF_FILL +#undef AUXBUF_FILL_HELPER +#undef FILL_FUNCTION_RECURSIVE +#undef FILL_FUNCTION + +namespace Sci { + +#define GET_ABS_COORDS(x, y) \ + temp = *(resource + pos++); \ + x = *(resource + pos++); \ + y = *(resource + pos++); \ + x |= (temp & 0xf0) << 4; \ + y |= (temp & 0x0f) << 8; + +#define GET_REL_COORDS(x, y) \ + temp = *(resource + pos++); \ + if (temp & 0x80) \ + x -= ((temp >> 4) & 0x7); \ + else \ + x += (temp >> 4); \ + \ + if (temp & 0x08) \ + y -= (temp & 0x7); \ + else \ + y += (temp & 0x7); + +#define GET_MEDREL_COORDS(oldx, oldy) \ + temp = *(resource + pos++); \ + if (temp & 0x80) \ + y = oldy - (temp & 0x7f); \ + else \ + y = oldy + temp; \ + x = oldx + *((signed char *) resource + pos++); + + +static void check_and_remove_artifact(byte *dest, byte* srcp, int legalcolor, byte l, byte r, byte u, byte d) { + if (*dest == legalcolor) { + if (*srcp == legalcolor) + return; + if (l) { + if (srcp[-1] == legalcolor) + return; + if (u && srcp[-320 - 1] == legalcolor) + return; + if (d && srcp[320 - 1] == legalcolor) + return; + } + if (r) { + if (srcp[1] == legalcolor) + return; + if (u && srcp[-320 + 1] == legalcolor) + return; + if (d && srcp[320 + 1] == legalcolor) + return; + } + + if (u && srcp[-320] == legalcolor) + return; + + if (d && srcp[-320] == legalcolor) + return; + + *dest = *srcp; + } +} + +void gfxr_remove_artifacts_pic0(gfxr_pic_t *dest, gfxr_pic_t *src) { + int x_320, y_200; + int bound_x = dest->mode->xfact; + int bound_y = dest->mode->yfact; + int scaled_line_size = bound_x * 320; + int read_offset = 0; + + assert(src->mode->xfact == 1); + assert(src->mode->yfact == 1); + + if (bound_x == 1 && bound_y == 1) { + GFXWARN("attempt to remove artifacts from unscaled pic!\n"); + return; + } + + for (y_200 = 0; y_200 < 200; y_200++) { + for (x_320 = 0; x_320 < 320; x_320++) { + int write_offset = (y_200 * bound_y * scaled_line_size) + (x_320 * bound_x); + int sub_x, sub_y; + byte *src_visualp = &(src->visual_map->index_data[read_offset]); + byte *src_priorityp = &(src->priority_map->index_data[read_offset]); + + for (sub_y = 0; sub_y < bound_y; sub_y++) { + for (sub_x = 0; sub_x < bound_x; sub_x++) { + check_and_remove_artifact(dest->visual_map->index_data + write_offset, src_visualp, (int)0xff, + (byte)x_320, (byte)(x_320 < 319), (byte)(y_200 > 10), (byte)(y_200 < 199)); + check_and_remove_artifact(dest->priority_map->index_data + write_offset, src_priorityp, 0, + (byte)x_320, (byte)(x_320 < 319), (byte)(y_200 > 10), (byte)(y_200 < 199)); + ++write_offset; + } + write_offset += scaled_line_size - bound_x; + } + ++read_offset; + } + } + +} + +static void view_transparentize(gfx_pixmap_t *view, gfx_pixmap_t *background, int posx, int posy, int width, int height) { + int i, j; + byte *pic_index_data = background->index_data; + + // FIXME: this assumes view and background have the same palette... + // We may want to do a reverse mapping or similar to make it general, + // but this (hopefully...) suffices for the current uses of this function. + + for (i = 0;i < width;i++) + for (j = 0;j < height;j++) { + if (view->index_data[j*width+i] == view->color_key) { + view->index_data[j*width+i] = pic_index_data[(j+posy)*width+i+posx]; + } + } +} + +extern gfx_pixmap_t *gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size, gfxr_view_t *view, int mirrored); +extern gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, int size, gfxr_view_t *view, int amiga_game); +extern void _gfx_crossblit_simple(byte *dest, byte *src, int dest_line_width, int src_line_width, int xl, int yl, int bpp); + +void gfxr_draw_pic01(gfxr_pic_t *pic, int flags, int default_palette, int size, byte *resource, + gfxr_pic0_params_t *style, int resid, int sci1, Palette *static_pal) { + const int default_palette_table[GFXR_PIC0_PALETTE_SIZE] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x88, + 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, + 0x88, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x08, 0x91, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x88 + }; + + const int default_priority_table[GFXR_PIC0_PALETTE_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + int palette[GFXR_PIC0_NUM_PALETTES][GFXR_PIC0_PALETTE_SIZE]; + int priority_table[GFXR_PIC0_PALETTE_SIZE]; + int drawenable = GFX_MASK_VISUAL | GFX_MASK_PRIORITY; + int priority = 0; + int color = 0; + int pattern_nr = 0; + int pattern_code = 0; + int pattern_size = 0; + int control = 0; + int pos = 0; + int x, y; + int oldx, oldy; + int pal, index; + int temp; + int line_mode = style->line_mode; + int sci_titlebar_size = style->pic_port_bounds.y; + byte op, opx; + +#ifdef FILL_RECURSIVE_DEBUG + fillmagc = atoi(getenv("FOO")); + fillc = atoi(getenv("FOO2")); +#endif + + // Initialize palette + for (int i = 0; i < GFXR_PIC0_NUM_PALETTES; i++) + memcpy(palette[i], default_palette_table, sizeof(int) * GFXR_PIC0_PALETTE_SIZE); + + memcpy(priority_table, default_priority_table, sizeof(int) * GFXR_PIC0_PALETTE_SIZE); + + // Main loop + while (pos < size) { + op = *(resource + pos++); + + switch (op) { + + case PIC_OP_SET_COLOR: + p0printf("Set color @%d\n", pos); + + if (!sci1) { + pal = *(resource + pos++); + index = pal % GFXR_PIC0_PALETTE_SIZE; + pal /= GFXR_PIC0_PALETTE_SIZE; + + pal += default_palette; + + if (pal >= GFXR_PIC0_NUM_PALETTES) { + GFXERROR("Attempt to access invalid palette %d\n", pal); + return; + } + + color = palette[pal][index]; + } else + color = *(resource + pos++); + p0printf(" color <- %02x [%d/%d]\n", color, pal, index); + drawenable |= GFX_MASK_VISUAL; + goto end_op_loop; + + case PIC_OP_DISABLE_VISUAL: + p0printf("Disable visual @%d\n", pos); + drawenable &= ~GFX_MASK_VISUAL; + goto end_op_loop; + + case PIC_OP_SET_PRIORITY: + p0printf("Set priority @%d\n", pos); + + if (!sci1) { + pal = *(resource + pos++); + index = pal % GFXR_PIC0_PALETTE_SIZE; + pal /= GFXR_PIC0_PALETTE_SIZE; // Ignore pal + + priority = priority_table[index]; + } else priority = *(resource + pos++); + + p0printf(" priority <- %d [%d/%d]\n", priority, pal, index); + drawenable |= GFX_MASK_PRIORITY; + goto end_op_loop; + + case PIC_OP_DISABLE_PRIORITY: + p0printf("Disable priority @%d\n", pos); + drawenable &= ~GFX_MASK_PRIORITY; + goto end_op_loop; + + case PIC_OP_SHORT_PATTERNS: + p0printf("Short patterns @%d\n", pos); + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; + p0printf(" pattern_nr <- %d\n", pattern_nr); + } + + GET_ABS_COORDS(x, y); + + _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, + pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); + + while (*(resource + pos) < PIC_OP_FIRST) { + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; + p0printf(" pattern_nr <- %d\n", pattern_nr); + } + + GET_REL_COORDS(x, y); + + _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, + pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); + } + goto end_op_loop; + + case PIC_OP_MEDIUM_LINES: + p0printf("Medium lines @%d\n", pos); + GET_ABS_COORDS(oldx, oldy); + while (*(resource + pos) < PIC_OP_FIRST) { +#if 0 + fprintf(stderr, "Medium-line: [%04x] from %d,%d, data %02x %02x (dx=%d)", pos, oldx, oldy, + 0xff & resource[pos], 0xff & resource[pos+1], *((signed char *) resource + pos + 1)); +#endif + GET_MEDREL_COORDS(oldx, oldy); +#if 0 + fprintf(stderr, " to %d,%d\n", x, y); +#endif + _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, + PIC_OP_MEDIUM_LINES, sci_titlebar_size); + oldx = x; + oldy = y; + } + goto end_op_loop; + + case PIC_OP_LONG_LINES: + p0printf("Long lines @%d\n", pos); + GET_ABS_COORDS(oldx, oldy); + while (*(resource + pos) < PIC_OP_FIRST) { + GET_ABS_COORDS(x, y); + _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, + PIC_OP_LONG_LINES, sci_titlebar_size); + oldx = x; + oldy = y; + } + goto end_op_loop; + + case PIC_OP_SHORT_LINES: + p0printf("Short lines @%d\n", pos); + GET_ABS_COORDS(oldx, oldy); + x = oldx; + y = oldy; + while (*(resource + pos) < PIC_OP_FIRST) { + GET_REL_COORDS(x, y); + _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, + PIC_OP_SHORT_LINES, sci_titlebar_size); + oldx = x; + oldy = y; + } + goto end_op_loop; + + case PIC_OP_FILL: + p0printf("Fill @%d\n", pos); + while (*(resource + pos) < PIC_OP_FIRST) { + //fprintf(stderr,"####################\n"); + GET_ABS_COORDS(x, y); + p0printf("Abs coords %d,%d\n", x, y); + //fprintf(stderr,"C=(%d,%d)\n", x, y + sci_titlebar_size); +#ifdef WITH_PIC_SCALING + if (pic->mode->xfact > 1 || pic->mode->yfact > 1) + _gfxr_fill_any(pic, x, y + sci_titlebar_size, (flags & DRAWPIC01_FLAG_FILL_NORMALLY) ? + color : 0, priority, control, drawenable, sci_titlebar_size); + + else +#endif + _gfxr_fill_1(pic, x, y + sci_titlebar_size, (flags & DRAWPIC01_FLAG_FILL_NORMALLY) ? + color : 0, priority, control, drawenable, sci_titlebar_size); + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillmagc) { + int x, y; + if (getenv("FOO1")) + for (x = 0; x < 320; x++) + for (y = 0; y < 200; y++) { + int aux = pic->aux_map[x + y*320]; + int pix = (aux & 0xf); + int i; + + if (aux & 0x40) { + if (x == 0 || !(pic->aux_map[x-1 + y * 320] & 0x40)) + for (i = 0; i < pic->mode->yfact; i++) + pic->visual_map->index_data[(x + ((y*pic->mode->yfact)+i)*320) * pic->mode->xfact] ^= 0xff; + + if (x == 319 || !(pic->aux_map[x+1 + y * 320] & 0x40)) + for (i = 0; i < pic->mode->yfact; i++) + pic->visual_map->index_data[pic->mode->xfact - 1 +(x + ((y*pic->mode->yfact)+i)*320) * pic->mode->xfact] ^= 0xff; + + if (y == 0 || !(pic->aux_map[x + (y-1) * 320] & 0x40)) + for (i = 0; i < pic->mode->yfact; i++) + pic->visual_map->index_data[i+(x + ((y*pic->mode->yfact))*320) * pic->mode->xfact] ^= 0xff; + + if (y == 199 || !(pic->aux_map[x + (y+1) * 320] & 0x40)) + for (i = 0; i < pic->mode->yfact; i++) + pic->visual_map->index_data[i+(x + ((y*pic->mode->yfact)+pic->mode->yfact - 1)*320) * pic->mode->xfact] ^= 0xff; + } + + pix |= (aux & 0x40) >> 4; + pix |= (pix << 4); + + pic->visual_map->index_data[x + y*320*pic->mode->xfact] = pix; + } + return; + } + --fillmagc; +#endif // GFXR_DEBUG_PIC0 + } + goto end_op_loop; + + case PIC_OP_SET_PATTERN: + p0printf("Set pattern @%d\n", pos); + pattern_code = (*(resource + pos++)); + pattern_size = pattern_code & 0x07; + goto end_op_loop; + + case PIC_OP_ABSOLUTE_PATTERN: + p0printf("Absolute pattern @%d\n", pos); + while (*(resource + pos) < PIC_OP_FIRST) { + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; + p0printf(" pattern_nr <- %d\n", pattern_nr); + } + + GET_ABS_COORDS(x, y); + + _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, + pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); + } + goto end_op_loop; + + case PIC_OP_SET_CONTROL: + p0printf("Set control @%d\n", pos); + control = (*(resource + pos++)) & 0xf; + drawenable |= GFX_MASK_CONTROL; + goto end_op_loop; + + + case PIC_OP_DISABLE_CONTROL: + p0printf("Disable control @%d\n", pos); + drawenable &= ~GFX_MASK_CONTROL; + goto end_op_loop; + + + case PIC_OP_MEDIUM_PATTERNS: + p0printf("Medium patterns @%d\n", pos); + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; + p0printf(" pattern_nr <- %d\n", pattern_nr); + } + + GET_ABS_COORDS(oldx, oldy); + + _gfxr_draw_pattern(pic, oldx, oldy, color, priority, control, drawenable, pattern_code, + pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); + + x = oldx; + y = oldy; + while (*(resource + pos) < PIC_OP_FIRST) { + if (pattern_code & PATTERN_FLAG_USE_PATTERN) { + pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; + p0printf(" pattern_nr <- %d\n", pattern_nr); + } + + GET_MEDREL_COORDS(x, y); + + _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, + pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); + } + goto end_op_loop; + + case PIC_OP_OPX: + opx = *(resource + pos++); + p0printf("OPX: "); + + if (sci1) + opx += SCI1_OP_OFFSET; // See comment at the definition of SCI1_OP_OFFSET. + + switch (opx) { + + case PIC_SCI1_OPX_SET_PALETTE_ENTRIES: + GFXWARN("SCI1 Set palette entried not implemented\n"); + goto end_op_loop; + + case PIC_SCI0_OPX_SET_PALETTE_ENTRIES: + p0printf("Set palette entry @%d\n", pos); + while (*(resource + pos) < PIC_OP_FIRST) { + index = *(resource + pos++); + pal = index / GFXR_PIC0_PALETTE_SIZE; + index %= GFXR_PIC0_PALETTE_SIZE; + + if (pal >= GFXR_PIC0_NUM_PALETTES) { + GFXERROR("Attempt to write to invalid palette %d\n", pal); + return; + } + palette[pal][index] = *(resource + pos++); + } + goto end_op_loop; + + case PIC_SCI0_OPX_SET_PALETTE: + p0printf("Set palette @%d\n", pos); + pal = *(resource + pos++); + if (pal >= GFXR_PIC0_NUM_PALETTES) { + GFXERROR("Attempt to write to invalid palette %d\n", pal); + return; + } + + p0printf(" palette[%d] <- (", pal); + for (index = 0; index < GFXR_PIC0_PALETTE_SIZE; index++) { + palette[pal][index] = *(resource + pos++); + if (index > 0) + p0printf(","); + if (!(index & 0x7)) + p0printf("[%d]=", index); + p0printf("%02x", palette[pal][index]); + } + p0printf(")\n"); + goto end_op_loop; + + case PIC_SCI1_OPX_SET_PALETTE: + p0printf("Set palette @%d\n", pos); + if (pic->visual_map->palette) + pic->visual_map->palette->free(); + pic->visual_map->palette = gfxr_read_pal1(resid, + resource + pos, SCI1_PALETTE_SIZE); + pos += SCI1_PALETTE_SIZE; + goto end_op_loop; + + case PIC_SCI0_OPX_MONO0: + p0printf("Monochrome opx 0 @%d\n", pos); + pos += 41; + goto end_op_loop; + + case PIC_SCI0_OPX_MONO1: + case PIC_SCI0_OPX_MONO3: + ++pos; + p0printf("Monochrome opx %d @%d\n", opx, pos); + goto end_op_loop; + + case PIC_SCI0_OPX_MONO2: + case PIC_SCI0_OPX_MONO4: // Monochrome ops: Ignored by us + p0printf("Monochrome opx %d @%d\n", opx, pos); + goto end_op_loop; + + case PIC_SCI0_OPX_EMBEDDED_VIEW: + case PIC_SCI1_OPX_EMBEDDED_VIEW: { + int posx, posy; + int bytesize; + //byte *vismap = pic->visual_map->index_data; + int nodraw = 0; + + gfx_pixmap_t *view; + + p0printf("Embedded view @%d\n", pos); + + GET_ABS_COORDS(posx, posy); + bytesize = (*(resource + pos)) + (*(resource + pos + 1) << 8); + p0printf("(%d, %d)\n", posx, posy); + pos += 2; + if (!sci1 && !nodraw) + view = gfxr_draw_cel0(-1, -1, -1, resource + pos, bytesize, NULL, 0); + else + view = gfxr_draw_cel1(-1, -1, -1, 0, resource + pos, bytesize, NULL, (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR)); + pos += bytesize; + if (nodraw) + continue; + p0printf("(%d, %d)-(%d, %d)\n", posx, posy, posx + view->index_width, posy + view->index_height); + + // we can only safely replace the palette if it's static + // *if it's not for some reason, we should die + + if (view->palette && view->palette->isShared() && !sci1) { + sciprintf("gfx_draw_pic0(): can't set a non-static palette for an embedded view!\n"); + } + + // For SCI0, use special color mapping to copy the low + // nibble of the color index to the high nibble. + + if (sci1) { + if (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR) { + // Assume Amiga game + pic->visual_map->palette = static_pal->getref(); + } + if (view->palette) view->palette->free(); + view->palette = pic->visual_map->palette->copy(); + } else + view->palette = embedded_view_pal->getref(); + + // Hack to prevent overflowing the visual map buffer. + // Yes, this does happen otherwise. + if (view->index_height + sci_titlebar_size > 200) + sci_titlebar_size = 0; + + // Set up mode structure for resizing the view + Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1byte/p, which handles masks and the rest for us + gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, + pic->visual_map->index_height / 200, format, view->palette, 0); + + gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); + gfx_free_mode(mode); + // When the mode is freed, the associated view + // palette is freed too, so set it to NULL + view->palette = NULL; + + if (flags & DRAWPIC01_FLAG_OVERLAID_PIC) + view_transparentize(view, pic->visual_map, posx, sci_titlebar_size + posy, + view->index_width, view->index_height); + + _gfx_crossblit_simple(pic->visual_map->index_data + (sci_titlebar_size * 320) + posy * 320 + posx, + view->index_data, pic->visual_map->index_width, view->index_width, + view->index_width, view->index_height, 1); + + gfx_free_pixmap(view); + view = NULL; + } + goto end_op_loop; + + case PIC_SCI0_OPX_SET_PRIORITY_TABLE: + case PIC_SCI1_OPX_PRIORITY_TABLE_EXPLICIT: { + int *pri_table; + + p0printf("Explicit priority table @%d\n", pos); + if (!pic->priorityTable) { + pic->priorityTable = (int*)sci_malloc(16 * sizeof(int)); + } else { + GFXERROR("pic->priorityTable is not NULL (%p); this only occurs with overlaid pics, otherwise it's a bug", (void *)pic->priorityTable); + } + + pri_table = pic->priorityTable; + + pri_table[0] = 0; + pri_table[15] = 190; + + for (int i = 1; i < 15; i++) + pri_table[i] = resource[pos++]; + } + goto end_op_loop; + + case PIC_SCI1_OPX_PRIORITY_TABLE_EQDIST: { + int first = (int16)READ_LE_UINT16(resource + pos); + int last = (int16)READ_LE_UINT16(resource + pos + 2); + int nr; + int *pri_table; + + if (!pic->priorityTable) { + pic->priorityTable = (int*)sci_malloc(16 * sizeof(int)); + } else { + GFXERROR("pic->priorityTable is not NULL (%p); possible memory corruption", (void *)pic->priorityTable); + } + + pri_table = pic->priorityTable; + + for (nr = 0; nr < 16; nr ++) + pri_table[nr] = SCI0_PRIORITY_BAND_FIRST_14_ZONES(nr); + pos += 4; + goto end_op_loop; + } + + default: + sciprintf("%s L%d: Warning: Unknown opx %02x\n", __FILE__, __LINE__, opx); + return; + } + goto end_op_loop; + + case PIC_OP_TERMINATE: + p0printf("Terminator\n"); + //warning( "ARTIFACT REMOVAL CODE is commented out!") + //_gfxr_vismap_remove_artifacts(); + return; + + default: + GFXWARN("Unknown op %02x\n", op); + return; + } +end_op_loop: {} + } + + GFXWARN("Reached end of pic resource %04x\n", resid); +} + +void gfxr_draw_pic11(gfxr_pic_t *pic, int flags, int default_palette, int size, byte *resource, + gfxr_pic0_params_t *style, int resid, Palette *static_pal) { + int has_bitmap = READ_LE_UINT16(resource + 4); + int vector_data_ptr = READ_LE_UINT16(resource + 16); + int palette_data_ptr = READ_LE_UINT16(resource + 28); + int bitmap_data_ptr = READ_LE_UINT16(resource + 32); + int sci_titlebar_size = style->pic_port_bounds.y; + gfx_pixmap_t *view = NULL; + + if (pic->visual_map->palette) pic->visual_map->palette->free(); + pic->visual_map->palette = gfxr_read_pal11(-1, resource + palette_data_ptr, 1284); + + if (has_bitmap) + view = gfxr_draw_cel11(-1, 0, 0, 0, resource, resource + bitmap_data_ptr, size - bitmap_data_ptr, NULL); + + if (view) { + view->palette = pic->visual_map->palette->getref(); + + // Set up mode structure for resizing the view + Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1 byte/p, which handles masks and the rest for us + gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); + + gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); + gfx_free_mode(mode); + + if (flags & DRAWPIC01_FLAG_OVERLAID_PIC) + view_transparentize(view, pic->visual_map, 0, 0, view->index_width, view->index_height); + + // Hack to prevent overflowing the visual map buffer. + // Yes, this does happen otherwise. + if (view->index_height + sci_titlebar_size > 200) + sci_titlebar_size = 0; + + _gfx_crossblit_simple(pic->visual_map->index_data + sci_titlebar_size*view->index_width, + view->index_data, + pic->visual_map->index_width, view->index_width, + view->index_width, + view->index_height, + 1); + } else { + GFXWARN("No view was contained in SCI1.1 pic resource"); + } + + gfxr_draw_pic01(pic, flags, default_palette, size - vector_data_ptr, resource + vector_data_ptr, style, resid, 1, static_pal); +} + +void gfxr_dither_pic0(gfxr_pic_t *pic, int dmode, int pattern) { + int xl = pic->visual_map->index_width; + int yl = pic->visual_map->index_height; + int xfrob_max = (pattern == GFXR_DITHER_PATTERN_1) ? 1 : pic->mode->xfact; + int yfrob_max = (pattern == GFXR_DITHER_PATTERN_1) ? 1 : pic->mode->yfact; + int xfrobc = 0, yfrobc = 0; + int selection = 0; + int x, y; + byte *data = pic->visual_map->index_data; + + if (dmode == GFXR_DITHER_MODE_F256) + return; // Nothing to do + + if (dmode == GFXR_DITHER_MODE_D16) { // Limit to 16 colors + pic->visual_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); + } + + for (y = 0; y < yl; y++) { + for (x = 0; x < xl; x++) { + + switch (dmode) { + case GFXR_DITHER_MODE_D16: + if (selection) + *data = (*data & 0xf0) >> 4; + else + *data = (*data & 0xf); + break; + + case GFXR_DITHER_MODE_D256: + if (selection) + *data = ((*data & 0xf) << 4) | ((*data & 0xf0) >> 4); + break; + + default: + GFXERROR("Invalid dither mode %d!\n", dmode); + return; + } + + ++data; + + if (++xfrobc == xfrob_max) { + selection = !selection; + xfrobc = 0; + } + } + + if (++yfrobc == yfrob_max) { + selection = !selection; + yfrobc = 0; + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_view0.cpp b/engines/sci/gfx/res_view0.cpp new file mode 100644 index 0000000000..dd01ae4ad0 --- /dev/null +++ b/engines/sci/gfx/res_view0.cpp @@ -0,0 +1,229 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_system.h" +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" + +namespace Sci { + +gfx_pixmap_t *gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size, gfxr_view_t *view, int mirrored) { + int xl = READ_LE_UINT16(resource); + int yl = READ_LE_UINT16(resource + 2); + int xhot = ((signed char *)resource)[4]; + int yhot = ((signed char *)resource)[5]; + int color_key = resource[6]; + int pos = 7; + int writepos = mirrored ? xl : 0; + int pixmap_size = xl * yl; + int line_base = 0; + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + + retval->color_key = 255; // Pick something larger than 15 + + retval->xoffset = mirrored ? xhot : -xhot; + retval->yoffset = -yhot; + + if (view) { + retval->palette = view->palette->getref(); + } else { + retval->palette = gfx_sci0_image_pal[sci0_palette]->getref(); + } + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + if (mirrored) { + while (yl && pos < size) { + int op = resource[pos++]; + int count = op >> 4; + int color = op & 0xf; + + if (view->flags & GFX_PIXMAP_FLAG_PALETTIZED) + color = view->translation[color]; + + if (color == color_key) + color = retval->color_key; + + while (count) { + int pixels = writepos - line_base; + + if (pixels > count) + pixels = count; + + writepos -= pixels; + memset(dest + writepos, color, pixels); + count -= pixels; + + if (writepos == line_base) { + yl--; + writepos += (xl << 1); + line_base += xl; + } + } + } + } else { + + while (writepos < pixmap_size && pos < size) { + int op = resource[pos++]; + int count = op >> 4; + int color = op & 0xf; + + if (view && (view->flags & GFX_PIXMAP_FLAG_PALETTIZED)) + color = view->translation[color]; + + if (color == color_key) + color = retval->color_key; + + if (writepos + count > pixmap_size) { + GFXERROR("View %02x:(%d/%d) writes RLE data over its designated end at rel. offset 0x%04x\n", id, loop, cel, pos); + return NULL; + } + + memset(dest + writepos, color, count); + writepos += count; + } + } + + return retval; +} + +static int gfxr_draw_loop0(gfxr_loop_t *dest, int id, int loop, byte *resource, int offset, int size, gfxr_view_t *view, int mirrored) { + int i; + int cels_nr = READ_LE_UINT16(resource + offset); + + if (READ_LE_UINT16(resource + offset + 2)) { + GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, READ_LE_UINT16(resource + offset + 2)); + } + + if (cels_nr * 2 + 4 + offset > size) { + GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); + dest->cels_nr = 0; /* Mark as "delete no cels" */ + dest->cels = NULL; + return 1; + } + + dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) { + int cel_offset = READ_LE_UINT16(resource + offset + 4 + (i << 1)); + gfx_pixmap_t *cel = NULL; + + if (cel_offset >= size) { + GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); + cel = NULL; + } else + cel = gfxr_draw_cel0(id, loop, i, resource + cel_offset, size - cel_offset, view, mirrored); + + + if (!cel) { + dest->cels_nr = i; + return 1; + } + + dest->cels[i] = cel; + } + + dest->cels_nr = cels_nr; + + return 0; +} + +#define V0_LOOPS_NR_OFFSET 0 +#define V0_FIRST_LOOP_OFFSET 8 +#define V0_MIRROR_LIST_OFFSET 2 + +gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette) { + int i; + gfxr_view_t *view; + int mirror_bitpos = 1; + int mirror_bytepos = V0_MIRROR_LIST_OFFSET; + int palette_ofs = READ_LE_UINT16(resource + 6); + + if (size < V0_FIRST_LOOP_OFFSET + 8) { + GFXERROR("Attempt to draw empty view %04x\n", id); + return NULL; + } + + view = (gfxr_view_t *)sci_malloc(sizeof(gfxr_view_t)); + view->ID = id; + + view->loops_nr = resource[V0_LOOPS_NR_OFFSET]; + + // Set palette + view->flags = 0; + view->palette = gfx_sci0_image_pal[sci0_palette]->getref(); + + if ((palette_ofs) && (palette >= 0)) { + byte *paldata = resource + palette_ofs + (palette * GFX_SCI0_IMAGE_COLORS_NR); + + for (i = 0; i < GFX_SCI0_IMAGE_COLORS_NR; i++) + view->translation[i] = *(paldata++); + + view->flags |= GFX_PIXMAP_FLAG_PALETTIZED; + } + + if (view->loops_nr * 2 + V0_FIRST_LOOP_OFFSET > size) { + GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); + free(view); + return NULL; + } + + view->loops = (gfxr_loop_t*)sci_malloc(sizeof(gfxr_loop_t) * ((view->loops_nr) ? view->loops_nr : 1)); /* Alloc 1 if no loop */ + + for (i = 0; i < view->loops_nr; i++) { + int error_token = 0; + int loop_offset = READ_LE_UINT16(resource + V0_FIRST_LOOP_OFFSET + (i << 1)); + int mirrored = resource[mirror_bytepos] & mirror_bitpos; + + if ((mirror_bitpos <<= 1) == 0x100) { + mirror_bytepos++; + mirror_bitpos = 1; + } + + if (loop_offset >= size) { + GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i, loop_offset); + error_token = 1; + } + + if (error_token || gfxr_draw_loop0(view->loops + i, id, i, resource, loop_offset, size, view, mirrored)) { + // An error occured + view->loops_nr = i; + gfxr_free_view(view); + return NULL; + } + } + + return view; +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/res_view1.cpp b/engines/sci/gfx/res_view1.cpp new file mode 100644 index 0000000000..d743804971 --- /dev/null +++ b/engines/sci/gfx/res_view1.cpp @@ -0,0 +1,513 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + + * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// SCI 1 view resource defrobnicator + +#include "common/endian.h" + +#include "sci/sci_memory.h" +#include "sci/gfx/gfx_system.h" +#include "sci/gfx/gfx_resource.h" +#include "sci/gfx/gfx_tools.h" + +namespace Sci { + +#define V1_LOOPS_NR_OFFSET 0 +#define V1_MIRROR_MASK 2 +#define V1_PALETTE_OFFSET 6 +#define V1_FIRST_LOOP_OFFSET 8 + +#define V1_RLE 0x80 // run-length encode? +#define V1_RLE_BG 0x40 // background fill + +#define NEXT_RUNLENGTH_BYTE(n) \ + if (literal_pos == runlength_pos) \ + literal_pos += n; \ + runlength_pos += n; + +#define NEXT_LITERAL_BYTE(n) \ + if (literal_pos == runlength_pos) \ + runlength_pos += n; \ + literal_pos += n; + +static int decompress_sci_view(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, + int runlength_pos, int literal_pos, int xl, int yl, int color_key) { + int writepos = mirrored ? xl : 0; + + if (mirrored) { + int linebase = 0; + + while (linebase < pixmap_size && literal_pos < size && runlength_pos < size) { + int op = resource[runlength_pos]; + int bytes; + int readbytes = 0; + int color = 0; + + NEXT_RUNLENGTH_BYTE(1); + + if (op & V1_RLE) { + bytes = op & 0x3f; + op &= (V1_RLE | V1_RLE_BG); + readbytes = (op & V1_RLE_BG) ? 0 : 1; + } else { + readbytes = bytes = op & 0x3f; + op = 0; + } + + if (runlength_pos + readbytes > size) { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, readbytes, size - runlength_pos, runlength_pos - 1); + return 1; + } + /* + if (writepos - bytes < 0) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos - bytes, pixmap_size, pos - 1); + bytes = pixmap_size - writepos; + } + */ + if (op == V1_RLE) { + color = resource[literal_pos]; + NEXT_LITERAL_BYTE(1); + } + + if (!op && literal_pos + bytes > size) { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, bytes, size - literal_pos, literal_pos - 1); + return 1; + } + + while (bytes--) { + if (op) { + if (op & V1_RLE_BG) { + writepos--; + *(dest + writepos) = color_key; + } else { + writepos--; + *(dest + writepos) = color; + } + } else { + writepos--; + *(dest + writepos) = *(resource + literal_pos); + NEXT_LITERAL_BYTE(1); + + } + if (writepos == linebase) { + writepos += 2 * xl; + linebase += xl; + } + } + } + } else { + while (writepos < pixmap_size && literal_pos < size && runlength_pos < size) { + int op = resource[runlength_pos]; + int bytes; + int readbytes = 0; + + NEXT_RUNLENGTH_BYTE(1); + + if (op & V1_RLE) { + bytes = op & 0x3f; + op &= (V1_RLE | V1_RLE_BG); + readbytes = (op & V1_RLE_BG) ? 0 : 1; + } else { + readbytes = bytes = op & 0x3f; + op = 0; + } + + if (runlength_pos + readbytes > size) { + return 1; + } + + if (writepos + bytes > pixmap_size) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos - bytes, pixmap_size, runlength_pos - 1); + bytes = pixmap_size - writepos; + } + + if (!op && literal_pos + bytes > size) { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, bytes, size - literal_pos, literal_pos - 1); + return 1; + } + + if (writepos + bytes > pixmap_size) { + GFXWARN("Writing out of bounds: %d bytes at %d > size %d\n", bytes, writepos, pixmap_size); + } + + if (op) { + if (op & V1_RLE_BG) + memset(dest + writepos, color_key, bytes); + else { + int color = resource[literal_pos]; + + NEXT_LITERAL_BYTE(1); + memset(dest + writepos, color, bytes); + } + } else { + memcpy(dest + writepos, resource + literal_pos, bytes); + NEXT_LITERAL_BYTE(bytes); + } + writepos += bytes; + + } + + }; + + return 0; +} + +static int decompress_sci_view_amiga(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, + int pos, int xl, int yl, int color_key) { + int writepos = mirrored ? xl - 1 : 0; + + while (writepos < pixmap_size && pos < size) { + int op = resource[pos++]; + int bytes; + int color; + + if (op & 0x07) { + bytes = op & 0x07; + color = op >> 3; + } else { + bytes = op >> 3; + color = color_key; + } + + if (mirrored) { + while (bytes--) { + dest[writepos--] = color; + // If we've just written the first pixel of a line... + if (!((writepos + 1) % xl)) { + // Then move to the end of next line + writepos += 2 * xl; + + if (writepos >= pixmap_size && bytes) { + GFXWARN("View %02x:(%d/%d) writing out of bounds\n", id, loop, cel); + break; + } + } + } + } else { + if (writepos + bytes > pixmap_size) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos - bytes, pixmap_size, pos - 1); + bytes = pixmap_size - writepos; + } + memset(dest + writepos, color, bytes); + writepos += bytes; + } + } + + if (writepos < pixmap_size) { + GFXWARN("View %02x:(%d/%d) not enough pixel data in view\n", id, loop, cel); + return 1; + } + + return 0; +} + +gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, int size, gfxr_view_t *view, int amiga_game) { + int xl = READ_LE_UINT16(resource); + int yl = READ_LE_UINT16(resource + 2); + int xhot = (int8) resource[4]; + int yhot = (uint8) resource[5]; + int pos = 8; + int pixmap_size = xl * yl; + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + int decompress_failed; + + retval->color_key = resource[6]; + retval->xoffset = (mirrored) ? xhot : -xhot; + retval->yoffset = -yhot; + + if (view) + retval->palette = view->palette->getref(); + else + retval->palette = NULL; + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + if (amiga_game) + decompress_failed = decompress_sci_view_amiga(id, loop, cel, resource, dest, mirrored, pixmap_size, size, pos, + xl, yl, retval->color_key); + else + decompress_failed = decompress_sci_view(id, loop, cel, resource, dest, mirrored, pixmap_size, size, pos, + pos, xl, yl, retval->color_key); + + if (decompress_failed) { + gfx_free_pixmap(retval); + return NULL; + } + + return retval; +} + +static int gfxr_draw_loop1(gfxr_loop_t *dest, int id, int loop, int mirrored, byte *resource, int offset, int size, gfxr_view_t *view, int amiga_game) { + int i; + int cels_nr = READ_LE_UINT16(resource + offset); + + if (READ_LE_UINT16(resource + offset + 2)) { + GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, READ_LE_UINT16(resource + offset + 2)); + } + + if (cels_nr * 2 + 4 + offset > size) { + GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); + dest->cels_nr = 0; // Mark as "delete no cels" + dest->cels = NULL; + return 1; + } + + dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) { + int cel_offset = READ_LE_UINT16(resource + offset + 4 + (i << 1)); + gfx_pixmap_t *cel; + + if (cel_offset >= size) { + GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); + cel = NULL; + } else + cel = gfxr_draw_cel1(id, loop, i, mirrored, resource + cel_offset, size - cel_offset, view, amiga_game); + + if (!cel) { + dest->cels_nr = i; + return 1; + } + + dest->cels[i] = cel; + } + + dest->cels_nr = cels_nr; + + return 0; +} + +#define V1_FIRST_MAGIC 1 +#define V1_MAGICS_NR 5 +//static byte view_magics[V1_MAGICS_NR] = {0x80, 0x00, 0x00, 0x00, 0x00}; + +gfxr_view_t *gfxr_draw_view1(int id, byte *resource, int size, Palette *static_pal) { + int i; + int palette_offset; + gfxr_view_t *view; + int mirror_mask; + int amiga_game = 0; + + if (size < V1_FIRST_LOOP_OFFSET + 8) { + GFXERROR("Attempt to draw empty view %04x\n", id); + return NULL; + } + + view = (gfxr_view_t*)sci_malloc(sizeof(gfxr_view_t)); + view->ID = id; + view->flags = 0; + + view->loops_nr = resource[V1_LOOPS_NR_OFFSET]; + palette_offset = READ_LE_UINT16(resource + V1_PALETTE_OFFSET); + mirror_mask = READ_LE_UINT16(resource + V1_MIRROR_MASK); + + if (view->loops_nr * 2 + V1_FIRST_LOOP_OFFSET > size) { + GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); + free(view); + return NULL; + } + + /* fprintf(stderr, "View flags are 0x%02x\n", resource[3]);*/ + + /* + for (i = 0; i < V1_MAGICS_NR; i++) + if (resource[V1_FIRST_MAGIC + i] != view_magics[i]) { + GFXWARN("View %04x: View magic #%d should be %02x but is %02x\n", id, i, view_magics[i], resource[V1_FIRST_MAGIC + i]); + } + */ + + if (palette_offset > 0) { + if (palette_offset > size) { + GFXERROR("Palette is outside of view %04x\n", id); + free(view); + return NULL; + } + if (!(view->palette = gfxr_read_pal1(id, resource + palette_offset, size - palette_offset))) { + GFXERROR("view %04x: Palette reading failed. Aborting...\n", id); + free(view); + return NULL; + } + } else if (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR) { + // Assume we're running an amiga game. + amiga_game = 1; + view->palette = static_pal->getref(); + } else { + GFXWARN("view %04x: Doesn't have a palette. Can FreeSCI handle this?\n", view->ID); + view->palette = NULL; + } + + view->loops = (gfxr_loop_t*)sci_malloc(sizeof(gfxr_loop_t) * view->loops_nr); + + for (i = 0; i < view->loops_nr; i++) { + int error_token = 0; + int loop_offset = READ_LE_UINT16(resource + V1_FIRST_LOOP_OFFSET + (i << 1)); + + if (loop_offset >= size) { + GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i, loop_offset); + error_token = 1; + } + + if (error_token || gfxr_draw_loop1(view->loops + i, id, i, mirror_mask & (1 << i), resource, loop_offset, size, view, amiga_game)) { + // An error occured + view->loops_nr = i; + gfxr_free_view(view); + return NULL; + } + } + + return view; +} + +#define V2_HEADER_SIZE 0 +#define V2_LOOPS_NUM 2 +#define V2_PALETTE_OFFSET 8 +#define V2_BYTES_PER_LOOP 12 +#define V2_BYTES_PER_CEL 13 + +#define V2_IS_MIRROR 1 +#define V2_COPY_OF_LOOP 2 +#define V2_CELS_NUM 4 +#define V2_LOOP_OFFSET 14 + +#define V2_CEL_WIDTH 0 +#define V2_CEL_HEIGHT 2 +#define V2_X_DISPLACEMENT 4 +#define V2_Y_DISPLACEMENT 6 +#define V2_COLOR_KEY 8 +#define V2_RUNLENGTH_OFFSET 24 +#define V2_LITERAL_OFFSET 28 + +gfx_pixmap_t *gfxr_draw_cel11(int id, int loop, int cel, int mirrored, byte *resource_base, byte *cel_base, int size, gfxr_view_t *view) { + int xl = READ_LE_UINT16(cel_base + V2_CEL_WIDTH); + int yl = READ_LE_UINT16(cel_base + V2_CEL_HEIGHT); + int xdisplace = READ_LE_UINT16(cel_base + V2_X_DISPLACEMENT); + int ydisplace = READ_LE_UINT16(cel_base + V2_Y_DISPLACEMENT); + int runlength_offset = READ_LE_UINT16(cel_base + V2_RUNLENGTH_OFFSET); + int literal_offset = READ_LE_UINT16(cel_base + V2_LITERAL_OFFSET); + int pixmap_size = xl * yl; + + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + int decompress_failed; + + retval->color_key = cel_base[V2_COLOR_KEY]; + retval->xoffset = (mirrored) ? xdisplace : -xdisplace; + retval->yoffset = -ydisplace; + + if (view) + retval->palette = view->palette->getref(); + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + decompress_failed = decompress_sci_view(id, loop, cel, resource_base, dest, mirrored, pixmap_size, size, + runlength_offset, literal_offset, xl, yl, retval->color_key); + + if (decompress_failed) { + gfx_free_pixmap(retval); + return NULL; + } + + return retval; +} + +gfxr_loop_t *gfxr_draw_loop11(int id, int loop, int mirrored, byte *resource_base, byte *loop_base, int size, int cels_nr, + gfxr_loop_t *result, gfxr_view_t *view, int bytes_per_cel) { + byte *seeker = loop_base; + int i; + + result->cels_nr = cels_nr; + result->cels = (gfx_pixmap_t **)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) { + result->cels[i] = gfxr_draw_cel11(id, loop, i, mirrored, resource_base, seeker, size, view); + seeker += bytes_per_cel; + } + + return result; +} + +gfxr_view_t *gfxr_draw_view11(int id, byte *resource, int size) { + gfxr_view_t *view; + int header_size = READ_LE_UINT16(resource + V2_HEADER_SIZE); + int palette_offset = READ_LE_UINT16(resource + V2_PALETTE_OFFSET); + int bytes_per_loop = resource[V2_BYTES_PER_LOOP]; + int loops_num = resource[V2_LOOPS_NUM]; + int bytes_per_cel = resource[V2_BYTES_PER_CEL]; + int i; + byte *seeker; + + view = (gfxr_view_t *)sci_malloc(sizeof(gfxr_view_t)); + + memset(view, 0, sizeof(gfxr_view_t)); + view->ID = id; + view->flags = 0; + + view->loops_nr = loops_num; + view->loops = (gfxr_loop_t *)calloc(view->loops_nr, sizeof(gfxr_loop_t)); + + // There is no indication of size here, but this is certainly large enough + view->palette = gfxr_read_pal11(id, resource + palette_offset, 1284); + + seeker = resource + header_size; + for (i = 0; i < view->loops_nr; i++) { + int loop_offset = READ_LE_UINT16(seeker + V2_LOOP_OFFSET); + int cels = seeker[V2_CELS_NUM]; + int mirrored = seeker[V2_IS_MIRROR]; + int copy_entry = seeker[V2_COPY_OF_LOOP]; + + printf("%d\n", mirrored); + if (copy_entry == 255) + gfxr_draw_loop11(id, i, 0, resource, resource + loop_offset, size, cels, view->loops + i, + view, bytes_per_cel); + else { + byte *temp = resource + header_size + copy_entry * bytes_per_loop; + loop_offset = READ_LE_UINT16(temp + V2_LOOP_OFFSET); + cels = temp[V2_CELS_NUM]; + gfxr_draw_loop11(id, i, 1, resource, resource + loop_offset, size, cels, + view->loops + i, view, bytes_per_cel); + } + + seeker += bytes_per_loop; + } + + return view; +} + +} // End of namespace Sci diff --git a/engines/sci/gfx/resmgr.cpp b/engines/sci/gfx/resmgr.cpp deleted file mode 100644 index 890e5842d2..0000000000 --- a/engines/sci/gfx/resmgr.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -// Resource manager core part - -// FIXME/TODO: The name "(Graphics) resource manager", and the associated -// filenames, are misleading. This should be renamed to "Graphics manager" -// or something like that. - -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" -#include "sci/gfx/gfx_driver.h" -#include "sci/gfx/gfx_resmgr.h" -#include "sci/gfx/gfx_state_internal.h" -#include "sci/gfx/font.h" - -#include "common/system.h" - -namespace Sci { - -// Invalid hash mode: Used to invalidate modified pics -#define MODE_INVALID -1 - -struct param_struct { - int args[4]; - gfx_driver_t *driver; -}; - -#define DRAW_PIC01(pic, picStyle, isSci1) \ - gfxr_draw_pic01((pic), flags, default_palette, res->size, res->data, (picStyle), res->id, (isSci1), state->static_palette); - -#define DRAW_PIC11(pic, picStyle) \ - gfxr_draw_pic11((pic), flags, default_palette, res->size, res->data, (picStyle), res->id, state->static_palette); - -/* Calculate a picture -** Parameters: (gfx_resstate_t *) state: The resource state, containing options and version information -** (gfxr_pic_t *) scaled_pic: The pic structure that is to be written to -** (gfxr_pic_t *) unscaled_pic: The pic structure the unscaled pic is to be written to, -** or NULL if it isn't needed. -** (int) flags: Pic drawing flags (interpreter dependant) -** (int) default_palette: The default palette to use for pic drawing (interpreter dependant) -** (int) nr: pic resource number -** Returns : (int) GFX_ERROR if the resource could not be found, GFX_OK otherwise -*/ -int calculatePic(gfx_resstate_t *state, gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, int flags, int default_palette, int nr) { - Resource *res = state->resManager->findResource(kResourceTypePic, nr, 0); - int need_unscaled = unscaled_pic != NULL; - gfxr_pic0_params_t style, basic_style; - - basic_style.line_mode = GFX_LINE_MODE_CORRECT; - basic_style.brush_mode = GFX_BRUSH_MODE_SCALED; - basic_style.pic_port_bounds = state->options->pic_port_bounds; - - style.line_mode = state->options->pic0_line_mode; - style.brush_mode = state->options->pic0_brush_mode; - style.pic_port_bounds = state->options->pic_port_bounds; - - if (!res || !res->data) - return GFX_ERROR; - - if (need_unscaled) { - if (state->version == SCI_VERSION_1_1) - DRAW_PIC11(unscaled_pic, &basic_style) - else - DRAW_PIC01(unscaled_pic, &basic_style, state->version >= SCI_VERSION_01_VGA) - } - - if (scaled_pic && scaled_pic->undithered_buffer) - memcpy(scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer, scaled_pic->undithered_buffer_size); - - if (state->version == SCI_VERSION_1_1) - DRAW_PIC11(scaled_pic, &style) - else - DRAW_PIC01(scaled_pic, &style, state->version >= SCI_VERSION_01_VGA) - - if (state->version < SCI_VERSION_01_VGA) { - if (need_unscaled) - gfxr_remove_artifacts_pic0(scaled_pic, unscaled_pic); - - if (!scaled_pic->undithered_buffer) - scaled_pic->undithered_buffer = sci_malloc(scaled_pic->undithered_buffer_size); - - memcpy(scaled_pic->undithered_buffer, scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer_size); - - gfxr_dither_pic0(scaled_pic, state->options->pic0_dither_mode, state->options->pic0_dither_pattern); - } - - // Mark default palettes - if (scaled_pic) - scaled_pic->visual_map->loop = default_palette; - - if (unscaled_pic) - unscaled_pic->visual_map->loop = default_palette; - - return GFX_OK; -} - -gfx_resstate_t *gfxr_new_resource_manager(int version, gfx_options_t *options, gfx_driver_t *driver, ResourceManager *resManager) { - gfx_resstate_t *state = new gfx_resstate_t(); - - state->version = version; - state->options = options; - state->driver = driver; - state->resManager = resManager; - state->static_palette = 0; - - state->tag_lock_counter = state->lock_counter = 0; - - return state; -} - -int GfxResManager::getOptionsHash(gfx_resource_type_t type) { - switch (type) { - case GFX_RESOURCE_TYPE_VIEW: - // This should never happen - error("getOptionsHash called on a VIEW resource"); - - case GFX_RESOURCE_TYPE_PIC: - if (_state->version >= SCI_VERSION_01_VGA) - return _state->options->pic_port_bounds.y; - else - return (_state->options->pic0_unscaled) ? 0x10000 : (_state->options->pic0_dither_mode << 12) - | (_state->options->pic0_dither_pattern << 8) | (_state->options->pic0_brush_mode << 4) - | (_state->options->pic0_line_mode); - - case GFX_RESOURCE_TYPE_FONT: - case GFX_RESOURCE_TYPE_CURSOR: - return 0; - - case GFX_RESOURCE_TYPES_NR: - default: - GFXERROR("Invalid resource type: %d\n", type); - return -1; - } -} - -#define FREEALL(freecmd, type) \ - if (resource->scaled_data.type) \ - freecmd(resource->scaled_data.type); \ - resource->scaled_data.type = NULL; \ - if (resource->unscaled_data.type) \ - freecmd(resource->unscaled_data.type); \ - resource->unscaled_data.type = NULL; - -void gfxr_free_resource(gfx_resource_t *resource, int type) { - if (!resource) - return; - - switch (type) { - - case GFX_RESOURCE_TYPE_VIEW: - FREEALL(gfxr_free_view, view); - break; - - case GFX_RESOURCE_TYPE_PIC: - FREEALL(gfxr_free_pic, pic); - break; - - case GFX_RESOURCE_TYPE_FONT: - FREEALL(gfxr_free_font, font); - break; - - case GFX_RESOURCE_TYPE_CURSOR: - FREEALL(gfx_free_pixmap, pointer); - break; - - default: - GFXWARN("Attempt to free invalid resource type %d\n", type); - } - - free(resource); -} - -void GfxResManager::freeAllResources() { - for (int type = 0; type < GFX_RESOURCE_TYPES_NR; ++type) { - for (IntResMap::iterator iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { - gfxr_free_resource(iter->_value, type); - iter->_value = 0; - } - } -} - -void GfxResManager::freeResManager() { - freeAllResources(); - delete _state; -} - -void GfxResManager::freeTaggedResources() { - // Current heuristics: free tagged views and old pics - - IntResMap::iterator iter; - int type; - const int tmp = _state->tag_lock_counter; - - type = GFX_RESOURCE_TYPE_VIEW; - for (iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { - gfx_resource_t *resource = iter->_value; - - if (resource) { - if (resource->lock_sequence_nr < tmp) { - gfxr_free_resource(resource, type); - iter->_value = 0; - } else { - resource->lock_sequence_nr = 0; - } - } - } - - type = GFX_RESOURCE_TYPE_PIC; - for (iter = _state->_resourceMaps[type].begin(); iter != _state->_resourceMaps[type].end(); ++iter) { - gfx_resource_t *resource = iter->_value; - - if (resource) { - if (resource->lock_sequence_nr < 0) { - gfxr_free_resource(resource, type); - iter->_value = 0; - } else { - resource->lock_sequence_nr--; - } - } - } - - _state->tag_lock_counter = 0; -} - -#define XLATE_AS_APPROPRIATE(key, entry) \ - if (maps & key) { \ - if (res->unscaled_data.pic&& (force || !res->unscaled_data.pic->entry->data)) { \ - if (key == GFX_MASK_VISUAL) \ - gfx_get_res_config(options, res->unscaled_data.pic->entry); \ - gfx_xlate_pixmap(res->unscaled_data.pic->entry, mode, filter); \ - } if (scaled && res->scaled_data.pic && (force || !res->scaled_data.pic->entry->data)) { \ - if (key == GFX_MASK_VISUAL) \ - gfx_get_res_config(options, res->scaled_data.pic->entry); \ - gfx_xlate_pixmap(res->scaled_data.pic->entry, mode, filter); \ - } \ - } - -static gfxr_pic_t *gfxr_pic_xlate_common(gfx_resource_t *res, int maps, int scaled, int force, gfx_mode_t *mode, - gfx_xlate_filter_t filter, int endianize, gfx_options_t *options) { - XLATE_AS_APPROPRIATE(GFX_MASK_VISUAL, visual_map); - XLATE_AS_APPROPRIATE(GFX_MASK_PRIORITY, priority_map); - XLATE_AS_APPROPRIATE(GFX_MASK_CONTROL, control_map); - - if (endianize && (maps & GFX_MASK_VISUAL) && res->scaled_data.pic->visual_map) - gfxr_endianness_adjust(res->scaled_data.pic->visual_map, mode); - - return scaled ? res->scaled_data.pic : res->unscaled_data.pic; -} -#undef XLATE_AS_APPROPRIATE - -gfxr_pic_t *GfxResManager::getPic(int num, int maps, int flags, int default_palette, bool scaled) { - gfxr_pic_t *npic = NULL; - IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_PIC]; - gfx_resource_t *res = NULL; - int hash = getOptionsHash(GFX_RESOURCE_TYPE_PIC); - int must_post_process_pic = 0; - int need_unscaled = (_state->driver->mode->xfact != 1 || _state->driver->mode->yfact != 1); - - hash |= (flags << 20) | ((default_palette & 0x7) << 28); - - res = resMap.contains(num) ? resMap[num] : NULL; - - if (!res || res->mode != hash) { - gfxr_pic_t *pic; - gfxr_pic_t *unscaled_pic = NULL; - - if (_state->options->pic0_unscaled) { - need_unscaled = 0; - pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); - } else - pic = gfxr_init_pic(_state->driver->mode, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); - if (!pic) { - GFXERROR("Failed to allocate scaled pic!\n"); - return NULL; - } - - gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); - - if (need_unscaled) { - unscaled_pic = gfxr_init_pic(&mode_1x1_color_index, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num), _state->version >= SCI_VERSION_01_VGA); - if (!unscaled_pic) { - GFXERROR("Failed to allocate unscaled pic!\n"); - return NULL; - } - gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); - } - if (calculatePic(_state, pic, unscaled_pic, flags, default_palette, num)) { - gfxr_free_pic(pic); - if (unscaled_pic) - gfxr_free_pic(unscaled_pic); - return NULL; - } - if (!res) { - res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); - res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, num); - res->lock_sequence_nr = _state->options->buffer_pics_nr; - resMap[num] = res; - } else { - gfxr_free_pic(res->scaled_data.pic); - if (res->unscaled_data.pic) - gfxr_free_pic(res->unscaled_data.pic); - } - - res->mode = hash; - res->scaled_data.pic = pic; - res->unscaled_data.pic = unscaled_pic; - } else { - res->lock_sequence_nr = _state->options->buffer_pics_nr; // Update lock counter - } - - must_post_process_pic = res->scaled_data.pic->visual_map->data == NULL; - // If the pic was only just drawn, we'll have to endianness-adjust it now - - npic = gfxr_pic_xlate_common(res, maps, scaled || _state->options->pic0_unscaled, 0, _state->driver->mode, - _state->options->pic_xlate_filter, 0, _state->options); - - - if (must_post_process_pic) { - gfxr_endianness_adjust(npic->visual_map, _state->driver->mode); - } - - return npic; -} - -static void set_pic_id(gfx_resource_t *res, int id) { - if (res->scaled_data.pic) { - gfxr_pic_t *pic = res->scaled_data.pic; - pic->control_map->ID = id; - pic->priority_map->ID = id; - pic->visual_map->ID = id; - } - - if (res->unscaled_data.pic) { - gfxr_pic_t *pic = res->unscaled_data.pic; - pic->control_map->ID = id; - pic->priority_map->ID = id; - pic->visual_map->ID = id; - } -} - -static int get_pic_id(gfx_resource_t *res) { - if (res->scaled_data.pic) - return res->scaled_data.pic->visual_map->ID; - else - return res->unscaled_data.pic->visual_map->ID; -} - -static void _gfxr_unscale_pixmap_index_data(gfx_pixmap_t *pxm, gfx_mode_t *mode) { - int xmod = mode->xfact; // Step size horizontally - int ymod = pxm->index_width * mode->yfact; // Vertical step size - int maxpos = pxm->index_width * pxm->index_height; - int pos; - byte *dest = pxm->index_data; - - if (!(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)) - return; // It's not scaled! - - for (pos = 0; pos < maxpos; pos += ymod) { - int c; - - for (c = 0; c < pxm->index_width; c += xmod) - *dest++ = pxm->index_data[pos + c]; - // No overwrite since line and offset readers move much faster (proof by in-duction, trivial - // and left to the reader) - } - - pxm->index_width /= mode->xfact; - pxm->index_height /= mode->yfact; - pxm->flags &= ~GFX_PIXMAP_FLAG_SCALED_INDEX; -} - -gfxr_pic_t *GfxResManager::addToPic(int old_nr, int new_nr, int flags, int old_default_palette, int default_palette) { - IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_PIC]; - gfxr_pic_t *pic = NULL; - gfx_resource_t *res = NULL; - int hash = getOptionsHash(GFX_RESOURCE_TYPE_PIC); - int need_unscaled = !(_state->options->pic0_unscaled) && (_state->driver->mode->xfact != 1 || _state->driver->mode->yfact != 1); - - res = resMap.contains(old_nr) ? resMap[old_nr] : NULL; - - if (!res || (res->mode != MODE_INVALID && res->mode != hash)) { - // FIXME: the initialization of the GFX resource manager should - // be pushed up, and it shouldn't occur here - GfxResManager *_gfx = new GfxResManager(_state); - _gfx->getPic(old_nr, 0, flags, old_default_palette, 1); - delete _gfx; - - res = resMap.contains(old_nr) ? resMap[old_nr] : NULL; - - if (!res) { - GFXWARN("Attempt to add pic %d to non-existing pic %d\n", new_nr, old_nr); - return NULL; - } - } - - if (_state->options->pic0_unscaled) // Unscale priority map, if we scaled it earlier - _gfxr_unscale_pixmap_index_data(res->scaled_data.pic->priority_map, _state->driver->mode); - - // The following two operations are needed when returning scaled maps (which is always the case here) - res->lock_sequence_nr = _state->options->buffer_pics_nr; - calculatePic(_state, res->scaled_data.pic, need_unscaled ? res->unscaled_data.pic : NULL, - flags | DRAWPIC01_FLAG_OVERLAID_PIC, default_palette, new_nr); - - res->mode = MODE_INVALID; // Invalidate - - if (_state->options->pic0_unscaled) // Scale priority map again, if needed - res->scaled_data.pic->priority_map = gfx_pixmap_scale_index_data(res->scaled_data.pic->priority_map, _state->driver->mode); - { - int old_ID = get_pic_id(res); - set_pic_id(res, GFXR_RES_ID(GFX_RESOURCE_TYPE_PIC, new_nr)); // To ensure that our graphical translation optoins work properly - pic = gfxr_pic_xlate_common(res, GFX_MASK_VISUAL, 1, 1, _state->driver->mode, _state->options->pic_xlate_filter, 1, _state->options); - set_pic_id(res, old_ID); - } - - return pic; -} - -gfxr_view_t *gfxr_draw_view11(int id, byte *resource, int size); - -gfxr_view_t *GfxResManager::getView(int nr, int *loop, int *cel, int palette) { - IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_VIEW]; - gfx_resource_t *res = NULL; - int hash = palette; - gfxr_view_t *view = NULL; - gfxr_loop_t *loop_data = NULL; - gfx_pixmap_t *cel_data = NULL; - - res = resMap.contains(nr) ? resMap[nr] : NULL; - - if (!res || res->mode != hash) { - Resource *viewRes = _state->resManager->findResource(kResourceTypeView, nr, 0); - if (!viewRes || !viewRes->data) - return NULL; - - int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); - - if (_state->version < SCI_VERSION_01) - view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, -1); - else if (_state->version == SCI_VERSION_01) - view = gfxr_draw_view0(resid, viewRes->data, viewRes->size, palette); - else if (_state->version >= SCI_VERSION_01_VGA && _state->version <= SCI_VERSION_1_LATE) - view = gfxr_draw_view1(resid, viewRes->data, viewRes->size, _state->static_palette); - else if (_state->version >= SCI_VERSION_1_1) - view = gfxr_draw_view11(resid, viewRes->data, viewRes->size); - - if (_state->version >= SCI_VERSION_01_VGA) { - if (!view->palette) { - view->palette = new Palette(_state->static_palette->size()); - view->palette->name = "interpreter_get_view"; - } - - // Palettize view - for (unsigned i = 0; i < MIN(view->palette->size(), _state->static_palette->size()); i++) { - const PaletteEntry& vc = view->palette->getColor(i); - if (vc.r == 0 && vc.g == 0 && vc.b == 0) { - const PaletteEntry& sc = _state->static_palette->getColor(i); - view->palette->setColor(i, sc.r, sc.g, sc.b); - } - } - - } - - if (!res) { - res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); - res->scaled_data.view = NULL; - res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); - res->lock_sequence_nr = _state->tag_lock_counter; - res->mode = hash; - resMap[nr] = res; - } else { - gfxr_free_view(res->unscaled_data.view); - } - - res->mode = hash; - res->unscaled_data.view = view; - - } else { - res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter - view = res->unscaled_data.view; - } - - *loop = CLIP(*loop, 0, view->loops_nr - 1); - - if (*loop < 0) { - GFXWARN("View %d has no loops\n", nr); - return NULL; - } - - loop_data = view->loops + (*loop); - if (loop_data == NULL) { - GFXWARN("Trying to load invalid loop %d of view %d\n", *loop, nr); - return NULL; - } - - *cel = CLIP(*cel, 0, loop_data->cels_nr - 1); - - if (*cel < 0) { - GFXWARN("View %d loop %d has no cels\n", nr, *loop); - return NULL; - } - - cel_data = loop_data->cels[*cel]; - if (loop_data == NULL) { - GFXWARN("Trying to load invalid view/loop/cel %d/%d/%d\n", nr, *loop, *cel); - return NULL; - } - - if (!cel_data->data) { - gfx_get_res_config(_state->options, cel_data); - gfx_xlate_pixmap(cel_data, _state->driver->mode, _state->options->view_xlate_filter); - gfxr_endianness_adjust(cel_data, _state->driver->mode); - } - - return view; -} - -gfx_bitmap_font_t *GfxResManager::getFont(int num, bool scaled) { - IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_FONT]; - gfx_resource_t *res = NULL; - int hash = getOptionsHash(GFX_RESOURCE_TYPE_FONT); - - res = resMap.contains(num) ? resMap[num] : NULL; - - if (!res || res->mode != hash) { - Resource *fontRes = _state->resManager->findResource(kResourceTypeFont, num, 0); - if (!fontRes || !fontRes->data) - return NULL; - - gfx_bitmap_font_t *font = gfxr_read_font(fontRes->id, fontRes->data, fontRes->size); - - if (!res) { - res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); - res->scaled_data.font = NULL; - res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_FONT, num); - res->lock_sequence_nr = _state->tag_lock_counter; - res->mode = hash; - resMap[num] = res; - } else { - gfxr_free_font(res->unscaled_data.font); - } - - res->unscaled_data.font = font; - - return font; - } else { - res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter - if (res->unscaled_data.pointer) - return res->unscaled_data.font; - else - return res->scaled_data.font; - } -} - -gfx_pixmap_t *GfxResManager::getCursor(int num) { - IntResMap &resMap = _state->_resourceMaps[GFX_RESOURCE_TYPE_CURSOR]; - gfx_resource_t *res = NULL; - int hash = getOptionsHash(GFX_RESOURCE_TYPE_CURSOR); - - res = resMap.contains(num) ? resMap[num] : NULL; - - if (!res || res->mode != hash) { - Resource *cursorRes = _state->resManager->findResource(kResourceTypeCursor, num, 0); - if (!cursorRes || !cursorRes->data) - return NULL; - - if (_state->version >= SCI_VERSION_1_1) { - GFXWARN("Attempt to retrieve cursor in SCI1.1 or later\n"); - return NULL; - } - - gfx_pixmap_t *cursor = gfxr_draw_cursor(GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, num), - cursorRes->data, cursorRes->size, _state->version != SCI_VERSION_0); - - if (!cursor) - return NULL; - - if (!res) { - res = (gfx_resource_t *)sci_malloc(sizeof(gfx_resource_t)); - res->scaled_data.pointer = NULL; - res->ID = GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, num); - res->lock_sequence_nr = _state->tag_lock_counter; - res->mode = hash; - resMap[num] = res; - } else { - gfx_free_pixmap(res->unscaled_data.pointer); - } - gfx_get_res_config(_state->options, cursor); - gfx_xlate_pixmap(cursor, _state->driver->mode, _state->options->cursor_xlate_filter); - gfxr_endianness_adjust(cursor, _state->driver->mode); - - res->unscaled_data.pointer = cursor; - - return cursor; - } else { - res->lock_sequence_nr = _state->tag_lock_counter; // Update lock counter - return res->unscaled_data.pointer; - } -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/picfill.cpp b/engines/sci/gfx/resource/picfill.cpp deleted file mode 100644 index eb0e8b36c2..0000000000 --- a/engines/sci/gfx/resource/picfill.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/gfx/gfx_resource.h" - -/* Generic pic filling code, to be included by sci_pic_0.c - * - * - * To use, define the following: - * AUXBUF_FILL: Name of the exported floodfill function - * AUXBUF_FILL_HELPER: Name of the helper function - * FILL_FUNCTION: Name of the exported floodfill function - * FILL_FUNCTION_RECURSIVE: Name of the helper function - * - * Define DRAW_SCALED to support scaled drawing, or leave it out for faster - * processing. - * - */ - -namespace Sci { - -#define CLIPMASK_HARD_BOUND 0x80 /* ensures that we don't re-fill filled stuff */ - -static void AUXBUF_FILL_HELPER(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, - int clipmask, int control, int sci_titlebar_size) { - int xl, xr; - int oldytotal = y * 320; -#ifdef DRAW_SCALED - unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x78; -#else - unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x84; -#endif - - do { - int ytotal = oldytotal + (320 * dy); - int xcont; - int state; - - y += dy; - - if (y < sci_titlebar_size || y > 199) - return; - - xl = old_xl; - if (!(pic->aux_map[ytotal + xl] & clipmask)) { // go left - while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) - --xl; - } else // go right and look for the first valid spot - while ((xl <= old_xr) && (pic->aux_map[ytotal + xl] & clipmask)) - ++xl; - - if (xl > old_xr) // No fillable strip above the last one - return; - - if ((ytotal + xl) < 0) { - fprintf(stderr, "AARGH-%d\n", __LINE__); - BREAKPOINT(); - } - - xr = xl; - while (xr < 320 && !(pic->aux_map[ytotal + xr] & clipmask)) { - pic->aux_map[ytotal + xr] |= fillmask; - ++xr; - } - - if ((ytotal + xr) > 64000) { - fprintf(stderr, "AARGH-%d\n", __LINE__); - BREAKPOINT(); - } - - --xr; - - if (xr < xl) - return; - - // Check whether we need to recurse on branches in the same direction - if ((y > sci_titlebar_size && dy < 0) || (y < 199 && dy > 0)) { - state = 0; - xcont = xr + 1; - while (xcont <= old_xr) { - if (pic->aux_map[ytotal + xcont] & clipmask) - state = 0; - else if (!state) { // recurse - state = 1; - AUXBUF_FILL_HELPER(pic, xcont, old_xr, y - dy, dy, clipmask, control, sci_titlebar_size); - } - ++xcont; - } - } - - // Check whether we need to recurse on backward branches: - // left - if (xl < old_xl - 1) { - state = 0; - for (xcont = old_xl - 1; xcont >= xl; xcont--) { - if (pic->aux_map[oldytotal + xcont] & clipmask) - state = xcont; - else if (state) { // recurse - AUXBUF_FILL_HELPER(pic, xcont, state, y, -dy, clipmask, control, sci_titlebar_size); - state = 0; - } - } - } - - // right - if (xr > old_xr + 1) { - state = 0; - for (xcont = old_xr + 1; xcont <= xr; xcont++) { - if (pic->aux_map[oldytotal + xcont] & clipmask) - state = xcont; - else if (state) { // recurse - AUXBUF_FILL_HELPER(pic, state, xcont, y, -dy, clipmask, control, sci_titlebar_size); - state = 0; - } - } - } - - if ((ytotal + xl) < 0) { - fprintf(stderr, "AARGH-%d\n", __LINE__); - BREAKPOINT() - } - if ((ytotal + xr + 1) > 64000) { - fprintf(stderr, "AARGH-%d\n", __LINE__); - BREAKPOINT(); - } - - if (control) - memset(pic->control_map->index_data + ytotal + xl, control, xr - xl + 1); - - oldytotal = ytotal; - old_xr = xr; - old_xl = xl; - - } while (1); -} - - -static void AUXBUF_FILL(gfxr_pic_t *pic, int x, int y, int clipmask, int control, int sci_titlebar_size) { - // Fills the aux buffer and the control map (if control != 0) - int xl, xr; - int ytotal = y * 320; -#ifdef DRAW_SCALED - unsigned const char fillmask = 0x78; -#else - unsigned const char fillmask = 0x4; -#endif - -#ifndef DRAW_SCALED - if (!control || !(clipmask & 4)) - return; // Without pic scaling, we only do this to fill the control map -#endif - - if (clipmask & 1) - clipmask = 1; // vis - else if (clipmask & 2) - clipmask = 2; // pri - else if (clipmask & 4) - clipmask = 4; // ctl - else return; - -#ifdef DRAW_SCALED - clipmask |= fillmask; // Bits 3-5 -#endif - - if (pic->aux_map[ytotal + x] & clipmask) - return; - - pic->aux_map[ytotal + x] |= fillmask; - - xl = x; - while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) { - --xl; - pic->aux_map[ytotal + xl] |= fillmask; - } - - xr = x; - while ((xr < 319) && !(pic->aux_map[ytotal + xr + 1] & clipmask)) { - ++xr; - pic->aux_map[ytotal + xr] |= fillmask; - } - - clipmask |= CLIPMASK_HARD_BOUND; // Guarantee clipping - - if (control) // Draw the same strip on the control map - memset(pic->control_map->index_data + ytotal + xl, control, xr - xl + 1); - - if (y > sci_titlebar_size) - AUXBUF_FILL_HELPER(pic, xl, xr, y, -1, clipmask, control, sci_titlebar_size); - - if (y < 199) - AUXBUF_FILL_HELPER(pic, xl, xr, y, + 1, clipmask, control, sci_titlebar_size); -} - - -#undef CLIPMASK_HARD_BOUND - - -#ifdef FILL_RECURSIVE_DEBUG -# define PRINT_DEBUG0(s) if (!fillmagc) fprintf(stderr, s) -# define PRINT_DEBUG1(s,p1) if (!fillmagc) fprintf(stderr, s, p1) -# define PRINT_DEBUG4(s,p1,p2,p3,p4) if (!fillmagc) fprintf(stderr, s, p1) -#else -# define PRINT_DEBUG0(s) -# define PRINT_DEBUG1(s,p1) -# define PRINT_DEBUG4(s,p1,p2,p3,p4) -#endif - -#ifdef DRAW_SCALED -# define SCALED_CHECK(x) (x) -# define IS_BOUNDARY(x, y, index) (((index) & legalmask) != legalcolor) -#else -# define SCALED_CHECK(x) 1 -# define IS_BOUNDARY(x, y, index) ( \ - (((x)+(y)) & 1)? /* figure out which part of the mask to use, to simulate dithering */ \ - ((((index)) & ((legalmask) )) != ((legalcolor) & ((legalmask)))) /* odd coordinate */ \ - : ((((index)) & ((legalmask) >> 8)) != ((legalcolor) & ((legalmask) >> 8))) /* even coordinate */ \ - ) -#endif - -static void FILL_FUNCTION_RECURSIVE(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, byte *bounds, - int legalcolor, int legalmask, int color, int priority, int drawenable, int sci_titlebar_size) { - int linewidth = pic->mode->xfact * 320; - int miny = pic->mode->yfact * sci_titlebar_size; - int maxy = pic->mode->yfact * 200; - int xl, xr; - int oldytotal = y * linewidth; -#ifdef DRAW_SCALED - int old_proj_y = -42; - int proj_y; - int proj_ytotal; - int proj_x; - int proj_xl_bound = 0; - int proj_xr_bound = 0; -#endif - - do { - int ytotal = oldytotal + (linewidth * dy); - int xcont; - int state; - - y += dy; - -#ifdef FILL_RECURSIVE_DEBUG - if (!fillc) - return; - else if (!fillmagc) { - --fillc; - } -#endif - - if (y < miny || y >= maxy) { - PRINT_DEBUG0("ABRT on failed initial assertion!\n"); - return; - } -#ifdef DRAW_SCALED - proj_y = y / pic->mode->yfact; - - if (proj_y != old_proj_y) { - // First, find the projected coordinates, unless known already: - proj_ytotal = proj_y * 320; - proj_x = old_xl / pic->mode->xfact; - - proj_xl_bound = proj_x; - if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { - while (proj_xl_bound && pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT) - --proj_xl_bound; - } else { - while (proj_xl_bound < 319 && !(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT)) - ++proj_xl_bound; - - if (proj_xl_bound < 319) - ++proj_xl_bound; - } - - if (proj_xl_bound == 319 - && !(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { - PRINT_DEBUG0("ABRT because proj_xl_bound couldn't be found\n"); - return; - } - - proj_xr_bound = (proj_xl_bound > proj_x) ? proj_xl_bound : proj_x; - while ((proj_xr_bound < 319) - && pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT) - ++proj_xr_bound; - -#ifdef FILL_RECURSIVE_DEBUG - if (!fillmagc) { - fprintf(stderr, "l%d: {%d,%d} | ", proj_y, proj_xl_bound, proj_xr_bound); - pic->aux_map[proj_y*320 + proj_xl_bound] |= 0x2; - pic->aux_map[proj_y*320 + proj_xr_bound] |= 0x2; - } -#endif - - proj_xl_bound *= pic->mode->xfact; - if (proj_xl_bound) - proj_xl_bound -= pic->mode->xfact - 1; - - if (proj_xr_bound < 319) - ++proj_xr_bound; - proj_xr_bound *= pic->mode->xfact; - proj_xr_bound += pic->mode->xfact - 1; - - old_proj_y = proj_y; - } -#else -# define proj_xl_bound 0 -# define proj_xr_bound 319 -#endif - - // Now we have the projected limits, get the real ones: - - xl = (old_xl > proj_xl_bound) ? old_xl : proj_xl_bound; - if (!IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl])) { // go left as far as possible - while (xl > proj_xl_bound && (!IS_BOUNDARY(xl - 1, y + 1, bounds[ytotal + xl - 1]))) - --xl; - } else // go right until the fillable area starts - while (xl < proj_xr_bound && (IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl]))) - ++xl; - - - PRINT_DEBUG1("<%d,", xl); - - if ((xl > proj_xr_bound) - || (xl > old_xr)) { - PRINT_DEBUG0("ABRT because xl > xr_bound\n"); - return; - } - - xr = (xl > old_xl) ? xl : old_xl; - while (xr < proj_xr_bound && (!IS_BOUNDARY(xr + 1, y + 1, bounds[ytotal + xr + 1]))) - ++xr; - - PRINT_DEBUG1("%d> -> ", xr); - - if (IS_BOUNDARY(xl, y + 1, bounds[ytotal + xl])) { - PRINT_DEBUG0("ABRT because xl illegal\n"); - return; - } - -#ifdef DRAW_SCALED - PRINT_DEBUG4("[%d[%d,%d]%d]\n", proj_xl_bound, xl, xr, proj_xr_bound); - - if (xl < proj_xl_bound && xr - 3*pic->mode->xfact < proj_xl_bound) { - PRINT_DEBUG0("ABRT interval left of zone\n"); - return; - } - - if (xr > proj_xr_bound && xl + 3*pic->mode->xfact > proj_xr_bound) { - PRINT_DEBUG0("ABRT because interval right of zone\n"); - return; - } -#endif - - if (drawenable & GFX_MASK_VISUAL) - memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); - - if (drawenable & GFX_MASK_PRIORITY) - memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); - - - // Check whether we need to recurse on branches in the same direction - state = 0; - xcont = xr + 1; - while (xcont <= old_xr) { - if (IS_BOUNDARY(xcont, y + 1, bounds[ytotal + xcont])) - state = xcont; - else if (state) { // recurse - PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); - PRINT_DEBUG4("rec BRANCH %d [%d,%d] l%d\n", dy, state, xcont, y - dy); - - FILL_FUNCTION_RECURSIVE(pic, state, xcont, y - dy, dy, bounds, legalcolor, - legalmask, color, priority, drawenable, sci_titlebar_size); - state = 0; - } - ++xcont; - } - - // Check whether we need to recurse on backward branches: - // left - if (xl < old_xl - 1) { - state = 0; - for (xcont = old_xl - 1; xcont >= xl; xcont--) { - if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) - state = xcont; - else if (state) { // recurse - PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); - PRINT_DEBUG4("rec BACK-LEFT %d [%d,%d] l%d\n", -dy, state, xcont, y); - - FILL_FUNCTION_RECURSIVE(pic, xcont, state, y, -dy, bounds, - legalcolor, legalmask, color, priority, drawenable, - sci_titlebar_size); - state = 0; - } - } - } - - // right - if (xr > old_xr + 1) { - state = 0; - for (xcont = old_xr + 1; xcont <= xr; xcont++) { - if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) - state = xcont; - else if (state) { // recurse - PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); - PRINT_DEBUG4("rec BACK-RIGHT %d [%d,%d] l%d\n", -dy, state, xcont, y); - - FILL_FUNCTION_RECURSIVE(pic, state, xcont, y, -dy, bounds, - legalcolor, legalmask, color, priority, drawenable, - sci_titlebar_size); - state = 0; - } - } - } - - oldytotal = ytotal; - old_xl = xl; - old_xr = xr; - - } while (1); -} - - -static void FILL_FUNCTION(gfxr_pic_t *pic, int x_320, int y_200, int color, int priority, int control, int drawenable, - int sci_titlebar_size) { - int linewidth = pic->mode->xfact * 320; - int x, y; - int xl, xr; - int ytotal; - int bitmask; - byte *bounds = NULL; - int legalcolor, legalmask; -#ifdef DRAW_SCALED - int min_x, min_y, max_x, max_y; -#endif - int original_drawenable = drawenable; // Backup, since we need the unmodified value - // for filling the aux and control map - - // Restrict drawenable not to restrict itself to zero - if (pic->control_map->index_data[y_200 * 320 + x_320] != 0) - drawenable &= ~GFX_MASK_CONTROL; - - if (color == 0xff) - drawenable &= ~GFX_MASK_VISUAL; - - if (priority == 0) { - drawenable &= ~GFX_MASK_PRIORITY; - original_drawenable &= ~GFX_MASK_PRIORITY; - } - - AUXBUF_FILL(pic, x_320, y_200, original_drawenable, (drawenable & GFX_MASK_CONTROL) ? control : 0, - sci_titlebar_size); - -#ifdef DRAW_SCALED - _gfxr_auxbuf_spread(pic, &min_x, &min_y, &max_x, &max_y); - - if (_gfxr_find_fill_point(pic, min_x, min_y, max_x, max_y, x_320, y_200, color, drawenable, &x, &y)) { - //GFXWARN("Could not find scaled fill point, but unscaled fill point was available!\n"); - drawenable &= GFX_MASK_PRIORITY; - if (!drawenable) - _gfxr_auxbuf_propagate_changes(pic, 0); - } -#else - x = x_320; - y = y_200; -#endif - - ytotal = y * linewidth; - - if (!drawenable) - return; - - if (drawenable & GFX_MASK_VISUAL) { - bounds = pic->visual_map->index_data; -#if 0 - // Code disabled, as removing it fixes qg1 pic.095 (unscaled). However, - // it MAY be of relevance to scaled pic drawing... - - if ((color & 0xf) == 0xf // When dithering with white, do more - // conservative checks - || (color & 0xf0) == 0xf0) - legalcolor = 0xff; - else - legalcolor = 0xf0; // Only check the second color -#endif -#ifdef DRAW_SCALED - legalcolor = 0xff; - legalmask = legalcolor; -#else - legalmask = 0x0ff0; - legalcolor = 0xff; -#endif - } else if (drawenable & GFX_MASK_PRIORITY) { - bounds = pic->priority_map->index_data; - legalcolor = 0; - legalmask = 0x0f0f; - } else { - legalcolor = 0; - legalmask = 0x0f0f; - } - - if (!bounds || IS_BOUNDARY(x, y, bounds[ytotal + x])) - return; - - if (bounds) { -#ifdef DRAW_SCALED - int proj_y = y_200; - int proj_ytotal = proj_y * 320; - int proj_x = x_320; - int proj_xl_bound; - int proj_xr_bound; - int proj_xl, proj_xr; - - ytotal = y * linewidth; - - proj_xl_bound = proj_x; - if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { - while (proj_xl_bound && SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT)) - --proj_xl_bound; - } else - while (proj_xl_bound < 319 && SCALED_CHECK(!(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT))) - ++proj_xl_bound; - - proj_xr_bound = (proj_xl_bound > proj_x) ? proj_xl_bound : proj_x; - while ((proj_xr_bound < 319) && SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT)) - ++proj_xr_bound; - - proj_xl = proj_xl_bound; - proj_xr = proj_xr_bound; - - proj_xl_bound *= pic->mode->xfact; - if (proj_xl_bound) - proj_xl_bound -= pic->mode->xfact - 1; - - if (proj_xr_bound < 319) - ++proj_xr_bound; - proj_xr_bound *= pic->mode->xfact; - proj_xr_bound += pic->mode->xfact - 1; -#endif - xl = x; - while (xl > proj_xl_bound && (!IS_BOUNDARY(xl - 1, y, bounds[ytotal + xl -1]))) - --xl; - - while (x < proj_xr_bound && (!IS_BOUNDARY(x + 1, y, bounds[ytotal + x + 1]))) - ++x; - xr = x; - - if (drawenable & GFX_MASK_VISUAL) - memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); - - if (drawenable & GFX_MASK_PRIORITY) - memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); - - FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, -1, bounds, legalcolor, legalmask, color, priority, drawenable, - sci_titlebar_size); - FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, + 1, bounds, legalcolor, legalmask, color, priority, drawenable, - sci_titlebar_size); - } - - // Now finish the aux buffer - bitmask = drawenable & (((color != 0xff) ? 1 : 0) | ((priority) ? 2 : 0) | ((control) ? 4 : 0)); - -#ifdef DRAW_SCALED -# ifdef FILL_RECURSIVE_DEBUG - if (fillmagc) -# endif - _gfxr_auxbuf_propagate_changes(pic, bitmask); -#endif -} - -#undef SCALED_CHECK -#undef IS_BOUNDARY - -#ifndef DRAW_SCALED -# undef proj_xl_bound -# undef proj_xr_bound -#endif - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_cursor.cpp b/engines/sci/gfx/resource/res_cursor.cpp deleted file mode 100644 index 9a109f6ebf..0000000000 --- a/engines/sci/gfx/resource/res_cursor.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* SCI cursor functions */ - -#include "sci/gfx/gfx_system.h" -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" - -namespace Sci { - -#define CURSOR_RESOURCE_SIZE 68 -#define CURSOR_SIZE 16 - -#define GFX_SCI01_CURSOR_COLORS_NR 3 -#define GFX_SCI0_CURSOR_COLORS_NR 2 - -#define GFX_CURSOR_TRANSPARENT 255 - -gfx_pixmap_color_t gfx_sci01_cursor_colors[GFX_SCI01_CURSOR_COLORS_NR] = { - {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x00}, - {GFX_COLOR_INDEX_UNMAPPED, 0xff, 0xff, 0xff}, - {GFX_COLOR_INDEX_UNMAPPED, 0xaa, 0xaa, 0xaa} -}; - -gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, bool isSci01) { - int colors[4] = {0, 1, GFX_CURSOR_TRANSPARENT, 1}; - int line; - byte *data; - gfx_pixmap_t *retval; - - if (isSci01) - colors[3] = 2; - - if (size != CURSOR_RESOURCE_SIZE) { - GFXERROR("Expected resource size of %d, but found %d\n", CURSOR_RESOURCE_SIZE, size); - return NULL; - } - - retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(CURSOR_SIZE, CURSOR_SIZE, id, 0, 0)); - // FIXME: don't copy palette - retval->palette = new Palette(gfx_sci01_cursor_colors, isSci01 ? GFX_SCI01_CURSOR_COLORS_NR : GFX_SCI0_CURSOR_COLORS_NR); - retval->palette->name = "cursor"; - retval->color_key = GFX_CURSOR_TRANSPARENT; - - if (isSci01) { - retval->xoffset = READ_LE_UINT16(resource); - retval->yoffset = READ_LE_UINT16(resource + 2); - } else if (resource[3]) // center - retval->xoffset = retval->yoffset = CURSOR_SIZE / 2; - else - retval->xoffset = retval->yoffset = 0; - - resource += 4; - - data = retval->index_data; - for (line = 0; line < 16; line++) { - int mask_a = READ_LE_UINT16(resource + (line << 1)); - int mask_b = READ_LE_UINT16(resource + 32 + (line << 1)); - int i; - - for (i = 0; i < 16; i++) { - int color_code = ((mask_a << i) & 0x8000) | (((mask_b << i) >> 1) & 0x4000); - *data++ = colors[color_code >> 14]; - } - } - return retval; -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_font.cpp b/engines/sci/gfx/resource/res_font.cpp deleted file mode 100644 index c208fe16f0..0000000000 --- a/engines/sci/gfx/resource/res_font.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_system.h" -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" -#include "sci/gfx/font.h" - -namespace Sci { - -extern int font_counter; - -#define FONT_HEIGHT_OFFSET 4 -#define FONT_MAXCHAR_OFFSET 2 - -static int calc_char(byte *dest, int total_width, int total_height, byte *src, int size) { - int width = src[0]; - int height = src[1]; - int byte_width = (width + 7) >> 3; - int y; - - src += 2; - - if ((width >> 3) > total_width || height > total_height) { - GFXERROR("Weird character: width=%d/%d, height=%d/%d\n", width, total_width, height, total_height); - return GFX_ERROR; - } - - if (byte_width * height + 2 > size) { - GFXERROR("Character extends to %d of %d allowed bytes\n", byte_width * height + 2, size); - return GFX_ERROR; - } - - for (y = 0; y < height; y++) { - memcpy(dest, src, byte_width); - src += byte_width; - dest += total_width; - } - - return GFX_OK; -} - -gfx_bitmap_font_t *gfxr_read_font(int id, byte *resource, int size) { - gfx_bitmap_font_t *font = (gfx_bitmap_font_t*)sci_calloc(sizeof(gfx_bitmap_font_t), 1); - int chars_nr; - int max_width = 0, max_height; - int i; - - ++font_counter; - - if (size < 6) { - GFXERROR("Font %04x size is %d- this is a joke, right?\n", id, size); - gfxr_free_font(font); - return NULL; - } - - font->chars_nr = chars_nr = READ_LE_UINT16(resource + FONT_MAXCHAR_OFFSET); - font->line_height = max_height = READ_LE_UINT16(resource + FONT_HEIGHT_OFFSET); - - if (chars_nr < 0 || chars_nr > 256 || max_height < 0) { - if (chars_nr < 0 || chars_nr > 256) - GFXERROR("Font %04x: Invalid number of characters: %d\n", id, chars_nr); - if (max_height < 0) - GFXERROR("Font %04x: Invalid font height: %d\n", id, max_height); - gfxr_free_font(font); - return NULL; - } - - if (size < 6 + chars_nr * 2) { - GFXERROR("Font %04x: Insufficient space for %d characters in font\n", id, chars_nr); - gfxr_free_font(font); - return NULL; - } - - font->ID = id; - font->widths = (int*)sci_malloc(sizeof(int) * chars_nr); - - for (i = 0; i < chars_nr; i++) { - int offset = READ_LE_UINT16(resource + (i << 1) + 6); - - if (offset >= size) { - GFXERROR("Font %04x: Error: Character 0x%02x is at offset 0x%04x (beyond 0x%04x)\n", id, i, offset, size); - gfxr_free_font(font); - return NULL; - } - - if ((resource[offset]) > max_width) - max_width = resource[offset]; - if ((resource[offset + 1]) > max_height) - max_height = resource[offset + 1]; - - font->widths[i] = resource[offset]; - } - - font->height = max_height; - font->row_size = (max_width + 7) >> 3; - - if (font->row_size == 3) - font->row_size = 4; - - if (font->row_size > 4) - font->row_size = (font->row_size + 3) & ~3; - - font->char_size = font->row_size * max_height; - font->data = (byte *)sci_calloc(font->char_size, chars_nr); - - for (i = 0; i < chars_nr; i++) { - int offset = READ_LE_UINT16(resource + (i << 1) + 6); - - if (calc_char(font->data + (font->char_size * i), font->row_size, max_height, resource + offset, size - offset)) { - GFXERROR("Problem occured in font %04x, char %d/%d\n", id, i, chars_nr); - gfxr_free_font(font); - return NULL; - } - } - - return font; -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_pal.cpp b/engines/sci/gfx/resource/res_pal.cpp deleted file mode 100644 index 74fb8629b7..0000000000 --- a/engines/sci/gfx/resource/res_pal.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -/* SCI1 palette resource defrobnicator */ - -#include "common/file.h" -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_system.h" -#include "sci/gfx/gfx_resource.h" - -namespace Sci { - -#define MAX_COLORS 256 -#define PALETTE_START 260 -#define COLOR_OK 0x01 - -#define SCI_PAL_FORMAT_VARIABLE_FLAGS 0 -#define SCI_PAL_FORMAT_CONSTANT_FLAGS 1 - -Palette *gfxr_read_pal11(int id, byte *resource, int size) { - int start_color = resource[25]; - int format = resource[32]; - int entry_size = 0; - Palette *retval; - byte *pal_data = resource + 37; - int _colors_nr = READ_LE_UINT16(resource + 29); - int i; - - switch (format) { - case SCI_PAL_FORMAT_VARIABLE_FLAGS : - entry_size = 4; - break; - case SCI_PAL_FORMAT_CONSTANT_FLAGS : - entry_size = 3; - break; - } - - retval = new Palette(_colors_nr + start_color); - char buf[100]; - sprintf(buf, "read_pal11 (id %d)", id); - retval->name = buf; - - for (i = 0; i < start_color; i ++) { - retval->setColor(i, 0, 0, 0); - } - for (i = start_color; i < start_color + _colors_nr; i ++) { - switch (format) { - case SCI_PAL_FORMAT_CONSTANT_FLAGS: - retval->setColor(i, pal_data[0], pal_data[1], pal_data[2]); - break; - case SCI_PAL_FORMAT_VARIABLE_FLAGS: - retval->setColor(i, pal_data[1], pal_data[2], pal_data[3]); - break; - } - pal_data += entry_size; - } - - return retval; -} - -Palette *gfxr_read_pal1(int id, byte *resource, int size) { - int counter = 0; - int pos; - unsigned int colors[MAX_COLORS] = {0}; - - if (size < PALETTE_START + 4) { - GFXERROR("Palette resource too small in %04x\n", id); - return NULL; - } - - pos = PALETTE_START; - - while (pos < size/* && resource[pos] == COLOR_OK && counter < MAX_COLORS*/) { - int color = resource[pos] | (resource[pos + 1] << 8) | (resource[pos + 2] << 16) | (resource[pos + 3] << 24); - - pos += 4; - - colors[counter++] = color; - } - - if (counter < MAX_COLORS && resource[pos] != COLOR_OK) { - GFXERROR("Palette %04x uses unknown palette color prefix 0x%02x at offset 0x%04x\n", id, resource[pos], pos); - return NULL; - } - - if (counter < MAX_COLORS) { - GFXERROR("Palette %04x ends prematurely\n", id); - return NULL; - } - - Palette *retval = new Palette(counter); - char buf[100]; - sprintf(buf, "read_pal1 (id %d)", id); - retval->name = buf; - - for (pos = 0; pos < counter; pos++) { - unsigned int color = colors[pos]; - retval->setColor(pos, (color >> 8) & 0xff, (color >> 16) & 0xff, (color >> 24) & 0xff); - } - - return retval; -} - -Palette *gfxr_read_pal1_amiga(Common::File &file) { - int i; - Palette *retval = new Palette(32); - - for (i = 0; i < 32; i++) { - int b1, b2; - - b1 = file.readByte(); - b2 = file.readByte(); - - if (b1 == EOF || b2 == EOF) { - GFXERROR("Palette file ends prematurely\n"); - return NULL; - } - - retval->setColor(i, (b1 & 0xf) * 0x11, ((b2 & 0xf0) >> 4) * 0x11, (b2 & 0xf) * 0x11); - } - - return retval; -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_pic.cpp b/engines/sci/gfx/resource/res_pic.cpp deleted file mode 100644 index f9f56e4ce9..0000000000 --- a/engines/sci/gfx/resource/res_pic.cpp +++ /dev/null @@ -1,1881 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include // for time() to seed rand() via srand() -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" - -namespace Sci { - -#undef GFXR_DEBUG_PIC0 // Enable to debug pic0 messages -#undef FILL_RECURSIVE_DEBUG // Enable for verbose fill debugging - -#define GFXR_PIC0_PALETTE_SIZE 40 -#define GFXR_PIC0_NUM_PALETTES 4 - -#define INTERCOL(a, b) ((int) sqrt((((3.3 * (a))*(a)) + ((1.7 * (b))*(b))) / 5.0)) -// Macro for color interpolation - -#define SCI0_MAX_PALETTE 2 - -int sci0_palette = 0; - -// Copied from include/kernel.h -#define SCI0_PRIORITY_BAND_FIRST_14_ZONES(nr) ((((nr) == 0)? 0 : \ - ((first) + (((nr)-1) * (last - first)) / 14))) - -// Default color maps -gfx_pixmap_color_t gfx_sci0_image_colors[SCI0_MAX_PALETTE+1][GFX_SCI0_IMAGE_COLORS_NR] = { - {{GFX_COLOR_SYSTEM, 0x00, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0x00, 0xaa}, - {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0xaa}, - {GFX_COLOR_SYSTEM, 0xaa, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0x00, 0xaa}, - {GFX_COLOR_SYSTEM, 0xaa, 0x55, 0x00}, {GFX_COLOR_SYSTEM, 0xaa, 0xaa, 0xaa}, - {GFX_COLOR_SYSTEM, 0x55, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0x55, 0xff}, - {GFX_COLOR_SYSTEM, 0x55, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0xff, 0xff}, - {GFX_COLOR_SYSTEM, 0xff, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0x55, 0xff}, - {GFX_COLOR_SYSTEM, 0xff, 0xff, 0x55}, {GFX_COLOR_SYSTEM, 0xff, 0xff, 0xff}}, // "Normal" EGA - - - {{GFX_COLOR_SYSTEM, 0x00, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0x00, 0xff}, - {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0x00}, {GFX_COLOR_SYSTEM, 0x00, 0xaa, 0xaa}, - {GFX_COLOR_SYSTEM, 0xce, 0x00, 0x00}, {GFX_COLOR_SYSTEM, 0xbe, 0x71, 0xde}, - {GFX_COLOR_SYSTEM, 0x8d, 0x50, 0x00}, {GFX_COLOR_SYSTEM, 0xbe, 0xbe, 0xbe}, - {GFX_COLOR_SYSTEM, 0x55, 0x55, 0x55}, {GFX_COLOR_SYSTEM, 0x00, 0xbe, 0xff}, - {GFX_COLOR_SYSTEM, 0x00, 0xce, 0x55}, {GFX_COLOR_SYSTEM, 0x55, 0xff, 0xff}, - {GFX_COLOR_SYSTEM, 0xff, 0x9d, 0x8d}, {GFX_COLOR_SYSTEM, 0xff, 0x55, 0xff}, - {GFX_COLOR_SYSTEM, 0xff, 0xff, 0x00}, {GFX_COLOR_SYSTEM, 0xff, 0xff, 0xff}}, // AGI Amiga-ish - -// RGB and I intensities (former taken from the GIMP) -#define GR 30 -#define GG 59 -#define GB 11 -#define GI 15 - -#define FULL (GR+GG+GB+GI) - -#define CC(x) (((x)*255)/FULL),(((x)*255)/FULL),(((x)*255)/FULL) // Combines color intensities - - {{GFX_COLOR_SYSTEM, CC(0) }, {GFX_COLOR_SYSTEM, CC(GB) }, - {GFX_COLOR_SYSTEM, CC(GG) }, {GFX_COLOR_SYSTEM, CC(GB + GG) }, - {GFX_COLOR_SYSTEM, CC(GR) }, {GFX_COLOR_SYSTEM, CC(GB + GR) }, - {GFX_COLOR_SYSTEM, CC(GG + GR) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GR) }, - {GFX_COLOR_SYSTEM, CC(GI) }, {GFX_COLOR_SYSTEM, CC(GB + GI) }, - {GFX_COLOR_SYSTEM, CC(GG + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GI) }, - {GFX_COLOR_SYSTEM, CC(GR + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GR + GI) }, - {GFX_COLOR_SYSTEM, CC(GG + GR + GI) }, {GFX_COLOR_SYSTEM, CC(GB + GG + GR + GI) }} -}; // Grayscale - -#undef GR -#undef GG -#undef GB -#undef GI - -#undef FULL - -#undef C2 -#undef C3 -#undef C4 - -Palette* gfx_sci0_pic_colors = 0; // Initialized during initialization -Palette* gfx_sci0_image_pal[SCI0_MAX_PALETTE+1]; -Palette* embedded_view_pal = 0; - -#define SCI1_PALETTE_SIZE 1284 - -#ifdef FILL_RECURSIVE_DEBUG -/************************************/ -int fillc = 100000000; -int fillmagc = 30000000; -/************************************/ -#endif - -// Color mapping used while scaling embedded views. -gfx_pixmap_color_t embedded_view_colors[16] = { - {0x00, 0, 0, 0}, {0x11, 0, 0, 0}, {0x22, 0, 0, 0}, {0x33, 0, 0, 0}, - {0x44, 0, 0, 0}, {0x55, 0, 0, 0}, {0x66, 0, 0, 0}, {0x77, 0, 0, 0}, - {0x88, 0, 0, 0}, {0x99, 0, 0, 0}, {0xaa, 0, 0, 0}, {0xbb, 0, 0, 0}, - {0xcc, 0, 0, 0}, {0xdd, 0, 0, 0}, {0xee, 0, 0, 0}, {0xff, 0, 0, 0} -}; - -void gfxr_init_static_palette() { - if (!gfx_sci0_pic_colors) { - gfx_sci0_pic_colors = new Palette(256); - gfx_sci0_pic_colors->name = "gfx_sci0_pic_colors"; - for (int i = 0; i < 256; i++) { - byte r = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].r, - gfx_sci0_image_colors[sci0_palette][i >> 4].r); - byte g = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].g, - gfx_sci0_image_colors[sci0_palette][i >> 4].g); - byte b = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].b, - gfx_sci0_image_colors[sci0_palette][i >> 4].b); - gfx_sci0_pic_colors->setColor(i,r,g,b); - } - //warning("Uncomment me after fixing sci0_palette changes to reset me"); - //_gfxr_pic0_colors_initialized = 1; - - for (int i = 0; i <= SCI0_MAX_PALETTE; ++i) { - gfx_sci0_image_pal[i] = new Palette(gfx_sci0_image_colors[i], GFX_SCI0_IMAGE_COLORS_NR); - gfx_sci0_image_pal[i]->name = "gfx_sci0_image_pal[i]"; - } - - embedded_view_pal = new Palette(embedded_view_colors, 16); - embedded_view_pal->name = "embedded_view_pal"; - } -} - - -gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, int sci1) { - gfxr_pic_t *pic = (gfxr_pic_t*)sci_malloc(sizeof(gfxr_pic_t)); - - pic->mode = mode; - - pic->control_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, ID, 2, 0)); - - pic->priority_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(mode->xfact * 320, mode->yfact * 200, - ID, 1, 0)); - - - pic->visual_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * mode->xfact, - 200 * mode->yfact, ID, 0, 0)); - - // Initialize colors - if (!sci1) { - pic->ID = ID; - gfxr_init_static_palette(); - } - - pic->visual_map->palette = gfx_sci0_pic_colors->getref(); - pic->visual_map->color_key = GFX_PIXMAP_COLOR_KEY_NONE; - - pic->visual_map->flags = 0; - pic->priority_map->flags = 0; - pic->control_map->flags = 0; - if (mode->xfact > 1 || mode->yfact > 1) { - pic->visual_map->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; - pic->priority_map->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; - } - - pic->priority_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); - pic->control_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); - - pic->undithered_buffer_size = pic->visual_map->index_width * pic->visual_map->index_height; - pic->undithered_buffer = NULL; - pic->priorityTable = NULL; - - return pic; -} - -// Pic rendering operations - -void gfxr_clear_pic0(gfxr_pic_t *pic, int sci_titlebar_size) { - memset(pic->visual_map->index_data, 0x00, (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact)); - memset(pic->visual_map->index_data + (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact), - 0xff, pic->mode->xfact * 320 * pic->mode->yfact * (200 - sci_titlebar_size)); // white - memset(pic->priority_map->index_data + (320 * pic->mode->xfact * sci_titlebar_size * pic->mode->yfact), - 0x0, pic->mode->xfact * 320 * pic->mode->yfact * (200 - sci_titlebar_size)); - memset(pic->priority_map->index_data, 0x0a, sci_titlebar_size * (pic->mode->yfact * 320 * pic->mode->xfact)); - memset(pic->control_map->index_data, 0, GFXR_AUX_MAP_SIZE); - memset(pic->aux_map, 0, GFXR_AUX_MAP_SIZE); -} - - -//** Basic operations on the auxiliary buffer ** - -#define FRESH_PAINT 0x40 -// freshly filled or near to something that is - -#define LINEMACRO(startx, starty, deltalinear, deltanonlinear, linearvar, nonlinearvar, \ - linearend, nonlinearstart, linearmod, nonlinearmod, operation) \ - x = (startx); y = (starty); \ - incrNE = ((deltalinear) > 0)? (deltalinear) : -(deltalinear); \ - incrNE <<= 1; \ - deltanonlinear <<= 1; \ - incrE = ((deltanonlinear) > 0) ? -(deltanonlinear) : (deltanonlinear); \ - d = nonlinearstart-1; \ - while (linearvar != (linearend)) { \ - buffer[linewidth * y + x] operation color; \ -/* color ^= color2; color2 ^= color; color ^= color2; */ /* Swap colors */ \ - linearvar += linearmod; \ - if ((d+=incrE) < 0) { \ - d += incrNE; \ - nonlinearvar += nonlinearmod; \ - }; \ - }; \ - buffer[linewidth * y + x] operation color; - -static void _gfxr_auxbuf_line_draw(gfxr_pic_t *pic, rect_t line, int color, int color2, int sci_titlebar_size) { - int dx, dy, incrE, incrNE, d, finalx, finaly; - int x = line.x; - int y = line.y + sci_titlebar_size; - unsigned char *buffer = pic->aux_map; - int linewidth = 320; - - dx = line.width; - dy = line.height; - finalx = x + dx; - finaly = y + dy; - - dx = abs(dx); - dy = abs(dy); - - if (dx > dy) { - if (finalx < x) { - if (finaly < y) { // llu == left-left-up - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, -1, |=); - } else { // lld - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, 1, |=); - } - } else { // x1 >= x - if (finaly < y) { // rru - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, -1, |=); - } else { // rrd - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, 1, |=); - } - } - } else { // dx <= dy - if (finaly < y) { - if (finalx < x) { // luu - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, -1, |=); - } else { // ruu - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, 1, |=); - } - } else { // y1 >= y - if (finalx < x) { // ldd - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, -1, |=); - } else { // rdd - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, 1, |=); - } - } - } -} - -static void _gfxr_auxbuf_line_clear(gfxr_pic_t *pic, rect_t line, int color, int sci_titlebar_size) { - int dx, dy, incrE, incrNE, d, finalx, finaly; - int x = line.x; - int y = line.y + sci_titlebar_size; - unsigned char *buffer = pic->aux_map; - int linewidth = 320; - - dx = line.width; - dy = line.height; - finalx = x + dx; - finaly = y + dy; - - dx = abs(dx); - dy = abs(dy); - - if (dx > dy) { - if (finalx < x) { - if (finaly < y) { // llu == left-left-up - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, -1, &=); - } else { // lld - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -1, 1, &=); - } - } else { // x1 >= x - if (finaly < y) { // rru - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, -1, &=); - } else { // rrd - LINEMACRO(x, y, dx, dy, x, y, finalx, dx, 1, 1, &=); - } - } - } else { // dx <= dy - if (finaly < y) { - if (finalx < x) { // luu - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, -1, &=); - } else { // ruu - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, 1, &=); - } - } else { // y1 >= y - if (finalx < x) { // ldd - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, -1, &=); - } else { // rdd - LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, 1, &=); - } - } - } -} - -#undef LINEMACRO - -#ifdef WITH_PIC_SCALING -static void _gfxr_auxbuf_propagate_changes(gfxr_pic_t *pic, int bitmask) { - // Propagates all filled bits into the planes described by bitmask - unsigned long *data = (unsigned long *)pic->aux_map; - unsigned long clearmask = 0x07070707; - unsigned long andmask = (bitmask << 3) | (bitmask << (3 + 8)) | (bitmask << (3 + 16)) | (bitmask << (3 + 24)); - - if (sizeof(unsigned long) == 8) { // UltraSparc, Alpha, newer MIPSens, etc - andmask |= (andmask << 32); - clearmask |= (clearmask << 32); - } - - for (int i = 0; i < GFXR_AUX_MAP_SIZE / sizeof(unsigned long); i++) { - unsigned long temp = *data & andmask; - temp >>= 3; - *data = (temp | *data) & clearmask; - ++data; - } -} -#endif - - -#if 0 -// Unreferenced - removed -static void _gfxr_auxbuf_tag_line(gfxr_pic_t *pic, int pos, int width) { - for (int i = 0; i < width; i++) - pic->aux_map[i+pos] |= FRESH_PAINT; -} - -// Unreferenced - removed -static void _gfxr_auxbuf_spread(gfxr_pic_t *pic, int *min_x, int *min_y, int *max_x, int *max_y) { - // Tries to spread by approximating the first derivation of the border function. - // Draws to the current and the last line, thus taking up to twice as long as neccessary. - // Other than that, it's O(n^2) - - int intervals_nr = 0, old_intervals_nr; - int x, y, i, pos = 10 * 320; - struct interval_struct { - int xl, xr, tag; - } intervals[2][160]; - - *max_x = *max_y = -1; - *min_x = *min_y = 320; - -#ifdef FILL_RECURSIVE_DEBUG - if (!fillmagc) { - fprintf(stderr, "------------------------------------------------\n"); - fprintf(stderr, "LineID: "); - for (i = 0; i < 5; i++) - fprintf(stderr, " %d ", i); - fprintf(stderr, "\n"); - } -#endif - - for (y = 10; y < 200; y++) { - int ivi = y & 1; // InterVal Index: Current intervals; !ivi is the list of old ones - int old_intervals_start_offset = 0; - int width = 0; - - old_intervals_nr = intervals_nr; - intervals_nr = 0; - - for (x = 0; x < 321; x++) - if (x < 320 && pic->aux_map[pos+x] & 0x10) - width++; - else if (width) { // Found one interval - int xl = x - width; - int xr = x - 1; - int done = 0; - int found_interval = 0; - - intervals[ivi][intervals_nr].width = xl; - intervals[ivi][intervals_nr].tag = 0; - intervals[ivi][intervals_nr++].xr = xr; - - if (xl < *min_x) - *min_x = xl; - if (xr > *max_x) - *max_x = xr; - - i = old_intervals_start_offset; - while (!done && i < old_intervals_nr) { - if (intervals[!ivi][i].width > xr + 1) - done = 1; - - else if (intervals[!ivi][i].xr < xl - 1) { - int o_xl = intervals[!ivi][i].width; - int o_xr = intervals[!ivi][i].xr; - if (o_xr == o_xl && !intervals[!ivi][i].tag) { // thin bar - memcpy(intervals[ivi] + intervals_nr, intervals[ivi] + intervals_nr - 1, sizeof(struct interval_struct)); - memcpy(intervals[ivi] + intervals_nr - 1, intervals[!ivi] + i, sizeof(struct interval_struct)); - intervals[!ivi][i].tag = 1; - pic->aux_map[pos - 320 + o_xl] |= FRESH_PAINT; - ++intervals_nr; - } - - old_intervals_start_offset = i; - } else { - int k = i; - int old_xl = intervals[!ivi][i].width; - int dwidth_l = abs(old_xl - xl); - int old_xr, dwidth_r; - int write_left_width, write_right_width; - - intervals[!ivi][i].tag = 1; - while (k + 1 < old_intervals_nr && intervals[!ivi][k+1].width <= xr) { - ++k; - intervals[!ivi][i].tag = 1; - } - - old_xr = intervals[!ivi][k].xr; - dwidth_r = abs(old_xr - xr); - - // Current line - write_left_width = (dwidth_l > xl) ? xl : dwidth_l; - _gfxr_auxbuf_tag_line(pic, pos + xl - write_left_width, write_left_width); - - write_right_width = (dwidth_r + xr > 319) ? 320 - xr : dwidth_r; - _gfxr_auxbuf_tag_line(pic, pos + xr, write_right_width); - - if (xl - write_left_width < *min_x) - *min_x = xl - write_left_width; - if (xr + write_right_width > *max_x) - *max_x = xr + write_right_width; - - // Previous line - write_left_width = (dwidth_l > old_xl) ? old_xl : dwidth_l; - write_right_width = (dwidth_r + old_xr > 319) ? 320 - old_xr : dwidth_r; - - if (i == k) { // Only one predecessor interval - _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xl - write_left_width, write_left_width); - _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xr, write_right_width); - } else // Fill entire line - _gfxr_auxbuf_tag_line(pic, pos - 320 + old_xl - write_left_width, old_xr - old_xl - + 1 + write_left_width + write_right_width); - - if (xl - write_left_width < *min_x) - *min_x = xl - write_left_width; - if (xr + write_right_width > *max_x) - *max_x = xr + write_right_width; - - found_interval = done = 1; - } - i++; - } - width = 0; - } - -#ifdef FILL_RECURSIVE_DEBUG - if (!fillmagc && intervals_nr) { - fprintf(stderr, "AI L#%03d:", y); - for (int j = 0; j < intervals_nr; j++) - fprintf(stderr, "%c[%03d,%03d]", intervals[ivi][j].tag ? ' ' : '-', intervals[ivi][j].width, intervals[ivi][j].xr); - fprintf(stderr, "\n"); - } -#endif - - if (intervals_nr) { - if (y < *min_y) - *min_y = y; - *max_y = y; - } - - pos += 320; - } - - for (pos = 320 * 200 - 1; pos >= 320; pos--) - if (pic->aux_map[pos - 320] & 0x40) - pic->aux_map[pos] |= 0x40; - - if (*max_y < 199) - (*max_y)++; -} - -#endif - - -/*** Regular drawing operations ***/ - -#define PATTERN_FLAG_RECTANGLE 0x10 -#define PATTERN_FLAG_USE_PATTERN 0x20 - -#define PIC_OP_FIRST 0xf0 - -enum { - PIC_OP_SET_COLOR = 0xf0, - PIC_OP_DISABLE_VISUAL = 0xf1, - PIC_OP_SET_PRIORITY = 0xf2, - PIC_OP_DISABLE_PRIORITY = 0xf3, - PIC_OP_SHORT_PATTERNS = 0xf4, - PIC_OP_MEDIUM_LINES = 0xf5, - PIC_OP_LONG_LINES = 0xf6, - PIC_OP_SHORT_LINES = 0xf7, - PIC_OP_FILL = 0xf8, - PIC_OP_SET_PATTERN = 0xf9, - PIC_OP_ABSOLUTE_PATTERN = 0xfa, - PIC_OP_SET_CONTROL = 0xfb, - PIC_OP_DISABLE_CONTROL = 0xfc, - PIC_OP_MEDIUM_PATTERNS = 0xfd, - PIC_OP_OPX = 0xfe, - PIC_OP_TERMINATE = 0xff -}; - -enum { - PIC_SCI0_OPX_SET_PALETTE_ENTRIES = 0, - PIC_SCI0_OPX_SET_PALETTE = 1, - PIC_SCI0_OPX_MONO0 = 2, - PIC_SCI0_OPX_MONO1 = 3, - PIC_SCI0_OPX_MONO2 = 4, - PIC_SCI0_OPX_MONO3 = 5, - PIC_SCI0_OPX_MONO4 = 6, - PIC_SCI0_OPX_EMBEDDED_VIEW, - PIC_SCI0_OPX_SET_PRIORITY_TABLE -}; - -// We use this so we can keep OPX handling in one switch. -// We simply add this constant to the op number if we're running an SCI1 game, -// and offset the OPX constants below correspondingly. -#define SCI1_OP_OFFSET 42 - -enum { - PIC_SCI1_OPX_SET_PALETTE_ENTRIES = 0 + SCI1_OP_OFFSET, - PIC_SCI1_OPX_EMBEDDED_VIEW = 1 + SCI1_OP_OFFSET, - PIC_SCI1_OPX_SET_PALETTE = 2 + SCI1_OP_OFFSET, - PIC_SCI1_OPX_PRIORITY_TABLE_EQDIST = 3 + SCI1_OP_OFFSET, - PIC_SCI1_OPX_PRIORITY_TABLE_EXPLICIT = 4 + SCI1_OP_OFFSET -}; - - -#ifdef GFXR_DEBUG_PIC0 -#define p0printf sciprintf -#else -void do_nothing(...) { } -#define p0printf do_nothing -#endif - -enum { - ELLIPSE_SOLID, // Normal filled ellipse - ELLIPSE_OR // color ORred to the buffer -}; - -static void _gfxr_fill_ellipse(gfxr_pic_t *pic, byte *buffer, int linewidth, int x, int y, - int rad_x, int rad_y, int color, int fillstyle) { - int xx = 0, yy = rad_y; - int i, x_i, y_i; - int xr = 2 * rad_x * rad_x; - int yr = 2 * rad_y * rad_y; - - x_i = 1; - y_i = xr * rad_y - 1; - i = y_i >> 1; - - while (yy >= 0) { - int oldxx = xx; - int oldyy = yy; - - if (i >= 0) { - x_i += yr; - i -= x_i + 1; - ++xx; - } - - if (i < 0) { - y_i -= xr; - i += y_i - 1; - --yy; - } - - if (oldyy != yy) { - int j; - int offset0 = (y - oldyy) * linewidth; - int offset1 = (y + oldyy) * linewidth; - - offset0 += x - oldxx; - offset1 += x - oldxx; - - if (oldyy == 0) - offset1 = 0; // We never have to draw ellipses in the menu bar - - oldyy = yy; - - switch (fillstyle) { - - case ELLIPSE_SOLID: - memset(buffer + offset0, color, (oldxx << 1) + 1); - if (offset1) - memset(buffer + offset1, color, (oldxx << 1) + 1); - break; - - case ELLIPSE_OR: - for (j = 0; j < (oldxx << 1) + 1; j++) { - buffer[offset0 + j] |= color; - if (offset1) - buffer[offset1 + j] |= color; - } - break; - - default: - fprintf(stderr, "%s L%d: Invalid ellipse fill mode!\n", __FILE__, __LINE__); - return; - - } - } - } -} - -static void _gfxr_auxplot_brush(gfxr_pic_t *pic, byte *buffer, int yoffset, int offset, int plot, - int color, gfx_brush_mode_t brush_mode, int randseed) { - // yoffset 63680, offset 320, plot 1, color 34, brush_mode 0, randseed 432)*/ - // Auxplot: Used by plot_aux_pattern to plot to visual and priority - int xc, yc; - int line_width = 320 * pic->mode->xfact; - int full_offset = (yoffset * pic->mode->yfact + offset) * pic->mode->xfact; - - if (yoffset + offset >= 64000) { - BREAKPOINT(); - } - - switch (brush_mode) { - case GFX_BRUSH_MODE_SCALED: - if (plot) - for (yc = 0; yc < pic->mode->yfact; yc++) { - memset(buffer + full_offset, color, pic->mode->xfact); - full_offset += line_width; - } - break; - - case GFX_BRUSH_MODE_ELLIPSES: - if (plot) { - int x = offset * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); - int y = (yoffset / 320) * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); - - _gfxr_fill_ellipse(pic, buffer, line_width, x, y, pic->mode->xfact >> 1, pic->mode->yfact >> 1, color, ELLIPSE_SOLID); - } - break; - - case GFX_BRUSH_MODE_RANDOM_ELLIPSES: - if (plot) { - int x = offset * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); - int y = (yoffset / 320) * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); - int sizex = pic->mode->xfact >> 1; - int sizey = pic->mode->yfact >> 1; - - srand(randseed); - - x -= (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); - x += (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); - y -= (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); - y += (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); - sizex = (int)((sizex * rand() * 1.0) / (RAND_MAX + 1.0)); - sizey = (int)((sizey * rand() * 1.0) / (RAND_MAX + 1.0)); - - _gfxr_fill_ellipse(pic, buffer, line_width, x, y, pic->mode->xfact >> 1, pic->mode->yfact >> 1, - color, ELLIPSE_SOLID); - srand(time(NULL)); // Make sure we don't accidently forget to re-init the random number generator - } - break; - - case GFX_BRUSH_MODE_MORERANDOM: { - int mask = plot ? 7 : 1; - srand(randseed); - for (yc = 0; yc < pic->mode->yfact; yc++) { - for (xc = 0; xc < pic->mode->xfact; xc++) - if ((rand() & 7) < mask) - buffer[full_offset + xc] = color; - full_offset += line_width; - } - srand(time(NULL)); // Make sure we don't accidently forget to re-init the random number generator - } - break; - } -} - -#define PLOT_AUX_PATTERN_NO_RANDOM -1 - -static void _gfxr_plot_aux_pattern(gfxr_pic_t *pic, int x, int y, int size, int circle, int random, - int mask, int color, int priority, int control, gfx_brush_mode_t brush_mode, int map_nr) { - // Plots an appropriate pattern to the aux buffer and the control buffer, - // if mask & GFX_MASK_CONTROL - // random should be set to the random index, or -1 to disable - - // These circle offsets uniquely identify the circles used by Sierra: - int circle_data[][8] = { - {0}, - {1, 0}, - {2, 2, 1}, - {3, 3, 2, 1}, - {4, 4, 4, 3, 1}, - {5, 5, 4, 4, 3, 1}, - {6, 6, 6, 5, 5, 4, 2}, - {7, 7, 7, 6, 6, 5, 4, 2} - }; - - // 'Random' fill patterns, provided by Carl Muckenhoupt: - byte random_data[32] = { - 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, 0x82, 0x09, 0x0a, 0x22, - 0x12, 0x10, 0x42, 0x14, 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, - 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 - }; - - // 'Random' fill offsets, provided by Carl Muckenhoupt: - byte random_offset[128] = { - 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, - 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, - 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, - 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, - 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, - 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, - 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, - 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, - 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, - 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, - 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, - 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, - 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, - 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, - 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 - }; - - int offset = 0, width = 0; - int yoffset = (y - size) * 320; - int i; - int random_index = 0; - gfx_pixmap_t *map = NULL; - - switch (map_nr) { - case GFX_MASK_VISUAL: - map = pic->visual_map; - break; - case GFX_MASK_PRIORITY: - map = pic->priority_map; - break; - default: - map = pic->control_map; - break; - } - - if (random >= 0) - random_index = random_offset[random]; - - if (!circle) { - offset = -size; - width = (size << 1) + 2; - } - - for (i = -size; i <= size; i++) { - int j; - int height; - - if (circle) { - offset = circle_data[size][abs(i)]; - height = width = (offset << 1) + 1; - offset = -offset; - } else - height = width - 1; - - if (random == PLOT_AUX_PATTERN_NO_RANDOM) { - - if (mask & map_nr) - memset(map->index_data + yoffset + offset + x, control, width); - - if (map_nr == GFX_MASK_CONTROL) - for (j = x; j < x + width; j++) - pic->aux_map[yoffset + offset + j] |= mask; - - } else { // Semi-Random! - for (j = 0; j < height; j++) { - if (random_data[random_index >> 3] & (0x80 >> (random_index & 7))) { - // The 'seemingly' random decision - if (mask & GFX_MASK_CONTROL) - pic->control_map->index_data[yoffset + x + offset + j] = control; - - pic->aux_map[yoffset + x + offset + j] |= mask; - - if (mask & GFX_MASK_VISUAL) - _gfxr_auxplot_brush(pic, pic->visual_map->index_data, yoffset, x + offset + j, - 1, color, brush_mode, random_index + x); - - if (mask & GFX_MASK_PRIORITY) - _gfxr_auxplot_brush(pic, pic->priority_map->index_data, yoffset, x + offset + j, - 1, priority, brush_mode, random_index + x); - - } else { - if (mask & GFX_MASK_VISUAL) - _gfxr_auxplot_brush(pic, pic->visual_map->index_data, yoffset, x + offset + j, - 0, color, brush_mode, random_index + x); - - if (mask & GFX_MASK_PRIORITY) - _gfxr_auxplot_brush(pic, pic->priority_map->index_data, yoffset, x + offset + j, - 0, priority, brush_mode, random_index + x); - } - random_index = (random_index + 1) & 0xff; - } - } - yoffset += 320; - } -} - -static void _gfxr_draw_pattern(gfxr_pic_t *pic, int x, int y, int color, int priority, int control, int drawenable, - int pattern_code, int pattern_size, int pattern_nr, gfx_brush_mode_t brush_mode, int sci_titlebar_size) { - int xsize = (pattern_size + 1) * pic->mode->xfact - 1; - int ysize = (pattern_size + 1) * pic->mode->yfact - 1; - int scaled_x, scaled_y; - rect_t boundaries; - int max_x = (pattern_code & PATTERN_FLAG_RECTANGLE) ? 318 : 319; // Rectangles' width is size+1 - - p0printf(stderr, "Pattern at (%d,%d) size %d, rand=%d, code=%02x\n", x, y, pattern_size, pattern_nr, pattern_code); - - y += sci_titlebar_size; - - if (x - pattern_size < 0) - x = pattern_size; - - if (y - pattern_size < sci_titlebar_size) - y = sci_titlebar_size + pattern_size; - - if (x + pattern_size > max_x) - x = max_x - pattern_size; - - if (y + pattern_size > 199) - y = 199 - pattern_size; - - scaled_x = x * pic->mode->xfact + ((pic->mode->xfact - 1) >> 1); - scaled_y = y * pic->mode->yfact + ((pic->mode->yfact - 1) >> 1); - - if (scaled_x < xsize) - scaled_x = xsize; - - if (scaled_y < ysize + sci_titlebar_size * pic->mode->yfact) - scaled_y = ysize + sci_titlebar_size * pic->mode->yfact; - - if (scaled_x > (320 * pic->mode->xfact) - 1 - xsize) - scaled_x = (320 * pic->mode->xfact) - 1 - xsize; - - if (scaled_y > (200 * pic->mode->yfact) - 1 - ysize) - scaled_y = (200 * pic->mode->yfact) - 1 - ysize; - - if (pattern_code & PATTERN_FLAG_RECTANGLE) { - // Rectangle - boundaries.x = scaled_x - xsize; - boundaries.y = scaled_y - ysize; - boundaries.width = ((xsize + 1) << 1) + 1; - boundaries.height = (ysize << 1) + 1; - - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 0, pattern_nr, drawenable, color, priority, - control, brush_mode, GFX_MASK_CONTROL); - } else { - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 0, PLOT_AUX_PATTERN_NO_RANDOM, drawenable, 0, 0, control, - GFX_BRUSH_MODE_SCALED, GFX_MASK_CONTROL); - - if (drawenable & GFX_MASK_VISUAL) - gfx_draw_box_pixmap_i(pic->visual_map, boundaries, color); - - if (drawenable & GFX_MASK_PRIORITY) - gfx_draw_box_pixmap_i(pic->priority_map, boundaries, priority); - } - - } else { - // Circle - - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, pattern_nr, drawenable, color, priority, - control, brush_mode, GFX_MASK_CONTROL); - } else { - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, - drawenable, 0, 0, control, GFX_BRUSH_MODE_SCALED, GFX_MASK_CONTROL); - - if (pic->mode->xfact == 1 && pic->mode->yfact == 1) { - if (drawenable & GFX_MASK_VISUAL) - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, - drawenable, 0, 0, color, GFX_BRUSH_MODE_SCALED, GFX_MASK_VISUAL); - - if (drawenable & GFX_MASK_PRIORITY) - _gfxr_plot_aux_pattern(pic, x, y, pattern_size, 1, PLOT_AUX_PATTERN_NO_RANDOM, - drawenable, 0, 0, priority, GFX_BRUSH_MODE_SCALED, GFX_MASK_PRIORITY); - } else { - if (drawenable & GFX_MASK_VISUAL) - _gfxr_fill_ellipse(pic, pic->visual_map->index_data, 320 * pic->mode->xfact, - scaled_x, scaled_y, xsize, ysize, color, ELLIPSE_SOLID); - - if (drawenable & GFX_MASK_PRIORITY) - _gfxr_fill_ellipse(pic, pic->priority_map->index_data, 320 * pic->mode->xfact, - scaled_x, scaled_y, xsize, ysize, priority, ELLIPSE_SOLID); - } - } - } -} - -static void _gfxr_draw_subline(gfxr_pic_t *pic, int x, int y, int ex, int ey, int color, int priority, int drawenable) { - Common::Point start; - Common::Point end; - - start.x = x; - start.y = y; - end.x = ex; - end.y = ey; - - if (ex >= pic->visual_map->index_width || ey >= pic->visual_map->index_height || x < 0 || y < 0) { - fprintf(stderr, "While drawing pic0: INVALID LINE %d,%d,%d,%d\n", - start.x, start.y, end.x, end.y); - return; - } - - if (drawenable & GFX_MASK_VISUAL) - gfx_draw_line_pixmap_i(pic->visual_map, start, end, color); - - if (drawenable & GFX_MASK_PRIORITY) - gfx_draw_line_pixmap_i(pic->priority_map, start, end, priority); - -} - -static void _gfxr_draw_line(gfxr_pic_t *pic, int x, int y, int ex, int ey, int color, - int priority, int control, int drawenable, int line_mode, int cmd, int sci_titlebar_size) { - int scale_x = pic->mode->xfact; - int scale_y = pic->mode->yfact; - int xc, yc; - rect_t line; - int mask; - int partially_white = (drawenable & GFX_MASK_VISUAL) && (((color & 0xf0) == 0xf0) || ((color & 0x0f) == 0x0f)); - - line.x = x; - line.y = y; - line.width = ex - x; - line.height = ey - y; - - if (x > 319 || y > 199 || x < 0 || y < 0 || ex > 319 || ey > 199 || ex < 0 || ey < 0) { - GFXWARN("While building pic: Attempt to draw line (%d,%d) to (%d,%d): cmd was %d\n", x, y, ex, ey, cmd); - return; - } - - y += sci_titlebar_size; - ey += sci_titlebar_size; - - if (drawenable & GFX_MASK_CONTROL) { - p0printf(" ctl:%x", control); - gfx_draw_line_pixmap_i(pic->control_map, Common::Point(x, y), Common::Point(x + line.width, y + line.height), control); - } - - // Calculate everything that is changed to SOLID - mask = drawenable & (((color != 0xff) ? 1 : 0) | ((priority) ? 2 : 0) | ((control) ? 4 : 0)); - - if (mask) { - int mask2 = mask; - if (partially_white) - mask2 = mask &= ~GFX_MASK_VISUAL; - _gfxr_auxbuf_line_draw(pic, line, mask, mask2, sci_titlebar_size); - } - - // Calculate everything that is changed to TRANSPARENT - mask = drawenable & (((color == 0xff) ? 1 : 0) | ((!priority) ? 2 : 0) | ((!control) ? 4 : 0)); - - if (mask) - _gfxr_auxbuf_line_clear(pic, line, ~mask, sci_titlebar_size); - - x *= scale_x; - y *= scale_y; - ex *= scale_x; - ey *= scale_y; - - if (drawenable & GFX_MASK_VISUAL) - p0printf(" col:%02x", color); - - if (drawenable & GFX_MASK_PRIORITY) - p0printf(" pri:%x", priority); - - if (line_mode == GFX_LINE_MODE_FINE) { // Adjust lines to extend over the full visual - x = (x * ((320 + 1) * scale_x - 1)) / (320 * scale_x); - y = (y * ((200 + 1) * scale_y - 1)) / (200 * scale_y); - ex = (ex * ((320 + 1) * scale_x - 1)) / (320 * scale_x); - ey = (ey * ((200 + 1) * scale_y - 1)) / (200 * scale_y); - - _gfxr_draw_subline(pic, x, y, ex, ey, color, priority, drawenable); - } else { - if (x == ex && y == ey) { // Just one single point? - rect_t drawrect; - drawrect.x = x; - drawrect.y = y; - drawrect.width = scale_x; - drawrect.height = scale_y; - - if (drawenable & GFX_MASK_VISUAL) - gfx_draw_box_pixmap_i(pic->visual_map, drawrect, color); - - if (drawenable & GFX_MASK_PRIORITY) - gfx_draw_box_pixmap_i(pic->priority_map, drawrect, priority); - - } else { - int width = scale_x; - int height = scale_y; - int x_offset = 0; - int y_offset = 0; - - if (line_mode == GFX_LINE_MODE_FAST) { - width = (width + 1) >> 1; - height = (height + 1) >> 1; - x_offset = (width >> 1); - y_offset = (height >> 1); - } - - for (xc = 0; xc < width; xc++) - _gfxr_draw_subline(pic, x + xc + x_offset, y + y_offset, ex + xc + x_offset, ey + y_offset, - color, priority, drawenable); - - if (height > 0) - for (xc = 0; xc < width; xc++) - _gfxr_draw_subline(pic, x + xc + x_offset, y + height - 1 + y_offset, - ex + xc + x_offset, ey + height - 1 + y_offset, color, priority, drawenable); - - if (height > 1) { - for (yc = 1; yc < height - 1; yc++) - _gfxr_draw_subline(pic, x + x_offset, y + yc + y_offset, ex + x_offset, ey + yc + y_offset, - color, priority, drawenable); - if (width > 0) - for (yc = 1; yc < height - 1; yc++) - _gfxr_draw_subline(pic, x + width - 1 + x_offset, y + yc + y_offset, - ex + width - 1 + x_offset, ey + yc + y_offset, color, priority, drawenable); - } - } - } - - p0printf("\n"); -} - - -#define IS_FILL_BOUNDARY(x) (((x) & legalmask) != legalcolor) - -#ifdef WITH_PIC_SCALING - -#define TEST_POINT(xx, yy) \ - if (pic->aux_map[(yy) * 320 + (xx)] & FRESH_PAINT) { \ - mpos = (((yy) * 320 * pic->mode->yfact) + (xx)) * pic->mode->xfact; \ - for (iy = 0; iy < pic->mode->yfact; iy++) { \ - for (ix = 0; ix < pic->mode->xfact; ix++) { \ - if (!IS_FILL_BOUNDARY(test_map[mpos + ix])) { \ - *x = ix + (xx) * pic->mode->xfact; \ - *y = iy + (yy) * pic->mode->yfact; \ - return 0; \ - } \ - mpos += linewidth; \ - } \ - } \ - } - -static int _gfxr_find_fill_point(gfxr_pic_t *pic, int min_x, int min_y, int max_x, int max_y, int x_320, - int y_200, int color, int drawenable, int *x, int *y) { - // returns -1 on failure, 0 on success - int linewidth = pic->mode->xfact * 320; - int mpos, ix, iy; - int size_x = (max_x - min_x + 1) >> 1; - int size_y = (max_y - min_y + 1) >> 1; - int mid_x = min_x + size_x; - int mid_y = min_y + size_y; - int max_size = (size_x > size_y) ? size_x : size_y; - int size; - int legalcolor; - int legalmask; - byte *test_map; - *x = x_320 * pic->mode->xfact; - *y = y_200 * pic->mode->yfact; - - if (size_x < 0 || size_y < 0) - return 0; - - if (drawenable & GFX_MASK_VISUAL) { - test_map = pic->visual_map->index_data; - - if ((color & 0xf) == 0xf // When dithering with white, do more - // conservative checks - || (color & 0xf0) == 0xf0) - legalcolor = 0xff; - else - legalcolor = 0xf0; // Only check the second color - - legalmask = legalcolor; - } else if (drawenable & GFX_MASK_PRIORITY) { - test_map = pic->priority_map->index_data; - legalcolor = 0; - legalmask = 0xf; - } else return -3; - - TEST_POINT(x_320, y_200); // Most likely candidate - TEST_POINT(mid_x, mid_y); // Second most likely candidate - - for (size = 1; size <= max_size; size++) { - int i; - - if (size <= size_y) { - int limited_size = (size > size_x) ? size_x : size; - - for (i = mid_x - limited_size; i <= mid_x + limited_size; i++) { - TEST_POINT(i, mid_y - size); - TEST_POINT(i, mid_y + size); - } - } - - if (size <= size_x) { - int limited_size = (size - 1 > size_y) ? size_y : size - 1; - - for (i = mid_y - limited_size; i <= mid_y + limited_size; i++) { - TEST_POINT(mid_x - size, i); - TEST_POINT(mid_x + size, i); - } - } - } - - return -1; -} - -#undef TEST_POINT - -} // End of namespace Sci - -// Now include the actual filling code (with scaling support) -#define FILL_FUNCTION _gfxr_fill_any -#define FILL_FUNCTION_RECURSIVE _gfxr_fill_any_recursive -#define AUXBUF_FILL_HELPER _gfxr_auxbuf_fill_any_recursive -#define AUXBUF_FILL _gfxr_auxbuf_fill_any -#define DRAW_SCALED -# include "picfill.cpp" -#undef DRAW_SCALED -#undef AUXBUF_FILL -#undef AUXBUF_FILL_HELPER -#undef FILL_FUNCTION_RECURSIVE -#undef FILL_FUNCTION - -namespace Sci { - -#endif // defined(WITH_PIC_SCALING) - -} // End of namespace Sci - -// Include again, but this time without support for scaling -#define FILL_FUNCTION _gfxr_fill_1 -#define FILL_FUNCTION_RECURSIVE _gfxr_fill_1_recursive -#define AUXBUF_FILL_HELPER _gfxr_auxbuf_fill_1_recursive -#define AUXBUF_FILL _gfxr_auxbuf_fill_1 -# include "picfill.cpp" -#undef AUXBUF_FILL -#undef AUXBUF_FILL_HELPER -#undef FILL_FUNCTION_RECURSIVE -#undef FILL_FUNCTION - -namespace Sci { - -#define GET_ABS_COORDS(x, y) \ - temp = *(resource + pos++); \ - x = *(resource + pos++); \ - y = *(resource + pos++); \ - x |= (temp & 0xf0) << 4; \ - y |= (temp & 0x0f) << 8; - -#define GET_REL_COORDS(x, y) \ - temp = *(resource + pos++); \ - if (temp & 0x80) \ - x -= ((temp >> 4) & 0x7); \ - else \ - x += (temp >> 4); \ - \ - if (temp & 0x08) \ - y -= (temp & 0x7); \ - else \ - y += (temp & 0x7); - -#define GET_MEDREL_COORDS(oldx, oldy) \ - temp = *(resource + pos++); \ - if (temp & 0x80) \ - y = oldy - (temp & 0x7f); \ - else \ - y = oldy + temp; \ - x = oldx + *((signed char *) resource + pos++); - - -static void check_and_remove_artifact(byte *dest, byte* srcp, int legalcolor, byte l, byte r, byte u, byte d) { - if (*dest == legalcolor) { - if (*srcp == legalcolor) - return; - if (l) { - if (srcp[-1] == legalcolor) - return; - if (u && srcp[-320 - 1] == legalcolor) - return; - if (d && srcp[320 - 1] == legalcolor) - return; - } - if (r) { - if (srcp[1] == legalcolor) - return; - if (u && srcp[-320 + 1] == legalcolor) - return; - if (d && srcp[320 + 1] == legalcolor) - return; - } - - if (u && srcp[-320] == legalcolor) - return; - - if (d && srcp[-320] == legalcolor) - return; - - *dest = *srcp; - } -} - -void gfxr_remove_artifacts_pic0(gfxr_pic_t *dest, gfxr_pic_t *src) { - int x_320, y_200; - int bound_x = dest->mode->xfact; - int bound_y = dest->mode->yfact; - int scaled_line_size = bound_x * 320; - int read_offset = 0; - - assert(src->mode->xfact == 1); - assert(src->mode->yfact == 1); - - if (bound_x == 1 && bound_y == 1) { - GFXWARN("attempt to remove artifacts from unscaled pic!\n"); - return; - } - - for (y_200 = 0; y_200 < 200; y_200++) { - for (x_320 = 0; x_320 < 320; x_320++) { - int write_offset = (y_200 * bound_y * scaled_line_size) + (x_320 * bound_x); - int sub_x, sub_y; - byte *src_visualp = &(src->visual_map->index_data[read_offset]); - byte *src_priorityp = &(src->priority_map->index_data[read_offset]); - - for (sub_y = 0; sub_y < bound_y; sub_y++) { - for (sub_x = 0; sub_x < bound_x; sub_x++) { - check_and_remove_artifact(dest->visual_map->index_data + write_offset, src_visualp, (int)0xff, - (byte)x_320, (byte)(x_320 < 319), (byte)(y_200 > 10), (byte)(y_200 < 199)); - check_and_remove_artifact(dest->priority_map->index_data + write_offset, src_priorityp, 0, - (byte)x_320, (byte)(x_320 < 319), (byte)(y_200 > 10), (byte)(y_200 < 199)); - ++write_offset; - } - write_offset += scaled_line_size - bound_x; - } - ++read_offset; - } - } - -} - -static void view_transparentize(gfx_pixmap_t *view, gfx_pixmap_t *background, int posx, int posy, int width, int height) { - int i, j; - byte *pic_index_data = background->index_data; - - // FIXME: this assumes view and background have the same palette... - // We may want to do a reverse mapping or similar to make it general, - // but this (hopefully...) suffices for the current uses of this function. - - for (i = 0;i < width;i++) - for (j = 0;j < height;j++) { - if (view->index_data[j*width+i] == view->color_key) { - view->index_data[j*width+i] = pic_index_data[(j+posy)*width+i+posx]; - } - } -} - -extern gfx_pixmap_t *gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size, gfxr_view_t *view, int mirrored); -extern gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, int size, gfxr_view_t *view, int amiga_game); -extern void _gfx_crossblit_simple(byte *dest, byte *src, int dest_line_width, int src_line_width, int xl, int yl, int bpp); - -void gfxr_draw_pic01(gfxr_pic_t *pic, int flags, int default_palette, int size, byte *resource, - gfxr_pic0_params_t *style, int resid, int sci1, Palette *static_pal) { - const int default_palette_table[GFXR_PIC0_PALETTE_SIZE] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x88, - 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, - 0x88, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, - 0x08, 0x91, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x88 - }; - - const int default_priority_table[GFXR_PIC0_PALETTE_SIZE] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - int palette[GFXR_PIC0_NUM_PALETTES][GFXR_PIC0_PALETTE_SIZE]; - int priority_table[GFXR_PIC0_PALETTE_SIZE]; - int drawenable = GFX_MASK_VISUAL | GFX_MASK_PRIORITY; - int priority = 0; - int color = 0; - int pattern_nr = 0; - int pattern_code = 0; - int pattern_size = 0; - int control = 0; - int pos = 0; - int x, y; - int oldx, oldy; - int pal, index; - int temp; - int line_mode = style->line_mode; - int sci_titlebar_size = style->pic_port_bounds.y; - byte op, opx; - -#ifdef FILL_RECURSIVE_DEBUG - fillmagc = atoi(getenv("FOO")); - fillc = atoi(getenv("FOO2")); -#endif - - // Initialize palette - for (int i = 0; i < GFXR_PIC0_NUM_PALETTES; i++) - memcpy(palette[i], default_palette_table, sizeof(int) * GFXR_PIC0_PALETTE_SIZE); - - memcpy(priority_table, default_priority_table, sizeof(int) * GFXR_PIC0_PALETTE_SIZE); - - // Main loop - while (pos < size) { - op = *(resource + pos++); - - switch (op) { - - case PIC_OP_SET_COLOR: - p0printf("Set color @%d\n", pos); - - if (!sci1) { - pal = *(resource + pos++); - index = pal % GFXR_PIC0_PALETTE_SIZE; - pal /= GFXR_PIC0_PALETTE_SIZE; - - pal += default_palette; - - if (pal >= GFXR_PIC0_NUM_PALETTES) { - GFXERROR("Attempt to access invalid palette %d\n", pal); - return; - } - - color = palette[pal][index]; - } else - color = *(resource + pos++); - p0printf(" color <- %02x [%d/%d]\n", color, pal, index); - drawenable |= GFX_MASK_VISUAL; - goto end_op_loop; - - case PIC_OP_DISABLE_VISUAL: - p0printf("Disable visual @%d\n", pos); - drawenable &= ~GFX_MASK_VISUAL; - goto end_op_loop; - - case PIC_OP_SET_PRIORITY: - p0printf("Set priority @%d\n", pos); - - if (!sci1) { - pal = *(resource + pos++); - index = pal % GFXR_PIC0_PALETTE_SIZE; - pal /= GFXR_PIC0_PALETTE_SIZE; // Ignore pal - - priority = priority_table[index]; - } else priority = *(resource + pos++); - - p0printf(" priority <- %d [%d/%d]\n", priority, pal, index); - drawenable |= GFX_MASK_PRIORITY; - goto end_op_loop; - - case PIC_OP_DISABLE_PRIORITY: - p0printf("Disable priority @%d\n", pos); - drawenable &= ~GFX_MASK_PRIORITY; - goto end_op_loop; - - case PIC_OP_SHORT_PATTERNS: - p0printf("Short patterns @%d\n", pos); - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; - p0printf(" pattern_nr <- %d\n", pattern_nr); - } - - GET_ABS_COORDS(x, y); - - _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, - pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); - - while (*(resource + pos) < PIC_OP_FIRST) { - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; - p0printf(" pattern_nr <- %d\n", pattern_nr); - } - - GET_REL_COORDS(x, y); - - _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, - pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); - } - goto end_op_loop; - - case PIC_OP_MEDIUM_LINES: - p0printf("Medium lines @%d\n", pos); - GET_ABS_COORDS(oldx, oldy); - while (*(resource + pos) < PIC_OP_FIRST) { -#if 0 - fprintf(stderr, "Medium-line: [%04x] from %d,%d, data %02x %02x (dx=%d)", pos, oldx, oldy, - 0xff & resource[pos], 0xff & resource[pos+1], *((signed char *) resource + pos + 1)); -#endif - GET_MEDREL_COORDS(oldx, oldy); -#if 0 - fprintf(stderr, " to %d,%d\n", x, y); -#endif - _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, - PIC_OP_MEDIUM_LINES, sci_titlebar_size); - oldx = x; - oldy = y; - } - goto end_op_loop; - - case PIC_OP_LONG_LINES: - p0printf("Long lines @%d\n", pos); - GET_ABS_COORDS(oldx, oldy); - while (*(resource + pos) < PIC_OP_FIRST) { - GET_ABS_COORDS(x, y); - _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, - PIC_OP_LONG_LINES, sci_titlebar_size); - oldx = x; - oldy = y; - } - goto end_op_loop; - - case PIC_OP_SHORT_LINES: - p0printf("Short lines @%d\n", pos); - GET_ABS_COORDS(oldx, oldy); - x = oldx; - y = oldy; - while (*(resource + pos) < PIC_OP_FIRST) { - GET_REL_COORDS(x, y); - _gfxr_draw_line(pic, oldx, oldy, x, y, color, priority, control, drawenable, line_mode, - PIC_OP_SHORT_LINES, sci_titlebar_size); - oldx = x; - oldy = y; - } - goto end_op_loop; - - case PIC_OP_FILL: - p0printf("Fill @%d\n", pos); - while (*(resource + pos) < PIC_OP_FIRST) { - //fprintf(stderr,"####################\n"); - GET_ABS_COORDS(x, y); - p0printf("Abs coords %d,%d\n", x, y); - //fprintf(stderr,"C=(%d,%d)\n", x, y + sci_titlebar_size); -#ifdef WITH_PIC_SCALING - if (pic->mode->xfact > 1 || pic->mode->yfact > 1) - _gfxr_fill_any(pic, x, y + sci_titlebar_size, (flags & DRAWPIC01_FLAG_FILL_NORMALLY) ? - color : 0, priority, control, drawenable, sci_titlebar_size); - - else -#endif - _gfxr_fill_1(pic, x, y + sci_titlebar_size, (flags & DRAWPIC01_FLAG_FILL_NORMALLY) ? - color : 0, priority, control, drawenable, sci_titlebar_size); - -#ifdef FILL_RECURSIVE_DEBUG - if (!fillmagc) { - int x, y; - if (getenv("FOO1")) - for (x = 0; x < 320; x++) - for (y = 0; y < 200; y++) { - int aux = pic->aux_map[x + y*320]; - int pix = (aux & 0xf); - int i; - - if (aux & 0x40) { - if (x == 0 || !(pic->aux_map[x-1 + y * 320] & 0x40)) - for (i = 0; i < pic->mode->yfact; i++) - pic->visual_map->index_data[(x + ((y*pic->mode->yfact)+i)*320) * pic->mode->xfact] ^= 0xff; - - if (x == 319 || !(pic->aux_map[x+1 + y * 320] & 0x40)) - for (i = 0; i < pic->mode->yfact; i++) - pic->visual_map->index_data[pic->mode->xfact - 1 +(x + ((y*pic->mode->yfact)+i)*320) * pic->mode->xfact] ^= 0xff; - - if (y == 0 || !(pic->aux_map[x + (y-1) * 320] & 0x40)) - for (i = 0; i < pic->mode->yfact; i++) - pic->visual_map->index_data[i+(x + ((y*pic->mode->yfact))*320) * pic->mode->xfact] ^= 0xff; - - if (y == 199 || !(pic->aux_map[x + (y+1) * 320] & 0x40)) - for (i = 0; i < pic->mode->yfact; i++) - pic->visual_map->index_data[i+(x + ((y*pic->mode->yfact)+pic->mode->yfact - 1)*320) * pic->mode->xfact] ^= 0xff; - } - - pix |= (aux & 0x40) >> 4; - pix |= (pix << 4); - - pic->visual_map->index_data[x + y*320*pic->mode->xfact] = pix; - } - return; - } - --fillmagc; -#endif // GFXR_DEBUG_PIC0 - } - goto end_op_loop; - - case PIC_OP_SET_PATTERN: - p0printf("Set pattern @%d\n", pos); - pattern_code = (*(resource + pos++)); - pattern_size = pattern_code & 0x07; - goto end_op_loop; - - case PIC_OP_ABSOLUTE_PATTERN: - p0printf("Absolute pattern @%d\n", pos); - while (*(resource + pos) < PIC_OP_FIRST) { - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; - p0printf(" pattern_nr <- %d\n", pattern_nr); - } - - GET_ABS_COORDS(x, y); - - _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, - pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); - } - goto end_op_loop; - - case PIC_OP_SET_CONTROL: - p0printf("Set control @%d\n", pos); - control = (*(resource + pos++)) & 0xf; - drawenable |= GFX_MASK_CONTROL; - goto end_op_loop; - - - case PIC_OP_DISABLE_CONTROL: - p0printf("Disable control @%d\n", pos); - drawenable &= ~GFX_MASK_CONTROL; - goto end_op_loop; - - - case PIC_OP_MEDIUM_PATTERNS: - p0printf("Medium patterns @%d\n", pos); - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; - p0printf(" pattern_nr <- %d\n", pattern_nr); - } - - GET_ABS_COORDS(oldx, oldy); - - _gfxr_draw_pattern(pic, oldx, oldy, color, priority, control, drawenable, pattern_code, - pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); - - x = oldx; - y = oldy; - while (*(resource + pos) < PIC_OP_FIRST) { - if (pattern_code & PATTERN_FLAG_USE_PATTERN) { - pattern_nr = ((*(resource + pos++)) >> 1) & 0x7f; - p0printf(" pattern_nr <- %d\n", pattern_nr); - } - - GET_MEDREL_COORDS(x, y); - - _gfxr_draw_pattern(pic, x, y, color, priority, control, drawenable, pattern_code, - pattern_size, pattern_nr, style->brush_mode, sci_titlebar_size); - } - goto end_op_loop; - - case PIC_OP_OPX: - opx = *(resource + pos++); - p0printf("OPX: "); - - if (sci1) - opx += SCI1_OP_OFFSET; // See comment at the definition of SCI1_OP_OFFSET. - - switch (opx) { - - case PIC_SCI1_OPX_SET_PALETTE_ENTRIES: - GFXWARN("SCI1 Set palette entried not implemented\n"); - goto end_op_loop; - - case PIC_SCI0_OPX_SET_PALETTE_ENTRIES: - p0printf("Set palette entry @%d\n", pos); - while (*(resource + pos) < PIC_OP_FIRST) { - index = *(resource + pos++); - pal = index / GFXR_PIC0_PALETTE_SIZE; - index %= GFXR_PIC0_PALETTE_SIZE; - - if (pal >= GFXR_PIC0_NUM_PALETTES) { - GFXERROR("Attempt to write to invalid palette %d\n", pal); - return; - } - palette[pal][index] = *(resource + pos++); - } - goto end_op_loop; - - case PIC_SCI0_OPX_SET_PALETTE: - p0printf("Set palette @%d\n", pos); - pal = *(resource + pos++); - if (pal >= GFXR_PIC0_NUM_PALETTES) { - GFXERROR("Attempt to write to invalid palette %d\n", pal); - return; - } - - p0printf(" palette[%d] <- (", pal); - for (index = 0; index < GFXR_PIC0_PALETTE_SIZE; index++) { - palette[pal][index] = *(resource + pos++); - if (index > 0) - p0printf(","); - if (!(index & 0x7)) - p0printf("[%d]=", index); - p0printf("%02x", palette[pal][index]); - } - p0printf(")\n"); - goto end_op_loop; - - case PIC_SCI1_OPX_SET_PALETTE: - p0printf("Set palette @%d\n", pos); - if (pic->visual_map->palette) - pic->visual_map->palette->free(); - pic->visual_map->palette = gfxr_read_pal1(resid, - resource + pos, SCI1_PALETTE_SIZE); - pos += SCI1_PALETTE_SIZE; - goto end_op_loop; - - case PIC_SCI0_OPX_MONO0: - p0printf("Monochrome opx 0 @%d\n", pos); - pos += 41; - goto end_op_loop; - - case PIC_SCI0_OPX_MONO1: - case PIC_SCI0_OPX_MONO3: - ++pos; - p0printf("Monochrome opx %d @%d\n", opx, pos); - goto end_op_loop; - - case PIC_SCI0_OPX_MONO2: - case PIC_SCI0_OPX_MONO4: // Monochrome ops: Ignored by us - p0printf("Monochrome opx %d @%d\n", opx, pos); - goto end_op_loop; - - case PIC_SCI0_OPX_EMBEDDED_VIEW: - case PIC_SCI1_OPX_EMBEDDED_VIEW: { - int posx, posy; - int bytesize; - //byte *vismap = pic->visual_map->index_data; - int nodraw = 0; - - gfx_pixmap_t *view; - - p0printf("Embedded view @%d\n", pos); - - GET_ABS_COORDS(posx, posy); - bytesize = (*(resource + pos)) + (*(resource + pos + 1) << 8); - p0printf("(%d, %d)\n", posx, posy); - pos += 2; - if (!sci1 && !nodraw) - view = gfxr_draw_cel0(-1, -1, -1, resource + pos, bytesize, NULL, 0); - else - view = gfxr_draw_cel1(-1, -1, -1, 0, resource + pos, bytesize, NULL, (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR)); - pos += bytesize; - if (nodraw) - continue; - p0printf("(%d, %d)-(%d, %d)\n", posx, posy, posx + view->index_width, posy + view->index_height); - - // we can only safely replace the palette if it's static - // *if it's not for some reason, we should die - - if (view->palette && view->palette->isShared() && !sci1) { - sciprintf("gfx_draw_pic0(): can't set a non-static palette for an embedded view!\n"); - } - - // For SCI0, use special color mapping to copy the low - // nibble of the color index to the high nibble. - - if (sci1) { - if (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR) { - // Assume Amiga game - pic->visual_map->palette = static_pal->getref(); - } - if (view->palette) view->palette->free(); - view->palette = pic->visual_map->palette->copy(); - } else - view->palette = embedded_view_pal->getref(); - - // Hack to prevent overflowing the visual map buffer. - // Yes, this does happen otherwise. - if (view->index_height + sci_titlebar_size > 200) - sci_titlebar_size = 0; - - // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1byte/p, which handles masks and the rest for us - gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, - pic->visual_map->index_height / 200, format, view->palette, 0); - - gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); - gfx_free_mode(mode); - // When the mode is freed, the associated view - // palette is freed too, so set it to NULL - view->palette = NULL; - - if (flags & DRAWPIC01_FLAG_OVERLAID_PIC) - view_transparentize(view, pic->visual_map, posx, sci_titlebar_size + posy, - view->index_width, view->index_height); - - _gfx_crossblit_simple(pic->visual_map->index_data + (sci_titlebar_size * 320) + posy * 320 + posx, - view->index_data, pic->visual_map->index_width, view->index_width, - view->index_width, view->index_height, 1); - - gfx_free_pixmap(view); - view = NULL; - } - goto end_op_loop; - - case PIC_SCI0_OPX_SET_PRIORITY_TABLE: - case PIC_SCI1_OPX_PRIORITY_TABLE_EXPLICIT: { - int *pri_table; - - p0printf("Explicit priority table @%d\n", pos); - if (!pic->priorityTable) { - pic->priorityTable = (int*)sci_malloc(16 * sizeof(int)); - } else { - GFXERROR("pic->priorityTable is not NULL (%p); this only occurs with overlaid pics, otherwise it's a bug", (void *)pic->priorityTable); - } - - pri_table = pic->priorityTable; - - pri_table[0] = 0; - pri_table[15] = 190; - - for (int i = 1; i < 15; i++) - pri_table[i] = resource[pos++]; - } - goto end_op_loop; - - case PIC_SCI1_OPX_PRIORITY_TABLE_EQDIST: { - int first = (int16)READ_LE_UINT16(resource + pos); - int last = (int16)READ_LE_UINT16(resource + pos + 2); - int nr; - int *pri_table; - - if (!pic->priorityTable) { - pic->priorityTable = (int*)sci_malloc(16 * sizeof(int)); - } else { - GFXERROR("pic->priorityTable is not NULL (%p); possible memory corruption", (void *)pic->priorityTable); - } - - pri_table = pic->priorityTable; - - for (nr = 0; nr < 16; nr ++) - pri_table[nr] = SCI0_PRIORITY_BAND_FIRST_14_ZONES(nr); - pos += 4; - goto end_op_loop; - } - - default: - sciprintf("%s L%d: Warning: Unknown opx %02x\n", __FILE__, __LINE__, opx); - return; - } - goto end_op_loop; - - case PIC_OP_TERMINATE: - p0printf("Terminator\n"); - //warning( "ARTIFACT REMOVAL CODE is commented out!") - //_gfxr_vismap_remove_artifacts(); - return; - - default: - GFXWARN("Unknown op %02x\n", op); - return; - } -end_op_loop: {} - } - - GFXWARN("Reached end of pic resource %04x\n", resid); -} - -void gfxr_draw_pic11(gfxr_pic_t *pic, int flags, int default_palette, int size, byte *resource, - gfxr_pic0_params_t *style, int resid, Palette *static_pal) { - int has_bitmap = READ_LE_UINT16(resource + 4); - int vector_data_ptr = READ_LE_UINT16(resource + 16); - int palette_data_ptr = READ_LE_UINT16(resource + 28); - int bitmap_data_ptr = READ_LE_UINT16(resource + 32); - int sci_titlebar_size = style->pic_port_bounds.y; - gfx_pixmap_t *view = NULL; - - if (pic->visual_map->palette) pic->visual_map->palette->free(); - pic->visual_map->palette = gfxr_read_pal11(-1, resource + palette_data_ptr, 1284); - - if (has_bitmap) - view = gfxr_draw_cel11(-1, 0, 0, 0, resource, resource + bitmap_data_ptr, size - bitmap_data_ptr, NULL); - - if (view) { - view->palette = pic->visual_map->palette->getref(); - - // Set up mode structure for resizing the view - Graphics::PixelFormat format = { 1, 0, 0, 0, 0, 0, 0, 0, 0 }; // 1 byte/p, which handles masks and the rest for us - gfx_mode_t *mode = gfx_new_mode(pic->visual_map->index_width / 320, pic->visual_map->index_height / 200, format, view->palette, 0); - - gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE); - gfx_free_mode(mode); - - if (flags & DRAWPIC01_FLAG_OVERLAID_PIC) - view_transparentize(view, pic->visual_map, 0, 0, view->index_width, view->index_height); - - // Hack to prevent overflowing the visual map buffer. - // Yes, this does happen otherwise. - if (view->index_height + sci_titlebar_size > 200) - sci_titlebar_size = 0; - - _gfx_crossblit_simple(pic->visual_map->index_data + sci_titlebar_size*view->index_width, - view->index_data, - pic->visual_map->index_width, view->index_width, - view->index_width, - view->index_height, - 1); - } else { - GFXWARN("No view was contained in SCI1.1 pic resource"); - } - - gfxr_draw_pic01(pic, flags, default_palette, size - vector_data_ptr, resource + vector_data_ptr, style, resid, 1, static_pal); -} - -void gfxr_dither_pic0(gfxr_pic_t *pic, int dmode, int pattern) { - int xl = pic->visual_map->index_width; - int yl = pic->visual_map->index_height; - int xfrob_max = (pattern == GFXR_DITHER_PATTERN_1) ? 1 : pic->mode->xfact; - int yfrob_max = (pattern == GFXR_DITHER_PATTERN_1) ? 1 : pic->mode->yfact; - int xfrobc = 0, yfrobc = 0; - int selection = 0; - int x, y; - byte *data = pic->visual_map->index_data; - - if (dmode == GFXR_DITHER_MODE_F256) - return; // Nothing to do - - if (dmode == GFXR_DITHER_MODE_D16) { // Limit to 16 colors - pic->visual_map->palette = gfx_sci0_image_pal[sci0_palette]->getref(); - } - - for (y = 0; y < yl; y++) { - for (x = 0; x < xl; x++) { - - switch (dmode) { - case GFXR_DITHER_MODE_D16: - if (selection) - *data = (*data & 0xf0) >> 4; - else - *data = (*data & 0xf); - break; - - case GFXR_DITHER_MODE_D256: - if (selection) - *data = ((*data & 0xf) << 4) | ((*data & 0xf0) >> 4); - break; - - default: - GFXERROR("Invalid dither mode %d!\n", dmode); - return; - } - - ++data; - - if (++xfrobc == xfrob_max) { - selection = !selection; - xfrobc = 0; - } - } - - if (++yfrobc == yfrob_max) { - selection = !selection; - yfrobc = 0; - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_view0.cpp b/engines/sci/gfx/resource/res_view0.cpp deleted file mode 100644 index dd01ae4ad0..0000000000 --- a/engines/sci/gfx/resource/res_view0.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/endian.h" - -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_system.h" -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" - -namespace Sci { - -gfx_pixmap_t *gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size, gfxr_view_t *view, int mirrored) { - int xl = READ_LE_UINT16(resource); - int yl = READ_LE_UINT16(resource + 2); - int xhot = ((signed char *)resource)[4]; - int yhot = ((signed char *)resource)[5]; - int color_key = resource[6]; - int pos = 7; - int writepos = mirrored ? xl : 0; - int pixmap_size = xl * yl; - int line_base = 0; - gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); - byte *dest = retval->index_data; - - retval->color_key = 255; // Pick something larger than 15 - - retval->xoffset = mirrored ? xhot : -xhot; - retval->yoffset = -yhot; - - if (view) { - retval->palette = view->palette->getref(); - } else { - retval->palette = gfx_sci0_image_pal[sci0_palette]->getref(); - } - - if (xl <= 0 || yl <= 0) { - gfx_free_pixmap(retval); - GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); - return NULL; - } - - if (mirrored) { - while (yl && pos < size) { - int op = resource[pos++]; - int count = op >> 4; - int color = op & 0xf; - - if (view->flags & GFX_PIXMAP_FLAG_PALETTIZED) - color = view->translation[color]; - - if (color == color_key) - color = retval->color_key; - - while (count) { - int pixels = writepos - line_base; - - if (pixels > count) - pixels = count; - - writepos -= pixels; - memset(dest + writepos, color, pixels); - count -= pixels; - - if (writepos == line_base) { - yl--; - writepos += (xl << 1); - line_base += xl; - } - } - } - } else { - - while (writepos < pixmap_size && pos < size) { - int op = resource[pos++]; - int count = op >> 4; - int color = op & 0xf; - - if (view && (view->flags & GFX_PIXMAP_FLAG_PALETTIZED)) - color = view->translation[color]; - - if (color == color_key) - color = retval->color_key; - - if (writepos + count > pixmap_size) { - GFXERROR("View %02x:(%d/%d) writes RLE data over its designated end at rel. offset 0x%04x\n", id, loop, cel, pos); - return NULL; - } - - memset(dest + writepos, color, count); - writepos += count; - } - } - - return retval; -} - -static int gfxr_draw_loop0(gfxr_loop_t *dest, int id, int loop, byte *resource, int offset, int size, gfxr_view_t *view, int mirrored) { - int i; - int cels_nr = READ_LE_UINT16(resource + offset); - - if (READ_LE_UINT16(resource + offset + 2)) { - GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, READ_LE_UINT16(resource + offset + 2)); - } - - if (cels_nr * 2 + 4 + offset > size) { - GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); - dest->cels_nr = 0; /* Mark as "delete no cels" */ - dest->cels = NULL; - return 1; - } - - dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); - - for (i = 0; i < cels_nr; i++) { - int cel_offset = READ_LE_UINT16(resource + offset + 4 + (i << 1)); - gfx_pixmap_t *cel = NULL; - - if (cel_offset >= size) { - GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); - cel = NULL; - } else - cel = gfxr_draw_cel0(id, loop, i, resource + cel_offset, size - cel_offset, view, mirrored); - - - if (!cel) { - dest->cels_nr = i; - return 1; - } - - dest->cels[i] = cel; - } - - dest->cels_nr = cels_nr; - - return 0; -} - -#define V0_LOOPS_NR_OFFSET 0 -#define V0_FIRST_LOOP_OFFSET 8 -#define V0_MIRROR_LIST_OFFSET 2 - -gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette) { - int i; - gfxr_view_t *view; - int mirror_bitpos = 1; - int mirror_bytepos = V0_MIRROR_LIST_OFFSET; - int palette_ofs = READ_LE_UINT16(resource + 6); - - if (size < V0_FIRST_LOOP_OFFSET + 8) { - GFXERROR("Attempt to draw empty view %04x\n", id); - return NULL; - } - - view = (gfxr_view_t *)sci_malloc(sizeof(gfxr_view_t)); - view->ID = id; - - view->loops_nr = resource[V0_LOOPS_NR_OFFSET]; - - // Set palette - view->flags = 0; - view->palette = gfx_sci0_image_pal[sci0_palette]->getref(); - - if ((palette_ofs) && (palette >= 0)) { - byte *paldata = resource + palette_ofs + (palette * GFX_SCI0_IMAGE_COLORS_NR); - - for (i = 0; i < GFX_SCI0_IMAGE_COLORS_NR; i++) - view->translation[i] = *(paldata++); - - view->flags |= GFX_PIXMAP_FLAG_PALETTIZED; - } - - if (view->loops_nr * 2 + V0_FIRST_LOOP_OFFSET > size) { - GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); - free(view); - return NULL; - } - - view->loops = (gfxr_loop_t*)sci_malloc(sizeof(gfxr_loop_t) * ((view->loops_nr) ? view->loops_nr : 1)); /* Alloc 1 if no loop */ - - for (i = 0; i < view->loops_nr; i++) { - int error_token = 0; - int loop_offset = READ_LE_UINT16(resource + V0_FIRST_LOOP_OFFSET + (i << 1)); - int mirrored = resource[mirror_bytepos] & mirror_bitpos; - - if ((mirror_bitpos <<= 1) == 0x100) { - mirror_bytepos++; - mirror_bitpos = 1; - } - - if (loop_offset >= size) { - GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i, loop_offset); - error_token = 1; - } - - if (error_token || gfxr_draw_loop0(view->loops + i, id, i, resource, loop_offset, size, view, mirrored)) { - // An error occured - view->loops_nr = i; - gfxr_free_view(view); - return NULL; - } - } - - return view; -} - -} // End of namespace Sci diff --git a/engines/sci/gfx/resource/res_view1.cpp b/engines/sci/gfx/resource/res_view1.cpp deleted file mode 100644 index d743804971..0000000000 --- a/engines/sci/gfx/resource/res_view1.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program 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. - - * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -// SCI 1 view resource defrobnicator - -#include "common/endian.h" - -#include "sci/sci_memory.h" -#include "sci/gfx/gfx_system.h" -#include "sci/gfx/gfx_resource.h" -#include "sci/gfx/gfx_tools.h" - -namespace Sci { - -#define V1_LOOPS_NR_OFFSET 0 -#define V1_MIRROR_MASK 2 -#define V1_PALETTE_OFFSET 6 -#define V1_FIRST_LOOP_OFFSET 8 - -#define V1_RLE 0x80 // run-length encode? -#define V1_RLE_BG 0x40 // background fill - -#define NEXT_RUNLENGTH_BYTE(n) \ - if (literal_pos == runlength_pos) \ - literal_pos += n; \ - runlength_pos += n; - -#define NEXT_LITERAL_BYTE(n) \ - if (literal_pos == runlength_pos) \ - runlength_pos += n; \ - literal_pos += n; - -static int decompress_sci_view(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, - int runlength_pos, int literal_pos, int xl, int yl, int color_key) { - int writepos = mirrored ? xl : 0; - - if (mirrored) { - int linebase = 0; - - while (linebase < pixmap_size && literal_pos < size && runlength_pos < size) { - int op = resource[runlength_pos]; - int bytes; - int readbytes = 0; - int color = 0; - - NEXT_RUNLENGTH_BYTE(1); - - if (op & V1_RLE) { - bytes = op & 0x3f; - op &= (V1_RLE | V1_RLE_BG); - readbytes = (op & V1_RLE_BG) ? 0 : 1; - } else { - readbytes = bytes = op & 0x3f; - op = 0; - } - - if (runlength_pos + readbytes > size) { - GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", - id, loop, cel, readbytes, size - runlength_pos, runlength_pos - 1); - return 1; - } - /* - if (writepos - bytes < 0) { - GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", - id, loop, cel, writepos - bytes, pixmap_size, pos - 1); - bytes = pixmap_size - writepos; - } - */ - if (op == V1_RLE) { - color = resource[literal_pos]; - NEXT_LITERAL_BYTE(1); - } - - if (!op && literal_pos + bytes > size) { - GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", - id, loop, cel, bytes, size - literal_pos, literal_pos - 1); - return 1; - } - - while (bytes--) { - if (op) { - if (op & V1_RLE_BG) { - writepos--; - *(dest + writepos) = color_key; - } else { - writepos--; - *(dest + writepos) = color; - } - } else { - writepos--; - *(dest + writepos) = *(resource + literal_pos); - NEXT_LITERAL_BYTE(1); - - } - if (writepos == linebase) { - writepos += 2 * xl; - linebase += xl; - } - } - } - } else { - while (writepos < pixmap_size && literal_pos < size && runlength_pos < size) { - int op = resource[runlength_pos]; - int bytes; - int readbytes = 0; - - NEXT_RUNLENGTH_BYTE(1); - - if (op & V1_RLE) { - bytes = op & 0x3f; - op &= (V1_RLE | V1_RLE_BG); - readbytes = (op & V1_RLE_BG) ? 0 : 1; - } else { - readbytes = bytes = op & 0x3f; - op = 0; - } - - if (runlength_pos + readbytes > size) { - return 1; - } - - if (writepos + bytes > pixmap_size) { - GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", - id, loop, cel, writepos - bytes, pixmap_size, runlength_pos - 1); - bytes = pixmap_size - writepos; - } - - if (!op && literal_pos + bytes > size) { - GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", - id, loop, cel, bytes, size - literal_pos, literal_pos - 1); - return 1; - } - - if (writepos + bytes > pixmap_size) { - GFXWARN("Writing out of bounds: %d bytes at %d > size %d\n", bytes, writepos, pixmap_size); - } - - if (op) { - if (op & V1_RLE_BG) - memset(dest + writepos, color_key, bytes); - else { - int color = resource[literal_pos]; - - NEXT_LITERAL_BYTE(1); - memset(dest + writepos, color, bytes); - } - } else { - memcpy(dest + writepos, resource + literal_pos, bytes); - NEXT_LITERAL_BYTE(bytes); - } - writepos += bytes; - - } - - }; - - return 0; -} - -static int decompress_sci_view_amiga(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, - int pos, int xl, int yl, int color_key) { - int writepos = mirrored ? xl - 1 : 0; - - while (writepos < pixmap_size && pos < size) { - int op = resource[pos++]; - int bytes; - int color; - - if (op & 0x07) { - bytes = op & 0x07; - color = op >> 3; - } else { - bytes = op >> 3; - color = color_key; - } - - if (mirrored) { - while (bytes--) { - dest[writepos--] = color; - // If we've just written the first pixel of a line... - if (!((writepos + 1) % xl)) { - // Then move to the end of next line - writepos += 2 * xl; - - if (writepos >= pixmap_size && bytes) { - GFXWARN("View %02x:(%d/%d) writing out of bounds\n", id, loop, cel); - break; - } - } - } - } else { - if (writepos + bytes > pixmap_size) { - GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", - id, loop, cel, writepos - bytes, pixmap_size, pos - 1); - bytes = pixmap_size - writepos; - } - memset(dest + writepos, color, bytes); - writepos += bytes; - } - } - - if (writepos < pixmap_size) { - GFXWARN("View %02x:(%d/%d) not enough pixel data in view\n", id, loop, cel); - return 1; - } - - return 0; -} - -gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, int size, gfxr_view_t *view, int amiga_game) { - int xl = READ_LE_UINT16(resource); - int yl = READ_LE_UINT16(resource + 2); - int xhot = (int8) resource[4]; - int yhot = (uint8) resource[5]; - int pos = 8; - int pixmap_size = xl * yl; - gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); - byte *dest = retval->index_data; - int decompress_failed; - - retval->color_key = resource[6]; - retval->xoffset = (mirrored) ? xhot : -xhot; - retval->yoffset = -yhot; - - if (view) - retval->palette = view->palette->getref(); - else - retval->palette = NULL; - - if (xl <= 0 || yl <= 0) { - gfx_free_pixmap(retval); - GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); - return NULL; - } - - if (amiga_game) - decompress_failed = decompress_sci_view_amiga(id, loop, cel, resource, dest, mirrored, pixmap_size, size, pos, - xl, yl, retval->color_key); - else - decompress_failed = decompress_sci_view(id, loop, cel, resource, dest, mirrored, pixmap_size, size, pos, - pos, xl, yl, retval->color_key); - - if (decompress_failed) { - gfx_free_pixmap(retval); - return NULL; - } - - return retval; -} - -static int gfxr_draw_loop1(gfxr_loop_t *dest, int id, int loop, int mirrored, byte *resource, int offset, int size, gfxr_view_t *view, int amiga_game) { - int i; - int cels_nr = READ_LE_UINT16(resource + offset); - - if (READ_LE_UINT16(resource + offset + 2)) { - GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, READ_LE_UINT16(resource + offset + 2)); - } - - if (cels_nr * 2 + 4 + offset > size) { - GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); - dest->cels_nr = 0; // Mark as "delete no cels" - dest->cels = NULL; - return 1; - } - - dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); - - for (i = 0; i < cels_nr; i++) { - int cel_offset = READ_LE_UINT16(resource + offset + 4 + (i << 1)); - gfx_pixmap_t *cel; - - if (cel_offset >= size) { - GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); - cel = NULL; - } else - cel = gfxr_draw_cel1(id, loop, i, mirrored, resource + cel_offset, size - cel_offset, view, amiga_game); - - if (!cel) { - dest->cels_nr = i; - return 1; - } - - dest->cels[i] = cel; - } - - dest->cels_nr = cels_nr; - - return 0; -} - -#define V1_FIRST_MAGIC 1 -#define V1_MAGICS_NR 5 -//static byte view_magics[V1_MAGICS_NR] = {0x80, 0x00, 0x00, 0x00, 0x00}; - -gfxr_view_t *gfxr_draw_view1(int id, byte *resource, int size, Palette *static_pal) { - int i; - int palette_offset; - gfxr_view_t *view; - int mirror_mask; - int amiga_game = 0; - - if (size < V1_FIRST_LOOP_OFFSET + 8) { - GFXERROR("Attempt to draw empty view %04x\n", id); - return NULL; - } - - view = (gfxr_view_t*)sci_malloc(sizeof(gfxr_view_t)); - view->ID = id; - view->flags = 0; - - view->loops_nr = resource[V1_LOOPS_NR_OFFSET]; - palette_offset = READ_LE_UINT16(resource + V1_PALETTE_OFFSET); - mirror_mask = READ_LE_UINT16(resource + V1_MIRROR_MASK); - - if (view->loops_nr * 2 + V1_FIRST_LOOP_OFFSET > size) { - GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); - free(view); - return NULL; - } - - /* fprintf(stderr, "View flags are 0x%02x\n", resource[3]);*/ - - /* - for (i = 0; i < V1_MAGICS_NR; i++) - if (resource[V1_FIRST_MAGIC + i] != view_magics[i]) { - GFXWARN("View %04x: View magic #%d should be %02x but is %02x\n", id, i, view_magics[i], resource[V1_FIRST_MAGIC + i]); - } - */ - - if (palette_offset > 0) { - if (palette_offset > size) { - GFXERROR("Palette is outside of view %04x\n", id); - free(view); - return NULL; - } - if (!(view->palette = gfxr_read_pal1(id, resource + palette_offset, size - palette_offset))) { - GFXERROR("view %04x: Palette reading failed. Aborting...\n", id); - free(view); - return NULL; - } - } else if (static_pal && static_pal->size() == GFX_SCI1_AMIGA_COLORS_NR) { - // Assume we're running an amiga game. - amiga_game = 1; - view->palette = static_pal->getref(); - } else { - GFXWARN("view %04x: Doesn't have a palette. Can FreeSCI handle this?\n", view->ID); - view->palette = NULL; - } - - view->loops = (gfxr_loop_t*)sci_malloc(sizeof(gfxr_loop_t) * view->loops_nr); - - for (i = 0; i < view->loops_nr; i++) { - int error_token = 0; - int loop_offset = READ_LE_UINT16(resource + V1_FIRST_LOOP_OFFSET + (i << 1)); - - if (loop_offset >= size) { - GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i, loop_offset); - error_token = 1; - } - - if (error_token || gfxr_draw_loop1(view->loops + i, id, i, mirror_mask & (1 << i), resource, loop_offset, size, view, amiga_game)) { - // An error occured - view->loops_nr = i; - gfxr_free_view(view); - return NULL; - } - } - - return view; -} - -#define V2_HEADER_SIZE 0 -#define V2_LOOPS_NUM 2 -#define V2_PALETTE_OFFSET 8 -#define V2_BYTES_PER_LOOP 12 -#define V2_BYTES_PER_CEL 13 - -#define V2_IS_MIRROR 1 -#define V2_COPY_OF_LOOP 2 -#define V2_CELS_NUM 4 -#define V2_LOOP_OFFSET 14 - -#define V2_CEL_WIDTH 0 -#define V2_CEL_HEIGHT 2 -#define V2_X_DISPLACEMENT 4 -#define V2_Y_DISPLACEMENT 6 -#define V2_COLOR_KEY 8 -#define V2_RUNLENGTH_OFFSET 24 -#define V2_LITERAL_OFFSET 28 - -gfx_pixmap_t *gfxr_draw_cel11(int id, int loop, int cel, int mirrored, byte *resource_base, byte *cel_base, int size, gfxr_view_t *view) { - int xl = READ_LE_UINT16(cel_base + V2_CEL_WIDTH); - int yl = READ_LE_UINT16(cel_base + V2_CEL_HEIGHT); - int xdisplace = READ_LE_UINT16(cel_base + V2_X_DISPLACEMENT); - int ydisplace = READ_LE_UINT16(cel_base + V2_Y_DISPLACEMENT); - int runlength_offset = READ_LE_UINT16(cel_base + V2_RUNLENGTH_OFFSET); - int literal_offset = READ_LE_UINT16(cel_base + V2_LITERAL_OFFSET); - int pixmap_size = xl * yl; - - gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); - byte *dest = retval->index_data; - int decompress_failed; - - retval->color_key = cel_base[V2_COLOR_KEY]; - retval->xoffset = (mirrored) ? xdisplace : -xdisplace; - retval->yoffset = -ydisplace; - - if (view) - retval->palette = view->palette->getref(); - - if (xl <= 0 || yl <= 0) { - gfx_free_pixmap(retval); - GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); - return NULL; - } - - decompress_failed = decompress_sci_view(id, loop, cel, resource_base, dest, mirrored, pixmap_size, size, - runlength_offset, literal_offset, xl, yl, retval->color_key); - - if (decompress_failed) { - gfx_free_pixmap(retval); - return NULL; - } - - return retval; -} - -gfxr_loop_t *gfxr_draw_loop11(int id, int loop, int mirrored, byte *resource_base, byte *loop_base, int size, int cels_nr, - gfxr_loop_t *result, gfxr_view_t *view, int bytes_per_cel) { - byte *seeker = loop_base; - int i; - - result->cels_nr = cels_nr; - result->cels = (gfx_pixmap_t **)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); - - for (i = 0; i < cels_nr; i++) { - result->cels[i] = gfxr_draw_cel11(id, loop, i, mirrored, resource_base, seeker, size, view); - seeker += bytes_per_cel; - } - - return result; -} - -gfxr_view_t *gfxr_draw_view11(int id, byte *resource, int size) { - gfxr_view_t *view; - int header_size = READ_LE_UINT16(resource + V2_HEADER_SIZE); - int palette_offset = READ_LE_UINT16(resource + V2_PALETTE_OFFSET); - int bytes_per_loop = resource[V2_BYTES_PER_LOOP]; - int loops_num = resource[V2_LOOPS_NUM]; - int bytes_per_cel = resource[V2_BYTES_PER_CEL]; - int i; - byte *seeker; - - view = (gfxr_view_t *)sci_malloc(sizeof(gfxr_view_t)); - - memset(view, 0, sizeof(gfxr_view_t)); - view->ID = id; - view->flags = 0; - - view->loops_nr = loops_num; - view->loops = (gfxr_loop_t *)calloc(view->loops_nr, sizeof(gfxr_loop_t)); - - // There is no indication of size here, but this is certainly large enough - view->palette = gfxr_read_pal11(id, resource + palette_offset, 1284); - - seeker = resource + header_size; - for (i = 0; i < view->loops_nr; i++) { - int loop_offset = READ_LE_UINT16(seeker + V2_LOOP_OFFSET); - int cels = seeker[V2_CELS_NUM]; - int mirrored = seeker[V2_IS_MIRROR]; - int copy_entry = seeker[V2_COPY_OF_LOOP]; - - printf("%d\n", mirrored); - if (copy_entry == 255) - gfxr_draw_loop11(id, i, 0, resource, resource + loop_offset, size, cels, view->loops + i, - view, bytes_per_cel); - else { - byte *temp = resource + header_size + copy_entry * bytes_per_loop; - loop_offset = READ_LE_UINT16(temp + V2_LOOP_OFFSET); - cels = temp[V2_CELS_NUM]; - gfxr_draw_loop11(id, i, 1, resource, resource + loop_offset, size, cels, - view->loops + i, view, bytes_per_cel); - } - - seeker += bytes_per_loop; - } - - return view; -} - -} // End of namespace Sci diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 3b461aa10d..c0680fc782 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -38,6 +38,7 @@ MODULE_OBJS = \ gfx/font.o \ gfx/gfx_driver.o \ gfx/gfx_res_options.o \ + gfx/res_resmgr.o \ gfx/gfx_resource.o \ gfx/gfx_support.o \ gfx/gfx_tools.o \ @@ -45,14 +46,13 @@ MODULE_OBJS = \ gfx/menubar.o \ gfx/operations.o \ gfx/palette.o \ - gfx/resmgr.o \ gfx/sci_widgets.o \ - gfx/resource/res_cursor.o \ - gfx/resource/res_font.o \ - gfx/resource/res_pal.o \ - gfx/resource/res_pic.o \ - gfx/resource/res_view0.o \ - gfx/resource/res_view1.o \ + gfx/res_cursor.o \ + gfx/res_font.o \ + gfx/res_pal.o \ + gfx/res_pic.o \ + gfx/res_view0.o \ + gfx/res_view1.o \ scicore/decompressor.o \ scicore/resource.o \ scicore/sciconsole.o \ -- cgit v1.2.3