diff options
author | tron <tron@openttd.org> | 2005-07-23 15:16:57 +0000 |
---|---|---|
committer | tron <tron@openttd.org> | 2005-07-23 15:16:57 +0000 |
commit | 07a6e612ec560945c55798b67bbb56a00f1cb06b (patch) | |
tree | 1e83d1a7e27b80f46817858872b1f46a903f1d1b | |
parent | af1d71985678a907dcb2c76e4873ec317cefecfc (diff) | |
download | openttd-07a6e612ec560945c55798b67bbb56a00f1cb06b.tar.xz |
(svn r2685) -Codechange: Split the music/sound/video drivers into separate files and move them into subfolders.
This results in shorter and hopefully easier to maintain files.
Note: I had to change paths in #include statements of some unrelated files, because I added the ottd base directory to the include path (-I.)
-rw-r--r-- | Makefile | 23 | ||||
-rw-r--r-- | driver.c | 133 | ||||
-rw-r--r-- | driver.h | 11 | ||||
-rw-r--r-- | hal.h | 20 | ||||
-rw-r--r-- | music/bemidi.cpp (renamed from os/beos/bemidi.cpp) | 6 | ||||
-rw-r--r-- | music/bemidi.h | 8 | ||||
-rw-r--r-- | music/dmusic.c (renamed from w32dm.c) | 2 | ||||
-rw-r--r-- | music/dmusic.h | 8 | ||||
-rw-r--r-- | music/dmusic2.cpp (renamed from w32dm2.cpp) | 0 | ||||
-rw-r--r-- | music/extmidi.c (renamed from extmidi.c) | 2 | ||||
-rw-r--r-- | music/extmidi.h | 8 | ||||
-rw-r--r-- | music/null.c | 19 | ||||
-rw-r--r-- | music/null.h | 8 | ||||
-rw-r--r-- | music/win32.c | 146 | ||||
-rw-r--r-- | music/win32.h | 8 | ||||
-rw-r--r-- | openttd.c | 181 | ||||
-rw-r--r-- | sdl.c | 575 | ||||
-rw-r--r-- | sdl.h | 51 | ||||
-rw-r--r-- | sound/null.c | 11 | ||||
-rw-r--r-- | sound/null.h | 8 | ||||
-rw-r--r-- | sound/sdl.c | 40 | ||||
-rw-r--r-- | sound/sdl.h | 8 | ||||
-rw-r--r-- | sound/win32.c | 84 | ||||
-rw-r--r-- | sound/win32.h | 8 | ||||
-rw-r--r-- | table/engines.h | 2 | ||||
-rw-r--r-- | table/namegen.h | 4 | ||||
-rw-r--r-- | unix.c | 9 | ||||
-rw-r--r-- | video/null.c | 45 | ||||
-rw-r--r-- | video/null.h | 8 | ||||
-rw-r--r-- | video/sdl.c | 488 | ||||
-rw-r--r-- | video/sdl.h | 8 | ||||
-rw-r--r-- | video/win32.c | 800 | ||||
-rw-r--r-- | video/win32.h | 10 | ||||
-rw-r--r-- | win32.c | 1040 |
34 files changed, 1974 insertions, 1808 deletions
@@ -335,6 +335,7 @@ ifdef PROFILE endif CDEFS=-DWITH_REV +CFLAGS += -I. -I- ifndef DEBUG ifndef PROFILE @@ -624,6 +625,7 @@ C_SOURCES += dedicated.c C_SOURCES += depot.c C_SOURCES += disaster_cmd.c C_SOURCES += dock_gui.c +C_SOURCES += driver.c C_SOURCES += dummy_land.c C_SOURCES += economy.c C_SOURCES += engine.c @@ -707,24 +709,32 @@ C_SOURCES += water_cmd.c C_SOURCES += waypoint.c C_SOURCES += widget.c C_SOURCES += window.c +C_SOURCES += music/null.c +C_SOURCES += sound/null.c +C_SOURCES += video/null.c CXX_SOURCES = ifdef WITH_SDL C_SOURCES += sdl.c +C_SOURCES += sound/sdl.c +C_SOURCES += video/sdl.c endif ifdef WIN32 -C_SOURCES += win32.c w32dm.c +C_SOURCES += win32.c +C_SOURCES += music/win32.c +C_SOURCES += sound/win32.c +C_SOURCES += video/win32.c else -C_SOURCES += extmidi.c unix.c +C_SOURCES += unix.c +C_SOURCES += music/extmidi.c endif OBJS = $(C_SOURCES:%.c=%.o) $(CXX_SOURCES:%.cpp=%.o) ifdef BEOS -CXX_SOURCES += os/beos/bemidi.cpp -CFLAGS += -I. +CXX_SOURCES += music/bemidi.cpp endif ifdef WIN32 @@ -733,7 +743,8 @@ OBJS += winres.o endif ifdef WITH_DIRECTMUSIC -CXX_SOURCES += w32dm2.cpp +C_SOURCES += music/dmusic.c +CXX_SOURCES += music/dmusic2.cpp endif DEPS = $(OBJS:%.o=.deps/%.d) @@ -1022,7 +1033,7 @@ upgradeconf: $(MAKE_CONFIG) ### Internal build rules # This makes sure the .deps dir is always around. -DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) +DEPS_MAGIC := $(shell mkdir -p .deps .deps/music .deps/sound .deps/video) # Introduce the dependencies -include $(DEPS) diff --git a/driver.c b/driver.c new file mode 100644 index 000000000..e8bd81c8f --- /dev/null +++ b/driver.c @@ -0,0 +1,133 @@ +#include "stdafx.h" +#include "openttd.h" +#include "driver.h" +#include "functions.h" +#include "hal.h" +#include "string.h" + +typedef struct { + const DriverDesc *descs; + const char *name; + void *var; +} DriverClass; + +static DriverClass _driver_classes[] = { + {_video_driver_descs, "video", &_video_driver}, + {_sound_driver_descs, "sound", &_sound_driver}, + {_music_driver_descs, "music", &_music_driver}, +}; + +enum { + DF_PRIORITY_MASK = 0xF, +}; + +static const DriverDesc* GetDriverByName(const DriverDesc* dd, const char* name) +{ + for (; dd->name != NULL; dd++) { + if (strcmp(dd->name, name) == 0) return dd; + } + return NULL; +} + +static const DriverDesc* ChooseDefaultDriver(const DriverDesc* dd) +{ + byte os_version = GetOSVersion(); + const DriverDesc *best = NULL; + int best_pri = -1; + + for (; dd->name != NULL; dd++) { + if ((int)(dd->flags & DF_PRIORITY_MASK) > best_pri && os_version >= (byte)dd->flags) { + best_pri = dd->flags & DF_PRIORITY_MASK; + best = dd; + } + } + return best; +} + +void LoadDriver(int driver, const char *name) +{ + const DriverClass *dc = &_driver_classes[driver]; + const DriverDesc *dd; + const void **var; + const void *drv; + const char *err; + char *parm; + char buffer[256]; + const char *parms[32]; + + parms[0] = NULL; + + if (!*name) { + dd = ChooseDefaultDriver(dc->descs); + } else { + // Extract the driver name and put parameter list in parm + ttd_strlcpy(buffer, name, sizeof(buffer)); + parm = strchr(buffer, ':'); + if (parm) { + uint np = 0; + // Tokenize the parm. + do { + *parm++ = 0; + if (np < lengthof(parms) - 1) + parms[np++] = parm; + while (*parm != 0 && *parm != ',') + parm++; + } while (*parm == ','); + parms[np] = NULL; + } + dd = GetDriverByName(dc->descs, buffer); + if (dd == NULL) + error("No such %s driver: %s\n", dc->name, buffer); + } + var = dc->var; + if (*var != NULL) ((const HalCommonDriver*)*var)->stop(); + *var = NULL; + drv = dd->drv; + + err = ((const HalCommonDriver*)drv)->start(parms); + if (err != NULL) + error("Unable to load driver %s(%s). The error was: %s\n", dd->name, dd->longname, err); + *var = drv; +} + + +static const char* GetDriverParam(const char* const* parm, const char* name) +{ + uint len = strlen(name); + + for (; *parm != NULL; parm++) { + const char* p = *parm; + + if (strncmp(p, name, len) == 0) { + if (p[len] == '=') return p + len + 1; + if (p[len] == '\0') return p + len; + } + } + return NULL; +} + +bool GetDriverParamBool(const char* const* parm, const char* name) +{ + return GetDriverParam(parm, name) != NULL; +} + +int GetDriverParamInt(const char* const* parm, const char* name, int def) +{ + const char* p = GetDriverParam(parm, name); + return p != NULL ? atoi(p) : def; +} + + +void GetDriverList(char* p) +{ + const DriverClass* dc; + + for (dc = _driver_classes; dc != endof(_driver_classes); dc++) { + const DriverDesc* dd; + + p += sprintf(p, "List of %s drivers:\n", dc->name); + for (dd = dc->descs; dd->name != NULL; dd++) { + p += sprintf(p, "%10s: %s\n", dd->name, dd->longname); + } + } +} diff --git a/driver.h b/driver.h new file mode 100644 index 000000000..cfef360a6 --- /dev/null +++ b/driver.h @@ -0,0 +1,11 @@ +#ifndef DRIVER_H +#define DRIVER_H + +void LoadDriver(int driver, const char *name); + +bool GetDriverParamBool(const char* const* parm, const char* name); +int GetDriverParamInt(const char* const* parm, const char* name, int def); + +void GetDriverList(char* p); + +#endif @@ -47,10 +47,6 @@ enum { HALERR_ERROR = 1, }; -extern const HalMusicDriver _null_music_driver; -extern const HalVideoDriver _null_video_driver; -extern const HalSoundDriver _null_sound_driver; - VARDEF HalMusicDriver *_music_driver; VARDEF HalSoundDriver *_sound_driver; VARDEF HalVideoDriver *_video_driver; @@ -59,15 +55,6 @@ extern const DriverDesc _video_driver_descs[]; extern const DriverDesc _sound_driver_descs[]; extern const DriverDesc _music_driver_descs[]; -#if defined(WITH_SDL) -extern const HalSoundDriver _sdl_sound_driver; -extern const HalVideoDriver _sdl_video_driver; -#endif - -#if defined(UNIX) -extern const HalMusicDriver _extmidi_music_driver; -#endif - #if defined(__BEOS__) extern const HalMusicDriver _bemidi_music_driver; #endif @@ -87,13 +74,6 @@ enum DriverType { extern void GameLoop(void); extern bool _dbg_screen_rect; -void LoadDriver(int driver, const char *name); - -const char *GetDriverParam(const char * const *parm, const char *name); -bool GetDriverParamBool(const char * const *parm, const char *name); -int GetDriverParamInt(const char * const *parm, const char *name, int def); - - // Deals with finding savegames typedef struct { diff --git a/os/beos/bemidi.cpp b/music/bemidi.cpp index 16c8e82f7..146df3031 100644 --- a/os/beos/bemidi.cpp +++ b/music/bemidi.cpp @@ -1,8 +1,6 @@ -#ifdef __BEOS__ - #include "stdafx.h" #include "openttd.h" -#include "hal.h" +#include "music/bemidi.h" // BeOS System Includes #include <MidiSynthFile.h> @@ -51,5 +49,3 @@ const HalMusicDriver _bemidi_music_driver = { bemidi_is_playing, bemidi_set_volume, }; - -#endif // __BEOS__ diff --git a/music/bemidi.h b/music/bemidi.h new file mode 100644 index 000000000..049bf3247 --- /dev/null +++ b/music/bemidi.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_BEMIDI_H +#define MUSIC_BEMIDI_H + +#include "hal.h" + +extern const HalMusicDriver _bemidi_music_driver; + +#endif diff --git a/w32dm.c b/music/dmusic.c index adf45fe37..8842537a4 100644 --- a/w32dm.c +++ b/music/dmusic.c @@ -32,7 +32,7 @@ #include "string.h" #include "variables.h" #include "sound.h" -#include "hal.h" +#include "music/dmusic.h" static const char * DMusicMidiStart(const char * const *parm); static void DMusicMidiStop(void); diff --git a/music/dmusic.h b/music/dmusic.h new file mode 100644 index 000000000..dd05c2ced --- /dev/null +++ b/music/dmusic.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_DMUSIC_H +#define MUSIC_DMUSIC_H + +#include "hal.h" + +extern const HalMusicDriver _dmusic_midi_driver; + +#endif diff --git a/w32dm2.cpp b/music/dmusic2.cpp index ee8f71008..ee8f71008 100644 --- a/w32dm2.cpp +++ b/music/dmusic2.cpp diff --git a/extmidi.c b/music/extmidi.c index e9fcd59d1..031f7a383 100644 --- a/extmidi.c +++ b/music/extmidi.c @@ -3,7 +3,7 @@ #include "stdafx.h" #include "openttd.h" -#include "hal.h" +#include "music/extmidi.h" #include "sound.h" #include "string.h" #include "variables.h" diff --git a/music/extmidi.h b/music/extmidi.h new file mode 100644 index 000000000..3fb1848f7 --- /dev/null +++ b/music/extmidi.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_EXTERNAL_H +#define MUSIC_EXTERNAL_H + +#include "hal.h" + +extern const HalMusicDriver _extmidi_music_driver; + +#endif diff --git a/music/null.c b/music/null.c new file mode 100644 index 000000000..136f1d3e2 --- /dev/null +++ b/music/null.c @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "openttd.h" +#include "music/null.h" + +static const char* NullMidiStart(const char* const* parm) { return NULL; } +static void NullMidiStop(void) {} +static void NullMidiPlaySong(const char *filename) {} +static void NullMidiStopSong(void) {} +static bool NullMidiIsSongPlaying(void) { return true; } +static void NullMidiSetVolume(byte vol) {} + +const HalMusicDriver _null_music_driver = { + NullMidiStart, + NullMidiStop, + NullMidiPlaySong, + NullMidiStopSong, + NullMidiIsSongPlaying, + NullMidiSetVolume, +}; diff --git a/music/null.h b/music/null.h new file mode 100644 index 000000000..5f0be7ca4 --- /dev/null +++ b/music/null.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_NULL_H +#define MUSIC_NULL_H + +#include "hal.h" + +extern const HalMusicDriver _null_music_driver; + +#endif diff --git a/music/win32.c b/music/win32.c new file mode 100644 index 000000000..eb4d42d25 --- /dev/null +++ b/music/win32.c @@ -0,0 +1,146 @@ +#include "stdafx.h" +#include "openttd.h" +#include "music/win32.h" +#include <windows.h> + +static struct { + bool stop_song; + bool terminate; + bool playing; + int new_vol; + HANDLE wait_obj; + char start_song[260]; +} _midi; + +static void Win32MidiPlaySong(const char *filename) +{ + strcpy(_midi.start_song, filename); + _midi.playing = true; + _midi.stop_song = false; + SetEvent(_midi.wait_obj); +} + +static void Win32MidiStopSong(void) +{ + if (_midi.playing) { + _midi.stop_song = true; + _midi.start_song[0] = '\0'; + SetEvent(_midi.wait_obj); + } +} + +static bool Win32MidiIsSongPlaying(void) +{ + return _midi.playing; +} + +static void Win32MidiSetVolume(byte vol) +{ + _midi.new_vol = vol; + SetEvent(_midi.wait_obj); +} + +static long CDECL MidiSendCommand(const char *cmd, ...) { + va_list va; + char buf[512]; + + va_start(va, cmd); + vsprintf(buf, cmd, va); + va_end(va); + return mciSendStringA(buf, NULL, 0, 0); +} + +static bool MidiIntPlaySong(const char *filename) +{ + MidiSendCommand("close all"); + if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0) + return false; + + if (MidiSendCommand("play song from 0") != 0) + return false; + return true; +} + +static void MidiIntStopSong(void) +{ + MidiSendCommand("close all"); +} + +static void MidiIntSetVolume(int vol) +{ + uint v = (vol * 65535 / 127); + midiOutSetVolume((HMIDIOUT)-1, v + (v << 16)); +} + +static bool MidiIntIsSongPlaying(void) +{ + char buf[16]; + mciSendStringA("status song mode", buf, sizeof(buf), 0); + return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; +} + +static DWORD WINAPI MidiThread(LPVOID arg) +{ + _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); + + do { + char *s; + int vol; + + vol = _midi.new_vol; + if (vol != -1) { + _midi.new_vol = -1; + MidiIntSetVolume(vol); + } + + s = _midi.start_song; + if (s[0] != '\0') { + _midi.playing = MidiIntPlaySong(s); + s[0] = '\0'; + + // Delay somewhat in case we don't manage to play. + if (!_midi.playing) { + Sleep(5000); + } + } + + if (_midi.stop_song && _midi.playing) { + _midi.stop_song = false; + _midi.playing = false; + MidiIntStopSong(); + } + + if (_midi.playing && !MidiIntIsSongPlaying()) + _midi.playing = false; + + WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); + } while (!_midi.terminate); + + DeleteObject(_midi.wait_obj); + return 0; +} + +static const char *Win32MidiStart(const char * const *parm) +{ + DWORD threadId; + + memset(&_midi, 0, sizeof(_midi)); + _midi.new_vol = -1; + CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId); + return 0; +} + +static void Win32MidiStop(void) +{ + _midi.terminate = true; + SetEvent(_midi.wait_obj); +} + +const HalMusicDriver _win32_music_driver = { + Win32MidiStart, + Win32MidiStop, + Win32MidiPlaySong, + Win32MidiStopSong, + Win32MidiIsSongPlaying, + Win32MidiSetVolume, +}; diff --git a/music/win32.h b/music/win32.h new file mode 100644 index 000000000..8a2a0fb2d --- /dev/null +++ b/music/win32.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_WIN32_H +#define MUSIC_WIN32_H + +#include "hal.h" + +extern const HalMusicDriver _win32_music_driver; + +#endif @@ -2,6 +2,7 @@ #include "string.h" #include "table/strings.h" #include "debug.h" +#include "driver.h" #include "saveload.h" #include "strings.h" #include "map.h" @@ -64,7 +65,6 @@ extern void HalGameLoop(void); uint32 _pixels_redrawn; bool _dbg_screen_rect; -static byte _os_version = 0; /* TODO: usrerror() for errors which are not of an internal nature but * caused by the user, i.e. missing files or fatal configuration errors. @@ -112,104 +112,6 @@ char * CDECL str_fmt(const char *str, ...) } -// NULL midi driver -static const char *NullMidiStart(const char * const *parm) { return NULL; } -static void NullMidiStop(void) {} -static void NullMidiPlaySong(const char *filename) {} -static void NullMidiStopSong(void) {} -static bool NullMidiIsSongPlaying(void) { return true; } -static void NullMidiSetVolume(byte vol) {} - -const HalMusicDriver _null_music_driver = { - NullMidiStart, - NullMidiStop, - NullMidiPlaySong, - NullMidiStopSong, - NullMidiIsSongPlaying, - NullMidiSetVolume, -}; - -// NULL video driver -static void *_null_video_mem; -static const char *NullVideoStart(const char * const *parm) -{ - _screen.width = _screen.pitch = _cur_resolution[0]; - _screen.height = _cur_resolution[1]; - _null_video_mem = malloc(_cur_resolution[0]*_cur_resolution[1]); - return NULL; -} -static void NullVideoStop(void) { free(_null_video_mem); } -static void NullVideoMakeDirty(int left, int top, int width, int height) {} -static int NullVideoMainLoop(void) -{ - int i = 1000; - do { - GameLoop(); - _screen.dst_ptr = _null_video_mem; - UpdateWindows(); - } while (--i); - return ML_QUIT; -} - -static bool NullVideoChangeRes(int w, int h) { return false; } -static void NullVideoFullScreen(bool fs) {} - -const HalVideoDriver _null_video_driver = { - NullVideoStart, - NullVideoStop, - NullVideoMakeDirty, - NullVideoMainLoop, - NullVideoChangeRes, - NullVideoFullScreen, -}; - -// NULL sound driver -static const char *NullSoundStart(const char * const *parm) { return NULL; } -static void NullSoundStop(void) {} -const HalSoundDriver _null_sound_driver = { - NullSoundStart, - NullSoundStop, -}; - -enum { - DF_PRIORITY_MASK = 0xf, -}; - -typedef struct { - const DriverDesc *descs; - const char *name; - void *var; -} DriverClass; - -static DriverClass _driver_classes[] = { - {_video_driver_descs, "video", &_video_driver}, - {_sound_driver_descs, "sound", &_sound_driver}, - {_music_driver_descs, "music", &_music_driver}, -}; - -static const DriverDesc *GetDriverByName(const DriverDesc *dd, const char *name) -{ - do { - if (!strcmp(dd->name, name)) - return dd; - } while ((++dd)->name); - return NULL; -} - -static const DriverDesc *ChooseDefaultDriver(const DriverDesc *dd) -{ - const DriverDesc *best = NULL; - int best_pri = -1; - do { - if ((int)(dd->flags&DF_PRIORITY_MASK) > best_pri && _os_version >= (byte)dd->flags) { - best_pri = dd->flags&DF_PRIORITY_MASK; - best = dd; - } - } while ((++dd)->name); - return best; -} - - void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) { FILE *in; @@ -239,56 +141,9 @@ void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) return mem; } -void LoadDriver(int driver, const char *name) -{ - const DriverClass *dc = &_driver_classes[driver]; - const DriverDesc *dd; - const void **var; - const void *drv; - const char *err; - char *parm; - char buffer[256]; - const char *parms[32]; - - parms[0] = NULL; - - if (!*name) { - dd = ChooseDefaultDriver(dc->descs); - } else { - // Extract the driver name and put parameter list in parm - ttd_strlcpy(buffer, name, sizeof(buffer)); - parm = strchr(buffer, ':'); - if (parm) { - uint np = 0; - // Tokenize the parm. - do { - *parm++ = 0; - if (np < lengthof(parms) - 1) - parms[np++] = parm; - while (*parm != 0 && *parm != ',') - parm++; - } while (*parm == ','); - parms[np] = NULL; - } - dd = GetDriverByName(dc->descs, buffer); - if (dd == NULL) - error("No such %s driver: %s\n", dc->name, buffer); - } - var = dc->var; - if (*var != NULL) ((const HalCommonDriver*)*var)->stop(); - *var = NULL; - drv = dd->drv; - if ((err=((const HalCommonDriver*)drv)->start(parms)) != NULL) - error("Unable to load driver %s(%s). The error was: %s\n", dd->name, dd->longname, err); - *var = drv; -} - static void showhelp(void) { char buf[4096], *p; - const DriverClass *dc = _driver_classes; - const DriverDesc *dd; - int i; p = strecpy(buf, "Command line options:\n" @@ -314,43 +169,12 @@ static void showhelp(void) lastof(buf) ); - for(i=0; i!=lengthof(_driver_classes); i++,dc++) { - p += sprintf(p, "List of %s drivers:\n", dc->name); - dd = dc->descs; - do { - p += sprintf(p, "%10s: %s\n", dd->name, dd->longname); - } while ((++dd)->name); - } + GetDriverList(p); ShowInfo(buf); } -const char *GetDriverParam(const char * const *parm, const char *name) -{ - const char *p; - int len = strlen(name); - while ((p = *parm++) != NULL) { - if (!strncmp(p,name,len)) { - if (p[len] == '=') return p + len + 1; - if (p[len] == 0) return p + len; - } - } - return NULL; -} - -bool GetDriverParamBool(const char * const *parm, const char *name) -{ - const char *p = GetDriverParam(parm, name); - return p != NULL; -} - -int GetDriverParamInt(const char * const *parm, const char *name, int def) -{ - const char *p = GetDriverParam(parm, name); - return p != NULL ? atoi(p) : def; -} - typedef struct { char *opt; int numleft; @@ -645,7 +469,6 @@ int ttd_main(int argc, char* argv[]) // Sample catalogue DEBUG(misc, 1) ("Loading sound effects..."); - _os_version = GetOSVersion(); MxInitialize(11025); SoundInitialize("sample.cat"); @@ -1,17 +1,7 @@ #include "stdafx.h" - -#if defined(WITH_SDL) #include "openttd.h" -#include "debug.h" -#include "functions.h" -#include "gfx.h" -#include "mixer.h" -#include "window.h" +#include "sdl.h" #include <SDL.h> -#include "player.h" -#include "hal.h" -#include "network.h" -#include "variables.h" #ifdef UNIX #include <signal.h> @@ -23,52 +13,12 @@ #endif #endif -#define DYNAMICALLY_LOADED_SDL - -static SDL_Surface *_sdl_screen; static int _sdl_usage; -static bool _all_modes; - -#define MAX_DIRTY_RECTS 100 -static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; -static int _num_dirty_rects; -#define SDL_CALL - -#if defined(DYNAMICALLY_LOADED_SDL) && defined(WIN32) +#ifdef DYNAMICALLY_LOADED_SDL bool LoadLibraryList(void **proc, const char *dll); -typedef struct { - int (SDLCALL *SDL_Init)(Uint32); - int (SDLCALL *SDL_InitSubSystem)(Uint32); - char *(SDLCALL *SDL_GetError)(); - void (SDLCALL *SDL_QuitSubSystem)(Uint32); - void (SDLCALL *SDL_UpdateRect)(SDL_Surface *, Sint32, Sint32, Uint32, Uint32); - void (SDLCALL *SDL_UpdateRects)(SDL_Surface *, int, SDL_Rect *); - int (SDLCALL *SDL_SetColors)(SDL_Surface *, SDL_Color *, int, int); - void (SDLCALL *SDL_WM_SetCaption)(const char *, const char *); - int (SDLCALL *SDL_ShowCursor)(int); - void (SDLCALL *SDL_FreeSurface)(SDL_Surface *); - int (SDLCALL *SDL_PollEvent)(SDL_Event *); - void (SDLCALL *SDL_WarpMouse)(Uint16, Uint16); - uint32 (SDLCALL *SDL_GetTicks)(); - int (SDLCALL *SDL_OpenAudio)(SDL_AudioSpec *, SDL_AudioSpec*); - void (SDLCALL *SDL_PauseAudio)(int); - void (SDLCALL *SDL_CloseAudio)(); - int (SDLCALL *SDL_LockSurface)(SDL_Surface*); - void (SDLCALL *SDL_UnlockSurface)(SDL_Surface*); - SDLMod (SDLCALL *SDL_GetModState)(); - void (SDLCALL *SDL_Delay)(Uint32); - void (SDLCALL *SDL_Quit)(); - SDL_Surface *(SDLCALL *SDL_SetVideoMode)(int, int, int, Uint32); - int (SDLCALL *SDL_EnableKeyRepeat)(int, int); - void (SDLCALL *SDL_EnableUNICODE)(int); - void (SDLCALL *SDL_VideoDriverName)(char *, int); - SDL_Rect **(SDLCALL *SDL_ListModes)(void *, int); - Uint8 *(SDLCALL *SDL_GetKeyState)(int *); -} SDLProcs; - #define M(x) x "\0" static const char sdl_files[] = M("sdl.dll") @@ -103,21 +53,18 @@ static const char sdl_files[] = ; #undef M -static SDLProcs _proc; +SDLProcs sdl_proc; static const char *LoadSdlDLL(void) { - if (_proc.SDL_Init != NULL) + if (sdl_proc.SDL_Init != NULL) return NULL; - if (!LoadLibraryList((void**)&_proc, sdl_files)) + if (!LoadLibraryList((void**)&sdl_proc, sdl_files)) return "Unable to load sdl.dll"; return NULL; } -#undef SDL_CALL -#define SDL_CALL _proc. - -#endif +#endif // DYNAMICALLY_LOADED_SDL #ifdef UNIX @@ -140,9 +87,9 @@ static void SdlAbort(int sig) #endif -static const char *SdlOpen(uint32 x) +const char* SdlOpen(uint32 x) { -#if defined(DYNAMICALLY_LOADED_SDL) && defined(WIN32) +#ifdef DYNAMICALLY_LOADED_SDL { const char *s = LoadSdlDLL(); if (s != NULL) return s; @@ -165,7 +112,7 @@ static const char *SdlOpen(uint32 x) return NULL; } -static void SdlClose(uint32 x) +void SdlClose(uint32 x) { if (x != 0) SDL_CALL SDL_QuitSubSystem(x); @@ -178,507 +125,3 @@ static void SdlClose(uint32 x) #endif } } - -static void SdlVideoMakeDirty(int left, int top, int width, int height) -{ -// printf("(%d,%d)-(%d,%d)\n", left, top, width, height); -// _pixels_redrawn += width*height; - if (_num_dirty_rects < MAX_DIRTY_RECTS) { - _dirty_rects[_num_dirty_rects].x = left; - _dirty_rects[_num_dirty_rects].y = top; - _dirty_rects[_num_dirty_rects].w = width; - _dirty_rects[_num_dirty_rects].h = height; - } - _num_dirty_rects++; -} - -static SDL_Color pal[256]; - -static void UpdatePalette(uint start, uint end) -{ - uint i; - - for (i = start; i != end; i++) { - pal[i].r = _cur_palette[i].r; - pal[i].g = _cur_palette[i].g; - pal[i].b = _cur_palette[i].b; - pal[i].unused = 0; - } - - SDL_CALL SDL_SetColors(_sdl_screen, pal, start, end); -} - -static void InitPalette(void) -{ - UpdatePalette(0, 256); -} - -static void CheckPaletteAnim(void) -{ - if(_pal_last_dirty != -1) { - UpdatePalette(_pal_first_dirty, _pal_last_dirty + 1); - _pal_last_dirty = -1; - } -} - -static void DrawSurfaceToScreen(void) -{ - int n = _num_dirty_rects; - if (n != 0) { - _num_dirty_rects = 0; - if (n > MAX_DIRTY_RECTS) - SDL_CALL SDL_UpdateRect(_sdl_screen, 0, 0, 0, 0); - else - SDL_CALL SDL_UpdateRects(_sdl_screen, n, _dirty_rects); - } -} - -static const uint16 default_resolutions[][2] = { - { 640, 480}, - { 800, 600}, - {1024, 768}, - {1152, 864}, - {1280, 800}, - {1280, 960}, - {1280, 1024}, - {1400, 1050}, - {1600, 1200}, - {1680, 1050}, - {1920, 1200} -}; - -static void GetVideoModes(void) -{ - int i; - SDL_Rect **modes; - - modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE + (_fullscreen ? SDL_FULLSCREEN : 0)); - - if (modes == NULL) - error("sdl: no modes available"); - - _all_modes = (modes == (void*)-1); - - if (_all_modes) { - // all modes available, put some default ones here - memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); - _num_resolutions = lengthof(default_resolutions); - } else { - int n = 0; - for (i = 0; modes[i]; i++) { - int w = modes[i]->w; - int h = modes[i]->h; - if (IS_INT_INSIDE(w, 640, MAX_SCREEN_WIDTH + 1) && - IS_INT_INSIDE(h, 480, MAX_SCREEN_HEIGHT + 1)) { - int j; - for (j = 0; j < n; j++) { - if (_resolutions[j][0] == w && _resolutions[j][1] == h) break; - } - - if (j == n) { - _resolutions[j][0] = w; - _resolutions[j][1] = h; - if (++n == lengthof(_resolutions)) break; - } - } - } - _num_resolutions = n; - SortResolutions(_num_resolutions); - } -} - -static int GetAvailableVideoMode(int *w, int *h) -{ - int i; - int best; - uint delta; - - // all modes available? - if (_all_modes) - return 1; - - // is the wanted mode among the available modes? - for (i = 0; i != _num_resolutions; i++) { - if(*w == _resolutions[i][0] && *h == _resolutions[i][1]) - return 1; - } - - // use the closest possible resolution - best = 0; - delta = abs((_resolutions[0][0] - *w) * (_resolutions[0][1] - *h)); - for (i = 1; i != _num_resolutions; ++i) { - uint newdelta = abs((_resolutions[i][0] - *w) * (_resolutions[i][1] - *h)); - if (newdelta < delta) { - best = i; - delta = newdelta; - } - } - *w = _resolutions[best][0]; - *h = _resolutions[best][1]; - return 2; -} - -extern const char _openttd_revision[]; - -static bool CreateMainSurface(int w, int h) -{ - SDL_Surface *newscreen; - char caption[50]; - - GetAvailableVideoMode(&w, &h); - - DEBUG(misc, 1) ("sdl: using mode %dx%d", w, h); - - // DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK - newscreen = SDL_CALL SDL_SetVideoMode(w, h, 8, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); - if (newscreen == NULL) - return false; - - _screen.width = newscreen->w; - _screen.height = newscreen->h; - _screen.pitch = newscreen->pitch; - - _sdl_screen = newscreen; - InitPalette(); - - snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); - SDL_CALL SDL_WM_SetCaption(caption, caption); - SDL_CALL SDL_ShowCursor(0); - - GameSizeChanged(); - - return true; -} - -typedef struct VkMapping { - uint16 vk_from; - byte vk_count; - byte map_to; -} VkMapping; - -#define AS(x, z) {x, 0, z} -#define AM(x, y, z, w) {x, y - x, z} - -static const VkMapping _vk_mapping[] = { - // Pageup stuff + up/down - AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), - AS(SDLK_UP, WKC_UP), - AS(SDLK_DOWN, WKC_DOWN), - AS(SDLK_LEFT, WKC_LEFT), - AS(SDLK_RIGHT, WKC_RIGHT), - - AS(SDLK_HOME, WKC_HOME), - AS(SDLK_END, WKC_END), - - AS(SDLK_INSERT, WKC_INSERT), - AS(SDLK_DELETE, WKC_DELETE), - - // Map letters & digits - AM(SDLK_a, SDLK_z, 'A', 'Z'), - AM(SDLK_0, SDLK_9, '0', '9'), - - AS(SDLK_ESCAPE, WKC_ESC), - AS(SDLK_PAUSE, WKC_PAUSE), - AS(SDLK_BACKSPACE, WKC_BACKSPACE), - - AS(SDLK_SPACE, WKC_SPACE), - AS(SDLK_RETURN, WKC_RETURN), - AS(SDLK_TAB, WKC_TAB), - - // Function keys - AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), - - // Numeric part. - // What is the virtual keycode for numeric enter?? - AM(SDLK_KP0, SDLK_KP9, WKC_NUM_0, WKC_NUM_9), - AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), - AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), - AS(SDLK_KP_MINUS, WKC_NUM_MINUS), - AS(SDLK_KP_PLUS, WKC_NUM_PLUS), - AS(SDLK_KP_ENTER, WKC_NUM_ENTER), - AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL) -}; - -static uint32 ConvertSdlKeyIntoMy(SDL_keysym *sym) -{ - const VkMapping *map; - uint key = 0; - for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { - if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { - key = sym->sym - map->vk_from + map->map_to; - break; - } - } - - // check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) -#if defined(WIN32) || defined(__OS2__) - if (sym->scancode == 41) key |= WKC_BACKQUOTE; -#elif defined(__APPLE__) - if (sym->scancode == 10) key |= WKC_BACKQUOTE; -#elif defined(__MORPHOS__) - if (sym->scancode == 0) key |= WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) -#elif defined(__BEOS__) - if (sym->scancode == 17) key |= WKC_BACKQUOTE; -#elif defined(__SVR4) && defined(__sun) - if (sym->scancode == 60) key |= WKC_BACKQUOTE; - if (sym->scancode == 49) key |= WKC_BACKSPACE; -#elif defined(__sgi__) - if (sym->scancode == 22) key |= WKC_BACKQUOTE; -#else - if (sym->scancode == 41) key |= WKC_BACKQUOTE; // Linux console - if (sym->scancode == 49) key |= WKC_BACKQUOTE; -#endif - - // META are the command keys on mac - if (sym->mod & KMOD_META) key |= WKC_META; - if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; - if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; - if (sym->mod & KMOD_ALT) key |= WKC_ALT; - // these two lines really help porting hotkey combos. Uncomment to use -- Bjarni - //printf("scancode character pressed %d\n", sym->scancode); - //printf("unicode character pressed %d\n", sym->unicode); - return (key << 16) + sym->unicode; -} - -extern void DoExitSave(void); - -static int PollEvent(void) -{ - SDL_Event ev; - - if (!SDL_CALL SDL_PollEvent(&ev)) - return -2; - - switch (ev.type) { - case SDL_MOUSEMOTION: - if (_cursor.fix_at) { - int dx = ev.motion.x - _cursor.pos.x; - int dy = ev.motion.y - _cursor.pos.y; - if (dx != 0 || dy != 0) { - _cursor.delta.x += dx; - _cursor.delta.y += dy; - SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y); - } - } else { - _cursor.delta.x = ev.motion.x - _cursor.pos.x; - _cursor.delta.y = ev.motion.y - _cursor.pos.y; - _cursor.pos.x = ev.motion.x; - _cursor.pos.y = ev.motion.y; - _cursor.dirty = true; - } - break; - - case SDL_MOUSEBUTTONDOWN: - if (_rightclick_emulate && (SDL_CALL SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL))) - ev.button.button = SDL_BUTTON_RIGHT; - - switch (ev.button.button) { - case SDL_BUTTON_LEFT: - _left_button_down = true; - break; - case SDL_BUTTON_RIGHT: - _right_button_down = true; - _right_button_clicked = true; - break; - case SDL_BUTTON_WHEELUP: - _cursor.wheel--; - break; - case SDL_BUTTON_WHEELDOWN: - _cursor.wheel++; - break; - default: - break; - } - break; - - case SDL_MOUSEBUTTONUP: - if (_rightclick_emulate) { - _right_button_down = false; - _left_button_down = false; - _left_button_clicked = false; - } else if (ev.button.button == SDL_BUTTON_LEFT) { - _left_button_down = false; - _left_button_clicked = false; - } else if (ev.button.button == SDL_BUTTON_RIGHT) { - _right_button_down = false; - } - break; - - case SDL_QUIT: - // do not ask to quit on the main screen - if (_game_mode != GM_MENU) { - if(_patches.autosave_on_exit) { - DoExitSave(); - return ML_QUIT; - } else - AskExitGame(); - } else - return ML_QUIT; - break; - - case SDL_KEYDOWN: /* Toggle full-screen on ALT + ENTER/F */ - if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) && - (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { - ToggleFullScreen(!_fullscreen); - } else - _pressed_key = ConvertSdlKeyIntoMy(&ev.key.keysym); - - break; - - case SDL_VIDEORESIZE: { - int w = clamp(ev.resize.w, 64, MAX_SCREEN_WIDTH); - int h = clamp(ev.resize.h, 64, MAX_SCREEN_HEIGHT); - ChangeResInGame(w, h); - break; - } - } - return -1; -} - -static const char *SdlVideoStart(const char * const *parm) -{ - char buf[30]; - - const char *s = SdlOpen(SDL_INIT_VIDEO); - if (s != NULL) return s; - - SDL_CALL SDL_VideoDriverName(buf, 30); - DEBUG(misc, 1) ("sdl: using driver '%s'", buf); - - GetVideoModes(); - CreateMainSurface(_cur_resolution[0], _cur_resolution[1]); - MarkWholeScreenDirty(); - - SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - SDL_CALL SDL_EnableUNICODE(1); - return NULL; -} - -static void SdlVideoStop(void) -{ - SdlClose(SDL_INIT_VIDEO); -} - -static int SdlVideoMainLoop(void) -{ - uint32 next_tick = SDL_CALL SDL_GetTicks() + 30; - uint32 cur_ticks; - uint32 pal_tick = 0; - int i; - uint32 mod; - int numkeys; - Uint8 *keys; - - for (;;) { - InteractiveRandom(); // randomness - - while ((i = PollEvent()) == -1) {} - if (i >= 0) return i; - - if (_exit_game) return ML_QUIT; - - mod = SDL_CALL SDL_GetModState(); - keys = SDL_CALL SDL_GetKeyState(&numkeys); -#if defined(_DEBUG) - if (_shift_pressed) -#else - if (keys[SDLK_TAB]) -#endif - { - if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; - } else if (_fast_forward & 2) { - _fast_forward = 0; - } - - cur_ticks = SDL_CALL SDL_GetTicks(); - if ((_fast_forward && !_pause) || cur_ticks > next_tick) - next_tick = cur_ticks; - - if (cur_ticks == next_tick) { - next_tick += 30; - - _ctrl_pressed = !!(mod & (KMOD_LCTRL | KMOD_RCTRL)); - _shift_pressed = !!(mod & (KMOD_LSHIFT | KMOD_RSHIFT)); - _dbg_screen_rect = !!(mod & KMOD_CAPS); - - // determine which directional keys are down - _dirkeys = - (keys[SDLK_LEFT] ? 1 : 0) | - (keys[SDLK_UP] ? 2 : 0) | - (keys[SDLK_RIGHT] ? 4 : 0) | - (keys[SDLK_DOWN] ? 8 : 0); - GameLoop(); - - _screen.dst_ptr = _sdl_screen->pixels; - UpdateWindows(); - if (++pal_tick > 4) { - CheckPaletteAnim(); - pal_tick = 1; - } - DrawSurfaceToScreen(); - } else { - SDL_CALL SDL_Delay(1); - _screen.dst_ptr = _sdl_screen->pixels; - DrawTextMessage(); - DrawMouseCursor(); - DrawSurfaceToScreen(); - } - } -} - -static bool SdlVideoChangeRes(int w, int h) -{ - return CreateMainSurface(w, h); -} - -static void SdlVideoFullScreen(bool full_screen) -{ - _fullscreen = full_screen; - GetVideoModes(); // get the list of available video modes - if (!_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1])) - _fullscreen ^= true; // switching resolution failed, put back full_screen to original status -} - -const HalVideoDriver _sdl_video_driver = { - SdlVideoStart, - SdlVideoStop, - SdlVideoMakeDirty, - SdlVideoMainLoop, - SdlVideoChangeRes, - SdlVideoFullScreen, -}; - -static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) -{ - MxMixSamples(_mixer, stream, len / 4); -} - -static const char *SdlSoundStart(const char * const *parm) -{ - SDL_AudioSpec spec; - - const char *s = SdlOpen(SDL_INIT_AUDIO); - if (s != NULL) return s; - - spec.freq = GetDriverParamInt(parm, "hz", 11025); - spec.format = AUDIO_S16SYS; - spec.channels = 2; - spec.samples = 512; - spec.callback = fill_sound_buffer; - SDL_CALL SDL_OpenAudio(&spec, &spec); - SDL_CALL SDL_PauseAudio(0); - return NULL; -} - -static void SdlSoundStop(void) -{ - SDL_CALL SDL_CloseAudio(); - SdlClose(SDL_INIT_AUDIO); -} - -const HalSoundDriver _sdl_sound_driver = { - SdlSoundStart, - SdlSoundStop, -}; - -#endif /* WITH_SDL */ @@ -0,0 +1,51 @@ +#ifndef SDL_H +#define SDL_H + +const char* SdlOpen(uint32 x); +void SdlClose(uint32 x); + +#ifdef WIN32 + #define DYNAMICALLY_LOADED_SDL +#endif + +#ifdef DYNAMICALLY_LOADED_SDL + #include <SDL.h> + + typedef struct SDLProcs { + int (SDLCALL *SDL_Init)(Uint32); + int (SDLCALL *SDL_InitSubSystem)(Uint32); + char *(SDLCALL *SDL_GetError)(void); + void (SDLCALL *SDL_QuitSubSystem)(Uint32); + void (SDLCALL *SDL_UpdateRect)(SDL_Surface *, Sint32, Sint32, Uint32, Uint32); + void (SDLCALL *SDL_UpdateRects)(SDL_Surface *, int, SDL_Rect *); + int (SDLCALL *SDL_SetColors)(SDL_Surface *, SDL_Color *, int, int); + void (SDLCALL *SDL_WM_SetCaption)(const char *, const char *); + int (SDLCALL *SDL_ShowCursor)(int); + void (SDLCALL *SDL_FreeSurface)(SDL_Surface *); + int (SDLCALL *SDL_PollEvent)(SDL_Event *); + void (SDLCALL *SDL_WarpMouse)(Uint16, Uint16); + uint32 (SDLCALL *SDL_GetTicks)(void); + int (SDLCALL *SDL_OpenAudio)(SDL_AudioSpec *, SDL_AudioSpec*); + void (SDLCALL *SDL_PauseAudio)(int); + void (SDLCALL *SDL_CloseAudio)(void); + int (SDLCALL *SDL_LockSurface)(SDL_Surface*); + void (SDLCALL *SDL_UnlockSurface)(SDL_Surface*); + SDLMod (SDLCALL *SDL_GetModState)(void); + void (SDLCALL *SDL_Delay)(Uint32); + void (SDLCALL *SDL_Quit)(void); + SDL_Surface *(SDLCALL *SDL_SetVideoMode)(int, int, int, Uint32); + int (SDLCALL *SDL_EnableKeyRepeat)(int, int); + void (SDLCALL *SDL_EnableUNICODE)(int); + void (SDLCALL *SDL_VideoDriverName)(char *, int); + SDL_Rect **(SDLCALL *SDL_ListModes)(void *, int); + Uint8 *(SDLCALL *SDL_GetKeyState)(int *); + } SDLProcs; + + extern SDLProcs sdl_proc; + + #define SDL_CALL sdl_proc. +#else + #define SDL_CALL +#endif + +#endif diff --git a/sound/null.c b/sound/null.c new file mode 100644 index 000000000..e7d0c8c10 --- /dev/null +++ b/sound/null.c @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include "openttd.h" +#include "sound/null.h" + +static const char *NullSoundStart(const char * const *parm) { return NULL; } +static void NullSoundStop(void) {} + +const HalSoundDriver _null_sound_driver = { + NullSoundStart, + NullSoundStop, +}; diff --git a/sound/null.h b/sound/null.h new file mode 100644 index 000000000..63cc5ef8f --- /dev/null +++ b/sound/null.h @@ -0,0 +1,8 @@ +#ifndef SOUND_NULL_H +#define SOUND_NULL_H + +#include "hal.h" + +extern const HalSoundDriver _null_sound_driver; + +#endif diff --git a/sound/sdl.c b/sound/sdl.c new file mode 100644 index 000000000..2f227ad39 --- /dev/null +++ b/sound/sdl.c @@ -0,0 +1,40 @@ +#include "stdafx.h" +#include "openttd.h" +#include "driver.h" +#include "mixer.h" +#include "sdl.h" +#include "sound/sdl.h" +#include <SDL.h> + +static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) +{ + MxMixSamples(_mixer, stream, len / 4); +} + +static const char *SdlSoundStart(const char * const *parm) +{ + SDL_AudioSpec spec; + + const char *s = SdlOpen(SDL_INIT_AUDIO); + if (s != NULL) return s; + + spec.freq = GetDriverParamInt(parm, "hz", 11025); + spec.format = AUDIO_S16SYS; + spec.channels = 2; + spec.samples = 512; + spec.callback = fill_sound_buffer; + SDL_CALL SDL_OpenAudio(&spec, &spec); + SDL_CALL SDL_PauseAudio(0); + return NULL; +} + +static void SdlSoundStop(void) +{ + SDL_CALL SDL_CloseAudio(); + SdlClose(SDL_INIT_AUDIO); +} + +const HalSoundDriver _sdl_sound_driver = { + SdlSoundStart, + SdlSoundStop, +}; diff --git a/sound/sdl.h b/sound/sdl.h new file mode 100644 index 000000000..9e593991a --- /dev/null +++ b/sound/sdl.h @@ -0,0 +1,8 @@ +#ifndef SOUND_SDL_H +#define SOUND_SDL_H + +#include "hal.h" + +extern const HalSoundDriver _sdl_sound_driver; + +#endif diff --git a/sound/win32.c b/sound/win32.c new file mode 100644 index 000000000..9d58515a3 --- /dev/null +++ b/sound/win32.c @@ -0,0 +1,84 @@ +#include "stdafx.h" +#include "openttd.h" +#include "driver.h" +#include "functions.h" +#include "mixer.h" +#include "sound/win32.h" +#include <windows.h> + +static HWAVEOUT _waveout; +static WAVEHDR _wave_hdr[2]; +static int _bufsize; + +static void PrepareHeader(WAVEHDR *hdr) +{ + hdr->dwBufferLength = _bufsize * 4; + hdr->dwFlags = 0; + hdr->lpData = malloc(_bufsize * 4); + if (hdr->lpData == NULL || + waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) + error("waveOutPrepareHeader failed"); +} + +static void FillHeaders(void) +{ + WAVEHDR *hdr; + + for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) { + if (!(hdr->dwFlags & WHDR_INQUEUE)) { + MxMixSamples(_mixer, hdr->lpData, hdr->dwBufferLength / 4); + if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) + error("waveOutWrite failed"); + } + } +} + +static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + switch (uMsg) { + case WOM_DONE: + if (_waveout) FillHeaders(); + break; + + default: + break; + } +} + +static const char *Win32SoundStart(const char* const* parm) +{ + WAVEFORMATEX wfex; + int hz; + + _bufsize = GetDriverParamInt(parm, "bufsize", 1024); + hz = GetDriverParamInt(parm, "hz", 11025); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 2; + wfex.nSamplesPerSec = hz; + wfex.nAvgBytesPerSec = hz * 2 * 2; + wfex.nBlockAlign = 4; + wfex.wBitsPerSample = 16; + if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + return "waveOutOpen failed"; + PrepareHeader(&_wave_hdr[0]); + PrepareHeader(&_wave_hdr[1]); + FillHeaders(); + return NULL; +} + +static void Win32SoundStop(void) +{ + HWAVEOUT waveout = _waveout; + + _waveout = NULL; + waveOutReset(waveout); + waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR)); + waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR)); + waveOutClose(waveout); +} + +const HalSoundDriver _win32_sound_driver = { + Win32SoundStart, + Win32SoundStop, +}; diff --git a/sound/win32.h b/sound/win32.h new file mode 100644 index 000000000..1f7b82b27 --- /dev/null +++ b/sound/win32.h @@ -0,0 +1,8 @@ +#ifndef SOUND_WIN32_H +#define SOUND_WIN32_H + +#include "hal.h" + +extern const HalSoundDriver _win32_sound_driver; + +#endif diff --git a/table/engines.h b/table/engines.h index 23b0daf57..6e73f3e37 100644 --- a/table/engines.h +++ b/table/engines.h @@ -5,7 +5,7 @@ * This file contains all the data for vehicles */ -#include "../sound.h" +#include "sound.h" /** Writes the properties of a vehicle into the EngineInfo struct. * @see EngineInfo diff --git a/table/namegen.h b/table/namegen.h index 923ec2dfa..94781acec 100644 --- a/table/namegen.h +++ b/table/namegen.h @@ -1,5 +1,5 @@ -#include "../stdafx.h" -#include "../openttd.h" +#include "stdafx.h" +#include "openttd.h" static const char *name_original_english_1[] = { "Great ", @@ -7,6 +7,15 @@ #include "hal.h" #include "variables.h" +#include "music/extmidi.h" +#include "music/null.h" + +#include "sound/null.h" +#include "sound/sdl.h" + +#include "video/null.h" +#include "video/sdl.h" + #include <dirent.h> #include <unistd.h> #include <sys/stat.h> diff --git a/video/null.c b/video/null.c new file mode 100644 index 000000000..bbd839cc0 --- /dev/null +++ b/video/null.c @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "openttd.h" +#include "gfx.h" +#include "variables.h" +#include "video/null.h" +#include "window.h" + +static void* _null_video_mem = NULL; + +static const char* NullVideoStart(const char* const* parm) +{ + _screen.width = _screen.pitch = _cur_resolution[0]; + _screen.height = _cur_resolution[1]; + _null_video_mem = malloc(_cur_resolution[0] * _cur_resolution[1]); + return NULL; +} + +static void NullVideoStop(void) { free(_null_video_mem); } + +static void NullVideoMakeDirty(int left, int top, int width, int height) {} + +static int NullVideoMainLoop(void) +{ + uint i; + + for (i = 0; i < 1000; i++) { + GameLoop(); + _screen.dst_ptr = _null_video_mem; + UpdateWindows(); + } + + return ML_QUIT; +} + +static bool NullVideoChangeRes(int w, int h) { return false; } +static void NullVideoFullScreen(bool fs) {} + +const HalVideoDriver _null_video_driver = { + NullVideoStart, + NullVideoStop, + NullVideoMakeDirty, + NullVideoMainLoop, + NullVideoChangeRes, + NullVideoFullScreen, +}; diff --git a/video/null.h b/video/null.h new file mode 100644 index 000000000..d5d379158 --- /dev/null +++ b/video/null.h @@ -0,0 +1,8 @@ +#ifndef VIDEO_NULL_H +#define VIDEO_NULL_H + +#include "hal.h" + +extern const HalVideoDriver _null_video_driver; + +#endif diff --git a/video/sdl.c b/video/sdl.c new file mode 100644 index 000000000..5dc3a8cd4 --- /dev/null +++ b/video/sdl.c @@ -0,0 +1,488 @@ +#include "stdafx.h" +#include "openttd.h" +#include "debug.h" +#include "functions.h" +#include "gfx.h" +#include "macros.h" +#include "sdl.h" +#include "window.h" +#include "video/sdl.h" +#include <SDL.h> +#include "network.h" +#include "variables.h" + +static SDL_Surface *_sdl_screen; +static bool _all_modes; + +#define MAX_DIRTY_RECTS 100 +static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; +static int _num_dirty_rects; + +static void SdlVideoMakeDirty(int left, int top, int width, int height) +{ +// printf("(%d,%d)-(%d,%d)\n", left, top, width, height); +// _pixels_redrawn += width*height; + if (_num_dirty_rects < MAX_DIRTY_RECTS) { + _dirty_rects[_num_dirty_rects].x = left; + _dirty_rects[_num_dirty_rects].y = top; + _dirty_rects[_num_dirty_rects].w = width; + _dirty_rects[_num_dirty_rects].h = height; + } + _num_dirty_rects++; +} + +static SDL_Color pal[256]; + +static void UpdatePalette(uint start, uint end) +{ + uint i; + + for (i = start; i != end; i++) { + pal[i].r = _cur_palette[i].r; + pal[i].g = _cur_palette[i].g; + pal[i].b = _cur_palette[i].b; + pal[i].unused = 0; + } + + SDL_CALL SDL_SetColors(_sdl_screen, pal, start, end); +} + +static void InitPalette(void) +{ + UpdatePalette(0, 256); +} + +static void CheckPaletteAnim(void) +{ + if(_pal_last_dirty != -1) { + UpdatePalette(_pal_first_dirty, _pal_last_dirty + 1); + _pal_last_dirty = -1; + } +} + +static void DrawSurfaceToScreen(void) +{ + int n = _num_dirty_rects; + if (n != 0) { + _num_dirty_rects = 0; + if (n > MAX_DIRTY_RECTS) + SDL_CALL SDL_UpdateRect(_sdl_screen, 0, 0, 0, 0); + else + SDL_CALL SDL_UpdateRects(_sdl_screen, n, _dirty_rects); + } +} + +static const uint16 default_resolutions[][2] = { + { 640, 480}, + { 800, 600}, + {1024, 768}, + {1152, 864}, + {1280, 800}, + {1280, 960}, + {1280, 1024}, + {1400, 1050}, + {1600, 1200}, + {1680, 1050}, + {1920, 1200} +}; + +static void GetVideoModes(void) +{ + int i; + SDL_Rect **modes; + + modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE + (_fullscreen ? SDL_FULLSCREEN : 0)); + + if (modes == NULL) + error("sdl: no modes available"); + + _all_modes = (modes == (void*)-1); + + if (_all_modes) { + // all modes available, put some default ones here + memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); + _num_resolutions = lengthof(default_resolutions); + } else { + int n = 0; + for (i = 0; modes[i]; i++) { + int w = modes[i]->w; + int h = modes[i]->h; + if (IS_INT_INSIDE(w, 640, MAX_SCREEN_WIDTH + 1) && + IS_INT_INSIDE(h, 480, MAX_SCREEN_HEIGHT + 1)) { + int j; + for (j = 0; j < n; j++) { + if (_resolutions[j][0] == w && _resolutions[j][1] == h) break; + } + + if (j == n) { + _resolutions[j][0] = w; + _resolutions[j][1] = h; + if (++n == lengthof(_resolutions)) break; + } + } + } + _num_resolutions = n; + SortResolutions(_num_resolutions); + } +} + +static int GetAvailableVideoMode(int *w, int *h) +{ + int i; + int best; + uint delta; + + // all modes available? + if (_all_modes) + return 1; + + // is the wanted mode among the available modes? + for (i = 0; i != _num_resolutions; i++) { + if(*w == _resolutions[i][0] && *h == _resolutions[i][1]) + return 1; + } + + // use the closest possible resolution + best = 0; + delta = abs((_resolutions[0][0] - *w) * (_resolutions[0][1] - *h)); + for (i = 1; i != _num_resolutions; ++i) { + uint newdelta = abs((_resolutions[i][0] - *w) * (_resolutions[i][1] - *h)); + if (newdelta < delta) { + best = i; + delta = newdelta; + } + } + *w = _resolutions[best][0]; + *h = _resolutions[best][1]; + return 2; +} + +extern const char _openttd_revision[]; + +static bool CreateMainSurface(int w, int h) +{ + SDL_Surface *newscreen; + char caption[50]; + + GetAvailableVideoMode(&w, &h); + + DEBUG(misc, 1) ("sdl: using mode %dx%d", w, h); + + // DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK + newscreen = SDL_CALL SDL_SetVideoMode(w, h, 8, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); + if (newscreen == NULL) + return false; + + _screen.width = newscreen->w; + _screen.height = newscreen->h; + _screen.pitch = newscreen->pitch; + + _sdl_screen = newscreen; + InitPalette(); + + snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); + SDL_CALL SDL_WM_SetCaption(caption, caption); + SDL_CALL SDL_ShowCursor(0); + + GameSizeChanged(); + + return true; +} + +typedef struct VkMapping { + uint16 vk_from; + byte vk_count; + byte map_to; +} VkMapping; + +#define AS(x, z) {x, 0, z} +#define AM(x, y, z, w) {x, y - x, z} + +static const VkMapping _vk_mapping[] = { + // Pageup stuff + up/down + AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), + AS(SDLK_UP, WKC_UP), + AS(SDLK_DOWN, WKC_DOWN), + AS(SDLK_LEFT, WKC_LEFT), + AS(SDLK_RIGHT, WKC_RIGHT), + + AS(SDLK_HOME, WKC_HOME), + AS(SDLK_END, WKC_END), + + AS(SDLK_INSERT, WKC_INSERT), + AS(SDLK_DELETE, WKC_DELETE), + + // Map letters & digits + AM(SDLK_a, SDLK_z, 'A', 'Z'), + AM(SDLK_0, SDLK_9, '0', '9'), + + AS(SDLK_ESCAPE, WKC_ESC), + AS(SDLK_PAUSE, WKC_PAUSE), + AS(SDLK_BACKSPACE, WKC_BACKSPACE), + + AS(SDLK_SPACE, WKC_SPACE), + AS(SDLK_RETURN, WKC_RETURN), + AS(SDLK_TAB, WKC_TAB), + + // Function keys + AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), + + // Numeric part. + // What is the virtual keycode for numeric enter?? + AM(SDLK_KP0, SDLK_KP9, WKC_NUM_0, WKC_NUM_9), + AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), + AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), + AS(SDLK_KP_MINUS, WKC_NUM_MINUS), + AS(SDLK_KP_PLUS, WKC_NUM_PLUS), + AS(SDLK_KP_ENTER, WKC_NUM_ENTER), + AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL) +}; + +static uint32 ConvertSdlKeyIntoMy(SDL_keysym *sym) +{ + const VkMapping *map; + uint key = 0; + for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { + if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { + key = sym->sym - map->vk_from + map->map_to; + break; + } + } + + // check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) +#if defined(WIN32) || defined(__OS2__) + if (sym->scancode == 41) key |= WKC_BACKQUOTE; +#elif defined(__APPLE__) + if (sym->scancode == 10) key |= WKC_BACKQUOTE; +#elif defined(__MORPHOS__) + if (sym->scancode == 0) key |= WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) +#elif defined(__BEOS__) + if (sym->scancode == 17) key |= WKC_BACKQUOTE; +#elif defined(__SVR4) && defined(__sun) + if (sym->scancode == 60) key |= WKC_BACKQUOTE; + if (sym->scancode == 49) key |= WKC_BACKSPACE; +#elif defined(__sgi__) + if (sym->scancode == 22) key |= WKC_BACKQUOTE; +#else + if (sym->scancode == 41) key |= WKC_BACKQUOTE; // Linux console + if (sym->scancode == 49) key |= WKC_BACKQUOTE; +#endif + + // META are the command keys on mac + if (sym->mod & KMOD_META) key |= WKC_META; + if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; + if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; + if (sym->mod & KMOD_ALT) key |= WKC_ALT; + // these two lines really help porting hotkey combos. Uncomment to use -- Bjarni + //printf("scancode character pressed %d\n", sym->scancode); + //printf("unicode character pressed %d\n", sym->unicode); + return (key << 16) + sym->unicode; +} + +extern void DoExitSave(void); + +static int PollEvent(void) +{ + SDL_Event ev; + + if (!SDL_CALL SDL_PollEvent(&ev)) + return -2; + + switch (ev.type) { + case SDL_MOUSEMOTION: + if (_cursor.fix_at) { + int dx = ev.motion.x - _cursor.pos.x; + int dy = ev.motion.y - _cursor.pos.y; + if (dx != 0 || dy != 0) { + _cursor.delta.x += dx; + _cursor.delta.y += dy; + SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y); + } + } else { + _cursor.delta.x = ev.motion.x - _cursor.pos.x; + _cursor.delta.y = ev.motion.y - _cursor.pos.y; + _cursor.pos.x = ev.motion.x; + _cursor.pos.y = ev.motion.y; + _cursor.dirty = true; + } + break; + + case SDL_MOUSEBUTTONDOWN: + if (_rightclick_emulate && (SDL_CALL SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL))) + ev.button.button = SDL_BUTTON_RIGHT; + + switch (ev.button.button) { + case SDL_BUTTON_LEFT: + _left_button_down = true; + break; + case SDL_BUTTON_RIGHT: + _right_button_down = true; + _right_button_clicked = true; + break; + case SDL_BUTTON_WHEELUP: + _cursor.wheel--; + break; + case SDL_BUTTON_WHEELDOWN: + _cursor.wheel++; + break; + default: + break; + } + break; + + case SDL_MOUSEBUTTONUP: + if (_rightclick_emulate) { + _right_button_down = false; + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_LEFT) { + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_RIGHT) { + _right_button_down = false; + } + break; + + case SDL_QUIT: + // do not ask to quit on the main screen + if (_game_mode != GM_MENU) { + if(_patches.autosave_on_exit) { + DoExitSave(); + return ML_QUIT; + } else + AskExitGame(); + } else + return ML_QUIT; + break; + + case SDL_KEYDOWN: /* Toggle full-screen on ALT + ENTER/F */ + if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) && + (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { + ToggleFullScreen(!_fullscreen); + } else + _pressed_key = ConvertSdlKeyIntoMy(&ev.key.keysym); + + break; + + case SDL_VIDEORESIZE: { + int w = clamp(ev.resize.w, 64, MAX_SCREEN_WIDTH); + int h = clamp(ev.resize.h, 64, MAX_SCREEN_HEIGHT); + ChangeResInGame(w, h); + break; + } + } + return -1; +} + +static const char *SdlVideoStart(const char * const *parm) +{ + char buf[30]; + + const char *s = SdlOpen(SDL_INIT_VIDEO); + if (s != NULL) return s; + + SDL_CALL SDL_VideoDriverName(buf, 30); + DEBUG(misc, 1) ("sdl: using driver '%s'", buf); + + GetVideoModes(); + CreateMainSurface(_cur_resolution[0], _cur_resolution[1]); + MarkWholeScreenDirty(); + + SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_CALL SDL_EnableUNICODE(1); + return NULL; +} + +static void SdlVideoStop(void) +{ + SdlClose(SDL_INIT_VIDEO); +} + +static int SdlVideoMainLoop(void) +{ + uint32 next_tick = SDL_CALL SDL_GetTicks() + 30; + uint32 cur_ticks; + uint32 pal_tick = 0; + int i; + uint32 mod; + int numkeys; + Uint8 *keys; + + for (;;) { + InteractiveRandom(); // randomness + + while ((i = PollEvent()) == -1) {} + if (i >= 0) return i; + + if (_exit_game) return ML_QUIT; + + mod = SDL_CALL SDL_GetModState(); + keys = SDL_CALL SDL_GetKeyState(&numkeys); +#if defined(_DEBUG) + if (_shift_pressed) +#else + if (keys[SDLK_TAB]) +#endif + { + if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; + } else if (_fast_forward & 2) { + _fast_forward = 0; + } + + cur_ticks = SDL_CALL SDL_GetTicks(); + if ((_fast_forward && !_pause) || cur_ticks > next_tick) + next_tick = cur_ticks; + + if (cur_ticks == next_tick) { + next_tick += 30; + + _ctrl_pressed = !!(mod & (KMOD_LCTRL | KMOD_RCTRL)); + _shift_pressed = !!(mod & (KMOD_LSHIFT | KMOD_RSHIFT)); + _dbg_screen_rect = !!(mod & KMOD_CAPS); + + // determine which directional keys are down + _dirkeys = + (keys[SDLK_LEFT] ? 1 : 0) | + (keys[SDLK_UP] ? 2 : 0) | + (keys[SDLK_RIGHT] ? 4 : 0) | + (keys[SDLK_DOWN] ? 8 : 0); + GameLoop(); + + _screen.dst_ptr = _sdl_screen->pixels; + UpdateWindows(); + if (++pal_tick > 4) { + CheckPaletteAnim(); + pal_tick = 1; + } + DrawSurfaceToScreen(); + } else { + SDL_CALL SDL_Delay(1); + _screen.dst_ptr = _sdl_screen->pixels; + DrawTextMessage(); + DrawMouseCursor(); + DrawSurfaceToScreen(); + } + } +} + +static bool SdlVideoChangeRes(int w, int h) +{ + return CreateMainSurface(w, h); +} + +static void SdlVideoFullScreen(bool full_screen) +{ + _fullscreen = full_screen; + GetVideoModes(); // get the list of available video modes + if (!_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1])) + _fullscreen ^= true; // switching resolution failed, put back full_screen to original status +} + +const HalVideoDriver _sdl_video_driver = { + SdlVideoStart, + SdlVideoStop, + SdlVideoMakeDirty, + SdlVideoMainLoop, + SdlVideoChangeRes, + SdlVideoFullScreen, +}; diff --git a/video/sdl.h b/video/sdl.h new file mode 100644 index 000000000..d2e9dae7b --- /dev/null +++ b/video/sdl.h @@ -0,0 +1,8 @@ +#ifndef VIDEO_SDL_H +#define VIDEO_SDL_H + +#include "hal.h" + +extern const HalVideoDriver _sdl_video_driver; + +#endif diff --git a/video/win32.c b/video/win32.c new file mode 100644 index 000000000..d7d21b80b --- /dev/null +++ b/video/win32.c @@ -0,0 +1,800 @@ +#include "stdafx.h" +#include "openttd.h" +#include "functions.h" +#include "gfx.h" +#include "macros.h" +#include "network.h" +#include "variables.h" +#include "window.h" +#include "video/win32.h" +#include <windows.h> + +static struct { + HWND main_wnd; + HBITMAP dib_sect; + Pixel *bitmap_bits; + Pixel *buffer_bits; + Pixel *alloced_bits; + HPALETTE gdi_palette; + int width,height; + int width_org, height_org; + bool cursor_visible; + bool switch_driver; + bool fullscreen; + bool double_size; + bool has_focus; + bool running; +} _wnd; + +static void MakePalette(void) +{ + LOGPALETTE *pal; + uint i; + + pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY)); + + pal->palVersion = 0x300; + pal->palNumEntries = 256; + + for (i = 0; i != 256; i++) { + pal->palPalEntry[i].peRed = _cur_palette[i].r; + pal->palPalEntry[i].peGreen = _cur_palette[i].g; + pal->palPalEntry[i].peBlue = _cur_palette[i].b; + pal->palPalEntry[i].peFlags = 0; + + } + _wnd.gdi_palette = CreatePalette(pal); + if (_wnd.gdi_palette == NULL) + error("CreatePalette failed!\n"); +} + +static void UpdatePalette(HDC dc, uint start, uint count) +{ + RGBQUAD rgb[256]; + uint i; + + for (i = 0; i != count; i++) { + rgb[i].rgbRed = _cur_palette[start + i].r; + rgb[i].rgbGreen = _cur_palette[start + i].g; + rgb[i].rgbBlue = _cur_palette[start + i].b; + rgb[i].rgbReserved = 0; + } + + SetDIBColorTable(dc, start, count, rgb); +} + +bool MyShowCursor(bool show) +{ + if (_wnd.cursor_visible == show) + return show; + + _wnd.cursor_visible = show; + ShowCursor(show); + + return !show; +} + +typedef struct { + byte vk_from; + byte vk_count; + byte map_to; +} VkMapping; + +#define AS(x, z) {x, 0, z} +#define AM(x, y, z, w) {x, y - x, z} + +#ifndef VK_OEM_3 +#define VK_OEM_3 0xC0 +#endif + +static const VkMapping _vk_mapping[] = { + // Pageup stuff + up/down + AM(VK_PRIOR,VK_DOWN, WKC_PAGEUP, WKC_DOWN), + // Map letters & digits + AM('A','Z','A','Z'), + AM('0','9','0','9'), + + AS(VK_ESCAPE, WKC_ESC), + AS(VK_PAUSE, WKC_PAUSE), + AS(VK_BACK, WKC_BACKSPACE), + AM(VK_INSERT,VK_DELETE,WKC_INSERT, WKC_DELETE), + + AS(VK_SPACE, WKC_SPACE), + AS(VK_RETURN, WKC_RETURN), + AS(VK_TAB, WKC_TAB), + + // Function keys + AM(VK_F1, VK_F12, WKC_F1, WKC_F12), + + // Numeric part. + // What is the virtual keycode for numeric enter?? + AM(VK_NUMPAD0,VK_NUMPAD9, WKC_NUM_0, WKC_NUM_9), + AS(VK_DIVIDE, WKC_NUM_DIV), + AS(VK_MULTIPLY, WKC_NUM_MUL), + AS(VK_SUBTRACT, WKC_NUM_MINUS), + AS(VK_ADD, WKC_NUM_PLUS), + AS(VK_DECIMAL, WKC_NUM_DECIMAL) +}; + +static uint MapWindowsKey(uint sym) +{ + const VkMapping *map; + uint key = 0; + + for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { + if ((uint)(sym - map->vk_from) <= map->vk_count) { + key = sym - map->vk_from + map->map_to; + break; + } + } + + if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT; + if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL; + if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT; + return key; +} + +static void MakeWindow(bool full_screen); +static bool AllocateDibSection(int w, int h); + +static void ClientSizeChanged(int w, int h) +{ + if (_wnd.double_size) { + w /= 2; + h /= 2; + } + + // allocate new dib section of the new size + if (AllocateDibSection(w, h)) { + // mark all palette colors dirty + _pal_first_dirty = 0; + _pal_last_dirty = 255; + GameSizeChanged(); + + // redraw screen + if (_wnd.running) { + _screen.dst_ptr = _wnd.buffer_bits; + UpdateWindows(); + } + } +} + +extern void DoExitSave(void); + +#ifdef _DEBUG +// Keep this function here.. +// It allows you to redraw the screen from within the MSVC debugger +int RedrawScreenDebug(void) +{ + HDC dc,dc2; + static int _fooctr; + HBITMAP old_bmp; + HPALETTE old_palette; + + _screen.dst_ptr = _wnd.buffer_bits; + UpdateWindows(); + + dc = GetDC(_wnd.main_wnd); + dc2 = CreateCompatibleDC(dc); + + old_bmp = SelectObject(dc2, _wnd.dib_sect); + old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); + BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); + SelectPalette(dc, old_palette, TRUE); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + ReleaseDC(_wnd.main_wnd, dc); + + return _fooctr++; +} +#endif + +static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_PAINT: { + PAINTSTRUCT ps; + HDC dc,dc2; + HBITMAP old_bmp; + HPALETTE old_palette; + BeginPaint(hwnd, &ps); + dc = ps.hdc; + dc2 = CreateCompatibleDC(dc); + old_bmp = SelectObject(dc2, _wnd.dib_sect); + old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); + + if (_pal_last_dirty != -1) { + UpdatePalette(dc2, _pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1); + _pal_last_dirty = -1; + } + + BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); + SelectPalette(dc, old_palette, TRUE); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + EndPaint(hwnd, &ps); + } + return 0; + + case WM_PALETTECHANGED: + if ((HWND)wParam == hwnd) + return 0; + // FALL THROUGH + case WM_QUERYNEWPALETTE: { + HDC hDC = GetWindowDC(hwnd); + HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE); + UINT nChanged = RealizePalette(hDC); + SelectPalette(hDC, hOldPalette, TRUE); + ReleaseDC(hwnd, hDC); + if (nChanged) + InvalidateRect(hwnd, NULL, FALSE); + return 0; + } + + case WM_CLOSE: + if (_game_mode == GM_MENU) { // do not ask to quit on the main screen + _exit_game = true; + } else if (_patches.autosave_on_exit) { + DoExitSave(); + _exit_game = true; + } else + AskExitGame(); + + return 0; + + case WM_LBUTTONDOWN: + SetCapture(hwnd); + _left_button_down = true; + return 0; + + case WM_LBUTTONUP: + ReleaseCapture(); + _left_button_down = false; + _left_button_clicked = false; + return 0; + + case WM_RBUTTONDOWN: + SetCapture(hwnd); + _right_button_down = true; + _right_button_clicked = true; + return 0; + + case WM_RBUTTONUP: + ReleaseCapture(); + _right_button_down = false; + return 0; + + case WM_MOUSEMOVE: { + int x = (int16)LOWORD(lParam); + int y = (int16)HIWORD(lParam); + POINT pt; + + if (_wnd.double_size) { + x /= 2; + y /= 2; + } + + if (_cursor.fix_at) { + int dx = x - _cursor.pos.x; + int dy = y - _cursor.pos.y; + if (dx != 0 || dy != 0) { + _cursor.delta.x += dx; + _cursor.delta.y += dy; + + pt.x = _cursor.pos.x; + pt.y = _cursor.pos.y; + + if (_wnd.double_size) { + pt.x *= 2; + pt.y *= 2; + } + ClientToScreen(hwnd, &pt); + SetCursorPos(pt.x, pt.y); + } + } else { + _cursor.delta.x += x - _cursor.pos.x; + _cursor.delta.y += y - _cursor.pos.y; + _cursor.pos.x = x; + _cursor.pos.y = y; + _cursor.dirty = true; + } + MyShowCursor(false); + return 0; + } + + case WM_KEYDOWN: { + // this is the rewritten ascii input function + // it disables windows deadkey handling --> more linux like :D + unsigned short w = 0; + int r = 0; + byte ks[256]; + unsigned int scan = 0; + uint16 scancode = (( lParam & 0xFF0000 ) >> 16 ); + + GetKeyboardState(ks); + r = ToAscii(wParam, scan, ks, &w, 0); + if (r == 0) w = 0; // no translation was possible + + _pressed_key = w | MapWindowsKey(wParam) << 16; + + if (scancode == 41) + _pressed_key = w | WKC_BACKQUOTE << 16; + + if ((_pressed_key >> 16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) { + _double_size ^= 1; + _wnd.double_size = _double_size; + ClientSizeChanged(_wnd.width, _wnd.height); + MarkWholeScreenDirty(); + } + } break; + + case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */ + switch (wParam) { + case VK_RETURN: case 0x46: /* Full Screen on ALT + ENTER/F(VK_F) */ + ToggleFullScreen(!_wnd.fullscreen); + return 0; + case VK_MENU: /* Just ALT */ + return 0; // do nothing + case VK_F10: /* F10, ignore activation of menu */ + _pressed_key = MapWindowsKey(wParam) << 16; + return 0; + default: /* ALT in combination with something else */ + _pressed_key = MapWindowsKey(wParam) << 16; + break; + } + break; + case WM_NCMOUSEMOVE: + MyShowCursor(true); + return 0; + + case WM_SIZE: { + if (wParam != SIZE_MINIMIZED) { + ClientSizeChanged(LOWORD(lParam), HIWORD(lParam)); + } + return 0; + } + case WM_SIZING: { + RECT* r = (RECT*)lParam; + RECT r2; + int w, h; + + SetRect(&r2, 0, 0, 0, 0); + AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); + + w = r->right - r->left - (r2.right - r2.left); + h = r->bottom - r->top - (r2.bottom - r2.top); + if (_wnd.double_size) { + w /= 2; + h /= 2; + } + w = clamp(w, 64, MAX_SCREEN_WIDTH); + h = clamp(h, 64, MAX_SCREEN_HEIGHT); + if (_wnd.double_size) { + w *= 2; + h *= 2; + } + SetRect(&r2, 0, 0, w, h); + + AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); + w = r2.right - r2.left; + h = r2.bottom - r2.top; + + switch (wParam) { + case WMSZ_BOTTOM: + r->bottom = r->top + h; + break; + case WMSZ_BOTTOMLEFT: + r->bottom = r->top + h; + r->left = r->right - w; + break; + case WMSZ_BOTTOMRIGHT: + r->bottom = r->top + h; + r->right = r->left + w; + break; + case WMSZ_LEFT: + r->left = r->right - w; + break; + case WMSZ_RIGHT: + r->right = r->left + w; + break; + case WMSZ_TOP: + r->top = r->bottom - h; + break; + case WMSZ_TOPLEFT: + r->top = r->bottom - h; + r->left = r->right - w; + break; + case WMSZ_TOPRIGHT: + r->top = r->bottom - h; + r->right = r->left + w; + break; + } + return TRUE; + } + +// needed for wheel +#if !defined(WM_MOUSEWHEEL) +# define WM_MOUSEWHEEL 0x020A +#endif //WM_MOUSEWHEEL +#if !defined(GET_WHEEL_DELTA_WPARAM) +# define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) +#endif //GET_WHEEL_DELTA_WPARAM + + case WM_MOUSEWHEEL: { + int delta = GET_WHEEL_DELTA_WPARAM(wParam); + + if (delta < 0) { + _cursor.wheel++; + } else if (delta > 0) { + _cursor.wheel--; + } + return 0; + } + + case WM_ACTIVATEAPP: + _wnd.has_focus = (bool)wParam; + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static void RegisterWndClass(void) +{ + static bool registered; + if (!registered) { + HINSTANCE hinst = GetModuleHandle(NULL); + WNDCLASS wnd = { + 0, + WndProcGdi, + 0, + 0, + hinst, + LoadIcon(hinst, MAKEINTRESOURCE(100)), + LoadCursor(NULL, IDC_ARROW), + 0, + 0, + "OTTD" + }; + registered = true; + if (!RegisterClass(&wnd)) + error("RegisterClass failed"); + } +} + +extern const char _openttd_revision[]; + +static void MakeWindow(bool full_screen) +{ + _fullscreen = full_screen; + + _wnd.double_size = _double_size && !full_screen; + + // recreate window? + if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) { + DestroyWindow(_wnd.main_wnd); + _wnd.main_wnd = 0; + } + + if (full_screen) { + DEVMODE settings; + memset(&settings, 0, sizeof(DEVMODE)); + settings.dmSize = sizeof(DEVMODE); + settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + if (_fullscreen_bpp) { + settings.dmBitsPerPel = _fullscreen_bpp; + settings.dmFields |= DM_BITSPERPEL; + } + settings.dmPelsWidth = _wnd.width_org; + settings.dmPelsHeight = _wnd.height_org; + settings.dmDisplayFrequency = _display_hz; + if (settings.dmDisplayFrequency != 0) + settings.dmFields |= DM_DISPLAYFREQUENCY; + if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { + MakeWindow(false); + return; + } + } else if (_wnd.fullscreen) { + // restore display? + ChangeDisplaySettings(NULL, 0); + } + + { + RECT r; + uint style; + int x, y, w, h; + + _wnd.fullscreen = full_screen; + if (_wnd.fullscreen) { + style = WS_POPUP | WS_VISIBLE; + SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org); + } else { + style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + SetRect(&r, 0, 0, _wnd.width, _wnd.height); + } + + AdjustWindowRect(&r, style, FALSE); + w = r.right - r.left; + h = r.bottom - r.top; + x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + + if (_wnd.main_wnd) { + SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); + } else { + char Windowtitle[50]; + + snprintf(Windowtitle, lengthof(Windowtitle), "OpenTTD %s", _openttd_revision); + + _wnd.main_wnd = CreateWindow("OTTD", Windowtitle, style, x, y, w, h, 0, 0, GetModuleHandle(NULL), 0); + if (_wnd.main_wnd == NULL) + error("CreateWindow failed"); + } + } + GameSizeChanged(); // invalidate all windows, force redraw +} + +static bool AllocateDibSection(int w, int h) +{ + BITMAPINFO *bi; + HDC dc; + + w = clamp(w, 64, MAX_SCREEN_WIDTH); + h = clamp(h, 64, MAX_SCREEN_HEIGHT); + + if (w == _screen.width && h == _screen.height) + return false; + + _screen.width = w; + _screen.pitch = (w + 3) & ~0x3; + _screen.height = h; + + if (_wnd.alloced_bits) { + free(_wnd.alloced_bits); + _wnd.alloced_bits = NULL; + } + + bi = alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); + memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + if (_wnd.double_size) { + w = (w + 3) & ~0x3; + _wnd.alloced_bits = _wnd.buffer_bits = malloc(w * h); + w *= 2; + h *= 2; + } + + bi->bmiHeader.biWidth = _wnd.width = w; + bi->bmiHeader.biHeight = -(_wnd.height = h); + + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 8; + bi->bmiHeader.biCompression = BI_RGB; + + if (_wnd.dib_sect) + DeleteObject(_wnd.dib_sect); + + dc = GetDC(0); + _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void**)&_wnd.bitmap_bits, NULL, 0); + if (_wnd.dib_sect == NULL) + error("CreateDIBSection failed"); + ReleaseDC(0, dc); + + if (!_wnd.double_size) + _wnd.buffer_bits = _wnd.bitmap_bits; + + return true; +} + +static const uint16 default_resolutions[][2] = { + { 640, 480}, + { 800, 600}, + {1024, 768}, + {1152, 864}, + {1280, 800}, + {1280, 960}, + {1280, 1024}, + {1400, 1050}, + {1600, 1200}, + {1680, 1050}, + {1920, 1200} +}; + +static void FindResolutions(void) +{ + int i = 0, n = 0; + DEVMODE dm; + + while (EnumDisplaySettings(NULL, i++, &dm) != 0) { + if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) && + IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)){ + int j; + for (j = 0; j < n; j++) { + if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break; + } + + /* In the previous loop we have checked already existing/added resolutions if + * they are the same as the new ones. If this is not the case (j == n); we have + * looped all and found none, add the new one to the list. If we have reached the + * maximum amount of resolutions, then quit querying the display */ + if (j == n) { + _resolutions[j][0] = dm.dmPelsWidth; + _resolutions[j][1] = dm.dmPelsHeight; + if (++n == lengthof(_resolutions)) break; + } + } + } + + /* We have found no resolutions, show the default list */ + if (n == 0) { + memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); + n = lengthof(default_resolutions); + } + + _num_resolutions = n; + SortResolutions(_num_resolutions); +} + + +static const char *Win32GdiStart(const char * const *parm) +{ + memset(&_wnd, 0, sizeof(_wnd)); + _wnd.cursor_visible = true; + + RegisterWndClass(); + + MakePalette(); + + FindResolutions(); + + // fullscreen uses those + _wnd.width_org = _cur_resolution[0]; + _wnd.height_org = _cur_resolution[1]; + + AllocateDibSection(_cur_resolution[0], _cur_resolution[1]); + MarkWholeScreenDirty(); + + MakeWindow(_fullscreen); + + return NULL; +} + +static void Win32GdiStop(void) +{ + if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); + MyShowCursor(true); + DeleteObject(_wnd.gdi_palette); + DeleteObject(_wnd.dib_sect); + DestroyWindow(_wnd.main_wnd); +} + +// simple upscaler by 2 +static void filter(int left, int top, int width, int height) +{ + uint p = _screen.pitch; + const Pixel *s = _wnd.buffer_bits + top * p + left; + Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2; + + for (; height > 0; height--) { + int i; + + for (i = 0; i != width; i++) { + d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i]; + } + s += p; + d += p * 4; + } +} + +static void Win32GdiMakeDirty(int left, int top, int width, int height) +{ + RECT r = { left, top, left + width, top + height }; + + if (_wnd.double_size) { + filter(left, top, width, height); + r.left *= 2; + r.top *= 2; + r.right *= 2; + r.bottom *= 2; + } + InvalidateRect(_wnd.main_wnd, &r, FALSE); +} + +static void CheckPaletteAnim(void) +{ + if (_pal_last_dirty == -1) + return; + InvalidateRect(_wnd.main_wnd, NULL, FALSE); +} + +static int Win32GdiMainLoop(void) +{ + MSG mesg; + uint32 next_tick = GetTickCount() + 30, cur_ticks; + + _wnd.running = true; + + while(true) { + while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) { + InteractiveRandom(); // randomness + TranslateMessage(&mesg); + DispatchMessage(&mesg); + } + if (_exit_game) return ML_QUIT; + if (_wnd.switch_driver) return ML_SWITCHDRIVER; + +#if defined(_DEBUG) + if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) { + if ( +#else + if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0) { + /* Disable speeding up game with ALT+TAB (if syskey is pressed, the + * real key is in the upper 16 bits (see WM_SYSKEYDOWN in WndProcGdi()) */ + if ((_pressed_key >> 16) & WKC_TAB && +#endif + !_networking && _game_mode != GM_MENU) + _fast_forward |= 2; + } else if (_fast_forward & 2) + _fast_forward = 0; + + cur_ticks = GetTickCount(); + if ((_fast_forward && !_pause) || cur_ticks > next_tick) + next_tick = cur_ticks; + + if (cur_ticks == next_tick) { + next_tick += 30; + _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0; + _shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0; + _dbg_screen_rect = _wnd.has_focus && GetAsyncKeyState(VK_CAPITAL)<0; + + // determine which directional keys are down + if (_wnd.has_focus) { + _dirkeys = + (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) + + (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) + + (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) + + (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0); + } else + _dirkeys = 0; + + GameLoop(); + _cursor.delta.x = _cursor.delta.y = 0; + + if (_force_full_redraw) + MarkWholeScreenDirty(); + + GdiFlush(); + _screen.dst_ptr = _wnd.buffer_bits; + UpdateWindows(); + CheckPaletteAnim(); + } else { + Sleep(1); + GdiFlush(); + _screen.dst_ptr = _wnd.buffer_bits; + DrawTextMessage(); + DrawMouseCursor(); + } + } +} + +static bool Win32GdiChangeRes(int w, int h) +{ + _wnd.width = _wnd.width_org = w; + _wnd.height = _wnd.height_org = h; + + MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching + + return true; +} + +static void Win32GdiFullScreen(bool full_screen) {MakeWindow(full_screen);} + +const HalVideoDriver _win32_video_driver = { + Win32GdiStart, + Win32GdiStop, + Win32GdiMakeDirty, + Win32GdiMainLoop, + Win32GdiChangeRes, + Win32GdiFullScreen, +}; diff --git a/video/win32.h b/video/win32.h new file mode 100644 index 000000000..235040c44 --- /dev/null +++ b/video/win32.h @@ -0,0 +1,10 @@ +#ifndef VIDEO_WIN32_H +#define VIDEO_WIN32_H + +#include "hal.h" + +bool MyShowCursor(bool show); + +extern const HalVideoDriver _win32_video_driver; + +#endif @@ -2,1050 +2,37 @@ #include "openttd.h" #include "debug.h" #include "functions.h" +#include "macros.h" #include "saveload.h" #include "string.h" #include "table/strings.h" #include "gfx.h" -#include "mixer.h" #include "window.h" -#include "gui.h" #include <windows.h> -#include <mmsystem.h> -#include "hal.h" #include <winnt.h> #include <wininet.h> #include <io.h> #include <fcntl.h> -#include "network.h" #include "variables.h" -#define SMART_PALETTE_ANIM - -static struct { - HWND main_wnd; - HBITMAP dib_sect; - Pixel *bitmap_bits; - Pixel *buffer_bits; - Pixel *alloced_bits; - HPALETTE gdi_palette; - int width,height; - int width_org, height_org; - bool cursor_visible; - bool switch_driver; - bool fullscreen; - bool double_size; - bool has_focus; - bool running; -} _wnd; - -static HINSTANCE _inst; -static bool _has_console; - -#if defined(__MINGW32__) || defined(__CYGWIN__) - #define __TIMESTAMP__ __DATE__ __TIME__ -#endif - -#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT -extern const HalMusicDriver _dmusic_midi_driver; -#endif - -static void MakePalette(void) -{ - LOGPALETTE *pal; - uint i; - - pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY)); - - pal->palVersion = 0x300; - pal->palNumEntries = 256; - - for (i = 0; i != 256; i++) { - pal->palPalEntry[i].peRed = _cur_palette[i].r; - pal->palPalEntry[i].peGreen = _cur_palette[i].g; - pal->palPalEntry[i].peBlue = _cur_palette[i].b; - pal->palPalEntry[i].peFlags = 0; - - } - _wnd.gdi_palette = CreatePalette(pal); - if (_wnd.gdi_palette == NULL) - error("CreatePalette failed!\n"); -} - -static void UpdatePalette(HDC dc, uint start, uint count) -{ - RGBQUAD rgb[256]; - uint i; - - for (i = 0; i != count; i++) { - rgb[i].rgbRed = _cur_palette[start + i].r; - rgb[i].rgbGreen = _cur_palette[start + i].g; - rgb[i].rgbBlue = _cur_palette[start + i].b; - rgb[i].rgbReserved = 0; - } - - SetDIBColorTable(dc, start, count, rgb); -} - -static bool MyShowCursor(bool show) -{ - if (_wnd.cursor_visible == show) - return show; - - _wnd.cursor_visible = show; - ShowCursor(show); - - return !show; -} - -typedef struct { - byte vk_from; - byte vk_count; - byte map_to; -} VkMapping; - -#define AS(x, z) {x, 0, z} -#define AM(x, y, z, w) {x, y - x, z} - -#ifndef VK_OEM_3 -#define VK_OEM_3 0xC0 -#endif - -static const VkMapping _vk_mapping[] = { - // Pageup stuff + up/down - AM(VK_PRIOR,VK_DOWN, WKC_PAGEUP, WKC_DOWN), - // Map letters & digits - AM('A','Z','A','Z'), - AM('0','9','0','9'), - - AS(VK_ESCAPE, WKC_ESC), - AS(VK_PAUSE, WKC_PAUSE), - AS(VK_BACK, WKC_BACKSPACE), - AM(VK_INSERT,VK_DELETE,WKC_INSERT, WKC_DELETE), - - AS(VK_SPACE, WKC_SPACE), - AS(VK_RETURN, WKC_RETURN), - AS(VK_TAB, WKC_TAB), - - // Function keys - AM(VK_F1, VK_F12, WKC_F1, WKC_F12), - - // Numeric part. - // What is the virtual keycode for numeric enter?? - AM(VK_NUMPAD0,VK_NUMPAD9, WKC_NUM_0, WKC_NUM_9), - AS(VK_DIVIDE, WKC_NUM_DIV), - AS(VK_MULTIPLY, WKC_NUM_MUL), - AS(VK_SUBTRACT, WKC_NUM_MINUS), - AS(VK_ADD, WKC_NUM_PLUS), - AS(VK_DECIMAL, WKC_NUM_DECIMAL) -}; - -static uint MapWindowsKey(uint sym) -{ - const VkMapping *map; - uint key = 0; - - for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { - if ((uint)(sym - map->vk_from) <= map->vk_count) { - key = sym - map->vk_from + map->map_to; - break; - } - } - - if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL; - if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT; - return key; -} - -static void MakeWindow(bool full_screen); -static bool AllocateDibSection(int w, int h); - -static void ClientSizeChanged(int w, int h) -{ - if (_wnd.double_size) { - w /= 2; - h /= 2; - } - - // allocate new dib section of the new size - if (AllocateDibSection(w, h)) { - // mark all palette colors dirty - _pal_first_dirty = 0; - _pal_last_dirty = 255; - GameSizeChanged(); - - // redraw screen - if (_wnd.running) { - _screen.dst_ptr = _wnd.buffer_bits; - UpdateWindows(); - } - } -} - -extern void DoExitSave(void); - -#ifdef _DEBUG -// Keep this function here.. -// It allows you to redraw the screen from within the MSVC debugger -int RedrawScreenDebug() -{ - HDC dc,dc2; - static int _fooctr; - HBITMAP old_bmp; - HPALETTE old_palette; - - _screen.dst_ptr = _wnd.buffer_bits; - UpdateWindows(); - - dc = GetDC(_wnd.main_wnd); - dc2 = CreateCompatibleDC(dc); - - old_bmp = SelectObject(dc2, _wnd.dib_sect); - old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); - BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); - SelectPalette(dc, old_palette, TRUE); - SelectObject(dc2, old_bmp); - DeleteDC(dc2); - ReleaseDC(_wnd.main_wnd, dc); - - return _fooctr++; -} -#endif - -static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_PAINT: { - PAINTSTRUCT ps; - HDC dc,dc2; - HBITMAP old_bmp; - HPALETTE old_palette; - BeginPaint(hwnd, &ps); - dc = ps.hdc; - dc2 = CreateCompatibleDC(dc); - old_bmp = SelectObject(dc2, _wnd.dib_sect); - old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); - - if (_pal_last_dirty != -1) { - UpdatePalette(dc2, _pal_first_dirty, _pal_last_dirty - _pal_first_dirty + 1); - _pal_last_dirty = -1; - } - - BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); - SelectPalette(dc, old_palette, TRUE); - SelectObject(dc2, old_bmp); - DeleteDC(dc2); - EndPaint(hwnd, &ps); - } - return 0; - - case WM_PALETTECHANGED: - if ((HWND)wParam == hwnd) - return 0; - // FALL THROUGH - case WM_QUERYNEWPALETTE: { - HDC hDC = GetWindowDC(hwnd); - HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE); - UINT nChanged = RealizePalette(hDC); - SelectPalette(hDC, hOldPalette, TRUE); - ReleaseDC(hwnd, hDC); - if (nChanged) - InvalidateRect(hwnd, NULL, FALSE); - return 0; - } - - case WM_CLOSE: - if (_game_mode == GM_MENU) { // do not ask to quit on the main screen - _exit_game = true; - } else if (_patches.autosave_on_exit) { - DoExitSave(); - _exit_game = true; - } else - AskExitGame(); - - return 0; - - case WM_LBUTTONDOWN: - SetCapture(hwnd); - _left_button_down = true; - return 0; - - case WM_LBUTTONUP: - ReleaseCapture(); - _left_button_down = false; - _left_button_clicked = false; - return 0; - - case WM_RBUTTONDOWN: - SetCapture(hwnd); - _right_button_down = true; - _right_button_clicked = true; - return 0; - - case WM_RBUTTONUP: - ReleaseCapture(); - _right_button_down = false; - return 0; - - case WM_MOUSEMOVE: { - int x = (int16)LOWORD(lParam); - int y = (int16)HIWORD(lParam); - POINT pt; - - if (_wnd.double_size) { - x /= 2; - y /= 2; - } - - if (_cursor.fix_at) { - int dx = x - _cursor.pos.x; - int dy = y - _cursor.pos.y; - if (dx != 0 || dy != 0) { - _cursor.delta.x += dx; - _cursor.delta.y += dy; - - pt.x = _cursor.pos.x; - pt.y = _cursor.pos.y; - - if (_wnd.double_size) { - pt.x *= 2; - pt.y *= 2; - } - ClientToScreen(hwnd, &pt); - SetCursorPos(pt.x, pt.y); - } - } else { - _cursor.delta.x += x - _cursor.pos.x; - _cursor.delta.y += y - _cursor.pos.y; - _cursor.pos.x = x; - _cursor.pos.y = y; - _cursor.dirty = true; - } - MyShowCursor(false); - return 0; - } - - case WM_KEYDOWN: { - // this is the rewritten ascii input function - // it disables windows deadkey handling --> more linux like :D - unsigned short w = 0; - int r = 0; - byte ks[256]; - unsigned int scan = 0; - uint16 scancode = (( lParam & 0xFF0000 ) >> 16 ); - - GetKeyboardState(ks); - r = ToAscii(wParam, scan, ks, &w, 0); - if (r == 0) w = 0; // no translation was possible - - _pressed_key = w | MapWindowsKey(wParam) << 16; - - if (scancode == 41) - _pressed_key = w | WKC_BACKQUOTE << 16; - - if ((_pressed_key >> 16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) { - _double_size ^= 1; - _wnd.double_size = _double_size; - ClientSizeChanged(_wnd.width, _wnd.height); - MarkWholeScreenDirty(); - } - } break; - - case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */ - switch (wParam) { - case VK_RETURN: case 0x46: /* Full Screen on ALT + ENTER/F(VK_F) */ - ToggleFullScreen(!_wnd.fullscreen); - return 0; - case VK_MENU: /* Just ALT */ - return 0; // do nothing - case VK_F10: /* F10, ignore activation of menu */ - _pressed_key = MapWindowsKey(wParam) << 16; - return 0; - default: /* ALT in combination with something else */ - _pressed_key = MapWindowsKey(wParam) << 16; - break; - } - break; - case WM_NCMOUSEMOVE: - MyShowCursor(true); - return 0; - - case WM_SIZE: { - if (wParam != SIZE_MINIMIZED) { - ClientSizeChanged(LOWORD(lParam), HIWORD(lParam)); - } - return 0; - } - case WM_SIZING: { - RECT* r = (RECT*)lParam; - RECT r2; - int w, h; - - SetRect(&r2, 0, 0, 0, 0); - AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); - - w = r->right - r->left - (r2.right - r2.left); - h = r->bottom - r->top - (r2.bottom - r2.top); - if (_wnd.double_size) { - w /= 2; - h /= 2; - } - w = clamp(w, 64, MAX_SCREEN_WIDTH); - h = clamp(h, 64, MAX_SCREEN_HEIGHT); - if (_wnd.double_size) { - w *= 2; - h *= 2; - } - SetRect(&r2, 0, 0, w, h); - - AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); - w = r2.right - r2.left; - h = r2.bottom - r2.top; - - switch (wParam) { - case WMSZ_BOTTOM: - r->bottom = r->top + h; - break; - case WMSZ_BOTTOMLEFT: - r->bottom = r->top + h; - r->left = r->right - w; - break; - case WMSZ_BOTTOMRIGHT: - r->bottom = r->top + h; - r->right = r->left + w; - break; - case WMSZ_LEFT: - r->left = r->right - w; - break; - case WMSZ_RIGHT: - r->right = r->left + w; - break; - case WMSZ_TOP: - r->top = r->bottom - h; - break; - case WMSZ_TOPLEFT: - r->top = r->bottom - h; - r->left = r->right - w; - break; - case WMSZ_TOPRIGHT: - r->top = r->bottom - h; - r->right = r->left + w; - break; - } - return TRUE; - } +#include "driver.h" -// needed for wheel -#if !defined(WM_MOUSEWHEEL) -# define WM_MOUSEWHEEL 0x020A -#endif //WM_MOUSEWHEEL -#if !defined(GET_WHEEL_DELTA_WPARAM) -# define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) -#endif //GET_WHEEL_DELTA_WPARAM - - case WM_MOUSEWHEEL: { - int delta = GET_WHEEL_DELTA_WPARAM(wParam); - - if (delta < 0) { - _cursor.wheel++; - } else if (delta > 0) { - _cursor.wheel--; - } - return 0; - } - - case WM_ACTIVATEAPP: - _wnd.has_focus = (bool)wParam; - break; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} +#include "music/dmusic.h" +#include "music/null.h" +#include "music/win32.h" -static void RegisterWndClass(void) -{ - static bool registered; - if (!registered) { - HINSTANCE hinst = GetModuleHandle(NULL); - WNDCLASS wnd = { - 0, - WndProcGdi, - 0, - 0, - hinst, - LoadIcon(hinst, MAKEINTRESOURCE(100)), - LoadCursor(NULL, IDC_ARROW), - 0, - 0, - "OTTD" - }; - registered = true; - if (!RegisterClass(&wnd)) - error("RegisterClass failed"); - } -} - -extern const char _openttd_revision[]; - -static void MakeWindow(bool full_screen) -{ - _fullscreen = full_screen; - - _wnd.double_size = _double_size && !full_screen; - - // recreate window? - if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) { - DestroyWindow(_wnd.main_wnd); - _wnd.main_wnd = 0; - } +#include "sound/null.h" +#include "sound/win32.h" - if (full_screen) { - DEVMODE settings; - memset(&settings, 0, sizeof(DEVMODE)); - settings.dmSize = sizeof(DEVMODE); - settings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; +#include "video/null.h" +#include "video/win32.h" - if (_fullscreen_bpp) { - settings.dmBitsPerPel = _fullscreen_bpp; - settings.dmFields |= DM_BITSPERPEL; - } - settings.dmPelsWidth = _wnd.width_org; - settings.dmPelsHeight = _wnd.height_org; - settings.dmDisplayFrequency = _display_hz; - if (settings.dmDisplayFrequency != 0) - settings.dmFields |= DM_DISPLAYFREQUENCY; - if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { - MakeWindow(false); - return; - } - } else if (_wnd.fullscreen) { - // restore display? - ChangeDisplaySettings(NULL, 0); - } - - { - RECT r; - uint style; - int x, y, w, h; - - _wnd.fullscreen = full_screen; - if (_wnd.fullscreen) { - style = WS_POPUP | WS_VISIBLE; - SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org); - } else { - style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; - SetRect(&r, 0, 0, _wnd.width, _wnd.height); - } - - AdjustWindowRect(&r, style, FALSE); - w = r.right - r.left; - h = r.bottom - r.top; - x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; - y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; - - if (_wnd.main_wnd) { - SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); - } else { - char Windowtitle[50]; - - snprintf(Windowtitle, lengthof(Windowtitle), "OpenTTD %s", _openttd_revision); - - _wnd.main_wnd = CreateWindow("OTTD", Windowtitle, style, x, y, w, h, 0, 0, _inst, 0); - if (_wnd.main_wnd == NULL) - error("CreateWindow failed"); - } - } - GameSizeChanged(); // invalidate all windows, force redraw -} - -static bool AllocateDibSection(int w, int h) -{ - BITMAPINFO *bi; - HDC dc; - - w = clamp(w, 64, MAX_SCREEN_WIDTH); - h = clamp(h, 64, MAX_SCREEN_HEIGHT); - - if (w == _screen.width && h == _screen.height) - return false; - - _screen.width = w; - _screen.pitch = (w + 3) & ~0x3; - _screen.height = h; - - if (_wnd.alloced_bits) { - free(_wnd.alloced_bits); - _wnd.alloced_bits = NULL; - } - - bi = alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); - memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); - bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - - if (_wnd.double_size) { - w = (w + 3) & ~0x3; - _wnd.alloced_bits = _wnd.buffer_bits = malloc(w * h); - w *= 2; - h *= 2; - } - - bi->bmiHeader.biWidth = _wnd.width = w; - bi->bmiHeader.biHeight = -(_wnd.height = h); - - bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = 8; - bi->bmiHeader.biCompression = BI_RGB; - - if (_wnd.dib_sect) - DeleteObject(_wnd.dib_sect); - - dc = GetDC(0); - _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void**)&_wnd.bitmap_bits, NULL, 0); - if (_wnd.dib_sect == NULL) - error("CreateDIBSection failed"); - ReleaseDC(0, dc); - - if (!_wnd.double_size) - _wnd.buffer_bits = _wnd.bitmap_bits; - - return true; -} - -static const uint16 default_resolutions[][2] = { - { 640, 480}, - { 800, 600}, - {1024, 768}, - {1152, 864}, - {1280, 800}, - {1280, 960}, - {1280, 1024}, - {1400, 1050}, - {1600, 1200}, - {1680, 1050}, - {1920, 1200} -}; - -static void FindResolutions(void) -{ - int i = 0, n = 0; - DEVMODE dm; - - while (EnumDisplaySettings(NULL, i++, &dm) != 0) { - if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) && - IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)){ - int j; - for (j = 0; j < n; j++) { - if (_resolutions[j][0] == dm.dmPelsWidth && _resolutions[j][1] == dm.dmPelsHeight) break; - } - - /* In the previous loop we have checked already existing/added resolutions if - * they are the same as the new ones. If this is not the case (j == n); we have - * looped all and found none, add the new one to the list. If we have reached the - * maximum amount of resolutions, then quit querying the display */ - if (j == n) { - _resolutions[j][0] = dm.dmPelsWidth; - _resolutions[j][1] = dm.dmPelsHeight; - if (++n == lengthof(_resolutions)) break; - } - } - } - - /* We have found no resolutions, show the default list */ - if (n == 0) { - memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); - n = lengthof(default_resolutions); - } - - _num_resolutions = n; - SortResolutions(_num_resolutions); -} - - -static const char *Win32GdiStart(const char * const *parm) -{ - memset(&_wnd, 0, sizeof(_wnd)); - _wnd.cursor_visible = true; - - RegisterWndClass(); - - MakePalette(); - - FindResolutions(); - - // fullscreen uses those - _wnd.width_org = _cur_resolution[0]; - _wnd.height_org = _cur_resolution[1]; - - AllocateDibSection(_cur_resolution[0], _cur_resolution[1]); - MarkWholeScreenDirty(); - - MakeWindow(_fullscreen); - - return NULL; -} - -static void Win32GdiStop(void) -{ - if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); - MyShowCursor(true); - DeleteObject(_wnd.gdi_palette); - DeleteObject(_wnd.dib_sect); - DestroyWindow(_wnd.main_wnd); -} - -// simple upscaler by 2 -static void filter(int left, int top, int width, int height) -{ - uint p = _screen.pitch; - const Pixel *s = _wnd.buffer_bits + top * p + left; - Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2; - - for (; height > 0; height--) { - int i; - - for (i = 0; i != width; i++) { - d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i]; - } - s += p; - d += p * 4; - } -} - -static void Win32GdiMakeDirty(int left, int top, int width, int height) -{ - RECT r = { left, top, left + width, top + height }; - - if (_wnd.double_size) { - filter(left, top, width, height); - r.left *= 2; - r.top *= 2; - r.right *= 2; - r.bottom *= 2; - } - InvalidateRect(_wnd.main_wnd, &r, FALSE); -} - -static void CheckPaletteAnim(void) -{ - if (_pal_last_dirty == -1) - return; - InvalidateRect(_wnd.main_wnd, NULL, FALSE); -} - -static int Win32GdiMainLoop(void) -{ - MSG mesg; - uint32 next_tick = GetTickCount() + 30, cur_ticks; - - _wnd.running = true; - - while(true) { - while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) { - InteractiveRandom(); // randomness - TranslateMessage(&mesg); - DispatchMessage(&mesg); - } - if (_exit_game) return ML_QUIT; - if (_wnd.switch_driver) return ML_SWITCHDRIVER; +static bool _has_console; -#if defined(_DEBUG) - if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) { - if ( -#else - if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0) { - /* Disable speeding up game with ALT+TAB (if syskey is pressed, the - * real key is in the upper 16 bits (see WM_SYSKEYDOWN in WndProcGdi()) */ - if ((_pressed_key >> 16) & WKC_TAB && +#if defined(__MINGW32__) || defined(__CYGWIN__) + #define __TIMESTAMP__ __DATE__ __TIME__ #endif - !_networking && _game_mode != GM_MENU) - _fast_forward |= 2; - } else if (_fast_forward & 2) - _fast_forward = 0; - - cur_ticks = GetTickCount(); - if ((_fast_forward && !_pause) || cur_ticks > next_tick) - next_tick = cur_ticks; - - if (cur_ticks == next_tick) { - next_tick += 30; - _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0; - _shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0; - _dbg_screen_rect = _wnd.has_focus && GetAsyncKeyState(VK_CAPITAL)<0; - - // determine which directional keys are down - if (_wnd.has_focus) { - _dirkeys = - (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) + - (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) + - (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) + - (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0); - } else - _dirkeys = 0; - - GameLoop(); - _cursor.delta.x = _cursor.delta.y = 0; - - if (_force_full_redraw) - MarkWholeScreenDirty(); - - GdiFlush(); - _screen.dst_ptr = _wnd.buffer_bits; - UpdateWindows(); - CheckPaletteAnim(); - } else { - Sleep(1); - GdiFlush(); - _screen.dst_ptr = _wnd.buffer_bits; - DrawTextMessage(); - DrawMouseCursor(); - } - } -} - -static bool Win32GdiChangeRes(int w, int h) -{ - _wnd.width = _wnd.width_org = w; - _wnd.height = _wnd.height_org = h; - - MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching - return true; -} - -static void Win32GdiFullScreen(bool full_screen) {MakeWindow(full_screen);} - -const HalVideoDriver _win32_video_driver = { - Win32GdiStart, - Win32GdiStop, - Win32GdiMakeDirty, - Win32GdiMainLoop, - Win32GdiChangeRes, - Win32GdiFullScreen, -}; - - -/********************** - * WIN32 MIDI PLAYER - **********************/ - -static struct { - bool stop_song; - bool terminate; - bool playing; - int new_vol; - HANDLE wait_obj; - char start_song[260]; -} _midi; - -static void Win32MidiPlaySong(const char *filename) -{ - strcpy(_midi.start_song, filename); - _midi.playing = true; - _midi.stop_song = false; - SetEvent(_midi.wait_obj); -} - -static void Win32MidiStopSong(void) -{ - if (_midi.playing) { - _midi.stop_song = true; - _midi.start_song[0] = '\0'; - SetEvent(_midi.wait_obj); - } -} - -static bool Win32MidiIsSongPlaying(void) -{ - return _midi.playing; -} - -static void Win32MidiSetVolume(byte vol) -{ - _midi.new_vol = vol; - SetEvent(_midi.wait_obj); -} - -static long CDECL MidiSendCommand(const char *cmd, ...) { - va_list va; - char buf[512]; - - va_start(va, cmd); - vsprintf(buf, cmd, va); - va_end(va); - return mciSendStringA(buf, NULL, 0, 0); -} - -static bool MidiIntPlaySong(const char *filename) -{ - MidiSendCommand("close all"); - if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0) - return false; - - if (MidiSendCommand("play song from 0") != 0) - return false; - return true; -} - -static void MidiIntStopSong(void) -{ - MidiSendCommand("close all"); -} - -static void MidiIntSetVolume(int vol) -{ - uint v = (vol * 65535 / 127); - midiOutSetVolume((HMIDIOUT)-1, v + (v << 16)); -} - -static bool MidiIntIsSongPlaying(void) -{ - char buf[16]; - mciSendStringA("status song mode", buf, sizeof(buf), 0); - return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; -} - -static DWORD WINAPI MidiThread(LPVOID arg) -{ - _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); - - do { - char *s; - int vol; - - vol = _midi.new_vol; - if (vol != -1) { - _midi.new_vol = -1; - MidiIntSetVolume(vol); - } - - s = _midi.start_song; - if (s[0] != '\0') { - _midi.playing = MidiIntPlaySong(s); - s[0] = '\0'; - - // Delay somewhat in case we don't manage to play. - if (!_midi.playing) { - Sleep(5000); - } - } - - if (_midi.stop_song && _midi.playing) { - _midi.stop_song = false; - _midi.playing = false; - MidiIntStopSong(); - } - - if (_midi.playing && !MidiIntIsSongPlaying()) - _midi.playing = false; - - WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); - } while (!_midi.terminate); - - DeleteObject(_midi.wait_obj); - return 0; -} - -static const char *Win32MidiStart(const char * const *parm) -{ - DWORD threadId; - - memset(&_midi, 0, sizeof(_midi)); - _midi.new_vol = -1; - CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId); - return 0; -} - -static void Win32MidiStop(void) -{ - _midi.terminate = true; - SetEvent(_midi.wait_obj); -} - -const HalMusicDriver _win32_music_driver = { - Win32MidiStart, - Win32MidiStop, - Win32MidiPlaySong, - Win32MidiStopSong, - Win32MidiIsSongPlaying, - Win32MidiSetVolume, -}; - -// WIN32 Sound code. - -static HWAVEOUT _waveout; -static WAVEHDR _wave_hdr[2]; -static int _bufsize; -static void PrepareHeader(WAVEHDR *hdr) -{ - hdr->dwBufferLength = _bufsize * 4; - hdr->dwFlags = 0; - hdr->lpData = malloc(_bufsize * 4); - if (hdr->lpData == NULL || - waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) - error("waveOutPrepareHeader failed"); -} - -static void FillHeaders(void) -{ - WAVEHDR *hdr; - - for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) { - if (!(hdr->dwFlags & WHDR_INQUEUE)) { - MxMixSamples(_mixer, hdr->lpData, hdr->dwBufferLength / 4); - if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) - error("waveOutWrite failed"); - } - } -} - -static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2) -{ - switch (uMsg) { - case WOM_DONE: - if (_waveout) FillHeaders(); - break; - - default: - break; - } -} - -static const char *Win32SoundStart(const char * const *parm) -{ - WAVEFORMATEX wfex; - int hz; - - _bufsize = GetDriverParamInt(parm, "bufsize", 1024); - hz = GetDriverParamInt(parm, "hz", 11025); - wfex.wFormatTag = WAVE_FORMAT_PCM; - wfex.nChannels = 2; - wfex.nSamplesPerSec = hz; - wfex.nAvgBytesPerSec = hz*2*2; - wfex.nBlockAlign = 4; - wfex.wBitsPerSample = 16; - if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD)&waveOutProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) - return "waveOutOpen failed"; - PrepareHeader(&_wave_hdr[0]); - PrepareHeader(&_wave_hdr[1]); - FillHeaders(); - return NULL; -} - -static void Win32SoundStop(void) -{ - HWAVEOUT waveout = _waveout; - - _waveout = NULL; - waveOutReset(waveout); - waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR)); - waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR)); - waveOutClose(waveout); -} - -const HalSoundDriver _win32_sound_driver = { - Win32SoundStart, - Win32SoundStop, -}; // Helper function needed by dynamically loading SDL bool LoadLibraryList(void **proc, const char *dll) @@ -2092,7 +1079,7 @@ void CreateConsole(void) SetConsoleScreenBufferSize(hand, coninfo.dwSize); // redirect unbuffered STDIN, STDOUT, STDERR to the console -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && 0 *stdout = *_fdopen( _open_osfhandle((long)hand, _O_TEXT), "w" ); *stdin = *_fdopen(_open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" ); *stderr = *_fdopen(_open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" ); @@ -2132,7 +1119,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, { int argc; char *argv[64]; // max 64 command line arguments - _inst = hInstance; #if defined(_DEBUG) CreateConsole(); |