diff options
Diffstat (limited to 'engines/sci/gfx/operations.cpp')
-rw-r--r-- | engines/sci/gfx/operations.cpp | 1212 |
1 files changed, 0 insertions, 1212 deletions
diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp deleted file mode 100644 index a2791794fd..0000000000 --- a/engines/sci/gfx/operations.cpp +++ /dev/null @@ -1,1212 +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$ - * - */ - -// Graphical operations, called from the widget state manager - -#include "sci/sci.h" -#include "sci/gfx/operations.h" -#ifdef INCLUDE_OLDGFX -#include "sci/gui32/font.h" -#endif -#include "sci/console.h" -#include "sci/event.h" - -#include "common/system.h" -#include "common/events.h" - -namespace Sci { - -#ifdef INCLUDE_OLDGFX - -#define PRECISE_PRIORITY_MAP // Duplicate all operations on the local priority map as appropriate - -#undef GFXW_DEBUG_DIRTY -// Enable to debug stuff relevant for dirty rectsin widget management - -#ifdef GFXW_DEBUG_DIRTY -# define DDIRTY fprintf(stderr, "%s:%5d| ", __FILE__, __LINE__); fprintf -#else -# define DDIRTY if (0) fprintf -#endif - -// Default color maps -#define DEFAULT_COLORS_NR 16 - -PaletteEntry default_colors[DEFAULT_COLORS_NR] = { - PaletteEntry(0x00, 0x00, 0x00), PaletteEntry(0x00, 0x00, 0xaa), - PaletteEntry(0x00, 0xaa, 0x00), PaletteEntry(0x00, 0xaa, 0xaa), - PaletteEntry(0xaa, 0x00, 0x00), PaletteEntry(0xaa, 0x00, 0xaa), - PaletteEntry(0xaa, 0x55, 0x00), PaletteEntry(0xaa, 0xaa, 0xaa), - PaletteEntry(0x55, 0x55, 0x55), PaletteEntry(0x55, 0x55, 0xff), - PaletteEntry(0x55, 0xff, 0x55), PaletteEntry(0x55, 0xff, 0xff), - PaletteEntry(0xff, 0x55, 0x55), PaletteEntry(0xff, 0x55, 0xff), - PaletteEntry(0xff, 0xff, 0x55), PaletteEntry(0xff, 0xff, 0xff) -}; // "Normal" EGA - -#define POINTER_VISIBLE_BUT_CLIPPED 2 - -// How to determine whether colors have to be allocated -#define SCREEN_PALETTE state->driver->getMode()->palette - -//#define GFXOP_DEBUG_DIRTY - -// Internal operations - -static void _gfxop_scale_rect(rect_t *rect, gfx_mode_t *mode) { - rect->x *= mode->scaleFactor; - rect->y *= mode->scaleFactor; - rect->width *= mode->scaleFactor; - rect->height *= mode->scaleFactor; -} - -static void _gfxop_scale_point(Common::Point *point, gfx_mode_t *mode) { - point->x *= mode->scaleFactor; - point->y *= mode->scaleFactor; -} - -int _gfxop_clip(rect_t *rect, rect_t clipzone) { -// Returns 1 if nothing is left */ -#if 0 - printf("Clipping (%d, %d) size (%d, %d) by (%d,%d)(%d,%d)\n", rect->x, rect->y, rect->width, rect->height, - clipzone.x, clipzone.y, clipzone.width, clipzone.height); -#endif - - if (rect->x < clipzone.x) { - rect->width -= (clipzone.x - rect->x); - rect->x = clipzone.x; - } - - if (rect->y < clipzone.y) { - rect->height -= (clipzone.y - rect->y); - rect->y = clipzone.y; - } - - if (rect->x + rect->width > clipzone.x + clipzone.width) - rect->width = (clipzone.x + clipzone.width) - rect->x; - - if (rect->y + rect->height > clipzone.y + clipzone.height) - rect->height = (clipzone.y + clipzone.height) - rect->y; - - if (rect->width < 0) - rect->width = 0; - if (rect->height < 0) - rect->height = 0; - -#if 0 - printf(" => (%d, %d) size (%d, %d)\n", rect->x, rect->y, rect->width, rect->height); -#endif - return (rect->width <= 0 || rect->height <= 0); -} - -static void _gfxop_grab_pixmap(GfxState *state, gfx_pixmap_t **pxmp, int x, int y, - int xl, int yl, int priority, rect_t *zone) { - // Returns 1 if the resulting data size was zero, GFX_OK or an error code otherwise */ - int xfact = state->driver->getMode()->scaleFactor; - int yfact = state->driver->getMode()->scaleFactor; - int unscaled_xl = (xl + xfact - 1) / xfact; - int unscaled_yl = (yl + yfact - 1) / yfact; - *zone = gfx_rect(x, y, xl, yl); - - if (_gfxop_clip(zone, gfx_rect(0, 0, 320 * state->driver->getMode()->scaleFactor, 200 * state->driver->getMode()->scaleFactor))) - error("_gfxop_grab_pixmap: zone was empty"); - - if (!*pxmp) - *pxmp = gfx_new_pixmap(unscaled_xl, unscaled_yl, GFX_RESID_NONE, 0, 0); - else - if (xl * yl > (*pxmp)->width * (*pxmp)->height) { - free((*pxmp)->data); - (*pxmp)->data = NULL; - } - - if (!(*pxmp)->data) { - (*pxmp)->index_width = unscaled_xl + 1; - (*pxmp)->index_height = unscaled_yl + 1; - gfx_pixmap_alloc_data(*pxmp, state->driver->getMode()); - } - state->driver->grabPixmap(*zone, *pxmp, priority ? GFX_MASK_PRIORITY : GFX_MASK_VISUAL); -} - -#define DRAW_LOOP(condition) \ -{ \ - rect_t drawrect = gfx_rect(pos.x, pos.y, pxm->index_width, pxm->index_height); \ - int offset, base_offset; \ - int read_offset, base_read_offset; \ - int x,y; \ - \ - if (!pxm->index_data) { \ - error("Attempt to draw control color %d on pixmap %d/%d/%d without index data", color, pxm->ID, pxm->loop, pxm->cel); \ - return; \ - } \ - \ - if (_gfxop_clip(&drawrect, gfx_rect(0, 0, 320, 200))) \ - return; \ - \ - offset = base_offset = drawrect.x + drawrect.y * 320; \ - read_offset = base_read_offset = (drawrect.x - pos.x) + ((drawrect.y - pos.y) * pxm->index_width); \ - \ - for (y = 0; y < drawrect.height; y++) { \ - for (x = 0; x < drawrect.width; x++) \ - if (pxm->index_data[read_offset++] != pxm->color_key) { \ - if (condition) \ - map->index_data[offset++] = color; \ - else \ - ++offset; \ - } else \ - ++offset; \ - \ - offset = base_offset += 320; \ - read_offset = base_read_offset += pxm->index_width; \ - } \ -} - -static void _gfxop_draw_control(gfx_pixmap_t *map, gfx_pixmap_t *pxm, int color, Common::Point pos) -DRAW_LOOP(1) // Always draw - -#ifdef PRECISE_PRIORITY_MAP -static void _gfxop_draw_priority(gfx_pixmap_t *map, gfx_pixmap_t *pxm, int color, Common::Point pos) -DRAW_LOOP(map->index_data[offset] < color) // Draw only lower priority -#endif - -#undef DRAW_LOOP - -static void _gfxop_install_pixmap(GfxDriver *driver, gfx_pixmap_t *pxm) { - if (!driver->getMode()->palette) - return; - if (!pxm->palette) - return; - - pxm->palette->mergeInto(driver->getMode()->palette); - assert(pxm->palette->getParent() == driver->getMode()->palette); - - if (pxm->palette_revision != pxm->palette->getRevision()) - gfx_xlate_pixmap(pxm, driver->getMode()); - - if (!driver->getMode()->palette->isDirty()) - return; - - // TODO: We probably want to only update the colours used by this pixmap - // here. This will require updating the 'dirty' system. - byte paletteData[4*256]; - const uint paletteSize = driver->getMode()->palette->size(); - for (uint i = 0; i < paletteSize; ++i) { - const PaletteEntry& c = (*driver->getMode()->palette)[i]; - paletteData[4*i+0] = c.r; - paletteData[4*i+1] = c.g; - paletteData[4*i+2] = c.b; - paletteData[4*i+3] = 255; - } - - g_system->setPalette(paletteData, 0, paletteSize); - driver->getMode()->palette->markClean(); -} - -static void _gfxop_draw_pixmap(GfxDriver *driver, gfx_pixmap_t *pxm, int priority, int control, - rect_t src, rect_t dest, rect_t clip, int static_buf, gfx_pixmap_t *control_map, gfx_pixmap_t *priority_map) { - rect_t clipped_dest = gfx_rect(dest.x, dest.y, dest.width, dest.height); - - if (control >= 0 || priority >= 0) { - Common::Point original_pos = Common::Point(dest.x / driver->getMode()->scaleFactor, dest.y / driver->getMode()->scaleFactor); - - if (control >= 0) - _gfxop_draw_control(control_map, pxm, control, original_pos); - -#ifdef PRECISE_PRIORITY_MAP - if (priority >= 0) - _gfxop_draw_priority(priority_map, pxm, priority, original_pos); -#endif - } - - if (_gfxop_clip(&clipped_dest, clip)) - return; - - src.x += clipped_dest.x - dest.x; - src.y += clipped_dest.y - dest.y; - src.width = clipped_dest.width; - src.height = clipped_dest.height; - - _gfxop_install_pixmap(driver, pxm); - - DDIRTY(stderr, "\\-> Drawing to actual %d %d %d %d\n", clipped_dest.x / driver->getMode()->scaleFactor, - clipped_dest.y / driver->getMode()->scaleFactor, clipped_dest.width / driver->getMode()->scaleFactor, clipped_dest.height / driver->getMode()->scaleFactor); - - driver->drawPixmap(pxm, priority, src, clipped_dest, static_buf ? GFX_BUFFER_STATIC : GFX_BUFFER_BACK); -} - -static void _gfxop_buffer_propagate_box(GfxState *state, rect_t box, gfx_buffer_t buffer) { - if (_gfxop_clip(&box, gfx_rect(0, 0, 320 * state->driver->getMode()->scaleFactor, 200 * state->driver->getMode()->scaleFactor))) - return; - - state->driver->update(box, Common::Point(box.x, box.y), buffer); -} - -//** Dirty rectangle operations ** - -static void _gfxop_update_box(GfxState *state, rect_t box) { - _gfxop_scale_rect(&box, state->driver->getMode()); - _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_FRONT); -} - -void gfxdr_add_dirty(DirtyRectList &list, rect_t box) { - if (box.width < 0) { - box.x += box.width; - box.width = - box.width; - } - - if (box.height < 0) { - box.y += box.height; - box.height = - box.height; - } -#ifdef GFXOP_DEBUG_DIRTY - fprintf(stderr, "Adding new dirty (%d %d %d %d)\n", - GFX_PRINT_RECT(box)); -#endif - if (_gfxop_clip(&box, gfx_rect(0, 0, 320, 200))) - return; - - DirtyRectList::iterator dirty = list.begin(); - while (dirty != list.end()) { - if (gfx_rects_overlap(*dirty, box)) { - Common::Rect tmp = toCommonRect(box); - tmp.extend(toCommonRect(*dirty)); - box = toSCIRect(tmp); - - dirty = list.erase(dirty); - } else - ++dirty; - } - list.push_back(box); -} - -static void _gfxop_add_dirty(GfxState *state, rect_t box) { - if (state->disable_dirty) - return; - - gfxdr_add_dirty(state->_dirtyRects, box); -} - -static void _gfxop_add_dirty_x(GfxState *state, rect_t box) { - // Extends the box size by one before adding (used for lines) - if (box.width < 0) - box.width--; - else - box.width++; - - if (box.height < 0) - box.height--; - else - box.height++; - - _gfxop_add_dirty(state, box); -} - -static void _gfxop_clear_dirty_rec(GfxState *state, DirtyRectList &dirtyRects) { - DirtyRectList::iterator dirty = dirtyRects.begin(); - while (dirty != dirtyRects.end()) { - - #ifdef GFXOP_DEBUG_DIRTY - fprintf(stderr, "\tClearing dirty (%d %d %d %d)\n", GFX_PRINT_RECT(*dirty)); - #endif - _gfxop_update_box(state, *dirty); - ++dirty; - } - dirtyRects.clear(); -} - -//** Exported operations ** - -static void init_aux_pixmap(gfx_pixmap_t **pixmap) { - *pixmap = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, GFX_RESID_NONE, 0, 0)); - // FIXME: don't duplicate this palette for every aux_pixmap - (*pixmap)->palette = new Palette(default_colors, DEFAULT_COLORS_NR); -} - -void gfxop_init(GfxState *state, ResourceManager *resMan, - SciGuiScreen *screen, SciGuiPalette *palette, int scaleFactor) { - state->visible_map = GFX_MASK_VISUAL; - state->disable_dirty = 0; - state->pic = state->pic_unscaled = NULL; - state->pic_nr = -1; // Set background pic number to an invalid value - state->tag_mode = 0; - state->_dirtyRects.clear(); - - // Jones in the Fast Lane uses up the whole window - if (!scumm_stricmp(((SciEngine *)g_engine)->getGameID(), "jones")) - state->pic_port_bounds = gfx_rect(0, 0, 320, 200); - else - state->pic_port_bounds = gfx_rect(0, 10, 320, 190); - - state->driver = new GfxDriver(screen, scaleFactor); - - state->gfxResMan = new GfxResManager(state->driver, resMan, screen, palette, toCommonRect(state->pic_port_bounds)); - - gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); - - init_aux_pixmap(&(state->control_map)); - init_aux_pixmap(&(state->priority_map)); - init_aux_pixmap(&(state->static_priority_map)); -} - -void gfxop_exit(GfxState *state) { - state->gfxResMan->freeResManager(); - - if (state->control_map) { - gfx_free_pixmap(state->control_map); - state->control_map = NULL; - } - - if (state->priority_map) { - gfx_free_pixmap(state->priority_map); - state->priority_map = NULL; - } - - if (state->static_priority_map) { - gfx_free_pixmap(state->static_priority_map); - state->static_priority_map = NULL; - } - - delete state->driver; -} - -static int _gfxop_scan_one_bitmask(gfx_pixmap_t *pixmap, rect_t zone) { - int retval = 0; - int pixmap_xscale = pixmap->index_width / 320; - int pixmap_yscale = pixmap->index_height / 200; - int line_width = pixmap_yscale * pixmap->index_width; - int startindex = (line_width * zone.y) + (zone.x * pixmap_xscale); - - startindex += pixmap_xscale >> 1; // Center on X - startindex += (pixmap_yscale >> 1) * pixmap->index_width; // Center on Y - - if (_gfxop_clip(&zone, gfx_rect(0, 0, pixmap->index_width, pixmap->index_height))) - return 0; - - while (zone.height--) { - int i; - for (i = 0; i < (zone.width * pixmap_xscale); i += pixmap_xscale) - retval |= (1 << ((pixmap->index_data[startindex + i]) & 0xf)); - - startindex += line_width; - } - - return retval; -} - -int gfxop_scan_bitmask(GfxState *state, rect_t area, gfx_map_mask_t map) { - gfxr_pic_t *pic = (state->pic_unscaled) ? state->pic_unscaled : state->pic; - int retval = 0; - - _gfxop_clip(&area, gfx_rect(0, 10, 320, 200)); - - if (area.width <= 0 - || area.height <= 0) - return 0; - - if (map & GFX_MASK_VISUAL) - retval |= _gfxop_scan_one_bitmask(pic->visual_map, area); - - if (map & GFX_MASK_PRIORITY) - retval |= _gfxop_scan_one_bitmask(state->priority_map, area); - if (map & GFX_MASK_CONTROL) - retval |= _gfxop_scan_one_bitmask(state->control_map, area); - - return retval; -} - -#define MIN_X 0 -#define MIN_Y 0 -#define MAX_X 319 -#define MAX_Y 199 - -void gfxop_set_clip_zone(GfxState *state, rect_t zone) { - int xfact, yfact; - - DDIRTY(stderr, "-- Setting clip zone %d %d %d %d\n", GFX_PRINT_RECT(zone)); - - xfact = state->driver->getMode()->scaleFactor; - yfact = state->driver->getMode()->scaleFactor; - - if (zone.x < MIN_X) { - zone.width -= (zone.x - MIN_X); - zone.x = MIN_X; - } - - if (zone.y < MIN_Y) { - zone.height -= (zone.y - MIN_Y); - zone.y = MIN_Y; - } - - if (zone.x + zone.width > MAX_X) - zone.width = MAX_X + 1 - zone.x; - - if (zone.y + zone.height > MAX_Y) - zone.height = MAX_Y + 1 - zone.y; - - memcpy(&(state->clip_zone_unscaled), &zone, sizeof(rect_t)); - - state->clip_zone.x = state->clip_zone_unscaled.x * xfact; - state->clip_zone.y = state->clip_zone_unscaled.y * yfact; - state->clip_zone.width = state->clip_zone_unscaled.width * xfact; - state->clip_zone.height = state->clip_zone_unscaled.height * yfact; -} - -void gfxop_set_color(GfxState *state, gfx_color_t *color, int r, int g, int b, int a, int priority, int control) { - int mask = ((r >= 0 && g >= 0 && b >= 0) ? GFX_MASK_VISUAL : 0) | ((priority >= 0) ? GFX_MASK_PRIORITY : 0) - | ((control >= 0) ? GFX_MASK_CONTROL : 0); - - if (a >= GFXOP_ALPHA_THRESHOLD) - mask &= ~GFX_MASK_VISUAL; - - color->mask = mask; - - color->priority = priority; - color->control = control; - - if (mask & GFX_MASK_VISUAL) { - color->visual.r = r; - color->visual.g = g; - color->visual.b = b; - color->alpha = a; - color->visual._parentIndex = SCREEN_PALETTE->findNearbyColor(r,g,b,true); - } -} - -// Wrapper for gfxop_set_color -void gfxop_set_color(GfxState *state, gfx_color_t *colorOut, gfx_color_t &colorIn) { - gfxop_set_color(state, colorOut, - (colorIn.mask & GFX_MASK_VISUAL) ? colorIn.visual.r : -1, - (colorIn.mask & GFX_MASK_VISUAL) ? colorIn.visual.g : -1, - (colorIn.mask & GFX_MASK_VISUAL) ? colorIn.visual.b : -1, - (colorIn.mask & GFX_MASK_VISUAL) ? colorIn.alpha : -1, - (colorIn.mask & GFX_MASK_PRIORITY) ? colorIn.priority : -1, - (colorIn.mask & GFX_MASK_CONTROL) ? colorIn.control : -1); -} - -// Generic drawing operations - -static int line_check_bar(int *start, int *length, int clipstart, int cliplength) { - int overlength; - - if (*start < clipstart) { - *length -= (clipstart - *start); - *start = clipstart; - } - - overlength = 1 + (*start + *length) - (clipstart + cliplength); - - if (overlength > 0) - *length -= overlength; - - return (*length < 0); -} - -static void clip_line_partial(float *start, float *end, float delta_val, float pos_val, float start_val, float end_val) { - float my_start = (start_val - pos_val) * delta_val; - float my_end = (end_val - pos_val) * delta_val; - - if (my_end < *end) - *end = my_end; - if (my_start > *start) - *start = my_start; -} - -static int line_clip(rect_t *line, rect_t clip, int xfact, int yfact) { - // returns 1 if nothing is left, or 0 if part of the line is in the clip window - // Compensate for line thickness (should match precisely) - clip.width -= xfact; - clip.height -= yfact; - - if (!line->width) { // vbar - if (line->x < clip.x || line->x >= (clip.x + clip.width)) - return 1; - - return line_check_bar(&(line->y), &(line->height), clip.y, clip.height); - - } else { - if (!line->height) {// hbar - if (line->y < clip.y || line->y >= (clip.y + clip.height)) - return 1; - - return line_check_bar(&(line->x), &(line->width), clip.x, clip.width); - - } else { // "normal" line - float start = 0.0f, end = 1.0f; - float xv = (float)line->width; - float yv = (float)line->height; - - if (line->width < 0) - clip_line_partial(&start, &end, (float)(1.0 / xv), (float)line->x, (float)(clip.x + clip.width), (float)clip.x); - else - clip_line_partial(&start, &end, (float)(1.0 / xv), (float)line->x, (float)clip.x, (float)(clip.x + clip.width)); - - if (line->height < 0) - clip_line_partial(&start, &end, (float)(1.0 / yv), (float)line->y, (float)(clip.y + clip.height), (float)clip.y); - else - clip_line_partial(&start, &end, (float)(1.0 / yv), (float)line->y, (float)clip.y, (float)(clip.y + clip.height)); - - line->x += (int)(xv * start); - line->y += (int)(yv * start); - - line->width = (int)(xv * (end - start)); - line->height = (int)(yv * (end - start)); - - return (start > 1.0f || end < 0.0f); - } - } - - return 0; -} - -static int point_clip(Common::Point *start, Common::Point *end, rect_t clip, int xfact, int yfact) { - rect_t line = gfx_rect(start->x, start->y, end->x - start->x, end->y - start->y); - int retval = line_clip(&line, clip, xfact, yfact); - - start->x = line.x; - start->y = line.y; - - end->x = line.x + line.width; - end->y = line.y + line.height; - - return retval; -} - -static void draw_line_to_control_map(GfxState *state, Common::Point start, Common::Point end, gfx_color_t color) { - if (color.mask & GFX_MASK_CONTROL) - if (!point_clip(&start, &end, state->clip_zone_unscaled, 0, 0)) - gfx_draw_line_pixmap_i(state->control_map, start, end, color.control); -} - -static void simulate_stippled_line_draw(GfxDriver *driver, int skipone, Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode) { - // Draws a stippled line if this isn't supported by the driver (skipone is ignored ATM) - int xl = end.x - start.x; - int yl = end.y - start.y; - int stepwidth = (xl) ? driver->getMode()->scaleFactor : driver->getMode()->scaleFactor; - int dbl_stepwidth = 2 * stepwidth; - int linelength = (line_mode == GFX_LINE_MODE_FINE) ? stepwidth - 1 : 0; - int16 *posvar; - int length; - int delta; - int length_left; - - if (!xl) { // xl = 0, so we move along yl - posvar = &start.y; - length = yl; - delta = (yl < 0) ? -dbl_stepwidth : dbl_stepwidth; - } else { - assert(!yl); // We don't do diagonals; that's not needed ATM. - posvar = &start.x; - length = xl; - delta = (xl < 0) ? -dbl_stepwidth : dbl_stepwidth; - } - - length_left = length; - - if (skipone) { - length_left -= stepwidth; - *posvar += stepwidth; - } - - length /= delta; - - length_left -= length * dbl_stepwidth; - - if (xl) - xl = linelength; - else - yl = linelength; - - while (length--) { - Common::Point nextpos = Common::Point(start.x + xl, start.y + yl); - driver->drawLine(start, nextpos, color, line_mode, GFX_LINE_STYLE_NORMAL); - *posvar += delta; - } - - if (length_left) { - Common::Point nextpos; - - if (length_left > stepwidth) - length_left = stepwidth; - - if (xl) - xl = length_left; - else - if (yl) - yl = length_left; - - nextpos = Common::Point(start.x + xl, start.y + yl); - - driver->drawLine(start, nextpos, color, line_mode, GFX_LINE_STYLE_NORMAL); - } -} - -static void _gfxop_draw_line_clipped(GfxState *state, Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, - gfx_line_style_t line_style) { - int skipone = (start.x ^ end.y) & 1; // Used for simulated line stippling - - // First, make sure that the line is normalized - if (start.y > end.y) { - Common::Point swap = start; - start = end; - end = swap; - } - - if (start.x < state->clip_zone.x - || start.y < state->clip_zone.y - || end.x >= (state->clip_zone.x + state->clip_zone.width) - || end.y >= (state->clip_zone.y + state->clip_zone.height)) - if (point_clip(&start, &end, state->clip_zone, state->driver->getMode()->scaleFactor - 1, state->driver->getMode()->scaleFactor - 1)) - return; // Clipped off - - if (line_style == GFX_LINE_STYLE_STIPPLED) { - if (start.x != end.x && start.y != end.y) - error("[GFX] Attempt to draw stippled line which is neither an hbar nor a vbar: (%d,%d) -- (%d,%d)", start.x, start.y, end.x, end.y); - simulate_stippled_line_draw(state->driver, skipone, start, end, color, line_mode); - } - - state->driver->drawLine(start, end, color, line_mode, line_style); -} - -void gfxop_draw_line(GfxState *state, Common::Point start, Common::Point end, - gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { - int xfact, yfact; - - _gfxop_add_dirty_x(state, gfx_rect(start.x, start.y, end.x - start.x, end.y - start.y)); - - xfact = state->driver->getMode()->scaleFactor; - yfact = state->driver->getMode()->scaleFactor; - - draw_line_to_control_map(state, start, end, color); - - _gfxop_scale_point(&start, state->driver->getMode()); - _gfxop_scale_point(&end, state->driver->getMode()); - - if (line_mode == GFX_LINE_MODE_FINE) { - start.x += xfact >> 1; - start.y += yfact >> 1; - - end.x += xfact >> 1; - end.y += yfact >> 1; - } - - if (color.visual.getParentIndex() == -1) - gfxop_set_color(state, &color, color); - _gfxop_draw_line_clipped(state, start, end, color, line_mode, line_style); -} - -void gfxop_draw_rectangle(GfxState *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) { - int xfact, yfact; - int x, y, xl, yl; - Common::Point upper_left_u, upper_right_u, lower_left_u, lower_right_u; - Common::Point upper_left, upper_right, lower_left, lower_right; - - xfact = state->driver->getMode()->scaleFactor; - yfact = state->driver->getMode()->scaleFactor; - - int offset = line_mode == GFX_LINE_MODE_FINE ? 1 : 0; - x = rect.x * xfact + (xfact - 1) * offset; - y = rect.y * yfact + (yfact - 1) * offset; - xl = offset + (rect.width - offset) * xfact; - yl = offset + (rect.height - offset) * yfact; - - upper_left_u = Common::Point(rect.x, rect.y); - upper_right_u = Common::Point(rect.x + rect.width, rect.y); - lower_left_u = Common::Point(rect.x, rect.y + rect.height); - lower_right_u = Common::Point(rect.x + rect.width, rect.y + rect.height); - - upper_left = Common::Point(x, y); - upper_right = Common::Point(x + xl, y); - lower_left = Common::Point(x, y + yl); - lower_right = Common::Point(x + xl, y + yl); - -#define PARTIAL_LINE(pt1, pt2) \ - _gfxop_draw_line_clipped(state, pt1, pt2, color, line_mode, line_style); \ - draw_line_to_control_map(state, pt1##_u, pt2##_u, color); \ - _gfxop_add_dirty_x(state, gfx_rect(pt1##_u.x, pt1##_u.y, pt2##_u.x - pt1##_u.x, pt2##_u.y - pt1##_u.y)) - - PARTIAL_LINE(upper_left, upper_right); - PARTIAL_LINE(upper_right, lower_right); - PARTIAL_LINE(lower_right, lower_left); - PARTIAL_LINE(lower_left, upper_left); - -#undef PARTIAL_LINE -} - - -void gfxop_draw_box(GfxState *state, rect_t box, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type) { - GfxDriver *drv = state->driver; - int reverse = 0; // switch color1 and color2 - float mod_offset = 0.0f, mod_breadth = 1.0f; // 0.0 to 1.0: Color adjustment - gfx_rectangle_fill_t driver_shade_type; - rect_t new_box; - - shade_type = GFX_BOX_SHADE_FLAT; - - _gfxop_add_dirty(state, box); - - if (color1.mask & GFX_MASK_CONTROL) { - // Write control block, clipped by 320x200 - memcpy(&new_box, &box, sizeof(rect_t)); - _gfxop_clip(&new_box, gfx_rect(0, 0, 320, 200)); - - gfx_draw_box_pixmap_i(state->control_map, new_box, color1.control); - } - - _gfxop_scale_rect(&box, state->driver->getMode()); - - if (!(color1.mask & (GFX_MASK_VISUAL | GFX_MASK_PRIORITY))) - return; - - if (box.width <= 1 || box.height <= 1) { - debugC(2, kDebugLevelGraphics, "Attempt to draw box with size %dx%d", box.width, box.height); - return; - } - - memcpy(&new_box, &box, sizeof(rect_t)); - if (_gfxop_clip(&new_box, state->clip_zone)) - return; - - switch (shade_type) { - - case GFX_BOX_SHADE_FLAT: - driver_shade_type = GFX_SHADE_FLAT; - break; - - case GFX_BOX_SHADE_LEFT: - reverse = 1; - case GFX_BOX_SHADE_RIGHT: - driver_shade_type = GFX_SHADE_HORIZONTALLY; - mod_offset = (float)(((new_box.x - box.x) * 1.0) / (box.width * 1.0)); - mod_breadth = (float)((new_box.width * 1.0) / (box.width * 1.0)); - break; - - case GFX_BOX_SHADE_UP: - reverse = 1; - case GFX_BOX_SHADE_DOWN: - driver_shade_type = GFX_SHADE_VERTICALLY; - mod_offset = (float)(((new_box.y - box.y) * 1.0) / (box.height * 1.0)); - mod_breadth = (float)((new_box.height * 1.0) / (box.height * 1.0)); - break; - - default: - error("Invalid shade type: %d", shade_type); - } - - - if (reverse) - mod_offset = (float)(1.0 - (mod_offset + mod_breadth)); - // Reverse offset if we have to interpret colors inversely - - if (shade_type == GFX_BOX_SHADE_FLAT) { - color1.priority = 0; - color1.control = 0; - if (color1.visual.getParentIndex() == -1) - gfxop_set_color(state, &color1, color1); - drv->drawFilledRect(new_box, color1, color1, GFX_SHADE_FLAT); - return; - } -} - -void gfxop_fill_box(GfxState *state, rect_t box, gfx_color_t color) { - gfxop_draw_box(state, box, color, color, GFX_BOX_SHADE_FLAT); -} - -extern int sci0_palette; - -void gfxop_clear_box(GfxState *state, rect_t box) { - _gfxop_add_dirty(state, box); - DDIRTY(stderr, "[] clearing box %d %d %d %d\n", GFX_PRINT_RECT(box)); - - _gfxop_clip(&box, gfx_rect(0, 0, 320, 200)); -#ifdef PRECISE_PRIORITY_MAP - if (state->pic_unscaled) - gfx_copy_pixmap_box_i(state->priority_map, state->static_priority_map, box); -#endif - - _gfxop_scale_rect(&box, state->driver->getMode()); - - _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_BACK); -} - -void gfxop_update(GfxState *state) { - _gfxop_clear_dirty_rec(state, state->_dirtyRects); - - if (state->tag_mode) { - // This usually happens after a pic and all resources have been drawn - state->gfxResMan->freeTaggedResources(); - state->tag_mode = 0; - } -} - -void gfxop_update_box(GfxState *state, rect_t box) { - if (state->disable_dirty) - _gfxop_update_box(state, box); - else - _gfxop_add_dirty(state, box); - - gfxop_update(state); -} - -void gfxop_enable_dirty_frames(GfxState *state) { - state->disable_dirty = 0; -} - -void gfxop_disable_dirty_frames(GfxState *state) { - state->disable_dirty = 1; -} - -// View operations - -void gfxop_get_cel_parameters(GfxState *state, int nr, int loop, int cel, int *width, int *height, Common::Point *offset) { - gfxr_view_t *view = NULL; - gfx_pixmap_t *pxm = NULL; - - view = state->gfxResMan->getView(nr, &loop, &cel, 0); - - if (!view) - error("[GFX] Attempt to get cel parameters for invalid view %d", nr); - - pxm = view->loops[loop].cels[cel]; - *width = pxm->index_width; - *height = pxm->index_height; - offset->x = pxm->xoffset; - offset->y = pxm->yoffset; -} - -static void _gfxop_draw_cel_buffer(GfxState *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int static_buf, int palette) { - int priority = (color.mask & GFX_MASK_PRIORITY) ? color.priority : -1; - int control = (color.mask & GFX_MASK_CONTROL) ? color.control : -1; - gfxr_view_t *view = NULL; - gfx_pixmap_t *pxm = NULL; - int old_x, old_y; - - view = state->gfxResMan->getView(nr, &loop, &cel, palette); - - if (!view) { - warning("[GFX] Attempt to draw loop/cel %d/%d in invalid view %d\n", loop, cel, nr); - return; - } - pxm = view->loops[loop].cels[cel]; - - old_x = pos.x -= pxm->xoffset; - old_y = pos.y -= pxm->yoffset; - - pos.x *= state->driver->getMode()->scaleFactor; - pos.y *= state->driver->getMode()->scaleFactor; - - if (!static_buf) - _gfxop_add_dirty(state, gfx_rect(old_x, old_y, pxm->index_width, pxm->index_height)); - - _gfxop_draw_pixmap(state->driver, pxm, priority, control, gfx_rect(0, 0, pxm->width, pxm->height), - gfx_rect(pos.x, pos.y, pxm->width, pxm->height), state->clip_zone, static_buf , state->control_map, - static_buf ? state->static_priority_map : state->priority_map); -} - -void gfxop_draw_cel(GfxState *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) { - _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 0, palette); -} - -void gfxop_draw_cel_static(GfxState *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) { - rect_t oldclip = state->clip_zone; - - state->clip_zone = gfx_rect_fullscreen; - _gfxop_scale_rect(&(state->clip_zone), state->driver->getMode()); - gfxop_draw_cel_static_clipped(state, nr, loop, cel, pos, color, palette); - // Except that the area it's clipped against is... unusual ;-) - state->clip_zone = oldclip; -} - -void gfxop_draw_cel_static_clipped(GfxState *state, int nr, int loop, int cel, Common::Point pos, gfx_color_t color, int palette) { - _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 1, palette); -} - -// Pic operations - -static void _gfxop_set_pic(GfxState *state) { - gfx_copy_pixmap_box_i(state->control_map, state->pic->control_map, gfx_rect(0, 0, 320, 200)); - gfx_copy_pixmap_box_i(state->priority_map, state->pic_unscaled->priority_map, gfx_rect(0, 0, 320, 200)); - gfx_copy_pixmap_box_i(state->static_priority_map, state->pic_unscaled->priority_map, gfx_rect(0, 0, 320, 200)); - - // Reset global palette to this PIC's palette - // FIXME: The _gfxop_install_pixmap call below updates the OSystem palette. - // This is too soon, since it causes brief palette corruption until the - // screen is updated too. (Possibly related: EngineState::pic_not_valid .) - if (state->pic->visual_map->palette) { - state->pic->visual_map->palette->forceInto(SCREEN_PALETTE); - _gfxop_install_pixmap(state->driver, state->pic->visual_map); - } - - state->driver->setStaticBuffer(state->pic->visual_map, state->pic->priority_map); -} - -void gfxop_new_pic(GfxState *state, int nr, int flags, int default_palette) { - state->gfxResMan->tagResources(); - state->tag_mode = 1; - state->palette_nr = default_palette; - state->pic = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, true); - - if (state->driver->getMode()->scaleFactor == 1 && state->driver->getMode()->scaleFactor == 1) { - state->pic_unscaled = state->pic; - } else { - state->pic_unscaled = state->gfxResMan->getPic(nr, GFX_MASK_VISUAL, flags, default_palette, false); - } - - if (!state->pic || !state->pic_unscaled) { - warning("Could not retrieve background pic %d", nr); - if (state->pic) { - warning(" -- Inconsistency: scaled pic _was_ retrieved!"); - } - - if (state->pic_unscaled) { - warning(" -- Inconsistency: unscaled pic _was_ retrieved!"); - } - - error("Error occured in gfxop_new_pic()"); - state->pic = state->pic_unscaled = NULL; - } - - state->pic_nr = nr; - - _gfxop_set_pic(state); -} - -void gfxop_add_to_pic(GfxState *state, int nr, int flags, int default_palette) { - if (!state->pic) - error("Attempt to add to pic with no pic active"); - - state->pic = state->gfxResMan->addToPic(state->pic_nr, nr, flags, state->palette_nr, default_palette); - - if (!state->pic) - error("Could not add pic #%d to pic #%d", state->pic_nr, nr); - - state->pic_unscaled = state->gfxResMan->addToPic(state->pic_nr, nr, flags, state->palette_nr, default_palette); - - _gfxop_set_pic(state); -} - -// Text operations - -void gfxop_get_text_params(GfxState *state, int font_nr, const char *text, int maxwidth, int *width, int *height, int text_flags, - int *lines_nr, int *lineheight, int *lastline_width) { - Common::Array<TextFragment> fragments; - bool textsplits; - gfx_bitmap_font_t *font; - - font = state->gfxResMan->getFont(font_nr); - - if (!font) - error("Attempt to calculate text size with invalid font #%d", font_nr); - - textsplits = gfxr_font_calculate_size(fragments, font, maxwidth, text, width, height, lineheight, lastline_width, text_flags); - - if (!textsplits) - error("Could not calculate text size"); - - if (lines_nr) - *lines_nr = fragments.size(); -} - -TextHandle *gfxop_new_text(GfxState *state, int font_nr, const Common::String &text, int maxwidth, gfx_alignment_t halign, - gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, gfx_color_t bg_color, int flags) { - TextHandle *handle; - gfx_bitmap_font_t *font; - - // mapping text colors to palette - gfxop_set_color(state, &color1, color1); - gfxop_set_color(state, &color2, color2); - gfxop_set_color(state, &bg_color, bg_color); - - font = state->gfxResMan->getFont(font_nr); - - if (!font) { - error("Attempt to draw text with invalid font #%d", font_nr); - return NULL; - } - - handle = new TextHandle(); - - handle->_text = text; - handle->halign = halign; - handle->valign = valign; - handle->line_height = font->line_height; - - bool result = gfxr_font_calculate_size(handle->lines, font, maxwidth, handle->_text.c_str(), &(handle->width), &(handle->height), - NULL, NULL, flags); - - if (!result) { - error("Could not calculate text parameters in font #%d", font_nr); - delete handle; - return NULL; - } - - if (flags & kFontNoNewlines) { - handle->lines.resize(1); - handle->lines[0].length = text.size(); - } - - handle->text_pixmaps.resize(handle->lines.size()); - - for (uint i = 0; i < handle->lines.size(); i++) { - int chars_nr = handle->lines[i].length; - - handle->text_pixmaps[i] = gfxr_draw_font(font, handle->lines[i].offset, chars_nr, - (color1.mask & GFX_MASK_VISUAL) ? &color1.visual : NULL, - (color2.mask & GFX_MASK_VISUAL) ? &color2.visual : NULL, - (bg_color.mask & GFX_MASK_VISUAL) ? &bg_color.visual : NULL); - - if (!handle->text_pixmaps[i]) { - error("Failed to draw text pixmap for line %d/%d", i, handle->lines.size()); - delete handle; - return NULL; - } - } - - handle->font = font; - - handle->priority = (color1.mask & GFX_MASK_PRIORITY) ? color1.priority : -1; - handle->control = (color1.mask & GFX_MASK_CONTROL) ? color1.control : -1; - - return handle; -} - -TextHandle::TextHandle() { - line_height = 0; - font = 0; - - width = height = 0; - - priority = control = 0; - halign = valign = ALIGN_BOTTOM; -} - -TextHandle::~TextHandle() { - for (uint j = 0; j < text_pixmaps.size(); j++) - if (text_pixmaps[j]) - gfx_free_pixmap(text_pixmaps[j]); -} - -void gfxop_draw_text(GfxState *state, TextHandle *handle, rect_t zone) { - int line_height; - rect_t pos; - - if (!handle) - error("Attempt to draw text with NULL handle"); - - if (handle->lines.empty()) { - debugC(2, kDebugLevelGraphics, "Skipping draw_text operation because number of lines is zero\n"); - return; - } - - _gfxop_scale_rect(&zone, state->driver->getMode()); - - line_height = handle->line_height * state->driver->getMode()->scaleFactor; - - pos.y = zone.y; - - switch (handle->valign) { - - case ALIGN_TOP: - break; - - case ALIGN_CENTER: - pos.y += (zone.height - (line_height * handle->lines.size())) >> 1; - break; - - case ALIGN_BOTTOM: - pos.y += (zone.height - (line_height * handle->lines.size())); - break; - - default: - error("Invalid vertical alignment %d", handle->valign); - } - - for (uint i = 0; i < handle->lines.size(); i++) { - - gfx_pixmap_t *pxm = handle->text_pixmaps[i]; - - if (!pxm->data) { - gfx_xlate_pixmap(pxm, state->driver->getMode()); - } - if (!pxm) - error("Could not find text pixmap %d/%d", i, handle->lines.size()); - - pos.x = zone.x; - - switch (handle->halign) { - - case ALIGN_LEFT: - break; - - case ALIGN_CENTER: - pos.x += (zone.width - pxm->width) >> 1; - break; - - case ALIGN_RIGHT: - pos.x += (zone.width - pxm->width); - break; - - default: - error("Invalid vertical alignment %d", handle->valign); - } - - pos.width = pxm->width; - pos.height = pxm->height; - - _gfxop_add_dirty(state, pos); - _gfxop_draw_pixmap(state->driver, pxm, handle->priority, handle->control, - gfx_rect(0, 0, pxm->width, pxm->height), pos, state->clip_zone, 0, state->control_map, state->priority_map); - - pos.y += line_height; - } -} - -gfx_pixmap_t *gfxop_grab_pixmap(GfxState *state, rect_t area) { - gfx_pixmap_t *pixmap = NULL; - rect_t resultzone; // Ignored for this application - - _gfxop_scale_rect(&area, state->driver->getMode()); - _gfxop_grab_pixmap(state, &pixmap, area.x, area.y, area.width, area.height, 0, &resultzone); - - return pixmap; -} - -void gfxop_draw_pixmap(GfxState *state, gfx_pixmap_t *pxm, rect_t zone, Common::Point pos) { - rect_t target = gfx_rect(pos.x, pos.y, zone.width, zone.height); - - if (!pxm) - error("Attempt to draw NULL pixmap"); - - _gfxop_add_dirty(state, target); - - _gfxop_scale_rect(&zone, state->driver->getMode()); - _gfxop_scale_rect(&target, state->driver->getMode()); - - return _gfxop_draw_pixmap(state->driver, pxm, -1, -1, zone, target, gfx_rect(0, 0, 320*state->driver->getMode()->scaleFactor, - 200*state->driver->getMode()->scaleFactor), 0, NULL, NULL); -} - - - -#endif // INCLUDE_OLDGFX - -} // End of namespace Sci |