aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/drivers
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/drivers
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/drivers')
-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
17 files changed, 9528 insertions, 0 deletions
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 */