aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx
diff options
context:
space:
mode:
authorJordi Vilalta Prat2009-02-15 06:10:59 +0000
committerJordi Vilalta Prat2009-02-15 06:10:59 +0000
commitfa6e10e9cec163845aa29e7940c86e9c9ab8a2bc (patch)
treece87338830cc8c149e1de545246bcefe4f45da00 /engines/sci/gfx
parent7c148ddf021c990fa866b7600f979aac9a5b26c9 (diff)
downloadscummvm-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')
-rw-r--r--engines/sci/gfx/Makefile.am20
-rw-r--r--engines/sci/gfx/alpha_mvi_crossblit.c360
-rw-r--r--engines/sci/gfx/antialias.c163
-rw-r--r--engines/sci/gfx/drivers/EXPORTS_ggi1
-rw-r--r--engines/sci/gfx/drivers/EXPORTS_sdl1
-rw-r--r--engines/sci/gfx/drivers/EXPORTS_xlib2
-rw-r--r--engines/sci/gfx/drivers/Makefile.am32
-rw-r--r--engines/sci/gfx/drivers/dc_driver.c1267
-rw-r--r--engines/sci/gfx/drivers/dd_driver.cpp1021
-rw-r--r--engines/sci/gfx/drivers/dd_driver.h2
-rw-r--r--engines/sci/gfx/drivers/dd_driver_line.cpp163
-rw-r--r--engines/sci/gfx/drivers/directfb_driver.c1033
-rw-r--r--engines/sci/gfx/drivers/dx_driver.cpp1179
-rw-r--r--engines/sci/gfx/drivers/dx_driver.h151
-rw-r--r--engines/sci/gfx/drivers/gfx_drivers.c192
-rw-r--r--engines/sci/gfx/drivers/ggi_driver.c1035
-rw-r--r--engines/sci/gfx/drivers/null_driver.c211
-rw-r--r--engines/sci/gfx/drivers/scummvm_driver.cpp543
-rw-r--r--engines/sci/gfx/drivers/sdl_driver.c1235
-rw-r--r--engines/sci/gfx/drivers/xlib_driver.c1460
-rw-r--r--engines/sci/gfx/font-5x8.c2580
-rw-r--r--engines/sci/gfx/font-6x10.c3092
-rw-r--r--engines/sci/gfx/font.c385
-rw-r--r--engines/sci/gfx/gfx_console.c1450
-rw-r--r--engines/sci/gfx/gfx_crossblit.c107
-rw-r--r--engines/sci/gfx/gfx_line.c96
-rw-r--r--engines/sci/gfx/gfx_pixmap_scale.c497
-rw-r--r--engines/sci/gfx/gfx_res_options.c652
-rw-r--r--engines/sci/gfx/gfx_resource.c434
-rw-r--r--engines/sci/gfx/gfx_support.c450
-rw-r--r--engines/sci/gfx/gfx_test.c1504
-rw-r--r--engines/sci/gfx/gfx_tools.c465
-rw-r--r--engines/sci/gfx/menubar.c536
-rw-r--r--engines/sci/gfx/operations.c2490
-rw-r--r--engines/sci/gfx/resmgr.c708
-rw-r--r--engines/sci/gfx/resource/Makefile.am7
-rw-r--r--engines/sci/gfx/resource/sci_cursor_0.c107
-rw-r--r--engines/sci/gfx/resource/sci_font.c153
-rw-r--r--engines/sci/gfx/resource/sci_pal_1.c178
-rw-r--r--engines/sci/gfx/resource/sci_pic_0.c2023
-rw-r--r--engines/sci/gfx/resource/sci_picfill.c429
-rw-r--r--engines/sci/gfx/resource/sci_picfill_aux.c205
-rw-r--r--engines/sci/gfx/resource/sci_resmgr.c341
-rw-r--r--engines/sci/gfx/resource/sci_view_0.c254
-rw-r--r--engines/sci/gfx/resource/sci_view_1.c554
-rw-r--r--engines/sci/gfx/sbtree.c473
-rw-r--r--engines/sci/gfx/sci_widgets.c765
-rw-r--r--engines/sci/gfx/widgets.c2600
-rw-r--r--engines/sci/gfx/wrapper.c26
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, &region, &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, &region, 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 *) &params, 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 *) &params, 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 *) &params, 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 *) &params, 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>
+
+***************************************************************************/