diff options
author | Max Horn | 2002-08-24 10:41:32 +0000 |
---|---|---|
committer | Max Horn | 2002-08-24 10:41:32 +0000 |
commit | f3b4f38892a9b0138c60b5402e03701eb727d8d5 (patch) | |
tree | 8ad19db7b99996e934ca63ac66eceb73609fd2b1 | |
parent | 51730bb3feceb66e03bbeac1dc3d08699a86f166 (diff) | |
download | scummvm-rg350-f3b4f38892a9b0138c60b5402e03701eb727d8d5.tar.gz scummvm-rg350-f3b4f38892a9b0138c60b5402e03701eb727d8d5.tar.bz2 scummvm-rg350-f3b4f38892a9b0138c60b5402e03701eb727d8d5.zip |
SDL_gl and normal SDL backend now share a common base class
svn-id: r4813
-rw-r--r-- | backends/sdl/build.rules | 3 | ||||
-rw-r--r-- | backends/sdl/sdl-common.cpp | 859 | ||||
-rw-r--r-- | backends/sdl/sdl-common.h | 197 | ||||
-rw-r--r-- | backends/sdl/sdl.cpp | 1083 | ||||
-rw-r--r-- | backends/sdl/sdl_gl.cpp | 921 |
5 files changed, 1103 insertions, 1960 deletions
diff --git a/backends/sdl/build.rules b/backends/sdl/build.rules index bc91d660ef..51f25bf3bc 100644 --- a/backends/sdl/build.rules +++ b/backends/sdl/build.rules @@ -3,9 +3,10 @@ MODULES += backends/sdl DEFINES += -DUNIX INCLUDES += `sdl-config --cflags` LIBS += `sdl-config --libs` +OBJS += backends/sdl/sdl-common.o # The normal (non OpenGL-accelerated) SDL backend -OBJS += backends/sdl/sdl.o +OBJS += backends/sdl/sdl.o # Uncomment these lines (instead of the above) to use SDL with OpenGL # OBJS += backends/sdl/sdl_gl.o diff --git a/backends/sdl/sdl-common.cpp b/backends/sdl/sdl-common.cpp new file mode 100644 index 0000000000..f2a88e06a5 --- /dev/null +++ b/backends/sdl/sdl-common.cpp @@ -0,0 +1,859 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "sdl-common.h" +#include "sound/mididrv.h" +#include "gameDetector.h" +#include "scaler.h" +#include "scumm.h" // Only #included for error() and warning() + +#include "scummvm.xpm" + + +bool atexit_proc_installed = false; +void atexit_proc() { + SDL_ShowCursor(SDL_ENABLE); + SDL_Quit(); +} + +OSystem *OSystem_SDL_create(int gfx_mode, bool full_screen) { + return OSystem_SDL_Common::create(gfx_mode, full_screen); +} + +OSystem *OSystem_SDL_Common::create(int gfx_mode, bool full_screen) { + OSystem_SDL_Common *syst = OSystem_SDL_Common::create(); + syst->_mode = gfx_mode; + syst->_full_screen = full_screen; + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) ==-1) { + error("Could not initialize SDL: %s.\n", SDL_GetError()); + } + +#ifdef WIN32 // Use waveout on win32, not + SDL_AudioInit("waveout"); // dsound - unfortunatly dsound +#endif // doesn't do COOPERATIVE mode + + SDL_ShowCursor(SDL_DISABLE); + + // Setup the icon + syst->setup_icon(); + +#ifndef MACOSX // Work around a bug in OS X + // Clean up on exit + atexit_proc_installed = true; + atexit(atexit_proc); +#endif + + return syst; +} + +void OSystem_SDL_Common::set_timer(int timer, int (*callback)(int)) { + SDL_SetTimer(timer, (SDL_TimerCallback) callback); +} + +void OSystem_SDL_Common::init_size(uint w, uint h) { + //if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) + // error("320x200 is the only game resolution supported"); + + SCREEN_WIDTH = w; + SCREEN_HEIGHT = h; + CKSUM_NUM = (SCREEN_WIDTH*SCREEN_HEIGHT/(8*8)); + /* allocate palette, it needs to be persistent across + * driver changes, so i'll alloc it here */ + _cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256); + + dirty_rect_list = (SDL_Rect*)calloc(NUM_DIRTY_RECT, sizeof(SDL_Rect)); + _mouse_backup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING); + dirty_checksums = (uint32*)calloc(CKSUM_NUM*2, sizeof(uint32)); + + load_gfx_mode(); + +#ifdef MACOSX // Work around a bug in OS X 10.1 related to OpenGL in windowed mode + if (!atexit_proc_installed) { + atexit_proc_installed = true; + atexit(atexit_proc); + } +#endif +} + +void OSystem_SDL_Common::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) { + if (sdl_screen == NULL) + return; + + if (pitch == SCREEN_WIDTH && x==0 && y==0 && w==SCREEN_WIDTH && h==SCREEN_HEIGHT && _mode_flags&DF_WANT_RECT_OPTIM) { + /* Special, optimized case for full screen updates. + * It tries to determine what areas were actually changed, + * and just updates those, on the actual display. */ + add_dirty_rgn_auto(buf); + } else { + /* Clip the coordinates */ + if (x < 0) { w+=x; buf-=x; x = 0; } + if (y < 0) { h+=y; buf-=y*pitch; y = 0; } + if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } + if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } + + if (w <= 0 || h <= 0) + return; + + cksum_valid = false; + add_dirty_rect(x, y, w, h); + } + + /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ + if (_mouse_drawn) + undraw_mouse(); + + if (SDL_LockSurface(sdl_screen) == -1) + error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + byte *dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; + do { + memcpy(dst, buf, w); + dst += SCREEN_WIDTH; + buf += pitch; + } while (--h); + + SDL_UnlockSurface(sdl_screen); +} + + +void OSystem_SDL_Common::add_dirty_rect(int x, int y, int w, int h) { + if (force_full) + return; + + if (num_dirty_rects == NUM_DIRTY_RECT) + force_full = true; + else { + SDL_Rect *r = &dirty_rect_list[num_dirty_rects++]; + + /* Update the dirty region by 1 pixel for graphics drivers + * that "smear" the screen */ + if (_mode_flags & DF_UPDATE_EXPAND_1_PIXEL) { + x--; + y--; + w+=2; + h+=2; + } + + /* clip */ + if (x < 0) { w+=x; x=0; } + if (y < 0) { h+=y; y=0; } + if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } + if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + } +} + +#define ROL(a,n) a = (a<<(n)) | (a>>(32-(n))) +#define DOLINE(x) a ^= ((uint32*)buf)[0+(x)*(SCREEN_WIDTH/4)]; b ^= ((uint32*)buf)[1+(x)*(SCREEN_WIDTH/4)] +void OSystem_SDL_Common::mk_checksums(const byte *buf) { + uint32 *sums = dirty_checksums; + uint x,y; + const uint last_x = (uint)SCREEN_WIDTH/8; + const uint last_y = (uint)SCREEN_HEIGHT/8; + + /* the 8x8 blocks in buf are enumerated starting in the top left corner and + * reading each line at a time from left to right */ + for(y=0; y != last_y; y++, buf+=SCREEN_WIDTH*(8-1)) + for(x=0; x != last_x; x++, buf+=8) { + uint32 a = x; + uint32 b = y; + + DOLINE(0); ROL(a,13); ROL(b,11); + DOLINE(2); ROL(a,13); ROL(b,11); + DOLINE(4); ROL(a,13); ROL(b,11); + DOLINE(6); ROL(a,13); ROL(b,11); + + a*=0xDEADBEEF; + b*=0xBAADF00D; + + DOLINE(1); ROL(a,13); ROL(b,11); + DOLINE(3); ROL(a,13); ROL(b,11); + DOLINE(5); ROL(a,13); ROL(b,11); + DOLINE(7); ROL(a,13); ROL(b,11); + + /* output the checksum for this block */ + *sums++=a+b; + } +} +#undef DOLINE +#undef ROL + + +void OSystem_SDL_Common::add_dirty_rgn_auto(const byte *buf) { + assert( ((uint32)buf & 3) == 0); + + /* generate a table of the checksums */ + mk_checksums(buf); + + if (!cksum_valid) { + force_full = true; + cksum_valid = true; + } + + /* go through the checksum list, compare it with the previous checksums, + and add all dirty rectangles to a list. try to combine small rectangles + into bigger ones in a simple way */ + if (!force_full) { + int x,y,w; + uint32 *ck = dirty_checksums; + + for(y=0; y!=SCREEN_HEIGHT/8; y++) { + for(x=0; x!=SCREEN_WIDTH/8; x++,ck++) { + if (ck[0] != ck[CKSUM_NUM]) { + /* found a dirty 8x8 block, now go as far to the right as possible, + and at the same time, unmark the dirty status by setting old to new. */ + w=0; + do { + ck[w+CKSUM_NUM] = ck[w]; + w++; + } while (x+w != SCREEN_WIDTH/8 && ck[w] != ck[w+CKSUM_NUM]); + + add_dirty_rect(x*8, y*8, w*8, 8); + + if (force_full) + goto get_out; + } + } + } + } else { + get_out:; + /* Copy old checksums to new */ + memcpy(dirty_checksums + CKSUM_NUM, dirty_checksums, CKSUM_NUM * sizeof(uint32)); + } +} + +void OSystem_SDL_Common::kbd_mouse() { + uint32 time = get_msecs(); + if (time >= km.last_time + km.delay_time) { + km.last_time = time; + if (km.x_down_count == 1) { + km.x_down_time = time; + km.x_down_count = 2; + } + if (km.y_down_count == 1) { + km.y_down_time = time; + km.y_down_count = 2; + } + + if (km.x_vel || km.y_vel) { + if (km.x_down_count) { + if (time > km.x_down_time + km.delay_time*12) { + if (km.x_vel > 0) + km.x_vel++; + else + km.x_vel--; + } else if (time > km.x_down_time + km.delay_time*8) { + if (km.x_vel > 0) + km.x_vel = 5; + else + km.x_vel = -5; + } + } + if (km.y_down_count) { + if (time > km.y_down_time + km.delay_time*12) { + if (km.y_vel > 0) + km.y_vel++; + else + km.y_vel--; + } else if (time > km.y_down_time + km.delay_time*8) { + if (km.y_vel > 0) + km.y_vel = 5; + else + km.y_vel = -5; + } + } + + km.x += km.x_vel; + km.y += km.y_vel; + + if (km.x < 0) { + km.x = 0; + km.x_vel = -1; + km.x_down_count = 1; + } else if (km.x > km.x_max) { + km.x = km.x_max; + km.x_vel = 1; + km.x_down_count = 1; + } + + if (km.y < 0) { + km.y = 0; + km.y_vel = -1; + km.y_down_count = 1; + } else if (km.y > km.y_max) { + km.y = km.y_max; + km.y_vel = 1; + km.y_down_count = 1; + } + + SDL_WarpMouse(km.x, km.y); + } + } +} + +bool OSystem_SDL_Common::show_mouse(bool visible) { + if (_mouse_visible == visible) + return visible; + + bool last = _mouse_visible; + _mouse_visible = visible; + + if (visible) + draw_mouse(); + else + undraw_mouse(); + + return last; +} + +void OSystem_SDL_Common::set_mouse_pos(int x, int y) { + if (x != _mouse_cur_state.x || y != _mouse_cur_state.y) { + _mouse_cur_state.x = x; + _mouse_cur_state.y = y; + undraw_mouse(); + } +} + +void OSystem_SDL_Common::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) { + _mouse_cur_state.w = w; + _mouse_cur_state.h = h; + + _mouse_hotspot_x = hotspot_x; + _mouse_hotspot_y = hotspot_y; + + _mouse_data = (byte*)buf; + + undraw_mouse(); +} + +void OSystem_SDL_Common::set_shake_pos(int shake_pos) { + _new_shake_pos = shake_pos; +} + +uint32 OSystem_SDL_Common::get_msecs() { + return SDL_GetTicks(); +} + +void OSystem_SDL_Common::delay_msecs(uint msecs) { + SDL_Delay(msecs); +} + +void *OSystem_SDL_Common::create_thread(ThreadProc *proc, void *param) { + return SDL_CreateThread(proc, param); +} + +int mapKey(int key, byte mod) +{ + if (key >= SDLK_F1 && key <= SDLK_F9) { + return key - SDLK_F1 + 315; + } else if (key >= 'a' && key <= 'z' && mod & KMOD_SHIFT) { + key &= ~0x20; + } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) + return 0; + return key; +} + +bool OSystem_SDL_Common::poll_event(Event *event) { + SDL_Event ev; + kbd_mouse(); + + for(;;) { + if (!SDL_PollEvent(&ev)) + return false; + + switch(ev.type) { + case SDL_KEYDOWN: { + byte b = 0; + if (ev.key.keysym.mod & KMOD_SHIFT) b |= KBD_SHIFT; + if (ev.key.keysym.mod & KMOD_CTRL) b |= KBD_CTRL; + if (ev.key.keysym.mod & KMOD_ALT) b |= KBD_ALT; + event->kbd.flags = b; + + /* internal keypress? */ + if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) { + property(PROP_TOGGLE_FULLSCREEN, NULL); + break; + } + + if ((b == KBD_CTRL && ev.key.keysym.sym=='z') || (b == KBD_ALT && ev.key.keysym.sym=='x')) { + quit(); + break; + } + if (b == (KBD_CTRL|KBD_ALT) && + (ev.key.keysym.sym>='1') && (ev.key.keysym.sym<='7')) { + Property prop; + prop.gfx_mode = ev.key.keysym.sym - '1'; + property(PROP_SET_GFX_MODE, &prop); + break; + } + #ifdef QTOPIA + // quit on fn+backspace on zaurus + if (ev.key.keysym.sym==127) { + quit(); + break; + } + // map menu key (f11) to f5 (scumm menu) + if (ev.key.keysym.sym==292) { + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = 286; + event->kbd.ascii = mapKey(286, ev.key.keysym.mod); + } + // map center (space) to tab (default action ) + // i wanted to map the calendar button but the calendar comes up + // + else if (ev.key.keysym.sym==32) { + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = 9; + event->kbd.ascii = mapKey(9, ev.key.keysym.mod); + } + // since we stole space (pause) above we'll rebind it to the tab key on the keyboard + else if (ev.key.keysym.sym==9) { + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = 32; + event->kbd.ascii = mapKey(32, ev.key.keysym.mod); + } + else { + // let the events fall through if we didn't change them, this may not be the best way to + // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. + // and yes i have an huge terminal size so i dont wrap soon enough. + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = ev.key.keysym.sym; + event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); + } + #endif + #ifndef QTOPIA + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = ev.key.keysym.sym; + event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); + #endif + + switch(ev.key.keysym.sym) { + case SDLK_LEFT: + km.x_vel = -1; + km.x_down_count = 1; + break; + case SDLK_RIGHT: + km.x_vel = 1; + km.x_down_count = 1; + break; + case SDLK_UP: + km.y_vel = -1; + km.y_down_count = 1; + break; + case SDLK_DOWN: + km.y_vel = 1; + km.y_down_count = 1; + break; + default: + break; + } + + return true; + } + + case SDL_KEYUP: { + event->event_code = EVENT_KEYUP; + event->kbd.keycode = ev.key.keysym.sym; + event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); + + switch(ev.key.keysym.sym){ + case SDLK_LEFT: + if (km.x_vel < 0) { + km.x_vel = 0; + km.x_down_count = 0; + } + break; + case SDLK_RIGHT: + if (km.x_vel > 0) { + km.x_vel = 0; + km.x_down_count = 0; + } + break; + case SDLK_UP: + if (km.y_vel < 0) { + km.y_vel = 0; + km.y_down_count = 0; + } + break; + case SDLK_DOWN: + if (km.y_vel > 0) { + km.y_vel = 0; + km.y_down_count = 0; + } + break; + default: + break; + } + return true; + } + + case SDL_MOUSEMOTION: + event->event_code = EVENT_MOUSEMOVE; + km.x = event->mouse.x = ev.motion.x; + km.y = event->mouse.y = ev.motion.y; + + event->mouse.x /= scaling; + event->mouse.y /= scaling; + + return true; + + case SDL_MOUSEBUTTONDOWN: + if (ev.button.button == SDL_BUTTON_LEFT) + event->event_code = EVENT_LBUTTONDOWN; + else if (ev.button.button == SDL_BUTTON_RIGHT) + event->event_code = EVENT_RBUTTONDOWN; + else + break; + km.x = event->mouse.x = ev.motion.x; + km.y = event->mouse.y = ev.motion.y; + event->mouse.x /= scaling; + event->mouse.y /= scaling; + + return true; + + case SDL_MOUSEBUTTONUP: + if (ev.button.button == SDL_BUTTON_LEFT) + event->event_code = EVENT_LBUTTONUP; + else if (ev.button.button == SDL_BUTTON_RIGHT) + event->event_code = EVENT_RBUTTONUP; + else + break; + event->mouse.x = ev.button.x; + event->mouse.y = ev.button.y; + event->mouse.x /= scaling; + event->mouse.y /= scaling; + return true; + + case SDL_QUIT: + quit(); + } + } +} + +bool OSystem_SDL_Common::set_sound_proc(void *param, SoundProc *proc, byte format) { + SDL_AudioSpec desired; + + /* only one format supported at the moment */ + + desired.freq = SAMPLES_PER_SEC; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = 2048; + desired.callback = proc; + desired.userdata = param; + if (SDL_OpenAudio(&desired, NULL) != 0) { + return false; + } + SDL_PauseAudio(0); + return true; +} + + +/* retrieve the 320x200 bitmap currently being displayed */ +void OSystem_SDL_Common::get_320x200_image(byte *buf) { + /* make sure the mouse is gone */ + undraw_mouse(); + + if (SDL_LockSurface(sdl_screen) == -1) + error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + memcpy(buf, sdl_screen->pixels, SCREEN_WIDTH*SCREEN_HEIGHT); + + SDL_UnlockSurface(sdl_screen); +} + +uint32 OSystem_SDL_Common::property(int param, Property *value) { + switch(param) { + + case PROP_GET_FULLSCREEN: + return _full_screen; + + case PROP_SET_WINDOW_CAPTION: + SDL_WM_SetCaption(value->caption, value->caption); + return 1; + + case PROP_OPEN_CD: + if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) + cdrom = NULL; + else { + cdrom = SDL_CDOpen(value->cd_num); + /* Did if open? Check if cdrom is NULL */ + if (!cdrom) { + warning("Couldn't open drive: %s\n", SDL_GetError()); + } + } + break; + + case PROP_SET_GFX_MODE: + if (value->gfx_mode >= 7) + return 0; + + _mode = value->gfx_mode; + hotswap_gfx_mode(); + + return 1; + + case PROP_SHOW_DEFAULT_CURSOR: + SDL_ShowCursor(value->show_cursor ? SDL_ENABLE : SDL_DISABLE); + break; + + case PROP_GET_SAMPLE_RATE: + return SAMPLES_PER_SEC; + } + + return 0; +} + +void OSystem_SDL_Common::quit() { + if(cdrom) { + SDL_CDStop(cdrom); + SDL_CDClose(cdrom); + } + unload_gfx_mode(); + exit(1); +} + +void OSystem_SDL_Common::draw_mouse() { + if (_mouse_drawn || !_mouse_visible) + return; + + int x = _mouse_cur_state.x - _mouse_hotspot_x; + int y = _mouse_cur_state.y - _mouse_hotspot_y; + int w = _mouse_cur_state.w; + int h = _mouse_cur_state.h; + byte color; + byte *src = _mouse_data; // Image representing the mouse + byte *bak = _mouse_backup; // Surface used to backup the area obscured by the mouse + byte *dst; // Surface we are drawing into + + // clip the mouse rect, and addjust the src pointer accordingly + if (x < 0) { + w += x; + src -= x; + x = 0; + } + if (y < 0) { + h += y; + src -= y * _mouse_cur_state.w; + y = 0; + } + if (w > SCREEN_WIDTH - x) + w = SCREEN_WIDTH - x; + if (h > SCREEN_HEIGHT - y) + h = SCREEN_HEIGHT - y; + + // Store the bounding box so that undraw mouse can restore the area the + // mouse currently covers to its original content. + _mouse_old_state.x = x; + _mouse_old_state.y = y; + _mouse_old_state.w = w; + _mouse_old_state.h = h; + + // Quick check to see if anything has to be drawn at all + if (w <= 0 || h <= 0) + return; + + // Draw the mouse cursor; backup the covered area in "bak" + + if (SDL_LockSurface(sdl_screen) == -1) + error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + add_dirty_rect(x, y, w, h); + + dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; + while (h > 0) { + int width = w; + while (width > 0) { + *bak++ = *dst; + color = *src++; + if (color != 0xFF) // 0xFF = transparent, don't draw + *dst = color; + dst++; + width--; + } + src += _mouse_cur_state.w - w; + bak += MAX_MOUSE_W - w; + dst += SCREEN_WIDTH - w; + h--; + } + + SDL_UnlockSurface(sdl_screen); + + // Finally, set the flag to indicate the mouse has been drawn + _mouse_drawn = true; +} + +void OSystem_SDL_Common::undraw_mouse() { + if (!_mouse_drawn) + return; + _mouse_drawn = false; + + if (SDL_LockSurface(sdl_screen) == -1) + error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + byte *dst, *bak = _mouse_backup; + const int old_mouse_x = _mouse_old_state.x; + const int old_mouse_y = _mouse_old_state.y; + const int old_mouse_w = _mouse_old_state.w; + const int old_mouse_h = _mouse_old_state.h; + int x,y; + + // No need to do clipping here, since draw_mouse() did that already + + dst = (byte *)sdl_screen->pixels + old_mouse_y * SCREEN_WIDTH + old_mouse_x; + for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += SCREEN_WIDTH) { + for (x = 0; x < old_mouse_w; ++x) { + dst[x] = bak[x]; + } + } + + add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); + + SDL_UnlockSurface(sdl_screen); +} + +void OSystem_SDL_Common::stop_cdrom() { /* Stop CD Audio in 1/10th of a second */ + cd_stop_time = SDL_GetTicks() + 100; + cd_num_loops = 0; + +} + +void OSystem_SDL_Common::play_cdrom(int track, int num_loops, int start_frame, int end_frame) { + if (!num_loops && !start_frame) + return; + + if (!cdrom) + return; + + if (end_frame > 0) + end_frame+=5; + + cd_track = track; + cd_num_loops = num_loops; + cd_start_frame = start_frame; + + SDL_CDStatus(cdrom); + SDL_CDPlayTracks(cdrom, track, start_frame, 0, end_frame); + cd_end_frame = end_frame; + cd_stop_time = 0; + cd_end_time = SDL_GetTicks() + cdrom->track[track].length * 1000 / CD_FPS; +} + +bool OSystem_SDL_Common::poll_cdrom() { + if (!cdrom) + return false; + + return (cd_num_loops != 0 && (SDL_GetTicks() < cd_end_time || SDL_CDStatus(cdrom) != CD_STOPPED)); +} + +void OSystem_SDL_Common::update_cdrom() { + if (!cdrom) + return; + + if (cd_stop_time != 0 && SDL_GetTicks() >= cd_stop_time) { + SDL_CDStop(cdrom); + cd_num_loops = 0; + cd_stop_time = 0; + return; + } + + if (cd_num_loops == 0 || SDL_GetTicks() < cd_end_time) + return; + + if (cd_num_loops != 1 && SDL_CDStatus(cdrom) != CD_STOPPED) { + // Wait another second for it to be done + cd_end_time += 1000; + return; + } + + if (cd_num_loops > 0) + cd_num_loops--; + + if (cd_num_loops != 0) { + SDL_CDPlayTracks(cdrom, cd_track, cd_start_frame, 0, cd_end_frame); + cd_end_time = SDL_GetTicks() + cdrom->track[cd_track].length * 1000 / CD_FPS; + } +} + +void OSystem_SDL_Common::setup_icon() { + int w, h, ncols, nbytes, i; + unsigned int rgba[256], icon[32 * 32]; + unsigned char mask[32][4]; + + sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); + if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { + warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); + return; + } + for (i = 0; i < ncols; i++) { + unsigned char code; + char color[32]; + unsigned int col; + sscanf(scummvm_icon[1 + i], "%c c %s", &code, color); + if (!strcmp(color, "None")) + col = 0x00000000; + else if (!strcmp(color, "black")) + col = 0xFF000000; + else if (color[0] == '#') { + sscanf(color + 1, "%06x", &col); + col |= 0xFF000000; + } else { + warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + return; + } + + rgba[code] = col; + } + memset(mask, 0, sizeof(mask)); + for (h = 0; h < 32; h++) { + char *line = scummvm_icon[1 + ncols + h]; + for (w = 0; w < 32; w++) { + icon[w + 32 * h] = rgba[line[w]]; + if (rgba[line[w]] & 0xFF000000) { + mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); + } + } + } + + SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); + SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); +} + +void *OSystem_SDL_Common::create_mutex(void) { + return (void *) SDL_CreateMutex(); +} + +void OSystem_SDL_Common::lock_mutex(void *mutex) { + SDL_mutexP((SDL_mutex *) mutex); +} + +void OSystem_SDL_Common::unlock_mutex(void *mutex) { + SDL_mutexV((SDL_mutex *) mutex); +} + +void OSystem_SDL_Common::delete_mutex(void *mutex) { + SDL_DestroyMutex((SDL_mutex *) mutex); +} diff --git a/backends/sdl/sdl-common.h b/backends/sdl/sdl-common.h new file mode 100644 index 0000000000..ae7b64306e --- /dev/null +++ b/backends/sdl/sdl-common.h @@ -0,0 +1,197 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef SDL_COMMON_H +#define SDL_COMMON_H + +#include "stdafx.h" +#include "scummsys.h" +#include "system.h" + +#include <SDL.h> +#include <SDL_thread.h> + +class OSystem_SDL_Common : public OSystem { +public: + // Set colors of the palette + void set_palette(const byte *colors, uint start, uint num) = 0; + + // Set the size of the video bitmap. + // Typically, 320x200 + void init_size(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); + + // Update the dirty areas of the screen + void update_screen() = 0; + + // Either show or hide the mouse cursor + bool show_mouse(bool visible); + + // Set the position of the mouse cursor + void set_mouse_pos(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y); + + // Shaking is used in SCUMM. Set current shake position. + void set_shake_pos(int shake_pos); + + // Get the number of milliseconds since the program was started. + uint32 get_msecs(); + + // Delay for a specified amount of milliseconds + void delay_msecs(uint msecs); + + // Create a thread + void *create_thread(ThreadProc *proc, void *param); + + // Get the next event. + // Returns true if an event was retrieved. + bool poll_event(Event *event); + + // Set function that generates samples + bool set_sound_proc(void *param, SoundProc *proc, byte sound); + + // Poll cdrom status + // Returns true if cd audio is playing + bool poll_cdrom(); + + // Play cdrom audio track + void play_cdrom(int track, int num_loops, int start_frame, int end_frame); + + // Stop cdrom audio track + void stop_cdrom(); + + // Update cdrom audio status + void update_cdrom(); + + // Quit + void quit(); + + // Set a parameter + uint32 property(int param, Property *value); + + // Add a callback timer + void set_timer(int timer, int (*callback)(int)); + + // Mutex handling + void *create_mutex(void); + void lock_mutex(void *mutex); + void unlock_mutex(void *mutex); + void delete_mutex(void *mutex); + + static OSystem *create(int gfx_mode, bool full_screen); + +protected: + typedef void TwoXSaiProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, + uint8 *dstPtr, uint32 dstPitch, int width, int height); + + SDL_Surface *sdl_screen; // unseen game screen + SDL_Surface *sdl_tmpscreen; // temporary screen (for 2xsai) + SDL_CD *cdrom; + + enum { + DF_WANT_RECT_OPTIM = 1 << 0, + DF_REAL_8BIT = 1 << 1, + DF_SEPARATE_TEMPSCREEN = 1 << 2, + DF_UPDATE_EXPAND_1_PIXEL = 1 << 3 + }; + + int _mode; + bool _full_screen; + bool _mouse_visible; + bool _mouse_drawn; + uint32 _mode_flags; + + bool force_full; //Force full redraw on next update_screen + bool cksum_valid; + + enum { + NUM_DIRTY_RECT = 100, + + MAX_MOUSE_W = 40, + MAX_MOUSE_H = 40, + MAX_SCALING = 3 + }; + + int SCREEN_WIDTH, SCREEN_HEIGHT, CKSUM_NUM; + SDL_Rect *dirty_rect_list; + int num_dirty_rects; + uint32 *dirty_checksums; + + int scaling; + + /* CD Audio */ + int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; + Uint32 cd_end_time, cd_stop_time, cd_next_second; + + /* Keyboard mouse emulation */ + struct KbdMouse { + int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count; + uint32 last_time, delay_time, x_down_time, y_down_time; + } km; + + struct MousePos { + int16 x, y, w, h; + }; + + byte *_mouse_data; + byte *_mouse_backup; + MousePos _mouse_cur_state; + MousePos _mouse_old_state; + int16 _mouse_hotspot_x; + int16 _mouse_hotspot_y; + int _current_shake_pos; + int _new_shake_pos; + TwoXSaiProc *_sai_func; + SDL_Color *_cur_pal; + + uint _palette_changed_first, _palette_changed_last; + + OSystem_SDL_Common() : _current_shake_pos(0), _new_shake_pos(0) {} + + void add_dirty_rgn_auto(const byte *buf); + void mk_checksums(const byte *buf); + + static void fill_sound(void *userdata, Uint8 * stream, int len); + + void add_dirty_rect(int x, int y, int w, int h); + + void draw_mouse(); + void undraw_mouse(); + + virtual void load_gfx_mode() = 0; + virtual void unload_gfx_mode() = 0; + virtual void hotswap_gfx_mode() = 0; + + void get_320x200_image(byte *buf); + + void setup_icon(); + void kbd_mouse(); + + static OSystem_SDL_Common *create(); +}; + + +#endif diff --git a/backends/sdl/sdl.cpp b/backends/sdl/sdl.cpp index 204d1323dd..37afc12c48 100644 --- a/backends/sdl/sdl.cpp +++ b/backends/sdl/sdl.cpp @@ -20,227 +20,35 @@ * */ -#include "stdafx.h" -#include "scummsys.h" -#include "system.h" -#include "sound/mididrv.h" -#include "gameDetector.h" +#include "sdl-common.h" #include "scaler.h" #include "scumm.h" // Only #included for error() and warning() -#include "scummvm.xpm" -#include <SDL.h> -#include <SDL_thread.h> - - -class OSystem_SDL : public OSystem { +class OSystem_SDL_Normal : public OSystem_SDL_Common { public: // Set colors of the palette void set_palette(const byte *colors, uint start, uint num); - // Set the size of the video bitmap. - // Typically, 320x200 - void init_size(uint w, uint h); - - // Draw a bitmap to screen. - // The screen will not be updated to reflect the new bitmap - void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); - // Update the dirty areas of the screen void update_screen(); - // Either show or hide the mouse cursor - bool show_mouse(bool visible); - - // Set the position of the mouse cursor - void set_mouse_pos(int x, int y); - - // Set the bitmap that's used when drawing the cursor. - void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y); - - // Shaking is used in SCUMM. Set current shake position. - void set_shake_pos(int shake_pos); - - // Get the number of milliseconds since the program was started. - uint32 get_msecs(); - - // Delay for a specified amount of milliseconds - void delay_msecs(uint msecs); - - // Create a thread - void *create_thread(ThreadProc *proc, void *param); - - // Get the next event. - // Returns true if an event was retrieved. - bool poll_event(Event *event); - - // Set function that generates samples - bool set_sound_proc(void *param, SoundProc *proc, byte sound); - - // Poll cdrom status - // Returns true if cd audio is playing - bool poll_cdrom(); - - // Play cdrom audio track - void play_cdrom(int track, int num_loops, int start_frame, int end_frame); - - // Stop cdrom audio track - void stop_cdrom(); - - // Update cdrom audio status - void update_cdrom(); - - // Quit - void quit(); - // Set a parameter uint32 property(int param, Property *value); - // Add a callback timer - void set_timer(int timer, int (*callback)(int)); - - // Mutex handling - void *create_mutex(void); - void lock_mutex(void *mutex); - void unlock_mutex(void *mutex); - void delete_mutex(void *mutex); - - static OSystem *create(int gfx_mode, bool full_screen); - -private: - typedef void TwoXSaiProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, - uint8 *dstPtr, uint32 dstPitch, int width, int height); - - SDL_Surface *sdl_screen; // unseen game screen +protected: SDL_Surface *sdl_hwscreen; // hardware screen - SDL_Surface *sdl_tmpscreen; // temporary screen (for 2xsai) - SDL_CD *cdrom; - - enum { - DF_WANT_RECT_OPTIM = 1 << 0, - DF_REAL_8BIT = 1 << 1, - DF_SEPARATE_TEMPSCREEN = 1 << 2, - DF_UPDATE_EXPAND_1_PIXEL = 1 << 3 - }; - - int _mode; - bool _full_screen; - bool _mouse_visible; - bool _mouse_drawn; - uint32 _mode_flags; - - bool force_full; //Force full redraw on next update_screen - bool cksum_valid; - - enum { - NUM_DIRTY_RECT = 100, - - MAX_MOUSE_W = 40, - MAX_MOUSE_H = 40, - MAX_SCALING = 3 - }; - - int SCREEN_WIDTH, SCREEN_HEIGHT, CKSUM_NUM; - SDL_Rect *dirty_rect_list; - int num_dirty_rects; - uint32 *dirty_checksums; - - int scaling; - - /* CD Audio */ - int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; - Uint32 cd_end_time, cd_stop_time, cd_next_second; - - /* Keyboard mouse emulation */ - struct KbdMouse { - int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count; - uint32 last_time, delay_time, x_down_time, y_down_time; - } km; - - struct MousePos { - int16 x, y, w, h; - }; - - byte *_mouse_data; - byte *_mouse_backup; - MousePos _mouse_cur_state; - MousePos _mouse_old_state; - int16 _mouse_hotspot_x; - int16 _mouse_hotspot_y; - int _current_shake_pos; - int _new_shake_pos; - TwoXSaiProc *_sai_func; - SDL_Color *_cur_pal; - - uint _palette_changed_first, _palette_changed_last; - - OSystem_SDL() : _current_shake_pos(0), _new_shake_pos(0) {} - - void add_dirty_rgn_auto(const byte *buf); - void mk_checksums(const byte *buf); - - static void fill_sound(void *userdata, Uint8 * stream, int len); - - void add_dirty_rect(int x, int y, int w, int h); - - void draw_mouse(); - void undraw_mouse(); void load_gfx_mode(); void unload_gfx_mode(); - void hotswap_gfx_mode(); - - void get_320x200_image(byte *buf); - - void setup_icon(); - void kbd_mouse(); }; -void atexit_proc() { - SDL_ShowCursor(SDL_ENABLE); - - SDL_QuitSubSystem(SDL_INIT_VIDEO); - SDL_QuitSubSystem(SDL_INIT_TIMER); - SDL_QuitSubSystem(SDL_INIT_CDROM); -#ifndef WIN32 // FIXME: SDL bug - closing audio freezes w/ waveout - SDL_QuitSubSystem(SDL_INIT_AUDIO); -#endif +OSystem_SDL_Common *OSystem_SDL_Common::create() { + return new OSystem_SDL_Normal(); } -OSystem *OSystem_SDL::create(int gfx_mode, bool full_screen) { - OSystem_SDL *syst = new OSystem_SDL(); - syst->_mode = gfx_mode; - syst->_full_screen = full_screen; - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) ==-1) { - error("Could not initialize SDL: %s.\n", SDL_GetError()); - } - -#ifdef WIN32 /* Use waveout on win32, not */ - SDL_AudioInit("waveout"); /* dsound - unfortunatly dsound */ -#endif /* doesn't do COOPERATIVE mode*/ - - SDL_ShowCursor(SDL_DISABLE); - - /* Setup the icon */ - syst->setup_icon(); - - /* Clean up on exit */ - atexit(atexit_proc); - - return syst; -} - -void OSystem_SDL::set_timer(int timer, int (*callback)(int)) { - SDL_SetTimer(timer, (SDL_TimerCallback) callback); -} -OSystem *OSystem_SDL_create(int gfx_mode, bool full_screen) { - return OSystem_SDL::create(gfx_mode, full_screen); -} - -void OSystem_SDL::set_palette(const byte *colors, uint start, uint num) { +void OSystem_SDL_Normal::set_palette(const byte *colors, uint start, uint num) { const byte *b = colors; uint i; SDL_Color *base = _cur_pal + start; @@ -258,7 +66,7 @@ void OSystem_SDL::set_palette(const byte *colors, uint start, uint num) { _palette_changed_last = start + num; } -void OSystem_SDL::load_gfx_mode() { +void OSystem_SDL_Normal::load_gfx_mode() { force_full = true; scaling = 1; _mode_flags = 0; @@ -363,13 +171,17 @@ normal_mode:; } -void OSystem_SDL::unload_gfx_mode() { - SDL_FreeSurface(sdl_screen); - sdl_screen = NULL; - - SDL_FreeSurface(sdl_hwscreen); - sdl_hwscreen = NULL; +void OSystem_SDL_Normal::unload_gfx_mode() { + if (sdl_screen) { + SDL_FreeSurface(sdl_screen); + sdl_screen = NULL; + } + if (sdl_hwscreen) { + SDL_FreeSurface(sdl_hwscreen); + sdl_hwscreen = NULL; + } + if (_mode_flags & DF_SEPARATE_TEMPSCREEN) { free((uint16*)sdl_tmpscreen->pixels); SDL_FreeSurface(sdl_tmpscreen); @@ -377,176 +189,7 @@ void OSystem_SDL::unload_gfx_mode() { sdl_tmpscreen = NULL; } -void OSystem_SDL::init_size(uint w, uint h) { - //if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) - // error("320x200 is the only game resolution supported"); - - SCREEN_WIDTH = w; - SCREEN_HEIGHT = h; - CKSUM_NUM = (SCREEN_WIDTH*SCREEN_HEIGHT/(8*8)); - /* allocate palette, it needs to be persistent across - * driver changes, so i'll alloc it here */ - _cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256); - - dirty_rect_list = (SDL_Rect*)calloc(NUM_DIRTY_RECT, sizeof(SDL_Rect)); - _mouse_backup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING); - dirty_checksums = (uint32*)calloc(CKSUM_NUM*2, sizeof(uint32)); - - load_gfx_mode(); -} - -void OSystem_SDL::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) { - if (sdl_screen == NULL) - return; - - if (pitch == SCREEN_WIDTH && x==0 && y==0 && w==SCREEN_WIDTH && h==SCREEN_HEIGHT && _mode_flags&DF_WANT_RECT_OPTIM) { - /* Special, optimized case for full screen updates. - * It tries to determine what areas were actually changed, - * and just updates those, on the actual display. */ - add_dirty_rgn_auto(buf); - } else { - /* Clip the coordinates */ - if (x < 0) { w+=x; buf-=x; x = 0; } - if (y < 0) { h+=y; buf-=y*pitch; y = 0; } - if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } - if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } - - if (w <= 0 || h <= 0) - return; - - cksum_valid = false; - add_dirty_rect(x, y, w, h); - } - - /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ - if (_mouse_drawn) - undraw_mouse(); - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - byte *dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; - do { - memcpy(dst, buf, w); - dst += SCREEN_WIDTH; - buf += pitch; - } while (--h); - - SDL_UnlockSurface(sdl_screen); -} - - -void OSystem_SDL::add_dirty_rect(int x, int y, int w, int h) { - if (force_full) - return; - - if (num_dirty_rects == NUM_DIRTY_RECT) - force_full = true; - else { - SDL_Rect *r = &dirty_rect_list[num_dirty_rects++]; - - /* Update the dirty region by 1 pixel for graphics drivers - * that "smear" the screen */ - if (_mode_flags & DF_UPDATE_EXPAND_1_PIXEL) { - x--; - y--; - w+=2; - h+=2; - } - - /* clip */ - if (x < 0) { w+=x; x=0; } - if (y < 0) { h+=y; y=0; } - if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } - if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } - - r->x = x; - r->y = y; - r->w = w; - r->h = h; - } -} - -#define ROL(a,n) a = (a<<(n)) | (a>>(32-(n))) -#define DOLINE(x) a ^= ((uint32*)buf)[0+(x)*(SCREEN_WIDTH/4)]; b ^= ((uint32*)buf)[1+(x)*(SCREEN_WIDTH/4)] -void OSystem_SDL::mk_checksums(const byte *buf) { - uint32 *sums = dirty_checksums; - uint x,y; - const uint last_x = (uint)SCREEN_WIDTH/8; - const uint last_y = (uint)SCREEN_HEIGHT/8; - - /* the 8x8 blocks in buf are enumerated starting in the top left corner and - * reading each line at a time from left to right */ - for(y=0; y != last_y; y++, buf+=SCREEN_WIDTH*(8-1)) - for(x=0; x != last_x; x++, buf+=8) { - uint32 a = x; - uint32 b = y; - - DOLINE(0); ROL(a,13); ROL(b,11); - DOLINE(2); ROL(a,13); ROL(b,11); - DOLINE(4); ROL(a,13); ROL(b,11); - DOLINE(6); ROL(a,13); ROL(b,11); - - a*=0xDEADBEEF; - b*=0xBAADF00D; - - DOLINE(1); ROL(a,13); ROL(b,11); - DOLINE(3); ROL(a,13); ROL(b,11); - DOLINE(5); ROL(a,13); ROL(b,11); - DOLINE(7); ROL(a,13); ROL(b,11); - - /* output the checksum for this block */ - *sums++=a+b; - } -} -#undef DOLINE -#undef ROL - - -void OSystem_SDL::add_dirty_rgn_auto(const byte *buf) { - assert( ((uint32)buf & 3) == 0); - - /* generate a table of the checksums */ - mk_checksums(buf); - - if (!cksum_valid) { - force_full = true; - cksum_valid = true; - } - - /* go through the checksum list, compare it with the previous checksums, - and add all dirty rectangles to a list. try to combine small rectangles - into bigger ones in a simple way */ - if (!force_full) { - int x,y,w; - uint32 *ck = dirty_checksums; - - for(y=0; y!=SCREEN_HEIGHT/8; y++) { - for(x=0; x!=SCREEN_WIDTH/8; x++,ck++) { - if (ck[0] != ck[CKSUM_NUM]) { - /* found a dirty 8x8 block, now go as far to the right as possible, - and at the same time, unmark the dirty status by setting old to new. */ - w=0; - do { - ck[w+CKSUM_NUM] = ck[w]; - w++; - } while (x+w != SCREEN_WIDTH/8 && ck[w] != ck[w+CKSUM_NUM]); - - add_dirty_rect(x*8, y*8, w*8, 8); - - if (force_full) - goto get_out; - } - } - } - } else { - get_out:; - /* Copy old checksums to new */ - memcpy(dirty_checksums + CKSUM_NUM, dirty_checksums, CKSUM_NUM * sizeof(uint32)); - } -} - -void OSystem_SDL::update_screen() { +void OSystem_SDL_Normal::update_screen() { if (sdl_hwscreen == NULL) return; // Can this really happen? @@ -687,347 +330,7 @@ void OSystem_SDL::update_screen() { force_full = false; } -void OSystem_SDL::kbd_mouse() { - uint32 time = get_msecs(); - if (time >= km.last_time + km.delay_time) { - km.last_time = time; - if (km.x_down_count == 1) { - km.x_down_time = time; - km.x_down_count = 2; - } - if (km.y_down_count == 1) { - km.y_down_time = time; - km.y_down_count = 2; - } - - if (km.x_vel || km.y_vel) { - if (km.x_down_count) { - if (time > km.x_down_time + km.delay_time*12) { - if (km.x_vel > 0) - km.x_vel++; - else - km.x_vel--; - } else if (time > km.x_down_time + km.delay_time*8) { - if (km.x_vel > 0) - km.x_vel = 5; - else - km.x_vel = -5; - } - } - if (km.y_down_count) { - if (time > km.y_down_time + km.delay_time*12) { - if (km.y_vel > 0) - km.y_vel++; - else - km.y_vel--; - } else if (time > km.y_down_time + km.delay_time*8) { - if (km.y_vel > 0) - km.y_vel = 5; - else - km.y_vel = -5; - } - } - - km.x += km.x_vel; - km.y += km.y_vel; - - if (km.x < 0) { - km.x = 0; - km.x_vel = -1; - km.x_down_count = 1; - } else if (km.x > km.x_max) { - km.x = km.x_max; - km.x_vel = 1; - km.x_down_count = 1; - } - - if (km.y < 0) { - km.y = 0; - km.y_vel = -1; - km.y_down_count = 1; - } else if (km.y > km.y_max) { - km.y = km.y_max; - km.y_vel = 1; - km.y_down_count = 1; - } - - SDL_WarpMouse(km.x, km.y); - } - } -} - -bool OSystem_SDL::show_mouse(bool visible) { - if (_mouse_visible == visible) - return visible; - - bool last = _mouse_visible; - _mouse_visible = visible; - - if (visible) - draw_mouse(); - else - undraw_mouse(); - - return last; -} - -void OSystem_SDL::set_mouse_pos(int x, int y) { - if (x != _mouse_cur_state.x || y != _mouse_cur_state.y) { - _mouse_cur_state.x = x; - _mouse_cur_state.y = y; - undraw_mouse(); - } -} - -void OSystem_SDL::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) { - _mouse_cur_state.w = w; - _mouse_cur_state.h = h; - - _mouse_hotspot_x = hotspot_x; - _mouse_hotspot_y = hotspot_y; - - _mouse_data = (byte*)buf; - - undraw_mouse(); -} - -void OSystem_SDL::set_shake_pos(int shake_pos) { - _new_shake_pos = shake_pos; -} - -uint32 OSystem_SDL::get_msecs() { - return SDL_GetTicks(); -} - -void OSystem_SDL::delay_msecs(uint msecs) { - SDL_Delay(msecs); -} - -void *OSystem_SDL::create_thread(ThreadProc *proc, void *param) { - return SDL_CreateThread(proc, param); -} - -int mapKey(int key, byte mod) -{ - if (key >= SDLK_F1 && key <= SDLK_F9) { - return key - SDLK_F1 + 315; - } else if (key >= 'a' && key <= 'z' && mod & KMOD_SHIFT) { - key &= ~0x20; - } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) - return 0; - return key; -} - -bool OSystem_SDL::poll_event(Event *event) { - SDL_Event ev; - kbd_mouse(); - - for(;;) { - if (!SDL_PollEvent(&ev)) - return false; - - switch(ev.type) { - case SDL_KEYDOWN: { - byte b = 0; - if (ev.key.keysym.mod & KMOD_SHIFT) b |= KBD_SHIFT; - if (ev.key.keysym.mod & KMOD_CTRL) b |= KBD_CTRL; - if (ev.key.keysym.mod & KMOD_ALT) b |= KBD_ALT; - event->kbd.flags = b; - - /* internal keypress? */ - if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) { - property(PROP_TOGGLE_FULLSCREEN, NULL); - break; - } - - if ((b == KBD_CTRL && ev.key.keysym.sym=='z') || (b == KBD_ALT && ev.key.keysym.sym=='x')) { - quit(); - break; - } - if (b == (KBD_CTRL|KBD_ALT) && - (ev.key.keysym.sym>='1') && (ev.key.keysym.sym<='7')) { - Property prop; - prop.gfx_mode = ev.key.keysym.sym - '1'; - property(PROP_SET_GFX_MODE, &prop); - break; - } - #ifdef QTOPIA - // quit on fn+backspace on zaurus - if (ev.key.keysym.sym==127) { - quit(); - break; - } - // map menu key (f11) to f5 (scumm menu) - if (ev.key.keysym.sym==292) { - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = 286; - event->kbd.ascii = mapKey(286, ev.key.keysym.mod); - } - // map center (space) to tab (default action ) - // i wanted to map the calendar button but the calendar comes up - // - else if (ev.key.keysym.sym==32) { - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = 9; - event->kbd.ascii = mapKey(9, ev.key.keysym.mod); - } - // since we stole space (pause) above we'll rebind it to the tab key on the keyboard - else if (ev.key.keysym.sym==9) { - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = 32; - event->kbd.ascii = mapKey(32, ev.key.keysym.mod); - } - else { - // let the events fall through if we didn't change them, this may not be the best way to - // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. - // and yes i have an huge terminal size so i dont wrap soon enough. - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = ev.key.keysym.sym; - event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); - } - #endif - #ifndef QTOPIA - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = ev.key.keysym.sym; - event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); - #endif - - switch(ev.key.keysym.sym) { - case SDLK_LEFT: - km.x_vel = -1; - km.x_down_count = 1; - break; - case SDLK_RIGHT: - km.x_vel = 1; - km.x_down_count = 1; - break; - case SDLK_UP: - km.y_vel = -1; - km.y_down_count = 1; - break; - case SDLK_DOWN: - km.y_vel = 1; - km.y_down_count = 1; - break; - default: - break; - } - - return true; - } - - case SDL_KEYUP: { - event->event_code = EVENT_KEYUP; - event->kbd.keycode = ev.key.keysym.sym; - event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); - - switch(ev.key.keysym.sym){ - case SDLK_LEFT: - if (km.x_vel < 0) { - km.x_vel = 0; - km.x_down_count = 0; - } - break; - case SDLK_RIGHT: - if (km.x_vel > 0) { - km.x_vel = 0; - km.x_down_count = 0; - } - break; - case SDLK_UP: - if (km.y_vel < 0) { - km.y_vel = 0; - km.y_down_count = 0; - } - break; - case SDLK_DOWN: - if (km.y_vel > 0) { - km.y_vel = 0; - km.y_down_count = 0; - } - break; - default: - break; - } - return true; - } - - case SDL_MOUSEMOTION: - event->event_code = EVENT_MOUSEMOVE; - km.x = event->mouse.x = ev.motion.x; - km.y = event->mouse.y = ev.motion.y; - - event->mouse.x /= scaling; - event->mouse.y /= scaling; - - return true; - - case SDL_MOUSEBUTTONDOWN: - if (ev.button.button == SDL_BUTTON_LEFT) - event->event_code = EVENT_LBUTTONDOWN; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event->event_code = EVENT_RBUTTONDOWN; - else - break; - km.x = event->mouse.x = ev.motion.x; - km.y = event->mouse.y = ev.motion.y; - event->mouse.x /= scaling; - event->mouse.y /= scaling; - - return true; - - case SDL_MOUSEBUTTONUP: - if (ev.button.button == SDL_BUTTON_LEFT) - event->event_code = EVENT_LBUTTONUP; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event->event_code = EVENT_RBUTTONUP; - else - break; - event->mouse.x = ev.button.x; - event->mouse.y = ev.button.y; - event->mouse.x /= scaling; - event->mouse.y /= scaling; - return true; - - case SDL_QUIT: - quit(); - } - } -} - -bool OSystem_SDL::set_sound_proc(void *param, SoundProc *proc, byte format) { - SDL_AudioSpec desired; - - /* only one format supported at the moment */ - - desired.freq = SAMPLES_PER_SEC; - desired.format = AUDIO_S16SYS; - desired.channels = 2; - desired.samples = 2048; - desired.callback = proc; - desired.userdata = param; - if (SDL_OpenAudio(&desired, NULL) != 0) { - return false; - } - SDL_PauseAudio(0); - return true; -} - - -/* retrieve the 320x200 bitmap currently being displayed */ -void OSystem_SDL::get_320x200_image(byte *buf) { - /* make sure the mouse is gone */ - undraw_mouse(); - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - memcpy(buf, sdl_screen->pixels, SCREEN_WIDTH*SCREEN_HEIGHT); - - SDL_UnlockSurface(sdl_screen); -} - -void OSystem_SDL::hotswap_gfx_mode() { +void OSystem_SDL_Normal::hotswap_gfx_mode() { /* hmm, need to allocate a 320x200 bitmap * which will contain the "backup" of the screen during the change. * then draw that to the new screen right after it's setup. @@ -1049,16 +352,15 @@ void OSystem_SDL::hotswap_gfx_mode() { SDL_SetColors(sdl_screen, _cur_pal, 0, 256); /* blit image */ - OSystem_SDL::copy_rect(bak_mem, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + OSystem_SDL_Normal::copy_rect(bak_mem, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); free(bak_mem); - OSystem_SDL::update_screen(); + OSystem_SDL_Normal::update_screen(); } -uint32 OSystem_SDL::property(int param, Property *value) { - switch(param) { +uint32 OSystem_SDL_Normal::property(int param, Property *value) { - case PROP_TOGGLE_FULLSCREEN: + if (param == PROP_TOGGLE_FULLSCREEN) { _full_screen ^= true; if (!SDL_WM_ToggleFullScreen(sdl_hwscreen)) { @@ -1066,344 +368,7 @@ uint32 OSystem_SDL::property(int param, Property *value) { hotswap_gfx_mode(); } return 1; - - case PROP_GET_FULLSCREEN: - return _full_screen; - - case PROP_SET_WINDOW_CAPTION: - SDL_WM_SetCaption(value->caption, value->caption); - return 1; - - case PROP_OPEN_CD: - if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) - cdrom = NULL; - else { - cdrom = SDL_CDOpen(value->cd_num); - /* Did if open? Check if cdrom is NULL */ - if (!cdrom) { - warning("Couldn't open drive: %s\n", SDL_GetError()); - } - } - break; - - case PROP_SET_GFX_MODE: - if (value->gfx_mode >= 7) - return 0; - - _mode = value->gfx_mode; - hotswap_gfx_mode(); - - return 1; - - case PROP_SHOW_DEFAULT_CURSOR: - SDL_ShowCursor(value->show_cursor ? SDL_ENABLE : SDL_DISABLE); - break; - - case PROP_GET_SAMPLE_RATE: - return SAMPLES_PER_SEC; - } - - return 0; -} - -void OSystem_SDL::quit() { - if(cdrom) { - SDL_CDStop(cdrom); - SDL_CDClose(cdrom); - } - unload_gfx_mode(); - exit(1); -} - -void OSystem_SDL::draw_mouse() { - if (_mouse_drawn || !_mouse_visible) - return; - - int x = _mouse_cur_state.x - _mouse_hotspot_x; - int y = _mouse_cur_state.y - _mouse_hotspot_y; - int w = _mouse_cur_state.w; - int h = _mouse_cur_state.h; - byte color; - byte *src = _mouse_data; // Image representing the mouse - byte *bak = _mouse_backup; // Surface used to backup the area obscured by the mouse - byte *dst; // Surface we are drawing into - - // clip the mouse rect, and addjust the src pointer accordingly - if (x < 0) { - w += x; - src -= x; - x = 0; - } - if (y < 0) { - h += y; - src -= y * _mouse_cur_state.w; - y = 0; - } - if (w > SCREEN_WIDTH - x) - w = SCREEN_WIDTH - x; - if (h > SCREEN_HEIGHT - y) - h = SCREEN_HEIGHT - y; - - // Store the bounding box so that undraw mouse can restore the area the - // mouse currently covers to its original content. - _mouse_old_state.x = x; - _mouse_old_state.y = y; - _mouse_old_state.w = w; - _mouse_old_state.h = h; - - // Quick check to see if anything has to be drawn at all - if (w <= 0 || h <= 0) - return; - - // Draw the mouse cursor; backup the covered area in "bak" - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - add_dirty_rect(x, y, w, h); - - dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; - while (h > 0) { - int width = w; - while (width > 0) { - *bak++ = *dst; - color = *src++; - if (color != 0xFF) // 0xFF = transparent, don't draw - *dst = color; - dst++; - width--; - } - src += _mouse_cur_state.w - w; - bak += MAX_MOUSE_W - w; - dst += SCREEN_WIDTH - w; - h--; } - - SDL_UnlockSurface(sdl_screen); - // Finally, set the flag to indicate the mouse has been drawn - _mouse_drawn = true; -} - -void OSystem_SDL::undraw_mouse() { - if (!_mouse_drawn) - return; - _mouse_drawn = false; - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - byte *dst, *bak = _mouse_backup; - const int old_mouse_x = _mouse_old_state.x; - const int old_mouse_y = _mouse_old_state.y; - const int old_mouse_w = _mouse_old_state.w; - const int old_mouse_h = _mouse_old_state.h; - int x,y; - - // No need to do clipping here, since draw_mouse() did that already - - dst = (byte *)sdl_screen->pixels + old_mouse_y * SCREEN_WIDTH + old_mouse_x; - for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += SCREEN_WIDTH) { - for (x = 0; x < old_mouse_w; ++x) { - dst[x] = bak[x]; - } - } - - add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); - - SDL_UnlockSurface(sdl_screen); -} - -void OSystem_SDL::stop_cdrom() { /* Stop CD Audio in 1/10th of a second */ - cd_stop_time = SDL_GetTicks() + 100; - cd_num_loops = 0; - -} - -void OSystem_SDL::play_cdrom(int track, int num_loops, int start_frame, int end_frame) { - if (!num_loops && !start_frame) - return; - - if (!cdrom) - return; - - if (end_frame > 0) - end_frame+=5; - - cd_track = track; - cd_num_loops = num_loops; - cd_start_frame = start_frame; - - SDL_CDStatus(cdrom); - SDL_CDPlayTracks(cdrom, track, start_frame, 0, end_frame); - cd_end_frame = end_frame; - cd_stop_time = 0; - cd_end_time = SDL_GetTicks() + cdrom->track[track].length * 1000 / CD_FPS; -} - -bool OSystem_SDL::poll_cdrom() { - if (!cdrom) - return false; - - return (cd_num_loops != 0 && (SDL_GetTicks() < cd_end_time || SDL_CDStatus(cdrom) != CD_STOPPED)); -} - -void OSystem_SDL::update_cdrom() { - if (!cdrom) - return; - - if (cd_stop_time != 0 && SDL_GetTicks() >= cd_stop_time) { - SDL_CDStop(cdrom); - cd_num_loops = 0; - cd_stop_time = 0; - return; - } - - if (cd_num_loops == 0 || SDL_GetTicks() < cd_end_time) - return; - - if (cd_num_loops != 1 && SDL_CDStatus(cdrom) != CD_STOPPED) { - // Wait another second for it to be done - cd_end_time += 1000; - return; - } - - if (cd_num_loops > 0) - cd_num_loops--; - - if (cd_num_loops != 0) { - SDL_CDPlayTracks(cdrom, cd_track, cd_start_frame, 0, cd_end_frame); - cd_end_time = SDL_GetTicks() + cdrom->track[cd_track].length * 1000 / CD_FPS; - } -} - -void OSystem_SDL::setup_icon() { - int w, h, ncols, nbytes, i; - unsigned int rgba[256], icon[32 * 32]; - unsigned char mask[32][4]; - - sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); - if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { - warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); - return; - } - for (i = 0; i < ncols; i++) { - unsigned char code; - char color[32]; - unsigned int col; - sscanf(scummvm_icon[1 + i], "%c c %s", &code, color); - if (!strcmp(color, "None")) - col = 0x00000000; - else if (!strcmp(color, "black")) - col = 0xFF000000; - else if (color[0] == '#') { - sscanf(color + 1, "%06x", &col); - col |= 0xFF000000; - } else { - warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); - return; - } - - rgba[code] = col; - } - memset(mask, 0, sizeof(mask)); - for (h = 0; h < 32; h++) { - char *line = scummvm_icon[1 + ncols + h]; - for (w = 0; w < 32; w++) { - icon[w + 32 * h] = rgba[line[w]]; - if (rgba[line[w]] & 0xFF000000) { - mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); - } - } - } - - SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); - SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); -} - -void *OSystem_SDL::create_mutex(void) { - return (void *) SDL_CreateMutex(); + return OSystem_SDL_Common::property(param, value); } - -void OSystem_SDL::lock_mutex(void *mutex) { - SDL_mutexP((SDL_mutex *) mutex); -} - -void OSystem_SDL::unlock_mutex(void *mutex) { - SDL_mutexV((SDL_mutex *) mutex); -} - -void OSystem_SDL::delete_mutex(void *mutex) { - SDL_DestroyMutex((SDL_mutex *) mutex); -} - - -#ifdef USE_NULL_DRIVER - -/* NULL video driver */ -class OSystem_NULL : public OSystem { -public: - void set_palette(const byte *colors, uint start, uint num) {} - void init_size(uint w, uint h); - void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) {} - void update_screen() {} - bool show_mouse(bool visible) { return false; } - void set_mouse_pos(int x, int y) {} - void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) {} - void set_shake_pos(int shake_pos) {} - uint32 get_msecs(); - void delay_msecs(uint msecs); - void *create_thread(ThreadProc *proc, void *param) { return NULL; } - bool poll_event(Event *event) { return false; } - bool set_sound_proc(void *param, SoundProc *proc, byte sound) {} - void quit() { exit(1); } - uint32 property(int param, Property *value) { return 0; } - static OSystem *create(int gfx_mode, bool full_screen); -private: - - uint msec_start; - - uint32 get_ticks(); -}; - -void OSystem_NULL::init_size(uint w, uint h, byte sound) { - msec_start = get_ticks(); -} - -uint32 OSystem_NULL::get_ticks() { - uint a = 0; -#ifdef WIN32 - a = GetTickCount(); -#endif -#ifdef UNIX - struct timeval tv; - gettimeofday(&tv, NULL); - a = tv.tv_sec * 1000 + tv.tv_usec/1000; -#endif - - return a; -} - -void OSystem_NULL::delay_msecs(uint msecs) { -#ifdef WIN32 - Sleep(msecs); -#endif -#ifdef UNIX - usleep(msecs*1000); -#endif -} - -uint32 OSystem_NULL::get_msecs() { - return get_ticks() - msec_start; -} - -OSystem *OSystem_NULL_create() { - return new OSystem_NULL(); -} -#else /* USE_NULL_DRIVER */ - -OSystem *OSystem_NULL_create() { - return NULL; -} - -#endif diff --git a/backends/sdl/sdl_gl.cpp b/backends/sdl/sdl_gl.cpp index adec2a1f6b..2fa1c5cb69 100644 --- a/backends/sdl/sdl_gl.cpp +++ b/backends/sdl/sdl_gl.cpp @@ -20,19 +20,10 @@ * */ -#include "stdafx.h" -#include "scummsys.h" -#include "system.h" -#include "sound/mididrv.h" -#include "gameDetector.h" +#include "sdl-common.h" #include "scaler.h" #include "scumm.h" // Only #included for error() and warning() -#include "scummvm.xpm" - -#include <SDL.h> -#include <SDL_thread.h> - #ifdef WIN32 int glColorTable(int, int, int, int, int, void *) { return 0; } int glGetColorTable(int, int, int, void *) { return 0; } @@ -43,205 +34,32 @@ bool OGL_1_1 = false; #endif #include "fb2opengl.h" -FB2GL fb2gl; -class OSystem_SDL : public OSystem { + +class OSystem_SDL_GL : public OSystem_SDL_Common { public: // Set colors of the palette void set_palette(const byte *colors, uint start, uint num); - // Set the size of the video bitmap. - // Typically, 320x200 - void init_size(uint w, uint h); - - // Draw a bitmap to screen. - // The screen will not be updated to reflect the new bitmap - void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); - // Update the dirty areas of the screen void update_screen(); - // Either show or hide the mouse cursor - bool show_mouse(bool visible); - - // Set the position of the mouse cursor - void set_mouse_pos(int x, int y); - - // Set the bitmap that's used when drawing the cursor. - void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y); - - // Shaking is used in SCUMM. Set current shake position. - void set_shake_pos(int shake_pos); - - // Get the number of milliseconds since the program was started. - uint32 get_msecs(); - - // Delay for a specified amount of milliseconds - void delay_msecs(uint msecs); - - // Create a thread - void *create_thread(ThreadProc *proc, void *param); - - // Get the next event. - // Returns true if an event was retrieved. - bool poll_event(Event *event); - - // Set function that generates samples - bool set_sound_proc(void *param, SoundProc *proc, byte sound); - - // Poll cdrom status - // Returns true if cd audio is playing - bool poll_cdrom(); - - // Play cdrom audio track - void play_cdrom(int track, int num_loops, int start_frame, int end_frame); - - // Stop cdrom audio track - void stop_cdrom(); - - // Update cdrom audio status - void update_cdrom(); - - // Quit - void quit(); - // Set a parameter uint32 property(int param, Property *value); - // Add a callback timer - void set_timer(int timer, int (*callback)(int)); - - // Mutex handling - void *create_mutex(void); - void lock_mutex(void *mutex); - void unlock_mutex(void *mutex); - void delete_mutex(void *mutex); - - static OSystem *create(int gfx_mode, bool full_screen); - -private: - typedef void TwoXSaiProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, - uint8 *dstPtr, uint32 dstPitch, int width, int height); - - SDL_Surface *sdl_screen; - SDL_Surface *sdl_tmpscreen; - SDL_CD *cdrom; - - enum { - DF_WANT_RECT_OPTIM = 1 << 0, - DF_REAL_8BIT = 1 << 1, - DF_SEPARATE_TEMPSCREEN = 1 << 2, - DF_UPDATE_EXPAND_1_PIXEL = 1 << 3 - }; - - int _mode; - bool _full_screen; - bool _mouse_visible; - bool _mouse_drawn; - uint32 _mode_flags; - - bool force_full; //Force full redraw on next update_screen - bool cksum_valid; - - enum { - NUM_DIRTY_RECT = 100, - - MAX_MOUSE_W = 40, - MAX_MOUSE_H = 40, - MAX_SCALING = 3 - }; - - int SCREEN_WIDTH, SCREEN_HEIGHT, CKSUM_NUM; - SDL_Rect *dirty_rect_list; - int num_dirty_rects; - uint32 *dirty_checksums; - - int scaling; - - /* CD Audio */ - int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; - Uint32 cd_end_time, cd_stop_time, cd_next_second; - - struct MousePos { - int16 x, y, w, h; - }; - - byte *_mouse_data; - byte *_mouse_backup; - MousePos _mouse_cur_state; - MousePos _mouse_old_state; - int16 _mouse_hotspot_x; - int16 _mouse_hotspot_y; - int _current_shake_pos; - int _new_shake_pos; - TwoXSaiProc *_sai_func; - SDL_Color *_cur_pal; - - uint _palette_changed_first, _palette_changed_last; - - OSystem_SDL() : _current_shake_pos(0), _new_shake_pos(0) {} - - void add_dirty_rgn_auto(const byte *buf); - void mk_checksums(const byte *buf); - - static void fill_sound(void *userdata, Uint8 * stream, int len); - - void add_dirty_rect(int x, int y, int w, int h); - - void draw_mouse(); - void undraw_mouse(); +protected: + FB2GL fb2gl; void load_gfx_mode(); void unload_gfx_mode(); - void hotswap_gfx_mode(); - - void get_320x200_image(byte *buf); - - void setup_icon(); }; -bool atexit_proc_instaled = false; -void atexit_proc() { - SDL_ShowCursor(SDL_ENABLE); - SDL_Quit(); -} - -OSystem *OSystem_SDL::create(int gfx_mode, bool full_screen) { - OSystem_SDL *syst = new OSystem_SDL(); - syst->_mode = gfx_mode; - syst->_full_screen = full_screen; - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) ==-1) { - error("Could not initialize SDL: %s.\n", SDL_GetError()); - } - -#ifdef WIN32 /* Use waveout on win32, not */ - SDL_AudioInit("waveout"); /* dsound - unfortunatly dsound */ -#endif /* doesn't do COOPERATIVE mode*/ - - SDL_ShowCursor(SDL_DISABLE); - - /* Setup the icon */ - syst->setup_icon(); - -#ifndef MACOSX // Work around a bug in OS X - /* Clean up on exit */ - atexit_proc_instaled = true; - atexit(atexit_proc); -#endif - - return syst; +OSystem_SDL_Common *OSystem_SDL_Common::create() { + return new OSystem_SDL_GL(); } -void OSystem_SDL::set_timer(int timer, int (*callback)(int)) { - SDL_SetTimer(timer, (SDL_TimerCallback) callback); -} -OSystem *OSystem_SDL_create(int gfx_mode, bool full_screen) { - return OSystem_SDL::create(gfx_mode, full_screen); -} - -void OSystem_SDL::set_palette(const byte *colors, uint start, uint num) { +void OSystem_SDL_GL::set_palette(const byte *colors, uint start, uint num) { const byte *b = colors; uint i; @@ -257,7 +75,7 @@ void OSystem_SDL::set_palette(const byte *colors, uint start, uint num) { _palette_changed_last = start + num; } -void OSystem_SDL::load_gfx_mode() { +void OSystem_SDL_GL::load_gfx_mode() { int gl_flags = FB2GL_320 | FB2GL_PITCH; force_full = true; scaling = 1; @@ -290,21 +108,16 @@ void OSystem_SDL::load_gfx_mode() { } } -#ifdef MACOSX // Work around a bug in OS X - if (!atexit_proc_instaled) { - atexit_proc_instaled = true; - atexit(atexit_proc); - } -#endif - SDL_SetGamma(1.25,1.25,1.25); sdl_tmpscreen = sdl_screen; } -void OSystem_SDL::unload_gfx_mode() { - SDL_FreeSurface(sdl_screen); - sdl_screen = NULL; +void OSystem_SDL_GL::unload_gfx_mode() { + if (sdl_screen) { + SDL_FreeSurface(sdl_screen); + sdl_screen = NULL; + } if (_mode_flags & DF_SEPARATE_TEMPSCREEN) { free((uint16*)sdl_tmpscreen->pixels); @@ -313,176 +126,7 @@ void OSystem_SDL::unload_gfx_mode() { sdl_tmpscreen = NULL; } -void OSystem_SDL::init_size(uint w, uint h) { - //if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) - // error("320x200 is the only game resolution supported"); - - SCREEN_WIDTH = w; - SCREEN_HEIGHT = h; - CKSUM_NUM = (SCREEN_WIDTH*SCREEN_HEIGHT/(8*8)); - /* allocate palette, it needs to be persistent across - * driver changes, so i'll alloc it here */ - _cur_pal = (SDL_Color*)calloc(sizeof(SDL_Color), 256); - - dirty_rect_list = (SDL_Rect*)calloc(NUM_DIRTY_RECT, sizeof(SDL_Rect)); - _mouse_backup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING); - dirty_checksums = (uint32*)calloc(CKSUM_NUM*2, sizeof(uint32)); - - load_gfx_mode(); -} - -void OSystem_SDL::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) { - if (sdl_screen == NULL) - return; - - if (pitch == SCREEN_WIDTH && x==0 && y==0 && w==SCREEN_WIDTH && h==SCREEN_HEIGHT && _mode_flags&DF_WANT_RECT_OPTIM) { - /* Special, optimized case for full screen updates. - * It tries to determine what areas were actually changed, - * and just updates those, on the actual display. */ - add_dirty_rgn_auto(buf); - } else { - /* Clip the coordinates */ - if (x < 0) { w+=x; buf-=x; x = 0; } - if (y < 0) { h+=y; buf-=y*pitch; y = 0; } - if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } - if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } - - if (w <= 0 || h <= 0) - return; - - cksum_valid = false; - add_dirty_rect(x, y, w, h); - } - - /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ - if (_mouse_drawn) - undraw_mouse(); - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - byte *dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; - do { - memcpy(dst, buf, w); - dst += SCREEN_WIDTH; - buf += pitch; - } while (--h); - - SDL_UnlockSurface(sdl_screen); -} - - -void OSystem_SDL::add_dirty_rect(int x, int y, int w, int h) { - if (force_full) - return; - - if (num_dirty_rects == NUM_DIRTY_RECT) - force_full = true; - else { - SDL_Rect *r = &dirty_rect_list[num_dirty_rects++]; - - /* Update the dirty region by 1 pixel for graphics drivers - * that "smear" the screen */ - if (_mode_flags & DF_UPDATE_EXPAND_1_PIXEL) { - x--; - y--; - w+=2; - h+=2; - } - - /* clip */ - if (x < 0) { w+=x; x=0; } - if (y < 0) { h+=y; y=0; } - if (w > SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } - if (h > SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } - - r->x = x; - r->y = y; - r->w = w; - r->h = h; - } -} - -#define ROL(a,n) a = (a<<(n)) | (a>>(32-(n))) -#define DOLINE(x) a ^= ((uint32*)buf)[0+(x)*(SCREEN_WIDTH/4)]; b ^= ((uint32*)buf)[1+(x)*(SCREEN_WIDTH/4)] -void OSystem_SDL::mk_checksums(const byte *buf) { - uint32 *sums = dirty_checksums; - uint x,y; - const uint last_x = (uint)SCREEN_WIDTH/8; - const uint last_y = (uint)SCREEN_HEIGHT/8; - - /* the 8x8 blocks in buf are enumerated starting in the top left corner and - * reading each line at a time from left to right */ - for(y=0; y != last_y; y++, buf+=SCREEN_WIDTH*(8-1)) - for(x=0; x != last_x; x++, buf+=8) { - uint32 a = x; - uint32 b = y; - - DOLINE(0); ROL(a,13); ROL(b,11); - DOLINE(2); ROL(a,13); ROL(b,11); - DOLINE(4); ROL(a,13); ROL(b,11); - DOLINE(6); ROL(a,13); ROL(b,11); - - a*=0xDEADBEEF; - b*=0xBAADF00D; - - DOLINE(1); ROL(a,13); ROL(b,11); - DOLINE(3); ROL(a,13); ROL(b,11); - DOLINE(5); ROL(a,13); ROL(b,11); - DOLINE(7); ROL(a,13); ROL(b,11); - - /* output the checksum for this block */ - *sums++=a+b; - } -} -#undef DOLINE -#undef ROL - - -void OSystem_SDL::add_dirty_rgn_auto(const byte *buf) { - assert( ((uint32)buf & 3) == 0); - - /* generate a table of the checksums */ - mk_checksums(buf); - - if (!cksum_valid) { - force_full = true; - cksum_valid = true; - } - - /* go through the checksum list, compare it with the previous checksums, - and add all dirty rectangles to a list. try to combine small rectangles - into bigger ones in a simple way */ - if (!force_full) { - int x,y,w; - uint32 *ck = dirty_checksums; - - for(y=0; y!=SCREEN_HEIGHT/8; y++) { - for(x=0; x!=SCREEN_WIDTH/8; x++,ck++) { - if (ck[0] != ck[CKSUM_NUM]) { - /* found a dirty 8x8 block, now go as far to the right as possible, - and at the same time, unmark the dirty status by setting old to new. */ - w=0; - do { - ck[w+CKSUM_NUM] = ck[w]; - w++; - } while (x+w != SCREEN_WIDTH/8 && ck[w] != ck[w+CKSUM_NUM]); - - add_dirty_rect(x*8, y*8, w*8, 8); - - if (force_full) - goto get_out; - } - } - } - } else { - get_out:; - /* Copy old checksums to new */ - memcpy(dirty_checksums + CKSUM_NUM, dirty_checksums, CKSUM_NUM * sizeof(uint32)); - } -} - -void OSystem_SDL::update_screen() { +void OSystem_SDL_GL::update_screen() { /* First make sure the mouse is drawn, if it should be drawn. */ draw_mouse(); @@ -510,192 +154,7 @@ void OSystem_SDL::update_screen() { } -bool OSystem_SDL::show_mouse(bool visible) { - if (_mouse_visible == visible) - return visible; - - bool last = _mouse_visible; - _mouse_visible = visible; - - if (visible) - draw_mouse(); - else - undraw_mouse(); - - return last; -} - -void OSystem_SDL::set_mouse_pos(int x, int y) { - if (x != _mouse_cur_state.x || y != _mouse_cur_state.y) { - _mouse_cur_state.x = x; - _mouse_cur_state.y = y; - undraw_mouse(); - } -} - -void OSystem_SDL::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) { - _mouse_cur_state.w = w; - _mouse_cur_state.h = h; - - _mouse_hotspot_x = hotspot_x; - _mouse_hotspot_y = hotspot_y; - - _mouse_data = (byte*)buf; - - undraw_mouse(); -} - -void OSystem_SDL::set_shake_pos(int shake_pos) { - _new_shake_pos = shake_pos; -} - -uint32 OSystem_SDL::get_msecs() { - return SDL_GetTicks(); -} - -void OSystem_SDL::delay_msecs(uint msecs) { - SDL_Delay(msecs); -} - -void *OSystem_SDL::create_thread(ThreadProc *proc, void *param) { - return SDL_CreateThread(proc, param); -} - -int mapKey(int key, byte mod) -{ - if (key >= SDLK_F1 && key <= SDLK_F9) { - return key - SDLK_F1 + 315; - } else if (key >= 'a' && key <= 'z' && mod & KMOD_SHIFT) { - key &= ~0x20; - } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) - return 0; - return key; -} - -bool OSystem_SDL::poll_event(Event *event) { - SDL_Event ev; - - for(;;) { - if (!SDL_PollEvent(&ev)) - return false; - - switch(ev.type) { - case SDL_KEYDOWN: { - byte b = 0; - if (ev.key.keysym.mod & KMOD_SHIFT) b |= KBD_SHIFT; - if (ev.key.keysym.mod & KMOD_CTRL) b |= KBD_CTRL; - if (ev.key.keysym.mod & KMOD_ALT) b |= KBD_ALT; - event->kbd.flags = b; - - /* internal keypress? */ - if (b == KBD_ALT && ev.key.keysym.sym==SDLK_RETURN) { - property(PROP_TOGGLE_FULLSCREEN, NULL); - break; - } - - if ((b == KBD_CTRL && ev.key.keysym.sym=='z') || (b == KBD_ALT && ev.key.keysym.sym=='x')) { - quit(); - break; - } - - if (b == (KBD_CTRL|KBD_ALT) && - (ev.key.keysym.sym>='1') && (ev.key.keysym.sym<='7')) { - Property prop; - prop.gfx_mode = ev.key.keysym.sym - '1'; - property(PROP_SET_GFX_MODE, &prop); - break; - } - - - event->event_code = EVENT_KEYDOWN; - event->kbd.keycode = ev.key.keysym.sym; - event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); - return true; - } - - case SDL_KEYUP: - event->event_code = EVENT_KEYUP; - event->kbd.keycode = ev.key.keysym.sym; - event->kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod); - - return true; - - case SDL_MOUSEMOTION: - event->event_code = EVENT_MOUSEMOVE; - event->mouse.x = ev.motion.x; - event->mouse.y = ev.motion.y; - - event->mouse.x /= scaling; - event->mouse.y /= scaling; - - return true; - - case SDL_MOUSEBUTTONDOWN: - if (ev.button.button == SDL_BUTTON_LEFT) - event->event_code = EVENT_LBUTTONDOWN; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event->event_code = EVENT_RBUTTONDOWN; - else - break; - event->mouse.x = ev.button.x; - event->mouse.y = ev.button.y; - event->mouse.x /= scaling; - event->mouse.y /= scaling; - - return true; - - case SDL_MOUSEBUTTONUP: - if (ev.button.button == SDL_BUTTON_LEFT) - event->event_code = EVENT_LBUTTONUP; - else if (ev.button.button == SDL_BUTTON_RIGHT) - event->event_code = EVENT_RBUTTONUP; - else - break; - event->mouse.x = ev.button.x; - event->mouse.y = ev.button.y; - event->mouse.x /= scaling; - event->mouse.y /= scaling; - return true; - - case SDL_QUIT: - quit(); - } - } -} - -bool OSystem_SDL::set_sound_proc(void *param, SoundProc *proc, byte format) { - SDL_AudioSpec desired; - - /* only one format supported at the moment */ - - desired.freq = SAMPLES_PER_SEC; - desired.format = AUDIO_S16SYS; - desired.channels = 2; - desired.samples = 2048; - desired.callback = proc; - desired.userdata = param; - if (SDL_OpenAudio(&desired, NULL) != 0) { - return false; - } - SDL_PauseAudio(0); - return true; -} - - -/* retrieve the 320x200 bitmap currently being displayed */ -void OSystem_SDL::get_320x200_image(byte *buf) { - /* make sure the mouse is gone */ - undraw_mouse(); - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - memcpy(buf, sdl_screen->pixels, SCREEN_WIDTH*SCREEN_HEIGHT); - - SDL_UnlockSurface(sdl_screen); -} - -void OSystem_SDL::hotswap_gfx_mode() { +void OSystem_SDL_GL::hotswap_gfx_mode() { /* hmm, need to allocate a 320x200 bitmap * which will contain the "backup" of the screen during the change. * then draw that to the new screen right after it's setup. @@ -712,357 +171,19 @@ void OSystem_SDL::hotswap_gfx_mode() { fb2gl.update(sdl_tmpscreen->pixels,320,200,320,0,_current_shake_pos); /* blit image */ - OSystem_SDL::copy_rect(bak_mem, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + copy_rect(bak_mem, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); free(bak_mem); - OSystem_SDL::update_screen(); + update_screen(); } -uint32 OSystem_SDL::property(int param, Property *value) { - switch(param) { +uint32 OSystem_SDL_GL::property(int param, Property *value) { - case PROP_TOGGLE_FULLSCREEN: + if (param == PROP_TOGGLE_FULLSCREEN) { _full_screen ^= true; SDL_WM_ToggleFullScreen(fb2gl.screen); return 1; - - case PROP_GET_FULLSCREEN: - return _full_screen; - - case PROP_SET_WINDOW_CAPTION: - SDL_WM_SetCaption(value->caption, value->caption); - return 1; - - case PROP_OPEN_CD: - if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) - cdrom = NULL; - else { - cdrom = SDL_CDOpen(value->cd_num); - /* Did if open? Check if cdrom is NULL */ - if (!cdrom) { - warning("Couldn't open drive: %s\n", SDL_GetError()); - } - } - break; - - case PROP_SET_GFX_MODE: - if (value->gfx_mode >= 7) - return 0; - - _mode = value->gfx_mode; - hotswap_gfx_mode(); - - return 1; - - case PROP_SHOW_DEFAULT_CURSOR: - SDL_ShowCursor(value->show_cursor ? SDL_ENABLE : SDL_DISABLE); - break; - - case PROP_GET_SAMPLE_RATE: - return SAMPLES_PER_SEC; - } - - return 0; -} - -void OSystem_SDL::quit() { - if(cdrom) { - SDL_CDStop(cdrom); - SDL_CDClose(cdrom); - } - unload_gfx_mode(); - exit(1); -} - -void OSystem_SDL::draw_mouse() { - if (_mouse_drawn || !_mouse_visible) - return; - - int x = _mouse_cur_state.x - _mouse_hotspot_x; - int y = _mouse_cur_state.y - _mouse_hotspot_y; - int w = _mouse_cur_state.w; - int h = _mouse_cur_state.h; - byte color; - byte *src = _mouse_data; // Image representing the mouse - byte *bak = _mouse_backup; // Surface used to backup the area obscured by the mouse - byte *dst; // Surface we are drawing into - - // clip the mouse rect, and addjust the src pointer accordingly - if (x < 0) { - w += x; - src -= x; - x = 0; - } - if (y < 0) { - h += y; - src -= y * _mouse_cur_state.w; - y = 0; - } - if (w > SCREEN_WIDTH - x) - w = SCREEN_WIDTH - x; - if (h > SCREEN_HEIGHT - y) - h = SCREEN_HEIGHT - y; - - // Store the bounding box so that undraw mouse can restore the area the - // mouse currently covers to its original content. - _mouse_old_state.x = x; - _mouse_old_state.y = y; - _mouse_old_state.w = w; - _mouse_old_state.h = h; - - // Quick check to see if anything has to be drawn at all - if (w <= 0 || h <= 0) - return; - - // Draw the mouse cursor; backup the covered area in "bak" - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - add_dirty_rect(x, y, w, h); - - dst = (byte *)sdl_screen->pixels + y * SCREEN_WIDTH + x; - while (h > 0) { - int width = w; - while (width > 0) { - *bak++ = *dst; - color = *src++; - if (color != 0xFF) // 0xFF = transparent, don't draw - *dst = color; - dst++; - width--; - } - src += _mouse_cur_state.w - w; - bak += MAX_MOUSE_W - w; - dst += SCREEN_WIDTH - w; - h--; - } - - SDL_UnlockSurface(sdl_screen); - - // Finally, set the flag to indicate the mouse has been drawn - _mouse_drawn = true; -} - -void OSystem_SDL::undraw_mouse() { - if (!_mouse_drawn) - return; - _mouse_drawn = false; - - if (SDL_LockSurface(sdl_screen) == -1) - error("SDL_LockSurface failed: %s.\n", SDL_GetError()); - - byte *dst, *bak = _mouse_backup; - const int old_mouse_x = _mouse_old_state.x; - const int old_mouse_y = _mouse_old_state.y; - const int old_mouse_w = _mouse_old_state.w; - const int old_mouse_h = _mouse_old_state.h; - int x,y; - - // No need to do clipping here, since draw_mouse() did that already - - dst = (byte *)sdl_screen->pixels + old_mouse_y * SCREEN_WIDTH + old_mouse_x; - for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += SCREEN_WIDTH) { - for (x = 0; x < old_mouse_w; ++x) { - dst[x] = bak[x]; - } } - - add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); - - SDL_UnlockSurface(sdl_screen); -} - -void OSystem_SDL::stop_cdrom() { /* Stop CD Audio in 1/10th of a second */ - cd_stop_time = SDL_GetTicks() + 100; - cd_num_loops = 0; - -} - -void OSystem_SDL::play_cdrom(int track, int num_loops, int start_frame, int end_frame) { - if (!num_loops && !start_frame) - return; - - if (!cdrom) - return; - if (end_frame > 0) - end_frame+=5; - - cd_track = track; - cd_num_loops = num_loops; - cd_start_frame = start_frame; - - SDL_CDStatus(cdrom); - SDL_CDPlayTracks(cdrom, track, start_frame, 0, end_frame); - cd_end_frame = end_frame; - cd_stop_time = 0; - cd_end_time = SDL_GetTicks() + cdrom->track[track].length * 1000 / CD_FPS; -} - -bool OSystem_SDL::poll_cdrom() { - if (!cdrom) - return false; - - return (cd_num_loops != 0 && (SDL_GetTicks() < cd_end_time || SDL_CDStatus(cdrom) != CD_STOPPED)); -} - -void OSystem_SDL::update_cdrom() { - if (!cdrom) - return; - - if (cd_stop_time != 0 && SDL_GetTicks() >= cd_stop_time) { - SDL_CDStop(cdrom); - cd_num_loops = 0; - cd_stop_time = 0; - return; - } - - if (cd_num_loops == 0 || SDL_GetTicks() < cd_end_time) - return; - - if (cd_num_loops != 1 && SDL_CDStatus(cdrom) != CD_STOPPED) { - // Wait another second for it to be done - cd_end_time += 1000; - return; - } - - if (cd_num_loops > 0) - cd_num_loops--; - - if (cd_num_loops != 0) { - SDL_CDPlayTracks(cdrom, cd_track, cd_start_frame, 0, cd_end_frame); - cd_end_time = SDL_GetTicks() + cdrom->track[cd_track].length * 1000 / CD_FPS; - } -} - -void OSystem_SDL::setup_icon() { - int w, h, ncols, nbytes, i; - unsigned int rgba[256], icon[32 * 32]; - unsigned char mask[32][4]; - - sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); - if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { - warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); - return; - } - for (i = 0; i < ncols; i++) { - unsigned char code; - char color[32]; - unsigned int col; - sscanf(scummvm_icon[1 + i], "%c c %s", &code, color); - if (!strcmp(color, "None")) - col = 0x00000000; - else if (!strcmp(color, "black")) - col = 0xFF000000; - else if (color[0] == '#') { - sscanf(color + 1, "%06x", &col); - col |= 0xFF000000; - } else { - warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); - return; - } - - rgba[code] = col; - } - memset(mask, 0, sizeof(mask)); - for (h = 0; h < 32; h++) { - char *line = scummvm_icon[1 + ncols + h]; - for (w = 0; w < 32; w++) { - icon[w + 32 * h] = rgba[line[w]]; - if (rgba[line[w]] & 0xFF000000) { - mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); - } - } - } - - SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); - SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); -} - -void *OSystem_SDL::create_mutex(void) { - return (void *) SDL_CreateMutex(); -} - -void OSystem_SDL::lock_mutex(void *mutex) { - SDL_mutexP((SDL_mutex *) mutex); + return OSystem_SDL_Common::property(param, value); } - -void OSystem_SDL::unlock_mutex(void *mutex) { - SDL_mutexV((SDL_mutex *) mutex); -} - -void OSystem_SDL::delete_mutex(void *mutex) { - SDL_DestroyMutex((SDL_mutex *) mutex); -} - - -#ifdef USE_NULL_DRIVER - -/* NULL video driver */ -class OSystem_NULL : public OSystem { -public: - void set_palette(const byte *colors, uint start, uint num) {} - void init_size(uint w, uint h); - void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) {} - void update_screen() {} - bool show_mouse(bool visible) { return false; } - void set_mouse_pos(int x, int y) {} - void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) {} - void set_shake_pos(int shake_pos) {} - uint32 get_msecs(); - void delay_msecs(uint msecs); - void *create_thread(ThreadProc *proc, void *param) { return NULL; } - bool poll_event(Event *event) { return false; } - bool set_sound_proc(void *param, SoundProc *proc, byte sound) {} - void quit() { exit(1); } - uint32 property(int param, Property *value) { return 0; } - static OSystem *create(int gfx_mode, bool full_screen); -private: - - uint msec_start; - - uint32 get_ticks(); -}; - -void OSystem_NULL::init_size(uint w, uint h, byte sound) { - msec_start = get_ticks(); -} - -uint32 OSystem_NULL::get_ticks() { - uint a = 0; -#ifdef WIN32 - a = GetTickCount(); -#endif -#ifdef UNIX - struct timeval tv; - gettimeofday(&tv, NULL); - a = tv.tv_sec * 1000 + tv.tv_usec/1000; -#endif - - return a; -} - -void OSystem_NULL::delay_msecs(uint msecs) { -#ifdef WIN32 - Sleep(msecs); -#endif -#ifdef UNIX - usleep(msecs*1000); -#endif -} - -uint32 OSystem_NULL::get_msecs() { - return get_ticks() - msec_start; -} - -OSystem *OSystem_NULL_create() { - return new OSystem_NULL(); -} -#else /* USE_NULL_DRIVER */ - -OSystem *OSystem_NULL_create() { - return NULL; -} - -#endif |