diff options
author | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
---|---|---|
committer | Jordi Vilalta Prat | 2009-02-15 06:10:59 +0000 |
commit | fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch) | |
tree | ce87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/gfx | |
parent | 7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff) | |
download | scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.gz scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.tar.bz2 scummvm-rg350-fa6e10e9cec163845aa29e7940c86e9c9ab8a2bc.zip |
Import the SCI engine sources from the FreeSCI Glutton branch (it doesn't compile yet)
svn-id: r38192
Diffstat (limited to 'engines/sci/gfx')
49 files changed, 33632 insertions, 0 deletions
diff --git a/engines/sci/gfx/Makefile.am b/engines/sci/gfx/Makefile.am new file mode 100644 index 0000000000..599d04aba5 --- /dev/null +++ b/engines/sci/gfx/Makefile.am @@ -0,0 +1,20 @@ +SUBDIRS = resource drivers +INCLUDES = -I$(top_srcdir)/src/include @EXTRA_INCLUDES@ +EXTRA_DIST = gfx_line.c gfx_crossblit.c gfx_pixmap_scale.c alpha_mvi_crossblit.c + +noinst_LIBRARIES = libscigraphics.a +libscigraphics_a_LIBADD = alpha_mvi_crossblit_32.o alpha_mvi_crossblit_32_P.o drivers/libscidrivers.a resource/libsciresources.a +EXTRA_libscigraphics_a_SOURCES = gfx_crossblit.c gfx_pixmap_scale.c +libscigraphics_a_SOURCES = font.c gfx_resource.c gfx_support.c gfx_tools.c operations.c resmgr.c sbtree.c widgets.c menubar.c sci_widgets.c antialias.c gfx_console.c gfx_res_options.c font-5x8.c font-6x10.c + +check_PROGRAMS = gfx_test +gfx_test_LDADD = libscigraphics.a drivers/libscidrivers.a @X_LIBS@ @ac_glx_libraries@ @ac_ggi_libraries@ @ac_readline@ @ac_curses_libraries@ @ac_png_libraries@ -lm @SDL_LIBS@ +gfx_test_SOURCES = gfx_test.c + +alpha_mvi_crossblit_32.o: + $(COMPILE) @ev6_cpu@ -I../.. -I../include -DHAVE_CONFIG_H -DFUNCT_NAME=alpha_mvi_crossblit_32 -c $(top_srcdir)/src/gfx/alpha_mvi_crossblit.c -o $(top_builddir)/src/gfx/alpha_mvi_crossblit_32.o + +alpha_mvi_crossblit_32_P.o: + $(COMPILE) @ev6_cpu@ -I../.. -I../include -DHAVE_CONFIG_H -DPRIORITY=1 -DFUNCT_NAME=alpha_mvi_crossblit_32_P -c $(top_srcdir)/src/gfx/alpha_mvi_crossblit.c -o $(top_builddir)/src/gfx/alpha_mvi_crossblit_32_P.o + + diff --git a/engines/sci/gfx/alpha_mvi_crossblit.c b/engines/sci/gfx/alpha_mvi_crossblit.c new file mode 100644 index 0000000000..6a1e238c2b --- /dev/null +++ b/engines/sci/gfx/alpha_mvi_crossblit.c @@ -0,0 +1,360 @@ +/*************************************************************************** + alpha_mvi_crossblit.c Copyright (C) 2001 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +/** MUST be compiled with -mcpu=cv6! */ + +#include <gfx_tools.h> + + +#ifdef HAVE_ALPHA_EV6_SUPPORT + +#ifdef __DECC +# include "c_asm.h" +# define USE_C_CODE +#else /* GNU C */ +# undef USE_C_CODE +#endif + +void +FUNCT_NAME(byte *dest, byte *src, int bytes_per_dest_line, int bytes_per_src_line, + int xl, int yl, byte *alpha, int bytes_per_alpha_line, int bytes_per_alpha_pixel, + unsigned int alpha_test_mask, int alpha_shift +#ifdef PRIORITY + ,byte *priority_pos ,int bytes_per_priority_line, int bytes_per_priority_pixel, int priority +#endif + ) +{ +#ifdef USE_C_CODE +#ifdef PRIORITY + int left_mask = (255 << (((unsigned long) dest) & 7)) & 255; + int right_mask = (255 >> (((unsigned long) dest + bytes_per_dest_line) & 7)); +#endif + unsigned long data; + + assert(!(bytes_per_alpha_line & 7)); + assert(!(((unsigned long) src) & 3)); + assert(!(((unsigned long) dest) & 3)); + assert(bytes_per_alpha_pixel < 2); + + yl++; + while (--yl) { + int x; + byte *dest_next = dest + bytes_per_dest_line; + byte *src_next = src + bytes_per_src_line; +#ifdef PRIORITY + byte *pri_next = priority_pos + bytes_per_priority_line; +#endif + asm ("ldl $31, 0($31)\n\t" + "ldl $31, 0($31)\n\t"); /* Prefetch memory for next line */ + + if (((unsigned long)src) & 4) + data = *((unsigned int *) src); + + for (x = xl; x > 0; x--) { + unsigned long alpha; + + if (!(((unsigned long)src) & 4)) + data = *((unsigned long *) src); + alpha = (data & alpha_test_mask) >> alpha_shift; + + if ( +#ifdef PRIORITY + (*priority_pos <= priority) && +#endif + alpha != 255) { + unsigned long result; + unsigned long orig; + unsigned long unpkdata; + + unpkdata = asm("unpkbw %0, %v0\n\t", data); + + result = unpkdata * (255 - alpha); + + orig = *((unsigned int *) dest); + + orig = asm("unpkbw %0, %v0\n\t", orig); + + result += orig * alpha; + src += 4; + + result >>= 8; + + result = asm("pkwb %0, %v0\n\t", result); + + data >>= 32; + *((unsigned int *) dest) = result; +#ifdef PRIORITY + *priority_pos = priority; +#endif + dest += 4; + } else { + data >>= 32; + src += 4; + dest += 4; + } + +#ifdef PRIORITY + priority_pos++; +#endif + } + + dest = dest_next; + src = src_next; +#ifdef PRIORITY + priority_pos = pri_next; +#endif + } +#else + unsigned long real_alpha_shift = alpha_shift; +#ifdef PRIORITY + assert(!(bytes_per_alpha_line & 7)); + assert(bytes_per_alpha_pixel < 2); + real_alpha_shift |= (unsigned long) (priority << 16) | ((unsigned long) bytes_per_priority_pixel << 32); + /* Work around gcc design bug allowing only 10 asm parameters */ +#endif + __asm__ __volatile__ ( +#ifdef PRIORITY + /* + ** dest: $16 + ** src: $17 + ** bytes_per_dest_line: $18 + ** bytes_per_src_line: $19 + ** xl : $20 + ** yl : $21 + ** alpha_test_mask: $24 + ** alpha_shift: $25 + ** 255: $8 + ** + ** bytes_per_priority_line: $9 + ** priority_pos: $10 + ** priority extended to 8 bytes: $7 + ** bytes_per_priority_pixel: $6 + ** + ** temp_priority_collection: $11 + ** priority_pos backup: $12 + ** left border mask: $13 + ** right border mask: $28 + ** priority test bit: $15 + ** ldq4priority result: $26 + */ + + "lda $30, -88($30) \n\t" + "stq $9, 0($30) \n\t" + "stq $10, 8($30) \n\t" + "stq $11, 16($30) \n\t" + "stq $12, 24($30) \n\t" + "stq $13, 32($30) \n\t" + "stq $15, 40($30) \n\t" + "stq $26, 48($30) \n\t" + "stq %8, 56($30) \n\t" + "stq %9, 64($30) \n\t" + "stq $7, 72($30) \n\t" + "stq $6, 80($30) \n\t" + + "mov %8, $9 \n\t" + "mov %9, $10 \n\t" +#endif + "mov %6, $24 \n\t" + "mov %7, $25 \n\t" + "mov 255, $8 \n\t" + "subl $21, 1, $21 \n\t" +#ifdef PRIORITY + + /* Defrobnicate real_alpha_shift data */ + "srl $25, 32, $6 \n\t" + "srl $25, 16, $7 \n\t" + "and $7, $8, $7 \n\t" + + /* Load first priority data quad */ + "andnot $10, 7, $0 \n\t" + "ldq $26, 0($0) \n\t" /* Load priority */ + "and $10, 7, $13 \n\t" + "sll $13, 3, $0 \n\t" + + /* Calculate right border mask */ + "addl $13, $20, $28\n\t" + "and $28, 7, $28 \n\t" + "beq $28, 7f \n\t" + "mov 8, $0 \n\t" + "subl $0, $28, $28 \n" + "7:\n\t" + "srl $8, $28, $28 \n\t" + /* Left border mask */ + "sll $8, $13, $13 \n\t" + "and $13, $8, $13 \n\t" + + "mov $10, $12 \n\t" + + "sll $7, 8, $0 \n\t" + "or $7, $0, $7 \n\t" + "sll $7, 16, $0 \n\t" + "or $7, $0, $7 \n\t" + "sll $7, 32, $0 \n\t" + "or $7, $0, $7 \n\t" + "cmpbge $7, $26, $3 \n\t" + + "and $10, 7, $0 \n\t" /* Init priority bitptr */ + "mov 1, $15 \n\t" /* .. */ + "sll $15, $0, $15 \n\t" /* .. */ + + /* -> Priority buffer */ + "and $3, $13, $11 \n\t" + "cmplt $20, 8, $0 \n\t" + "beq $0, 6f \n\t" + "and $11, $28, $11 \n\t" + "6:\n\t" +#endif + "and $25, $8, $25 \n\t" + + /***/ + /*** Variable settings apply NOW ***/ + /***/ + + "mov $20, $1 \n\t" + "mov $16, $2 \n\t" + "mov $17, $3 \n" + "8:\n\t" + "addq $2, $18, $2 \n\t" + "ldl $31, 0($2) \n\t" /* Prefetch dest */ + "addq $3, $19, $3 \n\t" + "ldl $31, 0($3) \n" /* Prefetch src */ + "1:\n\t" + "addq $17, 4, $17 \n\t" + "beq $20, 3f \n\t" + "subl $20, 1, $20 \n\t" +#ifdef PRIORITY + "5:\n\t" + "addq $10, 1, $10 \n\t" + "and $11, $15, $0 \n\t" /* Other priority beat our priority? */ + "beq $0, 2f \n\t" +#endif + "ldl $0, -4($17) \n\t" + "unpkbw $0, $5 \n\t" + "and $0, $24, $0 \n\t" + + "xor $0, $24, $4 \n\t" + "beq $4, 2f \n\t" + + "ldl $4, 0($16) \n\t" + "unpkbw $4, $4 \n\t" + "srl $0, $25, $0 \n\t" + "mulq $4, $0, $4 \n\t" + "subl $8, $0, $0 \n\t" + "mulq $5, $0, $5 \n\t" + "addq $4, $5, $4 \n\t" + "srl $4, 8, $4 \n\t" + "pkwb $4, $0 \n\t" + "stl $0, 0($16) \n\t" + "br 9f \n\t" + "2:\n" + "andnot $11, $15, $11 \n\t" /* Don't draw priority if we're fully transparent */ + "9:\n\t" + "addq $16, 4, $16 \n\t" +#ifdef PRIORITY + "sll $15, 1, $15 \n\t" + + "and $10, 7, $0 \n\t" /* Do we need to re-load priority mask? */ +/**/ "bne $0, 1b \n\t" + + /* Write back to priority buffer */ + "zap $26, $11, $26 \n\t" + "zapnot $7, $11, $0 \n\t" + "or $0, $26, $0 \n\t" + "stq $0, -8($10) \n\t" + + "ldq $26, 0($10) \n\t" /* Load priority */ + "cmpbge $7, $26, $11\n\t" + + "mov 1, $15 \n\t" /* Init bitcmpmask */ + + "cmplt $20, 8, $0 \n\t" +/**/ "beq $0, 1b \n\t" + "and $11, $28, $11 \n\t" +#endif + "br 1b \n" + "3:\n\t" +#ifdef PRIORITY + "and $10, 7, $16 \n\t" + "beq $16, 7f \n\t" + "and $11, $28, $11 \n\t" + "zap $26, $11, $26 \n\t" + "zapnot $7, $11, $0 \n\t" + "or $0, $26, $0 \n\t" + "andnot $10, 7, $16 \n\t" + "stq $0, 0($16) \n" /* Write back */ + "7:\n\t" + + "addq $9, $12, $12 \n\t" + "mov $12, $10 \n\t" + "andnot $10, 7, $0 \n\t" + "ldq $26, 0($0) \n\t" + + "and $10, 7, $0 \n\t" + "mov 1, $15 \n\t" + "sll $15, $0, $15 \n\t" /* Store priority-induced write-enable mask */ + + "cmpbge $7, $26, $16 \n\t" + /* -> Priority buffer */ + "and $16, $13, $11 \n\t" +#endif + "beq $21, 4f \n\t" + "subl $21, 1, $21 \n\t" + "mov $1, $20 \n\t" + "mov $2, $16 \n\t" /* Set line numbers for next line */ + "mov $3, $17 \n\t" + "br 8b \n" + "4:\n\t" +#ifdef PRIORITY + "ldq $9, 0($30) \n\t" + "ldq $10, 8($30) \n\t" + "ldq $11, 16($30) \n\t" + "ldq $12, 24($30) \n\t" + "ldq $13, 32($30) \n\t" + "ldq $15, 40($30) \n\t" + "ldq $26, 48($30) \n\t" + "ldq %8, 56($30) \n\t" + "ldq %9, 64($30) \n\t" + "ldq $7, 72($30) \n\t" + "ldq $6, 80($30) \n\t" + "lda $30, 88($30) \n\t" +#endif + : + : + "r"(dest), "r"(src), "r"(bytes_per_dest_line), + /*3*/ "r"(bytes_per_src_line), "r"(xl), "r"(yl), + /*6*/ "r"((unsigned long) alpha_test_mask), "r"(real_alpha_shift) +#ifdef PRIORITY + , "r"(bytes_per_priority_line), "r"(priority_pos) +#endif + : "%0", "%1", "%2", "%3", "%4", "%5", "%6", + "%7", "$16", "$17", "$18", "$19", "$20", "$21", "$24", "$25", + "$8", "memory" + ); +#endif +} + +#endif /* __alpha__ */ diff --git a/engines/sci/gfx/antialias.c b/engines/sci/gfx/antialias.c new file mode 100644 index 0000000000..ad264d18bd --- /dev/null +++ b/engines/sci/gfx/antialias.c @@ -0,0 +1,163 @@ +/*************************************************************************** + antialias.c Copyright (C) 2001 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +/** Antialiasing code **/ + +#include <gfx_system.h> +#include <gfx_tools.h> + +static void +antialiase_simple(gfx_pixmap_t *pixmap, int mask[], int shift_const, gfx_mode_t *mode) +{ + int x, y, c; + int bytespp = mode->bytespp; + int line_size = bytespp * pixmap->xl; + char *lastline[2]; + char *lastline_p = NULL; + char *data_p = (char *) pixmap->data; + + lastline[0] = (char*)sci_malloc(line_size); + lastline[1] = (char*)sci_malloc(line_size); + + for (y = 0; y < pixmap->yl; y++) { + int visimode = (y > 0 && y+1 < pixmap->yl)? 1 : 0; + unsigned long last_pixel; + + memcpy(lastline[y & 1], data_p, line_size); + lastline_p = lastline[(y & 1)^1]; + + for (x = 0; x < pixmap->xl; x++) { + unsigned long result = 0; + + if (x == 1) + visimode++; + else if (x+1 == pixmap->xl) + visimode--; + + for (c = 0; c < 3; c++) { + unsigned long accum = 0; + unsigned long reader = 0; + int y_mode; + + /* Yes, bad compilers will read three times as often as neccessary. + ** This optimization is straightforward to detect (common subexpression + ** elemination), so I prefer to write the stuff semi-legibly... + */ + for (y_mode = 0; y_mode < 2; y_mode++) + if ((y_mode == 0 && y > 0) + || (y_mode == 1 && y+1 < pixmap->yl)) { + + char *src = (y_mode)? data_p + line_size : lastline_p; + + if (x > 0) { + memcpy(&reader, src - bytespp, bytespp); + accum += ((reader >> shift_const) & mask[c]) << 0; + } + + memcpy(&reader, src, bytespp); + accum += ((reader >> shift_const) & mask[c]) << 1; + + if (x+1 < pixmap->xl) { + memcpy(&reader, src + bytespp, bytespp); + accum += ((reader >> shift_const) & mask[c]) << 0; + } + } + + if (x > 0) + accum += ((last_pixel >> shift_const) & mask[c]) << 1; + + memcpy(&reader, data_p, bytespp); + if (c == 2) + last_pixel = reader; + accum += ((reader >> shift_const) & mask[c]) << 2; + + if (x+1 < pixmap->xl) { + memcpy(&reader, data_p + bytespp, bytespp); + accum += ((reader >> shift_const) & mask[c]) << 1; + } + + switch (visimode) { + + case 0: accum /= 9; /* Only happens twelve times */ + break; + + case 1: accum = (accum >> 6) + (accum >> 4); /* 15/16 intensity */ + break; + + case 2: accum >>= 4; + break; + + default: accum = (c == 0)? 0xffffffff : 0; /* Error: mark as red */ + } + + result |= (accum & mask[c]); + } + + result <<= shift_const; + memcpy(data_p, &result, bytespp); + + data_p += bytespp; + lastline_p += bytespp; + } + } + + free(lastline[0]); + free(lastline[1]); +} + +void +gfxr_antialiase(gfx_pixmap_t *pixmap, gfx_mode_t *mode, gfxr_antialiasing_t type) +{ + int masks[3]; + int shift_const = 0; + +#ifdef WORDS_BIGENDIAN + shift_const = (sizeof(unsigned long) - mode->bytespp) << 3; +#endif /* WORDS_BIGENDIAN */ + + masks[0] = mode->red_mask; + masks[1] = mode->green_mask; + masks[2] = mode->blue_mask; + + if (mode->palette) + return; + + switch (type) { + + case GFXR_ANTIALIASING_NONE: + break; + + case GFXR_ANTIALIASING_SIMPLE: + antialiase_simple(pixmap, masks, shift_const, mode); + break; + + default: + GFXERROR("Invalid antialiasing mode %d (internal error)\n", type); + } + + return; +} diff --git a/engines/sci/gfx/drivers/EXPORTS_ggi b/engines/sci/gfx/drivers/EXPORTS_ggi new file mode 100644 index 0000000000..0f9ed580f6 --- /dev/null +++ b/engines/sci/gfx/drivers/EXPORTS_ggi @@ -0,0 +1 @@ +gfx_driver_ggi diff --git a/engines/sci/gfx/drivers/EXPORTS_sdl b/engines/sci/gfx/drivers/EXPORTS_sdl new file mode 100644 index 0000000000..55e1950033 --- /dev/null +++ b/engines/sci/gfx/drivers/EXPORTS_sdl @@ -0,0 +1 @@ +gfx_driver_sdl diff --git a/engines/sci/gfx/drivers/EXPORTS_xlib b/engines/sci/gfx/drivers/EXPORTS_xlib new file mode 100644 index 0000000000..5d705799b0 --- /dev/null +++ b/engines/sci/gfx/drivers/EXPORTS_xlib @@ -0,0 +1,2 @@ +gfx_driver_xlib + diff --git a/engines/sci/gfx/drivers/Makefile.am b/engines/sci/gfx/drivers/Makefile.am new file mode 100644 index 0000000000..c5dbbe0e9f --- /dev/null +++ b/engines/sci/gfx/drivers/Makefile.am @@ -0,0 +1,32 @@ +EXTRA_DIST = dc_driver.c dd_driver.cpp dd_driver.h dd_driver_line.cpp dx_driver.cpp dx_driver.h +INCLUDES = -I$(top_srcdir)/src/include @ac_ggi_includes@ @ac_png_includes@ @X_CFLAGS@ @EXTRA_INCLUDES@ +AM_CFLAGS = $(SDL_CFLAGS) +LDADD = $(LDADD_ALL) + +gfxdriverdir = $(libdir)/freesci/gfx + +#EXTRA_LTLIBRARIES = xlib_driver.la ggi_driver.la sdl_driver.la +#gfxdriver_LTLIBRARIES = @fsci_xlib_dl@ @fsci_ggi_dl@ @fsci_sdl_dl@ + +noinst_LIBRARIES = libscidrivers.a +libscidrivers_a_SOURCES = gfx_drivers.c xlib_driver.c ggi_driver.c sdl_driver.c directfb_driver.c \ + null_driver.c +#libscidrivers_a_OBJECTS = gfx_drivers.o @fsci_xlib_st@ @fsci_ggi_st@ @fsci_sdl_st@ + + +#xlib_driver_la_LDFLAGS = -rpath $(gfxdriverdir) -module -no-undefined \ +# -export-symbols $(srcdir)/EXPORTS_xlib +#xlib_driver_la_LIBADD = @X_LIBS@ +#xlib_driver_la_SOURCES = xlib_driver.c + +#ggi_driver_la_LDFLAGS = -rpath $(gfxdriverdir) -module -no-undefined \ +# -export-symbols $(srcdir)/EXPORTS_ggi +#ggi_driver_la_LIBADD = @X_LIBS@ @ac_ggi_libraries@ +#ggi_driver_la_SOURCES = ggi_driver.c + +#sdl_driver_la_LDFLAGS = -rpath $(gfxdriverdir) -module -no-undefined \ +# -export-symbols $(srcdir)/EXPORTS_sdl +#sdl_driver_la_LIBADD = @SDL_LIBS@ +#3sdl_driver_la_SOURCES = sdl_driver.c + + diff --git a/engines/sci/gfx/drivers/dc_driver.c b/engines/sci/gfx/drivers/dc_driver.c new file mode 100644 index 0000000000..5f2b4419ae --- /dev/null +++ b/engines/sci/gfx/drivers/dc_driver.c @@ -0,0 +1,1267 @@ +/*************************************************************************** + dc_driver.c Copyright (C) 2002-2005 Walter van Niftrik + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Walter van Niftrik <w.f.b.w.v.niftrik@stud.tue.nl> + +***************************************************************************/ + +#include <kos/thread.h> +#include <kos/sem.h> +#include <dc/maple.h> +#include <dc/maple/mouse.h> +#include <dc/maple/keyboard.h> +#include <dc/maple/controller.h> +#include <dc/pvr.h> + +#include <sci_memory.h> +#include <gfx_driver.h> +#include <gfx_tools.h> + +#include "keyboard.h" + +/* Event queue struct */ + +struct dc_event_t { + sci_event_t event; + struct dc_event_t *next; +}; + +#define SCI_DC_RENDER_PVR (1 << 0) /* 0 = VRAM rendering, 1 = PVR */ +#define SCI_DC_REFRESH_50HZ (1 << 1) /* 0 = 60Hz refresh rate, 1 = 50Hz */ + +static int flags = 0; + +struct _dc_state { + /* 0 = static buffer, 1 = back buffer, 2 = front buffer */ + /* Visual maps */ + byte *visual[3]; + /* Priority maps */ + byte *priority[2]; + /* Line pitch of visual buffers */ + int line_pitch[3]; + + /* PVR only */ + /* Polygon header */ + pvr_poly_hdr_t pvr_hdr; + /* Polygon header for virtual keyboard */ + pvr_poly_hdr_t pvr_hdr_vkbd; + /* Texture for virtual keyboard */ + uint16 *vkbd_txr; + + /* Pointers to first and last event in the event queue */ + struct dc_event_t *first_event; + struct dc_event_t *last_event; + + /* Semaphores for mouse pointer location and event queue updates */ + semaphore_t *sem_event, *sem_pointer; + + /* The dx and dy of the mouse pointer since last get_event() */ + int pointer_dx, pointer_dy; + + /* The current bucky state of the keys */ + int buckystate; + + /* Thread ID of the input thread */ + kthread_t *thread; + + /* Flag to stop the input thread. (!0 = run, 0 = stop) */ + int run_thread; + + /* Controller key repeat timer */ + int timer; + + /* Controller state */ + unsigned int cont_state; + + /* Virtual keyboard on/off flag */ + int vkbd; +}; + +#define S ((struct _dc_state *)(drv->state)) + +#define XFACT drv->mode->xfact +#define YFACT drv->mode->yfact +#define BYTESPP drv->mode->bytespp + +#define DC_MOUSE_LEFT (1<<0) +#define DC_MOUSE_RIGHT (1<<1) + +#define DC_KEY_CAPSLOCK (1<<0) +#define DC_KEY_NUMLOCK (1<<1) +#define DC_KEY_SCRLOCK (1<<2) +#define DC_KEY_INSERT (1<<3) + +static void +pvr_init_gfx(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +/* Initialises the graphics driver for PVR rendering mode +** Parameters: (_gfx_driver *) drv: The driver to use +** (int) xfact, yfact: X and Y scaling factors. (xfact, yfact) +** has to be either (1, 1) or (2, 2). +** (int) bytespp: The display depth in bytes per pixel. Must be 2. +** Returns : void +*/ +{ + pvr_poly_cxt_t cxt; + + /* Initialize PVR to defaults and set background color to black */ + + if (flags & SCI_DC_REFRESH_50HZ) + vid_set_mode(DM_640x480_PAL_IL, PM_RGB565); + else + vid_set_mode(DM_640x480, PM_RGB565); + + pvr_init_defaults(); + pvr_set_bg_color(0,0,0); + + /* Allocate and initialize texture RAM */ + S->visual[2] = pvr_mem_malloc(512*256*bytespp*xfact*yfact); + S->line_pitch[2] = 512*bytespp*xfact; + memset(S->visual[2], 0, 512*256*bytespp*xfact*yfact); + + /* Create textured polygon context */ + pvr_poly_cxt_txr(&cxt, PVR_LIST_OP_POLY, PVR_TXRFMT_RGB565 | + PVR_TXRFMT_NONTWIDDLED, 512*xfact, 256*yfact, S->visual[2], 0); + + /* Create polygon header from context */ + pvr_poly_compile(&(S->pvr_hdr), &cxt); + + /* Allocate and initialize texture RAM for virtual keyboard */ + S->vkbd_txr = pvr_mem_malloc(512*64*bytespp*xfact*yfact); + memset(S->vkbd_txr, 0, 512*64*bytespp*xfact*yfact); + + /* Create textured polygon context for virtual keyboard */ + pvr_poly_cxt_txr(&cxt, PVR_LIST_TR_POLY, PVR_TXRFMT_RGB565 | + PVR_TXRFMT_NONTWIDDLED, 512*xfact, 64*yfact, S->vkbd_txr, 0); + + /* Create polygon header from context for virtual keyboard */ + pvr_poly_compile(&(S->pvr_hdr_vkbd), &cxt); + + vkbd_init((uint16 *) S->vkbd_txr, 512); + vkbd_draw(); +} + +static void +pvr_do_frame(struct _gfx_driver *drv) +/* Renders a frame for PVR rendering mode +** Parameters: (_gfx_driver *) drv: The driver to use +** Returns : void +*/ +{ + pvr_vertex_t vert; + + /* Wait until we can send another frame to the PVR */ + pvr_wait_ready(); + + /* Start a new scene */ + pvr_scene_begin(); + + /* Start an opaque polygon list */ + pvr_list_begin(PVR_LIST_OP_POLY); + + /* Submit polygon header */ + pvr_prim(&(S->pvr_hdr), sizeof(S->pvr_hdr)); + + /* Create and submit vertices */ + vert.flags = PVR_CMD_VERTEX; + vert.x = 0.0f; + vert.y = 480.0f; + vert.z = 1.0f; + vert.u = 0.0f; + vert.v = 0.78125f; + vert.argb = PVR_PACK_COLOR(1.0f, 1.0f, 1.0f, 1.0f); + vert.oargb = 0; + pvr_prim(&vert, sizeof(vert)); + + vert.y = 0.0f; + vert.v = 0.0f; + pvr_prim(&vert, sizeof(vert)); + + vert.x = 640.0f; + vert.y = 480.0f; + vert.u = 0.625f; + vert.v = 0.78125f; + pvr_prim(&vert, sizeof(vert)); + + vert.flags = PVR_CMD_VERTEX_EOL; + vert.y = 0.0f; + vert.v = 0.0f; + pvr_prim(&vert, sizeof(vert)); + + /* End list */ + pvr_list_finish(); + + /* Display virtual keyboard */ + if (S->vkbd) { + /* Start an translucent polygon list */ + pvr_list_begin(PVR_LIST_TR_POLY); + + /* Submit polygon header */ + pvr_prim(&(S->pvr_hdr_vkbd), sizeof(S->pvr_hdr_vkbd)); + + /* Create and submit vertices */ + vert.flags = PVR_CMD_VERTEX; + vert.x = 0.0f; + vert.y = 480.0f; + vert.z = 1.0f; + vert.u = 0.0f; + vert.v = 0.625f; + vert.argb = PVR_PACK_COLOR(0.8f, 1.0f, 1.0f, 1.0f); + vert.oargb = 0; + pvr_prim(&vert, sizeof(vert)); + + vert.y = 400.0f; + vert.v = 0.0f; + pvr_prim(&vert, sizeof(vert)); + + vert.x = 640.0f; + vert.y = 480.0f; + vert.u = 0.625f; + vert.v = 0.625f; + pvr_prim(&vert, sizeof(vert)); + + vert.flags = PVR_CMD_VERTEX_EOL; + vert.y = 400.0f; + vert.v = 0.0f; + pvr_prim(&vert, sizeof(vert)); + + /* End list */ + pvr_list_finish(); + } + + /* End scene */ + pvr_scene_finish(); +} + +static void +vram_init_gfx(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +/* Initialises the graphics driver for VRAM rendering mode +** Parameters: (_gfx_driver *) drv: The driver to use +** (int) xfact, yfact: X and Y scaling factors. (xfact, yfact) +** has to be either (1, 1) or (2, 2). +** (int) bytespp: The display depth in bytes per pixel. Must be +** either 2 or 4. +** Returns : void +*/ +{ + int vidres = 0, vidcol = 0; + + /* Center screen vertically */ + S->visual[2] = (byte *) vram_s+320*xfact*20*yfact*bytespp; + + S->line_pitch[2] = 320*xfact*bytespp; + + memset(S->visual[2], 0, 320*xfact*240*yfact*bytespp); + + switch(bytespp) { + case 2: + vidcol = PM_RGB565; + break; + case 4: + vidcol = PM_RGB888; + } + + if (flags & SCI_DC_REFRESH_50HZ) switch (xfact) { + case 1: + vidres = DM_320x240_PAL; + break; + case 2: + vidres = DM_640x480_PAL_IL; + } + else switch (xfact) { + case 1: + vidres = DM_320x240; + break; + case 2: + vidres = DM_640x480; + } + + vid_set_mode(vidres, vidcol); + + vkbd_init((uint16 *) (S->visual[2] + 320 * xfact * 200 * yfact * bytespp), 320); +} + +static void +vram_hide_keyboard(struct _gfx_driver *drv) +/* Hides the virtual keyboard in VRAM rendering mode +** Parameters: (_gfx_driver *) drv: The driver to use +** Returns : void +*/ +{ + vid_set_start(0); + memset4(S->visual[2] + 320 * XFACT * 200 * YFACT * BYTESPP, 0, 320 * XFACT * 40 * YFACT * BYTESPP); +} + +static void +vram_show_keyboard(struct _gfx_driver *drv) +/* Displays the virtual keyboard in VRAM rendering mode +** Parameters: (_gfx_driver *) drv: The driver to use +** Returns : void +*/ +{ + vid_set_start(320 * XFACT * 20 * YFACT * BYTESPP); + vkbd_draw(); +} + +static int +dc_add_event(struct _gfx_driver *drv, sci_event_t *event) +/* Adds an event to the end of an event queue +** Parameters: (_gfx_driver *) drv: The driver to use +** (sci_event_t *) event: The event to add +** Returns : (int) 1 on success, 0 on error +*/ +{ + struct dc_event_t *dc_event; + if (!(dc_event = sci_malloc(sizeof(dc_event)))) { + printf("Error: Could not reserve memory for event\n"); + return 0; + } + + dc_event->event = *event; + dc_event->next = NULL; + + /* Semaphore prevents get_event() from removing the last event in + ** the event queue while a next event is being attached to it. + */ + + sem_wait(S->sem_event); + if (!(S->last_event)) { + /* Event queue is empty */ + S->first_event = dc_event; + S->last_event = dc_event; + sem_signal(S->sem_event); + return 1; + } + + S->last_event->next = dc_event; + S->last_event = dc_event; + sem_signal(S->sem_event); + return 1; +} + +static int +dc_map_key(int *keystate, uint8 key) +/* Converts a kos keycode to a freesci keycode. This function also adjusts +** the caps lock, num lock, scroll lock and insert states in keystate. +** Parameters: (int *) keystate: Pointer to the keystate variable +** (uint8) key: The kos keycode to convert +** Returns : (int) Converted freesci keycode on success, 0 on error +*/ +{ + if ((key >= KBD_KEY_A) && (key <= KBD_KEY_Z)) + return 'a' + (key - KBD_KEY_A); + + if ((key >= KBD_KEY_1) && (key <= KBD_KEY_9)) + return '1' + (key - KBD_KEY_1); + + switch (key) { + case KBD_KEY_0: return '0'; + case KBD_KEY_BACKSPACE: return SCI_K_BACKSPACE; + case KBD_KEY_TAB: return 9; + case KBD_KEY_ESCAPE: return SCI_K_ESC; + case KBD_KEY_ENTER: + case KBD_KEY_PAD_ENTER: return SCI_K_ENTER; + case KBD_KEY_DEL: + case KBD_KEY_PAD_PERIOD: return SCI_K_DELETE; + case KBD_KEY_INSERT: + case KBD_KEY_PAD_0: *keystate ^= DC_KEY_INSERT; + return SCI_K_INSERT; + case KBD_KEY_END: + case KBD_KEY_PAD_1: return SCI_K_END; + case KBD_KEY_DOWN: + case KBD_KEY_PAD_2: return SCI_K_DOWN; + case KBD_KEY_PGDOWN: + case KBD_KEY_PAD_3: return SCI_K_PGDOWN; + case KBD_KEY_LEFT: + case KBD_KEY_PAD_4: return SCI_K_LEFT; + case KBD_KEY_PAD_5: return SCI_K_CENTER; + case KBD_KEY_RIGHT: + case KBD_KEY_PAD_6: return SCI_K_RIGHT; + case KBD_KEY_HOME: + case KBD_KEY_PAD_7: return SCI_K_HOME; + case KBD_KEY_UP: + case KBD_KEY_PAD_8: return SCI_K_UP; + case KBD_KEY_PGUP: + case KBD_KEY_PAD_9: return SCI_K_PGUP; + case KBD_KEY_F1: return SCI_K_F1; + case KBD_KEY_F2: return SCI_K_F2; + case KBD_KEY_F3: return SCI_K_F3; + case KBD_KEY_F4: return SCI_K_F4; + case KBD_KEY_F5: return SCI_K_F5; + case KBD_KEY_F6: return SCI_K_F6; + case KBD_KEY_F7: return SCI_K_F7; + case KBD_KEY_F8: return SCI_K_F8; + case KBD_KEY_F9: return SCI_K_F9; + case KBD_KEY_F10: return SCI_K_F10; + case KBD_KEY_PAD_PLUS: return '+'; + case KBD_KEY_SLASH: + case KBD_KEY_PAD_DIVIDE: return '/'; + case KBD_KEY_MINUS: + case KBD_KEY_PAD_MINUS: return '-'; + case KBD_KEY_PAD_MULTIPLY: return '*'; + case KBD_KEY_COMMA: return ','; + case KBD_KEY_PERIOD: return '.'; + case KBD_KEY_BACKSLASH: return '\\'; + case KBD_KEY_SEMICOLON: return ';'; + case KBD_KEY_QUOTE: return '\''; + case KBD_KEY_LBRACKET: return '['; + case KBD_KEY_RBRACKET: return ']'; + case KBD_KEY_TILDE: return '`'; + case KBD_KEY_PLUS: return '='; + case KBD_KEY_SPACE: return ' '; + case KBD_KEY_CAPSLOCK: *keystate ^= DC_KEY_CAPSLOCK; + return 0; + case KBD_KEY_SCRLOCK: *keystate ^= DC_KEY_SCRLOCK; + return 0; + case KBD_KEY_PAD_NUMLOCK: *keystate ^= DC_KEY_NUMLOCK; + return 0; + } + + printf("Warning: Unmapped key: %02x\n", key); + + return 0; +} + +static void +dc_input_thread(struct _gfx_driver *drv) +/* Thread that checks the dreamcast keyboard and mouse states. It adds +** keypresses and mouseclicks to the end of the event queue. It also updates +** drv->state.buckystate and drv->state.pointer_dx/dy. +** Parameters: (_gfx_driver *) drv: The driver to use +** Returns : void +*/ +{ + /* State of mouse buttons */ + unsigned int mstate = 0; + /* Last key pressed */ + unsigned int lastkey = KBD_KEY_NONE; + /* State of caps lock, scroll lock, num lock and insert keys */ + int keystate = DC_KEY_INSERT; + + while (S->run_thread) { + maple_device_t *kaddr = NULL, *maddr, *caddr; + mouse_state_t *mouse; + kbd_state_t *kbd = 0; + cont_state_t *cont; + uint8 key; + int skeys; + int bucky = 0, vkbd_bucky = 0; + sci_event_t event; + + if (!(flags & SCI_DC_RENDER_PVR)) + /* Sleep for 10ms */ + thd_sleep(10); + else + pvr_do_frame(drv); + + /* Keyboard handling */ + /* Experimental workaround for the Mad Catz adapter problem */ + if (!kaddr) + kaddr = maple_enum_type(0, MAPLE_FUNC_KEYBOARD); + if (kaddr && (kbd = maple_dev_status(kaddr))) { + key = kbd->cond.keys[0]; + skeys = kbd->shift_keys; + + bucky = ((skeys & (KBD_MOD_LCTRL | KBD_MOD_RCTRL))? + SCI_EVM_CTRL : 0) | + ((skeys & (KBD_MOD_LALT | KBD_MOD_RALT))? + SCI_EVM_ALT : 0) | + ((skeys & KBD_MOD_LSHIFT)? + SCI_EVM_LSHIFT : 0) | + ((skeys & KBD_MOD_RSHIFT)? + SCI_EVM_RSHIFT : 0) | + ((keystate & DC_KEY_NUMLOCK)? + SCI_EVM_NUMLOCK : 0) | + ((keystate & DC_KEY_SCRLOCK)? + SCI_EVM_SCRLOCK : 0) | + ((keystate & DC_KEY_INSERT)? + SCI_EVM_INSERT : 0); + + /* If a shift key is pressed when caps lock is on, set + ** both shift key states to 0. If no shift keys are + ** pressed when caps lock is on, set both shift key + ** states to 1 + */ + + if (keystate & DC_KEY_CAPSLOCK) { + if ((bucky & SCI_EVM_LSHIFT) || + (bucky & SCI_EVM_RSHIFT)) + bucky &= + ~(SCI_EVM_LSHIFT | SCI_EVM_RSHIFT); + else bucky |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + } + + if ((key != lastkey) && (key != KBD_KEY_NONE)) { + event.type = SCI_EVT_KEYBOARD; + event.data = dc_map_key(&keystate, key); + event.buckybits = bucky | vkbd_bucky; + if (event.data) dc_add_event(drv, &event); + } + lastkey = key; + } + else kaddr = NULL; + + /* Mouse handling */ + if ((maddr = maple_enum_type(0, MAPLE_FUNC_MOUSE)) && + (mouse = maple_dev_status(maddr))) { + + /* Enable mouse support */ + drv->capabilities |= GFX_CAPABILITY_MOUSE_SUPPORT; + + /* Semaphore prevents get_event() from accessing + ** S->pointer_dx/dy while they are being updated + */ + sem_wait(S->sem_pointer); + S->pointer_dx += mouse->dx; + S->pointer_dy += mouse->dy; + sem_signal(S->sem_pointer); + + if ((mouse->buttons & MOUSE_LEFTBUTTON) && + !(mstate & DC_MOUSE_LEFT)) { + event.type = SCI_EVT_MOUSE_PRESS; + event.data = 1; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate |= DC_MOUSE_LEFT; + } + if ((mouse->buttons & MOUSE_RIGHTBUTTON) && + !(mstate & DC_MOUSE_RIGHT)) { + event.type = SCI_EVT_MOUSE_PRESS; + event.data = 2; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate |= DC_MOUSE_RIGHT; + } + if (!(mouse->buttons & MOUSE_LEFTBUTTON) && + (mstate & DC_MOUSE_LEFT)) { + event.type = SCI_EVT_MOUSE_RELEASE; + event.data = 1; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate &= ~DC_MOUSE_LEFT; + } + if (!(mouse->buttons & MOUSE_RIGHTBUTTON) && + (mstate & DC_MOUSE_RIGHT)) { + event.type = SCI_EVT_MOUSE_RELEASE; + event.data = 2; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate &= ~DC_MOUSE_RIGHT; + } + } + else if ((caddr = maple_enum_type(0, MAPLE_FUNC_CONTROLLER)) && + (cont = maple_dev_status(caddr))) { + /* Enable mouse support */ + drv->capabilities |= GFX_CAPABILITY_MOUSE_SUPPORT; + + /* Semaphore prevents get_event() from accessing + ** S->pointer_dx/dy while they are being updated + */ + sem_wait(S->sem_pointer); + S->pointer_dx += cont->joyx/20; + S->pointer_dy += cont->joyy/20; + sem_signal(S->sem_pointer); + + if ((cont->ltrig > 5) && + !(mstate & DC_MOUSE_LEFT)) { + event.type = SCI_EVT_MOUSE_PRESS; + event.data = 1; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate |= DC_MOUSE_LEFT; + } + if ((cont->rtrig > 5) && + !(mstate & DC_MOUSE_RIGHT)) { + event.type = SCI_EVT_MOUSE_PRESS; + event.data = 2; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate |= DC_MOUSE_RIGHT; + } + if ((cont->ltrig <= 5) && + (mstate & DC_MOUSE_LEFT)) { + event.type = SCI_EVT_MOUSE_RELEASE; + event.data = 1; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate &= ~DC_MOUSE_LEFT; + } + if ((cont->rtrig <= 5) && + (mstate & DC_MOUSE_RIGHT)) { + event.type = SCI_EVT_MOUSE_RELEASE; + event.data = 2; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + mstate &= ~DC_MOUSE_RIGHT; + } + if (S->timer > 0) + S->timer--; + if ((cont->buttons != S->cont_state) || !S->timer) { + S->cont_state = cont->buttons; + S->timer = 25; + if (cont->buttons & CONT_START) { + S->vkbd = S->vkbd ^ 1; + if (!(flags & SCI_DC_RENDER_PVR)) { + if(S->vkbd) + vram_show_keyboard(drv); + else + vram_hide_keyboard(drv); + } + } + if (S->vkbd) { + if (cont->buttons & CONT_DPAD_RIGHT) + vkbd_handle_input(KBD_RIGHT); + if (cont->buttons & CONT_DPAD_LEFT) + vkbd_handle_input(KBD_LEFT); + if (cont->buttons & CONT_DPAD_UP) + vkbd_handle_input(KBD_UP); + if (cont->buttons & CONT_DPAD_DOWN) + vkbd_handle_input(KBD_DOWN); + if (cont->buttons & CONT_A) { + int vkbd_key; + if (vkbd_get_key(&vkbd_key, &vkbd_bucky)) { + event.type = SCI_EVT_KEYBOARD; + event.data = vkbd_key; + event.buckybits = bucky | vkbd_bucky; + dc_add_event(drv, &event); + } + } + } + else { + event.data = 0; + if (cont->buttons & CONT_DPAD_RIGHT) + event.data = SCI_K_RIGHT; + else if (cont->buttons & CONT_DPAD_LEFT) + event.data = SCI_K_LEFT; + else if (cont->buttons & CONT_DPAD_UP) + event.data = SCI_K_UP; + else if (cont->buttons & CONT_DPAD_DOWN) + event.data = SCI_K_DOWN; + event.type = SCI_EVT_KEYBOARD; + event.buckybits = bucky | vkbd_bucky; + if (event.data) dc_add_event(drv, &event); + } + event.data = 0; + if (cont->buttons & CONT_B) + event.data = SCI_K_ENTER; + else if (cont->buttons & CONT_X) + event.data = ' '; + else if (cont->buttons & CONT_Y) + event.data = SCI_K_ESC; + event.type = SCI_EVT_KEYBOARD; + event.buckybits = bucky | vkbd_bucky; + if (event.data) + dc_add_event(drv, &event); + } + } + else drv->capabilities &= ~GFX_CAPABILITY_MOUSE_SUPPORT; + + S->buckystate = bucky | vkbd_bucky; + } +} + +static uint32 +dc_get_color(struct _gfx_driver *drv, gfx_color_t col) +/* Converts a color as described in col to it's representation in memory +** Parameters: (_gfx_driver *) drv: The driver to use +** (gfx_color_t) color: The color to convert +** Returns : (uint32) the color's representation in memory +*/ +{ + uint32 retval; + uint32 temp; + + retval = 0; + + temp = col.visual.r; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> drv->mode->red_shift) & (drv->mode->red_mask); + temp = col.visual.g; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> drv->mode->green_shift) & (drv->mode->green_mask); + temp = col.visual.b; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> drv->mode->blue_shift) & (drv->mode->blue_mask); + + return retval; +} + +static void +dc_draw_line_buffer(byte *buf, int line, int bytespp, int x1, + int y1, int x2, int y2, uint32 color) +/* Draws a line in a buffer +** This function was taken from sdl_driver.c with small modifications +** Parameters: (byte *) buf: The buffer to draw in +** (int) line: line pitch of buf in bytes +** (int) bytespp: number of bytes per pixel of buf +** (int) x1, y1, x2, y2: The line to draw: (x1,y1)-(x2,y2). +** (uint32) color: The color to draw with +** Returns : (void) +*/ +{ + int pixx, pixy; + int x,y; + int dx,dy; + int sx,sy; + int swaptmp; + uint8 *pixel; + + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = bytespp; + pixy = line; + pixel = ((uint8*) buf) + pixx * x1 + pixy * y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; dx = dy; dy = swaptmp; + swaptmp = pixx; pixx = pixy; pixy = swaptmp; + } + + x=0; + y=0; + switch(bytespp) { + case 1: + for(; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 2: + for (; x < dx; x++, pixel += pixx) { + *(uint16*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 4: + for(; x < dx; x++, pixel += pixx) { + *(uint32*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + } + +} + +static void +dc_draw_filled_rect_buffer(byte *buf, int line, int bytespp, rect_t rect, + uint32 color) +/* Draws a filled rectangle in a buffer +** Parameters: (byte *) buf: The buffer to draw in +** (int) line: line pitch of buf in bytes +** (int) bytespp: number of bytes per pixel of buf +** (rect_t) rect: The rectangle to fill +** (uint32) color: The fill color +** Returns : (void) +*/ +{ + buf += rect.y*line + rect.x*bytespp; + int i; + + switch (bytespp) { + case 1: for (i = 0; i<rect.yl; i++) { + memset(buf, color, rect.xl); + buf += line; + } + break; + case 2: for (i = 0; i<rect.yl; i++) { + memset2(buf, color, rect.xl*2); + buf += line; + } + break; + case 4: for (i = 0; i<rect.yl; i++) { + memset4(buf, color, rect.xl*4); + buf += line; + } + } +} + + +static void +dc_copy_rect_buffer(byte *src, byte *dest, int srcline, int destline, + int bytespp, rect_t sr, point_t dp) +/* Copies a rectangle from one buffer to another +** Parameters: (byte *) src: The source buffer +** (byte *) dest: The destination buffer +** (int) srcline: line pitch of src in bytes +** (int) destline: line pitch of dest in bytes +** (int) bytespp: number of bytes per pixel of src and dest +** (rect_t) sr: Rectangle of src to copy +** (point_t) dp: Left top corner in dest where copy should go +** Returns : (void) +*/ +{ + src += sr.y*srcline + sr.x*bytespp; + dest += dp.y*destline + dp.x*bytespp; + int i; + + switch (bytespp) { + case 1: for (i = 0; i<sr.yl; i++) { + memcpy(dest, src, sr.xl); + src += srcline; + dest += destline; + } + break; + case 2: for (i = 0; i<sr.yl; i++) { + memcpy2(dest, src, sr.xl*2); + src += srcline; + dest += destline; + } + break; + case 4: for (i = 0; i<sr.yl; i++) { + memcpy4(dest, src, sr.xl*4); + src += srcline; + dest += destline; + } + } +} + +static int +dc_set_parameter(struct _gfx_driver *drv, char *attribute, char *value) +{ + if (!strcasecmp(attribute, "render_mode")) { + if (!strcasecmp(value, "vram")) { + flags &= ~SCI_DC_RENDER_PVR; + return GFX_OK; + } + else if (!strcasecmp(value, "pvr")) { + flags |= SCI_DC_RENDER_PVR; + return GFX_OK; + } + else { + sciprintf("Fatal error: Invalid value `%s' specified for attribute `render_mode'\n", value); + return GFX_FATAL; + } + } + if (!strcasecmp(attribute, "refresh_rate")) { + if (!strcasecmp(value, "60Hz")) { + flags &= ~SCI_DC_REFRESH_50HZ; + return GFX_OK; + } + else if (!strcasecmp(value, "50Hz")) { + flags |= SCI_DC_REFRESH_50HZ; + return GFX_OK; + } + else { + sciprintf("Fatal error: Invalid value `%s' specified for attribute `refresh_rate'\n", value); + return GFX_FATAL; + } + } + + sciprintf("Fatal error: Attribute '%s' does not exist\n", attribute); + return GFX_FATAL; +} + + +static int +dc_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + int i; + int rmask = 0, gmask = 0, bmask = 0, rshift = 0, gshift = 0; + int bshift = 0; + + sciprintf("Initialising video mode\n"); + + pvr_shutdown(); + + if (!drv->state /* = S */) + drv->state = sci_malloc(sizeof(struct _dc_state)); + if (!S) + return GFX_FATAL; + + if ((flags & SCI_DC_RENDER_PVR) && ((xfact != 1 && xfact != 2) + || bytespp != 2 || xfact != yfact)) { + sciprintf("Error: PVR rendering mode does not support " + "buffers with scale factors (%d,%d) and bpp=%d\n", + xfact, yfact, bytespp); + return GFX_ERROR; + } + else if ((xfact != 1 && xfact != 2) || (bytespp != 2 && bytespp != 4) + || xfact != yfact) { + sciprintf("Error: VRAM rendering mode does not support " + "buffers with scale factors (%d,%d) and bpp=%d\n", + xfact, yfact, bytespp); + return GFX_ERROR; + } + + for (i = 0; i < 2; i++) { + if (!(S->priority[i] = sci_malloc(320*xfact*200*yfact)) || + !(S->visual[i] = sci_malloc(320*xfact*200*yfact* bytespp))) { + sciprintf("Error: Could not reserve memory for buffer\n"); + return GFX_ERROR; + } + } + + for (i = 0; i < 2; i++) { + S->line_pitch[i] = 320*xfact*bytespp; + memset(S->visual[i], 0, 320*xfact*200*yfact*bytespp); + memset(S->priority[i], 0, 320*xfact*200*yfact); + } + + S->pointer_dx = 0; + S->pointer_dy = 0; + S->buckystate = 0; + S->timer = 0; + S->vkbd = 0; + + switch(bytespp) { + case 2: rmask = 0xF800; + gmask = 0x7E0; + bmask = 0x1F; + rshift = 16; + gshift = 21; + bshift = 27; + break; + case 4: rmask = 0xFF0000; + gmask = 0xFF00; + bmask = 0xFF; + rshift = 8; + gshift = 16; + bshift = 24; + } + + if (!(flags & SCI_DC_RENDER_PVR)) + vram_init_gfx(drv, xfact, yfact, bytespp); + else + pvr_init_gfx(drv, xfact, yfact, bytespp); + + drv->mode = gfx_new_mode(xfact, yfact, bytespp, rmask, gmask, bmask, 0, + rshift, gshift, bshift, 0, 0, 0); + + printf("Video mode initialisation completed succesfully\n"); + + S->run_thread = 1; + + S->thread = thd_create((void *) dc_input_thread, drv); + + S->first_event = NULL; + S->last_event = NULL; + + if (!(S->sem_event = sem_create(1)) || + !(S->sem_pointer = sem_create(1))) { + printf("Error: Could not reserve memory for semaphore\n"); + return GFX_ERROR; + }; + + return GFX_OK; +} + +static int +dc_init(struct _gfx_driver *drv) +{ + if (dc_init_specific(drv, 1, 1, 2) != GFX_OK) + return GFX_FATAL; + + return GFX_OK; +} + +static void +dc_exit(struct _gfx_driver *drv) +{ + if (S) { + sciprintf("Freeing graphics buffers\n"); + sci_free(S->visual[0]); + sci_free(S->visual[1]); + sci_free(S->priority[0]); + sci_free(S->priority[1]); + if (flags & SCI_DC_RENDER_PVR) { + pvr_mem_free(S->visual[2]); + pvr_mem_free(S->vkbd_txr); + } + + sciprintf("Waiting for input thread to exit... "); + S->run_thread = 0; + thd_wait(S->thread); + sciprintf("ok\n"); + + sciprintf("Freeing semaphores\n"); + sem_destroy(S->sem_event); + sem_destroy(S->sem_pointer); + sci_free(S); + drv->state /* = S */ = NULL; + } +} + + /*** Drawing operations ***/ + +static int +dc_draw_line(struct _gfx_driver *drv, point_t start, point_t end, + gfx_color_t color, gfx_line_mode_t line_mode, + gfx_line_style_t line_style) +{ + uint32 scolor; + int xfact = (line_mode == GFX_LINE_MODE_FINE)? 1: XFACT; + int yfact = (line_mode == GFX_LINE_MODE_FINE)? 1: YFACT; + int xsize = XFACT*320; + int ysize = YFACT*200; + + int xc, yc; + int x1, y1, x2, y2; + + scolor = dc_get_color(drv, color); + + for (xc = 0; xc < xfact; xc++) + for (yc = 0; yc < yfact; yc++) { + x1 = start.x + xc; + y1 = start.y + yc; + x2 = end.x + xc; + y2 = end.y + yc; + + if (x1 < 0) + x1 = 0; + if (x2 < 0) + x2 = 0; + if (y1 < 0) + y1 = 0; + if (y2 < 0) + y2 = 0; + + if (x1 > xsize) + x1 = xsize; + if (x2 >= xsize) + x2 = xsize - 1; + if (y1 > ysize) + y1 = ysize; + if (y2 >= ysize) + y2 = ysize - 1; + + if (color.mask & GFX_MASK_VISUAL) + dc_draw_line_buffer(S->visual[1], + XFACT*320*BYTESPP, BYTESPP, x1, y1, x2, y2, + dc_get_color(drv, color)); + + if (color.mask & GFX_MASK_PRIORITY) + dc_draw_line_buffer(S->priority[1], XFACT*320, + 1, x1, y1, x2, y2, color.priority); + } + + return GFX_OK; +} + +static int +dc_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, gfx_rectangle_fill_t shade_mode) +{ + if (color1.mask & GFX_MASK_VISUAL) + dc_draw_filled_rect_buffer(S->visual[1], S->line_pitch[1], + BYTESPP, rect, dc_get_color(drv, color1)); + + if (color1.mask & GFX_MASK_PRIORITY) + dc_draw_filled_rect_buffer(S->priority[1], XFACT*320, 1, rect, + color1.priority); + + return GFX_OK; +} + + /*** Pixmap operations ***/ + +static int +dc_register_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + return GFX_ERROR; +} + +static int +dc_unregister_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + return GFX_ERROR; +} + +static int +dc_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + int bufnr = (buffer == GFX_BUFFER_STATIC)? 0:1; + + return gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, + S->visual[bufnr], S->line_pitch[bufnr], S->priority[bufnr], XFACT*320, + 1, 0); +} + +static int +dc_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + switch (map) { + case GFX_MASK_VISUAL: + dc_copy_rect_buffer(S->visual[1], pxm->data, + S->line_pitch[1], src.xl*BYTESPP, BYTESPP, src, + gfx_point(0, 0)); + pxm->xl = src.xl; + pxm->yl = src.yl; + return GFX_OK; + case GFX_MASK_PRIORITY: + dc_copy_rect_buffer(S->priority[1], pxm->index_data, + XFACT*320, src.xl, 1, src, gfx_point(0, 0)); + pxm->index_xl = src.xl; + pxm->index_yl = src.yl; + return GFX_OK; + default: + sciprintf("Error: attempt to grab pixmap from invalid map"); + return GFX_ERROR; + } +} + + + /*** Buffer operations ***/ + +static int +dc_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + int tbufnr = (buffer == GFX_BUFFER_BACK)? 1:2; + + dc_copy_rect_buffer(S->visual[tbufnr-1], S->visual[tbufnr], + S->line_pitch[tbufnr-1], S->line_pitch[tbufnr], BYTESPP, src, dest); + + if ((tbufnr == 1) && (src.x == dest.x) && (src.y == dest.y)) + dc_copy_rect_buffer(S->priority[0], S->priority[1], XFACT*320, + XFACT*320, 1, src, dest); + + return GFX_OK; +} + +static int +dc_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + memcpy4(S->visual[0], pic->data, XFACT*320 * YFACT*200 * BYTESPP); + memcpy4(S->priority[0], priority->index_data, XFACT*320 * YFACT*200); + return GFX_OK; +} + + /*** Palette operations ***/ + +static int +dc_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) +{ + return GFX_ERROR; +} + + + /*** Mouse pointer operations ***/ + +static int +dc_set_pointer (struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + return GFX_ERROR; +} + + /*** Event management ***/ + +static sci_event_t +dc_get_event(struct _gfx_driver *drv) +{ + sci_event_t event; + struct dc_event_t *first; + sem_wait(S->sem_pointer); + drv->pointer_x += S->pointer_dx; + drv->pointer_y += S->pointer_dy; + S->pointer_dx = 0; + S->pointer_dy = 0; + sem_signal(S->sem_pointer); + + if (drv->pointer_x < 0) + drv->pointer_x = 0; + if (drv->pointer_x >= 320*XFACT) + drv->pointer_x = 320*XFACT-1; + if (drv->pointer_y < 0) + drv->pointer_y = 0; + if (drv->pointer_y >= 200*YFACT) + drv->pointer_y = 200*YFACT-1; + + sem_wait(S->sem_event); + first = S->first_event; + + if (first) { + event = first->event; + S->first_event = first->next; + free(first); + if (S->first_event == NULL) S->last_event = NULL; + sem_signal(S->sem_event); + return event; + } + + sem_signal(S->sem_event); + event.type = SCI_EVT_NONE; + event.buckybits = S->buckystate; + return event; +} + + +static int +dc_usec_sleep(struct _gfx_driver *drv, long usecs) +{ + /* TODO: wake up on mouse move */ + int ms = usecs/1000; + if (ms) + thd_sleep(ms); + return GFX_OK; +} + +gfx_driver_t +gfx_driver_dc = { + "dc", + "0.2b", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, + 0, + GFX_CAPABILITY_FINE_LINES, + 0, + dc_set_parameter, + dc_init_specific, + dc_init, + dc_exit, + dc_draw_line, + dc_draw_filled_rect, + dc_register_pixmap, + dc_unregister_pixmap, + dc_draw_pixmap, + dc_grab_pixmap, + dc_update, + dc_set_static_buffer, + dc_set_pointer, + dc_set_palette, + dc_get_event, + dc_usec_sleep, + NULL +}; diff --git a/engines/sci/gfx/drivers/dd_driver.cpp b/engines/sci/gfx/drivers/dd_driver.cpp new file mode 100644 index 0000000000..f2920b4089 --- /dev/null +++ b/engines/sci/gfx/drivers/dd_driver.cpp @@ -0,0 +1,1021 @@ +#ifndef __cplusplus +#error NOTE: This file MUST be compiled as C++. In Visual C++, use the /Tp command line option. +#endif + +// for WINNT 4.0 (only DirectDraw 3) +#ifdef HAVE_DDRAW + +#define DIRECTDRAW_VERSION 0x0300 + +#define INITGUID + +#include <windows.h> +#include <ddraw.h> +#include <stdarg.h> + +extern "C" { +#include <gfx_system.h> +#include <gfx_driver.h> +#include <gfx_tools.h> +#include <assert.h> +#include <uinput.h> +#include <ctype.h> +#include <console.h> // for sciprintf +#include <sci_memory.h> +}; + +#include "dd_driver.h" + +#define DD_DRIVER_VERSION "0.1" + +#define GFX_DD_DEBUG + + +#ifdef GFX_DD_DEBUG +#define POSMSG sciprintf("%s L%d:", __FILE__, __LINE__) +#define DEBUG_PTR (!(drv->debug_flags & GFX_DEBUG_POINTER))? 0 : POSMSG && sciprintf +#define DEBUG_UPDATES (!(drv->debug_flags & GFX_DEBUG_UPDATES))? 0 : POSMSG && sciprintf +#define DEBUG_PIXMAPS (!(drv->debug_flags & GFX_DEBUG_PIXMAPS))? 0 : POSMSG && sciprintf +#define DEBUG_BASIC (!(drv->debug_flags & GFX_DEBUG_BASIC))? 0 : POSMSG , sciprintf +#else /* !GFX_DD_DEBUG */ +#define DEBUG_PTR (1)? 0 : +#define DEBUG_UPDATES (1)? 0 : +#define DEBUG_PIXMAPS (1)? 0 : +#define DEBUG_BASIC (1)? 0 : +#endif /* !GFX_DD_DEBUG */ + +BOOL g_bFullScreen = FALSE; + +#define DD_BUFFER_BACK 0 +#define DD_BUFFER_STATIC 1 + +static long FAR PASCAL WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static int process_messages(void); + +struct gfx_dd_struct_t +{ + LPDIRECTDRAW pDD; + HWND hMainWnd; + LPDIRECTDRAWSURFACE pPrimary; + LPDIRECTDRAWSURFACE pBack; + LPDIRECTDRAWSURFACE pStatic; + LPDIRECTDRAWCLIPPER pClipper; // used in windowed (not fullscreen) mode + int win_xpos,win_ypos; // current position of the window (windowed mode only) + BOOL bShowMouse; + gfx_pixmap_t *priority_maps[2]; + // event queue + int queue_size,queue_first,queue_last; + sci_event_t * event_queue; +}; + +static void init_event_queue(gfx_dd_struct_t *ctx); +static void free_event_queue(gfx_dd_struct_t *ctx); + +static __inline DWORD MakeRGB(gfx_mode_t *mode,unsigned int r,unsigned int g,unsigned int b) +{ + return ((r << mode->red_shift) & mode->red_mask) | + ((g << mode->green_shift) & mode->green_mask) | + ((b << mode->blue_shift) & mode->blue_mask); +}; + +static int +dd_set_param(gfx_driver_t *drv, char *attribute, char *value) +{ + DEBUG_BASIC("dd_set_param('%s' to '%s')\n", attribute, value); + return GFX_OK; +} + +static int +ShiftCount(DWORD mask) +{ + int cnt; + + if(mask==0) + return 0; // error !!! + + cnt=0; + + while((mask & 1)==0) + { + mask >>=1; + cnt++; + } + return cnt; +} + +static int +dd_init_specific(gfx_driver_t *drv, int xres, int yres, int bpp) +{ + DDSURFACEDESC dd_desc,ddsd; + HRESULT hr; + WNDCLASS wc; + RECT rc; + POINT pnt; + gfx_dd_struct_t *ctx; + int dd_bpp,r_sh,g_sh,b_sh,dd_bpp2,tbytes; +// const ggi_pixelformat *pixelformat; + int frames = 3; + + // force .... + xres=1; yres=1; bpp=1; + + if(g_bFullScreen) + { + // force the best mode + xres=1; yres=1; bpp=1; + } + switch(bpp) // bpp of 8,16,24,32 + { + case 1: + dd_bpp=8; break; + case 2: + dd_bpp=16; break; + case 3: + dd_bpp=24; break; + case 4: + dd_bpp=32; break; + default: + sciprintf("GFXDD: Error: Invalid bytes per pixel value: %d\n", bpp); + return GFX_ERROR; + } + + drv->state = NULL; + + ctx = (struct gfx_dd_struct_t *) sci_malloc(sizeof(gfx_dd_struct_t)); + if(ctx == NULL) + return GFX_FATAL; + + memset(ctx,0,sizeof(gfx_dd_struct_t)); + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(void *); + wc.hInstance = NULL; + wc.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wc.hCursor = NULL; /*LoadCursor (NULL, IDC_ARROW)*/; + wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = "freesci.WndClass"; + RegisterClass (&wc); + + SetRect (&rc, 0, 0, xres*320-1, yres*200-1); + if(!g_bFullScreen) + { + AdjustWindowRectEx (&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); + } + + init_event_queue(ctx); + + ctx->hMainWnd = CreateWindowEx (0,"freesci.WndClass","FreeSCI", + g_bFullScreen ? WS_POPUP : (WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU), + 0,0,rc.right-rc.left,rc.bottom-rc.top,NULL,NULL,NULL,NULL); + + SetWindowLong(ctx->hMainWnd,0,(long) drv); + + hr = DirectDrawCreate(NULL,&(ctx->pDD),NULL); + if ( FAILED(hr)) + { + DestroyWindow(ctx->hMainWnd); + free(ctx); + return GFX_FATAL; + } + + + if(g_bFullScreen) + { + // fulscreen mode, change to the desired mode + hr = ctx->pDD->SetCooperativeLevel ( ctx->hMainWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + hr = ctx->pDD->SetDisplayMode ( xres*320, yres*200, dd_bpp); + } + else + { + // windowed mode, accept whatever mode is current + hr = ctx->pDD->SetCooperativeLevel (ctx->hMainWnd, DDSCL_NORMAL); + } + + drv->state = ctx; + + ShowWindow(ctx->hMainWnd,SW_NORMAL); + UpdateWindow(ctx->hMainWnd); + + pnt.x = 0; pnt.y = 0; + ClientToScreen (ctx->hMainWnd, &pnt); + ctx->win_xpos = pnt.x; + ctx->win_ypos = pnt.y; + + // create surface - primary + memset(&dd_desc,0,sizeof(dd_desc)); + dd_desc.dwSize = sizeof(dd_desc); + dd_desc.dwFlags = DDSD_CAPS; + dd_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = ctx->pDD->CreateSurface(&dd_desc,&ctx->pPrimary,NULL); + if(FAILED(hr)) + { + if(g_bFullScreen) + { + hr = ctx->pDD->RestoreDisplayMode (); + hr = ctx->pDD->SetCooperativeLevel (ctx->hMainWnd, DDSCL_NORMAL); + } + ctx->pDD->Release(); + free(ctx); + return GFX_FATAL; + } + + // get the current mode; in windowed mode it can be different than the one we want + memset(&dd_desc,0,sizeof(dd_desc)); + dd_desc.dwSize = sizeof(dd_desc); + hr = ctx->pDD->GetDisplayMode(&dd_desc); + + r_sh = ShiftCount(dd_desc.ddpfPixelFormat.dwRBitMask); + g_sh = ShiftCount(dd_desc.ddpfPixelFormat.dwGBitMask); + b_sh = ShiftCount(dd_desc.ddpfPixelFormat.dwBBitMask); + dd_bpp2=0; + if(dd_desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) + dd_bpp2=2; + if(dd_desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) + dd_bpp2=4; + if(dd_desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + dd_bpp2=16; + if(dd_desc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + dd_bpp2=256; + + drv->mode = gfx_new_mode(xres,yres,dd_desc.ddpfPixelFormat.dwRGBBitCount/8, + dd_desc.ddpfPixelFormat.dwRBitMask,dd_desc.ddpfPixelFormat.dwGBitMask,dd_desc.ddpfPixelFormat.dwBBitMask,0, + r_sh,g_sh,b_sh,0, dd_bpp2, 0); + + tbytes = 320*xres*200*yres* (dd_desc.ddpfPixelFormat.dwRGBBitCount/8); + + // create a secondary surfaces + memset (&ddsd, 0, sizeof (DDSURFACEDESC)); + ddsd.dwSize = sizeof (DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = 320 * drv->mode->xfact; + ddsd.dwHeight = 200 * drv->mode->yfact; + hr = ctx->pDD->CreateSurface(&ddsd,&ctx->pBack,NULL); + if(FAILED(hr)) + { + return GFX_FATAL; + } + memset (&ddsd, 0, sizeof (DDSURFACEDESC)); + ddsd.dwSize = sizeof (DDSURFACEDESC); + hr = ctx->pBack->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL); + if(!FAILED(hr)) + { + memset(ddsd.lpSurface,0,tbytes); + hr = ctx->pBack->Unlock(NULL); + } + + memset (&ddsd, 0, sizeof (DDSURFACEDESC)); + ddsd.dwSize = sizeof (DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + ddsd.dwWidth = 320 * drv->mode->xfact; + ddsd.dwHeight = 200 * drv->mode->yfact; + hr = ctx->pDD->CreateSurface(&ddsd,&ctx->pStatic,NULL); + if(FAILED(hr)) + { + return GFX_FATAL; + } + memset (&ddsd, 0, sizeof (DDSURFACEDESC)); + ddsd.dwSize = sizeof (DDSURFACEDESC); + hr = ctx->pStatic->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL); + if(!FAILED(hr)) + { + memset(ddsd.lpSurface,0,tbytes); + hr = ctx->pStatic->Unlock(NULL); + } + + // if not in full-screen mode, set the clipper + if (!g_bFullScreen) + { + hr = ctx->pDD->CreateClipper (0, &ctx->pClipper, NULL); + hr = ctx->pClipper->SetHWnd (0, ctx->hMainWnd); + hr = ctx->pPrimary->SetClipper (ctx->pClipper); + } + + ctx->priority_maps[DD_BUFFER_BACK] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * xres, 200 * yres, GFX_RESID_NONE, 0, 0)); + ctx->priority_maps[DD_BUFFER_STATIC] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * xres, 200 * yres, GFX_RESID_NONE, 0, 0)); + + ctx->priority_maps[DD_BUFFER_BACK]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + ctx->priority_maps[DD_BUFFER_STATIC]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + +/* + if (_open_meta_visuals(drv)) { + free(meta); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_BACK]); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_STATIC]); + ggiClose(meta->vis); + ggiExit(); + return GFX_ERROR; + } + + if (frames < 2) { + meta->alt_back_buffer = sci_malloc(bpp * 320 * 200 * xres * yres); + meta->back_vis = ggiOpen("memory:pointer", meta->alt_back_buffer, NULL); + if (ggiSetSimpleMode(meta->back_vis, xres * 320, yres * 200, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual failed\n"); + } + } else meta->alt_back_buffer = NULL; + + if (frames < 3) { + meta->static_buffer = sci_malloc(bpp * 320 * 200 * xres * yres); + meta->static_vis = ggiOpen("memory:pointer", meta->static_buffer, NULL); + if (ggiSetSimpleMode(meta->static_vis, xres * 320, yres * 200, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual #2 failed\n"); + } + } else meta->static_buffer = NULL; + + init_input_ggi(); +*/ + return GFX_OK; +} + +int +dd_init(gfx_driver_t *drv) +{ + return dd_init_specific(drv,1,1,1); +} + +void +dd_exit(gfx_driver_t *drv) +{ + HRESULT hr; + gfx_dd_struct_t *ctx; + + if(drv->state == NULL) + return; + + ctx = (gfx_dd_struct_t *) drv->state; + + if(g_bFullScreen) + { + hr = ctx->pDD->RestoreDisplayMode (); + hr = ctx->pDD->SetCooperativeLevel (ctx->hMainWnd, DDSCL_NORMAL); + } + + free_event_queue(ctx); + + gfx_free_pixmap(drv, ctx->priority_maps[0]); + gfx_free_pixmap(drv, ctx->priority_maps[1]); + + if(ctx->hMainWnd) + { + DestroyWindow(ctx->hMainWnd); + ctx->hMainWnd = NULL; + } + + if(ctx->pBack) + { + ctx->pBack->Release(); + ctx->pBack=NULL; + } + if(ctx->pStatic) + { + ctx->pStatic->Release(); + ctx->pStatic=NULL; + } + if(ctx->pPrimary) + { + ctx->pPrimary->Release(); + ctx->pPrimary=NULL; + } + if(ctx->pClipper) + { + ctx->pClipper->Release(); + ctx->pClipper=NULL; + } + if(ctx->pDD) + { + ctx->pDD->Release(); + ctx->pDD = NULL; + } + + drv->state = NULL; + + free(ctx); +} + +int +dd_draw_line(gfx_driver_t *drv, + point_t start, point_t end, + gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + rect_t line = gfx_rect(start.x, start.y, + end.x - start.x, end.y - start.y); + HRESULT hr; + DDSURFACEDESC ddsc; + gfx_dd_struct_t *ctx; + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + memset(&ddsc,0,sizeof(ddsc)); + ddsc.dwSize = sizeof(ddsc); + hr = ctx->pBack->Lock(NULL,&ddsc,DDLOCK_WAIT,NULL); + if(FAILED(hr)) + { + return GFX_ERROR; + } + + _dd_draw_line(drv->mode, start, end, (byte *) ddsc.lpSurface, ddsc.lPitch,color); + +// gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, (byte *) ddsc.lpSurface, +// ddsc.lPitch,pri_map, drv->mode->xfact * 320, 1); + + hr = ctx->pBack->Unlock(NULL); + return GFX_OK; +} + +int +dd_draw_filled_rect(gfx_driver_t *drv, rect_t box, gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + HRESULT hr; + RECT rcDest; + DDBLTFX ddblt; + gfx_dd_struct_t *ctx; + byte *pri; + int i; + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + rcDest.left = box.x; + rcDest.top = box.y; + rcDest.right = box.x+box.xl; + rcDest.bottom = box.y+box.yl; + + if (color1.mask & GFX_MASK_VISUAL) + { + memset(&ddblt,0,sizeof(ddblt)); + ddblt.dwSize = sizeof(ddblt); + if(drv->mode->palette!=NULL) + ddblt.dwFillColor = color1.visual.global_index; + else + ddblt.dwFillColor = MakeRGB(drv->mode,color1.visual.r,color1.visual.g,color1.visual.b); + hr = ctx->pBack->Blt(&rcDest,NULL,NULL,DDBLT_COLORFILL,&ddblt); + } + + if (color1.mask & GFX_MASK_PRIORITY) + { + pri = ctx->priority_maps[DD_BUFFER_BACK]->index_data + box.x + box.y*(drv->mode->xfact * 320); + for(i=0; i<box.yl; i++) + { + memset(pri,color1.priority,box.xl); + pri += drv->mode->xfact * 320; + } + } + + return GFX_OK; +} + +int +dd_draw_pixmap(gfx_driver_t *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + HRESULT hr; + gfx_dd_struct_t *ctx; + LPDIRECTDRAWSURFACE dst; + DDSURFACEDESC ddsc; + byte *pri_map = NULL; + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + if (src.xl != dest.xl || src.yl != dest.yl) + { + GFXERROR("Attempt to draw scaled view- not supported by this driver!\n"); + return GFX_FATAL; /* Scaling not supported! */ + } + + switch(buffer) + { + case GFX_BUFFER_FRONT: + GFXERROR("Attempt to draw pixmap to front buffer\n"); + return GFX_ERROR; + case GFX_BUFFER_BACK: + dst = ctx->pBack; + pri_map = ctx->priority_maps[DD_BUFFER_BACK]->index_data; + break; + case GFX_BUFFER_STATIC: + dst = ctx->pStatic; + pri_map = ctx->priority_maps[DD_BUFFER_STATIC]->index_data; + break; + default: + GFXERROR("Unexpected buffer ID %d\n", buffer); + return GFX_ERROR; + } + + memset(&ddsc,0,sizeof(ddsc)); + ddsc.dwSize = sizeof(ddsc); + hr = dst->Lock(NULL,&ddsc,DDLOCK_WAIT,NULL); + if(FAILED(hr)) + { + return GFX_ERROR; + } + + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, (byte *) ddsc.lpSurface, + ddsc.lPitch,pri_map, drv->mode->xfact * 320, 1, 0); + + hr = dst->Unlock(NULL); + + return GFX_OK; +} + +int +dd_grab_pixmap(gfx_driver_t *drv, rect_t src, gfx_pixmap_t *pxm, gfx_map_mask_t map) +{ + HRESULT hr; + gfx_dd_struct_t *ctx; + DDSURFACEDESC ddsc; + int i,x,y,xlb,bpp; + BYTE *s,*d; + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + if (src.x < 0 || src.y < 0) + { + GFXERROR("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) + { + GFXERROR("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + + pxm->xl = src.xl; + pxm->yl = src.yl; + + memset(&ddsc,0,sizeof(ddsc)); + ddsc.dwSize = sizeof(ddsc); + hr = ctx->pBack->Lock(NULL,&ddsc,DDLOCK_WAIT,NULL); + if(FAILED(hr)) + return GFX_ERROR; + + bpp = ddsc.ddpfPixelFormat.dwRGBBitCount / 8; + x = src.x*drv->mode->xfact; + y = src.y*drv->mode->yfact; +/* + if(!g_bFullScreen) + { + x += ctx->win_xpos; + y += ctx->win_ypos; + } +*/ + s = (BYTE *) ddsc.lpSurface + x*bpp + y*ddsc.lPitch; + d = pxm->data; + xlb = src.xl * bpp; + + for(i=0; i<src.yl; i++) + { + memcpy(d,s,xlb); + d += xlb; + s += ddsc.lPitch; + } + + hr = ctx->pBack->Unlock(NULL); + + return GFX_OK; +} + +static int +dd_update(gfx_driver_t *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + gfx_dd_struct_t *ctx; + RECT rcDst,rcSrc; + HRESULT hr; + LPDIRECTDRAWSURFACE p_dst,p_src; + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + rcSrc.left = src.x; + rcSrc.right = src.x + src.xl; + rcSrc.top = src.y; + rcSrc.bottom = src.y + src.yl; + + rcDst.left = dest.x; + rcDst.right = dest.x + src.xl; + rcDst.top = dest.y; + rcDst.bottom = dest.y + src.yl; + + switch(buffer) + { + case GFX_BUFFER_FRONT: + rcDst.left += ctx->win_xpos; + rcDst.right += ctx->win_xpos; + rcDst.top += ctx->win_ypos; + rcDst.bottom += ctx->win_ypos; + p_dst = ctx->pPrimary; + p_src = ctx->pBack; + break; + case GFX_BUFFER_BACK: + p_dst = ctx->pBack; + p_src = ctx->pStatic; + break; + default: + return GFX_ERROR; + } + + hr = p_dst->Blt(&rcDst,p_src,&rcSrc,DDBLT_WAIT,NULL); + if(FAILED(hr)) + return GFX_ERROR; + + return GFX_OK; +} + +static int +dd_set_static_buffer(gfx_driver_t *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + gfx_dd_struct_t *ctx; + DDSURFACEDESC ddsc; + HRESULT hr; + int i,xs; + byte *s,*d; +// ggi_visual_t vis = get_writeable_static_visual(drv); + + if(drv->state == NULL) + return GFX_ERROR; + + ctx = (gfx_dd_struct_t *) drv->state; + + /* First, check if the priority map is sane */ + if (priority->index_xl != ctx->priority_maps[DD_BUFFER_STATIC]->index_xl + || priority->index_yl != ctx->priority_maps[DD_BUFFER_STATIC]->index_yl) + { + GFXERROR("Invalid priority map: (%dx%d) vs expected (%dx%d)\n", + priority->index_xl, priority->index_yl, + ctx->priority_maps[DD_BUFFER_STATIC]->index_xl, + ctx->priority_maps[DD_BUFFER_STATIC]->index_yl); + return GFX_ERROR; + } + +// ggiPutBox(vis, 0, 0, pic->xl, pic->yl, pic->data); + memset(&ddsc,0,sizeof(ddsc)); + ddsc.dwSize = sizeof(ddsc); + hr = ctx->pStatic->Lock(NULL,&ddsc,DDLOCK_WAIT,NULL); + if(FAILED(hr)) + { + return GFX_ERROR; + } + + s = pic->data; + d = (byte *) ddsc.lpSurface; + xs = drv->mode->bytespp * pic->xl; + + for(i=0; i<pic->yl; i++) + { + memcpy(d,s,xs); + s+= xs; + d+= ddsc.lPitch; + } + + hr = ctx->pStatic->Unlock(NULL); + + memcpy(ctx->priority_maps[DD_BUFFER_STATIC]->index_data, priority->index_data, + priority->index_xl * priority->index_yl); + + return GFX_OK; +} + +static int +dd_set_palette(gfx_driver_t *drv, int index, byte red, byte green, byte blue) +{ + //!! implement me !! + return GFX_ERROR; +} + +// ------------------------------------- non-drawing functions ------------------------------------ +sci_event_t get_queue_event(gfx_dd_struct_t *ctx); + +static int process_messages(void) +{ + MSG msg; + + while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!GetMessage (&msg, NULL, 0, 0)) + return 0; + TranslateMessage (&msg); + DispatchMessage(&msg); + } + return 1; +} + +static sci_event_t +dd_get_event(gfx_driver_t *drv) +{ + gfx_dd_struct_t *ctx; + + process_messages(); + + assert(drv->state!=NULL); + + ctx = (gfx_dd_struct_t *) drv->state; + + return get_queue_event(ctx); +} + +static void +MsgWait (long WaitTime) +{ + DWORD dwRet=0; + long dwWait; + DWORD StartTime=timeGetTime(); + + dwWait = WaitTime; + + if (!process_messages()) + return; + + if (dwWait <= 0) + return; + do + { + dwWait=WaitTime-(timeGetTime()-StartTime); + if (dwWait <= 0) + break; + + dwRet=MsgWaitForMultipleObjects (0, NULL, FALSE, dwWait, QS_ALLINPUT); + + if(dwRet == WAIT_TIMEOUT) + return; + + if (!process_messages()) + return; + + } while(1); +} + +int +dd_usleep(gfx_driver_t* drv, long usec) +{ + if (usec < 1000) + Sleep(usec / 1000); + else + MsgWait (usec / 1000); + + return GFX_OK; +} +/* --------------------------------------------------------------- */ + +static void init_event_queue(gfx_dd_struct_t *ctx) +{ + ctx->queue_first = 0; + ctx->queue_last = 0; + ctx->queue_size = 256; + ctx->event_queue = (sci_event_t *) sci_malloc (ctx->queue_size * sizeof (sci_event_t)); +} + +static void free_event_queue(gfx_dd_struct_t *ctx) +{ + if (ctx->event_queue) sci_free(ctx->event_queue); + ctx->queue_size = 0; + ctx->queue_first =0; + ctx->queue_last =0; +} + +static void add_queue_event(gfx_dd_struct_t *ctx,int type, int data, int buckybits) +{ + if ((ctx->queue_last+1) % ctx->queue_size == ctx->queue_first) + { + /* Reallocate queue */ + int i, event_count; + sci_event_t *new_queue; + + new_queue = (sci_event_t *) sci_malloc (ctx->queue_size * 2 * sizeof (sci_event_t)); + event_count = (ctx->queue_last - ctx->queue_first) % ctx->queue_size; + for (i=0; i<event_count; i++) + new_queue [i] = ctx->event_queue [(ctx->queue_first+i) % ctx->queue_size]; + free (ctx->event_queue); + ctx->event_queue = new_queue; + ctx->queue_size *= 2; + ctx->queue_first = 0; + ctx->queue_last = event_count; + } + + ctx->event_queue [ctx->queue_last].data = data; + ctx->event_queue [ctx->queue_last].type = type; + ctx->event_queue [ctx->queue_last++].buckybits = buckybits; + if (ctx->queue_last == ctx->queue_size) + ctx->queue_last=0; +} + +static void add_mouse_event (gfx_dd_struct_t *ctx,int type, int data, WPARAM wParam) +{ + int buckybits = 0; + + if (wParam & MK_SHIFT) + buckybits |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + if (wParam & MK_CONTROL) + buckybits |= SCI_EVM_CTRL; + + add_queue_event (ctx,type, data, buckybits); +} + +static void add_key_event (gfx_dd_struct_t *ctx,int data) +{ + int buckybits = 0; + + /* FIXME: If anyone cares, on Windows NT we can distinguish left and right shift */ + if (GetAsyncKeyState (VK_SHIFT)) + buckybits |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + if (GetAsyncKeyState (VK_CONTROL)) + buckybits |= SCI_EVM_CTRL; + if (GetAsyncKeyState (VK_MENU)) + buckybits |= SCI_EVM_ALT; + if (GetKeyState (VK_CAPITAL) & 1) + buckybits |= SCI_EVM_CAPSLOCK; + + add_queue_event (ctx,SCI_EVT_KEYBOARD, data, buckybits); +} + +sci_event_t get_queue_event(gfx_dd_struct_t *ctx) +{ + if (ctx->queue_first == ctx->queue_size) + ctx->queue_first = 0; + + if (ctx->queue_first == ctx->queue_last) + { + sci_event_t noevent; + noevent.data = 0; + noevent.type = SCI_EVT_NONE; + noevent.buckybits = 0; + return noevent; + } + else + return ctx->event_queue [ctx->queue_first++]; +} + +#define MAP_KEY(x,y) case x: add_key_event (ctx, y); break + +static long FAR PASCAL WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HRESULT hr; + gfx_dd_struct_t *ctx; + gfx_driver_t* drv; + + drv = (gfx_driver_t *) GetWindowLong(hWnd,0); + if(drv == NULL) + return DefWindowProc(hWnd,message,wParam,lParam); + ctx = (gfx_dd_struct_t *) drv->state; + if(ctx == NULL) + return DefWindowProc(hWnd,message,wParam,lParam); + + switch(message) + { + case WM_SIZE: + case WM_MOVE: + { + POINT pnt; + pnt.x = 0; pnt.y = 0; + ClientToScreen (hWnd, &pnt); + ctx->win_xpos = pnt.x; + ctx->win_ypos = pnt.y; + } + break; + case WM_PAINT: + { + RECT rcSrc,rcDst; + if (ctx->pPrimary!=NULL && ctx->pBack!=NULL && GetUpdateRect (hWnd, &rcSrc, FALSE)) + { + if(rcSrc.right>320) + rcSrc.right=320; + if(rcSrc.bottom>200) + rcSrc.bottom=200; + rcDst.left = rcSrc.left + ctx->win_xpos; + rcDst.right = rcSrc.right + ctx->win_xpos; + rcDst.top = rcSrc.top + ctx->win_ypos; + rcDst.bottom = rcSrc.bottom + ctx->win_ypos; + hr = ctx->pPrimary->Blt(&rcDst,ctx->pBack,&rcSrc,DDBLT_WAIT,NULL); + ValidateRect(hWnd,&rcSrc); + } + } + break; + case WM_SETCURSOR: + if(IsIconic(hWnd) || ctx->bShowMouse) + { + SetCursor(LoadCursor (NULL, IDC_ARROW)); + } + else + { + SetCursor(NULL); + } + return TRUE; + case WM_NCMOUSEMOVE: + ctx->bShowMouse = TRUE; + break; + case WM_MOUSEMOVE: + ctx->bShowMouse = FALSE; + if( ((lParam & 0xFFFF) >= 320*drv->mode->xfact) || ((lParam >> 16) >= 200*drv->mode->yfact)) + break; + drv->pointer_x = lParam & 0xFFFF; + drv->pointer_y = lParam >> 16; + break; + + case WM_LBUTTONDOWN: add_mouse_event (ctx, SCI_EVT_MOUSE_PRESS, 1, wParam); break; + case WM_RBUTTONDOWN: add_mouse_event (ctx, SCI_EVT_MOUSE_PRESS, 2, wParam); break; + case WM_MBUTTONDOWN: add_mouse_event (ctx, SCI_EVT_MOUSE_PRESS, 3, wParam); break; + case WM_LBUTTONUP: add_mouse_event (ctx, SCI_EVT_MOUSE_RELEASE, 1, wParam); break; + case WM_RBUTTONUP: add_mouse_event (ctx, SCI_EVT_MOUSE_RELEASE, 2, wParam); break; + case WM_MBUTTONUP: add_mouse_event (ctx, SCI_EVT_MOUSE_RELEASE, 3, wParam); break; + + case WM_KEYDOWN: + switch (wParam) + { + MAP_KEY (VK_ESCAPE, SCI_K_ESC); + MAP_KEY (VK_END, SCI_K_END); + MAP_KEY (VK_DOWN, SCI_K_DOWN); + MAP_KEY (VK_NEXT, SCI_K_PGDOWN); + MAP_KEY (VK_LEFT, SCI_K_LEFT); + MAP_KEY (VK_RIGHT, SCI_K_RIGHT); + MAP_KEY (VK_HOME, SCI_K_HOME); + MAP_KEY (VK_UP, SCI_K_UP); + MAP_KEY (VK_PRIOR, SCI_K_PGUP); + MAP_KEY (VK_INSERT, SCI_K_INSERT); + MAP_KEY (VK_DELETE, SCI_K_DELETE); + MAP_KEY (VK_BACK, SCI_K_BACKSPACE); + MAP_KEY (VK_TAB, '\t'); + MAP_KEY (VK_RETURN, '\r'); + + default: + if (wParam >= VK_F1 && wParam <= VK_F10) + add_key_event (ctx, wParam - VK_F1 + SCI_K_F1); + else if (wParam >= 'A' && wParam <= 'Z') + add_key_event (ctx, wParam - 'A' + 97); + else if (wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) + { + if (GetKeyState (VK_NUMLOCK) & 1) + add_key_event (ctx, wParam - VK_NUMPAD0 + '0'); + else + switch (wParam) + { + MAP_KEY (VK_NUMPAD0, SCI_K_INSERT); + MAP_KEY (VK_NUMPAD1, SCI_K_END); + MAP_KEY (VK_NUMPAD2, SCI_K_DOWN); + MAP_KEY (VK_NUMPAD3, SCI_K_PGDOWN); + MAP_KEY (VK_NUMPAD4, SCI_K_LEFT); + MAP_KEY (VK_NUMPAD6, SCI_K_RIGHT); + MAP_KEY (VK_NUMPAD7, SCI_K_HOME); + MAP_KEY (VK_NUMPAD8, SCI_K_UP); + MAP_KEY (VK_NUMPAD9, SCI_K_PGUP); + } + } + else if (wParam == 0xC0) /* tilde key - used for invoking console */ + add_key_event (ctx, '`'); + else + add_key_event (ctx, wParam); + break; + } + } + return DefWindowProc(hWnd,message,wParam,lParam); +} + +/* --------------------------------------------------------------- */ +extern "C" +gfx_driver_t gfx_driver_dd = { + "ddraw", + DD_DRIVER_VERSION, + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0,0, + 0, + GFX_DEBUG_POINTER | GFX_DEBUG_UPDATES | GFX_DEBUG_PIXMAPS | GFX_DEBUG_BASIC, + dd_set_param, + dd_init_specific, + dd_init, + dd_exit, + dd_draw_line, + dd_draw_filled_rect, + NULL, + NULL, + dd_draw_pixmap, + dd_grab_pixmap, + dd_update, + dd_set_static_buffer, + NULL, + dd_set_palette, + dd_get_event, + dd_usleep +}; + +#endif // HAVE_DDRAW diff --git a/engines/sci/gfx/drivers/dd_driver.h b/engines/sci/gfx/drivers/dd_driver.h new file mode 100644 index 0000000000..209fe51569 --- /dev/null +++ b/engines/sci/gfx/drivers/dd_driver.h @@ -0,0 +1,2 @@ + +void _dd_draw_line(gfx_mode_t * mode, rect_t line, byte * dest, int linewidth,gfx_color_t color); diff --git a/engines/sci/gfx/drivers/dd_driver_line.cpp b/engines/sci/gfx/drivers/dd_driver_line.cpp new file mode 100644 index 0000000000..e83b368a5e --- /dev/null +++ b/engines/sci/gfx/drivers/dd_driver_line.cpp @@ -0,0 +1,163 @@ +#ifndef __cplusplus +#error NOTE: This file MUST be compiled as C++. In Visual C++, use the /Tp command line option. +#endif + +extern "C" { +#include <gfx_system.h> +#include <gfx_tools.h> +}; + +#define LINEMACRO_1(startx, starty, deltalinear, deltanonlinear, linearvar, nonlinearvar, \ + linearend, nonlinearstart, linearmod, nonlinearmod) \ + 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] = color; \ + linearvar += linearmod; \ + if ((d+=incrE) < 0) { \ + d += incrNE; \ + nonlinearvar += nonlinearmod; \ + }; \ + }; \ + buffer[linewidth * y + x] = color; + +#define LINEMACRO_N(startx, starty, deltalinear, deltanonlinear, linearvar, nonlinearvar, \ + linearend, nonlinearstart, linearmod, nonlinearmod) \ + x = (startx); y = (starty); \ + incrNE = ((deltalinear) > 0)? (deltalinear) : -(deltalinear); \ + incrNE <<= 1; \ + deltanonlinear <<= 1; \ + incrE = ((deltanonlinear) > 0) ? -(deltanonlinear) : (deltanonlinear); \ + d = nonlinearstart-1; \ + while (linearvar != (linearend)) { \ + memcpy(&buffer[linewidth * y + bpp*x],&color,bpp); \ + linearvar += linearmod; \ + if ((d+=incrE) < 0) { \ + d += incrNE; \ + nonlinearvar += nonlinearmod; \ + }; \ + }; \ + memcpy(&buffer[linewidth * y + x],&color,bpp); + +void _dd_draw_line_buffer_1(byte *buffer, int linewidth, rect_t line, int color) +{ + /*void dither_line(picture_t buffers, int curx, int cury, short x1, short y1, + int col1, int col2, int priority, int special, char drawenable)*/ + + int dx, dy, incrE, incrNE, d, finalx, finaly; + int x = line.x; + int y = line.y; + 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_1(x, y, dx, dy, x, y, finalx, dx, -1, -1); + } else { /* lld */ + LINEMACRO_1(x, y, dx, dy, x, y, finalx, dx, -1, 1); + } + } else { /* x1 >= x */ + if (finaly < y) { /* rru */ + LINEMACRO_1(x, y, dx, dy, x, y, finalx, dx, 1, -1); + } else { /* rrd */ + LINEMACRO_1(x, y, dx, dy, x, y, finalx, dx, 1, 1); + } + } + } else { /* dx <= dy */ + if (finaly < y) { + if (finalx < x) { /* luu */ + LINEMACRO_1(x, y, dy, dx, y, x, finaly, dy, -1, -1); + } else { /* ruu */ + LINEMACRO_1(x, y, dy, dx, y, x, finaly, dy, -1, 1); + } + } else { /* y1 >= y */ + if (finalx < x) { /* ldd */ + LINEMACRO_1(x, y, dy, dx, y, x, finaly, dy, 1, -1); + } else { /* rdd */ + LINEMACRO_1(x, y, dy, dx, y, x, finaly, dy, 1, 1); + } + } + } +} + +void _dd_draw_line_buffer_n(int bpp,byte *buffer, int linewidth, rect_t line, byte * color) +{ + /*void dither_line(picture_t buffers, int curx, int cury, short x1, short y1, + int col1, int col2, int priority, int special, char drawenable)*/ + + int dx, dy, incrE, incrNE, d, finalx, finaly; + int x = line.x; + int y = line.y; + 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_N(x, y, dx, dy, x, y, finalx, dx, -1, -1); + } else { /* lld */ + LINEMACRO_N(x, y, dx, dy, x, y, finalx, dx, -1, 1); + } + } else { /* x1 >= x */ + if (finaly < y) { /* rru */ + LINEMACRO_N(x, y, dx, dy, x, y, finalx, dx, 1, -1); + } else { /* rrd */ + LINEMACRO_N(x, y, dx, dy, x, y, finalx, dx, 1, 1); + } + } + } else { /* dx <= dy */ + if (finaly < y) { + if (finalx < x) { /* luu */ + LINEMACRO_N(x, y, dy, dx, y, x, finaly, dy, -1, -1); + } else { /* ruu */ + LINEMACRO_N(x, y, dy, dx, y, x, finaly, dy, -1, 1); + } + } else { /* y1 >= y */ + if (finalx < x) { /* ldd */ + LINEMACRO_N(x, y, dy, dx, y, x, finaly, dy, 1, -1); + } else { /* rdd */ + LINEMACRO_N(x, y, dy, dx, y, x, finaly, dy, 1, 1); + } + } + } +} + +void _dd_draw_line(gfx_mode_t * mode, rect_t line, byte * dest, int linewidth,gfx_color_t color) +{ + byte ca[4]; + unsigned short co1; + + switch(mode->bytespp) + { + case 1: + _dd_draw_line_buffer_1(dest,linewidth,line,color.visual.global_index); + break; + case 2: + co1 = (color.visual.r << mode->red_shift) & mode->red_mask; + co1 |= (color.visual.g << mode->green_shift) & mode->green_mask; + co1 |= (color.visual.b << mode->blue_shift) & mode->blue_mask; + _dd_draw_line_buffer_n(2,dest,linewidth,line, (byte *) &co1); + break; + case 3: + ca[mode->red_shift/8]=color.visual.r; + ca[mode->green_shift/8]=color.visual.g; + ca[mode->blue_shift/8]=color.visual.b; + _dd_draw_line_buffer_n(3,dest,linewidth,line, ca); + break; + } +} diff --git a/engines/sci/gfx/drivers/directfb_driver.c b/engines/sci/gfx/drivers/directfb_driver.c new file mode 100644 index 0000000000..634b2b11df --- /dev/null +++ b/engines/sci/gfx/drivers/directfb_driver.c @@ -0,0 +1,1033 @@ +/*************************************************************************** + directfb_driver.c Copyright (C) 2002 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* FreeSCI 0.3.1+ graphics driver module for libdirectfb */ + + +#include <stdarg.h> +#include <gfx_system.h> +#include <gfx_driver.h> +#include <gfx_tools.h> +#include <assert.h> +#include <uinput.h> + +#ifdef HAVE_DIRECTFB + +#include <stdio.h> +#include <stdlib.h> +#include <directfb/directfb.h> +#include <unistd.h> + +#define SCIDFB_DRIVER_VERSION "0.4" + +typedef struct _event_queue_struct { + sci_event_t evt; + struct _event_queue_struct *next; +} event_queue_t; + +/* +** For this driver to work to the fullest of its capabilities, the user running it +** must have rw permissions on the following: +** /dev/tty0 (including VT_ACTIVATE perms) +** /dev/tty7 +** /dev/fb0 +** /dev/psaux (if using a PS/2 mouse) +** +** VT_ACTIVATE permissions are, AFAIK, only available to root ATM :-( +*/ + +#define SCIDFB_CAP_ALPHA (1 << 0) /* Do we have an Alpha channel? */ + +#define SCIDFB_MAY_ALPHA (scidfb_internal_caps & SCIDFB_CAP_ALPHA) + +/* Global data */ + +static IDirectFB *scidfb_framebuffer; /* The global framebuffer */ +static IDirectFBDisplayLayer *scidfb_layer; /* The layer we use for drawing */ +static IDirectFBSurface *scidfb_visual; /* Static visual buffer */ +static IDirectFBSurface *scidfb_static_visual; /* Static visual buffer */ +static gfx_pixmap_t *scidfb_static_priority = NULL; +static gfx_pixmap_t *scidfb_back_priority = NULL; +static int scidfb_internal_caps = 0; /* Certain internal capabilities available to us */ + +/* Input structures */ +static IDirectFBEventBuffer *scidfb_input_buffer = NULL; +static event_queue_t *scidfb_event_queue = NULL; +static unsigned int scidfb_buckybits = SCI_EVM_INSERT; + + +/*#define LIST_ALL_DFB_MODES */ /* Uncomment for minimal debugging */ + +#define SCIDFB_CHECKED(f) \ + { \ + DFBResult _r = (f); \ + if (_r != DFB_OK) { \ + scidfb_handle_error(_r, __FILE__, __LINE__); \ + return GFX_ERROR; \ + } \ + } + +#define SCIGFX_CHECKED(f) \ + { \ + DFBResult _r = (f); \ + if (_r != GFX_OK) { \ + return _r; \ + } \ + } + + +static void +scidfb_handle_error(DFBResult errc, char *file, int line) +{ + const char *err = DirectFBErrorString(errc); + + GFXERROR("DFB-GFX, %s L%d: %s\n", file, line, err); +} + + +typedef struct { + int x, y, bpp; +} scidfb_mode_t; + + +static DFBEnumerationResult +scidfb_mode_callback(unsigned int width, unsigned int height, unsigned int bpp, void *conf) +{ + scidfb_mode_t *aim = (scidfb_mode_t *) conf; + scidfb_mode_t *best = aim + 1; + + if ((width >= aim->x && height >= aim->y && bpp >= aim->bpp) + /* Sufficient in all respects... */ + && ((best->bpp == 0) /* First mode that matched */ + || (width < best->x && height <= best->y) /* Improvement on x */ + || (width <= best->x && height < best->y) /* Improvement on y */ + || (width <= best->x && height <= best->y && bpp < best->bpp) + /* Improvement on bpp */ + )) { + best->x = width; + best->y = height; + best->bpp = bpp; + } + +#ifdef LIST_ALL_DFB_MODES + GFXERROR("DFB-GFX: Supports %dx%d at %d bpp\n", width, height, bpp); + return DFENUM_OK; +#endif + + if (aim->x == best->x + && aim->y == best->y + && aim->bpp == best->bpp) + return DFENUM_CANCEL; /* We have what we were looking for */ + + return DFENUM_OK; /* Continue searching */ +} + + +static DFBEnumerationResult +scidfb_layer_callback(unsigned int layer_id, DFBDisplayLayerCapabilities caps, void *resultp) +{ + unsigned int *results = (unsigned int *) resultp; + + if (!(caps & DLCAPS_SURFACE)) + return DFENUM_OK; /* We need a surface */ + + if (!results[1]) + results[0] = layer_id; + + results[1] = 1; + + if (caps & DLCAPS_ALPHACHANNEL) { + /* Optimal! */ + scidfb_internal_caps |= SCIDFB_MAY_ALPHA; + return DFENUM_CANCEL; /* We're done */ + } + + /* Found something, but it might get better */ + return DFENUM_OK; +} + +#define LOOKING_FOR_POINTING_DEVICE 1 +#define LOOKING_FOR_KEYBOARD 2 +#define FOUND_IT 255 + +static DFBEnumerationResult +scidfb_input_callback(unsigned int device_id, DFBInputDeviceDescription descr, void *p) +{ + int *state = (int *) p; + int *result = state + 1; + + /* Check for mouse */ + if (*state == LOOKING_FOR_POINTING_DEVICE + && (descr.type & DIDTF_MOUSE)) { + *result = device_id; + *state = FOUND_IT; + return DFENUM_CANCEL; + } + + /* Check for keyboard */ + if (*state == LOOKING_FOR_KEYBOARD + && (descr.type & DIDTF_KEYBOARD)) { + *result = device_id; + *state = FOUND_IT; + return DFENUM_CANCEL; + } + + return DFENUM_OK; +} + +static int +scidfb_find_layer() +{ + unsigned int results[2]; + + results[1] = 0; + SCIDFB_CHECKED(scidfb_framebuffer->EnumDisplayLayers(scidfb_framebuffer, + scidfb_layer_callback, &results)); + + if (!results[1]) + return GFX_FATAL; /* No decent layer! */ + else { + SCIDFB_CHECKED(scidfb_framebuffer->GetDisplayLayer(scidfb_framebuffer, + results[0], + &scidfb_layer)); + + return GFX_OK; + } +} + +static int +_scidfb_init_input(int *found_keyboard, int *found_mouse) +{ + int inputs[2]; + + inputs[0] = LOOKING_FOR_POINTING_DEVICE; + SCIDFB_CHECKED(scidfb_framebuffer->EnumInputDevices(scidfb_framebuffer, + scidfb_input_callback, &inputs)); + + if ((*found_mouse = (inputs[0] == FOUND_IT))) { + IDirectFBInputDevice *mouse; + SCIDFB_CHECKED(scidfb_framebuffer->GetInputDevice(scidfb_framebuffer, + inputs[1], &mouse)); + + SCIDFB_CHECKED(mouse->CreateEventBuffer(mouse, &scidfb_input_buffer)); + } + + inputs[0] = LOOKING_FOR_KEYBOARD; + SCIDFB_CHECKED(scidfb_framebuffer->EnumInputDevices(scidfb_framebuffer, + scidfb_input_callback, &inputs)); + if ((*found_keyboard = (inputs[0] == FOUND_IT))) { + IDirectFBInputDevice *keyboard; + SCIDFB_CHECKED(scidfb_framebuffer->GetInputDevice(scidfb_framebuffer, + inputs[1], &keyboard)); + + if (scidfb_input_buffer) + SCIDFB_CHECKED(keyboard->AttachEventBuffer(keyboard, scidfb_input_buffer)) + else + SCIDFB_CHECKED(keyboard->CreateEventBuffer(keyboard, + &scidfb_input_buffer)); + } + + + SCIDFB_CHECKED(scidfb_framebuffer->CreateEventBuffer(scidfb_framebuffer, + DICAPS_KEYS + | DICAPS_AXES + | DICAPS_BUTTONS, + &scidfb_input_buffer)); +} + +static int +_scidfb_init_gfx_mode(int width, int height, int bpp) +{ + scidfb_mode_t modes[2]; + modes[0].x = width; + modes[0].y = height; + modes[0].bpp = bpp; + + modes[1].bpp = 0; /* nothing found yet */ + + SCIDFB_CHECKED(DirectFBCreate(&scidfb_framebuffer)); + SCIDFB_CHECKED(scidfb_framebuffer->EnumVideoModes(scidfb_framebuffer, + scidfb_mode_callback, &modes)); + + if (modes[1].bpp) { + DFBDisplayLayerConfig conf; + + if (scidfb_find_layer()) { + GFXERROR("DFB-GFX: No useable display layer found"); + return GFX_FATAL; + } + + SCIDFB_CHECKED(scidfb_framebuffer->SetVideoMode(scidfb_framebuffer, + modes[1].x, modes[1].y, modes[1].bpp)); + + SCIDFB_CHECKED(scidfb_layer->SetCooperativeLevel(scidfb_layer, DLSCL_EXCLUSIVE)); + SCIDFB_CHECKED(scidfb_layer->GetSurface(scidfb_layer, &scidfb_visual)); + + return GFX_OK; + } else + GFXERROR("DFB-GFX: No matching visual could be found!\n"); + + return GFX_FATAL; +} + + +static int +scidfb_build_virtual_surface(IDirectFBSurface **result, int width, int height, + IDirectFBSurface *prototype) +{ + /* This function creates a _virtual_ surface, i.e. a memory buffer, + ** without flipping support */ + DFBSurfaceDescription srf_desc; + IDirectFBSurface *surface; + + SCIDFB_CHECKED(prototype->GetCapabilities(prototype, &(srf_desc.caps))); + srf_desc.caps &= ~DSCAPS_FLIPPING; + srf_desc.width = width; + srf_desc.height = height; + SCIDFB_CHECKED(prototype->GetPixelFormat(prototype, &(srf_desc.pixelformat))); + srf_desc.flags = (DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT); + SCIDFB_CHECKED(scidfb_framebuffer->CreateSurface(scidfb_framebuffer, &srf_desc, &surface)); + SCIDFB_CHECKED(surface->Clear(surface, 0, 0, 0, 255)); + + *result = surface; + + return GFX_OK; +} + +static int +scidfb_deactivate_pointer() +{ + SCIDFB_CHECKED(scidfb_layer->EnableCursor(scidfb_layer, 0)); + return 0; +} + + + /*----------------------------------------------------------------*/ +/*----------- Event queue implementation --------------*/ + /*----------------------------------------------------------------*/ + +#define MILLION 1000000 + +static int +scidfb_xlate_key(DFBInputDeviceKeyIdentifier key, int keysym) +{ + if ((keysym >= 'A') && (keysym <= 'Z')) + return keysym; + if ((keysym >= 'a') && (keysym <= 'z')) + return keysym; + if ((keysym >= '0') && (keysym <= '9')) + return keysym; + + switch (key) { + + case DIKI_0: return '0'; + case DIKI_1: return '1'; + case DIKI_2: return '2'; + case DIKI_3: return '3'; + case DIKI_4: return '4'; + case DIKI_5: return '5'; + case DIKI_6: return '6'; + case DIKI_7: return '7'; + case DIKI_8: return '8'; + case DIKI_9: return '9'; + + case DIKI_F1: return SCI_K_F1; + case DIKI_F2: return SCI_K_F2; + case DIKI_F3: return SCI_K_F3; + case DIKI_F4: return SCI_K_F4; + case DIKI_F5: return SCI_K_F5; + case DIKI_F6: return SCI_K_F6; + case DIKI_F7: return SCI_K_F7; + case DIKI_F8: return SCI_K_F8; + case DIKI_F9: return SCI_K_F9; + case DIKI_F10: return SCI_K_F10; + + case DIKI_KP_0: + case DIKI_INSERT: scidfb_buckybits ^= SCI_EVM_INSERT; + return SCI_K_INSERT; + + case DIKI_ESCAPE: return SCI_K_ESC; + case DIKI_LEFT: return SCI_K_LEFT; + case DIKI_RIGHT: return SCI_K_RIGHT; + case DIKI_UP: return SCI_K_UP; + case DIKI_DOWN: return SCI_K_DOWN; + case DIKI_TAB: return SCI_K_TAB; + case DIKI_ENTER: return SCI_K_ENTER; + case DIKI_SPACE: return ' '; + case DIKI_BACKSPACE: return SCI_K_BACKSPACE; + case DIKI_DELETE: return SCI_K_DELETE; + case DIKI_HOME: return SCI_K_HOME; + case DIKI_END: return SCI_K_END; + case DIKI_PAGE_UP: return SCI_K_PGDOWN; + case DIKI_PAGE_DOWN: return SCI_K_PGUP; + + case DIKI_QUOTE_LEFT: return '`'; + case DIKI_MINUS_SIGN: return '-'; + case DIKI_EQUALS_SIGN: return '='; + case DIKI_BRACKET_LEFT: return '['; + case DIKI_BRACKET_RIGHT: return ']'; + case DIKI_BACKSLASH: return '\\'; + case DIKI_SEMICOLON: return ';'; + case DIKI_QUOTE_RIGHT: return '\''; + case DIKI_COMMA: return ','; + case DIKI_SLASH: return '/'; + case DIKI_PERIOD: return '.'; + + case DIKI_KP_DIV: return '/'; + case DIKI_KP_MULT: return '*'; + case DIKI_KP_MINUS: return '-'; + case DIKI_KP_PLUS: return '+'; + case DIKI_KP_ENTER: return SCI_K_ENTER; + case DIKI_KP_SPACE: return ' '; + case DIKI_KP_TAB: return SCI_K_TAB; + case DIKI_KP_F1: return SCI_K_F1; + case DIKI_KP_F2: return SCI_K_F2; + case DIKI_KP_F3: return SCI_K_F3; + case DIKI_KP_F4: return SCI_K_F4; + case DIKI_KP_EQUAL: return '='; + + case DIKI_KP_DECIMAL: return SCI_K_DELETE; + case DIKI_KP_1: return SCI_K_END; + case DIKI_KP_2: return SCI_K_DOWN; + case DIKI_KP_3: return SCI_K_PGDOWN; + case DIKI_KP_4: return SCI_K_LEFT; + case DIKI_KP_5: return SCI_K_CENTER; + case DIKI_KP_6: return SCI_K_RIGHT; + case DIKI_KP_7: return SCI_K_HOME; + case DIKI_KP_8: return SCI_K_UP; + case DIKI_KP_9: return SCI_K_PGUP; + + default: + + } + return 0; /* Could not map key */ +} + + +scidfb_handle_bucky(int add, DFBInputDeviceKeyIdentifier key) +{ + int modifier = 0; + + switch(key) { + case DIKI_SHIFT_L: modifier = SCI_EVM_LSHIFT; + break; + case DIKI_SHIFT_R: modifier = SCI_EVM_RSHIFT; + break; + case DIKI_CONTROL_L: + case DIKI_CONTROL_R: modifier = SCI_EVM_CTRL; + break; + case DIKI_ALT_L: + case DIKI_ALT_R: + case DIKI_META_L: + case DIKI_META_R: modifier = SCI_EVM_ALT; + break; + case DIKI_CAPS_LOCK: modifier = SCI_EVM_CAPSLOCK; + break; + case DIKI_NUM_LOCK: modifier = SCI_EVM_NUMLOCK; + break; + case DIKI_SCROLL_LOCK: modifier = SCI_EVM_SCRLOCK; + break; + } + + if (add) + scidfb_buckybits |= modifier; + else + scidfb_buckybits &= ~modifier; +} + +static sci_event_t +scidfb_xlate_event(gfx_driver_t *drv, DFBEvent dfb_pre_evt) +{ + sci_event_t retval; + + retval.type = SCI_EVT_NONE; + retval.buckybits = scidfb_buckybits; + + if (dfb_pre_evt.clazz == DFEC_INPUT) { /* What kind of idiot named these field members? */ + DFBInputEvent dfbevt = dfb_pre_evt.input; + switch (dfbevt.type) { + + case DIET_KEYPRESS: + retval.type = SCI_EVT_KEYBOARD; + scidfb_handle_bucky(1, dfbevt.key_id); + retval.data = scidfb_xlate_key(dfbevt.key_id, dfbevt.key_symbol); + if (retval.data == 0) + retval.type = SCI_EVT_NONE; + break; + + case DIET_KEYRELEASE: + scidfb_handle_bucky(0, dfbevt.key_id); + break; + + case DIET_BUTTONPRESS: + retval.type = SCI_EVT_MOUSE_PRESS; + retval.data = dfbevt.button - DIBI_FIRST; + break; + + case DIET_AXISMOTION:{ + int *victim = NULL; + + if (dfbevt.axis == DIAI_X) + victim = &(drv->pointer_x); + else if (dfbevt.axis == DIAI_Y) + victim = &(drv->pointer_y); + else break; + + if (dfbevt.flags & DIEF_AXISABS) + *victim = dfbevt.axisabs; + else if (dfbevt.flags & DIEF_AXISREL) + *victim += dfbevt.axisrel; + } + break; + + case DIET_BUTTONRELEASE: + retval.type = SCI_EVT_MOUSE_RELEASE; + retval.data = dfbevt.button - DIBI_FIRST; + break; + } + } + + return retval; +} + +static void +scidfb_queue_event(sci_event_t evt) +{ + event_queue_t *node = malloc(sizeof(event_queue_t)); + event_queue_t **seekerp = &scidfb_event_queue; + + node->evt = evt; + node->next = NULL; + + while (*seekerp) + seekerp = &((*seekerp)->next); + + *seekerp = node; +} + + +static int +scidfb_queue_next_event(gfx_driver_t *drv, long micros_to_wait) +{ + DFBEvent dfb_event; + long secs = micros_to_wait / MILLION; + long usecs = (micros_to_wait - (secs * MILLION)) / 1000; + int has_event; + DFBResult timeout; + + timeout = scidfb_input_buffer->WaitForEventWithTimeout(scidfb_input_buffer, + secs, usecs); + if (timeout != DFB_TIMEOUT) + SCIDFB_CHECKED(timeout); + + has_event = scidfb_input_buffer->HasEvent(scidfb_input_buffer); + if (has_event == DFB_OK) { + sci_event_t evt; + /* We have a new event */ + SCIDFB_CHECKED(scidfb_input_buffer->GetEvent(scidfb_input_buffer, &dfb_event)); + evt = scidfb_xlate_event(drv, dfb_event); + + if (evt.type != SCI_EVT_NONE) + scidfb_queue_event(evt); + + return 0; + } else + if (has_event != DFB_BUFFEREMPTY) + return has_event; /* An error occured */ +} + + +static int +_scidfb_read_event(sci_event_t *evtp) +{ + if (scidfb_event_queue) { + event_queue_t *q = scidfb_event_queue; + *evtp = q->evt; + scidfb_event_queue = q->next; + free(q); + + return 1; + } else { + evtp->type = SCI_EVT_NONE; + return 0; + } +} + + + + + /*----------------------------------------------------------------*/ +/*----------- Implementations required by gfx_driver_t --------------*/ + /*----------------------------------------------------------------*/ + + +static int +scidfb_set_parameter(gfx_driver_t *drv, char *name, char *value) +{ + fprintf(stderr, "FIXME: These must be caught and moved in between DirectFBInit() and ..Create()\n"); + exit(1); + SCIDFB_CHECKED(DirectFBSetOption(name, value)); + return GFX_OK; +} + +static int +_scidfb_decode_pixel_format(DFBSurfacePixelFormat pixel_format, + int *rm, int *gm, int *bm, int *am, + int *rs, int *gs, int *bs, int *as, int *bytespp) +{ + /* Initially, the masks are set to the number of bits they occupy, and shifts + ** are left shifts */ + int _rs, _gs, _bs, _as; + + _as = 0; + *am = 0; + *as = 0; + + switch (pixel_format) { + + case DSPF_RGB15: + *bytespp = 2; + *rm = 5; _rs = 10; + *gm = 5; _gs = 5; + *bm = 5; _bs = 0; + break; + + case DSPF_RGB16: + *bytespp = 2; + *rm = 5; _rs = 11; + *gm = 6; _gs = 5; + *bm = 5; _bs = 0; + break; + + case DSPF_RGB24: + *bytespp = 3; + *rm = 8; _rs = 16; + *gm = 8; _gs = 8; + *bm = 8; _bs = 0; + break; + + case DSPF_RGB32: + *bytespp = 4; + *rm = 8; _rs = 16; + *gm = 8; _gs = 8; + *bm = 8; _bs = 0; + break; + + case DSPF_ARGB: + *bytespp = 4; + *am = 8; _as = 24; + *rm = 8; _rs = 16; + *gm = 8; _gs = 8; + *bm = 8; _bs = 0; + break; + + case DSPF_RGB332: + *bytespp = 1; + *rm = 3; _rs = 5; + *gm = 3; _gs = 2; + *bm = 2; _bs = 0; + break; + + default: + GFXERROR("DFB-GFX: Unknown/unsupported pixel format %08x\n", pixel_format); + return GFX_FATAL; + } + + /* Calculate correct shifts */ + *rs = 32 - *rm - _rs; + *gs = 32 - *gm - _gs; + *bs = 32 - *bm - _bs; + *as = 32 - *am - _as; + + /* Calculate correct masks */ + *rm = ((1 << (*rm)) - 1) << _rs; + *gm = ((1 << (*gm)) - 1) << _gs; + *bm = ((1 << (*bm)) - 1) << _bs; + *am = ((1 << (*am)) - 1) << _as; + + return GFX_OK; +} + +static int +scidfb_init_specific(gfx_driver_t *drv, int xres, int yres, int bytespp) +{ + DFBSurfacePixelFormat pixel_format; + char **p; + char *foo = ""; + int n = 1; + + int width, height; + int red_mask, green_mask, blue_mask, alpha_mask; + int red_shift, green_shift, blue_shift, alpha_shift; + int bytespp_real; + int mouse, keyboard; + + p = &foo; + DirectFBInit(&n, &p); + + SCIDFB_CHECKED(DirectFBSetOption("no-sighandler", "1")); + + SCIGFX_CHECKED(_scidfb_init_gfx_mode(xres, yres, (1 << bytespp) - 1)); + SCIGFX_CHECKED(_scidfb_init_input(&keyboard, &mouse)); + + if (!keyboard) { + GFXERROR("DFB-GFX: No keyboard found-- aborting...\n"); + return GFX_FATAL; + } + if (!mouse) { + GFXWARN("DFB-GFX: No pointing device found, disabling mouse support...\n"); + drv->capabilities &= ~GFX_CAPABILITY_MOUSE_SUPPORT; + } + + SCIDFB_CHECKED(scidfb_visual->GetSize(scidfb_visual, &width, &height)); + + scidfb_deactivate_pointer(); + SCIDFB_CHECKED(scidfb_visual->Clear(scidfb_visual, 0, 0, 0, 255)); + SCIDFB_CHECKED(scidfb_visual->Flip(scidfb_visual, NULL, DSFLIP_BLIT)); + + + /* If neccessary, create a sub-surface */ + if (width > xres * 320 || height > yres * 200) { + IDirectFBSurface *subsurface; + DFBRectangle region; + region.w = xres * 320; + region.h = yres * 200; + region.x = (width - region.w) >> 1; + region.y = (height - region.h) >> 1; + + SCIDFB_CHECKED(scidfb_visual->GetSubSurface(scidfb_visual, ®ion, &subsurface)); + + scidfb_visual = subsurface; + } + + scidfb_visual->SetDrawingFlags(scidfb_visual, DSDRAW_BLEND); /* Unchecked: It's just a + ** feature */ + SCIDFB_CHECKED(scidfb_visual->GetPixelFormat(scidfb_visual, &pixel_format)); + + SCIGFX_CHECKED(_scidfb_decode_pixel_format(pixel_format, + &red_mask, &green_mask, &blue_mask, &alpha_mask, + &red_shift, &green_shift, &blue_shift, &alpha_shift, + &bytespp_real)); + + fprintf(stderr, "Mode %08x -> (%x>>%d, %x>>%d, %x>>%d, %x>>%d) at %d bytespp\n", + pixel_format, + red_mask, red_shift, + green_mask, green_shift, + blue_mask, blue_shift, + alpha_mask, alpha_shift, + bytespp_real); + + drv->mode = gfx_new_mode(xres, yres, + bytespp_real, + red_mask, green_mask, blue_mask, alpha_mask, + red_shift, green_shift, blue_shift, alpha_shift, + 0 /* not palette mode*/, + 0); + + SCIGFX_CHECKED(scidfb_build_virtual_surface(&scidfb_static_visual, + drv->mode->xfact * 320, + drv->mode->yfact * 200, + scidfb_visual)); + + scidfb_back_priority = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(drv->mode->xfact * 320, + drv->mode->yfact * 200, + GFX_RESID_NONE, 0, 0)); + + return GFX_OK; +} + +static int +_scidfb_set_color(gfx_color_t *c) +{ + SCIDFB_CHECKED(scidfb_visual->SetColor(scidfb_visual, + c->visual.r, c->visual.g, c->visual.b, + (c->mask & GFX_MASK_VISUAL)? (255 - c->alpha) : 0)); + return GFX_OK; +} + +static int +scidfb_init(gfx_driver_t *drv) +{ + return scidfb_init_specific(drv, 2, 2, 1); +} + + +static void +scidfb_exit(gfx_driver_t *drv) +{ + gfx_free_pixmap(drv, scidfb_back_priority); +} + +static int +scidfb_draw_line(gfx_driver_t *drv, point_t start, point_t end, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + int xc, yc; + + SCIGFX_CHECKED(_scidfb_set_color(&color)); + + if (line_mode == GFX_LINE_MODE_FINE) { + SCIDFB_CHECKED(scidfb_visual->DrawLine(scidfb_visual, + start.x, start.y, + end.x, end.y)); + } else /* "Correct" lines */ + for (xc = 0; xc < drv->mode->xfact; xc++) + for (yc = 0; yc < drv->mode->yfact; yc++) + SCIDFB_CHECKED(scidfb_visual->DrawLine(scidfb_visual, + start.x + xc, + start.y + yc, + end.x + xc, + end.y + yc)); + + return GFX_OK; +} + +static int +scidfb_draw_filled_rect(gfx_driver_t *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + SCIGFX_CHECKED(_scidfb_set_color(&color1)); + SCIDFB_CHECKED(scidfb_visual->FillRectangle(scidfb_visual, + rect.x, rect.y, + rect.xl, rect.yl)); + + return GFX_OK; +} + +static int +scidfb_register_pixmap(gfx_driver_t *drv, gfx_pixmap_t *pxm) +{ + return GFX_OK; +} + + +static int +scidfb_unregister_pixmap(gfx_driver_t *drv, gfx_pixmap_t *pxm) +{ + return GFX_OK; +} + + +static int +scidfb_draw_pixmap(gfx_driver_t *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + void *_dest_data; + byte *dest_data; + int line_width; + IDirectFBSurface *visual = (buffer == GFX_BUFFER_STATIC)? + scidfb_static_visual : scidfb_visual; + gfx_pixmap_t *priority_map = (buffer == GFX_BUFFER_STATIC)? + scidfb_static_priority : scidfb_back_priority; + + SCIDFB_CHECKED(visual->Lock(visual, DSLF_WRITE | DSLF_READ, + &_dest_data, &line_width)); + dest_data = (byte *) _dest_data; + + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, dest_data, + line_width, + priority_map->index_data, priority_map->index_xl, + 1, 0); + + SCIDFB_CHECKED(visual->Unlock(visual)); +} + +static int +scidfb_grab_pixmap(gfx_driver_t *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + void *_src_data; + byte *src_data; + byte *dest = pxm->data; + int line_width; + int write_width = drv->mode->bytespp * (src.xl); + + pxm->xl = src.xl; + pxm->yl = src.yl; + + if (map != GFX_MASK_VISUAL) { + fprintf(stderr, "Not trying to read from visual mask-- not supported!"); + return GFX_FATAL; + } + + SCIDFB_CHECKED(scidfb_visual->Lock(scidfb_visual, DSLF_READ | DSLF_WRITE, + /* Must use DSLF_WRITE to choose the back buffer, + ** otherwise the front buffer would be chosen */ + &_src_data, &line_width)); + src_data = (byte *) _src_data; + + src_data += (drv->mode->bytespp * src.x) + + (line_width * src.y); /* left upper corner of the source */ + + if (src.y < 0){ + fprintf(stderr, "src.y=%d\n", src.y); + exit(1); + } + + while (src.yl--) { + memcpy(dest, src_data, write_width); + src_data += line_width; + dest += write_width; + } + + + SCIDFB_CHECKED(scidfb_visual->Unlock(scidfb_visual)); +} + +static int +scidfb_update(gfx_driver_t *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + if (src.x != dest.x + || src.y != dest.y) { + GFXERROR("DFB-GFX: Attempt to update from (%d,%d,%d,%d) to (%d,%d)\n", + GFX_PRINT_RECT(src), dest.x, dest.y); + } + + if (buffer == GFX_BUFFER_FRONT) { + DFBRegion region; + region.x1 = src.x; + region.y1 = src.y; + region.x2 = src.x + src.xl; + region.y2 = src.y + src.yl; + + SCIDFB_CHECKED(scidfb_visual->Flip(scidfb_visual, ®ion, DSFLIP_BLIT)); + } else { /* Back buffer update */ + DFBRectangle dest_rect; + dest_rect.x = src.x; + dest_rect.y = src.y; + dest_rect.w = src.xl; + dest_rect.h = src.yl; + + SCIDFB_CHECKED(scidfb_visual->Blit(scidfb_visual, + scidfb_static_visual, + &dest_rect, + dest.x, dest.y)); + + /* Now update the priority map: */ + if (scidfb_static_priority) /* only if the buffers have been initialized */ + gfx_copy_pixmap_box_i(scidfb_back_priority, scidfb_static_priority, src); + } + + return GFX_OK; +} + +static int +scidfb_set_static_buffer(gfx_driver_t *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + void *_dest; + byte *dest; + byte *src = pic->data; + int line_width; + int draw_width = pic->xl * drv->mode->bytespp; + int i; + + scidfb_static_priority = priority; + SCIDFB_CHECKED(scidfb_static_visual->Lock(scidfb_static_visual, DSLF_WRITE, + &_dest, &line_width)); + dest = (byte *) _dest; + + for (i = 0; i < pic->yl; i++) { + memcpy(dest, src, draw_width); + dest += line_width; + src += draw_width; + } + + SCIDFB_CHECKED(scidfb_static_visual->Unlock(scidfb_static_visual)); + + return GFX_OK; +} + +static void +_normalize_pointer(gfx_driver_t *drv) +{ + int maxw = drv->mode->xfact * 320; + int maxh = drv->mode->yfact * 200; + + if (drv->pointer_x < 0) + drv->pointer_x = 0; + if (drv->pointer_x >= maxw) + drv->pointer_x = maxw - 1; + if (drv->pointer_y < 0) + drv->pointer_y = 0; + if (drv->pointer_y >= maxh) + drv->pointer_y = maxh - 1; +} + + +static sci_event_t +scidfb_get_event(gfx_driver_t *drv) +{ + sci_event_t retval; + + scidfb_queue_next_event(drv, 0); + _scidfb_read_event(&retval); + + _normalize_pointer(drv); + + + return retval; +} + +static int +scidfb_usec_sleep(gfx_driver_t *drv, long usecs) +{ + scidfb_queue_next_event(drv, usecs); + _normalize_pointer(drv); + return GFX_OK; +} + +gfx_driver_t gfx_driver_dfb = { + "dfb", + SCIDFB_DRIVER_VERSION, + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, 0, + GFX_CAPABILITY_MOUSE_SUPPORT + | GFX_CAPABILITY_FINE_LINES, + 0, + scidfb_set_parameter, + scidfb_init_specific, + scidfb_init, + scidfb_exit, + scidfb_draw_line, + scidfb_draw_filled_rect, + scidfb_register_pixmap, + scidfb_unregister_pixmap, + scidfb_draw_pixmap, + scidfb_grab_pixmap, + scidfb_update, + scidfb_set_static_buffer, + NULL, + NULL, + scidfb_get_event, + scidfb_usec_sleep, + NULL +}; + +#endif diff --git a/engines/sci/gfx/drivers/dx_driver.cpp b/engines/sci/gfx/drivers/dx_driver.cpp new file mode 100644 index 0000000000..899d1fa70c --- /dev/null +++ b/engines/sci/gfx/drivers/dx_driver.cpp @@ -0,0 +1,1179 @@ +/*************************************************************************** + dx_driver.cpp Copyright (C) 2008 Alexander R Angas, + Some portions Copyright (C) 1999 Dmitry Jemerov + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Alexander R Angas (Alex) <arangas AT internode dot on dot net> + + History: + 20051106 (AAngas) - Rewrite + 20060201 (AAngas) - Fixed wrong format for texture priority maps + 20060205 (AAngas) - Changed pointer to use D3DXSprite + 20060208 (AAngas) - Fixed pointer alpha blending bug + 20060307 (AAngas) - Fixed crash on exit + 20080118 (AAngas) - Fixed pointer scaling and window size + + Notes: + DirectX handles all scaling. All drawing functions assume an unscaled + resolution. + +TODO: + P1 - Corrupt cursor at different resolutions + P1 - Lost devices + P1 - Problems moving and activating window + P1 - Occasional pause when starting FreeSCI and poor sound resulting (?) + P1 - Mouse pointer corruption at bottom and why need to scale vertical by 4? + P2 - Full screen + P3 - Draw lines as Direct3D vertices + P3 - Fine line mode + P3 - Allow user to specify hardware or software vertex processing + P3 - Fancies + +***************************************************************************/ + +#ifdef HAVE_DIRECTX + +#ifndef __cplusplus +#error NOTE: This file MUST be compiled as C++. In Visual C++, use the /Tp command line option. +#endif + +#include "dx_driver.h" + +#define TO_STRING2(x) #x +#define TO_STRING(x) TO_STRING2(x) +#if (DIRECT3D_VERSION < 0x0800) +# error The DirectX 8 SDK (or higher) is required for this driver. +#elif (DIRECT3D_VERSION > 0x0800) +# pragma message (" ") +# pragma message ("*** This driver has been developed against version 8 of the DirectX SDK and may not work against your version " TO_STRING(DIRECT3D_VERSION)) +# pragma message (" ") +#endif + + +// Stores driver flags +static int flags = 0; + + +// Windows message processing +LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + return DefWindowProc( hWnd, msg, wParam, lParam ); +} + + +///// RENDERING + +// Render the scene to screen +static gfx_return_value_t +RenderD3D(struct _gfx_driver *drv) +{ + HRESULT hr; + + // Check we haven't lost the device (i.e. window focus) + if (CheckDevice(drv)) + { + // Begin scene + DODX( (dx_state->pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0, 0)), RenderD3D ); + DODX( (dx_state->pDevice->BeginScene()), RenderD3D ); + + // Set texture + DODX( (dx_state->pDevice->SetTexture( 0, dx_state->pTexVisuals[PRIMARY_VIS] )), RenderD3D ); // Scene image + + // Set texture states for scene + DODX( (dx_state->pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE )), RenderD3D ); + DODX( (dx_state->pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE )), RenderD3D ); + DODX( (dx_state->pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE )), RenderD3D ); + + // Set vertices and how to draw + DODX( (dx_state->pDevice->SetStreamSource(0, dx_state->pVertBuff, sizeof(CUSTOMVERTEX))), RenderD3D ); + DODX( (dx_state->pDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX )), RenderD3D ); + DODX( (dx_state->pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2)), RenderD3D ); + + // Draw the pointer sprite + if (dx_state->pTexPointer) + { + D3DXVECTOR2 pointerPos((float)drv->pointer_x, (float)drv->pointer_y); + DODX( (dx_state->pSPointer->Begin()), RenderD3D ); + DODX( (dx_state->pSPointer->Draw(dx_state->pTexPointer, NULL, NULL, NULL, 0.0, &pointerPos, 0xFFFFFFFF)), RenderD3D ); + DODX( (dx_state->pSPointer->End()), RenderD3D ); + } + + // Present scene + DODX( (dx_state->pDevice->EndScene()), RenderD3D ); + DODX( (dx_state->pDevice->Present(NULL, NULL, NULL, NULL)), RenderD3D ); + } + + return GFX_OK; +} + + +// Check device hasn't been lost +static int +CheckDevice(struct _gfx_driver *drv) +{ + HRESULT hr; + switch ( dx_state->pDevice->TestCooperativeLevel() ) + { + case D3DERR_DEVICELOST: return false; // Lost window focus + + case D3DERR_DEVICENOTRESET: // We're back! + { + // Reset with our presentation parameters and reinitialise the scene + DODX( (dx_state->pDevice->Reset(&dx_state->presParams)), CheckDevice ); + if (hr != D3D_OK) + return false; + + InitScene(drv); + return true; + } + + default: return true; + } +} + + +///// INITIALIZATION + +// Create window to draw to +static gfx_return_value_t +InitWindow(struct _gfx_driver *drv, UINT width, UINT height) +{ + DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dwStyle = WS_OVERLAPPEDWINDOW; + RECT clientSize = { 0, 0, width, height }; + sciprintf("Window %d x %d\n", width, height); + + // Register the window class + ZeroMemory( &(dx_state->wc), sizeof(WNDCLASSEX) ); + dx_state->wc.cbSize = sizeof(WNDCLASSEX); + dx_state->wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; + dx_state->wc.lpfnWndProc = MsgProc; + dx_state->wc.hInstance = GetModuleHandle(NULL); + dx_state->wc.lpszClassName = DX_CLASS_NAME; + if ( RegisterClassEx( &dx_state->wc ) == 0 ) + { + sciprintf("InitWindow(): RegisterClassEx failed (%u)\n", GetLastError()); + return GFX_FATAL; + } + + // Get correct size of window to pass to CreateWindow (considering window decorations) + if ( AdjustWindowRectEx( &clientSize, dwStyle, false, dwExStyle ) == 0 ) + { + sciprintf("InitWindow(): Window size calculation failed (%u)\n", GetLastError()); + return GFX_FATAL; + } + + // Create the application's window + dx_state->hWnd = CreateWindowEx( + dwExStyle, + DX_CLASS_NAME, DX_APP_NAME, + dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, + clientSize.right - clientSize.left, clientSize.bottom - clientSize.top, + NULL/*GetDesktopWindow()*/, NULL, dx_state->wc.hInstance, NULL ); + + if ( dx_state->hWnd == NULL ) + { + sciprintf("InitWindow(): CreateWindow failed (%u)\n", GetLastError()); + return GFX_FATAL; + } + + // Show the window + ShowWindow( dx_state->hWnd, SW_SHOWDEFAULT ); + UpdateWindow( dx_state->hWnd ); + + return GFX_OK; +} + + +// Initialize Direct3D +static gfx_return_value_t +InitD3D(struct _gfx_driver *drv) +{ + HRESULT hr; + + sciprintf("Initializing Direct3D\n"); + + // Set our colour format + dx_state->d3dFormat = D3DFMT_A8R8G8B8; + dx_state->vertexProcessing = D3DCREATE_MIXED_VERTEXPROCESSING; + + // Create Direct3D object + dx_state->pD3d = Direct3DCreate8( D3D_SDK_VERSION ); + if ( FAILED( dx_state->pD3d ) ) { + sciprintf("InitD3D(): Direct3DCreate8 failed\n"); + return GFX_FATAL; + } + + // Look for adapters + for ( UINT adapterLoop = 0; adapterLoop < dx_state->pD3d->GetAdapterCount(); adapterLoop++ ) + { + D3DADAPTER_IDENTIFIER8 adapterId; + DODX( (dx_state->pD3d->GetAdapterIdentifier(adapterLoop, D3DENUM_NO_WHQL_LEVEL, &adapterId)), InitD3D ); + if ( FAILED( hr ) ) + break; + if (adapterId.Driver[0] == '\0') + break; + sciprintf(" Adapter %u: %s\n", adapterLoop++, adapterId.Description); + } + if (dx_state->adapterId == -1) + dx_state->adapterId = D3DADAPTER_DEFAULT; + + // Get device caps + DODX( (dx_state->pD3d->GetDeviceCaps(dx_state->adapterId, D3DDEVTYPE_HAL, &(dx_state->deviceCaps))), InitD3D ); + if ( FAILED( hr ) ) { + sciprintf("Sorry, this adapter does not have a 3D accelerated video driver installed.\n"); + return GFX_FATAL; + } + + // Define presentation parameters + ZeroMemory( &dx_state->presParams, sizeof(D3DPRESENT_PARAMETERS) ); + dx_state->presParams.Windowed = TRUE; // We want windowed by default + dx_state->presParams.SwapEffect = D3DSWAPEFFECT_DISCARD; // Throw away last frame + dx_state->presParams.hDeviceWindow = dx_state->hWnd; // Window handle + dx_state->presParams.BackBufferWidth = 320; // Back buffer dimensions + dx_state->presParams.BackBufferHeight = 200; // + dx_state->presParams.BackBufferFormat = dx_state->d3dFormat; // Colour format + + // Check if user requested full screen + if (flags & DX_FLAGS_FULLSCREEN) + { + if (dx_state->deviceCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) { + dx_state->presParams.Windowed = FALSE; + sciprintf("Full screen mode"); + } else { + sciprintf("Sorry, DirectX will not render in full screen with your video card\n"); + } + } + + // Get current display mode + DODX( (dx_state->pD3d->GetAdapterDisplayMode( dx_state->adapterId, &dx_state->displayMode )), InitD3D ); + sciprintf("Chosen adapter %u\n", dx_state->adapterId); + + // Turn off Windows mouse pointer + ShowCursor(FALSE); + + return GFX_OK; +} + + +// Initialize scene +static gfx_return_value_t +InitScene(struct _gfx_driver *drv) +{ + HRESULT hr; + + sciprintf("Creating scene\n"); + + // Describe how scene will be rendered + DODX((dx_state->pDevice->SetRenderState( D3DRS_AMBIENT, RGB(255,255,255) )), InitScene); // Maximum ambient light + DODX((dx_state->pDevice->SetRenderState( D3DRS_LIGHTING, FALSE )), InitScene); // Disable lighting features + DODX((dx_state->pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE )), InitScene); // Don't cull back side of polygons + DODX((dx_state->pDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE )), InitScene); // No depth buffering + + return GFX_OK; +} + + +// For user to set a driver-specific parameter +static int +dx_set_param(struct _gfx_driver *drv, char *attribute, char *value) +{ +/* // Full screen + if (!strncmp(attribute, "fullscreen", 11)) { + if (string_truep(value)) + flags |= DX_FLAGS_FULLSCREEN; + else + flags &= ~DX_FLAGS_FULLSCREEN; + + return GFX_OK; + } +*/ + // Adapter ID + if (!strncmp(attribute, "adapterid", 11)) { + int aid = D3DADAPTER_DEFAULT; + dx_state->adapterId = atoi(value); + + return GFX_OK; + } + + sciprintf("Unrecognised attempt to set DirectX parameter \"%s\" to \"%s\"\n", attribute, value); + return GFX_ERROR; +} + + +// Initialize a specific graphics mode +static int +dx_init_specific(struct _gfx_driver *drv, + int xfact, int yfact, /* horizontal and vertical scaling */ + int bytespp) /* must be value 4 */ +{ + HRESULT hr; + int red_shift = 8, green_shift = 16, blue_shift = 24, alpha_shift = 32; + int alpha_mask = 0x00000000, red_mask = 0x00ff0000, green_mask = 0x0000ff00, blue_mask = 0x000000ff; + gfx_return_value_t d3dret; + + // Error checking + if (xfact < 1 || yfact < 1 || bytespp < 1 || bytespp > 4) { + sciprintf("Attempt to open window with invalid scale factors (%d,%d) and bpp=%d!\n", + xfact, yfact, bytespp); + return GFX_ERROR; + } + + // Prepare memory for gfx_dx_struct_t + drv->state = (struct gfx_dx_struct_t *) sci_malloc(sizeof(gfx_dx_struct_t)); + ZeroMemory(drv->state, sizeof(gfx_dx_struct_t)); + dx_state->adapterId = -1; // we will set this later + + // Set window size factor + dx_state->xfact = xfact; + dx_state->yfact = yfact; + dx_state->bpp = bytespp; + sciprintf("Window scaling %d x %d @ %d bpp\n", dx_state->xfact, dx_state->yfact, dx_state->bpp << 3); + + // Set up Direct3D + d3dret = InitD3D(drv); + if (d3dret != GFX_OK) + return d3dret; + + // Create window + InitWindow(drv, dx_state->xfact * 320, dx_state->yfact * 200); + + // Create D3D device + DODX( (dx_state->pD3d->CreateDevice(dx_state->adapterId, D3DDEVTYPE_HAL, dx_state->hWnd, + dx_state->vertexProcessing, &dx_state->presParams, &dx_state->pDevice)), dx_init_specific ); + + // Create the scene + d3dret = InitScene(drv); + if (d3dret != GFX_OK) + return d3dret; + + // Define and populate vertex buffers + DODX((dx_state->pDevice->CreateVertexBuffer( 4 * sizeof(CUSTOMVERTEX), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, + D3DPOOL_MANAGED, &dx_state->pVertBuff )), dx_init_specific); + + dx_state->pvData[0].p = D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f); + dx_state->pvData[1].p = D3DXVECTOR4(320.0f, 0.0f, 0.0f, 1.0f); + dx_state->pvData[2].p = D3DXVECTOR4( 0.0f, 200.0f, 0.0f, 1.0f); + dx_state->pvData[3].p = D3DXVECTOR4(320.0f, 200.0f, 0.0f, 1.0f); + dx_state->pvData[0].colour = dx_state->pvData[1].colour = dx_state->pvData[2].colour = dx_state->pvData[3].colour = 0xffffffff; + dx_state->pvData[0].t = D3DXVECTOR2(0.0f, 0.0f); + dx_state->pvData[1].t = D3DXVECTOR2(1.0f, 0.0f); + dx_state->pvData[2].t = D3DXVECTOR2(0.0f, 1.0f); + dx_state->pvData[3].t = D3DXVECTOR2(1.0f, 1.0f); + + VOID *ptr; + DODX((dx_state->pVertBuff->Lock(0, 0, (BYTE**)&ptr, 0)), dx_init_specific); + memcpy(ptr, dx_state->pvData, sizeof(dx_state->pvData)); + DODX((dx_state->pVertBuff->Unlock()), dx_init_specific); + + // Create textures + int i; + for (i = 0; i < NUM_VISUAL_BUFFERS; i++) + { + DODX((dx_state->pDevice->CreateTexture(320, 200, + 1, 0, + dx_state->d3dFormat, + D3DPOOL_MANAGED, + &dx_state->pTexVisuals[i])), dx_init_specific); + } + for (i = 0; i < NUM_PRIORITY_BUFFERS; i++) + { + DODX((dx_state->pDevice->CreateTexture(320, 200, + 1, 0, + dx_state->d3dFormat, + D3DPOOL_MANAGED, + &dx_state->pTexPrioritys[i])), dx_init_specific); + } + + // Create sprite for pointer + DODX( (D3DXCreateSprite(dx_state->pDevice, &dx_state->pSPointer)), dx_init_specific ); + + // Allocate priority maps + for (int i = 0; i < NUM_PRIORITY_BUFFERS; i++) + { + dx_state->priority_maps[i] = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, GFX_RESID_NONE, -i, -777)); + if (!dx_state->priority_maps[i]) { + GFXERROR("Out of memory: Could not allocate priority maps! (%dx%d)\n", 320, 200); + return GFX_FATAL; + } + dx_state->priority_maps[i]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + } + + // Set up the event queue + dx_state->queue_first = 0; + dx_state->queue_last = 0; + dx_state->queue_size = 256; + dx_state->event_queue = (sci_event_t *) sci_malloc (dx_state->queue_size * sizeof (sci_event_t)); + + // Set up graphics mode for primary vis + drv->mode = gfx_new_mode(1, 1, dx_state->bpp, + red_mask, green_mask, blue_mask, alpha_mask, + red_shift, green_shift, blue_shift, alpha_shift, + (dx_state->bpp == 1) ? 256 : 0, 0); + + // Set up graphics mode for pointer + dx_state->pointerMode = gfx_new_mode(1, 4, dx_state->bpp, + 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, + 24, 16, 8, 0, + 0, GFX_MODE_FLAG_REVERSE_ALPHA); + + return GFX_OK; +} + + +// Initialize 'most natural' graphics mode +static int +dx_init(struct _gfx_driver *drv) +{ + return dx_init_specific(drv, 2, 2, 4); +} + + +// Uninitialize the current graphics mode +static void +dx_exit(struct _gfx_driver *drv) +{ + int i; + + if(drv->state == NULL) + return; + + for (i = 0; i < NUM_PRIORITY_BUFFERS; i++) + SAFE_RELEASE( dx_state->pTexPrioritys[i] ); + for (i = 0; i < NUM_VISUAL_BUFFERS; i++) + SAFE_RELEASE( dx_state->pTexVisuals[i] ); + SAFE_RELEASE( dx_state->pTexPointer ); + SAFE_RELEASE( dx_state->pSPointer ); + SAFE_RELEASE( dx_state->pVertBuff ); + SAFE_RELEASE( dx_state->pDevice ); + SAFE_RELEASE( dx_state->pD3d ); + + if ( dx_state->pointerMode ) + gfx_free_mode(dx_state->pointerMode); + if ( drv->mode ) + gfx_free_mode(drv->mode); + + if ( dx_state->event_queue ) + sci_free(dx_state->event_queue); + dx_state->queue_size = 0; + + for (i = 0; i < NUM_PRIORITY_BUFFERS; i++) + gfx_free_pixmap(drv, dx_state->priority_maps[i]); + + UnregisterClass( DX_CLASS_NAME, dx_state->wc.hInstance ); + DestroyWindow(dx_state->hWnd); + + sci_free(dx_state); +} + + +///// DRAWING + +// Draws a single filled and possibly shaded rectangle to the back buffer +static int +dx_draw_filled_rect(struct _gfx_driver *drv, rect_t box, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (color1.mask & GFX_MASK_VISUAL) + { + HRESULT hr; + D3DLOCKED_RECT lockedRect; + + // Calculate colour value for line pixel + UINT lineColor = (color1.alpha << 24) | (color1.visual.r << 16) | (color1.visual.g << 8) | color1.visual.b; + RECT r = { box.x, box.y, box.x + box.xl, box.y + box.yl }; + RECT lr = r; + + // Fix bounds + if (lr.left == lr.right) + lr.right++; + if (lr.top == lr.bottom) + lr.bottom++; + if ((UINT)r.right > 320) + lr.right = r.right = 320; + if ((UINT)r.bottom > 200) + lr.bottom = r.bottom = 200; + + sciprintf("dx_draw_filled_rect(): %08X %i,%i -> %i,%i\n", lineColor, r.left, r.top, r.right, r.bottom); + + DODX( (dx_state->pTexVisuals[BACK_VIS]->LockRect(0, &lockedRect, &lr, 0)), dx_draw_filled_rect ); + UINT *rectPtr = (UINT*)lockedRect.pBits; + + // Going along x axis + for (int y_pixel = r.top; y_pixel < r.bottom; y_pixel++) + { + UINT *startLine = rectPtr; + for (int x_pixel = r.left; x_pixel < r.right; x_pixel++) + { + *rectPtr = lineColor; + rectPtr++; + } + rectPtr = startLine; + rectPtr += 320; + } + + DODX( (dx_state->pTexVisuals[BACK_VIS]->UnlockRect(0)), dx_draw_filled_rect ); + } + + if (color1.mask & GFX_MASK_PRIORITY) + { + byte *pri; + pri = dx_state->priority_maps[BACK_PRI]->index_data + box.x + box.y*(320); + for(int i=0; i<box.yl; i++) + { + memset(pri,color1.priority,box.xl); + pri += 320; + } + } + + return GFX_OK; +} + + +// Draws a single line to the back buffer +static int +dx_draw_line(struct _gfx_driver *drv, + point_t start, point_t end, + gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + if (color.mask & GFX_MASK_VISUAL) { + + rect_t line_rect = { start.x, start.y, end.x - start.x + 1, end.y - start.y + 1 }; + + sciprintf("dx_draw_line(): %i,%i -> %i,%i\n", line_rect.x, line_rect.y, line_rect.xl + line_rect.x, line_rect.yl + line_rect.y); + + // Make sure priorities are not updated in dx_draw_filled_rect() + gfx_color_t col = color; + col.mask = GFX_MASK_VISUAL; + + dx_draw_filled_rect(drv, line_rect, col, col, GFX_SHADE_FLAT); + } + + if (color.mask & GFX_MASK_PRIORITY) { + gfx_draw_line_pixmap_i(dx_state->priority_maps[BACK_PRI], start, end, color.priority); + } + + return GFX_OK; +} + + +///// PIXMAPS + +// Register the pixmap as a texture +static int +dx_register_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + HRESULT hr; + + int i, xs; + byte *s, *d; + D3DLOCKED_RECT lockedRect; + LPDIRECT3DTEXTURE8 newTex; + DODX( (dx_state->pDevice->CreateTexture(pxm->xl, pxm->yl, 1, 0, dx_state->d3dFormat, D3DPOOL_MANAGED, &newTex )), dx_register_pixmap ); + + // Do gfx crossblit + DODX( (newTex->LockRect(0, &lockedRect, NULL, 0)), dx_register_pixmap ); + s = pxm->data; + d = (byte *) lockedRect.pBits; + xs = drv->mode->bytespp * pxm->xl; + + for(i = 0; i < pxm->yl; i++) + { + memcpy(d, s, xs); + s += xs; + d += lockedRect.Pitch; + } + DODX( (newTex->UnlockRect(0)), dx_register_pixmap ); + + pxm->internal.info = newTex; + pxm->internal.handle = SCI_DX_HANDLE_NORMAL; + + return GFX_OK; +} + + +// Unregister the pixmap +static int +dx_unregister_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + SAFE_RELEASE((LPDIRECT3DTEXTURE8) (pxm->internal.info)); + pxm->internal.info = NULL; + + return GFX_OK; +} + + +// Draws part of a pixmap to the static or back buffer +static int +dx_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + HRESULT hr; + int bufnr = (buffer == GFX_BUFFER_STATIC) ? 2 : 1; + int pribufnr = bufnr - 1; + LPDIRECT3DTEXTURE8 srct, dstt; + LPDIRECT3DSURFACE8 sbuf, dbuf; + D3DLOCKED_RECT lockedRect; + byte *pri_map = NULL; + + if (pxm->internal.handle == SCI_DX_HANDLE_GRABBED) { + // copy from pxm->internal.info to visual[bufnr] + RECT srcRect = RECT_T_TO_RECT(src); + POINT dstPoint = { dest.x, dest.y }; + + srct = (LPDIRECT3DTEXTURE8) (pxm->internal.info); + dstt = dx_state->pTexVisuals[bufnr]; + + DODX( (srct->GetSurfaceLevel(0, &sbuf)), dx_draw_pixmap ); + DODX( (dstt->GetSurfaceLevel(0, &dbuf)), dx_draw_pixmap ); + DODX( (dx_state->pDevice->CopyRects(sbuf, &srcRect, 1, dbuf, &dstPoint)), dx_draw_pixmap ); + + SAFE_RELEASE(sbuf); + SAFE_RELEASE(dbuf); + + return GFX_OK; + } + + + // Create texture to temporarily hold visuals[bufnr] + LPDIRECT3DTEXTURE8 temp; + DODX( (dx_state->pDevice->CreateTexture(pxm->xl, pxm->yl, 1, 0, dx_state->d3dFormat, D3DPOOL_MANAGED, &temp)), dx_draw_pixmap ); + RECT srcRect = RECT_T_TO_RECT(dest); + RECT destRect = { 0, 0, dest.xl, dest.yl }; + POINT dstPoint = { destRect.left, destRect.top }; + + // Copy from visuals[bufnr] to temp + srct = dx_state->pTexVisuals[bufnr]; + dstt = temp; + DODX( (srct->GetSurfaceLevel(0, &sbuf)), dx_draw_pixmap ); + DODX( (dstt->GetSurfaceLevel(0, &dbuf)), dx_draw_pixmap ); + DODX( (dx_state->pDevice->CopyRects(sbuf, &srcRect, 1, dbuf, &dstPoint)), dx_draw_pixmap ); + + // Copy from given pixmap to temp + DODX( (dbuf->LockRect(&lockedRect, &destRect, 0)), dx_draw_pixmap ); + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, + (byte *) lockedRect.pBits, lockedRect.Pitch, + dx_state->priority_maps[pribufnr]->index_data, + dx_state->priority_maps[pribufnr]->index_xl, 1, + GFX_CROSSBLIT_FLAG_DATA_IS_HOMED); + DODX( (dbuf->UnlockRect()), dx_draw_pixmap ); + + SAFE_RELEASE(sbuf); + SAFE_RELEASE(dbuf); + + + // Copy from temp to visuals[bufnr] + RECT src2Rect = { 0, 0, dest.xl, dest.yl }; + POINT dst2Point = { dest.x, dest.y }; + + srct = temp; + dstt = dx_state->pTexVisuals[bufnr]; + DODX( (srct->GetSurfaceLevel(0, &sbuf)), dx_draw_pixmap ); + DODX( (dstt->GetSurfaceLevel(0, &dbuf)), dx_draw_pixmap ); + DODX( (dx_state->pDevice->CopyRects(sbuf, &src2Rect, 1, dbuf, &dst2Point)), dx_draw_pixmap ); + + SAFE_RELEASE(sbuf); + SAFE_RELEASE(dbuf); + SAFE_RELEASE(temp); + + return GFX_OK; +} + + +// Grabs an image from the visual or priority back buffer +static int +dx_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + HRESULT hr; + + if (src.x < 0 || src.y < 0) { + GFXERROR("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) { + GFXERROR("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + + // Choose map to grab from + switch (map) { + + case GFX_MASK_VISUAL: { + LPDIRECT3DTEXTURE8 temp; + LPDIRECT3DSURFACE8 tempSrf, backSrf; + CONST RECT srcRect = RECT_T_TO_RECT(src); + CONST POINT dstPoint = { 0, 0 }; + + pxm->xl = src.xl; + pxm->yl = src.yl; + + DODX( (dx_state->pDevice->CreateTexture(pxm->xl, pxm->yl, 1, 0, dx_state->d3dFormat, D3DPOOL_MANAGED, &temp)), dx_grab_pixmap ); + + DODX( (dx_state->pTexVisuals[BACK_VIS]->GetSurfaceLevel(0, &backSrf)), dx_grab_pixmap ); + DODX( (temp->GetSurfaceLevel(0, &tempSrf)), dx_grab_pixmap ); + DODX( (dx_state->pDevice->CopyRects(backSrf, &srcRect, 1, tempSrf, &dstPoint)), dx_grab_pixmap ); + + pxm->internal.info = temp; + pxm->internal.handle = SCI_DX_HANDLE_GRABBED; + pxm->flags |= GFX_PIXMAP_FLAG_INSTALLED | GFX_PIXMAP_FLAG_EXTERNAL_PALETTE | GFX_PIXMAP_FLAG_PALETTE_SET; + + SAFE_RELEASE(backSrf); + SAFE_RELEASE(tempSrf); + + break; + } + + case GFX_MASK_PRIORITY: + sciprintf("FIXME: priority map grab not implemented yet!\n"); + break; + + default: + sciprintf("Attempt to grab pixmap from invalid map 0x%02x\n", map); + return GFX_ERROR; + } + + return GFX_OK; +} + + +///// BUFFERING + +// Updates the front buffer or the back buffers +static int +dx_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + HRESULT hr; + LPDIRECT3DTEXTURE8 srct, dstt; + LPDIRECT3DSURFACE8 sbuf, dbuf; + CONST RECT srcRect = RECT_T_TO_RECT(src); + CONST POINT dstPoint = { dest.x, dest.y }; + + switch (buffer) { + + case GFX_BUFFER_FRONT: + srct = dx_state->pTexVisuals[BACK_VIS]; + dstt = dx_state->pTexVisuals[PRIMARY_VIS]; + + DODX( (srct->GetSurfaceLevel(0, &sbuf)), dx_update ); + DODX( (dstt->GetSurfaceLevel(0, &dbuf)), dx_update ); + + DODX( (dx_state->pDevice->CopyRects(sbuf, &srcRect, 1, dbuf, &dstPoint)), dx_update ); + + SAFE_RELEASE(sbuf); + SAFE_RELEASE(dbuf); + + RenderD3D(drv); + break; + + case GFX_BUFFER_BACK: + if (src.x == dest.x && src.y == dest.y) + gfx_copy_pixmap_box_i(dx_state->priority_maps[BACK_PRI], dx_state->priority_maps[STATIC_PRI], src); + + srct = dx_state->pTexVisuals[STATIC_VIS]; + dstt = dx_state->pTexVisuals[BACK_VIS]; + + DODX( (srct->GetSurfaceLevel(0, &sbuf)), dx_update ); + DODX( (dstt->GetSurfaceLevel(0, &dbuf)), dx_update ); + + DODX( (dx_state->pDevice->CopyRects(sbuf, &srcRect, 1, dbuf, &dstPoint)), dx_update ); + + SAFE_RELEASE(sbuf); + SAFE_RELEASE(dbuf); + + break; + + default: + GFXERROR("Invalid buffer %d in update!\n", buffer); + return GFX_ERROR; + } + + return GFX_OK; +} + + +// Sets the contents of the static visual and priority buffers +static int +dx_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, + gfx_pixmap_t *priority) +{ + if (!pic->internal.info) { + GFXERROR("Attempt to set static buffer with unregistered pixmap!\n"); + return GFX_ERROR; + } + + HRESULT hr; + LPDIRECT3DTEXTURE8 pii = (LPDIRECT3DTEXTURE8) (pic->internal.info); + LPDIRECT3DSURFACE8 pbf; + LPDIRECT3DTEXTURE8 vis = dx_state->pTexVisuals[STATIC_VIS]; + LPDIRECT3DSURFACE8 vbf; + + // Copy from pic to visual[static] + DODX( (pii->GetSurfaceLevel(0, &pbf)), dx_set_static_buffer ); + DODX( (vis->GetSurfaceLevel(0, &vbf)), dx_set_static_buffer ); + DODX( (dx_state->pDevice->CopyRects(pbf, NULL, 0, vbf, NULL)), dx_set_static_buffer ); + + SAFE_RELEASE(pbf); + SAFE_RELEASE(vbf); + + // Copy priority map + gfx_copy_pixmap_box_i(dx_state->priority_maps[STATIC_PRI], priority, gfx_rect(0, 0, 320, 200)); + + return GFX_OK; +} + + +///// MOUSE + +// Sets a new mouse pointer +static int +dx_set_pointer(struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + HRESULT hr; + + if (pointer->data == NULL) + return GFX_OK; + pointer->yl /= 2; // Scale the pointer to compensate for mode scale + + LPDIRECT3DTEXTURE8 pntTex; + LPDIRECT3DSURFACE8 pntSrf; + + // Get pointer dimensions and init + POINTS pDims = {pointer->xl, pointer->yl}; + dx_state->pointerDims = pDims; + RECT r = {0, 0, pointer->xl, pointer->yl}; + + // Recreate pointer data according to the graphics mode we need + gfx_pixmap_free_data(pointer); + gfx_xlate_pixmap(pointer, dx_state->pointerMode, GFX_XLATE_FILTER_NONE); + + // Create texture and fill with pointer data + DODX( (dx_state->pDevice->CreateTexture(pointer->xl, pointer->yl, 1, 0, dx_state->d3dFormat, D3DPOOL_MANAGED, &pntTex )), dx_set_pointer ); + DODX( (pntTex->GetSurfaceLevel(0, &pntSrf)), dx_set_pointer ); + + DODX( (D3DXLoadSurfaceFromMemory(pntSrf, NULL, &r, pointer->data, dx_state->d3dFormat, 256, NULL, &r, D3DX_FILTER_NONE, 0)), dx_set_pointer); + + SAFE_RELEASE(pntSrf); + + // Assign as current pointer texture + if (dx_state->pTexPointer) + SAFE_RELEASE(dx_state->pTexPointer); + dx_state->pTexPointer = pntTex; + + return GFX_OK; +} + + +// Display mouse pointer +static int +show_pointer(struct _gfx_driver *drv, LPARAM pos) +{ + POINTS mousePos; // mouse coordinates + + // Sort out coordinates + mousePos = MAKEPOINTS(pos); + + // Update pos + drv->pointer_x = mousePos.x; + drv->pointer_y = mousePos.y; + + RenderD3D(drv); + + return GFX_OK; +} + + +///// EVENTS + +// Get event from the queue +static sci_event_t +get_queue_event(gfx_dx_struct_t *ctx) +{ + if (ctx->queue_first == ctx->queue_size) + ctx->queue_first = 0; + + if (ctx->queue_first == ctx->queue_last) + { + sci_event_t noevent; + noevent.data = 0; + noevent.type = SCI_EVT_NONE; + noevent.buckybits = 0; + return noevent; + } + else + return ctx->event_queue [ctx->queue_first++]; +} + + +// Add event to the queue +static void add_queue_event(gfx_dx_struct_t *ctx, int type, int data, short buckybits) +{ + if ((ctx->queue_last+1) % ctx->queue_size == ctx->queue_first) + { + /* Reallocate queue */ + int i, event_count; + sci_event_t *new_queue; + + new_queue = (sci_event_t *) sci_malloc (ctx->queue_size * 2 * sizeof (sci_event_t)); + event_count = (ctx->queue_last - ctx->queue_first) % ctx->queue_size; + for (i=0; i<event_count; i++) + new_queue [i] = ctx->event_queue [(ctx->queue_first+i) % ctx->queue_size]; + free (ctx->event_queue); + ctx->event_queue = new_queue; + ctx->queue_size *= 2; + ctx->queue_first = 0; + ctx->queue_last = event_count; + } + + ctx->event_queue [ctx->queue_last].data = data; + ctx->event_queue [ctx->queue_last].type = type; + ctx->event_queue [ctx->queue_last++].buckybits = buckybits; + if (ctx->queue_last == ctx->queue_size) + ctx->queue_last=0; +} + + +// Add keystroke event to queue +static void add_key_event (gfx_dx_struct_t *ctx, int data) +{ + short buckybits = 0; + + if (GetAsyncKeyState (VK_RSHIFT)) + buckybits |= SCI_EVM_RSHIFT; + if (GetAsyncKeyState (VK_LSHIFT)) + buckybits |= SCI_EVM_LSHIFT; + if (GetAsyncKeyState (VK_CONTROL)) + buckybits |= SCI_EVM_CTRL; + if (GetAsyncKeyState (VK_MENU)) + buckybits |= SCI_EVM_ALT; + if (GetKeyState (VK_SCROLL) & 1) + buckybits |= SCI_EVM_SCRLOCK; + if (GetKeyState (VK_NUMLOCK) & 1) + buckybits |= SCI_EVM_NUMLOCK; + if (GetKeyState (VK_CAPITAL) & 1) + buckybits |= SCI_EVM_CAPSLOCK; + + add_queue_event (ctx, SCI_EVT_KEYBOARD, data, buckybits); +} + + +// Add mouse event to queue +static void add_mouse_event(gfx_dx_struct_t *ctx, int type, int data, WPARAM wParam) +{ + short buckybits = 0; + if (wParam & MK_SHIFT) + buckybits |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + if (wParam & MK_CONTROL) + buckybits |= SCI_EVM_CTRL; + + add_queue_event (ctx, type, data, buckybits); +} + + +// Returns the next event in the event queue for this driver +static sci_event_t +dx_get_event(struct _gfx_driver *drv) +{ + assert(drv->state != NULL); + return get_queue_event(dx_state); +} + + +// Sleeps the specified amount of microseconds, or until the mouse moves +static int +dx_usleep(struct _gfx_driver *drv, long usecs) +{ + if (usecs < 1000) + { + sleep(0); + } + else + { + sleep(usecs/1000); + } + ProcessMessages(drv); + + return GFX_OK; +} + + +// Process any Windows messages +static int +ProcessMessages(struct _gfx_driver *drv) +{ + MSG msg; + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + switch( msg.message ) + { + case WM_PAINT: + ValidateRect( dx_state->hWnd, NULL ); + RenderD3D(drv); + break; + + case WM_KEYDOWN: + switch (msg.wParam) + { + MAP_KEY (VK_ESCAPE, SCI_K_ESC); + MAP_KEY (VK_BACK, SCI_K_BACKSPACE); + MAP_KEY (VK_RETURN, SCI_K_ENTER); + MAP_KEY (VK_TAB, SCI_K_TAB); + MAP_KEY (VK_END, SCI_K_END); + MAP_KEY (VK_DOWN, SCI_K_DOWN); + MAP_KEY (VK_NEXT, SCI_K_PGDOWN); + MAP_KEY (VK_LEFT, SCI_K_LEFT); + MAP_KEY (VK_RIGHT, SCI_K_RIGHT); + MAP_KEY (VK_HOME, SCI_K_HOME); + MAP_KEY (VK_UP, SCI_K_UP); + MAP_KEY (VK_PRIOR, SCI_K_PGUP); + MAP_KEY (VK_INSERT, SCI_K_INSERT); + MAP_KEY (VK_DELETE, SCI_K_DELETE); + MAP_KEY (VK_DECIMAL, SCI_K_DELETE); + /* TODO: Glutton no longer had SCI_K etc... declared + MAP_KEY (VK_ADD, SCI_K_PLUS); + MAP_KEY (VK_OEM_PLUS, SCI_K_EQUALS); + MAP_KEY (VK_SUBTRACT, SCI_K_MINUS); + MAP_KEY (VK_OEM_MINUS, SCI_K_MINUS); + MAP_KEY (VK_MULTIPLY, SCI_K_MULTIPLY); + MAP_KEY (VK_DIVIDE, SCI_K_DIVIDE); + */ + MAP_KEY (VK_OEM_COMMA, ','); + MAP_KEY (VK_OEM_PERIOD, '.'); + MAP_KEY (VK_OEM_1, ';'); // US keyboards only + MAP_KEY (VK_OEM_2, '/'); + MAP_KEY (VK_OEM_3, '`'); + MAP_KEY (VK_OEM_4, '['); + MAP_KEY (VK_OEM_5, '\\'); + MAP_KEY (VK_OEM_6, ']'); + MAP_KEY (VK_OEM_7, '\''); + MAP_KEY (VK_F1, SCI_K_F1); + MAP_KEY (VK_F2, SCI_K_F2); + MAP_KEY (VK_F3, SCI_K_F3); + MAP_KEY (VK_F4, SCI_K_F4); + MAP_KEY (VK_F5, SCI_K_F5); + MAP_KEY (VK_F6, SCI_K_F6); + MAP_KEY (VK_F7, SCI_K_F7); + MAP_KEY (VK_F8, SCI_K_F8); + MAP_KEY (VK_F9, SCI_K_F9); + MAP_KEY (VK_F10, SCI_K_F10); + + case VK_RSHIFT: + case VK_LSHIFT: + case VK_CONTROL: + case VK_MENU: + case VK_SCROLL: + case VK_NUMLOCK: + case VK_CAPITAL: + break; // ignore + + default: + if (msg.wParam >= 'A' && msg.wParam <= 'Z') + add_key_event (dx_state, msg.wParam - 'A' + 97); + else if (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9) + { + if (GetKeyState (VK_NUMLOCK) & 1) + add_key_event (dx_state, msg.wParam - VK_NUMPAD0 + '0'); + else + switch (msg.wParam) + { + MAP_KEY (VK_NUMPAD0, SCI_K_INSERT); + MAP_KEY (VK_NUMPAD1, SCI_K_END); + MAP_KEY (VK_NUMPAD2, SCI_K_DOWN); + MAP_KEY (VK_NUMPAD3, SCI_K_PGDOWN); + MAP_KEY (VK_NUMPAD4, SCI_K_LEFT); + MAP_KEY (VK_NUMPAD6, SCI_K_RIGHT); + MAP_KEY (VK_NUMPAD7, SCI_K_HOME); + MAP_KEY (VK_NUMPAD8, SCI_K_UP); + MAP_KEY (VK_NUMPAD9, SCI_K_PGUP); + } + } + else if (msg.wParam == 0xC0) // tilde key - used for invoking console + add_key_event (dx_state, '`'); + else + add_key_event (dx_state, msg.wParam); + break; + } + break; + + case WM_MOUSEMOVE: + // Turn off mouse cursor + ShowCursor(FALSE); + show_pointer(drv, msg.lParam); + break; + + case WM_MOUSELEAVE: + // Turn on mouse cursor + ShowCursor(TRUE); + break; + + case WM_LBUTTONDOWN: add_mouse_event (dx_state, SCI_EVT_MOUSE_PRESS, 1, msg.wParam); break; + case WM_RBUTTONDOWN: add_mouse_event (dx_state, SCI_EVT_MOUSE_PRESS, 2, msg.wParam); break; + case WM_MBUTTONDOWN: add_mouse_event (dx_state, SCI_EVT_MOUSE_PRESS, 3, msg.wParam); break; + case WM_LBUTTONUP: add_mouse_event (dx_state, SCI_EVT_MOUSE_RELEASE, 1, msg.wParam); break; + case WM_RBUTTONUP: add_mouse_event (dx_state, SCI_EVT_MOUSE_RELEASE, 2, msg.wParam); break; + case WM_MBUTTONUP: add_mouse_event (dx_state, SCI_EVT_MOUSE_RELEASE, 3, msg.wParam); break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + drv->exit(drv); + exit(-1); + break; + + } + } + + return 0; +} + + +extern "C" +gfx_driver_t gfx_driver_dx = { + "directx", + "0.4.2", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, /* mode */ + 0, 0, /* mouse pointer position */ + GFX_CAPABILITY_MOUSE_SUPPORT | GFX_CAPABILITY_MOUSE_POINTER | GFX_CAPABILITY_COLOR_MOUSE_POINTER | GFX_CAPABILITY_PIXMAP_REGISTRY | GFX_CAPABILITY_WINDOWED, + 0, + dx_set_param, + dx_init_specific, + dx_init, + dx_exit, + dx_draw_line, + dx_draw_filled_rect, + dx_register_pixmap, + dx_unregister_pixmap, + dx_draw_pixmap, + dx_grab_pixmap, + dx_update, + dx_set_static_buffer, + dx_set_pointer, + NULL, + dx_get_event, + dx_usleep, + NULL +}; + +#endif diff --git a/engines/sci/gfx/drivers/dx_driver.h b/engines/sci/gfx/drivers/dx_driver.h new file mode 100644 index 0000000000..3eb280cefb --- /dev/null +++ b/engines/sci/gfx/drivers/dx_driver.h @@ -0,0 +1,151 @@ +/*************************************************************************** + graphics_directx.h Copyright (C) 2008 Alexander R Angas, + Some portions Copyright (C) 1999 Dmitry Jemerov + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Alexander R Angas (Alex) <arangas AT internode dot on dot net> + +***************************************************************************/ + +#include <windows.h> +#include <d3d8.h> +#include <d3dx8math.h> +#include <dxerr8.h> + +extern "C" { +#include <gfx_system.h> +#include <gfx_driver.h> +#include <gfx_tools.h> +#include <assert.h> +#include <uinput.h> +#include <ctype.h> +#include <console.h> // for sciprintf +#include <sci_win32.h> +#include <sci_memory.h> +}; + +// Error trapping, every DirectX call should use this +#define DODX(cmd, proc) \ + hr = cmd; \ + if (hr != S_OK) { \ + sciprintf("%s, %i, %i, %s from %s\n", __FILE__, __LINE__, hr, #cmd, #proc); \ + DXTrace(__FILE__, __LINE__, hr, #cmd" from "#proc, 1); \ + } + + +// Easily release only allocated objects +#define SAFE_RELEASE(p) \ + if (p) \ + (p)->Release(); + + +// Make it simple to access drv->state +#define dx_state ((struct gfx_dx_struct_t *)(drv->state)) + + +// Simply map a key using add_key_event() +#define MAP_KEY(x,y) case x: add_key_event ((struct gfx_dx_struct_t *)(drv->state), y); break + + +#define DX_CLASS_NAME "FreeSCI DirectX Graphics" +#define DX_APP_NAME "FreeSCI" + +// Vertex format +#define D3DFVF_CUSTOMVERTEX ( D3DFVF_DIFFUSE | D3DFVF_XYZRHW | D3DFVF_TEX1 ) + +// Vertex structure +struct CUSTOMVERTEX +{ + D3DXVECTOR4 p; // Vertex coordinates + DWORD colour; // Colour + D3DXVECTOR2 t; // Texture coordinates +}; + +#define SCI_DX_HANDLE_NORMAL 0 +#define SCI_DX_HANDLE_GRABBED 1 + +// Number of buffers for each type of texture +#define NUM_VISUAL_BUFFERS 3 +#define NUM_PRIORITY_BUFFERS 2 + +// What each buffer references +#define PRIMARY_VIS 0 +#define BACK_VIS 1 +#define STATIC_VIS 2 + +#define BACK_PRI 0 +#define STATIC_PRI 1 + +// Struct that holds everything +struct gfx_dx_struct_t +{ + D3DFORMAT d3dFormat; // Colour format + UINT adapterId; // Adapter ID to use + DWORD vertexProcessing; // Hardware or software vertex processing + + LPDIRECT3D8 pD3d; // D3D object + D3DCAPS8 deviceCaps; // Capabilities of device + D3DDISPLAYMODE displayMode; // Width and height of screen + D3DPRESENT_PARAMETERS presParams; // Presentation parameters + LPDIRECT3DDEVICE8 pDevice; // Rendering device + + LPDIRECT3DVERTEXBUFFER8 pVertBuff; // Buffer to hold pixmap vertices + CUSTOMVERTEX pvData[4]; // Buffer of pixmap vertex structs + + LPDIRECT3DTEXTURE8 pTexVisuals[NUM_VISUAL_BUFFERS]; // Array of visual textures + LPDIRECT3DTEXTURE8 pTexPrioritys[NUM_PRIORITY_BUFFERS]; // Array of priority textures + gfx_pixmap_t *priority_maps[NUM_PRIORITY_BUFFERS]; // Array of SCI priority maps + + gfx_mode_t *pointerMode; // SCI graphics mode for pointer + LPDIRECT3DTEXTURE8 pTexPointer; // Mouse pointer texture + LPD3DXSPRITE pSPointer; // Mouse pointer sprite + POINTS pointerDims; // Pointer dimensions + + WNDCLASSEX wc; // Window class + HWND hWnd; // Window + UINT xfact, yfact; // Scaling factors + UINT bpp; // Bits per pixel + + // Event queue + int queue_size, queue_first, queue_last; + sci_event_t *event_queue; +}; + +// Flags that may be set in the driver +#define DX_FLAGS_FULLSCREEN 1 + +// Initialization functions +static int +ProcessMessages(struct _gfx_driver *drv); + +static gfx_return_value_t +RenderD3D(struct _gfx_driver *drv); + +static int +CheckDevice(struct _gfx_driver *drv); + +static gfx_return_value_t +InitWindow(struct _gfx_driver *drv, UINT width, UINT height); + +static gfx_return_value_t +InitD3D(struct _gfx_driver *drv); + +static gfx_return_value_t +InitScene(struct _gfx_driver *drv); diff --git a/engines/sci/gfx/drivers/gfx_drivers.c b/engines/sci/gfx/drivers/gfx_drivers.c new file mode 100644 index 0000000000..b47d6467c9 --- /dev/null +++ b/engines/sci/gfx/drivers/gfx_drivers.c @@ -0,0 +1,192 @@ +/*************************************************************************** + gfx_drivers.c Copyright (C) 2001 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <gfx_driver.h> +#include <modules.h> + + +static char *oldname = NULL; +static void *oldhandle; + + + +#ifndef HAVE_DLOPEN +# ifdef HAVE_LIBGGI +extern gfx_driver_t gfx_driver_ggi; +# endif + + +# ifndef X_DISPLAY_MISSING +extern gfx_driver_t gfx_driver_xlib; +# endif + +# ifdef HAVE_DIRECTX +extern gfx_driver_t gfx_driver_dx; +# endif + +# ifdef HAVE_DDRAW +extern gfx_driver_t gfx_driver_dd; +# endif + +# ifdef HAVE_SDL +extern gfx_driver_t gfx_driver_sdl; +# endif + +# ifdef HAVE_DIRECTFB +extern gfx_driver_t gfx_driver_dfb; +# endif + +# ifdef _DREAMCAST +extern gfx_driver_t gfx_driver_dc; +# endif +#endif + +extern gfx_driver_t gfx_driver_null; + +static gfx_driver_t *gfx_drivers[] = { +#ifndef HAVE_DLOPEN +# ifndef X_DISPLAY_MISSING + &gfx_driver_xlib, +# endif +# ifdef HAVE_SDL + &gfx_driver_sdl, +# endif +# ifdef HAVE_DIRECTX + &gfx_driver_dx, +# endif +# ifdef HAVE_DDRAW + &gfx_driver_dd, +# endif +# ifdef HAVE_DIRECTFB + &gfx_driver_dfb, +# endif +# ifdef HAVE_LIBGGI + &gfx_driver_ggi, +# endif +# ifdef _DREAMCAST + &gfx_driver_dc, +# endif +#endif + &gfx_driver_null, + NULL +}; + +#define DRIVER_TYPE "gfx" +#define DRIVER_PREFIX "gfx_driver_" +#define DRIVER_FILE_SUFFIX "_driver" + +#ifdef HAVE_DLOPEN +struct _gfx_driver * +gfx_find_driver(char *path, char *name) +{ + int retval = 0; + + if (oldhandle) + sci_close_module(oldhandle, DRIVER_TYPE, oldname); + + if (!name) { /* Find default driver */ +#ifdef _WIN32 + name = "sdl"; +#else /* !_WIN32 */ +# ifndef X_DISPLAY_MISSING + if (getenv("DISPLAY")) + name = "xlib"; + else +# endif + name = "ggi"; +#endif /* !_WIN32 */ + } + + oldname = name; + return (struct _gfx_driver *) + sci_find_module(path, name, DRIVER_TYPE, + DRIVER_PREFIX, + DRIVER_FILE_SUFFIX, + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + &oldhandle); +} +#else /* No dlopen */ +struct _gfx_driver * +gfx_find_driver(char *path, char *name) +{ + int retval = 0; + + if (!name) { /* Find default driver */ +#ifndef X_DISPLAY_MISSING + if (getenv("DISPLAY")) + return &gfx_driver_xlib; +#endif +#if defined (MACOSX) && defined(HAVE_SDL) + return &gfx_driver_sdl; +#endif + return gfx_drivers[0]; + } + + while (gfx_drivers[retval] && strcasecmp(name, gfx_drivers[retval]->name)) + retval++; + + return gfx_drivers[retval]; +} +#endif + + +const char * +gfx_get_driver_name(int nr) +{ + return (gfx_drivers[nr])? gfx_drivers[nr]->name : NULL; +} + + +int +string_truep(char *value) +{ + return !(strcasecmp(value, "ok") && + strcasecmp(value, "enable") && + strcasecmp(value, "1") && + strcasecmp(value, "true") && + strcasecmp(value, "yes") && + strcasecmp(value, "on")); +} + + +int +string_falsep(char *value) +{ + return !(strcasecmp(value, "disable") && + strcasecmp(value, "0") && + strcasecmp(value, "false") && + strcasecmp(value, "no") && + strcasecmp(value, "off")); +} + + + + diff --git a/engines/sci/gfx/drivers/ggi_driver.c b/engines/sci/gfx/drivers/ggi_driver.c new file mode 100644 index 0000000000..c6cf4b0f00 --- /dev/null +++ b/engines/sci/gfx/drivers/ggi_driver.c @@ -0,0 +1,1035 @@ +/*************************************************************************** + ggi_driver.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* FreeSCI 0.3.1+ graphics driver module for libggi */ + + +#include <stdarg.h> +#include <gfx_system.h> +#include <gfx_driver.h> +#include <gfx_tools.h> +#include <assert.h> +#include <uinput.h> + +#ifdef HAVE_LIBGGI + +#include <ggi/ggi.h> +#include <ctype.h> + + +#define GGI_DRIVER_VERSION "0.4" + +#define GFX_GGI_DEBUG + +#ifdef GFX_GGI_DEBUG + +#define POSMSG sciprintf("%s L%d:", __FILE__, __LINE__) +#define DEBUG_POINTER (!(drv->debug_flags & GFX_DEBUG_POINTER))? 0 : POSMSG && gfxprintf +#define DEBUG_UPDATES (!(drv->debug_flags & GFX_DEBUG_UPDATES))? 0 : POSMSG && gfxprintf +#define DEBUG_PIXMAPS (!(drv->debug_flags & GFX_DEBUG_PIXMAPS))? 0 : POSMSG && sciprintf +#define DEBUG_BASIC (!(drv->debug_flags & GFX_DEBUG_BASIC))? 0 : POSMSG && sciprintf +#else /* !GFX_GGI_DEBUG */ +#define DEBUG_POINTER (1)? 0 : +#define DEBUG_UPDATES (1)? 0 : +#define DEBUG_PIXMAPS (1)? 0 : +#define DEBUG_BASIC (1)? 0 : +#endif /* !GFX_GGI_DEBUG */ + +static gfx_mode_t * +_aberr(char *file, int line, char *message); + +static void +init_input_ggi(); + +#define MODE ((drv->mode)? drv->mode : _aberr(__FILE__, __LINE__, "drv->mode is NULL")) +#define STATE ((gfx_ggi_struct_t *)drv->state) +#define VISUAL ((gfx_ggi_struct_t *)drv->state)->vis +#define FRAMES ((gfx_ggi_struct_t *)drv->state)->frames + +static gfx_mode_t * +_aberr(char *file, int line, char *message) +{ + fprintf(stderr,"GFXGGI: Fatal: %s L%d: %s\n", file, line, message); + exit(1); /* Die */ + return NULL; +} + +#define GGI_BUFFER_BACK 0 +#define GGI_BUFFER_STATIC 1 + +#define SCI_GGI_SWAP_CTRL_CAPS (1 << 0) + +typedef struct { + ggi_visual_t vis; + int frames; + + byte *alt_back_buffer; /* if frames < 2: Virtual back buffer */ + ggi_visual_t back_vis; /* Memory visual for the back buffer */ + + byte *static_buffer; /* if frames < 3: Virtual static buffer */ + ggi_visual_t static_vis; /* Memory visual for the static buffer */ + + gfx_pixmap_t *priority_maps[2]; + ggi_visual_t priority_visuals[2]; /* Visuals for the maps */ + + int x_blank, y_blank; + int x_blank2, y_blank2; + +} gfx_ggi_struct_t; + +static int flags; + +static int +ggi_set_param(gfx_driver_t *drv, char *attribute, char *value) +{ + gfx_ggi_struct_t *meta = (gfx_ggi_struct_t *) drv->state; + + if (!strcmp(attribute, "swap_ctrl_caps") || + !strcmp(attribute, "swap_caps_ctrl")) { + if (string_truep(value)) + flags |= SCI_GGI_SWAP_CTRL_CAPS; + else + flags &= ~SCI_GGI_SWAP_CTRL_CAPS; + + return GFX_OK; + } + + DEBUG_BASIC("ggi_set_param('%s' to '%s')\n", attribute, value); + return GFX_ERROR; +} + + +static int +_open_meta_visuals(gfx_driver_t *drv) +{ + int i; + + for (i = 0; i < 2; i++) { + if (!(STATE->priority_visuals[i] = ggiOpen("memory:pointer", STATE->priority_maps[i]->data))) { + sciprintf("GFXGGI: Could not open priority map #%d\n", i); + return 1; + } + if (ggiSetSimpleMode(STATE->priority_visuals[i], 320 * MODE->xfact, 200 * MODE->yfact, 1, GT_8BIT)) { + sciprintf("GFXGGI: Could not set mode for priority visual %d\n", i); + return 1; + } + } + + return 0; +} + +static int +ggi_init_specific(gfx_driver_t *drv, int xres, int yres, int bpp) +{ + gfx_ggi_struct_t *meta; + ggi_graphtype graphtype; + const ggi_pixelformat *pixelformat; + int frames = 3; + + switch (bpp) { + case 1: graphtype = GT_8BIT; break; + case 2: graphtype = GT_16BIT; break; + case 3: graphtype = GT_24BIT; break; + case 4: graphtype = GT_32BIT; break; + default: sciprintf("GFXGGI: Error: Invalid bytes per pixel value: %d\n", bpp); + return GFX_ERROR; + } + + drv->state = NULL; + + if (ggiInit() < 0) + return GFX_FATAL; + + meta = (gfx_ggi_struct_t *) sci_calloc(sizeof(gfx_ggi_struct_t), 1); + + if (!(meta->vis = ggiOpen(NULL))) { + DEBUG_BASIC("ggiOpen() failed!\n"); + free(meta); + ggiExit(); + return GFX_FATAL; + } + + while ((frames > 0) && (ggiSetSimpleMode(meta->vis, xres * 320, yres * 200, frames, graphtype))) + --frames; + + if (!frames) { + DEBUG_BASIC("Initializing %dx%d at %d bpp failed\n", xres*320, yres*200, bpp << 3); + free(meta); + ggiExit(); + return GFX_ERROR; + } + + DEBUG_BASIC("Initialized with %d frames\n", frames); + + meta->frames = frames; + + pixelformat = ggiGetPixelFormat(meta->vis); + drv->mode = gfx_new_mode(xres, yres, pixelformat->size >> 3, + pixelformat->red_mask, pixelformat->green_mask, pixelformat->blue_mask, + 0, /* alpha mask */ + pixelformat->red_shift, pixelformat->green_shift, pixelformat->blue_shift, + 0, /* alpha shift */ + (bpp == 1)? 256 : 0, 0); + drv->state = meta; + + meta->priority_maps[GGI_BUFFER_BACK] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * xres, 200 * yres, GFX_RESID_NONE, 0, 0)); + meta->priority_maps[GGI_BUFFER_STATIC] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(320 * xres, 200 * yres, GFX_RESID_NONE, 0, 0)); + + meta->priority_maps[GGI_BUFFER_BACK]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + meta->priority_maps[GGI_BUFFER_STATIC]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + + if (_open_meta_visuals(drv)) { + free(meta); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_BACK]); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_STATIC]); + ggiClose(meta->vis); + ggiExit(); + return GFX_ERROR; + } + + if (frames < 2) { + meta->alt_back_buffer = (byte *) sci_malloc(bpp * 320 * 200 * xres * yres); + meta->back_vis = ggiOpen("memory:pointer", meta->alt_back_buffer, NULL); + if (ggiSetSimpleMode(meta->back_vis, xres * 320, yres * 200, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual failed\n"); + } + } else meta->alt_back_buffer = NULL; + + if (frames < 3) { + meta->static_buffer = (byte *) sci_malloc(bpp * 320 * 200 * xres * yres); + meta->static_vis = ggiOpen("memory:pointer", meta->static_buffer, NULL); + if (ggiSetSimpleMode(meta->static_vis, xres * 320, yres * 200, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual #2 failed\n"); + } + } else meta->static_buffer = NULL; + + init_input_ggi(); + flags = 0; + + return GFX_OK; +} + + +static int +ggi_init(gfx_driver_t *drv) +{ + gfx_ggi_struct_t *meta; + ggi_mode mode; + int x_blank, y_blank; + const ggi_pixelformat *pixelformat; + mode.frames = 3; + mode.visible.x = mode.visible.y = mode.virt.x = mode.virt.y + = mode.size.x = mode.size.y = mode.dpp.x = mode.dpp.y = GGI_AUTO; + + mode.graphtype = GT_AUTO; + + drv->state = NULL; + + if (ggiInit() < 0) + return GFX_FATAL; + + meta = (gfx_ggi_struct_t *) sci_calloc(sizeof(gfx_ggi_struct_t), 1); + + if (!(meta->vis = ggiOpen(NULL))) { + DEBUG_BASIC("ggiOpen() failed!\n"); + free(meta); + ggiExit(); + return GFX_FATAL; + } + + while (mode.frames && ggiCheckMode(meta->vis, &mode)) + --(mode.frames); + + if (!mode.frames) { + sciprintf("GFXGGI: Could not find any graphics mode!\n"); + free(meta); + ggiExit(); + return GFX_FATAL; + } + + x_blank = mode.visible.x % 320; + y_blank = mode.visible.y % 200; + mode.visible.x -= x_blank; + mode.visible.y -= y_blank; + + if (mode.visible.x == 0) + mode.visible.x = 320; + + if (mode.visible.y == 0) + mode.visible.y = 200; + + if (GT_DEPTH(mode.graphtype) < 8) + mode.graphtype = GT_8BIT; /* We don't support less than 8 bpp */ + + DEBUG_BASIC("Attempting to create mode with %dx%d, graphtype=%08x, %d frames\n", + mode.visible.x, mode.visible.y, mode.graphtype, mode.frames); + + mode.virt.x = mode.visible.x; + mode.virt.y = mode.visible.y; + mode.size.x = GGI_AUTO; + mode.size.y = GGI_AUTO; + + if (ggiSetMode(meta->vis, &mode)) { + sciprintf("GFXGGI: Could not set proposed graphics mode!\n"); + + mode.virt.x = mode.visible.x += x_blank; + mode.virt.y = mode.visible.y += y_blank; + mode.size.x = GGI_AUTO; + mode.size.y = GGI_AUTO; + + DEBUG_BASIC("Attempting to create augmented mode with %dx%d, graphtype=%08x, %d frames\n", + mode.visible.x, mode.visible.y, mode.graphtype, mode.frames); + + if (ggiSetMode(meta->vis, &mode)) { + sciprintf("GFXGGI: Could not set proposed graphics mode!\n"); + free(meta); + ggiExit(); + return GFX_FATAL; + } + + ggiSetOrigin(meta->vis, (x_blank >> 1), (y_blank >> 1)); + + mode.virt.x = mode.size.x = mode.visible.x -= x_blank; + mode.virt.y = mode.size.y = mode.visible.y -= y_blank; + } else + x_blank = y_blank = 0; + + meta->frames = mode.frames; + + pixelformat = ggiGetPixelFormat(meta->vis); + + drv->mode = gfx_new_mode(mode.visible.x / 320, mode.visible.y / 200, pixelformat->size >> 3, + pixelformat->red_mask, pixelformat->green_mask, pixelformat->blue_mask, + 0, /* alpha mask */ + pixelformat->red_shift, pixelformat->green_shift, pixelformat->blue_shift, + 0, /* alpha shift */ + (GT_SCHEME(mode.graphtype) == GT_PALETTE)? (1 << GT_DEPTH(mode.graphtype)) : 0, 0); + + drv->state = meta; + + meta->priority_maps[GGI_BUFFER_BACK] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(mode.visible.x, mode.visible.y, GFX_RESID_NONE, 0, 0)); + meta->priority_maps[GGI_BUFFER_STATIC] = + gfx_pixmap_alloc_index_data(gfx_new_pixmap(mode.visible.x, mode.visible.y, GFX_RESID_NONE, 0, 0)); + + meta->priority_maps[GGI_BUFFER_BACK]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + meta->priority_maps[GGI_BUFFER_STATIC]->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + + if (_open_meta_visuals(drv)) { + free(meta); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_BACK]); + gfx_free_pixmap(drv, meta->priority_maps[GGI_BUFFER_STATIC]); + ggiClose(meta->vis); + ggiExit(); + return GFX_FATAL; + } + + if (meta->frames < 2) { + meta->alt_back_buffer = (byte *) sci_malloc((pixelformat->size >> 3) * mode.visible.x * mode.visible.y); + meta->back_vis = ggiOpen("memory:pointer", meta->alt_back_buffer, NULL); + if (ggiSetSimpleMode(meta->back_vis, mode.visible.x, mode.visible.y, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual failed\n"); + } + } else meta->alt_back_buffer = NULL; + + if (meta->frames < 3) { + meta->static_buffer = (byte *) sci_malloc((pixelformat->size >> 3) * mode.visible.x * mode.visible.y); + meta->static_vis = ggiOpen("memory:pointer", meta->static_buffer, NULL); + if (ggiSetSimpleMode(meta->static_vis, mode.visible.x, mode.visible.y, 1, GT_8BIT)) { + sciprintf("GFXGGI: Warning: Setting mode for memory visual #2 failed\n"); + } + } else meta->static_buffer = NULL; + + init_input_ggi(); + flags = 0; + + STATE->x_blank = x_blank; + STATE->y_blank = y_blank; + STATE->x_blank2 = x_blank >> 1; + STATE->y_blank2 = y_blank >> 1; + + return GFX_OK; +} + + +static void +ggi_exit(gfx_driver_t *drv) +{ + if (drv->state) { + gfx_free_pixmap(drv, STATE->priority_maps[0]); + gfx_free_pixmap(drv, STATE->priority_maps[1]); + + if (STATE->frames < 2) + ggiClose(STATE->back_vis); + + if (STATE->frames < 3) + ggiClose(STATE->static_vis); + + ggiClose(STATE->priority_visuals[0]); + ggiClose(STATE->priority_visuals[1]); + + ggiClose(VISUAL); + } + + gfx_free_mode(drv->mode); + + ggiExit(); + + if (FRAMES < 2) + free(STATE->alt_back_buffer); + + free(drv->state); +} + + +static inline ggi_visual_t +get_writeable_back_visual(gfx_driver_t *drv) +{ + if (STATE->frames > 1) { + ggiSetWriteFrame(VISUAL, 1); + return VISUAL; + } else + return STATE->back_vis; +} + +static inline ggi_visual_t +get_writeable_static_visual(gfx_driver_t *drv) +{ + if (STATE->frames > 2) { + ggiSetWriteFrame(VISUAL, 2); + return VISUAL; + } else + return STATE->static_vis; +} + +static inline ggi_pixel +ggi_map_color(gfx_driver_t *drv, ggi_visual_t vis, gfx_color_t color) +{ + if (MODE->palette) + return (ggi_pixel) color.visual.global_index; + else { + ggi_color gcolor; + gcolor.r = ((int) color.visual.r << 8) | color.visual.r; + gcolor.g = ((int) color.visual.g << 8) | color.visual.g; + gcolor.b = ((int) color.visual.b << 8) | color.visual.b; + gcolor.a = ((int) color.alpha << 8) | color.alpha; + + return ggiMapColor(vis, &gcolor); + } +} + +static int +ggi_draw_filled_rect(gfx_driver_t *drv, rect_t box, gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode); + +static int +ggi_draw_line(gfx_driver_t *drv, point_t start, point_t end, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + ggi_pixel pixel; + + int xw = MODE->xfact, yw = MODE->yfact; + int rx, ry, endx, endy; + int xc, yc; + + if (line_mode == GFX_LINE_MODE_FINE) + xw = yw = 1; + else { + xw = MODE->xfact, yw = MODE->yfact; + } + + rx = start.x; + ry = start.y; + endx = end.x; + endy = end.y; + + if ((rx == endx) && (ry == endy)) + return ggi_draw_filled_rect(drv, gfx_rect(rx, ry, xw, yw), color, color, GFX_SHADE_FLAT); + + if (color.mask & GFX_MASK_PRIORITY) { + ggi_visual_t privis = STATE->priority_visuals[GFX_BUFFER_BACK]; + + ggiSetGCForeground(privis, color.priority); + + for (xc = 0; xc < xw; xc++) + ggiDrawLine(privis, rx + xc, ry, endx + xc, endy); + if (yw > 0) + for (xc = 0; xc < xw; xc++) + ggiDrawLine(privis, rx + xc, ry + yw - 1, endx + xc, endy + yw - 1); + + if (yw > 1) { + for (yc = 1; yc < yw-1; yc++) + ggiDrawLine(privis, rx, ry + yc, endx, endy + yc); + + if (xw > 0) + for (yc = 1; yc < yw-1; yc++) + ggiDrawLine(privis, rx + xw - 1, ry + yc, endx + xw - 1, endy + yc); + } + } + + if (color.mask & GFX_MASK_VISUAL) { + ggi_visual_t vis; + + pixel = ggi_map_color(drv, VISUAL, color); + + vis = get_writeable_back_visual(drv); + + ggiSetGCForeground(vis, pixel); + + for (xc = 0; xc < xw; xc++) + ggiDrawLine(vis, rx + xc, ry, endx + xc, endy); + if (yw > 0) + for (xc = 0; xc < xw; xc++) + ggiDrawLine(vis, rx + xc, ry + yw - 1, endx + xc, endy + yw - 1); + + if (yw > 1) { + for (yc = 1; yc < yw-1; yc++) + ggiDrawLine(vis, rx, ry + yc, endx, endy + yc); + + if (xw > 0) + for (yc = 1; yc < yw-1; yc++) + ggiDrawLine(vis, rx + xw - 1, ry + yc, endx + xw - 1, endy + yc); + } + } + + return GFX_OK; +} + +static int +ggi_draw_filled_rect(gfx_driver_t *drv, rect_t box, gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (color1.mask & GFX_MASK_VISUAL) { + ggi_pixel pixel = ggi_map_color(drv, VISUAL, color1); + ggi_visual_t vis = get_writeable_back_visual(drv); + + ggiSetGCForeground(vis, pixel); + ggiDrawBox(vis, box.x, box.y, box.xl, box.yl); + } + + if (color1.mask & GFX_MASK_PRIORITY) { + ggi_visual_t vis; + + ggiSetGCForeground(vis = STATE->priority_visuals[GFX_BUFFER_BACK], color1.priority); + ggiDrawBox(vis, box.x, box.y, box.xl, box.yl); + } + + return GFX_OK; +} + +/**************/ +/* Pixmap ops */ +/**************/ + +int +ggi_draw_pixmap(gfx_driver_t *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + ggi_visual_t vis = VISUAL; + const ggi_directbuffer *dbuf; + byte *pri_map = NULL; + + if (dest.xl != src.xl || dest.yl != src.yl) { + GFXERROR("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n", + src.xl, src.yl, dest.xl, dest.yl); + return GFX_ERROR; + } + + switch (buffer) { + + case GFX_BUFFER_FRONT: + GFXERROR("Attempt to draw pixmap to front buffer\n"); + return GFX_ERROR; + + case GFX_BUFFER_BACK: + if (STATE->frames > 1) + ggiSetWriteFrame(VISUAL, 1); + else vis = STATE->back_vis; + pri_map = STATE->priority_maps[GGI_BUFFER_BACK]->index_data; + break; + + + case GFX_BUFFER_STATIC: + if (STATE->frames > 2) + ggiSetWriteFrame(VISUAL, 2); + else vis = STATE->static_vis; + pri_map = STATE->priority_maps[GGI_BUFFER_STATIC]->index_data; + break; + + + default: + GFXERROR("Unexpected buffer ID %d\n", buffer); + return GFX_ERROR; + + } + + assert(pri_map); + assert(vis); + + dbuf = ggiDBGetBuffer(vis, (vis == VISUAL)? buffer : 0); + if (!dbuf) { + GFXERROR("Could not acquire direct buffer!\n"); + return GFX_FATAL; + } + + if (dbuf->resource) { + if (ggiResourceAcquire(dbuf->resource, GGI_ACTYPE_WRITE)) { + GFXERROR("Failed to allocate resource for direct buffer!\n"); + return GFX_FATAL; + } + } + + if (dbuf->layout != blPixelLinearBuffer) { + char *type; + + switch (dbuf->layout) { + case blPixelPlanarBuffer: type = "planar"; + break; + + case blExtended: type = "extended"; + break; + + default: type = "invalid"; + + } + + GFXERROR("Error: Pixel buffer is %s! Non-linear buffers are not supported.\n", type); + + if (dbuf->resource) + ggiResourceRelease(dbuf->resource); + return GFX_FATAL; + } + + gfx_crossblit_pixmap(MODE, pxm, priority, src, dest, (byte *) dbuf->write, + dbuf->buffer.plb.stride, + pri_map, MODE->xfact * 320, 1, 0); + + /* ggiPutBox(vis, dest.x * MODE->xfact, dest.y * MODE->yfact, pxm->xl, pxm->yl, pxm->data); */ + + if (dbuf->resource) + ggiResourceRelease(dbuf->resource); + + return GFX_OK; +} + +int +ggi_grab_pixmap(gfx_driver_t *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + ggi_visual_t vis = VISUAL; + int error; + + pxm->xl = src.xl; + pxm->yl = src.yl; + + if (STATE->frames > 1) + ggiSetReadFrame(VISUAL, 1); + else vis = STATE->back_vis; + + if (src.x < 0 || src.y < 0) { + GFXERROR("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) { + GFXERROR("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + + if ((error = ggiGetBox(vis, src.x, src.y, src.xl, src.yl, pxm->data))) { + GFXERROR("ggiGetBox(%d, %d, %d, %d) returned error code %d\n", src.x, src.y, src.xl, src.yl, error); + return GFX_ERROR; + } + + return GFX_OK; +} + +/************/ +/* Misc ops */ +/************/ + + +static int +ggi_update(gfx_driver_t *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + int sx = src.x, sy = src.y; + int dx = dest.x, dy = dest.y; + int xl = src.xl, yl = src.yl; + + switch (buffer) { + case GFX_BUFFER_FRONT: + ggiSetWriteFrame(VISUAL, 0); + + if (STATE->frames < 2) + ggiCrossBlit(STATE->back_vis, sx, sy, xl, yl, VISUAL, dx + STATE->x_blank2, dy + STATE->y_blank2); + else { + ggiSetReadFrame(VISUAL, 1); + ggiCopyBox(VISUAL, sx, sy, xl, yl, dx + STATE->x_blank2, dy + STATE->y_blank2); + } + + break; + + case GFX_BUFFER_BACK: + if (src.x == dest.x && src.y == dest.y) + gfx_copy_pixmap_box_i(STATE->priority_maps[GGI_BUFFER_BACK], STATE->priority_maps[GGI_BUFFER_STATIC], src); + + if (STATE->frames > 1) + ggiSetWriteFrame(VISUAL, 1); + + if (STATE->frames > 2) { + ggiSetReadFrame(VISUAL, 2); + ggiCopyBox(VISUAL, sx, sy, xl, yl, dx, dy); + return GFX_OK; + } + + ggiCrossBlit(STATE->static_vis, sx, sy, xl, yl, STATE->back_vis, dx, dy); + + break; + + default: + GFXERROR("Invalid buffer %d in update!\n", buffer); + return GFX_ERROR; + } + return GFX_OK; +} + + +static int +ggi_set_palette(gfx_driver_t *drv, int index, byte red, byte green, byte blue) +{ + ggi_color color; + color.r = (red << 8) | red; + color.g = (green << 8) | green; + color.b = (blue << 8) | blue; + + /* DEBUG_POINTER(stderr,"Setting index %d to %04x %04x %04x\n", index, color.r, color.g, color.b); */ + + if (ggiSetPalette(VISUAL, index, 1, &color) < 0) + return GFX_ERROR; + else + return GFX_OK; +} + + +static int +ggi_set_static_buffer(gfx_driver_t *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + ggi_visual_t vis = get_writeable_static_visual(drv); + + /* First, check if the priority map is sane */ + if (priority->index_xl != STATE->priority_maps[GGI_BUFFER_STATIC]->index_xl + || priority->index_yl != STATE->priority_maps[GGI_BUFFER_STATIC]->index_yl) { + GFXERROR("Invalid priority map: (%dx%d) vs expected (%dx%d)\n", + priority->index_xl, priority->index_yl, + STATE->priority_maps[GGI_BUFFER_STATIC]->index_xl, + STATE->priority_maps[GGI_BUFFER_STATIC]->index_yl); + return GFX_ERROR; + } + + ggiPutBox(vis, 0, 0, pic->xl, pic->yl, pic->data); + + memcpy(STATE->priority_maps[GGI_BUFFER_STATIC]->index_data, priority->index_data, + priority->index_xl * priority->index_yl); + + return GFX_OK; +} + + +/********************/ +/* Input management */ +/********************/ + + +struct timeval _sci_ggi_redraw_loopt, _sci_ggi_loopt; +/* timer variables */ + +int _sci_ggi_double_visual; + +static int buckybits; + +#define SCI_TIMEVAL_ADD(timev, addusec) \ + { timev.tv_usec += addusec; \ + while (timev.tv_usec >= 1000000L) { \ + timev.tv_usec -= 1000000L; \ + timev.tv_sec++; \ + }} + +#define SCI_TIMEVAL_LATER(later, earlier) \ + ((later.tv_sec == earlier.tv_sec)? (later.tv_usec >= earlier.tv_usec) \ + : (later.tv_sec >= earlier.tv_sec)) + + +static sci_event_t +ggi_get_event(gfx_driver_t *drv) +{ + struct timeval temptime = {0,0}; + gfx_ggi_struct_t *meta = (gfx_ggi_struct_t *) drv->state; + int modifiers; + + while (1) { + + if (ggiEventPoll(VISUAL, emAll, &temptime)) { + ggi_event event; + sci_event_t retval; + + ggiEventRead(VISUAL, &event, emAll); + + if (flags & SCI_GGI_SWAP_CTRL_CAPS + && ((event.any.type == evKeyPress) + || (event.any.type == evKeyRepeat) + || (event.any.type == evKeyRelease))) { + + switch (event.key.label) { + case GIIK_CtrlL: event.key.label = GIIK_CapsLock; break; + case GIIK_CapsLock: event.key.label = GIIK_CtrlL; break; + } + } + + switch (event.any.type) { + case evKeyPress: + case evKeyRepeat: + retval.type = SCI_EVT_KEYBOARD; + retval.data=-1; + retval.buckybits = 0; + switch(event.key.label) + { + case GIIK_P4: + case GIIK_Left: retval.data=SCI_K_LEFT; retval.buckybits = SCI_EVM_NUMLOCK; break; + case GIIK_P6: + case GIIK_Right: retval.data=SCI_K_RIGHT; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P8: + case GIIK_Up: retval.data=SCI_K_UP; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P2: + case GIIK_Down: retval.data=SCI_K_DOWN; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P7: + case GIIK_Home: retval.data=SCI_K_HOME; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P1: + case GIIK_End: retval.data=SCI_K_END; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P9: + case GIIK_PageUp: retval.data=SCI_K_PGUP; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P3: + case GIIK_PageDown: retval.data=SCI_K_PGDOWN; retval.buckybits = SCI_EVM_NUMLOCK;break; + case GIIK_P5: retval.data=SCI_K_CENTER; retval.buckybits = SCI_EVM_NUMLOCK;break; + + case GIIUC_Minus: + case GIIK_PMinus: retval.data = '-'; break; + case GIIUC_Plus: + case GIIK_PPlus: retval.data = '+'; break; + + case GIIUC_Grave: retval.data = '`'; break; +#if 0 + case GIIK_ShiftL: buckybits |= SCI_EVM_LSHIFT; break; + case GIIK_ShiftR: buckybits |= SCI_EVM_RSHIFT; break; + case GIIK_CtrlR: + case GIIK_CtrlL: buckybits |= SCI_EVM_CTRL; break; + case GIIK_AltL: + case GIIK_AltR: + case GIIK_MetaL: + case GIIK_MetaR: buckybits |= SCI_EVM_ALT; break; + case GIIK_CapsLock: buckybits ^= SCI_EVM_CAPSLOCK; break; + case GIIK_NumLock: buckybits ^= SCI_EVM_NUMLOCK; break; + case GIIK_ScrollLock: buckybits ^= SCI_EVM_SCRLOCK; break; +#endif + case GIIK_Insert: buckybits ^= SCI_EVM_INSERT; break; + case GIIK_PEnter: + case GIIK_Enter: retval.data='\r'; break; + case GIIUC_Tab: retval.data='\t'; break; + case GIIUC_Space: retval.data=' '; break; + case GIIUC_BackSpace: retval.data=SCI_K_BACKSPACE; break; + case GIIK_F1: retval.data = SCI_K_F1; break; + case GIIK_F2: retval.data = SCI_K_F2; break; + case GIIK_F3: retval.data = SCI_K_F3; break; + case GIIK_F4: retval.data = SCI_K_F4; break; + case GIIK_F5: retval.data = SCI_K_F5; break; + case GIIK_F6: retval.data = SCI_K_F6; break; + case GIIK_F7: retval.data = SCI_K_F7; break; + case GIIK_F8: retval.data = SCI_K_F8; break; + case GIIK_F9: retval.data = SCI_K_F9; break; + case GIIK_F10: retval.data = SCI_K_F10; break; + case GIIUC_Escape: retval.data = SCI_K_ESC; break; + + /*FIXME: Add all special keys in a sane way*/ + default: + { + if(event.key.label>='a' && event.key.label<='z') + retval.data=event.key.label-'a'+97; + if(event.key.label>='A' && event.key.label<='Z') + retval.data=event.key.label-'A'+97; + if(event.key.label>='0' && event.key.label<='9') + retval.data=event.key.label-'0'+48; + } + } + + modifiers = event.key.modifiers; + + buckybits = (buckybits & SCI_EVM_INSERT) | + (((modifiers & GII_MOD_CAPS)? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0) + | ((modifiers & GII_MOD_CTRL)? SCI_EVM_CTRL : 0) + | ((modifiers & (GII_MOD_ALT | GII_MOD_META))? SCI_EVM_ALT : 0) + | ((modifiers & GII_MOD_NUM)? SCI_EVM_NUMLOCK : 0) + | ((modifiers & GII_MOD_SCROLL)? SCI_EVM_SCRLOCK : 0)) + ^ ((modifiers & GII_MOD_SHIFT)? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0); + + if(retval.data==-1) continue; + retval.buckybits |= buckybits; + + return retval; + + case evKeyRelease: +#if 0 + switch(event.key.label) + { + case GIIK_ShiftL: buckybits &= ~SCI_EVM_LSHIFT; break; + case GIIK_ShiftR: buckybits &= ~SCI_EVM_RSHIFT; break; + case GIIK_CtrlR: + case GIIK_CtrlL: buckybits &= ~SCI_EVM_CTRL; break; + case GIIK_AltL: + case GIIK_AltR: + case GIIK_MetaL: + case GIIK_MetaR: buckybits &= ~SCI_EVM_ALT; break; + } +#endif + continue; + + case evPtrButtonPress: + retval.type = SCI_EVT_MOUSE_PRESS; + retval.data = event.pbutton.button; + retval.buckybits=buckybits; + + if (event.pbutton.button == GII_PBUTTON_LEFT) + retval.buckybits |= SCI_EVM_CTRL; + + if (event.pbutton.button == GII_PBUTTON_RIGHT) + retval.buckybits |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + return retval; + + case evPtrButtonRelease: + retval.type = SCI_EVT_MOUSE_RELEASE; + retval.data = event.pbutton.button; + retval.buckybits=buckybits; + + if (event.pbutton.button == GII_PBUTTON_LEFT) + retval.buckybits |= SCI_EVM_CTRL; + + if (event.pbutton.button == GII_PBUTTON_RIGHT) + retval.buckybits |= SCI_EVM_LSHIFT | SCI_EVM_RSHIFT; + + return retval; + + case evPtrAbsolute: + drv->pointer_x = event.pmove.x - STATE->x_blank2; + drv->pointer_y = event.pmove.y - STATE->y_blank2; + continue; + + case evPtrRelative: + drv->pointer_x += event.pmove.x; + drv->pointer_y += event.pmove.y; + /* FIXME: This may make the pointer too fast on high res! */ + continue; + } + } else { + sci_event_t retval; + + retval.type = SCI_EVT_NONE; /* Nothing happened */ + return retval; + } + + } +} + +static void +init_input_ggi() +{ + _sci_ggi_loopt = _sci_ggi_redraw_loopt; + buckybits = SCI_EVM_INSERT; /* Start up in "insert" mode */ + /* reset timers, leave them at current time to send redraw events ASAP */ + +} + + +int +ggi_usleep(gfx_driver_t* drv, long usec) +{ + struct timeval tv = {0, usec}; + + while(tv.tv_usec>0) + { + if(ggiEventPoll(VISUAL, emPtrMove, &tv)) + { + ggi_event e; + ggiEventRead(VISUAL, &e, emPtrMove); + switch(e.any.type) + { + case evPtrRelative: + { + drv->pointer_x+=e.pmove.x; + drv->pointer_y+=e.pmove.y; + } return GFX_OK; + case evPtrAbsolute: + { + drv->pointer_x=e.pmove.x - STATE->x_blank2; + drv->pointer_y=e.pmove.y - STATE->y_blank2; + } return GFX_OK; + } + } + } + return GFX_OK; +} + + + + +gfx_driver_t gfx_driver_ggi = { + "ggi", + GGI_DRIVER_VERSION, + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0,0, + GFX_CAPABILITY_FINE_LINES, GFX_DEBUG_POINTER + | GFX_DEBUG_UPDATES | GFX_DEBUG_PIXMAPS | GFX_DEBUG_BASIC, + ggi_set_param, + ggi_init_specific, + ggi_init, + ggi_exit, + ggi_draw_line, + ggi_draw_filled_rect, + NULL, + NULL, + ggi_draw_pixmap, + ggi_grab_pixmap, + ggi_update, + ggi_set_static_buffer, + NULL, + ggi_set_palette, + ggi_get_event, + ggi_usleep +}; + + +#endif /* HAVE_LIBGGI */ diff --git a/engines/sci/gfx/drivers/null_driver.c b/engines/sci/gfx/drivers/null_driver.c new file mode 100644 index 0000000000..e6821f56ef --- /dev/null +++ b/engines/sci/gfx/drivers/null_driver.c @@ -0,0 +1,211 @@ +/*************************************************************************** + null_driver.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <gfx_driver.h> +#include <gfx_tools.h> + +static int debug_sleep = 0; +static int debug_draw = 0; + +static int +null_set_parameter(struct _gfx_driver *drv, char *attribute, char *value) +{ + printf("[GFX-NULL] Setting '%s' <- '%s'\n", attribute, value); + + return GFX_OK; +} + + + +static int +null_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + printf("[GFX-NULL] Initializing specific: %dx%d, %d bytespp\n", + xfact, yfact, bytespp); + + drv->mode = gfx_new_mode(xfact, yfact, bytespp, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0); + + return GFX_OK; +} + + +static int +null_init(struct _gfx_driver *drv) +{ + printf("[GFX-NULL] Initializing default\n"); + return null_init_specific(drv, 1, 1, 1); +} + +static void +null_exit(struct _gfx_driver *drv) +{ + printf("[GFX-NULL] Exitting\n"); +} + + + /*** Drawing operations ***/ + +static int +null_draw_line(struct _gfx_driver *drv, point_t start, point_t end, + gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + if (debug_draw) + printf("[GFX-NULL] Line (%d,%d) -- (%d,%d)\n", + GFX_PRINT_POINT(start), + GFX_PRINT_POINT(end)); + return GFX_OK; +} + +static int +null_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (debug_draw) + printf("[GFX-NULL] Box (%d,%d)d(%d,%d)\n", + GFX_PRINT_RECT(rect)); + return GFX_OK; +} + + + /*** Pixmap operations ***/ + +static int +null_register_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + return GFX_OK; +} + +static int +null_unregister_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + return GFX_OK; +} + +static int +null_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + return GFX_OK; +} + +static int +null_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + return GFX_OK; + pxm->xl = src.xl; + pxm->yl = src.yl; +} + + + /*** Buffer operations ***/ + +static int +null_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + return GFX_OK; +} + +static int +null_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + return GFX_OK; +} + + + /*** Mouse pointer operations ***/ + + +static int +null_set_pointer(struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + return GFX_OK; +} + + + /*** Palette operations ***/ + +static int +null_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) +{ + return GFX_OK; +} + + + /*** Event management ***/ + +static sci_event_t +null_get_event(struct _gfx_driver *drv) +{ + sci_event_t input; + + input.type = SCI_EVT_NONE; + + return input; +} + + +static int +null_usec_sleep(struct _gfx_driver *drv, long usecs) +{ + if (debug_sleep) + sciprintf("[GFX-NULL] Sleeping %ld usecs...\n", usecs); + return GFX_OK; +} + +gfx_driver_t +gfx_driver_null = { + "null", + "0.1", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, 0, + GFX_CAPABILITY_WINDOWED, + GFX_DEBUG_POINTER | GFX_DEBUG_UPDATES | GFX_DEBUG_PIXMAPS | GFX_DEBUG_BASIC, + null_set_parameter, + null_init_specific, + null_init, + null_exit, + null_draw_line, + null_draw_filled_rect, + null_register_pixmap, + null_unregister_pixmap, + null_draw_pixmap, + null_grab_pixmap, + null_update, + null_set_static_buffer, + null_set_pointer, + null_set_palette, + null_get_event, + null_usec_sleep, + NULL +}; diff --git a/engines/sci/gfx/drivers/scummvm_driver.cpp b/engines/sci/gfx/drivers/scummvm_driver.cpp new file mode 100644 index 0000000000..dc38cb58e4 --- /dev/null +++ b/engines/sci/gfx/drivers/scummvm_driver.cpp @@ -0,0 +1,543 @@ +#include <common/scummsys.h> +#include <common/system.h> +#include <common/events.h> + +#include "gfx_driver.h" +#include "gfx_tools.h" + +struct _scummvm_driver_state { + gfx_pixmap_t *priority[2]; + byte *visual[3]; + byte *pointer_data[2]; + int xsize, ysize; + //int buckystate; + bool update_screen; + bool update_mouse; +}; + +#define S ((struct _scummvm_driver_state *)(drv->state)) + +static int +scummvm_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + int i; + + if (!drv->state) // = S + drv->state = new _scummvm_driver_state; + if (!drv->state) + return GFX_FATAL; + + S->xsize = xfact * 320; + S->ysize = yfact * 200; + + S->pointer_data[0] = NULL; + S->pointer_data[1] = NULL; + //S->buckystate = 0; + + for (i = 0; i < 2; i++) { + S->priority[i] = gfx_pixmap_alloc_index_data(gfx_new_pixmap(S->xsize, S->ysize, GFX_RESID_NONE, -i, -777)); + if (!S->priority[i]) { + printf("Out of memory: Could not allocate priority maps! (%dx%d)\n", + S->xsize, S->ysize); + return GFX_FATAL; + } + } + // create the visual buffers + for (i = 0; i < 3; i++) { + S->visual[i] = NULL; + S->visual[i] = new byte[S->xsize * S->ysize]; + if (!S->visual[i]) { + printf("Out of memory: Could not allocate visual buffers! (%dx%d)\n", + S->xsize, S->ysize); + return GFX_FATAL; + } + memset(S->visual[i], 0, S->xsize * S->ysize); + } + + drv->mode = gfx_new_mode(xfact, yfact, bytespp, + 0, 0, 0, 0, + 0, 0, 0, 0, 256, 0); + + return GFX_OK; +} + +static int +scummvm_init(struct _gfx_driver *drv) +{ + return scummvm_init_specific(drv, 1, 1, GFX_COLOR_MODE_INDEX); +} + +static void +scummvm_exit(struct _gfx_driver *drv) +{ + int i; + if (S) { + for (i = 0; i < 2; i++) { + gfx_free_pixmap(drv, S->priority[i]); + S->priority[i] = NULL; + } + + for (i = 0; i < 3; i++) { + delete[] S->visual[i]; + S->visual[i] = NULL; + } + + for (i = 0; i < 2; i++) + if (S->pointer_data[i]) { + delete[] S->pointer_data[i]; + S->pointer_data[i] = NULL; + } + + delete S; + } +} + + +// Drawing operations + +/* This code shamelessly lifted from the SDL_gfxPrimitives package */ +static void +lineColor2(byte *dst, int16 x1, int16 y1, int16 x2, int16 y2, uint32 color) +{ + int pixx, pixy; + int x,y; + int dx,dy; + int sx,sy; + int swaptmp; + uint8 *pixel; + + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = 1; + pixy = 320; + pixel = ((uint8*)dst) + pixx * (int)x1 + pixy * (int)y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; dx = dy; dy = swaptmp; + swaptmp = pixx; pixx = pixy; pixy = swaptmp; + } + + /* Draw */ + x=0; + y=0; + for(; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; pixel += pixy; + } + } +} + +static int +scummvm_draw_line(struct _gfx_driver *drv, point_t start, point_t end, + gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + uint32 scolor = color.visual.global_index; + int xsize = S->xsize; + int ysize = S->ysize; + + if (color.mask & GFX_MASK_VISUAL) { + point_t nstart, nend; + + nstart.x = start.x; + nstart.y = start.y; + nend.x = end.x; + nend.y = end.y; + + if (nstart.x < 0) + nstart.x = 0; + if (nend.x < 0) + nstart.x = 0; + if (nstart.y < 0) + nstart.y = 0; + if (nend.y < 0) + nend.y = 0; + if (nstart.x > xsize) + nstart.x = xsize; + if (nend.x >= xsize) + nend.x = xsize -1; + if (nstart.y > ysize) + nstart.y = ysize; + if (nend.y >= ysize) + nend.y = ysize -1; + + lineColor2(S->visual[1], (int16)nstart.x, (int16)nstart.y, + (int16)nend.x, (int16)nend.y, scolor); + + if (color.mask & GFX_MASK_PRIORITY) { + gfx_draw_line_pixmap_i(S->priority[0], nstart, nend, + color.priority); + } + } + + return GFX_OK; +} + +static int +scummvm_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (color1.mask & GFX_MASK_VISUAL) { + for (int i = rect.y; i < rect.y + rect.yl; i++) { + memset(S->visual[1] + i * S->xsize + rect.x, color1.visual.global_index, rect.xl); + } + } + + if (color1.mask & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(S->priority[0], rect, color1.priority); + + return GFX_OK; +} + + +// Pixmap operations + +static int +scummvm_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + int bufnr = (buffer == GFX_BUFFER_STATIC)? 2:1; + int pribufnr = bufnr -1; + + if (dest.xl != src.xl || dest.yl != src.yl) { + printf("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n", + src.xl, src.yl, dest.xl, dest.yl); + return GFX_ERROR; + } + + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, + S->visual[bufnr], S->xsize, + S->priority[pribufnr]->index_data, + S->priority[pribufnr]->index_xl, 1, 0); + + return GFX_OK; +} + +static int +scummvm_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + if (src.x < 0 || src.y < 0) { + printf("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) { + printf("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + + switch (map) { + + case GFX_MASK_VISUAL: + pxm->xl = src.xl; + pxm->yl = src.yl; + for (int i = 0; i < src.yl; i++) { + memcpy(pxm->data + i * src.xl, S->visual[1] + (i + src.y) * S->xsize + src.x, src.xl); + } + break; + + case GFX_MASK_PRIORITY: + printf("FIXME: priority map grab not implemented yet!\n"); + break; + + default: + printf("Attempt to grab pixmap from invalid map 0x%02x\n", map); + return GFX_ERROR; + } + + return GFX_OK; +} + + +// Buffer operations + +static int +scummvm_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + //TODO + int data_source = (buffer == GFX_BUFFER_BACK)? 2 : 1; + int data_dest = data_source - 1; + + /* + if (src.x != dest.x || src.y != dest.y) { + printf("Updating %d (%d,%d)(%dx%d) to (%d,%d) on %d\n", buffer, src.x, src.y, + src.xl, src.yl, dest.x, dest.y, data_dest); + } else { + printf("Updating %d (%d,%d)(%dx%d) to %d\n", buffer, src.x, src.y, src.xl, src.yl, data_dest); + } + */ + + switch (buffer) { + case GFX_BUFFER_BACK: + //memcpy(S->visual[data_dest], S->visual[data_source], + // S->xsize * S->ysize); + for (int i = 0; i < src.yl; i++) { + memcpy(S->visual[data_dest] + (dest.y + i) * S->xsize + dest.x, + S->visual[data_source] + (src.y + i) * S->xsize + src.x, src.xl); + } + + if ((src.x == dest.x) && (src.y == dest.y)) + gfx_copy_pixmap_box_i(S->priority[0], S->priority[1], src); + break; + case GFX_BUFFER_FRONT: + memcpy(S->visual[data_dest], S->visual[data_source], + S->xsize * S->ysize); + + g_system->copyRectToScreen(S->visual[data_dest] + src.x + src.y * S->xsize, + S->xsize, dest.x, dest.y, src.xl, src.yl); + /* + g_system->copyRectToScreen(S->visual[data_dest], + S->xsize, 0, 0, S->xsize, S->ysize); + */ + S->update_screen = true; + break; + default: + GFXERROR("Invalid buffer %d in update!\n", buffer); + return GFX_ERROR; + } + + + return GFX_OK; +} + +static int +scummvm_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + memcpy(S->visual[2], pic->data, S->xsize * S->ysize); + /*gfx_crossblit_pixmap(drv->mode, pic, 0, rect, rect, + S->visual[2], S->xsize, + S->priority[1]->index_data, + S->priority[1]->index_xl, 1, 0);*/ + + gfx_copy_pixmap_box_i(S->priority[1], priority, gfx_rect(0, 0, S->xsize, S->ysize)); + + return GFX_OK; +} + + +// Mouse pointer operations + +static int +scummvm_set_pointer(struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + if (pointer == NULL) { + g_system->showMouse(false); + } else { + g_system->setMouseCursor(pointer->index_data, pointer->xl, pointer->yl, pointer->xoffset, pointer->yoffset); + g_system->showMouse(true); + } + + // Pointer pixmap or mouse position has changed + S->update_mouse = true; + return GFX_OK; +} + + +// Palette operations + +static int +scummvm_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) +{ + byte color[] = {red, green, blue, 255}; + g_system->setPalette(color, index, 1); + return GFX_OK; +} + + +// Event management + +static sci_event_t +scummvm_get_event(struct _gfx_driver *drv) +{ + sci_event_t input; + input.type = SCI_EVT_NONE; + + Common::EventManager *em = g_system->getEventManager(); + Common::Event ev; + + bool found = em->pollEvent(ev); + Common::Point p = ev.mouse; + + // Don't generate events for mouse movement + while (found && ev.type == Common::EVENT_MOUSEMOVE) { + found = em->pollEvent(ev); + p = ev.mouse; + drv->pointer_x = p.x; + drv->pointer_y = p.y; + S->update_mouse = true; + } + + // Update the screen here, since it's called very often + if (S->update_mouse) + g_system->warpMouse(drv->pointer_x, drv->pointer_y); + if (S->update_screen || S->update_mouse) { + g_system->updateScreen(); + S->update_screen = false; + S->update_mouse = false; + } + + if (found && !ev.synthetic && ev.type != Common::EVENT_MOUSEMOVE) { + int modifiers; + if (ev.type == Common::EVENT_KEYDOWN) + modifiers = ev.kbd.flags; + else + modifiers = em->getModifierState(); + + input.buckybits = + ((modifiers & Common::KBD_ALT) ? SCI_EVM_ALT : 0) | + ((modifiers & Common::KBD_CTRL) ? SCI_EVM_CTRL : 0) | + ((modifiers & Common::KBD_SHIFT) ? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0); + //TODO: SCI_EVM_SCRLOCK SCI_EVM_NUMLOCK SCI_EVM_CAPSLOCK SCI_EVM_INSERT + + switch (ev.type) { + // Keyboard events + case Common::EVENT_KEYDOWN: + input.data = ev.kbd.keycode; + input.character = ev.kbd.ascii; + + if (!(input.data & 0xFF00)) { + // Directly accept most common keys without conversion + input.type = SCI_EVT_KEYBOARD; + if (input.data == Common::KEYCODE_TAB) { + // Tab + input.type = SCI_EVT_KEYBOARD; + input.data = SCI_K_TAB; + if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT)) + input.character = SCI_K_SHIFT_TAB; + else + input.character = SCI_K_TAB; + } + } else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) { + // F1-F10 + input.type = SCI_EVT_KEYBOARD; + // SCI_K_F1 == 59 << 8 + // SCI_K_SHIFT_F1 == 84 << 8 + input.data = (input.data - Common::KEYCODE_F1 + SCI_K_F1) << 8; + if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT)) + input.character = input.data + ((SCI_K_SHIFT_F1 - SCI_K_F1) << 8); + else + input.character = input.data; + } else { + // Special keys that need conversion + input.type = SCI_EVT_KEYBOARD; + switch (ev.kbd.keycode) { + case Common::KEYCODE_UP: + input.data = SCI_K_UP; + break; + case Common::KEYCODE_DOWN: + input.data = SCI_K_DOWN; + break; + case Common::KEYCODE_RIGHT: + input.data = SCI_K_RIGHT; + break; + case Common::KEYCODE_LEFT: + input.data = SCI_K_LEFT; + break; + case Common::KEYCODE_INSERT: + input.data = SCI_K_INSERT; + break; + case Common::KEYCODE_HOME: + input.data = SCI_K_HOME; + break; + case Common::KEYCODE_END: + input.data = SCI_K_END; + break; + case Common::KEYCODE_PAGEUP: + input.data = SCI_K_PGUP; + break; + case Common::KEYCODE_PAGEDOWN: + input.data = SCI_K_PGDOWN; + break; + case Common::KEYCODE_DELETE: + input.data = SCI_K_DELETE; + break; + //TODO: SCI_K_CENTER + default: + input.type = SCI_EVT_NONE; + break; + } + input.character = input.data; + } + break; + + // Mouse events + case Common::EVENT_LBUTTONDOWN: + input.type = SCI_EVT_MOUSE_PRESS; + input.data = 1; + drv->pointer_x = p.x; + drv->pointer_y = p.y; + break; + case Common::EVENT_RBUTTONDOWN: + input.type = SCI_EVT_MOUSE_PRESS; + input.data = 2; + drv->pointer_x = p.x; + drv->pointer_y = p.y; + break; + case Common::EVENT_LBUTTONUP: + input.type = SCI_EVT_MOUSE_RELEASE; + input.data = 1; + drv->pointer_x = p.x; + drv->pointer_y = p.y; + break; + case Common::EVENT_RBUTTONUP: + input.type = SCI_EVT_MOUSE_RELEASE; + input.data = 2; + drv->pointer_x = p.x; + drv->pointer_y = p.y; + break; + + // Misc events + case Common::EVENT_QUIT: + input.type = SCI_EVT_QUIT; + break; + } + } + + return input; +} + +static int +scummvm_usec_sleep(struct _gfx_driver *drv, long usecs) +{ + g_system->delayMillis(usecs/1000); + return GFX_OK; +} + +gfx_driver_t +gfx_driver_scummvm = { + "ScummVM", + "0.1", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, 0, + GFX_CAPABILITY_MOUSE_POINTER | GFX_CAPABILITY_COLOR_MOUSE_POINTER | GFX_CAPABILITY_MOUSE_SUPPORT | GFX_CAPABILITY_FINE_LINES | GFX_CAPABILITY_WINDOWED, + 0, + NULL, + scummvm_init_specific, + scummvm_init, + scummvm_exit, + scummvm_draw_line, + scummvm_draw_filled_rect, + NULL, + NULL, + scummvm_draw_pixmap, + scummvm_grab_pixmap, + scummvm_update, + scummvm_set_static_buffer, + scummvm_set_pointer, + scummvm_set_palette, + scummvm_get_event, + scummvm_usec_sleep, + NULL +}; diff --git a/engines/sci/gfx/drivers/sdl_driver.c b/engines/sci/gfx/drivers/sdl_driver.c new file mode 100644 index 0000000000..e52cea9db5 --- /dev/null +++ b/engines/sci/gfx/drivers/sdl_driver.c @@ -0,0 +1,1235 @@ +/*************************************************************************** + sdl_driver.c Copyright (C) 2001 Solomon Peachy + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + Solomon Peachy <pizza@shaftnet.org> + +***************************************************************************/ + +/* set optimisations for Win32: */ +/* g on: enable global optimizations */ +/* t on: use fast code */ +/* y on: suppress creation of frame pointers on stack */ +/* s off: disable minimize size code */ +#ifdef _WIN32 +# include <memory.h> +# ifndef SATISFY_PURIFY +# pragma optimize( "s", off ) +# pragma optimize( "gty", on ) +# pragma intrinsic( memcpy, memset ) +# endif +#endif + +#include <sci_memory.h> + +#include <gfx_driver.h> +#ifdef HAVE_SDL +#include <gfx_tools.h> + +#if !defined(_MSC_VER) +# include <sys/time.h> +#endif + +#include <SDL_config.h> +#undef HAVE_ICONV +#undef HAVE_ICONV_H +#undef HAVE_ALLOCA_H + +#include <SDL.h> + +#ifndef SDL_DISABLE +# define SDL_DISABLE 0 +#endif +#ifndef SDL_ALPHA_OPAQUE +# define SDL_ALPHA_OPAQUE 255 +#endif + +#define SCI_SDL_HANDLE_NORMAL 0 +#define SCI_SDL_HANDLE_GRABBED 1 + +#define SCI_SDL_SWAP_CTRL_CAPS (1 << 0) +#define SCI_SDL_FULLSCREEN (1 << 2) + +static int +sdl_usec_sleep(struct _gfx_driver *drv, long usecs); + +static int flags = 0; + +struct _sdl_state { + int used_bytespp; + gfx_pixmap_t *priority[2]; + SDL_Color colors[256]; + SDL_Surface *visual[3]; + SDL_Surface *primary; + int buckystate; + byte *pointer_data[2]; + int alpha_mask; + int SDL_alpha_shift; + int SDL_alpha_loss; +}; + +#define S ((struct _sdl_state *)(drv->state)) + +#define XFACT drv->mode->xfact +#define YFACT drv->mode->yfact + +#define DEBUGB if (drv->debug_flags & GFX_DEBUG_BASIC && ((debugline = __LINE__))) sdlprintf +#define DEBUGU if (drv->debug_flags & GFX_DEBUG_UPDATES && ((debugline = __LINE__))) sdlprintf +#define DEBUGPXM if (drv->debug_flags & GFX_DEBUG_PIXMAPS && ((debugline = __LINE__))) sdlprintf +#define DEBUGPTR if (drv->debug_flags & GFX_DEBUG_POINTER && ((debugline = __LINE__))) sdlprintf +#define SDLERROR if ((debugline = __LINE__)) sdlprintf +#define SDLPRINTF if ((debugline = __LINE__)) sdlprintf + +#define ALPHASURFACE (S->used_bytespp == 4) + +static int debugline = 0; + +static void +sdlprintf(const char *fmt, ...) +{ + va_list argp; + fprintf(stderr,"GFX-SDL %d:", debugline); + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); +} + +static int +sdl_init_libsdl(struct _gfx_driver *drv) +{ + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)) { + DEBUGB("Failed to init SDL\n"); + return -1; + } + + SDL_EnableUNICODE(SDL_ENABLE); + + return 0; +} + +static int +sdl_alloc_primary(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + int i = SDL_HWSURFACE | SDL_HWPALETTE; + + if (flags & SCI_SDL_FULLSCREEN) { + i |= SDL_FULLSCREEN; + } + + S->primary = SDL_SetVideoMode(xfact * 320, yfact * 200, bytespp << 3, i); + + if (!S->primary) { + SDLERROR("Could not set up a primary SDL surface!\n"); + return -1; + } + + if (S->primary->format->BytesPerPixel != bytespp) { + SDLERROR("Could not set up a primary SDL surface of depth %d bpp!\n",bytespp); + S->primary = NULL; + return -1; + } + + /* Set windowed flag */ + if (S->primary->flags & SDL_FULLSCREEN) + drv->capabilities &= ~GFX_CAPABILITY_WINDOWED; + else + drv->capabilities |= GFX_CAPABILITY_WINDOWED; + + return 0; +} + +static int +sdl_blit_surface(gfx_driver_t *drv, + SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect) +{ + if (S->used_bytespp == 1) { + SDL_SetColors(src, S->colors, 0, 256); + SDL_SetColors(dst, S->colors, 0, 256); + } + return SDL_BlitSurface(src, srcrect, dst, dstrect); +} + +static int +sdl_set_parameter(struct _gfx_driver *drv, char *attribute, char *value) +{ + if (!strncmp(attribute, "swap_ctrl_caps", 14) || + !strncmp(attribute, "swap_caps_ctrl", 14)) { + if (string_truep(value)) + flags |= SCI_SDL_SWAP_CTRL_CAPS; + else + flags &= ~SCI_SDL_SWAP_CTRL_CAPS; + return GFX_OK; + } + + if (!strncmp(attribute, "fullscreen", 10)) { + if (string_truep(value)) + flags |= SCI_SDL_FULLSCREEN; + else + flags &= ~SCI_SDL_FULLSCREEN; + + return GFX_OK; + } + + + SDLERROR("Attempt to set sdl parameter \"%s\" to \"%s\"\n", attribute, value); + return GFX_ERROR; +} + +static int +sdl_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + int red_shift, green_shift, blue_shift, alpha_shift; + int xsize = xfact * 320; + int ysize = yfact * 200; + + int i; + +#ifdef _MSC_VER /* Win32 doesn't support mouse pointers greater than 64x64 */ + if (xfact > 2 || yfact > 2) + drv->capabilities &= ~GFX_CAPABILITY_MOUSE_POINTER; +#endif +#if defined(__BEOS__) || defined(__amigaos4__) /* BeOS has been reported not to work well with the mouse pointer at all */ + drv->capabilities &= ~GFX_CAPABILITY_MOUSE_POINTER; +#endif + + if (sdl_init_libsdl(drv)) + return GFX_FATAL; + + if (!drv->state /* = S */) + drv->state = sci_malloc(sizeof(struct _sdl_state)); + if (!drv->state) + return GFX_FATAL; + + if (xfact < 1 || yfact < 1 || bytespp < 1 || bytespp > 4) { + SDLERROR("Internal error: Attempt to open window w/ scale factors (%d,%d) and bpp=%d!\n", + xfact, yfact, bytespp); + } + + if (sdl_alloc_primary(drv, xfact, yfact, bytespp)) + return GFX_FATAL; + + S->used_bytespp = bytespp; + + printf("Using primary SDL surface of %d,%d @%d bpp\n", + xsize, ysize, bytespp << 3); + + /* if (S->primary->format->BytesPerPixel == 4) { + S->alpha_mask = 0xff000000; + S->SDL_alpha_shift = 24; + S->SDL_alpha_loss = 0; + alpha_shift = 0; + } else { */ + S->alpha_mask = S->primary->format->Amask; + S->SDL_alpha_shift = S->primary->format->Ashift; + S->SDL_alpha_loss = S->primary->format->Aloss; + alpha_shift = bytespp << 3; + /* }*/ + + /* clear palette */ + for (i = 0; i < 256; i++) { + S->colors[i].r = (i & 1)? 0 : 0; + S->colors[i].g = (i & 2)? 0 : 0; + S->colors[i].b = (i & 4)? 0 : 0; + } + if (bytespp == 1) + SDL_SetColors(S->primary, S->colors, 0, 256); + + /* create an input event mask */ + SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE); + SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE); + SDL_EventState(SDL_KEYUP, SDL_IGNORE); + + SDL_WM_SetCaption("FreeSCI", "freesci"); + + SDL_ShowCursor(SDL_DISABLE); + S->pointer_data[0] = NULL; + S->pointer_data[1] = NULL; + + S->buckystate = 0; + + if (bytespp == 1) { + red_shift = green_shift = blue_shift = alpha_shift = 0; + } else { + red_shift = 24 - S->primary->format->Rshift + S->primary->format->Rloss; + green_shift = 24 - S->primary->format->Gshift + S->primary->format->Gloss; + blue_shift = 24 - S->primary->format->Bshift + S->primary->format->Bloss; + } + + printf("%08x %08x %08x %08x %d/%d=%d %d/%d=%d %d/%d=%d %d/%d=%d\n", + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask, + /* S->primary->format->Amask,*/ + S->primary->format->Rshift, + S->primary->format->Rloss, + red_shift, + S->primary->format->Gshift, + S->primary->format->Gloss, + green_shift, + S->primary->format->Bshift, + S->primary->format->Bloss, + blue_shift, + S->SDL_alpha_shift, + S->SDL_alpha_loss, + /* + S->primary->format->Ashift, + S->primary->format->Aloss, */ + alpha_shift); + + for (i = 0; i < 2; i++) { + S->priority[i] = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xsize, ysize, GFX_RESID_NONE, -i, -777)); + if (!S->priority[i]) { + SDLERROR("Out of memory: Could not allocate priority maps! (%dx%d)\n", + xsize, ysize); + return GFX_FATAL; + } + } + + /* create the visual buffers */ + for (i = 0; i < 3; i++) { + S->visual[i] = SDL_CreateRGBSurface(SDL_SRCALPHA, + /* SDL_HWSURFACE | SDL_SWSURFACE, */ + xsize, ysize, + bytespp << 3, + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask); + if (S->visual[i] == NULL) { + SDLERROR("Could not set up visual buffers!\n"); + return GFX_FATAL; + } + + if (ALPHASURFACE) + SDL_SetAlpha(S->visual[i],SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + + if (SDL_FillRect(S->primary, NULL, SDL_MapRGB(S->primary->format, 0,0,0))) + SDLERROR("Couldn't fill backbuffer!\n"); + } + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + drv->mode = gfx_new_mode(xfact, yfact, bytespp, + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask, + red_shift, green_shift, blue_shift, alpha_shift, + (bytespp == 1)? 256 : 0, 0); /*GFX_MODE_FLAG_REVERSE_ALPHA);*/ + + return GFX_OK; +} + +static int +sdl_init(struct _gfx_driver *drv) +{ + int depth = 0; + int i; + + if (sdl_init_libsdl(drv)) + return GFX_FATAL; + + i = SDL_HWSURFACE | SDL_HWPALETTE; + if (flags & SCI_SDL_FULLSCREEN) { + i |= SDL_FULLSCREEN; + } + + depth = SDL_VideoModeOK(640,400, 32, i); + if (depth && (! sdl_init_specific(drv, 2, 2, depth >> 3 ))) + return GFX_OK; + + DEBUGB("Failed to find visual!\n"); + return GFX_FATAL; +} + +static void +sdl_exit(struct _gfx_driver *drv) +{ + int i; + if (S) { + for (i = 0; i < 2; i++) { + gfx_free_pixmap(drv, S->priority[i]); + S->priority[i] = NULL; + } + + for (i = 0; i < 3; i++) { + SDL_FreeSurface(S->visual[i]); + S->visual[i] = NULL; + } + + SDL_FreeCursor(SDL_GetCursor()); + + for (i = 0; i < 2; i++) + if (S->pointer_data[i]) { + free(S->pointer_data[i]); + S->pointer_data[i] = NULL; + } + + } + + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + if (!SDL_WasInit(SDL_INIT_EVERYTHING)) { + SDLPRINTF("No active SDL subsystems found.. shutting down SDL\n"); + SDL_Quit(); + } +} + +static void +toggle_fullscreen(struct _gfx_driver *drv) +{ + rect_t src; + point_t dest; + + flags ^= SCI_SDL_FULLSCREEN; + if (sdl_alloc_primary(drv, XFACT, YFACT, drv->mode->bytespp)) { + SDLERROR("failed to switch to full-screen mode\n"); + /* Failed to set mode, revert to previous */ + flags ^= SCI_SDL_FULLSCREEN; + + if (sdl_alloc_primary(drv, XFACT, YFACT, drv->mode->bytespp)) { + /* This shouldn't happen... */ + SDLERROR("failed to revert to previous display mode\n"); + exit(-1); + } + } + + src.x = 0; + src.y = 0; + src.xl = XFACT * 320; + src.yl = YFACT * 200; + dest.x = 0; + dest.y = 0; + + drv->update(drv, src, dest, GFX_BUFFER_FRONT); +} + +/*** Drawing operations ***/ + +static Uint32 +sdl_map_color(gfx_driver_t *drv, gfx_color_t color) +{ + int opacity = 255 - color.alpha; + + if (drv->mode->palette && opacity < 255) { + if (opacity < 127) + opacity = 0; + else + opacity = 255; + + } + + if (drv->mode->palette) + return color.visual.global_index; + + return SDL_MapRGBA(S->visual[0]->format, + color.visual.r, + color.visual.g, + color.visual.b, + opacity); +} + +/* This code shamelessly lifted from the SDL_gfxPrimitives package */ +static void lineColor2(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color) +{ + int pixx, pixy; + int x,y; + int dx,dy; + int sx,sy; + int swaptmp; + Uint8 *pixel; + + dx = x2 - x1; + dy = y2 - y1; + sx = (dx >= 0) ? 1 : -1; + sy = (dy >= 0) ? 1 : -1; + + dx = sx * dx + 1; + dy = sy * dy + 1; + pixx = dst->format->BytesPerPixel; + pixy = dst->pitch; + pixel = ((Uint8*)dst->pixels) + pixx * (int)x1 + pixy * (int)y1; + pixx *= sx; + pixy *= sy; + if (dx < dy) { + swaptmp = dx; dx = dy; dy = swaptmp; + swaptmp = pixx; pixx = pixy; pixy = swaptmp; + } + +/* Draw */ + x=0; + y=0; + switch(dst->format->BytesPerPixel) { + case 1: + for(; x < dx; x++, pixel += pixx) { + *pixel = color; + y += dy; + if (y >= dx) { + y -= dx; pixel += pixy; + } + } + break; + case 2: + for (; x < dx; x++, pixel += pixx) { + *(Uint16*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 3: + for(; x < dx; x++, pixel += pixx) { + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + pixel[0] = (color >> 16) & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = color & 0xff; + } else { + pixel[0] = color & 0xff; + pixel[1] = (color >> 8) & 0xff; + pixel[2] = (color >> 16) & 0xff; + } + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + case 4: + for(; x < dx; x++, pixel += pixx) { + *(Uint32*)pixel = color; + y += dy; + if (y >= dx) { + y -= dx; + pixel += pixy; + } + } + break; + default: + fprintf(stderr, "invalid depth\n"); + } + +} + +static int +sdl_draw_line(struct _gfx_driver *drv, point_t start, point_t end, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + Uint32 scolor; + int xfact = (line_mode == GFX_LINE_MODE_FINE)? 1: XFACT; + int yfact = (line_mode == GFX_LINE_MODE_FINE)? 1: YFACT; + int xsize = S->visual[1]->w; + int ysize = S->visual[1]->h; + + if (color.mask & GFX_MASK_VISUAL) { + int xc, yc; + point_t nstart, nend; + + scolor = sdl_map_color(drv, color); + + for (xc = 0; xc < xfact; xc++) + for (yc = 0; yc < yfact; yc++) { + nstart.x = start.x + xc; + nstart.y = start.y + yc; + nend.x = end.x + xc; + nend.y = end.y + yc; + + if (nstart.x < 0) + nstart.x = 0; + if (nend.x < 0) + nstart.x = 0; + if (nstart.y < 0) + nstart.y = 0; + if (nend.y < 0) + nend.y = 0; + if (nstart.x > xsize) + nstart.x = xsize; + if (nend.x >= xsize) + nend.x = xsize -1; + if (nstart.y > ysize) + nstart.y = ysize; + if (nend.y >= ysize) + nend.y = ysize -1; + +#if 0 + fprintf(stderr, "draw %d %d to %d %d %08x %d %d\n", nstart.x, + nstart.y, nend.x, nend.yl, scolor, xsize, ysize); +#endif + + SDL_LockSurface(S->visual[1]); + lineColor2(S->visual[1], (Sint16)nstart.x, (Sint16)nstart.y, + (Sint16)nend.x, (Sint16)nend.y, scolor); + SDL_UnlockSurface(S->visual[1]); + + if (color.mask & GFX_MASK_PRIORITY) { + gfx_draw_line_pixmap_i(S->priority[0], nstart, nend, + color.priority); + } + } + } + + return GFX_OK; +} + +static int +sdl_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + Uint32 color; + SDL_Rect srect; + + if (color1.mask & GFX_MASK_VISUAL) { + color = sdl_map_color(drv, color1); + + srect.x = rect.x; + srect.y = rect.y; + srect.w = rect.xl; + srect.h = rect.yl; + + if (SDL_FillRect(S->visual[1], &srect, color)) + SDLERROR("Can't fill rect"); + } + + if (color1.mask & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(S->priority[0], rect, color1.priority); + + return GFX_OK; +} + +/*** Pixmap operations ***/ + +static int +sdl_register_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + SDL_Surface *reg_surface; + + if (pxm->internal.info) { + SDLERROR("Attempt to register pixmap twice!\n"); + return GFX_ERROR; + } + + reg_surface = + SDL_CreateRGBSurfaceFrom(pxm->data, pxm->xl, pxm->yl, + S->used_bytespp << 3, + S->used_bytespp * pxm->xl, + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask); + + if (ALPHASURFACE) + SDL_SetAlpha(reg_surface, SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + + pxm->internal.handle = SCI_SDL_HANDLE_NORMAL; + + DEBUGPXM("Registered surface %d/%d/%d at %p (%dx%d)\n", pxm->ID, pxm->loop, pxm->cel, + pxm->internal.info, pxm->xl, pxm->yl); + + pxm->internal.info = reg_surface; + + return GFX_OK; +} + +static int +sdl_unregister_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + DEBUGPXM("Freeing surface %d/%d/%d at %p\n", pxm->ID, pxm->loop, pxm->cel, + pxm->internal.info); + + if (!pxm->internal.info) { + SDLERROR("Attempt to unregister pixmap twice!\n"); + return GFX_ERROR; + } + + SDL_FreeSurface((SDL_Surface *) pxm->internal.info); + pxm->internal.info = NULL; + if (pxm->internal.handle != SCI_SDL_HANDLE_GRABBED) + free(pxm->data); + pxm->data = NULL; + return GFX_OK; +} + +static int +sdl_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + int bufnr = (buffer == GFX_BUFFER_STATIC)? 2:1; + int pribufnr = bufnr -1; + + SDL_Surface *temp; + SDL_Rect srect; + SDL_Rect drect; + + if (dest.xl != src.xl || dest.yl != src.yl) { + SDLERROR("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n", + src.xl, src.yl, dest.xl, dest.yl); + return GFX_ERROR; + } + + srect.x = src.x; + srect.y = src.y; + srect.w = src.xl; + srect.h = src.yl; + drect.x = dest.x; + drect.y = dest.y; + drect.w = dest.xl; + drect.h = dest.yl; + + DEBUGU("Drawing %d (%d,%d)(%dx%d) onto (%d,%d)\n", pxm, srect.x, srect.y, + srect.w, srect.h, drect.x, drect.y); + + if (pxm->internal.handle == SCI_SDL_HANDLE_GRABBED) { + if (sdl_blit_surface(drv, (SDL_Surface *)pxm->internal.info, &srect , + S->visual[bufnr], &drect )) { + SDLERROR("blt failed"); + return GFX_ERROR; + } + return GFX_OK; + } + + temp = SDL_CreateRGBSurface(SDL_SWSURFACE, drect.w, drect.h, + S->used_bytespp << 3, + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask); + + if (ALPHASURFACE) + SDL_SetAlpha(temp, SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + + if (!temp) { + SDLERROR("Failed to allocate SDL surface"); + return GFX_ERROR; + } + + srect.x = dest.x; + srect.y = dest.y; + drect.x = 0; + drect.y = 0; + + if(sdl_blit_surface(drv, S->visual[bufnr], &srect, temp, &drect)) + SDLERROR("blt failed"); + + SDL_LockSurface(temp); + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, + (byte *) temp->pixels, temp->pitch, + S->priority[pribufnr]->index_data, + S->priority[pribufnr]->index_xl, 1, + GFX_CROSSBLIT_FLAG_DATA_IS_HOMED); + SDL_UnlockSurface(temp); + + srect.x = 0; + srect.y = 0; + drect.x = dest.x; + drect.y = dest.y; + + if(sdl_blit_surface(drv, temp, &srect, S->visual[bufnr], &drect)) + SDLERROR("blt failed"); + + SDL_FreeSurface(temp); + return GFX_OK; +} + +static int +sdl_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + + + if (src.x < 0 || src.y < 0) { + SDLERROR("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) { + SDLERROR("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + switch (map) { + + case GFX_MASK_VISUAL: { + SDL_Rect srect, drect; + SDL_Surface *temp; + + pxm->xl = src.xl; + pxm->yl = src.yl; + temp = SDL_CreateRGBSurface(SDL_SWSURFACE, src.xl, src.yl, + S->used_bytespp << 3, + S->primary->format->Rmask, + S->primary->format->Gmask, + S->primary->format->Bmask, + S->alpha_mask); + + if (!temp) { + SDLERROR("Failed to allocate SDL surface"); + return GFX_ERROR; + } + + if (SDL_MUSTLOCK(temp)) + sciprintf("Warning: SDL surface for pixmap grabbing requires locking\n"); + + if (ALPHASURFACE) + SDL_SetAlpha(temp, SDL_SRCALPHA,SDL_ALPHA_OPAQUE); + + srect.x = src.x; + srect.y = src.y; + srect.w = src.xl; + srect.h = src.yl; + drect.x = 0; + drect.y = 0; + drect.w = src.xl; + drect.h = src.yl; + + if (sdl_blit_surface(drv, S->visual[1], &srect, temp, &drect)) + SDLERROR("grab_pixmap: grab blit failed!\n"); + + pxm->internal.info = temp; + pxm->internal.handle = SCI_SDL_HANDLE_GRABBED; + pxm->flags |= GFX_PIXMAP_FLAG_INSTALLED | GFX_PIXMAP_FLAG_EXTERNAL_PALETTE | GFX_PIXMAP_FLAG_PALETTE_SET; + free(pxm->data); + pxm->data = (byte *) temp->pixels; + + DEBUGPXM("Grabbed surface %p (%dx%d)(%dx%d)\n", + pxm->internal.info, srect.x, srect.y, pxm->xl, pxm->yl); + + break; + } + + case GFX_MASK_PRIORITY: + SDLERROR("FIXME: priority map grab not implemented yet!\n"); + break; + + default: + SDLERROR("Attempt to grab pixmap from invalid map 0x%02x\n", map); + return GFX_ERROR; + } + + return GFX_OK; +} + + + /*** Buffer operations ***/ + +static int +sdl_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + int data_source = (buffer == GFX_BUFFER_BACK)? 2 : 1; + int data_dest = data_source - 1; + SDL_Rect srect, drect; + + if (src.x != dest.x || src.y != dest.y) { + DEBUGU("Updating %d (%d,%d)(%dx%d) to (%d,%d) on %d\n", buffer, src.x, src.y, + src.xl, src.yl, dest.x, dest.y, data_dest); + } else { + DEBUGU("Updating %d (%d,%d)(%dx%d) to %d\n", buffer, src.x, src.y, src.xl, src.yl, data_dest); + } + + srect.x = src.x; + srect.y = src.y; + srect.w = src.xl; + srect.h = src.yl; + drect.x = dest.x; + drect.y = dest.y; + drect.w = src.xl; + drect.h = src.yl; + + switch (buffer) { + case GFX_BUFFER_BACK: + if (sdl_blit_surface(drv, S->visual[data_source], &srect, + S->visual[data_dest], &drect)) + SDLERROR("surface update failed!\n"); + + if ((src.x == dest.x) && (src.y == dest.y)) + gfx_copy_pixmap_box_i(S->priority[0], S->priority[1], src); + break; + case GFX_BUFFER_FRONT: + if (sdl_blit_surface(drv, S->visual[data_source], &srect, S->primary, &drect)) + SDLERROR("primary surface update failed!\n"); + SDL_UpdateRect(S->primary, drect.x, drect.y, drect.w, drect.h); + break; + default: + GFXERROR("Invalid buffer %d in update!\n", buffer); + return GFX_ERROR; + } + + return GFX_OK; +} + +static int +sdl_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + + if (!pic->internal.info) { + SDLERROR("Attempt to set static buffer with unregisterd pixmap!\n"); + return GFX_ERROR; + } + sdl_blit_surface(drv, (SDL_Surface *)pic->internal.info, NULL, + S->visual[2], NULL); + + gfx_copy_pixmap_box_i(S->priority[1], priority, gfx_rect(0, 0, 320*XFACT, 200*YFACT)); + + return GFX_OK; +} + + /*** Palette operations ***/ + +static int +sdl_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) +{ + if (index < 0 || index > 255) + { + SDLERROR("Attempt to set invalid palette entry %d\n", index); + return GFX_ERROR; + } + + S->colors[index].r = red; + S->colors[index].g = green; + S->colors[index].b = blue; + + SDL_SetColors(S->primary, S->colors + index, index, 1); + return GFX_OK; +} + + + /*** Mouse pointer operations ***/ + +byte * +sdl_create_cursor_rawdata(gfx_driver_t *drv, gfx_pixmap_t *pointer, int mode) +{ + int linewidth = (pointer->xl + 7) >> 3; + int lines = pointer->yl; + int xc, yc; + byte *data = (byte*)sci_calloc(linewidth, lines); + byte *linebase = data, *pos; + byte *src = pointer->index_data; + + for (yc = 0; yc < pointer->index_yl; yc++) { + int scalectr; + int bitc = 7; + pos = linebase; + + for (xc = 0; xc < pointer->index_xl; xc++) { + int draw = mode ? (*src == 0) : (*src < 255); + for (scalectr = 0; scalectr < XFACT; scalectr++) { + if (draw) + *pos |= (1 << bitc); + bitc--; + if (bitc < 0) { + bitc = 7; + pos++; + } + } + src++; + } + for (scalectr = 1; scalectr < YFACT; scalectr++) + memcpy(linebase + linewidth * scalectr, linebase, linewidth); + linebase += linewidth * YFACT; + } + return data; +} + + +static SDL_Cursor +*sdl_create_cursor_data(gfx_driver_t *drv, gfx_pixmap_t *pointer) +{ + byte *visual_data, *mask_data; + + S->pointer_data[0] = visual_data = sdl_create_cursor_rawdata(drv, pointer, 1); + S->pointer_data[1] = mask_data = sdl_create_cursor_rawdata(drv, pointer, 0); + + return SDL_CreateCursor(visual_data, mask_data, + pointer->xl, pointer->yl, + pointer->xoffset, pointer->yoffset); + +} + +static int sdl_set_pointer (struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + int i; + + if (pointer == NULL) + SDL_ShowCursor(SDL_DISABLE); + else { + SDL_Cursor *cursor; + for (i = 0; i < 2; i++) + if (S->pointer_data[i]) { + free(S->pointer_data[i]); + S->pointer_data[i] = NULL; + } + + cursor = SDL_GetCursor(); + SDL_SetCursor(sdl_create_cursor_data(drv, pointer)); + SDL_FreeCursor(cursor); + SDL_ShowCursor(SDL_ENABLE); + } + + return 0; +} + +/*** Event management ***/ + +int +sdl_map_key(gfx_driver_t *drv, SDL_keysym keysym) +{ + SDLKey skey = keysym.sym; + int rkey = keysym.unicode & 0x7f; + + if ((skey >= SDLK_a) && (skey <= SDLK_z)) + return ('a' + (skey - SDLK_a)); + + if ((skey >= SDLK_0) && (skey <= SDLK_9)) + return ('0' + (skey - SDLK_0)); + + if (flags & SCI_SDL_SWAP_CTRL_CAPS) { + switch (skey) { + case SDLK_LCTRL: skey = SDLK_CAPSLOCK; break; + case SDLK_CAPSLOCK: skey = SDLK_LCTRL; break; + default: break; + } + } + + switch (skey) { + /* XXXX catch KMOD_NUM for KP0-9 */ + case SDLK_BACKSPACE: return SCI_K_BACKSPACE; + case SDLK_TAB: return 9; + case SDLK_ESCAPE: return SCI_K_ESC; + case SDLK_RETURN: + case SDLK_KP_ENTER: + if (SDL_GetModState() & KMOD_ALT) { + toggle_fullscreen(drv); + return 0; + } + return SCI_K_ENTER; + case SDLK_KP_PERIOD: return SCI_K_DELETE; + case SDLK_KP0: + case SDLK_INSERT: return SCI_K_INSERT; + case SDLK_KP1: + case SDLK_END: return SCI_K_END; + case SDLK_KP2: + case SDLK_DOWN: return SCI_K_DOWN; + case SDLK_KP3: + case SDLK_PAGEDOWN: return SCI_K_PGDOWN; + case SDLK_KP4: + case SDLK_LEFT: return SCI_K_LEFT; + case SDLK_KP5: return SCI_K_CENTER; + case SDLK_KP6: + case SDLK_RIGHT: return SCI_K_RIGHT; + case SDLK_KP7: + case SDLK_HOME: return SCI_K_HOME; + case SDLK_KP8: + case SDLK_UP: return SCI_K_UP; + case SDLK_KP9: + case SDLK_PAGEUP: return SCI_K_PGUP; + + case SDLK_F1: return SCI_K_F1; + case SDLK_F2: return SCI_K_F2; + case SDLK_F3: return SCI_K_F3; + case SDLK_F4: return SCI_K_F4; + case SDLK_F5: return SCI_K_F5; + case SDLK_F6: return SCI_K_F6; + case SDLK_F7: return SCI_K_F7; + case SDLK_F8: return SCI_K_F8; + case SDLK_F9: return SCI_K_F9; + case SDLK_F10: return SCI_K_F10; + + case SDLK_LCTRL: + case SDLK_RCTRL: + case SDLK_LALT: + case SDLK_RALT: + case SDLK_LMETA: + case SDLK_RMETA: + case SDLK_CAPSLOCK: + case SDLK_SCROLLOCK: + case SDLK_NUMLOCK: + case SDLK_LSHIFT: + case SDLK_RSHIFT: return 0; + + case SDLK_PLUS: + case SDLK_KP_PLUS: return '+'; + case SDLK_SLASH: + case SDLK_KP_DIVIDE: return '/'; + case SDLK_MINUS: + case SDLK_KP_MINUS: return '-'; + case SDLK_ASTERISK: + case SDLK_KP_MULTIPLY: return '*'; + case SDLK_EQUALS: + case SDLK_KP_EQUALS: return '='; + + case SDLK_COMMA: + case SDLK_PERIOD: + case SDLK_BACKSLASH: + case SDLK_SEMICOLON: + case SDLK_QUOTE: + case SDLK_LEFTBRACKET: + case SDLK_RIGHTBRACKET: + case SDLK_LESS: + case SDLK_DOLLAR: + case SDLK_GREATER: return rkey; + case SDLK_SPACE: return ' '; + +#ifdef MACOSX + case SDLK_WORLD_0: +#endif + case SDLK_BACKQUOTE: + if (keysym.mod & KMOD_CTRL) + return '`'; + else + return rkey; + + default: + break; + } + + sciprintf("Unknown SDL keysym: %04x (%d) \n", skey, rkey); + return 0; +} + + +void +sdl_fetch_event(gfx_driver_t *drv, sci_event_t *sci_event) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + + switch (event.type) { + case SDL_KEYDOWN: { + int modifiers = event.key.keysym.mod; + sci_event->type = SCI_EVT_KEYBOARD; + + S->buckystate = (((modifiers & KMOD_CAPS)? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0) + | ((modifiers & KMOD_CTRL)? SCI_EVM_CTRL : 0) + | ((modifiers & KMOD_ALT)? SCI_EVM_ALT : 0) + | ((modifiers & KMOD_NUM) ? SCI_EVM_NUMLOCK : 0) + | ((modifiers & KMOD_RSHIFT)? SCI_EVM_RSHIFT : 0) + | ((modifiers & KMOD_LSHIFT)? SCI_EVM_LSHIFT : 0)); + + sci_event->buckybits = S->buckystate; + sci_event->data = sdl_map_key(drv, event.key.keysym); + if (sci_event->data) + return; + break; + } + case SDL_MOUSEBUTTONDOWN: + sci_event->type = SCI_EVT_MOUSE_PRESS; + sci_event->buckybits = S->buckystate; + sci_event->data = event.button.button - 1; + drv->pointer_x = event.button.x; + drv->pointer_y = event.button.y; + return; + case SDL_MOUSEBUTTONUP: + sci_event->type = SCI_EVT_MOUSE_RELEASE; + sci_event->buckybits = S->buckystate; + sci_event->data = event.button.button - 1; + drv->pointer_x = event.button.x; + drv->pointer_y = event.button.y; + return; + case SDL_MOUSEMOTION: + drv->pointer_x = event.motion.x; + drv->pointer_y = event.motion.y; + break; + case SDL_QUIT: + sci_event->type = SCI_EVT_QUIT; + return; + break; + case SDL_VIDEOEXPOSE: + break; + default: + SDLERROR("Received unhandled SDL event %04x\n", event.type); + } + } + + sci_event->type = SCI_EVT_NONE; /* No event. */ +} + +static sci_event_t +sdl_get_event(struct _gfx_driver *drv) +{ + sci_event_t input; + + sdl_fetch_event(drv, &input); + return input; +} + +static int +sdl_usec_sleep(struct _gfx_driver *drv, long usecs) +{ + int msecs; + SDL_Event event; + + /* Wait at most 10ms to keep mouse cursor responsive. */ + msecs = usecs / 1000; + if (msecs > 10) + msecs = 10; + + SDL_PumpEvents(); + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, + SDL_EVENTMASK(SDL_MOUSEMOTION)) == 1) { + drv->pointer_x = event.motion.x; + drv->pointer_y = event.motion.y; + } + + SDL_Delay(msecs); + + return GFX_OK; +} + +gfx_driver_t +gfx_driver_sdl = { + "sdl", + "0.3a", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, 0, + GFX_CAPABILITY_MOUSE_SUPPORT | GFX_CAPABILITY_MOUSE_POINTER + | GFX_CAPABILITY_PIXMAP_REGISTRY | GFX_CAPABILITY_FINE_LINES, + 0, /*GFX_DEBUG_POINTER | GFX_DEBUG_UPDATES | GFX_DEBUG_PIXMAPS | GFX_DEBUG_BASIC, */ + sdl_set_parameter, + sdl_init_specific, + sdl_init, + sdl_exit, + sdl_draw_line, + sdl_draw_filled_rect, + sdl_register_pixmap, + sdl_unregister_pixmap, + sdl_draw_pixmap, + sdl_grab_pixmap, + sdl_update, + sdl_set_static_buffer, + sdl_set_pointer, + sdl_set_palette, + sdl_get_event, + sdl_usec_sleep, + NULL +}; + +#endif /* HAVE_SDL */ + + +/* reset to original optimisations for Win32: */ +/* (does not reset intrinsics) */ +#ifdef _WIN32 +//#pragma optimize( "", on ) +#endif diff --git a/engines/sci/gfx/drivers/xlib_driver.c b/engines/sci/gfx/drivers/xlib_driver.c new file mode 100644 index 0000000000..baa65d406b --- /dev/null +++ b/engines/sci/gfx/drivers/xlib_driver.c @@ -0,0 +1,1460 @@ +/*************************************************************************** + xlib_driver.h Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <creichen@gmail.com> + +***************************************************************************/ + +#include <sci_memory.h> +#include <gfx_driver.h> +#ifndef X_DISPLAY_MISSING +#include <gfx_tools.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#ifdef HAVE_MITSHM +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> +#if defined(HAVE_X11_EXTENSIONS_XRENDER_H) +# define HAVE_RENDER +# include <X11/extensions/Xrender.h> +# if defined(HAVE_X11_XFT_XFT_H) +# include <X11/Xft/Xft.h> +# endif +#endif +#include <errno.h> +#endif + +#ifdef HAVE_XM_MWMUTIL_H +#include <Xm/MwmUtil.h> +#endif + +#define SCI_XLIB_PIXMAP_HANDLE_NORMAL 0 +#define SCI_XLIB_PIXMAP_HANDLE_GRABBED 1 + +#define SCI_XLIB_SWAP_CTRL_CAPS (1 << 0) +#define SCI_XLIB_INSERT_MODE (1 << 1) +#define SCI_XLIB_NLS (1 << 2) /* Non-US keyboard support, sacrificing shortcut keys */ + +#define X_COLOR_EXT(c) ((c << 8) | c) + +/* In C++ mode, we re-name ``class'' to ``class_''. However, this screws up +** our interface to xlib, so we're not doing it in here. +*/ +#ifdef class +# undef class +#endif + +static int flags; + +struct _xlib_state { + Display *display; + Window window; + GC gc; + XGCValues gc_values; + Colormap colormap; + Pixmap visual[3]; + gfx_pixmap_t *priority[2]; +#ifdef HAVE_MITSHM + XShmSegmentInfo *shm[4]; +#endif + int use_render; + int buckystate; + XErrorHandler old_error_handler; + Cursor mouse_cursor; + byte *pointer_data[2]; + int used_bytespp; /* bytes actually used to display stuff, rather than bytes occupied in data space */ + XVisualInfo visinfo; +#ifdef HAVE_RENDER + Picture picture; +#endif +}; + +#define VISUAL S->visinfo.visual + +#define S ((struct _xlib_state *)(drv->state)) + +#define XASS(foo) { int val = foo; if (!val) xlderror(drv, __LINE__); } +#define XFACT drv->mode->xfact +#define YFACT drv->mode->yfact + +#define DEBUGB if (drv->debug_flags & GFX_DEBUG_BASIC && ((debugline = __LINE__))) xldprintf +#define DEBUGU if (drv->debug_flags & GFX_DEBUG_UPDATES && ((debugline = __LINE__))) xldprintf +#define DEBUGPXM if (drv->debug_flags & GFX_DEBUG_PIXMAPS && ((debugline = __LINE__))) xldprintf +#define DEBUGPTR if (drv->debug_flags & GFX_DEBUG_POINTER && ((debugline = __LINE__))) xldprintf +#define ERROR if ((debugline = __LINE__)) xldprintf + +#ifdef HAVE_MITSHM + +XShmSegmentInfo shminfo; +int have_shmem = 0; +int x11_error = 0; + +static int check_for_xshm(Display *display) +{ + int major, minor, ignore; + Bool pixmaps; + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) { + if (XShmQueryVersion( display, &major, &minor, &pixmaps) == True) { + return (pixmaps == True) ? 2 : 1 ; + } else { + return 0; + } + } + return 0; +} +#endif + +#ifdef HAVE_RENDER +static int x_have_render(Display *display) +{ + int ignore, retval; + + printf("Checking for X11 RENDER extension:"); + + retval = XQueryExtension(display, "RENDER", &ignore, &ignore, &ignore); + + if (retval) + printf(" found.\n"); + else + printf(" not found.\n"); + + return retval; +} +#endif + +static int debugline = 0; + +static void +xldprintf(const char *fmt, ...) +{ + va_list argp; + fprintf(stderr,"GFX-XLIB %d:", debugline); + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); +} + +static void +xlderror(gfx_driver_t *drv, int line) +{ + xldprintf("Xlib Error in line %d\n", line); +} + +static unsigned long +xlib_map_color(gfx_driver_t *drv, gfx_color_t color) +{ + gfx_mode_t *mode = drv->mode; + unsigned long temp; + unsigned long retval = 0; + + if (drv->mode->palette) + return color.visual.global_index; + + temp = color.visual.r; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> mode->red_shift) & (mode->red_mask); + temp = color.visual.g; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> mode->green_shift) & (mode->green_mask); + temp = color.visual.b; + temp |= temp << 8; + temp |= temp << 16; + retval |= (temp >> mode->blue_shift) & (mode->blue_mask); + + return retval; +} + + +static int +xlib_error_handler(Display *display, XErrorEvent *error) +{ + char errormsg[256]; +#ifdef HAVE_MITSHM + x11_error = 1; +#endif + XGetErrorText(display, error->error_code, errormsg, 255); + ERROR(" X11: %s\n", errormsg); + return 0; +} + +#define UPDATE_NLS_CAPABILITY \ + if (flags & SCI_XLIB_NLS) \ + drv->capabilities |= GFX_CAPABILITY_KEYTRANSLATE; \ + else \ + drv->capabilities &= ~GFX_CAPABILITY_KEYTRANSLATE + + + +static int +xlib_set_parameter(struct _gfx_driver *drv, char *attribute, char *value) +{ + if (!strncmp(attribute, "swap_ctrl_caps",17) || + !strncmp(attribute, "swap_caps_ctrl",17)) { + if (string_truep(value)) + flags |= SCI_XLIB_SWAP_CTRL_CAPS; + else + flags &= ~SCI_XLIB_SWAP_CTRL_CAPS; + + + return GFX_OK; + } + + if (!strncmp(attribute, "localised_keyboard", 18) + || !strncmp(attribute, "localized_keyboard", 18)) { + if (string_truep(value)) + flags |= SCI_XLIB_NLS; + else + flags &= ~SCI_XLIB_NLS; + + UPDATE_NLS_CAPABILITY; + + return GFX_OK; + + } + + if (!strncmp(attribute, "disable_shmem", 14)) { +#ifdef HAVE_MITSHM + if (string_truep(value)) + have_shmem = -1; +#endif + return GFX_OK; + } + + ERROR("Attempt to set xlib parameter \"%s\" to \"%s\"\n", attribute, value); + return GFX_ERROR; +} + +Cursor +x_empty_cursor(Display *display, Drawable drawable) /* Generates an empty X cursor */ +{ + byte cursor_data[] = {0}; + XColor black = {0,0,0}; + Pixmap cursor_map; + + Cursor retval; + + cursor_map = XCreateBitmapFromData(display, drawable, (char *) cursor_data, 1, 1); + + retval = XCreatePixmapCursor(display, cursor_map, cursor_map, &black, &black, 0, 0); + + XFreePixmap(display, cursor_map); + + return retval; +} + +static int +xlib_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode); +static int +xlib_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer); + + +static int +xlib_init_specific(struct _gfx_driver *drv, int xfact, int yfact, int bytespp) +{ + XVisualInfo xvisinfo; + XSetWindowAttributes win_attr; + int default_screen; + int vistype = (bytespp == 1)? 3 /* PseudoColor */ : 4 /* TrueColor */; + int red_shift, green_shift, blue_shift, alpha_shift; + int bytespp_physical; + int depth_mod; /* Number of bits to subtract from the depth while checking */ + unsigned int alpha_mask; + int xsize, ysize; + XSizeHints *size_hints; + XClassHint *class_hint; + XImage *foo_image = NULL; + int reverse_endian = 0; +#ifdef HAVE_XM_MWMUTIL_H + PropMotifWmHints motif_hints; + Atom prop, proptype; +#endif + + int i; + + + UPDATE_NLS_CAPABILITY; + + if (!drv->state /* = S */) + drv->state = sci_malloc(sizeof(struct _xlib_state)); + + flags |= SCI_XLIB_INSERT_MODE; + + S->display = XOpenDisplay(NULL); + + if (!S->display) { + ERROR("Could not open X connection!\n"); + return GFX_FATAL; + } + + default_screen = DefaultScreen(S->display); + + if (xfact == -1 && yfact == -1) { /* Detect (used INTERNALLY!) */ + xfact = 2; + if (DisplayWidth(S->display, default_screen) < 640 + || DisplayHeight(S->display, default_screen) < 400) + xfact = 1; + + yfact = xfact; + } + + xsize = xfact * 320; + ysize = yfact * 200; + if (xfact < 1 || yfact < 1 || bytespp < 1 || bytespp > 4) { + ERROR("Internal error: Attempt to open window w/ scale factors (%d,%d) and bpp=%d!\n", + xfact, yfact, bytespp); + BREAKPOINT(); + } + +#ifdef HAVE_MITSHM + if (!have_shmem) { + have_shmem = check_for_xshm(S->display); + if (have_shmem) { + printf("Using the MIT-SHM extension (%d/%d)\n", have_shmem, + XShmPixmapFormat(S->display)); + } + memset(&shminfo, 0, sizeof(XShmSegmentInfo)); + } + for (i = 0; i < 4; i++) + S->shm[i] = NULL; +#endif + + depth_mod = 0; + + /* Try all bit size twiddling */ + for (depth_mod = 0; depth_mod < 8; depth_mod++) + /* Try all viable depths */ + for (; bytespp > 0; bytespp--) + /* Try all interesting visuals */ + for (vistype = 4; vistype >= 3; vistype--) + if (XMatchVisualInfo(S->display, default_screen, + (bytespp << 3) - depth_mod, vistype, &xvisinfo)) + goto found_visual; + found_visual: + + S->visinfo = xvisinfo; + + if (vistype < 3 || ((vistype == 3) && (bytespp != 1))) { + if (bytespp == 1) { + ERROR("Could not get an 8 bit Pseudocolor visual!\n"); + } else { + ERROR("Could not get a %d bit TrueColor visual!\n", bytespp << 3); + } + return GFX_FATAL; + } + + S->colormap = win_attr.colormap = + XCreateColormap(S->display, RootWindow(S->display, default_screen), + VISUAL, (bytespp == 1)? AllocAll : AllocNone); + + win_attr.event_mask = PointerMotionMask | StructureNotifyMask | ButtonPressMask + | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ExposureMask; + win_attr.background_pixel = win_attr.border_pixel = 0; + + S->window = XCreateWindow(S->display, RootWindow(S->display, default_screen), + 0, 0, xsize, ysize, 0, xvisinfo.depth, InputOutput, + VISUAL, (CWBackPixel | CWBorderPixel | CWColormap | CWEventMask), + &win_attr); + + if (!S->window) { + ERROR("Could not create window of size %dx%d!\n", 320*xfact, 200*yfact); + return GFX_FATAL; + } + + XSync(S->display, False); +#ifdef HAVE_XM_MWMUTIL_H + motif_hints.flags = MWM_HINTS_DECORATIONS|MWM_HINTS_FUNCTIONS; + motif_hints.decorations = MWM_DECOR_BORDER|MWM_DECOR_TITLE|MWM_DECOR_MENU|MWM_DECOR_MINIMIZE; + motif_hints.functions=0 +#ifdef MWM_FUNC_MOVE + | MWM_FUNC_MOVE +#endif +#ifdef MWM_FUNC_MINIMIZE + | MWM_FUNC_MINIMIZE +#endif +#ifdef MWM_FUNC_CLOSE + | MWM_FUNC_CLOSE +#endif +#ifdef MWM_FUNC_QUIT_APP + | MWM_FUNC_QUIT_APP +#endif + ; + + prop = XInternAtom(S->display, "_MOTIF_WM_HINTS", True ); + if (prop) { + proptype = prop; + XChangeProperty(S->display, S->window, prop, proptype, 32, PropModeReplace, (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS); + } +#endif + + XStoreName(S->display, S->window, "FreeSCI"); + XDefineCursor(S->display, S->window, (S->mouse_cursor = x_empty_cursor(S->display, S->window))); + + XMapWindow(S->display, S->window); + S->buckystate = 0; + + if (bytespp == 1) + red_shift = green_shift = blue_shift = 0; + else { + red_shift = 32 - ffs((~xvisinfo.red_mask >> 1) & (xvisinfo.red_mask)); + green_shift = 32 - ffs((~xvisinfo.green_mask >> 1) & (xvisinfo.green_mask)); + blue_shift = 32 - ffs((~xvisinfo.blue_mask >> 1) & (xvisinfo.blue_mask)); + } + + class_hint = XAllocClassHint(); + class_hint->res_name = "FreeSCI"; + class_hint->res_class = "FreeSCI"; + XSetIconName(S->display, S->window, "FreeSCI"); + XSetClassHint(S->display, S->window, class_hint); + XFree(class_hint); + size_hints = XAllocSizeHints(); + size_hints->base_width = size_hints->min_width = size_hints->max_width = xsize; + size_hints->base_height = size_hints->min_height = size_hints->max_height = ysize; + size_hints->flags |= PMinSize | PMaxSize | PBaseSize; + XSetWMNormalHints(S->display, S->window, size_hints); + XFree(size_hints); + + S->gc_values.foreground = BlackPixel(S->display, DefaultScreen(S->display)); + S->gc = XCreateGC(S->display, S->window, GCForeground, &(S->gc_values)); + + for (i = 0; i < 2; i++) { + S->priority[i] = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xsize, ysize, GFX_RESID_NONE, -i, -777)); + if (!S->priority[i]) { + ERROR("Out of memory: Could not allocate priority maps! (%dx%d)\n", + xsize, ysize); + return GFX_FATAL; + } + } + + foo_image = XCreateImage(S->display, VISUAL, + bytespp << 3, ZPixmap, 0, (char*)sci_malloc(23), 2, 2, 8, 0); + + bytespp_physical = foo_image->bits_per_pixel >> 3; +#ifdef WORDS_BIGENDIAN + reverse_endian = foo_image->byte_order == LSBFirst; +#else + reverse_endian = foo_image->byte_order == MSBFirst; +#endif + XDestroyImage(foo_image); + +#ifdef HAVE_MITSHM + /* set up and test the XSHM extension to make sure it's sane */ + if (have_shmem) { + XErrorHandler old_handler; + + x11_error = 0; + old_handler = XSetErrorHandler(xlib_error_handler); + + foo_image = XShmCreateImage(S->display, VISUAL, + bytespp_physical << 3, ZPixmap, 0, &shminfo, 2, 2); + if (foo_image) + shminfo.shmid = shmget(IPC_PRIVATE, + foo_image->bytes_per_line * + foo_image->height, + IPC_CREAT | 0777); + if (-1 == shminfo.shmid) { + have_shmem = 0; + ERROR("System does not support SysV IPC, disabling XSHM\n"); + perror("reason"); + foo_image = NULL; + } else { + + shminfo.shmaddr = (char *) shmat(shminfo.shmid, 0, 0); + if ((void *) -1 == shminfo.shmaddr) { + ERROR("Could not attach shared memory segment\n"); + perror("reason"); + if (foo_image) + XDestroyImage(foo_image); + return GFX_FATAL; + } + + foo_image->data = shminfo.shmaddr; + shminfo.readOnly = False; + + XShmAttach(S->display, &shminfo); + XSync(S->display, False); + shmctl(shminfo.shmid, IPC_RMID, 0); + + if (x11_error) { + have_shmem = 0; + ERROR("System does not support Shared XImages, disabling\n"); + shmdt(shminfo.shmaddr); + XDestroyImage(foo_image); + foo_image = NULL; + x11_error = 0; + } + XSetErrorHandler(old_handler); + } + } + +#endif + + + alpha_mask = xvisinfo.red_mask | xvisinfo.green_mask | xvisinfo.blue_mask; + if (!reverse_endian && bytespp_physical == 4 && (!(alpha_mask & 0xff000000) || !(alpha_mask & 0xff))) { + if (alpha_mask & 0xff) { + alpha_mask = 0xff000000; + alpha_shift = 0; + } else { /* Lowest byte */ + alpha_mask = 0x000000ff; + alpha_shift = 24; + } + } else { + alpha_mask = 0; + alpha_shift = 0; + } + /* create the visual buffers */ + for (i = 0; i < 3; i++) { +#ifdef HAVE_MITSHM + XErrorHandler old_handler; + + if (have_shmem && have_shmem != 2) { + ERROR("Shared memory pixmaps not supported. Reverting\n"); + perror("reason"); + have_shmem = 0; + } + + if (have_shmem) { + old_handler = XSetErrorHandler(xlib_error_handler); + + if ((S->shm[i] = (XShmSegmentInfo*)sci_malloc(sizeof(XShmSegmentInfo))) == 0) { + ERROR("AIEEEE! Malloc failed!\n"); + return GFX_FATAL; + } + memset(S->shm[i], 0, sizeof(XShmSegmentInfo)); + + S->shm[i]->shmid = shmget(IPC_PRIVATE, xsize * ysize * + bytespp_physical, + IPC_CREAT | IPC_EXCL | 0666); + S->shm[i]->readOnly = False; + + if (S->shm[i]->shmid == -1) { + have_shmem = 0; + ERROR("System does not support SysV IPC, disabling XSHM\n"); + perror("reason"); + } + } + if (have_shmem) { + S->shm[i]->shmaddr = (char *) shmat(S->shm[i]->shmid, 0, 0); + if (S->shm[i]->shmaddr == (void *) -1) { + ERROR("Could not attach shared memory segment\n"); + perror("reason"); + have_shmem = 0; + } + } + if (have_shmem) { + if (!XShmAttach(S->display, S->shm[i]) || x11_error) { + ERROR("ARGH! Can't attach shared memory segment\n"); + have_shmem = 0; + } + XSync(S->display, False); + shmctl(S->shm[i]->shmid, IPC_RMID, 0); + } + + if (have_shmem && !x11_error) { + S->visual[i] = XShmCreatePixmap(S->display, S->window, + S->shm[i]->shmaddr, + S->shm[i], xsize, ysize, + bytespp << 3); + XSync(S->display, False); + + if (x11_error || !S->visual[i]) { + ERROR("Shared Memory Pixmaps not supported on this system. Disabling!\n"); + have_shmem = 0; + XFreePixmap(S->display, S->visual[i]); + XShmDetach(S->display ,S->shm[i]); + XSync(S->display, False); + S->visual[i] = 0; + x11_error = 0; + shmdt(S->shm[i]->shmaddr); + sci_free(S->shm[i]); + + } + + } + XSetErrorHandler(old_handler); + + if (!have_shmem) +#endif + S->visual[i] = XCreatePixmap(S->display, S->window, xsize, ysize, bytespp << 3); + + XFillRectangle(S->display, S->visual[i], S->gc, 0, 0, xsize, ysize); + } + + /** X RENDER handling **/ +#ifdef HAVE_RENDER + S->use_render = x_have_render(S->display); + + if (S->use_render) { + XRenderPictFormat * format + = XRenderFindVisualFormat (S->display, + VISUAL); + S->picture = XRenderCreatePicture (S->display, + (Drawable) S->visual[1], + format, + 0, 0); + } else /* No Xrender */ + drv->draw_filled_rect = xlib_draw_filled_rect; +#else + S->use_render = 0; +#endif + /** End of X RENDER handling **/ + + + drv->mode = gfx_new_mode(xfact, yfact, bytespp_physical, + xvisinfo.red_mask, xvisinfo.green_mask, + xvisinfo.blue_mask, alpha_mask, + red_shift, green_shift, blue_shift, alpha_shift, + (bytespp == 1)? xvisinfo.colormap_size : 0, + (reverse_endian)? GFX_MODE_FLAG_REVERSE_ENDIAN : 0); + +#ifdef HAVE_MITSHM + if (have_shmem) { + XShmDetach(S->display, &shminfo); + XDestroyImage(foo_image); + shmdt(shminfo.shmaddr); + } +#endif + + S->used_bytespp = bytespp; + S->old_error_handler = (XErrorHandler) XSetErrorHandler(xlib_error_handler); + S->pointer_data[0] = NULL; + S->pointer_data[1] = NULL; + + + return GFX_OK; +} + + +static void +xlib_xdpy_info() +{ + int i; + XVisualInfo foo; + XVisualInfo *visuals; + int visuals_nr; + Display *display = XOpenDisplay(NULL); + const char *vis_classes[6] = {"StaticGray", "GrayScale", "StaticColor", + "PseudoColor", "TrueColor", "DirectColor"}; + + printf("Visuals provided by X11 server:\n"); + visuals = XGetVisualInfo(display, VisualNoMask, &foo, &visuals_nr); + + if (!visuals_nr) { + printf(" None!\n"); + } + + for (i = 0; i < visuals_nr; i++) { + XVisualInfo *visual = visuals + i; + + /* This works around an incompatibility between C++ and xlib: access visual->class */ + int visual_class = *((int *) (((byte *)(&(visual->depth))) + sizeof(unsigned int))); + + printf("%d:\t%d bpp %s(%d)\n" + "\tR:%08lx G:%08lx B:%08lx\n" + "\tbits_per_rgb=%d\n" + "\tcolormap_size=%d\n\n", + i, + visual->depth, + (visual_class < 0 || visual_class >5)? + "INVALID" : + vis_classes[visual_class], + visual_class, + visual->red_mask, visual->green_mask, visual->blue_mask, + visual->bits_per_rgb, visual->colormap_size); + + } + + if (visuals) + XFree(visuals); +} + +static int +xlib_init(struct _gfx_driver *drv) +{ + int i; + + /* Try 32-bit mode last due to compiz issue with bit depth 32. */ + for (i = 3; i > 0; i--) + if (!xlib_init_specific(drv, -1, -1, i)) + return GFX_OK; + + if (!xlib_init_specific(drv, -1, -1, 4)) + return GFX_OK; + + fprintf(stderr, "Could not find supported mode!\n"); + xlib_xdpy_info(); + + return GFX_FATAL; +} + +static void +xlib_exit(struct _gfx_driver *drv) +{ + int i; + if (S) { + for (i = 0; i < 2; i++) { + gfx_free_pixmap(drv, S->priority[i]); + S->priority[i] = NULL; + } + + for (i = 0; i < 3; i++) { +#ifdef HAVE_MITSHM + if (have_shmem && S->shm[i]) { + XFreePixmap(S->display, S->visual[i]); + XShmDetach(S->display, S->shm[i]); + + if (S->shm[i]->shmid >=0) + shmctl(S->shm[i]->shmid, IPC_RMID, 0); + if (S->shm[i]->shmaddr) + shmdt(S->shm[i]->shmaddr); + + sci_free(S->shm[i]); + S->shm[i] = NULL; + } else +#endif + XFreePixmap(S->display, S->visual[i]); + } + +#ifdef HAVE_RENDER + XRenderFreePicture(S->display, S->picture); +#endif + XFreeGC(S->display, S->gc); + XDestroyWindow(S->display, S->window); + XCloseDisplay(S->display); + XSetErrorHandler((XErrorHandler) (S->old_error_handler)); + sci_free(S); + drv->state /* = S */ = NULL; + gfx_free_mode(drv->mode); + } +} + + + /*** Drawing operations ***/ + +static int +xlib_draw_line(struct _gfx_driver *drv, point_t start, point_t end, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + int linewidth = (line_mode == GFX_LINE_MODE_FINE)? 1: + (drv->mode->xfact + drv->mode->yfact) >> 1; + + if (color.mask & GFX_MASK_VISUAL) { + int xmod = drv->mode->xfact >> 1; + int ymod = drv->mode->yfact >> 1; + + if (line_mode == GFX_LINE_MODE_FINE) + xmod = ymod = 0; + + S->gc_values.foreground = xlib_map_color(drv, color); + S->gc_values.line_width = linewidth; + S->gc_values.line_style = (line_style == GFX_LINE_STYLE_NORMAL)? + LineSolid : LineOnOffDash; + S->gc_values.cap_style = CapProjecting; + + XChangeGC(S->display, S->gc, GCLineWidth | GCLineStyle | GCForeground | GCCapStyle, &(S->gc_values)); + + XASS(XDrawLine(S->display, S->visual[1], S->gc, + start.x + xmod, start.y + ymod, + end.x + xmod, end.y + ymod)); + } + + if (color.mask & GFX_MASK_PRIORITY) { + int xc, yc; + point_t nstart, nend; + + linewidth--; + for (xc = 0; xc <= linewidth; xc++) + for (yc = -linewidth; yc <= linewidth; yc++) { + nstart.x = start.x + xc; + nstart.y = start.y + yc; + + nend.x = end.x + xc; + nend.y = end.y + yc; + + gfx_draw_line_pixmap_i(S->priority[0], + nstart, nend, color.priority); + } + } + + return GFX_OK; +} + +static int +xlib_draw_filled_rect(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (color1.mask & GFX_MASK_VISUAL) { + S->gc_values.foreground = xlib_map_color(drv, color1); + XChangeGC(S->display, S->gc, GCForeground, &(S->gc_values)); + XASS(XFillRectangle(S->display, S->visual[1], S->gc, rect.x, rect.y, + rect.xl, rect.yl)); + } + + if (color1.mask & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(S->priority[0], rect, color1.priority); + + return GFX_OK; +} + +#ifdef HAVE_RENDER +static int +xlib_draw_filled_rect_RENDER(struct _gfx_driver *drv, rect_t rect, + gfx_color_t color1, gfx_color_t color2, + gfx_rectangle_fill_t shade_mode) +{ + if (S->used_bytespp == 1) /* No room for alpha! */ + return xlib_draw_filled_rect(drv, rect, color1, color2, shade_mode); + + if (color1.mask & GFX_MASK_VISUAL) { + XRenderColor fg; + + fg.red = X_COLOR_EXT(color1.visual.r); + fg.green = X_COLOR_EXT(color1.visual.g); + fg.blue = X_COLOR_EXT(color1.visual.b); + fg.alpha = 0xffff - X_COLOR_EXT(color1.alpha); + + + XRenderFillRectangle(S->display, + PictOpOver, + S->picture, + &fg, + rect.x, rect.y, + rect.xl, rect.yl); + } + + if (color1.mask & GFX_MASK_PRIORITY) + gfx_draw_box_pixmap_i(S->priority[0], rect, color1.priority); + + return GFX_OK; +} +#endif + + /*** Pixmap operations ***/ + +static int +xlib_register_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + if (pxm->internal.info) { + ERROR("Attempt to register pixmap twice!\n"); + return GFX_ERROR; + } + pxm->internal.info = XCreateImage(S->display, VISUAL, + S->used_bytespp << 3, ZPixmap, 0, (char *) pxm->data, pxm->xl, + pxm->yl, 8, 0); + + DEBUGPXM("Registered pixmap %d/%d/%d at %p (%dx%d)\n", pxm->ID, pxm->loop, pxm->cel, + pxm->internal.info, pxm->xl, pxm->yl); + return GFX_OK; +} + +static int +xlib_unregister_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm) +{ + DEBUGPXM("Freeing pixmap %d/%d/%d at %p\n", pxm->ID, pxm->loop, pxm->cel, + pxm->internal.info); + + if (!pxm->internal.info) { + ERROR("Attempt to unregister pixmap twice!\n"); + return GFX_ERROR; + } + + XDestroyImage((XImage *) pxm->internal.info); + pxm->internal.info = NULL; + pxm->data = NULL; /* Freed by XDestroyImage */ + return GFX_OK; +} + +static int +xlib_draw_pixmap(struct _gfx_driver *drv, gfx_pixmap_t *pxm, int priority, + rect_t src, rect_t dest, gfx_buffer_t buffer) +{ + int bufnr = (buffer == GFX_BUFFER_STATIC)? 2:1; + int pribufnr = bufnr -1; + XImage *tempimg; + + if (dest.xl != src.xl || dest.yl != src.yl) { + ERROR("Attempt to scale pixmap (%dx%d)->(%dx%d): Not supported\n", + src.xl, src.yl, dest.xl, dest.yl); + return GFX_ERROR; + } + + if (pxm->internal.handle == SCI_XLIB_PIXMAP_HANDLE_GRABBED) { + XPutImage(S->display, S->visual[bufnr], S->gc, (XImage *) pxm->internal.info, + src.x, src.y, dest.x, dest.y, dest.xl, dest.yl); + return GFX_OK; + } + + tempimg = XGetImage(S->display, S->visual[bufnr], dest.x, dest.y, + dest.xl, dest.yl, 0xffffffff, ZPixmap); + + if (!tempimg) { + ERROR("Failed to grab X image!\n"); + return GFX_ERROR; + } + + gfx_crossblit_pixmap(drv->mode, pxm, priority, src, dest, + (byte *) tempimg->data, tempimg->bytes_per_line, + S->priority[pribufnr]->index_data, + S->priority[pribufnr]->index_xl, 1, + GFX_CROSSBLIT_FLAG_DATA_IS_HOMED); + + XPutImage(S->display, S->visual[bufnr], S->gc, tempimg, + 0, 0, dest.x, dest.y, dest.xl, dest.yl); + + XDestroyImage(tempimg); + return GFX_OK; +} + + +static int +xlib_grab_pixmap(struct _gfx_driver *drv, rect_t src, gfx_pixmap_t *pxm, + gfx_map_mask_t map) +{ + + if (src.x < 0 || src.y < 0) { + ERROR("Attempt to grab pixmap from invalid coordinates (%d,%d)\n", src.x, src.y); + return GFX_ERROR; + } + + if (!pxm->data) { + ERROR("Attempt to grab pixmap to unallocated memory\n"); + return GFX_ERROR; + } + + switch (map) { + + case GFX_MASK_VISUAL: + pxm->xl = src.xl; + pxm->yl = src.yl; + + pxm->internal.info = XGetImage(S->display, S->visual[1], src.x, src.y, + src.xl, src.yl, 0xffffffff, ZPixmap); + pxm->internal.handle = SCI_XLIB_PIXMAP_HANDLE_GRABBED; + pxm->flags |= GFX_PIXMAP_FLAG_INSTALLED | GFX_PIXMAP_FLAG_EXTERNAL_PALETTE | GFX_PIXMAP_FLAG_PALETTE_SET; + sci_free(pxm->data); + pxm->data = (byte *) ((XImage *)(pxm->internal.info))->data; + break; + + case GFX_MASK_PRIORITY: + ERROR("FIXME: priority map grab not implemented yet!\n"); + break; + + default: + ERROR("Attempt to grab pixmap from invalid map 0x%02x\n", map); + return GFX_ERROR; + } + + return GFX_OK; +} + + + /*** Buffer operations ***/ + +static int +xlib_update(struct _gfx_driver *drv, rect_t src, point_t dest, gfx_buffer_t buffer) +{ + int data_source = (buffer == GFX_BUFFER_BACK)? 2 : 1; + int data_dest = data_source - 1; + + + if (src.x != dest.x || src.y != dest.y) { + DEBUGU("Updating %d (%d,%d)(%dx%d) to (%d,%d)\n", buffer, src.x, src.y, + src.xl, src.yl, dest.x, dest.y); + } else { + DEBUGU("Updating %d (%d,%d)(%dx%d)\n", buffer, src.x, src.y, src.xl, src.yl); + } + + XCopyArea(S->display, S->visual[data_source], S->visual[data_dest], S->gc, + src.x, src.y, src.xl, src.yl, dest.x, dest.y); + + if (buffer == GFX_BUFFER_BACK && (src.x == dest.x) && (src.y == dest.y)) + gfx_copy_pixmap_box_i(S->priority[0], S->priority[1], src); + else { + gfx_color_t col; + col.mask = GFX_MASK_VISUAL; + col.visual.r = 0xff; + col.visual.g = 0; + col.visual.b = 0; + + XCopyArea(S->display, S->visual[0], S->window, S->gc, + dest.x, dest.y, src.xl, src.yl, dest.x, dest.y); + } + + return GFX_OK; +} + +static int +xlib_set_static_buffer(struct _gfx_driver *drv, gfx_pixmap_t *pic, gfx_pixmap_t *priority) +{ + + if (!pic->internal.info) { + ERROR("Attempt to set static buffer with unregisterd pixmap!\n"); + return GFX_ERROR; + } + XPutImage(S->display, S->visual[2], S->gc, (XImage *) pic->internal.info, + 0, 0, 0, 0, 320 * XFACT, 200 * YFACT); + gfx_copy_pixmap_box_i(S->priority[1], priority, gfx_rect(0, 0, 320*XFACT, 200*YFACT)); + + return GFX_OK; +} + + + /*** Mouse pointer operations ***/ + +byte * +xlib_create_cursor_data(gfx_driver_t *drv, gfx_pixmap_t *pointer, int mode) +{ + int linewidth = (pointer->xl + 7) >> 3; + int lines = pointer->yl; + int xc, yc; + int xfact = drv->mode->xfact; + byte *data = (byte*)sci_calloc(linewidth, lines); + byte *linebase = data, *pos; + byte *src = pointer->index_data; + + + for (yc = 0; yc < pointer->index_yl; yc++) { + int scalectr; + int bitc = 0; + pos = linebase; + + + for (xc = 0; xc < pointer->index_xl; xc++) { + int draw = mode? + (*src == 0) : (*src < 255); + + for (scalectr = 0; scalectr < xfact; scalectr++) { + if (draw) + *pos |= (1 << bitc); + + bitc++; + if (bitc == 8) { + bitc = 0; + pos++; + } + } + + src++; + } + for (scalectr = 1; scalectr < drv->mode->yfact; scalectr++) + memcpy(linebase + linewidth * scalectr, linebase, linewidth); + + linebase += linewidth * drv->mode->yfact; + } + + return data; +} + +static int +xlib_set_pointer(struct _gfx_driver *drv, gfx_pixmap_t *pointer) +{ + int i; + XFreeCursor(S->display, S->mouse_cursor); + + for (i = 0; i < 2; i++) + if (S->pointer_data[i]) { + sci_free(S->pointer_data[i]); + S->pointer_data[i] = NULL; + } + + if (pointer == NULL) + S->mouse_cursor = x_empty_cursor(S->display, S->window); + else { + XColor cols[2]; + Pixmap visual, mask; + byte *mask_data, *visual_data; + int real_xl = ((pointer->xl + 7) >> 3) << 3; + int i; + + for (i = 0; i < 2; i++) { + cols[i].red = pointer->colors[i].r; + cols[i].red |= (cols[i].red << 8); + cols[i].green = pointer->colors[i].g; + cols[i].green |= (cols[i].green << 8); + cols[i].blue = pointer->colors[i].b; + cols[i].blue |= (cols[i].blue << 8); + } + + S->pointer_data[0] = visual_data = xlib_create_cursor_data(drv, pointer, 1); + S->pointer_data[1] = mask_data = xlib_create_cursor_data(drv, pointer, 0); + S->pointer_data[0] = NULL; + S->pointer_data[1] = NULL; + visual = XCreateBitmapFromData(S->display, S->window, (char *) visual_data, real_xl, pointer->yl); + mask = XCreateBitmapFromData(S->display, S->window, (char *) mask_data, real_xl, pointer->yl); + + + S->mouse_cursor = + XCreatePixmapCursor(S->display, visual, mask, + &(cols[0]), &(cols[1]), + pointer->xoffset, pointer->yoffset); + + XFreePixmap(S->display, visual); + XFreePixmap(S->display, mask); + sci_free(mask_data); + sci_free(visual_data); + } + + XDefineCursor(S->display, S->window, S->mouse_cursor); + + return 0; +} + + + /*** Palette operations ***/ + +static int +xlib_set_palette(struct _gfx_driver *drv, int index, byte red, byte green, byte blue) +{ + char stringbuf[8]; + sprintf(stringbuf, "#%02x%02x%02x", red, green, blue); /* Argh. */ + + XStoreNamedColor(S->display, S->colormap, stringbuf, index, DoRed | DoGreen | DoBlue); + /* Isn't there some way to do this without strings? */ + + return GFX_OK; +} + + + /*** Event management ***/ +/* +int +x_unmap_key(gfx_driver_t *drv, int keycode) +{ + KeySym xkey = XKeycodeToKeysym(S->display, keycode, 0); + + return 0; +} +*/ +int +x_map_key(gfx_driver_t *drv, XEvent *key_event, char *character) +{ + KeySym xkey = XKeycodeToKeysym(S->display, key_event->xkey.keycode, 0); + + *character = 0; + + if (flags & SCI_XLIB_SWAP_CTRL_CAPS) { + switch (xkey) { + case XK_Control_L: xkey = XK_Caps_Lock; break; + case XK_Caps_Lock: xkey = XK_Control_L; break; + } + } + + switch(xkey) { + + case XK_BackSpace: return SCI_K_BACKSPACE; + case XK_Tab: return 9; + case XK_Escape: return SCI_K_ESC; + case XK_Return: + case XK_KP_Enter: return SCI_K_ENTER; + + case XK_KP_Decimal: + case XK_KP_Delete: return SCI_K_DELETE; + case XK_KP_0: + case XK_KP_Insert: return SCI_K_INSERT; + case XK_End: + case XK_KP_End: + case XK_KP_1: return SCI_K_END; + case XK_Down: + case XK_KP_Down: + case XK_KP_2: return SCI_K_DOWN; + case XK_Page_Down: + case XK_KP_Page_Down: + case XK_KP_3: return SCI_K_PGDOWN; + case XK_Left: + case XK_KP_Left: + case XK_KP_4: return SCI_K_LEFT; + case XK_KP_Begin: + case XK_KP_5: return SCI_K_CENTER; + case XK_Right: + case XK_KP_Right: + case XK_KP_6: return SCI_K_RIGHT; + case XK_Home: + case XK_KP_Home: + case XK_KP_7: return SCI_K_HOME; + case XK_Up: + case XK_KP_Up: + case XK_KP_8: return SCI_K_UP; + case XK_Page_Up: + case XK_KP_Page_Up: + case XK_KP_9: return SCI_K_PGUP; + + case XK_F1: return SCI_K_F1; + case XK_F2: return SCI_K_F2; + case XK_F3: return SCI_K_F3; + case XK_F4: return SCI_K_F4; + case XK_F5: return SCI_K_F5; + case XK_F6: return SCI_K_F6; + case XK_F7: return SCI_K_F7; + case XK_F8: return SCI_K_F8; + case XK_F9: return SCI_K_F9; + case XK_F10: return SCI_K_F10; + + + case XK_Control_L: + case XK_Control_R:/* S->buckystate |= SCI_EVM_CTRL; return 0; */ + case XK_Alt_L: + case XK_Alt_R:/* S->buckystate |= SCI_EVM_ALT; return 0; */ + case XK_Caps_Lock: + case XK_Shift_Lock:/* S->buckystate ^= SCI_EVM_CAPSLOCK; return 0; */ + case XK_Scroll_Lock:/* S->buckystate ^= SCI_EVM_SCRLOCK; return 0; */ + case XK_Num_Lock:/* S->buckystate ^= SCI_EVM_NUMLOCK; return 0; */ + case XK_Shift_L:/* S->buckystate |= SCI_EVM_LSHIFT; return 0; */ + case XK_Shift_R:/* S->buckystate |= SCI_EVM_RSHIFT; return 0; */ + return 0; + default: + break; + } + + + if (flags & SCI_XLIB_NLS) { + /* Localised key lookup */ + XLookupString(&(key_event->xkey), character, 1, &xkey, NULL); + } + + if ((xkey >= ' ') && (xkey <= '~')) + return xkey; /* All printable ASCII characters */ + + switch (xkey) { + case XK_KP_Add: return '+'; + case XK_KP_Divide: return '/'; + case XK_KP_Subtract: return '-'; + case XK_KP_Multiply: return '*'; + } + + if (*character) + return xkey; /* Should suffice for all practical purposes */ + + sciprintf("Unknown X keysym: %04x\n", xkey); + return 0; +} + + +void +x_get_event(gfx_driver_t *drv, int eventmask, long wait_usec, sci_event_t *sci_event) +{ + int x_button_xlate[] = {0, 1, 3, 2, 4, 5}; + XEvent event; + Window window = S->window; + Display *display = S->display; + struct timeval ctime, timeout_time, sleep_time; + long usecs_to_sleep; + + eventmask |= ExposureMask; /* Always check for this */ + + gettimeofday(&timeout_time, NULL); + timeout_time.tv_usec += wait_usec; + + /* Calculate wait time */ + timeout_time.tv_sec += (timeout_time.tv_usec / 1000000); + timeout_time.tv_usec %= 1000000; + + do { + int hasnext_event = 1; + + while (hasnext_event) { + if (sci_event) { /* Capable of handling any event? */ + hasnext_event = XPending(display); + if (hasnext_event) + XNextEvent(display, &event); + } else + hasnext_event = XCheckWindowEvent(display, window, eventmask, &event); + + + if (hasnext_event) + switch (event.type) { + + case ReparentNotify: + case ConfigureNotify: + case MapNotify: + case UnmapNotify: + break; + + case KeyPress: { + int modifiers = event.xkey.state; + char ch = 0; + sci_event->type = SCI_EVT_KEYBOARD; + + S->buckystate = ((flags & SCI_XLIB_INSERT_MODE)? SCI_EVM_INSERT : 0) + | (((modifiers & LockMask)? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0) + | ((modifiers & ControlMask)? SCI_EVM_CTRL : 0) + | ((modifiers & (Mod1Mask | Mod4Mask))? SCI_EVM_ALT : 0) + | ((modifiers & Mod2Mask)? SCI_EVM_NUMLOCK : 0) + | ((modifiers & Mod5Mask)? SCI_EVM_SCRLOCK : 0)) + ^ ((modifiers & ShiftMask)? SCI_EVM_LSHIFT | SCI_EVM_RSHIFT : 0); + + sci_event->buckybits = S->buckystate; + sci_event->data = + x_map_key(drv, &event, &ch); + + if (ch) + sci_event->character = ch; + else + sci_event->character = sci_event->data; + + if (sci_event->data == SCI_K_INSERT) + flags ^= SCI_XLIB_INSERT_MODE; + + if (sci_event->data) + return; + + break; + } + + case KeyRelease: + /*x_unmap_key(drv, event.xkey.keycode);*/ + break; + + case ButtonPress: { + sci_event->type = SCI_EVT_MOUSE_PRESS; + sci_event->buckybits = S->buckystate; + sci_event->data = x_button_xlate[event.xbutton.button]; + return; + } + + case ButtonRelease: { + sci_event->type = SCI_EVT_MOUSE_RELEASE; + sci_event->buckybits = S->buckystate; + sci_event->data = x_button_xlate[event.xbutton.button]; + return; + } + + case MotionNotify: { + + drv->pointer_x = event.xmotion.x; + drv->pointer_y = event.xmotion.y; + if (!sci_event) + /* Wake up from sleep */ + return; + } + break; + + case GraphicsExpose: + case Expose: { + XCopyArea(S->display, S->visual[0], S->window, S->gc, + event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height, + event.xexpose.x, event.xexpose.y); + } + break; + + case NoExpose: + break; + + default: + ERROR("Received unhandled X event %04x\n", event.type); + } + } + + gettimeofday(&ctime, NULL); + + usecs_to_sleep = (timeout_time.tv_sec > ctime.tv_sec)? 1000000 : 0; + usecs_to_sleep += timeout_time.tv_usec - ctime.tv_usec; + if (ctime.tv_sec > timeout_time.tv_sec) usecs_to_sleep = -1; + + + if (usecs_to_sleep > 0) { + + if (usecs_to_sleep > 10000) + usecs_to_sleep = 10000; /* Sleep for a maximum of 10 ms */ + + sleep_time.tv_usec = usecs_to_sleep; + sleep_time.tv_sec = 0; + + select(0, NULL, NULL, NULL, &sleep_time); /* Sleep. */ + } + + } while (usecs_to_sleep >= 0); + + if (sci_event) + sci_event->type = SCI_EVT_NONE; /* No event. */ +} + + +static sci_event_t +xlib_get_event(struct _gfx_driver *drv) +{ + sci_event_t input; + + x_get_event(drv, PointerMotionMask | StructureNotifyMask | ButtonPressMask + | ButtonReleaseMask | KeyPressMask | KeyReleaseMask, + 0, &input); + + return input; +} + + +static int +xlib_usec_sleep(struct _gfx_driver *drv, long usecs) +{ + x_get_event(drv, PointerMotionMask | StructureNotifyMask, usecs, NULL); + return GFX_OK; +} + +gfx_driver_t +gfx_driver_xlib = { + "xlib", + "0.6a", + SCI_GFX_DRIVER_MAGIC, + SCI_GFX_DRIVER_VERSION, + NULL, + 0, 0, + GFX_CAPABILITY_STIPPLED_LINES | GFX_CAPABILITY_MOUSE_SUPPORT + | GFX_CAPABILITY_MOUSE_POINTER | GFX_CAPABILITY_PIXMAP_REGISTRY + | GFX_CAPABILITY_FINE_LINES | GFX_CAPABILITY_WINDOWED + | GFX_CAPABILITY_KEYTRANSLATE, + 0/*GFX_DEBUG_POINTER | GFX_DEBUG_UPDATES | GFX_DEBUG_PIXMAPS | GFX_DEBUG_BASIC*/, + xlib_set_parameter, + xlib_init_specific, + xlib_init, + xlib_exit, + xlib_draw_line, +#ifdef HAVE_RENDER + xlib_draw_filled_rect_RENDER, +#else + xlib_draw_filled_rect, +#endif + xlib_register_pixmap, + xlib_unregister_pixmap, + xlib_draw_pixmap, + xlib_grab_pixmap, + xlib_update, + xlib_set_static_buffer, + xlib_set_pointer, + xlib_set_palette, + xlib_get_event, + xlib_usec_sleep, + NULL +}; + +#endif /* X_DISPLAY_MISSING */ diff --git a/engines/sci/gfx/font-5x8.c b/engines/sci/gfx/font-5x8.c new file mode 100644 index 0000000000..9fe2e587e7 --- /dev/null +++ b/engines/sci/gfx/font-5x8.c @@ -0,0 +1,2580 @@ +/* Auto-generated by bdftofont.c */ + +#include <gfx_system.h> + +static int gfxfont_5x8_widths[] = { + 5, /* 0x00 */ + 5, /* 0x01 */ + 5, /* 0x02 */ + 5, /* 0x03 */ + 5, /* 0x04 */ + 5, /* 0x05 */ + 5, /* 0x06 */ + 5, /* 0x07 */ + 5, /* 0x08 */ + 5, /* 0x09 */ + 5, /* 0x0a */ + 5, /* 0x0b */ + 5, /* 0x0c */ + 5, /* 0x0d */ + 5, /* 0x0e */ + 5, /* 0x0f */ + 5, /* 0x10 */ + 5, /* 0x11 */ + 5, /* 0x12 */ + 5, /* 0x13 */ + 5, /* 0x14 */ + 5, /* 0x15 */ + 5, /* 0x16 */ + 5, /* 0x17 */ + 5, /* 0x18 */ + 5, /* 0x19 */ + 5, /* 0x1a */ + 5, /* 0x1b */ + 5, /* 0x1c */ + 5, /* 0x1d */ + 5, /* 0x1e */ + 5, /* 0x1f */ + 5, /* 0x20 */ + 2, /* 0x21 */ + 4, /* 0x22 */ + 6, /* 0x23 */ + 6, /* 0x24 */ + 6, /* 0x25 */ + 6, /* 0x26 */ + 2, /* 0x27 */ + 3, /* 0x28 */ + 3, /* 0x29 */ + 5, /* 0x2a */ + 6, /* 0x2b */ + 3, /* 0x2c */ + 5, /* 0x2d */ + 2, /* 0x2e */ + 7, /* 0x2f */ + 5, /* 0x30 */ + 4, /* 0x31 */ + 5, /* 0x32 */ + 5, /* 0x33 */ + 5, /* 0x34 */ + 5, /* 0x35 */ + 5, /* 0x36 */ + 5, /* 0x37 */ + 5, /* 0x38 */ + 5, /* 0x39 */ + 2, /* 0x3a */ + 3, /* 0x3b */ + 4, /* 0x3c */ + 5, /* 0x3d */ + 4, /* 0x3e */ + 5, /* 0x3f */ + 6, /* 0x40 */ + 5, /* 0x41 */ + 5, /* 0x42 */ + 5, /* 0x43 */ + 5, /* 0x44 */ + 5, /* 0x45 */ + 5, /* 0x46 */ + 5, /* 0x47 */ + 5, /* 0x48 */ + 4, /* 0x49 */ + 5, /* 0x4a */ + 5, /* 0x4b */ + 5, /* 0x4c */ + 6, /* 0x4d */ + 5, /* 0x4e */ + 5, /* 0x4f */ + 5, /* 0x50 */ + 5, /* 0x51 */ + 5, /* 0x52 */ + 5, /* 0x53 */ + 4, /* 0x54 */ + 5, /* 0x55 */ + 5, /* 0x56 */ + 6, /* 0x57 */ + 5, /* 0x58 */ + 6, /* 0x59 */ + 5, /* 0x5a */ + 4, /* 0x5b */ + 7, /* 0x5c */ + 4, /* 0x5d */ + 4, /* 0x5e */ + 4, /* 0x5f */ + 3, /* 0x60 */ + 5, /* 0x61 */ + 5, /* 0x62 */ + 4, /* 0x63 */ + 5, /* 0x64 */ + 5, /* 0x65 */ + 5, /* 0x66 */ + 5, /* 0x67 */ + 5, /* 0x68 */ + 4, /* 0x69 */ + 4, /* 0x6a */ + 5, /* 0x6b */ + 4, /* 0x6c */ + 6, /* 0x6d */ + 5, /* 0x6e */ + 5, /* 0x6f */ + 5, /* 0x70 */ + 5, /* 0x71 */ + 5, /* 0x72 */ + 4, /* 0x73 */ + 5, /* 0x74 */ + 5, /* 0x75 */ + 4, /* 0x76 */ + 6, /* 0x77 */ + 5, /* 0x78 */ + 5, /* 0x79 */ + 5, /* 0x7a */ + 5, /* 0x7b */ + 2, /* 0x7c */ + 5, /* 0x7d */ + 5, /* 0x7e */ + 5, /* 0x7f */ + 5, /* 0x80 */ + 5, /* 0x81 */ + 5, /* 0x82 */ + 5, /* 0x83 */ + 5, /* 0x84 */ + 5, /* 0x85 */ + 5, /* 0x86 */ + 5, /* 0x87 */ + 5, /* 0x88 */ + 5, /* 0x89 */ + 5, /* 0x8a */ + 5, /* 0x8b */ + 5, /* 0x8c */ + 5, /* 0x8d */ + 5, /* 0x8e */ + 5, /* 0x8f */ + 5, /* 0x90 */ + 5, /* 0x91 */ + 5, /* 0x92 */ + 5, /* 0x93 */ + 5, /* 0x94 */ + 5, /* 0x95 */ + 5, /* 0x96 */ + 5, /* 0x97 */ + 5, /* 0x98 */ + 5, /* 0x99 */ + 5, /* 0x9a */ + 5, /* 0x9b */ + 5, /* 0x9c */ + 5, /* 0x9d */ + 5, /* 0x9e */ + 5, /* 0x9f */ + 5, /* 0xa0 */ + 5, /* 0xa1 */ + 5, /* 0xa2 */ + 5, /* 0xa3 */ + 5, /* 0xa4 */ + 5, /* 0xa5 */ + 5, /* 0xa6 */ + 5, /* 0xa7 */ + 5, /* 0xa8 */ + 5, /* 0xa9 */ + 5, /* 0xaa */ + 5, /* 0xab */ + 5, /* 0xac */ + 5, /* 0xad */ + 5, /* 0xae */ + 5, /* 0xaf */ + 5, /* 0xb0 */ + 5, /* 0xb1 */ + 5, /* 0xb2 */ + 5, /* 0xb3 */ + 5, /* 0xb4 */ + 5, /* 0xb5 */ + 5, /* 0xb6 */ + 5, /* 0xb7 */ + 5, /* 0xb8 */ + 5, /* 0xb9 */ + 5, /* 0xba */ + 5, /* 0xbb */ + 5, /* 0xbc */ + 5, /* 0xbd */ + 5, /* 0xbe */ + 5, /* 0xbf */ + 5, /* 0xc0 */ + 5, /* 0xc1 */ + 5, /* 0xc2 */ + 5, /* 0xc3 */ + 5, /* 0xc4 */ + 5, /* 0xc5 */ + 5, /* 0xc6 */ + 5, /* 0xc7 */ + 5, /* 0xc8 */ + 5, /* 0xc9 */ + 5, /* 0xca */ + 5, /* 0xcb */ + 5, /* 0xcc */ + 5, /* 0xcd */ + 5, /* 0xce */ + 5, /* 0xcf */ + 5, /* 0xd0 */ + 5, /* 0xd1 */ + 5, /* 0xd2 */ + 5, /* 0xd3 */ + 5, /* 0xd4 */ + 5, /* 0xd5 */ + 5, /* 0xd6 */ + 5, /* 0xd7 */ + 5, /* 0xd8 */ + 5, /* 0xd9 */ + 5, /* 0xda */ + 5, /* 0xdb */ + 5, /* 0xdc */ + 5, /* 0xdd */ + 5, /* 0xde */ + 5, /* 0xdf */ + 5, /* 0xe0 */ + 5, /* 0xe1 */ + 5, /* 0xe2 */ + 5, /* 0xe3 */ + 5, /* 0xe4 */ + 5, /* 0xe5 */ + 5, /* 0xe6 */ + 5, /* 0xe7 */ + 5, /* 0xe8 */ + 5, /* 0xe9 */ + 5, /* 0xea */ + 5, /* 0xeb */ + 5, /* 0xec */ + 5, /* 0xed */ + 5, /* 0xee */ + 5, /* 0xef */ + 5, /* 0xf0 */ + 5, /* 0xf1 */ + 5, /* 0xf2 */ + 5, /* 0xf3 */ + 5, /* 0xf4 */ + 5, /* 0xf5 */ + 5, /* 0xf6 */ + 5, /* 0xf7 */ + 5, /* 0xf8 */ + 5, /* 0xf9 */ + 5, /* 0xfa */ + 5, /* 0xfb */ + 5, /* 0xfc */ + 5, /* 0xfd */ + 5, /* 0xfe */ + 5 /* 0xff */ +}; + +static unsigned char gfxfont_5x8_data[] = { + /* 0x00 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x01 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x02 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x03 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x04 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x05 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x06 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x07 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x08 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x09 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0a ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0b ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0c ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0d ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0e ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x0f ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x10 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x11 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x12 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x13 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x14 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x15 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x16 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x17 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x18 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x19 ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1a ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1b ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1c ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1d ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1e ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x1f ('.') */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x10, /* ......##.. */ + 0x80, /* ##........ */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0x20 (' ') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x21 ('!') */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x00, /* .... */ + /* 0x22 ('"') */ + 0x00, /* ........ */ + 0xa0, /* ##..##.. */ + 0xa0, /* ##..##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x23 ('#') */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + /* 0x24 ('$') */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0xa0, /* ##..##...... */ + 0x70, /* ..######.... */ + 0x28, /* ....##..##.. */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + /* 0x25 ('%') */ + 0x00, /* ............ */ + 0xc8, /* ####....##.. */ + 0x90, /* ##....##.... */ + 0x20, /* ....##...... */ + 0x48, /* ..##....##.. */ + 0x98, /* ##....####.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x26 ('&') */ + 0x40, /* ..##........ */ + 0xa0, /* ##..##...... */ + 0xa0, /* ##..##...... */ + 0x40, /* ..##........ */ + 0xb8, /* ##..######.. */ + 0x90, /* ##....##.... */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + /* 0x27 (''') */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + /* 0x28 ('(') */ + 0x00, /* ...... */ + 0x40, /* ..##.. */ + 0x80, /* ##.... */ + 0x80, /* ##.... */ + 0x80, /* ##.... */ + 0x80, /* ##.... */ + 0x40, /* ..##.. */ + 0x00, /* ...... */ + /* 0x29 (')') */ + 0x00, /* ...... */ + 0x80, /* ##.... */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x80, /* ##.... */ + 0x00, /* ...... */ + /* 0x2a ('*') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0xf0, /* ########.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x2b ('+') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + /* 0x2c (',') */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x80, /* ##.... */ + /* 0x2d ('-') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x2e ('.') */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x00, /* .... */ + /* 0x2f ('/') */ + 0x00, /* .............. */ + 0x04, /* ..........##.. */ + 0x08, /* ........##.... */ + 0x10, /* ......##...... */ + 0x20, /* ....##........ */ + 0x40, /* ..##.......... */ + 0x80, /* ##............ */ + 0x00, /* .............. */ + /* 0x30 ('0') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x31 ('1') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x32 ('2') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0x33 ('3') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0x10, /* ......##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x34 ('4') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0xa0, /* ##..##.... */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x35 ('5') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x10, /* ......##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x36 ('6') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x37 ('7') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + /* 0x38 ('8') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x39 ('9') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x3a (':') */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x00, /* .... */ + 0x00, /* .... */ + /* 0x3b (';') */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x40, /* ..##.. */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x80, /* ##.... */ + /* 0x3c ('<') */ + 0x00, /* ........ */ + 0x20, /* ....##.. */ + 0x40, /* ..##.... */ + 0x80, /* ##...... */ + 0x80, /* ##...... */ + 0x40, /* ..##.... */ + 0x20, /* ....##.. */ + 0x00, /* ........ */ + /* 0x3d ('=') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x3e ('>') */ + 0x00, /* ........ */ + 0x80, /* ##...... */ + 0x40, /* ..##.... */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0x40, /* ..##.... */ + 0x80, /* ##...... */ + 0x00, /* ........ */ + /* 0x3f ('?') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x40 ('@') */ + 0x30, /* ....####.... */ + 0x48, /* ..##....##.. */ + 0x98, /* ##....####.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0x90, /* ##....##.... */ + 0x40, /* ..##........ */ + 0x30, /* ....####.... */ + /* 0x41 ('A') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x42 ('B') */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0x43 ('C') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x44 ('D') */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0x45 ('E') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0x46 ('F') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x00, /* .......... */ + /* 0x47 ('G') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x48 ('H') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x49 ('I') */ + 0x00, /* ........ */ + 0xe0, /* ######.. */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x4a ('J') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0xa0, /* ##..##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + /* 0x4b ('K') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0xa0, /* ##..##.... */ + 0xc0, /* ####...... */ + 0xa0, /* ##..##.... */ + 0xa0, /* ##..##.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x4c ('L') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0x4d ('M') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0xd8, /* ####..####.. */ + 0xa8, /* ##..##..##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + /* 0x4e ('N') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0xd0, /* ####..##.. */ + 0xd0, /* ####..##.. */ + 0xb0, /* ##..####.. */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x4f ('O') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x50 ('P') */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x00, /* .......... */ + /* 0x51 ('Q') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xb0, /* ##..####.. */ + 0x60, /* ..####.... */ + 0x10, /* ......##.. */ + /* 0x52 ('R') */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x53 ('S') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x54 ('T') */ + 0x00, /* ........ */ + 0xe0, /* ######.. */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + /* 0x55 ('U') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x56 ('V') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xa0, /* ##..##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + /* 0x57 ('W') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0xd8, /* ####..####.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + /* 0x58 ('X') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x59 ('Y') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + /* 0x5a ('Z') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0x5b ('[') */ + 0x00, /* ........ */ + 0xe0, /* ######.. */ + 0x80, /* ##...... */ + 0x80, /* ##...... */ + 0x80, /* ##...... */ + 0x80, /* ##...... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x5c ('\') */ + 0x00, /* .............. */ + 0x80, /* ##............ */ + 0x40, /* ..##.......... */ + 0x20, /* ....##........ */ + 0x10, /* ......##...... */ + 0x08, /* ........##.... */ + 0x04, /* ..........##.. */ + 0x00, /* .............. */ + /* 0x5d (']') */ + 0x00, /* ........ */ + 0xe0, /* ######.. */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x5e ('^') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0xa0, /* ##..##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x5f ('_') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xf0, /* ######## */ + /* 0x60 ('`') */ + 0x00, /* ...... */ + 0x80, /* ##.... */ + 0x40, /* ..##.. */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + /* 0x61 ('a') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x62 ('b') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0x63 ('c') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x60, /* ..####.. */ + 0x80, /* ##...... */ + 0x80, /* ##...... */ + 0x60, /* ..####.. */ + 0x00, /* ........ */ + /* 0x64 ('d') */ + 0x00, /* .......... */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x65 ('e') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x66 ('f') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x40, /* ..##...... */ + 0xe0, /* ######.... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + /* 0x67 ('g') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + /* 0x68 ('h') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x69 ('i') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x6a ('j') */ + 0x00, /* ........ */ + 0x20, /* ....##.. */ + 0x00, /* ........ */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0x20, /* ....##.. */ + 0xa0, /* ##..##.. */ + 0x40, /* ..##.... */ + /* 0x6b ('k') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x6c ('l') */ + 0x00, /* ........ */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + /* 0x6d ('m') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xd0, /* ####..##.... */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + /* 0x6e ('n') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x6f ('o') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0x70 ('p') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + /* 0x71 ('q') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + /* 0x72 ('r') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0xd0, /* ####..##.. */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x00, /* .......... */ + /* 0x73 ('s') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x60, /* ..####.. */ + 0xc0, /* ####.... */ + 0x20, /* ....##.. */ + 0xc0, /* ####.... */ + 0x00, /* ........ */ + /* 0x74 ('t') */ + 0x00, /* .......... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0xe0, /* ######.... */ + 0x40, /* ..##...... */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x75 ('u') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x76 ('v') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xa0, /* ##..##.. */ + 0xa0, /* ##..##.. */ + 0xa0, /* ##..##.. */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + /* 0x77 ('w') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + /* 0x78 ('x') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0x79 ('y') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + /* 0x7a ('z') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0x7b ('{') */ + 0x30, /* ....####.. */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0xc0, /* ####...... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x30, /* ....####.. */ + 0x00, /* .......... */ + /* 0x7c ('|') */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x00, /* .... */ + /* 0x7d ('}') */ + 0xc0, /* ####...... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x30, /* ....####.. */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0xc0, /* ####...... */ + 0x00, /* .......... */ + /* 0x7e ('~') */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x7f ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x80 ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x81 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0xa0, /* ##..##.... */ + 0xa0, /* ##..##.... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + /* 0x82 ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0xe0, /* ######.... */ + 0x40, /* ..##...... */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + /* 0x83 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x88, /* ##......## */ + 0x70, /* ..######.. */ + 0x50, /* ..##..##.. */ + 0x70, /* ..######.. */ + 0x88, /* ##......## */ + 0x00, /* .......... */ + /* 0x84 ('.') */ + 0x00, /* .......... */ + 0x88, /* ##......## */ + 0x50, /* ..##..##.. */ + 0xf8, /* ########## */ + 0x20, /* ....##.... */ + 0xf8, /* ########## */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x85 ('.') */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x86 ('.') */ + 0x70, /* ..######.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0x87 ('.') */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x88 ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0xa8, /* ##..##..## */ + 0xc8, /* ####....## */ + 0xc8, /* ####....## */ + 0xa8, /* ##..##..## */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x89 ('.') */ + 0x30, /* ....####.. */ + 0x50, /* ..##..##.. */ + 0x30, /* ....####.. */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x8a ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x8b ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x00, /* .......... */ + /* 0x8c ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x8d ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0xe8, /* ######..## */ + 0xd8, /* ####..#### */ + 0xe8, /* ######..## */ + 0xd8, /* ####..#### */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x8e ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x8f ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x90 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x91 ('.') */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x92 ('.') */ + 0x60, /* ..####.... */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x93 ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x94 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + /* 0x95 ('.') */ + 0x00, /* .......... */ + 0x78, /* ..######## */ + 0xe8, /* ######..## */ + 0xe8, /* ######..## */ + 0x68, /* ..####..## */ + 0x28, /* ....##..## */ + 0x28, /* ....##..## */ + 0x00, /* .......... */ + /* 0x96 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x97 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + /* 0x98 ('.') */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x99 ('.') */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x9a ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xa0, /* ##..##.... */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x9b ('.') */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xa0, /* ##..##.... */ + 0x60, /* ..####.... */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x9c ('.') */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xa0, /* ##..##.... */ + 0xd0, /* ####..##.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0x9d ('.') */ + 0x80, /* ##........ */ + 0x40, /* ..##...... */ + 0x80, /* ##........ */ + 0x60, /* ..####.... */ + 0xa0, /* ##..##.... */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x9e ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0x9f ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa0 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa1 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa2 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa3 ('.') */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa4 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xa5 ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0xa0, /* ##..##.... */ + 0xa0, /* ##..##.... */ + 0xf0, /* ########.. */ + 0xa0, /* ##..##.... */ + 0xb0, /* ##..####.. */ + 0x00, /* .......... */ + /* 0xa6 ('.') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x40, /* ..##...... */ + /* 0xa7 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xa8 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xa9 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xaa ('.') */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xab ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xac ('.') */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xad ('.') */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xae ('.') */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xaf ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x48, /* ..##....## */ + 0xe8, /* ######..## */ + 0x48, /* ..##....## */ + 0x48, /* ..##....## */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xb0 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x90, /* ##....##.. */ + 0xd0, /* ####..##.. */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xb1 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb2 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb3 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb4 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb5 ('.') */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb6 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + /* 0xb7 ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0xb0, /* ##..####.. */ + 0xb0, /* ##..####.. */ + 0xd0, /* ####..##.. */ + 0xd0, /* ####..##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0xb8 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xb9 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xba ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xbb ('.') */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xbc ('.') */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x88, /* ##......## */ + 0x50, /* ..##..##.. */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0xbd ('.') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x00, /* .......... */ + /* 0xbe ('.') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xa0, /* ##..##.... */ + 0xa0, /* ##..##.... */ + 0x90, /* ##....##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + /* 0xbf ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc0 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc1 ('.') */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc2 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc3 ('.') */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc4 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xc5 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x68, /* ..####..## */ + 0xb0, /* ##..####.. */ + 0x78, /* ..######## */ + 0x00, /* .......... */ + /* 0xc6 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x30, /* ....####.. */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x30, /* ....####.. */ + 0x20, /* ....##.... */ + /* 0xc7 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xc8 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xc9 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xca ('.') */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xcb ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xcc ('.') */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xcd ('.') */ + 0x20, /* ....##.... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xce ('.') */ + 0x00, /* .......... */ + 0x50, /* ..##..##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xcf ('.') */ + 0xa0, /* ##..##.... */ + 0x40, /* ..##...... */ + 0xa0, /* ##..##.... */ + 0x10, /* ......##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd0 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xd1 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd2 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd3 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd4 ('.') */ + 0x50, /* ..##..##.. */ + 0xa0, /* ##..##.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd5 ('.') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xd6 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + /* 0xd7 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0xb0, /* ##..####.. */ + 0xd0, /* ####..##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0xd8 ('.') */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xd9 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xda ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xdb ('.') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xdc ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + /* 0xdd ('.') */ + 0x00, /* .......... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + /* 0xde ('.') */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + /* 0xdf ('.') */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xe0 ('.') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xe1 ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + /* 0xe2 ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xe3 ('.') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xf0, /* ########.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x30, /* ....####.. */ + /* 0xe4 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + /* 0xe5 ('.') */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xe6 ('.') */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x30, /* ....####.. */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x30, /* ....####.. */ + 0x00, /* .......... */ + /* 0xe7 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xe8 ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xe9 ('.') */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xea ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x00, /* .......... */ + 0x30, /* ....####.. */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x30, /* ....####.. */ + 0x00, /* .......... */ + /* 0xeb ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x80, /* ##........ */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xec ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xed ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0xe0, /* ######.... */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0xe0, /* ######.... */ + 0x00, /* .......... */ + /* 0xee ('.') */ + 0xa0, /* ##..##.... */ + 0x50, /* ..##..##.. */ + 0x10, /* ......##.. */ + 0x70, /* ..######.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xef ('.') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x48, /* ..##....## */ + 0xe8, /* ######..## */ + 0x48, /* ..##....## */ + 0x48, /* ..##....## */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + /* 0xf0 ('.') */ + 0x00, /* .......... */ + 0x20, /* ....##.... */ + 0x70, /* ..######.. */ + 0x20, /* ....##.... */ + 0x60, /* ..####.... */ + 0xa0, /* ##..##.... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xf1 ('.') */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xf2 ('.') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xf3 ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xf4 ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xf5 ('.') */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xf6 ('.') */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xf7 ('.') */ + 0x00, /* .......... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x20, /* ....##.... */ + /* 0xf8 ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x20, /* ....##.... */ + /* 0xf9 ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0xf0, /* ########.. */ + 0x80, /* ##........ */ + 0xe0, /* ######.... */ + 0x80, /* ##........ */ + 0xf0, /* ########.. */ + 0x00, /* .......... */ + /* 0xfa ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0xb0, /* ##..####.. */ + 0xc0, /* ####...... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xfb ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x80, /* ##........ */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xfc ('.') */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + /* 0xfd ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x70, /* ..######.. */ + 0x80, /* ##........ */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + /* 0xfe ('.') */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x90, /* ##....##.. */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x60, /* ..####.... */ + /* 0xff ('.') */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x80, /* ##........ */ + 0xb0, /* ##..####.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + 0x00 /* .......... */ +}; + +gfx_bitmap_font_t gfxfont_5x8 = { + -1, /* resource ID */ + 256, /* # of characters */ + gfxfont_5x8_widths, /* Widths */ + 1, /* Bytes per row */ + 9, /* Line height */ + 8, /* Char height */ + 8, /* Char size (occupied, in bytes) */ + gfxfont_5x8_data /* Bulk data */ +}; diff --git a/engines/sci/gfx/font-6x10.c b/engines/sci/gfx/font-6x10.c new file mode 100644 index 0000000000..11919c00bd --- /dev/null +++ b/engines/sci/gfx/font-6x10.c @@ -0,0 +1,3092 @@ +/* Auto-generated by bdftofont.c */ + +#include <gfx_system.h> + +static int gfxfont_6x10_widths[] = { + 6, /* 0x00 */ + 6, /* 0x01 */ + 6, /* 0x02 */ + 6, /* 0x03 */ + 6, /* 0x04 */ + 6, /* 0x05 */ + 6, /* 0x06 */ + 6, /* 0x07 */ + 6, /* 0x08 */ + 6, /* 0x09 */ + 6, /* 0x0a */ + 6, /* 0x0b */ + 6, /* 0x0c */ + 6, /* 0x0d */ + 6, /* 0x0e */ + 6, /* 0x0f */ + 6, /* 0x10 */ + 6, /* 0x11 */ + 6, /* 0x12 */ + 6, /* 0x13 */ + 6, /* 0x14 */ + 6, /* 0x15 */ + 6, /* 0x16 */ + 6, /* 0x17 */ + 6, /* 0x18 */ + 6, /* 0x19 */ + 6, /* 0x1a */ + 6, /* 0x1b */ + 6, /* 0x1c */ + 6, /* 0x1d */ + 6, /* 0x1e */ + 6, /* 0x1f */ + 4, /* 0x20 */ + 4, /* 0x21 */ + 4, /* 0x22 */ + 6, /* 0x23 */ + 6, /* 0x24 */ + 6, /* 0x25 */ + 6, /* 0x26 */ + 2, /* 0x27 */ + 5, /* 0x28 */ + 5, /* 0x29 */ + 6, /* 0x2a */ + 6, /* 0x2b */ + 4, /* 0x2c */ + 6, /* 0x2d */ + 5, /* 0x2e */ + 7, /* 0x2f */ + 6, /* 0x30 */ + 4, /* 0x31 */ + 6, /* 0x32 */ + 6, /* 0x33 */ + 6, /* 0x34 */ + 6, /* 0x35 */ + 6, /* 0x36 */ + 6, /* 0x37 */ + 6, /* 0x38 */ + 6, /* 0x39 */ + 5, /* 0x3a */ + 5, /* 0x3b */ + 6, /* 0x3c */ + 6, /* 0x3d */ + 6, /* 0x3e */ + 6, /* 0x3f */ + 6, /* 0x40 */ + 6, /* 0x41 */ + 6, /* 0x42 */ + 6, /* 0x43 */ + 6, /* 0x44 */ + 6, /* 0x45 */ + 6, /* 0x46 */ + 6, /* 0x47 */ + 6, /* 0x48 */ + 4, /* 0x49 */ + 6, /* 0x4a */ + 6, /* 0x4b */ + 6, /* 0x4c */ + 6, /* 0x4d */ + 6, /* 0x4e */ + 6, /* 0x4f */ + 6, /* 0x50 */ + 6, /* 0x51 */ + 6, /* 0x52 */ + 6, /* 0x53 */ + 6, /* 0x54 */ + 6, /* 0x55 */ + 6, /* 0x56 */ + 6, /* 0x57 */ + 6, /* 0x58 */ + 6, /* 0x59 */ + 6, /* 0x5a */ + 5, /* 0x5b */ + 7, /* 0x5c */ + 5, /* 0x5d */ + 6, /* 0x5e */ + 5, /* 0x5f */ + 3, /* 0x60 */ + 6, /* 0x61 */ + 6, /* 0x62 */ + 6, /* 0x63 */ + 6, /* 0x64 */ + 6, /* 0x65 */ + 6, /* 0x66 */ + 6, /* 0x67 */ + 6, /* 0x68 */ + 4, /* 0x69 */ + 5, /* 0x6a */ + 6, /* 0x6b */ + 4, /* 0x6c */ + 6, /* 0x6d */ + 6, /* 0x6e */ + 6, /* 0x6f */ + 6, /* 0x70 */ + 6, /* 0x71 */ + 6, /* 0x72 */ + 6, /* 0x73 */ + 6, /* 0x74 */ + 6, /* 0x75 */ + 6, /* 0x76 */ + 6, /* 0x77 */ + 6, /* 0x78 */ + 6, /* 0x79 */ + 6, /* 0x7a */ + 6, /* 0x7b */ + 3, /* 0x7c */ + 6, /* 0x7d */ + 6, /* 0x7e */ + 6, /* 0x7f */ + 6, /* 0x80 */ + 6, /* 0x81 */ + 6, /* 0x82 */ + 6, /* 0x83 */ + 6, /* 0x84 */ + 6, /* 0x85 */ + 6, /* 0x86 */ + 6, /* 0x87 */ + 6, /* 0x88 */ + 6, /* 0x89 */ + 6, /* 0x8a */ + 6, /* 0x8b */ + 6, /* 0x8c */ + 6, /* 0x8d */ + 6, /* 0x8e */ + 6, /* 0x8f */ + 6, /* 0x90 */ + 6, /* 0x91 */ + 6, /* 0x92 */ + 6, /* 0x93 */ + 6, /* 0x94 */ + 6, /* 0x95 */ + 6, /* 0x96 */ + 6, /* 0x97 */ + 6, /* 0x98 */ + 6, /* 0x99 */ + 6, /* 0x9a */ + 6, /* 0x9b */ + 6, /* 0x9c */ + 6, /* 0x9d */ + 6, /* 0x9e */ + 6, /* 0x9f */ + 6, /* 0xa0 */ + 6, /* 0xa1 */ + 6, /* 0xa2 */ + 6, /* 0xa3 */ + 6, /* 0xa4 */ + 6, /* 0xa5 */ + 6, /* 0xa6 */ + 6, /* 0xa7 */ + 6, /* 0xa8 */ + 6, /* 0xa9 */ + 6, /* 0xaa */ + 6, /* 0xab */ + 6, /* 0xac */ + 6, /* 0xad */ + 6, /* 0xae */ + 6, /* 0xaf */ + 6, /* 0xb0 */ + 6, /* 0xb1 */ + 6, /* 0xb2 */ + 6, /* 0xb3 */ + 6, /* 0xb4 */ + 6, /* 0xb5 */ + 6, /* 0xb6 */ + 6, /* 0xb7 */ + 6, /* 0xb8 */ + 6, /* 0xb9 */ + 6, /* 0xba */ + 6, /* 0xbb */ + 6, /* 0xbc */ + 6, /* 0xbd */ + 6, /* 0xbe */ + 6, /* 0xbf */ + 6, /* 0xc0 */ + 6, /* 0xc1 */ + 6, /* 0xc2 */ + 6, /* 0xc3 */ + 6, /* 0xc4 */ + 6, /* 0xc5 */ + 6, /* 0xc6 */ + 6, /* 0xc7 */ + 6, /* 0xc8 */ + 6, /* 0xc9 */ + 6, /* 0xca */ + 6, /* 0xcb */ + 6, /* 0xcc */ + 6, /* 0xcd */ + 6, /* 0xce */ + 6, /* 0xcf */ + 6, /* 0xd0 */ + 6, /* 0xd1 */ + 6, /* 0xd2 */ + 6, /* 0xd3 */ + 6, /* 0xd4 */ + 6, /* 0xd5 */ + 6, /* 0xd6 */ + 6, /* 0xd7 */ + 6, /* 0xd8 */ + 6, /* 0xd9 */ + 6, /* 0xda */ + 6, /* 0xdb */ + 6, /* 0xdc */ + 6, /* 0xdd */ + 6, /* 0xde */ + 6, /* 0xdf */ + 6, /* 0xe0 */ + 6, /* 0xe1 */ + 6, /* 0xe2 */ + 6, /* 0xe3 */ + 6, /* 0xe4 */ + 6, /* 0xe5 */ + 6, /* 0xe6 */ + 6, /* 0xe7 */ + 6, /* 0xe8 */ + 6, /* 0xe9 */ + 6, /* 0xea */ + 6, /* 0xeb */ + 6, /* 0xec */ + 6, /* 0xed */ + 6, /* 0xee */ + 6, /* 0xef */ + 6, /* 0xf0 */ + 6, /* 0xf1 */ + 6, /* 0xf2 */ + 6, /* 0xf3 */ + 6, /* 0xf4 */ + 6, /* 0xf5 */ + 6, /* 0xf6 */ + 6, /* 0xf7 */ + 6, /* 0xf8 */ + 6, /* 0xf9 */ + 6, /* 0xfa */ + 6, /* 0xfb */ + 6, /* 0xfc */ + 6, /* 0xfd */ + 6, /* 0xfe */ + 6 /* 0xff */ +}; + +static unsigned char gfxfont_6x10_data[] = { + /* 0x00 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x01 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x02 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x03 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x04 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x05 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x06 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x07 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x08 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x09 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0a ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0b ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0c ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0d ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0e ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x0f ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x10 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x11 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x12 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x13 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x14 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x15 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x16 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x17 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x18 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x19 ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1a ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1b ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1c ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1d ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1e ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x1f ('.') */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0xa8, /* ##..##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x20 (' ') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x21 ('!') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x22 ('"') */ + 0x00, /* ........ */ + 0xa0, /* ##..##.. */ + 0xa0, /* ##..##.. */ + 0xa0, /* ##..##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x23 ('#') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x24 ('$') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0xa0, /* ##..##...... */ + 0x70, /* ..######.... */ + 0x28, /* ....##..##.. */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x25 ('%') */ + 0x00, /* ............ */ + 0x48, /* ..##....##.. */ + 0xa8, /* ##..##..##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0xa8, /* ##..##..##.. */ + 0x90, /* ##....##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x26 ('&') */ + 0x00, /* ............ */ + 0x40, /* ..##........ */ + 0xa0, /* ##..##...... */ + 0xa0, /* ##..##...... */ + 0x40, /* ..##........ */ + 0xa8, /* ##..##..##.. */ + 0x90, /* ##....##.... */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x27 (''') */ + 0x00, /* .... */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x80, /* ##.. */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + 0x00, /* .... */ + /* 0x28 ('(') */ + 0x00, /* .......... */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x10, /* ......##.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x29 (')') */ + 0x00, /* .......... */ + 0x40, /* ..##...... */ + 0x20, /* ....##.... */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x20, /* ....##.... */ + 0x40, /* ..##...... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x2a ('*') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x2b ('+') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x2c (',') */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x60, /* ..####.. */ + 0x40, /* ..##.... */ + 0x80, /* ##...... */ + 0x00, /* ........ */ + /* 0x2d ('-') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x2e ('.') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x2f ('/') */ + 0x00, /* .............. */ + 0x02, /* ............## */ + 0x04, /* ..........##.. */ + 0x08, /* ........##.... */ + 0x10, /* ......##...... */ + 0x20, /* ....##........ */ + 0x40, /* ..##.......... */ + 0x80, /* ##............ */ + 0x00, /* .............. */ + 0x00, /* .............. */ + /* 0x30 ('0') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x31 ('1') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x32 ('2') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x08, /* ........##.. */ + 0x30, /* ....####.... */ + 0x40, /* ..##........ */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x33 ('3') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x30, /* ....####.... */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x34 ('4') */ + 0x00, /* ............ */ + 0x10, /* ......##.... */ + 0x30, /* ....####.... */ + 0x50, /* ..##..##.... */ + 0x90, /* ##....##.... */ + 0xf8, /* ##########.. */ + 0x10, /* ......##.... */ + 0x10, /* ......##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x35 ('5') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x36 ('6') */ + 0x00, /* ............ */ + 0x30, /* ....####.... */ + 0x40, /* ..##........ */ + 0x80, /* ##.......... */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x37 ('7') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x38 ('8') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x39 ('9') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x60, /* ..####...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x3a (':') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x3b (';') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x60, /* ..####.... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x60, /* ..####.... */ + 0x40, /* ..##...... */ + 0x80, /* ##........ */ + 0x00, /* .......... */ + /* 0x3c ('<') */ + 0x00, /* ............ */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x10, /* ......##.... */ + 0x08, /* ........##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x3d ('=') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x3e ('>') */ + 0x00, /* ............ */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x10, /* ......##.... */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x3f ('?') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x40 ('@') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0xa8, /* ##..##..##.. */ + 0xb0, /* ##..####.... */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x41 ('A') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x42 ('B') */ + 0x00, /* ............ */ + 0xf0, /* ########.... */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0x70, /* ..######.... */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x43 ('C') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x44 ('D') */ + 0x00, /* ............ */ + 0xf0, /* ########.... */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x45 ('E') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x46 ('F') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x47 ('G') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x48 ('H') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x49 ('I') */ + 0x00, /* ........ */ + 0xe0, /* ######.. */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x4a ('J') */ + 0x00, /* ............ */ + 0x38, /* ....######.. */ + 0x10, /* ......##.... */ + 0x10, /* ......##.... */ + 0x10, /* ......##.... */ + 0x10, /* ......##.... */ + 0x90, /* ##....##.... */ + 0x60, /* ..####...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x4b ('K') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x90, /* ##....##.... */ + 0xa0, /* ##..##...... */ + 0xc0, /* ####........ */ + 0xa0, /* ##..##...... */ + 0x90, /* ##....##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x4c ('L') */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x4d ('M') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xd8, /* ####..####.. */ + 0xa8, /* ##..##..##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x4e ('N') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xc8, /* ####....##.. */ + 0xa8, /* ##..##..##.. */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x4f ('O') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x50 ('P') */ + 0x00, /* ............ */ + 0xf0, /* ########.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x51 ('Q') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x00, /* ............ */ + /* 0x52 ('R') */ + 0x00, /* ............ */ + 0xf0, /* ########.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf0, /* ########.... */ + 0xa0, /* ##..##...... */ + 0x90, /* ##....##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x53 ('S') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x54 ('T') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x55 ('U') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x56 ('V') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x57 ('W') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0xd8, /* ####..####.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x58 ('X') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x59 ('Y') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x5a ('Z') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x08, /* ........##.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x5b ('[') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x40, /* ..##...... */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x5c ('\') */ + 0x00, /* .............. */ + 0x80, /* ##............ */ + 0x40, /* ..##.......... */ + 0x20, /* ....##........ */ + 0x10, /* ......##...... */ + 0x08, /* ........##.... */ + 0x04, /* ..........##.. */ + 0x02, /* ............## */ + 0x00, /* .............. */ + 0x00, /* .............. */ + /* 0x5d (']') */ + 0x00, /* .......... */ + 0x70, /* ..######.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x70, /* ..######.. */ + 0x00, /* .......... */ + 0x00, /* .......... */ + /* 0x5e ('^') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x5f ('_') */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0x00, /* .......... */ + 0xf8, /* ########## */ + 0x00, /* .......... */ + /* 0x60 ('`') */ + 0x80, /* ##.... */ + 0x40, /* ..##.. */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + 0x00, /* ...... */ + /* 0x61 ('a') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x62 ('b') */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0xc8, /* ####....##.. */ + 0xb0, /* ##..####.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x63 ('c') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x64 ('d') */ + 0x00, /* ............ */ + 0x08, /* ........##.. */ + 0x08, /* ........##.. */ + 0x68, /* ..####..##.. */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x65 ('e') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x66 ('f') */ + 0x00, /* ............ */ + 0x30, /* ....####.... */ + 0x48, /* ..##....##.. */ + 0x40, /* ..##........ */ + 0xf0, /* ########.... */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x67 ('g') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0x68 ('h') */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x69 ('i') */ + 0x00, /* ........ */ + 0x40, /* ..##.... */ + 0x00, /* ........ */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6a ('j') */ + 0x00, /* .......... */ + 0x10, /* ......##.. */ + 0x00, /* .......... */ + 0x30, /* ....####.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x10, /* ......##.. */ + 0x90, /* ##....##.. */ + 0x90, /* ##....##.. */ + 0x60, /* ..####.... */ + /* 0x6b ('k') */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x90, /* ##....##.... */ + 0xe0, /* ######...... */ + 0x90, /* ##....##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x6c ('l') */ + 0x00, /* ........ */ + 0xc0, /* ####.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0x40, /* ..##.... */ + 0xe0, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + /* 0x6d ('m') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xd0, /* ####..##.... */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x6e ('n') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x6f ('o') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x70 ('p') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0xc8, /* ####....##.. */ + 0xb0, /* ##..####.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + /* 0x71 ('q') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x68, /* ..####..##.. */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x08, /* ........##.. */ + 0x08, /* ........##.. */ + /* 0x72 ('r') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x73 ('s') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x74 ('t') */ + 0x00, /* ............ */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0xf0, /* ########.... */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0x48, /* ..##....##.. */ + 0x30, /* ....####.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x75 ('u') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x76 ('v') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x77 ('w') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0xa8, /* ##..##..##.. */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x78 ('x') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x79 ('y') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0x7a ('z') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x7b ('{') */ + 0x00, /* ............ */ + 0x18, /* ......####.. */ + 0x20, /* ....##...... */ + 0x10, /* ......##.... */ + 0x60, /* ..####...... */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x18, /* ......####.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x7c ('|') */ + 0x00, /* ...... */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x40, /* ..##.. */ + 0x00, /* ...... */ + 0x00, /* ...... */ + /* 0x7d ('}') */ + 0x00, /* ............ */ + 0x60, /* ..####...... */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x18, /* ......####.. */ + 0x20, /* ....##...... */ + 0x10, /* ......##.... */ + 0x60, /* ..####...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x7e ('~') */ + 0x00, /* ............ */ + 0x48, /* ..##....##.. */ + 0xa8, /* ##..##..##.. */ + 0x90, /* ##....##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x7f ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x80 ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x81 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x78, /* ..########.. */ + 0xa0, /* ##..##...... */ + 0xa0, /* ##..##...... */ + 0xa0, /* ##..##...... */ + 0x78, /* ..########.. */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + /* 0x82 ('.') */ + 0x00, /* ............ */ + 0x30, /* ....####.... */ + 0x48, /* ..##....##.. */ + 0x40, /* ..##........ */ + 0xe0, /* ######...... */ + 0x40, /* ..##........ */ + 0x48, /* ..##....##.. */ + 0xb0, /* ##..####.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x83 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x84 ('.') */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + /* 0x85 ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x86 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x80, /* ##.......... */ + 0xe0, /* ######...... */ + 0x90, /* ##....##.... */ + 0x48, /* ..##....##.. */ + 0x38, /* ....######.. */ + 0x08, /* ........##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + /* 0x87 ('.') */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x88 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xa8, /* ##..##..##.. */ + 0xc8, /* ####....##.. */ + 0xa8, /* ##..##..##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x89 ('.') */ + 0x00, /* ............ */ + 0x38, /* ....######.. */ + 0x48, /* ..##....##.. */ + 0x58, /* ..##..####.. */ + 0x28, /* ....##..##.. */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8a ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x24, /* ....##....## */ + 0x48, /* ..##....##.. */ + 0x90, /* ##....##.... */ + 0x48, /* ..##....##.. */ + 0x24, /* ....##....## */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8b ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x08, /* ........##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8c ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8d ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xe8, /* ######..##.. */ + 0xc8, /* ####....##.. */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8e ('.') */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x8f ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x90 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x91 ('.') */ + 0x30, /* ....####.... */ + 0x48, /* ..##....##.. */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x92 ('.') */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x30, /* ....####.... */ + 0x08, /* ........##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x93 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x94 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xc8, /* ####....##.. */ + 0xb0, /* ##..####.... */ + 0x80, /* ##.......... */ + 0x00, /* ............ */ + /* 0x95 ('.') */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0xe8, /* ######..##.. */ + 0xe8, /* ######..##.. */ + 0x68, /* ..####..##.. */ + 0x28, /* ....##..##.. */ + 0x28, /* ....##..##.. */ + 0x28, /* ....##..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x96 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x97 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + /* 0x98 ('.') */ + 0x20, /* ....##...... */ + 0x60, /* ..####...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x99 ('.') */ + 0x00, /* ............ */ + 0x30, /* ....####.... */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0x30, /* ....####.... */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x9a ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x90, /* ##....##.... */ + 0x48, /* ..##....##.. */ + 0x24, /* ....##....## */ + 0x48, /* ..##....##.. */ + 0x90, /* ##....##.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x9b ('.') */ + 0x40, /* ..##........ */ + 0xc0, /* ####........ */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0xe4, /* ######....## */ + 0x0c, /* ........#### */ + 0x14, /* ......##..## */ + 0x3c, /* ....######## */ + 0x04, /* ..........## */ + 0x00, /* ............ */ + /* 0x9c ('.') */ + 0x40, /* ..##........ */ + 0xc0, /* ####........ */ + 0x40, /* ..##........ */ + 0x40, /* ..##........ */ + 0xe8, /* ######..##.. */ + 0x14, /* ......##..## */ + 0x04, /* ..........## */ + 0x08, /* ........##.. */ + 0x1c, /* ......###### */ + 0x00, /* ............ */ + /* 0x9d ('.') */ + 0xc0, /* ####........ */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0xc8, /* ####....##.. */ + 0x18, /* ......####.. */ + 0x28, /* ....##..##.. */ + 0x78, /* ..########.. */ + 0x08, /* ........##.. */ + 0x00, /* ............ */ + /* 0x9e ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0x9f ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa0 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa1 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa2 ('.') */ + 0x48, /* ..##....##.. */ + 0xb0, /* ##..####.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa3 ('.') */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa4 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa5 ('.') */ + 0x00, /* ............ */ + 0x3c, /* ....######## */ + 0x50, /* ..##..##.... */ + 0x90, /* ##....##.... */ + 0x9c, /* ##....###### */ + 0xf0, /* ########.... */ + 0x90, /* ##....##.... */ + 0x9c, /* ##....###### */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa6 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + /* 0xa7 ('.') */ + 0x40, /* ..##........ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa8 ('.') */ + 0x10, /* ......##.... */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xa9 ('.') */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xaa ('.') */ + 0x50, /* ..##..##.... */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xab ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xac ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xad ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xae ('.') */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xaf ('.') */ + 0x00, /* ............ */ + 0xf0, /* ########.... */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0xe8, /* ######..##.. */ + 0x48, /* ..##....##.. */ + 0x48, /* ..##....##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb0 ('.') */ + 0x28, /* ....##..##.. */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0xc8, /* ####....##.. */ + 0xa8, /* ##..##..##.. */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb1 ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb2 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb3 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb4 ('.') */ + 0x28, /* ....##..##.. */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb5 ('.') */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb6 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb7 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x98, /* ##....####.. */ + 0x98, /* ##....####.. */ + 0xa8, /* ##..##..##.. */ + 0xc8, /* ####....##.. */ + 0xc8, /* ####....##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb8 ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xb9 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xba ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xbb ('.') */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xbc ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xbd ('.') */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x88, /* ##......##.. */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xbe ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x90, /* ##....##.... */ + 0xa0, /* ##..##...... */ + 0x90, /* ##....##.... */ + 0x88, /* ##......##.. */ + 0xb0, /* ##..####.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xbf ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc0 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc1 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc2 ('.') */ + 0x28, /* ....##..##.. */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc3 ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc4 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc5 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x14, /* ......##..## */ + 0x7c, /* ..########## */ + 0x90, /* ##....##.... */ + 0x7c, /* ..########## */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc6 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + /* 0xc7 ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc8 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xc9 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xca ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xcb ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x60, /* ..####...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xcc ('.') */ + 0x20, /* ....##...... */ + 0x40, /* ..##........ */ + 0x00, /* ............ */ + 0x60, /* ..####...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xcd ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x60, /* ..####...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xce ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x60, /* ..####...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xcf ('.') */ + 0x00, /* ............ */ + 0xc0, /* ####........ */ + 0x30, /* ....####.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd0 ('.') */ + 0x28, /* ....##..##.. */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0xb0, /* ##..####.... */ + 0xc8, /* ####....##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd1 ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd2 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd3 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd4 ('.') */ + 0x28, /* ....##..##.. */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd5 ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd6 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd7 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x98, /* ##....####.. */ + 0xa8, /* ##..##..##.. */ + 0xc8, /* ####....##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd8 ('.') */ + 0x40, /* ..##........ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xd9 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xda ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xdb ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xdc ('.') */ + 0x00, /* ............ */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0xdd ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + /* 0xde ('.') */ + 0x00, /* ............ */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x08, /* ........##.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0xdf ('.') */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe0 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe1 ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe2 ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe3 ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x10, /* ......##.... */ + 0x18, /* ......####.. */ + /* 0xe4 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x08, /* ........##.. */ + 0x78, /* ..########.. */ + 0x88, /* ##......##.. */ + 0x78, /* ..########.. */ + 0x10, /* ......##.... */ + 0x18, /* ......####.. */ + /* 0xe5 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe6 ('.') */ + 0x10, /* ......##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe7 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe8 ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xe9 ('.') */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xea ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xeb ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xec ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xed ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0xf0, /* ########.... */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0x88, /* ##......##.. */ + 0xf0, /* ########.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xee ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x08, /* ........##.. */ + 0x68, /* ..####..##.. */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x98, /* ##....####.. */ + 0x68, /* ..####..##.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xef ('.') */ + 0x00, /* ............ */ + 0x78, /* ..########.. */ + 0x44, /* ..##......## */ + 0x44, /* ..##......## */ + 0xe4, /* ######....## */ + 0x44, /* ..##......## */ + 0x44, /* ..##......## */ + 0x78, /* ..########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf0 ('.') */ + 0x00, /* ............ */ + 0x10, /* ......##.... */ + 0x38, /* ....######.. */ + 0x10, /* ......##.... */ + 0x70, /* ..######.... */ + 0x90, /* ##....##.... */ + 0x90, /* ##....##.... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf1 ('.') */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf2 ('.') */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf3 ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf4 ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf5 ('.') */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf6 ('.') */ + 0x00, /* ............ */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xf7 ('.') */ + 0x00, /* ............ */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x20, /* ....##...... */ + 0x30, /* ....####.... */ + /* 0xf8 ('.') */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x20, /* ....##...... */ + 0x30, /* ....####.... */ + /* 0xf9 ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0xf0, /* ########.... */ + 0x80, /* ##.......... */ + 0x80, /* ##.......... */ + 0xf8, /* ##########.. */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xfa ('.') */ + 0x50, /* ..##..##.... */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0xf8, /* ##########.. */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xfb ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xfc ('.') */ + 0x20, /* ....##...... */ + 0x50, /* ..##..##.... */ + 0x00, /* ............ */ + 0x68, /* ..####..##.. */ + 0x90, /* ##....##.... */ + 0x60, /* ..####...... */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0xfd ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00, /* ............ */ + /* 0xfe ('.') */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x68, /* ..####..##.. */ + 0x90, /* ##....##.... */ + 0x60, /* ..####...... */ + 0x80, /* ##.......... */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + /* 0xff ('.') */ + 0x20, /* ....##...... */ + 0x00, /* ............ */ + 0x70, /* ..######.... */ + 0x88, /* ##......##.. */ + 0x80, /* ##.......... */ + 0x98, /* ##....####.. */ + 0x88, /* ##......##.. */ + 0x70, /* ..######.... */ + 0x00, /* ............ */ + 0x00 /* ............ */ +}; + +gfx_bitmap_font_t gfxfont_6x10 = { + -1, /* resource ID */ + 256, /* # of characters */ + gfxfont_6x10_widths, /* Widths */ + 1, /* Bytes per row */ + 11, /* Line height */ + 10, /* Char height */ + 10, /* Char size (occupied, in bytes) */ + gfxfont_6x10_data /* Bulk data */ +}; diff --git a/engines/sci/gfx/font.c b/engines/sci/gfx/font.c new file mode 100644 index 0000000000..c5de8715b8 --- /dev/null +++ b/engines/sci/gfx/font.c @@ -0,0 +1,385 @@ +/*************************************************************************** + font.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + + +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + +int font_counter = 0; + +void +gfxr_free_font(gfx_bitmap_font_t *font) +{ + if (font->widths) + free(font->widths); + + if (font->data) + free(font->data); + + --font_counter; + + free(font); +} + + + +void +scale_char(byte *dest, byte *src, int width, int height, int newwidth, int xfact, int yfact) +{ + int x, y; + + for (y = 0; y < height; y++) { + int yc; + byte *bdest = dest; + byte *bsrc = src; + + for (x = 0; x < width; x++) { + int xbitc; + int bits = 0; + int value = 0; + + for (xbitc = 128; xbitc; xbitc >>= 1) { + int xc; + + for (xc = 0; xc < xfact; xc++) { + if (*bsrc & xbitc) + value |= 1; + value <<= 1; + + if (++bits == 8) { + *bdest++ = value; + bits = value = 0; + } + } + } + bsrc++; + } + + src += width; + for (yc = 1; yc < yfact; yc++) { + memcpy(dest + newwidth, dest, newwidth); + dest += newwidth; + } + dest += newwidth; + } +} + +gfx_bitmap_font_t * +gfxr_scale_font_unfiltered(gfx_bitmap_font_t *orig_font, gfx_mode_t *mode) +{ + gfx_bitmap_font_t *font = (gfx_bitmap_font_t*)sci_malloc(sizeof(gfx_bitmap_font_t)); + int height = orig_font->height * mode->yfact; + int width = 0; + int byte_width; + int i; + + font->chars_nr = orig_font->chars_nr; + for (i = 0; i < font->chars_nr; i++) + if (orig_font->widths[i] > width) + width = orig_font->widths[i]; + + width *= mode->xfact; + byte_width = (width + 7) >> 3; + if (byte_width == 3) + byte_width = 4; + if (byte_width > 4) + byte_width = (byte_width + 3) & ~3; + + font->row_size = byte_width; + font->height = height; + font->line_height = orig_font->line_height * mode->yfact; + + font->widths = (int*)sci_malloc(sizeof(int) * orig_font->chars_nr); + font->char_size = byte_width * height; + font->data = (byte*)sci_malloc(font->chars_nr * font->char_size); + + for (i = 0; i < font->chars_nr; i++) { + font->widths[i] = orig_font->widths[i] * mode->xfact; + scale_char(font->data + font->char_size * i, + orig_font->data + orig_font->char_size * i, + orig_font->row_size, orig_font->height, + font->row_size, + mode->xfact, mode->yfact); + } + return font; +} + + +gfx_bitmap_font_t * +gfxr_scale_font(gfx_bitmap_font_t *orig_font, gfx_mode_t *mode, gfxr_font_scale_filter_t filter) +{ + GFXWARN("This function hasn't been tested yet!\n"); + + switch (filter) { + + case GFXR_FONT_SCALE_FILTER_NONE: + return gfxr_scale_font_unfiltered(orig_font, mode); + + default: + GFXERROR("Invalid font filter mode %d!\n", filter); + return NULL; + } +} + + + + +text_fragment_t * +gfxr_font_calculate_size(gfx_bitmap_font_t *font, int max_width, const char *text, + int *width, int *height, + int *lines, int *line_height_p, int *last_offset_p, + int flags) +{ + int est_char_width = font->widths[(font->chars_nr > 'M')? 'M' : font->chars_nr - 1]; + /* 'M' is typically among the widest chars */ + int fragments_nr; + text_fragment_t *fragments; + int lineheight = font->line_height; + int maxheight = lineheight; + int last_breakpoint = 0; + int last_break_width = 0; + int max_allowed_width = max_width; + int maxwidth = 0, localmaxwidth = 0; + int current_fragment = 1; + const char *breakpoint_ptr = NULL; + unsigned char foo; + + if (line_height_p) + *line_height_p = lineheight; + + if (max_width>1) fragments_nr = 3 + (strlen(text) * est_char_width)*3 / (max_width << 1); else fragments_nr = 1; + + fragments = (text_fragment_t*)sci_calloc(sizeof(text_fragment_t), fragments_nr); + + + fragments[0].offset = text; + + while ((foo = *text++)) { + + if (foo >= font->chars_nr) { + GFXWARN("Invalid char 0x%02x (max. 0x%02x) encountered in text string '%s', font %04x\n", + foo, font->chars_nr, text, font->ID); + if (font->chars_nr > ' ') + foo = ' '; + else { + free(fragments); + return NULL; + } + } + + if (((foo == '\n') || (foo == 0x0d)) + && !(flags & GFXR_FONT_FLAG_NO_NEWLINES)) { + + fragments[current_fragment-1].length = text - 1 - fragments[current_fragment-1].offset; + + if (*text) + maxheight += lineheight; + + if (foo == 0x0d && *text == '\n') + text++; /* Interpret DOS-style CR LF as single NL */ + + fragments[current_fragment++].offset = text; + + if (localmaxwidth > maxwidth) + maxwidth = localmaxwidth; + + if (current_fragment == fragments_nr) + fragments = (text_fragment_t*)sci_realloc(fragments, sizeof(text_fragment_t) * (fragments_nr <<= 1)); + + localmaxwidth = 0; + + } else { /* foo != '\n' */ + localmaxwidth += font->widths[foo]; + + if (localmaxwidth > max_allowed_width) { + int blank_break = 1; /* break is at a blank char, i.e. not within a word */ + + maxheight += lineheight; + + if (last_breakpoint == 0) { /* Text block too long and without whitespace? */ + last_breakpoint = localmaxwidth - font->widths[foo]; + last_break_width = 0; + --text; + blank_break = 0; /* non-blank break */ + } else { + text = breakpoint_ptr + 1; + assert(breakpoint_ptr); + } + + if (last_breakpoint == 0) { + GFXWARN("Warning: maxsize %d too small for '%s'\n", + max_allowed_width, text); + } + + if (last_breakpoint > maxwidth) + maxwidth = last_breakpoint; + + fragments[current_fragment-1].length = text - blank_break - fragments[current_fragment-1].offset; + fragments[current_fragment++].offset = text; + + if (current_fragment == fragments_nr) + fragments = (text_fragment_t*)sci_realloc(fragments, sizeof(text_fragment_t *) * (fragments_nr <<= 1)); + + localmaxwidth = localmaxwidth - last_breakpoint; + if (!(flags & GFXR_FONT_FLAG_COUNT_WHITESPACE)) + localmaxwidth -= last_break_width; + last_breakpoint = localmaxwidth = 0; + + } else if (*text == ' ') { + last_breakpoint = localmaxwidth; + last_break_width = font->widths[foo]; + breakpoint_ptr = text; + } + + } + } + + if (localmaxwidth > maxwidth) + *width = localmaxwidth; + else + *width = maxwidth; + + if (last_offset_p) + *last_offset_p = localmaxwidth; + + if (height) + *height = maxheight; + if (lines) + *lines = current_fragment; + + fragments[current_fragment-1].length = text - fragments[current_fragment-1].offset - 1; + + return fragments; +} + + +static inline void +render_char(byte *dest, byte *src, int width, int line_width, int lines, int bytes_per_src_line, int fg0, int fg1, int bg) +{ + int x, y; + + for (y = 0; y < lines; y++) { + int dat = 0; + byte *vdest = dest; + byte *vsrc = src; + int xc = 0; + + for (x = 0; x < width; x++) { + if (!xc) { + dat = *vsrc++; + xc = 8; + } + xc--; + + if (dat & 0x80) + *vdest++ = ((xc ^ y) & 1)? fg0 : fg1; /* dither */ + else + *vdest++ = bg; + + dat <<= 1; + } + src += bytes_per_src_line; + dest += line_width; + } +} + +gfx_pixmap_t * +gfxr_draw_font(gfx_bitmap_font_t *font, const char *stext, int characters, + gfx_pixmap_color_t *fg0, gfx_pixmap_color_t *fg1, gfx_pixmap_color_t *bg) +{ + unsigned char *text = (unsigned char *) stext; + int height = font->height; + int width = 0; + gfx_pixmap_t *pxm; + int fore_0, fore_1, back; + int i; + int hack = 0; + gfx_pixmap_color_t dummy = {0}; + byte *offset; + + for (i = 0; i < characters; i++) { + int ch = (int) text[i]; + + if (ch >= font->chars_nr) { + GFXERROR("Invalid character 0x%02x encountered!\n", text[i]); + return NULL; + } + + width += font->widths[ch]; + } + + pxm = gfx_pixmap_alloc_index_data(gfx_new_pixmap(width, height, GFX_RESID_NONE, 0, 0)); + + pxm->colors_nr = !!fg0 + !!fg1 + !!bg; + if (pxm->colors_nr == 0) + { + GFXWARN("Pixmap would have zero colors, resetting!\n"); + pxm->colors_nr = 3; + hack = 1; + fg0 = fg1 = bg = &dummy; + } + pxm->colors = (gfx_pixmap_color_t*)sci_malloc(sizeof(gfx_pixmap_color_t) * pxm->colors_nr); +#ifdef SATISFY_PURIFY + memset(pxm->colors, 0, sizeof(gfx_pixmap_color_t) * pxm->colors_nr); +#endif + pxm->flags |= GFX_PIXMAP_FLAG_PALETTE_ALLOCATED | GFX_PIXMAP_FLAG_DONT_UNALLOCATE_PALETTE; + + i = 0; + + if (fg0 || hack) { + memcpy(pxm->colors + i, fg0, sizeof(gfx_pixmap_color_t)); + fore_0 = i++; + } else fore_0 = pxm->color_key; + + if (fg1 || hack) { + memcpy(pxm->colors + i, fg1, sizeof(gfx_pixmap_color_t)); + fore_1 = i++; + } else fore_1 = pxm->color_key; + + if (bg || hack) { + memcpy(pxm->colors + i, bg, sizeof(gfx_pixmap_color_t)); + back = i++; + } else back = pxm->color_key; + + offset = pxm->index_data; + + memset(pxm->index_data, back, pxm->index_xl * pxm->index_yl); + for (i = 0; i < characters; i++) { + unsigned char ch = text[i]; + width = font->widths[ch]; + + render_char(offset, font->data + (ch * font->char_size), width, + pxm->index_xl, pxm->index_yl, font->row_size, + fore_0, fore_1, back); + + offset += width; + } + + return pxm; +} + diff --git a/engines/sci/gfx/gfx_console.c b/engines/sci/gfx/gfx_console.c new file mode 100644 index 0000000000..0cde8092f3 --- /dev/null +++ b/engines/sci/gfx/gfx_console.c @@ -0,0 +1,1450 @@ +/*************************************************************************** + gfx_console.c Copyright (C) 2002 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Graphical on-screen console */ + + +#include <console.h> +#include <ctype.h> + +#ifdef WANT_CONSOLE +# define CON_MAX_CLUSTERS 16 + +#define CON_CLUSTER_SIZE 64 + +/* Number of console entries stored = CON_MAX_CLUSTERS * CON_CLUSTER_SIZE */ + +#define CON_ENTRY_USED(e) ((e).height > 0) + +#define CON_INPUT_HISTORY_SIZE 64 +#define CON_BUILTIN_CHARS_NR 256 +#define CON_BUILTIN_CHARS_HEIGHT 8 +#define CON_BUILTIN_CHARS_WIDTH 8 + +#define CON_OVERWRAP_SYMBOL 0x10 + +#define CON_GFX_PROMPT "$ " + +extern byte con_builtin_font_data[]; + +typedef struct { + int height; /* Number of pixels occupied by this entry, or 0 if unused */ + int pixmaps_nr; + gfx_pixmap_t **pixmaps; + char *text; /* Dynamically allocated */ +} con_entry_t; + + +typedef struct _con_buffer { + con_entry_t entries[CON_CLUSTER_SIZE]; + struct _con_buffer *next; + struct _con_buffer *prev; +} con_buffer_t; + +typedef struct { + con_buffer_t *buf; + int entry; + int offset; /* pixel offset relative to the bottom */ +} con_pos_t; + +typedef struct { + int locked_to_end; + con_pos_t pos; + gfx_pixmap_t *background; + gfx_color_t color_bg, color_transparent, color_cursor, color_text, color_input; + gfx_pixmap_t *input_prompt; + gfx_pixmap_t *input_precursor; + gfx_pixmap_t *input_oncursor; + gfx_pixmap_t *input_postcursor; + int cursor_position; + int input_window; /* First character to display, may be up to -2 to include prompt */ + char *input_text; + int input_bufsize; + int input_prompt_pos; /* -strlen(input prompt) */ + int input_history_pos; + int partial_write; + char *input_history[CON_INPUT_HISTORY_SIZE]; +} con_t; + + +/* Visual options for the con */ +static int con_bg_red = 0; +static int con_bg_green = 0; +static int con_bg_blue = 64; +static int con_bg_alpha = 64; +static int con_displayed_lines = 180; +static int con_border_width = 3; + +static int con_top_buffer_entry_nr = 0; +static int con_buffer_clusters = 0; +static con_buffer_t *con_buffer = NULL; +static con_buffer_t *con_buffer_tail = NULL; +static con_t con; /* The global con */ +static gfx_bitmap_font_t con_font; +static int con_font_initialized = 0; +static gfx_state_t *con_last_gfx_state = NULL; + +/*-- Forwards --*/ +static void +_con_free_entry_pixmaps(gfx_state_t *state, con_entry_t *entry); +/* Free all pixmaps from the specified entry +** Parameters: (gfx_state_t *) state: The state to free from +** (con_entry_t *) entry: The entry to liberate from its pixmaps +*/ + +static gfx_pixmap_t * +_con_render_text(gfx_state_t *state, char *text, int len, + gfx_color_t *color, gfx_color_t *bgcolor); +/* Renders the specified text in the specified fg color +** Parameters: (gfx_state_t *) state: The state to render in +** (char *) text: The text to render +** (int) len: Length of the text to render, or -1 for strlen +** (gfx_color_t *) color: The fg color to choose +** (gfx_color_t *) bgcolor: The bg color to choose +** Returns : (gfx_pixmap_t *) An appropriate pixmap +*/ + + +void +con_jump_to_end(gfx_state_t *gfx); +/* Makes the console jump to the logical end of its buffer and redraws +** Parameters: (gfx_stat_t *) gfx: The graphics state to use fo rdrawing +*/ + +static void +_con_redraw(gfx_state_t *state, int update_display_field, int update_input_field); +/* Performs a (partial) redraw +** Parameters: (gfx_state_t *) state: The graphical state to draw with +** (int) update_display_field: Whether the upper part of the +** console, used to display test, should be updated +** (int) update_input_field: Whether the lower part of the +** console, used to display the user input, should be +** updated +*/ + +static void +free_con_buffer(con_buffer_t *buf); +/* Frees the specified con buffer and all of its predecessors +** Parameters: (con_buffer_t *) buf: The buffer to free +** Pixmaps are freed if neccessary, using the last used gfx state for con_gfx_show(). +*/ + +void +con_gfx_hide(gfx_state_t *state); +/* Removes the console, restoring the background graphics +** Parameters: (gfx_state_t *state: The graphics state to draw with +*/ + +static gfx_pixmap_t ** +_con_render_text_multiline(gfx_state_t *state, char *text, int maxchars, int *nr); +/*-- code --*/ + +static rect_t +con_box() +{ + return gfx_rect(0, 0, 320, + con_displayed_lines + + con_border_width); +} + +void +con_gfx_show(gfx_state_t *state) +{ + gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); + con_last_gfx_state = state; + + con.locked_to_end = 1; + con.background = gfxop_grab_pixmap(state, con_box()); + + gfxop_set_color(state, &con.color_bg, con_bg_red, con_bg_green, + con_bg_blue, con_bg_alpha, -1, -1); + gfxop_set_color(state, &con.color_transparent, 0, 0, 0, 255, -1, -1); + gfxop_set_color(state, &con.color_text, 255, 255, 255, 0, -1, -1); + gfxop_set_color(state, &con.color_input, 255, 255, 0, 0, -1, -1); + gfxop_set_color(state, &con.color_cursor, 255, 0, 0, 0, -1, -1); + + if (!con.input_prompt) { + con.input_prompt = _con_render_text(state, CON_GFX_PROMPT, -1, + &con.color_input, NULL); + con.input_text = (char*)sci_malloc(con.input_bufsize = 64); + con.input_text[0] = 0; + con.input_history_pos = 0; + con.partial_write = 0; + memset(con.input_history, 0, sizeof(char *) * CON_INPUT_HISTORY_SIZE); + } + + con_jump_to_end(state); + _con_redraw(state, 0, 1); +} + +static void +_con_draw_bg_pic(gfx_state_t *state, rect_t zone) +{ + gfxop_draw_pixmap(state, con.background, zone, gfx_point(zone.x,zone.y)); +} + +void +con_jump_to_end(gfx_state_t *state) +{ + con.locked_to_end = 1; + _con_redraw(state, 1, 0); +} + + +void +con_fold_text(gfx_state_t *state) +{ + con_buffer_t *seeker = con_buffer; + + /* Fold all text pixmaps */ + while (seeker) { + int i; + for (i = 0; i < CON_CLUSTER_SIZE; i++) + if (CON_ENTRY_USED(seeker->entries[i]) + && seeker->entries[i].text && seeker->entries[i].pixmaps_nr) + _con_free_entry_pixmaps(state, &seeker->entries[i]); + + seeker = seeker->next; + } +} + +void +con_gfx_hide(gfx_state_t *state) +{ + /* Restore background */ + _con_draw_bg_pic(state, con_box()); + + if (con.background) + gfxop_free_pixmap(state, con.background); + con.background = NULL; + + con_fold_text(state); + gfxop_update(state); +} + +static inline con_buffer_t * +_create_con_buffer(con_buffer_t *prev) +{ + con_buffer_t *buf = (con_buffer_t *)sci_malloc(sizeof (con_buffer_t)); + int i; + + for (i = 0; i < CON_CLUSTER_SIZE; i++) + buf->entries[i].height = 0; + + buf->prev = prev; + buf->next = NULL; + if (prev) + prev->next = buf; + + con_buffer_clusters++; + + return buf; +} + + +static inline void +_add_into_con_buffer(gfx_pixmap_t *pixmap, char *text) +{ + con_entry_t *target; + + if (!con_buffer) { + con_buffer = con_buffer_tail = _create_con_buffer(NULL); + con_top_buffer_entry_nr = 0; + } + + if (con_top_buffer_entry_nr == CON_CLUSTER_SIZE) { + /* Out of entries in this cluster */ + con_buffer = _create_con_buffer(con_buffer); + con_top_buffer_entry_nr = 0; + } + + target = con_buffer->entries + con_top_buffer_entry_nr; + + if (con.partial_write && text) { + int real_entry = con_top_buffer_entry_nr - 1; + int needlen = strlen(text); + char *oldtext; + + if (real_entry < 0) + target = con_buffer->prev->entries + CON_CLUSTER_SIZE - 1; + else + target = con_buffer->entries + real_entry; + + if (target->pixmaps) + _con_free_entry_pixmaps(con_last_gfx_state, target); + + needlen += strlen(target->text); + oldtext = target->text; + target->text = (char *)sci_malloc(needlen+1); + strcpy(target->text, oldtext); + strcat(target->text, text); + free(oldtext); + free(text); + + con.partial_write = (target->text && *(target->text) && + target->text[strlen(target->text) - 1] != '\n'); + + return; + } + else ++con_top_buffer_entry_nr; + + + con.partial_write = (text && *(text) && + text[strlen(text) - 1] != '\n'); + + if (pixmap) + target->height = pixmap->index_yl; + else + target->height = 1; /* Will be calculated on demand */ + + if (!pixmap) { + target->pixmaps = NULL; + target->pixmaps_nr = 0; + } else { + target->pixmaps = (gfx_pixmap_t **)sci_malloc(sizeof(gfx_pixmap_t *)); + target->pixmaps[0] = pixmap; + target->pixmaps_nr = 1; + } + target->text = text; + + while (con_buffer_clusters > CON_MAX_CLUSTERS + && con_buffer_tail) { + if (con_buffer_tail->next) { + con_buffer_tail = con_buffer_tail->next; + free_con_buffer(con_buffer_tail->prev); + } else { + fprintf(stderr,"WARNING: During cleanup, con_buffer_tail ran out!\n"); + free_con_buffer(con_buffer_tail->prev); + con_buffer_tail = con_buffer = NULL; + } + } +} + + +void +con_gfx_insert_string(char *string) +{ + if (string) + _add_into_con_buffer(NULL, string); +} + +void +con_gfx_insert_pixmap(gfx_pixmap_t *pixmap) +{ + if (pixmap) + _add_into_con_buffer(pixmap, NULL); +} + +static int +_unfold_graphics(gfx_state_t *state, con_entry_t *drawme, int nr_chars) + /* Returns whether unfolding was neccessary */ +{ + if (drawme->text && !drawme->pixmaps_nr) { + int i; + drawme->pixmaps = _con_render_text_multiline(state, drawme->text, + nr_chars, + &drawme->pixmaps_nr); + + drawme->height = 0; + for (i = 0; i < drawme->pixmaps_nr; i++) + drawme->height += + (drawme->pixmaps[i]->yl + state->driver->mode->yfact - 1) + / state->driver->mode->yfact; + /* Divide by scaler, round up */ + return 1; + } + + return 0; +} + +void +con_scroll(gfx_state_t *state, int offset, int maxchars) +{ + con_entry_t *next_entry; + /* Scrolls within the display by the specified amount */ + + if (con.locked_to_end) { + con.pos.buf = con_buffer; + con.pos.offset = 0; + con.pos.entry = con_top_buffer_entry_nr - 1; + } + + if (!con.pos.buf) + return; + + con.locked_to_end = 0; + + con.pos.offset += offset; /* offset exceeds size -> Use PREVIOUS entry */ + + while (con.pos.offset < 0 || con.pos.offset > con.pos.buf->entries[con.pos.entry].height) { + + if (con.pos.offset < 0) { + if (++con.pos.entry == CON_CLUSTER_SIZE + || ((con.pos.buf == con_buffer) + && (con.pos.entry >= con_top_buffer_entry_nr))) { + if (con.pos.buf->next) { + con.pos.entry = 0; + con.pos.buf = con.pos.buf->next; + } else { + con_jump_to_end(state); + return; + } + } + + next_entry = con.pos.buf->entries + con.pos.entry; + + _unfold_graphics(state, next_entry, maxchars); + con.pos.offset += next_entry->height; + } else { /* offset too great ? */ + + if (con.pos.entry == 0) { + if (con.pos.buf->prev) { + con.pos.entry = CON_CLUSTER_SIZE; + con.pos.buf = con.pos.buf->prev; + } else { + con.pos.offset = con.pos.buf->entries[0].height - 1; + return; + } + } + --con.pos.entry; + + next_entry = con.pos.buf->entries + con.pos.entry; + + _unfold_graphics(state, next_entry, maxchars); + con.pos.offset -= next_entry->height; + + if (con.pos.offset < 0) + con.pos.offset = -con.pos.offset; + } + } +} + +void +con_gfx_init() +{ + con_set_string_callback(con_gfx_insert_string); + con_set_pixmap_callback(con_gfx_insert_pixmap); + con.input_prompt = NULL; + con.input_text = NULL; + con.input_window = con.input_prompt_pos = -(int)strlen(CON_GFX_PROMPT); + con.cursor_position = 0; + con.input_precursor = NULL; + con.input_postcursor = NULL; + con.input_oncursor = NULL; +} + + +static void +_init_con_font() +{ + int i; + + con_font.ID = 0; + con_font.chars_nr = CON_BUILTIN_CHARS_NR; + con_font.widths = (int *)sci_malloc(sizeof(int) * CON_BUILTIN_CHARS_NR); + for (i = 0; i < CON_BUILTIN_CHARS_NR; i++) + con_font.widths[i] = CON_BUILTIN_CHARS_WIDTH; + con_font.row_size = (CON_BUILTIN_CHARS_WIDTH + 7) >> 3; + con_font.height = con_font.line_height = CON_BUILTIN_CHARS_HEIGHT; + con_font.char_size = ((CON_BUILTIN_CHARS_WIDTH + 7) >> 3) * CON_BUILTIN_CHARS_HEIGHT; + con_font.data = con_builtin_font_data; + + con_font_initialized = 1; +} + +static gfx_pixmap_t ** +_con_render_text_multiline(gfx_state_t *state, char *text, int maxchars, int *nr) +{ + int pixmaps_allocd = 1; + gfx_pixmap_t **retval = (gfx_pixmap_t **)sci_malloc(sizeof(gfx_pixmap_t *) * pixmaps_allocd); + char *printbuf = (char *)sci_malloc(maxchars + 8); + int index = 0; + int overwrap = 0; + + while (*text) { + int len = 0; + + if (overwrap) { + len = 2; + printbuf[0] = ' '; + printbuf[1] = CON_OVERWRAP_SYMBOL; + overwrap = 0; + } + + while (*text && + *text != '\n' && len < maxchars) { + if (*text != '\t') + printbuf[len++] = *text; + else { + int tabwidth = 8 - (len & 7); + memset(printbuf + len, ' ', tabwidth); + len += tabwidth; + } + text++; + } + + if (*text && (*text != '\n')) + overwrap = 1; + + if (index == pixmaps_allocd) + retval = (gfx_pixmap_t **)sci_realloc(retval, sizeof(gfx_pixmap_t *) * (pixmaps_allocd+= 4)); + + retval[index++] = _con_render_text(state, printbuf, len, + &con.color_text, NULL); + if (*text) text += (1 - overwrap); + } + + *nr = index; + sci_free(printbuf); + return retval; +} + +static gfx_pixmap_t * +_con_render_text(gfx_state_t *state, char *text, int len, + gfx_color_t *color, gfx_color_t *bgcolor) +{ + gfx_pixmap_t *pxm; + + if (len < 0) + len = strlen(text); + + if (!con_font_initialized) + _init_con_font(); + + pxm = gfxr_draw_font(&con_font, text, len, + &color->visual, + &color->visual, + (bgcolor) ? &bgcolor->visual : NULL); + + pxm->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + + gfx_xlate_pixmap(gfx_pixmap_alloc_data(pxm, state->driver->mode), + state->driver->mode, GFX_XLATE_FILTER_NONE); + return pxm; +} + +static inline int +_str_move_blank(char *data, int data_length, int initial_offset, int direction) + /* Finds the next beginning or end of a word */ +{ + int offset = initial_offset; + int abort = (direction < 0)? 0 : data_length; + int lookahead = (direction < 0)? -1 : 0; + + if (offset != abort) + offset += direction; + + while (offset != abort && isspace(data[offset])) + offset += direction; + + while (offset != abort && !isspace(data[offset + lookahead])) + offset += direction; + + return offset; +} + +char * +con_history_get_prev(int *handle) /* Should be -1 if not initialized yet */ +{ + int nexthandle; + + if (*handle == con.input_history_pos) + return NULL; + + if (*handle == -1) + *handle = con.input_history_pos; + + nexthandle = (*handle) - 1; + if (nexthandle == -1) + nexthandle = CON_INPUT_HISTORY_SIZE - 1; + + if (con.input_history[nexthandle]) + *handle = nexthandle; + + return con.input_history[nexthandle]; +} + +char * +con_history_get_next(int *handle) +{ + int last = (con.input_history_pos + CON_INPUT_HISTORY_SIZE - 1) % CON_INPUT_HISTORY_SIZE; + int nexthandle; + + if (*handle < 0 || *handle > CON_INPUT_HISTORY_SIZE) + return NULL; + + if (*handle == last) { + *handle = -1; + return NULL; /* End of history */ + } + + nexthandle = *handle + 1; + if (nexthandle == CON_INPUT_HISTORY_SIZE) + nexthandle = 0; + + if (con.input_history[nexthandle]) + *handle = nexthandle; + + return con.input_history[nexthandle]; +} + +void +con_history_archive(char *msg) +{ + char **writepos = &(con.input_history[con.input_history_pos]); + + if (*writepos) + sci_free(*writepos); + + *writepos = msg; + + if (++con.input_history_pos >= CON_INPUT_HISTORY_SIZE) + con.input_history_pos = 0; +} + +char * +con_gfx_read(gfx_state_t *state) +{ + int chwidth = CON_BUILTIN_CHARS_WIDTH / state->driver->mode->xfact; + int maxchars = 320 / chwidth; + sci_event_t evt; + char *retval; + int done = 0; + int slen = strlen(con.input_text); + int history_handle = -1; + + do { + int old_pos = con.cursor_position; + int must_resize = 0; /* Have to re-calculate the strlen */ + int must_redraw = 0; /* Redraw input field */ + int must_rewin = 0; /* Re-calculate window */ + int must_redraw_text = 0; /* Redraw display field */ + if (slen+1 >= con.input_bufsize) + con.input_text = (char *)sci_realloc(con.input_text, con.input_bufsize += 64); + + evt.type = 0; + while (!evt.type) + evt = gfxop_get_event(state, SCI_EVT_ANY); + + if (evt.type == SCI_EVT_KEYBOARD) { + + if (evt.buckybits & SCI_EVM_CTRL) { + switch(evt.data) { + case 'p': + case 'P': { + char *hist = con_history_get_prev(&history_handle); + + if (hist) { + sci_free(con.input_text); + con.input_text = sci_strdup(hist); + } + must_resize = must_redraw = must_rewin = 1; + } + break; + + case 'n': + case 'N': { + char *hist = con_history_get_next(&history_handle); + + if (hist) { + sci_free(con.input_text); + con.input_text = sci_strdup(hist); + } + must_resize = must_redraw = must_rewin = 1; + } + break; + + case 'a': + case 'A': /* C-a */ + con.cursor_position = 0; + break; + + case 'b': + case 'B': /* C-b */ + if (con.cursor_position) + --con.cursor_position; + break; + + case 'e': + case 'E': /* C-e */ + con.cursor_position = slen; + break; + + case 'f': + case 'F': /* C-f */ + if (con.cursor_position < slen) + ++con.cursor_position; + break; + + case 'd': + case 'D': + memmove(con.input_text + con.cursor_position, + con.input_text + con.cursor_position + 1, + slen - con.cursor_position); + must_resize = must_redraw = 1; + break; + + case 'h': + case 'H': + if (!con.cursor_position) + break; + + memmove(con.input_text + con.cursor_position - 1, + con.input_text + con.cursor_position, + slen - con.cursor_position + 1); + must_resize = must_redraw = 1; + --con.cursor_position; + break; + + case 'k': + case 'K': + con.input_text[con.cursor_position] = 0; + must_resize = must_redraw = 1; + break; + + case '`': return "go"; + + default: + break; + } + } else if (evt.buckybits & SCI_EVM_ALT) { + switch(evt.data) { + case 'b': + case 'B': + con.cursor_position = _str_move_blank(con.input_text, + slen, + con.cursor_position, + -1); + break; + + case 'f': + case 'F': + con.cursor_position = _str_move_blank(con.input_text, + slen, + con.cursor_position, + 1); + break; + + case 'd': + case 'D': { + int delpos = _str_move_blank(con.input_text, slen, + con.cursor_position, 1); + + must_resize = must_redraw = 1; + memmove(con.input_text + con.cursor_position, + con.input_text + delpos, + slen - delpos + 1); + } + + default: + break; + } + } else switch (evt.data) { + + case SCI_K_UP: { + char *hist = con_history_get_prev(&history_handle); + + if (hist) { + sci_free(con.input_text); + con.input_text = sci_strdup(hist); + } + must_resize = must_redraw = must_rewin = 1; + } + break; + + case SCI_K_DOWN: { + char *hist = con_history_get_next(&history_handle); + + if (hist) { + sci_free(con.input_text); + con.input_text = sci_strdup(hist); + } + must_resize = must_redraw = must_rewin = 1; + } + break; + + + case SCI_K_LEFT: + if (con.cursor_position) + --con.cursor_position; + break; + + case SCI_K_RIGHT: + if (con.cursor_position < slen) + ++con.cursor_position; + break; + + + case SCI_K_PGDOWN: + must_redraw_text = 1; + con_scroll(state, -75, maxchars); + break; + + case SCI_K_PGUP: + must_redraw_text = 1; + con_scroll(state, 75, maxchars); + break; + + case SCI_K_END: + con_jump_to_end(state); + must_redraw_text = 1; + break; + + case SCI_K_DELETE: + memmove(con.input_text + con.cursor_position, + con.input_text + con.cursor_position + 1, + slen - con.cursor_position); + must_resize = must_redraw = 1; + break; + + case SCI_K_BACKSPACE: + if (!con.cursor_position) + break; + + memmove(con.input_text + con.cursor_position - 1, + con.input_text + con.cursor_position, + slen - con.cursor_position + 1); + must_resize = must_redraw = 1; + --con.cursor_position; + break; + + + case SCI_K_ENTER: + done = 1; + break; + + default: + if ((evt.character >= 32) && (evt.character <= 255)) { + memmove(con.input_text + con.cursor_position + 1, + con.input_text + con.cursor_position, + slen - con.cursor_position + 1); + + con.input_text[con.cursor_position] = evt.character; + ++con.cursor_position; + ++slen; + must_redraw = 1; + } + } + } + + if (must_resize) + slen = strlen(con.input_text); + + if (old_pos != con.cursor_position) + must_redraw = 1; + + if (must_rewin) { + int chwidth = CON_BUILTIN_CHARS_WIDTH / state->driver->mode->xfact; + int nr_chars = 320 / chwidth; + + con.cursor_position = slen; + con.input_window = slen - nr_chars + (nr_chars >> 3); + } + + if (must_redraw || must_redraw_text) { + _con_redraw(state, must_redraw_text, must_redraw); + gfxop_update(state); + } + } while (!done); + + retval = con.input_text; + con.input_text = (char *)sci_malloc(64); + con.input_text[0] = 0; + con.input_window = con.input_prompt_pos; + con.cursor_position = 0; + + if (!*retval) { + int hist = -1; + sci_free(retval); + return con_history_get_prev(&hist); + } + /* else */ + con_history_archive(retval); + return retval; +} + +static void +_con_redraw(gfx_state_t *state, int update_display_field, int update_input_field) +{ + int chwidth = CON_BUILTIN_CHARS_WIDTH / state->driver->mode->xfact; + int nr_chars = 320 / chwidth; + int offset = con_displayed_lines; + int pixmap_index = -42; + int must_recompute_pixmap_index = 1; + int max_offset; + con_pos_t pos = con.pos; + rect_t fullbox = con_box(); + int yscale = state->driver->mode->yfact; + int input_field_height = con.input_prompt ? + (con.input_prompt->index_yl + yscale - 1) / yscale : 0; + /* This delta is in "virtual" SCI pixels */ + int input_field_size = con_border_width + input_field_height; + /* Let's consider the bottom padding to be part of the input field */ + + + if (!update_input_field && !update_display_field) + return; + if (!update_input_field) + fullbox.yl -= input_field_size; + + if (!update_display_field) { + fullbox.y = fullbox.yl - input_field_size; + fullbox.yl = input_field_size; + } + + if (con.color_bg.alpha) + _con_draw_bg_pic(state, fullbox); + + /* Draw overlay box */ + gfxop_draw_box(state, fullbox, con.color_bg, con.color_bg, + GFX_BOX_SHADE_FLAT); + + if (update_input_field) { + + if (con_border_width >= 2) { + int y = con_displayed_lines + con_border_width - 2; + + gfxop_draw_line(state, gfx_point(0, y), gfx_point(319, y), + con.color_input, GFX_LINE_MODE_FINE, + GFX_LINE_STYLE_NORMAL); + } + + if (con.input_prompt) { + int promptlen = strlen(CON_GFX_PROMPT); + + if (con.cursor_position - con.input_window < (nr_chars >> 3)) + con.input_window -= (nr_chars >> 1); + else if (con.cursor_position - con.input_window > (nr_chars - (nr_chars >> 3))) + con.input_window += (nr_chars >> 1); + + if (con.input_window < con.input_prompt_pos) + con.input_window = con.input_prompt_pos; + + offset -= input_field_height; + + if (con.input_oncursor) { + gfxop_free_pixmap(state, con.input_oncursor); + con.input_oncursor = NULL; + } + + if (con.input_text) { + char oncursorbuf[2]; + char *postcursor_text = con.input_text + con.cursor_position + 1; + char temp_sep; + + oncursorbuf[1] = 0; + oncursorbuf[0] = temp_sep = con.input_text[con.cursor_position]; + + if (!temp_sep) + oncursorbuf[0] = ' '; /* Draw at least a blank cursor */ + + if (con.input_precursor) { + gfxop_free_pixmap(state, con.input_precursor); + con.input_precursor = NULL; + } + if (con.input_postcursor) { + gfxop_free_pixmap(state, con.input_postcursor); + con.input_postcursor = NULL; + } + + con.input_oncursor = _con_render_text(state, oncursorbuf, -1, + &con.color_input, + &con.color_cursor); + if (con.input_text[0]) + con.input_precursor = _con_render_text(state, + con.input_text, -1, + &con.color_input, + NULL); + if (postcursor_text[-1]) + con.input_postcursor = _con_render_text(state, + postcursor_text, + -1, + &con.color_input, + NULL); + + con.input_text[con.cursor_position] = temp_sep; + } else { + con.input_oncursor = _con_render_text(state, " ", -1, + &con.color_input, + &con.color_cursor); + } + + + if (con.input_window < 0) { + con.input_prompt->xoffset = 0; + con.input_prompt->yoffset = 0; + gfxop_draw_pixmap(state, con.input_prompt, + gfx_rect(0, 0, + con.input_prompt->index_xl, + con.input_prompt->index_yl), + gfx_point(chwidth * (strlen(CON_GFX_PROMPT) + + con.input_window), + offset)); + } + + if (con.input_precursor && con.input_window < con.cursor_position) + gfxop_draw_pixmap(state, con.input_precursor, + gfx_rect(0, 0, + con.input_precursor->index_xl, + con.input_precursor->index_yl), + gfx_point(chwidth * -con.input_window, + offset)); + + if (con.input_postcursor && con.input_window + nr_chars - 1 > + con.cursor_position) { + gfxop_draw_pixmap(state, con.input_postcursor, + gfx_rect(0, 0, + con.input_postcursor->index_xl, + con.input_postcursor->index_yl), + gfx_point(chwidth * (con.cursor_position + 1 + - con.input_window), + offset)); + } + + if (con.input_oncursor) + gfxop_draw_pixmap(state, con.input_oncursor, + gfx_rect(0, 0, + con.input_oncursor->index_xl, + con.input_oncursor->index_yl), + gfx_point(chwidth * (con.cursor_position + - con.input_window), + offset)); + + + } + } else + offset -= input_field_height; + + if (!update_display_field) { + gfxop_update_box(state, fullbox); + return; + } + + max_offset = offset; + + if (con.locked_to_end) { + pos.buf = con_buffer; + pos.offset = 0; + pos.entry = con_top_buffer_entry_nr - 1; + } + + while (pos.buf && offset >= 0) { + con_entry_t *drawme; + int depth = pos.offset; + int line_yl; + + pos.offset = 0; + + if (pos.entry < 0) { + pos.entry = CON_CLUSTER_SIZE - 1; + if (pos.buf) + pos.buf = pos.buf->prev; + + if (!pos.buf) + break; + } + + drawme = &(pos.buf->entries[pos.entry]); + + if (_unfold_graphics(state, drawme, nr_chars)) + must_recompute_pixmap_index = 1; + + if (must_recompute_pixmap_index) { + pixmap_index = drawme->pixmaps_nr - 1; + must_recompute_pixmap_index = 0; + } + + if (pixmap_index < 0) { + pos.entry--; + continue; + } + + while (pixmap_index >= 0 + && depth > (drawme->pixmaps[pixmap_index]->yl + yscale - 1) / yscale) + depth -= (drawme->pixmaps[pixmap_index--]->yl + yscale -1) / yscale; + + if (pixmap_index == -1) { + fprintf(stderr, "ERROR: Offset too great! It was %d in a block of height %d\n", + con.pos.offset, drawme->height); + exit(1); + continue; + } + + line_yl = (drawme->pixmaps[pixmap_index]->yl + yscale - 1) / yscale; + + offset -= line_yl - depth; + depth = line_yl; + + if (offset + depth > max_offset) + depth = max_offset - offset; + + gfxop_draw_pixmap(state, drawme->pixmaps[pixmap_index], + gfx_rect(0, 0, + drawme->pixmaps[pixmap_index]->index_xl, depth), + gfx_point(0, offset)); + /* + ** TODO: Insert stuff into overwrapped lines ** + if (pixmap_index) + gfxop_draw_line(state, gfx_rect(chwidth - 2, offset, + chwidth - 2, offset + depth), + con.color_text, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_NORMAL); + */ + + if (!pixmap_index) { + pos.entry--; + must_recompute_pixmap_index = 1; + } else + --pixmap_index; + } + + gfxop_update_box(state, fullbox); +} + +static void +_con_free_entry_pixmaps(gfx_state_t *state, con_entry_t *entry) +{ + int j; + + if (entry->pixmaps) { + for (j = 0; j < entry->pixmaps_nr; j++) + gfxop_free_pixmap(state, entry->pixmaps[j]); + sci_free(entry->pixmaps); + entry->pixmaps_nr = 0; + entry->pixmaps = NULL; + } +} + + +static void +_free_con_buffer(con_buffer_t *buf); + +static void +free_con_buffer(con_buffer_t *buf) +/* Frees a con buffer and all of its predecessors */ +{ + /* First, make sure we're not destroying the current display */ + if (!con.locked_to_end) { + con_buffer_t *seeker = con.pos.buf; + while (seeker && seeker != buf) + seeker = seeker->prev; + + if (seeker) { + if (seeker->prev) + con.pos.buf = seeker->next; + else + con.locked_to_end = 1; + } + } + _free_con_buffer(buf); +} + +static void +_free_con_buffer(con_buffer_t *buf) +{ + int i; + + if (buf) { + con_buffer_t *prev = buf->prev; + + if (buf->next) + buf->next->prev = NULL; + for (i = 0; i < CON_CLUSTER_SIZE; i++) + if (CON_ENTRY_USED(buf->entries[i])) { + if (buf->entries[i].text) + sci_free(buf->entries[i].text); + _con_free_entry_pixmaps(con_last_gfx_state, &buf->entries[i]); + + buf->entries[i].height = -1; + } + sci_free(buf); + --con_buffer_clusters; + + if (prev) + _free_con_buffer(prev); + } +} + + +byte con_builtin_font_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0xd6, 0x10, 0x38, + 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x7c, 0x10, 0x38, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, + 0x18, 0xdb, 0x3c, 0xe7, 0xe7, 0x3c, 0xdb, 0x18, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, + 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x3e, 0x61, 0x3c, 0x66, 0x66, 0x3c, 0x86, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00, + 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, + 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, + 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00, + 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, + 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00, + 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, + 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x00, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x7c, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3a, 0x00, + 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, + 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x7c, 0x0e, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, + 0x3c, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x3c, 0x00, + 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00, + 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, + 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0xdc, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, + 0x1c, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x3c, 0x66, 0x60, 0xf8, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x06, 0x00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, + 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x7e, 0xc0, 0x7c, 0x06, 0xfc, 0x00, + 0x30, 0x30, 0xfc, 0x30, 0x30, 0x36, 0x1c, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc, + 0x00, 0x00, 0x7e, 0x4c, 0x18, 0x32, 0x7e, 0x00, + 0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x70, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x70, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, + 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0x66, 0xfc, 0x00, + 0x00, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0x00, + 0x66, 0x66, 0x3c, 0x7e, 0x18, 0x7e, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, + 0x3e, 0x61, 0x3c, 0x66, 0x66, 0x3c, 0x86, 0x7c, + 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0x9d, 0xa1, 0xa1, 0x9d, 0x81, 0x7e, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xb9, 0xa5, 0xb9, 0xa5, 0x81, 0x7e, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, + 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x00, 0x00, 0x00, + 0x78, 0x0c, 0x38, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0xc0, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x38, + 0x18, 0x38, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x63, 0xe6, 0x6c, 0x7a, 0x36, 0x6a, 0xdf, 0x06, + 0x63, 0xe6, 0x6c, 0x7e, 0x33, 0x66, 0xcc, 0x0f, + 0xe1, 0x32, 0xe4, 0x3a, 0xf6, 0x2a, 0x5f, 0x86, + 0x18, 0x00, 0x18, 0x18, 0x30, 0x63, 0x3e, 0x00, + 0x18, 0x0c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x30, 0x60, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x7c, 0x82, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x76, 0xdc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x38, 0x6c, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, + 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x0c, 0x78, + 0x30, 0x18, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0x18, 0x30, 0xfe, 0xc0, 0xf8, 0xc0, 0xfe, 0x00, + 0x7c, 0x82, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0xc6, 0x00, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0x30, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x0c, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x3c, 0x42, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0xf6, 0x66, 0x6c, 0xf8, 0x00, + 0x76, 0xdc, 0x00, 0xe6, 0xf6, 0xde, 0xce, 0x00, + 0x0c, 0x06, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x30, 0x60, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x7c, 0x82, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x76, 0xdc, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, + 0x3a, 0x6c, 0xce, 0xd6, 0xe6, 0x6c, 0xb8, 0x00, + 0x60, 0x30, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x18, 0x30, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0x00, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x0c, 0x18, 0x66, 0x66, 0x3c, 0x18, 0x3c, 0x00, + 0xf0, 0x60, 0x7c, 0x66, 0x7c, 0x60, 0xf0, 0x00, + 0x78, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xcc, 0x00, + 0x30, 0x18, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x7c, 0x82, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x76, 0xdc, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00, + 0xc6, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x7e, 0x12, 0xfe, 0x90, 0xfe, 0x00, + 0x00, 0x00, 0x7e, 0xc0, 0xc0, 0x7e, 0x0c, 0x38, + 0x30, 0x18, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x0c, 0x18, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, + 0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, + 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x30, 0x7e, 0x0c, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x00, + 0x30, 0x18, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x0c, 0x18, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x76, 0xdc, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x02, 0x7c, 0xce, 0xd6, 0xe6, 0x7c, 0x80, + 0x60, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x78, 0x84, 0x00, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc, + 0xe0, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc +}; + +#endif /* !WANT_CONSOLE */ diff --git a/engines/sci/gfx/gfx_crossblit.c b/engines/sci/gfx/gfx_crossblit.c new file mode 100644 index 0000000000..af55a90490 --- /dev/null +++ b/engines/sci/gfx/gfx_crossblit.c @@ -0,0 +1,107 @@ +/*************************************************************************** + gfx_crossblit.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +/* This file isn't used directly; rather, it's included by a different file. */ +/* Note that memcpy() is assumed to be an inlineable built-in. If it isn't, +** performance will suck... badly. +*/ +/* Config parameters: +** FUNCTION_NAME: Name of the blitter function +** USE_PRIORITY: Whether to care about the priority buffer +** BYTESPP: Bytes per pixel +*/ + +/* set optimisations for Win32: */ +/* g on: enable global optimizations */ +/* t on: use fast code */ +/* y on: suppress creation of frame pointers on stack */ +/* s off: disable minimize size code */ +#ifdef _WIN32 +# include <memory.h> +# ifndef SATISFY_PURIFY +# pragma optimize( "s", off ) +# pragma optimize( "gty", on ) +# pragma intrinsic( memcpy, memset ) +# endif +#endif + +static void FUNCTION_NAME(byte *dest, byte *src, int bytes_per_dest_line, int bytes_per_src_line, + int xl, int yl, byte *alpha, int bytes_per_alpha_line, int bytes_per_alpha_pixel, + unsigned int alpha_test_mask, unsigned int alpha_min +#ifdef USE_PRIORITY + , byte *priority_buffer, int bytes_per_priority_line, int bytes_per_priority_pixel, int priority +#endif /* USE_PRIORITY */ + ) +{ + int x, y; + int alpha_end = xl * bytes_per_alpha_pixel; + + for (y = 0; y < yl; y++) { + int pixel_offset = 0; + int alpha_offset = 0; +#ifdef USE_PRIORITY + int priority_offset = 0; +#endif /* USE_PRIORITY */ + + for (x = 0; x < alpha_end; x += bytes_per_alpha_pixel) { + if ((alpha_test_mask & alpha[x]) +#ifdef REVERSE_ALPHA + >= +#else + < +#endif + alpha_min) +#ifdef USE_PRIORITY + if (priority_buffer[priority_offset] <= priority) { + priority_buffer[priority_offset] = priority; +#endif /* USE_PRIORITY */ + memcpy(dest + pixel_offset, src + pixel_offset, BYTESPP); +#ifdef USE_PRIORITY + } +#endif /* USE_PRIORITY */ + + pixel_offset += BYTESPP; + alpha_offset += bytes_per_alpha_pixel; +#ifdef USE_PRIORITY + priority_offset += bytes_per_priority_pixel; +#endif /* USE_PRIORITY */ + } + + dest += bytes_per_dest_line; + src += bytes_per_src_line; + alpha += bytes_per_alpha_line; +#ifdef USE_PRIORITY + priority_buffer += bytes_per_priority_line; +#endif /* USE_PRIORITY */ + } +} + +/* reset to original optimisations for Win32: */ +/* (does not reset intrinsics) */ +#ifdef _WIN32 +# pragma optimize( "", on ) +#endif diff --git a/engines/sci/gfx/gfx_line.c b/engines/sci/gfx/gfx_line.c new file mode 100644 index 0000000000..01b6a8fd2a --- /dev/null +++ b/engines/sci/gfx/gfx_line.c @@ -0,0 +1,96 @@ +/*************************************************************************** + gfx_line.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#define LINEMACRO(startx, starty, deltalinear, deltanonlinear, linearvar, nonlinearvar, \ + linearend, nonlinearstart, linearmod, nonlinearmod) \ + x = (startx); y = (starty); \ + incrNE = ((deltalinear) > 0)? (deltalinear) : -(deltalinear); \ + incrNE <<= 1; \ + deltanonlinear <<= 1; \ + incrE = ((deltanonlinear) > 0) ? -(deltanonlinear) : (deltanonlinear); \ + d = nonlinearstart-1; \ + while (linearvar != (linearend)) { \ + memcpy(buffer + linewidth * y + x, &color, PIXELWIDTH); \ + linearvar += linearmod; \ + if ((d+=incrE) < 0) { \ + d += incrNE; \ + nonlinearvar += nonlinearmod; \ + }; \ + }; \ + memcpy(buffer + linewidth * y + x, &color, PIXELWIDTH); + + +static inline +void DRAWLINE_FUNC(byte *buffer, int linewidth, point_t start, point_t end, unsigned int color) +{ + int dx, dy, incrE, incrNE, d, finalx, finaly; + int x = start.x; + int y = start.y; + dx = end.x - start.x; + dy = end.y - start.y; + finalx = end.x; + finaly = end.y; +#ifdef WORDS_BIGENDIAN + color = GUINT32_SWAP_LE_BE_CONSTANT(color); +#endif + 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, -PIXELWIDTH, -1); + } else { /* lld */ + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, -PIXELWIDTH, 1); + } + } else { /* x1 >= x */ + if (finaly < y) { /* rru */ + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, PIXELWIDTH, -1); + } else { /* rrd */ + LINEMACRO(x, y, dx, dy, x, y, finalx, dx, PIXELWIDTH, 1); + } + } + } else { /* dx <= dy */ + if (finaly < y) { + if (finalx < x) { /* luu */ + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, -PIXELWIDTH); + } else { /* ruu */ + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, -1, PIXELWIDTH); + } + } else { /* y1 >= y */ + if (finalx < x) { /* ldd */ + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, -PIXELWIDTH); + } else { /* rdd */ + LINEMACRO(x, y, dy, dx, y, x, finaly, dy, 1, PIXELWIDTH); + } + } + } +} + + + +#undef LINEMACRO diff --git a/engines/sci/gfx/gfx_pixmap_scale.c b/engines/sci/gfx/gfx_pixmap_scale.c new file mode 100644 index 0000000000..c288553eb1 --- /dev/null +++ b/engines/sci/gfx/gfx_pixmap_scale.c @@ -0,0 +1,497 @@ +/* Required defines: +** FUNCNAME: Function name +** SIZETYPE: Type used for each pixel +** EXTRA_BYTE_OFFSET: Extra source byte offset for copying (used on big-endian machines in 24 bit mode) +*/ + +/* set optimisations for Win32: */ +/* g on: enable global optimizations */ +/* t on: use fast code */ +/* y on: suppress creation of frame pointers on stack */ +/* s off: disable minimize size code */ +#ifdef _WIN32 +# include <memory.h> +# ifndef SATISFY_PURIFY +# pragma optimize( "s", off ) +# pragma optimize( "gty", on ) +# pragma intrinsic( memcpy, memset ) +# endif +#endif + +#include <sci_memory.h> + +#define EXTEND_COLOR(x) (unsigned) ((((unsigned) x) << 24) | (((unsigned) x) << 16) | (((unsigned) x) << 8) | ((unsigned) x)) +#define PALETTE_MODE mode->palette + +void +FUNCNAME(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + SIZETYPE result_colors[GFX_PIC_COLORS]; + SIZETYPE alpha_color = 0xffffffff & mode->alpha_mask; + SIZETYPE alpha_ormask = 0; + int xfact = (scale)? mode->xfact: 1; + int yfact = (scale)? mode->yfact: 1; + int widthc, heightc; /* Width duplication counter */ + int line_width = xfact * pxm->index_xl; + int bytespp = mode->bytespp; + int x, y; + int i; + byte byte_transparent = (mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA)? 0 : 255; + byte byte_opaque = (mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA)? 255 : 0; + byte *src = pxm->index_data; + byte *dest = pxm->data; + byte *alpha_dest = pxm->alpha_map; + int using_alpha = pxm->color_key != GFX_PIXMAP_COLOR_KEY_NONE; + int separate_alpha_map = (!mode->alpha_mask) && using_alpha; + + if (mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA) { + alpha_ormask = alpha_color; + alpha_color = 0; + } + + assert(bytespp == COPY_BYTES); + + if (separate_alpha_map && !alpha_dest) + alpha_dest = pxm->alpha_map = (byte*)sci_malloc(pxm->index_xl * xfact * pxm->index_yl * yfact); + + /* Calculate all colors */ + for (i = 0; i < pxm->colors_nr; i++) { + int col; + + if (PALETTE_MODE) + col = pxm->colors[i].global_index; + else { + col = mode->red_mask & ((EXTEND_COLOR(pxm->colors[i].r)) >> mode->red_shift); + col |= mode->green_mask & ((EXTEND_COLOR(pxm->colors[i].g)) >> mode->green_shift); + col |= mode->blue_mask & ((EXTEND_COLOR(pxm->colors[i].b)) >> mode->blue_shift); + col |= alpha_ormask; + } + result_colors[i] = col; + } + + if (!separate_alpha_map && pxm->color_key != GFX_PIXMAP_COLOR_KEY_NONE) + result_colors[pxm->color_key] = alpha_color; + + src = pxm->index_data; /* Workaround for gcc 4.2.3 bug on EMT64 */ + for (y = 0; y < pxm->index_yl; y++) { + byte *prev_dest = dest; + byte *prev_alpha_dest = alpha_dest; + + for (x = 0; x < pxm->index_xl; x++) { + int isalpha; + SIZETYPE col = result_colors[isalpha = *src++] << (EXTRA_BYTE_OFFSET * 8); + isalpha = (isalpha == pxm->color_key) && using_alpha; + + /* O(n) loops. There is an O(ln(n)) algorithm for this, but its slower for small n (which we're optimizing for here). + ** And, anyway, most of the time is spent in memcpy() anyway. */ + + for (widthc = 0; widthc < xfact; widthc++) { + memcpy(dest, &col, COPY_BYTES); + dest += COPY_BYTES; + } + + if (separate_alpha_map) { /* Set separate alpha map */ + memset(alpha_dest, (isalpha)? byte_transparent : byte_opaque, xfact); + alpha_dest += xfact; + } + } + + /* Copies each line. O(n) iterations; again, this could be optimized to O(ln(n)) for very high resolutions, + ** but that wouldn't really help that much, as the same amount of data still would have to be transferred. + */ + for (heightc = 1; heightc < yfact; heightc++) { + memcpy(dest, prev_dest, line_width * bytespp); + dest += line_width * bytespp; + if (separate_alpha_map) { + memcpy(alpha_dest, prev_alpha_dest, line_width); + alpha_dest += line_width; + } + } + } +} + + + + +/* linear filter: Macros (in reverse order) */ + +#define X_CALC_INTENSITY_NORMAL (ctexel[i] << 16) + ((linecolor[i])*(256-column_valuator)) + ((othercolumn[i]*column_valuator))*(256-line_valuator) +#define X_CALC_INTENSITY_CENTER (ctexel[i] << 16) + ((linecolor[i])*(256-column_valuator)) + +#define WRITE_XPART(X_CALC_INTENSITY, DO_X_STEP) \ + for (subx = 0; subx < ((DO_X_STEP)? (xfact >> 1) : 1); subx++) { \ + unsigned int intensity; \ + wrcolor = 0; \ + for (i = 0; i < 3; i++) { \ + intensity = X_CALC_INTENSITY; \ + wrcolor |= (intensity >> shifts[i]) & masks[i]; \ + } \ + i = 3; \ + intensity = X_CALC_INTENSITY; \ + if (inverse_alpha) \ + intensity = ~intensity; \ + wrcolor |= (intensity >> shifts[i]) & masks[i]; \ + if (separate_alpha_map) \ + *alpha_wrpos++ = intensity >> 24; \ + wrcolor <<= (EXTRA_BYTE_OFFSET * 8); \ + memcpy(wrpos, &wrcolor, COPY_BYTES); \ + wrpos += COPY_BYTES; \ + if (DO_X_STEP) \ + column_valuator -= column_step; \ + } \ + if (DO_X_STEP) \ + column_step = -column_step +/* End of macro definition */ + + +#define Y_CALC_INTENSITY_CENTER 0 +#define Y_CALC_INTENSITY_NORMAL otherline[i]*line_valuator + +#define WRITE_YPART(DO_Y_STEP, LINE_COLOR) \ + for (suby = 0; suby < ((DO_Y_STEP)? yfact >> 1 : 1); suby++) { \ + int column_valuator = column_step? 128 - (column_step >> 1) : 256; \ + int linecolor[4]; \ + int othercolumn[4]; \ + int i; \ + SIZETYPE wrcolor; \ + wrpos = sublinepos; \ + alpha_wrpos = alpha_sublinepos; \ + for (i = 0; i < 4; i++) \ + linecolor[i] = LINE_COLOR; \ + /*-- left half --*/ \ + MAKE_PIXEL((x == 0), othercolumn, ctexel, src[-1]); \ + WRITE_XPART(X_CALC_INTENSITY_NORMAL, 1); \ + column_valuator -= column_step; \ + /*-- center --*/ \ + if (xfact & 1) { \ + WRITE_XPART(X_CALC_INTENSITY_CENTER, 0); \ + } \ + /*-- right half --*/ \ + MAKE_PIXEL((x+1 == pxm->index_xl), othercolumn, ctexel, src[+1]); \ + WRITE_XPART(X_CALC_INTENSITY_NORMAL, 1); \ + if (DO_Y_STEP) \ + line_valuator -= line_step; \ + sublinepos += pxm->xl * bytespp; \ + alpha_sublinepos += pxm->xl; \ + } \ + if (DO_Y_STEP) \ + line_step = -line_step +/* End of macro definition */ + + + + +void +FUNCNAME_LINEAR(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + int xfact = mode->xfact; + int yfact = mode->yfact; + int line_step = (yfact < 2)? 0 : 256 / (yfact & ~1); + int column_step = (xfact < 2)? 0 : 256 / (xfact & ~1); + int bytespp = mode->bytespp; + byte *src = pxm->index_data; + byte *dest = pxm->data; + byte *alpha_dest = pxm->alpha_map; + int using_alpha = pxm->color_key != GFX_PIXMAP_COLOR_KEY_NONE; + int separate_alpha_map = (!mode->alpha_mask) && using_alpha; + unsigned int masks[4], shifts[4], zero[3]; + int x,y; + byte inverse_alpha = mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA; + + zero[0] = 255; + zero[1] = zero[2] = 0; + + if (separate_alpha_map) { + masks[3] = 0; + shifts[3] = 24; + } + + assert(bytespp == COPY_BYTES); + assert(!PALETTE_MODE); + + masks[0] = mode->red_mask; + masks[1] = mode->green_mask; + masks[2] = mode->blue_mask; + masks[3] = mode->alpha_mask; + shifts[0] = mode->red_shift; + shifts[1] = mode->green_shift; + shifts[2] = mode->blue_shift; + shifts[3] = mode->alpha_shift; + + if (separate_alpha_map && !alpha_dest) + alpha_dest = pxm->alpha_map = (byte*)sci_malloc(pxm->index_xl * xfact * pxm->index_yl * yfact); + + for (y = 0; y < pxm->index_yl; y++) { + byte *linepos = dest; + byte *alpha_linepos = alpha_dest; + + for (x = 0; x < pxm->index_xl; x++) { + int otherline[4]; /* the above line or the line below */ + int ctexel[4]; /* Current texel */ + int subx, suby; + int line_valuator = line_step? 128 - (line_step >> 1) : 256; + byte *wrpos, *alpha_wrpos; + byte *sublinepos = linepos; + byte *alpha_sublinepos = alpha_linepos; + + ctexel[0] = ctexel[1] = ctexel[2] = ctexel[3] = 0; + +#define MAKE_PIXEL(cond, rec, other, nr) \ + if ((cond) || (using_alpha && nr == pxm->color_key)) { \ + rec[0] = other[0] - ctexel[0]; \ + rec[1] = other[1] - ctexel[1]; \ + rec[2] = other[2] - ctexel[2]; \ + rec[3] = 0xffff - ctexel[3]; \ + } else { \ + rec[0] = (EXTEND_COLOR(pxm->colors[nr].r) >> 16) - ctexel[0]; \ + rec[1] = (EXTEND_COLOR(pxm->colors[nr].g) >> 16) - ctexel[1]; \ + rec[2] = (EXTEND_COLOR(pxm->colors[nr].b) >> 16) - ctexel[2]; \ + rec[3] = 0 - ctexel[3]; \ + } + + MAKE_PIXEL(0, ctexel, zero, *src); + + /*-- Upper half --*/ + MAKE_PIXEL((y == 0), otherline, ctexel, src[-pxm->index_xl]); + WRITE_YPART(1, Y_CALC_INTENSITY_NORMAL); + + if (yfact & 1) { + WRITE_YPART(0, Y_CALC_INTENSITY_CENTER); + } + + /*-- Lower half --*/ + line_valuator -= line_step; + MAKE_PIXEL((y+1 == pxm->index_yl), otherline, ctexel, src[pxm->index_xl]); + WRITE_YPART(1, Y_CALC_INTENSITY_NORMAL); + + src++; + linepos += xfact * bytespp; + alpha_linepos += xfact; + } + + dest += pxm->xl * yfact * bytespp; + alpha_dest += pxm->xl * yfact; + } +} + + + +/*----------------------*/ +/*** Trilinear filter ***/ +/*----------------------*/ + + +#ifndef GFX_GET_PIXEL_DELTA +#define GFX_GET_PIXEL_DELTA +static inline void +gfx_get_pixel_delta(unsigned int *color, int *delta, unsigned int *pixel0, unsigned int *pixel1) +{ + int j; + int transp0 = pixel0[3] == 0xffffff; + int transp1 = pixel1[3] == 0xffffff; + + if (transp0 && !transp1) { /* Transparent -> Opaque */ + memset(delta, 0, sizeof(int) * 3); + delta[3] = ((pixel1[3] >> 8) - (pixel0[3] >> 8)); + memcpy(color, pixel1, sizeof(int) * 3); + color[3] = 0xffffff; + } else if (!transp0 && transp1) { /* Opaque -> Transparent */ + memset(delta, 0, sizeof(int) * 3); + delta[3] = ((pixel1[3] >> 8) - (pixel0[3] >> 8)); + memcpy(color, pixel0, sizeof(int) * 4); + } else if (transp0 && transp1) { /* Transparent */ + delta[3] = 0; + color[3] = 0xffffff; + } else { /* Opaque */ + memcpy(color, pixel0, sizeof(int) * 4); + for (j = 0; j < 4; j++) + delta[j] = ((pixel1[j] >> 8) - (pixel0[j] >> 8)); + } +} + + +static inline void +gfx_apply_delta(unsigned int *color, int *delta, int factor) +{ + int i; + for (i = 0; i < 4; i++) + color[i] += delta[i] * factor; +} +#endif + +#define MAKE_PIXEL_TRILINEAR(cond, rec, nr) \ + if (!(cond) || (using_alpha && nr == pxm->color_key)) { \ + rec[0] = 0; \ + rec[1] = 0; \ + rec[2] = 0; \ + rec[3] = 0xffffff; \ + } else { \ + rec[0] = (EXTEND_COLOR(pxm->colors[nr].r) >> 8); \ + rec[1] = (EXTEND_COLOR(pxm->colors[nr].g) >> 8); \ + rec[2] = (EXTEND_COLOR(pxm->colors[nr].b) >> 8); \ + rec[3] = 0; \ + } + +#define REVERSE_ALPHA(foo) ((inverse_alpha)? ~(foo) : (foo)) + +void +FUNCNAME_TRILINEAR(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + int xfact = mode->xfact; + int yfact = mode->yfact; + int line_step = (yfact < 2)? 0 : 256 / yfact; + int column_step = (xfact < 2)? 0 : 256 / xfact; + int bytespp = mode->bytespp; + byte *src = pxm->index_data; + byte *dest = pxm->data; + byte *alpha_dest = pxm->alpha_map; + int using_alpha = pxm->color_key != GFX_PIXMAP_COLOR_KEY_NONE; + int separate_alpha_map = (!mode->alpha_mask) && using_alpha; + unsigned int masks[4], shifts[4]; + unsigned int pixels[4][4]; + /* 0 1 + ** 2 3 */ + int x,y; + byte inverse_alpha = mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA; + + if (separate_alpha_map) { + masks[3] = 0; + shifts[3] = 24; + } + + assert(bytespp == COPY_BYTES); + assert(!PALETTE_MODE); + + masks[0] = mode->red_mask; + masks[1] = mode->green_mask; + masks[2] = mode->blue_mask; + masks[3] = mode->alpha_mask; + shifts[0] = mode->red_shift; + shifts[1] = mode->green_shift; + shifts[2] = mode->blue_shift; + shifts[3] = mode->alpha_shift; + + if (!(pxm->index_xl && pxm->index_yl)) + return; /* Duh. */ + + if (separate_alpha_map && !alpha_dest) + alpha_dest = pxm->alpha_map = (byte*)sci_malloc(pxm->index_xl * xfact * pxm->index_yl * yfact); + + src -= pxm->index_xl + 1; + + for (y = 0; y <= pxm->index_yl; y++) { + byte *y_dest_backup = dest; + byte *y_alpha_dest_backup = alpha_dest; + int y_valuator = (y > 0)? 0 : 128; + int yc_count; + + + if (y == 0) + yc_count = yfact >> 1; + else if (y == pxm->index_yl) + yc_count = (yfact + 1) >> 1; + else + yc_count = yfact; + + if (yfact & 1) + y_valuator += line_step >> 1; + + for (x = 0; x <= pxm->index_xl; x++) { + byte *x_dest_backup = dest; + byte *x_alpha_dest_backup = alpha_dest; + int x_valuator = (x > 0)? 0 : 128; + int xc_count; + unsigned int leftcolor[4], rightcolor[4]; + int leftdelta[4], rightdelta[4]; + int xc, yc; + + if (x == 0) + xc_count = xfact >> 1; + else if (x == pxm->index_xl) + xc_count = (xfact + 1) >> 1; + else + xc_count = xfact; + + if (xfact & 1) + x_valuator += column_step >> 1; + + MAKE_PIXEL_TRILINEAR((y && x), pixels[0], *src); + MAKE_PIXEL_TRILINEAR((y && (x < pxm->index_xl)), pixels[1], src[1]); + MAKE_PIXEL_TRILINEAR(((y < pxm->index_yl) && x), pixels[2], src[pxm->index_xl]); + MAKE_PIXEL_TRILINEAR(((y < pxm->index_yl) && (x < pxm->index_xl)), + pixels[3], src[pxm->index_xl + 1]); + + /* OptimizeMe */ + + gfx_get_pixel_delta(leftcolor, leftdelta, pixels[0], pixels[2]); + gfx_get_pixel_delta(rightcolor, rightdelta, pixels[1], pixels[3]); + gfx_apply_delta(leftcolor, leftdelta, y_valuator); + gfx_apply_delta(rightcolor, rightdelta, y_valuator); + + for (yc = 0; yc < yc_count; yc++) { + unsigned int color[4]; + int delta[4]; + byte *yc_dest_backup = dest; + byte *yc_alpha_dest_backup = alpha_dest; + + gfx_get_pixel_delta(color, delta, leftcolor, rightcolor); + + gfx_apply_delta(color, delta, x_valuator); + + for (xc = 0; xc < xc_count; xc++) { + SIZETYPE wrcolor; + int i; + wrcolor = 0; + + for (i = 0; i < 3; i++) + wrcolor |= ((color[i] << 8) >> shifts[i]) & masks[i]; + + if (separate_alpha_map) { + *alpha_dest++ = REVERSE_ALPHA(color[3] >> 16); + } else + wrcolor |= REVERSE_ALPHA((color[3] << 8) >> shifts[3]) & masks[3]; + + wrcolor <<= (EXTRA_BYTE_OFFSET * 8); + + memcpy(dest, &wrcolor, COPY_BYTES); + dest += COPY_BYTES; + gfx_apply_delta(color, delta, column_step); + } + gfx_apply_delta(leftcolor, leftdelta, line_step); + gfx_apply_delta(rightcolor, rightdelta, line_step); + + dest = yc_dest_backup + pxm->index_xl * xfact * COPY_BYTES; + alpha_dest = yc_alpha_dest_backup + pxm->index_xl * xfact; + } + + dest = x_dest_backup + xc_count * COPY_BYTES; + alpha_dest = x_alpha_dest_backup + xc_count; + + if (x < pxm->index_xl) + src++; + } + dest = y_dest_backup + pxm->index_xl * xfact * yc_count * COPY_BYTES; + alpha_dest = y_alpha_dest_backup + pxm->index_xl * xfact * yc_count; + } +} + +#undef REVERSE_ALPHA +#undef WRITE_YPART +#undef Y_CALC_INTENSITY_CENTER +#undef Y_CALC_INTENSITY_NORMAL +#undef WRITE_XPART +#undef X_CALC_INTENSITY_CENTER +#undef X_CALC_INTENSITY_NORMAL +#undef MAKE_PIXEL_TRILINEAR +#undef MAKE_PIXEL +#undef FUNCNAME +#undef FUNCNAME_LINEAR +#undef FUNCNAME_TRILINEAR +#undef SIZETYPE +#undef EXTEND_COLOR + +/* reset to original optimisations for Win32: */ +/* (does not reset intrinsics) */ +#ifdef _WIN32 +# pragma optimize( "", on ) +#endif diff --git a/engines/sci/gfx/gfx_res_options.c b/engines/sci/gfx/gfx_res_options.c new file mode 100644 index 0000000000..cec2c1f26a --- /dev/null +++ b/engines/sci/gfx/gfx_res_options.c @@ -0,0 +1,652 @@ +/*************************************************************************** + gfx_res_options.c Copyright (C) 2002 Christoph Reichenbach + + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundaton; either version 2 of the + Licence, or (at your option) any later version. + + It is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantibility or fitness for a particular purpose. See the + GNU General Public Licence for more details. + + You should have received a copy of the GNU General Public Licence + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + + Please contact the maintainer for any program-related bug reports or + inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <gfx_system.h> +#include <gfx_options.h> +#include <gfx_resmgr.h> + +#include <ctype.h> + +/*#define DEBUG*/ + +static gfx_res_pattern_list_t* +pattern_list_insert(gfx_res_pattern_list_t *list, int min, int max) +{ + gfx_res_pattern_list_t *retval = (gfx_res_pattern_list_t*)sci_malloc(sizeof(gfx_res_pattern_list_t)); + retval->pattern.min = min; + retval->pattern.max = max; + retval->next = list; + + return retval; +} + +static int +pattern_list_len(gfx_res_pattern_list_t *list) +{ + int v = 0; + while (list) { + ++v; + list = list->next; + } + + return v; +} + +static void +pattern_list_flatten(gfx_res_pattern_t *dest, gfx_res_pattern_list_t *list) +{ + while (list) { + *dest++ = list->pattern; + list = list->next; + } +} + +static inline void +pattern_list_free(gfx_res_pattern_list_t *list) +{ + if (list) + pattern_list_free(list->next); + + free(list); +} + + +static inline int +extract_pattern(gfx_res_pattern_list_t **destp, + char *src, int offset) +{ + char *src_orig = src - offset; + int final = 0; + int wildcard = 0; + + while (!final) { + char *end = strchr(src, ','); + if (end) + *end = 0; + else + final = 1; + + while (*src && isblank(*src)) + ++src; + + if (*src == '*' + || *src == '_') { + wildcard = 1; + ++src; + } else if (*src == '.' || isdigit(*src)) { + char *endp; + int start = strtol(src, &endp, 0); + + if (*src == '.' + && src[1] == '.') { + start = GFX_RES_PATTERN_MIN; + endp = src; + } + + src = endp; + + while (*src && isblank(*src)) + ++src; + + if (*src) { + int stop; + if (*src == '.' + && src[1] == '.') { + + src += 2; + while (*src && isblank(*src)) + ++src; + + if (!*src) + stop = GFX_RES_PATTERN_MAX; + else if (!isdigit(*src)) { + if (end) + *end = ','; + goto lexical_error_label; + } + + stop = strtol(src, &endp, 0); + src = endp; + + *destp = pattern_list_insert(*destp, + start, stop); + + } else { /* No ellipsis */ + if (end) + *end = ','; + goto lexical_error_label; + } + } else /* End of sub-pattern */ + *destp = pattern_list_insert(*destp, + start, start); + + while (*src && isblank(*src)) + ++src; + + if (*src) { + if (end) + *end = ','; + goto lexical_error_label; + } + + } else { + if (end) + *end = ','; + sciprintf("[gfx-conf] Unexpected character '%c'\n", + *src); + goto lexical_error_label; + } + + if (!final) { + *end = ','; + src = end + 1; + } + } + + if (wildcard) { + pattern_list_free(*destp); + *destp = NULL; + } + + return 0; + + lexical_error_label: + sciprintf("[gfx-conf] Lexical error in pattern at offset %d\n", + src - src_orig); + return 1; +} + +static int +extract_mod_rule(char *src, gfx_res_mod_t *rule) +{ + char *orig_src = src; + char *endp; + float f[3]; + int i; + + rule->type = GFX_RES_MULTIPLY_FIXED; + + if (isdigit(*src) || *src == '.') { + f[0] = f[1] = f[2] = strtod(src, &endp); + + if (*endp) + goto mod_error_label; + } else if (*src == '(') { + i = 0; + ++src; + + do { + while (*src && isblank(*src)) + ++src; + if (!*src || !(isdigit(*src) || *src == '.')) { + sciprintf("[gfx-conf] Unexpected character '%c'\n", + *src); + goto mod_error_label; + } + f[i++] = strtod(src, &endp); + + src = endp; + + while (*src && isblank(*src)) + ++src; + + if ((i == 3) && *src != ')') { + sciprintf("[gfx-conf] Error: Expected ')' at end of modification rule\n"); + goto mod_error_label; + } else if (i<3 && !isdigit(*src) && *src != '.' && *src != ',') { + sciprintf("[gfx-conf] Error: Expected ',' as separator in modification rule, not '%c'\n", + *src); + goto mod_error_label; + } + ++src; + } while (i < 3); + + if (*src) { + sciprintf("[gfx-conf] Error: Trailing garbage after modification rule\n"); + goto mod_error_label; + } + + } else + goto mod_error_label; + + for (i = 0; i < 3; i++) { + int v = (int)(f[i] * 16.0); + rule->mod.factor[i] = (v > 255) ? 255 : v; + } + + return 0; + mod_error_label: + sciprintf("[gfx-conf] Ill-formed modification rule '%s'\n", + orig_src); + return 1; +} + + +extern gfx_pixmap_color_t gfx_sci0_image_colors[][GFX_SCI0_IMAGE_COLORS_NR]; + +#define PREDEFINED_PALETTES_NR 4 +static int +extract_assign_rule(char *src, gfx_res_assign_t *rule) +{ + /*char *orig_src = src;*/ + struct { + const char *name; + int colors_nr; + gfx_pixmap_color_t *colors; + } predefined_palettes[PREDEFINED_PALETTES_NR] = { + {"default", 16, (gfx_pixmap_color_t *) &(gfx_sci0_image_colors[0])}, + {"amiga", 16, (gfx_pixmap_color_t *) &(gfx_sci0_image_colors[1])}, + {"gray", 16, (gfx_pixmap_color_t *) &(gfx_sci0_image_colors[2])}, + {"grey", 16, (gfx_pixmap_color_t *) &(gfx_sci0_image_colors[2])}, + }; + int i; + + rule->type = GFX_RES_ASSIGN_TYPE_PALETTE; + + for (i = 0; i < PREDEFINED_PALETTES_NR; i++) + if (!strcmp(src, predefined_palettes[i].name)) { + rule->assign.palette.colors_nr = + predefined_palettes[i].colors_nr; + rule->assign.palette.colors = + predefined_palettes[i].colors; + return 0; + } + + sciprintf("[gfx-conf] Unknown palette '%s'\n", src); + return 1; + /* + assign_error_label: + sciprintf("[gfx-conf] Ill-formed assignment rule '%s'\n", + orig_src); + return 1; + */ +} + +#define CLASSES_NR 3 +int +gfx_update_conf(gfx_options_t *options, char *str) +{ + int total_patterns; + int mod = 0; /* Modifier or assignment rule? */ + char *orig_str = str; + char *sem_end; + + int fields_nr; /* Number of fields a restriction is possible by. + ** cursors:1, pics:2, views:3. */ + struct { + const char *class_name; + int class_id; + int fields_nr; + } classes[CLASSES_NR] = { + {"view", GFX_RESOURCE_TYPE_VIEW, 3}, + {"pic", GFX_RESOURCE_TYPE_PIC, 2}, + {"cursor", GFX_RESOURCE_TYPE_CURSOR, 1}, + }; + gfx_res_conf_t *conf = (gfx_res_conf_t*)sci_malloc(sizeof(gfx_res_conf_t)); + gfx_res_pattern_list_t *patterns = NULL; + gfx_res_pattern_list_t *loops = NULL; + gfx_res_pattern_list_t *cels = NULL; + gfx_res_pattern_list_t **fields[3] = { + &patterns, &loops, &cels + }; + int i; + int fieldcnt; + const char *pat_name_str; + + /* Extract pattern(s) */ + while (*str && isblank(*str)) + ++str; + + fields_nr = -1; + for (i = 0; i < CLASSES_NR; i++) { + int len = strlen(classes[i].class_name); + + if (!strncmp(str, classes[i].class_name, len)) { + pat_name_str = classes[i].class_name; + conf->type = classes[i].class_id; + fields_nr = classes[i].fields_nr; + str += len; + break; + } + } + + if (fields_nr == -1) { + sciprintf("[gfx-conf] Unexpected pattern class: Expected one of 'view', 'pic', 'cursor'\n"); + goto failure_label; + } + + fieldcnt = 0; + do { + while (*str && isblank(*str)) + ++str; + + if (!*str) + goto unexpected_end; + + if (*str == '=' + || *str == '*') + break; + + if (*str == '(') { + char *end = strchr(str, ')'); + + if (fieldcnt >= fields_nr) { + sciprintf("[gfx-conf] Error: Patterns of class '%s' may only be" + " constrained by %d arguments\n", + pat_name_str, fields_nr); + goto failure_label; + } + + if (!end) { + sciprintf("[gfx-conf] Unmatched parentheses at offset %d\n", + str - orig_str); + goto failure_label; + } + *end = 0; + + if (extract_pattern(fields[fieldcnt++], + str + 1, + str + 1 - orig_str)) + goto failure_label; + + *end = ')'; + str = end + 1; + + continue; + } + + sciprintf("[gfx-conf] Lexical error in pattern at offset %d: Unexpected '%c'\n", + str - orig_str, *str); + goto failure_label; + } while (1); + + + /* Flatten patterns */ + conf->patterns = NULL; + total_patterns = conf->patterns_nr = pattern_list_len(patterns); + total_patterns += (conf->loops_nr = pattern_list_len(loops)); + total_patterns += (conf->cels_nr = pattern_list_len(cels)); + + conf->patterns = (gfx_res_pattern_t*)sci_malloc(1 + (sizeof(gfx_res_pattern_t) * total_patterns)); + pattern_list_flatten(conf->patterns, patterns); + pattern_list_flatten(conf->patterns + conf->patterns_nr, loops); + pattern_list_flatten(conf->patterns + conf->patterns_nr + conf->loops_nr, cels); + + pattern_list_free(patterns); + patterns = NULL; + pattern_list_free(loops); + loops = NULL; + pattern_list_free(cels); + cels = NULL; + + /* Parse remainder */ + if (*str == '*') { + mod = 1; + ++str; + } + + if (*str != '=') { + sciprintf("[gfx-conf] Expected '='\n"); + goto failure_label; + } + + do { ++str; } + while (*str && isblank(*str)); + + sem_end = strchr(str, ';'); + if (!sem_end) { + sciprintf("[gfx-conf] Expected ';' at end of rule\n"); + goto failure_label; + } + do { *sem_end-- = 0; } + while (sem_end >= str + && isblank(*sem_end)); + + if (mod) { + if (extract_mod_rule(str, &conf->conf.mod)) + goto failure_label; + } else { + if (extract_assign_rule(str, &conf->conf.assign)) + goto failure_label; + } + + /* Write back into options */ + if (mod) { + conf->next = options->res_conf.mod[conf->type]; + options->res_conf.mod[conf->type] = conf; + } else { + conf->next = options->res_conf.assign[conf->type]; + options->res_conf.assign[conf->type] = conf; + } + + return 0; + + /* Error handling */ +unexpected_end: + sciprintf("[gfx-conf] Unexpected end of pattern encountered\n"); + failure_label: + sciprintf("[gfx-conf] Error occured in: '%s'\n", orig_str); + pattern_list_free(patterns); + pattern_list_free(loops); + pattern_list_free(cels); + if (conf->patterns) + free(conf->patterns); + free(conf); + return 1; +} + +static inline int +matches_patternlist(gfx_res_pattern_t *patterns, int nr, int val) +{ + int i; + for (i = 0; i < nr; i++) + if (patterns[i].min <= val + && patterns[i].max >= val) + return 1; + + return 0; +} + +#ifdef DEBUG +static void +print_pattern(gfx_res_pattern_t *pat) +{ + fprintf(stderr, "[%d..%d]", + pat->min, pat->max); +} +#endif + +static inline int +resource_matches_patternlists(gfx_res_conf_t *conf, + int type, int nr, int loop, int cel) +{ + int loc; +#ifdef DEBUG + int i; + fprintf(stderr, "[DEBUG:gfx-res] Trying to match against %d/%d/%d choices\n", + conf->patterns_nr, conf->loops_nr, conf->cels_nr); + for (i = 0; i < conf->patterns_nr; i++) { + fprintf(stderr, "[DEBUG:gfx-res] Pat #%d: ", i); + print_pattern(conf->patterns + i); + fprintf(stderr, "\n"); + } + loc = conf->patterns_nr; + for (i = 0; i < conf->loops_nr; i++) { + fprintf(stderr, "[DEBUG:gfx-res] Loop #%d: ", i); + print_pattern(conf->patterns + i + loc); + fprintf(stderr, "\n"); + } + loc += conf->loops_nr; + for (i = 0; i < conf->cels_nr; i++) { + fprintf(stderr, "[DEBUG:gfx-res] Cel #%d: ", i); + print_pattern(conf->patterns + i + loc); + fprintf(stderr, "\n"); + } +#endif + if (conf->patterns_nr && + !matches_patternlist(conf->patterns, + conf->patterns_nr, + nr)) + return 0; + + if (type == GFX_RESOURCE_TYPE_CURSOR) + return 1; + + /* Otherwise, we must match at least the loop (pic) + ** and, for views, the cel as well */ + loc = conf->patterns_nr; + if (conf->loops_nr && + !matches_patternlist(conf->patterns + loc, + conf->loops_nr, + loop)) + return 0; + + if (type != GFX_RESOURCE_TYPE_VIEW) + return 1; + + loc += conf->loops_nr; + + if (!conf->cels_nr) + return 1; + + return matches_patternlist(conf->patterns + loc, + conf->cels_nr, + cel); +} + +static inline gfx_res_conf_t * +find_match(gfx_res_conf_t *conflist, + int type, int nr, int loop, int cel) +{ + while (conflist) { + if (resource_matches_patternlists(conflist, + type, nr, loop, cel)) { +#ifdef DEBUG + fprintf(stderr, "[DEBUG:gfx-res] Found match!\n"); +#endif + return conflist; + } + + conflist = conflist->next; + } + return NULL; +} + +void +apply_assign(gfx_res_assign_t *conf, gfx_pixmap_t *pxm) +{ + /* Has a dynamically allocated palette? Must clean up */ + if (!(pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) { + if (pxm->colors) + free(pxm->colors); + pxm->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + } + + pxm->colors_nr = conf->assign.palette.colors_nr; + pxm->colors = conf->assign.palette.colors; +} + +void +apply_mod(gfx_res_mod_t *mod, gfx_pixmap_t *pxm) +{ + gfx_pixmap_color_t *pal = pxm->colors; + int i, pal_size = pxm->colors_nr; + + /* Does not have a dynamically allocated palette? Must dup current one */ + if (pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE) { + int size = sizeof(gfx_pixmap_color_t) * pal_size; + pxm->colors = (gfx_pixmap_color_t*)sci_malloc(size); + memcpy(pxm->colors, pal, size); + pal = pxm->colors; + pxm->flags &= ~GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + /* Flag for later deallocation */ + } + + switch (mod->type) { + + case GFX_RES_MULTIPLY_FIXED: { + for (i = 0; i < pal_size; i++) { + int v; + +#define UPDATE_COL(nm, idx) \ + v = pal[i].nm; \ + v *= mod->mod.factor[idx]; \ + v >>= 4; \ + pal[i].nm = (v > 255)? 255 : v; + + UPDATE_COL(r, 0); + UPDATE_COL(g, 1); + UPDATE_COL(b, 2); +#undef UPDATE_COL + } + break; + } + + default: + GFXERROR("Using unexpected visual resource modifier %d\n", mod->type); + } +} + +int +gfx_get_res_config(gfx_options_t *options, gfx_pixmap_t *pxm) +{ + int restype = GFXR_RES_TYPE(pxm->ID); + int nr = GFXR_RES_NR(pxm->ID); + int loop = pxm->loop; + int cel = pxm->cel; + + gfx_res_conf_t *conf; + +#ifdef DEBUG + fprintf(stderr, "[DEBUG:gfx-res] Trying to conf %d/%d/%d/%d (ID=%d)\n", + restype, nr, loop, cel, pxm->ID); +#endif + + if (pxm->ID < 0 || restype < 0 || restype >= GFX_RESOURCE_TYPES_NR) + return 1; /* Not appropriate */ + + conf = find_match(options->res_conf.assign[restype], + restype, nr, loop, cel); + + if (conf) + apply_assign(&(conf->conf.assign), pxm); + + conf = options->res_conf.mod[restype]; + while (conf) { + conf = find_match(conf, + restype, nr, loop, cel); + if (conf) { + apply_mod(&(conf->conf.mod), pxm); + conf = conf->next; + } + } + fflush(NULL); + + return 0; +} diff --git a/engines/sci/gfx/gfx_resource.c b/engines/sci/gfx/gfx_resource.c new file mode 100644 index 0000000000..6ac7567d76 --- /dev/null +++ b/engines/sci/gfx/gfx_resource.c @@ -0,0 +1,434 @@ +/*************************************************************************** + gfx_resource.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + +gfx_mode_t mode_1x1_color_index = { /* Fake 1x1 mode */ + /* xfact */ 1, /* yfact */ 1, + /* bytespp */ 1, + /* flags */ 0, + /* palette */ NULL, + + /* color masks */ 0, 0, 0, 0, + /* color shifts */ 0, 0, 0, 0 +}; + + +static void +gfxr_free_loop(gfx_driver_t *driver, gfxr_loop_t *loop) +{ + int i; + + if (loop->cels) { + for (i = 0; i < loop->cels_nr; i++) + if (loop->cels[i]) + gfx_free_pixmap(driver, loop->cels[i]); + + free(loop->cels); + } +} + +void +gfxr_free_view(gfx_driver_t *driver, gfxr_view_t *view) +{ + int i; + + if (view->colors && !(view->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) + free(view->colors); + + if (view->loops) { + for (i = 0; i < view->loops_nr; i++) + gfxr_free_loop(driver, view->loops + i); + + free(view->loops); + } + free(view); +} + + +static void +pixmap_endianness_reverse_2_simple(byte *data, int area) +{ + int c; + for (c = 0; c < area; c++) { + byte val = *data; + *data = data[1]; + data[1] = val; + + data += 2; + } +} + +static void +pixmap_endianness_reverse_2(byte *data, int area) +{ + int c; + int sl = sizeof(unsigned long); + + for (c = 0; c < (area & ~(sl-1)); c += (sl>>1)) { + unsigned long temp; + + memcpy(&temp, data, sl); + + /* The next line will give warnings on 32 bit archs, but + ** that's OK. */ +#if SIZEOF_LONG < 8 + temp = 0; +#else + temp = ((temp & 0xff00ff00ff00ff00l) >> 8) + | ((temp & 0x00ff00ff00ff00ffl) << 8); +#endif /* SIZEOF_INT < 8 */ + + memcpy(data, &temp, sl); + + data += sl; + } + + pixmap_endianness_reverse_2_simple(data, area & (sl-1)); +} + +static void +pixmap_endianness_reverse_3_simple(byte *data, int area) +{ + int c; + for (c = 0; c < area; c++) { + byte val0 = data[0]; + + data[0] = data[2]; + data[2] = val0; + + data += 3; + } +} + +static void +pixmap_endianness_reverse_4_simple(byte *data, int area) +{ + int c; + for (c = 0; c < area; c++) { + byte val0 = data[0]; + byte val1 = data[1]; + + data[0] = data[3]; + data[3] = val0; + + data[1] = data[2]; + data[2] = val1; + + data += 4; + } +} + +static void +pixmap_endianness_reverse_4(byte *data, int area) +{ + int c; + int sl = sizeof(unsigned long); + + for (c = 0; c < (area & ~(sl-1)); c += (sl>>2)) { + unsigned long temp; + + memcpy(&temp, data, sl); + + /* The next lines will give warnings on 32 bit archs, but + ** that's OK. */ +#if SIZEOF_LONG < 8 + temp = 0l; +#else + temp = ((temp & 0xffff0000ffff0000l) >> 16) + | ((temp & 0x0000ffff0000ffffl) << 16); + temp = ((temp & 0xff00ff00ff00ff00l) >> 8) + | ((temp & 0x00ff00ff00ff00ffl) << 8); +#endif /* SIZEOF_LONG < 8 */ + + memcpy(data, &temp, sl); + + data += sl; + } + + pixmap_endianness_reverse_4_simple(data, area & (sl-1)); +} + +gfx_pixmap_t * +gfxr_endianness_adjust(gfx_pixmap_t *pixmap, gfx_mode_t *mode) +{ + int bytespp; + byte *data; + + if (!pixmap || !pixmap->data || !mode) { + GFXERROR("gfxr_endianness_adjust(): Invoked with invalid values\n"); + BREAKPOINT(); + return NULL; + } + + if (!(mode->flags & GFX_MODE_FLAG_REVERSE_ENDIAN)) + return pixmap; + + bytespp = mode->bytespp; + + data = pixmap->data; + + switch (bytespp) { + case 1: + break; + + case 2: pixmap_endianness_reverse_2(data, pixmap->xl + * pixmap->yl); + break; + + case 3: pixmap_endianness_reverse_3_simple(data, pixmap->xl + * pixmap->yl); + break; + + case 4: pixmap_endianness_reverse_4(data, pixmap->xl * pixmap->yl); + break; + + default: fprintf(stderr,"gfxr_endianness_adjust(): Cannot adjust endianness for %d bytespp!\n", bytespp); + return NULL; + } + + return pixmap; +} + + +/* Now construct the pixmap scaling functions */ +#define EXTRA_BYTE_OFFSET 0 +#define SIZETYPE guint8 +#define FUNCNAME _gfx_xlate_pixmap_unfiltered_1 +#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_1 +#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_1 +#define COPY_BYTES 1 +#include "gfx_pixmap_scale.c" +#undef COPY_BYTES + +#define SIZETYPE guint16 +#define FUNCNAME _gfx_xlate_pixmap_unfiltered_2 +#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_2 +#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_2 +#define COPY_BYTES 2 +#include "gfx_pixmap_scale.c" +#undef COPY_BYTES + +#ifdef WORDS_BIGENDIAN +# undef EXTRA_BYTE_OFFSET +# define EXTRA_BYTE_OFFSET 1 +#endif /* WORDS_BIGENDIAN */ +#define SIZETYPE guint32 +#define FUNCNAME _gfx_xlate_pixmap_unfiltered_3 +#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_3 +#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_3 +#define COPY_BYTES 3 +#include "gfx_pixmap_scale.c" +#undef COPY_BYTES +#ifdef WORDS_BIGENDIAN +# undef EXTRA_BYTE_OFFSET +# define EXTRA_BYTE_OFFSET 0 +#endif /* WORDS_BIGENDIAN */ + +#define SIZETYPE guint32 +#define FUNCNAME _gfx_xlate_pixmap_unfiltered_4 +#define FUNCNAME_LINEAR _gfx_xlate_pixmap_linear_4 +#define FUNCNAME_TRILINEAR _gfx_xlate_pixmap_trilinear_4 +#define COPY_BYTES 4 +#include "gfx_pixmap_scale.c" +#undef COPY_BYTES +#undef EXTRA_BYTE_OFFSET +#undef SIZETYPE + +static inline void +_gfx_xlate_pixmap_unfiltered(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + switch (mode->bytespp) { + + case 1:_gfx_xlate_pixmap_unfiltered_1(mode, pxm, scale); + break; + + case 2:_gfx_xlate_pixmap_unfiltered_2(mode, pxm, scale); + break; + + case 3:_gfx_xlate_pixmap_unfiltered_3(mode, pxm, scale); + break; + + case 4:_gfx_xlate_pixmap_unfiltered_4(mode, pxm, scale); + break; + + default: + GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp); + + } + + if (pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) { + pxm->xl = pxm->index_xl; + pxm->yl = pxm->index_yl; + } else { + pxm->xl = pxm->index_xl * mode->xfact; + pxm->yl = pxm->index_yl * mode->yfact; + } +} + +static inline void +_gfx_xlate_pixmap_linear(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + if (mode->palette || !scale) { /* fall back to unfiltered */ + _gfx_xlate_pixmap_unfiltered(mode, pxm, scale); + return; + } + + pxm->xl = pxm->index_xl * mode->xfact; + pxm->yl = pxm->index_yl * mode->yfact; + + switch (mode->bytespp) { + + case 1:_gfx_xlate_pixmap_linear_1(mode, pxm, scale); + break; + + case 2:_gfx_xlate_pixmap_linear_2(mode, pxm, scale); + break; + + case 3:_gfx_xlate_pixmap_linear_3(mode, pxm, scale); + break; + + case 4:_gfx_xlate_pixmap_linear_4(mode, pxm, scale); + break; + + default: + GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp); + + } + +} + +static inline void +_gfx_xlate_pixmap_trilinear(gfx_mode_t *mode, gfx_pixmap_t *pxm, int scale) +{ + if (mode->palette || !scale) { /* fall back to unfiltered */ + _gfx_xlate_pixmap_unfiltered(mode, pxm, scale); + return; + } + + pxm->xl = pxm->index_xl * mode->xfact; + pxm->yl = pxm->index_yl * mode->yfact; + + switch (mode->bytespp) { + + case 1:_gfx_xlate_pixmap_trilinear_1(mode, pxm, scale); + break; + + case 2:_gfx_xlate_pixmap_trilinear_2(mode, pxm, scale); + break; + + case 3:_gfx_xlate_pixmap_trilinear_3(mode, pxm, scale); + break; + + case 4:_gfx_xlate_pixmap_trilinear_4(mode, pxm, scale); + break; + + default: + GFXERROR("Invalid mode->bytespp=%d\n", mode->bytespp); + + } + +} + +void +gfx_xlate_pixmap(gfx_pixmap_t *pxm, gfx_mode_t *mode, gfx_xlate_filter_t filter) +{ + int was_allocated = 0; + + if (mode->palette + && !(pxm->flags & GFX_PIXMAP_FLAG_PALETTE_ALLOCATED)) { + int i; + + for (i = 0; i < pxm->colors_nr; i++) { + if (gfx_alloc_color(mode->palette, pxm->colors + i) < 0) { + GFXWARN("Failed to allocate color %d/%d in pixmap (color %02x/%02x/%02x)!\n", + i, pxm->colors_nr, pxm->colors[i].r, pxm->colors[i].g, pxm->colors[i].b); + pxm->colors[i].global_index = 0; + } + /* + GFXDEBUG("alloc(%02x/%02x/%02x) -> %d\n", pxm->colors[i].r,pxm->colors[i].g,pxm->colors[i].b,pxm->colors[i].global_index); + */ + } + + pxm->flags |= GFX_PIXMAP_FLAG_PALETTE_ALLOCATED; + } + + + if (!pxm->data) { + pxm->data = (byte*)sci_malloc(mode->xfact * mode->yfact * pxm->index_xl * pxm->index_yl * mode->bytespp + 1); + /* +1: Eases coying on BE machines in 24 bpp packed mode */ + /* Assume that memory, if allocated already, will be sufficient */ + + /* Allocate alpha map */ + if (!mode->alpha_mask && pxm->colors_nr < GFX_PIC_COLORS) + pxm->alpha_map = (byte*)sci_malloc(mode->xfact * mode->yfact * pxm->index_xl * pxm->index_yl + 1); + } else + was_allocated = 1; + + switch (filter) { + + case GFX_XLATE_FILTER_NONE: _gfx_xlate_pixmap_unfiltered(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)); + break; + + case GFX_XLATE_FILTER_LINEAR: _gfx_xlate_pixmap_linear(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)); + break; + + case GFX_XLATE_FILTER_TRILINEAR: _gfx_xlate_pixmap_trilinear(mode, pxm, !(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)); + break; + + default: + GFXERROR("Attempt to filter pixmap %04x in invalid mode #%d\n", pxm->ID, filter); + + if (!was_allocated) { + if (!mode->alpha_mask && pxm->colors_nr < GFX_PIC_COLORS) + free(pxm->alpha_map); + free(pxm->data); + } + } +} + + +void +gfxr_free_pic(gfx_driver_t *driver, gfxr_pic_t *pic) +{ + gfx_free_pixmap(driver, pic->visual_map); + gfx_free_pixmap(driver, pic->priority_map); + gfx_free_pixmap(driver, pic->control_map); + pic->visual_map = NULL; + pic->priority_map = NULL; + pic->control_map = NULL; + if (pic->internal) + free(pic->internal); + pic->internal = NULL; + if (pic->undithered_buffer) + free(pic->undithered_buffer); + pic->undithered_buffer = 0; + free(pic); +} + diff --git a/engines/sci/gfx/gfx_support.c b/engines/sci/gfx/gfx_support.c new file mode 100644 index 0000000000..8edf9b3dff --- /dev/null +++ b/engines/sci/gfx/gfx_support.c @@ -0,0 +1,450 @@ +/*************************************************************************** + gfx_support.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Graphics support functions for drivers and replacements for driver functions +** for use with the graphical state manager +*/ + +#include <gfx_system.h> +#include <gfx_tools.h> + +#ifdef HAVE_ALPHA_EV6_SUPPORT +int axp_have_mvi = 0; +#endif + +int gfx_crossblit_alpha_threshold = 128; + +#define DRAWLINE_FUNC _gfx_draw_line_buffer_1 +#define PIXELWIDTH 1 +#include "gfx_line.c" +#undef PIXELWIDTH +#undef DRAWLINE_FUNC + +#define DRAWLINE_FUNC _gfx_draw_line_buffer_2 +#define PIXELWIDTH 2 +#include "gfx_line.c" +#undef PIXELWIDTH +#undef DRAWLINE_FUNC + +#define DRAWLINE_FUNC _gfx_draw_line_buffer_3 +#define PIXELWIDTH 3 +#include "gfx_line.c" +#undef PIXELWIDTH +#undef DRAWLINE_FUNC + +#define DRAWLINE_FUNC _gfx_draw_line_buffer_4 +#define PIXELWIDTH 4 +#include "gfx_line.c" +#undef PIXELWIDTH +#undef DRAWLINE_FUNC + +inline void +gfx_draw_line_buffer(byte *buffer, int linewidth, int pixelwidth, point_t start, point_t end, unsigned int color) +{ + switch (pixelwidth) { + + case 1: + _gfx_draw_line_buffer_1(buffer, linewidth, start, end, color); + return; + + case 2: + _gfx_draw_line_buffer_2(buffer, linewidth, start, end, color); + return; + + case 3: + _gfx_draw_line_buffer_3(buffer, linewidth, start, end, color); + return; + + case 4: + _gfx_draw_line_buffer_4(buffer, linewidth, start, end, color); + return; + + default: + GFXERROR("pixelwidth=%d not supported!\n", pixelwidth); + return; + + } +} + + + + +void +gfx_draw_line_pixmap_i(gfx_pixmap_t *pxm, point_t start, point_t end, int color) +{ + gfx_draw_line_buffer(pxm->index_data, pxm->index_xl, 1, start, end, color); +} + + + + +void +gfx_draw_box_buffer(byte *buffer, int linewidth, rect_t zone, int color) +{ + byte *dest = buffer + zone.x + (linewidth * zone.y); + int i; + + if (zone.xl <= 0 || zone.yl <= 0) + return; + + for (i = 0; i < zone.yl; i++) { + memset(dest, color, zone.xl); + dest += linewidth; + } +} + + +void +gfx_draw_box_pixmap_i(gfx_pixmap_t *pxm, rect_t box, int color) +{ + gfx_clip_box_basic(&box, pxm->index_xl - 1, pxm->index_yl - 1); + + gfx_draw_box_buffer(pxm->index_data, pxm->index_xl, box, color); +} + + +/* Import various crossblit functions */ +#undef USE_PRIORITY +#undef FUNCTION_NAME +#undef BYTESPP + +# define FUNCTION_NAME _gfx_crossblit_8 +# define BYTESPP 1 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_16 +# define BYTESPP 2 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_24 +# define BYTESPP 3 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_32 +# define BYTESPP 4 +# include "gfx_crossblit.c" + +#define USE_PRIORITY + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_8_P +# define BYTESPP 1 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_16_P +# define BYTESPP 2 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_24_P +# define BYTESPP 3 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_32_P +# define BYTESPP 4 +# include "gfx_crossblit.c" + +#undef USE_PRIORITY +#undef FUNCTION_NAME +#undef BYTESPP + +/* Reverse alpha versions */ +#undef USE_PRIORITY +#undef FUNCTION_NAME +#undef BYTESPP +#undef REVERSE_ALPHA + +#define REVERSE_ALPHA +# define FUNCTION_NAME _gfx_crossblit_8_RA +# define BYTESPP 1 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_16_RA +# define BYTESPP 2 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_24_RA +# define BYTESPP 3 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_32_RA +# define BYTESPP 4 +# include "gfx_crossblit.c" + +#define USE_PRIORITY + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_8_P_RA +# define BYTESPP 1 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_16_P_RA +# define BYTESPP 2 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_24_P_RA +# define BYTESPP 3 +# include "gfx_crossblit.c" + +# undef FUNCTION_NAME +# undef BYTESPP +# define FUNCTION_NAME _gfx_crossblit_32_P_RA +# define BYTESPP 4 +# include "gfx_crossblit.c" + +#undef USE_PRIORITY +#undef FUNCTION_NAME +#undef BYTESPP +#undef REVERSE_ALPHA + +static void (*crossblit_fns[5])(byte *, byte *, int, int, int, int, byte *, int, int, unsigned int, unsigned int) = +{ NULL, + _gfx_crossblit_8, + _gfx_crossblit_16, + _gfx_crossblit_24, + _gfx_crossblit_32 }; + +static void (*crossblit_fns_P[5])(byte *, byte *, int, int, int, int, byte *, int, int, unsigned int, unsigned int, byte *, int, int, int) = +{ NULL, + _gfx_crossblit_8_P, + _gfx_crossblit_16_P, + _gfx_crossblit_24_P, + _gfx_crossblit_32_P }; + +static void (*crossblit_fns_RA[5])(byte *, byte *, int, int, int, int, byte *, int, int, unsigned int, unsigned int) = +{ NULL, + _gfx_crossblit_8_RA, + _gfx_crossblit_16_RA, + _gfx_crossblit_24_RA, + _gfx_crossblit_32_RA }; + +static void (*crossblit_fns_P_RA[5])(byte *, byte *, int, int, int, int, byte *, int, int, unsigned int, unsigned int, byte *, int, int, int) = +{ NULL, + _gfx_crossblit_8_P_RA, + _gfx_crossblit_16_P_RA, + _gfx_crossblit_24_P_RA, + _gfx_crossblit_32_P_RA }; + + +void +_gfx_crossblit_simple(byte *dest, byte *src, int dest_line_width, int src_line_width, + int xl, int yl, int bpp) +{ + int line_width = xl * bpp; + int i; + + for (i = 0; i < yl; i++) { + memcpy(dest, src, line_width); + dest += dest_line_width; + src += src_line_width; + } +} + +int +gfx_crossblit_pixmap(gfx_mode_t *mode, gfx_pixmap_t *pxm, int priority, + rect_t src_coords, + rect_t dest_coords, byte *dest, int dest_line_width, + byte *priority_dest, int priority_line_width, + int priority_skip, int flags) +{ + int maxx = 320 * mode->xfact; + int maxy = 200 * mode->yfact; + byte *src = pxm->data; + byte *alpha = pxm->alpha_map? pxm->alpha_map : pxm->data; + byte *priority_pos = priority_dest; + unsigned int alpha_mask, alpha_min; + int bpp = mode->bytespp; + int bytes_per_alpha_pixel = pxm->alpha_map? 1 : bpp; + int bytes_per_alpha_line = bytes_per_alpha_pixel * pxm->xl; + int xl = pxm->xl, yl = pxm->yl; + int xoffset = (dest_coords.x < 0)? - dest_coords.x : 0; + int yoffset = (dest_coords.y < 0)? - dest_coords.y : 0; + int revalpha = mode->flags & GFX_MODE_FLAG_REVERSE_ALPHA; + + if (src_coords.x + src_coords.xl > xl) + src_coords.xl = xl - src_coords.x; + + if (src_coords.y + src_coords.yl > yl) + src_coords.yl = yl - src_coords.y; + +/** --???-- **/ + if (src_coords.y > yl) + return GFX_OK; + if (src_coords.x > xl) + return GFX_OK; +/** --???-- **/ + + if (dest_coords.x + xl >= maxx) + xl = maxx - dest_coords.x; + if (dest_coords.y + yl >= maxy) + yl = maxy - dest_coords.y; + + xl -= xoffset; + yl -= yoffset; + + if (!pxm->data) + return GFX_ERROR; + + if (xl <= 0 || yl <= 0) + return GFX_OK; + + /* Set destination offsets */ + + /* Set x offsets */ + if (!(flags & GFX_CROSSBLIT_FLAG_DATA_IS_HOMED)) + dest += dest_coords.x * bpp; + priority_pos += dest_coords.x * priority_skip; + + /* Set y offsets */ + if (!(flags & GFX_CROSSBLIT_FLAG_DATA_IS_HOMED)) + dest += dest_coords.y * dest_line_width; + priority_pos += dest_coords.y * priority_line_width; + + /* Set source offsets */ + if (xoffset += src_coords.x) { + dest_coords.x = 0; + src += xoffset * bpp; + alpha += xoffset * bytes_per_alpha_pixel; + } + + + if (yoffset += src_coords.y) { + dest_coords.y = 0; + src += yoffset * bpp * pxm->xl; + alpha += yoffset * bytes_per_alpha_line; + } + + /* Adjust length for clip box */ + if (xl > src_coords.xl) + xl = src_coords.xl; + if (yl > src_coords.yl) + yl = src_coords.yl; + + /* now calculate alpha */ + if (pxm->alpha_map) + alpha_mask = 0xff; + else { + int shift_nr = 0; + + alpha_mask = mode->alpha_mask; + if (!alpha_mask && pxm->alpha_map) { + GFXERROR("Invalid alpha mode: both pxm->alpha_map and alpha_mask are white!\n"); + return GFX_ERROR; + } + + if (alpha_mask) { + while (!(alpha_mask & 0xff)) { + alpha_mask >>= 8; + shift_nr++; + } + alpha_mask &= 0xff; + } + +#ifdef WORDS_BIGENDIAN + alpha += (mode->bytespp) - (shift_nr + 1); +#else + alpha += shift_nr; +#endif + } + +#ifdef HAVE_ALPHA_EV6_SUPPORT + if (mode->alpha_mask && axp_have_mvi && bpp == 4) { + if (priority == GFX_NO_PRIORITY) + alpha_mvi_crossblit_32(dest, src, dest_line_width, pxm->xl * bpp, + xl, yl, NULL, 0, 0, mode->alpha_mask, 24 - mode->alpha_shift); + else + alpha_mvi_crossblit_32_P(dest, src, dest_line_width, pxm->xl * bpp, + xl, yl, NULL, 0, 0, mode->alpha_mask, 24 - mode->alpha_shift, + priority_pos, priority_line_width, priority_skip, priority); + } else { +#endif + + if (alpha_mask & 0xff) + alpha_min = ((alpha_mask * gfx_crossblit_alpha_threshold) >> 8) & alpha_mask; + else + alpha_min = ((alpha_mask >> 8) * gfx_crossblit_alpha_threshold) & alpha_mask; + + if (revalpha) + alpha_min = 255 - alpha_min; /* Since we use it for the reverse effect */ + + if (!alpha_mask) + _gfx_crossblit_simple(dest, src, dest_line_width, pxm->xl * bpp, + xl, yl, bpp); + else + + if (priority == GFX_NO_PRIORITY) { + if (bpp > 0 && bpp < 5) + ((revalpha) ? crossblit_fns_RA : crossblit_fns)[bpp](dest, src, dest_line_width, pxm->xl * bpp, + xl, yl, alpha, bytes_per_alpha_line, bytes_per_alpha_pixel, + alpha_mask, alpha_min); + else { + GFXERROR("Invalid mode->bytespp: %d\n", mode->bytespp); + return GFX_ERROR; + } + } else { /* priority */ + if (bpp > 0 && bpp < 5) + ((revalpha) ? crossblit_fns_P_RA : crossblit_fns_P)[bpp](dest, src, dest_line_width, pxm->xl * bpp, + xl, yl, alpha, bytes_per_alpha_line, bytes_per_alpha_pixel, + alpha_mask, alpha_min, priority_pos, + priority_line_width, priority_skip, priority); + else { + GFXERROR("Invalid mode->bytespp: %d\n", mode->bytespp); + return GFX_ERROR; + } + } +#ifdef HAVE_ALPHA_EV6_SUPPORT + } +#endif + + return GFX_OK; +} + + + + diff --git a/engines/sci/gfx/gfx_test.c b/engines/sci/gfx/gfx_test.c new file mode 100644 index 0000000000..2b5b8f36ec --- /dev/null +++ b/engines/sci/gfx/gfx_test.c @@ -0,0 +1,1504 @@ +/*************************************************************************** + gfx_test.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* gfx driver test and verification program */ + +#define DISABLE_SCI_MEMORY + +#ifdef _MSC_VER +# include <unistd.h> +# include <sys/time.h> +# include <windows.h> +#endif + +#include <assert.h> +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <string.h> +#include <gfx_resource.h> +#include <gfx_tools.h> +#include <gfx_operations.h> + +int +sci0_palette; + +gfx_pixmap_color_t gfx_sci0_image_colors[1][16]; + +gfx_pixmap_color_t * +gfxr_interpreter_get_static_palette(gfx_resstate_t *state, int version, int *colors_nr, void *internal) +{ + return NULL; +} + +int +sciprintf(const char *fmt, ...) +{ + va_list argp; + va_start(argp, fmt); + vprintf(fmt, argp); + va_end(argp); + return 0; +} + + +void * +memdup(void *mem, size_t size) +{ + void *r = malloc(size); + if (r) + memcpy(r, mem, size); + return r; +} + +#ifdef FREESCI_PRIMARY_RESOURCE_H_ +# include "../scicore/sci_memory.c" +#endif + +void +sci_gettime(long *seconds, long *useconds) +{ + struct timeval tv; + +#ifdef _WIN32 + timeBeginPeriod(0); +#endif + + assert(!gettimeofday(&tv, NULL)); + *seconds = time(NULL); + *useconds = tv.tv_usec; + +#ifdef _WIN32 + timeEndPeriod(0); +#endif +} + +static int xres = 1; +static int yres = 1; +static int color_mode = 1; +static char *driver = NULL; +static int set_mode = 0; +static int nowait = 0; +static int skip_intro = 0; + +#define ALL_TESTS "abcdefghijkl" +static char tests[256]; + +gfx_state_t graphics_state; +gfx_state_t *state = &graphics_state; + +gfx_options_t graphics_options; +gfx_options_t *options = &graphics_options; + + +#define CAPABILITY_IDS_NR 11 + +static struct { + int mask; + char *description; +} capability_ids[CAPABILITY_IDS_NR] = { + {GFX_CAPABILITY_SHADING, "shaded boxes"}, + {GFX_CAPABILITY_MOUSE_POINTER, "mouse pointers"}, + {GFX_CAPABILITY_COLOR_MOUSE_POINTER, "multi-color mouse pointers"}, + {GFX_CAPABILITY_PIXMAP_REGISTRY, "pixmaps must be registered"}, + {GFX_CAPABILITY_SCALEABLE_PIXMAPS, "pixmap scaling"}, + {GFX_CAPABILITY_STIPPLED_LINES, "stippled lines"}, + {GFX_CAPABILITY_MOUSE_SUPPORT, "pointing device input"}, + {GFX_CAPABILITY_POINTER_PIXMAP_REGISTRY, "pointer pixmaps must be registered"}, + {GFX_CAPABILITY_FINE_LINES, "fine lines"}, + {GFX_CAPABILITY_WINDOWED, "windowed mode active"}, + {GFX_CAPABILITY_KEYTRANSLATE, "built-in keyboard translation"} +}; + +int +init_driver(gfx_driver_t *drv) +{ + int i; + + state->driver = drv; + options->dirty_frames = GFXOP_DIRTY_FRAMES_CLUSTERS; + + if (set_mode) { + if (gfxop_init(state, xres, yres, color_mode, options, NULL)) { + printf("Custom initialization failed\n"); + return 1; + } + } else { + if (gfxop_init_default(state, options, NULL)) { + printf("Default initialization failed\n"); + return 1; + } + } + + printf("Using graphics driver %s, version %s\n", drv->name, drv->version); + printf("Graphics driver capabilities:\n"); + for (i = 0; i < CAPABILITY_IDS_NR; i++) + if (drv->capabilities & capability_ids[i].mask) + printf("\t%s\n", capability_ids[i].description); + + printf("\n"); + return 0; +} + + +/* ---------------------------------- */ +/* Functions for the resource manager */ +/* ---------------------------------- */ + +int multicolored_pointers = 1; /* Whether to test multicolored pointer support */ + +#define TEST_PICS_NR 2 +#define TEST_VIEWS_NR 1 +#define TEST_FONTS_NR 1 +#define TEST_CURSORS_NR 2 + +int test_pics[TEST_PICS_NR] = {0, 1}; +int test_views[TEST_VIEWS_NR] = {0}; +int test_fonts[TEST_FONTS_NR] = {0}; +int test_cursors[TEST_CURSORS_NR] = {0, 1}; + +int +gfxr_interpreter_options_hash(gfx_resource_type_t type, int version, gfx_options_t *options, void *internal, int palette) +{ + return 0; +} + + +int * +arrdup(int *src, int count) +{ + int *retval = sci_malloc(sizeof(int) * count); + memcpy(retval, src, sizeof(int) * count); + return retval; +} + +int * +gfxr_interpreter_get_resources(gfx_resstate_t *resstate, gfx_resource_type_t type, + int version, int *entries_nr, void *internal) +{ + switch (type) { + + case GFX_RESOURCE_TYPE_VIEW: + *entries_nr = TEST_VIEWS_NR; + return arrdup(test_views, TEST_VIEWS_NR); + + case GFX_RESOURCE_TYPE_PIC: + *entries_nr = TEST_PICS_NR; + return arrdup(test_pics, TEST_PICS_NR); + + case GFX_RESOURCE_TYPE_FONT: + *entries_nr = TEST_FONTS_NR; + return arrdup(test_fonts, TEST_FONTS_NR); + + case GFX_RESOURCE_TYPE_CURSOR: + *entries_nr = TEST_CURSORS_NR; + return arrdup(test_cursors, TEST_CURSORS_NR); + + default: + fprintf(stderr,"Attept to get resource list for invalid resource type %d\n", type); + return NULL; + } +} + +#define PIC_COLORS_NR 32 + +gfx_pixmap_color_t pic_colors[PIC_COLORS_NR] = { + {GFX_COLOR_INDEX_UNMAPPED, 0x0f, 0x0f, 0x0f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x1f, 0x1f, 0x1f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x2f, 0x2f, 0x2f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x3f, 0x3f, 0x3f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x4f, 0x4f, 0x4f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x5f, 0x5f, 0x5f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x6f, 0x6f, 0x6f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x7f, 0x7f, 0x7f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x8f, 0x8f, 0x8f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x9f, 0x9f, 0x9f}, + {GFX_COLOR_INDEX_UNMAPPED, 0xaf, 0xaf, 0xaf}, + {GFX_COLOR_INDEX_UNMAPPED, 0xbf, 0xbf, 0xbf}, + {GFX_COLOR_INDEX_UNMAPPED, 0xcf, 0xcf, 0xcf}, + {GFX_COLOR_INDEX_UNMAPPED, 0xdf, 0xdf, 0xdf}, + {GFX_COLOR_INDEX_UNMAPPED, 0xef, 0xef, 0xef}, + {GFX_COLOR_INDEX_UNMAPPED, 0xff, 0xff, 0xff}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x0f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x1f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x2f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x3f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x4f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x5f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x6f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x7f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x8f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x9f}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xaf}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xbf}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xcf}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xdf}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xef}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0xff} +}; + +gfxr_pic_t * +gfxr_interpreter_init_pic(int version, gfx_mode_t *mode, int ID, void *internal) +{ + gfxr_pic_t *pic = sci_malloc(sizeof(gfxr_pic_t)); + + pic->mode = mode; + pic->undithered_buffer = NULL; + pic->internal = NULL; + + 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(320 * mode->xfact, + 200 * mode->yfact, ID, 1, 0)); + pic->visual_map = gfx_pixmap_alloc_index_data(gfx_new_pixmap(320, 200, ID, 0, 0)); + + pic->visual_map->colors = pic_colors; + pic->visual_map->colors_nr = PIC_COLORS_NR; + + 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; + + pic->priority_map->colors = pic_colors; + pic->priority_map->colors_nr = PIC_COLORS_NR; + pic->control_map->colors = pic_colors; + pic->control_map->colors_nr = PIC_COLORS_NR; + + return pic; +} + + + +void +gfxr_interpreter_clear_pic(int version, gfxr_pic_t *pic, void *internal) +{ + memset(pic->visual_map->index_data, 0x00, 320 * 200); + memset(pic->priority_map->index_data, 0, 320 * pic->mode->xfact * 200 * pic->mode->yfact); + memset(pic->control_map->index_data, 0, GFXR_AUX_MAP_SIZE); + memset(pic->aux_map, 0, GFXR_AUX_MAP_SIZE); +} + + +int +gfxr_interpreter_calculate_pic(gfx_resstate_t *state, gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, + int flags, int default_palette, int nr, void *internal) +{ + gfxr_pic_t *pic = scaled_pic; + int i, x, y, pos; + int xfact = pic->mode->xfact; + int yfact = pic->mode->yfact; + + if (nr < 0 || nr > TEST_PICS_NR) + return GFX_ERROR; + + switch (nr) { + case 0: + pos = 0; + for (y = 0; y < 200; y++) { + for (x = 0; x < 32; x++) { + memset(pic->visual_map->index_data + pos, x, 5); + memset(pic->visual_map->index_data + 315 + pos - x*10, x, 5); + pos += 5; + } + pos += 160; + } + + for (y = 0; y < 200*yfact; y++) { + memset(pic->priority_map->index_data + y * 320*xfact + (100*xfact), 10, 120*xfact); + memset(pic->priority_map->index_data + y * 320*xfact + (150*xfact), 20, 20*xfact); + } + break; + + case 1: + memset(pic->visual_map->index_data + 80*320, 15, 120*320); + memset(pic->priority_map->index_data + 80*xfact * 320*yfact, 20, + 120*320*xfact*yfact); + + for (i = 40; i < 80; i++) { + int j; + + memset(pic->visual_map->index_data + i*320 + 140, 15, 80); + for (j = 0; j < pic->mode->yfact; j++) + memset(pic->priority_map->index_data + (i*yfact+j)*320*xfact + + 140*xfact , 20, 80*xfact); + } + break; + + default: + fprintf(stderr,"Attempt to reference invalid pic #%d\n", nr); + } + + printf(">> resource manager retreived pic #%d\n", nr); + return GFX_OK; +} + + +#define VIEW_COLORS_NR 16 + +gfx_pixmap_color_t view_colors[VIEW_COLORS_NR] = { + {GFX_COLOR_INDEX_UNMAPPED, 0x0f, 0x00, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x2f, 0x20, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x4f, 0x40, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x6f, 0x60, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x8f, 0x80, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0xaf, 0xa0, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0xcf, 0xc0, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0xef, 0xe0, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x1f, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x3f, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x5f, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x7f, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x9f, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0xbf, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0xdf, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0xff, 0x00} +}; + +gfxr_view_t * +gfxr_interpreter_get_view(gfx_resstate_t *state, int nr, void *internal, int palette) +{ + gfxr_view_t *view; + gfxr_loop_t *loop; + int i; + + if (nr < 0 || nr > TEST_VIEWS_NR) + return NULL; + + view = sci_malloc(sizeof(gfxr_view_t)); + view->ID = nr | 2048; + view->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + + view->colors_nr = VIEW_COLORS_NR; + view->colors = view_colors; + + view->loops_nr = 1; + view->loops = loop = sci_malloc(sizeof(gfxr_loop_t)); + + loop->cels_nr = 3; + loop->cels = sci_malloc(sizeof(gfx_pixmap_t *) * loop->cels_nr); + + for (i = 0; i < 3; i++) { + gfx_pixmap_t *pxm = gfx_pixmap_alloc_index_data(gfx_new_pixmap(16, 16, 2048 | nr, 0, i)); + int offset = (i == 1)? 8 : 0; + int x, y; + + pxm->colors_nr = VIEW_COLORS_NR; + pxm->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + pxm->colors = view_colors; + pxm->xoffset = 8; + pxm->yoffset = 8; + + for (y = 0; y < 16; y++) + for (x = 0; x < 16; x++) { + int dx = (8-x); + int dy = (8-y); + int dist = dx*dx + dy*dy; + int index = (dist * 8) / 64; + int pos = x + y*16; + + if (i == 2) { + offset = (!dx || !dy)? 8 : 0; + if (offset == 8) index <<= 1; + } + + index = 7-index; + if (index < 0) + pxm->index_data[pos] = 0xff; + else + pxm->index_data[pos] = index + offset; + } + + loop->cels[i] = pxm; + } + + printf(">> resource manager retreived view #%d\n", nr); + + return view; +} + +#define BUILTIN_CHARS_NR 256 +#define BUILTIN_CHARS_HEIGHT 8 +#define BUILTIN_CHARS_WIDTH 8 + +extern byte builtin_font[]; + +gfx_bitmap_font_t * +gfxr_interpreter_get_font(gfx_resstate_t *state, int nr, void *internal) +{ + gfx_bitmap_font_t *font; + int i; + if (nr < 0 || nr > TEST_FONTS_NR) + return NULL; + + font = sci_malloc(sizeof(gfx_bitmap_font_t)); + font->ID = nr; + font->chars_nr = BUILTIN_CHARS_NR; + font->widths = sci_malloc(sizeof(int) * BUILTIN_CHARS_NR); + for (i = 0; i < BUILTIN_CHARS_NR; i++) + font->widths[i] = BUILTIN_CHARS_WIDTH; + font->row_size = (BUILTIN_CHARS_WIDTH + 7) >> 3; + font->height = font->line_height = BUILTIN_CHARS_HEIGHT; + font->char_size = ((BUILTIN_CHARS_WIDTH + 7) >> 3) * BUILTIN_CHARS_HEIGHT; + font->data = memdup(builtin_font, font->char_size * BUILTIN_CHARS_NR); + + printf(">> resource manager retreived font #%d\n", nr); + + return font; +} + +gfx_pixmap_color_t _cursor_colors[3] = { + {GFX_COLOR_INDEX_UNMAPPED, 0, 0, 0}, + {GFX_COLOR_INDEX_UNMAPPED, 0xff, 0xff, 0xff}, + {GFX_COLOR_INDEX_UNMAPPED, 0x80, 0x80, 0x80} +}; + +gfx_pixmap_t * +gfxr_interpreter_get_cursor(gfx_resstate_t *state, int nr, void *internal) +{ + gfx_pixmap_t *cursor; + int xl, yl, x, y; + + if (nr < 0 || nr > TEST_CURSORS_NR) + return NULL; + + if (!nr) + xl = yl = 31; + else { + xl = 8; + yl = 16; + } + + + cursor = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, 1024 + nr, 0, 0)); + cursor->colors = _cursor_colors; + cursor->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + + memset(cursor->index_data, 0xff, xl * yl); + + switch (nr) { + case 0: + cursor->colors_nr = multicolored_pointers? 3 : 2; + cursor->xoffset = 16; + cursor->yoffset = 16; + + for (x = 0; x < 31; x++) if (x != 16) { + cursor->index_data[31*x + 16] = 1; + cursor->index_data[31*16 + x] = 1; + + if (multicolored_pointers && ((x < 8) || (x > 23))) { + cursor->index_data[31*x + 14] = 0; + cursor->index_data[31*x + 15] = 2; + cursor->index_data[31*x + 17] = 2; + cursor->index_data[31*x + 18] = 0; + + cursor->index_data[31*14 + x] = 0; + cursor->index_data[31*15 + x] = 2; + cursor->index_data[31*17 + x] = 2; + cursor->index_data[31*18 + x] = 0; + } else { + cursor->index_data[31*x + 15] = 0; + cursor->index_data[31*x + 17] = 0; + + cursor->index_data[31*15 + x] = 0; + cursor->index_data[31*17 + x] = 0; + } + } + break; + + case 1: + cursor->colors_nr = 2; + cursor->xoffset = 0; + cursor->yoffset = 0; + for (y = 0; y < yl; y++) + for (x = 0; x <= (y >> 1); x++) + cursor->index_data[x + y*xl] = 1; + break; + + default: + fprintf(stderr,"Attempt to load invalid pointer %d\n", nr); + gfx_free_pixmap(state->driver, cursor); + return NULL; + } + + printf(">> resource manager retreived cursor #%d\n", nr); + + return cursor; +} + +gfx_pixmap_color_t * +gfxr_interpreter_get_palette(gfx_resstate_t *state, int version, int *colors_nr, void *internal, int nr) +{ + return NULL; +} + +int +gfxr_interpreter_needs_multicolored_pointers(int version, void *internal) +{ + return multicolored_pointers; +} + +gfx_color_t red, green, blue, dblue, white, white8, white16, white24, black, transparent; + +void +init_colors() +{ + gfxop_set_color(state, &red, 0xff, 0x00, 0x00, 0x00, -1, -1); + gfxop_set_color(state, &green, 0x00, 0xff, 0x00, 0x00, -1, -1); + gfxop_set_color(state, &blue, 0x00, 0x00, 0xff, 0x00, -1, -1); + gfxop_set_color(state, &dblue, 0x00, 0x00, 0x40, 0x00, -1, -1); + gfxop_set_color(state, &white, 0xff, 0xff, 0xff, 0x00, -1, -1); + gfxop_set_color(state, &white8, 0xff, 0xff, 0xff, 0x00, 8, -1); + gfxop_set_color(state, &white16, 0xff, 0xff, 0xff, 0x00, 16, -1); + gfxop_set_color(state, &white24, 0xff, 0xff, 0xff, 0x00, 24, -1); + gfxop_set_color(state, &black, 0x00, 0x00, 0x00, 0x00, -1, -1); + gfxop_set_color(state, &transparent, -1 , -1 , -1 , 0x00, -1, -1); +} + + +#define MESSAGE(foo) if (message(foo)) { fprintf(stderr,"Message '%s' could not be print!\n", foo); return;} +#define MESSAGE1(foo,a) { char buf[1024]; sprintf(buf,foo,a); if (message(buf)) { fprintf(stderr,"Message '%s' could not be print!\n", buf); return;}} +#define MESSAGE2(foo,a,b) { char buf[1024]; sprintf(buf,foo,a,b); if (message(buf)) { fprintf(stderr,"Message '%s' could not be print!\n", buf); return;}} +#define MESSAGE3(foo,a,b,c) { char buf[1024]; sprintf(buf,foo,a,b,c); if (message(buf)) { fprintf(stderr,"Message '%s' could not be print!\n", buf); return;}} +#define MESSAGE4(foo,a,b,c,d) { char buf[1024]; sprintf(buf,foo,a,b,c,d); if (message(buf)) { fprintf(stderr,"Message '%s' could not be print!\n", buf); return;}} + + +int +waitkey(void) +{ + int count = 100000; + sci_event_t event; + + while (count--) { + event = gfxop_get_event(state, SCI_EVT_ANY); + + if (event.type) + return 0; + + gfxop_usleep(state, 1000); + } + return 1; +} + +int +wait_specific_key(int key) +{ + int count = 20000; + sci_event_t event; + + while (count--) { + event = gfxop_get_event(state, SCI_EVT_ANY); + + if (event.type == SCI_EVT_KEYBOARD + && event.data == key) + return 0; + + gfxop_usleep(state, 1000); + } + return 1; +} + + +int +message(char *msg) +{ + gfx_text_handle_t *handle; + rect_t text_rect = gfx_rect(0, 150, 320, 50); + + + handle = gfxop_new_text(state, 0, msg, 320, ALIGN_CENTER, ALIGN_TOP, + white, white, black, 0); + + if (!handle) return 1; + + printf("-----------------------------------------\n%s\n-----------------------------------------\n", msg); + + gfxop_fill_box(state, text_rect, black); + gfxop_draw_text(state, handle, text_rect); + gfxop_free_text(state, handle); + gfxop_update(state); + return 0; +} + +void +update(void) +{ + /* gfxop_update_box(state, gfx_rect(0, 0, 320, 150)); */ + gfxop_update(state); +} + +void +explicit_clear_buffer(void) +{ + gfxop_clear_box(state, gfx_rect(0, 0, 320, 150)); + gfxop_update(state); +} + +void +clear_buffer(void) +{ + gfxop_disable_dirty_frames(state); + gfxop_clear_box(state, gfx_rect(0, 0, 320, 150)); + gfxop_enable_dirty_frames(state); +} + +void +clear(void) +{ + gfxop_fill_box(state, gfx_rect(0, 0, 320, 150), black); +} + +void +identify_event(sci_event_t event) +{ + switch(event.type) { + + case SCI_EVT_NONE: + MESSAGE("No event"); + break; + + case SCI_EVT_MOUSE_PRESS: + MESSAGE4("Mouse press at (%d,%d)\ndata/modifiers (%d/%d)", + state->pointer_pos.x, state->pointer_pos.y, event.data, event.buckybits); + break; + + case SCI_EVT_MOUSE_RELEASE: + MESSAGE4("Mouse release at (%d,%d)\ndata/modifiers (%d/%d)", + state->pointer_pos.x, state->pointer_pos.y, event.data, event.buckybits); + break; + + case SCI_EVT_KEYBOARD: + if (event.data > 127) { + MESSAGE2("Key 0x%04x\nmodifiers %04x", event.data, event.buckybits); + } else + MESSAGE3("Key '%c' (0x%02x)\nmodifiers %04x", event.data, event.data, event.buckybits); + break; + + case SCI_EVT_JOYSTICK: + MESSAGE1("Joystick direction %d", event.data); + break; + + case SCI_EVT_ERROR: + MESSAGE("Error event"); + break; + + default: MESSAGE1("Unknown event type %d!\n", event.type); + } +} + + +int +test_a(void) +{ + if (message("-- Test A --\nText display and basic input\nPlease press 'space' within 20 seconds")) + return 1; + + return (wait_specific_key(' ')); +} + + +#define TEST_LINE(x, y, xl, yl) \ + gfxop_draw_line(state, gfx_point(x, y), gfx_point((x)+(xl), (y)+(yl)), blue, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); \ + gfxop_set_clip_zone(state, gfx_rect(140, 60, 40, 40)); \ + gfxop_draw_line(state, gfx_point(x, y), gfx_point((x)+(xl), (y)+(yl)), red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); \ + gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); + +#define LINES_NR 19 + +int test_b_lines[LINES_NR][4] = { + {10, 10, 300, 0}, + {160, 30, 0, 100}, + {162, 20, 0, 50}, + {162, 90, 0, 50}, + {110, 80, 100, 0}, + {100, 82, 50, 0}, + {170, 82, 50, 0}, + {135, 70, 20, -20}, + {135, 90, 20, 20}, + {185, 70, -20, -20}, + {185, 90, -20, 20}, + {150, 70, -20, -10}, + {150, 70, -10, -20}, + {170, 70, 20, -10}, + {170, 70, 10, -20}, + {150, 90, -20, 10}, + {150, 90, -10, 20}, + {170, 90, 10, 20}, + {170, 90, 20, 10} +}; + +void +test_b(void) +{ + int i; + + MESSAGE("-- Test B --\nLines"); + waitkey(); + MESSAGE("Some tests will include 'fine' lines.\nNote that support for those is\noptional."); + waitkey(); + + gfxop_draw_line(state, gfx_point(30, 30), gfx_point(290, 30), red, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_NORMAL); + gfxop_draw_line(state, gfx_point(30, 40), gfx_point(290, 40), blue, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_draw_line(state, gfx_point(30, 50), gfx_point(290, 50), green, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_STIPPLED); + gfxop_draw_line(state, gfx_point(30, 60), gfx_point(290, 60), white, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_STIPPLED); + update(); + MESSAGE("B.0: horizontal lines:\nYou should now be seeing (top-down):\nred-fine, blue-normal,\ngreen-fine-stippled, white-stippled"); + waitkey(); + + clear(); + gfxop_draw_line(state, gfx_point(30, 30), gfx_point(290, 130), blue, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_draw_line(state, gfx_point(30, 130), gfx_point(290, 30), blue, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_set_clip_zone(state, gfx_rect(140, 60, 40, 40)); + gfxop_draw_line(state, gfx_point(30, 30), gfx_point(290, 130), red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_draw_line(state, gfx_point(30, 130), gfx_point(290, 30), red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); + update(); + MESSAGE("B.1: line clipping:\nTwo identical pairs of lines.\nblue lines are unclipped,\nred ones are clipped."); + waitkey(); + + clear(); + for (i = 0; i < LINES_NR; i++) { + TEST_LINE(test_b_lines[i][0], test_b_lines[i][1], test_b_lines[i][2], test_b_lines[i][3]); + } + update(); + MESSAGE1("B.2: line clipping:\n%d lines.", LINES_NR); + waitkey(); + + clear(); + gfxop_draw_rectangle(state, gfx_rect(30, 30, 260, 100), red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_draw_rectangle(state, gfx_rect(40, 40, 240, 80), red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_STIPPLED); + update(); + MESSAGE("B.3: Rectangles:\nNormal rectangle (outside)\nStippled rectangle (inside)"); + waitkey(); + + gfxop_draw_rectangle(state, gfx_rect(30, 30, 260, 100), green, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_NORMAL); + gfxop_draw_rectangle(state, gfx_rect(40, 40, 240, 80), green, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_STIPPLED); + update(); + MESSAGE("B.4: Fine rectangles (optional):\nTwo green rectangles should now have\noverwritten the _inner_ bounds\nof the red ones"); + waitkey(); +} + + +void +test_c(void) +{ + int i; + clear(); + update(); + MESSAGE("-- Test C: Boxes and updates --"); + waitkey(); + + gfxop_fill_box(state, gfx_rect(50, 50, 210, 80), red); + update(); + MESSAGE("C.0: Simple box"); + waitkey(); + + gfxop_disable_dirty_frames(state); + clear(); + gfxop_fill_box(state, gfx_rect(30, 30, 260, 100), white); + gfxop_fill_box(state, gfx_rect(50, 50, 210, 80), blue); + gfxop_enable_dirty_frames(state); + + MESSAGE("C.1: Partial propagation\nA white box containing a blue box\nhas been written to the back buffer.\nPress a key to propagate it."); + + for (i = 0; i <= 40; i++) { + gfxop_update_box(state, gfx_rect(i*4, 0 , 4, 150)); + gfxop_update_box(state, gfx_rect(317-i*4, 0 , 4, 150)); + gfxop_usleep(state, 4000); + } + + gfxop_disable_dirty_frames(state); + clear(); + gfxop_fill_box(state, gfx_rect(30, 30, 260, 100), red); + gfxop_enable_dirty_frames(state); + + MESSAGE("C.2: Single line propagation\nPress a key to propagate a red box.\nNote that dirty frame\naccounting must be dis-\n" + "abled for manual updates\nto work like this."); + waitkey(); + for (i = 159; i >= 0; i--) { + gfxop_update_box(state, gfx_rect(i, 0 , 1, 150)); + gfxop_update_box(state, gfx_rect(319-i, 0 , 1, 150)); + gfxop_usleep(state, 1000); + } + + clear(); + gfxop_draw_box(state, gfx_rect(150, 70, 20, 20), red, green, GFX_BOX_SHADE_FLAT); + gfxop_draw_box(state, gfx_rect(120, 70, 20, 20), red, green, GFX_BOX_SHADE_LEFT); + gfxop_draw_box(state, gfx_rect(180, 70, 20, 20), red, green, GFX_BOX_SHADE_RIGHT); + gfxop_draw_box(state, gfx_rect(150, 40, 20, 20), red, green, GFX_BOX_SHADE_UP); + gfxop_draw_box(state, gfx_rect(150, 100, 20, 20), red, green, GFX_BOX_SHADE_DOWN); + update(); + MESSAGE("C.3: Gradient boxes\nIf your driver supports gradient\nboxes, you should now see\nthe four outer boxes being\nred on the inside,--more--"); + waitkey(); + MESSAGE("C.3: Gradient boxes\n(cont.)and green on the\n outside.\n\nIf unsupported, all should be red."); + waitkey(); +} + + +void +test_d(void) +{ + rect_t line; + int pressed = 0; + sci_event_t event; + + event.type = 0; + + MESSAGE("-- Test D: Pointers and input --"); + clear(); + gfxop_fill_box(state, gfx_rect(30, 30, 260, 100), white); + gfxop_fill_box(state, gfx_rect(50, 50, 210, 80), blue); + waitkey(); + update(); + + gfxop_set_pointer_cursor(state, 1); + MESSAGE("D.0: Simple mouse pointer\nThis pointer's hot spot is at the\ntop left"); + waitkey(); + + gfxop_set_pointer_cursor(state, 0); + MESSAGE("D.1: Crosshair pointer\nHot spot is in the center.\nThis is a 'multicolor' pointer."); + waitkey(); + + MESSAGE("D.2: Mouse clicks\nPress and release buttons to\ndraw lines\nPress any key to continue"); + + while (event.type != SCI_EVT_KEYBOARD) { + event = gfxop_get_event(state, SCI_EVT_ANY); + + if (event.type == SCI_EVT_MOUSE_PRESS) { + + pressed = 1; + line.x = state->pointer_pos.x; + line.y = state->pointer_pos.y; + + } else if (event.type == SCI_EVT_MOUSE_RELEASE) + + if (pressed) { + point_t line_pt = gfx_point(line.x, line.y); + pressed = 0; + line.xl = state->pointer_pos.x - line.x; + line.yl = state->pointer_pos.y - line.y; + gfxop_draw_line(state, state->pointer_pos, line_pt, red, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + + if (line.xl < 0) { + line.x += line.xl; + line.xl = - line.xl; + } + + if (line.yl < 0) { + line.y += line.yl; + line.yl = - line.yl; + } + + gfxop_update_box(state, line); + } + + gfxop_usleep(state, 1000); + } + + event.type = 0; + + MESSAGE("D.3 Event test\nPress the space bar when finished"); + waitkey(); + + while (event.type != SCI_EVT_KEYBOARD || event.data != ' ') { + event = gfxop_get_event(state, SCI_EVT_ANY); + + if (event.type) + identify_event(event); + } +} + + +void +test_e(void) +{ + int x; + + gfxop_set_pointer_cursor(state, 1); + + MESSAGE("-- Test E: Pics and Views --"); + waitkey(); + + gfxop_new_pic(state, 0, 0, 0); + + explicit_clear_buffer(); + update(); + MESSAGE("E.0: Static buffer\nYou should now see a gray and\nblue background image now.\nIt is stored in the static\nbuffer, and --more--"); + waitkey(); + MESSAGE("E.0: Static buffer\n(cont.)then propagated to\nthe back buffer and then to\nthe front buffer."); + waitkey(); + + MESSAGE("E.1: Views and animation\nPress a key to see a cel move\nacross the screen\n(doing _full_ updates)"); + waitkey(); + + for (x = -20; x < 340; x++) { + clear_buffer(); + gfxop_draw_cel(state, 0, 0, 0, gfx_point(x, 40), white, 0); + update(); + gfxop_usleep(state, 10000); + } + + MESSAGE("E.2: Pic views\nFour pic views will now be added to\nthe static buffer"); + waitkey(); + + gfxop_draw_cel_static(state, 0, 0, 1, gfx_point(50, 100), white24, 0); + gfxop_draw_cel_static(state, 0, 0, 1, gfx_point(50, 20), white24, 0); + gfxop_draw_cel_static(state, 0, 0, 1, gfx_point(220, 20), white16, 0); + gfxop_draw_cel_static(state, 0, 0, 1, gfx_point(220, 100), white16, 0); + + update(); + MESSAGE("E.2: Pic views\nThe pic views should NOT\nbe visible yet!\n"); + waitkey(); + + explicit_clear_buffer(); + update(); + MESSAGE("E.2: Pic views\nNow they should be.\n"); + waitkey(); + + MESSAGE("E.3: Priority buffer\nPress a key to see two cels move\nacross the screen and re-\nspecting the Z buffer"); + waitkey(); + + for (x = -20; x < 340; x++) { + clear_buffer(); + gfxop_draw_cel(state, 0, 0, 2, gfx_point(x, 20), white8, 0); + gfxop_draw_cel(state, 0, 0, 2, gfx_point(x, 100), white16, 0); + update(); + gfxop_usleep(state, 10000); + } + + gfxop_add_to_pic(state, 1, 0, 0); + explicit_clear_buffer(); + update(); + MESSAGE("E.4: Adding to a pic\nSome new stuff should\nhave been added to the\nbackground pic now"); + waitkey(); + MESSAGE("E.5: Animation with partial updates\nIf you're running high-res,\nthis should be considerably\nfaster."); + waitkey(); + for (x = -20; x < 340; x++) { + gfxop_clear_box(state, gfx_rect(x-9, 40-8, 17, 16)); + gfxop_clear_box(state, gfx_rect(x-9, 70-8, 17, 16)); + gfxop_draw_cel(state, 0, 0, 2, gfx_point(x, 40), white16, 0); + gfxop_draw_cel(state, 0, 0, 2, gfx_point(x, 70), white16, 0); + gfxop_update(state); + /* gfxop_update_box(state, gfx_rect(x-1, 40, 17, 16)); */ + /* gfxop_update_box(state, gfx_rect(x-1, 70, 17, 16)); */ + gfxop_usleep(state, 10000); + } + waitkey(); +} + +void +test_wrap(int width, char *text) +{ + rect_t rect = gfx_rect(0, 0, width, 120); + gfx_text_handle_t *handle = gfxop_new_text(state, 0, + text, + width, ALIGN_LEFT, ALIGN_TOP, white, white, transparent, 0); + + gfxop_fill_box(state, rect, dblue); + gfxop_draw_rectangle(state, rect, blue, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL); + gfxop_draw_text(state, handle, gfx_rect(0, 0, 320, 150)); + gfxop_free_text(state, handle); +} + +void +test_f(void) +{ + int i; + int x, y; + gfx_text_handle_t *handle; + MESSAGE("-- Test F: Full font test --"); + waitkey(); + + handle = gfxop_new_text(state, 0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890", + 320, ALIGN_LEFT, ALIGN_TOP, white, white, transparent, 0); + gfxop_draw_text(state, handle, gfx_rect(0, 0, 320, 150)); + gfxop_free_text(state, handle); + update(); + + MESSAGE("F.0: Font wrap\nYou should now see the alphabet\n(capitals, then small letters),\nand the numbers from 1 to 0" + "\nwrapped with a maxwidth of\n320 (screen width)"); + waitkey(); + + MESSAGE("F.1: Font wrap:\nMisc. wrap widths\nAll text should be /within/ the\nblue box (it may touch\nthe border, though)"); + waitkey(); + for (i = 200; i > 50; i -= 7) { + clear_buffer(); + test_wrap(i, "\"Far out in the uncharted regions of the western spiral arm of the galaxy...\""); + update(); + MESSAGE1("\nwidth=%d", i); + waitkey(); + } + + handle = gfxop_new_text(state, 0, "And now for something completely different.", + 320, ALIGN_LEFT, ALIGN_TOP, red, green, black, 0); + gfxop_draw_text(state, handle, gfx_rect(0, 0, 320, 150)); + gfxop_free_text(state, handle); + update(); + MESSAGE("F.2: Dithered text\nThis text should now be dithered\nred/green on black background"); + waitkey(); + + clear_buffer(); + handle = gfxop_new_text(state, 0, "foo!", + 320, ALIGN_CENTER, ALIGN_CENTER, blue, blue, transparent, 0); + x = 10; y = 10; + + for (i = 0; i < 1000; i++) { + x = (x+(70 + (i / y) + y*y*x / (i+1))); + y = (y+(30 + (i / x) + x*x*y / (i+1))); + gfxop_draw_text(state, handle, gfx_rect(x % 320, y % 140, 0, 0)); + } + + gfxop_free_text(state, handle); + update(); + MESSAGE("F.3: Multiple draws\nText handles may be used more\nthan once\n(1000 times here)"); + waitkey(); +} + +void +do_tests(char *conf) +{ + init_colors(); + + + if (strchr(conf, 'a')) + if (test_a()) + return; + + if (strchr(conf, 'b')) + test_b(); + + if (strchr(conf, 'c')) + test_c(); + + if (strchr(conf, 'd')) + test_d(); + + if (strchr(conf, 'e')) + test_e(); + + if (strchr(conf, 'f')) + test_f(); +} + +int +c_quit(void *S) +{ + exit(0); + return 0; /* hahaha */ +} + +int +main(int argc, char **argv) +{ + gfx_driver_t *drv = NULL; + char c; + + strcpy(tests, ALL_TESTS); + + printf("gfx_test Copyright (C) 2000 Christoph Reichenbach\nThis program is provided WITHOUT WARRANTY of any kind. Please\n" + "refer to the file COPYING that should have come with this\ndistribution for licensing details.\n\n"); + + while ((c = getopt(argc, argv, "nhslc:g:x:y:t:")) > -1) + switch (c) { + + case 'h': + printf("Usage: gfx_test [-l] [-h] [-g driver] [-x xfact] [-y yfact] [-c bpp]\n" + "-l: List all graphics targets\n" + "-x: Set x resolution scale factor\n" + "-y: Set y resolution scale factor\n" + "-s: Skip intro text and getchar()\n" + "-c: Set bytes per pixel\n" + "-h: Display this help message\n" + "-n: Immediately stop after displaying (for performance tests)\n" + "-g: Select any of the graphics drivers shown with -l\n" + "-t: Select the tests to run:\n" + "\ta: Text display and basic input\n" + "\tb: Lines\n" + "\tc: Boxes and updates\n" + "\td: Pointers and input\n" + "\te: Pics and Views\n" + " -- for example, use \"-t abc\" to run tests A, B, and C\n" + ); + return 0; + + case 'n': nowait = 1; + break; + + case 's': skip_intro = 1; + break; + + case 'g': if (driver) sci_free(driver); + driver = sci_strdup(optarg); + break; + + case 'l': { + int first = 1; + int i = 0; + + printf("Available graphics drivers: "); + while (gfx_get_driver_name(i)) { + if (!first) + printf(", "); + first = 0; + printf("%s", gfx_get_driver_name(i++)); + } + printf("\n"); + } break; + + case 't': + strcpy(tests, optarg); + break; + + case 'x': + set_mode = xres = atoi(optarg); + if (xres < 1) { + fprintf(stderr,"Invalid x scale factor!\n"); + return 1; + } + break; + + case 'y': + set_mode = yres = atoi(optarg); + if (yres < 1) { + fprintf(stderr,"Invalid y scale factor!\n"); + return 1; + } + break; + + case 'c': + set_mode = color_mode = atoi(optarg); + if (color_mode < 1 || color_mode > 4) { + fprintf(stderr,"Invalid number of bytes per pixel!\n"); + return 1; + } + break; + + default: + fprintf(stderr,"Run 'gfx_test -h' for help\n"); + return 1; + } + + drv = gfx_find_driver("/tmp", driver); + + if (drv) { + printf("Using graphics driver '%s'\n", drv->name); + + if (!skip_intro) { + printf("Testing will now start. The first test will check whether displaying\n" + "text and reading input works; it will display a message and wait for twenty\n" + "seconds for you to press the space bar. If it does not register a space bar\n" + "keypress, it will abort.\n" + "Note that it can happen that no text is displayed, but you still are able\n" + "to proceed to the next test by pressing the space bar. However, unless you\n" + "are running in windowed mode, you will not be able to read which kinds of\n" + "tests are being run, so it is recommended that you fix pixmap displaying\n" + "and back-to-front-buffer updating first, so that the text can be displayed\n" + "correctly.\n" + "-- Press any key to start the first test or Ctrl-C to abort --\n"); + getchar(); + } + + if (init_driver(drv)) { + fprintf(stderr,"Initialization failed!\n"); + return 1; + } + + do_tests(tests); + + if (gfxop_exit(state)) { + fprintf(stderr,"Something weird happened while exitting...\n"); + } + } else { + fprintf(stderr,"No graphics driver found!\n"); + return 1; + } + + return 0; +} + + + +byte builtin_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0xd6, 0x10, 0x38, + 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x7c, 0x10, 0x38, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, + 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, + 0x18, 0xdb, 0x3c, 0xe7, 0xe7, 0x3c, 0xdb, 0x18, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, + 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x3e, 0x61, 0x3c, 0x66, 0x66, 0x3c, 0x86, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x18, 0x3e, 0x60, 0x3c, 0x06, 0x7c, 0x18, 0x00, + 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, + 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, + 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, + 0x7c, 0xc6, 0x06, 0x1c, 0x30, 0x66, 0xfe, 0x00, + 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, + 0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0xc6, 0x7c, 0x00, + 0x38, 0x60, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, + 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x00, + 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x7c, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, + 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3a, 0x00, + 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, + 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xce, 0x7c, 0x0e, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, + 0x3c, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x3c, 0x00, + 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00, + 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, + 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0xdc, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, + 0x1c, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x3c, 0x66, 0x60, 0xf8, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x06, 0x00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, + 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x7e, 0xc0, 0x7c, 0x06, 0xfc, 0x00, + 0x30, 0x30, 0xfc, 0x30, 0x30, 0x36, 0x1c, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc, + 0x00, 0x00, 0x7e, 0x4c, 0x18, 0x32, 0x7e, 0x00, + 0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x70, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x70, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, + 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0x66, 0xfc, 0x00, + 0x00, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0x00, + 0x66, 0x66, 0x3c, 0x7e, 0x18, 0x7e, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, + 0x3e, 0x61, 0x3c, 0x66, 0x66, 0x3c, 0x86, 0x7c, + 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0x9d, 0xa1, 0xa1, 0x9d, 0x81, 0x7e, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x81, 0xb9, 0xa5, 0xb9, 0xa5, 0x81, 0x7e, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, + 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x00, 0x00, 0x00, + 0x78, 0x0c, 0x38, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0xc0, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x38, + 0x18, 0x38, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x63, 0xe6, 0x6c, 0x7a, 0x36, 0x6a, 0xdf, 0x06, + 0x63, 0xe6, 0x6c, 0x7e, 0x33, 0x66, 0xcc, 0x0f, + 0xe1, 0x32, 0xe4, 0x3a, 0xf6, 0x2a, 0x5f, 0x86, + 0x18, 0x00, 0x18, 0x18, 0x30, 0x63, 0x3e, 0x00, + 0x18, 0x0c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x30, 0x60, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x7c, 0x82, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0x76, 0xdc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x38, 0x6c, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, + 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x0c, 0x78, + 0x30, 0x18, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0x18, 0x30, 0xfe, 0xc0, 0xf8, 0xc0, 0xfe, 0x00, + 0x7c, 0x82, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0xc6, 0x00, 0xfe, 0xc0, 0xfc, 0xc0, 0xfe, 0x00, + 0x30, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x0c, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x3c, 0x42, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0xf6, 0x66, 0x6c, 0xf8, 0x00, + 0x76, 0xdc, 0x00, 0xe6, 0xf6, 0xde, 0xce, 0x00, + 0x0c, 0x06, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x30, 0x60, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x7c, 0x82, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0x76, 0xdc, 0x38, 0x6c, 0xc6, 0x6c, 0x38, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, + 0x3a, 0x6c, 0xce, 0xd6, 0xe6, 0x6c, 0xb8, 0x00, + 0x60, 0x30, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x18, 0x30, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0x00, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x0c, 0x18, 0x66, 0x66, 0x3c, 0x18, 0x3c, 0x00, + 0xf0, 0x60, 0x7c, 0x66, 0x7c, 0x60, 0xf0, 0x00, + 0x78, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xcc, 0x00, + 0x30, 0x18, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x7c, 0x82, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x76, 0xdc, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00, + 0xc6, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x7e, 0x12, 0xfe, 0x90, 0xfe, 0x00, + 0x00, 0x00, 0x7e, 0xc0, 0xc0, 0x7e, 0x0c, 0x38, + 0x30, 0x18, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x0c, 0x18, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, + 0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, + 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x30, 0x7e, 0x0c, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x00, + 0x30, 0x18, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x0c, 0x18, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x76, 0xdc, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x02, 0x7c, 0xce, 0xd6, 0xe6, 0x7c, 0x80, + 0x60, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x78, 0x84, 0x00, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x18, 0x30, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc, + 0xe0, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0xf0, + 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0xfc +}; + + + + diff --git a/engines/sci/gfx/gfx_tools.c b/engines/sci/gfx/gfx_tools.c new file mode 100644 index 0000000000..b82627c896 --- /dev/null +++ b/engines/sci/gfx/gfx_tools.c @@ -0,0 +1,465 @@ +/*************************************************************************** + gfx_tools.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <sci_memory.h> +#include <gfx_tools.h> + +/* set optimisations for Win32: */ +#ifdef _WIN32 +# include <memory.h> +# ifndef SATISFY_PURIFY +# pragma intrinsic( memcpy, memset ) +# endif +#endif + +rect_t gfx_rect_fullscreen = {0, 0, 320, 200}; + +void +gfx_clip_box_basic(rect_t *box, int maxx, int maxy) +{ + if (box->x < 0) + box->x = 0; + + if (box->y < 0) + box->y = 0; + + if (box->x + box->xl > maxx) + box->xl = maxx - box->x + 1; + + if (box->y + box->yl > maxy) + box->yl = maxy - box->y + 1; +} + + +gfx_mode_t * +gfx_new_mode(int xfact, int yfact, int bytespp, unsigned int red_mask, unsigned int green_mask, + unsigned int blue_mask, unsigned int alpha_mask, int red_shift, int green_shift, + int blue_shift, int alpha_shift, int palette, int flags) +{ + gfx_mode_t *mode = (gfx_mode_t*)sci_malloc(sizeof(gfx_mode_t)); +#ifdef SATISFY_PURIFY + memset(mode, 0, sizeof(gfx_mode_t)); +#endif + + mode->xfact = xfact; + mode->yfact = yfact; + mode->bytespp = bytespp; + mode->red_mask = red_mask; + mode->green_mask = green_mask; + mode->blue_mask = blue_mask; + mode->alpha_mask = alpha_mask; + mode->red_shift = red_shift; + mode->green_shift = green_shift; + mode->blue_shift = blue_shift; + mode->alpha_shift = alpha_shift; + mode->flags = flags; + + if (palette) { + mode->palette = (gfx_palette_t*)sci_malloc(sizeof(gfx_palette_t)); +#ifdef SATISFY_PURIFY + memset(mode->palette, 0, sizeof(gfx_palette_t)); +#endif + mode->palette->max_colors_nr = palette; + mode->palette->colors = (gfx_palette_color_t*)sci_calloc(sizeof(gfx_palette_color_t), palette); /* Initialize with empty entries */ + } else mode->palette = NULL; + + return mode; +} + + +void +gfx_free_mode(gfx_mode_t *mode) +{ + if (mode->palette) { + free(mode->palette->colors); + free(mode->palette); + } + free(mode); +} + + + +void +gfx_copy_pixmap_box_i(gfx_pixmap_t *dest, gfx_pixmap_t *src, rect_t box) +{ + int width, height; + int offset; + + if ((dest->index_xl != src->index_xl) || (dest->index_yl != src->index_yl)) + return; + + gfx_clip_box_basic(&box, dest->index_xl, dest->index_yl); + + if (box.xl <= 0 || box.yl <= 0) + return; + + height = box.yl; + width = box.xl; + + offset = box.x + (box.y * dest->index_xl); + + while (height--) { + memcpy(dest->index_data + offset, src->index_data + offset, width); + offset += dest->index_xl; + } +} + + +gfx_pixmap_t * +gfx_clone_pixmap(gfx_pixmap_t *pxm, gfx_mode_t *mode) +{ + gfx_pixmap_t *clone = (gfx_pixmap_t*)sci_malloc(sizeof(gfx_pixmap_t)); + *clone = *pxm; + clone->index_data = NULL; + clone->colors = NULL; + clone->data = NULL; + gfx_pixmap_alloc_data(clone, mode); + + memcpy(clone->data, pxm->data, clone->data_size); + if (clone->alpha_map) { + clone->alpha_map = (byte *) sci_malloc(clone->xl * clone->yl); + memcpy(clone->alpha_map, pxm->alpha_map, clone->xl * clone->yl); + } + + return clone; +} + +gfx_pixmap_t * +gfx_new_pixmap(int xl, int yl, int resid, int loop, int cel) +{ + gfx_pixmap_t *pxm = (gfx_pixmap_t*)sci_malloc(sizeof(gfx_pixmap_t)); +#ifdef SATISFY_PURIFY + memset(pxm, 0, sizeof(gfx_pixmap_t)); +#endif + + pxm->alpha_map = NULL; + pxm->data = NULL; + pxm->internal.info = NULL; + pxm->colors = NULL; + pxm->internal.handle = 0; + + pxm->index_xl = xl; + pxm->index_yl = yl; + + pxm->ID = resid; + pxm->loop = loop; + pxm->cel = cel; + + pxm->index_data = NULL; + + pxm->flags = 0; + + pxm->color_key = 0xff; + + return pxm; +} + + +void +gfx_free_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm) +{ + if (driver) { + if (pxm->flags & GFX_PIXMAP_FLAG_INSTALLED) { + if (driver->capabilities & GFX_CAPABILITY_PIXMAP_REGISTRY) + driver->unregister_pixmap(driver, pxm); + } + + if (driver->mode->palette + && pxm->flags & GFX_PIXMAP_FLAG_PALETTE_ALLOCATED + && !(pxm->flags & GFX_PIXMAP_FLAG_DONT_UNALLOCATE_PALETTE) + && !(pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) { + int i; + int error = 0; + GFXDEBUG("UNALLOCATING %d\n", pxm->colors_nr); + for (i = 0; i < pxm->colors_nr; i++) + if (gfx_free_color(driver->mode->palette, pxm->colors + i)) + error++; + + if (error) { + GFXWARN("%d errors occured while freeing %d colors of pixmap with ID %06x/%d/%d\n", + error, pxm->colors_nr,pxm->ID, pxm->loop, pxm->cel); + } + } + } + + if (pxm->index_data) + free(pxm->index_data); + + if (pxm->alpha_map) + free(pxm->alpha_map); + + if (pxm->data) + free(pxm->data); + + if (pxm->colors && !(pxm->flags & GFX_PIXMAP_FLAG_EXTERNAL_PALETTE)) + free(pxm->colors); + + free(pxm); +} + + +gfx_pixmap_t * +gfx_pixmap_alloc_index_data(gfx_pixmap_t *pixmap) +{ + int size; + + if (pixmap->index_data) { + GFXWARN("Attempt to allocate pixmap index data twice!\n"); + return pixmap; + } + + size = pixmap->index_xl * pixmap->index_yl; + if (!size) + size = 1; + + pixmap->index_data = (byte*)sci_malloc(size); + + memset(pixmap->index_data, 0, size); + + return pixmap; +} + + +gfx_pixmap_t * +gfx_pixmap_free_index_data(gfx_pixmap_t *pixmap) +{ + if (!pixmap->index_data) { + GFXWARN("Attempt to free pixmap index data twice!\n"); + return pixmap; + } + + free(pixmap->index_data); + pixmap->index_data = NULL; + return pixmap; +} + + +gfx_pixmap_t * +gfx_pixmap_alloc_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode) +{ + int size; + + if (pixmap->data) { + GFXWARN("Attempt to allocate pixmap data twice!\n"); + return pixmap; + } + + if (pixmap->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) { + pixmap->xl = pixmap->index_xl; + pixmap->yl = pixmap->index_yl; + } else { + pixmap->xl = pixmap->index_xl * mode->xfact; + pixmap->yl = pixmap->index_yl * mode->yfact; + } + + size = pixmap->xl * pixmap->yl * mode->bytespp; + if (!size) + size = 1; + + pixmap->data = (byte*)sci_malloc(pixmap->data_size = size); + return pixmap; +} + + +gfx_pixmap_t * +gfx_pixmap_free_data(gfx_pixmap_t *pixmap) +{ + if (!pixmap->data) { + GFXWARN("Attempt to free pixmap data twice!\n"); + return pixmap; + } + + free(pixmap->data); + pixmap->data = NULL; + return pixmap; +} + + +int +gfx_alloc_color(gfx_palette_t *pal, gfx_pixmap_color_t *color) +{ + int i; + int dr, dg, db; /* deltas */ + int bestdelta = 1 + ((0x100 * 0x100) * 3); + int bestcolor = -1; + int firstfree = -1; + + if (pal == NULL) + return GFX_OK; + + if (pal->max_colors_nr <= 0) { + GFXERROR("Palette has zero or less color entries!\n"); + return GFX_ERROR; + } + + + if (color->global_index != GFX_COLOR_INDEX_UNMAPPED) { +#if 0 + GFXDEBUG("Attempt to allocate color twice: index 0x%d (%02x/%02x/%02x)!\n", + color->global_index, color->r, color->g, color->b); +#endif + return GFX_OK; + } + + for (i = 0; i < pal->max_colors_nr; i++) { + gfx_palette_color_t *pal_color = pal->colors + i; + + if (pal_color->lockers) { + int delta; + + dr = abs(pal_color->r - color->r); + dg = abs(pal_color->g - color->g); + db = abs(pal_color->b - color->b); + + if (dr == 0 && dg == 0 && db == 0) { + color->global_index = i; + return GFX_OK; + } + + delta = (dr * dr) + (dg * dg) + (db * db); + if (delta < bestdelta) { + bestdelta = delta; + bestcolor = i; + } + } else + if (firstfree == -1) + firstfree = i; + } + + if (firstfree != -1) { + pal->colors[firstfree].r = color->r; + pal->colors[firstfree].g = color->g; + pal->colors[firstfree].b = color->b; + pal->colors[firstfree].lockers = 1; + color->global_index = firstfree; + + return 42; /* positive value to indicate that this color still needs to be set */ + } + + color->global_index = bestcolor; + +// GFXWARN("Out of palette colors- doing approximated mapping!\n"); + return GFX_OK; +} + + +int +gfx_free_color(gfx_palette_t *pal, gfx_pixmap_color_t *color) +{ + gfx_palette_color_t *palette_color = pal->colors + color->global_index; + + if (!pal) + return GFX_OK; + + if (color->global_index == GFX_COLOR_INDEX_UNMAPPED) { + GFXWARN("Attempt to free unmapped color %02x/%02x/%02x!\n", color->r, color->g, color->b); + BREAKPOINT(); + return GFX_ERROR; + } + + if (color->global_index >= pal->max_colors_nr) { + GFXERROR("Attempt to free invalid color index %d (%02x/%02x/%02x)!\n", + color->global_index, color->r, color->g, color->b); + return GFX_ERROR; + } + + if (!palette_color->lockers) { + GFXERROR("Attempt to free unused color index %d (%02x/%02x/%02x)!\n", + color->global_index, color->r, color->g, color->b); + return GFX_ERROR; + } + + if (palette_color->lockers != GFX_COLOR_SYSTEM) + --(palette_color->lockers); + + color->global_index = GFX_COLOR_INDEX_UNMAPPED; + return GFX_OK; +} + + +gfx_pixmap_t * +gfx_pixmap_scale_index_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode) +{ + byte *old_data, *new_data, *initial_new_data; + byte *linestart; + int linewidth; + int xl, yl; + int i, yc; + int xfact = mode->xfact; + int yfact = mode->yfact; + + if (xfact == 1 && yfact == 1) + return pixmap; + + if (!pixmap) + return NULL; + + if (pixmap->flags & GFX_PIXMAP_FLAG_SCALED_INDEX) + return pixmap; /* Already done */ + + old_data = pixmap->index_data; + + if (!old_data) { + GFXERROR("Attempt to scale index data without index data!\n"); + return pixmap; + } + + xl = pixmap->index_xl; + yl = pixmap->index_yl; + linewidth = xfact * xl; + initial_new_data = new_data = (byte *) sci_malloc(linewidth * yfact * yl); + + for (yc = 0; yc < yl; yc++) { + + linestart = new_data; + + if (xfact == 1) { + memcpy(new_data, old_data, linewidth); + new_data += linewidth; + old_data += linewidth; + } else for (i = 0; i < xl; i++) { + byte fillc = *old_data++; + memset(new_data, fillc, xfact); + new_data += xfact; + } + + for (i = 1; i < yfact; i++) { + memcpy(new_data, linestart, linewidth); + new_data += linewidth; + } + } + + free(pixmap->index_data); + pixmap->index_data = initial_new_data; + + pixmap->flags |= GFX_PIXMAP_FLAG_SCALED_INDEX; + + pixmap->index_xl = linewidth; + pixmap->index_yl *= yfact; + + return pixmap; +} diff --git a/engines/sci/gfx/menubar.c b/engines/sci/gfx/menubar.c new file mode 100644 index 0000000000..ff4cb4a11e --- /dev/null +++ b/engines/sci/gfx/menubar.c @@ -0,0 +1,536 @@ +/*************************************************************************** + menubar.c Copyright (C) 1999,2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CJR) [jameson@linuxgames.com] + +***************************************************************************/ +/* Management and drawing operations for the SCI0 menu bar */ +/* I currently assume that the hotkey information used in the menu bar is NOT +** used for any actual actions on behalf of the interpreter. +*/ + +#include <sci_memory.h> +#include <engine.h> +#include <menubar.h> + +#define SIZE_INF 32767 + +/* +static int __active = 0; + +inline void* +__my_malloc(long size, char *function, int line) +{ + void *retval = sci_malloc(size); + __active++; + fprintf(stderr,"[%d] line %d, %s: malloc(%d) -> %p\n", __active, line, function, size, retval); + return retval; +} + +inline void* +__my_realloc(void *origin, long size, char *function, int line) +{ + void *retval = sci_realloc(origin, size); + fprintf(stderr,"line %d, %s: realloc(%p, %d) -> %p\n", line, function, origin, size, retval); + return retval; +} + +inline void +__my_free(void *origin, char *function, int line) +{ + free(origin); + fprintf(stderr,"[%d] line %d, %s: free(%p)\n", __active, line, function, origin); + __active--; +} + +#define malloc(x) __my_malloc(x, __PRETTY_FUNCTION__, __LINE__) +#define realloc(x,y) __my_realloc(x,y, __PRETTY_FUNCTION__, __LINE__) +#define free(x) __my_free(x, __PRETTY_FUNCTION__, __LINE__) +*/ + +menubar_t * +menubar_new() +{ + menubar_t *tmp = (menubar_t*)sci_malloc(sizeof(menubar_t)); + tmp->menus_nr = 0; + + return tmp; +} + +void +menubar_free(menubar_t *menubar) +{ + int i; + + for (i = 0; i < menubar->menus_nr; i++) { + menu_t *menu = &(menubar->menus[i]); + int j; + + for (j = 0; j < menu->items_nr; j++) { + if (menu->items[j].keytext) + free (menu->items[j].keytext); + if (menu->items[j].text) + free (menu->items[j].text); + } + + free(menu->items); + free(menu->title); + } + + if (menubar->menus_nr) + free (menubar->menus); + + free(menubar); +} + + +int +_menubar_add_menu_item(gfx_state_t *state, menu_t *menu, int type, char *left, char *right, + int font, int key, int modifiers, int tag, reg_t text_pos) +/* Returns the total text size, plus MENU_BOX_CENTER_PADDING if (right != NULL) */ +{ + menu_item_t *item; + int total_left_size = 0; + int width, height; + + if (menu->items_nr == 0) { + menu->items = (menu_item_t *) sci_malloc(sizeof(menu_item_t)); + menu->items_nr = 1; + } else menu->items = (menu_item_t *) sci_realloc(menu->items, sizeof(menu_item_t) * ++(menu->items_nr)); + + item = &(menu->items[menu->items_nr - 1]); + + memset(item, 0, sizeof(menu_item_t)); + + if ((item->type = type) == MENU_TYPE_HBAR) + return 0; + + /* else assume MENU_TYPE_NORMAL */ + item->text = left; + if (right) { + int end = strlen(right); + item->keytext = right; + while (end && isspace(right[end])) + right[end--] = 0; /* Remove trailing whitespace */ + item->flags = MENU_ATTRIBUTE_FLAGS_KEY; + item->key = key; + item->modifiers = modifiers; + } else { + item->keytext=NULL; + item->flags = 0; + } + + if (right) { + gfxop_get_text_params(state, font, right, SIZE_INF, &width, &height, 0, + NULL, NULL, NULL); + total_left_size = MENU_BOX_CENTER_PADDING + (item->keytext_size = width); + } + + item->enabled = 1; + item->tag = tag; + item->text_pos = text_pos; + gfxop_get_text_params(state, font, left, SIZE_INF, &width, &height, 0, + NULL, NULL, NULL); + + return total_left_size + width; +} + +void +menubar_add_menu(gfx_state_t *state, menubar_t *menubar, char *title, char *entries, int font, + reg_t entries_base) +{ + int i, add_freesci = 0; + menu_t *menu; + char tracker; + char *left = NULL, *right; + reg_t left_origin; + int string_len = 0; + int tag = 0, c_width, max_width = 0; + int height; + + if (menubar->menus_nr == 0) { +#ifdef MENU_FREESCI_BLATANT_PLUG + add_freesci = 1; +#endif + menubar->menus = (menu_t*)sci_malloc(sizeof(menu_t)); + menubar->menus_nr = 1; + } else menubar->menus = (menu_t*)sci_realloc(menubar->menus, ++(menubar->menus_nr) * sizeof (menu_t)); + + menu = &(menubar->menus[menubar->menus_nr-1]); + memset(menu, 0, sizeof(menu_t)); + menu->items_nr = 0; + menu->title = sci_strdup(title); + + gfxop_get_text_params(state, font, menu->title, SIZE_INF, &(menu->title_width), &height, 0, + NULL, NULL, NULL); + + do { + tracker = *entries++; + entries_base.offset++; + + if (!left) { /* Left string not finished? */ + + if (tracker == '=') { /* Hit early-SCI tag assignment? */ + + left = sci_strndup(entries - string_len - 1, string_len); + tag = atoi(entries++); + tracker = *entries++; + } + if ((tracker == 0 && string_len > 0) || (tracker == '=') || (tracker == ':')) { /* End of entry */ + int entrytype = MENU_TYPE_NORMAL; + char *inleft; + reg_t beginning; + + if (!left) + left = sci_strndup(entries - string_len - 1, string_len); + + inleft = left; + while (isspace(*inleft)) + inleft++; /* Seek beginning of actual string */ + + if (!strncmp(inleft, MENU_HBAR_STRING_1, strlen(MENU_HBAR_STRING_1)) + || !strncmp(inleft, MENU_HBAR_STRING_2, strlen(MENU_HBAR_STRING_2)) + || !strncmp(inleft, MENU_HBAR_STRING_3, strlen(MENU_HBAR_STRING_3))) + { + entrytype = MENU_TYPE_HBAR; /* Horizontal bar */ + free(left); + left = NULL; + } + + beginning = entries_base; beginning.offset -= string_len + 1; + c_width = _menubar_add_menu_item(state, menu, entrytype, left, NULL, font, 0, 0, tag, + beginning); + if (c_width > max_width) + max_width = c_width; + + string_len = 0; + left = NULL; /* Start over */ + + } else if (tracker == '`') { /* Start of right string */ + + if (!left) + { + left_origin = entries_base; left_origin.offset -= string_len + 1; + left = sci_strndup(entries - string_len -1, string_len); + } + string_len = 0; /* Continue with the right string */ + + } + else string_len++; /* Nothing special */ + + } else { /* Left string finished => working on right string */ + if ((tracker == ':') || (tracker == 0)) { /* End of entry */ + int key, modifiers = 0; + + right = sci_strndup(entries - string_len - 1, string_len); + + if (right[0] == '#') { + right[0] = SCI_SPECIAL_CHAR_FUNCTION; /* Function key */ + + key = SCI_K_F1 + ((right[1] - '1') << 8); + + if (right[1] == '0') + key = SCI_K_F10; /* F10 */ + + if (right[2]=='=') { + tag = atoi(right + 3); + right[2] = 0; + }; + } + else if (right[0] == '@') { /* Alt key */ + right[0] = SCI_SPECIAL_CHAR_ALT; /* ALT */ + key = right[1]; + modifiers = SCI_EVM_ALT; + + if ((key >= 'a') && (key <= 'z')) + right[1] = key - 'a' + 'A'; + + if (right[2]=='=') { + tag = atoi(right+3); + right[2] = 0; + }; + + } + else { + + if (right[0] == '^') { + right[0] = SCI_SPECIAL_CHAR_CTRL; /* Control key - there must be a replacement... */ + key = right[1]; + modifiers = SCI_EVM_CTRL; + + if ((key >= 'a') && (key <= 'z')) + right[1] = key - 'a' + 'A'; + + if (right[2]=='=') { + tag = atoi(right+3); + right[2] = 0; + } + + } + else { + key = right[0]; + if ((key >= 'a') && (key <= 'z')) + right[0] = key - 'a' + 'A'; + + if (right[1]=='=') { + tag=atoi(right+2); + right[1] = 0; + } + } + + if ((key >= 'A') && (key <= 'Z')) + key = key - 'A' + 'a'; /* Lowercase the key */ + } + + + i = strlen(right); + + while (i>0 && right[--i] == ' ') + right[i] = 0; /* Cut off chars to the right */ + + c_width = _menubar_add_menu_item(state, menu, MENU_TYPE_NORMAL, left, right, font, key, + modifiers, tag, left_origin); + tag = 0; + if (c_width > max_width) + max_width = c_width; + + string_len = 0; + left = NULL; /* Start over */ + + } else string_len++; /* continuing entry */ + } /* right string finished */ + + } while (tracker); + +#ifdef MENU_FREESCI_BLATANT_PLUG + if (add_freesci) { + + char *freesci_text = sci_strdup ("About FreeSCI"); + c_width = _menubar_add_menu_item(state, menu, MENU_TYPE_NORMAL, freesci_text, NULL, font, 0, 0, 0, NULL_REG); + if (c_width > max_width) + max_width = c_width; + + menu->items[menu->items_nr-1].flags = MENU_FREESCI_BLATANT_PLUG; + } +#endif /* MENU_FREESCI_BLATANT_PLUG */ + menu->width = max_width; +} + +int +menubar_match_key(menu_item_t *item, int message, int modifiers) +{ + if ((item->key == message) + && ((modifiers & (SCI_EVM_CTRL | SCI_EVM_ALT)) == item->modifiers)) + return 1; + + if (message == '\t' + && item->key == 'i' + && ((modifiers & (SCI_EVM_CTRL | SCI_EVM_ALT)) == 0) + && item->modifiers == SCI_EVM_CTRL) + return 1; /* Match TAB to ^I */ + + return 0; +} + +int +menubar_set_attribute(state_t *s, int menu_nr, int item_nr, int attribute, reg_t value) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return 1; + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return 1; + + item = menubar->menus[menu_nr].items + item_nr; + + switch (attribute) { + + case MENU_ATTRIBUTE_SAID: + if (value.segment) { + item->said_pos = value; + memcpy(item->said, kernel_dereference_bulk_pointer(s, value, 0), MENU_SAID_SPEC_SIZE); /* Copy Said spec */ + item->flags |= MENU_ATTRIBUTE_FLAGS_SAID; + + } else + item->flags &= ~MENU_ATTRIBUTE_FLAGS_SAID; + + break; + + case MENU_ATTRIBUTE_TEXT: + free(item->text); + assert(value.segment); + item->text = sci_strdup(kernel_dereference_char_pointer(s, value, 0)); + item->text_pos = value; + break; + + case MENU_ATTRIBUTE_KEY: + if (item->keytext) + free(item->keytext); + + if (value.segment) { + + /* FIXME: What happens here if <value> is an extended key? Potential bug. LS */ + item->key = value.offset; + item->modifiers = 0; + item->keytext = (char*)sci_malloc(2); + item->keytext[0] = value.offset; + item->keytext[1] = 0; + item->flags |= MENU_ATTRIBUTE_FLAGS_KEY; + if ((item->key >= 'A') && (item->key <= 'Z')) + item->key = item->key - 'A' + 'a'; /* Lowercase the key */ + + + } else { + + item->keytext = NULL; + item->flags &= ~MENU_ATTRIBUTE_FLAGS_KEY; + + } + break; + + case MENU_ATTRIBUTE_ENABLED: + item->enabled = value.offset; + break; + + case MENU_ATTRIBUTE_TAG: + item->tag = value.offset; + break; + + default: + sciprintf("Attempt to set invalid attribute of menu %d, item %d: 0x%04x\n", + menu_nr, item_nr, attribute); + return 1; + } + + return 0; +} + +reg_t +menubar_get_attribute(state_t *s, int menu_nr, int item_nr, int attribute) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return make_reg(0, -1); + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return make_reg(0, -1); + + item = menubar->menus[menu_nr].items + item_nr; + + switch (attribute) { + case MENU_ATTRIBUTE_SAID: + return item->said_pos; + + case MENU_ATTRIBUTE_TEXT: + return item->text_pos; + + case MENU_ATTRIBUTE_KEY: + return make_reg(0, item->key); + + case MENU_ATTRIBUTE_ENABLED: + return make_reg(0, item->enabled); + + case MENU_ATTRIBUTE_TAG: + return make_reg(0, item->tag); + + default: + sciprintf("Attempt to read invalid attribute from menu %d, item %d: 0x%04x\n", + menu_nr, item_nr, attribute); + return make_reg(0, -1); + } +} + +int +menubar_item_valid(state_t *s, int menu_nr, int item_nr) +{ + menubar_t *menubar = s->menubar; + menu_item_t *item; + + if ((menu_nr < 0) || (item_nr < 0)) + return 0; + + if ((menu_nr >= menubar->menus_nr) || (item_nr >= menubar->menus[menu_nr].items_nr)) + return 0; + + item = menubar->menus[menu_nr].items + item_nr; + + if ((item->type == MENU_TYPE_NORMAL) + && item->enabled) + return 1; + + return 0; /* May not be selected */ +} + + +int +menubar_map_pointer(state_t *s, int *menu_nr, int *item_nr, gfxw_port_t *port) +{ + menubar_t *menubar = s->menubar; + menu_t *menu; + + if (s->gfx_state->pointer_pos.y <= 10) { /* Re-evaulate menu */ + int x = MENU_LEFT_BORDER; + int i; + + for (i = 0; i < menubar->menus_nr; i++) { + int newx = x + MENU_BORDER_SIZE * 2 + menubar->menus[i].title_width; + + if (s->gfx_state->pointer_pos.x < x) + return 0; + + if (s->gfx_state->pointer_pos.x < newx) { + *menu_nr = i; + *item_nr = -1; + } + + x = newx; + } + + return 0; + + } else { + int row = (s->gfx_state->pointer_pos.y / 10) - 1; + + if ((*menu_nr < 0) || (*menu_nr >= menubar->menus_nr)) + return 1; /* No menu */ + else + menu = menubar->menus + *menu_nr; /* Menu is valid, assume that it's popped up */ + + if (menu->items_nr <= row) + return 1; + + if ((s->gfx_state->pointer_pos.x < port->bounds.x) || (s->gfx_state->pointer_pos.x > port->bounds.x + port->bounds.xl)) + return 1; + + if (menubar_item_valid(s, *menu_nr, row)) + *item_nr = row; /* Only modify if we'll be hitting a valid element */ + + return 0; + } + +} diff --git a/engines/sci/gfx/operations.c b/engines/sci/gfx/operations.c new file mode 100644 index 0000000000..a19e0bc99f --- /dev/null +++ b/engines/sci/gfx/operations.c @@ -0,0 +1,2490 @@ +/*************************************************************************** + gfx_operations Copyright (C) 2000 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Graphical operations, called from the widget state manager */ + +#include <sci_memory.h> +#include <gfx_operations.h> + +#include <ctype.h> + +#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 rects + ** in 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 +gfx_pixmap_color_t default_colors[DEFAULT_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 */ + + +#define POINTER_VISIBLE_BUT_CLIPPED 2 + +/* Performs basic checks that apply to most functions */ +#define BASIC_CHECKS(error_retval) \ +if (!state) { \ + GFXERROR("Null state!\n"); \ + return error_retval; \ +} \ +if (!state->driver) { \ + GFXERROR("GFX driver invalid!\n"); \ + return error_retval; \ +} + +/* How to determine whether colors have to be allocated */ +#define PALETTE_MODE state->driver->mode->palette + +#define DRAW_POINTER { int __x = _gfxop_draw_pointer(state); if (__x) { GFXERROR("Drawing the mouse pointer failed!\n"); return __x;} } +#define REMOVE_POINTER { int __x = _gfxop_remove_pointer(state); if (__x) { GFXERROR("Removing the mouse pointer failed!\n"); return __x;} } + +/* #define GFXOP_DEBUG_DIRTY */ + +/* Internal operations */ + +static void +_gfxop_scale_rect(rect_t *rect, gfx_mode_t *mode) +{ + int xfact = mode->xfact; + int yfact = mode->yfact; + + rect->x *= xfact; + rect->y *= yfact; + rect->xl *= xfact; + rect->yl *= yfact; +} + +static void +_gfxop_scale_point(point_t *point, gfx_mode_t *mode) +{ + int xfact = mode->xfact; + int yfact = mode->yfact; + + point->x *= xfact; + point->y *= yfact; +} + +static void +_gfxop_alloc_colors(gfx_state_t *state, gfx_pixmap_color_t *colors, int colors_nr) +{ + int i; + + if (!PALETTE_MODE) + return; + + for (i = 0; i < colors_nr; i++) + gfx_alloc_color(state->driver->mode->palette, colors + i); +} + +static void +_gfxop_free_colors(gfx_state_t *state, gfx_pixmap_color_t *colors, int colors_nr) +{ + int i; + + if (!PALETTE_MODE) + return; + + for (i = 0; i < colors_nr; i++) + gfx_free_color(state->driver->mode->palette, colors + i); +} + + +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->xl, rect->yl, + clipzone.x, clipzone.y, clipzone.xl, clipzone.yl); +#endif + + if (rect->x < clipzone.x) { + rect->xl -= (clipzone.x - rect->x); + rect->x = clipzone.x; + } + + if (rect->y < clipzone.y) { + rect->yl -= (clipzone.y - rect->y); + rect->y = clipzone.y; + } + + if (rect->x + rect->xl > clipzone.x + clipzone.xl) + rect->xl = (clipzone.x + clipzone.xl) - rect->x; + + if (rect->y + rect->yl > clipzone.y + clipzone.yl) + rect->yl = (clipzone.y + clipzone.yl) - rect->y; + + if (rect->xl < 0) + rect->xl = 0; + if (rect->yl < 0) + rect->yl = 0; + +#if 0 + printf (" => (%d, %d) size (%d, %d)\n", rect->x, rect->y, rect->xl, rect->yl); +#endif + return (rect->xl <= 0 || rect->yl <= 0); +} + +static int +_gfxop_grab_pixmap(gfx_state_t *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->mode->xfact; + int yfact = state->driver->mode->yfact; + 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->mode->xfact, + 200 * state->driver->mode->yfact))) + return GFX_ERROR; + + if (!*pxmp) + *pxmp = gfx_new_pixmap(unscaled_xl, unscaled_yl, GFX_RESID_NONE, 0, 0); + else + if (xl * yl > (*pxmp)->xl * (*pxmp)->yl) { + gfx_pixmap_free_data(*pxmp); + (*pxmp)->data = NULL; + } + + if (!(*pxmp)->data) { + (*pxmp)->index_xl = unscaled_xl + 1; + (*pxmp)->index_yl = unscaled_yl + 1; + gfx_pixmap_alloc_data(*pxmp, state->driver->mode); + } + return state->driver->grab_pixmap(state->driver, *zone, *pxmp, + priority? GFX_MASK_PRIORITY : GFX_MASK_VISUAL); +} + + +#define DRAW_LOOP(condition) \ +{ \ + rect_t drawrect = gfx_rect(pos.x, pos.y, pxm->index_xl, pxm->index_yl); \ + int offset, base_offset; \ + int read_offset, base_read_offset; \ + int x,y; \ + \ + if (!pxm->index_data) { \ + GFXERROR("Attempt to draw control color %d on pixmap %d/%d/%d without index data!\n", \ + 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_xl); \ + \ + for (y = 0; y < drawrect.yl; y++) { \ + for (x = 0; x < drawrect.xl; 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_xl; \ + } \ +} + +static void +_gfxop_draw_control(gfx_pixmap_t *map, gfx_pixmap_t *pxm, int color, point_t 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, point_t pos) +DRAW_LOOP(map->index_data[offset] < color) /* Draw only lower priority */ +#endif + +#undef DRAW_LOOP + +static int +_gfxop_install_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm) +{ + int error; + + if (driver->capabilities & GFX_CAPABILITY_PIXMAP_REGISTRY + && !(pxm->flags & GFX_PIXMAP_FLAG_INSTALLED)) { + error = driver->register_pixmap(driver, pxm); + + if (error) { + GFXERROR("driver->register_pixmap() returned error!\n"); + return error; + } + pxm->flags |= GFX_PIXMAP_FLAG_INSTALLED; + } + + if (driver->mode->palette && + (!(pxm->flags & GFX_PIXMAP_FLAG_PALETTE_SET))) { + int i; + int error; + + for (i = 0; i < pxm->colors_nr; i++) { + if ((error = driver->set_palette(driver, pxm->colors[i].global_index, + pxm->colors[i].r, + pxm->colors[i].g, + pxm->colors[i].b))) { + + GFXWARN("driver->set_palette(%d, %02x/%02x/%02x) failed!\n", + pxm->colors[i].global_index, + pxm->colors[i].r, + pxm->colors[i].g, + pxm->colors[i].b); + + if (error == GFX_FATAL) + return GFX_FATAL; + } + } + + pxm->flags |= GFX_PIXMAP_FLAG_PALETTE_SET; + } + return GFX_OK; +} + +static int +_gfxop_draw_pixmap(gfx_driver_t *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) +{ + int error; + rect_t clipped_dest = gfx_rect(dest.x, dest.y, dest.xl, dest.yl); + + if (control >= 0 || priority >= 0) { + point_t original_pos = gfx_point(dest.x / driver->mode->xfact, + dest.y / driver->mode->yfact); + + 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 GFX_OK; + + src.x += clipped_dest.x - dest.x; + src.y += clipped_dest.y - dest.y; + src.xl = clipped_dest.xl; + src.yl = clipped_dest.yl; + + error = _gfxop_install_pixmap(driver, pxm); + if (error) return error; + + DDIRTY(stderr, "\\-> Drawing to actual %d %d %d %d\n", + clipped_dest.x / driver->mode->xfact, + clipped_dest.y / driver->mode->yfact, + clipped_dest.xl / driver->mode->xfact, + clipped_dest.yl / driver->mode->yfact); + + error = driver->draw_pixmap(driver, pxm, priority, src, clipped_dest, + static_buf? GFX_BUFFER_STATIC : GFX_BUFFER_BACK); + + if (error) { + GFXERROR("driver->draw_pixmap() returned error!\n"); + return error; + } + return GFX_OK; +} + +static int +_gfxop_remove_pointer(gfx_state_t *state) +{ + if (state->mouse_pointer_visible + && !state->mouse_pointer_in_hw + && state->mouse_pointer_bg) { + int retval; + + if (state->mouse_pointer_visible == POINTER_VISIBLE_BUT_CLIPPED) { + state->mouse_pointer_visible = 0; + state->pointer_pos.x = state->driver->pointer_x / state->driver->mode->xfact; + state->pointer_pos.y = state->driver->pointer_y / state->driver->mode->yfact; + return GFX_OK; + } + + state->mouse_pointer_visible = 0; + + retval = state->driver->draw_pixmap(state->driver, state->mouse_pointer_bg, GFX_NO_PRIORITY, + gfx_rect(0, 0, state->mouse_pointer_bg->xl, state->mouse_pointer_bg->yl), + state->pointer_bg_zone, + GFX_BUFFER_BACK); + + state->pointer_pos.x = state->driver->pointer_x / state->driver->mode->xfact; + state->pointer_pos.y = state->driver->pointer_y / state->driver->mode->yfact; + + return retval; + + } else { + state->pointer_pos.x = state->driver->pointer_x / state->driver->mode->xfact; + state->pointer_pos.y = state->driver->pointer_y / state->driver->mode->yfact; + return GFX_OK; + } +} + +static int /* returns 1 if there are no pointer bounds, 0 otherwise */ +_gfxop_get_pointer_bounds(gfx_state_t *state, rect_t *rect) +{ + gfx_pixmap_t *ppxm = state->mouse_pointer; + + if (!ppxm) + return 1; + + rect->x = state->driver->pointer_x - ppxm->xoffset * (state->driver->mode->xfact); + rect->y = state->driver->pointer_y - ppxm->yoffset * (state->driver->mode->yfact); + rect->xl = ppxm->xl; + rect->yl = ppxm->yl; + + return (_gfxop_clip(rect, gfx_rect(0, 0, 320 * state->driver->mode->xfact, + 200 * state->driver->mode->yfact))); +} + +static int +_gfxop_buffer_propagate_box(gfx_state_t *state, rect_t box, gfx_buffer_t buffer); + +static int +_gfxop_draw_pointer(gfx_state_t *state) +{ + if (state->mouse_pointer_visible || !state->mouse_pointer || state->mouse_pointer_in_hw) + return GFX_OK; + else { + int retval; + gfx_pixmap_t *ppxm = state->mouse_pointer; + int xfact, yfact; + int x = state->driver->pointer_x - ppxm->xoffset * (xfact = state->driver->mode->xfact); + int y = state->driver->pointer_y - ppxm->yoffset * (yfact = state->driver->mode->yfact); + int error; + + state->mouse_pointer_visible = 1; + + state->old_pointer_draw_pos.x = x; + state->old_pointer_draw_pos.y = y; + + /* FIXME: we are leaking the mouse_pointer_bg, but freeing it causes weirdness in jones + * we should reuse the buffer instead of malloc/free for better performance */ + + retval = _gfxop_grab_pixmap(state, &(state->mouse_pointer_bg), x, y, + ppxm->xl, ppxm->yl, 0, + &(state->pointer_bg_zone)); + + if (retval == GFX_ERROR) { + state->pointer_bg_zone = gfx_rect(0, 0, 320, 200); + state->mouse_pointer_visible = POINTER_VISIBLE_BUT_CLIPPED; + return GFX_OK; + } + + if (retval) + return retval; + + error = _gfxop_draw_pixmap(state->driver, ppxm, -1, -1, + gfx_rect(0, 0, ppxm->xl, ppxm->yl), + gfx_rect(x, y, ppxm->xl, ppxm->yl), + gfx_rect(0, 0, xfact * 320 , yfact * 200), + 0, state->control_map, state->priority_map); + + if (error) + return error; + + + return GFX_OK; + } +} + +gfx_pixmap_t * +_gfxr_get_cel(gfx_state_t *state, int nr, int *loop, int *cel, int palette) +{ + gfxr_view_t *view = gfxr_get_view(state->resstate, nr, loop, cel, palette); + gfxr_loop_t *indexed_loop; + + if (!view) + return NULL; + + if (*loop >= view->loops_nr + || *loop < 0) { + GFXWARN("Attempt to get cel from loop %d/%d inside view %d\n", *loop, + view->loops_nr, nr); + return NULL; + } + indexed_loop = view->loops + *loop; + + if (*cel >= indexed_loop->cels_nr + || *cel < 0) { + GFXWARN("Attempt to get cel %d/%d from view %d/%d\n", *cel, indexed_loop->cels_nr, + nr, *loop); + return NULL; + } + + return indexed_loop->cels[*cel]; /* Yes, view->cels uses a malloced pointer list. */ +} + +/*** Dirty rectangle operations ***/ + +static inline int +_gfxop_update_box(gfx_state_t *state, rect_t box) +{ + int retval; + _gfxop_scale_rect(&box, state->driver->mode); + + if ((retval = _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_FRONT))) { + GFXERROR("Error occured while propagating box (%d,%d,%d,%d) to front buffer\n", + box.x, box.y, box.xl, box.yl); + return retval; + } + return GFX_OK; +} + + +static struct _dirty_rect * +_rect_create(rect_t box) +{ + struct _dirty_rect *rect; + + rect = (struct _dirty_rect*)sci_malloc(sizeof(struct _dirty_rect)); + rect->next = NULL; + rect->rect = box; + + return rect; +} + + +gfx_dirty_rect_t * +gfxdr_add_dirty(gfx_dirty_rect_t *base, rect_t box, int strategy) +{ + if (box.xl < 0) { + box.x += box.xl; + box.xl = - box.xl; + } + + if (box.yl < 0) { + box.y += box.yl; + box.yl = - box.yl; + } +#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 base; + + switch (strategy) { + + case GFXOP_DIRTY_FRAMES_ONE: + if (base) + base->rect = gfx_rects_merge(box, base->rect); + else + base = _rect_create(box); + break; + + case GFXOP_DIRTY_FRAMES_CLUSTERS: { + struct _dirty_rect **rectp = &(base); + + while (*rectp) { + if (gfx_rects_overlap((*rectp)->rect, box)) { + struct _dirty_rect *next = (*rectp)->next; + box = gfx_rects_merge((*rectp)->rect, box); + free(*rectp); + *rectp = next; + } else + rectp = &((*rectp)->next); + } + *rectp = _rect_create(box); + + } break; + + default: + GFXERROR("Attempt to use invalid dirty frame mode %d!\nPlease refer to gfx_options.h.", strategy); + + } + + return base; +} + +static void +_gfxop_add_dirty(gfx_state_t *state, rect_t box) +{ + if (state->disable_dirty) + return; + + state->dirty_rects = gfxdr_add_dirty(state->dirty_rects, box, state->options->dirty_frames); +} + +static inline void +_gfxop_add_dirty_x(gfx_state_t *state, rect_t box) + /* Extends the box size by one before adding (used for lines) */ +{ + if (box.xl < 0) + box.xl--; + else + box.xl++; + + if (box.yl < 0) + box.yl--; + else + box.yl++; + + _gfxop_add_dirty(state, box); +} + +static int +_gfxop_clear_dirty_rec(gfx_state_t *state, struct _dirty_rect *rect) +{ + int retval; + + if (!rect) + return GFX_OK; + +#ifdef GFXOP_DEBUG_DIRTY + fprintf(stderr, "\tClearing dirty (%d %d %d %d)\n", + GFX_PRINT_RECT(rect->rect)); +#endif + if (!state->fullscreen_override) + retval = _gfxop_update_box(state, rect->rect); + else + retval = GFX_OK; + + retval |= _gfxop_clear_dirty_rec(state, rect->next); + + free(rect); + return retval; +} + + +/*** 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)); + (*pixmap)->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + (*pixmap)->colors_nr = DEFAULT_COLORS_NR; + (*pixmap)->colors = default_colors; +} + +static int +_gfxop_init_common(gfx_state_t *state, gfx_options_t *options, void *misc_payload) +{ + state->options = options; + + if (!((state->resstate = gfxr_new_resource_manager(state->version, + state->options, + state->driver, + misc_payload)))) { + GFXERROR("Failed to initialize resource manager!\n"); + return GFX_FATAL; + } + + if ((state->static_palette = + gfxr_interpreter_get_static_palette(state->resstate, + state->version, + &(state->static_palette_entries), + misc_payload))) + _gfxop_alloc_colors(state, state->static_palette, state->static_palette_entries); + + state->visible_map = GFX_MASK_VISUAL; + state->fullscreen_override = NULL; /* No magical override */ + gfxop_set_clip_zone(state, gfx_rect(0, 0, 320, 200)); + + state->mouse_pointer = state->mouse_pointer_bg = NULL; + state->mouse_pointer_visible = 0; + + init_aux_pixmap(&(state->control_map)); + init_aux_pixmap(&(state->priority_map)); + init_aux_pixmap(&(state->static_priority_map)); + + state->options = options; + state->mouse_pointer_in_hw = 0; + state->disable_dirty = 0; + state->events = NULL; + + state->pic = state->pic_unscaled = NULL; + + state->pic_nr = -1; /* Set background pic number to an invalid value */ + + state->tag_mode = 0; + + state->dirty_rects = NULL; + + + return GFX_OK; +} + +int +gfxop_init_default(gfx_state_t *state, gfx_options_t *options, void *misc_info) +{ + BASIC_CHECKS(GFX_FATAL); + if (state->driver->init(state->driver)) + return GFX_FATAL; + + return _gfxop_init_common(state, options, misc_info); +} + + +int +gfxop_init(gfx_state_t *state, int xfact, int yfact, gfx_color_mode_t bpp, + gfx_options_t *options, void *misc_info) +{ + int color_depth = bpp? bpp : 1; + int initialized = 0; + + BASIC_CHECKS(GFX_FATAL); + + do { + if (!state->driver->init_specific(state->driver, xfact, yfact, color_depth)) + initialized = 1; + else + color_depth++; + } while (!initialized && color_depth < 9 && !bpp); + + if (!initialized) + return GFX_FATAL; + + return _gfxop_init_common(state, options, misc_info); +} + + +int +gfxop_set_parameter(gfx_state_t *state, char *attribute, char *value) +{ + BASIC_CHECKS(GFX_FATAL); + + return state->driver->set_parameter(state->driver, attribute, value); +} + + +int +gfxop_exit(gfx_state_t *state) +{ + BASIC_CHECKS(GFX_ERROR); + gfxr_free_resource_manager(state->driver, state->resstate); + + if (state->control_map) { + gfx_free_pixmap(state->driver, state->control_map); + state->control_map = NULL; + } + + if (state->priority_map) { + gfx_free_pixmap(state->driver, state->priority_map); + state->priority_map = NULL; + } + + if (state->static_priority_map) { + gfx_free_pixmap(state->driver, state->static_priority_map); + state->static_priority_map = NULL; + } + + if (state->mouse_pointer_bg) { + gfx_free_pixmap(state->driver, state->mouse_pointer_bg); + state->mouse_pointer_bg = NULL; + } + + state->driver->exit(state->driver); + return GFX_OK; +} + + +int +gfxop_have_mouse(gfx_state_t *state) +{ + return state->driver->capabilities & GFX_CAPABILITY_MOUSE_SUPPORT; +} + + +static int +_gfxop_scan_one_bitmask(gfx_pixmap_t *pixmap, rect_t zone) +{ + int retval = 0; + int pixmap_xscale = pixmap->index_xl / 320; + int pixmap_yscale = pixmap->index_yl / 200; + int line_width = pixmap_yscale * pixmap->index_xl; + int startindex = (line_width * zone.y) + (zone.x * pixmap_xscale); + + startindex += pixmap_xscale >> 1; /* Center on X */ + startindex += (pixmap_yscale >> 1) * pixmap->index_xl; /* Center on Y */ + + if (_gfxop_clip(&zone, gfx_rect(0, 0, pixmap->index_xl, pixmap->index_yl))) + return 0; + + while (zone.yl--) { + int i; + for (i = 0; i < (zone.xl * pixmap_xscale); i += pixmap_xscale) + retval |= (1 << ((pixmap->index_data[startindex + i]) & 0xf)); + + startindex += line_width; + } + + return retval; +} + +int +gfxop_scan_bitmask(gfx_state_t *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.xl <= 0 + || area.yl <= 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 + +int +gfxop_set_clip_zone(gfx_state_t *state, rect_t zone) +{ + int xfact, yfact; + BASIC_CHECKS(GFX_ERROR); + + DDIRTY(stderr, "-- Setting clip zone %d %d %d %d\n", GFX_PRINT_RECT(zone)); + + xfact = state->driver->mode->xfact; + yfact = state->driver->mode->yfact; + + if (zone.x < MIN_X) { + zone.xl -= (zone.x - MIN_X); + zone.x = MIN_X; + } + + if (zone.y < MIN_Y) { + zone.yl -= (zone.y - MIN_Y); + zone.y = MIN_Y; + } + + if (zone.x + zone.xl > MAX_X) + zone.xl = MAX_X + 1 - zone.x; + + if (zone.y + zone.yl > MAX_Y) + zone.yl = 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.xl = state->clip_zone_unscaled.xl * xfact; + state->clip_zone.yl = state->clip_zone_unscaled.yl * yfact; + + return GFX_OK; +} + +int +gfxop_set_color(gfx_state_t *state, gfx_color_t *color, int r, int g, int b, int a, + int priority, int control) +{ + gfx_pixmap_color_t pixmap_color = {0}; + int error_code; + int mask = ((r >= 0 && g >= 0 && b >= 0) ? GFX_MASK_VISUAL : 0) + | ((priority >= 0)? GFX_MASK_PRIORITY : 0) + | ((control >= 0)? GFX_MASK_CONTROL : 0); + + BASIC_CHECKS(GFX_FATAL); + + if (PALETTE_MODE && 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; + + if (PALETTE_MODE) { + pixmap_color.r = r; + pixmap_color.g = g; + pixmap_color.b = b; + pixmap_color.global_index = GFX_COLOR_INDEX_UNMAPPED; + if ((error_code = gfx_alloc_color(state->driver->mode->palette, &pixmap_color))) { + if (error_code < 0) { + GFXWARN("Could not get color entry for %02x/%02x/%02x\n", r, g, b); + return error_code; + } else if ((error_code = state->driver->set_palette(state->driver, pixmap_color.global_index, (byte) r, (byte) g, (byte) b))) { + GFXWARN("Graphics driver failed to set color index %d to (%02x/%02x/%02x)\n", + pixmap_color.global_index, r, g, b); + return error_code; + } + } + color->visual.global_index = pixmap_color.global_index; + } + } + return GFX_OK; +} + +int +gfxop_set_system_color(gfx_state_t *state, gfx_color_t *color) +{ + gfx_palette_color_t *palette_colors; + BASIC_CHECKS(GFX_FATAL); + + if (!PALETTE_MODE) + return GFX_OK; + + if (color->visual.global_index < 0 + || color->visual.global_index >= state->driver->mode->palette->max_colors_nr) { + GFXERROR("Attempt to set invalid color index %02x as system color\n", color->visual.global_index); + return GFX_ERROR; + } + + palette_colors = state->driver->mode->palette->colors; + palette_colors[color->visual.global_index].lockers = GFX_COLOR_SYSTEM; + + return GFX_OK; +} + +int +gfxop_free_color(gfx_state_t *state, gfx_color_t *color) +{ + gfx_palette_color_t *palette_color = {0}; + gfx_pixmap_color_t pixmap_color = {0}; + int error_code; + BASIC_CHECKS(GFX_FATAL); + + if (!PALETTE_MODE) + return GFX_OK; + + if (color->visual.global_index < 0 + || color->visual.global_index >= state->driver->mode->palette->max_colors_nr) { + GFXERROR("Attempt to free invalid color index %02x\n", color->visual.global_index); + return GFX_ERROR; + } + + pixmap_color.global_index = color->visual.global_index; + palette_color = state->driver->mode->palette->colors + pixmap_color.global_index; + pixmap_color.r = palette_color->r; + pixmap_color.g = palette_color->g; + pixmap_color.b = palette_color->b; + + if ((error_code = gfx_free_color(state->driver->mode->palette, &pixmap_color))) { + GFXWARN("Failed to free color with color index %02x\n", color->visual.global_index); + return error_code; + } + + return GFX_OK; +} + +/******************************/ +/* 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.xl -= xfact; + clip.yl -= yfact; + + if (!line->xl) {/* vbar */ + if (line->x < clip.x || line->x >= (clip.x + clip.xl)) + return 1; + + return line_check_bar(&(line->y), &(line->yl), clip.y, clip.yl); + + } else + + if (!line->yl) {/* hbar */ + if (line->y < clip.y || line->y >= (clip.y + clip.yl)) + return 1; + + return line_check_bar(&(line->x), &(line->xl), clip.x, clip.xl); + + } else { /* "normal" line */ + float start = 0.0, end = 1.0; + float xv = (float) line->xl; + float yv = (float) line->yl; + + if (line->xl < 0) + clip_line_partial(&start, &end, (float) (1.0 / xv), (float) line->x, (float) (clip.x + clip.xl), (float) clip.x); + else + clip_line_partial(&start, &end, (float) (1.0 / xv), (float) line->x, (float) clip.x, (float) (clip.x + clip.xl)); + + if (line->yl < 0) + clip_line_partial(&start, &end, (float) (1.0 / yv), (float) line->y, (float) (clip.y + clip.yl), (float) clip.y); + else + clip_line_partial(&start, &end, (float) (1.0 / yv), (float) line->y, (float) clip.y, (float) (clip.y + clip.yl)); + + line->x += (int) (xv * start); + line->y += (int) (yv * start); + + line->xl = (int) (xv * (end-start)); + line->yl = (int) (yv * (end-start)); + + return (start > 1.0 || end < 0.0); + } + return 0; +} + +static int +point_clip(point_t *start, point_t *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.xl; + end->y = line.y + line.yl; + + return retval; +} + + + +static void +draw_line_to_control_map(gfx_state_t *state, point_t start, point_t 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 int +simulate_stippled_line_draw(gfx_driver_t *driver, int skipone, point_t start, point_t 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->mode->xfact : driver->mode->yfact; + int dbl_stepwidth = 2*stepwidth; + int linelength = (line_mode == GFX_LINE_MODE_FINE)? stepwidth - 1 : 0; + int *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--) { + int retval; + point_t nextpos = gfx_point(start.x + xl, start.y + yl); + + if ((retval = driver->draw_line(driver, start, nextpos, + color, line_mode, GFX_LINE_STYLE_NORMAL))) { + GFXERROR("Failed to draw partial stippled line (%d,%d) -- (%d,%d)\n", + GFX_PRINT_POINT(start), GFX_PRINT_POINT(nextpos)); + return retval; + } + *posvar += delta; + } + + if (length_left) { + int retval; + point_t nextpos; + + if (length_left > stepwidth) + length_left = stepwidth; + + if (xl) + xl = length_left; + else + if (yl) + yl = length_left; + + nextpos = gfx_point(start.x + xl, start.y + yl); + + if ((retval = driver->draw_line(driver, start, nextpos, color, line_mode, GFX_LINE_STYLE_NORMAL))) { + GFXERROR("Failed to draw partial stippled line (%d,%d) -- (%d,%d)\n", + GFX_PRINT_POINT(start), GFX_PRINT_POINT(nextpos)); + return retval; + } + } + + return GFX_OK; +} + + +static int +_gfxop_draw_line_clipped(gfx_state_t *state, point_t start, point_t end, gfx_color_t color, gfx_line_mode_t line_mode, + gfx_line_style_t line_style) +{ + int retval; + int skipone = (start.x ^ end.y) & 1; /* Used for simulated line stippling */ + + BASIC_CHECKS(GFX_FATAL); + REMOVE_POINTER; + + /* First, make sure that the line is normalized */ + if (start.y > end.y) { + point_t 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.xl) + || end.y >= (state->clip_zone.y + state->clip_zone.yl)) + if (point_clip(&start, &end, state->clip_zone, state->driver->mode->xfact - 1, + state->driver->mode->yfact - 1)) + return GFX_OK; /* Clipped off */ + + if (line_style == GFX_LINE_STYLE_STIPPLED) { + if (start.x != end.x && start.y != end.y) { + GFXWARN("Attempt to draw stippled line which is neither an hbar nor a vbar: (%d,%d) -- (%d,%d)\n", + GFX_PRINT_POINT(start), GFX_PRINT_POINT(end)); + return GFX_ERROR; + } + if (!(state->driver->capabilities & GFX_CAPABILITY_STIPPLED_LINES)) + return simulate_stippled_line_draw(state->driver, skipone, start, end, color, line_mode); + } + + if (line_mode == GFX_LINE_MODE_FINE + && !(state->driver->capabilities & GFX_CAPABILITY_FINE_LINES)) + line_mode = GFX_LINE_MODE_FAST; + + if ((retval = state->driver->draw_line(state->driver, start, end, color, line_mode, line_style))) { + GFXERROR("Failed to draw line (%d,%d) -- (%d,%d)\n", + GFX_PRINT_POINT(start), GFX_PRINT_POINT(end)); + return retval; + } + return GFX_OK; +} + +int +gfxop_draw_line(gfx_state_t *state, point_t start, point_t end, + gfx_color_t color, gfx_line_mode_t line_mode, + gfx_line_style_t line_style) +{ + int xfact, yfact; + + BASIC_CHECKS(GFX_FATAL); + _gfxop_add_dirty_x(state, gfx_rect(start.x, start.y, end.x - start.x, end.y - start.y)); + + xfact = state->driver->mode->xfact; + yfact = state->driver->mode->yfact; + + draw_line_to_control_map(state, start, end, color); + + _gfxop_scale_point(&start, state->driver->mode); + _gfxop_scale_point(&end, state->driver->mode); + + if (line_mode == GFX_LINE_MODE_FINE) { + start.x += xfact >> 1; + start.y += yfact >> 1; + + end.x += xfact >> 1; + end.y += yfact >> 1; + } + + return _gfxop_draw_line_clipped(state, start, end, color, line_mode, line_style); +} + +int +gfxop_draw_rectangle(gfx_state_t *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, + gfx_line_style_t line_style) +{ + int retval = 0; + int xfact, yfact; + int xunit, yunit; + int x, y, xl, yl; + point_t upper_left_u, upper_right_u, lower_left_u, lower_right_u; + point_t upper_left, upper_right, lower_left, lower_right; + + BASIC_CHECKS(GFX_FATAL); + REMOVE_POINTER; + + xfact = state->driver->mode->xfact; + yfact = state->driver->mode->yfact; + + if (line_mode == GFX_LINE_MODE_FINE + && state->driver->capabilities & GFX_CAPABILITY_FINE_LINES) { + xunit = yunit = 1; + xl = 1 + (rect.xl - 1) * xfact; + yl = 1 + (rect.yl - 1) * yfact; + x = rect.x * xfact + (xfact - 1); + y = rect.y * yfact + (yfact - 1); + } else { + xunit = xfact; + yunit = yfact; + xl = rect.xl * xfact; + yl = rect.yl * yfact; + x = rect.x * xfact; + y = rect.y * yfact; + } + + upper_left_u = gfx_point(rect.x, rect.y); + upper_right_u = gfx_point(rect.x + rect.xl, rect.y); + lower_left_u = gfx_point(rect.x, rect.y + rect.yl); + lower_right_u = gfx_point(rect.x + rect.xl, rect.y + rect.yl); + + upper_left = gfx_point(x, y); + upper_right = gfx_point(x + xl, y); + lower_left = gfx_point(x, y + yl); + lower_right = gfx_point(x + xl, y + yl); + +#define PARTIAL_LINE(pt1, pt2) \ + retval |= _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 + if (retval) { + GFXERROR("Failed to draw rectangle (%d,%d)+(%d,%d)\n", rect.x, rect.y, rect.xl, rect.yl); + return retval; + } + return GFX_OK; +} + + +#define COLOR_MIX(type, dist) ((color1.type * dist) + (color2.type * (1.0 - dist))) + + +int +gfxop_draw_box(gfx_state_t *state, rect_t box, gfx_color_t color1, gfx_color_t color2, + gfx_box_shade_t shade_type) +{ + gfx_driver_t *drv = state->driver; + int reverse = 0; /* switch color1 and color2 */ + float mod_offset = 0.0, mod_breadth = 1.0; /* 0.0 to 1.0: Color adjustment */ + gfx_rectangle_fill_t driver_shade_type; + rect_t new_box; + gfx_color_t draw_color1, draw_color2 = {{0, 0, 0}, 0, 0, 0, 0}; + + BASIC_CHECKS(GFX_FATAL); + REMOVE_POINTER; + + if (PALETTE_MODE || !(state->driver->capabilities & GFX_CAPABILITY_SHADING)) + 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->mode); + + if (!(color1.mask & (GFX_MASK_VISUAL | GFX_MASK_PRIORITY))) + return GFX_OK; /* So long... */ + + if (box.xl <= 1 || box.yl <= 1) { + GFXDEBUG("Attempt to draw box with size %dx%d\n", box.xl, box.yl); + return GFX_OK; + } + + memcpy(&new_box, &box, sizeof(rect_t)); + if (_gfxop_clip(&new_box, state->clip_zone)) + return GFX_OK; + + 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.xl * 1.0)); + mod_breadth = (float) ((new_box.xl * 1.0) / (box.xl * 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.yl * 1.0)); + mod_breadth = (float) ((new_box.yl * 1.0) / (box.yl * 1.0)); + break; + + default: + GFXERROR("Invalid shade type: %d\n", shade_type); + return GFX_ERROR; + } + + + 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) + return drv->draw_filled_rect(drv, new_box, color1, color1, GFX_SHADE_FLAT); + else { + if (PALETTE_MODE) { + GFXWARN("Attempting to draw shaded box in palette mode!\n"); + return GFX_ERROR; + } + + draw_color1.mask = draw_color2.mask = color1.mask; + draw_color1.priority = draw_color2.priority = color1.priority; + + if (draw_color1.mask & GFX_MASK_VISUAL) { + draw_color1.visual.r = (guint8) COLOR_MIX(visual.r, mod_offset); + draw_color1.visual.g = (guint8) COLOR_MIX(visual.g, mod_offset); + draw_color1.visual.b = (guint8) COLOR_MIX(visual.b, mod_offset); + draw_color1.alpha = (guint8) COLOR_MIX(alpha, mod_offset); + + mod_offset += mod_breadth; + + draw_color2.visual.r = (guint8) COLOR_MIX(visual.r, mod_offset); + draw_color2.visual.g = (guint8) COLOR_MIX(visual.g, mod_offset); + draw_color2.visual.b = (guint8) COLOR_MIX(visual.b, mod_offset); + draw_color2.alpha = (guint8) COLOR_MIX(alpha, mod_offset); + } + if (reverse) + return drv->draw_filled_rect(drv, new_box, draw_color2, draw_color1, driver_shade_type); + else + return drv->draw_filled_rect(drv, new_box, draw_color1, draw_color2, driver_shade_type); + } +} +#undef COLOR_MIX + + +int +gfxop_fill_box(gfx_state_t *state, rect_t box, gfx_color_t color) +{ + return gfxop_draw_box(state, box, color, color, GFX_BOX_SHADE_FLAT); +} + + + +static int +_gfxop_buffer_propagate_box(gfx_state_t *state, rect_t box, gfx_buffer_t buffer) +{ + int error; + + if (_gfxop_clip(&box, gfx_rect(0, 0, 320 * state->driver->mode->xfact, 200 * state->driver->mode->yfact))) + return GFX_OK; + + if ((error = state->driver->update(state->driver, box, gfx_point(box.x, box.y), buffer))) { + GFXERROR("Error occured while updating region (%d,%d,%d,%d) in buffer %d\n", + box.x, box.y, box.xl, box.yl, buffer); + return error; + } + return GFX_OK; +} + +extern int sci0_palette; +int +gfxop_clear_box(gfx_state_t *state, rect_t box) +{ + BASIC_CHECKS(GFX_FATAL); + REMOVE_POINTER; + _gfxop_add_dirty(state, box); + DDIRTY(stderr, "[] clearing box %d %d %d %d\n", GFX_PRINT_RECT(box)); + if (box.x == 29 + && box.y == 77 + && (sci0_palette == 1)) { + BREAKPOINT(); + } + + _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->mode); + + return _gfxop_buffer_propagate_box(state, box, GFX_BUFFER_BACK); +} + +int +gfxop_set_visible_map(gfx_state_t *state, gfx_map_mask_t visible_map) +{ + switch (visible_map) { + + case GFX_MASK_VISUAL: + state->fullscreen_override = NULL; + if (visible_map != state->visible_map) { + rect_t rect = gfx_rect(0, 0, 320, 200); + gfxop_clear_box(state, rect); + gfxop_update_box(state, rect); + } + break; + + case GFX_MASK_PRIORITY: + state->fullscreen_override = state->priority_map; + break; + + case GFX_MASK_CONTROL: + state->fullscreen_override = state->control_map; + break; + + default: + fprintf(stderr, "Invalid display map %d selected!\n", visible_map); + return GFX_ERROR; + } + + state->visible_map = visible_map; + return GFX_OK; +} + +int +gfxop_update(gfx_state_t *state) +{ + int retval; + + BASIC_CHECKS(GFX_FATAL); + DRAW_POINTER; + + retval = _gfxop_clear_dirty_rec(state, state->dirty_rects); + + state->dirty_rects = NULL; + + if (state->fullscreen_override) { + /* We've been asked to re-draw the active full-screen image, essentially. */ + rect_t rect = gfx_rect(0, 0, 320, 200); + gfx_xlate_pixmap(state->fullscreen_override, state->driver->mode, GFX_XLATE_FILTER_NONE); + gfxop_draw_pixmap(state, state->fullscreen_override, rect, gfx_point(0,0)); + retval |= _gfxop_update_box(state, rect); + } + + if (retval) { + GFXERROR("Clearing the dirty rectangles failed!\n"); + } + + if (state->tag_mode) { + /* This usually happens after a pic and all resources have been drawn */ + gfxr_free_tagged_resources(state->driver, state->resstate); + state->tag_mode = 0; + } + + return retval; +} + + +int +gfxop_update_box(gfx_state_t *state, rect_t box) +{ + BASIC_CHECKS(GFX_FATAL); + DRAW_POINTER; + + if (state->disable_dirty) + _gfxop_update_box(state, box); + else + _gfxop_add_dirty(state, box); + + return gfxop_update(state); +} + +int +gfxop_enable_dirty_frames(gfx_state_t *state) +{ + BASIC_CHECKS(GFX_ERROR); + state->disable_dirty = 0; + + return GFX_OK; +} + +int +gfxop_disable_dirty_frames(gfx_state_t *state) +{ + BASIC_CHECKS(GFX_ERROR); + + state->disable_dirty = 1; + + return GFX_OK; +} + + +/**********************/ +/* Pointer and IO ops */ +/**********************/ + +#define SECONDS_OF_DAY (24*60*60) +#define MILLION 1000000 +/* Sure, this may seem silly, but it's too easy to miss a zero...) */ + + +#define GFXOP_FULL_POINTER_REFRESH if (_gfxop_full_pointer_refresh(state)) { GFXERROR("Failed to do full pointer refresh!\n"); return GFX_ERROR; } + +static int +_gfxop_full_pointer_refresh(gfx_state_t *state) +{ + rect_t pointer_bounds; + rect_t old_pointer_bounds = {0, 0, 0, 0}; + int new_x = state->driver->pointer_x; + int new_y = state->driver->pointer_y; + + if (new_x != state->old_pointer_draw_pos.x + || new_y != state->old_pointer_draw_pos.y) { + point_t pp_new = gfx_point(new_x / state->driver->mode->xfact, + new_y / state->driver->mode->yfact); + + if (!_gfxop_get_pointer_bounds(state, &pointer_bounds)) { + memcpy(&old_pointer_bounds, &(state->pointer_bg_zone), sizeof(rect_t)); + REMOVE_POINTER; + state->pointer_pos = pp_new; + + DRAW_POINTER; + if (_gfxop_buffer_propagate_box(state, pointer_bounds, GFX_BUFFER_FRONT)) return 1; + if (_gfxop_buffer_propagate_box(state, old_pointer_bounds, GFX_BUFFER_FRONT)) return 1; + + state->old_pointer_draw_pos = gfx_point(new_x, new_y); + } else + state->pointer_pos = pp_new; + } + return 0; +} + +int +gfxop_usleep(gfx_state_t *state, long usecs) +{ + long time, utime; + long wakeup_time, wakeup_utime; + long add_seconds; + int retval = GFX_OK; + + BASIC_CHECKS(GFX_FATAL); + + sci_gettime(&wakeup_time, &wakeup_utime); + wakeup_utime += usecs; + + add_seconds = (wakeup_utime / MILLION); + wakeup_time += add_seconds; + wakeup_utime -= (MILLION * add_seconds); + + do { + GFXOP_FULL_POINTER_REFRESH; + sci_gettime(&time, &utime); + usecs = (wakeup_time - time) * MILLION + wakeup_utime - utime; + } while ((usecs > 0) && !(retval = state->driver->usec_sleep(state->driver, usecs))); + + if (retval) { + GFXWARN("Waiting failed\n"); + } + + return retval; +} + + +int +_gfxop_set_pointer(gfx_state_t *state, gfx_pixmap_t *pxm) +{ + rect_t old_pointer_bounds = {0}; + rect_t pointer_bounds = {0}; + int retval = -1; + int draw_old; + int draw_new = 0; + + BASIC_CHECKS(GFX_FATAL); + + draw_old = state->mouse_pointer != NULL; + + if (state->driver->capabilities & GFX_CAPABILITY_MOUSE_POINTER) { + + if (draw_old && state->mouse_pointer->colors_nr > 2) + draw_old = state->driver->capabilities & GFX_CAPABILITY_COLOR_MOUSE_POINTER; + + if (!draw_old + && state->mouse_pointer + && (state->driver->capabilities & GFX_CAPABILITY_POINTER_PIXMAP_REGISTRY)) + if ((retval = state->driver->unregister_pixmap(state->driver, state->mouse_pointer))){ + GFXERROR("Pointer un-registration failed!\n"); + return retval; + } + + if (pxm == NULL + || (state->driver->capabilities & GFX_CAPABILITY_COLOR_MOUSE_POINTER) + || pxm->colors_nr <= 2) { + if (state->driver->capabilities & GFX_CAPABILITY_POINTER_PIXMAP_REGISTRY) { + if ((pxm) && (retval = state->driver->register_pixmap(state->driver, pxm))) { + GFXERROR("Pixmap-registering a new mouse pointer failed!\n"); + return retval; + } + } + draw_new = 0; + state->driver->set_pointer(state->driver, pxm); + state->mouse_pointer_in_hw = 1; + } else { + draw_new = 1; + state->mouse_pointer_in_hw = 0; + } + + } else draw_new = 1; + + if (!state->mouse_pointer_in_hw) + draw_old = state->mouse_pointer != NULL; + + + if (draw_old) { + _gfxop_get_pointer_bounds(state, &old_pointer_bounds); + REMOVE_POINTER; + } + + + if (draw_new) { + state->mouse_pointer = pxm; + DRAW_POINTER; + _gfxop_get_pointer_bounds(state, &pointer_bounds); + } + + if (draw_new && state->mouse_pointer) + _gfxop_buffer_propagate_box(state, pointer_bounds, GFX_BUFFER_FRONT); + + if (draw_old) + _gfxop_buffer_propagate_box(state, old_pointer_bounds, GFX_BUFFER_FRONT); + + if (state->mouse_pointer == NULL) + state->mouse_pointer_visible = 0; + else if (!state->mouse_pointer_visible) + state->mouse_pointer_visible = 1; + /* else don't touch it, as it might be VISIBLE_BUT_CLIPPED! */ + + return GFX_OK; +} + + +int +gfxop_set_pointer_cursor(gfx_state_t *state, int nr) +{ + gfx_pixmap_t *new_pointer = NULL; + + BASIC_CHECKS(GFX_FATAL); + + if (nr == GFXOP_NO_POINTER) + new_pointer = NULL; + else { + new_pointer = gfxr_get_cursor(state->resstate, nr); + + if (!new_pointer) { + GFXWARN("Attempt to set invalid pointer #%d\n", nr); + } + } + + return _gfxop_set_pointer(state, new_pointer); +} + + +int +gfxop_set_pointer_view(gfx_state_t *state, int nr, int loop, int cel, point_t *hotspot) +{ + int real_loop = loop; + int real_cel = cel; + gfx_pixmap_t *new_pointer = NULL; + + BASIC_CHECKS(GFX_FATAL); + + new_pointer = _gfxr_get_cel(state, nr, &real_loop, &real_cel, + 0); /* FIXME: For now, don't palettize pointers */ + + if (hotspot) + { + new_pointer->xoffset = hotspot->x; + new_pointer->yoffset = hotspot->y; + } + + if (!new_pointer) { + GFXWARN("Attempt to set invalid pointer #%d\n", nr); + return GFX_ERROR; + } else + { + if (real_loop != loop || real_cel != cel) { + GFXDEBUG("Changed loop/cel from %d/%d to %d/%d in view %d\n", + loop, cel, real_loop, real_cel, nr); + } + return _gfxop_set_pointer(state, new_pointer); + } +} + +int +gfxop_set_pointer_position(gfx_state_t *state, point_t pos) +{ + BASIC_CHECKS(GFX_ERROR); + + state->pointer_pos = pos; + + if (pos.x > 320 || pos.y > 200) + { + GFXWARN("Attempt to place pointer at invalid coordinates (%d, %d)\n", pos.x, pos.y); + return 0; /* Not fatal */ + } + + state->driver->pointer_x = pos.x * state->driver->mode->xfact; + state->driver->pointer_y = pos.y * state->driver->mode->yfact; + + GFXOP_FULL_POINTER_REFRESH; + return 0; +} + +#define SCANCODE_ROWS_NR 3 + +struct scancode_row { + int offset; + const char *keys; +} scancode_rows[SCANCODE_ROWS_NR] = { + {0x10, "QWERTYUIOP[]"}, + {0x1e, "ASDFGHJKL;'\\"}, + {0x2c, "ZXCVBNM,./"} +}; + +static int +_gfxop_scancode(int ch) + /* Calculates a PC keyboard scancode from a character */ +{ + int row; + int c = toupper((char)ch); + + for (row = 0; row < SCANCODE_ROWS_NR; row++) { + const char *keys = scancode_rows[row].keys; + int offset = scancode_rows[row].offset; + + while (*keys) { + if (*keys == c) + return offset << 8; + + offset++; + keys++; + } + } + + return ch; /* not found */ +} + +/* static */ int +_gfxop_shiftify(int c) +{ + char shifted_numbers[] = ")!@#$%^&*("; + + if (c < 256) + { + c = toupper((char)c); + + if (c >= 'A' && c <= 'Z') + return c; + + if (c >= '0' && c <= '9') + return shifted_numbers[c-'0']; + + switch (c) { + case SCI_K_TAB: return SCI_K_SHIFT_TAB; + case ']': return '}'; + case '[': return '{'; + case '`': return '~'; + case '-': return '_'; + case '=': return '+'; + case ';': return ':'; + case '\'': return '"'; + case '\\': return '|'; + case ',': return '<'; + case '.': return '>'; + case '/': return '?'; + default: return c; /* No match */ + } + } + + switch (c) + { + case SCI_K_F1 : return SCI_K_SHIFT_F1; + case SCI_K_F2 : return SCI_K_SHIFT_F2; + case SCI_K_F3 : return SCI_K_SHIFT_F3; + case SCI_K_F4 : return SCI_K_SHIFT_F4; + case SCI_K_F5 : return SCI_K_SHIFT_F5; + case SCI_K_F6 : return SCI_K_SHIFT_F6; + case SCI_K_F7 : return SCI_K_SHIFT_F7; + case SCI_K_F8 : return SCI_K_SHIFT_F8; + case SCI_K_F9 : return SCI_K_SHIFT_F9; + case SCI_K_F10 : return SCI_K_SHIFT_F10; + } + + return c; +} + +static int +_gfxop_numlockify(int c) +{ + switch (c) { + case SCI_K_DELETE: return '.'; + case SCI_K_INSERT: return '0'; + case SCI_K_END: return '1'; + case SCI_K_DOWN: return '2'; + case SCI_K_PGDOWN: return '3'; + case SCI_K_LEFT: return '4'; + case SCI_K_CENTER: return '5'; + case SCI_K_RIGHT: return '6'; + case SCI_K_HOME: return '7'; + case SCI_K_UP: return '8'; + case SCI_K_PGUP: return '9'; + default: return c; /* Unchanged */ + } +} + + +sci_event_t +gfxop_get_event(gfx_state_t *state, unsigned int mask) +{ + sci_event_t error_event = { SCI_EVT_ERROR, 0, 0 }; + sci_event_t event; + gfx_input_event_t **seekerp = &(state->events); + + BASIC_CHECKS(error_event); + if (_gfxop_remove_pointer(state)) { + GFXERROR("Failed to remove pointer before processing event!\n"); + } + + while (*seekerp && !((*seekerp)->event.type & mask)) + seekerp = &((*seekerp)->next); + + if (*seekerp) { + gfx_input_event_t *goner = *seekerp; + event = goner->event; + *seekerp = goner->next; + free(goner); + } else { + event.type = 0; + + if (!(mask & SCI_EVT_NONBLOCK)) + { + do { + if (event.type) { + *seekerp = (gfx_input_event_t*)sci_malloc(sizeof(gfx_input_event_t)); + (*seekerp)->next = NULL; + + event.data = (char) (event.data); + /* Clip illegal bits */ + + (*seekerp)->event = event; + seekerp = &((*seekerp)->next); + } + event = state->driver->get_event(state->driver); + + } while (event.type && !(event.type & mask)); + } + } + + if (_gfxop_full_pointer_refresh(state)) { + GFXERROR("Failed to update the mouse pointer!\n"); + return error_event; + } + + if (event.type == SCI_EVT_KEYBOARD + && !(state->driver->capabilities & GFX_CAPABILITY_KEYTRANSLATE)) { + /* Do we still have to translate the key? */ + + event.character = event.data; + + /* Scancodify if appropriate */ + if (event.buckybits & SCI_EVM_ALT) + event.character = _gfxop_scancode(event.character); + + /* Shift if appropriate */ + else if (((event.buckybits & (SCI_EVM_RSHIFT | SCI_EVM_LSHIFT)) + && !(event.buckybits & SCI_EVM_CAPSLOCK)) + || + (!(event.buckybits & (SCI_EVM_RSHIFT | SCI_EVM_LSHIFT)) + && (event.buckybits & SCI_EVM_CAPSLOCK))) + event.character = _gfxop_shiftify(event.character); + + /* Numlockify if appropriate */ + else if (event.buckybits & SCI_EVM_NUMLOCK) + event.data = _gfxop_numlockify(event.data); + } + + return event; +} + + +/*******************/ +/* View operations */ +/*******************/ + +int +gfxop_lookup_view_get_loops(gfx_state_t *state, int nr) +{ + int loop = 0, cel = 0; + gfxr_view_t *view = NULL; + + BASIC_CHECKS(GFX_ERROR); + + view = gfxr_get_view(state->resstate, nr, &loop, &cel, 0); + + if (!view) { + GFXWARN("Attempt to retreive number of loops from invalid view %d\n", nr); + return 0; + } + + return view->loops_nr; +} + + +int +gfxop_lookup_view_get_cels(gfx_state_t *state, int nr, int loop) +{ + int real_loop = loop, cel = 0; + gfxr_view_t *view = NULL; + + BASIC_CHECKS(GFX_ERROR); + + view = gfxr_get_view(state->resstate, nr, &real_loop, &cel, 0); + + if (!view) { + GFXWARN("Attempt to retreive number of cels from invalid/broken view %d\n", nr); + return 0; + } else if (real_loop != loop) { + GFXWARN("Loop number was corrected from %d to %d in view %d\n", loop, real_loop, nr); + } + + return view->loops[real_loop].cels_nr; +} + + +int +gfxop_check_cel(gfx_state_t *state, int nr, int *loop, int *cel) +{ + BASIC_CHECKS(GFX_ERROR); + + if (!gfxr_get_view(state->resstate, nr, loop, cel, 0)) { + GFXWARN("Attempt to verify loop/cel values for invalid view %d\n", nr); + return GFX_ERROR; + } + + return GFX_OK; +} + +int +gfxop_overflow_cel(gfx_state_t *state, int nr, int *loop, int *cel) +{ + int loop_v = *loop; + int cel_v = *cel; + BASIC_CHECKS(GFX_ERROR); + + if (!gfxr_get_view(state->resstate, nr, &loop_v, &cel_v, 0)) { + GFXWARN("Attempt to verify loop/cel values for invalid view %d\n", nr); + return GFX_ERROR; + } + + if (loop_v != *loop) + *loop = 0; + + if (loop_v != *loop + || cel_v != *cel) + *cel = 0; + + return GFX_OK; +} + + +int +gfxop_get_cel_parameters(gfx_state_t *state, int nr, int loop, int cel, + int *width, int *height, point_t *offset) +{ + gfxr_view_t *view = NULL; + gfx_pixmap_t *pxm = NULL; + BASIC_CHECKS(GFX_ERROR); + + if (!(view = gfxr_get_view(state->resstate, nr, &loop, &cel, 0))) { + GFXWARN("Attempt to get cel parameters for invalid view %d\n", nr); + return GFX_ERROR; + } + + pxm = view->loops[loop].cels[cel]; + *width = pxm->index_xl; + *height = pxm->index_yl; + offset->x = pxm->xoffset; + offset->y = pxm->yoffset; + + return GFX_OK; +} + + +static int +_gfxop_draw_cel_buffer(gfx_state_t *state, int nr, int loop, int cel, + point_t 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; + BASIC_CHECKS(GFX_FATAL); + + if (!(view = gfxr_get_view(state->resstate, nr, &loop, &cel, palette))) { + GFXWARN("Attempt to draw loop/cel %d/%d in invalid view %d\n", loop, cel, nr); + return GFX_ERROR; + } + pxm = view->loops[loop].cels[cel]; + + old_x = pos.x -= pxm->xoffset; + old_y = pos.y -= pxm->yoffset; + + pos.x *= state->driver->mode->xfact; + pos.y *= state->driver->mode->yfact; + + if (!static_buf) + _gfxop_add_dirty(state, gfx_rect(old_x, old_y, pxm->index_xl, pxm->index_yl)); + + return _gfxop_draw_pixmap(state->driver, pxm, priority, control, + gfx_rect(0, 0, pxm->xl, pxm->yl), + gfx_rect(pos.x, pos.y, pxm->xl, pxm->yl), + state->clip_zone, + static_buf , state->control_map, + static_buf + ? state->static_priority_map + : state->priority_map); +} + + +int +gfxop_draw_cel(gfx_state_t *state, int nr, int loop, int cel, point_t pos, + gfx_color_t color, int palette) +{ + return _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 0, palette); +} + + +int +gfxop_draw_cel_static(gfx_state_t *state, int nr, int loop, int cel, point_t pos, + gfx_color_t color, int palette) +{ + int retval; + rect_t oldclip = state->clip_zone; + + state->clip_zone = gfx_rect_fullscreen; + _gfxop_scale_rect(&(state->clip_zone), state->driver->mode); + retval = 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; + + return retval; +} + + +int +gfxop_draw_cel_static_clipped(gfx_state_t *state, int nr, int loop, int cel, + point_t pos, gfx_color_t color, int palette) +{ + return _gfxop_draw_cel_buffer(state, nr, loop, cel, pos, color, 1, palette); +} + + +/******************/ +/* Pic operations */ +/******************/ + +static int +_gfxop_set_pic(gfx_state_t *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)); + + _gfxop_install_pixmap(state->driver, state->pic->visual_map); + + if (state->options->pic0_unscaled) + state->pic->priority_map = gfx_pixmap_scale_index_data(state->pic->priority_map, state->driver->mode); + return state->driver->set_static_buffer(state->driver, state->pic->visual_map, state->pic->priority_map); +} + + +void * +gfxop_get_pic_metainfo(gfx_state_t *state) +{ + return (state->pic)? state->pic->internal : NULL; +} + + +int +gfxop_new_pic(gfx_state_t *state, int nr, int flags, int default_palette) +{ + BASIC_CHECKS(GFX_FATAL); + + gfxr_tag_resources(state->resstate); + state->tag_mode = 1; + state->palette_nr = default_palette; + + state->pic = gfxr_get_pic(state->resstate, nr, GFX_MASK_VISUAL, flags, default_palette, 1); + + if (state->driver->mode->xfact == 1 && state->driver->mode->yfact == 1) + state->pic_unscaled = state->pic; + else + state->pic_unscaled = gfxr_get_pic(state->resstate, nr, GFX_MASK_VISUAL, flags, default_palette, 0); + + if (!state->pic || !state->pic_unscaled) { + GFXERROR("Could not retreive background pic %d!\n", nr); + if (state->pic) { + GFXERROR(" -- Inconsistency: scaled pic _was_ retreived!\n"); + } + + if (state->pic_unscaled) { + GFXERROR(" -- Inconsistency: unscaled pic _was_ retreived!\n"); + } + + state->pic = state->pic_unscaled = NULL; + return GFX_ERROR; + } + + state->pic_nr = nr; + + return _gfxop_set_pic(state); +} + + +int +gfxop_add_to_pic(gfx_state_t *state, int nr, int flags, int default_palette) +{ + BASIC_CHECKS(GFX_FATAL); + + if (!state->pic) { + GFXERROR("Attempt to add to pic with no pic active!\n"); + return GFX_ERROR; + } + + if (!(state->pic = gfxr_add_to_pic(state->resstate, state->pic_nr, nr, + GFX_MASK_VISUAL, flags, state->palette_nr, default_palette, 1))) { + GFXERROR("Could not add pic #%d to pic #%d!\n", state->pic_nr, nr); + return GFX_ERROR; + } + state->pic_unscaled = gfxr_add_to_pic(state->resstate, state->pic_nr, nr, + GFX_MASK_VISUAL, flags, + state->palette_nr, + default_palette, 1); + + return _gfxop_set_pic(state); +} + + +/*******************/ +/* Text operations */ +/*******************/ + + +int +gfxop_get_font_height(gfx_state_t *state, int font_nr) +{ + gfx_bitmap_font_t *font; + BASIC_CHECKS(GFX_FATAL); + + font = gfxr_get_font(state->resstate, font_nr, 0); + if (!font) + return GFX_ERROR; + + return font->line_height; +} + +int +gfxop_get_text_params(gfx_state_t *state, int font_nr, const char *text, + int maxwidth, int *width, int *height, int text_flags, + int *lines_nr, int *lineheight, int *lastline_width) +{ + text_fragment_t *textsplits; + gfx_bitmap_font_t *font; + + BASIC_CHECKS(GFX_FATAL); + + font = gfxr_get_font(state->resstate, font_nr, 0); + + if (!font) { + GFXERROR("Attempt to calculate text size with invalid font #%d\n", font_nr); + *width = *height = 0; + return GFX_ERROR; + } + + textsplits = gfxr_font_calculate_size(font, maxwidth, text, width, + height, lines_nr, + lineheight, lastline_width, + (state->options->workarounds & GFX_WORKAROUND_WHITESPACE_COUNT) + | text_flags); + + + if (!textsplits) { + GFXERROR("Could not calculate text size!"); + *width = *height = 0; + return GFX_ERROR; + } + + free(textsplits); + return GFX_OK; +} + + +#define COL_XLATE(des,src) \ + des = src.visual; /* The new gfx_color_t structure makes things a lot easier :-) */ /* \ + if (gfxop_set_color(state, &src, \ + src.visual.r, \ + src.visual.g, \ + src.visual.b, \ + src.alpha, \ + src.priority, \ + src.control)) \ + { \ + GFXERROR("Unable to set up colors"); \ + return NULL; \ + } +*/ + +gfx_text_handle_t * +gfxop_new_text(gfx_state_t *state, int font_nr, char *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) +{ + gfx_text_handle_t *handle = {0}; + gfx_bitmap_font_t *font = {0}; + int i; + gfx_pixmap_color_t pxm_col1, pxm_col2, pxm_colbg= {0}; + BASIC_CHECKS(NULL); + + COL_XLATE(pxm_col1, color1); + COL_XLATE(pxm_col2, color2); + COL_XLATE(pxm_colbg, bg_color); + + font = gfxr_get_font(state->resstate, font_nr, 0); + + if (!font) { + GFXERROR("Attempt to draw text with invalid font #%d\n", font_nr); + return NULL; + } + + handle = (gfx_text_handle_t*)sci_malloc(sizeof(gfx_text_handle_t)); + + handle->text = (char*)sci_malloc(strlen(text) + 1); + strcpy(handle->text, text); + handle->halign = halign; + handle->valign = valign; + handle->line_height = font->line_height; + + handle->lines = + gfxr_font_calculate_size(font, maxwidth, handle->text, &(handle->width), &(handle->height), + &(handle->lines_nr), + NULL, NULL, + ((state->options->workarounds & GFX_WORKAROUND_WHITESPACE_COUNT)? + GFXR_FONT_FLAG_COUNT_WHITESPACE : 0) + | flags); + + if (!handle->lines) { + free(handle->text); + free(handle); + GFXERROR("Could not calculate text parameters in font #%d\n", font_nr); + return NULL; + } + + + if (flags & GFXR_FONT_FLAG_NO_NEWLINES) { + handle->lines_nr = 1; + handle->lines->length = strlen(text); + } + + handle->text_pixmaps = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * handle->lines_nr); + + for (i = 0; i < handle->lines_nr; 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)? &pxm_col1 : NULL, + (color2.mask & GFX_MASK_VISUAL)? &pxm_col2 : NULL, + (bg_color.mask & GFX_MASK_VISUAL)? &pxm_colbg : NULL); + + if (!handle->text_pixmaps[i]) { + int j; + + for (j = 0; j < i; j++) + gfx_free_pixmap(state->driver, handle->text_pixmaps[j]); + sci_free(handle->text_pixmaps); + sci_free(handle->text); + sci_free(handle->lines); + GFXERROR("Failed to draw text pixmap for line %d/%d\n", i, handle->lines_nr); + sci_free(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; +} + + +int +gfxop_free_text(gfx_state_t *state, gfx_text_handle_t *handle) +{ + int j; + + BASIC_CHECKS(GFX_ERROR); + + if (handle->text_pixmaps) { + for (j = 0; j < handle->lines_nr; j++) + gfx_free_pixmap(state->driver, handle->text_pixmaps[j]); + free(handle->text_pixmaps); + } + + free(handle->text); + free(handle->lines); + free(handle); + return GFX_OK; +} + + +int +gfxop_draw_text(gfx_state_t *state, gfx_text_handle_t *handle, rect_t zone) +{ + int line_height; + rect_t pos; + int i; + BASIC_CHECKS(GFX_FATAL); + REMOVE_POINTER; + + if (!handle) { + GFXERROR("Attempt to draw text with NULL handle!\n"); + return GFX_ERROR; + } + + if (!handle->lines_nr) { + GFXDEBUG("Skipping draw_text operation because number of lines is zero\n"); + return GFX_OK; + } + + _gfxop_scale_rect(&zone, state->driver->mode); + + line_height = handle->line_height * state->driver->mode->yfact; + + pos.y = zone.y; + + switch (handle->valign) { + + case ALIGN_TOP: + break; + + case ALIGN_CENTER: + pos.y += (zone.yl - (line_height * handle->lines_nr)) >> 1; + break; + + case ALIGN_BOTTOM: + pos.y += (zone.yl - (line_height * handle->lines_nr)); + break; + + default: + GFXERROR("Invalid vertical alignment %d!\n", handle->valign); + return GFX_FATAL; /* Internal error... */ + } + + for (i = 0; i < handle->lines_nr; i++) { + + gfx_pixmap_t *pxm = handle->text_pixmaps[i]; + + if (!pxm->data) { + gfx_xlate_pixmap(pxm, state->driver->mode, state->options->text_xlate_filter); + gfxr_endianness_adjust(pxm, state->driver->mode); /* FIXME: resmgr layer! */ + } + if (!pxm) { + GFXERROR("Could not find text pixmap %d/%d\n", i, handle->lines_nr); + return GFX_ERROR; + } + + pos.x = zone.x; + + switch (handle->halign) { + + case ALIGN_LEFT: + break; + + case ALIGN_CENTER: + pos.x += (zone.xl - pxm->xl) >> 1; + break; + + case ALIGN_RIGHT: + pos.x += (zone.xl - pxm->xl); + break; + + default: + GFXERROR("Invalid vertical alignment %d!\n", handle->valign); + return GFX_FATAL; /* Internal error... */ + } + + pos.xl = pxm->xl; + pos.yl = pxm->yl; + + _gfxop_add_dirty(state, pos); + + _gfxop_draw_pixmap(state->driver, pxm, handle->priority, handle->control, + gfx_rect(0, 0, pxm->xl, pxm->yl), pos, state->clip_zone, 0, + state->control_map, state->priority_map); + + pos.y += line_height; + } + + return GFX_OK; +} + + +gfx_pixmap_t * +gfxop_grab_pixmap(gfx_state_t *state, rect_t area) +{ + gfx_pixmap_t *pixmap = NULL; + rect_t resultzone; /* Ignored for this application */ + BASIC_CHECKS(NULL); + if (_gfxop_remove_pointer(state)) { + GFXERROR("Could not remove pointer!\n"); + return NULL; + } + + _gfxop_scale_rect(&area, state->driver->mode); + if (_gfxop_grab_pixmap(state, &pixmap, area.x, area.y, area.xl, area.yl, 0, &resultzone)) + return NULL; /* area CUT the visual screen had a null or negative size */ + + pixmap->flags |= GFX_PIXMAP_FLAG_PALETTE_SET | GFX_PIXMAP_FLAG_DONT_UNALLOCATE_PALETTE; + + return pixmap; +} + +int +gfxop_draw_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm, rect_t zone, point_t pos) +{ + rect_t target; + BASIC_CHECKS(GFX_ERROR); + + if (!pxm) { + GFXERROR("Attempt to draw NULL pixmap!\n"); + return GFX_ERROR; + } + + REMOVE_POINTER; + + target = gfx_rect(pos.x, pos.y, zone.xl, zone.yl); + + _gfxop_add_dirty(state, target); + + if (!pxm) { + GFXERROR("Attempt to draw_pixmap with pxm=NULL\n"); + return GFX_ERROR; + } + + _gfxop_scale_rect(&zone, state->driver->mode); + _gfxop_scale_rect(&target, state->driver->mode); + + return _gfxop_draw_pixmap(state->driver, pxm, -1, -1, zone, target, + gfx_rect(0, 0, 320*state->driver->mode->xfact, + 200*state->driver->mode->yfact), 0, NULL, NULL); +} + +int +gfxop_free_pixmap(gfx_state_t *state, gfx_pixmap_t *pxm) +{ + BASIC_CHECKS(GFX_ERROR); + gfx_free_pixmap(state->driver, pxm); + return GFX_OK; +} + diff --git a/engines/sci/gfx/resmgr.c b/engines/sci/gfx/resmgr.c new file mode 100644 index 0000000000..2a525f675f --- /dev/null +++ b/engines/sci/gfx/resmgr.c @@ -0,0 +1,708 @@ +/*************************************************************************** + resmgr.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Resource manager core part */ + + +#include <gfx_resource.h> +#include <gfx_tools.h> +#include <gfx_driver.h> +#include <gfx_resmgr.h> +#include <gfx_state_internal.h> + +#undef TIME_PICDRAWING + +/* Invalid hash mode: Used to invalidate modified pics */ +#define MODE_INVALID -1 + +struct param_struct { + int args[4]; + gfx_driver_t *driver; +}; + + +gfx_resstate_t * +gfxr_new_resource_manager(int version, gfx_options_t *options, + gfx_driver_t *driver, void *misc_payload) +{ + gfx_resstate_t *state = (gfx_resstate_t*)sci_malloc(sizeof(gfx_resstate_t)); + int ii; + + state->version = version; + state->options = options; + state->driver = driver; + state->misc_payload = misc_payload; + + state->tag_lock_counter = state->lock_counter = 0; + for (ii = 0; ii < GFX_RESOURCE_TYPES_NR; ii++) { + gfx_resource_type_t i = (gfx_resource_type_t) ii; + sbtree_t *tree; + int entries_nr; + int *resources = gfxr_interpreter_get_resources(state, i, version, + &entries_nr, misc_payload); + + if (!resources) + state->resource_trees[i] = NULL; + else { + tree = sbtree_new(entries_nr, resources); + if (!tree) { + GFXWARN("Failed to allocate tree for %d entries of resource type %d!\n", entries_nr, i); + } + state->resource_trees[i] = tree; + free(resources); + } + } + return state; +} + +#define FREEALL(freecmd, type) \ + if (resource->scaled_data.type) \ + freecmd(driver, resource->scaled_data.type); \ + resource->scaled_data.type = NULL; \ + if (resource->unscaled_data.type) \ + freecmd(driver, resource->unscaled_data.type); \ + resource->unscaled_data.type = NULL; + +#define FREEALL_SIMPLE(freecmd, type) \ + if (resource->scaled_data.type) \ + freecmd(resource->scaled_data.type); \ + resource->scaled_data.type = NULL; \ + if (resource->unscaled_data.type) \ + freecmd(resource->unscaled_data.type); \ + resource->unscaled_data.type = NULL; + + +void +gfxr_free_resource(gfx_driver_t *driver, gfx_resource_t *resource, int type) +{ + if (!resource) + return; + + switch (type) { + + case GFX_RESOURCE_TYPE_VIEW: + FREEALL(gfxr_free_view, view); + break; + + case GFX_RESOURCE_TYPE_PIC: + FREEALL(gfxr_free_pic, pic); + break; + + case GFX_RESOURCE_TYPE_FONT: + FREEALL_SIMPLE(gfxr_free_font, font); + break; + + case GFX_RESOURCE_TYPE_CURSOR: + FREEALL(gfx_free_pixmap, pointer); + break; + + default: + GFXWARN("Attempt to free invalid resource type %d\n", type); + } + + free(resource); +} + +#undef FREECMD + + +void * +gfxr_sbtree_free_func(sbtree_t *tree, const int key, const void *value, void *args) +{ + struct param_struct *params = (struct param_struct *) args; + int type = params->args[0]; + gfx_driver_t *driver = params->driver; + + if (value) + gfxr_free_resource(driver, (gfx_resource_t *) value, type); + + return NULL; +} + +#define SBTREE_FREE_TAGGED_ARG_TYPE 0 +#define SBTREE_FREE_TAGGED_ARG_TAGVALUE 1 +#define SBTREE_FREE_TAGGED_ARG_ACTION 2 + +#define ARG_ACTION_RESET 0 +#define ARG_ACTION_DECREMENT 1 + +void * +gfxr_sbtree_free_tagged_func(sbtree_t *tree, const int key, const void *value, void *args) +{ + struct param_struct *params = (struct param_struct *) args; + int type = params->args[SBTREE_FREE_TAGGED_ARG_TYPE]; + int tag_value = params->args[SBTREE_FREE_TAGGED_ARG_TAGVALUE]; + int action = params->args[SBTREE_FREE_TAGGED_ARG_ACTION]; + gfx_driver_t *driver = params->driver; + gfx_resource_t *resource = (gfx_resource_t *) value; + if (resource) { + if (resource->lock_sequence_nr < tag_value) { + gfxr_free_resource(driver, (gfx_resource_t *) value, type); + return NULL; + } else { + if (action == ARG_ACTION_RESET) + resource->lock_sequence_nr = 0; + else + (resource->lock_sequence_nr)--; + return (void *) value; + } + } else return NULL; +} + + +void +gfxr_free_all_resources(gfx_driver_t *driver, gfx_resstate_t *state) +{ + struct param_struct params; + int i; + sbtree_t *tree = NULL; + + for (i = 0; i < GFX_RESOURCE_TYPES_NR; i++) + if ((tree = state->resource_trees[i])) { + params.args[0] = i; + params.driver = driver; + sbtree_foreach(tree, (void *) ¶ms, gfxr_sbtree_free_func); + } +} + +void +gfxr_free_resource_manager(gfx_driver_t *driver, gfx_resstate_t *state) +{ + struct param_struct params; + int i; + sbtree_t *tree = NULL; + + for (i = 0; i < GFX_RESOURCE_TYPES_NR; i++) + if ((tree = state->resource_trees[i])) { + params.args[0] = i; + params.driver = driver; + sbtree_foreach(tree, (void *) ¶ms, gfxr_sbtree_free_func); + sbtree_free(tree); + } + + free(state); +} + + +void +gfxr_tag_resources(gfx_resstate_t *state) +{ + (state->tag_lock_counter)++; +} + + + +void +gfxr_free_tagged_resources(gfx_driver_t *driver, gfx_resstate_t *state) +{ + /* Current heuristics: free tagged views and old pics */ + struct param_struct params; + + if (state->resource_trees[GFX_RESOURCE_TYPE_VIEW]) { + params.args[SBTREE_FREE_TAGGED_ARG_TYPE] = GFX_RESOURCE_TYPE_VIEW; + params.args[SBTREE_FREE_TAGGED_ARG_TAGVALUE] = state->tag_lock_counter; + params.args[SBTREE_FREE_TAGGED_ARG_ACTION] = ARG_ACTION_RESET; + params.driver = driver; + sbtree_foreach(state->resource_trees[GFX_RESOURCE_TYPE_VIEW], (void *) ¶ms, gfxr_sbtree_free_tagged_func); + } + + if (state->resource_trees[GFX_RESOURCE_TYPE_PIC]) { + params.args[SBTREE_FREE_TAGGED_ARG_TYPE] = GFX_RESOURCE_TYPE_PIC; + params.args[SBTREE_FREE_TAGGED_ARG_TAGVALUE] = 0; + params.args[SBTREE_FREE_TAGGED_ARG_ACTION] = ARG_ACTION_DECREMENT; + params.driver = driver; + sbtree_foreach(state->resource_trees[GFX_RESOURCE_TYPE_PIC], (void *) ¶ms, gfxr_sbtree_free_tagged_func); + } + + state->tag_lock_counter = 0; +} + + +#define XLATE_AS_APPROPRIATE(key, entry) \ + if (maps & key) { \ + if (res->unscaled_data.pic \ + && (force || !res->unscaled_data.pic->entry->data)) { \ + if (key == GFX_MASK_VISUAL) \ + gfx_get_res_config(options, res->unscaled_data.pic->entry); \ + gfx_xlate_pixmap(res->unscaled_data.pic->entry, mode, filter); \ + } if (scaled && res->scaled_data.pic \ + && (force || !res->scaled_data.pic->entry->data)) { \ + if (key == GFX_MASK_VISUAL) \ + gfx_get_res_config(options, res->scaled_data.pic->entry); \ + gfx_xlate_pixmap(res->scaled_data.pic->entry, mode, filter); \ + } \ + } + +static gfxr_pic_t * +gfxr_pic_xlate_common(gfx_resource_t *res, int maps, int scaled, + int force, gfx_mode_t *mode, gfx_xlate_filter_t filter, int endianize, + gfx_options_t *options) +{ + XLATE_AS_APPROPRIATE(GFX_MASK_VISUAL, visual_map); + XLATE_AS_APPROPRIATE(GFX_MASK_PRIORITY, priority_map); + XLATE_AS_APPROPRIATE(GFX_MASK_CONTROL, control_map); + + if (endianize && (maps & GFX_MASK_VISUAL) && res->scaled_data.pic->visual_map) + gfxr_endianness_adjust(res->scaled_data.pic->visual_map, mode); + + + return scaled? res->scaled_data.pic : res->unscaled_data.pic; +} +#undef XLATE_AS_APPROPRIATE + + +gfxr_pic_t * +gfxr_get_pic(gfx_resstate_t *state, int nr, int maps, int flags, int default_palette, int scaled) +{ + gfxr_pic_t *npic = NULL; + gfx_resource_type_t restype = GFX_RESOURCE_TYPE_PIC; + sbtree_t *tree = state->resource_trees[restype]; + gfx_resource_t *res = NULL; + int hash = gfxr_interpreter_options_hash(restype, state->version, + state->options, state->misc_payload, 0); + int must_post_process_pic = 0; + int need_unscaled = + (state->driver->mode->xfact != 1 || state->driver->mode->yfact != 1); + + if (!tree) + return NULL; + + hash |= (flags << 20) | ((default_palette & 0x7) << 28); + + res = (gfx_resource_t *) sbtree_get(tree, nr); + + if (!res || res->mode != hash) { + gfxr_pic_t *pic; + gfxr_pic_t *unscaled_pic = NULL; + + if (state->options->pic0_unscaled) { + need_unscaled = 0; + pic = gfxr_interpreter_init_pic(state->version, + &mode_1x1_color_index, + GFXR_RES_ID(restype, nr), + state->misc_payload); + } else pic = gfxr_interpreter_init_pic(state->version, + state->driver->mode, + GFXR_RES_ID(restype, nr), + state->misc_payload); + + if (!pic) { + GFXERROR("Failed to allocate scaled pic!\n"); + return NULL; + } + + gfxr_interpreter_clear_pic(state->version, pic, state->misc_payload); + + if (need_unscaled) { + unscaled_pic = gfxr_interpreter_init_pic(state->version, + &mode_1x1_color_index, + GFXR_RES_ID(restype, nr), + state->misc_payload); + if (!unscaled_pic) { + GFXERROR("Failed to allocate unscaled pic!\n"); + return NULL; + } + gfxr_interpreter_clear_pic(state->version, unscaled_pic, + state->misc_payload); + } +#ifdef TIME_PICDRAWING + {long start_sec, start_usec; + long end_sec, end_usec; + sci_gettime(&start_sec, &start_usec); +#endif + if (gfxr_interpreter_calculate_pic(state, pic, unscaled_pic, flags, + default_palette, nr, + state->misc_payload)) { + gfxr_free_pic(state->driver, pic); + if (unscaled_pic) + gfxr_free_pic(state->driver, unscaled_pic); + + return NULL; + } +#ifdef TIME_PICDRAWING + sci_gettime(&end_sec, &end_usec); + printf("\nTIME: %d for drawing pic.%03d\n", + (end_sec - start_sec) * 1000000 + (end_usec - start_usec), nr); + } +#endif + + if (!res) { + res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t)); + res->ID = GFXR_RES_ID(restype, nr); + res->lock_sequence_nr = state->options->buffer_pics_nr; + sbtree_set(tree, nr, (void *) res); + } else { + gfxr_free_pic(state->driver, res->scaled_data.pic); + if (res->unscaled_data.pic) + gfxr_free_pic(state->driver, res->unscaled_data.pic); + } + + res->mode = hash; + res->scaled_data.pic = pic; + res->unscaled_data.pic = unscaled_pic; + } else { + res->lock_sequence_nr = state->options->buffer_pics_nr; /* Update lock counter */ + } + + must_post_process_pic = res->scaled_data.pic->visual_map->data == NULL; + /* If the pic was only just drawn, we'll have to antialiase and endianness-adjust it now */ + + npic = gfxr_pic_xlate_common(res, maps, + scaled || state->options->pic0_unscaled, + 0, state->driver->mode, + state->options->pic_xlate_filter, 0, + state->options); + + + if (must_post_process_pic) { + + if (scaled || state->options->pic0_unscaled && maps & GFX_MASK_VISUAL) + gfxr_antialiase(npic->visual_map, state->driver->mode, + state->options->pic0_antialiasing); + + gfxr_endianness_adjust(npic->visual_map, state->driver->mode); + } + + return npic; +} + + +static void +set_pic_id(gfx_resource_t *res, int id) +{ + if (res->scaled_data.pic) { + gfxr_pic_t *pic = res->scaled_data.pic; + pic->control_map->ID = id; + pic->priority_map->ID = id; + pic->visual_map->ID = id; + } + + if (res->unscaled_data.pic) { + gfxr_pic_t *pic = res->unscaled_data.pic; + pic->control_map->ID = id; + pic->priority_map->ID = id; + pic->visual_map->ID = id; + } +} + +static int +get_pic_id(gfx_resource_t *res) +{ + if (res->scaled_data.pic) + return res->scaled_data.pic->visual_map->ID; + else + return res->unscaled_data.pic->visual_map->ID; +} + +static void +_gfxr_unscale_pixmap_index_data(gfx_pixmap_t *pxm, gfx_mode_t *mode) +{ + int xmod = mode->xfact; /* Step size horizontally */ + int ymod = pxm->index_xl * mode->yfact; /* Vertical step size */ + int maxpos = pxm->index_xl * pxm->index_yl; + int pos; + byte *dest = pxm->index_data; + + if (!(pxm->flags & GFX_PIXMAP_FLAG_SCALED_INDEX)) + return; /* It's not scaled! */ + + for (pos = 0; pos < maxpos; pos += ymod) { + int c; + + for (c = 0; c < pxm->index_xl; c += xmod) + *dest++ = pxm->index_data[pos + c]; /* No overwrite since + ** line and offset + ** readers move much + ** faster + ** (proof by in- + ** duction, trivial + ** and left to the + ** reader) */ + } + + pxm->index_xl /= mode->xfact; + pxm->index_yl /= mode->yfact; + pxm->flags &= ~GFX_PIXMAP_FLAG_SCALED_INDEX; +} + + +gfxr_pic_t * +gfxr_add_to_pic(gfx_resstate_t *state, int old_nr, int new_nr, int maps, int flags, + int old_default_palette, int default_palette, int scaled) +{ + gfx_resource_type_t restype = GFX_RESOURCE_TYPE_PIC; + sbtree_t *tree = state->resource_trees[restype]; + gfxr_pic_t *pic = NULL; + gfx_resource_t *res = NULL; + int hash = gfxr_interpreter_options_hash(restype, state->version, + state->options, + state->misc_payload, 0); + int need_unscaled = !(state->options->pic0_unscaled) + && (state->driver->mode->xfact != 1 || state->driver->mode->yfact != 1); + + if (!tree) { + GFXERROR("No pics registered\n"); + return NULL; + } + + res = (gfx_resource_t *) sbtree_get(tree, old_nr); + + if (!res || + (res->mode != MODE_INVALID + && res->mode != hash)) { + gfxr_get_pic(state, old_nr, 0, flags, old_default_palette, scaled); + + res = (gfx_resource_t *) sbtree_get(tree, old_nr); + + if (!res) { + GFXWARN("Attempt to add pic %d to non-existing pic %d\n", new_nr, old_nr); + return NULL; + } + } + + if (state->options->pic0_unscaled) /* Unscale priority map, if we scaled it earlier */ + _gfxr_unscale_pixmap_index_data(res->scaled_data.pic->priority_map, state->driver->mode); + + if (scaled) { + res->lock_sequence_nr = state->options->buffer_pics_nr; + + gfxr_interpreter_calculate_pic(state, res->scaled_data.pic, need_unscaled? res->unscaled_data.pic : NULL, + flags | DRAWPIC01_FLAG_OVERLAID_PIC, + default_palette, new_nr, state->misc_payload); + } + + res->mode = MODE_INVALID; /* Invalidate */ + + if (state->options->pic0_unscaled) /* Scale priority map again, if needed */ + res->scaled_data.pic->priority_map = gfx_pixmap_scale_index_data(res->scaled_data.pic->priority_map, state->driver->mode); + { + int old_ID = get_pic_id(res); + set_pic_id(res, GFXR_RES_ID(restype, new_nr)); /* To ensure that our graphical translation optoins work properly */ + pic = gfxr_pic_xlate_common(res, maps, scaled, 1, state->driver->mode, + state->options->pic_xlate_filter, 1, + state->options); + set_pic_id(res, old_ID); + } + + if (scaled || state->options->pic0_unscaled && maps & GFX_MASK_VISUAL) + gfxr_antialiase(pic->visual_map, state->driver->mode, + state->options->pic0_antialiasing); + + return pic; +} + + +gfxr_view_t * +gfxr_get_view(gfx_resstate_t *state, int nr, int *loop, int *cel, int palette) +{ + gfx_resource_type_t restype = GFX_RESOURCE_TYPE_VIEW; + sbtree_t *tree = state->resource_trees[restype]; + gfx_resource_t *res = NULL; + int hash = gfxr_interpreter_options_hash(restype, state->version, + state->options, state->misc_payload, + palette); + gfxr_view_t *view = NULL; + gfxr_loop_t *loop_data = NULL; + gfx_pixmap_t *cel_data = NULL; + + if (!tree) + return NULL; + + res = (gfx_resource_t *) sbtree_get(tree, nr); + + if (!res || res->mode != hash) { + view = gfxr_interpreter_get_view(state, nr, state->misc_payload, palette); + + if (!view) + return NULL; + + if (!res) { + res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.view = NULL; + res->ID = GFXR_RES_ID(restype, nr); + res->lock_sequence_nr = state->tag_lock_counter; + res->mode = hash; + sbtree_set(tree, nr, (void *) res); + } else { + gfxr_free_view(state->driver, res->unscaled_data.view); + } + + res->mode = hash; + res->unscaled_data.view = view; + + } else { + res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */ + view = res->unscaled_data.view; + } + + if (*loop < 0) + *loop = 0; + else + if (*loop >= view->loops_nr) + *loop = view->loops_nr - 1; + + if (*loop < 0) { + GFXWARN("View %d has no loops\n", nr); + return NULL; + } + + loop_data = view->loops + (*loop); + if (loop_data == NULL) + { + GFXWARN("Trying to load invalid loop %d of view %d\n", *loop, nr); + return NULL; + } + + if (*cel < 0) + { + sciprintf("Resetting cel! %d\n", *cel); + *cel = 0; + } + else + if (*cel >= loop_data->cels_nr) + *cel = loop_data->cels_nr - 1; + + if (*cel < 0) { + GFXWARN("View %d loop %d has no cels\n", nr, *loop); + return NULL; + } + + cel_data = loop_data->cels[*cel]; + if (loop_data == NULL) + { + GFXWARN("Trying to load invalid view/loop/cel %d/%d/%d\n", nr, *loop, *cel); + return NULL; + } + + if (!cel_data->data) { + gfx_get_res_config(state->options, cel_data); + gfx_xlate_pixmap(cel_data, state->driver->mode, state->options->view_xlate_filter); + gfxr_endianness_adjust(cel_data, state->driver->mode); + } + + return view; +} + +extern gfx_bitmap_font_t gfxfont_5x8; +extern gfx_bitmap_font_t gfxfont_6x10; + +gfx_bitmap_font_t * +gfxr_get_font(gfx_resstate_t *state, int nr, int scaled) +{ + gfx_resource_type_t restype = GFX_RESOURCE_TYPE_FONT; + sbtree_t *tree = NULL; + gfx_resource_t *res = NULL; + int hash; + + if (nr == GFX_FONT_BUILTIN_5x8) + return &gfxfont_5x8; + else if (nr == GFX_FONT_BUILTIN_6x10) + return &gfxfont_6x10; + + tree = state->resource_trees[restype]; + + hash = gfxr_interpreter_options_hash(restype, state->version, + state->options, state->misc_payload, 0); + + if (!tree) + return NULL; + + res = (gfx_resource_t *) sbtree_get(tree, nr); + + if (!res || res->mode != hash) { + gfx_bitmap_font_t *font = gfxr_interpreter_get_font(state, nr, + state->misc_payload); + + if (!font) + return NULL; + + if (!res) { + res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.font = NULL; + res->ID = GFXR_RES_ID(restype, nr); + res->lock_sequence_nr = state->tag_lock_counter; + res->mode = hash; + sbtree_set(tree, nr, (void *) res); + } else { + gfxr_free_font(res->unscaled_data.font); + } + + res->unscaled_data.font = font; + + return font; + } else { + res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */ + if (res->unscaled_data.pointer) + return res->unscaled_data.font; + else + return res->scaled_data.font; + } +} + + +gfx_pixmap_t * +gfxr_get_cursor(gfx_resstate_t *state, int nr) +{ + gfx_resource_type_t restype = GFX_RESOURCE_TYPE_CURSOR; + sbtree_t *tree = state->resource_trees[restype]; + gfx_resource_t *res = NULL; + int hash = gfxr_interpreter_options_hash(restype, state->version, + state->options, state->misc_payload, 0); + + if (!tree) + return NULL; + + res = (gfx_resource_t *) sbtree_get(tree, nr); + + if (!res || res->mode != hash) { + gfx_pixmap_t *cursor = gfxr_interpreter_get_cursor(state, nr, + state->misc_payload); + + if (!cursor) + return NULL; + + if (!res) { + res = (gfx_resource_t*)sci_malloc(sizeof(gfx_resource_t)); + res->scaled_data.pointer = NULL; + res->ID = GFXR_RES_ID(restype, nr); + res->lock_sequence_nr = state->tag_lock_counter; + res->mode = hash; + sbtree_set(tree, nr, (void *) res); + } else { + gfx_free_pixmap(state->driver, res->unscaled_data.pointer); + } + gfx_get_res_config(state->options, cursor); + gfx_xlate_pixmap(cursor, state->driver->mode, state->options->cursor_xlate_filter); + gfxr_endianness_adjust(cursor, state->driver->mode); + + res->unscaled_data.pointer = cursor; + + return cursor; + } else { + res->lock_sequence_nr = state->tag_lock_counter; /* Update lock counter */ + return res->unscaled_data.pointer; + } +} diff --git a/engines/sci/gfx/resource/Makefile.am b/engines/sci/gfx/resource/Makefile.am new file mode 100644 index 0000000000..4a943e67f0 --- /dev/null +++ b/engines/sci/gfx/resource/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I$(top_srcdir)/src/include @EXTRA_INCLUDES@ +LDADD = $(LDADD_ALL) +EXTRA_DIST = sci_picfill.c sci_picfill_aux.c + +noinst_LIBRARIES = libsciresources.a +libsciresources_a_SOURCES = sci_font.c sci_resmgr.c sci_pic_0.c sci_view_0.c sci_cursor_0.c sci_pal_1.c \ + sci_view_1.c diff --git a/engines/sci/gfx/resource/sci_cursor_0.c b/engines/sci/gfx/resource/sci_cursor_0.c new file mode 100644 index 0000000000..18960516c3 --- /dev/null +++ b/engines/sci/gfx/resource/sci_cursor_0.c @@ -0,0 +1,107 @@ +/*************************************************************************** + cursor_0.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + + +#define CURSOR_RESOURCE_SIZE 68 +#define CURSOR_SIZE 16 + +#define GFX_SCI01_CURSOR_COLORS_NR 3 +#define GFX_SCI0_CURSOR_COLORS_NR 2 + +#define GFX_CURSOR_TRANSPARENT 255 + +gfx_pixmap_color_t gfx_sci01_cursor_colors[GFX_SCI01_CURSOR_COLORS_NR] = { + {GFX_COLOR_INDEX_UNMAPPED, 0x00, 0x00, 0x00}, + {GFX_COLOR_INDEX_UNMAPPED, 0xff, 0xff, 0xff}, + {GFX_COLOR_INDEX_UNMAPPED, 0xaa, 0xaa, 0xaa}}; + + +static gfx_pixmap_t * +_gfxr_draw_cursor(int id, byte *resource, int size, int sci01) +{ + int colors[4] = {0, 1, GFX_CURSOR_TRANSPARENT, 1}; + int line; + byte *data; + gfx_pixmap_t *retval; + + if (sci01) + colors[3] = 2; + + if (size != CURSOR_RESOURCE_SIZE) { + GFXERROR("Expected resource size of %d, but found %d\n", CURSOR_RESOURCE_SIZE, size); + return NULL; + } + + retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(CURSOR_SIZE, CURSOR_SIZE, id, 0, 0)); + retval->colors = gfx_sci01_cursor_colors; + retval->colors_nr = sci01? GFX_SCI01_CURSOR_COLORS_NR : GFX_SCI0_CURSOR_COLORS_NR; + retval->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + retval->color_key = GFX_CURSOR_TRANSPARENT; + + if (sci01) { + retval->xoffset = get_int_16(resource); + retval->yoffset = get_int_16(resource + 2); + } else if (resource[3]) /* center */ + retval->xoffset = retval->yoffset = CURSOR_SIZE / 2; + else + retval->xoffset = retval->yoffset = 0; + + resource += 4; + + data = retval->index_data; + for (line = 0; line < 16; line++) { + int mask_a = get_int_16(resource + (line << 1)); + int mask_b = get_int_16(resource + 32 + (line << 1)); + int i; + + for (i = 0; i < 16; i++) { + int color_code = ((mask_a << i) & 0x8000) + | (((mask_b << i) >> 1) & 0x4000); + + *data++ = colors[color_code >> 14]; + } + } + return retval; +} + + +gfx_pixmap_t * +gfxr_draw_cursor0(int id, byte *resource, int size) +{ + return _gfxr_draw_cursor(id, resource, size, 0); +} + +gfx_pixmap_t * +gfxr_draw_cursor01(int id, byte *resource, int size) +{ + return _gfxr_draw_cursor(id, resource, size, 1); +} + diff --git a/engines/sci/gfx/resource/sci_font.c b/engines/sci/gfx/resource/sci_font.c new file mode 100644 index 0000000000..5bdb3be1a1 --- /dev/null +++ b/engines/sci/gfx/resource/sci_font.c @@ -0,0 +1,153 @@ +/*************************************************************************** + sci_font.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <sci_memory.h> +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + + +extern int font_counter; + + +#define FONT_HEIGHT_OFFSET 4 +#define FONT_MAXCHAR_OFFSET 2 + +static int +calc_char(byte *dest, int total_width, int total_height, byte *src, int size) +{ + int width = src[0]; + int height = src[1]; + int byte_width = (width + 7) >> 3; + int y; + + src += 2; + + if ((width >> 3) > total_width || height > total_height) { + GFXERROR("Weird character: width=%d/%d, height=%d/%d\n", width, total_width, height, total_height); + return GFX_ERROR; + } + + if (byte_width * height + 2 > size) { + GFXERROR("Character extends to %d of %d allowed bytes\n", byte_width * height + 2, size); + return GFX_ERROR; + } + + for (y = 0; y < height; y++) { + memcpy(dest, src, byte_width); + src += byte_width; + dest += total_width; + } + + return GFX_OK; +} + + +gfx_bitmap_font_t * +gfxr_read_font(int id, byte *resource, int size) +{ + gfx_bitmap_font_t *font = (gfx_bitmap_font_t*)sci_calloc(sizeof(gfx_bitmap_font_t), 1); + int chars_nr; + int max_width = 0, max_height; + int i; + + ++font_counter; + + if (size < 6) { + GFXERROR("Font %04x size is %d- this is a joke, right?\n", id, size); + gfxr_free_font(font); + return NULL; + } + + font->chars_nr = chars_nr = get_int_16(resource + FONT_MAXCHAR_OFFSET); + font->line_height = max_height = get_int_16(resource + FONT_HEIGHT_OFFSET); + + if (chars_nr < 0 || chars_nr > 256 || max_height < 0) { + if (chars_nr < 0 || chars_nr > 256) + GFXERROR("Font %04x: Invalid number of characters: %d\n", id, + chars_nr); + if (max_height < 0) + GFXERROR("Font %04x: Invalid font height: %d\n", id, max_height); + gfxr_free_font(font); + return NULL; + } + + if (size < 6 + chars_nr * 2) { + GFXERROR("Font %04x: Insufficient space for %d characters in font\n", + id, chars_nr); + gfxr_free_font(font); + return NULL; + } + + font->ID = id; + font->widths = (int*)sci_malloc(sizeof(int) * chars_nr); + + for (i = 0; i < chars_nr; i++) { + int offset = get_int_16(resource + (i << 1) + 6); + + if (offset >= size) { + GFXERROR("Font %04x: Error: Character 0x%02x is at offset 0x%04x (beyond 0x%04x)\n", + id, i, offset, size); + gfxr_free_font(font); + return NULL; + } + + if ((resource[offset]) > max_width) + max_width = resource[offset]; + if ((resource[offset + 1]) > max_height) + max_height = resource[offset + 1]; + + font->widths[i] = resource[offset]; + } + + font->height = max_height; + font->row_size = (max_width + 7) >> 3; + + if (font->row_size == 3) + font->row_size = 4; + + if (font->row_size > 4) + font->row_size = (font->row_size + 3) & ~3; + + font->char_size = font->row_size * max_height; + font->data = (byte*)sci_calloc(font->char_size, chars_nr); + + for (i = 0; i < chars_nr; i++) { + int offset = get_int_16(resource + (i << 1) + 6); + + if (calc_char(font->data + (font->char_size * i), font->row_size, max_height, + resource + offset, size - offset)) { + GFXERROR("Problem occured in font %04x, char %d/%d\n", id, i, chars_nr); + gfxr_free_font(font); + return NULL; + } + } + + return font; +} + + diff --git a/engines/sci/gfx/resource/sci_pal_1.c b/engines/sci/gfx/resource/sci_pal_1.c new file mode 100644 index 0000000000..72adb7b02a --- /dev/null +++ b/engines/sci/gfx/resource/sci_pal_1.c @@ -0,0 +1,178 @@ +/*************************************************************************** + pal_1.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* SCI1 palette resource defrobnicator */ + +#include <sci_memory.h> +#include <gfx_system.h> +#include <gfx_resource.h> + +#define MAX_COLORS 256 +#define PALETTE_START 260 +#define COLOR_OK 0x01 + +#define SCI_PAL_FORMAT_VARIABLE_FLAGS 0 +#define SCI_PAL_FORMAT_CONSTANT_FLAGS 1 + +gfx_pixmap_color_t * +gfxr_read_pal11(int id, int *colors_nr, byte *resource, int size) +{ + int start_color = resource[25]; + int format = resource[32]; + int entry_size; + gfx_pixmap_color_t *retval; + byte *pal_data = resource + 37; + int _colors_nr = *colors_nr = getUInt16(resource + 29); + int i; + + switch (format) + { + case SCI_PAL_FORMAT_VARIABLE_FLAGS : + entry_size = 4; + break; + case SCI_PAL_FORMAT_CONSTANT_FLAGS : + entry_size = 3; + break; + } + + retval = (gfx_pixmap_color_t *) + sci_malloc(sizeof(gfx_pixmap_color_t) * (_colors_nr + start_color)); + memset(retval, 0, sizeof(gfx_pixmap_color_t) * (_colors_nr + start_color)); + + for (i = 0; i < start_color; i ++) + { + retval[i].global_index = GFX_COLOR_INDEX_UNMAPPED; + retval[i].r = 0; + retval[i].g = 0; + retval[i].b = 0; + } + for (i = start_color; i < start_color + _colors_nr; i ++) + { + switch (format) + { + case SCI_PAL_FORMAT_CONSTANT_FLAGS: + retval[i].global_index = GFX_COLOR_INDEX_UNMAPPED; + retval[i].r = pal_data[0]; + retval[i].g = pal_data[1]; + retval[i].b = pal_data[2]; + break; + case SCI_PAL_FORMAT_VARIABLE_FLAGS: + retval[i].global_index = GFX_COLOR_INDEX_UNMAPPED; + retval[i].r = pal_data[1]; + retval[i].g = pal_data[2]; + retval[i].b = pal_data[3]; + break; + } + pal_data += entry_size; + } + + return retval; +} + +gfx_pixmap_color_t * +gfxr_read_pal1(int id, int *colors_nr, byte *resource, int size) +{ + int counter = 0; + int pos; + unsigned int colors[MAX_COLORS] = {0}; + gfx_pixmap_color_t *retval; + + if (size < PALETTE_START + 4) { + GFXERROR("Palette resource too small in %04x\n", id); + return NULL; + } + + + pos = PALETTE_START; + + while (pos < size/* && resource[pos] == COLOR_OK && counter < MAX_COLORS*/) { + int color = resource[pos] + | (resource[pos + 1] << 8) + | (resource[pos + 2] << 16) + | (resource[pos + 3] << 24); + + pos += 4; + + colors[counter++] = color; + } + + if (counter < MAX_COLORS && resource[pos] != COLOR_OK) { + GFXERROR("Palette %04x uses unknown palette color prefix 0x%02x at offset 0x%04x\n", id, resource[pos], pos); + return NULL; + } + + if (counter < MAX_COLORS) { + GFXERROR("Palette %04x ends prematurely\n", id); + return NULL; + } + + retval = (gfx_pixmap_color_t*)sci_malloc(sizeof(gfx_pixmap_color_t) * counter); +#ifdef SATISFY_PURIFY + memset(retval, 0, sizeof(gfx_pixmap_color_t) * counter); +#endif + + *colors_nr = counter; + for (pos = 0; pos < counter; pos++) { + unsigned int color = colors[pos]; + + retval[pos].global_index = GFX_COLOR_INDEX_UNMAPPED; + retval[pos].r = (color >> 8) & 0xff; + retval[pos].g = (color >> 16) & 0xff; + retval[pos].b = (color >> 24) & 0xff; + } + + return retval; +} + +gfx_pixmap_color_t * +gfxr_read_pal1_amiga(int *colors_nr, FILE *f) +{ + int i; + gfx_pixmap_color_t *retval; + + retval = (gfx_pixmap_color_t*)sci_malloc(sizeof(gfx_pixmap_color_t) * 32); + + for (i = 0; i < 32; i++) { + int b1, b2; + + b1 = fgetc(f); + b2 = fgetc(f); + + if (b1 == EOF || b2 == EOF) { + GFXERROR("Palette file ends prematurely\n"); + return NULL; + } + + retval[i].global_index = GFX_COLOR_INDEX_UNMAPPED; + retval[i].r = (b1 & 0xf) * 0x11; + retval[i].g = ((b2 & 0xf0) >> 4) * 0x11; + retval[i].b = (b2 & 0xf) * 0x11; + } + + *colors_nr = 32; + return retval; +} + diff --git a/engines/sci/gfx/resource/sci_pic_0.c b/engines/sci/gfx/resource/sci_pic_0.c new file mode 100644 index 0000000000..63130b53f4 --- /dev/null +++ b/engines/sci/gfx/resource/sci_pic_0.c @@ -0,0 +1,2023 @@ +/*************************************************************************** + sci_pic_0.c Copyright (C) 2000 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <sci_memory.h> +#include <assert.h> +#include <math.h> +#include <time.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + +#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 SCI_PIC0_MAX_FILL 30 /* Number of times to fill before yielding to scheduler */ + +#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() +{ + int i; + + if (!_gfxr_pic0_colors_initialized) { + for (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; + int color2 = color; + + 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)); + int i; + + if (sizeof(unsigned long) == 8) { /* UltraSparc, Alpha, newer MIPSens, etc */ + andmask |= (andmask << 32); + clearmask |= (clearmask << 32); + } + + for (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; +} + + +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)++; +} + + + +/*** 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 +#define p0printf if (0) +#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); /* Ouch! */ + + _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); /* Ouch! */ + 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) +{ + point_t start; + point_t 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", + GFX_PRINT_POINT(start), GFX_PRINT_POINT(end)); + 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, gfx_point(x, y), gfx_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 /* returns -1 on failure, 0 on success */ +_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) +{ + 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 + +/* 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.c" +# include "sci_picfill.c" +#undef DRAW_SCALED +#undef AUXBUF_FILL +#undef AUXBUF_FILL_HELPER +#undef FILL_FUNCTION_RECURSIVE +#undef FILL_FUNCTION + +#endif /* defined(WITH_PIC_SCALING) */ + +/* 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.c" +# include "sci_picfill.c" +#undef AUXBUF_FILL +#undef AUXBUF_FILL_HELPER +#undef FILL_FUNCTION_RECURSIVE +#undef FILL_FUNCTION + + +#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) { + /* D'Oh! */ + 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 i; + 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; + int fill_count = 0; + byte op, opx; + +#ifdef FILL_RECURSIVE_DEBUG + fillmagc = atoi(getenv("FOO")); + fillc = atoi(getenv("FOO2")); +#endif /* FILL_RECURSIVE_DEBUG */ + + /* Initialize palette */ + for (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); + + if (fill_count++ > SCI_PIC0_MAX_FILL) { + sci_sched_yield(); + fill_count = 0; + } + +#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 i; + 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 (%08x); this only occurs with overlaid pics, otherwise it's a bug!\n", pic->internal); + } + + pri_table = (int*)pic->internal; + + pri_table[0] = 0; + pri_table[15] = 190; + + for (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 (%08x); possible memory corruption!\n", 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; + } + } +} + diff --git a/engines/sci/gfx/resource/sci_picfill.c b/engines/sci/gfx/resource/sci_picfill.c new file mode 100644 index 0000000000..c7ecea08a7 --- /dev/null +++ b/engines/sci/gfx/resource/sci_picfill.c @@ -0,0 +1,429 @@ +/*************************************************************************** + Copyright (C) 2004 Christoph Reichenbach <reichenb@colorado.edu> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundaton; either version 2 of the + Licence, or (at your option) any later version. + + It is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantibility or fitness for a particular purpose. See the + GNU General Public Licence for more details. + + You should have received a copy of the GNU General Public Licence + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +***************************************************************************/ + +/* Generic pic filling code, to be included by sci_pic_0.c + * + * + * To use, define the following: + * FILL_FUNCTION: Name of the exported floodfill function + * FILL_FUNCTION_RECURSIVE: Name of the helper function + * + * Define DRAW_SCALED to support scaled drawing, or leave it out for faster + * processing. + * + */ + +#ifdef FILL_RECURSIVE_DEBUG +# define PRINT_DEBUG0(s) if (!fillmagc) fprintf(stderr, s) +# define PRINT_DEBUG1(s,p1) if (!fillmagc) fprintf(stderr, s, p1) +# define PRINT_DEBUG4(s,p1,p2,p3,p4) if (!fillmagc) fprintf(stderr, s, p1) +#else +# define PRINT_DEBUG0(s) +# define PRINT_DEBUG1(s,p1) +# define PRINT_DEBUG4(s,p1,p2,p3,p4) +#endif + +#ifdef DRAW_SCALED +# define SCALED_CHECK(x) (x) +# define IS_BOUNDARY(x, y, index) (((index) & legalmask) != legalcolor) +#else +# define SCALED_CHECK(x) 1 +# define IS_BOUNDARY(x, y, index) ( \ + (((x)+(y)) & 1)? /* figure out which part of the mask to use, to simulate dithering */ \ + ((((index)) & ((legalmask) )) != ((legalcolor) & ((legalmask)))) /* odd coordinate */ \ + : ((((index)) & ((legalmask) >> 8)) != ((legalcolor) & ((legalmask) >> 8))) /* even coordinate */ \ + ) +#endif + +static void +FILL_FUNCTION_RECURSIVE(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, byte *bounds, + int legalcolor, int legalmask, int color, int priority, int drawenable, + int sci_titlebar_size) +{ + int linewidth = pic->mode->xfact * 320; + int miny = pic->mode->yfact * sci_titlebar_size; + int maxy = pic->mode->yfact * 200; + int xl, xr; + int oldytotal = y * linewidth; +#ifdef DRAW_SCALED + int old_proj_y = -42; + int proj_y; + int proj_ytotal; + int proj_x; + int proj_xl_bound = 0; + int proj_xr_bound = 0; +#endif + + do { + int ytotal = oldytotal + (linewidth * dy); + int xcont; + int state; + + y += dy; + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillc) + return; + else if (!fillmagc) { --fillc; + } +#endif /* defined(FILL_RECURSIVE_DEBUG) */ + + if (y < miny || y >= maxy) { + PRINT_DEBUG0("ABRT on failed initial assertion!\n"); + return; + } +#ifdef DRAW_SCALED + proj_y = y / pic->mode->yfact; + + if (proj_y != old_proj_y) { + /* First, find the projected coordinates, unless known already: */ + proj_ytotal = proj_y * 320; + proj_x = old_xl / pic->mode->xfact; + + proj_xl_bound = proj_x; + if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)){ + while (proj_xl_bound + && pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT) + --proj_xl_bound; + } else { + while (proj_xl_bound < 319 + && !(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT)) + ++proj_xl_bound; + + if (proj_xl_bound < 319) + ++proj_xl_bound; + } + + if (proj_xl_bound == 319 + && !(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { + PRINT_DEBUG0("ABRT because proj_xl_bound couldn't be found\n"); + return; + } + + proj_xr_bound = (proj_xl_bound > proj_x)? proj_xl_bound : proj_x; + while ((proj_xr_bound < 319) + && pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT) + ++proj_xr_bound; + +#ifdef FILL_RECURSIVE_DEBUG + if (!fillmagc) { + fprintf(stderr,"l%d: {%d,%d} | ", proj_y, proj_xl_bound, proj_xr_bound); + pic->aux_map[proj_y*320 + proj_xl_bound] |= 0x2; + pic->aux_map[proj_y*320 + proj_xr_bound] |= 0x2; + } +#endif + + proj_xl_bound *= pic->mode->xfact; + if (proj_xl_bound) + proj_xl_bound -= pic->mode->xfact - 1; + + if (proj_xr_bound < 319) + ++proj_xr_bound; + proj_xr_bound *= pic->mode->xfact; + proj_xr_bound += pic->mode->xfact -1; + + old_proj_y = proj_y; + } +#else +# define proj_xl_bound 0 +# define proj_xr_bound 319 +#endif + + /* Now we have the projected limits, get the real ones: */ + + xl = (old_xl > proj_xl_bound)? old_xl : proj_xl_bound; + if (!IS_BOUNDARY(xl, y+1, bounds[ytotal + xl])) { /* go left as far as possible */ + while (xl > proj_xl_bound && (!IS_BOUNDARY(xl-1, y+1, bounds[ytotal + xl - 1]))) + --xl; + } else /* go right until the fillable area starts */ + while (xl < proj_xr_bound && (IS_BOUNDARY(xl, y+1, bounds[ytotal + xl]))) + ++xl; + + + PRINT_DEBUG1("<%d,", xl); + + if ((xl > proj_xr_bound) + || (xl > old_xr)) { + PRINT_DEBUG0("ABRT because xl > xr_bound\n"); + return; + } + + xr = (xl > old_xl)? xl : old_xl; + while (xr < proj_xr_bound && (!IS_BOUNDARY(xr+1, y+1, bounds[ytotal + xr + 1]))) + ++xr; + + PRINT_DEBUG1("%d> -> ", xr); + + if (IS_BOUNDARY(xl, y+1, bounds[ytotal + xl])) { + PRINT_DEBUG0("ABRT because xl illegal\n"); + return; + } + +#ifdef DRAW_SCALED + PRINT_DEBUG4("[%d[%d,%d]%d]\n", proj_xl_bound, xl, xr, proj_xr_bound); + + if (xl < proj_xl_bound && xr - 3*pic->mode->xfact < proj_xl_bound) { + PRINT_DEBUG0("ABRT interval left of zone\n"); + return; + } + + if (xr > proj_xr_bound && xl + 3*pic->mode->xfact > proj_xr_bound) { + PRINT_DEBUG0("ABRT because interval right of zone\n"); + return; + } +#endif + + if (drawenable & GFX_MASK_VISUAL) + memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); + + if (drawenable & GFX_MASK_PRIORITY) + memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); + + + /* Check whether we need to recurse on branches in the same direction */ + state = 0; + xcont = xr + 1; + while (xcont <= old_xr) { + if (IS_BOUNDARY(xcont, y+1, bounds[ytotal + xcont])) + state = xcont; + else if (state) { /* recurse */ + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BRANCH %d [%d,%d] l%d\n", dy, state, xcont, y - dy); + + FILL_FUNCTION_RECURSIVE(pic, state, xcont, y - dy, dy, bounds, legalcolor, + legalmask, color, priority, drawenable, sci_titlebar_size); + state = 0; + } + ++xcont; + } + + /* Check whether we need to recurse on backward branches: */ + /* left */ + if (xl < old_xl - 1) { + state = 0; + for (xcont = old_xl-1; xcont >= xl; xcont--) { + if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) + state = xcont; + else if (state) { /* recurse */ + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BACK-LEFT %d [%d,%d] l%d\n", -dy, state, xcont, y); + + FILL_FUNCTION_RECURSIVE(pic, xcont, state, y, -dy, bounds, + legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + state = 0; + } + } + } + + /* right */ + if (xr > old_xr + 1) { + state = 0; + for (xcont = old_xr + 1; xcont <= xr; xcont++) { + if (IS_BOUNDARY(xcont, y, bounds[oldytotal + xcont])) + state = xcont; + else if (state) { /* recurse */ + PRINT_DEBUG4("[%d[%d,%d],%d]: ", old_xl, xl, xr, old_xr); + PRINT_DEBUG4("rec BACK-RIGHT %d [%d,%d] l%d\n", -dy, state, xcont, y); + + FILL_FUNCTION_RECURSIVE(pic, state, xcont, y, -dy, bounds, + legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + state = 0; + } + } + } + + oldytotal = ytotal; + old_xl = xl; + old_xr = xr; + + } while (1); +} + + +static void +FILL_FUNCTION(gfxr_pic_t *pic, int x_320, int y_200, int color, int priority, int control, int drawenable, + int sci_titlebar_size) +{ + int linewidth = pic->mode->xfact * 320; + int x, y; + int xl, xr; + int ytotal; + int bitmask; + byte *bounds = NULL; + int legalcolor, legalmask; +#ifdef DRAW_SCALED + int min_x, min_y, max_x, max_y; +#endif + int original_drawenable = drawenable; /* Backup, since we need the unmodified value + ** for filling the aux and control map */ + + /* Restrict drawenable not to restrict itself to zero */ + if (pic->control_map->index_data[y_200 * 320 + x_320] != 0) + drawenable &= ~GFX_MASK_CONTROL; + + if (color == 0xff) + drawenable &= ~GFX_MASK_VISUAL; + + if (priority == 0) { + drawenable &= ~GFX_MASK_PRIORITY; + original_drawenable &= ~GFX_MASK_PRIORITY; + } + + AUXBUF_FILL(pic, x_320, y_200, original_drawenable, + (drawenable & GFX_MASK_CONTROL)? control : 0, + sci_titlebar_size); + +#ifdef DRAW_SCALED + _gfxr_auxbuf_spread(pic, &min_x, &min_y, &max_x, &max_y); + + if (_gfxr_find_fill_point(pic, min_x, min_y, max_x, max_y, x_320, y_200, color, drawenable, &x, &y)) { + /* GFXWARN("Could not find scaled fill point, but unscaled fill point was available!\n"); */ + drawenable &= GFX_MASK_PRIORITY; + if (!drawenable) + _gfxr_auxbuf_propagate_changes(pic, 0); + } +#else + x = x_320; + y = y_200; +#endif + + ytotal = y * linewidth; + + if (!drawenable) + return; + + if (drawenable & GFX_MASK_VISUAL) { + bounds = pic->visual_map->index_data; +#if 0 + /* Code disabled, as removing it fixes qg1 pic.095 (unscaled). However, + ** it MAY be of relevance to scaled pic drawing... */ + + if ((color & 0xf) == 0xf /* When dithering with white, do more + ** conservative checks */ + || (color & 0xf0) == 0xf0) + legalcolor = 0xff; + else + legalcolor = 0xf0; /* Only check the second color */ +#endif +#ifdef DRAW_SCALED + legalcolor = 0xff; + legalmask = legalcolor; +#else + legalmask = 0x0ff0; + legalcolor = 0xff; +#endif + } else if (drawenable & GFX_MASK_PRIORITY) { + bounds = pic->priority_map->index_data; + legalcolor = 0; + legalmask = 0x0f0f; + } else { + legalcolor = 0; + legalmask = 0x0f0f; + } + + if (!bounds || IS_BOUNDARY(x, y, bounds[ytotal + x])) + return; + + if (bounds) { +#ifdef DRAW_SCALED + int proj_y = y_200; + int proj_ytotal = proj_y * 320; + int proj_x = x_320; + int proj_xl_bound; + int proj_xr_bound; + int proj_xl, proj_xr; + + ytotal = y * linewidth; + + proj_xl_bound = proj_x; + if (SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound] & FRESH_PAINT)) { + while (proj_xl_bound + && SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xl_bound - 1] & FRESH_PAINT)) + --proj_xl_bound; + } else + while (proj_xl_bound < 319 + && SCALED_CHECK(!(pic->aux_map[proj_ytotal + proj_xl_bound + 1] & FRESH_PAINT))) + ++proj_xl_bound; + + proj_xr_bound = (proj_xl_bound > proj_x)? proj_xl_bound : proj_x; + while ((proj_xr_bound < 319) && + SCALED_CHECK(pic->aux_map[proj_ytotal + proj_xr_bound + 1] & FRESH_PAINT)) + ++proj_xr_bound; + + proj_xl = proj_xl_bound; + proj_xr = proj_xr_bound; + + proj_xl_bound *= pic->mode->xfact; + if (proj_xl_bound) + proj_xl_bound -= pic->mode->xfact -1; + + if (proj_xr_bound < 319) + ++proj_xr_bound; + proj_xr_bound *= pic->mode->xfact; + proj_xr_bound += pic->mode->xfact -1; +#endif + xl = x; + while (xl > proj_xl_bound && (!IS_BOUNDARY(xl-1, y, bounds[ytotal + xl -1]))) + --xl; + + while (x < proj_xr_bound && (!IS_BOUNDARY(x+1, y, bounds[ytotal + x + 1]))) + ++x; + xr = x; + + if (drawenable & GFX_MASK_VISUAL) + memset(pic->visual_map->index_data + ytotal + xl, color, xr - xl + 1); + + if (drawenable & GFX_MASK_PRIORITY) + memset(pic->priority_map->index_data + ytotal + xl, priority, xr - xl + 1); + + FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, -1, bounds, legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + FILL_FUNCTION_RECURSIVE(pic, xl, xr, y, +1, bounds, legalcolor, legalmask, color, priority, drawenable, + sci_titlebar_size); + } + + /* Now finish the aux buffer */ + bitmask = drawenable & + ( + ((color != 0xff)? 1 : 0) + | ((priority)? 2 : 0) + | ((control)? 4 : 0) + ); + +#ifdef DRAW_SCALED +# ifdef FILL_RECURSIVE_DEBUG + if (fillmagc) +# endif + _gfxr_auxbuf_propagate_changes(pic, bitmask); +#endif +} + +#undef SCALED_CHECK +#undef IS_BOUNDARY + +#ifndef DRAW_SCALED +# undef proj_xl_bound +# undef proj_xr_bound +#endif + + + diff --git a/engines/sci/gfx/resource/sci_picfill_aux.c b/engines/sci/gfx/resource/sci_picfill_aux.c new file mode 100644 index 0000000000..70d8a822da --- /dev/null +++ b/engines/sci/gfx/resource/sci_picfill_aux.c @@ -0,0 +1,205 @@ +/*************************************************************************** + Copyright (C) 2004 Christoph Reichenbach <reichenb@colorado.edu> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundaton; either version 2 of the + Licence, or (at your option) any later version. + + It is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantibility or fitness for a particular purpose. See the + GNU General Public Licence for more details. + + You should have received a copy of the GNU General Public Licence + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +***************************************************************************/ + +/* Generic pic auxbuf filling code, to be included by sci_pic_0.c + * + * + * To use, define the following: + * AUXBUF_FILL: Name of the exported floodfill function + * AUXBUF_FILL_HELPER: Name of the helper function + * + * Define DRAW_SCALED to support scaled drawing, or leave it out for faster + * processing. + * + */ + +#define CLIPMASK_HARD_BOUND 0x80 /* ensures that we don't re-fill filled stuff */ + +static void +AUXBUF_FILL_HELPER(gfxr_pic_t *pic, int old_xl, int old_xr, int y, int dy, + int clipmask, int control, int sci_titlebar_size) +{ + int xl, xr; + int oldytotal = y * 320; +#ifdef DRAW_SCALED + unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x78; +#else + unsigned const char fillmask = CLIPMASK_HARD_BOUND | 0x84; +#endif + + do { + int ytotal = oldytotal + (320 * dy); + int xcont; + int state; + + y += dy; + + if (y < sci_titlebar_size || y > 199) + return; + + xl = old_xl; + if (!(pic->aux_map[ytotal + xl] & clipmask)) { /* go left */ + while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) + --xl; + } else /* go right and look for the first valid spot */ + while ((xl <= old_xr) && (pic->aux_map[ytotal + xl] & clipmask)) + ++xl; + + if (xl > old_xr) /* No fillable strip above the last one */ + return; + + if ((ytotal + xl) < 0) { fprintf(stderr,"AARGH-%d\n", __LINE__); BREAKPOINT(); } + + xr = xl; + while (xr < 320 && !(pic->aux_map[ytotal + xr] & clipmask)) { + pic->aux_map[ytotal + xr] |= fillmask; + ++xr; + } + + if ((ytotal + xr) > 64000) { fprintf(stderr,"AARGH-%d\n", __LINE__); + BREAKPOINT(); + } + + --xr; + + if (xr < xl) + return; + + /* Check whether we need to recurse on branches in the same direction */ + if ((y > sci_titlebar_size && dy < 0) + || (y < 199 && dy > 0)) { + + state = 0; + xcont = xr + 1; + while (xcont <= old_xr) { + if (pic->aux_map[ytotal + xcont] & clipmask) + state = 0; + else if (!state) { /* recurse */ + state = 1; + AUXBUF_FILL_HELPER(pic, xcont, old_xr, + y - dy, dy, clipmask, control, sci_titlebar_size); + } + ++xcont; + } + } + + /* Check whether we need to recurse on backward branches: */ + /* left */ + if (xl < old_xl - 1) { + state = 0; + for (xcont = old_xl - 1; xcont >= xl; xcont--) { + if (pic->aux_map[oldytotal + xcont] & clipmask) + state = xcont; + else if (state) { /* recurse */ + AUXBUF_FILL_HELPER(pic, xcont, state, + y, -dy, clipmask, control, sci_titlebar_size); + state = 0; + } + } + } + + /* right */ + if (xr > old_xr + 1) { + state = 0; + for (xcont = old_xr + 1; xcont <= xr; xcont++) { + if (pic->aux_map[oldytotal + xcont] & clipmask) + state = xcont; + else if (state) { /* recurse */ + AUXBUF_FILL_HELPER(pic, state, xcont, + y, -dy, clipmask, control, sci_titlebar_size); + state = 0; + } + } + } + + if ((ytotal + xl) < 0) { fprintf(stderr,"AARGH-%d\n", __LINE__); BREAKPOINT() } + if ((ytotal + xr+1) > 64000) { fprintf(stderr,"AARGH-%d\n", __LINE__); BREAKPOINT(); } + + if (control) + memset(pic->control_map->index_data + ytotal + xl, control, xr-xl+1); + + oldytotal = ytotal; + old_xr = xr; + old_xl = xl; + + } while (1); +} + + +static void +AUXBUF_FILL(gfxr_pic_t *pic, int x, int y, int clipmask, int control, int sci_titlebar_size) +{ + /* Fills the aux buffer and the control map (if control != 0) */ + int xl, xr; + int ytotal = y * 320; +#ifdef DRAW_SCALED + unsigned const char fillmask = 0x78; +#else + unsigned const char fillmask = 0x4; +#endif + +#ifndef DRAW_SCALED + if (!control || !(clipmask & 4)) + return; /* Without pic scaling, we only do this to fill the control map */ +#endif + + if (clipmask & 1) + clipmask = 1; /* vis */ + else if (clipmask & 2) + clipmask = 2; /* pri */ + else if (clipmask & 4) + clipmask = 4; /* ctl */ + else return; + +#ifdef DRAW_SCALED + clipmask |= fillmask; /* Bits 3-5 */ +#endif + + if (pic->aux_map[ytotal + x] & clipmask) + return; + + pic->aux_map[ytotal + x] |= fillmask; + + xl = x; + while (xl && !(pic->aux_map[ytotal + xl - 1] & clipmask)) { + --xl; + pic->aux_map[ytotal + xl] |= fillmask; + } + + xr = x; + while ((xr < 319) && !(pic->aux_map[ytotal + xr + 1] & clipmask)) { + ++xr; + pic->aux_map[ytotal + xr] |= fillmask; + } + + clipmask |= CLIPMASK_HARD_BOUND; /* Guarantee clipping */ + + if (control) /* Draw the same strip on the control map */ + memset(pic->control_map->index_data + ytotal + xl, control, xr - xl + 1); + + if (y > sci_titlebar_size) + AUXBUF_FILL_HELPER(pic, xl, xr, y, -1, clipmask, control, sci_titlebar_size); + + if (y < 199) + AUXBUF_FILL_HELPER(pic, xl, xr, y, +1, clipmask, control, sci_titlebar_size); +} + + +#undef CLIPMASK_HARD_BOUND diff --git a/engines/sci/gfx/resource/sci_resmgr.c b/engines/sci/gfx/resource/sci_resmgr.c new file mode 100644 index 0000000000..6475369230 --- /dev/null +++ b/engines/sci/gfx/resource/sci_resmgr.c @@ -0,0 +1,341 @@ +/*************************************************************************** + sci_resmgr.c Copyright (C) 2000 Christoph Reichenbach + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* The interpreter-specific part of the resource manager, for SCI */ + +#include <sci_memory.h> +#include <sciresource.h> +#include <gfx_widgets.h> +#include <gfx_resmgr.h> +#include <gfx_options.h> + +int +gfxr_interpreter_options_hash(gfx_resource_type_t type, int version, + gfx_options_t *options, + void *internal, int palette) +{ + switch (type) { + + case GFX_RESOURCE_TYPE_VIEW: + return palette; + + case GFX_RESOURCE_TYPE_PIC: + if (version >= SCI_VERSION_01_VGA) + return options->pic_port_bounds.y; + else + return (options->pic0_unscaled)? 0x10000 : + (options->pic0_dither_mode << 12) + | (options->pic0_dither_pattern << 8) + | (options->pic0_brush_mode << 4) + | (options->pic0_line_mode); + + case GFX_RESOURCE_TYPE_FONT: + return 0; + + case GFX_RESOURCE_TYPE_CURSOR: + return 0; + + case GFX_RESOURCE_TYPES_NR: + default: + GFXERROR("Invalid resource type: %d\n", type); + return -1; + } +} + + +gfxr_pic_t * +gfxr_interpreter_init_pic(int version, gfx_mode_t *mode, int ID, void *internal) +{ + return gfxr_init_pic(mode, ID, version >= SCI_VERSION_01_VGA); +} + + +void +gfxr_interpreter_clear_pic(int version, gfxr_pic_t *pic, void *internal) +{ + gfxr_clear_pic0(pic, SCI_TITLEBAR_SIZE); +} + + +int +gfxr_interpreter_calculate_pic(gfx_resstate_t *state, gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, + int flags, int default_palette, int nr, void *internal) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + resource_t *res = scir_find_resource(resmgr, sci_pic, nr, 0); + int need_unscaled = unscaled_pic != NULL; + gfxr_pic0_params_t style, basic_style; + + basic_style.line_mode = GFX_LINE_MODE_CORRECT; + basic_style.brush_mode = GFX_BRUSH_MODE_SCALED; + basic_style.pic_port_bounds = state->options->pic_port_bounds; + + style.line_mode = state->options->pic0_line_mode; + style.brush_mode = state->options->pic0_brush_mode; + style.pic_port_bounds = state->options->pic_port_bounds; + + if (!res || !res->data) + return GFX_ERROR; + + if (state->version >= SCI_VERSION_01_VGA) { + if (need_unscaled) + { + if (state->version == SCI_VERSION_1_1) + gfxr_draw_pic11(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id, + state->static_palette, state->static_palette_entries); + else + gfxr_draw_pic01(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id, 1, + state->static_palette, state->static_palette_entries); + } + if (scaled_pic && scaled_pic->undithered_buffer) + memcpy(scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer, scaled_pic->undithered_buffer_size); + + if (state->version == SCI_VERSION_1_1) + gfxr_draw_pic11(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id, + state->static_palette, state->static_palette_entries); + else + gfxr_draw_pic01(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id, state->version, + state->static_palette, state->static_palette_entries); + } else { + if (need_unscaled) + gfxr_draw_pic01(unscaled_pic, flags, default_palette, res->size, res->data, &basic_style, res->id, 0, + state->static_palette, state->static_palette_entries); + + if (scaled_pic && scaled_pic->undithered_buffer) + memcpy(scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer, scaled_pic->undithered_buffer_size); + + gfxr_draw_pic01(scaled_pic, flags, default_palette, res->size, res->data, &style, res->id, 0, + state->static_palette, state->static_palette_entries); + if (need_unscaled) + gfxr_remove_artifacts_pic0(scaled_pic, unscaled_pic); + + if (!scaled_pic->undithered_buffer) + scaled_pic->undithered_buffer = sci_malloc(scaled_pic->undithered_buffer_size); + + memcpy(scaled_pic->undithered_buffer, scaled_pic->visual_map->index_data, scaled_pic->undithered_buffer_size); + + gfxr_dither_pic0(scaled_pic, state->options->pic0_dither_mode, state->options->pic0_dither_pattern); + } + + /* Mark default palettes */ + if (scaled_pic) + scaled_pic->visual_map->loop = default_palette; + + if (unscaled_pic) + unscaled_pic->visual_map->loop = default_palette; + + return GFX_OK; +} + + +void +gfxr_palettize_view(gfxr_view_t *view, gfx_pixmap_color_t *source, int source_entries) +{ + int i; + + for (i=0;i<MIN(view->colors_nr,source_entries);i++) + { + if ((view->colors[i].r == 0) && + (view->colors[i].g == 0) && + (view->colors[i].b == 0)) + { + view->colors[i] = source[i]; + } + } +} + +gfxr_view_t * +gfxr_draw_view11(int id, byte *resource, int size); + +gfxr_view_t * +gfxr_interpreter_get_view(gfx_resstate_t *state, int nr, void *internal, int palette) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + resource_t *res = scir_find_resource(resmgr, sci_view, nr, 0); + int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_VIEW, nr); + gfxr_view_t *result; + + if (!res || !res->data) + return NULL; + + if (state->version < SCI_VERSION_01) palette=-1; + + switch (state->version) + { + case SCI_VERSION_0: + case SCI_VERSION_01: + result=gfxr_draw_view0(resid, res->data, res->size, palette); + break; + case SCI_VERSION_01_VGA: + case SCI_VERSION_01_VGA_ODD: + case SCI_VERSION_1_EARLY: + case SCI_VERSION_1_LATE: + result=gfxr_draw_view1(resid, res->data, res->size, state->static_palette, state->static_palette_entries); + break; + case SCI_VERSION_1_1: + case SCI_VERSION_32: + result=gfxr_draw_view11(resid, res->data, res->size); + break; + } + + if (state->version >= SCI_VERSION_01_VGA) + { + if (!result->colors) + { + result->colors = (gfx_pixmap_color_t*)sci_malloc(sizeof(gfx_pixmap_color_t) * state->static_palette_entries); + memset(result->colors, 0, sizeof(gfx_pixmap_color_t) * state->static_palette_entries); + result->colors_nr = state->static_palette_entries; + } + gfxr_palettize_view(result, state->static_palette, state->static_palette_entries); + } + return result; +} + + +gfx_bitmap_font_t * +gfxr_interpreter_get_font(gfx_resstate_t *state, int nr, void *internal) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + resource_t *res = scir_find_resource(resmgr, sci_font, nr, 0); + if (!res || !res->data) + return NULL; + + return gfxr_read_font(res->id, res->data, res->size); +} + + +gfx_pixmap_t * +gfxr_interpreter_get_cursor(gfx_resstate_t *state, int nr, void *internal) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + resource_t *res = scir_find_resource(resmgr, sci_cursor, nr, 0); + int resid = GFXR_RES_ID(GFX_RESOURCE_TYPE_CURSOR, nr); + + if (!res || !res->data) + return NULL; + + if (state->version >= SCI_VERSION_1_1) { + GFXWARN("Attempt to retreive cursor in SCI1.1 or later\n"); + return NULL; + } + + if (state->version == SCI_VERSION_0) + return gfxr_draw_cursor0(resid, res->data, res->size); + else + return gfxr_draw_cursor01(resid, res->data, res->size); +} + + +int * +gfxr_interpreter_get_resources(gfx_resstate_t *state, gfx_resource_type_t type, + int version, int *entries_nr, void *internal) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + int restype; + int *resources; + int count = 0; + int top = sci_max_resource_nr[version] + 1; + int i; + switch (type) { + + case GFX_RESOURCE_TYPE_VIEW: restype = sci_view; + break; + + case GFX_RESOURCE_TYPE_PIC: restype = sci_pic; + break; + + case GFX_RESOURCE_TYPE_CURSOR: restype = sci_cursor; + break; + + case GFX_RESOURCE_TYPE_FONT: restype = sci_font; + break; + + default: + GFX_DEBUG("Unsupported resource %d\n", type); + return NULL; /* unsupported resource */ + + } + + resources = (int*)sci_malloc(sizeof(int) * top); + + for (i = 0; i < top; i++) + if (scir_test_resource(resmgr, restype, i)) + resources[count++] = i; + + *entries_nr = count; + + return resources; +} + +gfx_pixmap_color_t * +gfxr_interpreter_get_static_palette(gfx_resstate_t *state, int version, int *colors_nr, void *internal) +{ + if (version >= SCI_VERSION_01_VGA) + return gfxr_interpreter_get_palette(state, version, colors_nr, internal, 999); + + *colors_nr = GFX_SCI0_PIC_COLORS_NR; + return gfx_sci0_pic_colors; +} + +gfx_pixmap_color_t * +gfxr_interpreter_get_palette(gfx_resstate_t *state, int version, int *colors_nr, + void *internal, int nr) +{ + resource_mgr_t *resmgr = (resource_mgr_t *) state->misc_payload; + resource_t *res; + + if (version < SCI_VERSION_01_VGA) + return NULL; + + res = scir_find_resource(resmgr, sci_palette, nr, 0); + if (!res || !res->data) + return NULL; + + switch (version) + { + case SCI_VERSION_01_VGA : + case SCI_VERSION_01_VGA_ODD : + case SCI_VERSION_1_EARLY : + case SCI_VERSION_1_LATE : + return gfxr_read_pal1(res->id, colors_nr, res->data, res->size); + case SCI_VERSION_1_1 : + case SCI_VERSION_32 : + GFX_DEBUG("Palettes are not yet supported in this SCI version\n"); + return NULL; + + default: + BREAKPOINT(); + return NULL; + } +} + +int +gfxr_interpreter_needs_multicolored_pointers(int version, void *internal) +{ + return (version > SCI_VERSION_1); +} + + + diff --git a/engines/sci/gfx/resource/sci_view_0.c b/engines/sci/gfx/resource/sci_view_0.c new file mode 100644 index 0000000000..98b3654b3c --- /dev/null +++ b/engines/sci/gfx/resource/sci_view_0.c @@ -0,0 +1,254 @@ +/*************************************************************************** + view_0.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +/* set optimisations for Win32: */ +#ifdef _WIN32 +# include <memory.h> +//# pragma intrinsic( memcpy, memset ) +#endif + +#include <sci_memory.h> +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + + +gfx_pixmap_t * +gfxr_draw_cel0(int id, int loop, int cel, byte *resource, int size, gfxr_view_t *view, int mirrored) +{ + int xl = get_int_16(resource); + int yl = get_int_16(resource + 2); + int xhot = ((signed char *) resource)[4]; + int yhot = ((signed char *) resource)[5]; + int color_key = resource[6]; + int pos = 7; + int writepos = mirrored? xl : 0; + int pixmap_size = xl * yl; + int line_base = 0; + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + + retval->color_key = 255; /* Pick something larger than 15 */ + + retval->xoffset = mirrored? xhot : -xhot; + retval->yoffset = -yhot; + + if (view) { + retval->colors = view->colors; + retval->colors_nr = view->colors_nr; + retval->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + } else + { + retval->colors = gfx_sci0_image_colors[sci0_palette]; + retval->colors_nr = GFX_SCI0_IMAGE_COLORS_NR; + retval->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + } + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(NULL, retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + if (mirrored) { + + while (yl && pos < size) { + int op = resource[pos++]; + int count = op >> 4; + int color = op & 0xf; + + if (view->flags & GFX_PIXMAP_FLAG_PALETTIZED) + color = view->translation[color]; + + if (color == color_key) + color = retval->color_key; + + while (count) { + int pixels = writepos - line_base; + + if (pixels > count) + pixels = count; + + writepos -= pixels; + memset(dest + writepos, color, pixels); + count -= pixels; + + if (writepos == line_base) { + yl--; + writepos += (xl << 1); + line_base += xl; + } + } + } + } else { + + while (writepos < pixmap_size && pos < size) { + int op = resource[pos++]; + int count = op >> 4; + int color = op & 0xf; + + if (view && (view->flags & GFX_PIXMAP_FLAG_PALETTIZED)) + color = view->translation[color]; + + if (color == color_key) + color = retval->color_key; + + if (writepos + count > pixmap_size) { + GFXERROR("View %02x:(%d/%d) writes RLE data over its designated end at rel. offset 0x%04x\n", id, loop, cel, pos); + return NULL; + } + + memset(dest + writepos, color, count); + writepos += count; + } + } + + return retval; +} + +static int +gfxr_draw_loop0(gfxr_loop_t *dest, int id, int loop, byte *resource, int offset, int size, gfxr_view_t *view, int mirrored) +{ + int i; + int cels_nr = get_int_16(resource + offset); + + if (get_uint_16(resource + offset + 2)) { + GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, get_uint_16(resource + offset + 2)); + } + + if (cels_nr * 2 + 4 + offset > size) { + GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); + dest->cels_nr = 0; /* Mark as "delete no cels" */ + dest->cels = NULL; + return 1; + } + + dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) { + int cel_offset = get_uint_16(resource + offset + 4 + (i << 1)); + gfx_pixmap_t *cel = NULL; + + if (cel_offset >= size) { + GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); + cel = NULL; + } else + cel = gfxr_draw_cel0(id, loop, i, resource + cel_offset, size - cel_offset, view, mirrored); + + + if (!cel) { + dest->cels_nr = i; + return 1; + } + + dest->cels[i] = cel; + } + + dest->cels_nr = cels_nr; + + return 0; +} + + +#define V0_LOOPS_NR_OFFSET 0 +#define V0_FIRST_LOOP_OFFSET 8 +#define V0_MIRROR_LIST_OFFSET 2 + +gfxr_view_t * +gfxr_draw_view0(int id, byte *resource, int size, int palette) +{ + int i; + gfxr_view_t *view; + int mirror_bitpos = 1; + int mirror_bytepos = V0_MIRROR_LIST_OFFSET; + int palette_ofs = get_int_16(resource + 6); + + if (size < V0_FIRST_LOOP_OFFSET + 8) { + GFXERROR("Attempt to draw empty view %04x\n", id); + return NULL; + } + + view = (gfxr_view_t*)sci_malloc(sizeof(gfxr_view_t)); + view->ID = id; + + view->loops_nr = resource[V0_LOOPS_NR_OFFSET]; + + /* Set palette */ + view->colors_nr = GFX_SCI0_IMAGE_COLORS_NR; + view->flags = GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + view->colors = gfx_sci0_image_colors[sci0_palette]; + + if ((palette_ofs)&&(palette>=0)) + { + byte *paldata = resource + palette_ofs + (palette * GFX_SCI0_IMAGE_COLORS_NR); + + for (i = 0; i < GFX_SCI0_IMAGE_COLORS_NR; i++) + view->translation[i] = *(paldata++); + + view->flags |= GFX_PIXMAP_FLAG_PALETTIZED; + } + + if (view->loops_nr * 2 + V0_FIRST_LOOP_OFFSET > size) { + GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); + free(view); + return NULL; + } + + view->loops = (gfxr_loop_t*)sci_malloc(sizeof (gfxr_loop_t) * ((view->loops_nr)? view->loops_nr : 1)); /* Alloc 1 if no loop */ + + for (i = 0; i < view->loops_nr; i++) { + int error_token = 0; + int loop_offset = get_uint_16(resource + V0_FIRST_LOOP_OFFSET + (i << 1)); + int mirrored = resource[mirror_bytepos] & mirror_bitpos; + + if ((mirror_bitpos <<= 1) == 0x100) { + mirror_bytepos++; + mirror_bitpos = 1; + } + + if (loop_offset >= size) { + GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i, loop_offset); + error_token = 1; + } + + if (error_token || gfxr_draw_loop0(view->loops + i, id, i, resource, loop_offset, size, view, mirrored)) { + /* An error occured */ + view->loops_nr = i; + gfxr_free_view(NULL, view); + return NULL; + } + } + + return view; +} + + + + + + + diff --git a/engines/sci/gfx/resource/sci_view_1.c b/engines/sci/gfx/resource/sci_view_1.c new file mode 100644 index 0000000000..1387696416 --- /dev/null +++ b/engines/sci/gfx/resource/sci_view_1.c @@ -0,0 +1,554 @@ +/*************************************************************************** + view_1.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* SCI 1 view resource defrobnicator */ + +#include <sci_memory.h> +#include <gfx_system.h> +#include <gfx_resource.h> +#include <gfx_tools.h> + +#define V1_LOOPS_NR_OFFSET 0 +#define V1_MIRROR_MASK 2 +#define V1_PALETTE_OFFSET 6 +#define V1_FIRST_LOOP_OFFSET 8 + +#define V1_RLE 0x80 /* run-length encode? */ +#define V1_RLE_BG 0x40 /* background fill */ + +#define NEXT_RUNLENGTH_BYTE(n) \ + if (literal_pos == runlength_pos) \ + literal_pos += n; \ + runlength_pos += n; + +#define NEXT_LITERAL_BYTE(n) \ + if (literal_pos == runlength_pos) \ + runlength_pos += n; \ + literal_pos += n; + +static int +decompress_sci_view(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, + int runlength_pos, int literal_pos, int xl, int yl, int color_key) +{ + int writepos = mirrored? xl : 0; + + if (mirrored) { + int linebase = 0; + + while (linebase < pixmap_size && literal_pos < size && runlength_pos < size) { + int op = resource[runlength_pos]; + int bytes; + int readbytes = 0; + int color; + + NEXT_RUNLENGTH_BYTE(1); + + if (op & V1_RLE) { + bytes = op & 0x3f; + op &= (V1_RLE | V1_RLE_BG); + readbytes = (op & V1_RLE_BG)? 0 : 1; + } else { + readbytes = bytes = op & 0x3f; + op = 0; + } + + if (runlength_pos + readbytes > size) + { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, readbytes, size - runlength_pos, runlength_pos-1); + return 1; + } +/* + if (writepos - bytes < 0) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos - bytes, pixmap_size, pos - 1); + bytes = pixmap_size - writepos; + } +*/ + if (op==V1_RLE) + { + color = resource[literal_pos]; + NEXT_LITERAL_BYTE(1); + } + + if (!op && literal_pos + bytes > size) + { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, bytes, size - literal_pos, literal_pos-1); + return 1; + } + + while (bytes--) + { + if (op) { + if (op & V1_RLE_BG) { + writepos--; + *(dest + writepos) = color_key; + } else { + writepos--; + *(dest + writepos) = color; + } + } else { + writepos--; + *(dest + writepos) = *(resource + literal_pos); + NEXT_LITERAL_BYTE(1); + + } + if (writepos == linebase) + { + writepos+=2*xl; + linebase+=xl; + } + } + } + } + else { + while (writepos < pixmap_size && literal_pos < size && runlength_pos < size) { + int op = resource[runlength_pos]; + int bytes; + int readbytes = 0; + + NEXT_RUNLENGTH_BYTE(1); + + if (op & V1_RLE) { + bytes = op & 0x3f; + op &= (V1_RLE | V1_RLE_BG); + readbytes = (op & V1_RLE_BG)? 0 : 1; + } else { + readbytes = bytes = op & 0x3f; + op = 0; + } + + if (runlength_pos + readbytes > size) { + return 1; + } + + if (writepos + bytes > pixmap_size) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos-bytes, pixmap_size, runlength_pos - 1); + bytes = pixmap_size - writepos; + } + + if (!op && literal_pos + bytes > size) + { + GFXWARN("View %02x:(%d/%d) requires %d bytes to be read when %d are available at pos %d\n", + id, loop, cel, bytes, size - literal_pos, literal_pos-1); + return 1; + } + + if (writepos + bytes > pixmap_size) + { + GFXWARN("Writing out of bounds: %d bytes at %d > size %d\n", bytes, writepos, pixmap_size); + } + + if (op) { + if (op & V1_RLE_BG) + memset(dest + writepos, color_key, bytes); + else { + int color = resource[literal_pos]; + + NEXT_LITERAL_BYTE(1); + memset(dest + writepos, color, bytes); + } + } else { + memcpy(dest + writepos, resource + literal_pos, bytes); + NEXT_LITERAL_BYTE(bytes); + } + writepos += bytes; + + } + + }; + + return 0; +} + +static int +decompress_sci_view_amiga(int id, int loop, int cel, byte *resource, byte *dest, int mirrored, int pixmap_size, int size, + int pos, int xl, int yl, int color_key) +{ + int writepos = mirrored? xl - 1 : 0; + + while (writepos < pixmap_size && pos < size) { + int op = resource[pos++]; + int bytes; + int color; + + if (op & 0x07) { + bytes = op & 0x07; + color = op >> 3; + } else { + bytes = op >> 3; + color = color_key; + } + + if (mirrored) { + while (bytes--) { + dest[writepos--] = color; + /* If we've just written the first pixel of a line... */ + if (!((writepos + 1) % xl)) { + /* Then move to the end of next line */ + writepos += 2 * xl; + + if (writepos >= pixmap_size && bytes) + { + GFXWARN("View %02x:(%d/%d) writing out of bounds\n", id, loop, cel); + break; + } + } + } + } else { + if (writepos + bytes > pixmap_size) { + GFXWARN("View %02x:(%d/%d) describes more bytes than needed: %d/%d bytes at rel. offset 0x%04x\n", + id, loop, cel, writepos-bytes, pixmap_size, pos - 1); + bytes = pixmap_size - writepos; + } + memset(dest + writepos, color, bytes); + writepos += bytes; + } + } + + if (writepos < pixmap_size) { + GFXWARN("View %02x:(%d/%d) not enough pixel data in view\n", id, loop, cel); + return 1; + } + + return 0; +} + +gfx_pixmap_t * +gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, int size, gfxr_view_t *view, int amiga_game) +{ + int xl = get_int_16(resource); + int yl = get_int_16(resource + 2); + int xhot = (gint8) resource[4]; + int yhot = (guint8) resource[5]; + int pos = 8; + int pixmap_size = xl * yl; + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + int decompress_failed; + + retval->color_key = resource[6]; + retval->xoffset = (mirrored)? xhot : -xhot; + retval->yoffset = -yhot; + + if (view) { + retval->colors = view->colors; + retval->colors_nr = view->colors_nr; + } + + retval->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(NULL, retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + if (amiga_game) + decompress_failed = decompress_sci_view_amiga(id, loop, cel, + resource, dest, mirrored, pixmap_size, size, pos, + xl, yl, retval->color_key); + else + decompress_failed = decompress_sci_view(id, loop, cel, + resource, dest, mirrored, pixmap_size, size, pos, + pos, xl, yl, retval->color_key); + + if (decompress_failed) { + gfx_free_pixmap(NULL, retval); + return NULL; + } + + return retval; +} + +static int +gfxr_draw_loop1(gfxr_loop_t *dest, int id, int loop, int mirrored, byte *resource, int offset, int size, gfxr_view_t *view, int amiga_game) +{ + int i; + int cels_nr = get_int_16(resource + offset); + + if (get_uint_16(resource + offset + 2)) { + GFXWARN("View %02x:(%d): Gray magic %04x in loop, expected white\n", id, loop, get_uint_16(resource + offset + 2)); + } + + if (cels_nr * 2 + 4 + offset > size) { + GFXERROR("View %02x:(%d): Offset array for %d cels extends beyond resource space\n", id, loop, cels_nr); + dest->cels_nr = 0; /* Mark as "delete no cels" */ + dest->cels = NULL; + return 1; + } + + dest->cels = (gfx_pixmap_t**)sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) { + int cel_offset = get_uint_16(resource + offset + 4 + (i << 1)); + gfx_pixmap_t *cel; + + if (cel_offset >= size) { + GFXERROR("View %02x:(%d/%d) supposed to be at illegal offset 0x%04x\n", id, loop, i, cel_offset); + cel = NULL; + } else + cel = gfxr_draw_cel1(id, loop, i, mirrored, resource + cel_offset, size - cel_offset, view, amiga_game); + + if (!cel) { + dest->cels_nr = i; + return 1; + } + + dest->cels[i] = cel; + } + + dest->cels_nr = cels_nr; + + return 0; +} + + +#define V1_FIRST_MAGIC 1 +#define V1_MAGICS_NR 5 +/*static byte view_magics[V1_MAGICS_NR] = {0x80, 0x00, 0x00, 0x00, 0x00};*/ + +gfxr_view_t * +gfxr_draw_view1(int id, byte *resource, int size, gfx_pixmap_color_t *static_pal, + int static_pal_nr) +{ + int i; + int palette_offset; + gfxr_view_t *view; + int mirror_mask; + int amiga_game = 0; + + if (size < V1_FIRST_LOOP_OFFSET + 8) { + GFXERROR("Attempt to draw empty view %04x\n", id); + return NULL; + } + + view = (gfxr_view_t*)sci_malloc(sizeof(gfxr_view_t)); + view->ID = id; + view->flags = 0; + + view->loops_nr = resource[V1_LOOPS_NR_OFFSET]; + palette_offset = get_uint_16(resource + V1_PALETTE_OFFSET); + mirror_mask = get_uint_16(resource + V1_MIRROR_MASK); + + if (view->loops_nr * 2 + V1_FIRST_LOOP_OFFSET > size) { + GFXERROR("View %04x: Not enough space in resource to accomodate for the claimed %d loops\n", id, view->loops_nr); + free(view); + return NULL; + } + +/* fprintf(stderr, "View flags are 0x%02x\n", resource[3]);*/ + +/* + for (i = 0; i < V1_MAGICS_NR; i++) + if (resource[V1_FIRST_MAGIC + i] != view_magics[i]) { + GFXWARN("View %04x: View magic #%d should be %02x but is %02x\n", + id, i, view_magics[i], resource[V1_FIRST_MAGIC + i]); + } +*/ + + if (palette_offset > 0) + { + if (palette_offset > size) { + GFXERROR("Palette is outside of view %04x\n", id); + free(view); + return NULL; + } + if (!(view->colors = gfxr_read_pal1(id, &(view->colors_nr), + resource + palette_offset, size - palette_offset))) { + GFXERROR("view %04x: Palette reading failed. Aborting...\n", id); + free(view); + return NULL; + } + } else if (static_pal_nr == GFX_SCI1_AMIGA_COLORS_NR) { + /* Assume we're running an amiga game. */ + amiga_game = 1; + view->colors = static_pal; + view->colors_nr = static_pal_nr; + view->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + } else { + GFXWARN("view %04x: Doesn't have a palette. Can FreeSCI handle this?\n", view->ID); + view->colors = NULL; + view->colors_nr = 0; + } + + view->loops = (gfxr_loop_t*)sci_malloc(sizeof (gfxr_loop_t) * view->loops_nr); + + for (i = 0; i < view->loops_nr; i++) { + int error_token = 0; + int loop_offset = get_uint_16(resource + V1_FIRST_LOOP_OFFSET + (i << 1)); + + if (loop_offset >= size) { + GFXERROR("View %04x:(%d) supposed to be at illegal offset 0x%04x\n", id, i); + error_token = 1; + } + + if (error_token || gfxr_draw_loop1(view->loops + i, id, i, mirror_mask & (1<<i), + resource, loop_offset, size, view, amiga_game)) { + /* An error occured */ + view->loops_nr = i; + gfxr_free_view(NULL, view); + return NULL; + } + } + + return view; +} + +#define V2_HEADER_SIZE 0 +#define V2_LOOPS_NUM 2 +#define V2_PALETTE_OFFSET 8 +#define V2_BYTES_PER_LOOP 12 +#define V2_BYTES_PER_CEL 13 + +#define V2_IS_MIRROR 1 +#define V2_COPY_OF_LOOP 2 +#define V2_CELS_NUM 4 +#define V2_LOOP_OFFSET 14 + +#define V2_CEL_WIDTH 0 +#define V2_CEL_HEIGHT 2 +#define V2_X_DISPLACEMENT 4 +#define V2_Y_DISPLACEMENT 6 +#define V2_COLOR_KEY 8 +#define V2_RUNLENGTH_OFFSET 24 +#define V2_LITERAL_OFFSET 28 + +gfx_pixmap_t * +gfxr_draw_cel11(int id, int loop, int cel, int mirrored, byte *resource_base, byte *cel_base, int size, gfxr_view_t *view) +{ + int xl = get_uint_16(cel_base + V2_CEL_WIDTH); + int yl = get_uint_16(cel_base + V2_CEL_HEIGHT); + int xdisplace = get_uint_16(cel_base + V2_X_DISPLACEMENT); + int ydisplace = get_uint_16(cel_base + V2_Y_DISPLACEMENT); + int runlength_offset = get_uint_16(cel_base + V2_RUNLENGTH_OFFSET); + int literal_offset = get_uint_16(cel_base + V2_LITERAL_OFFSET); + int pixmap_size = xl * yl; + + gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); + byte *dest = retval->index_data; + int decompress_failed; + + retval->color_key = cel_base[V2_COLOR_KEY]; + retval->xoffset = (mirrored)? xdisplace : -xdisplace; + retval->yoffset = -ydisplace; + + if (view) { + retval->colors = view->colors; + retval->colors_nr = view->colors_nr; + } + + retval->flags |= GFX_PIXMAP_FLAG_EXTERNAL_PALETTE; + + if (xl <= 0 || yl <= 0) { + gfx_free_pixmap(NULL, retval); + GFXERROR("View %02x:(%d/%d) has invalid xl=%d or yl=%d\n", id, loop, cel, xl, yl); + return NULL; + } + + decompress_failed = decompress_sci_view(id, loop, cel, resource_base, dest, mirrored, pixmap_size, size, + runlength_offset, literal_offset, xl, yl, retval->color_key); + + if (decompress_failed) { + gfx_free_pixmap(NULL, retval); + return NULL; + } + + return retval; +} + +gfxr_loop_t * +gfxr_draw_loop11(int id, int loop, int mirrored, byte *resource_base, byte *loop_base, int size, int cels_nr, + gfxr_loop_t *result, gfxr_view_t *view, int bytes_per_cel) +{ + byte *seeker = loop_base; + int i; + + result->cels_nr = cels_nr; + result->cels = (gfx_pixmap_t **) + sci_malloc(sizeof(gfx_pixmap_t *) * cels_nr); + + for (i = 0; i < cels_nr; i++) + { + result->cels[i] = gfxr_draw_cel11(id, loop, i, mirrored, resource_base, seeker, size, view); + seeker += bytes_per_cel; + } + + return result; +} + +gfxr_view_t * +gfxr_draw_view11(int id, byte *resource, int size) +{ + gfxr_view_t *view; + int header_size = get_uint_16(resource + V2_HEADER_SIZE); + int palette_offset = get_uint_16(resource + V2_PALETTE_OFFSET); + int bytes_per_loop = resource[V2_BYTES_PER_LOOP]; + int loops_num = resource[V2_LOOPS_NUM]; + int bytes_per_cel = resource[V2_BYTES_PER_CEL]; + int i; + byte *seeker; + + view = (gfxr_view_t*)sci_malloc(sizeof(gfxr_view_t)); + + memset(view, 0, sizeof(gfxr_view_t)); + view->ID = id; + view->flags = 0; + + view->loops_nr = loops_num; + view->loops = (gfxr_loop_t *)calloc(view->loops_nr, sizeof(gfxr_loop_t)); + + /* There is no indication of size here, but this is certainly large enough */ + view->colors = gfxr_read_pal11(id, &view->colors_nr, resource + palette_offset, 1284); + + seeker = resource + header_size; + for (i = 0; i < view->loops_nr; i++) + { + static char *truth[2] = {"not ",""}; + int loop_offset = get_uint_16(seeker + V2_LOOP_OFFSET); + int cels = seeker[V2_CELS_NUM]; + int mirrored = seeker[V2_IS_MIRROR]; + int copy_entry = seeker[V2_COPY_OF_LOOP]; + + printf("%d\n", mirrored); + if (copy_entry == 255) + gfxr_draw_loop11(id, i, 0, resource, resource + loop_offset, size, cels, view->loops + i, + view, bytes_per_cel); else + { + byte *temp = resource + header_size + copy_entry * bytes_per_loop; + loop_offset = get_uint_16(temp + V2_LOOP_OFFSET); + cels = temp[V2_CELS_NUM]; + gfxr_draw_loop11(id, i, 1, resource, resource + loop_offset, size, cels, + view->loops + i, view, bytes_per_cel); + } + + seeker += bytes_per_loop; + } + + return view; +} diff --git a/engines/sci/gfx/sbtree.c b/engines/sci/gfx/sbtree.c new file mode 100644 index 0000000000..b5e2c6b068 --- /dev/null +++ b/engines/sci/gfx/sbtree.c @@ -0,0 +1,473 @@ +/*************************************************************************** + sbtree.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ +/* Static binary lookup tree lookup */ + + +#include <sci_memory.h> +#include <sbtree.h> +#include <stdlib.h> +#include <stdio.h> + +#define NOT_A_KEY -1 + +typedef struct { + int key; + void *value; +} sbcell_t; + +int +int_compar(const void *a, const void *b) +{ + return (*((int *)a))-(*((int *)b)); +} + + +void +insert_interval(sbcell_t *data, int start, int stop, int *keys, int plus) +{ + int center = start + ((stop - start) >> 1); + + data->key = keys[center]; + + if (start == stop) + return; + + if (center > start) + insert_interval(data + plus, start, center - 1, keys, plus << 1); + + if (center < stop) + insert_interval(data + plus + 1, center + 1, stop, keys, ((plus << 1) + 1)); +} + +sbtree_t * +sbtree_new(int size, int *keys) +{ + int table_size = 2; + int levels = 0; + sbcell_t *table; + sbtree_t *tree; + int i; + + if (size < 0) + return NULL; + + while (table_size <= size) { + table_size <<= 1; + ++levels; + } + + if (table_size > 1) + --table_size; + + table = (sbcell_t*)sci_calloc(sizeof(sbcell_t), table_size); + for (i = 0; i < table_size; i++) + table[i].key = NOT_A_KEY; + + if (!table) { + fprintf(stderr,"SBTree: Out of memory: Could not allocate %d cells\n", table_size); + return NULL; + } + + tree = (sbtree_t*)sci_malloc(sizeof(sbtree_t)); + + if (!tree) { + fprintf(stderr,"SBTree: Could not allocate tree structure\n"); + free(table); + return NULL; + } + + qsort(keys, size, sizeof(int), int_compar); + + insert_interval(table, 0, size-1, keys, 1); + + tree->levels = levels; + tree->entries_nr = size; + if ((tree->min_entry = keys[0]) < 0) { + fprintf(stderr,"SBTree: Error: Using negative keys\n"); + free(table); + free(tree); + return NULL; + } + tree->max_entry = keys[size - 1]; + tree->data = (void *) table; + tree->alloced_entries = table_size; + return tree; +} + + +void +sbtree_free(sbtree_t *tree) +{ + if (!tree) { + fprintf(stderr,"SBTree: Attempt to free NULL sbtree\n"); + return; + } + + free(tree->data); + free(tree); +} + + +void +sbtree_foreach(sbtree_t *tree, void *args, void *(*operation)(sbtree_t *, const int, + const void *, void *)) +{ + int i; + sbcell_t *cell = (sbcell_t *) tree->data; + + for (i = 0; i < tree->alloced_entries; i++) { + if (cell->key != NOT_A_KEY) + cell->value = operation(tree, cell->key, cell->value, args); + cell = cell + 1; + } +} + +sbcell_t * +locate(sbcell_t *start, int key, int level, int levels, int plus) +{ + int comparison; + + if (level >= levels && (level != levels || start->key == NOT_A_KEY)) + /* For large tables, the speed improvement caused by this comparison + ** scheme is almost (cough) measurable... + */ + return NULL; + + comparison = key - start->key; + + if (!comparison) + return start; + + return locate(start + plus + (comparison > 0), key, level + 1, levels, (plus << 1) + (comparison > 0)); +} + + +int +sbtree_set(sbtree_t *tree, int key, void *value) +{ + sbcell_t *cell = locate((sbcell_t *) tree->data, key, 0, tree->levels, 1); + + if (cell) + cell->value = value; + else + return -1; + + return 0; +} + + +void * +sbtree_get(sbtree_t *tree, int key) +{ + sbcell_t *cell = locate((sbcell_t *) tree->data, key, 0, tree->levels, 1); + + if (cell) + return cell->value; + else + return NULL; +} + +static void +sbtree_print(sbtree_t *tree) +{ + int l, i; + sbcell_t *cells = (sbcell_t *) tree->data; + + fprintf(stderr,"\tTree:\n"); + for (l = 0; l <= tree->levels; l++) { + fprintf(stderr,"\t "); + for (i = 0; i < (1 << l); i++) { + if (cells->key == NOT_A_KEY) + fprintf(stderr,"-- "); + else { + if (cells->value) + fprintf(stderr,"%d+ ", cells->key); + else + fprintf(stderr,"%d ", cells->key); + } + + cells = cells + 1; + } + fprintf(stderr,"\n"); + } + fprintf(stderr,"\n"); +} + + + +/***************************** TEST CODE ********************************/ + + +#ifdef SBTREE_DEBUG + +static int any_error; + + +void * +foreach_double_func(sbtree_t *tree, const int key, const void *value, void *args) +{ + int *real_value = (int *) value; + + if (!real_value) + fprintf(stderr,"foreach_double_func(): key %d mapped to non-value!\n", key); + else *real_value *= 2; + + return real_value; +} + +int * +generate_linear_forward(int numbers) +{ + int i; + int *data = sci_malloc(sizeof(int) * numbers); + for (i = 0; i < numbers; i++) + data[i] = i + 1; + + return data; +} + +int * +generate_linear_backward(int numbers) +{ + int i; + int *data = sci_malloc(sizeof(int) * numbers); + for (i = 0; i < numbers; i++) + data[i] = numbers - i; + + return data; +} + +int * +generate_random(int numbers, int max) +{ + int i; + int *data = sci_malloc(sizeof(int) * numbers); + + for (i = 0; i < numbers; i++) + data[i] = 1 + (int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); + + return data; +} + + +void +insert_values(sbtree_t *tree, int nr, int *data) +{ + int i; + + for (i = 0; i < nr; i++) + if (sbtree_set(tree, data[i], (void *)(data + i))) { + fprintf(stderr, "While inserting: %d incorrectly deemed invalid\n", data[i]); + any_error = 1; + } +} + + +#define MODE_LINEAR 0 +#define MODE_LINEAR_MAP 1 +#define MODE_RANDOM 2 +#define MODE_LINEAR_DOUBLE 3 + +void +test_value(sbtree_t *tree, int times, int max, int numbers, int *data, int mode) +{ + int i; + int failed = 0; + + for (i = 0; i < times; i++) { + int key = (mode == MODE_LINEAR || mode == MODE_LINEAR_DOUBLE)? i : + (mode == MODE_LINEAR_MAP)? data[i % numbers] : + (int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); + int *value = (int *) sbtree_get(tree, (mode == MODE_LINEAR_DOUBLE)? key >> 1 : key); + int found = 0; + int j; + + for (j = 0; j < numbers && !found; j++) + if (data[j] == key) + found = 1; + + if (found && !value) { + fprintf(stderr, "!%d ", key); + ++failed; + } + else if (!found && found) { + fprintf(stderr, "?[%d]=%d ", key, *value); + ++failed; + } + } + + if (failed) + fprintf(stderr, "(%d/%d errors)\n", any_error = failed, times); + else + fprintf(stderr, "OK\n"); +} + + +void +test_boundary(sbtree_t *tree, int max, int random) +{ + int *value_too_low = sbtree_get(tree, 0); + int *value_too_high = sbtree_get(tree, max + 1); + int *value_low = sbtree_get(tree, 1); + int *value_high = sbtree_get(tree, max); + int failure = (value_too_low || value_too_high || (!random && (!value_low || !value_high))); + + if (!failure) + fprintf(stderr, "OK\n"); + else { + any_error = 1; + + fprintf(stderr, "Errors: "); + if (value_too_low) + fprintf(stderr, "too-low=%d ", *value_too_low); + if (value_too_high) + fprintf(stderr, "too-high=%d ", *value_too_high); + + if (!random) { + if (!value_low) + fprintf(stderr, "!low "); + if (!value_high) + fprintf(stderr, "!high "); + } + fprintf(stderr, "\n"); + } +} + + +void +test_empty(sbtree_t *tree, int count, int max) +{ + int i; + int errors = 0; + + for (i = 0; i < count; i++) { + int key = 1 + (int) ((rand() * 1.0 * max) / (RAND_MAX + 1.0)); + int *value; + + if ((value = (int *) sbtree_get(tree, key))) { + fprintf(stderr, "?[%d]=%d\n", key, *value); + ++errors; + } + } + + if (errors) + fprintf(stderr," (%d/%d errors)\n", any_error = errors, count); + else + fprintf(stderr,"OK\n"); +} + +void +run_test(sbtree_t *tree, int entries, int *data, int random, int max_value) +{ + char *tests[] = {"\tLinear reference test: \t\t", "\tKey map reference test: \t", "\tRandom access test: \t\t"}; + int i; + + any_error = 0; + + fprintf(stderr, "\tEmpty test: \t\t\t"); + test_empty(tree, entries * 2, entries + 1); + insert_values(tree, entries, data); + fprintf(stderr, "\tBoundary test: \t\t\t"); + test_boundary(tree, max_value, random); + + for (i = 0; i < 3; i++) { + fprintf(stderr, tests[i]); + test_value(tree, entries * 2, entries * 2, entries, data, i); + } + + if (!random) { + i = data[0]; + sbtree_foreach(tree, NULL, foreach_double_func); + fprintf(stderr, "\tForeach test: \t\t\t"); + if (i * 2 != data[0]) { + fprintf(stderr,"Error: No effect: %d * 2 != %d\n", i, data[0]); + any_error = 1; + } else + test_value(tree, entries * 2, entries * 2, entries, data, MODE_LINEAR_DOUBLE); + } + + if (any_error) + sbtree_print(tree); + + free(data); + sbtree_free(tree); +} + + +#define TESTS_NR 11 + +int +main(int argc, char **argv) +{ + int tests_nr = TESTS_NR; + int test_sizes[TESTS_NR] = {1, 2, 3, 7, 8, 9, 1000, 16383, 16384, 16385, 1000000}; + int i; + fprintf(stderr, "sbtree.c Copyright (C) 2000 Christoph Reichenbach <jameson@linuxgames.com>\n" + "This program is provided WITHOUT WARRANTY of any kind\n" + "Please refer to the file COPYING that should have come with this program\n"); + fprintf(stderr, "Static Binary Tree testing facility\n"); + + free(malloc(42)); /* Make sure libefence's Copyright message is print here if we're using it */ + + fprintf(stderr,"\nsbtree.c: Running %d tests.\n", tests_nr); + + for (i = 0; i < tests_nr; i++) { + int entries = test_sizes[i]; + sbtree_t *tree; + int *data; + + fprintf(stderr,"Test #%d: %d entries\n", i+1, entries); + + fprintf(stderr,"\t%da: Linear values\n", i+1); + data = generate_linear_forward(entries); + tree = sbtree_new(entries, data); + run_test(tree, entries, data, 0, entries); + + fprintf(stderr,"\t%db: Reverse linear values\n", i+1); + data = generate_linear_backward(entries); + tree = sbtree_new(entries, data); + run_test(tree, entries, data, 0, entries); + + fprintf(stderr,"\t%dc: Dense random values\n", i+1); + data = generate_random(entries, 1 + (entries >> 2)); + tree = sbtree_new(entries, data); + run_test(tree, entries, data, 1, 1 + (entries >> 2)); + + fprintf(stderr,"\t%dc: Sparse random values\n", i+1); + data = generate_random(entries, (entries << 2)); + tree = sbtree_new(entries, data); + run_test(tree, entries, data, 1, entries << 2); + + fprintf(stderr,"Test #%d completed.\n\n", i+1); + } + + fprintf(stderr,"Test suite completed.\n"); + return 0; +} + + +#endif /* SBTREE_DEBUG */ diff --git a/engines/sci/gfx/sci_widgets.c b/engines/sci/gfx/sci_widgets.c new file mode 100644 index 0000000000..fe4cfda1a3 --- /dev/null +++ b/engines/sci/gfx/sci_widgets.c @@ -0,0 +1,765 @@ +/*************************************************************************** + sci_widgets.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <gfx_operations.h> +#include <gfx_widgets.h> +#include <engine.h> +#include <menubar.h> +#include <sci_widgets.h> + +#define SCI_SPECIAL_CHAR_ARROW_UP 0x18 +#define SCI_SPECIAL_CHAR_ARROW_DOWN 0x19 + + +static void +clear_titlebar(gfxw_port_t *titlebar) +{ + if (titlebar->contents) { + titlebar->contents->widfree(titlebar->contents); + titlebar->contents = NULL; + titlebar->nextpp = &(titlebar->contents); + } +} + +static gfxw_list_t * +make_titlebar_list(state_t *s, rect_t bounds, gfxw_port_t *status_bar) +{ + gfx_color_t color = status_bar->bgcolor; + gfxw_list_t *list; + gfxw_box_t *bgbox; + + + list = gfxw_new_list(status_bar->bounds, 0); + bgbox = gfxw_new_box(s->gfx_state, gfx_rect(0, 0, status_bar->bounds.xl, status_bar->bounds.yl - 1), + color, color, GFX_BOX_SHADE_FLAT); + + list->add((gfxw_container_t *) list, (gfxw_widget_t *) bgbox); + + return list; +} + +static gfxw_list_t * +finish_titlebar_list(state_t *s, gfxw_list_t *list, gfxw_port_t *status_bar) +{ + gfx_color_t black = s->ega_colors[0]; + gfxw_primitive_t *line; + + line = gfxw_new_line(gfx_point(0, status_bar->bounds.yl - 1), + gfx_point(status_bar->bounds.xl, status_bar->bounds.yl - 1), + black, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL); + list->add((gfxw_container_t *) list, (gfxw_widget_t *) line); + + return list; +} + +void +sciw_set_status_bar(state_t *s, gfxw_port_t *status_bar, char *text, int fgcolor, int bgcolor) +{ + gfx_state_t *state; + gfxw_list_t *list; + gfx_color_t bg = status_bar->bgcolor; + gfx_color_t fg = status_bar->color; + gfx_color_t black = s->ega_colors[0]; + + if (!status_bar->visual) { + GFXERROR("Attempt to change title bar without visual!\n"); + return; + } + + state = status_bar->visual->gfx_state; + + if (!state) { + GFXERROR("Attempt to change title bar with stateless visual!\n"); + return; + } + + clear_titlebar(status_bar); + + if (text) { + gfxw_text_t *textw = gfxw_new_text(state, gfx_rect(0, 0, status_bar->bounds.xl, status_bar->bounds.yl), + status_bar->font_nr, text, ALIGN_LEFT, ALIGN_CENTER, + fg, fg, bg, GFXR_FONT_FLAG_NO_NEWLINES); + + list = make_titlebar_list(s, status_bar->bounds, status_bar); + + list->add((gfxw_container_t *) list, (gfxw_widget_t *) textw); + + } else { + gfxw_box_t *bgbox = gfxw_new_box(state, gfx_rect(0, 0, status_bar->bounds.xl, status_bar->bounds.yl - 1), + black, black, GFX_BOX_SHADE_FLAT); + + list = gfxw_new_list(status_bar->bounds, 0); + + list->add((gfxw_container_t *) list, (gfxw_widget_t *) bgbox); + } + + list->add(GFXWC(status_bar), GFXW(list)); + finish_titlebar_list(s, list, status_bar); + + status_bar->draw(GFXW(status_bar), gfxw_point_zero); + gfxop_update(state); +} + +static void +sciw_make_window_fit(rect_t *rect, gfxw_port_t *parent) +{ + /* This window is meant to cover the whole screen, so we allow it to go through. */ + if (rect->xl == 319 && rect->yl == 189) return; + + if (rect->x + rect->xl > parent->bounds.x + parent->bounds.xl) + rect->x -= (rect->x + rect->xl) - (parent->bounds.x + parent->bounds.xl) + 2; + + if (rect->y + rect->yl > parent->bounds.y + parent->bounds.yl) + rect->y -= (rect->y + rect->yl) - (parent->bounds.y + parent->bounds.yl) + 2; +} + +gfxw_port_t * +sciw_new_window(state_t *s, rect_t area, int font, gfx_color_t color, gfx_color_t bgcolor, + int title_font, gfx_color_t title_color, gfx_color_t title_bgcolor, + const char *title, int flags) +{ + gfxw_visual_t *visual = s->visual; + gfx_state_t *state = s->gfx_state; + int shadow_offset = 2; + rect_t frame; + gfx_color_t black = {0}; + gfxw_port_t *win; + gfxw_list_t *decorations; + int xextra = !(flags & WINDOW_FLAG_NOFRAME) ? 1 : 0; + int yextra = !(flags & WINDOW_FLAG_NOFRAME) ? 2 : 0; + + if (area.xl == 319 && area.yl == 189) + { + flags |= WINDOW_FLAG_NOFRAME; + /* The below line makes the points bar in QfG2 work, but breaks + the one in QfG1. Hm. */ + if (bgcolor.priority == 255) /* Yep, QfG2 */ + area.y += 3; + } + + /* + if (area.y + area.yl > visual->bounds.y + visual->bounds.yl) + { + area.y -= (area.y + area.yl) - (visual->bounds.y + visual->bounds.yl) + yextra; + } + + if (area.x + area.xl > visual->bounds.x + visual->bounds.xl) + { + area.x -= (area.x + area.xl) - (visual->bounds.x + visual->bounds.xl) + xextra; + } + */ + + if (flags & WINDOW_FLAG_TITLE) + area. y += 10; + + if (!(flags & (WINDOW_FLAG_TITLE | WINDOW_FLAG_NOFRAME))) + area.yl -= 1; /* Normal windows are drawn one pixel too small. */ + + sciw_make_window_fit(&area, s->wm_port); + win = gfxw_new_port(visual, s->wm_port, area, color, bgcolor); + + win->font_nr = font; + win->title_text = title; + win->port_flags = flags; + + win->flags |= GFXW_FLAG_IMMUNE_TO_SNAPSHOTS; + + if (flags & WINDOW_FLAG_DONTDRAW) + flags = WINDOW_FLAG_TRANSPARENT | WINDOW_FLAG_NOFRAME; + + if (flags == (WINDOW_FLAG_TRANSPARENT | WINDOW_FLAG_NOFRAME)) + return win; /* Fully transparent window */ + + if (flags & WINDOW_FLAG_TITLE) + frame = gfx_rect(area.x-1, area.y-10, area.xl + 2, area.yl + 11); + else + frame = gfx_rect(area.x-1, area.y-1, area.xl + 2, area.yl + 2); + + /* Set visible window boundaries */ + win->bounds = gfx_rect(frame.x, frame.y, frame.xl + shadow_offset, frame.yl + shadow_offset); + + decorations = gfxw_new_list(gfx_rect(frame.x, frame.y, + frame.xl + 1 + shadow_offset, frame.yl + 1 + shadow_offset), 0); + + if (!(flags & WINDOW_FLAG_TRANSPARENT)) { + /* Draw window background */ + win->port_bg = (gfxw_widget_t *) gfxw_new_box (state, + gfx_rect(1, (flags & WINDOW_FLAG_TITLE)? 10 : 1, + area.xl, area.yl), + bgcolor, bgcolor, GFX_BOX_SHADE_FLAT); + decorations->add((gfxw_container_t *) decorations, win->port_bg); + win->flags |= GFXW_FLAG_OPAQUE; + } + + if (flags & WINDOW_FLAG_TITLE) { + /* Add window title */ + rect_t title_rect = gfx_rect(1, 1, area.xl, 8); + + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_box(state, title_rect, title_bgcolor, title_bgcolor, GFX_BOX_SHADE_FLAT)); + + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_text(state, title_rect, title_font, title, + ALIGN_CENTER, ALIGN_CENTER, title_color, title_color, + title_bgcolor, GFXR_FONT_FLAG_NO_NEWLINES)); + } + + if (!(flags & WINDOW_FLAG_NOFRAME)) { + /* Draw backdrop shadow */ + + if (!(flags & WINDOW_FLAG_NO_DROP_SHADOW)) { + if (gfxop_set_color(state, &black, 0, 0, 0, 0x80, bgcolor.priority, -1)) { + GFXERROR("Could not get black/semitrans color entry!\n"); + return NULL; + } + + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_box(state, gfx_rect(shadow_offset + 1, frame.yl - 1, + frame.xl - 4, shadow_offset), + black, black, GFX_BOX_SHADE_FLAT)); + + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_box(state, gfx_rect(frame.xl - 1, shadow_offset + 1, + shadow_offset, frame.yl - 2), + black, black, GFX_BOX_SHADE_FLAT)); + } + + /* Draw frame */ + + if (gfxop_set_color(state, &black, 0, 0, 0, 0, bgcolor.priority, -1)) { + GFXERROR("Could not get black color entry!\n"); + return NULL; + } + + if (!(flags & WINDOW_FLAG_NO_DROP_SHADOW)) { + + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_rect(gfx_rect(0, 0, frame.xl-1, frame.yl-1), + black, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_NORMAL)); + + if (flags & WINDOW_FLAG_TITLE) + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_line(gfx_point(1, 9), + gfx_point(frame.xl - 2, 9), + black, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL)); + } else { + decorations->add((gfxw_container_t *) decorations, (gfxw_widget_t *) + gfxw_new_rect(gfx_rect(0, 0, frame.xl, frame.yl), + black, GFX_LINE_MODE_FINE, GFX_LINE_STYLE_NORMAL)); + } + + } + + win->decorations = decorations; + decorations->parent = GFXWC(win); + + return win; +} + + + +/*----------------*/ +/**** Controls ****/ +/*----------------*/ +static inline rect_t +_move_and_extend_rect(rect_t rect, point_t point, int yplus) +{ + return gfx_rect(rect.x + point.x, rect.y + point.y, rect.xl + 1, rect.yl + yplus); +} + + +gfxw_list_t * +_sciw_add_text_to_list(gfxw_list_t *list, gfxw_port_t *port, rect_t zone, char *text, + int font, gfx_alignment_t align, char framed, char inverse, int flags, + char gray_text) +{ + gfx_color_t *color1, *color2, *bgcolor = {0}; + + if (inverse) { + color1 = color2 = &(port->bgcolor); + bgcolor = &(port->color); + } else if (gray_text) { + bgcolor = color1 = &(port->bgcolor); + color2 = &(port->color); + } else { + color1 = color2 = &(port->color); + bgcolor = &(port->bgcolor); + } + + list->add(GFXWC(list), GFXW(gfxw_new_text(port->visual->gfx_state, zone, + font, text, align, ALIGN_TOP, + *color1, *color2, *bgcolor, flags))); + + + zone.xl--; + zone.yl -= 2; + + if (framed) { + list->add(GFXWC(list), + GFXW(gfxw_new_rect(zone, *color2, GFX_LINE_MODE_CORRECT, + GFX_LINE_STYLE_STIPPLED))); + } + + return list; +} + +gfxw_list_t * +sciw_new_button_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char grayed_out) +{ + gfx_color_t *frame_col = (inverse)? &(port->bgcolor) : &(port->color); + gfxw_list_t *list; + + zone.x--; + zone.y--; + zone.xl++; + zone.yl++; + + list = gfxw_new_list(_move_and_extend_rect(zone, gfx_point(port->zone.x, port->zone.y), 1), 0); + + gfxw_set_id(GFXW(list), ID.segment, ID.offset); + + zone.x = 0; + zone.y = 0; + + if (inverse) + list->add(GFXWC(list), GFXW(gfxw_new_box(NULL, gfx_rect(zone.x, zone.y, zone.xl + 1, zone.yl + 1), + port->color, port->color, GFX_BOX_SHADE_FLAT))); + + if (!inverse) + list = _sciw_add_text_to_list(list, port, gfx_rect(zone.x + 1, zone.y + 2, zone.xl - 1, zone.yl), + text, font, ALIGN_CENTER, 0, inverse, GFXR_FONT_FLAG_EAT_TRAILING_LF, grayed_out); + + if (!inverse) + list->add(GFXWC(list), + GFXW(gfxw_new_rect(zone, *frame_col, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + + if (inverse) + list = _sciw_add_text_to_list(list, port, gfx_rect(zone.x + 1, zone.y + 2, zone.xl - 1, zone.yl), + text, font, ALIGN_CENTER, 0, inverse, GFXR_FONT_FLAG_EAT_TRAILING_LF, grayed_out); + + if (selected) + list->add(GFXWC(list), + GFXW(gfxw_new_rect(gfx_rect(zone.x + 1, zone.y + 1, zone.xl - 2, zone.yl - 2), + *frame_col, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + + return list; +} + + +gfxw_list_t * +sciw_new_text_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, + gfx_alignment_t align, char framed, char inverse) +{ + gfxw_list_t *list = gfxw_new_list(_move_and_extend_rect(zone, gfx_point(port->zone.x, port->zone.y), 2), 0); + + gfxw_set_id(GFXW(list), ID.segment, ID.offset); + + zone.x = 0; + zone.y = 0; + + return _sciw_add_text_to_list(list, port, zone, text, font, align, framed, inverse, 0, port->gray_text); +} + + +gfxw_list_t * +sciw_new_edit_control(gfxw_port_t *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor, + char inverse) +{ + gfxw_text_t *text_handle; + long draw_cursor; + long foo; + + gfxw_list_t *list; + int cursor_height = gfxop_get_font_height(port->visual->gfx_state, font); + + zone.x--; + zone.y--; + zone.xl++; + zone.yl++; + + list = gfxw_new_list(_move_and_extend_rect(zone, gfx_point(port->zone.x, port->zone.y), 1), 0); + gfxw_set_id(GFXW(list), ID.segment, ID.offset); + zone.x = 1; + zone.y = 1; + + sci_gettime(&foo, &draw_cursor); + draw_cursor = draw_cursor > 500000; + + if (!draw_cursor) { + text_handle = gfxw_new_text(port->visual->gfx_state, zone, + font, text, ALIGN_LEFT, ALIGN_TOP, + port->color, port->color, port->bgcolor, GFXR_FONT_FLAG_NO_NEWLINES); + + list->add(GFXWC(list), GFXW(text_handle)); + } else { + char *textdup = (char*)sci_malloc(strlen(text) + 1); + + strncpy(textdup, text, cursor); + + if (cursor <= strlen(text)) + textdup[cursor] = 0; /* terminate */ + + if (cursor > 0) { + text_handle = gfxw_new_text(port->visual->gfx_state, zone, + font, textdup, ALIGN_LEFT, ALIGN_TOP, + port->color, port->color, port->bgcolor, GFXR_FONT_FLAG_NO_NEWLINES); + + list->add(GFXWC(list), GFXW(text_handle)); + zone.x += text_handle->width; + } + + if (cursor < strlen(text)) { + textdup[0] = text[cursor]; + textdup[1] = 0; + text_handle = gfxw_new_text(port->visual->gfx_state, zone, + font, textdup, ALIGN_LEFT, ALIGN_TOP, + port->bgcolor, port->bgcolor, port->color, GFXR_FONT_FLAG_NO_NEWLINES); + list->add(GFXWC(list), GFXW(text_handle)); + zone.x += text_handle->width; + }; + + if (cursor+1 < strlen(text)) { + text_handle = gfxw_new_text(port->visual->gfx_state, zone, + font, text + cursor + 1, ALIGN_LEFT, ALIGN_TOP, + port->color, port->color, port->bgcolor, GFXR_FONT_FLAG_NO_NEWLINES); + list->add(GFXWC(list), GFXW(text_handle)); + zone.x += text_handle->width; + }; + + if (cursor == strlen(text)) + list->add(GFXWC(list), GFXW(gfxw_new_line(gfx_point(zone.x, zone.y), + gfx_point(zone.x, zone.y + cursor_height - 1), + port->color, GFX_LINE_MODE_FAST, GFX_LINE_STYLE_NORMAL))); + free(textdup); + } + + + zone.x = zone.y = 0; + + list->add(GFXWC(list), + GFXW(gfxw_new_rect(zone, port->color, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + + return list; +} + + +gfxw_list_t * +sciw_new_icon_control(gfxw_port_t *port, reg_t ID, rect_t zone, int view, int loop, int cel, + char frame, char inverse) +{ + gfxw_list_t *list = gfxw_new_list(_move_and_extend_rect(zone, gfx_point(port->zone.x, port->zone.y), 1), 0); + gfxw_widget_t *icon; + gfxw_set_id(GFXW(list), ID.segment, ID.offset); + + if (!port->visual) { + GFXERROR("Attempting to create icon control for virtual port!\n"); + return NULL; + } + + zone.x = 0; + zone.y = 0; + + icon = GFXW(gfxw_new_view(port->visual->gfx_state, gfx_point(zone.x, zone.y), view, loop, cel, 0, -1, -1, + ALIGN_LEFT, ALIGN_TOP, GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET)); + + if (!icon) { + GFXERROR("Attempt to create icon control with cel %d/%d/%d (invalid)\n", view, loop, cel); + return NULL; + } + + list->flags |= GFXW_FLAG_MULTI_ID; + + list->add(GFXWC(list), icon); + + return list; +} + + +gfxw_list_t * +sciw_new_list_control(gfxw_port_t *port, reg_t ID, rect_t zone, int font_nr, char **entries_list, + int entries_nr, int list_top, int selection, char inverse) +{ + gfxw_list_t *list; + + char arr_up[2], arr_down[2]; + int i; + + int font_height; + int columns; + + zone.x--; + zone.y--; + zone.xl++; + zone.yl++; + + list = gfxw_new_list(_move_and_extend_rect(zone, gfx_point(port->zone.x, port->zone.y), 1), 0); + + font_height = gfxop_get_font_height(port->visual->gfx_state, font_nr); + columns = (zone.yl - 20); + + if (font_height <= 0) { + GFXERROR("Attempt to create list control with invalid font %d\n", font_nr); + list->widfree(GFXW(list)); + return NULL; + } + + columns /= font_height; + + gfxw_set_id(GFXW(list), ID.segment, ID.offset); + + arr_up[0] = SCI_SPECIAL_CHAR_ARROW_UP; + arr_down[0] = SCI_SPECIAL_CHAR_ARROW_DOWN; + arr_up[1] = arr_down[1] = 0; + + zone.x = 1; + zone.y = 11; + + /* Draw text */ + + for (i = list_top; columns-- && i < entries_nr; i++) { + + if (i != selection) + list->add(GFXWC(list), + GFXW(gfxw_new_text(port->visual->gfx_state, gfx_rect(zone.x, zone.y, zone.xl - 2, font_height), + font_nr, entries_list[i], ALIGN_LEFT, ALIGN_TOP, + port->color, port->color, port->bgcolor, GFXR_FONT_FLAG_NO_NEWLINES))); + else { + list->add(GFXWC(list), GFXW(gfxw_new_box(port->visual->gfx_state, gfx_rect(zone.x, zone.y, zone.xl - 1, font_height), + port->color, port->color, GFX_BOX_SHADE_FLAT))); + list->add(GFXWC(list), + GFXW(gfxw_new_text(port->visual->gfx_state, gfx_rect(zone.x, zone.y, zone.xl - 2, font_height), + font_nr, entries_list[i], ALIGN_LEFT, ALIGN_TOP, + port->bgcolor, port->bgcolor, port->color, GFXR_FONT_FLAG_NO_NEWLINES))); + } + + zone.y += font_height; + } + + /* Draw frames */ + + zone.x = 0; + zone.y = 0; + + /* Add up arrow */ + list->add(GFXWC(list), + GFXW(gfxw_new_text(port->visual->gfx_state, gfx_rect(1, 0, zone.xl-2, 8), + port->font_nr, arr_up, ALIGN_CENTER, ALIGN_CENTER, + port->color, port->color, port->bgcolor, 0))); + + /* Add down arrow */ + list->add(GFXWC(list), + GFXW(gfxw_new_text(port->visual->gfx_state, gfx_rect(1, zone.yl-9, zone.xl-2, 8), + port->font_nr, arr_down, ALIGN_CENTER, ALIGN_CENTER, + port->color, port->color, port->bgcolor, 0))); + + if (list_top & 1) { /* Hack to work around aggressive caching */ + + list->add(GFXWC(list), + GFXW(gfxw_new_rect(zone, port->color, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + + list->add(GFXWC(list), + GFXW(gfxw_new_rect(gfx_rect(zone.x, zone.y + 10, zone.xl, zone.yl - 20), + port->color, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + } else { + + list->add(GFXWC(list), + GFXW(gfxw_new_rect(gfx_rect(zone.x, zone.y, zone.xl, zone.yl - 10), + port->color, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + + list->add(GFXWC(list), + GFXW(gfxw_new_rect(gfx_rect(zone.x, zone.y + 10, zone.xl, zone.yl - 10), + port->color, GFX_LINE_MODE_CORRECT, GFX_LINE_STYLE_NORMAL))); + } + + return list; +} + + +void +sciw_set_menubar(state_t *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection) +{ + gfxw_list_t *list = make_titlebar_list(s, status_bar->bounds, status_bar); + int offset = MENU_LEFT_BORDER; + int i; + + clear_titlebar(status_bar); + + for (i = 0; i < menubar->menus_nr; i++) { + menu_t *menu = menubar->menus + i; + int width = menu->title_width + (MENU_BORDER_SIZE * 2); + + if (i == selection) { + list->add(GFXWC(list), GFXW(gfxw_new_box(status_bar->visual->gfx_state, gfx_rect(offset, 0, width, MENU_BAR_HEIGHT), + status_bar->color, status_bar->color, GFX_BOX_SHADE_FLAT))); + list->add(GFXWC(list), + GFXW(gfxw_new_text(s->gfx_state, gfx_rect(offset, 0, width, MENU_BAR_HEIGHT), + status_bar->font_nr, menu->title, ALIGN_CENTER, ALIGN_CENTER, + status_bar->bgcolor, status_bar->bgcolor, status_bar->color, GFXR_FONT_FLAG_NO_NEWLINES))); + } else + list->add(GFXWC(list), + GFXW(gfxw_new_text(s->gfx_state, gfx_rect(offset, 0, width, MENU_BAR_HEIGHT), + status_bar->font_nr, menu->title, ALIGN_CENTER, ALIGN_CENTER, + status_bar->color, status_bar->color, status_bar->bgcolor, GFXR_FONT_FLAG_NO_NEWLINES))); + + offset += width; + } + + status_bar->add(GFXWC(status_bar), GFXW(list)); + finish_titlebar_list(s, list, status_bar); +} + +gfxw_port_t * +sciw_new_menu(state_t *s, gfxw_port_t *status_bar, menubar_t *menubar, int selection) +{ + gfxw_port_t *retval; + menu_t *menu = menubar->menus + selection; + rect_t area = gfx_rect(MENU_LEFT_BORDER, 10, 0, 0); + int i; + + if (selection < -1) + return NULL; + + if (selection >= menubar->menus_nr) { + GFXERROR("Attempt to make menu #%d of %d\n", selection, menubar->menus_nr); + return NULL; + } + + for (i = 0; i < selection; i++) + area.x += menubar->menus[i].title_width; + + area.xl = menu->width - 1; + area.yl = menu->items_nr * 10; + + retval = sciw_new_window(s, area, status_bar->font_nr, status_bar->color, status_bar->bgcolor, + 0, status_bar->color, status_bar->bgcolor, + NULL, WINDOW_FLAG_NO_DROP_SHADOW | WINDOW_FLAG_TRANSPARENT); + + retval->set_visual(GFXW(retval), s->visual); + + for (i = 0; i < menu->items_nr; i++) + sciw_unselect_item(s, retval, menu, i); + + return retval; +} + +#define MAGIC_ID_OFFSET 0x2000 + +static inline gfx_color_t +un_prioritize(gfx_color_t col) +{ + col.priority = -1; + col.mask &= ~GFX_MASK_PRIORITY; + + return col; +} + +gfxw_widget_t * +_make_menu_entry(menu_item_t *item, int offset, int width, gfxw_port_t *port, gfx_color_t color, gfx_color_t bgcolor, int ID, int gray) +{ + rect_t area = gfx_rect(MENU_BOX_LEFT_PADDING, 0, width - MENU_BOX_LEFT_PADDING, 10); + rect_t list_area = gfx_rect(port->zone.x, area.y + offset + port->zone.y, width, area.yl); + gfxw_list_t *list = (gfxw_list_t *) gfxw_set_id(GFXW(gfxw_new_list(list_area, 0)), ID, GFXW_NO_ID); + gfx_color_t xcolor = {0}; + + color = un_prioritize(color); + bgcolor = un_prioritize(bgcolor); + + xcolor = gray? color : bgcolor; + + list->add(GFXWC(list), GFXW(gfxw_new_box(port->visual->gfx_state, area, bgcolor, bgcolor, GFX_BOX_SHADE_FLAT))); + list->add(GFXWC(list), GFXW(gfxw_new_text(port->visual->gfx_state, area, port->font_nr, item->text, ALIGN_LEFT, ALIGN_CENTER, + color, xcolor, bgcolor, GFXR_FONT_FLAG_NO_NEWLINES))); + + if (item->keytext) { + area.xl -= MENU_BOX_RIGHT_PADDING; + list->add(GFXWC(list), GFXW(gfxw_new_text(port->visual->gfx_state, area, port->font_nr, item->keytext, ALIGN_RIGHT, ALIGN_CENTER, + color, xcolor, bgcolor, GFXR_FONT_FLAG_NO_NEWLINES))); + } + + return GFXW(list); +} + +gfxw_widget_t * +_make_menu_hbar(int offset, int width, gfxw_port_t *port, gfx_color_t color, gfx_color_t bgcolor, int ID) +{ + rect_t area = gfx_rect(0, 0, width, 10); + rect_t list_area = gfx_rect(area.x + port->zone.x, area.y + offset + port->zone.y, area.xl, area.yl); + gfxw_list_t *list = (gfxw_list_t *) gfxw_set_id(GFXW(gfxw_new_list(list_area, 0)), ID, GFXW_NO_ID); + + color = un_prioritize(color); + bgcolor = un_prioritize(bgcolor); + + list->add(GFXWC(list), GFXW(gfxw_new_box(port->visual->gfx_state, area, bgcolor, bgcolor, GFX_BOX_SHADE_FLAT))); + list->add(GFXWC(list), GFXW(gfxw_new_line(gfx_point(0, 5), + gfx_point(width, 5), + color, + GFX_LINE_MODE_FAST, GFX_LINE_STYLE_STIPPLED))); + + return GFXW(list); +} + +gfxw_port_t * +sciw_unselect_item(state_t *s, gfxw_port_t *menu_port, menu_t *menu, int selection) +{ + menu_item_t *item = menu->items + selection; + + if (selection < 0 || selection >= menu->items_nr) + return menu_port; + + if (item->type == MENU_TYPE_NORMAL) + menu_port->add(GFXWC(menu_port), GFXW(_make_menu_entry(item, selection * 10, menu_port->zone.xl + 1, + menu_port, menu_port->color, + menu_port->bgcolor, selection + MAGIC_ID_OFFSET, + item->enabled))); + else + menu_port->add(GFXWC(menu_port), GFXW(_make_menu_hbar(selection * 10, menu_port->zone.xl + 1, + menu_port, menu_port->color, + menu_port->bgcolor, selection + MAGIC_ID_OFFSET))); + + return menu_port; +} + +gfxw_port_t * +sciw_select_item(state_t *s, gfxw_port_t *menu_port, menu_t *menu, int selection) +{ + menu_item_t *item = menu->items + selection; + + if (selection < 0 || selection >= menu->items_nr) + return menu_port; + + if (item->type == MENU_TYPE_NORMAL) + menu_port->add(GFXWC(menu_port), GFXW(_make_menu_entry(item, selection * 10, menu_port->zone.xl + 1, + menu_port, menu_port->bgcolor, + menu_port->color, selection + MAGIC_ID_OFFSET, + item->enabled))); + else + menu_port->add(GFXWC(menu_port), GFXW(_make_menu_hbar(selection * 10, menu_port->zone.xl + 1, + menu_port, menu_port->bgcolor, + menu_port->color, selection + MAGIC_ID_OFFSET))); + + return menu_port; +} diff --git a/engines/sci/gfx/widgets.c b/engines/sci/gfx/widgets.c new file mode 100644 index 0000000000..f81a717f21 --- /dev/null +++ b/engines/sci/gfx/widgets.c @@ -0,0 +1,2600 @@ +/*************************************************************************** + widgets.c Copyright (C) 2000,01 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ + +#include <sci_memory.h> +#include <gfx_widgets.h> + +#undef GFXW_DEBUG_DIRTY /* Enable to debug dirty rectangle propagation (writes to stderr) */ + +#ifdef GFXW_DEBUG_DIRTY +# define DDIRTY fprintf(stderr, "%s:%5d| ", __FILE__, __LINE__); fprintf +#else +# define DDIRTY if (0) fprintf +#endif + +point_t gfxw_point_zero = {0, 0}; + +#define MAX_SERIAL_NUMBER 0x7fffffff +static int widget_serial_number_counter = 0x10000; /* Avoid confusion with IDs */ + +#ifdef GFXW_DEBUG_WIDGETS + +gfxw_widget_t *debug_widgets[GFXW_DEBUG_WIDGETS]; +int debug_widget_pos = 0; + +static void +_gfxw_debug_add_widget(gfxw_widget_t *widget) +{ + if (debug_widget_pos == GFXW_DEBUG_WIDGETS) { + GFXERROR("WIDGET DEBUG: Allocated the maximum number of %d widgets- Aborting!\n", GFXW_DEBUG_WIDGETS); + BREAKPOINT(); + } + debug_widgets[debug_widget_pos++] = widget; +} + +static void +_gfxw_debug_remove_widget(gfxw_widget_t *widget) { + int i; + int found = 0; + for (i = 0; i < debug_widget_pos; i++) { + if (debug_widgets[i] == widget) { + memmove(debug_widgets + i, debug_widgets + i + 1, + (sizeof (gfxw_widget_t *)) * (debug_widget_pos - i - 1)); + debug_widgets[debug_widget_pos--] = NULL; + found++; + } + } + + if (found > 1) { + GFXERROR("While removing widget: Found it %d times!\n", found); + BREAKPOINT(); + } + + if (found == 0) { + GFXERROR("Attempted removal of unregistered widget!\n"); + BREAKPOINT(); + } +} +#else /* !GFXW_DEBUG_WIDGETS */ +#define _gfxw_debug_add_widget(a) +#define _gfxw_debug_remove_widget(a) +#endif + + +static inline void +indent(int indentation) +{ + int i; + for (i = 0; i < indentation; i++) + sciprintf(" "); +} + +static void +_gfxw_print_widget(gfxw_widget_t *widget, int indentation) +{ + unsigned int i; + char flags_list[] = "VOCDTMI"; + + indent(indentation); + + if (widget->magic == GFXW_MAGIC_VALID) { + if (widget->visual) + sciprintf("v "); + else + sciprintf("NoVis "); + } else if (widget->magic == GFXW_MAGIC_INVALID) + sciprintf("INVALID "); + + sciprintf("S%08x", widget->serial); + + if (widget->ID != GFXW_NO_ID) { + sciprintf("#%x", widget->ID); + + if (widget->subID != GFXW_NO_ID) + sciprintf(":%x ", widget->subID); + else + sciprintf(" "); + } + + sciprintf("[(%d,%d)(%dx%d)]", widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); + + for (i = 0; i < strlen(flags_list); i++) + if (widget->flags & (1 << i)) + sciprintf("%c", flags_list[i]); + + sciprintf(" "); +} + +static int +_gfxwop_print_empty(gfxw_widget_t *widget, int indentation) +{ + _gfxw_print_widget(widget, indentation); + sciprintf("<untyped #%d>", widget->type); + + return 0; +} + + +gfxw_widget_t * +_gfxw_new_widget(int size, gfxw_widget_type_t type) +{ + gfxw_widget_t *widget = (gfxw_widget_t*)sci_malloc(size); +#ifdef SATISFY_PURIFY + memset(widget, 0, size); +#endif + + widget->magic = GFXW_MAGIC_VALID; + widget->parent = NULL; + widget->visual = NULL; + widget->next = NULL; + widget->type = type; + widget->bounds = gfx_rect(0, 0, 0, 0); + widget->flags = GFXW_FLAG_DIRTY; + widget->ID = GFXW_NO_ID; + widget->subID = GFXW_NO_ID; + widget->serial = widget_serial_number_counter++; + widget->widget_priority = -1; + + widget_serial_number_counter &= MAX_SERIAL_NUMBER; + + widget->draw = NULL; + widget->widfree = NULL; + widget->tag = NULL; + widget->print = _gfxwop_print_empty; + widget->should_replace = NULL; + widget->compare_to = widget->equals = widget->superarea_of = NULL; + + _gfxw_debug_add_widget(widget); + + return widget; +} + + +static inline int +verify_widget(gfxw_widget_t *widget) +{ + if (!widget) { + GFXERROR("Attempt to use NULL widget\n"); +#ifdef GFXW_DEBUG_WIDGETS + BREAKPOINT(); +#endif /* GFXW_DEBUG_WIDGETS */ + return 1; + } else if (widget->magic != GFXW_MAGIC_VALID) { + if (widget->magic == GFXW_MAGIC_INVALID) { + GFXERROR("Attempt to use invalidated widget\n"); + } else { + GFXERROR("Attempt to use non-widget\n"); + } +#ifdef GFXW_DEBUG_WIDGETS + BREAKPOINT(); +#endif /* GFXW_DEBUG_WIDGETS */ + return 1; + } + return 0; +} + +#define VERIFY_WIDGET(w) \ + if (verify_widget((gfxw_widget_t *)(w))) { GFXERROR("Error occured while validating widget\n"); } + +static void +_gfxw_unallocate_widget(gfx_state_t *state, gfxw_widget_t *widget) +{ + if (GFXW_IS_TEXT(widget)) { + gfxw_text_t *text = (gfxw_text_t *) widget; + + if (text->text_handle) { + if (!state) { + GFXERROR("Attempt to free text without supplying mode to free it from!\n"); + BREAKPOINT(); + } else { + gfxop_free_text(state, text->text_handle); + text->text_handle = NULL; + } + } + } + + widget->magic = GFXW_MAGIC_INVALID; + free(widget); + _gfxw_debug_remove_widget(widget); +} + +#define GFX_ASSERT(_x) \ + { \ + int retval = (_x); \ + if (retval == GFX_ERROR) { \ + GFXERROR("Error occured while drawing widget!\n"); \ + return 1; \ + } else if (retval == GFX_FATAL) { \ + GFXERROR("Fatal error occured while drawing widget!\nGraphics state invalid; aborting program..."); \ + exit(1); \ + } \ + } + + +/**********************************/ +/*********** Widgets **************/ +/**********************************/ + +/* Base class operations and common stuff */ + +/* Assertion for drawing */ +#define DRAW_ASSERT(widget, exp_type) \ + if (!(widget)) { \ + sciprintf("L%d: NULL widget!\n", __LINE__); \ + return 1; \ + } \ + if (!(widget)->print) { \ + sciprintf("L%d: Widget of type %d does not have print function!\n", __LINE__, \ + (widget)->type); \ + } \ + if ((widget)->type != (exp_type)) { \ + sciprintf("L%d: Error in widget: Expected type " # exp_type "(%d) but got %d\n", \ + __LINE__, exp_type, (widget)->type); \ + sciprintf("Erroneous widget: "); \ + widget->print(widget, 4); \ + sciprintf("\n"); \ + return 1; \ + } \ + if (!(widget->flags & GFXW_FLAG_VISIBLE)) \ + return 0; \ + if (!(widget->type == GFXW_VISUAL || widget->visual)) { \ + sciprintf("L%d: Error while drawing widget: Widget has no visual\n", __LINE__); \ + sciprintf("Erroneous widget: "); \ + widget->print(widget, 1); \ + sciprintf("\n"); \ + return 1; \ + } + + +static inline int +_color_equals(gfx_color_t a, gfx_color_t b) +{ + if (a.mask != b.mask) + return 0; + + if (a.mask & GFX_MASK_VISUAL) { + if (a.visual.r != b.visual.r + || a.visual.g != b.visual.g + || a.visual.b != b.visual.b + || a.alpha != b.alpha) + return 0; + } + + if (a.mask & GFX_MASK_PRIORITY) + if (a.priority != b.priority) + return 0; + + if (a.mask & GFX_MASK_CONTROL) + if (a.control != b.control) + return 0; + + return 1; +} + +static int +_gfxwop_basic_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) +{ + widget->visual = visual; + + if (widget->parent) { + DDIRTY(stderr,"basic_set_visual: DOWNWARDS rel(%d,%d,%d,%d, 1)\n", + GFX_PRINT_RECT(widget->bounds)); + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return 0; +} + + +static int +_gfxwop_basic_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + return 0; +} + +static inline void +_gfxw_set_ops(gfxw_widget_t *widget, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, gfxw_op_int *print, + gfxw_bin_op *compare_to, gfxw_bin_op *equals, gfxw_bin_op *superarea_of) +{ + widget->draw = draw; + widget->widfree = free; + widget->tag = tag; + widget->print = print; + widget->compare_to = compare_to; + widget->equals = equals; + widget->superarea_of = superarea_of; + + widget->should_replace = _gfxwop_basic_should_replace; + widget->set_visual = _gfxwop_basic_set_visual; +} + +void +gfxw_remove_widget_from_container(gfxw_container_t *container, gfxw_widget_t *widget) +{ + gfxw_widget_t **seekerp; + + if (!container) { + GFXERROR("Attempt to remove widget from NULL container!\n"); + BREAKPOINT(); + } + + seekerp = &(container->contents); + + if (GFXW_IS_LIST(widget) && GFXW_IS_PORT(container)) { + gfxw_port_t *port = (gfxw_port_t *) container; + if (port->decorations == (gfxw_list_t *) widget) { + port->decorations = NULL; + return; + } + } + + while (*seekerp && *seekerp != widget) + seekerp = &((*seekerp)->next); + + if (!*seekerp) { + GFXERROR("Internal error: Attempt to remove widget from container it was not contained in!\n"); + sciprintf("Widget:"); + widget->print(GFXW(widget), 1); + sciprintf("Container:"); + widget->print(GFXW(container), 1); + BREAKPOINT(); + return; + } + + if (container->nextpp == &(widget->next)) + container->nextpp = seekerp; + + *seekerp = widget->next; /* Remove it */ + widget->parent = NULL; + widget->next = NULL; +} + +static int +_gfxwop_basic_free(gfxw_widget_t *widget) +{ + gfxw_visual_t *visual = widget->visual; + gfx_state_t *state = (visual)? visual->gfx_state : NULL; + + DDIRTY(stderr, "BASIC-FREE: SomeAddDirty\n"); + + if (widget->parent) { + if (GFXW_IS_CONTAINER(widget)) + widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); + else + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + + gfxw_remove_widget_from_container(widget->parent, widget); + } + + _gfxw_unallocate_widget(state, widget); + + + return 0; +} + + +static int +_gfxwop_basic_tag(gfxw_widget_t *widget) +{ + widget->flags |= GFXW_FLAG_TAGGED; + + return 0; +} + + +static int +_gfxwop_basic_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + return 1; +} + + +static int +_gfxwop_basic_equals(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + return 0; +} + + +static int +_gfxwop_basic_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + return (widget == other); +} + +/*-------------*/ +/**** Boxes ****/ +/*-------------*/ + +static inline rect_t +_move_rect(rect_t rect, point_t point) +{ + return gfx_rect(rect.x + point.x, rect.y + point.y, rect.xl, rect.yl); +} + +static inline void +_split_rect(rect_t rect, point_t *p1, point_t *p2) +{ + p1->x = rect.x; + p1->y = rect.y; + p2->x = rect.x + rect.xl; + p2->y = rect.y + rect.yl; +} + +static inline point_t +_move_point(rect_t rect, point_t point) +{ + return gfx_point(rect.x + point.x, rect.y + point.y); +} + +static int +_gfxwop_box_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_box_t *box = (gfxw_box_t *) widget; + DRAW_ASSERT(widget, GFXW_BOX); + GFX_ASSERT(gfxop_draw_box(box->visual->gfx_state, _move_rect(box->bounds, pos), box->color1, + box->color2, box->shade_type)); + + return 0; +} + +static int +_gfxwop_box_print(gfxw_widget_t *widget, int indentation) +{ + _gfxw_print_widget(widget, indentation); + sciprintf("BOX"); + return 0; +} + +static int +_gfxwop_box_superarea_of(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_box_t *box = (gfxw_box_t *) widget; + + if (box->color1.alpha) + return 0; + + if (box->shade_type != GFX_BOX_SHADE_FLAT && box->color2.alpha) + return 0; + + if (!gfx_rect_subset(other->bounds, box->bounds)) + return 0; + + return 1; +} + +static int +_gfxwop_box_equals(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_box_t *wbox = (gfxw_box_t *) widget, *obox; + if (other->type != GFXW_BOX) + return 0; + + obox = (gfxw_box_t *) other; + + if (!gfx_rect_equals(wbox->bounds, obox->bounds)) + return 0; + + if (!_color_equals(wbox->color1, obox->color1)) + return 0; + + if (wbox->shade_type != obox->shade_type) + return 0; + + if (wbox->shade_type != GFX_BOX_SHADE_FLAT + && _color_equals(wbox->color2, obox->color2)) + return 0; + + return 1; +} + +void +_gfxw_set_ops_BOX(gfxw_widget_t *widget) +{ + _gfxw_set_ops(GFXW(widget), _gfxwop_box_draw, + _gfxwop_basic_free, + _gfxwop_basic_tag, + _gfxwop_box_print, + _gfxwop_basic_compare_to, + _gfxwop_box_equals, + _gfxwop_box_superarea_of); +} + +static inline int +_gfxw_color_get_priority(gfx_color_t color) +{ + return (color.mask & GFX_MASK_PRIORITY)? color.priority : -1; +} + +gfxw_box_t * +gfxw_new_box(gfx_state_t *state, rect_t area, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type) +{ + gfxw_box_t *widget = (gfxw_box_t *) _gfxw_new_widget(sizeof(gfxw_box_t), GFXW_BOX); + + widget->widget_priority = _gfxw_color_get_priority(color1); + widget->bounds = area; + widget->color1 = color1; + widget->color2 = color2; + widget->shade_type = shade_type; + + widget->flags |= GFXW_FLAG_VISIBLE; + + if ((color1.mask & GFX_MASK_VISUAL) + && ((state && (state->driver->mode->palette)) + || (!color1.alpha && !color2.alpha))) + widget->flags |= GFXW_FLAG_OPAQUE; + + _gfxw_set_ops_BOX(GFXW(widget)); + + return widget; +} + + +static inline gfxw_primitive_t * +_gfxw_new_primitive(rect_t area, gfx_color_t color, gfx_line_mode_t mode, + gfx_line_style_t style, gfxw_widget_type_t type) +{ + gfxw_primitive_t *widget = (gfxw_primitive_t *) _gfxw_new_widget(sizeof(gfxw_primitive_t), type); + + widget->widget_priority = _gfxw_color_get_priority(color); + widget->bounds = area; + widget->color = color; + widget->line_mode = mode; + widget->line_style = style; + + widget->flags |= GFXW_FLAG_VISIBLE; + return widget; +} + +/*------------------*/ +/**** Rectangles ****/ +/*------------------*/ + +static int +_gfxwop_primitive_equals(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_primitive_t *wprim = (gfxw_primitive_t *) widget, *oprim; + if (widget->type != other->type) + return 0; + + oprim = (gfxw_primitive_t *) other; + + if (!gfx_rect_equals(wprim->bounds, oprim->bounds)) + return 0; + + if (!_color_equals(wprim->color, oprim->color)) + return 0; + + if (wprim->line_mode != oprim->line_mode) + return 0; + + if (wprim->line_style != oprim->line_style) + return 0; + + return 1; +} + +static int +_gfxwop_rect_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_primitive_t *rect = (gfxw_primitive_t *) widget; + DRAW_ASSERT(widget, GFXW_RECT); + + GFX_ASSERT(gfxop_draw_rectangle(rect->visual->gfx_state, + gfx_rect(rect->bounds.x + pos.x, rect->bounds.y + pos.y, + rect->bounds.xl - 1, rect->bounds.yl - 1), + rect->color, rect->line_mode, rect->line_style)); + + return 0; +} + +static int +_gfxwop_rect_print(gfxw_widget_t *rect, int indentation) +{ + _gfxw_print_widget(GFXW(rect), indentation); + sciprintf("RECT"); + return 0; +} + + +void +_gfxw_set_ops_RECT(gfxw_widget_t *prim) +{ + _gfxw_set_ops(GFXW(prim), _gfxwop_rect_draw, + _gfxwop_basic_free, + _gfxwop_basic_tag, + _gfxwop_rect_print, + _gfxwop_basic_compare_to, + _gfxwop_primitive_equals, + _gfxwop_basic_superarea_of); +} + +gfxw_primitive_t * +gfxw_new_rect(rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + gfxw_primitive_t *prim = _gfxw_new_primitive(rect, color, line_mode, line_style, GFXW_RECT); + prim->bounds.xl++; + prim->bounds.yl++; /* Since it is actually one pixel bigger in each direction */ + + _gfxw_set_ops_RECT(GFXW(prim)); + + return prim; +} + + +/*-------------*/ +/**** Lines ****/ +/*-------------*/ + +static int +_gfxwop_line_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_primitive_t *line = (gfxw_primitive_t *) widget; + rect_t linepos = widget->bounds; + point_t p1, p2; + + linepos.xl--; + linepos.yl--; + + if (widget->type == GFXW_INVERSE_LINE) { + linepos.x += linepos.xl; + linepos.xl = -linepos.xl; + } else { + DRAW_ASSERT(widget, GFXW_LINE); + } + + + _split_rect(_move_rect(linepos, pos), &p1, &p2); + GFX_ASSERT(gfxop_draw_line(line->visual->gfx_state, p1, p2, + line->color, line->line_mode, line->line_style)); + + return 0; +} + +static int +_gfxwop_line_print(gfxw_widget_t *widget, int indentation) +{ + _gfxw_print_widget(widget, indentation); + if (widget->type == GFXW_INVERSE_LINE) + sciprintf("INVERSE-LINE"); + else + sciprintf("LINE"); + return 0; +} + +void +_gfxw_set_ops_LINE(gfxw_widget_t *prim) +{ + _gfxw_set_ops(GFXW(prim), _gfxwop_line_draw, + _gfxwop_basic_free, + _gfxwop_basic_tag, + _gfxwop_line_print, + _gfxwop_basic_compare_to, + _gfxwop_primitive_equals, + _gfxwop_basic_superarea_of); + +} + +gfxw_primitive_t * +gfxw_new_line(point_t start, point_t end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style) +{ + gfxw_primitive_t *prim; + /* Encode into internal representation */ + rect_t line = gfx_rect (start.x, start.y, end.x - start.x, end.y - start.y); + + byte inverse = 0; + + if (line.xl < 0) { + line.x += line.xl; + line.y += line.yl; + line.xl = -line.xl; + line.yl = -line.yl; + } + + if (line.yl < 0) { + inverse = 1; + line.x += line.xl; + line.xl = -line.xl; + } + + line.xl++; + line.yl++; + + prim = _gfxw_new_primitive(line, color, line_mode, line_style, inverse? GFXW_INVERSE_LINE : GFXW_LINE); + + _gfxw_set_ops_LINE(GFXW(prim)); + + return prim; +} + +/*------------------------------*/ +/**** Views and static views ****/ +/*------------------------------*/ + + +gfxw_view_t * +_gfxw_new_simple_view(gfx_state_t *state, point_t pos, int view, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int size, gfxw_widget_type_t type) +{ + gfxw_view_t *widget; + int width, height; + point_t offset; + + if (!state) { + GFXERROR("Attempt to create view widget with NULL state!\n"); + return NULL; + } + + if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { + GFXERROR("Attempt to retreive cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", + view, cel, loop); + return NULL; + } + + widget = (gfxw_view_t *) _gfxw_new_widget(size, type); + + widget->widget_priority = priority; + widget->pos = pos; + widget->color.mask = + ((priority < 0)? 0 : GFX_MASK_PRIORITY) + | ((control < 0)? 0 : GFX_MASK_CONTROL); + widget->color.priority = priority; + widget->color.control = control; + widget->view = view; + widget->loop = loop; + widget->cel = cel; + widget->palette = palette; + + if (halign == ALIGN_CENTER) + widget->pos.x -= width >> 1; + else if (halign == ALIGN_RIGHT) + widget->pos.x -= width; + + if (valign == ALIGN_CENTER) + widget->pos.y -= height >> 1; + else if (valign == ALIGN_BOTTOM) + widget->pos.y -= height; + + widget->bounds = gfx_rect(widget->pos.x - offset.x, widget->pos.y - offset.y, width, height); + + widget->flags |= GFXW_FLAG_VISIBLE; + + return widget; +} + +int +_gfxwop_view_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_view_t *view = (gfxw_view_t *) widget; + DRAW_ASSERT(widget, GFXW_VIEW); + + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, + view->cel, gfx_point(view->pos.x + pos.x, view->pos.y + pos.y), + view->color, view->palette)); + + return 0; +} + +static int +_gfxwop_static_view_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_view_t *view = (gfxw_view_t *) widget; + DRAW_ASSERT(widget, GFXW_VIEW); + + GFX_ASSERT(gfxop_draw_cel_static(view->visual->gfx_state, view->view, view->loop, + view->cel, _move_point(view->bounds, pos), + view->color, view->palette)); + + return 0; +} + +static int +_w_gfxwop_view_print(gfxw_widget_t *widget, const char *name, int indentation) +{ + gfxw_view_t *view = (gfxw_view_t *) widget; + _gfxw_print_widget(widget, indentation); + + sciprintf(name); + sciprintf("(%d/%d/%d)@(%d,%d)[p:%d,c:%d]", view->view, view->loop, view->cel, view->pos.x, view->pos.y, + (view->color.mask & GFX_MASK_PRIORITY)? view->color.priority : -1, + (view->color.mask & GFX_MASK_CONTROL)? view->color.control : -1); + + return 0; +} + +static int +_gfxwop_view_print(gfxw_widget_t *widget, int indentation) +{ + return _w_gfxwop_view_print(widget, "VIEW", indentation); +} + +static int +_gfxwop_static_view_print(gfxw_widget_t *widget, int indentation) +{ + return _w_gfxwop_view_print(widget, "PICVIEW", indentation); +} + +void +_gfxw_set_ops_VIEW(gfxw_widget_t *view, char stat) +{ + _gfxw_set_ops(GFXW(view), (stat) ? _gfxwop_static_view_draw : _gfxwop_view_draw, + _gfxwop_basic_free, + _gfxwop_basic_tag, + (stat) ? _gfxwop_static_view_print : _gfxwop_view_print, + _gfxwop_basic_compare_to, + _gfxwop_basic_equals, + _gfxwop_basic_superarea_of); +} + +gfxw_view_t * +gfxw_new_view(gfx_state_t *state, point_t pos, int view_nr, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int flags) +{ + gfxw_view_t *view; + + if (flags & GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET) { + int foo; + point_t offset; + gfxop_get_cel_parameters(state, view_nr, loop, cel, &foo, &foo, &offset); + pos.x += offset.x; + pos.y += offset.y; + } + + view = _gfxw_new_simple_view(state, pos, view_nr, loop, cel, palette, priority, control, halign, valign, + sizeof(gfxw_view_t), (flags & GFXW_VIEW_FLAG_STATIC) ? GFXW_STATIC_VIEW : GFXW_VIEW); + + _gfxw_set_ops_VIEW(GFXW(view), (char)(flags & GFXW_VIEW_FLAG_STATIC)); + + return view; +} + +/*---------------------*/ +/**** Dynamic Views ****/ +/*---------------------*/ + +static int +_gfxwop_dyn_view_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; + DRAW_ASSERT(widget, GFXW_DYN_VIEW); + + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, view->view, view->loop, + view->cel, _move_point(view->draw_bounds, pos), + view->color, view->palette)); + + /* + gfx_color_t red; red.visual.r = 0xff; red.visual.g = red.visual.b = 0; red.mask = GFX_MASK_VISUAL; + GFX_ASSERT(gfxop_draw_rectangle(view->visual->gfx_state, + gfx_rect(view->bounds.x + pos.x, view->bounds.y + pos.y, + view->bounds.xl - 1, view->bounds.yl - 1), + red, 0, 0)); + */ + + + return 0; + +} + +static int +_gfxwop_draw_nop(gfxw_widget_t *widget, point_t pos) +{ + return 0; +} + +static int +_gfxwop_pic_view_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; + DRAW_ASSERT(widget, GFXW_PIC_VIEW); + + GFX_ASSERT(gfxop_set_clip_zone(view->visual->gfx_state, view->parent->zone)); + GFX_ASSERT(gfxop_draw_cel_static_clipped(view->visual->gfx_state, + view->view, view->loop, + view->cel, + _move_point(view->draw_bounds, pos), + view->color, view->palette)); + + /* Draw again on the back buffer */ + GFX_ASSERT(gfxop_draw_cel(view->visual->gfx_state, + view->view, view->loop, + view->cel, + _move_point(view->draw_bounds, pos), + view->color, view->palette)); + + + widget->draw = _gfxwop_draw_nop; /* No more drawing needs to be done */ + + + return 0; +} + +static int +_gfxwop_some_view_print(gfxw_widget_t *widget, int indentation, const char *type_string) +{ + gfxw_dyn_view_t *view = (gfxw_dyn_view_t *) widget; + + _gfxw_print_widget(widget, indentation); + + sciprintf(type_string); + sciprintf(" SORT=%d z=%d seq=%d (%d/%d/%d)@(%d,%d)[p:%d,c:%d]; sig[%04x@%04x]", view->force_precedence, view->z, + view->sequence, view->view, view->loop, view->cel, view->pos.x, view->pos.y, + (view->color.mask & GFX_MASK_PRIORITY)? view->color.priority : -1, + (view->color.mask & GFX_MASK_CONTROL)? view->color.control : -1, + view->signal, view->signalp); + + return 0; +} + +static int +_gfxwop_dyn_view_print(gfxw_widget_t *widget, int indentation) +{ + return _gfxwop_some_view_print(widget, indentation, "DYNVIEW"); +} + +static int +_gfxwop_pic_view_print(gfxw_widget_t *widget, int indentation) +{ + return _gfxwop_some_view_print(widget, indentation, "PICVIEW"); +} + + +static int +_gfxwop_dyn_view_equals(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *) widget, *oview; + if (!GFXW_IS_DYN_VIEW(other)) + return 0; + + oview = (gfxw_dyn_view_t *) other; + + if (wview->pos.x != oview->pos.x + || wview->pos.y != oview->pos.y + || wview->z != oview->z) + return 0; + + if (wview->view != oview->view + || wview->loop != oview->loop + || wview->cel != oview->cel) + return 0; + + if (!_color_equals(wview->color, oview->color)) + return 0; + + if (wview->flags != oview->flags) + return 0; + + return 1; +} + +static int +_gfxwop_dyn_view_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + int retval; + gfxw_dyn_view_t *wview = (gfxw_dyn_view_t *) widget, *oview; + if (!GFXW_IS_DYN_VIEW(other)) + return 1; + + oview = (gfxw_dyn_view_t *) other; + + retval = wview->force_precedence - oview->force_precedence; + if (retval) + return retval; + + retval = wview->pos.y - oview->pos.y; + if (retval) + return retval; + + retval = (wview->z - oview->z); + if (retval) + return retval; + + return -(wview->sequence - oview->sequence); +} + + +void +_gfxw_set_ops_DYNVIEW(gfxw_widget_t *widget) +{ + _gfxw_set_ops(GFXW(widget), _gfxwop_dyn_view_draw, + _gfxwop_basic_free, + _gfxwop_basic_tag, + _gfxwop_dyn_view_print, + _gfxwop_dyn_view_compare_to, + _gfxwop_dyn_view_equals, + _gfxwop_basic_superarea_of); +} + +void +_gfxw_set_ops_PICVIEW(gfxw_widget_t *widget) +{ + _gfxw_set_ops_DYNVIEW(widget); + widget->draw = _gfxwop_pic_view_draw; + widget->print = _gfxwop_pic_view_print; +} + +gfxw_dyn_view_t * +gfxw_new_dyn_view(gfx_state_t *state, point_t pos, int z, int view, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int sequence) +{ + gfxw_dyn_view_t *widget; + int width, height; + int xalignmod, yalignmod; + point_t offset; + + if (!state) { + GFXERROR("Attempt to create view widget with NULL state!\n"); + return NULL; + } + + if (gfxop_get_cel_parameters(state, view, loop, cel, &width, &height, &offset)) { + GFXERROR("Attempt to retreive cel parameters for (%d/%d/%d) failed (Maybe the values weren't checked beforehand?)\n", + view, cel, loop); + return NULL; + } + + widget = (gfxw_dyn_view_t *) _gfxw_new_widget(sizeof(gfxw_dyn_view_t), GFXW_DYN_VIEW); + + widget->pos = pos; + widget->color.mask = + ((priority < 0)? 0 : GFX_MASK_PRIORITY) + | ((control < 0)? 0 : GFX_MASK_CONTROL); + widget->widget_priority = priority; + widget->color.priority = priority; + widget->color.control = control; + widget->color.alpha = 0; + widget->color.visual.global_index = 0; + widget->color.visual.r = 0; + widget->color.visual.g = 0; + widget->color.visual.b = 0; + widget->view = view; + widget->loop = loop; + widget->cel = cel; + widget->sequence = sequence; + widget->force_precedence = 0; + widget->palette = palette; + + if (halign == ALIGN_CENTER) + xalignmod = width >> 1; + else if (halign == ALIGN_RIGHT) + xalignmod = width; + else + xalignmod = 0; + + if (valign == ALIGN_CENTER) + yalignmod = height >> 1; + else if (valign == ALIGN_BOTTOM) + yalignmod = height; + else + yalignmod = 0; + + widget->z = z; + + widget->draw_bounds = gfx_rect(widget->pos.x - xalignmod, + widget->pos.y - yalignmod - z, width, height); + widget->bounds = gfx_rect(widget->pos.x - offset.x - xalignmod, + widget->pos.y - offset.y - yalignmod - z, width, height); + + widget->flags |= GFXW_FLAG_VISIBLE; + + _gfxw_set_ops_DYNVIEW(GFXW(widget)); + + widget->signalp = NULL; + widget->signal = 0; + + return widget; +} + +/*------------*/ +/**** Text ****/ +/*------------*/ + +static int +_gfxwop_text_free(gfxw_widget_t *widget) +{ + gfxw_text_t *text = (gfxw_text_t *) widget; + free(text->text); + return _gfxwop_basic_free(widget); +} + +static int +_gfxwop_text_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_text_t *text = (gfxw_text_t *) widget; + DRAW_ASSERT(widget, GFXW_TEXT); + + GFX_ASSERT(gfxop_draw_text(text->visual->gfx_state, text->text_handle, _move_rect(text->bounds, pos))); + + return 0; +} + +static int +_gfxwop_text_alloc_and_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_text_t *text = (gfxw_text_t *) widget; + DRAW_ASSERT(widget, GFXW_TEXT); + + text->text_handle = + gfxop_new_text(widget->visual->gfx_state, text->font_nr, text->text, text->bounds.xl, + text->halign, text->valign, text->color1, + text->color2, text->bgcolor, text->text_flags); + + text->draw = _gfxwop_text_draw; + + return _gfxwop_text_draw(widget, pos); +} + + +static int +_gfxwop_text_print(gfxw_widget_t *widget, int indentation) +{ + _gfxw_print_widget(widget, indentation); + sciprintf("TEXT:'%s'", ((gfxw_text_t *)widget)->text); + return 0; +} + + +static int +_gfxwop_text_equals(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_text_t *wtext = (gfxw_text_t *) widget, *otext; + if (other->type != GFXW_TEXT) + return 0; + + otext = (gfxw_text_t *) other; + + if ((wtext->bounds.x != otext->bounds.x) + || (wtext->bounds.y != otext->bounds.y)) + return 0; + + if (wtext->halign != otext->halign + || wtext->valign != otext->valign) + return 0; + + if (wtext->text_flags != otext->text_flags) + return 0; + + if (wtext->font_nr != otext->font_nr) + return 0; + + /* if (!(_color_equals(wtext->color1, otext->color1) + && _color_equals(wtext->color2, otext->color2) + && _color_equals(wtext->bgcolor, otext->bgcolor))) + return 0; */ + + return 1; +} + +static int +_gfxwop_text_should_replace(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + gfxw_text_t *wtext = (gfxw_text_t *) widget, *otext; + + if (other->type != GFXW_TEXT) + return 0; + + otext = (gfxw_text_t *) other; + + return strcmp(wtext->text, otext->text); +} + + +static int +_gfxwop_text_compare_to(gfxw_widget_t *widget, gfxw_widget_t *other) +{ + + return 1; +} + +void +_gfxw_set_ops_TEXT(gfxw_widget_t *widget) +{ + _gfxw_set_ops(GFXW(widget), _gfxwop_text_alloc_and_draw, + _gfxwop_text_free, + _gfxwop_basic_tag, + _gfxwop_text_print, + _gfxwop_text_compare_to, + _gfxwop_text_equals, + _gfxwop_basic_superarea_of); + widget->should_replace = _gfxwop_text_should_replace; +} + +gfxw_text_t * +gfxw_new_text(gfx_state_t *state, rect_t area, int font, const char *text, gfx_alignment_t halign, + gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, + gfx_color_t bgcolor, int text_flags) +{ + gfxw_text_t *widget = (gfxw_text_t *) + _gfxw_new_widget(sizeof(gfxw_text_t), GFXW_TEXT); + + widget->widget_priority = _gfxw_color_get_priority(color1); + widget->font_nr = font; + widget->text = (char*)sci_malloc(strlen(text) + 1); + widget->halign = halign; + widget->valign = valign; + widget->color1 = color1; + widget->color2 = color2; + widget->bgcolor = bgcolor; + widget->text_flags = text_flags; + widget->text_handle = NULL; + + strcpy(widget->text, text); + + gfxop_get_text_params(state, font, text, area.xl, &(widget->width), + &(widget->height), text_flags, + &(widget->lines_nr), &(widget->lineheight), + &(widget->lastline_width)); + + /* FIXME: Window is too big + area.x += _calc_needmove(halign, area.xl, widget->width); + area.y += _calc_needmove(valign, area.yl, widget->height); + */ + + if (halign == ALIGN_LEFT) + area.xl = widget->width; + if (valign == ALIGN_TOP) + area.yl = widget->height; + + widget->bounds = area; + + widget->flags |= GFXW_FLAG_VISIBLE; + + _gfxw_set_ops_TEXT(GFXW(widget)); + + return widget; +} + + +void +gfxw_text_info(gfx_state_t *state, gfxw_text_t *text, int *lines, + int *lineheight, int *offset) +{ + if (lines) + *lines = text->lines_nr; + if (lineheight) + *lineheight = text->lineheight; + if (offset) + *offset = text->lastline_width; +} + + +/***********************/ +/*-- Container types --*/ +/***********************/ + +static int +_gfxwop_container_add_dirty_rel(gfxw_container_t *cont, rect_t rect, int propagate) +{ + DDIRTY(stderr, "->container_add_dirty_rel(%d,%d,%d,%d, %d)\n", GFX_PRINT_RECT(rect), propagate); + return cont->add_dirty_abs(cont, _move_rect(rect, gfx_point(cont->zone.x, cont->zone.y)), propagate); +} + +static inline void +_gfxw_set_container_ops(gfxw_container_t *container, gfxw_point_op *draw, gfxw_op *free, gfxw_op *tag, + gfxw_op_int *print, gfxw_bin_op *compare_to, gfxw_bin_op *equals, + gfxw_bin_op *superarea_of, gfxw_visual_op *set_visual, + gfxw_unary_container_op *free_tagged, gfxw_unary_container_op *free_contents, + gfxw_rect_op *add_dirty, gfxw_container_op *add) +{ + _gfxw_set_ops(GFXW(container), + draw, + free, + tag, + print, + compare_to, + equals, + superarea_of); + + container->free_tagged = free_tagged; + container->free_contents = free_contents; + container->add_dirty_abs = add_dirty; + container->add_dirty_rel = _gfxwop_container_add_dirty_rel; + container->add = add; + container->set_visual = set_visual; +} + +static int +_w_gfxwop_container_print_contents(const char *name, gfxw_widget_t *widget, int indentation) +{ + gfxw_widget_t *seeker = widget; + + indent(indentation); + + sciprintf("--%s:\n", name); + + while (seeker) { + seeker->print(seeker, indentation + 1); + sciprintf("\n"); + seeker = seeker->next; + } + + return 0; +} + +static int +_w_gfxwop_container_print(gfxw_widget_t *widget, int indentation) +{ + gfx_dirty_rect_t *dirty; + gfxw_container_t *container = (gfxw_container_t *) widget; + if (!GFXW_IS_CONTAINER(widget)) { + GFXERROR("_w_gfxwop_container_print() called on type %d widget\n", widget->type); + return 1; + } + + sciprintf(" viszone=((%d,%d),(%dx%d))\n", container->zone.x, container->zone.y, + container->zone.xl, container->zone.yl); + + indent(indentation); + sciprintf("--dirty:\n"); + + dirty = container->dirty; + while (dirty) { + indent(indentation + 1); + sciprintf("dirty(%d,%d, (%dx%d))\n", + dirty->rect.x, dirty->rect.y, dirty->rect.xl, dirty->rect.yl); + dirty = dirty->next; + } + + _w_gfxwop_container_print_contents("contents", container->contents, indentation); + + return 0; +} + + + +gfxw_container_t * +_gfxw_new_container_widget(rect_t area, int size, gfxw_widget_type_t type) +{ + gfxw_container_t *widget = (gfxw_container_t *) + _gfxw_new_widget(size, type); + + widget->bounds = widget->zone = area; + widget->contents = NULL; + widget->nextpp = &(widget->contents); + widget->dirty = NULL; + + widget->flags |= GFXW_FLAG_VISIBLE | GFXW_FLAG_CONTAINER; + + return widget; +} + + +static void +recursively_free_dirty_rects(gfx_dirty_rect_t *dirty) +{ + if (dirty) { + recursively_free_dirty_rects(dirty->next); + free(dirty); + } +} + + +int ti = 0; + +static inline int +_gfxw_dirty_rect_overlaps_normal_rect(rect_t port_zone, rect_t bounds, rect_t dirty) +{ + bounds.x += port_zone.x; + bounds.y += port_zone.y; + return gfx_rects_overlap(bounds, dirty); +} + +static int +_gfxwop_container_draw_contents(gfxw_widget_t *widget, gfxw_widget_t *contents) +{ + gfxw_container_t *container = (gfxw_container_t *) widget; + gfx_dirty_rect_t *dirty = container->dirty; + gfx_state_t *gfx_state = (widget->visual)? widget->visual->gfx_state : ((gfxw_visual_t *) widget)->gfx_state; + int draw_ports; + rect_t nullzone = {0,0,0,0}; + + if (!contents) + return 0; + + while (dirty) { + gfxw_widget_t *seeker = contents; + + while (seeker) { + if (_gfxw_dirty_rect_overlaps_normal_rect(GFXW_IS_CONTAINER(seeker)? nullzone : container->zone, + /* Containers have absolute coordinates, reflect this. */ + seeker->bounds, dirty->rect)) { + + if (GFXW_IS_CONTAINER(seeker)) {/* Propagate dirty rectangles /upwards/ */ + DDIRTY(stderr,"container_draw_contents: propagate upwards (%d,%d,%d,%d ,0)\n", GFX_PRINT_RECT(dirty->rect)); + ((gfxw_container_t *)seeker)->add_dirty_abs((gfxw_container_t *)seeker, dirty->rect, 0); + } + + seeker->flags |= GFXW_FLAG_DIRTY; + } + + seeker = seeker->next; + } + + dirty = dirty->next; + } + + /* The draw loop is executed twice: Once for normal data, and once for ports. */ + for (draw_ports = 0; draw_ports < 2; draw_ports++) { + + dirty = container->dirty; + + while (dirty) { + + gfxw_widget_t *seeker = contents; + while (seeker && (draw_ports || !GFXW_IS_PORT(seeker))) { + rect_t small_rect; + byte draw_noncontainers; + + memcpy(&small_rect, &(dirty->rect), sizeof(rect_t)); + draw_noncontainers = !_gfxop_clip(&small_rect, container->bounds); + + if (seeker->flags & GFXW_FLAG_DIRTY) { + + if (!GFXW_IS_CONTAINER(seeker) && draw_noncontainers) { + GFX_ASSERT(gfxop_set_clip_zone(gfx_state, small_rect)); + } + /* Clip zone must be reset after each element, because we might + ** descend into containers. + ** Doing this is relatively cheap, though. */ + if (draw_noncontainers || GFXW_IS_CONTAINER(seeker)) + seeker->draw(seeker, gfx_point(container->zone.x, container->zone.y)); + + if (!dirty->next) + seeker->flags &= ~GFXW_FLAG_DIRTY; + } + + seeker = seeker->next; + } + dirty = dirty->next; + } + } + /* Remember that the dirty rects should be freed afterwards! */ + + return 0; +} + +static int +_gfxwop_container_free(gfxw_widget_t *widget) +{ + gfxw_container_t *container = (gfxw_container_t *) widget; + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + gfxw_widget_t *next = seeker->next; + seeker->widfree(seeker); + seeker = next; + } + + recursively_free_dirty_rects(container->dirty); + container->dirty = NULL; + + return _gfxwop_basic_free(widget); +} + +static int +_gfxwop_container_tag(gfxw_widget_t *widget) +{ + gfxw_container_t *container = (gfxw_container_t *) widget; + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + seeker->tag(seeker); + seeker = seeker->next; + } + return 0; +} + + +static int +_w_gfxwop_container_set_visual_contents(gfxw_widget_t *contents, gfxw_visual_t *visual) +{ + while (contents) { + contents->set_visual(contents, visual); + contents = contents->next; + } + return 0; +} + +static int +_gfxwop_container_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) +{ + gfxw_container_t *container = (gfxw_container_t *) widget; + + container->visual = visual; + if (widget->parent) { + if (!(GFXW_IS_LIST(widget) && !GFXWC(widget)->contents)) { + DDIRTY(stderr,"set_visual::DOWNWARDS abs(%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); + widget->parent->add_dirty_abs(widget->parent, widget->bounds, 1); + } + } + + return _w_gfxwop_container_set_visual_contents(container->contents, visual); +} + +static int +_gfxwop_container_free_tagged(gfxw_container_t *container) +{ + gfxw_widget_t *seekerp = (container->contents); + + while (seekerp) { + gfxw_widget_t *redshirt = seekerp; + + if (redshirt->flags & GFXW_FLAG_TAGGED) { + seekerp = (redshirt->next); + redshirt->widfree(redshirt); /* He's dead, Jim. */ + } else + seekerp = (seekerp)->next; + } + return 0; +} + +static int +_gfxwop_container_free_contents(gfxw_container_t *container) +{ + gfxw_widget_t *seeker = container->contents; + + while (seeker) { + gfxw_widget_t *next = seeker->next; + seeker->widfree(seeker); + seeker = next; + } + return 0; +} + +static void +_gfxw_dirtify_container(gfxw_container_t *container, gfxw_widget_t *widget) +{ + if (GFXW_IS_CONTAINER(widget)) + container->add_dirty_abs(GFXWC(container), widget->bounds, 1); + else + container->add_dirty_rel(GFXWC(container), widget->bounds, 1); +} + +static int +_parentize_widget(gfxw_container_t *container, gfxw_widget_t *widget) +{ + if (widget->parent) { + GFXERROR("_gfxwop_container_add(): Attempt to give second parent node to widget!\nWidget:"); + widget->print(GFXW(widget), 3); + sciprintf("\nContainer:"); + container->print(GFXW(container), 3); + + return 1; + } + + widget->parent = GFXWC(container); + + if (GFXW_IS_VISUAL(container)) + widget->set_visual(widget, (gfxw_visual_t *) container); + else if (container->visual) + widget->set_visual(widget, container->visual); + + return 0; +} + +static int +_gfxw_container_id_equals(gfxw_container_t *container, gfxw_widget_t *widget) +{ + gfxw_widget_t **seekerp = &(container->contents); + + if (GFXW_IS_PORT(widget)) + return 0; /* Don't match ports */ + + if (widget->ID == GFXW_NO_ID) + return 0; + + while (*seekerp + && ((*seekerp)->ID != widget->ID + || (*seekerp)->subID != widget->subID)) + seekerp = &((*seekerp)->next); + + if (!*seekerp) + return 0; + + if ((*seekerp)->equals(*seekerp, widget) + && !(*seekerp)->should_replace(*seekerp, widget)) { + widget->widfree(widget); + (*seekerp)->flags &= ~GFXW_FLAG_TAGGED; + return 1; + } else { + if (!(widget->flags & GFXW_FLAG_MULTI_ID)) + (*seekerp)->widfree(*seekerp); + return 0; + } +} + + +static int +_gfxwop_container_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) +{ +#if 0 + /* This code has been disabled because containers may contain sub-containers with + ** bounds greater than their own. */ + if (_gfxop_clip(&dirty, container->bounds)) + return 0; +#endif + + DDIRTY(stderr, "Effectively adding dirty %d,%d,%d,%d %d to ID %d\n", GFX_PRINT_RECT(dirty), propagate, container->ID); + container->dirty = gfxdr_add_dirty(container->dirty, dirty, GFXW_DIRTY_STRATEGY); + return 0; +} + + +static int +_gfxwop_container_add(gfxw_container_t *container, gfxw_widget_t *widget) +{ + if (_gfxw_container_id_equals(container, widget)) + return 0; + + if (_parentize_widget(container, widget)) + return 1; + + if (!(GFXW_IS_LIST(widget) && (!GFXWC(widget)->contents))) { /* Don't dirtify self on empty lists */ + DDIRTY(stderr, "container_add: dirtify DOWNWARDS (%d,%d,%d,%d, 1)\n", GFX_PRINT_RECT(widget->bounds)); + _gfxw_dirtify_container(container, widget); + } + + *(container->nextpp) = widget; + container->nextpp = &(widget->next); + + return 0; +} + +/*------------------------------*/ +/**** Lists and sorted lists ****/ +/*------------------------------*/ + +static int +_gfxwop_list_draw(gfxw_widget_t *list, point_t pos) +{ + DRAW_ASSERT(list, GFXW_LIST); + + _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); + recursively_free_dirty_rects(GFXWC(list)->dirty); + GFXWC(list)->dirty = NULL; + list->flags &= ~GFXW_FLAG_DIRTY; + return 0; +} + +static int +_gfxwop_sorted_list_draw(gfxw_widget_t *list, point_t pos) +{ + DRAW_ASSERT(list, GFXW_SORTED_LIST); + + _gfxwop_container_draw_contents(list, ((gfxw_list_t *)list)->contents); + recursively_free_dirty_rects(GFXWC(list)->dirty); + GFXWC(list)->dirty = NULL; + return 0; +} + +static inline int +_w_gfxwop_list_print(gfxw_widget_t *list, const char *name, int indentation) +{ + _gfxw_print_widget(list, indentation); + sciprintf(name); + return _w_gfxwop_container_print(list, indentation); +} + +static int +_gfxwop_list_print(gfxw_widget_t *list, int indentation) +{ + return _w_gfxwop_list_print(list, "LIST", indentation); +} + +static int +_gfxwop_sorted_list_print(gfxw_widget_t *list, int indentation) +{ + return _w_gfxwop_list_print(list, "SORTED_LIST", indentation); +} + +/* --- */ +#if 0 +struct gfxw_widget_list { + gfxw_widget_t *widget; + struct gfxw_widget_list *next; +}; + +static struct gfxw_widtet_list * +_gfxw_make_widget_list_recursive(gfxw_widget_t *widget) +{ + gfxw_widget_list *node; + + if (!widget) + return NULL; + + node = sci_malloc(sizeof(struct gfxw_widget_list)); + node->widget = widget; + node->next = _gfxw_make_widget_list_recursive(widget->next); + + return node; +} + +static struct gfxw_widget_list * +_gfxw_make_widget_list(gfxw_container_t *container) +{ + return _gfxw_make_widget_list_recursive(container->contents); +} +#endif +/* --- */ + + +static int +_gfxwop_list_equals(gfxw_widget_t *widget, gfxw_widget_t *other) + /* Requires identical order of list elements. */ +{ + gfxw_list_t *wlist, *olist; + + if (widget->type != other->type) + return 0; + + if (!GFXW_IS_LIST(widget)) { + GFXWARN("_gfxwop_list_equals(): Method called on non-list!\n"); + widget->print(widget, 0); + sciprintf("\n"); + return 0; + } + + wlist = (gfxw_list_t *) widget; + olist = (gfxw_list_t *) other; + + if (memcmp(&(wlist->bounds), &(olist->bounds), sizeof(rect_t))) + return 0; + + widget = wlist->contents; + other = olist->contents; + + while (widget && other) { + + if (!(widget->equals(widget, other) && !widget->should_replace(widget,other))) + return 0; + + widget = widget->next; + other = other->next; + } + + return (!widget && !other); /* True if both are finished now */ +} + +static int +_gfxwop_list_add_dirty(gfxw_container_t *container, rect_t dirty, int propagate) +{ + /* Lists add dirty boxes to both themselves and their parenting port/visual */ + + container->flags |= GFXW_FLAG_DIRTY; + + DDIRTY(stderr,"list_add_dirty %d,%d,%d,%d %d\n", GFX_PRINT_RECT(dirty), propagate); + if (propagate) + if (container->parent) { + DDIRTY(stderr, "->PROPAGATING\n"); + container->parent->add_dirty_abs(container->parent, dirty, 1); + } + + return _gfxwop_container_add_dirty(container, dirty, propagate); +} + +/* static inline */ int +_gfxwop_ordered_add(gfxw_container_t *container, gfxw_widget_t *widget, int compare_all) + /* O(n) */ +{ + gfxw_widget_t **seekerp = &(container->contents); + + if (widget->next) { + GFXERROR("_gfxwop_sorted_list_add(): Attempt to add widget to two lists!\nWidget:"); + widget->print(GFXW(widget), 3); + sciprintf("\nList:"); + container->print(GFXW(container), 3); + BREAKPOINT(); + + return 1; + } + + if (_gfxw_container_id_equals(container, widget)) + return 0; + + while (*seekerp && (compare_all || (widget->compare_to(widget, *seekerp) >= 0))) { + + if (widget->equals(GFXW(widget), GFXW(*seekerp))) { + if (compare_all) { + if ((*seekerp)->visual) + (*seekerp)->widfree(GFXW(*seekerp)); /* If it's a fresh widget */ + else + gfxw_annihilate(GFXW(*seekerp)); + + return _gfxwop_ordered_add(container, widget, compare_all); /* We might have destroyed the container's contents */ + } else { + widget->next = (*seekerp)->next; + (*seekerp)->widfree(GFXW(*seekerp)); + *seekerp = widget; + return (_parentize_widget(container, widget)); + } + } + + if (*seekerp) + seekerp = &((*seekerp)->next); + } + + widget->next = *seekerp; + *seekerp = widget; + + return _parentize_widget(container, widget); +} + +static int +_gfxwop_sorted_list_add(gfxw_container_t *container, gfxw_widget_t *widget) + /* O(n) */ +{ + return _gfxwop_ordered_add(container, widget, 0); +} + +void +_gfxw_set_ops_LIST(gfxw_container_t *list, char sorted) +{ + _gfxw_set_container_ops((gfxw_container_t *) list, + sorted? _gfxwop_sorted_list_draw : _gfxwop_list_draw, + _gfxwop_container_free, + _gfxwop_container_tag, + sorted? _gfxwop_sorted_list_print : _gfxwop_list_print, + _gfxwop_basic_compare_to, + sorted? _gfxwop_basic_equals : _gfxwop_list_equals, + _gfxwop_basic_superarea_of, + _gfxwop_container_set_visual, + _gfxwop_container_free_tagged, + _gfxwop_container_free_contents, + _gfxwop_list_add_dirty, + sorted? _gfxwop_sorted_list_add : _gfxwop_container_add); +} + +gfxw_list_t * +gfxw_new_list(rect_t area, int sorted) +{ + gfxw_list_t *list = (gfxw_list_t *) _gfxw_new_container_widget(area, sizeof(gfxw_list_t), + sorted? GFXW_SORTED_LIST : GFXW_LIST); + + _gfxw_set_ops_LIST(GFXWC(list), (char)sorted); + + return list; +} + + +/*---------------*/ +/**** Visuals ****/ +/*---------------*/ + +static int +_gfxwop_visual_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + gfx_dirty_rect_t *dirty = visual->dirty; + DRAW_ASSERT(widget, GFXW_VISUAL); + + while (dirty) { + int err = gfxop_clear_box(visual->gfx_state, dirty->rect); + + if (err) { + GFXERROR("Error while clearing dirty rect (%d,%d,(%dx%d))\n", dirty->rect.x, + dirty->rect.y, dirty->rect.xl, dirty->rect.yl); + if (err == GFX_FATAL) + return err; + } + + dirty = dirty->next; + } + + _gfxwop_container_draw_contents(widget, visual->contents); + + recursively_free_dirty_rects(visual->dirty); + visual->dirty = NULL; + widget->flags &= ~GFXW_FLAG_DIRTY; + + return 0; +} + +static int +_gfxwop_visual_free(gfxw_widget_t *widget) +{ + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + gfxw_port_t **portrefs; + int retval; + + if (!GFXW_IS_VISUAL(visual)) { + GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); + widget->print(widget, 3); + return 1; + } + + portrefs = visual->port_refs; + + retval = _gfxwop_container_free(widget); + + free(portrefs); + return 0; +} + +static int +_gfxwop_visual_print(gfxw_widget_t *widget, int indentation) +{ + int i; + int comma = 0; + gfxw_visual_t *visual = (gfxw_visual_t *) widget; + + if (!GFXW_IS_VISUAL(visual)) { + GFXERROR("_gfxwop_visual_free() called on non-visual!Widget was: "); + widget->print(widget, 3); + return 1; + } + + _gfxw_print_widget(widget, indentation); + sciprintf("VISUAL; ports={"); + for (i = 0; i < visual->port_refs_nr; i++) + if (visual->port_refs[i]) { + if (comma) + sciprintf(","); + else + comma = 1; + + sciprintf("%d", i); + } + sciprintf("}\n"); + + return _w_gfxwop_container_print(widget, indentation); +} + +static int +_gfxwop_visual_set_visual(gfxw_widget_t *self, gfxw_visual_t *visual) +{ + if (self != GFXW(visual)) { + GFXWARN("Attempt to set a visual's parent visual to something else!\n"); + } else { + GFXWARN("Attempt to set a visual's parent visual!\n"); + } + return 1; +} + +void +_gfxw_set_ops_VISUAL(gfxw_container_t *visual) +{ + _gfxw_set_container_ops((gfxw_container_t *) visual, + _gfxwop_visual_draw, + _gfxwop_visual_free, + _gfxwop_container_tag, + _gfxwop_visual_print, + _gfxwop_basic_compare_to, + _gfxwop_basic_equals, + _gfxwop_basic_superarea_of, + _gfxwop_visual_set_visual, + _gfxwop_container_free_tagged, + _gfxwop_container_free_contents, + _gfxwop_container_add_dirty, + _gfxwop_container_add); +} + +gfxw_visual_t * +gfxw_new_visual(gfx_state_t *state, int font) +{ + gfxw_visual_t *visual = (gfxw_visual_t *) _gfxw_new_container_widget(gfx_rect(0, 0, 320, 200), sizeof(gfxw_visual_t), GFXW_VISUAL); + + visual->font_nr = font; + visual->gfx_state = state; + + visual->port_refs = (struct _gfxw_port**)sci_calloc(sizeof(gfxw_port_t), visual->port_refs_nr = 16); + + _gfxw_set_ops_VISUAL(GFXWC(visual)); + + return visual; +} + + +static int +_visual_find_free_ID(gfxw_visual_t *visual) +{ + int id = 0; + int newports = 16; + + while (visual->port_refs[id] && id < visual->port_refs_nr) + id++; + + if (id == visual->port_refs_nr) {/* Out of ports? */ + visual->port_refs = (struct _gfxw_port**)sci_realloc(visual->port_refs, visual->port_refs_nr += newports); + memset(visual->port_refs + id, 0, newports * sizeof(gfxw_port_t *)); /* Clear new port refs */ + } + + return id; +} + +static int +_gfxwop_add_dirty_rects(gfxw_container_t *dest, gfx_dirty_rect_t *src) +{ + DDIRTY(stderr, "Adding multiple dirty to #%d\n", dest->ID); + if (src) { + dest->dirty = gfxdr_add_dirty(dest->dirty, src->rect, GFXW_DIRTY_STRATEGY); + _gfxwop_add_dirty_rects(dest, src->next); + } + return 0; +} + +/*-------------*/ +/**** Ports ****/ +/*-------------*/ + +static int +_gfxwop_port_draw(gfxw_widget_t *widget, point_t pos) +{ + gfxw_port_t *port = (gfxw_port_t *) widget; + DRAW_ASSERT(widget, GFXW_PORT); + + if (port->decorations) { + DDIRTY(stderr, "Getting/applying deco dirty (multi)\n"); + _gfxwop_add_dirty_rects(GFXWC(port->decorations), port->dirty); + if (port->decorations->draw(GFXW(port->decorations), gfxw_point_zero)) { + port->decorations->dirty = NULL; + return 1; + } + port->decorations->dirty = NULL; + } + + _gfxwop_container_draw_contents(widget, port->contents); + + recursively_free_dirty_rects(port->dirty); + port->dirty = NULL; + widget->flags &= ~GFXW_FLAG_DIRTY; + return 0; +} + +static int +_gfxwop_port_free(gfxw_widget_t *widget) +{ + gfxw_port_t *port = (gfxw_port_t *) widget; + + if (port->visual) { + gfxw_visual_t *visual = port->visual; + int ID = port->ID; + + if (ID < 0 || ID >= visual->port_refs_nr) { + GFXWARN("Attempt to free port #%d; allowed: [0..%d]!\n", ID, visual->port_refs_nr); + return GFX_ERROR; + } + + if (visual->port_refs[ID] != port) { + GFXWARN("While freeing port %d: Port is at %p, but port list indicates %p!\n", + ID, port, visual->port_refs[ID]); + } else visual->port_refs[ID] = NULL; + + } + + if (port->decorations) + port->decorations->widfree(GFXW(port->decorations)); + + return _gfxwop_container_free(widget); +} + +static int +_gfxwop_port_print(gfxw_widget_t *widget, int indentation) +{ + gfxw_port_t *port = (gfxw_port_t *) widget; + + _gfxw_print_widget(widget, indentation); + sciprintf("PORT"); + sciprintf(" font=%d drawpos=(%d,%d)", port->font_nr, port->draw_pos.x, port->draw_pos.y); + if (port->gray_text) + sciprintf(" (gray)"); + _w_gfxwop_container_print(GFXW(port), indentation); + return _w_gfxwop_container_print_contents("decorations", GFXW(port->decorations), indentation); + +} + +static int +_gfxwop_port_superarea_of(gfxw_widget_t *self, gfxw_widget_t *other) +{ + gfxw_port_t *port = (gfxw_port_t *) self; + + if (!port->port_bg) + return _gfxwop_basic_superarea_of(self, other); + + return port->port_bg->superarea_of(port->port_bg, other); +} + +static int +_gfxwop_port_set_visual(gfxw_widget_t *widget, gfxw_visual_t *visual) +{ + gfxw_list_t *decorations = ((gfxw_port_t *) widget)->decorations; + widget->visual = visual; + + if (decorations) + if (decorations->set_visual(GFXW(decorations), visual)) { + GFXWARN("Setting the visual for decorations failed for port "); + widget->print(widget, 1); + return 1; + } + + return _gfxwop_container_set_visual(widget, visual); +} + +static int +_gfxwop_port_add_dirty(gfxw_container_t *widget, rect_t dirty, int propagate) +{ + gfxw_port_t *self = (gfxw_port_t *) widget; + + self->flags |= GFXW_FLAG_DIRTY; + + _gfxwop_container_add_dirty(widget, dirty, propagate); + + DDIRTY(stderr,"Added dirty to ID %d\n", widget->ID); + DDIRTY(stderr, "dirty= (%d,%d,%d,%d) bounds (%d,%d,%d,%d)\n", dirty.x, dirty.x, dirty.xl, dirty.yl, + widget->bounds.x, widget->bounds.y, widget->bounds.xl, widget->bounds.yl); +#if 0 + /* FIXME: This is a worthwhile optimization */ + if (self->port_bg) { + gfxw_widget_t foo; + + foo.bounds = dirty; /* Yeah, sub-elegant, I know */ + foo.bounds.x -= self->zone.x; + foo.bounds.y -= self->zone.y; + if (self->port_bg->superarea_of(self->port_bg, &foo)) { + gfxw_container_t *parent = self->parent; + while (parent) { + fprintf(stderr,"Dirtifying parent id %d\n", parent->ID); + parent->flags |= GFXW_FLAG_DIRTY; + parent = parent->parent; + } + return 0; + } + } /* else propagate to the parent, since we're not 'catching' the dirty rect */ +#endif + + if (propagate) + if (self->parent) { + DDIRTY(stderr, "PROPAGATE\n"); + return self->parent->add_dirty_abs(self->parent, dirty, 1); + } + + return 0; +} + +static int +_gfxwop_port_add(gfxw_container_t *container, gfxw_widget_t *widget) + /* O(n) */ +{ + return _gfxwop_ordered_add(container, widget, 1); +} + +void +_gfxw_set_ops_PORT(gfxw_container_t *widget) +{ + _gfxw_set_container_ops((gfxw_container_t *) widget, + _gfxwop_port_draw, + _gfxwop_port_free, + _gfxwop_container_tag, + _gfxwop_port_print, + _gfxwop_basic_compare_to, + _gfxwop_basic_equals, + _gfxwop_port_superarea_of, + _gfxwop_port_set_visual, + _gfxwop_container_free_tagged, + _gfxwop_container_free_contents, + _gfxwop_port_add_dirty, + _gfxwop_port_add); +} + +gfxw_port_t * +gfxw_new_port(gfxw_visual_t *visual, gfxw_port_t *predecessor, rect_t area, gfx_color_t fgcolor, gfx_color_t bgcolor) +{ + gfxw_port_t *widget = (gfxw_port_t *) + _gfxw_new_container_widget(area, sizeof(gfxw_port_t), GFXW_PORT); + + VERIFY_WIDGET(visual); + + widget->port_bg = NULL; + widget->parent = NULL; + widget->decorations = NULL; + widget->title_text = NULL; + widget->draw_pos = gfx_point(0, 0); + widget->gray_text = 0; + widget->color = fgcolor; + widget->bgcolor = bgcolor; + widget->font_nr = visual->font_nr; + widget->ID = _visual_find_free_ID(visual); + widget->chrono_port = 0; + visual->port_refs[widget->ID] = widget; + + _gfxw_set_ops_PORT(GFXWC(widget)); + + return widget; +} + +void gfxw_port_auto_restore_background(gfxw_visual_t *visual, gfxw_port_t *window, rect_t auto_rect) +{ + window->port_flags |= WINDOW_FLAG_AUTO_RESTORE; + window->restore_snap = gfxw_make_snapshot(visual, auto_rect); +} + +gfxw_port_t * +gfxw_remove_port(gfxw_visual_t *visual, gfxw_port_t *port) +{ + gfxw_port_t *parent; + VERIFY_WIDGET(visual); + VERIFY_WIDGET(port); + + if (!visual->contents) { + GFXWARN("Attempt to remove port from empty visual\n"); + return NULL; + } + + parent = (gfxw_port_t *) port->parent; + if (port->port_flags & WINDOW_FLAG_AUTO_RESTORE) + gfxw_restore_snapshot(visual, port->restore_snap); + + if (port->widfree(GFXW(port))) + return parent; + + while (parent && !GFXW_IS_PORT(parent)) + parent = (gfxw_port_t *) parent->parent; /* Ascend through ancestors */ + + return parent; +} + + +gfxw_port_t * +gfxw_find_port(gfxw_visual_t *visual, int ID) +{ + if (ID < 0 || ID >= visual->port_refs_nr) + return NULL; + + return visual->port_refs[ID]; +} + + +gfxw_port_t * +gfxw_find_default_port(gfxw_visual_t *visual) +{ + int id = visual->port_refs_nr; + + while (id--) { + gfxw_port_t *port = visual->port_refs[id]; + + if (port) + return port; + } + + return NULL; +} + + +/*** - other functions - ***/ + +gfxw_widget_t * +gfxw_set_id(gfxw_widget_t *widget, int ID, int subID) +{ + if (widget) { + widget->ID = ID; + widget->subID = subID; + } + + return widget; +} + +gfxw_dyn_view_t * +gfxw_dyn_view_set_params(gfxw_dyn_view_t *widget, int under_bits, void *under_bitsp, + int signal, void *signalp) +{ + if (!widget) + return NULL; + + widget->under_bits = under_bits; + widget->under_bitsp = under_bitsp; + widget->signal = signal; + widget->signalp = signalp; + + return widget; +} + +gfxw_widget_t * +gfxw_remove_id(gfxw_container_t *container, int ID, int subID) +{ + gfxw_widget_t **wp = &(container->contents); + + while (*wp) { + if ((*wp)->ID == ID + && (subID == GFXW_NO_ID + || (*wp)->subID == subID)) { + gfxw_widget_t *widget = *wp; + + *wp = (*wp)->next; + widget->next = NULL; + widget->parent = NULL; + widget->visual = NULL; + + return widget; + } + + wp = &((*wp)->next); + } + + return NULL; +} + + +gfxw_widget_t * +gfxw_hide_widget(gfxw_widget_t *widget) +{ + if (widget->flags & GFXW_FLAG_VISIBLE) { + widget->flags &= ~GFXW_FLAG_VISIBLE; + + if (widget->parent) + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return widget; +} + +gfxw_widget_t * +gfxw_show_widget(gfxw_widget_t *widget) +{ + if (!(widget->flags & GFXW_FLAG_VISIBLE)) { + widget->flags |= GFXW_FLAG_VISIBLE; + + if (widget->parent) + widget->parent->add_dirty_rel(widget->parent, widget->bounds, 1); + } + + return widget; +} + + +gfxw_snapshot_t * +gfxw_make_snapshot(gfxw_visual_t *visual, rect_t area) +{ + gfxw_snapshot_t *retval = (gfxw_snapshot_t*)sci_malloc(sizeof(gfxw_snapshot_t)); + + retval->serial = widget_serial_number_counter++; + + retval->area = area; + + /* Work around subset semantics in gfx_rect_subset. + This fixes the help icon in LSL5. */ + if (retval->area.xl == 320) retval->area.xl = 321; + + return retval; +} + + +int +gfxw_widget_matches_snapshot(gfxw_snapshot_t *snapshot, gfxw_widget_t *widget) +{ + int free_below = (snapshot->serial < widget_serial_number_counter)? 0: widget_serial_number_counter; + int free_above_eq = snapshot->serial; + rect_t bounds = widget->bounds; + + if (!GFXW_IS_CONTAINER(widget) && widget->parent) { + bounds.x += widget->parent->bounds.x; + bounds.y += widget->parent->bounds.y; + } + + return ((widget->serial >= free_above_eq + || widget->serial < free_below) + && gfx_rect_subset(bounds, snapshot->area)); +} + +#define MAGIC_FREE_NUMBER -42 + +void +_gfxw_free_contents_appropriately(gfxw_container_t *container, gfxw_snapshot_t *snapshot, int priority) +{ + gfxw_widget_t *widget = container->contents; + + while (widget) { + gfxw_widget_t *next = widget->next; + + if (gfxw_widget_matches_snapshot(snapshot, widget) && !(widget->flags & GFXW_FLAG_IMMUNE_TO_SNAPSHOTS) + && (priority == MAGIC_FREE_NUMBER || priority <= widget->widget_priority || widget->widget_priority == -1)) { + widget->widfree(widget); + } else { + if (GFXW_IS_CONTAINER(widget)) + _gfxw_free_contents_appropriately(GFXWC(widget), snapshot, priority); + } + + widget = next; + } +} + +gfxw_snapshot_t * +gfxw_restore_snapshot(gfxw_visual_t *visual, gfxw_snapshot_t *snapshot) +{ + _gfxw_free_contents_appropriately(GFXWC(visual), snapshot, MAGIC_FREE_NUMBER); + + return snapshot; +} + +void +gfxw_annihilate(gfxw_widget_t *widget) +{ + gfxw_visual_t *visual = widget->visual; + int widget_priority = 0; + int free_overdrawn = 0; + + gfxw_snapshot_t snapshot; + if (!GFXW_IS_CONTAINER(widget) && widget->parent && visual && (widget->flags & GFXW_FLAG_VISIBLE)) { + snapshot.serial = 0; + snapshot.area = widget->bounds; + snapshot.area.x += widget->parent->zone.x; + snapshot.area.y += widget->parent->zone.y; + free_overdrawn = 1; + widget_priority = widget->widget_priority; + } + + widget->widfree(GFXW(widget)); + + if (free_overdrawn) + _gfxw_free_contents_appropriately(GFXWC(visual), &snapshot, widget_priority); +} + + + +gfxw_dyn_view_t * +gfxw_picviewize_dynview(gfxw_dyn_view_t *dynview) +{ + dynview->type = GFXW_PIC_VIEW; + dynview->flags |= GFXW_FLAG_DIRTY; + + _gfxw_set_ops_PICVIEW(GFXW(dynview)); + + if (dynview->parent) + _gfxw_dirtify_container(dynview->parent, GFXW(dynview)); + + return dynview; +} + +/* Chrono-Ports (tm) */ + +gfxw_port_t * +gfxw_get_chrono_port(gfxw_visual_t *visual, gfxw_list_t **temp_widgets_list, int flags) +{ + gfxw_port_t *result = NULL; + gfx_color_t transparent = {0}; + int id = 0; + + if (!(flags & GFXW_CHRONO_NON_TOPMOST)) + { + result = gfxw_find_default_port(visual); + } else + { + id = visual->port_refs_nr; + while (id >= 0 && (!visual->port_refs[id] || + !visual->port_refs[id]->chrono_port)) + id--; + + if (id >= 0) + result = visual->port_refs[id]; + } + + if (!result || !result->chrono_port) + { + if (flags & GFXW_CHRONO_NO_CREATE) return NULL; + result = gfxw_new_port(visual, NULL, gfx_rect(0, 0, 320, 200), transparent, transparent); + *temp_widgets_list = gfxw_new_list(gfx_rect(0, 0, 320, 200), 1); + result->add(GFXWC(result), GFXW(*temp_widgets_list)); + result->chrono_port = 1; + if (temp_widgets_list) + *temp_widgets_list = GFXWC(result->contents); + return result; + }; + + if (temp_widgets_list) + *temp_widgets_list = GFXWC(result->contents); + return result; +} + +static int +gfxw_check_chrono_overlaps(gfxw_port_t *chrono, gfxw_widget_t *widget) +{ + gfxw_widget_t *seeker = GFXWC(chrono->contents)->contents; + + while (seeker) { + if (gfx_rect_equals(seeker->bounds, widget->bounds)) + { + gfxw_annihilate(GFXW(seeker)); + return 1; + } + + seeker = seeker->next; + } + + return 0; +} + +void +gfxw_add_to_chrono(gfxw_visual_t *visual, gfxw_widget_t *widget) +{ + gfxw_list_t *tw; + gfxw_port_t *chrono = + gfxw_get_chrono_port(visual, &tw, 0); + + gfxw_check_chrono_overlaps(chrono, widget); + chrono->add(GFXWC(chrono), widget); +} + +static gfxw_widget_t * +gfxw_widget_intersects_chrono(gfxw_list_t *tw, gfxw_widget_t *widget) +{ + gfxw_widget_t *seeker; + + assert(tw->type == GFXW_SORTED_LIST); + + seeker = tw->contents; + while (seeker) + { + point_t origin; + rect_t bounds = widget->bounds; + + bounds = widget->bounds; + origin.x = seeker->parent->zone.x; + origin.y = seeker->parent->zone.y; + gfx_rect_translate(bounds, origin); + + if (gfx_rects_overlap(bounds, seeker->bounds)) + return seeker; + + seeker = seeker->next; + } + + return 0; +} + +void +gfxw_widget_reparent_chrono(gfxw_visual_t *visual, gfxw_widget_t *view, gfxw_list_t *target) +{ + gfxw_list_t *tw; + gfxw_port_t *chrono; + gfxw_widget_t *intersector; + + chrono = gfxw_get_chrono_port(visual, &tw, GFXW_CHRONO_NO_CREATE); + if (chrono == NULL) return; + + intersector = gfxw_widget_intersects_chrono(tw, view); + if (intersector) + { + point_t origin = gfx_point(intersector->parent->zone.x, + intersector->parent->zone.y); + + gfxw_remove_widget_from_container(GFXWC(chrono), GFXW(tw)); + gfxw_remove_widget_from_container(GFXWC(chrono->parent), GFXW(chrono)); + gfxw_annihilate(GFXW(chrono)); + + gfx_rect_translate(tw->zone, origin); + target->add(GFXWC(target), GFXW(tw)); + } +} + +void +gfxw_widget_kill_chrono(gfxw_visual_t *visual, int window) +{ + int i; + + for (i=window; i < visual->port_refs_nr ; i++) + { + if (visual->port_refs[i] && visual->port_refs[i]->chrono_port) + gfxw_annihilate(GFXW(visual->port_refs[i])); + } +} diff --git a/engines/sci/gfx/wrapper.c b/engines/sci/gfx/wrapper.c new file mode 100644 index 0000000000..0bf1097c2a --- /dev/null +++ b/engines/sci/gfx/wrapper.c @@ -0,0 +1,26 @@ +/*************************************************************************** + wrapper.c Copyright (C) 2000 Christoph Reichenbach + + + This program may be modified and copied freely according to the terms of + the GNU general public license (GPL), as long as the above copyright + notice and the licensing information contained herein are preserved. + + Please refer to www.gnu.org for licensing details. + + This work is provided AS IS, without warranty of any kind, expressed or + implied, including but not limited to the warranties of merchantibility, + noninfringement, and fitness for a specific purpose. The author will not + be held liable for any damage caused by this work or derivatives of it. + + By using this source code, you agree to the licensing terms as stated + above. + + + Please contact the maintainer for bug reports or inquiries. + + Current Maintainer: + + Christoph Reichenbach (CR) <jameson@linuxgames.com> + +***************************************************************************/ |