mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-11 05:36:12 +00:00
1874 lines
57 KiB
C++
1874 lines
57 KiB
C++
/* 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 <time.h> // for time() to seed rand() via srand()
|
|
#include "sci/include/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
|
|
|
|
gfx_pixmap_color_t gfx_sci0_pic_colors[GFX_SCI0_PIC_COLORS_NR]; // Initialized during initialization
|
|
|
|
static int _gfxr_pic0_colors_initialized = 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 (!_gfxr_pic0_colors_initialized) {
|
|
for (int i = 0; i < 256; i++) {
|
|
gfx_sci0_pic_colors[i].global_index = GFX_COLOR_INDEX_UNMAPPED;
|
|
gfx_sci0_pic_colors[i].r = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].r,
|
|
gfx_sci0_image_colors[sci0_palette][i >> 4].r);
|
|
gfx_sci0_pic_colors[i].g = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].g,
|
|
gfx_sci0_image_colors[sci0_palette][i >> 4].g);
|
|
gfx_sci0_pic_colors[i].b = INTERCOL(gfx_sci0_image_colors[sci0_palette][i & 0xf].b,
|
|
gfx_sci0_image_colors[sci0_palette][i >> 4].b);
|
|
}
|
|
//warning("Uncomment me after fixing sci0_palette changes to reset me");
|
|
//_gfxr_pic0_colors_initialized = 1;
|
|
}
|
|
}
|
|
|
|
|
|
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));
|
|
pic->visual_map->colors = gfx_sci0_pic_colors;
|
|
pic->visual_map->colors_nr = GFX_SCI0_PIC_COLORS_NR;
|
|
pic->visual_map->color_key = GFX_PIXMAP_COLOR_KEY_NONE;
|
|
|
|
pic->visual_map->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE;
|
|
pic->priority_map->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE;
|
|
pic->control_map->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE;
|
|
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->colors = gfx_sci0_image_colors[sci0_palette];
|
|
pic->priority_map->colors_nr = GFX_SCI0_IMAGE_COLORS_NR;
|
|
pic->control_map->colors = gfx_sci0_image_colors[sci0_palette];
|
|
pic->control_map->colors_nr = GFX_SCI0_IMAGE_COLORS_NR;
|
|
|
|
// Initialize colors
|
|
if (!sci1) {
|
|
pic->ID = ID;
|
|
gfxr_init_static_palette();
|
|
}
|
|
|
|
pic->undithered_buffer_size = pic->visual_map->index_xl * pic->visual_map->index_yl;
|
|
pic->undithered_buffer = NULL;
|
|
pic->internal = 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.xl;
|
|
dy = line.yl;
|
|
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.xl;
|
|
dy = line.yl;
|
|
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
|
|
|
|
|
|
static inline void
|
|
_gfxr_auxbuf_tag_line(gfxr_pic_t *pic, int pos, int width) {
|
|
int i;
|
|
for (i = 0; i < width; i++)
|
|
pic->aux_map[i+pos] |= FRESH_PAINT;
|
|
}
|
|
|
|
#if 0
|
|
// 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].xl = 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].xl > xr + 1)
|
|
done = 1;
|
|
|
|
else if (intervals[!ivi][i].xr < xl - 1) {
|
|
int o_xl = intervals[!ivi][i].xl;
|
|
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].xl;
|
|
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].xl <= 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].xl, 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 inline 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.xl = ((xsize + 1) << 1) + 1;
|
|
boundaries.yl = (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 inline 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_xl || ey >= pic->visual_map->index_yl || 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.xl = ex - x;
|
|
line.yl = 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.xl, y + line.yl), 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.xl = scale_x;
|
|
drawrect.yl = 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 inline 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 "sci_picfill_aux.cpp"
|
|
# include "sci_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 "sci_picfill_aux.cpp"
|
|
# include "sci_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++);
|
|
|
|
|
|
inline 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, byte *pic_index_data, int posx, int posy, int width, int height) {
|
|
int i, j;
|
|
|
|
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, gfx_pixmap_color_t *static_pal, int static_pal_nr) {
|
|
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);
|
|
pic->visual_map->flags &= ~GFX_PIXMAP_FLAG_EXTERNAL_PALETTE;
|
|
pic->visual_map->colors = gfxr_read_pal1(resid, &pic->visual_map->colors_nr,
|
|
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;
|
|
gfx_mode_t *mode;
|
|
|
|
p0printf("Embedded view @%d\n", pos);
|
|
|
|
// Set up mode structure for resizing the view
|
|
mode = gfx_new_mode(pic->visual_map->index_xl / 320,
|
|
pic->visual_map->index_yl / 200, 1, // 1bpp, which handles masks and the rest for us
|
|
0, 0, 0, 0, 0, 0, 0, 0, 16, 0);
|
|
|
|
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_nr == GFX_SCI1_AMIGA_COLORS_NR);
|
|
pos += bytesize;
|
|
if (nodraw)
|
|
continue;
|
|
p0printf("(%d, %d)-(%d, %d)\n", posx, posy, posx + view->index_xl, posy + view->index_yl);
|
|
|
|
// we can only safely replace the palette if it's static
|
|
// *if it's not for some reason, we should die
|
|
|
|
if (!(view->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE) && !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_nr == GFX_SCI1_AMIGA_COLORS_NR) {
|
|
// Assume Amiga game
|
|
pic->visual_map->colors = static_pal;
|
|
pic->visual_map->colors_nr = static_pal_nr;
|
|
pic->visual_map->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE;
|
|
}
|
|
view->colors = pic->visual_map->colors;
|
|
view->colors_nr = pic->visual_map->colors_nr;
|
|
} else
|
|
view->colors = embedded_view_colors;
|
|
|
|
// Hack to prevent overflowing the visual map buffer.
|
|
// Yes, this does happen otherwise.
|
|
if (view->index_yl + sci_titlebar_size > 200)
|
|
sci_titlebar_size = 0;
|
|
|
|
gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE);
|
|
|
|
if (flags & DRAWPIC01_FLAG_OVERLAID_PIC)
|
|
view_transparentize(view, pic->visual_map->index_data, posx, sci_titlebar_size + posy,
|
|
view->index_xl, view->index_yl);
|
|
|
|
_gfx_crossblit_simple(pic->visual_map->index_data + (sci_titlebar_size * 320) + posy * 320 + posx,
|
|
view->index_data, pic->visual_map->index_xl, view->index_xl,
|
|
view->index_xl, view->index_yl, 1);
|
|
|
|
gfx_free_mode(mode);
|
|
gfx_free_pixmap(NULL, view);
|
|
}
|
|
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->internal) {
|
|
pic->internal = sci_malloc(16 * sizeof(int));
|
|
} else {
|
|
GFXERROR("pic->internal is not NULL (%p); this only occurs with overlaid pics, otherwise it's a bug", pic->internal);
|
|
}
|
|
|
|
pri_table = (int*)pic->internal;
|
|
|
|
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 = getInt16(resource + pos);
|
|
int last = getInt16(resource + pos + 2);
|
|
int nr;
|
|
int *pri_table;
|
|
|
|
if (!pic->internal) {
|
|
pic->internal = sci_malloc(16 * sizeof(int));
|
|
} else {
|
|
GFXERROR("pic->internal is not NULL (%p); possible memory corruption", pic->internal);
|
|
}
|
|
|
|
pri_table = (int*)pic->internal;
|
|
|
|
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, gfx_pixmap_color_t *static_pal, int static_pal_nr) {
|
|
int has_bitmap = getUInt16(resource + 4);
|
|
int vector_data_ptr = getUInt16(resource + 16);
|
|
int palette_data_ptr = getUInt16(resource + 28);
|
|
int bitmap_data_ptr = getUInt16(resource + 32);
|
|
int sci_titlebar_size = style->pic_port_bounds.y;
|
|
gfx_mode_t *mode;
|
|
gfx_pixmap_t *view = NULL;
|
|
// Set up mode structure for resizing the view
|
|
mode = gfx_new_mode(pic->visual_map->index_xl / 320, pic->visual_map->index_yl / 200,
|
|
1, // 1bpp, which handles masks and the rest for us
|
|
0, 0, 0, 0, 0, 0, 0, 0, 16, 0);
|
|
|
|
pic->visual_map->colors = gfxr_read_pal11(-1, &(pic->visual_map->colors_nr), 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->colors = pic->visual_map->colors;
|
|
view->colors_nr = pic->visual_map->colors_nr;
|
|
|
|
gfx_xlate_pixmap(view, mode, GFX_XLATE_FILTER_NONE);
|
|
|
|
if (flags & DRAWPIC01_FLAG_OVERLAID_PIC)
|
|
view_transparentize(view, pic->visual_map->index_data, 0, 0, view->index_xl, view->index_yl);
|
|
|
|
// Hack to prevent overflowing the visual map buffer.
|
|
// Yes, this does happen otherwise.
|
|
if (view->index_yl + sci_titlebar_size > 200)
|
|
sci_titlebar_size = 0;
|
|
|
|
_gfx_crossblit_simple(pic->visual_map->index_data + sci_titlebar_size*view->index_xl,
|
|
view->index_data,
|
|
pic->visual_map->index_xl, view->index_xl,
|
|
view->index_xl,
|
|
view->index_yl,
|
|
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, static_pal_nr);
|
|
}
|
|
|
|
void gfxr_dither_pic0(gfxr_pic_t *pic, int dmode, int pattern) {
|
|
int xl = pic->visual_map->index_xl;
|
|
int yl = pic->visual_map->index_yl;
|
|
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->colors = gfx_sci0_image_colors[sci0_palette];
|
|
pic->visual_map->colors_nr = GFX_SCI0_IMAGE_COLORS_NR;
|
|
}
|
|
|
|
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
|