aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/gfx/drivers/sdl_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/gfx/drivers/sdl_driver.c')
-rw-r--r--engines/sci/gfx/drivers/sdl_driver.c1235
1 files changed, 1235 insertions, 0 deletions
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