aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS12
-rw-r--r--NEWS2
-rw-r--r--README3
-rw-r--r--audio/mididrv.cpp15
-rw-r--r--backends/fs/ds/ds-fs-factory.cpp2
-rw-r--r--backends/fs/ps2/ps2-fs-factory.cpp2
-rw-r--r--backends/fs/psp/psp-fs-factory.cpp2
-rw-r--r--backends/fs/wii/wii-fs-factory.cpp2
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.cpp6
-rw-r--r--backends/platform/ps2/systemps2.cpp4
-rw-r--r--backends/platform/psp/display_manager.cpp2
-rw-r--r--backends/platform/psp/powerman.cpp2
-rw-r--r--backends/platform/psp/rtc.cpp2
-rw-r--r--backends/platform/sdl/win32/win32.cpp60
-rw-r--r--backends/platform/sdl/win32/win32.h1
-rw-r--r--backends/platform/wince/README-WinCE.txt20
-rw-r--r--backends/plugins/elf/memory-manager.cpp2
-rw-r--r--backends/plugins/elf/shorts-segment-manager.cpp2
-rw-r--r--backends/taskbar/win32/win32-taskbar.cpp122
-rw-r--r--backends/taskbar/win32/win32-taskbar.h5
-rw-r--r--base/commandLine.cpp23
-rw-r--r--base/plugins.cpp4
-rw-r--r--common/EventRecorder.cpp4
-rw-r--r--common/archive.cpp4
-rw-r--r--common/config-manager.cpp4
-rw-r--r--common/debug.cpp5
-rw-r--r--common/hashmap.h11
-rw-r--r--common/singleton.h6
-rw-r--r--common/system.h4
-rw-r--r--common/translation.cpp4
-rw-r--r--common/xmlparser.h1
-rwxr-xr-xconfigure7
-rw-r--r--devtools/convbdf.c6
-rw-r--r--devtools/create_project/scripts/installer.vbs5
-rw-r--r--devtools/create_project/scripts/postbuild.cmd18
-rwxr-xr-xdevtools/credits.pl12
-rwxr-xr-xdevtools/update-version.pl2
-rw-r--r--dists/scummvm.rc7
-rw-r--r--dists/scummvm.rc.in7
-rw-r--r--dists/win32/ScummVM.iss10
-rw-r--r--dists/win32/graphics/left.bmp (renamed from dists/nsis/graphics/left.bmp)bin154542 -> 154542 bytes
-rw-r--r--dists/win32/graphics/scummvm-install.ico (renamed from dists/nsis/graphics/scummvm-install.ico)bin77799 -> 77799 bytes
-rw-r--r--dists/win32/plugins/Games.dllbin0 -> 105472 bytes
-rw-r--r--dists/win32/scummvm.gdf.xml44
-rw-r--r--dists/win32/scummvm.nsi (renamed from dists/nsis/scummvm.nsi)147
-rw-r--r--dists/win32/scummvm.nsi.in (renamed from dists/nsis/scummvm.nsi.in)147
-rw-r--r--engines/agi/preagi_winnie.cpp81
-rw-r--r--engines/cine/various.cpp5
-rw-r--r--engines/cruise/cruise_main.cpp10
-rw-r--r--engines/cruise/mainDraw.cpp8
-rw-r--r--engines/cruise/script.cpp4
-rw-r--r--engines/dreamweb/detection.cpp2
-rw-r--r--engines/dreamweb/detection_tables.h35
-rw-r--r--engines/engine.cpp2
-rw-r--r--engines/groovie/saveload.cpp4
-rw-r--r--engines/groovie/script.cpp6
-rw-r--r--engines/kyra/debugger.cpp4
-rw-r--r--engines/kyra/gui_lok.cpp14
-rw-r--r--engines/kyra/gui_lol.cpp10
-rw-r--r--engines/kyra/gui_v2.cpp9
-rw-r--r--engines/kyra/kyra_v1.cpp4
-rw-r--r--engines/kyra/screen.cpp2
-rw-r--r--engines/kyra/sound.cpp4
-rw-r--r--engines/kyra/sound.h2
-rw-r--r--engines/kyra/sound_midi.cpp3
-rw-r--r--engines/lastexpress/data/snd.cpp389
-rw-r--r--engines/lastexpress/data/snd.h14
-rw-r--r--engines/lastexpress/resource.h2
-rw-r--r--engines/lastexpress/shared.h21
-rw-r--r--engines/lastexpress/sound/entry.cpp159
-rw-r--r--engines/lastexpress/sound/entry.h60
-rw-r--r--engines/lastexpress/sound/queue.cpp515
-rw-r--r--engines/lastexpress/sound/queue.h10
-rw-r--r--engines/lastexpress/sound/sound.cpp6
-rw-r--r--engines/lastexpress/sound/sound.h12
-rw-r--r--engines/lure/disk.cpp3
-rw-r--r--engines/lure/hotspots.cpp3
-rw-r--r--engines/lure/sound.cpp2
-rw-r--r--engines/made/detection.cpp4
-rw-r--r--engines/mohawk/console.cpp21
-rw-r--r--engines/mohawk/cursors.cpp11
-rw-r--r--engines/mohawk/cursors.h2
-rw-r--r--engines/mohawk/detection_tables.h15
-rw-r--r--engines/mohawk/livingbooks.cpp261
-rw-r--r--engines/mohawk/livingbooks.h3
-rw-r--r--engines/mohawk/livingbooks_code.cpp491
-rw-r--r--engines/mohawk/livingbooks_code.h12
-rw-r--r--engines/mohawk/myst_scripts.cpp1
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp20
-rw-r--r--engines/mohawk/resource.cpp3
-rw-r--r--engines/mohawk/sound.cpp13
-rw-r--r--engines/parallaction/graphics.h1
-rw-r--r--engines/savestate.cpp43
-rw-r--r--engines/savestate.h165
-rw-r--r--engines/sci/engine/kstring.cpp6
-rw-r--r--engines/sci/graphics/screen.cpp2
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/imuse/instrument.h1
-rw-r--r--engines/scumm/imuse_digi/dimuse_codecs.cpp2
-rw-r--r--engines/sword2/controls.cpp2
-rw-r--r--engines/sword2/render.cpp10
-rw-r--r--engines/sword25/gfx/animationtemplateregistry.cpp2
-rw-r--r--engines/sword25/gfx/graphicengine.cpp2
-rw-r--r--engines/sword25/gfx/image/art.cpp2
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp5
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp3
-rw-r--r--engines/sword25/kernel/inputpersistenceblock.cpp5
-rw-r--r--engines/sword25/kernel/inputpersistenceblock.h6
-rw-r--r--engines/sword25/kernel/persistenceservice.cpp30
-rw-r--r--engines/sword25/kernel/persistenceservice.h1
-rw-r--r--engines/sword25/math/regionregistry.cpp2
-rw-r--r--engines/sword25/sfx/soundengine.cpp75
-rw-r--r--engines/sword25/sfx/soundengine.h11
-rw-r--r--engines/sword25/sword25.cpp2
-rw-r--r--engines/testbed/config-params.cpp2
-rw-r--r--engines/tsage/ringworld_scenes1.cpp8
-rw-r--r--engines/tsage/saveload.cpp13
-rw-r--r--engines/tsage/saveload.h1
-rw-r--r--engines/tsage/sound.cpp319
-rw-r--r--engines/tsage/sound.h47
-rw-r--r--graphics/cursorman.cpp2
-rw-r--r--graphics/font.cpp766
-rw-r--r--graphics/font.h63
-rw-r--r--graphics/fontman.cpp6
-rw-r--r--graphics/fonts/bdf.cpp796
-rw-r--r--graphics/fonts/bdf.h100
-rw-r--r--graphics/fonts/consolefont.cpp4
-rw-r--r--graphics/fonts/newfont.cpp4
-rw-r--r--graphics/fonts/newfont_big.cpp4
-rw-r--r--graphics/module.mk1
-rw-r--r--graphics/sjis.cpp377
-rw-r--r--graphics/sjis.h44
-rw-r--r--graphics/yuv_to_rgb.cpp2
-rw-r--r--gui/ThemeEngine.cpp11
-rw-r--r--gui/credits.h6
-rw-r--r--gui/debugger.h1
-rw-r--r--gui/gui-manager.cpp2
-rw-r--r--gui/saveload.cpp35
-rw-r--r--icons/count.icobin0 -> 1150 bytes
-rw-r--r--ports.mk55
-rw-r--r--video/codecs/cdtoons.cpp1
142 files changed, 3556 insertions, 2507 deletions
diff --git a/.gitignore b/.gitignore
index 4ad9f07b34..99902064ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ lib*.a
/Icon.*
/build
+/staging
/backends/platform/dc/gui
/backends/platform/dc/graphics
diff --git a/AUTHORS b/AUTHORS
index e998390a12..d7b16e3d3b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,7 +19,7 @@ ScummVM Team
Jonathan Gray - (retired)
Vincent Hamm - (retired)
Max Horn - (retired)
- Travis Howell - (retired)
+ Travis Howell
Pawel Kolodziejski - Codecs, iMUSE, Smush, etc.
Gregory Montoir
Eugene Sandulenko - FT INSANE, MM NES, MM C64, game detection,
@@ -28,7 +28,7 @@ ScummVM Team
HE:
Jonathan Gray - (retired)
- Travis Howell - (retired)
+ Travis Howell
Gregory Montoir
Eugene Sandulenko
@@ -37,7 +37,7 @@ ScummVM Team
Matthew Hoops
Filippos Karapetis
Pawel Kolodziejski
- Walter van Niftrik
+ Walter van Niftrik - (retired)
Kari Salminen
Eugene Sandulenko
David Symonds - (retired)
@@ -45,7 +45,7 @@ ScummVM Team
AGOS:
Torbjorn Andersson
Paul Gilbert
- Travis Howell - (retired)
+ Travis Howell
Oliver Kiehl - (retired)
Ludvig Strigeus - (retired)
@@ -141,7 +141,7 @@ ScummVM Team
Max Horn - (retired)
Filippos Karapetis
Martin Kiewitz
- Walter van Niftrik
+ Walter van Niftrik - (retired)
Willem Jan Palenstijn
Jordi Vilalta Prat
Lars Skovlund
@@ -361,7 +361,7 @@ Other contributions
Markus Strangl
Win32:
- Travis Howell - (retired)
+ Travis Howell
Win64:
Chris Gray - (retired)
diff --git a/NEWS b/NEWS
index 9be9b252ca..9f1e7c698e 100644
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,7 @@ For a more comprehensive changelog of the latest experimental code, see:
SDL ports:
- Added support for OpenGL (GSoC Task).
-1.3.1 (????-??-??)
+1.3.1 (2011-07-12)
General:
- Improved audio device detection and fallback.
There should be no more silent errors due to invalid audio devices.
diff --git a/README b/README
index e13a8c9a01..48929816fd 100644
--- a/README
+++ b/README
@@ -219,6 +219,7 @@ AGI Games by Sierra:
AGOS Games by Adventuresoft/Horrorsoft:
Elvira - Mistress of the Dark [elvira1]
Elvira II - The Jaws of Cerberus [elvira2]
+ Personal Nightmare [pn]
Waxworks [waxworks]
Simon the Sorcerer 1 [simon1]
Simon the Sorcerer 2 [simon2]
@@ -942,6 +943,7 @@ arguments -- see the next section.
-z, --list-games Display list of supported games and exit
-t, --list-targets Display list of configured targets and exit
--list-saves=TARGET Display a list of savegames for the game (TARGET) specified
+ --console Enable the console window (default: enabled) (Windows only)
-c, --config=CONFIG Use alternate configuration file
-p, --path=PATH Path to where the game is installed
@@ -1974,6 +1976,7 @@ The following keywords are recognized:
confirm_exit bool Ask for confirmation by the user before quitting
(SDL backend only).
+ console bool Enable the console window (default: enabled) (Windows only).
cdrom number Number of CD-ROM unit to use for audio. If
negative, don't even try to access the CD-ROM.
joystick_num number Number of joystick device to use for input
diff --git a/audio/mididrv.cpp b/audio/mididrv.cpp
index b71c02f991..27f02c9053 100644
--- a/audio/mididrv.cpp
+++ b/audio/mididrv.cpp
@@ -128,7 +128,8 @@ Common::String MidiDriver::getDeviceString(DeviceHandle handle, DeviceStringType
MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
// Query the selected music device (defaults to MT_AUTO device).
- DeviceHandle hdl = getDeviceHandle(ConfMan.get("music_driver"));
+ Common::String selDevStr = ConfMan.hasKey("music_driver") ? ConfMan.get("music_driver") : Common::String("auto");
+ DeviceHandle hdl = getDeviceHandle(selDevStr.empty() ? Common::String("auto") : selDevStr);
DeviceHandle reslt = 0;
_forceTypeMT32 = false;
@@ -200,7 +201,7 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
if (getMusicType(hdl) == MT_INVALID) {
// If the expressly selected driver or device cannot be found (no longer compiled in, turned off, etc.)
// we display a warning and continue.
- failedDevStr = ConfMan.get("music_driver");
+ failedDevStr = selDevStr;
Common::String warningMsg = Common::String::format(_("The selected audio device '%s' was not found (e.g. might be turned off or disconnected). Attempting to fall back to the next available device..."), failedDevStr.c_str());
GUI::MessageDialog dialog(warningMsg);
dialog.runModal();
@@ -230,13 +231,15 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
// If a preferred MT32 or GM device has been selected that device gets returned if available.
Common::String devStr;
if (flags & MDT_PREFER_MT32)
- devStr = ConfMan.get("mt32_device");
+ devStr = ConfMan.hasKey("mt32_device") ? ConfMan.get("mt32_device") : Common::String("null");
else if (flags & MDT_PREFER_GM)
- devStr = ConfMan.get("gm_device");
+ devStr = ConfMan.hasKey("gm_device") ? ConfMan.get("gm_device") : Common::String("null");
else
devStr = "auto";
-
- hdl = getDeviceHandle(devStr);
+
+ // Default to Null device here, since we also register a default null setting for
+ // the MT32 or GM device in the config manager.
+ hdl = getDeviceHandle(devStr.empty() ? Common::String("null") : devStr);
const MusicType type = getMusicType(hdl);
// If we have a "Don't use GM/MT-32" setting we skip this part and jump
diff --git a/backends/fs/ds/ds-fs-factory.cpp b/backends/fs/ds/ds-fs-factory.cpp
index 3fd97d07eb..4e09c3446b 100644
--- a/backends/fs/ds/ds-fs-factory.cpp
+++ b/backends/fs/ds/ds-fs-factory.cpp
@@ -27,7 +27,9 @@
#include "backends/fs/ds/ds-fs.h"
#include "dsmain.h" //for the isGBAMPAvailable() function
+namespace Common {
DECLARE_SINGLETON(DSFilesystemFactory);
+}
AbstractFSNode *DSFilesystemFactory::makeRootFileNode() const {
if (DS::isGBAMPAvailable()) {
diff --git a/backends/fs/ps2/ps2-fs-factory.cpp b/backends/fs/ps2/ps2-fs-factory.cpp
index cad92b5dec..ef7b2013a3 100644
--- a/backends/fs/ps2/ps2-fs-factory.cpp
+++ b/backends/fs/ps2/ps2-fs-factory.cpp
@@ -27,7 +27,9 @@
#include "backends/fs/ps2/ps2-fs-factory.h"
#include "backends/fs/ps2/ps2-fs.h"
+namespace Common {
DECLARE_SINGLETON(Ps2FilesystemFactory);
+}
AbstractFSNode *Ps2FilesystemFactory::makeRootFileNode() const {
return new Ps2FilesystemNode();
diff --git a/backends/fs/psp/psp-fs-factory.cpp b/backends/fs/psp/psp-fs-factory.cpp
index ef1df246ba..bb3aca8ee6 100644
--- a/backends/fs/psp/psp-fs-factory.cpp
+++ b/backends/fs/psp/psp-fs-factory.cpp
@@ -43,7 +43,9 @@
#include <unistd.h>
+namespace Common {
DECLARE_SINGLETON(PSPFilesystemFactory);
+}
AbstractFSNode *PSPFilesystemFactory::makeRootFileNode() const {
return new PSPFilesystemNode();
diff --git a/backends/fs/wii/wii-fs-factory.cpp b/backends/fs/wii/wii-fs-factory.cpp
index 34cde8ef46..fbc9ef1da8 100644
--- a/backends/fs/wii/wii-fs-factory.cpp
+++ b/backends/fs/wii/wii-fs-factory.cpp
@@ -40,7 +40,9 @@
#include <smb.h>
#endif
+namespace Common {
DECLARE_SINGLETON(WiiFilesystemFactory);
+}
WiiFilesystemFactory::WiiFilesystemFactory() :
_dvdMounted(false),
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index 66207b6808..2d41ecead4 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -752,6 +752,12 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
error("allocating _screen failed");
#endif
+ // SDL 1.2 palettes default to all black,
+ // SDL 1.3 palettes default to all white,
+ // Thus set our own default palette to all black.
+ // SDL_SetColors does nothing for non indexed surfaces.
+ SDL_SetColors(_screen, _currentPalette, 0, 256);
+
//
// Create the surface that contains the scaled graphics in 16 bit mode
//
diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp
index d3acd06089..c75d7493a2 100644
--- a/backends/platform/ps2/systemps2.cpp
+++ b/backends/platform/ps2/systemps2.cpp
@@ -66,7 +66,7 @@
#include "engines/engine.h"
-#include "graphics/font.h"
+#include "graphics/fonts/bdf.h"
#include "graphics/surface.h"
#include "icon.h"
@@ -96,7 +96,7 @@ OSystem_PS2 *g_systemPs2;
#define FOREVER 2147483647
namespace Graphics {
- extern const NewFont g_sysfont;
+ extern const BdfFont g_sysfont;
};
PS2Device detectBootPath(const char *elfPath, char *bootPath);
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index e945dca4a8..422805714f 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -62,7 +62,9 @@ const OSystem::GraphicsMode DisplayManager::_supportedModes[] = {
// Class VramAllocator -----------------------------------
+namespace Common {
DECLARE_SINGLETON(VramAllocator);
+}
//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
//#define __PSP_DEBUG_PRINT__
diff --git a/backends/platform/psp/powerman.cpp b/backends/platform/psp/powerman.cpp
index fe9dcfa673..b72d05809d 100644
--- a/backends/platform/psp/powerman.cpp
+++ b/backends/platform/psp/powerman.cpp
@@ -30,7 +30,9 @@
//#define __PSP_DEBUG_PRINT__
#include "backends/platform/psp/trace.h"
+namespace Common {
DECLARE_SINGLETON(PowerManager);
+}
// Function to debug the Power Manager (we have no output to screen)
inline void PowerManager::debugPM() {
diff --git a/backends/platform/psp/rtc.cpp b/backends/platform/psp/rtc.cpp
index 3d6d4295a6..6c8e919986 100644
--- a/backends/platform/psp/rtc.cpp
+++ b/backends/platform/psp/rtc.cpp
@@ -34,7 +34,9 @@
// Class PspRtc ---------------------------------------------------------------
+namespace Common {
DECLARE_SINGLETON(PspRtc);
+}
void PspRtc::init() { // init our starting ticks
uint32 ticks[2];
diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp
index 420ed2465b..c1b6c853e4 100644
--- a/backends/platform/sdl/win32/win32.cpp
+++ b/backends/platform/sdl/win32/win32.cpp
@@ -24,6 +24,7 @@
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/scummsys.h"
+#include "common/config-manager.h"
#include "common/error.h"
#include "common/textconsole.h"
@@ -44,46 +45,7 @@
#define DEFAULT_CONFIG_FILE "scummvm.ini"
-//#define HIDE_CONSOLE
-
-#ifdef HIDE_CONSOLE
-struct SdlConsoleHidingWin32 {
- DWORD myPid;
- DWORD myTid;
- HWND consoleHandle;
-};
-
-// console hiding for win32
-static BOOL CALLBACK initBackendFindConsoleWin32Proc(HWND hWnd, LPARAM lParam) {
- DWORD pid, tid;
- SdlConsoleHidingWin32 *variables = (SdlConsoleHidingWin32 *)lParam;
- tid = GetWindowThreadProcessId(hWnd, &pid);
- if ((tid == variables->myTid) && (pid == variables->myPid)) {
- variables->consoleHandle = hWnd;
- return FALSE;
- }
- return TRUE;
-}
-
-#endif
-
void OSystem_Win32::init() {
-#ifdef HIDE_CONSOLE
- // console hiding for win32
- SdlConsoleHidingWin32 consoleHidingWin32;
- consoleHidingWin32.consoleHandle = 0;
- consoleHidingWin32.myPid = GetCurrentProcessId();
- consoleHidingWin32.myTid = GetCurrentThreadId();
- EnumWindows (initBackendFindConsoleWin32Proc, (LPARAM)&consoleHidingWin32);
-
- if (!ConfMan.getBool("show_console")) {
- if (consoleHidingWin32.consoleHandle) {
- // We won't find a window with our TID/PID in case we were started from command-line
- ShowWindow(consoleHidingWin32.consoleHandle, SW_HIDE);
- }
- }
-#endif
-
// Initialize File System Factory
_fsFactory = new WindowsFilesystemFactory();
@@ -96,6 +58,26 @@ void OSystem_Win32::init() {
OSystem_SDL::init();
}
+void OSystem_Win32::initBackend() {
+ // Console window is enabled by default on Windows
+ ConfMan.registerDefault("console", true);
+
+ // Enable or disable the window console window
+ if (ConfMan.getBool("console")) {
+ if (AllocConsole()) {
+ freopen("CONIN$","r",stdin);
+ freopen("CONOUT$","w",stdout);
+ freopen("CONOUT$","w",stderr);
+ }
+ SetConsoleTitle("ScummVM Status Window");
+ } else {
+ FreeConsole();
+ }
+
+ // Invoke parent implementation of this method
+ OSystem_SDL::initBackend();
+}
+
bool OSystem_Win32::hasFeature(Feature f) {
if (f == kFeatureDisplayLogFile)
diff --git a/backends/platform/sdl/win32/win32.h b/backends/platform/sdl/win32/win32.h
index cc2fc51d36..b56997a63b 100644
--- a/backends/platform/sdl/win32/win32.h
+++ b/backends/platform/sdl/win32/win32.h
@@ -28,6 +28,7 @@
class OSystem_Win32 : public OSystem_SDL {
public:
virtual void init();
+ virtual void initBackend();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
diff --git a/backends/platform/wince/README-WinCE.txt b/backends/platform/wince/README-WinCE.txt
index c48d9ca998..8f1262051a 100644
--- a/backends/platform/wince/README-WinCE.txt
+++ b/backends/platform/wince/README-WinCE.txt
@@ -1,10 +1,26 @@
ScummVM Windows CE FAQ
-Last updated: 2011-05-27
-Release version: 1.3.0
+Last updated: 2011-07-01
+Release version: 1.3.1
------------------------------------------------------------------------
New in this version
-------------------
+1.3.1:
+- Fix for Normal2xAspect scaler which was causing screen update issues in some
+ games.
+- Fix for Normal1xAspect scaler which caused problems in the bottom part of the
+ screen when toolbar was hidden.
+- Fix for freelook mode.
+- Fix for timer manager, caused timing issues in some games.
+- Activated runtime language detection for ScummVM gui.
+- Toolbar is now hidden when returning to the game list.
+- Double-tap right-click emulation is now turned off for SCI games by default.
+- Added a new option "no_doubletap_paneltoggle" for scummvm.ini to disable
+ toolbar toggling when double-tapping on the top part of the screen.
+- SDL library related fixes:
+ * Fix for screen/mouse-cursor rotation issues (fixes erratic touchscreen
+ behaviour)
+ * Fix for hardware keyboard on some devices (HTC Touch Pro, etc.)
1.3.0:
This is the first official Windows CE release since 1.1.1.
diff --git a/backends/plugins/elf/memory-manager.cpp b/backends/plugins/elf/memory-manager.cpp
index 02669b3647..058d818dc4 100644
--- a/backends/plugins/elf/memory-manager.cpp
+++ b/backends/plugins/elf/memory-manager.cpp
@@ -29,7 +29,9 @@
#include "common/util.h"
#include <malloc.h>
+namespace Common {
DECLARE_SINGLETON(ELFMemoryManager);
+}
ELFMemoryManager::ELFMemoryManager() :
_heap(0), _heapSize(0), _heapAlign(0),
diff --git a/backends/plugins/elf/shorts-segment-manager.cpp b/backends/plugins/elf/shorts-segment-manager.cpp
index b3a9531c2d..caa328a4f2 100644
--- a/backends/plugins/elf/shorts-segment-manager.cpp
+++ b/backends/plugins/elf/shorts-segment-manager.cpp
@@ -33,7 +33,9 @@ extern char __plugin_hole_start; // Indicates start of hole in program file for
extern char __plugin_hole_end; // Indicates end of hole in program file
extern char _gp[]; // Value of gp register
+namespace Common {
DECLARE_SINGLETON(ShortSegmentManager); // For singleton
+}
ShortSegmentManager::ShortSegmentManager() {
_shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking
diff --git a/backends/taskbar/win32/win32-taskbar.cpp b/backends/taskbar/win32/win32-taskbar.cpp
index 18d99d6eca..04889f3dd7 100644
--- a/backends/taskbar/win32/win32-taskbar.cpp
+++ b/backends/taskbar/win32/win32-taskbar.cpp
@@ -66,7 +66,7 @@
// System.Title property key, values taken from http://msdn.microsoft.com/en-us/library/bb787584.aspx
const PROPERTYKEY PKEY_Title = { /* fmtid = */ { 0xF29F85E0, 0x4FF9, 0x1068, { 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 } }, /* propID = */ 2 };
-Win32TaskbarManager::Win32TaskbarManager() : _taskbar(NULL) {
+Win32TaskbarManager::Win32TaskbarManager() : _taskbar(NULL), _count(0), _icon(NULL) {
// Do nothing if not running on Windows 7 or later
if (!isWin7OrLater())
return;
@@ -96,6 +96,9 @@ Win32TaskbarManager::~Win32TaskbarManager() {
_taskbar->Release();
_taskbar = NULL;
+ if (_icon)
+ DestroyIcon(_icon);
+
CoUninitialize();
}
@@ -144,6 +147,123 @@ void Win32TaskbarManager::setProgressState(TaskbarProgressState state) {
_taskbar->SetProgressState(getHwnd(), (TBPFLAG)state);
}
+void Win32TaskbarManager::setCount(int count) {
+ if (_taskbar == NULL)
+ return;
+
+ if (count == 0) {
+ _taskbar->SetOverlayIcon(getHwnd(), NULL, L"");
+ return;
+ }
+
+ // FIXME: This isn't really nice and could use a cleanup.
+ // The only good thing is that it doesn't use GDI+
+ // and thus does not have a dependancy on it,
+ // with the downside of being a lot more ugly.
+ // Maybe replace it by a Graphic::Surface, use
+ // ScummVM font drawing and extract the contents at
+ // the end?
+
+ if (_count != count || _icon == NULL) {
+ // Cleanup previous icon
+ _count = count;
+ if (_icon)
+ DestroyIcon(_icon);
+
+ Common::String countString = (count < 100 ? Common::String::format("%d", count) : "9+");
+
+ // Create transparent background
+ BITMAPV5HEADER bi;
+ ZeroMemory(&bi, sizeof(BITMAPV5HEADER));
+ bi.bV5Size = sizeof(BITMAPV5HEADER);
+ bi.bV5Width = 16;
+ bi.bV5Height = 16;
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_RGB;
+ // Set 32 BPP alpha format
+ bi.bV5RedMask = 0x00FF0000;
+ bi.bV5GreenMask = 0x0000FF00;
+ bi.bV5BlueMask = 0x000000FF;
+ bi.bV5AlphaMask = 0xFF000000;
+
+ // Get DC
+ HDC hdc;
+ hdc = GetDC(NULL);
+ HDC hMemDC = CreateCompatibleDC(hdc);
+ ReleaseDC(NULL, hdc);
+
+ // Create a bitmap mask
+ HBITMAP hBitmapMask = CreateBitmap(16, 16, 1, 1, NULL);
+
+ // Create the DIB section with an alpha channel
+ void *lpBits;
+ HBITMAP hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, 0);
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
+
+ // Load the icon background
+ HICON hIconBackground = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(1002 /* IDI_COUNT */));
+ DrawIconEx(hMemDC, 0, 0, hIconBackground, 16, 16, 0, 0, DI_NORMAL);
+ DeleteObject(hIconBackground);
+
+ // Draw the count
+ LOGFONT lFont;
+ memset(&lFont, 0, sizeof(LOGFONT));
+ lFont.lfHeight = 10;
+ lFont.lfWeight = FW_BOLD;
+ lFont.lfItalic = 1;
+ strcpy(lFont.lfFaceName, "Arial");
+
+ HFONT hFont = CreateFontIndirect(&lFont);
+ SelectObject(hMemDC, hFont);
+
+ RECT rect;
+ SetRect(&rect, 4, 4, 12, 12);
+ SetTextColor(hMemDC, RGB(48, 48, 48));
+ SetBkMode(hMemDC, TRANSPARENT);
+ DrawText(hMemDC, countString.c_str(), -1, &rect, DT_NOCLIP|DT_CENTER);
+
+ // Set the text alpha to fully opaque (we consider the data inside the text rect)
+ DWORD *lpdwPixel = (DWORD *)lpBits;
+ for (int x = 3; x < 12; x++) {
+ for(int y = 3; y < 12; y++) {
+ unsigned char *p = (unsigned char *)(lpdwPixel + x * 16 + y);
+
+ if (p[0] != 0 && p[1] != 0 && p[2] != 0)
+ p[3] = 255;
+ }
+ }
+
+ // Cleanup DC
+ DeleteObject(hFont);
+ SelectObject(hMemDC, hOldBitmap);
+ DeleteDC(hMemDC);
+
+ // Prepare our new icon
+ ICONINFO ii;
+ ii.fIcon = FALSE;
+ ii.xHotspot = 0;
+ ii.yHotspot = 0;
+ ii.hbmMask = hBitmapMask;
+ ii.hbmColor = hBitmap;
+
+ _icon = CreateIconIndirect(&ii);
+
+ DeleteObject(hBitmap);
+ DeleteObject(hBitmapMask);
+
+ if (!_icon) {
+ warning("[Win32TaskbarManager::setCount] Cannot create icon for count");
+ return;
+ }
+ }
+
+ // Sets the overlay icon
+ LPWSTR desc = ansiToUnicode(Common::String::format("Found games: %d", count).c_str());
+ _taskbar->SetOverlayIcon(getHwnd(), _icon, desc);
+ delete[] desc;
+}
+
void Win32TaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
//warning("[Win32TaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
diff --git a/backends/taskbar/win32/win32-taskbar.h b/backends/taskbar/win32/win32-taskbar.h
index 3415a79bd7..c9d1761017 100644
--- a/backends/taskbar/win32/win32-taskbar.h
+++ b/backends/taskbar/win32/win32-taskbar.h
@@ -41,11 +41,16 @@ public:
virtual void setOverlayIcon(const Common::String &name, const Common::String &description);
virtual void setProgressValue(int completed, int total);
virtual void setProgressState(TaskbarProgressState state);
+ virtual void setCount(int count);
virtual void addRecent(const Common::String &name, const Common::String &description);
private:
ITaskbarList3 *_taskbar;
+ // Count handling
+ HICON _icon;
+ int _count;
+
/**
* Get the path to an icon for the game
*
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 1cd3643f5a..6550f60670 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -65,6 +65,9 @@ static const char HELP_STRING[] =
" -z, --list-games Display list of supported games and exit\n"
" -t, --list-targets Display list of configured targets and exit\n"
" --list-saves=TARGET Display a list of savegames for the game (TARGET) specified\n"
+#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+ " --console Enable the console window (default:enabled)\n"
+#endif
"\n"
" -c, --config=CONFIG Use alternate configuration file\n"
" -p, --path=PATH Path to where the game is installed\n"
@@ -181,8 +184,8 @@ void registerDefaults() {
ConfMan.registerDefault("native_mt32", false);
ConfMan.registerDefault("enable_gs", false);
ConfMan.registerDefault("midi_gain", 100);
-// ConfMan.registerDefault("music_driver", ???);
+ ConfMan.registerDefault("music_driver", "auto");
ConfMan.registerDefault("mt32_device", "null");
ConfMan.registerDefault("gm_device", "null");
@@ -231,13 +234,6 @@ void registerDefaults() {
ConfMan.registerDefault("record_temp_file_name", "record.tmp");
ConfMan.registerDefault("record_time_file_name", "record.time");
-#if 0
- // NEW CODE TO HIDE CONSOLE FOR WIN32
-#ifdef WIN32
- // console hiding for win32
- ConfMan.registerDefault("show_console", false);
-#endif
-#endif
}
//
@@ -554,14 +550,11 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
END_OPTION
#endif
-#if 0
- // NEW CODE TO HIDE CONSOLE FOR WIN32
-#ifdef WIN32
- // console hiding for win32
- DO_LONG_OPTION_BOOL("show-console")
+#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+ // Optional console window on Windows (default: enabled)
+ DO_LONG_OPTION_BOOL("console")
END_OPTION
#endif
-#endif
unknownOption:
// If we get till here, the option is unhandled and hence unknown.
@@ -669,7 +662,7 @@ static Common::Error listSaves(const char *target) {
" ---- ------------------------------------------------------\n");
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
- printf(" %-4s %s\n", x->save_slot().c_str(), x->description().c_str());
+ printf(" %-4d %s\n", x->getSaveSlot(), x->getDescription().c_str());
// TODO: Could also iterate over the full hashmap, printing all key-value pairs
}
} else {
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 46fd646563..7dbbf9843d 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -543,7 +543,9 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) {
#include "engines/metaengine.h"
+namespace Common {
DECLARE_SINGLETON(EngineManager);
+}
/**
* This function works for both cached and uncached PluginManagers.
@@ -634,7 +636,9 @@ const EnginePlugin::List &EngineManager::getPlugins() const {
#include "audio/musicplugin.h"
+namespace Common {
DECLARE_SINGLETON(MusicManager);
+}
const MusicPlugin::List &MusicManager::getPlugins() const {
return (const MusicPlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);
diff --git a/common/EventRecorder.cpp b/common/EventRecorder.cpp
index eb22e1ea88..4441070050 100644
--- a/common/EventRecorder.cpp
+++ b/common/EventRecorder.cpp
@@ -27,10 +27,10 @@
#include "common/savefile.h"
#include "common/textconsole.h"
-DECLARE_SINGLETON(Common::EventRecorder);
-
namespace Common {
+DECLARE_SINGLETON(EventRecorder);
+
#define RECORD_SIGNATURE 0x54455354
#define RECORD_VERSION 1
diff --git a/common/archive.cpp b/common/archive.cpp
index 0ef3893a8c..102d7aaa3f 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -285,7 +285,7 @@ void SearchManager::clear() {
addDirectory(".", ".", -2);
}
-} // namespace Common
+DECLARE_SINGLETON(SearchManager);
-DECLARE_SINGLETON(Common::SearchManager);
+} // namespace Common
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index a9d8c89035..fbdb611f3c 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -27,8 +27,6 @@
#include "common/system.h"
#include "common/textconsole.h"
-DECLARE_SINGLETON(Common::ConfigManager);
-
static bool isValidDomainName(const Common::String &domName) {
const char *p = domName.c_str();
while (*p && (isalnum(static_cast<unsigned char>(*p)) || *p == '-' || *p == '_'))
@@ -38,6 +36,8 @@ static bool isValidDomainName(const Common::String &domName) {
namespace Common {
+DECLARE_SINGLETON(ConfigManager);
+
const char *ConfigManager::kApplicationDomain = "scummvm";
const char *ConfigManager::kTransientDomain = "__TRANSIENT";
diff --git a/common/debug.cpp b/common/debug.cpp
index 0dae344bb2..9c3a93e5a6 100644
--- a/common/debug.cpp
+++ b/common/debug.cpp
@@ -23,16 +23,17 @@
#include "common/debug-channels.h"
#include "common/system.h"
#include "common/textconsole.h"
+#include "common/algorithm.h"
#include <stdarg.h> // For va_list etc.
// TODO: Move gDebugLevel into namespace Common.
int gDebugLevel = -1;
-DECLARE_SINGLETON(Common::DebugManager);
-
namespace Common {
+DECLARE_SINGLETON(DebugManager);
+
namespace {
struct DebugLevelComperator {
diff --git a/common/hashmap.h b/common/hashmap.h
index f2a4d843b8..347ac1fd25 100644
--- a/common/hashmap.h
+++ b/common/hashmap.h
@@ -106,8 +106,9 @@ private:
HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
};
-
+#ifdef USE_HASHMAP_MEMORY_POOL
ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool;
+#endif
Node **_storage; ///< hashtable of size arrsize.
uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one
@@ -128,12 +129,20 @@ private:
#endif
Node *allocNode(const Key &key) {
+#ifdef USE_HASHMAP_MEMORY_POOL
return new (_nodePool) Node(key);
+#else
+ return new Node(key);
+#endif
}
void freeNode(Node *node) {
if (node && node != HASHMAP_DUMMY_NODE)
+#ifdef USE_HASHMAP_MEMORY_POOL
_nodePool.deleteChunk(node);
+#else
+ delete node;
+#endif
}
void assign(const HM_t &map);
diff --git a/common/singleton.h b/common/singleton.h
index 2f5fa41877..43f1c0c4d0 100644
--- a/common/singleton.h
+++ b/common/singleton.h
@@ -89,15 +89,13 @@ protected:
};
/**
- * Note that you need to use this macro from the global namespace.
+ * Note that you need to use this macro from the Common namespace.
*
* This is because C++ requires initial explicit specialization
* to be placed in the same namespace as the template.
- * It has to be put in the global namespace to assure the correct
- * namespace Common is referenced.
*/
#define DECLARE_SINGLETON(T) \
- template<> T *Common::Singleton<T>::_singleton = 0
+ template<> T *Singleton<T>::_singleton = 0
} // End of namespace Common
diff --git a/common/system.h b/common/system.h
index 15fbe386b1..9b833c5b1a 100644
--- a/common/system.h
+++ b/common/system.h
@@ -154,9 +154,9 @@ protected:
#if defined(USE_TASKBAR)
/**
- * No default value is provided for _savefileManager by OSystem.
+ * No default value is provided for _taskbarManager by OSystem.
*
- * @note _savefileManager is deleted by the OSystem destructor.
+ * @note _taskbarManager is deleted by the OSystem destructor.
*/
Common::TaskbarManager *_taskbarManager;
#endif
diff --git a/common/translation.cpp b/common/translation.cpp
index e456f733fd..5c8a04352d 100644
--- a/common/translation.cpp
+++ b/common/translation.cpp
@@ -37,10 +37,10 @@
#ifdef USE_TRANSLATION
-DECLARE_SINGLETON(Common::TranslationManager);
-
namespace Common {
+DECLARE_SINGLETON(TranslationManager);
+
bool operator<(const TLanguage &l, const TLanguage &r) {
return strcmp(l.name, r.name) < 0;
}
diff --git a/common/xmlparser.h b/common/xmlparser.h
index 40c779b87e..d75dc0e4a9 100644
--- a/common/xmlparser.h
+++ b/common/xmlparser.h
@@ -31,6 +31,7 @@
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/stack.h"
+#include "common/memorypool.h"
namespace Common {
diff --git a/configure b/configure
index 537b62d456..fbcd2147c6 100755
--- a/configure
+++ b/configure
@@ -175,7 +175,8 @@ _strip=strip
_ar="ar cru"
_as="as"
_windres=windres
-_win32path="build/x86"
+_stagingpath="staging"
+_win32path="c:/scummvm"
_aos4path="Games:ScummVM"
_staticlibpath=/sw
_sdlconfig=sdl-config
@@ -1854,7 +1855,8 @@ case $_host_os in
mingw*)
DEFINES="$DEFINES -DWIN32"
DEFINES="$DEFINES -D__USE_MINGW_ANSI_STDIO=0"
- LIBS="$LIBS -lmingw32 -lwinmm"
+ LDFLAGS="$LDFLAGS -static-libgcc -static-libstdc++"
+ LIBS="$LIBS -lmingw32 -lwinmm -lgdi32"
OBJS="$OBJS scummvmwinres.o"
add_line_to_config_mk 'WIN32 = 1'
;;
@@ -3518,6 +3520,7 @@ AS := $_as
ASFLAGS := $ASFLAGS
WINDRES := $_windres
WINDRESFLAGS := $WINDRESFLAGS
+STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path
AOS4PATH=$_aos4path
STATICLIBPATH=$_staticlibpath
diff --git a/devtools/convbdf.c b/devtools/convbdf.c
index 4b1640dba7..e465b77a9c 100644
--- a/devtools/convbdf.c
+++ b/devtools/convbdf.c
@@ -721,7 +721,7 @@ int gen_c_source(struct font* pf, char *path) {
char bbuf[256];
char hdr1[] = {
"/* Generated by convbdf on %s. */\n"
- "#include \"graphics/font.h\"\n"
+ "#include \"graphics/fonts/bdf.h\"\n"
"\n"
"/* Font information:\n"
" name: %s\n"
@@ -890,7 +890,7 @@ int gen_c_source(struct font* pf, char *path) {
fprintf(ofp,
"/* Exported structure definition. */\n"
- "static const FontDesc desc = {\n"
+ "static const BdfFontDesc desc = {\n"
"\t" "\"%s\",\n"
"\t" "%d,\n"
"\t" "%d,\n"
@@ -917,7 +917,7 @@ int gen_c_source(struct font* pf, char *path) {
pf->defaultchar);
fprintf(ofp, "\n" "#if !(defined(__GP32__))\n");
- fprintf(ofp, "extern const NewFont g_sysfont(desc);\n");
+ fprintf(ofp, "extern const BdfFont g_sysfont(desc);\n");
fprintf(ofp, "#else\n");
fprintf(ofp, "DEFINE_FONT(g_sysfont)\n");
fprintf(ofp, "#endif\n");
diff --git a/devtools/create_project/scripts/installer.vbs b/devtools/create_project/scripts/installer.vbs
index d752355acd..19b4eee49b 100644
--- a/devtools/create_project/scripts/installer.vbs
+++ b/devtools/create_project/scripts/installer.vbs
@@ -72,10 +72,9 @@ Sub CreateInstaller()
' Build command line
Dim commandLine : commandLine = """" & nsisPath & "\makensis.exe"" /V2" & _
" /Dtop_srcdir=""" & rootFolder & """" & _
- " /Dbuild_dir=""" & targetFolder & """" & _
- " /Dtext_dir=""" & rootFolder & """" & _
+ " /Dstaging_dir=""" & targetFolder & """" & _
" /DARCH=""" & arch & """" & _
- " """ & rootFolder & "\dists\nsis\scummvm.nsi"""
+ " """ & rootFolder & "\dists\win32\scummvm.nsi"""
Dim oExec: Set oExec = WshShell.Exec(commandline)
If Err.Number <> 0 Then
diff --git a/devtools/create_project/scripts/postbuild.cmd b/devtools/create_project/scripts/postbuild.cmd
index a5051d8228..dd52c0217c 100644
--- a/devtools/create_project/scripts/postbuild.cmd
+++ b/devtools/create_project/scripts/postbuild.cmd
@@ -23,23 +23,7 @@ if "%~5"=="" goto error_installer
echo Copying data files
echo.
-REM xcopy /F /Y "%~1/AUTHORS" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/COPYING.GPL" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/COPYING" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/COPYING.LGPL" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/COPYRIGHT" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/NEWS" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/README" %~2 1>NUL 2>&1
-
-REM xcopy /F /Y "%~1/dists/engine-data/*.dat" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/dists/engine-data/*.tbl" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/dists/engine-data/*.cpt" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/gui/themes/*.zip" %~2 1>NUL 2>&1
-REM xcopy /F /Y "%~1/gui/themes/translations.dat" %~2 1>NUL 2>&1
-
-xcopy /F /Y "%~4/lib/%~3/SDL.dll" "%~2" 1>NUL 2>&1
-xcopy /F /Y "%~4/README-SDL" "%~2" 1>NUL 2>&1
-
+xcopy /F /Y "%~4/lib/%~3/SDL.dll" "%~2" 1>NUL 2>&1
xcopy /F /Y "%~1/backends/vkeybd/packs/vkeybd_default.zip" "%~2" 1>NUL 2>&1
if "%~5"=="0" goto done
diff --git a/devtools/credits.pl b/devtools/credits.pl
index de669184e1..a124314670 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -467,7 +467,7 @@ begin_credits("Credits");
add_person("Jonathan Gray", "khalek", "(retired)");
add_person("Vincent Hamm", "yaz0r", "(retired)");
add_person("Max Horn", "Fingolfin", "(retired)");
- add_person("Travis Howell", "Kirben", "(retired)");
+ add_person("Travis Howell", "Kirben", "");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "Codecs, iMUSE, Smush, etc.");
add_person("Gregory Montoir", "cyx", "");
add_person("Eugene Sandulenko", "sev", "FT INSANE, MM NES, MM C64, game detection, Herc/CGA");
@@ -476,7 +476,7 @@ begin_credits("Credits");
begin_section("HE");
add_person("Jonathan Gray", "khalek", "(retired)");
- add_person("Travis Howell", "Kirben", "(retired)");
+ add_person("Travis Howell", "Kirben", "");
add_person("Gregory Montoir", "cyx", "");
add_person("Eugene Sandulenko", "sev", "");
end_section();
@@ -486,7 +486,7 @@ begin_credits("Credits");
add_person("Matthew Hoops", "clone2727", "");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "");
- add_person("Walter van Niftrik", "waltervn", "");
+ add_person("Walter van Niftrik", "waltervn", "(retired)");
add_person("Kari Salminen", "Buddha^", "");
add_person("Eugene Sandulenko", "sev", "");
add_person("David Symonds", "dsymonds", "(retired)");
@@ -495,7 +495,7 @@ begin_credits("Credits");
begin_section("AGOS");
add_person("Torbj&ouml;rn Andersson", "eriktorbjorn", "");
add_person("Paul Gilbert", "dreammaster", "");
- add_person("Travis Howell", "Kirben", "(retired)");
+ add_person("Travis Howell", "Kirben", "");
add_person("Oliver Kiehl", "olki", "(retired)");
add_person("Ludvig Strigeus", "ludde", "(retired)");
end_section();
@@ -609,7 +609,7 @@ begin_credits("Credits");
add_person("Max Horn", "Fingolfin", "(retired)");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Martin Kiewitz", "m_kiewitz", "");
- add_person("Walter van Niftrik", "waltervn", "");
+ add_person("Walter van Niftrik", "waltervn", "(retired)");
add_person("Willem Jan Palenstijn", "wjp", "");
add_person("Jordi Vilalta Prat", "jvprat", "");
add_person("Lars Skovlund", "lskovlun", "");
@@ -878,7 +878,7 @@ begin_credits("Credits");
end_section();
begin_section("Win32");
- add_person("Travis Howell", "Kirben", "(retired)");
+ add_person("Travis Howell", "Kirben", "");
end_section();
begin_section("Win64");
diff --git a/devtools/update-version.pl b/devtools/update-version.pl
index 788cbc7e40..169fba7788 100755
--- a/devtools/update-version.pl
+++ b/devtools/update-version.pl
@@ -39,7 +39,7 @@ my @subs_files = qw(
dists/macosx/Info.plist
dists/iphone/Info.plist
dists/irix/scummvm.spec
- dists/nsis/scummvm.nsi
+ dists/win32/scummvm.nsi
dists/wii/meta.xml
dists/android/AndroidManifest.xml
dists/android/plugin-manifest.xml
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index d3330045b5..9fa5489547 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -5,9 +5,14 @@
#endif
#define FILE 256
-#define IDI_ICON 1001
+#define IDI_ICON 1001
+#define IDI_COUNT 1002
+#define ID_GDF_XML __GDF_XML
IDI_ICON ICON DISCARDABLE "icons/scummvm.ico"
+IDI_COUNT ICON DISCARDABLE "icons/count.ico"
+
+ID_GDF_XML DATA "dists/win32/scummvm.gdf.xml"
scummmodern.zip FILE "gui/themes/scummmodern.zip"
#ifdef USE_TRANSLATION
diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in
index 8186e0e8ef..b91e7ebb0c 100644
--- a/dists/scummvm.rc.in
+++ b/dists/scummvm.rc.in
@@ -5,9 +5,14 @@
#endif
#define FILE 256
-#define IDI_ICON 1001
+#define IDI_ICON 1001
+#define IDI_COUNT 1002
+#define ID_GDF_XML __GDF_XML
IDI_ICON ICON DISCARDABLE "icons/scummvm.ico"
+IDI_COUNT ICON DISCARDABLE "icons/count.ico"
+
+ID_GDF_XML DATA "dists/win32/scummvm.gdf.xml"
scummmodern.zip FILE "gui/themes/scummmodern.zip"
#ifdef USE_TRANSLATION
diff --git a/dists/win32/ScummVM.iss b/dists/win32/ScummVM.iss
index 00f4868e60..8edc647e62 100644
--- a/dists/win32/ScummVM.iss
+++ b/dists/win32/ScummVM.iss
@@ -1,8 +1,12 @@
[Setup]
-DefaultDirName={pf}\ScummVM
AppCopyright=2011
AppName=ScummVM
AppVerName=ScummVM Git
+AppPublisher=The ScummVM Team
+AppPublisherURL=http://www.scummvm.org/
+AppSupportURL=http://www.scummvm.org/
+AppUpdatesURL=http://www.scummvm.org/
+DefaultDirName={pf}\ScummVM
DefaultGroupName=ScummVM
AllowNoIcons=true
AlwaysUsePersonalGroup=false
@@ -14,7 +18,8 @@ DisableStartupPrompt=true
AppendDefaultDirName=false
SolidCompression=true
DirExistsWarning=no
-SetupIconFile=scummvm.ico
+SetupIconFile=graphics\scummvm-install.ico
+WizardImageFile=graphics\left.bmp
ShowLanguageDialog=yes
LanguageDetectionMethod=uilanguage
@@ -44,6 +49,7 @@ Name: es; MessagesFile: compiler:Languages\Spanish.isl
[Icons]
Name: {group}\{cm:UninstallProgram, ScummVM}; Filename: {uninstallexe}
Name: {group}\ScummVM; Filename: {app}\scummvm.exe; WorkingDir: {app}; Comment: scummvm; Flags: createonlyiffileexists; IconIndex: 0
+Name: {group}\ScummVM (noconsole); Filename: {app}\scummvm.exe; Parameters: "--no-console"; WorkingDir: {app}; Comment: scummvm; Flags: createonlyiffileexists; IconIndex: 0
Name: {group}\Authors; Filename: {app}\AUTHORS.txt; WorkingDir: {app}; Comment: AUTHORS; Flags: createonlyiffileexists
Name: {group}\Copying; Filename: {app}\COPYING.txt; WorkingDir: {app}; Comment: COPYING; Flags: createonlyiffileexists
Name: {group}\Copying.LGPL; Filename: {app}\COPYING.LGPL.txt; WorkingDir: {app}; Comment: COPYING.LGPL; Flags: createonlyiffileexists
diff --git a/dists/nsis/graphics/left.bmp b/dists/win32/graphics/left.bmp
index 8b31d7d09a..8b31d7d09a 100644
--- a/dists/nsis/graphics/left.bmp
+++ b/dists/win32/graphics/left.bmp
Binary files differ
diff --git a/dists/nsis/graphics/scummvm-install.ico b/dists/win32/graphics/scummvm-install.ico
index 6312959509..6312959509 100644
--- a/dists/nsis/graphics/scummvm-install.ico
+++ b/dists/win32/graphics/scummvm-install.ico
Binary files differ
diff --git a/dists/win32/plugins/Games.dll b/dists/win32/plugins/Games.dll
new file mode 100644
index 0000000000..3a378b7064
--- /dev/null
+++ b/dists/win32/plugins/Games.dll
Binary files differ
diff --git a/dists/win32/scummvm.gdf.xml b/dists/win32/scummvm.gdf.xml
new file mode 100644
index 0000000000..1c50924e15
--- /dev/null
+++ b/dists/win32/scummvm.gdf.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<GameDefinitionFile xmlns:baseTypes="urn:schemas-microsoft-com:GamesExplorerBaseTypes.v1" xmlns="urn:schemas-microsoft-com:GameDescription.v1">
+ <GameDefinition gameID="{F2475C5C-EA7C-41F0-A56D-1ABF7CFEA389}">
+ <Name>ScummVM</Name>
+ <Description>ScummVM is a program which allows you to run certain classic graphical point-and-click adventure games, provided you already have their data files. The clever part about this: ScummVM just replaces the executables shipped with the games, allowing you to play them on systems for which they were never designed!</Description>
+ <ReleaseDate>2011-09-30</ReleaseDate>
+ <Genres>
+ <Genre>Adventure</Genre>
+ </Genres>
+ <Version>
+ <VersionFile path="scummvm.exe" />
+ </Version>
+ <WindowsSystemPerformanceRating minimum="1.0" recommended="2.0" />
+ <Developers>
+ <Developer URI="http://www.scummvm.org">The ScummVM Team</Developer>
+ </Developers>
+ <Publishers>
+ <Publisher URI="http://www.scummvm.org">The ScummVM Team</Publisher>
+ </Publishers>
+ <GameExecutables>
+ <GameExecutable path="scummvm.exe" />
+ </GameExecutables>
+ <ExtendedProperties>
+ <GameTasks>
+ <Play>
+ <Primary>
+ <FileTask path="scummvm.exe" arguments="--no-console" />
+ </Primary>
+ <Task index="1" name="Play (console)">
+ <FileTask path="scummvm.exe" arguments="" />
+ </Task>
+ </Play>
+ <Support>
+ <Task index="0" name="View README">
+ <FileTask path="README.txt" arguments="" />
+ </Task>
+ <Task index="1" name="ScummVM Website">
+ <URLTask Link="http://www.scummvm.org" />
+ </Task>
+ </Support>
+ </GameTasks>
+ </ExtendedProperties>
+ </GameDefinition>
+</GameDefinitionFile> \ No newline at end of file
diff --git a/dists/nsis/scummvm.nsi b/dists/win32/scummvm.nsi
index 50ccadaf74..01a7e72afe 100644
--- a/dists/nsis/scummvm.nsi
+++ b/dists/win32/scummvm.nsi
@@ -20,19 +20,26 @@
#!define _DEBUG
#!define _INCLUDE_DATA_FILES
+!define _ENABLE_GAME_EXPLORER
+#!define _LOG_BUILD
+!define _CONVERT_TEXT
Name ScummVM
# Included files
!include MUI2.nsh
+# Plugins
+!ifdef _ENABLE_GAME_EXPLORER
+!AddPluginDir "./plugins"
+!endif
+
#########################################################################################
# Command line options
#########################################################################################
#!define top_srcdir ""
-#!define build_dir ""
-#!define text_dir ""
+#!define staging_dir ""
#!define ARCH "" ;(optional, defaults to win32)
# Check parameters
@@ -40,17 +47,19 @@ Name ScummVM
!error "Top source folder has not been passed to command line!"
!endif
-!ifndef build_dir
- !error "Build folder has not been passed to command line (this folder should contain the executable and linked DLLs)!"
-!endif
-
-!ifndef text_dir
- !error "Text folder has not been passed to command line (this folder should contain all the text files used by the installer)!"
+!ifndef staging_dir
+ !error "Staging folder has not been passed to command line (this folder should contain the executable and linked DLLs)!"
!endif
!ifndef ARCH
!warning "ARCH has not been defined, defaulting to 'win32'"
!define ARCH "win32"
+!else
+ !if "${ARCH}" == ""
+ !warning "ARCH was empty, defaulting to 'win32'"
+ !undef ARCH
+ !define ARCH "win32"
+ !endif
!endif
#########################################################################################
@@ -72,7 +81,7 @@ Name ScummVM
#########################################################################################
# Installer configuration
#########################################################################################
-OutFile ${build_dir}\scummvm-${VERSION}-${ARCH}.exe
+OutFile ${staging_dir}\scummvm-${VERSION}-${ARCH}.exe
InstallDir $PROGRAMFILES\ScummVM ; Default installation folder
InstallDirRegKey HKCU "Software\ScummVM\ScummVM" "InstallPath" ; Get installation folder from registry if available
; The application name needs to be refered directly instead of through ${REGKEY}
@@ -220,17 +229,35 @@ Var StartMenuGroup
# Installer sections
#########################################################################################
Section "ScummVM" SecMain
+!ifdef _LOG_BUILD
+ LogSet on
+!endif
SetOutPath $INSTDIR
SetOverwrite on
# Text files
- File /oname=AUTHORS.txt "${text_dir}\AUTHORS"
- File /oname=COPYING.LGPL.txt "${text_dir}\COPYING.LGPL"
- File /oname=COPYING.txt "${text_dir}\COPYING"
- File /oname=COPYRIGHT.txt "${text_dir}\COPYRIGHT"
- File /oname=NEWS.txt "${text_dir}\NEWS"
- File /oname=README.txt "${text_dir}\README"
- File /oname=README-SDL.txt "${build_dir}\README-SDL"
+ File /oname=AUTHORS.txt "${top_srcdir}\AUTHORS"
+ File /oname=COPYING.LGPL.txt "${top_srcdir}\COPYING.LGPL"
+ File /oname=COPYING.txt "${top_srcdir}\COPYING"
+ File /oname=COPYRIGHT.txt "${top_srcdir}\COPYRIGHT"
+ File /oname=NEWS.txt "${top_srcdir}\NEWS"
+ File /oname=README.txt "${top_srcdir}\README"
+
+!ifdef _CONVERT_TEXT
+ # Convert line endings
+ Push "$INSTDIR\AUTHORS.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYING.LGPL.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYING.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYRIGHT.txt"
+ Call unix2dos
+ Push "$INSTDIR\NEWS.txt"
+ Call unix2dos
+ Push "$INSTDIR\README.txt"
+ Call unix2dos
+!endif
!ifdef _INCLUDE_DATA_FILES
# Engine data
@@ -253,10 +280,27 @@ Section "ScummVM" SecMain
!endif
# Main exe and dlls
- File "${build_dir}\scummvm.exe"
- File "${build_dir}\SDL.dll"
+ File "${staging_dir}\scummvm.exe"
+ File "${staging_dir}\SDL.dll"
WriteRegStr HKCU "${REGKEY}" InstallPath "$INSTDIR" ; Store installation folder
+
+ #Register with game explorer
+!ifdef _ENABLE_GAME_EXPLORER
+ Games::registerGame "$INSTDIR\scummvm.exe"
+ pop $0
+ # This is for Vista only, for 7 the tasks are defined in the gdf xml
+ ${If} $0 != "0"
+ ${AndIf} $0 != ""
+ ${AndIf} $0 != "$INSTDIR\scummvm.exe"
+ CreateDirectory "$0\PlayTasks\0"
+ CreateShortcut "$0\PlayTasks\0\Play.lnk" "$INSTDIR\scummvm.exe" "--no-console"
+ CreateDirectory "$0\PlayTasks\1"
+ CreateShortcut "$0\PlayTasks\1\Play (console).lnk" "$INSTDIR\scummvm.exe"
+ CreateDirectory "$0\SupportTasks\0"
+ CreateShortcut "$0\SupportTasks\0\Home Page.lnk" "${URL}"
+ ${EndIf}
+!endif
SectionEnd
# Write Start menu entries and uninstaller
@@ -266,7 +310,8 @@ Section -post SecMainPost
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
SetShellVarContext all ; Create shortcuts in the all-users folder
CreateDirectory "$SMPROGRAMS\$StartMenuGroup"
- CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\$(^Name).exe "" "$INSTDIR\$(^Name).exe" 0 ; Create shortcut with icon
+ CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\$(^Name).exe "" "$INSTDIR\$(^Name).exe" 0 ; Create shortcut with icon
+ CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name) (No console).lnk" $INSTDIR\$(^Name).exe "--no-console" "$INSTDIR\$(^Name).exe" 0
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Readme.lnk" $INSTDIR\README.txt
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_END
@@ -320,6 +365,10 @@ Section -un.Main SecUninstall
Delete /REBOOTOK $INSTDIR\translations.dat
!endif
+!ifdef _ENABLE_GAME_EXPLORER
+ Games::unregisterGame "$INSTDIR\scummvm.exe"
+!endif
+
Delete /REBOOTOK $INSTDIR\scummvm.exe
Delete /REBOOTOK $INSTDIR\SDL.dll
SectionEnd
@@ -354,3 +403,63 @@ Function un.onInit
ReadRegStr $INSTDIR HKCU "${REGKEY}" InstallPath
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup
FunctionEnd
+
+
+#########################################################################################
+# Helper functions
+#########################################################################################
+
+!ifdef _CONVERT_TEXT
+;-------------------------------------------------------------------------------
+; strips all CRs and then converts all LFs into CRLFs
+; (this is roughly equivalent to "cat file | dos2unix | unix2dos")
+;
+; Usage:
+; Push "infile"
+; Call unix2dos
+;
+; Note: this function destroys $0 $1 $2
+Function unix2dos
+ ClearErrors
+
+ Pop $2
+ Rename $2 $2.U2D
+ FileOpen $1 $2 w
+
+ FileOpen $0 $2.U2D r
+
+ Push $2 ; save name for deleting
+
+ IfErrors unix2dos_done
+
+ ; $0 = file input (opened for reading)
+ ; $1 = file output (opened for writing)
+
+unix2dos_loop:
+ ; read a byte (stored in $2)
+ FileReadByte $0 $2
+ IfErrors unix2dos_done ; EOL
+ ; skip CR
+ StrCmp $2 13 unix2dos_loop
+ ; if LF write an extra CR
+ StrCmp $2 10 unix2dos_cr unix2dos_write
+
+unix2dos_cr:
+ FileWriteByte $1 13
+
+unix2dos_write:
+ ; write byte
+ FileWriteByte $1 $2
+ ; read next byte
+ Goto unix2dos_loop
+
+unix2dos_done:
+ ; close files
+ FileClose $0
+ FileClose $1
+
+ ; delete original
+ Pop $0
+ Delete $0.U2D
+FunctionEnd
+!endif
diff --git a/dists/nsis/scummvm.nsi.in b/dists/win32/scummvm.nsi.in
index c94e5943f7..cba1e81e33 100644
--- a/dists/nsis/scummvm.nsi.in
+++ b/dists/win32/scummvm.nsi.in
@@ -20,19 +20,26 @@
#!define _DEBUG
#!define _INCLUDE_DATA_FILES
+!define _ENABLE_GAME_EXPLORER
+#!define _LOG_BUILD
+!define _CONVERT_TEXT
Name ScummVM
# Included files
!include MUI2.nsh
+# Plugins
+!ifdef _ENABLE_GAME_EXPLORER
+!AddPluginDir "./plugins"
+!endif
+
#########################################################################################
# Command line options
#########################################################################################
#!define top_srcdir ""
-#!define build_dir ""
-#!define text_dir ""
+#!define staging_dir ""
#!define ARCH "" ;(optional, defaults to win32)
# Check parameters
@@ -40,17 +47,19 @@ Name ScummVM
!error "Top source folder has not been passed to command line!"
!endif
-!ifndef build_dir
- !error "Build folder has not been passed to command line (this folder should contain the executable and linked DLLs)!"
-!endif
-
-!ifndef text_dir
- !error "Text folder has not been passed to command line (this folder should contain all the text files used by the installer)!"
+!ifndef staging_dir
+ !error "Staging folder has not been passed to command line (this folder should contain the executable and linked DLLs)!"
!endif
!ifndef ARCH
!warning "ARCH has not been defined, defaulting to 'win32'"
!define ARCH "win32"
+!else
+ !if "${ARCH}" == ""
+ !warning "ARCH was empty, defaulting to 'win32'"
+ !undef ARCH
+ !define ARCH "win32"
+ !endif
!endif
#########################################################################################
@@ -72,7 +81,7 @@ Name ScummVM
#########################################################################################
# Installer configuration
#########################################################################################
-OutFile ${build_dir}\scummvm-${VERSION}-${ARCH}.exe
+OutFile ${staging_dir}\scummvm-${VERSION}-${ARCH}.exe
InstallDir $PROGRAMFILES\ScummVM ; Default installation folder
InstallDirRegKey HKCU "Software\ScummVM\ScummVM" "InstallPath" ; Get installation folder from registry if available
; The application name needs to be refered directly instead of through ${REGKEY}
@@ -220,17 +229,35 @@ Var StartMenuGroup
# Installer sections
#########################################################################################
Section "ScummVM" SecMain
+!ifdef _LOG_BUILD
+ LogSet on
+!endif
SetOutPath $INSTDIR
SetOverwrite on
# Text files
- File /oname=AUTHORS.txt "${text_dir}\AUTHORS"
- File /oname=COPYING.LGPL.txt "${text_dir}\COPYING.LGPL"
- File /oname=COPYING.txt "${text_dir}\COPYING"
- File /oname=COPYRIGHT.txt "${text_dir}\COPYRIGHT"
- File /oname=NEWS.txt "${text_dir}\NEWS"
- File /oname=README.txt "${text_dir}\README"
- File /oname=README-SDL.txt "${build_dir}\README-SDL"
+ File /oname=AUTHORS.txt "${top_srcdir}\AUTHORS"
+ File /oname=COPYING.LGPL.txt "${top_srcdir}\COPYING.LGPL"
+ File /oname=COPYING.txt "${top_srcdir}\COPYING"
+ File /oname=COPYRIGHT.txt "${top_srcdir}\COPYRIGHT"
+ File /oname=NEWS.txt "${top_srcdir}\NEWS"
+ File /oname=README.txt "${top_srcdir}\README"
+
+!ifdef _CONVERT_TEXT
+ # Convert line endings
+ Push "$INSTDIR\AUTHORS.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYING.LGPL.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYING.txt"
+ Call unix2dos
+ Push "$INSTDIR\COPYRIGHT.txt"
+ Call unix2dos
+ Push "$INSTDIR\NEWS.txt"
+ Call unix2dos
+ Push "$INSTDIR\README.txt"
+ Call unix2dos
+!endif
!ifdef _INCLUDE_DATA_FILES
# Engine data
@@ -253,10 +280,27 @@ Section "ScummVM" SecMain
!endif
# Main exe and dlls
- File "${build_dir}\scummvm.exe"
- File "${build_dir}\SDL.dll"
+ File "${staging_dir}\scummvm.exe"
+ File "${staging_dir}\SDL.dll"
WriteRegStr HKCU "${REGKEY}" InstallPath "$INSTDIR" ; Store installation folder
+
+ #Register with game explorer
+!ifdef _ENABLE_GAME_EXPLORER
+ Games::registerGame "$INSTDIR\scummvm.exe"
+ pop $0
+ # This is for Vista only, for 7 the tasks are defined in the gdf xml
+ ${If} $0 != "0"
+ ${AndIf} $0 != ""
+ ${AndIf} $0 != "$INSTDIR\scummvm.exe"
+ CreateDirectory "$0\PlayTasks\0"
+ CreateShortcut "$0\PlayTasks\0\Play.lnk" "$INSTDIR\scummvm.exe" "--no-console"
+ CreateDirectory "$0\PlayTasks\1"
+ CreateShortcut "$0\PlayTasks\1\Play (console).lnk" "$INSTDIR\scummvm.exe"
+ CreateDirectory "$0\SupportTasks\0"
+ CreateShortcut "$0\SupportTasks\0\Home Page.lnk" "${URL}"
+ ${EndIf}
+!endif
SectionEnd
# Write Start menu entries and uninstaller
@@ -266,7 +310,8 @@ Section -post SecMainPost
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
SetShellVarContext all ; Create shortcuts in the all-users folder
CreateDirectory "$SMPROGRAMS\$StartMenuGroup"
- CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\$(^Name).exe "" "$INSTDIR\$(^Name).exe" 0 ; Create shortcut with icon
+ CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\$(^Name).exe "" "$INSTDIR\$(^Name).exe" 0 ; Create shortcut with icon
+ CreateShortCut "$SMPROGRAMS\$StartMenuGroup\$(^Name) (No console).lnk" $INSTDIR\$(^Name).exe "--no-console" "$INSTDIR\$(^Name).exe" 0
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Readme.lnk" $INSTDIR\README.txt
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_END
@@ -320,6 +365,10 @@ Section -un.Main SecUninstall
Delete /REBOOTOK $INSTDIR\translations.dat
!endif
+!ifdef _ENABLE_GAME_EXPLORER
+ Games::unregisterGame "$INSTDIR\scummvm.exe"
+!endif
+
Delete /REBOOTOK $INSTDIR\scummvm.exe
Delete /REBOOTOK $INSTDIR\SDL.dll
SectionEnd
@@ -354,3 +403,63 @@ Function un.onInit
ReadRegStr $INSTDIR HKCU "${REGKEY}" InstallPath
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup
FunctionEnd
+
+
+#########################################################################################
+# Helper functions
+#########################################################################################
+
+!ifdef _CONVERT_TEXT
+;-------------------------------------------------------------------------------
+; strips all CRs and then converts all LFs into CRLFs
+; (this is roughly equivalent to "cat file | dos2unix | unix2dos")
+;
+; Usage:
+; Push "infile"
+; Call unix2dos
+;
+; Note: this function destroys $0 $1 $2
+Function unix2dos
+ ClearErrors
+
+ Pop $2
+ Rename $2 $2.U2D
+ FileOpen $1 $2 w
+
+ FileOpen $0 $2.U2D r
+
+ Push $2 ; save name for deleting
+
+ IfErrors unix2dos_done
+
+ ; $0 = file input (opened for reading)
+ ; $1 = file output (opened for writing)
+
+unix2dos_loop:
+ ; read a byte (stored in $2)
+ FileReadByte $0 $2
+ IfErrors unix2dos_done ; EOL
+ ; skip CR
+ StrCmp $2 13 unix2dos_loop
+ ; if LF write an extra CR
+ StrCmp $2 10 unix2dos_cr unix2dos_write
+
+unix2dos_cr:
+ FileWriteByte $1 13
+
+unix2dos_write:
+ ; write byte
+ FileWriteByte $1 $2
+ ; read next byte
+ Goto unix2dos_loop
+
+unix2dos_done:
+ ; close files
+ FileClose $0
+ FileClose $1
+
+ ; delete original
+ Pop $0
+ Delete $0.U2D
+FunctionEnd
+!endif
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index 1df31ff72a..af26fe62d0 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -86,27 +86,30 @@ void Winnie::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) {
}
uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) {
- char szFile[256] = {0};
+ Common::String fileName;
if (_vm->getPlatform() == Common::kPlatformPC)
- sprintf(szFile, IDS_WTP_ROOM_DOS, iRoom);
+ fileName = Common::String::format(IDS_WTP_ROOM_DOS, iRoom);
else if (_vm->getPlatform() == Common::kPlatformAmiga)
- sprintf(szFile, IDS_WTP_ROOM_AMIGA, iRoom);
+ fileName = Common::String::format(IDS_WTP_ROOM_AMIGA, iRoom);
else if (_vm->getPlatform() == Common::kPlatformC64)
- sprintf(szFile, IDS_WTP_ROOM_C64, iRoom);
+ fileName = Common::String::format(IDS_WTP_ROOM_C64, iRoom);
else if (_vm->getPlatform() == Common::kPlatformApple2GS)
- sprintf(szFile, IDS_WTP_ROOM_APPLE, iRoom);
+ fileName = Common::String::format(IDS_WTP_ROOM_APPLE, iRoom);
+
Common::File file;
- if (!file.open(szFile)) {
- warning ("Could not open file \'%s\'", szFile);
+ if (!file.open(fileName)) {
+ warning("Could not open file \'%s\'", fileName.c_str());
return 0;
}
+
uint32 filelen = file.size();
- if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address
+ if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address
filelen -= 2;
file.seek(2, SEEK_CUR);
}
- memset(buffer, 0, sizeof(buffer));
+
+ memset(buffer, 0, 4096);
file.read(buffer, filelen);
file.close();
@@ -116,26 +119,30 @@ uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) {
}
uint32 Winnie::readObj(int iObj, uint8 *buffer) {
- char szFile[256] = {0};
+ Common::String fileName;
+
if (_vm->getPlatform() == Common::kPlatformPC)
- sprintf(szFile, IDS_WTP_OBJ_DOS, iObj);
+ fileName = Common::String::format(IDS_WTP_OBJ_DOS, iObj);
else if (_vm->getPlatform() == Common::kPlatformAmiga)
- sprintf(szFile, IDS_WTP_OBJ_AMIGA, iObj);
+ fileName = Common::String::format(IDS_WTP_OBJ_AMIGA, iObj);
else if (_vm->getPlatform() == Common::kPlatformC64)
- sprintf(szFile, IDS_WTP_OBJ_C64, iObj);
+ fileName = Common::String::format(IDS_WTP_OBJ_C64, iObj);
else if (_vm->getPlatform() == Common::kPlatformApple2GS)
- sprintf(szFile, IDS_WTP_OBJ_APPLE, iObj);
+ fileName = Common::String::format(IDS_WTP_OBJ_APPLE, iObj);
+
Common::File file;
- if (!file.open(szFile)) {
- warning ("Could not open file \'%s\'", szFile);
+ if (!file.open(fileName)) {
+ warning ("Could not open file \'%s\'", fileName.c_str());
return 0;
}
+
uint32 filelen = file.size();
- if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address
+ if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address
filelen -= 2;
file.seek(2, SEEK_CUR);
}
- memset(buffer, 0, sizeof(buffer));
+
+ memset(buffer, 0, 2048);
file.read(buffer, filelen);
file.close();
return filelen;
@@ -461,8 +468,6 @@ void Winnie::keyHelp() {
}
void Winnie::inventory() {
- char szMissing[41] = {0};
-
if (_game.iObjHave)
printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE);
else {
@@ -470,8 +475,9 @@ void Winnie::inventory() {
_vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0);
}
- sprintf(szMissing, IDS_WTP_INVENTORY_1, _game.nObjMiss);
- _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, szMissing);
+ Common::String missing = Common::String::format(IDS_WTP_INVENTORY_1, _game.nObjMiss);
+
+ _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, missing.c_str());
_vm->_gfx->doUpdate();
_vm->_system->updateScreen(); //TODO: Move to game's main loop
_vm->getSelection(kSelAnyKey);
@@ -1042,16 +1048,15 @@ phase2:
}
void Winnie::drawPic(const char *szName) {
- char szFile[256] = {0};
- Common::File file;
+ Common::String fileName = szName;
- // construct filename
if (_vm->getPlatform() != Common::kPlatformAmiga)
- sprintf(szFile, "%s.pic", szName);
- else
- strcpy(szFile, szName);
- if (!file.open(szFile)) {
- warning ("Could not open file \'%s\'", szFile);
+ fileName += ".pic";
+
+ Common::File file;
+
+ if (!file.open(fileName)) {
+ warning ("Could not open file \'%s\'", fileName.c_str());
return;
}
@@ -1142,12 +1147,11 @@ void Winnie::gameOver() {
}
void Winnie::saveGame() {
- Common::OutSaveFile* outfile;
- char szFile[256] = {0};
int i = 0;
- sprintf(szFile, IDS_WTP_FILE_SAVEGAME);
- if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile)))
+ Common::OutSaveFile *outfile = _vm->getSaveFileMan()->openForSaving(IDS_WTP_FILE_SAVEGAME);
+
+ if (!outfile)
return;
outfile->writeUint32BE(MKTAG('W','I','N','N')); // header
@@ -1171,19 +1175,18 @@ void Winnie::saveGame() {
outfile->finalize();
if (outfile->err())
- warning("Can't write file '%s'. (Disk full?)", szFile);
+ warning("Can't write file '%s'. (Disk full?)", IDS_WTP_FILE_SAVEGAME);
delete outfile;
}
void Winnie::loadGame() {
- Common::InSaveFile* infile;
- char szFile[256] = {0};
int saveVersion = 0;
int i = 0;
- sprintf(szFile, IDS_WTP_FILE_SAVEGAME);
- if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile)))
+ Common::InSaveFile *infile = _vm->getSaveFileMan()->openForLoading(IDS_WTP_FILE_SAVEGAME);
+
+ if (!infile)
return;
if (infile->readUint32BE() == MKTAG('W','I','N','N')) {
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index cdb5140002..2f0c13740f 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -688,8 +688,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
int16 di;
uint16 j;
int16 mouseX, mouseY;
- int16 var_16;
- int16 var_14;
int16 currentSelection, oldSelection;
int16 var_4;
SelectionMenu *menu;
@@ -731,9 +729,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
manageEvents();
getMouseData(mouseUpdateStatus, &button, (uint16 *)&mouseX, (uint16 *)&mouseY);
- var_16 = mouseX;
- var_14 = mouseY;
-
menuVar = 0;
do {
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index a97583c972..031c53b96a 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -902,18 +902,8 @@ bool createDialog(int objOvl, int objIdx, int x, int y) {
if (!obj2Ovl) obj2Ovl = j;
char verbe_name[80];
- char obj1_name[80];
- char obj2_name[80];
- char r_verbe_name[80];
- char r_obj1_name[80];
- char r_obj2_name[80];
verbe_name[0] = 0;
- obj1_name[0] = 0;
- obj2_name[0] = 0;
- r_verbe_name[0] = 0;
- r_obj1_name[0] = 0;
- r_obj2_name[0] = 0;
ovlDataStruct *ovl2 = NULL;
ovlDataStruct *ovl3 = NULL;
diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp
index 814d0aa9e9..14b6daf4bb 100644
--- a/engines/cruise/mainDraw.cpp
+++ b/engines/cruise/mainDraw.cpp
@@ -440,7 +440,6 @@ void buildSegment() {
// is segment on screen ?
if (!((tempAX > 199) || (tempDX < 0))) {
- int dx = Y1;
int cx = X2 - X1;
if (cx == 0) {
// vertical line
@@ -473,7 +472,6 @@ void buildSegment() {
} else {
if (cx < 0) {
cx = -cx;
- dx = Y2;
SWAP(X1, X2);
SWAP(Y1, Y2);
@@ -1490,9 +1488,6 @@ void mainDraw(int16 param) {
if (currentObjPtr->animLoop > 0)
currentObjPtr->animLoop--;
} else {
- int16 data2;
- data2 = currentObjPtr->animStart;
-
change = false;
currentObjPtr->animStep = 0;
@@ -1512,9 +1507,6 @@ void mainDraw(int16 param) {
if (currentObjPtr->animLoop > 0)
currentObjPtr->animLoop--;
} else {
- int16 data2;
- data2 = currentObjPtr->animStart;
-
change = false;
currentObjPtr->animStep = 0;
diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp
index 4e76194a45..cf28548e7d 100644
--- a/engines/cruise/script.cpp
+++ b/engines/cruise/script.cpp
@@ -231,9 +231,7 @@ int32 opcodeType2() {
int type = getByteFromScript();
int overlay = getByteFromScript();
- int firstOffset;
- int offset;
- firstOffset = offset = getShortFromScript();
+ int offset = getShortFromScript();
offset += index;
int typ7 = type & 7;
diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp
index d32be6a2b7..ef4a746b62 100644
--- a/engines/dreamweb/detection.cpp
+++ b/engines/dreamweb/detection.cpp
@@ -43,7 +43,7 @@ public:
AdvancedMetaEngine(DreamWeb::gameDescriptions,
sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames) {
_singleid = "dreamweb";
- _guioptions = Common::GUIO_NOMIDI;
+ _guioptions = Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD;
}
virtual const char *getName() const {
diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h
index 0449361a98..6c7d8e4809 100644
--- a/engines/dreamweb/detection_tables.h
+++ b/engines/dreamweb/detection_tables.h
@@ -31,6 +31,7 @@ namespace DreamWeb {
using Common::GUIO_NONE;
static const DreamWebGameDescription gameDescriptions[] = {
+ // International floppy release
{
{
"dreamweb",
@@ -81,6 +82,23 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
},
+ // French CD release
+ {
+ {
+ "dreamweb",
+ "CD",
+ {
+ {"dreamwfr.r00", 0, "e354582a8564faf5c515df92f207e8d1", 154657},
+ {"dreamwfr.r02", 0, "57f3f08d5aefd04184eac76927eced80", 200575},
+ AD_LISTEND
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ ADGF_CD | ADGF_UNSTABLE,
+ GUIO_NONE
+ },
+ },
+
// German floppy release
{
{
@@ -132,6 +150,23 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
},
+ // Spanish CD release
+ {
+ {
+ "dreamweb",
+ "CD",
+ {
+ {"dreamwsp.r00", 0, "2df07174321de39c4f17c9ff654b268a", 153608},
+ {"dreamwsp.r02", 0, "577d435ad5da08fb1bcf6ea3dd6e0b9e", 199499},
+ AD_LISTEND
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ ADGF_CD | ADGF_UNSTABLE,
+ GUIO_NONE
+ },
+ },
+
// Italian floppy release
{
{
diff --git a/engines/engine.cpp b/engines/engine.cpp
index b952f065ad..b19daa2611 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -410,7 +410,7 @@ void Engine::openMainMenuDialog() {
// value, which is quite bad since it could
// be a fatal loading error, which renders
// the engine unusable.
- if (_saveSlotToLoad > 0)
+ if (_saveSlotToLoad >= 0)
loadGameState(_saveSlotToLoad);
syncSoundSettings();
diff --git a/engines/groovie/saveload.cpp b/engines/groovie/saveload.cpp
index a0463db0be..14e7a09cb2 100644
--- a/engines/groovie/saveload.cpp
+++ b/engines/groovie/saveload.cpp
@@ -102,7 +102,7 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s
// Fill the SaveStateDescriptor if it was provided
if (descriptor) {
// Initialize the SaveStateDescriptor
- descriptor->setVal("save_slot", Common::String('0' + slot));
+ descriptor->setSaveSlot(slot);
descriptor->setDeletableFlag(true);
descriptor->setWriteProtectedFlag(false);
@@ -132,7 +132,7 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s
description += c;
}
}
- descriptor->setVal("description", description);
+ descriptor->setDescription(description);
}
// Return a substream, skipping the metadata
diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp
index f87e6bb91b..5a24559e8b 100644
--- a/engines/groovie/script.cpp
+++ b/engines/groovie/script.cpp
@@ -1350,15 +1350,15 @@ void Script::o_checkvalidsaves() {
uint count = 0;
SaveStateList::iterator it = list.begin();
while (it != list.end()) {
- int8 slot = it->getVal("save_slot").lastChar() - '0';
+ int8 slot = it->getSaveSlot();
if (SaveLoad::isSlotValid(slot)) {
- debugScript(2, true, " Found valid savegame: %s", it->getVal("description").c_str());
+ debugScript(2, true, " Found valid savegame: %s", it->getDescription().c_str());
// Mark this slot as used
setVariable(slot, 1);
// Cache this slot's description
- _saveNames[slot] = it->getVal("description");
+ _saveNames[slot] = it->getDescription();
count++;
}
it++;
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index e8dd9e9a15..4a48ac0674 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -71,7 +71,7 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) {
}
if (_vm->game() != GI_KYRA1 && _vm->resource()->getFileSize(argv[1]) != 768) {
- uint8 *buffer = (uint8 *)malloc(320 * 200 * sizeof(uint8));
+ uint8 *buffer = new uint8[320 * 200 * sizeof(uint8)];
if (!buffer) {
DebugPrintf("ERROR: Cannot allocate buffer for screen region!\n");
return true;
@@ -82,7 +82,7 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) {
palette.copy(_vm->screen()->getCPagePtr(5), 0, 256);
_vm->screen()->copyBlockToPage(5, 0, 0, 320, 200, buffer);
- free(buffer);
+ delete[] buffer;
} else if (!_vm->screen()->loadPalette(argv[1], palette)) {
DebugPrintf("ERROR: Palette '%s' not found!\n", argv[1]);
return true;
diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp
index eac82ec2c5..eba2f8f279 100644
--- a/engines/kyra/gui_lok.cpp
+++ b/engines/kyra/gui_lok.cpp
@@ -576,6 +576,15 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) {
if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header))) {
Common::strlcpy(_savegameNames[i], header.description.c_str(), ARRAYSIZE(_savegameNames[0]));
+ // Trim long GMM save descriptions to fit our save slots
+ _screen->_charWidth = -2;
+ int fC = _screen->getTextWidth(_savegameNames[i]);
+ while (_savegameNames[i][0] && (fC > 240 )) {
+ _savegameNames[i][strlen(_savegameNames[i]) - 1] = 0;
+ fC = _screen->getTextWidth(_savegameNames[i]);
+ }
+ _screen->_charWidth = 0;
+
Util::convertISOToDOS(_savegameNames[i]);
menu.item[i].itemString = _savegameNames[i];
@@ -693,12 +702,15 @@ void GUI_LoK::updateSavegameString() {
if (_keyPressed.keycode) {
length = strlen(_savegameName);
+ _screen->_charWidth = -2;
+ int width = _screen->getTextWidth(_savegameName) + 7;
+ _screen->_charWidth = 0;
char inputKey = _keyPressed.ascii;
Util::convertISOToDOS(inputKey);
if ((uint8)inputKey > 31 && (uint8)inputKey < (_vm->gameFlags().lang == Common::JA_JPN ? 128 : 226)) {
- if (length < ARRAYSIZE(_savegameName)-1) {
+ if ((length < ARRAYSIZE(_savegameName)-1) && (width <= 240)) {
_savegameName[length] = inputKey;
_savegameName[length+1] = 0;
redrawTextfield();
diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp
index fb11040168..c64d3e7723 100644
--- a/engines/kyra/gui_lol.cpp
+++ b/engines/kyra/gui_lol.cpp
@@ -2572,9 +2572,19 @@ void GUI_LoL::setupSaveMenuSlots(Menu &menu, int num) {
slotOffs = 1;
}
+ int saveSlotMaxLen = ((_screen->getScreenDim(8))->w << 3) - _screen->getCharWidth('W');
+
for (int i = startSlot; i < num && _savegameOffset + i - slotOffs < _savegameListSize; ++i) {
if (_savegameList[_saveSlots[i + _savegameOffset - slotOffs]]) {
Common::strlcpy(s, _savegameList[_saveSlots[i + _savegameOffset - slotOffs]], 80);
+
+ // Trim long GMM save descriptions to fit our save slots
+ int fC = _screen->getTextWidth(s);
+ while (s[0] && fC >= saveSlotMaxLen) {
+ s[strlen(s) - 1] = 0;
+ fC = _screen->getTextWidth(s);
+ }
+
menu.item[i].itemString = s;
s += (strlen(s) + 1);
menu.item[i].saveSlot = _saveSlots[i + _savegameOffset - slotOffs];
diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp
index 0b82df8cd5..dcc53b7c9e 100644
--- a/engines/kyra/gui_v2.cpp
+++ b/engines/kyra/gui_v2.cpp
@@ -457,6 +457,15 @@ void GUI_v2::setupSavegameNames(Menu &menu, int num) {
Common::strlcpy(s, header.description.c_str(), 80);
Util::convertISOToDOS(s);
+ // Trim long GMM save descriptions to fit our save slots
+ _screen->_charWidth = -2;
+ int fC = _screen->getTextWidth(s);
+ while (s[0] && fC > 240) {
+ s[strlen(s) - 1] = 0;
+ fC = _screen->getTextWidth(s);
+ }
+ _screen->_charWidth = 0;
+
menu.item[i].saveSlot = _saveSlots[i + _savegameOffset];
menu.item[i].enabled = true;
delete in;
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index 3d81368d2d..3b2c9b67eb 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -83,7 +83,9 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags)
}
void KyraEngine_v1::pauseEngineIntern(bool pause) {
- _sound->pause(pause);
+ Engine::pauseEngineIntern(pause);
+ if (_sound)
+ _sound->pause(pause);
_timer->pause(pause);
}
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index b4304a6de0..8f008a58b6 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -3359,7 +3359,7 @@ void SJISFont::drawChar(uint16 c, byte *dst, int pitch) const {
color2 = _colorMap[0];
}
- _font->drawChar(dst, c, 640, 1, color1, color2);
+ _font->drawChar(dst, c, 640, 1, color1, color2, 640, 400);
}
#pragma mark -
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 3713537afd..4da35cc28b 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -43,10 +43,6 @@ Sound::Sound(KyraEngine_v1 *vm, Audio::Mixer *mixer)
Sound::~Sound() {
}
-void Sound::pause(bool paused) {
- _mixer->pauseAll(paused);
-}
-
bool Sound::voiceFileIsPresent(const char *file) {
for (int i = 0; _supportedCodecs[i].fileext; ++i) {
Common::String f = file;
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 566b37ff43..c3c32331be 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -156,7 +156,7 @@ public:
/**
* Stops all audio playback when paused. Continues after end of pause.
*/
- virtual void pause(bool paused);
+ virtual void pause(bool paused) {}
void enableMusic(int enable) { _musicEnabled = enable; }
int musicEnabled() const { return _musicEnabled; }
diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index dc0f8c11ec..26b6b31d0a 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -716,9 +716,6 @@ void SoundMidiPC::beginFadeOut() {
}
void SoundMidiPC::pause(bool paused) {
- // Stop all mixer related sounds
- Sound::pause(paused);
-
Common::StackLock lock(_mutex);
if (paused) {
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp
index d92ebbc5e3..28d20df9bd 100644
--- a/engines/lastexpress/data/snd.cpp
+++ b/engines/lastexpress/data/snd.cpp
@@ -36,13 +36,329 @@
namespace LastExpress {
+#pragma region Sound filters tables
+
+static const int filterData[1424] = {
+ 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 128, 256,
+ 384, 512, 0, 0, 0, 0, 192, 320, 448, 576, 0, 0, 0, 0,
+ 192, 320, 448, 576, 64, 64, 64, 64, 256, 384, 512, 640,
+ 64, 64, 64, 64, 256, 384, 512, 640, 128, 128, 128, 128,
+ 320, 448, 576, 704, 128, 128, 128, 128, 320, 448, 576,
+ 704, 192, 192, 192, 192, 384, 512, 640, 768, 192, 192,
+ 192, 192, 384, 512, 640, 768, 256, 256, 256, 256, 448,
+ 576, 704, 832, 256, 256, 256, 256, 448, 576, 704, 832,
+ 320, 320, 320, 320, 512, 640, 768, 896, 320, 320, 320,
+ 320, 512, 640, 768, 896, 384, 384, 384, 384, 576, 704,
+ 832, 960, 384, 384, 384, 384, 576, 704, 832, 960, 448,
+ 448, 448, 448, 640, 768, 896, 1024, 448, 448, 448, 448,
+ 640, 768, 896, 1024, 512, 512, 512, 512, 704, 832, 960,
+ 1088, 512, 512, 512, 512, 704, 832, 960, 1088, 576,
+ 576, 576, 576, 768, 896, 1024, 1152, 576, 576, 576,
+ 576, 768, 896, 1024, 1152, 640, 640, 640, 640, 832,
+ 960, 1088, 1216, 640, 640, 640, 640, 832, 960, 1088,
+ 1216, 704, 704, 704, 704, 896, 1024, 1152, 1280, 704,
+ 704, 704, 704, 896, 1024, 1152, 1280, 768, 768, 768,
+ 768, 960, 1088, 1216, 1344, 768, 768, 768, 768, 960,
+ 1088, 1216, 1344, 832, 832, 832, 832, 1024, 1152, 1280,
+ 1408, 832, 832, 832, 832, 1024, 1152, 1280, 1408, 896,
+ 896, 896, 896, 1088, 1216, 1344, 1472, 896, 896, 896,
+ 896, 1088, 1216, 1344, 1472, 960, 960, 960, 960, 1152,
+ 1280, 1408, 1536, 960, 960, 960, 960, 1152, 1280, 1408,
+ 1536, 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600,
+ 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, 1088,
+ 1088, 1088, 1088, 1280, 1408, 1536, 1664, 1088, 1088,
+ 1088, 1088, 1280, 1408, 1536, 1664, 1152, 1152, 1152,
+ 1152, 1344, 1472, 1600, 1728, 1152, 1152, 1152, 1152,
+ 1344, 1472, 1600, 1728, 1216, 1216, 1216, 1216, 1408,
+ 1536, 1664, 1792, 1216, 1216, 1216, 1216, 1408, 1536,
+ 1664, 1792, 1280, 1280, 1280, 1280, 1472, 1600, 1728,
+ 1856, 1280, 1280, 1280, 1280, 1472, 1600, 1728, 1856,
+ 1344, 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1344,
+ 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1408, 1408,
+ 1408, 1408, 1600, 1728, 1856, 1984, 1408, 1408, 1408,
+ 1408, 1600, 1728, 1856, 1984, 1472, 1472, 1472, 1472,
+ 1664, 1792, 1920, 2048, 1472, 1472, 1472, 1472, 1664,
+ 1792, 1920, 2048, 1536, 1536, 1536, 1536, 1728, 1856,
+ 1984, 2112, 1536, 1536, 1536, 1536, 1728, 1856, 1984,
+ 2112, 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176,
+ 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, 1664,
+ 1664, 1664, 1664, 1856, 1984, 2112, 2240, 1664, 1664,
+ 1664, 1664, 1856, 1984, 2112, 2240, 1728, 1728, 1728,
+ 1728, 1920, 2048, 2176, 2304, 1728, 1728, 1728, 1728,
+ 1920, 2048, 2176, 2304, 1792, 1792, 1792, 1792, 1984,
+ 2112, 2240, 2368, 1792, 1792, 1792, 1792, 1984, 2112,
+ 2240, 2368, 1856, 1856, 1856, 1856, 2048, 2176, 2304,
+ 2432, 1856, 1856, 1856, 1856, 2048, 2176, 2304, 2432,
+ 1920, 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1920,
+ 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1984, 1984,
+ 1984, 1984, 2176, 2304, 2432, 2560, 1984, 1984, 1984,
+ 1984, 2176, 2304, 2432, 2560, 2048, 2048, 2048, 2048,
+ 2240, 2368, 2496, 2624, 2048, 2048, 2048, 2048, 2240,
+ 2368, 2496, 2624, 2112, 2112, 2112, 2112, 2304, 2432,
+ 2560, 2688, 2112, 2112, 2112, 2112, 2304, 2432, 2560,
+ 2688, 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752,
+ 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, 2240,
+ 2240, 2240, 2240, 2432, 2560, 2688, 2816, 2240, 2240,
+ 2240, 2240, 2432, 2560, 2688, 2816, 2304, 2304, 2304,
+ 2304, 2496, 2624, 2752, 2880, 2304, 2304, 2304, 2304,
+ 2496, 2624, 2752, 2880, 2368, 2368, 2368, 2368, 2560,
+ 2688, 2816, 2944, 2368, 2368, 2368, 2368, 2560, 2688,
+ 2816, 2944, 2432, 2432, 2432, 2432, 2624, 2752, 2880,
+ 3008, 2432, 2432, 2432, 2432, 2624, 2752, 2880, 3008,
+ 2496, 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2496,
+ 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2560, 2560,
+ 2560, 2560, 2752, 2880, 3008, 3136, 2560, 2560, 2560,
+ 2560, 2752, 2880, 3008, 3136, 2624, 2624, 2624, 2624,
+ 2816, 2944, 3072, 3200, 2624, 2624, 2624, 2624, 2816,
+ 2944, 3072, 3200, 2688, 2688, 2688, 2688, 2880, 3008,
+ 3136, 3264, 2688, 2688, 2688, 2688, 2880, 3008, 3136,
+ 3264, 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328,
+ 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, 2816,
+ 2816, 2816, 2816, 3008, 3136, 3264, 3392, 2816, 2816,
+ 2816, 2816, 3008, 3136, 3264, 3392, 2880, 2880, 2880,
+ 2880, 3072, 3200, 3328, 3456, 2880, 2880, 2880, 2880,
+ 3072, 3200, 3328, 3456, 2944, 2944, 2944, 2944, 3136,
+ 3264, 3392, 3520, 2944, 2944, 2944, 2944, 3136, 3264,
+ 3392, 3520, 3008, 3008, 3008, 3008, 3200, 3328, 3456,
+ 3584, 3008, 3008, 3008, 3008, 3200, 3328, 3456, 3584,
+ 3072, 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3072,
+ 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3136, 3136,
+ 3136, 3136, 3328, 3456, 3584, 3712, 3136, 3136, 3136,
+ 3136, 3328, 3456, 3584, 3712, 3200, 3200, 3200, 3200,
+ 3392, 3520, 3648, 3776, 3200, 3200, 3200, 3200, 3392,
+ 3520, 3648, 3776, 3264, 3264, 3264, 3264, 3456, 3584,
+ 3712, 3840, 3264, 3264, 3264, 3264, 3456, 3584, 3712,
+ 3840, 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904,
+ 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, 3392,
+ 3392, 3392, 3392, 3584, 3712, 3840, 3968, 3392, 3392,
+ 3392, 3392, 3584, 3712, 3840, 3968, 3456, 3456, 3456,
+ 3456, 3648, 3776, 3904, 4032, 3456, 3456, 3456, 3456,
+ 3648, 3776, 3904, 4032, 3520, 3520, 3520, 3520, 3712,
+ 3840, 3968, 4096, 3520, 3520, 3520, 3520, 3712, 3840,
+ 3968, 4096, 3584, 3584, 3584, 3584, 3776, 3904, 4032,
+ 4160, 3584, 3584, 3584, 3584, 3776, 3904, 4032, 4160,
+ 3648, 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3648,
+ 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3712, 3712,
+ 3712, 3712, 3904, 4032, 4160, 4288, 3712, 3712, 3712,
+ 3712, 3904, 4032, 4160, 4288, 3776, 3776, 3776, 3776,
+ 3968, 4096, 4224, 4352, 3776, 3776, 3776, 3776, 3968,
+ 4096, 4224, 4352, 3840, 3840, 3840, 3840, 4032, 4160,
+ 4288, 4416, 3840, 3840, 3840, 3840, 4032, 4160, 4288,
+ 4416, 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480,
+ 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, 3968,
+ 3968, 3968, 3968, 4160, 4288, 4416, 4544, 3968, 3968,
+ 3968, 3968, 4160, 4288, 4416, 4544, 4032, 4032, 4032,
+ 4032, 4224, 4352, 4480, 4608, 4032, 4032, 4032, 4032,
+ 4224, 4352, 4480, 4608, 4096, 4096, 4096, 4096, 4288,
+ 4416, 4544, 4672, 4096, 4096, 4096, 4096, 4288, 4416,
+ 4544, 4672, 4160, 4160, 4160, 4160, 4352, 4480, 4608,
+ 4.6, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736,
+ 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4224,
+ 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4288, 4288,
+ 4288, 4288, 4480, 4608, 4736, 4864, 4288, 4288, 4288,
+ 4288, 4480, 4608, 4736, 4864, 4352, 4352, 4352, 4352,
+ 4544, 4672, 4800, 4928, 4352, 4352, 4352, 4352, 4544,
+ 4672, 4800, 4928, 4416, 4416, 4416, 4416, 4608, 4736,
+ 4864, 4992, 4416, 4416, 4416, 4416, 4608, 4736, 4864,
+ 4992, 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056,
+ 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, 4544,
+ 4544, 4544, 4544, 4736, 4864, 4992, 5120, 4544, 4544,
+ 4544, 4544, 4736, 4864, 4992, 5120, 4608, 4608, 4608,
+ 4608, 4800, 4928, 5056, 5184, 4608, 4608, 4608, 4608,
+ 4800, 4928, 5056, 5184, 4672, 4672, 4672, 4672, 4864,
+ 4992, 5120, 5248, 4672, 4672, 4672, 4672, 4864, 4992,
+ 5120, 5248, 4736, 4736, 4736, 4736, 4928, 5056, 5184,
+ 5312, 4736, 4736, 4736, 4736, 4928, 5056, 5184, 5312,
+ 4800, 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4800,
+ 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4864, 4864,
+ 4864, 4864, 5056, 5184, 5312, 5440, 4864, 4864, 4864,
+ 4864, 5056, 5184, 5312, 5440, 4928, 4928, 4928, 4928,
+ 5120, 5248, 5376, 5504, 4928, 4928, 4928, 4928, 5120,
+ 5248, 5376, 5504, 4992, 4992, 4992, 4992, 5184, 5312,
+ 5440, 5568, 4992, 4992, 4992, 4992, 5184, 5312, 5440,
+ 5568, 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632,
+ 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, 5120,
+ 5120, 5120, 5120, 5312, 5440, 5568, 5632, 5120, 5120,
+ 5120, 5120, 5312, 5440, 5568, 5632, 5184, 5184, 5184,
+ 5184, 5376, 5504, 5632, 5632, 5184, 5184, 5184, 5184,
+ 5376, 5504, 5632, 5632, 5248, 5248, 5248, 5248, 5440,
+ 5568, 5632, 5632, 5248, 5248, 5248, 5248, 5440, 5568,
+ 5632, 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632,
+ 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, 5632,
+ 5376, 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5376,
+ 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5440, 5440,
+ 5440, 5440, 5632, 5632, 5632, 5632, 5440, 5440, 5440,
+ 5440, 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504,
+ 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, 5632,
+ 5632, 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632,
+ 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, 5632,
+ 5632
+};
+
+static const int filterData2[1424] = {
+ 0, 2, 4, 6, 7, 9, 11, 13, 0, -2, -4, -6, -7, -9, -11,
+ -13, 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9,
+ -11, -13, -15, 1, 3, 5, 7, 10, 12, 14, 16, -1, -3, -5,
+ -7, -10, -12, -14, -16, 1, 3, 6, 8, 11, 13, 16, 18,
+ -1, -3, -6, -8, -11, -13, -16, -18, 1, 4, 6, 9, 12,
+ 15, 17, 20, -1, -4, -6, -9, -12, -15, -17, -20, 1, 4,
+ 7, 10, 13, 16, 19, 22, -1, -4, -7, -10, -13, -16, -19,
+ -22, 1, 4, 8, 11, 14, 17, 21, 24, -1, -4, -8, -11, -14,
+ -17, -21, -24, 1, 5, 8, 12, 15, 19, 22, 26, -1, -5,
+ -8, -12, -15, -19, -22, -26, 2, 6, 10, 14, 18, 22, 26,
+ 30, -2, -6, -10, -14, -18, -22, -26, -30, 2, 6, 10,
+ 14, 19, 23, 27, 31, -2, -6, -10, -14, -19, -23, -27,
+ -31, 2, 7, 11, 16, 21, 26, 30, 35, -2, -7, -11, -16,
+ -21, -26, -30, -35, 2, 7, 13, 18, 23, 28, 34, 39, -2,
+ -7, -13, -18, -23, -28, -34, -39, 2, 8, 14, 20, 25,
+ 31, 37, 43, -2, -8, -14, -20, -25, -31, -37, -43, 3,
+ 9, 15, 21, 28, 34, 40, 46, -3, -9, -15, -21, -28, -34,
+ -40, -46, 3, 10, 17, 24, 31, 38, 45, 52, -3, -10, -17,
+ -24, -31, -38, -45, -52, 3, 11, 19, 27, 34, 42, 50,
+ 58, -3, -11, -19, -27, -34, -42, -50, -58, 4, 12, 21,
+ 29, 38, 46, 55, 63, -4, -12, -21, -29, -38, -46, -55,
+ -63, 4, 13, 23, 32, 41, 50, 60, 69, -4, -13, -23, -32,
+ -41, -50, -60, -69, 5, 15, 25, 35, 46, 56, 66, 76, -5,
+ -15, -25, -35, -46, -56, -66, -76, 5, 16, 28, 39, 50,
+ 61, 73, 84, -5, -16, -28, -39, -50, -61, -73, -84, 6,
+ 18, 31, 43, 56, 68, 81, 93, -6, -18, -31, -43, -56,
+ -68, -81, -93, 6, 20, 34, 48, 61, 75, 89, 103, -6, -20,
+ -34, -48, -61, -75, -89, -103, 7, 22, 37, 52, 67, 82,
+ 97, 112, -7, -22, -37, -52, -67, -82, -97, -112, 8,
+ 24, 41, 57, 74, 90, 107, 123, -8, -24, -41, -57, -74,
+ -90, -107, -123, 9, 27, 45, 63, 82, 100, 118, 136, -9,
+ -27, -45, -63, -82, -100, -118, -136, 10, 30, 50, 70,
+ 90, 110, 130, 150, -10, -30, -50, -70, -90, -110, -130,
+ -150, 11, 33, 55, 77, 99, 121, 143, 165, -11, -33, -55,
+ -77, -99, -121, -143, -165, 12, 36, 60, 84, 109, 133,
+ 157, 181, -12, -36, -60, -84, -109, -133, -157, -181,
+ 13, 40, 66, 93, 120, 147, 173, 200, -13, -40, -66, -93,
+ -120, -147, -173, -200, 14, 44, 73, 103, 132, 162, 191,
+ 221, -14, -44, -73, -103, -132, -162, -191, -221, 16,
+ 48, 81, 113, 146, 178, 211, 243, -16, -48, -81, -113,
+ -146, -178, -211, -243, 17, 53, 89, 125, 160, 196, 232,
+ 268, -17, -53, -89, -125, -160, -196, -232, -268, 19,
+ 58, 98, 137, 176, 215, 255, 294, -19, -58, -98, -137,
+ -176, -215, -255, -294, 21, 64, 108, 151, 194, 237,
+ 281, 324, -21, -64, -108, -151, -194, -237, -281, -324,
+ 23, 71, 118, 166, 213, 261, 308, 356, -23, -71, -118,
+ -166, -213, -261, -308, -356, 26, 78, 130, 182, 235,
+ 287, 339, 391, -26, -78, -130, -182, -235, -287, -339,
+ -391, 28, 86, 143, 201, 258, 316, 373, 431, -28, -86,
+ -143, -201, -258, -316, -373, -431, 31, 94, 158, 221,
+ 284, 347, 411, 474, -31, -94, -158, -221, -284, -347,
+ -411, -474, 34, 104, 174, 244, 313, 383, 453, 523, -34,
+ -104, -174, -244, -313, -383, -453, -523, 38, 115, 191,
+ 268, 345, 422, 498, 575, -38, -115, -191, -268, -345,
+ -422, -498, -575, 42, 126, 210, 294, 379, 463, 547,
+ 631, -42, -126, -210, -294, -379, -463, -547, -631,
+ 46, 139, 231, 324, 417, 510, 602, 695, -46, -139, -231,
+ -324, -417, -510, -602, -695, 51, 153, 255, 357, 459,
+ 561, 663, 765, -51, -153, -255, -357, -459, -561, -663,
+ -765, 56, 168, 280, 392, 505, 617, 729, 841, -56, -168,
+ -280, -392, -505, -617, -729, -841, 61, 185, 308, 432,
+ 555, 679, 802, 926, -61, -185, -308, -432, -555, -679,
+ -802, -926, 68, 204, 340, 476, 612, 748, 884, 1020,
+ -68, -204, -340, -476, -612, -748, -884, -1020, 74,
+ 224, 373, 523, 672, 822, 971, 1121, -74, -224, -373,
+ -523, -672, -822, -971, -1121, 82, 246, 411, 575, 740,
+ 904, 1069, 1233, -82, -246, -411, -575, -740, -904,
+ -1069, -1233, 90, 271, 452, 633, 814, 995, 1176, 1357,
+ -90, -271, -452, -633, -814, -995, -1176, -1357, 99,
+ 298, 497, 696, 895, 1094, 1293, 1492, -99, -298, -497,
+ -696, -895, -1094, -1293, -1492, 109, 328, 547, 766,
+ 985, 1204, 1423, 1642, -109, -328, -547, -766, -985,
+ -1204, -1423, -1642, 120, 361, 601, 842, 1083, 1324,
+ 1564, 1805, -120, -361, -601, -842, -1083, -1324, -1564,
+ -1805, 132, 397, 662, 927, 1192, 1457, 1722, 1987, -132,
+ -397, -662, -927, -1192, -1457, -1722, -1987, 145, 437,
+ 728, 1020, 1311, 1603, 1894, 2186, -145, -437, -728,
+ -1020, -1311, -1603, -1894, -2186, 160, 480, 801, 1121,
+ 1442, 1762, 2083, 2403, -160, -480, -801, -1121, -1442,
+ -1762, -2083, -2403, 176, 529, 881, 1234, 1587, 1940,
+ 2292, 2645, -176, -529, -881, -1234, -1587, -1940, -2292,
+ -2645, 194, 582, 970, 1358, 1746, 2134, 2522, 2910,
+ -194, -582, -970, -1358, -1746, -2134, -2522, -2910,
+ 213, 640, 1066, 1493, 1920, 2347, 2773, 3200, -213,
+ -640, -1066, -1493, -1920, -2347, -2773, -3200, 234,
+ 704, 1173, 1643, 2112, 2582, 3051, 3521, -234, -704,
+ -1173, -1643, -2112, -2582, -3051, -3521, 258, 774,
+ 1291, 1807, 2324, 2840, 3357, 3873, -258, -774, -1291,
+ -1807, -2324, -2840, -3357, -3873, 284, 852, 1420, 1988,
+ 2556, 3124, 3692, 4260, -284, -852, -1420, -1988, -2556,
+ -3124, -3692, -4260, 312, 937, 1561, 2186, 2811, 3436,
+ 4060, 4685, -312, -937, -1561, -2186, -2811, -3436,
+ -4060, -4685, 343, 1030, 1718, 2405, 3092, 3779, 4467,
+ 5154, -343, -1030, -1718, -2405, -3092, -3779, -4467,
+ -5154, 378, 1134, 1890, 2646, 3402, 4158, 4914, 5670,
+ -378, -1134, -1890, -2646, -3402, -4158, -4914, -5670,
+ 415, 1247, 2079, 2911, 3742, 4574, 5406, 6238, -415,
+ -1247, -2079, -2911, -3742, -4574, -5406, -6238, 457,
+ 1372, 2287, 3202, 4117, 5032, 5947, 6862, -457, -1372,
+ -2287, -3202, -4117, -5032, -5947, -6862, 503, 1509,
+ 2516, 3522, 4529, 5535, 6542, 7548, -503, -1509, -2516,
+ -3522, -4529, -5535, -6542, -7548, 553, 1660, 2767,
+ 3874, 4981, 6088, 7195, 8302, -553, -1660, -2767, -3874,
+ -4981, -6088, -7195, -8302, 608, 1826, 3044, 4262, 5479,
+ 6697, 7915, 9133, -608, -1826, -3044, -4262, -5479,
+ -6697, -7915, -9133, 669, 2009, 3348, 4688, 6027, 7367,
+ 8706, 10046, -669, -2009, -3348, -4688, -6027, -7367,
+ -8706, -10046, 736, 2210, 3683, 5157, 6630, 8104, 9577,
+ 11051, -736, -2210, -3683, -5157, -6630, -8104, -9577,
+ -11051, 810, 2431, 4052, 5673, 7294, 8915, 10536, 12157,
+ -810, -2431, -4052, -5673, -7294, -8915, -10536, -12157,
+ 891, 2674, 4457, 6240, 8023, 9806, 11589, 13372, -891,
+ -2674, -4457, -6240, -8023, -9806, -11589, -13372, 980,
+ 2941, 4903, 6864, 8825, 10786, 12748, 14709, -980, -2941,
+ -4903, -6864, -8825, -10786, -12748, -14709, 1078, 3236,
+ 5393, 7551, 9708, 11866, 14023, 16181, -1078, -3236,
+ -5393, -7551, -9708, -11866, -14023, -16181, 1186, 3559,
+ 5933, 8306, 10679, 13052, 15426, 17799, -1186, -3559,
+ -5933, -8306, -10679, -13052, -15426, -17799, 1305,
+ 3915, 6526, 9136, 11747, 14357, 16968, 19578, -1305,
+ -3915, -6526, -9136, -11747, -14357, -16968, -19578,
+ 1435, 4307, 7179, 10051, 12922, 15794, 18666, 21538,
+ -1435, -4307, -7179, -10051, -12922, -15794, -18666,
+ -21538, 1579, 4738, 7896, 11055, 14214, 17373, 20531,
+ 23690, -1579, -4738, -7896, -11055, -14214, -17373,
+ -20531, -23690, 1737, 5212, 8686, 12161, 15636, 19111,
+ 22585, 26060, -1737, -5212, -8686, -12161, -15636, -19111,
+ -22585, -26060, 1911, 5733, 9555, 13377, 17200, 21022,
+ 24844, 28666, -1911, -5733, -9555, -13377, -17200, -21022,
+ -24844, -28666, 2102, 6306, 10511, 14715, 18920, 23124,
+ 27329, 31533, -2102, -6306, -10511, -14715, -18920,
+ -23124, -27329, -31533, 2312, 6937, 11562, 16187, 20812,
+ 25437, 30062, 32767, -2312, -6937, -11562, -16187, -20812,
+ -25437, -30062, -32767, 2543, 7631, 12718, 17806, 22893,
+ 27981, 32767, 32767, -2543, -7631, -12718, -17806, -22893,
+ -27981, -32767, -32767, 2798, 8394, 13990, 19586, 25183,
+ 30779, 32767, 32767, -2798, -8394, -13990, -19586, -25183,
+ -30779, -32767, -32767, 3077, 9233, 15389, 21545, 27700,
+ 32767, 32767, 32767, -3077, -9233, -15389, -21545, -27700,
+ -32767, -32767, -32767, 3385, 10157, 16928, 23700, 30471,
+ 32767, 32767, 32767, -3385, -10157, -16928, -23700,
+ -30471, -32767, -32767, -32767, 3724, 11172, 18621,
+ 26069, 32767, 32767, 32767, 32767, -3724, -11172, -18621,
+ -26069, -32767, -32767, -32767, -32767, 4095, 12287,
+ 20479, 28671, 32767, 32767, 32767, 32767, -4095, -12287,
+ -20479, -28671, -32767, -32767, -32767, -32767
+};
+
+static const int p1s[17] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4, 0 };
+static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1 };
+
+#pragma endregion
+
// Last Express ADPCM is similar to MS IMA mono, but inverts its nibbles
// and does not have the 4 byte per channel requirement
class LastExpress_ADPCMStream : public Audio::Ima_ADPCMStream {
public:
- LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize) :
- Audio::Ima_ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) {}
+ LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize, int32 filterId) :
+ Audio::Ima_ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) {
+ _currentFilterId = -1;
+ _nextFilterId = filterId;
+ }
int readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
@@ -67,6 +383,45 @@ public:
return samples;
}
+
+ void setFilterId(int32 filterId) { _nextFilterId = filterId; }
+
+private:
+ int32 _currentFilterId;
+ int32 _nextFilterId; // the sound filter id, -1 for none
+
+ /**
+ * Sound filter
+ *
+ * @param [in] data If non-null, the input data
+ * @param [in,out] buffer If non-null, the output buffer.
+ * @param p1 The first filter input.
+ * @param p2 The second filter input.
+ */
+ static void soundFilter(byte *data, int16 *buffer, int p1, int p2) {
+ int data1, data2, data1p, data2p;
+ byte idx;
+
+ data2 = data[0];
+ data1 = data[1] << 6;
+
+ data += 2;
+
+ for (int count = 0; count < 735; count++) {
+ idx = data[count] >> 4;
+
+ data1p = filterData[idx + data1];
+ data2p = CLIP(filterData2[idx + data1] + data2, -32767, 32767);
+
+ buffer[2 * count] = (p2 * data2p) >> p1;
+
+ idx = data[count] & 0xF;
+
+ data1 = filterData[idx + data1p];
+ data2 = CLIP(filterData2[idx + data1p] + data2p, -32767, 32767);
+ buffer[2 * count + 1] = (p2 * data2) >> p1;
+ }
+ }
};
//////////////////////////////////////////////////////////////////////////
@@ -92,8 +447,8 @@ void SimpleSound::loadHeader(Common::SeekableReadStream *in) {
_blockSize = _size / _blocks;
}
-Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size) const {
- return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize);
+Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId) const {
+ return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize, filterId);
}
void SimpleSound::play(Audio::AudioStream *as) {
@@ -103,10 +458,11 @@ void SimpleSound::play(Audio::AudioStream *as) {
//////////////////////////////////////////////////////////////////////////
// StreamedSound
//////////////////////////////////////////////////////////////////////////
-StreamedSound::StreamedSound() {}
+StreamedSound::StreamedSound() : _as(NULL), _loaded(false) {}
+
StreamedSound::~StreamedSound() {}
-bool StreamedSound::load(Common::SeekableReadStream *stream) {
+bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) {
if (!stream)
return false;
@@ -115,14 +471,27 @@ bool StreamedSound::load(Common::SeekableReadStream *stream) {
loadHeader(stream);
// Start decoding the input stream
- Audio::AudioStream *as = makeDecoder(stream, _size);
+ _as = makeDecoder(stream, _size, filterId);
// Start playing the decoded audio stream
- play(as);
+ play(_as);
+
+ _loaded = true;
return true;
}
+bool StreamedSound::isFinished() {
+ if (!_loaded)
+ return false;
+
+ return !g_system->getMixer()->isSoundHandleActive(_handle);
+}
+
+void StreamedSound::setFilterId(int32 filterId) {
+ ((LastExpress_ADPCMStream *)_as)->setFilterId(filterId);
+}
+
//////////////////////////////////////////////////////////////////////////
// StreamedSound
//////////////////////////////////////////////////////////////////////////
@@ -172,4 +541,8 @@ void AppendableSound::finish() {
_finished = true;
}
+bool AppendableSound::isFinished() {
+ return _as->endOfStream();
+}
+
} // End of namespace LastExpress
diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h
index 95a136ee1c..7111d939e7 100644
--- a/engines/lastexpress/data/snd.h
+++ b/engines/lastexpress/data/snd.h
@@ -55,10 +55,11 @@ public:
virtual ~SimpleSound();
void stop() const;
+ virtual bool isFinished() = 0;
protected:
void loadHeader(Common::SeekableReadStream *in);
- Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size) const;
+ Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId = -1) const;
void play(Audio::AudioStream *as);
uint32 _size; ///< data size
@@ -75,7 +76,14 @@ public:
StreamedSound();
~StreamedSound();
- bool load(Common::SeekableReadStream *stream);
+ bool load(Common::SeekableReadStream *stream, int32 filterId = -1);
+ virtual bool isFinished();
+
+ void setFilterId(int32 filterId);
+
+private:
+ Audio::AudioStream *_as;
+ bool _loaded;
};
class AppendableSound : public SimpleSound {
@@ -87,6 +95,8 @@ public:
void queueBuffer(Common::SeekableReadStream *bufferIn);
void finish();
+ virtual bool isFinished();
+
private:
Audio::QueuingAudioStream *_as;
bool _finished;
diff --git a/engines/lastexpress/resource.h b/engines/lastexpress/resource.h
index 7dc909ab34..9e05a90399 100644
--- a/engines/lastexpress/resource.h
+++ b/engines/lastexpress/resource.h
@@ -26,6 +26,8 @@
#include "lastexpress/data/archive.h"
#include "lastexpress/shared.h"
+#include "common/array.h"
+
namespace LastExpress {
class Background;
diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h
index 69816a3d6c..7b640c773a 100644
--- a/engines/lastexpress/shared.h
+++ b/engines/lastexpress/shared.h
@@ -89,6 +89,27 @@ enum SoundState {
kSoundState2 = 2
};
+enum SoundStatus {
+ kSoundStatus_20 = 0x20,
+ kSoundStatus_40 = 0x40,
+ kSoundStatus_180 = 0x180,
+ kSoundStatusClosed = 0x200,
+ kSoundStatus_400 = 0x400,
+
+ kSoundStatus_8000 = 0x8000,
+ kSoundStatus_20000 = 0x20000,
+ kSoundStatus_100000 = 0x100000,
+ kSoundStatus_20000000 = 0x20000000,
+ kSoundStatus_40000000 = 0x40000000,
+
+ kSoundStatusClear0 = 0x10,
+ kSoundStatusFilter = 0x1F,
+ kSoundStatusCached = 0x80,
+ kSoundStatusClear3 = 0x200,
+ kSoundStatusClear4 = 0x800,
+ kSoundStatusClearAll = 0xFFFFFFE0
+};
+
//////////////////////////////////////////////////////////////////////////
// Time values
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp
index c34bb4f0cc..87d8ccdb30 100644
--- a/engines/lastexpress/sound/entry.cpp
+++ b/engines/lastexpress/sound/entry.cpp
@@ -38,15 +38,15 @@
namespace LastExpress {
+#define SOUNDCACHE_ENTRY_SIZE 92160
+#define FILTER_BUFFER_SIZE 2940
+
//////////////////////////////////////////////////////////////////////////
// SoundEntry
//////////////////////////////////////////////////////////////////////////
SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) {
_type = kSoundTypeNone;
- _currentDataPtr = 0;
- _soundData = NULL;
-
_blockCount = 0;
_time = 0;
@@ -55,7 +55,7 @@ SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) {
_field_34 = 0;
_field_38 = 0;
_field_3C = 0;
- _field_40 = 0;
+ _variant = 0;
_entity = kEntityPlayer;
_field_48 = 0;
_priority = 0;
@@ -63,13 +63,14 @@ SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) {
_subtitle = NULL;
_soundStream = NULL;
+
+ _queued = false;
}
SoundEntry::~SoundEntry() {
- // Entries that have been queued would have their streamed disposed automatically
+ // Entries that have been queued will have their streamed disposed automatically
if (!_soundStream)
SAFE_DELETE(_stream);
-
delete _soundStream;
// Zero passed pointers
@@ -79,18 +80,12 @@ SoundEntry::~SoundEntry() {
void SoundEntry::open(Common::String name, SoundFlag flag, int priority) {
_priority = priority;
setType(flag);
- setStatus(flag);
-
- // Add entry to sound list
- getSoundQueue()->addToQueue(this);
-
- // Add entry to cache and load sound data
- getSoundQueue()->setupCache(this);
- loadSoundData(name);
+ setupStatus(flag);
+ loadStream(name);
}
void SoundEntry::close() {
- _status.status |= kSoundStatusRemoved;
+ _status.status |= kSoundStatusClosed;
// Loop until ready
while (!(_status.status1 & 4) && !(getSoundQueue()->getFlag() & 8) && (getSoundQueue()->getFlag() & 1))
@@ -114,6 +109,43 @@ void SoundEntry::close() {
}
}
+void SoundEntry::play() {
+ if (!_stream) {
+ warning("[SoundEntry::play] stream has been disposed");
+ return;
+ }
+
+ // Prepare sound stream
+ if (!_soundStream)
+ _soundStream = new StreamedSound();
+
+ // Compute current filter id
+ int32 filterId = _status.status & kSoundStatusFilter;
+ // TODO adjust status (based on stepIndex)
+
+ if (_queued) {
+ _soundStream->setFilterId(filterId);
+ } else {
+ _stream->seek(0);
+
+ // Load the stream and start playing
+ _soundStream->load(_stream, filterId);
+
+ _queued = true;
+ }
+}
+
+bool SoundEntry::isFinished() {
+ if (!_stream)
+ return true;
+
+ if (!_soundStream || !_queued)
+ return false;
+
+ // TODO check that all data has been queued
+ return _soundStream->isFinished();
+}
+
void SoundEntry::setType(SoundFlag flag) {
switch (flag & kFlagType9) {
default:
@@ -186,10 +218,10 @@ void SoundEntry::setType(SoundFlag flag) {
}
}
-void SoundEntry::setStatus(SoundFlag flag) {
+void SoundEntry::setupStatus(SoundFlag flag) {
SoundStatus statusFlag = (SoundStatus)flag;
- if (!((statusFlag & 0xFF) & kSoundStatusClear1))
- statusFlag = (SoundStatus)(statusFlag | kSoundStatusClear2);
+ if (!((statusFlag & 0xFF) & kSoundStatusFilter))
+ statusFlag = (SoundStatus)(statusFlag | kSoundStatusCached);
if (((statusFlag & 0xFF00) >> 8) & kSoundStatusClear0)
_status.status = (uint32)statusFlag;
@@ -197,11 +229,7 @@ void SoundEntry::setStatus(SoundFlag flag) {
_status.status = (statusFlag | kSoundStatusClear4);
}
-void SoundEntry::setInCache() {
- _status.status |= kSoundStatusClear2;
-}
-
-void SoundEntry::loadSoundData(Common::String name) {
+void SoundEntry::loadStream(Common::String name) {
_name2 = name;
// Load sound data
@@ -210,11 +238,8 @@ void SoundEntry::loadSoundData(Common::String name) {
if (!_stream)
_stream = getArchive("DEFAULT.SND");
- if (_stream) {
- warning("[Sound::loadSoundData] Not implemented");
- } else {
- _status.status = kSoundStatusRemoved;
- }
+ if (!_stream)
+ _status.status = kSoundStatusClosed;
}
void SoundEntry::update(uint val) {
@@ -225,7 +250,7 @@ void SoundEntry::update(uint val) {
if (val) {
if (getSoundQueue()->getFlag() & 32) {
- _field_40 = val;
+ _variant = val;
value2 = val * 2 + 1;
}
@@ -237,15 +262,65 @@ void SoundEntry::update(uint val) {
}
}
+bool SoundEntry::updateSound() {
+ bool result;
+ char sub[16];
+
+ if (_status.status2 & 4) {
+ result = false;
+ } else {
+ if (_status.status2 & 0x80) {
+ if (_field_48 <= getSound()->getData2()) {
+ _status.status |= 0x20;
+ _status.status &= ~0x8000;
+ strcpy(sub, _name2.c_str());
+
+ int l = strlen(sub) + 1;
+ if (l - 1 > 4)
+ sub[l - 1 - 4] = 0;
+ showSubtitle(sub);
+ }
+ } else {
+ if (!(getSoundQueue()->getFlag() & 0x20)) {
+ if (!(_status.status3 & 8)) {
+ if (_entity) {
+ if (_entity < 0x80) {
+ updateEntryFlag(getSound()->getSoundFlag(_entity));
+ }
+ }
+ }
+ }
+ //if (status.status2 & 0x40 && !((uint32)_status.status & 0x180) && v1->soundBuffer)
+ // Sound_FillSoundBuffer(v1);
+ }
+ result = true;
+ }
+
+ return result;
+}
+
+void SoundEntry::updateEntryFlag(SoundFlag flag) {
+ if (flag) {
+ if (getSoundQueue()->getFlag() & 0x20 && _type != kSoundType9 && _type != kSoundType7)
+ update(flag);
+ else
+ _status.status = flag + (_status.status & ~0x1F);
+ } else {
+ _variant = 0;
+ _status.status |= 0x80u;
+ _status.status &= ~0x10001F;
+ }
+}
+
void SoundEntry::updateState() {
if (getSoundQueue()->getFlag() & 32) {
if (_type != kSoundType9 && _type != kSoundType7 && _type != kSoundType5) {
- uint32 newStatus = _status.status & kSoundStatusClear1;
+ uint32 variant = _status.status & kSoundStatusFilter;
_status.status &= kSoundStatusClearAll;
- _field_40 = newStatus;
- _status.status |= newStatus * 2 + 1;
+ _variant = variant;
+ _status.status |= variant * 2 + 1;
}
}
@@ -253,13 +328,14 @@ void SoundEntry::updateState() {
}
void SoundEntry::reset() {
- _status.status |= kSoundStatusRemoved;
+ _status.status |= kSoundStatusClosed;
_entity = kEntityPlayer;
if (_stream) {
if (!_soundStream) {
SAFE_DELETE(_stream);
} else {
+ // the original stream will be disposed
_soundStream->stop();
SAFE_DELETE(_soundStream);
}
@@ -307,13 +383,6 @@ void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) {
}
}
-void SoundEntry::loadStream() {
- if (!_soundStream)
- _soundStream = new StreamedSound();
-
- _soundStream->load(_stream);
-}
-
//////////////////////////////////////////////////////////////////////////
// SubtitleEntry
//////////////////////////////////////////////////////////////////////////
@@ -335,7 +404,7 @@ void SubtitleEntry::load(Common::String filename, SoundEntry *soundEntry) {
_sound = soundEntry;
// Load subtitle data
- if (_engine->getResourceManager()->hasFile(filename)) {
+ if (_engine->getResourceManager()->hasFile(_filename)) {
if (getSoundQueue()->getSubtitleFlag() & 2)
return;
@@ -369,6 +438,8 @@ void SubtitleEntry::setupAndDraw() {
}
getSoundQueue()->setCurrentSubtitle(this);
+
+ // TODO Missing code
}
void SubtitleEntry::draw() {
@@ -384,13 +455,11 @@ void SubtitleEntry::draw() {
}
void SubtitleEntry::drawOnScreen() {
- getSoundQueue()->setSubtitleFlag(getSoundQueue()->getSubtitleFlag() & -1);
-
if (_data == NULL)
return;
- if (getSoundQueue()->getSubtitleFlag() & 1)
- _engine->getGraphicsManager()->draw(_data, GraphicsManager::kBackgroundOverlay);
+ getSoundQueue()->setSubtitleFlag(getSoundQueue()->getSubtitleFlag() & -2);
+ _engine->getGraphicsManager()->draw(_data, GraphicsManager::kBackgroundOverlay);
}
} // End of namespace LastExpress
diff --git a/engines/lastexpress/sound/entry.h b/engines/lastexpress/sound/entry.h
index 60795332f8..a88b0b7210 100644
--- a/engines/lastexpress/sound/entry.h
+++ b/engines/lastexpress/sound/entry.h
@@ -76,27 +76,6 @@ namespace LastExpress {
class LastExpressEngine;
class SubtitleEntry;
-enum SoundStatus {
- kSoundStatus_20 = 0x20,
- kSoundStatus_40 = 0x40,
- kSoundStatus_180 = 0x180,
- kSoundStatusRemoved = 0x200,
- kSoundStatus_400 = 0x400,
-
- kSoundStatus_8000 = 0x8000,
- kSoundStatus_20000 = 0x20000,
- kSoundStatus_100000 = 0x100000,
- kSoundStatus_20000000 = 0x20000000,
- kSoundStatus_40000000 = 0x40000000,
-
- kSoundStatusClear0 = 0x10,
- kSoundStatusClear1 = 0x1F,
- kSoundStatusClear2 = 0x80,
- kSoundStatusClear3 = 0x200,
- kSoundStatusClear4 = 0x800,
- kSoundStatusClearAll = 0xFFFFFFE0
-};
-
union SoundStatusUnion {
uint32 status;
byte status1;
@@ -119,16 +98,13 @@ public:
void open(Common::String name, SoundFlag flag, int priority);
void close();
-
- void setStatus(SoundFlag flag);
- void setType(SoundFlag flag);
- void setInCache();
- void loadSoundData(Common::String name);
+ void play();
+ void reset();
+ bool isFinished();
void update(uint val);
+ bool updateSound();
void updateState();
- void reset();
-
- void loadStream();
+ void updateEntryFlag(SoundFlag flag);
// Subtitles
void showSubtitle(Common::String filename);
@@ -150,12 +126,7 @@ public:
Common::String getName2() { return _name2; }
// Streams
- Common::SeekableReadStream *getStream() { return _stream; }
- StreamedSound *getStreamedSound() { return _soundStream; }
-
-public:
- // TODO replace by on-the-fly allocated buffer
- void *_soundData;
+ SimpleSound *getSoundStream() { return _soundStream; }
private:
LastExpressEngine *_engine;
@@ -164,18 +135,18 @@ private:
SoundType _type; // int
//int _data;
//int _endOffset;
- int _currentDataPtr;
+ byte * _currentDataPtr;
//int _currentBufferPtr;
int _blockCount;
uint32 _time;
//int _size;
//int _field_28;
- Common::SeekableReadStream *_stream; // int
- //int _field_30;
+ Common::SeekableReadStream *_stream; // The file stream
+ //int _archive;
int _field_34;
int _field_38;
int _field_3C;
- int _field_40;
+ int _variant;
EntityIndex _entity;
int _field_48;
uint32 _priority;
@@ -184,8 +155,13 @@ private:
// original has pointer to the next structure in the list (not used)
SubtitleEntry *_subtitle;
- // Sound stream
- StreamedSound *_soundStream;
+ // Sound buffer & stream
+ bool _queued;
+ StreamedSound *_soundStream; // the filtered sound stream
+
+ void setType(SoundFlag flag);
+ void setupStatus(SoundFlag flag);
+ void loadStream(Common::String name);
};
//////////////////////////////////////////////////////////////////////////
@@ -204,7 +180,7 @@ public:
// Accessors
SoundStatusUnion getStatus() { return _status; }
- SoundEntry *getSoundEntry() { return _sound; }
+ SoundEntry *getSoundEntry() { return _sound; }
private:
LastExpressEngine *_engine;
diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp
index cbd942f082..0a6442ceed 100644
--- a/engines/lastexpress/sound/queue.cpp
+++ b/engines/lastexpress/sound/queue.cpp
@@ -32,18 +32,11 @@
namespace LastExpress {
-#define SOUNDCACHE_ENTRY_SIZE 92160
-#define SOUNDCACHE_MAX_SIZE 6
-
SoundQueue::SoundQueue(LastExpressEngine *engine) : _engine(engine) {
_state = 0;
_currentType = kSoundType16;
_flag = 0;
- // Cache and filter buffers
- memset(&_buffer, 0, sizeof(_buffer));
- _soundCacheData = malloc(6 * SOUNDCACHE_ENTRY_SIZE);
-
_subtitlesFlag = 0;
_currentSubtitle = NULL;
}
@@ -53,17 +46,12 @@ SoundQueue::~SoundQueue() {
SAFE_DELETE(*i);
_soundList.clear();
- // Entries in the cache are just pointers to sound list entries
- _soundCache.clear();
-
for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i)
SAFE_DELETE(*i);
_subtitles.clear();
_currentSubtitle = NULL;
- free(_soundCacheData);
-
// Zero passed pointers
_engine = NULL;
}
@@ -76,14 +64,17 @@ void SoundQueue::handleTimer() {
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) {
SoundEntry *entry = (*i);
- if (entry->getStream() == NULL) {
- SAFE_DELETE(*i);
+
+ // When the entry has stopped playing, we remove his buffer
+ if (entry->isFinished()) {
+ entry->close();
+ SAFE_DELETE(entry);
i = _soundList.reverse_erase(i);
continue;
- } else if (!entry->getStreamedSound()) {
- // TODO: stream any sound in the queue after filtering
- entry->loadStream();
}
+
+ // Queue the entry data, applying filtering
+ entry->play();
}
}
@@ -111,9 +102,80 @@ void SoundQueue::removeFromQueue(Common::String filename) {
}
void SoundQueue::updateQueue() {
- Common::StackLock locker(_mutex);
+ //Common::StackLock locker(_mutex);
+
+ //warning("[Sound::updateQueue] Not implemented");
+
+ int maxPriority = 0;
+ Common::List<SoundEntry *>::iterator lsnd;
+ SoundEntry *msnd;
+
+ bool loopedPlaying;
+
+ loopedPlaying = 0;
+ //++g_sound_flag;
+
+ for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) {
+ if ((*lsnd)->getType() == kSoundType1)
+ break;
+ }
+
+ if (getSoundState() & 1) {
+ if (!(*lsnd) || getFlags()->flag_3 || (*lsnd && (*lsnd)->getTime() > getSound()->getLoopingSoundDuration())) {
+ getSound()->playLoopingSound(0x45);
+ } else {
+ if (getSound()->getData1() && getSound()->getData2() >= getSound()->getData1()) {
+ (*lsnd)->update(getSound()->getData0());
+ getSound()->setData1(0);
+ }
+ }
+ }
+
+ msnd = NULL;
+
+ for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) {
+ if ((*lsnd)->getStatus().status2 & 0x1) { // Sound is stopped
+ // original code
+ //if ((*lsnd)->soundBuffer)
+ // Sound_RemoveSoundDataFromCache(*lsnd);
+ //if ((*lsnd)->archive) {
+ // Archive_SetStatusNotLoaded((*lsnd)->archive);
+ // (*lsnd)->archive = 0;
+ // (*lsnd)->field_28 = 3;
+ //}
+
+ if (_soundList.size() < 6) {
+ if ((*lsnd)->getStatus().status1 & 0x1F) {
+ int pri = (*lsnd)->getPriority() + ((*lsnd)->getStatus().status1 & 0x1F);
+
+ if (pri > maxPriority) {
+ msnd = *lsnd;
+ maxPriority = pri;
+ }
+ }
+ }
+ }
+
+ if (!(*lsnd)->updateSound() && !((*lsnd)->getStatus().status3 & 0x8)) {
+ if (msnd == *lsnd) {
+ maxPriority = 0;
+ msnd = 0;
+ }
+ if (*lsnd) {
+ (*lsnd)->close();
+ SAFE_DELETE(*lsnd);
+ lsnd = _soundList.reverse_erase(lsnd);
+ }
+ }
+ }
+
+
+ // We don't need this
+ //if (msnd)
+ // msnd->updateEntryInternal();
- warning("[Sound::updateQueue] Not implemented");
+ getFlags()->flag_3 = 0;
+ //--g_sound_flag;
}
void SoundQueue::resetQueue() {
@@ -301,11 +363,11 @@ void SoundQueue::updateSubtitles() {
if (!(status & kSoundStatus_40)
|| status & kSoundStatus_180
|| soundEntry->getTime() == 0
- || (status & kSoundStatusClear1) < 6
+ || (status & kSoundStatusFilter) < 6
|| ((getFlags()->nis & 0x8000) && soundEntry->getPriority() < 90)) {
current_index = 0;
} else {
- current_index = soundEntry->getPriority() + (status & kSoundStatusClear1);
+ current_index = soundEntry->getPriority() + (status & kSoundStatusFilter);
if (_currentSubtitle == (*i))
current_index += 4;
@@ -334,66 +396,6 @@ void SoundQueue::updateSubtitles() {
}
//////////////////////////////////////////////////////////////////////////
-// Cache
-//////////////////////////////////////////////////////////////////////////
-bool SoundQueue::setupCache(SoundEntry *entry) {
- if (entry->_soundData)
- return true;
-
- if (_soundCache.size() >= SOUNDCACHE_MAX_SIZE) {
-
- SoundEntry *cacheEntry = NULL;
- uint32 size = 1000;
-
- for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) {
- if (!((*i)->getStatus().status & kSoundStatus_180)) {
- uint32 newSize = (*i)->getPriority() + ((*i)->getStatus().status & kSoundStatusClear1);
-
- if (newSize < size) {
- cacheEntry = (*i);
- size = newSize;
- }
- }
- }
-
- if (entry->getPriority() <= size)
- return false;
-
- if (!cacheEntry)
- error("[SoundManager::setupCache] Cannot find a valid entry");
-
- cacheEntry->setInCache();
-
- // TODO: Wait until the cache entry is ready to be removed
- while (!(cacheEntry->getStatus().status1 & 1))
- ;
-
- if (cacheEntry->_soundData)
- removeFromCache(cacheEntry);
-
- _soundCache.push_back(entry);
- entry->_soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1);
- } else {
- _soundCache.push_back(entry);
- entry->_soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1);
- }
-
- return true;
-}
-
-void SoundQueue::removeFromCache(SoundEntry *entry) {
- for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) {
- if ((*i) == entry) {
- // Remove sound buffer
- entry->_soundData = NULL;
-
- // Remove entry from sound cache
- i = _soundCache.reverse_erase(i);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
// Savegame
//////////////////////////////////////////////////////////////////////////
void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) {
@@ -432,362 +434,13 @@ uint32 SoundQueue::count() {
}
//////////////////////////////////////////////////////////////////////////
-// Sound filters
-//////////////////////////////////////////////////////////////////////////
-static const int filterData[1424] = {
- 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 128, 256,
- 384, 512, 0, 0, 0, 0, 192, 320, 448, 576, 0, 0, 0, 0,
- 192, 320, 448, 576, 64, 64, 64, 64, 256, 384, 512, 640,
- 64, 64, 64, 64, 256, 384, 512, 640, 128, 128, 128, 128,
- 320, 448, 576, 704, 128, 128, 128, 128, 320, 448, 576,
- 704, 192, 192, 192, 192, 384, 512, 640, 768, 192, 192,
- 192, 192, 384, 512, 640, 768, 256, 256, 256, 256, 448,
- 576, 704, 832, 256, 256, 256, 256, 448, 576, 704, 832,
- 320, 320, 320, 320, 512, 640, 768, 896, 320, 320, 320,
- 320, 512, 640, 768, 896, 384, 384, 384, 384, 576, 704,
- 832, 960, 384, 384, 384, 384, 576, 704, 832, 960, 448,
- 448, 448, 448, 640, 768, 896, 1024, 448, 448, 448, 448,
- 640, 768, 896, 1024, 512, 512, 512, 512, 704, 832, 960,
- 1088, 512, 512, 512, 512, 704, 832, 960, 1088, 576,
- 576, 576, 576, 768, 896, 1024, 1152, 576, 576, 576,
- 576, 768, 896, 1024, 1152, 640, 640, 640, 640, 832,
- 960, 1088, 1216, 640, 640, 640, 640, 832, 960, 1088,
- 1216, 704, 704, 704, 704, 896, 1024, 1152, 1280, 704,
- 704, 704, 704, 896, 1024, 1152, 1280, 768, 768, 768,
- 768, 960, 1088, 1216, 1344, 768, 768, 768, 768, 960,
- 1088, 1216, 1344, 832, 832, 832, 832, 1024, 1152, 1280,
- 1408, 832, 832, 832, 832, 1024, 1152, 1280, 1408, 896,
- 896, 896, 896, 1088, 1216, 1344, 1472, 896, 896, 896,
- 896, 1088, 1216, 1344, 1472, 960, 960, 960, 960, 1152,
- 1280, 1408, 1536, 960, 960, 960, 960, 1152, 1280, 1408,
- 1536, 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600,
- 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, 1088,
- 1088, 1088, 1088, 1280, 1408, 1536, 1664, 1088, 1088,
- 1088, 1088, 1280, 1408, 1536, 1664, 1152, 1152, 1152,
- 1152, 1344, 1472, 1600, 1728, 1152, 1152, 1152, 1152,
- 1344, 1472, 1600, 1728, 1216, 1216, 1216, 1216, 1408,
- 1536, 1664, 1792, 1216, 1216, 1216, 1216, 1408, 1536,
- 1664, 1792, 1280, 1280, 1280, 1280, 1472, 1600, 1728,
- 1856, 1280, 1280, 1280, 1280, 1472, 1600, 1728, 1856,
- 1344, 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1344,
- 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1408, 1408,
- 1408, 1408, 1600, 1728, 1856, 1984, 1408, 1408, 1408,
- 1408, 1600, 1728, 1856, 1984, 1472, 1472, 1472, 1472,
- 1664, 1792, 1920, 2048, 1472, 1472, 1472, 1472, 1664,
- 1792, 1920, 2048, 1536, 1536, 1536, 1536, 1728, 1856,
- 1984, 2112, 1536, 1536, 1536, 1536, 1728, 1856, 1984,
- 2112, 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176,
- 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, 1664,
- 1664, 1664, 1664, 1856, 1984, 2112, 2240, 1664, 1664,
- 1664, 1664, 1856, 1984, 2112, 2240, 1728, 1728, 1728,
- 1728, 1920, 2048, 2176, 2304, 1728, 1728, 1728, 1728,
- 1920, 2048, 2176, 2304, 1792, 1792, 1792, 1792, 1984,
- 2112, 2240, 2368, 1792, 1792, 1792, 1792, 1984, 2112,
- 2240, 2368, 1856, 1856, 1856, 1856, 2048, 2176, 2304,
- 2432, 1856, 1856, 1856, 1856, 2048, 2176, 2304, 2432,
- 1920, 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1920,
- 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1984, 1984,
- 1984, 1984, 2176, 2304, 2432, 2560, 1984, 1984, 1984,
- 1984, 2176, 2304, 2432, 2560, 2048, 2048, 2048, 2048,
- 2240, 2368, 2496, 2624, 2048, 2048, 2048, 2048, 2240,
- 2368, 2496, 2624, 2112, 2112, 2112, 2112, 2304, 2432,
- 2560, 2688, 2112, 2112, 2112, 2112, 2304, 2432, 2560,
- 2688, 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752,
- 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, 2240,
- 2240, 2240, 2240, 2432, 2560, 2688, 2816, 2240, 2240,
- 2240, 2240, 2432, 2560, 2688, 2816, 2304, 2304, 2304,
- 2304, 2496, 2624, 2752, 2880, 2304, 2304, 2304, 2304,
- 2496, 2624, 2752, 2880, 2368, 2368, 2368, 2368, 2560,
- 2688, 2816, 2944, 2368, 2368, 2368, 2368, 2560, 2688,
- 2816, 2944, 2432, 2432, 2432, 2432, 2624, 2752, 2880,
- 3008, 2432, 2432, 2432, 2432, 2624, 2752, 2880, 3008,
- 2496, 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2496,
- 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2560, 2560,
- 2560, 2560, 2752, 2880, 3008, 3136, 2560, 2560, 2560,
- 2560, 2752, 2880, 3008, 3136, 2624, 2624, 2624, 2624,
- 2816, 2944, 3072, 3200, 2624, 2624, 2624, 2624, 2816,
- 2944, 3072, 3200, 2688, 2688, 2688, 2688, 2880, 3008,
- 3136, 3264, 2688, 2688, 2688, 2688, 2880, 3008, 3136,
- 3264, 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328,
- 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, 2816,
- 2816, 2816, 2816, 3008, 3136, 3264, 3392, 2816, 2816,
- 2816, 2816, 3008, 3136, 3264, 3392, 2880, 2880, 2880,
- 2880, 3072, 3200, 3328, 3456, 2880, 2880, 2880, 2880,
- 3072, 3200, 3328, 3456, 2944, 2944, 2944, 2944, 3136,
- 3264, 3392, 3520, 2944, 2944, 2944, 2944, 3136, 3264,
- 3392, 3520, 3008, 3008, 3008, 3008, 3200, 3328, 3456,
- 3584, 3008, 3008, 3008, 3008, 3200, 3328, 3456, 3584,
- 3072, 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3072,
- 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3136, 3136,
- 3136, 3136, 3328, 3456, 3584, 3712, 3136, 3136, 3136,
- 3136, 3328, 3456, 3584, 3712, 3200, 3200, 3200, 3200,
- 3392, 3520, 3648, 3776, 3200, 3200, 3200, 3200, 3392,
- 3520, 3648, 3776, 3264, 3264, 3264, 3264, 3456, 3584,
- 3712, 3840, 3264, 3264, 3264, 3264, 3456, 3584, 3712,
- 3840, 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904,
- 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, 3392,
- 3392, 3392, 3392, 3584, 3712, 3840, 3968, 3392, 3392,
- 3392, 3392, 3584, 3712, 3840, 3968, 3456, 3456, 3456,
- 3456, 3648, 3776, 3904, 4032, 3456, 3456, 3456, 3456,
- 3648, 3776, 3904, 4032, 3520, 3520, 3520, 3520, 3712,
- 3840, 3968, 4096, 3520, 3520, 3520, 3520, 3712, 3840,
- 3968, 4096, 3584, 3584, 3584, 3584, 3776, 3904, 4032,
- 4160, 3584, 3584, 3584, 3584, 3776, 3904, 4032, 4160,
- 3648, 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3648,
- 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3712, 3712,
- 3712, 3712, 3904, 4032, 4160, 4288, 3712, 3712, 3712,
- 3712, 3904, 4032, 4160, 4288, 3776, 3776, 3776, 3776,
- 3968, 4096, 4224, 4352, 3776, 3776, 3776, 3776, 3968,
- 4096, 4224, 4352, 3840, 3840, 3840, 3840, 4032, 4160,
- 4288, 4416, 3840, 3840, 3840, 3840, 4032, 4160, 4288,
- 4416, 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480,
- 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, 3968,
- 3968, 3968, 3968, 4160, 4288, 4416, 4544, 3968, 3968,
- 3968, 3968, 4160, 4288, 4416, 4544, 4032, 4032, 4032,
- 4032, 4224, 4352, 4480, 4608, 4032, 4032, 4032, 4032,
- 4224, 4352, 4480, 4608, 4096, 4096, 4096, 4096, 4288,
- 4416, 4544, 4672, 4096, 4096, 4096, 4096, 4288, 4416,
- 4544, 4672, 4160, 4160, 4160, 4160, 4352, 4480, 4608,
- 4736, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736,
- 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4224,
- 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4288, 4288,
- 4288, 4288, 4480, 4608, 4736, 4864, 4288, 4288, 4288,
- 4288, 4480, 4608, 4736, 4864, 4352, 4352, 4352, 4352,
- 4544, 4672, 4800, 4928, 4352, 4352, 4352, 4352, 4544,
- 4672, 4800, 4928, 4416, 4416, 4416, 4416, 4608, 4736,
- 4864, 4992, 4416, 4416, 4416, 4416, 4608, 4736, 4864,
- 4992, 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056,
- 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, 4544,
- 4544, 4544, 4544, 4736, 4864, 4992, 5120, 4544, 4544,
- 4544, 4544, 4736, 4864, 4992, 5120, 4608, 4608, 4608,
- 4608, 4800, 4928, 5056, 5184, 4608, 4608, 4608, 4608,
- 4800, 4928, 5056, 5184, 4672, 4672, 4672, 4672, 4864,
- 4992, 5120, 5248, 4672, 4672, 4672, 4672, 4864, 4992,
- 5120, 5248, 4736, 4736, 4736, 4736, 4928, 5056, 5184,
- 5312, 4736, 4736, 4736, 4736, 4928, 5056, 5184, 5312,
- 4800, 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4800,
- 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4864, 4864,
- 4864, 4864, 5056, 5184, 5312, 5440, 4864, 4864, 4864,
- 4864, 5056, 5184, 5312, 5440, 4928, 4928, 4928, 4928,
- 5120, 5248, 5376, 5504, 4928, 4928, 4928, 4928, 5120,
- 5248, 5376, 5504, 4992, 4992, 4992, 4992, 5184, 5312,
- 5440, 5568, 4992, 4992, 4992, 4992, 5184, 5312, 5440,
- 5568, 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632,
- 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, 5120,
- 5120, 5120, 5120, 5312, 5440, 5568, 5632, 5120, 5120,
- 5120, 5120, 5312, 5440, 5568, 5632, 5184, 5184, 5184,
- 5184, 5376, 5504, 5632, 5632, 5184, 5184, 5184, 5184,
- 5376, 5504, 5632, 5632, 5248, 5248, 5248, 5248, 5440,
- 5568, 5632, 5632, 5248, 5248, 5248, 5248, 5440, 5568,
- 5632, 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632,
- 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, 5632,
- 5376, 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5376,
- 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5440, 5440,
- 5440, 5440, 5632, 5632, 5632, 5632, 5440, 5440, 5440,
- 5440, 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504,
- 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, 5632,
- 5632, 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632,
- 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, 5632,
- 5632
-};
-
-static const int filterData2[1424] = {
- 0, 2, 4, 6, 7, 9, 11, 13, 0, -2, -4, -6, -7, -9, -11,
- -13, 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9,
- -11, -13, -15, 1, 3, 5, 7, 10, 12, 14, 16, -1, -3, -5,
- -7, -10, -12, -14, -16, 1, 3, 6, 8, 11, 13, 16, 18,
- -1, -3, -6, -8, -11, -13, -16, -18, 1, 4, 6, 9, 12,
- 15, 17, 20, -1, -4, -6, -9, -12, -15, -17, -20, 1, 4,
- 7, 10, 13, 16, 19, 22, -1, -4, -7, -10, -13, -16, -19,
- -22, 1, 4, 8, 11, 14, 17, 21, 24, -1, -4, -8, -11, -14,
- -17, -21, -24, 1, 5, 8, 12, 15, 19, 22, 26, -1, -5,
- -8, -12, -15, -19, -22, -26, 2, 6, 10, 14, 18, 22, 26,
- 30, -2, -6, -10, -14, -18, -22, -26, -30, 2, 6, 10,
- 14, 19, 23, 27, 31, -2, -6, -10, -14, -19, -23, -27,
- -31, 2, 7, 11, 16, 21, 26, 30, 35, -2, -7, -11, -16,
- -21, -26, -30, -35, 2, 7, 13, 18, 23, 28, 34, 39, -2,
- -7, -13, -18, -23, -28, -34, -39, 2, 8, 14, 20, 25,
- 31, 37, 43, -2, -8, -14, -20, -25, -31, -37, -43, 3,
- 9, 15, 21, 28, 34, 40, 46, -3, -9, -15, -21, -28, -34,
- -40, -46, 3, 10, 17, 24, 31, 38, 45, 52, -3, -10, -17,
- -24, -31, -38, -45, -52, 3, 11, 19, 27, 34, 42, 50,
- 58, -3, -11, -19, -27, -34, -42, -50, -58, 4, 12, 21,
- 29, 38, 46, 55, 63, -4, -12, -21, -29, -38, -46, -55,
- -63, 4, 13, 23, 32, 41, 50, 60, 69, -4, -13, -23, -32,
- -41, -50, -60, -69, 5, 15, 25, 35, 46, 56, 66, 76, -5,
- -15, -25, -35, -46, -56, -66, -76, 5, 16, 28, 39, 50,
- 61, 73, 84, -5, -16, -28, -39, -50, -61, -73, -84, 6,
- 18, 31, 43, 56, 68, 81, 93, -6, -18, -31, -43, -56,
- -68, -81, -93, 6, 20, 34, 48, 61, 75, 89, 103, -6, -20,
- -34, -48, -61, -75, -89, -103, 7, 22, 37, 52, 67, 82,
- 97, 112, -7, -22, -37, -52, -67, -82, -97, -112, 8,
- 24, 41, 57, 74, 90, 107, 123, -8, -24, -41, -57, -74,
- -90, -107, -123, 9, 27, 45, 63, 82, 100, 118, 136, -9,
- -27, -45, -63, -82, -100, -118, -136, 10, 30, 50, 70,
- 90, 110, 130, 150, -10, -30, -50, -70, -90, -110, -130,
- -150, 11, 33, 55, 77, 99, 121, 143, 165, -11, -33, -55,
- -77, -99, -121, -143, -165, 12, 36, 60, 84, 109, 133,
- 157, 181, -12, -36, -60, -84, -109, -133, -157, -181,
- 13, 40, 66, 93, 120, 147, 173, 200, -13, -40, -66, -93,
- -120, -147, -173, -200, 14, 44, 73, 103, 132, 162, 191,
- 221, -14, -44, -73, -103, -132, -162, -191, -221, 16,
- 48, 81, 113, 146, 178, 211, 243, -16, -48, -81, -113,
- -146, -178, -211, -243, 17, 53, 89, 125, 160, 196, 232,
- 268, -17, -53, -89, -125, -160, -196, -232, -268, 19,
- 58, 98, 137, 176, 215, 255, 294, -19, -58, -98, -137,
- -176, -215, -255, -294, 21, 64, 108, 151, 194, 237,
- 281, 324, -21, -64, -108, -151, -194, -237, -281, -324,
- 23, 71, 118, 166, 213, 261, 308, 356, -23, -71, -118,
- -166, -213, -261, -308, -356, 26, 78, 130, 182, 235,
- 287, 339, 391, -26, -78, -130, -182, -235, -287, -339,
- -391, 28, 86, 143, 201, 258, 316, 373, 431, -28, -86,
- -143, -201, -258, -316, -373, -431, 31, 94, 158, 221,
- 284, 347, 411, 474, -31, -94, -158, -221, -284, -347,
- -411, -474, 34, 104, 174, 244, 313, 383, 453, 523, -34,
- -104, -174, -244, -313, -383, -453, -523, 38, 115, 191,
- 268, 345, 422, 498, 575, -38, -115, -191, -268, -345,
- -422, -498, -575, 42, 126, 210, 294, 379, 463, 547,
- 631, -42, -126, -210, -294, -379, -463, -547, -631,
- 46, 139, 231, 324, 417, 510, 602, 695, -46, -139, -231,
- -324, -417, -510, -602, -695, 51, 153, 255, 357, 459,
- 561, 663, 765, -51, -153, -255, -357, -459, -561, -663,
- -765, 56, 168, 280, 392, 505, 617, 729, 841, -56, -168,
- -280, -392, -505, -617, -729, -841, 61, 185, 308, 432,
- 555, 679, 802, 926, -61, -185, -308, -432, -555, -679,
- -802, -926, 68, 204, 340, 476, 612, 748, 884, 1020,
- -68, -204, -340, -476, -612, -748, -884, -1020, 74,
- 224, 373, 523, 672, 822, 971, 1121, -74, -224, -373,
- -523, -672, -822, -971, -1121, 82, 246, 411, 575, 740,
- 904, 1069, 1233, -82, -246, -411, -575, -740, -904,
- -1069, -1233, 90, 271, 452, 633, 814, 995, 1176, 1357,
- -90, -271, -452, -633, -814, -995, -1176, -1357, 99,
- 298, 497, 696, 895, 1094, 1293, 1492, -99, -298, -497,
- -696, -895, -1094, -1293, -1492, 109, 328, 547, 766,
- 985, 1204, 1423, 1642, -109, -328, -547, -766, -985,
- -1204, -1423, -1642, 120, 361, 601, 842, 1083, 1324,
- 1564, 1805, -120, -361, -601, -842, -1083, -1324, -1564,
- -1805, 132, 397, 662, 927, 1192, 1457, 1722, 1987, -132,
- -397, -662, -927, -1192, -1457, -1722, -1987, 145, 437,
- 728, 1020, 1311, 1603, 1894, 2186, -145, -437, -728,
- -1020, -1311, -1603, -1894, -2186, 160, 480, 801, 1121,
- 1442, 1762, 2083, 2403, -160, -480, -801, -1121, -1442,
- -1762, -2083, -2403, 176, 529, 881, 1234, 1587, 1940,
- 2292, 2645, -176, -529, -881, -1234, -1587, -1940, -2292,
- -2645, 194, 582, 970, 1358, 1746, 2134, 2522, 2910,
- -194, -582, -970, -1358, -1746, -2134, -2522, -2910,
- 213, 640, 1066, 1493, 1920, 2347, 2773, 3200, -213,
- -640, -1066, -1493, -1920, -2347, -2773, -3200, 234,
- 704, 1173, 1643, 2112, 2582, 3051, 3521, -234, -704,
- -1173, -1643, -2112, -2582, -3051, -3521, 258, 774,
- 1291, 1807, 2324, 2840, 3357, 3873, -258, -774, -1291,
- -1807, -2324, -2840, -3357, -3873, 284, 852, 1420, 1988,
- 2556, 3124, 3692, 4260, -284, -852, -1420, -1988, -2556,
- -3124, -3692, -4260, 312, 937, 1561, 2186, 2811, 3436,
- 4060, 4685, -312, -937, -1561, -2186, -2811, -3436,
- -4060, -4685, 343, 1030, 1718, 2405, 3092, 3779, 4467,
- 5154, -343, -1030, -1718, -2405, -3092, -3779, -4467,
- -5154, 378, 1134, 1890, 2646, 3402, 4158, 4914, 5670,
- -378, -1134, -1890, -2646, -3402, -4158, -4914, -5670,
- 415, 1247, 2079, 2911, 3742, 4574, 5406, 6238, -415,
- -1247, -2079, -2911, -3742, -4574, -5406, -6238, 457,
- 1372, 2287, 3202, 4117, 5032, 5947, 6862, -457, -1372,
- -2287, -3202, -4117, -5032, -5947, -6862, 503, 1509,
- 2516, 3522, 4529, 5535, 6542, 7548, -503, -1509, -2516,
- -3522, -4529, -5535, -6542, -7548, 553, 1660, 2767,
- 3874, 4981, 6088, 7195, 8302, -553, -1660, -2767, -3874,
- -4981, -6088, -7195, -8302, 608, 1826, 3044, 4262, 5479,
- 6697, 7915, 9133, -608, -1826, -3044, -4262, -5479,
- -6697, -7915, -9133, 669, 2009, 3348, 4688, 6027, 7367,
- 8706, 10046, -669, -2009, -3348, -4688, -6027, -7367,
- -8706, -10046, 736, 2210, 3683, 5157, 6630, 8104, 9577,
- 11051, -736, -2210, -3683, -5157, -6630, -8104, -9577,
- -11051, 810, 2431, 4052, 5673, 7294, 8915, 10536, 12157,
- -810, -2431, -4052, -5673, -7294, -8915, -10536, -12157,
- 891, 2674, 4457, 6240, 8023, 9806, 11589, 13372, -891,
- -2674, -4457, -6240, -8023, -9806, -11589, -13372, 980,
- 2941, 4903, 6864, 8825, 10786, 12748, 14709, -980, -2941,
- -4903, -6864, -8825, -10786, -12748, -14709, 1078, 3236,
- 5393, 7551, 9708, 11866, 14023, 16181, -1078, -3236,
- -5393, -7551, -9708, -11866, -14023, -16181, 1186, 3559,
- 5933, 8306, 10679, 13052, 15426, 17799, -1186, -3559,
- -5933, -8306, -10679, -13052, -15426, -17799, 1305,
- 3915, 6526, 9136, 11747, 14357, 16968, 19578, -1305,
- -3915, -6526, -9136, -11747, -14357, -16968, -19578,
- 1435, 4307, 7179, 10051, 12922, 15794, 18666, 21538,
- -1435, -4307, -7179, -10051, -12922, -15794, -18666,
- -21538, 1579, 4738, 7896, 11055, 14214, 17373, 20531,
- 23690, -1579, -4738, -7896, -11055, -14214, -17373,
- -20531, -23690, 1737, 5212, 8686, 12161, 15636, 19111,
- 22585, 26060, -1737, -5212, -8686, -12161, -15636, -19111,
- -22585, -26060, 1911, 5733, 9555, 13377, 17200, 21022,
- 24844, 28666, -1911, -5733, -9555, -13377, -17200, -21022,
- -24844, -28666, 2102, 6306, 10511, 14715, 18920, 23124,
- 27329, 31533, -2102, -6306, -10511, -14715, -18920,
- -23124, -27329, -31533, 2312, 6937, 11562, 16187, 20812,
- 25437, 30062, 32767, -2312, -6937, -11562, -16187, -20812,
- -25437, -30062, -32767, 2543, 7631, 12718, 17806, 22893,
- 27981, 32767, 32767, -2543, -7631, -12718, -17806, -22893,
- -27981, -32767, -32767, 2798, 8394, 13990, 19586, 25183,
- 30779, 32767, 32767, -2798, -8394, -13990, -19586, -25183,
- -30779, -32767, -32767, 3077, 9233, 15389, 21545, 27700,
- 32767, 32767, 32767, -3077, -9233, -15389, -21545, -27700,
- -32767, -32767, -32767, 3385, 10157, 16928, 23700, 30471,
- 32767, 32767, 32767, -3385, -10157, -16928, -23700,
- -30471, -32767, -32767, -32767, 3724, 11172, 18621,
- 26069, 32767, 32767, 32767, 32767, -3724, -11172, -18621,
- -26069, -32767, -32767, -32767, -32767, 4095, 12287,
- 20479, 28671, 32767, 32767, 32767, 32767, -4095, -12287,
- -20479, -28671, -32767, -32767, -32767, -32767
-};
-
-static const int p1s[17] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4, 0 };
-static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1 };
-
-static void soundFilter(byte *data, int16 *buffer, int p1, int p2);
-
-void SoundQueue::applyFilter(SoundEntry *entry, int16 *buffer) {
- if ((((byte *)entry->_soundData)[1] << 6) > 0x1600) {
- entry->setStatus(entry->getStatus().status | kSoundStatus_20000000);
- } else {
- int variant = entry->getStatus().status & 0x1f;
-
- soundFilter((byte *)entry->_soundData, buffer, p1s[variant], p2s[variant]);
- }
-}
-
-
-static void soundFilter(byte *data, int16 *buffer, int p1, int p2) {
- int data1, data2, data1p, data2p;
- byte idx;
-
- data2 = data[0];
- data1 = data[1] << 6;
-
- data += 2;
-
- for (int count = 0; count < 735; count++) {
- idx = data[count] >> 4;
- data1p = filterData[idx + data1];
- data2p = CLIP(filterData2[idx + data1] + data2, -32767, 32767);
-
- buffer[2 * count] = (p2 * data2p) >> p1;
-
- idx = data[count] & 0xF;
-
- data1 = filterData[idx + data1p];
- data2 = CLIP(filterData2[idx + data1p] + data2p, -32767, 32767);
- buffer[2 * count + 1] = (p2 * data2) >> p1;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
// Debug
//////////////////////////////////////////////////////////////////////////
void SoundQueue::stopAllSound() {
Common::StackLock locker(_mutex);
for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i)
- (*i)->getStreamedSound()->stop();
+ (*i)->getSoundStream()->stop();
}
} // End of namespace LastExpress
diff --git a/engines/lastexpress/sound/queue.h b/engines/lastexpress/sound/queue.h
index 3748a266e0..75fe06883a 100644
--- a/engines/lastexpress/sound/queue.h
+++ b/engines/lastexpress/sound/queue.h
@@ -78,9 +78,6 @@ public:
void setCurrentSubtitle(SubtitleEntry *entry) { _currentSubtitle = entry; }
SubtitleEntry *getCurrentSubtitle() { return _currentSubtitle; }
- // Cache
- bool setupCache(SoundEntry *entry);
-
// Serializable
void saveLoadWithSerializer(Common::Serializer &ser);
uint32 count();
@@ -109,7 +106,6 @@ private:
// Entries
Common::List<SoundEntry *> _soundList; ///< List of all sound entries
- Common::List<SoundEntry *> _soundCache; ///< List of entries with a data buffer
void *_soundCacheData;
// Subtitles
@@ -117,12 +113,6 @@ private:
Common::List<SubtitleEntry *> _subtitles;
SubtitleEntry *_currentSubtitle;
- // Filters
- int32 _buffer[2940]; ///< Static sound buffer
-
- void removeFromCache(SoundEntry *entry);
- void applyFilter(SoundEntry *entry, int16 *buffer);
-
friend class Debugger;
};
diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp
index c726769495..c04b6d361f 100644
--- a/engines/lastexpress/sound/sound.cpp
+++ b/engines/lastexpress/sound/sound.cpp
@@ -162,13 +162,17 @@ bool SoundManager::playSoundWithSubtitles(Common::String filename, SoundFlag fla
entry->setStatus(entry->getStatus().status | kSoundStatus_8000);
} else {
// Get subtitles name
- while (filename.size() > 4)
+ uint32 size = filename.size();
+ while (filename.size() > size - 4)
filename.deleteLastChar();
entry->showSubtitle(filename);
entry->updateState();
}
+ // Add entry to sound list
+ _queue->addToQueue(entry);
+
return (entry->getType() != kSoundTypeNone);
}
diff --git a/engines/lastexpress/sound/sound.h b/engines/lastexpress/sound/sound.h
index 797e52646e..517543f470 100644
--- a/engines/lastexpress/sound/sound.h
+++ b/engines/lastexpress/sound/sound.h
@@ -64,7 +64,13 @@ public:
// Accessors
SoundQueue *getQueue() { return _queue; }
- uint32 getData2() { return _data2; }
+ uint32 getData0() { return _data0; }
+ int32 getData1() { return _data1; }
+ int32 getData2() { return _data2; }
+ uint32 getLoopingSoundDuration() { return _loopingSoundDuration; }
+
+ // Setters
+ void setData1(int32 data) { _data1 = data; }
private:
LastExpressEngine *_engine;
@@ -78,8 +84,8 @@ private:
// Unknown data
uint32 _data0;
- uint32 _data1;
- uint32 _data2;
+ int32 _data1;
+ int32 _data2;
};
} // End of namespace LastExpress
diff --git a/engines/lure/disk.cpp b/engines/lure/disk.cpp
index 9212508be0..552da73f18 100644
--- a/engines/lure/disk.cpp
+++ b/engines/lure/disk.cpp
@@ -98,7 +98,6 @@ void Disk::openFile(uint8 fileNum) {
error("Could not open %s", sFilename);
char buffer[7];
- uint32 bytesRead;
// If it's the support file, then move to the correct language area
@@ -130,7 +129,7 @@ void Disk::openFile(uint8 fileNum) {
// Validate the header
- bytesRead = _fileHandle->read(buffer, 6);
+ _fileHandle->read(buffer, 6);
buffer[6] = '\0';
if (strcmp(buffer, HEADER_IDENT_STRING) != 0)
error("The file %s was not a valid VGA file", sFilename);
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index 97fbaa72ae..f38bac6e12 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -763,7 +763,7 @@ void Hotspot::showMessage(uint16 messageId, uint16 destCharacterId) {
MemoryBlock *data = res.messagesData();
Hotspot *hotspot;
uint8 *msgData = (uint8 *) data->data();
- uint16 v2, idVal;
+ uint16 idVal;
messageId &= 0x7fff;
// Skip through header to find table for given character
@@ -781,7 +781,6 @@ void Hotspot::showMessage(uint16 messageId, uint16 destCharacterId) {
// Scan through secondary list
uint16 *v = (uint16 *) (msgData + READ_LE_UINT16(msgData + idx + sizeof(uint16)));
- v2 = 0;
while ((idVal = READ_LE_UINT16(v)) != 0xffff) {
++v;
if (READ_LE_UINT16(v) == messageId) break;
diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index cf28e0bb74..85b86a8400 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -31,7 +31,9 @@
#include "common/endian.h"
#include "audio/midiparser.h"
+namespace Common {
DECLARE_SINGLETON(Lure::SoundManager);
+}
namespace Lure {
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index e8c948af4e..1320daaf9d 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -542,7 +542,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- const ADGameDescription *fallbackDetect(const Common::FSList &fslist, const FileMap &allFiles) const;
+ const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
};
@@ -564,7 +564,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame
return gd != 0;
}
-const ADGameDescription *MadeMetaEngine::fallbackDetect(const Common::FSList &fslist, const FileMap &allFiles) const {
+const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// Set the default values for the fallback descriptor's ADGameDescription part.
Made::g_fallbackDesc.desc.language = Common::UNK_LANG;
Made::g_fallbackDesc.desc.platform = Common::kPlatformPC;
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 05012bec3d..e7dc84606c 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -700,14 +700,25 @@ bool LivingBooksConsole::Cmd_DrawImage(int argc, const char **argv) {
}
bool LivingBooksConsole::Cmd_ChangePage(int argc, const char **argv) {
- if (argc == 1) {
- DebugPrintf("Usage: changePage <page> [<mode>]\n");
+ if (argc < 2 || argc > 3) {
+ DebugPrintf("Usage: changePage <page>[.<subpage>] [<mode>]\n");
return true;
}
- if (_vm->tryLoadPageStart(argc == 2 ? _vm->getCurMode() : (LBMode)atoi(argv[2]), atoi(argv[1])))
- return false;
- DebugPrintf("no such page %d\n", atoi(argv[1]));
+ int page, subpage = 0;
+ if (sscanf(argv[1], "%d.%d", &page, &subpage) == 0) {
+ DebugPrintf("Usage: changePage <page>[.<subpage>] [<mode>]\n");
+ return true;
+ }
+ LBMode mode = argc == 2 ? _vm->getCurMode() : (LBMode)atoi(argv[2]);
+ if (subpage == 0) {
+ if (_vm->tryLoadPageStart(mode, page))
+ return false;
+ } else {
+ if (_vm->loadPage(mode, page, subpage))
+ return false;
+ }
+ DebugPrintf("no such page %d.%d\n", page, subpage);
return true;
}
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index 3284a3228f..78e099ccfe 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -252,6 +252,17 @@ void LivingBooksCursorManager_v2::setCursor(uint16 id) {
}
}
+void LivingBooksCursorManager_v2::setCursor(const Common::String &name) {
+ if (!_sysArchive)
+ return;
+
+ uint16 id = _sysArchive->findResourceID(ID_TCUR, name);
+ if (id == 0xffff)
+ error("Could not find cursor '%s'", name.c_str());
+ else
+ setCursor(id);
+}
+
PECursorManager::PECursorManager(const Common::String &appName) {
_exe = new Common::PEResources();
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index d92b6b4285..7bfa491904 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -56,6 +56,7 @@ public:
virtual void showCursor();
virtual void hideCursor();
virtual void setCursor(uint16 id);
+ virtual void setCursor(const Common::String &name) {}
virtual void setDefaultCursor();
virtual bool hasSource() const { return false; }
@@ -157,6 +158,7 @@ public:
~LivingBooksCursorManager_v2();
void setCursor(uint16 id);
+ void setCursor(const Common::String &name);
bool hasSource() const { return _sysArchive != 0; }
private:
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 2243dd1c1d..01eac0aaba 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -1474,6 +1474,21 @@ static const MohawkGameDescription gameDescriptions[] = {
0
},
+ {
+ {
+ "arthurrace",
+ "",
+ AD_ENTRY1("BookOutline", "f0a9251824a648fce1b49cb7c1a0ba67"),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_UNSTABLE,
+ Common::GUIO_NONE
+ },
+ GType_LIVINGBOOKSV3,
+ 0,
+ 0
+ },
+
// From zerep in bug #3287894
{
{
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 06500bc725..f9d18ff7ff 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -87,8 +87,14 @@ void LBPage::open(Archive *mhk, uint16 baseId) {
_baseId = baseId;
_vm->addArchive(_mhk);
- if (_vm->hasResource(ID_BCOD, baseId))
+ if (!_vm->hasResource(ID_BCOD, baseId)) {
+ // assume that BCOD is mandatory for v4/v5
+ if (_vm->getGameType() == GType_LIVINGBOOKSV4 || _vm->getGameType() == GType_LIVINGBOOKSV5)
+ error("missing BCOD resource (id %d)", baseId);
+ _code = new LBCode(_vm, 0);
+ } else {
_code = new LBCode(_vm, baseId);
+ }
loadBITL(baseId);
for (uint i = 0; i < _items.size(); i++)
@@ -2300,8 +2306,6 @@ void LBItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian *
{
assert(size == 4);
uint offset = stream->readUint32();
- if (!_page->_code)
- error("no BCOD?");
_page->_code->runCode(this, offset);
}
break;
@@ -2823,8 +2827,6 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) {
break;
case kLBOpSendExpression:
- if (!_page->_code)
- error("no BCOD?");
_page->_code->runCode(this, entry->offset);
break;
@@ -2858,8 +2860,6 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) {
case kLBOpJumpUnlessExpression:
case kLBOpBreakExpression:
case kLBOpJumpToExpression:
- if (!_page->_code)
- error("no BCOD?");
{
LBValue r = _page->_code->runCode(this, entry->offset);
// FIXME
@@ -2884,257 +2884,24 @@ void LBItem::setNextTime(uint16 min, uint16 max, uint32 start) {
debug(9, "nextTime is now %d frames away", _nextTime - (uint)(_vm->_system->getMillis() / 16));
}
-enum LBTokenType {
- kLBNoToken,
- kLBNameToken,
- kLBStringToken,
- kLBOperatorToken,
- kLBIntegerToken,
- kLBEndToken
-};
-
-static Common::String readToken(const Common::String &source, uint &pos, LBTokenType &type) {
- Common::String token;
- type = kLBNoToken;
-
- bool done = false;
- while (pos < source.size() && !done) {
- if (type == kLBStringToken) {
- if (source[pos] == '"') {
- pos++;
- return token;
- }
-
- token += source[pos];
- pos++;
- continue;
- }
-
- switch (source[pos]) {
- case ' ':
- pos++;
- done = true;
- break;
-
- case ')':
- if (type == kLBNoToken) {
- type = kLBEndToken;
- return Common::String();
- }
- done = true;
- break;
-
- case ';':
- if (type == kLBNoToken) {
- pos++;
- type = kLBEndToken;
- return Common::String();
- }
- done = true;
- break;
-
- case '@':
- // FIXME
- error("found @ in string '%s', not supported yet", source.c_str());
-
- case '+':
- case '-':
- case '!':
- case '=':
- case '>':
- case '<':
- if (type == kLBNoToken)
- type = kLBOperatorToken;
- if (type == kLBOperatorToken)
- token += source[pos];
- else
- done = true;
- break;
-
- case '"':
- if (type == kLBNoToken)
- type = kLBStringToken;
- else
- done = true;
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (type == kLBNoToken)
- type = kLBIntegerToken;
- if (type == kLBNameToken || type == kLBIntegerToken)
- token += source[pos];
- else
- done = true;
- break;
-
- default:
- if (type == kLBNoToken)
- type = kLBNameToken;
- if (type == kLBNameToken)
- token += source[pos];
- else
- done = true;
- break;
- }
-
- if (!done)
- pos++;
- }
-
- if (type == kLBStringToken)
- error("readToken: ran out of input while parsing string from '%s'", source.c_str());
-
- if (!token.size()) {
- assert(type == kLBNoToken);
- type = kLBEndToken;
- }
-
- return token;
-}
-
-LBValue LBItem::parseValue(const Common::String &source, uint &pos) {
- LBTokenType type, postOpType;
- Common::String preOp, postOp;
-
- Common::String str = readToken(source, pos, type);
- if (type == kLBOperatorToken) {
- preOp = str;
- str = readToken(source, pos, type);
- }
-
- LBValue value;
- if (type == kLBStringToken) {
- value.type = kLBValueString;
- value.string = str;
- } else if (type == kLBIntegerToken) {
- value.type = kLBValueInteger;
- value.integer = atoi(str.c_str());
- } else if (type == kLBNameToken) {
- value = _vm->_variables[str];
- } else {
- error("expected string/integer as value in '%s', got '%s'", source.c_str(), str.c_str());
- }
-
- uint readAheadPos = pos;
- postOp = readToken(source, readAheadPos, postOpType);
- if (postOpType != kLBEndToken) {
- if (postOpType != kLBOperatorToken)
- error("expected operator after '%s' in '%s', got '%s'", str.c_str(), source.c_str(), postOp.c_str());
- // might be a comparison operator, caller will handle other cases if valid
- if (postOp == "-" || postOp == "+") {
- pos = readAheadPos;
- LBValue nextValue = parseValue(source, pos);
- if (value.type != kLBValueInteger || nextValue.type != kLBValueInteger)
- error("expected integer for arthmetic operator in '%s'", source.c_str());
- if (postOp == "+")
- value.integer += nextValue.integer;
- else if (postOp == "-")
- value.integer -= nextValue.integer;
- }
- }
-
- if (preOp.size()) {
- if (preOp == "!") {
- if (value.type == kLBValueInteger)
- value.integer = !value.integer;
- else
- error("expected integer after ! operator in '%s'", source.c_str());
- } else {
- error("expected valid operator before '%s' in '%s', got '%s'", str.c_str(), source.c_str(), preOp.c_str());
- }
- }
-
- return value;
-}
-
void LBItem::runCommand(const Common::String &command) {
- uint pos = 0;
- LBTokenType type;
+ LBCode tempCode(_vm, 0);
debug(2, "running command '%s'", command.c_str());
- while (pos < command.size()) {
- Common::String varname = readToken(command, pos, type);
- if (type != kLBNameToken)
- error("expected name as lvalue of command '%s', got '%s'", command.c_str(), varname.c_str());
- Common::String op = readToken(command, pos, type);
- if (type != kLBOperatorToken || (op != "=" && op != "++" && op != "--"))
- error("expected assignment/postincrement/postdecrement operator for command '%s', got '%s'", command.c_str(), op.c_str());
-
- if (op == "=") {
- LBValue value = parseValue(command, pos);
- _vm->_variables[varname] = value;
- } else {
- if (_vm->_variables[varname].type != kLBValueInteger)
- error("expected integer after postincrement/postdecrement operator in '%s'", command.c_str());
- if (op == "++")
- _vm->_variables[varname].integer++;
- else if (op == "--")
- _vm->_variables[varname].integer--;
- }
-
- if (pos < command.size() && command[pos] == ';')
- pos++;
- }
+ uint offset = tempCode.parseCode(command);
+ tempCode.runCode(this, offset);
}
bool LBItem::checkCondition(const Common::String &condition) {
- uint pos = 0;
- LBTokenType type;
+ LBCode tempCode(_vm, 0);
debug(3, "checking condition '%s'", condition.c_str());
- if (condition.size() <= pos || condition[pos] != '(')
- error("bad condition '%s' (started wrong)", condition.c_str());
- pos++;
-
- LBValue value1 = parseValue(condition, pos);
-
- Common::String op = readToken(condition, pos, type);
- if (type == kLBEndToken) {
- if (condition.size() != pos + 1 || condition[pos] != ')')
- error("bad condition '%s' (ended wrong)", condition.c_str());
-
- if (value1.type == kLBValueInteger)
- return value1.integer;
- else
- error("expected comparison operator for condition '%s'", condition.c_str());
- }
- if (type != kLBOperatorToken || (op != "!=" && op != "==" && op != ">" && op != "<" && op != ">=" && op != "<="))
- error("expected comparison operator for condition '%s', got '%s'", condition.c_str(), op.c_str());
-
- LBValue value2 = parseValue(condition, pos);
-
- if (condition.size() != pos + 1 || condition[pos] != ')')
- error("bad condition '%s' (ended wrong)", condition.c_str());
-
- if (op == "!=")
- return (value1 != value2);
- else if (op == "==")
- return (value1 == value2);
-
- if (value1.type != kLBValueInteger || value2.type != kLBValueInteger)
- error("evaluation operator %s in condition '%s' expected two integer operands!", op.c_str(), condition.c_str());
-
- if (op == ">")
- return (value1.integer > value2.integer);
- else if (op == ">=")
- return (value1.integer >= value2.integer);
- else if (op == "<")
- return (value1.integer < value2.integer);
- else if (op == "<=")
- return (value1.integer <= value2.integer);
+ uint offset = tempCode.parseCode(condition);
+ LBValue result = tempCode.runCode(this, offset);
- return false; // unreachable
+ return result.toInt();
}
LBSoundItem::LBSoundItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) {
diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h
index ed198a60c1..ad2fe56a52 100644
--- a/engines/mohawk/livingbooks.h
+++ b/engines/mohawk/livingbooks.h
@@ -434,7 +434,6 @@ protected:
void runScript(uint event, uint16 data = 0, uint16 from = 0);
int runScriptEntry(LBScriptEntry *entry);
- LBValue parseValue(const Common::String &command, uint &pos);
void runCommand(const Common::String &command);
bool checkCondition(const Common::String &condition);
@@ -689,6 +688,7 @@ public:
LBMode getCurMode() { return _curMode; }
bool tryLoadPageStart(LBMode mode, uint page);
+ bool loadPage(LBMode mode, uint page, uint subpage);
void prevPage();
void nextPage();
@@ -717,7 +717,6 @@ private:
Common::Queue<DelayedEvent> _eventQueue;
LBItem *_focus;
void destroyPage();
- bool loadPage(LBMode mode, uint page, uint subpage);
void updatePage();
uint16 _lastSoundOwner, _lastSoundId;
diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp
index e72318d86a..e9ef2516e2 100644
--- a/engines/mohawk/livingbooks_code.cpp
+++ b/engines/mohawk/livingbooks_code.cpp
@@ -127,6 +127,12 @@ Common::Rect LBValue::toRect() const {
}
LBCode::LBCode(MohawkEngine_LivingBooks *vm, uint16 baseId) : _vm(vm) {
+ if (!baseId) {
+ _data = NULL;
+ _size = 0;
+ return;
+ }
+
Common::SeekableSubReadStreamEndian *bcodStream = _vm->wrapStreamEndian(ID_BCOD, baseId);
uint32 totalSize = bcodStream->readUint32();
@@ -172,12 +178,8 @@ LBValue LBCode::runCode(LBItem *src, uint32 offset) {
}
void LBCode::nextToken() {
- if (_currOffset + 1 >= _size) {
- // TODO
- warning("went off the end of code");
- _currToken = kTokenEndOfFile;
- _currValue = LBValue();
- return;
+ if (_currOffset >= _size) {
+ error("went off the end of code");
}
_currToken = _data[_currOffset++];
@@ -186,6 +188,8 @@ void LBCode::nextToken() {
switch (_currToken) {
case kTokenIdentifier:
{
+ if (_currOffset + 2 > _size)
+ error("went off the end of code reading identifier");
uint16 offset = READ_BE_UINT16(_data + _currOffset);
// TODO: check string exists
_currValue = _strings[offset];
@@ -195,9 +199,13 @@ void LBCode::nextToken() {
case kTokenLiteral:
{
+ if (_currOffset + 1 > _size)
+ error("went off the end of code reading literal");
byte literalType = _data[_currOffset++];
switch (literalType) {
case kLBCodeLiteralInteger:
+ if (_currOffset + 2 > _size)
+ error("went off the end of code reading literal integer");
_currValue = READ_BE_UINT16(_data + _currOffset);
_currOffset += 2;
break;
@@ -211,6 +219,8 @@ void LBCode::nextToken() {
case kTokenConstEventId:
case 0x5e: // TODO: ??
case kTokenKeycode:
+ if (_currOffset + 2 > _size)
+ error("went off the end of code reading immediate");
_currValue = READ_BE_UINT16(_data + _currOffset);
_currOffset += 2;
break;
@@ -227,6 +237,8 @@ void LBCode::nextToken() {
case kTokenString:
{
+ if (_currOffset + 2 > _size)
+ error("went off the end of code reading string");
uint16 offset = READ_BE_UINT16(_data + _currOffset);
// TODO: check string exists
_currValue = _strings[offset];
@@ -265,27 +277,27 @@ LBValue LBCode::runCode(byte terminator) {
void LBCode::parseStatement() {
parseComparisons();
- if (_currToken != kTokenAnd && _currToken != kTokenOr)
- return;
- byte op = _currToken;
- if (op == kTokenAnd)
- debugN(" && ");
- else
- debugN(" || ");
+ while (_currToken == kTokenAnd || _currToken == kTokenOr) {
+ byte op = _currToken;
+ if (op == kTokenAnd)
+ debugN(" && ");
+ else
+ debugN(" || ");
- nextToken();
- parseComparisons();
+ nextToken();
+ parseComparisons();
- LBValue val2 = _stack.pop();
- LBValue val1 = _stack.pop();
- bool result;
- if (op == kTokenAnd)
- result = !val1.isZero() && !val2.isZero();
- else
- result = !val1.isZero() || !val2.isZero();
+ LBValue val2 = _stack.pop();
+ LBValue val1 = _stack.pop();
+ bool result;
+ if (op == kTokenAnd)
+ result = !val1.isZero() && !val2.isZero();
+ else
+ result = !val1.isZero() || !val2.isZero();
- debugN(" [--> %s]", result ? "true" : "false");
- _stack.push(result);
+ debugN(" [--> %s]", result ? "true" : "false");
+ _stack.push(result);
+ }
}
void LBCode::parseComparisons() {
@@ -353,49 +365,95 @@ void LBCode::parseComparisons() {
void LBCode::parseConcat() {
parseArithmetic1();
- if (_currToken != kTokenConcat)
- return;
-
- debugN(" & ");
- nextToken();
- parseArithmetic1();
+ while (_currToken == kTokenConcat) {
+ debugN(" & ");
+ nextToken();
+ parseArithmetic1();
- LBValue val2 = _stack.pop();
- LBValue val1 = _stack.pop();
- Common::String result = val1.toString() + val2.toString();
- debugN(" [--> \"%s\"]", result.c_str());
- _stack.push(result);
+ LBValue val2 = _stack.pop();
+ LBValue val1 = _stack.pop();
+ Common::String result = val1.toString() + val2.toString();
+ debugN(" [--> \"%s\"]", result.c_str());
+ _stack.push(result);
+ }
}
void LBCode::parseArithmetic1() {
parseArithmetic2();
- if (_currToken != kTokenMinus && _currToken != kTokenPlus)
- return;
-
- byte op = _currToken;
- if (op == kTokenMinus)
- debugN(" - ");
- else if (op == kTokenPlus)
- debugN(" + ");
+ while (_currToken == kTokenMinus || _currToken == kTokenPlus) {
+ byte op = _currToken;
+ if (op == kTokenMinus)
+ debugN(" - ");
+ else if (op == kTokenPlus)
+ debugN(" + ");
- nextToken();
- parseArithmetic2();
-
- LBValue val2 = _stack.pop();
- LBValue val1 = _stack.pop();
- LBValue result;
- // TODO: cope with non-integers
- if (op == kTokenMinus)
- result = val1.toInt() - val2.toInt();
- else
- result = val1.toInt() + val2.toInt();
- _stack.push(result);
+ nextToken();
+ parseArithmetic2();
+
+ LBValue val2 = _stack.pop();
+ LBValue val1 = _stack.pop();
+ LBValue result;
+ // TODO: cope with non-integers
+ if (op == kTokenMinus)
+ result = val1.toInt() - val2.toInt();
+ else
+ result = val1.toInt() + val2.toInt();
+ debugN(" [--> %d]", result.toInt());
+ _stack.push(result);
+ }
}
void LBCode::parseArithmetic2() {
- // FIXME: other math operators
parseMain();
+
+ while (true) {
+ byte op = _currToken;
+ switch (op) {
+ case kTokenMultiply:
+ debugN(" * ");
+ break;
+ case kTokenDivide:
+ debugN(" / ");
+ break;
+ case kTokenIntDivide:
+ debugN(" div ");
+ break;
+ case kTokenModulo:
+ debugN(" %% ");
+ break;
+ default:
+ return;
+ }
+
+ nextToken();
+ parseMain();
+
+ LBValue val2 = _stack.pop();
+ LBValue val1 = _stack.pop();
+ LBValue result;
+ // TODO: cope with non-integers
+ if (op == kTokenMultiply) {
+ result = val1.toInt() * val2.toInt();
+ } else if (val2.toInt() == 0) {
+ result = 1;
+ } else {
+ switch (op) {
+ case kTokenDivide:
+ // TODO: fp divide
+ result = val1.toInt() / val2.toInt();
+ break;
+ case kTokenIntDivide:
+ result = val1.toInt() / val2.toInt();
+ break;
+ case kTokenModulo:
+ result = val1.toInt() % val2.toInt();
+ break;
+ }
+ }
+
+ _stack.push(result);
+ }
}
void LBCode::parseMain() {
@@ -549,6 +607,16 @@ void LBCode::parseMain() {
}
}
+LBItem *LBCode::resolveItem(const LBValue &value) {
+ if (value.type == kLBValueItemPtr)
+ return value.item;
+ if (value.type == kLBValueString)
+ return _vm->getItemByName(value.string);
+ if (value.type == kLBValueInteger)
+ return _vm->getItemById(value.integer);
+ return NULL;
+}
+
Common::Array<LBValue> LBCode::readParams() {
Common::Array<LBValue> params;
@@ -616,8 +684,8 @@ struct CodeCommandInfo {
#define NUM_GENERAL_COMMANDS 129
CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = {
- { "eval", 0 },
- { "random", 0 },
+ { "eval", &LBCode::cmdEval },
+ { "random", &LBCode::cmdRandom },
{ "stringLen", 0 },
{ "substring", 0 },
{ "max", 0 },
@@ -773,6 +841,26 @@ void LBCode::cmdUnimplemented(const Common::Array<LBValue> &params) {
warning("unimplemented command called");
}
+void LBCode::cmdEval(const Common::Array<LBValue> &params) {
+ // FIXME: v4 eval is different?
+ if (params.size() != 1)
+ error("incorrect number of parameters (%d) to eval", params.size());
+
+ LBCode tempCode(_vm, 0);
+
+ uint offset = tempCode.parseCode(params[0].toString());
+ _stack.push(tempCode.runCode(_currSource, offset));
+}
+
+void LBCode::cmdRandom(const Common::Array<LBValue> &params) {
+ if (params.size() != 2)
+ error("incorrect number of parameters (%d) to random", params.size());
+
+ int min = params[0].toInt();
+ int max = params[1].toInt();
+ _stack.push(_vm->_rnd->getRandomNumberRng(min, max));
+}
+
void LBCode::cmdGetRect(const Common::Array<LBValue> &params) {
if (params.size() < 2) {
_stack.push(getRectFromParams(params));
@@ -915,7 +1003,7 @@ CodeCommandInfo itemCommandInfo[NUM_ITEM_COMMANDS] = {
{ "moveTo", &LBCode::itemMoveTo },
{ "mute", 0 },
{ "play", 0 },
- { "seek", 0 },
+ { "seek", &LBCode::itemSeek },
{ "seekToFrame", 0 },
{ "setParent", &LBCode::itemSetParent },
{ "setZOrder", 0 },
@@ -951,6 +1039,17 @@ void LBCode::itemMoveTo(const Common::Array<LBValue> &params) {
warning("ignoring moveTo");
}
+void LBCode::itemSeek(const Common::Array<LBValue> &params) {
+ if (params.size() != 2)
+ error("incorrect number of parameters (%d) to seek", params.size());
+
+ LBItem *item = resolveItem(params[0]);
+ if (!item)
+ error("attempted seek on invalid item (%s)", params[0].toString().c_str());
+ uint seekTo = params[1].toInt();
+ item->seek(seekTo);
+}
+
void LBCode::itemSetParent(const Common::Array<LBValue> &params) {
if (params.size() > 2)
error("incorrect number of parameters (%d) to setParent", params.size());
@@ -1035,4 +1134,278 @@ void LBCode::runNotifyCommand() {
}
}
+/*
+ * Helper function for parseCode/parseCodeSymbol:
+ * Returns an unused string id.
+ */
+uint LBCode::nextFreeString() {
+ for (uint i = 0; i <= 0xffff; i++) {
+ if (!_strings.contains(i))
+ return i;
+ }
+
+ error("nextFreeString couldn't find a space");
+}
+
+/*
+ * Helper function for parseCode:
+ * Given a name, appends the appropriate data to the provided code array and
+ * returns true if it's a function, or false otherwise.
+ */
+bool LBCode::parseCodeSymbol(const Common::String &name, uint &pos, Common::Array<byte> &code) {
+ // first, check whether the name matches a known function
+ for (uint i = 0; i < 2; i++) {
+ byte cmdToken;
+ CodeCommandInfo *cmdInfo;
+ uint cmdCount;
+
+ switch (i) {
+ case 0:
+ cmdInfo = generalCommandInfo;
+ cmdToken = kTokenGeneralCommand;
+ cmdCount = NUM_GENERAL_COMMANDS;
+ break;
+ case 1:
+ cmdInfo = itemCommandInfo;
+ cmdToken = kTokenItemCommand;
+ cmdCount = NUM_ITEM_COMMANDS;
+ break;
+ }
+
+ for (uint n = 0; n < cmdCount; n++) {
+ const char *cmdName = cmdInfo[n].name;
+ if (!cmdName)
+ continue;
+ if (!name.equalsIgnoreCase(cmdName))
+ continue;
+
+ // found a matching function
+ code.push_back(cmdToken);
+ code.push_back(n + 1);
+ return true;
+ }
+ }
+
+ // not a function, so must be an identifier
+ code.push_back(kTokenIdentifier);
+
+ uint stringId = nextFreeString();
+ _strings[stringId] = name;
+
+ char tmp[2];
+ WRITE_BE_UINT16(tmp, (int16)stringId);
+ code.push_back(tmp[0]);
+ code.push_back(tmp[1]);
+
+ return false;
+}
+
+/*
+ * Parse a string for later execution, and return the offset where it was
+ * stored.
+ */
+uint LBCode::parseCode(const Common::String &source) {
+ struct LBCodeOperator {
+ byte token;
+ byte op;
+ byte lookahead1;
+ byte lookahead1Op;
+ byte lookahead2;
+ byte lookahead2Op;
+ };
+
+ #define NUM_LB_OPERATORS 11
+ static const LBCodeOperator operators[NUM_LB_OPERATORS] = {
+ { '+', kTokenPlus, '+', kTokenPlusPlus, '=', kTokenPlusEquals },
+ { '-', kTokenMinus, '-', kTokenMinusMinus, '=', kTokenMinusEquals },
+ { '/', kTokenDivide, '=', kTokenDivideEquals, 0, 0 },
+ { '*', kTokenMultiply, '=', kTokenMultiplyEquals, 0, 0 },
+ { '=', kTokenAssign, '=', kTokenEquals, 0, 0 },
+ { '>', kTokenGreaterThan, '=', kTokenGreaterThanEq, 0, 0 },
+ { '<', kTokenLessThan, '=', kTokenLessThanEq, 0, 0 },
+ { '!', kTokenNot, '=', kTokenNotEq, 0, 0 },
+ { '&', kTokenConcat, '&', kTokenAnd, '=', kTokenAndEquals },
+ { '|', 0, '|', kTokenOr, 0, 0 },
+ { ';', kTokenEndOfStatement, 0, 0, 0, 0 }
+ };
+
+ uint pos = 0;
+ Common::Array<byte> code;
+ Common::Array<uint> counterPositions;
+ bool wasFunction = false;
+
+ while (pos < source.size()) {
+ byte token = source[pos];
+ byte lookahead = 0;
+ if (pos + 1 < source.size())
+ lookahead = source[pos + 1];
+ pos++;
+
+ if (token != ' ' && token != '(' && wasFunction)
+ error("while parsing script '%s', encountered incomplete function call", source.c_str());
+
+ // First, we check for simple operators.
+ for (uint i = 0; i < NUM_LB_OPERATORS; i++) {
+ if (token != operators[i].token)
+ continue;
+ if (lookahead) {
+ if (lookahead == operators[i].lookahead1) {
+ code.push_back(operators[i].lookahead1Op);
+ token = 0;
+ } else if (lookahead == operators[i].lookahead2) {
+ code.push_back(operators[i].lookahead2Op);
+ token = 0;
+ }
+ if (!token) {
+ pos++;
+ break;
+ }
+ }
+ if (operators[i].op) {
+ code.push_back(operators[i].op);
+ token = 0;
+ }
+ break;
+ }
+ if (!token)
+ continue;
+
+ // Then, we check for more complex tokens.
+ switch (token) {
+ // whitespace
+ case ' ':
+ // ignore
+ break;
+ // literal string
+ case '"':
+ case '\'':
+ {
+ Common::String tempString;
+ while (pos < source.size()) {
+ if (source[pos] == token)
+ break;
+ tempString += source[pos++];
+ }
+ if (pos++ == source.size())
+ error("while parsing script '%s', string had no end", source.c_str());
+
+ code.push_back(kTokenString);
+
+ uint stringId = nextFreeString();
+ _strings[stringId] = tempString;
+
+ char tmp[2];
+ WRITE_BE_UINT16(tmp, (int16)stringId);
+ code.push_back(tmp[0]);
+ code.push_back(tmp[1]);
+ }
+ break;
+ // open bracket
+ case '(':
+ if (wasFunction) {
+ // function call parameters
+ wasFunction = false;
+ // we will need to back-patch the parameter count,
+ // if parameters are encountered
+ counterPositions.push_back(code.size());
+ code.push_back(1);
+ // if the next token is a ) then there are no
+ // parameters, otherwise start with 1 and increment
+ // if/when we encounter commas
+ for (uint i = pos; i < source.size(); i++) {
+ if (source[i] == ' ')
+ continue;
+ if (source[i] != ')')
+ break;
+ code[code.size() - 1] = 0;
+ break;
+ }
+ } else {
+ // brackets around expression
+ counterPositions.push_back(0);
+ }
+ code.push_back(kTokenOpenBracket);
+ break;
+ // close bracket
+ case ')':
+ if (counterPositions.empty())
+ error("while parsing script '%s', encountered unmatched )", source.c_str());
+ counterPositions.pop_back();
+ code.push_back(kTokenCloseBracket);
+ break;
+ // comma (seperating function params)
+ case ',':
+ {
+ if (counterPositions.empty())
+ error("while parsing script '%s', encountered unexpected ,", source.c_str());
+ code.push_back(kTokenComma);
+ uint counterPos = counterPositions.back();
+ if (!counterPos)
+ error("while parsing script '%s', encountered , outside parameter list", source.c_str());
+ code[counterPos]++;
+ }
+ break;
+ // old-style explicit function call
+ case '@':
+ {
+ Common::String tempString;
+ while (pos < source.size()) {
+ if (!isalpha(source[pos]) && !isdigit(source[pos]))
+ break;
+ tempString += source[pos++];
+ }
+ wasFunction = parseCodeSymbol(tempString, pos, code);
+ if (!wasFunction)
+ error("while parsing script '%s', encountered explicit function call to unknown function '%s'",
+ source.c_str(), tempString.c_str());
+ }
+ break;
+ default:
+ if (isdigit(token)) {
+ const char *in = source.c_str() + pos - 1;
+ // FIXME: handle floats?
+ char *endptr;
+ long int intValue = strtol(in, &endptr, 0);
+ assert(endptr > in);
+ pos += (endptr - in) - 1;
+
+ // FIXME: handle storing longs if needed
+ code.push_back(kTokenLiteral);
+ code.push_back(kLBCodeLiteralInteger);
+ char tmp[2];
+ WRITE_BE_UINT16(tmp, (int16)intValue);
+ code.push_back(tmp[0]);
+ code.push_back(tmp[1]);
+ } else if (isalpha(token)) {
+ Common::String tempString;
+ tempString += token;
+ while (pos < source.size()) {
+ if (!isalpha(source[pos]) && !isdigit(source[pos]))
+ break;
+ tempString += source[pos++];
+ }
+ wasFunction = parseCodeSymbol(tempString, pos, code);
+ } else {
+ error("while parsing script '%s', couldn't parse '%c'", source.c_str(), token);
+ }
+ }
+ }
+
+ if (wasFunction)
+ error("while parsing script '%s', encountered incomplete function call", source.c_str());
+ if (counterPositions.size())
+ error("while parsing script '%s', unmatched (", source.c_str());
+
+ code.push_back(kTokenEndOfFile);
+
+ uint codeOffset = _size;
+ byte *newData = new byte[_size + code.size()];
+ memcpy(newData, _data, _size);
+ memcpy(newData, &code[0], code.size());
+ delete[] _data;
+ _data = newData;
+ _size += code.size();
+ return codeOffset;
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h
index 9602e2d22d..9c58ed7a46 100644
--- a/engines/mohawk/livingbooks_code.h
+++ b/engines/mohawk/livingbooks_code.h
@@ -181,6 +181,7 @@ public:
~LBCode();
LBValue runCode(LBItem *src, uint32 offset);
+ uint parseCode(const Common::String &source);
protected:
MohawkEngine_LivingBooks *_vm;
@@ -206,6 +207,7 @@ protected:
void parseArithmetic2();
void parseMain();
+ LBItem *resolveItem(const LBValue &value);
Common::Array<LBValue> readParams();
Common::Rect getRectFromParams(const Common::Array<LBValue> &params);
@@ -213,8 +215,13 @@ protected:
void runItemCommand();
void runNotifyCommand();
+ uint nextFreeString();
+ bool parseCodeSymbol(const Common::String &name, uint &pos, Common::Array<byte> &code);
+
public:
void cmdUnimplemented(const Common::Array<LBValue> &params);
+ void cmdEval(const Common::Array<LBValue> &params);
+ void cmdRandom(const Common::Array<LBValue> &params);
void cmdGetRect(const Common::Array<LBValue> &params);
void cmdTopLeft(const Common::Array<LBValue> &params);
void cmdBottomRight(const Common::Array<LBValue> &params);
@@ -228,9 +235,10 @@ public:
void cmdSetHitTest(const Common::Array<LBValue> &params);
void cmdKey(const Common::Array<LBValue> &params);
- void itemSetParent(const Common::Array<LBValue> &params);
- void itemMoveTo(const Common::Array<LBValue> &params);
void itemIsPlaying(const Common::Array<LBValue> &params);
+ void itemMoveTo(const Common::Array<LBValue> &params);
+ void itemSeek(const Common::Array<LBValue> &params);
+ void itemSetParent(const Common::Array<LBValue> &params);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index 17f6de534f..307be2dd05 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -560,6 +560,7 @@ void MystScriptParser::o_playSoundBlocking(uint16 op, uint16 var, uint16 argc, u
debugC(kDebugScript, "Opcode %d: playSoundBlocking", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
+ _vm->_sound->stopSound();
_vm->_sound->playSoundBlocking(soundId);
}
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index d6dd1b5407..12d9dc7e2f 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -102,6 +102,7 @@ void Mechanical::setupOpcodes() {
void Mechanical::disablePersistentScripts() {
_fortressSimulationRunning = false;
+ _elevatorRotationLeverMoving = false;
_elevatorGoingMiddle = false;
_birdSinging = false;
_fortressRotationRunning = false;
@@ -126,10 +127,10 @@ void Mechanical::runPersistentScripts() {
uint16 Mechanical::getVar(uint16 var) {
switch(var) {
- case 0: // Sirrus's Secret Panel State
- return _state.sirrusPanelState;
- case 1: // Achenar's Secret Panel State
+ case 0: // Achenar's Secret Panel State
return _state.achenarPanelState;
+ case 1: // Sirrus's Secret Panel State
+ return _state.sirrusPanelState;
case 2: // Achenar's Secret Room Crate Lid Open and Blue Page Present
if (_state.achenarCrateOpened) {
if (_globals.bluePagesInBook & 4 || _globals.heldPage == 3)
@@ -195,16 +196,21 @@ uint16 Mechanical::getVar(uint16 var) {
void Mechanical::toggleVar(uint16 var) {
switch(var) {
- case 0: // Sirrus's Secret Panel State
- _state.sirrusPanelState ^= 1;
- case 1: // Achenar's Secret Panel State
+ case 0: // Achenar's Secret Panel State
_state.achenarPanelState ^= 1;
+ break;
+ case 1: // Sirrus's Secret Panel State
+ _state.sirrusPanelState ^= 1;
+ break;
case 3: // Achenar's Secret Room Crate State
_state.achenarCrateOpened ^= 1;
+ break;
case 4: // Myst Book Room Staircase State
_mystStaircaseState ^= 1;
+ break;
case 10: // Fortress Staircase State
_state.staircaseState ^= 1;
+ break;
case 16: // Code Lock Shape #1 - Left
case 17: // Code Lock Shape #2
case 18: // Code Lock Shape #3
@@ -242,6 +248,7 @@ bool Mechanical::setVarValue(uint16 var, uint16 value) {
switch (var) {
case 13:
_elevatorPosition = value;
+ break;
case 14: // Elevator going down when at top
_elevatorGoingDown = value;
break;
@@ -724,6 +731,7 @@ void Mechanical::birdSing_run() {
uint32 time = _vm->_system->getMillis();
if (_birdSingEndTime < time) {
_bird->pauseMovie(true);
+ _vm->_sound->stopSound();
_birdSinging = false;
}
}
diff --git a/engines/mohawk/resource.cpp b/engines/mohawk/resource.cpp
index 9b39692958..f01375bacf 100644
--- a/engines/mohawk/resource.cpp
+++ b/engines/mohawk/resource.cpp
@@ -294,7 +294,7 @@ bool MohawkArchive::openStream(Common::SeekableReadStream *stream) {
// We need to do this because of the way Mohawk is set up (this is much more "proper"
// than passing _stream at the right offset). We may want to do that in the future, though.
if (tag == ID_TMOV) {
- if (index == fileTable.size() - 1)
+ if (index == fileTable.size())
res.size = stream->size() - fileTable[index - 1].offset;
else
res.size = fileTable[index].offset - fileTable[index - 1].offset;
@@ -304,7 +304,6 @@ bool MohawkArchive::openStream(Common::SeekableReadStream *stream) {
debug(4, "Entry[%02x]: ID = %04x (%d) Index = %04x", j, id, id, index);
}
-
// Return to next TypeTable entry
stream->seek(absOffset + (i + 1) * 8 + 4);
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 6144c89e21..791b18db49 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -141,6 +141,19 @@ Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) {
&& name.equals(_vm->getResourceName(ID_MSND, convertMystID(_handles[i].id))))
return &_handles[i].handle;
+ // The original engine also forces looping for those sounds
+ switch (id) {
+ case 2205:
+ case 2207:
+ case 5378:
+ case 7220:
+ case 9119: // Elevator engine sound in mechanical age is looping.
+ case 9120:
+ case 9327:
+ loop = true;
+ break;
+ }
+
stopSound();
return playSound(id, volume, loop);
}
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index 2f86f3693b..3eea1e871a 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -28,6 +28,7 @@
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/stream.h"
+#include "common/array.h"
#include "graphics/surface.h"
diff --git a/engines/savestate.cpp b/engines/savestate.cpp
index 551c39b880..0b187ce630 100644
--- a/engines/savestate.cpp
+++ b/engines/savestate.cpp
@@ -24,49 +24,34 @@
#include "graphics/surface.h"
#include "common/textconsole.h"
-void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
- if (_thumbnail.get() == t)
- return;
-
- _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter());
+SaveStateDescriptor::SaveStateDescriptor()
+ // FIXME: default to 0 (first slot) or to -1 (invalid slot) ?
+ : _slot(-1), _description(), _isDeletable(true), _isWriteProtected(false),
+ _saveDate(), _saveTime(), _playTime(), _thumbnail() {
}
-bool SaveStateDescriptor::getBool(const Common::String &key) const {
- if (contains(key)) {
- const Common::String value = getVal(key);
- bool valueAsBool;
- if (Common::parseBool(value, valueAsBool))
- return valueAsBool;
- error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'",
- save_slot().c_str(), description().c_str(), value.c_str(), key.c_str());
- }
- return false;
+SaveStateDescriptor::SaveStateDescriptor(int s, const Common::String &d)
+ : _slot(s), _description(d), _isDeletable(true), _isWriteProtected(false),
+ _saveDate(), _saveTime(), _playTime(), _thumbnail() {
}
-void SaveStateDescriptor::setDeletableFlag(bool state) {
- setVal("is_deletable", state ? "true" : "false");
-}
+void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
+ if (_thumbnail.get() == t)
+ return;
-void SaveStateDescriptor::setWriteProtectedFlag(bool state) {
- setVal("is_write_protected", state ? "true" : "false");
+ _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter());
}
void SaveStateDescriptor::setSaveDate(int year, int month, int day) {
- Common::String buffer;
- buffer = Common::String::format("%.2d.%.2d.%.4d", day, month, year);
- setVal("save_date", buffer);
+ _saveDate = Common::String::format("%.2d.%.2d.%.4d", day, month, year);
}
void SaveStateDescriptor::setSaveTime(int hour, int min) {
- Common::String buffer;
- buffer = Common::String::format("%.2d:%.2d", hour, min);
- setVal("save_time", buffer);
+ _saveTime = Common::String::format("%.2d:%.2d", hour, min);
}
void SaveStateDescriptor::setPlayTime(int hours, int minutes) {
- Common::String buffer;
- buffer = Common::String::format("%.2d:%.2d", hours, minutes);
- setVal("play_time", buffer);
+ _playTime = Common::String::format("%.2d:%.2d", hours, minutes);
}
void SaveStateDescriptor::setPlayTime(uint32 msecs) {
diff --git a/engines/savestate.h b/engines/savestate.h
index df01732058..6cbdb22edf 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -24,7 +24,7 @@
#define ENGINES_SAVESTATE_H
#include "common/array.h"
-#include "common/hash-str.h"
+#include "common/str.h"
#include "common/ptr.h"
@@ -33,65 +33,60 @@ struct Surface;
}
/**
- * A hashmap describing details about a given save state.
- * TODO
- * Guaranteed to contain save_slot and description values.
- * Additional ideas: Playtime, creation date, thumbnail, ...
+ * Object describing a save state.
+ *
+ * This at least includes the save slot number and a human readable
+ * description of the save state.
+ *
+ * Further possibilites are a thumbnail, play time, creation date,
+ * creation time, delete protected, write protection.
*/
-class SaveStateDescriptor : public Common::StringMap {
-protected:
- Common::SharedPtr<Graphics::Surface> _thumbnail; // can be 0
-
+class SaveStateDescriptor {
public:
- SaveStateDescriptor() : _thumbnail() {
- setVal("save_slot", "-1"); // FIXME: default to 0 (first slot) or to -1 (invalid slot) ?
- setVal("description", "");
- }
-
- SaveStateDescriptor(int s, const Common::String &d) : _thumbnail() {
- setVal("save_slot", Common::String::format("%d", s));
- setVal("description", d);
- }
+ SaveStateDescriptor();
+ SaveStateDescriptor(int s, const Common::String &d);
- SaveStateDescriptor(const Common::String &s, const Common::String &d) : _thumbnail() {
- setVal("save_slot", s);
- setVal("description", d);
- }
-
- /** The saveslot id, as it would be passed to the "-x" command line switch. */
- Common::String &save_slot() { return getVal("save_slot"); }
+ /**
+ * @param slot The saveslot id, as it would be passed to the "-x" command line switch.
+ */
+ void setSaveSlot(int slot) { _slot = slot; }
- /** The saveslot id, as it would be passed to the "-x" command line switch (read-only variant). */
- const Common::String &save_slot() const { return getVal("save_slot"); }
+ /**
+ * @return The saveslot id, as it would be passed to the "-x" command line switch.
+ */
+ int getSaveSlot() const { return _slot; }
- /** A human readable description of the save state. */
- Common::String &description() { return getVal("description"); }
+ /**
+ * @param desc A human readable description of the save state.
+ */
+ void setDescription(const Common::String &desc) { _description = desc; }
- /** A human readable description of the save state (read-only variant). */
- const Common::String &description() const { return getVal("description"); }
+ /**
+ * @return A human readable description of the save state.
+ */
+ const Common::String &getDescription() const { return _description; }
/** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */
/**
- * Returns the value of a given key as boolean.
- * It accepts 'true', 'yes' and '1' for true and
- * 'false', 'no' and '0' for false.
- * (FIXME:) On unknown value it errors out ScummVM.
- * On unknown key it returns false as default.
+ * Defines whether the save state is allowed to be deleted.
*/
- bool getBool(const Common::String &key) const;
+ void setDeletableFlag(bool state) { _isDeletable = state; }
/**
- * Sets the 'is_deletable' key, which indicates if the
- * given savestate is safe for deletion.
+ * Queries whether the save state is allowed to be deleted.
*/
- void setDeletableFlag(bool state);
+ bool getDeletableFlag() const { return _isDeletable; }
/**
- * Sets the 'is_write_protected' key, which indicates if the
- * given savestate can be overwritten or not
+ * Defines whether the save state is write protected.
*/
- void setWriteProtectedFlag(bool state);
+ void setWriteProtectedFlag(bool state) { _isWriteProtected = state; }
+
+ /**
+ * Queries whether the save state is write protected.
+ */
+ bool getWriteProtectedFlag() const { return _isWriteProtected; }
/**
* Return a thumbnail graphics surface representing the savestate visually.
@@ -109,24 +104,100 @@ public:
void setThumbnail(Graphics::Surface *t);
/**
- * Sets the 'save_date' key properly, based on the given values.
+ * Sets the date the save state was created.
+ *
+ * @param year Year of creation.
+ * @param month Month of creation.
+ * @param day Day of creation.
*/
void setSaveDate(int year, int month, int day);
/**
- * Sets the 'save_time' key properly, based on the given values.
+ * Queries a human readable description of the date the save state was created.
+ *
+ * This will return an empty string in case the value is not set.
+ */
+ const Common::String &getSaveDate() const { return _saveDate; }
+
+ /**
+ * Sets the time the save state was created.
+ *
+ * @param hour Hour of creation.
+ * @param min Minute of creation.
*/
void setSaveTime(int hour, int min);
/**
- * Sets the 'play_time' key properly, based on the given values.
+ * Queries a human readable description of the time the save state was created.
+ *
+ * This will return an empty string in case the value is not set.
+ */
+ const Common::String &getSaveTime() const { return _saveTime; }
+
+ /**
+ * Sets the time the game was played before the save state was created.
+ *
+ * @param hours How many hours the user played the game so far.
+ * @param min How many minutes the user played the game so far.
*/
void setPlayTime(int hours, int minutes);
/**
- * Sets the 'play_time' key properly, based on the given value.
+ * Sets the time the game was played before the save state was created.
+ *
+ * @param msecs How many milliseconds the user played the game so far.
*/
void setPlayTime(uint32 msecs);
+
+ /**
+ * Queries a human readable description of the time the game was played
+ * before the save state was created.
+ *
+ * This will return an empty string in case the value is not set.
+ */
+ const Common::String &getPlayTime() const { return _playTime; }
+
+private:
+ /**
+ * The saveslot id, as it would be passed to the "-x" command line switch.
+ */
+ int _slot;
+
+ /**
+ * A human readable description of the save state.
+ */
+ Common::String _description;
+
+ /**
+ * Whether the save state can be deleted.
+ */
+ bool _isDeletable;
+
+ /**
+ * Whether the save state is write protected.
+ */
+ bool _isWriteProtected;
+
+ /**
+ * Human readable description of the date the save state was created.
+ */
+ Common::String _saveDate;
+
+ /**
+ * Human readable description of the time the save state was created.
+ */
+ Common::String _saveTime;
+
+ /**
+ * Human readable description of the time the game was played till the
+ * save state was created.
+ */
+ Common::String _playTime;
+
+ /**
+ * The thumbnail of the save state.
+ */
+ Common::SharedPtr<Graphics::Surface> _thumbnail;
};
/** List of savestates. */
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 9f10691767..7b8db22e3f 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -730,6 +730,10 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
case 8: { // Dup
const char *rawString = 0;
uint32 size = 0;
+ reg_t stringHandle;
+ // We allocate the new string first because if the StringTable needs to
+ // grow, our rawString pointer will be invalidated
+ SciString *dupString = s->_segMan->allocateString(&stringHandle);
if (argv[1].segment == s->_segMan->getStringSegmentId()) {
SciString *string = s->_segMan->lookupString(argv[1]);
@@ -741,8 +745,6 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
size = string.size() + 1;
}
- reg_t stringHandle;
- SciString *dupString = s->_segMan->allocateString(&stringHandle);
dupString->setSize(size);
for (uint32 i = 0; i < size; i++)
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 4ab0b9719f..dbe2135143 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -338,7 +338,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte
void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, uint16 chr, byte color) {
byte *displayPtr = _displayScreen + y * _displayWidth * 2 + x * 2;
// we don't use outline, so color 0 is actually not used
- commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0);
+ commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1);
}
byte GfxScreen::getVisual(int x, int y) {
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 7fb834ce98..eaae64dc77 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -779,7 +779,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->format.bytesPerPixel);
#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
else if (_vm->_cjkFont)
- _vm->_cjkFont->drawChar(vs, chr, _left, drawTop, _color, _shadowColor);
+ _vm->_cjkFont->drawChar(*vs, chr, _left, drawTop, _color, _shadowColor);
#endif
} else {
dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier);
diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h
index 3555d319e6..79cbd49032 100644
--- a/engines/scumm/imuse/instrument.h
+++ b/engines/scumm/imuse/instrument.h
@@ -39,7 +39,6 @@ public:
virtual void send(MidiChannel *mc) = 0;
virtual void copy_to(Instrument *dest) = 0;
virtual bool is_valid() = 0;
- virtual operator int() { return 255; }
};
class Instrument {
diff --git a/engines/scumm/imuse_digi/dimuse_codecs.cpp b/engines/scumm/imuse_digi/dimuse_codecs.cpp
index 69cd89320c..6edfe0bd33 100644
--- a/engines/scumm/imuse_digi/dimuse_codecs.cpp
+++ b/engines/scumm/imuse_digi/dimuse_codecs.cpp
@@ -105,7 +105,9 @@ static const byte imxOtherTable[6][64] = {
void releaseImcTables() {
free(_destImcTable);
+ _destImcTable = NULL;
free(_destImcTable2);
+ _destImcTable2 = NULL;
}
void initializeImcTables() {
diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp
index 6ce447a4cc..3611294eb8 100644
--- a/engines/sword2/controls.cpp
+++ b/engines/sword2/controls.cpp
@@ -477,6 +477,8 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc)
// Points to just after frame header, ie. start of sprite data
_sprites[state].data = frame + FrameHeader::size();
+ _sprites[state].colorTable = colTablePtr;
+ _sprites[state].isText = false;
_vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface);
_surfaces[state]._original = true;
diff --git a/engines/sword2/render.cpp b/engines/sword2/render.cpp
index 1e068d6061..8bf9d922d5 100644
--- a/engines/sword2/render.cpp
+++ b/engines/sword2/render.cpp
@@ -699,8 +699,6 @@ int32 Screen::initializePsxBackgroundLayer(byte *parallax) {
*/
int32 Screen::initializePsxParallaxLayer(byte *parallax) {
- uint16 plxXres, plxYres;
- uint16 xTiles, yTiles;
uint16 i, j, k;
byte *data;
byte *dst;
@@ -714,10 +712,10 @@ int32 Screen::initializePsxParallaxLayer(byte *parallax) {
return RD_OK;
}
- plxXres = READ_LE_UINT16(parallax);
- plxYres = READ_LE_UINT16(parallax + 2);
- xTiles = READ_LE_UINT16(parallax + 4);
- yTiles = READ_LE_UINT16(parallax + 6);
+ // uint16 plxXres = READ_LE_UINT16(parallax);
+ // uint16 plxYres = READ_LE_UINT16(parallax + 2);
+ uint16 xTiles = READ_LE_UINT16(parallax + 4);
+ uint16 yTiles = READ_LE_UINT16(parallax + 6);
// Beginning of parallax table composed by uint32,
// if word is 0, corresponding tile contains no data and must be skipped,
diff --git a/engines/sword25/gfx/animationtemplateregistry.cpp b/engines/sword25/gfx/animationtemplateregistry.cpp
index 43c099c89d..8184b49eba 100644
--- a/engines/sword25/gfx/animationtemplateregistry.cpp
+++ b/engines/sword25/gfx/animationtemplateregistry.cpp
@@ -34,7 +34,9 @@
#include "sword25/gfx/animationtemplateregistry.h"
#include "sword25/gfx/animationtemplate.h"
+namespace Common {
DECLARE_SINGLETON(Sword25::AnimationTemplateRegistry);
+}
namespace Sword25 {
diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp
index 91133b9fd2..14ba032107 100644
--- a/engines/sword25/gfx/graphicengine.cpp
+++ b/engines/sword25/gfx/graphicengine.cpp
@@ -156,7 +156,7 @@ RenderObjectPtr<Panel> GraphicEngine::getMainPanel() {
}
void GraphicEngine::setVsync(bool vsync) {
- warning("STUB: SetVsync(%d)", vsync);
+ // ScummVM has no concept of VSync
}
bool GraphicEngine::getVsync() const {
diff --git a/engines/sword25/gfx/image/art.cpp b/engines/sword25/gfx/image/art.cpp
index e9715481c6..2ba102e779 100644
--- a/engines/sword25/gfx/image/art.cpp
+++ b/engines/sword25/gfx/image/art.cpp
@@ -2030,7 +2030,6 @@ static void art_svp_intersect_add_seg(ArtIntersectCtx *ctx, const ArtSVPSeg *in_
ArtActiveSeg *seg = art_new(ArtActiveSeg, 1);
ArtActiveSeg *test;
double x0, y0;
- ArtActiveSeg *beg_range;
ArtActiveSeg *last = NULL;
ArtActiveSeg *left, *right;
ArtPriPoint *pri_pt = art_new(ArtPriPoint, 1);
@@ -2058,7 +2057,6 @@ static void art_svp_intersect_add_seg(ArtIntersectCtx *ctx, const ArtSVPSeg *in_
x0 = in_seg->points[0].x;
y0 = in_seg->points[0].y;
- beg_range = NULL;
for (test = ctx->active_head; test != NULL; test = test->right) {
double d;
int test_bneg = test->flags & ART_ACTIVE_FLAGS_BNEG;
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index f5f33d8e02..3b29b0333f 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -72,7 +72,10 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz
// Seek to the actual PNG image
loadString(*file); // Marker (BS25SAVEGAME)
- loadString(*file); // Version
+ Common::String storedVersionID = loadString(*file); // Version
+ if (storedVersionID != "SCUMMVM1")
+ loadString(*file);
+
loadString(*file); // Description
uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
loadString(*file); // Uncompressed game data size
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index b9ce5f7e00..45d43c465e 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -247,9 +247,6 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co
return;
}
- // readout SWF size
- Common::Rect movieRect = flashRectToBSRect(bs);
-
// Get frame rate and frame count
/* uint32 frameRate = */
bs.getUInt16();
diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp
index c1cd771e39..2d45dfb640 100644
--- a/engines/sword25/kernel/inputpersistenceblock.cpp
+++ b/engines/sword25/kernel/inputpersistenceblock.cpp
@@ -35,9 +35,10 @@
namespace Sword25 {
-InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength) :
+InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength, int version) :
_data(static_cast<const byte *>(data), dataLength),
- _errorState(NONE) {
+ _errorState(NONE),
+ _version(version) {
_iter = _data.begin();
}
diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h
index f643b06bc1..7e68137246 100644
--- a/engines/sword25/kernel/inputpersistenceblock.h
+++ b/engines/sword25/kernel/inputpersistenceblock.h
@@ -46,7 +46,7 @@ public:
OUT_OF_SYNC
};
- InputPersistenceBlock(const void *data, uint dataLength);
+ InputPersistenceBlock(const void *data, uint dataLength, int version);
virtual ~InputPersistenceBlock();
void read(int16 &value);
@@ -64,6 +64,8 @@ public:
return _errorState;
}
+ int getVersion() const { return _version; }
+
private:
bool checkMarker(byte marker);
bool checkBlockSize(int size);
@@ -72,6 +74,8 @@ private:
Common::Array<byte> _data;
Common::Array<byte>::const_iterator _iter;
ErrorState _errorState;
+
+ int _version;
};
} // End of namespace Sword25
diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp
index c88360e031..27d669caa1 100644
--- a/engines/sword25/kernel/persistenceservice.cpp
+++ b/engines/sword25/kernel/persistenceservice.cpp
@@ -50,7 +50,9 @@ static const char *SAVEGAME_DIRECTORY = "saves";
static const char *FILE_MARKER = "BS25SAVEGAME";
static const uint SLOT_COUNT = 18;
static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10;
-static const char *VERSIONID = "SCUMMVM1";
+static const char *VERSIONIDOLD = "SCUMMVM1";
+static const char *VERSIONID = "SCUMMVM2";
+static const int VERSIONNUM = 2;
#define MAX_SAVEGAME_SIZE 100
@@ -99,6 +101,7 @@ struct SavegameInformation {
bool isOccupied;
bool isCompatible;
Common::String description;
+ int version;
uint gamedataLength;
uint gamedataOffset;
uint gamedataUncompressedLength;
@@ -147,9 +150,15 @@ struct PersistenceService::Impl {
// Read in the header
Common::String storedMarker = loadString(file);
Common::String storedVersionID = loadString(file);
+ if (storedVersionID == VERSIONIDOLD) {
+ curSavegameInfo.version = 1;
+ } else {
+ Common::String versionNum = loadString(file);
+ curSavegameInfo.version = atoi(versionNum.c_str());
+ }
Common::String gameDescription = loadString(file);
- Common::String gameDataLength = loadString(file);
- curSavegameInfo.gamedataLength = atoi(gameDataLength.c_str());
+ Common::String gamedataLength = loadString(file);
+ curSavegameInfo.gamedataLength = atoi(gamedataLength.c_str());
Common::String gamedataUncompressedLength = loadString(file);
curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str());
@@ -158,7 +167,7 @@ struct PersistenceService::Impl {
// The slot is marked as occupied.
curSavegameInfo.isOccupied = true;
// Check if the saved game is compatible with the current engine version.
- curSavegameInfo.isCompatible = (storedVersionID == Common::String(VERSIONID));
+ curSavegameInfo.isCompatible = (curSavegameInfo.version <= VERSIONNUM);
// Load the save game description.
curSavegameInfo.description = gameDescription;
// The offset to the stored save game data within the file.
@@ -242,6 +251,12 @@ Common::String &PersistenceService::getSavegameFilename(uint slotID) {
return result;
}
+int PersistenceService::getSavegameVersion(uint slotID) {
+ if (!checkslotID(slotID))
+ return -1;
+ return _impl->_savegameInformations[slotID].version;
+}
+
bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) {
// FIXME: This code is a hack which bypasses the savefile API,
// and should eventually be removed.
@@ -264,6 +279,11 @@ bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotF
file->writeString(VERSIONID);
file->writeByte(0);
+ char buf[20];
+ snprintf(buf, 20, "%d", VERSIONNUM);
+ file->writeString(buf);
+ file->writeByte(0);
+
TimeDate dt;
g_system->getTimeAndDate(dt);
file->writeString(formatTimestamp(dt));
@@ -385,7 +405,7 @@ bool PersistenceService::loadGame(uint slotID) {
memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize);
}
- InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength);
+ InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version);
// Einzelne Engine-Module depersistieren.
bool success = true;
diff --git a/engines/sword25/kernel/persistenceservice.h b/engines/sword25/kernel/persistenceservice.h
index f73962892c..59e0a3661d 100644
--- a/engines/sword25/kernel/persistenceservice.h
+++ b/engines/sword25/kernel/persistenceservice.h
@@ -57,6 +57,7 @@ public:
void reloadSlots();
bool isSlotOccupied(uint slotID);
bool isSavegameCompatible(uint slotID);
+ int getSavegameVersion(uint slotID);
Common::String &getSavegameDescription(uint slotID);
Common::String &getSavegameFilename(uint slotID);
diff --git a/engines/sword25/math/regionregistry.cpp b/engines/sword25/math/regionregistry.cpp
index dff8560205..68c360a5ee 100644
--- a/engines/sword25/math/regionregistry.cpp
+++ b/engines/sword25/math/regionregistry.cpp
@@ -34,7 +34,9 @@
#include "sword25/math/regionregistry.h"
#include "sword25/math/region.h"
+namespace Common {
DECLARE_SINGLETON(Sword25::RegionRegistry);
+}
namespace Sword25 {
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index 7c8a6593aa..1b424dac65 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -33,6 +33,8 @@
#include "sword25/sfx/soundengine.h"
#include "sword25/package/packagemanager.h"
#include "sword25/kernel/resource.h"
+#include "sword25/kernel/inputpersistenceblock.h"
+#include "sword25/kernel/outputpersistenceblock.h"
#include "audio/decoders/vorbis.h"
@@ -202,17 +204,29 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl
return true;
}
-uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer) {
+uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer, uint handleId) {
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
#ifdef USE_VORBIS
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
#endif
uint id;
- SndHandle *handle = getHandle(&id);
+ SndHandle *handle;
- debugC(1, kDebugSound, "SoundEngine::playSoundEx(%s, %d, %f, %f, %d, %d, %d, %d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer);
+ if (handleId == 0x1337)
+ handle = getHandle(&id);
+ else
+ handle = &_handles[handleId];
- handle->type = kAllocatedHandle;
+ handle->fileName = fileName;
+ handle->sndType = type;
+ handle->volume = volume;
+ handle->pan = pan;
+ handle->loop = loop;
+ handle->loopStart = loopStart;
+ handle->loopEnd = loopEnd;
+ handle->layer = layer;
+
+ debugC(1, kDebugSound, "SoundEngine::playSoundEx(%s, %d, %f, %f, %d, %d, %d, %d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer);
#ifdef USE_VORBIS
_mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127));
@@ -311,16 +325,61 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) {
}
-bool SoundEngine::persist(OutputPersistenceBlock &writer) {
- warning("STUB: SoundEngine::persist()");
+ bool SoundEngine::persist(OutputPersistenceBlock &writer) {
+ writer.write(_maxHandleId);
+
+ for (uint i = 0; i < SOUND_HANDLES; i++) {
+ writer.write(_handles[i].id);
+
+ writer.writeString(_handles[i].fileName);
+ writer.write((int)_handles[i].sndType);
+ writer.write(_handles[i].volume);
+ writer.write(_handles[i].pan);
+ writer.write(_handles[i].loop);
+ writer.write(_handles[i].loopStart);
+ writer.write(_handles[i].loopEnd);
+ writer.write(_handles[i].layer);
+ }
return true;
}
bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
- warning("STUB: SoundEngine::unpersist()");
+ _mixer->stopAll();
- return true;
+ if (reader.getVersion() < 2)
+ return true;
+
+ reader.read(_maxHandleId);
+
+ for (uint i = 0; i < SOUND_HANDLES; i++) {
+ reader.read(_handles[i].id);
+
+ Common::String fileName;
+ int sndType;
+ float volume;
+ float pan;
+ bool loop;
+ int loopStart;
+ int loopEnd;
+ uint layer;
+
+ reader.readString(fileName);
+ reader.read(sndType);
+ reader.read(volume);
+ reader.read(pan);
+ reader.read(loop);
+ reader.read(loopStart);
+ reader.read(loopEnd);
+ reader.read(layer);
+
+ if (reader.isGood()) {
+ playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i);
+ } else
+ return false;
+ }
+
+ return reader.isGood();
}
diff --git a/engines/sword25/sfx/soundengine.h b/engines/sword25/sfx/soundengine.h
index 71f1602484..8132ec556e 100644
--- a/engines/sword25/sfx/soundengine.h
+++ b/engines/sword25/sfx/soundengine.h
@@ -65,6 +65,15 @@ struct SndHandle {
Audio::SoundHandle handle;
sndHandleType type;
uint32 id;
+
+ Common::String fileName;
+ int sndType;
+ float volume;
+ float pan;
+ bool loop;
+ int loopStart;
+ int loopEnd;
+ uint layer;
};
@@ -176,7 +185,7 @@ public:
* @remark If more control is needed over the playing, eg. changing the sound parameters
* for Volume and Panning, then PlaySoundEx should be used.
*/
- uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0);
+ uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0, uint handleId = 0x1337);
/**
* Sets the volume of a playing sound
diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp
index b111746c32..2201188052 100644
--- a/engines/sword25/sword25.cpp
+++ b/engines/sword25/sword25.cpp
@@ -50,7 +50,9 @@
#include "sword25/gfx/animationtemplateregistry.h" // Needed so we can destroy the singleton
#include "sword25/gfx/renderobjectregistry.h" // Needed so we can destroy the singleton
+namespace Common {
DECLARE_SINGLETON(Sword25::RenderObjectRegistry);
+}
#include "sword25/math/regionregistry.h" // Needed so we can destroy the singleton
namespace Sword25 {
diff --git a/engines/testbed/config-params.cpp b/engines/testbed/config-params.cpp
index 9a5062185b..d7ead48f63 100644
--- a/engines/testbed/config-params.cpp
+++ b/engines/testbed/config-params.cpp
@@ -24,7 +24,9 @@
#include "testbed/config-params.h"
+namespace Common {
DECLARE_SINGLETON(Testbed::ConfigParams);
+}
namespace Testbed {
diff --git a/engines/tsage/ringworld_scenes1.cpp b/engines/tsage/ringworld_scenes1.cpp
index 7fe2610fd7..8299a05967 100644
--- a/engines/tsage/ringworld_scenes1.cpp
+++ b/engines/tsage/ringworld_scenes1.cpp
@@ -3105,10 +3105,10 @@ void Scene6100::Object::synchronize(Serializer &s) {
SceneObject::synchronize(s);
// Save the double fields of the FloatSet
- s.syncBytes((byte *)&_floats._float1, sizeof(double));
- s.syncBytes((byte *)&_floats._float2, sizeof(double));
- s.syncBytes((byte *)&_floats._float3, sizeof(double));
- s.syncBytes((byte *)&_floats._float4, sizeof(double));
+ s.syncAsDouble(_floats._float1);
+ s.syncAsDouble(_floats._float2);
+ s.syncAsDouble(_floats._float3);
+ s.syncAsDouble(_floats._float4);
}
/*--------------------------------------------------------------------------*/
diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp
index b184e59c9e..40444cd630 100644
--- a/engines/tsage/saveload.cpp
+++ b/engines/tsage/saveload.cpp
@@ -103,6 +103,19 @@ void Serializer::validate(int v, Common::Serializer::Version minVersion,
error("Savegame is corrupt");
}
+#define DOUBLE_PRECISION 1000000000
+
+void Serializer::syncAsDouble(double &v) {
+ int32 num = (int32)(v);
+ uint32 fraction = (uint32)((v - (int32)v) * DOUBLE_PRECISION);
+
+ syncAsSint32LE(num);
+ syncAsUint32LE(fraction);
+
+ if (isLoading())
+ v = num + (double)fraction / DOUBLE_PRECISION;
+}
+
/*--------------------------------------------------------------------------*/
Common::Error Saver::save(int slot, const Common::String &saveName) {
diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h
index 0382e4a1fc..ce181cbc8f 100644
--- a/engines/tsage/saveload.h
+++ b/engines/tsage/saveload.h
@@ -77,6 +77,7 @@ public:
Common::Serializer::Version maxVersion = kLastVersion);
void validate(int v, Common::Serializer::Version minVersion = 0,
Common::Serializer::Version maxVersion = kLastVersion);
+ void syncAsDouble(double &v);
};
/*--------------------------------------------------------------------------*/
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index 01e770a77a..e26b3d1544 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -126,7 +126,10 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
assert(__sndmgrReady);
_availableDrivers.clear();
- // Build up a list of available drivers. Currently we only implement an Adlib driver
+ // Build up a list of available drivers. Currently we only implement an Adlib music
+ // and SoundBlaster FX driver
+
+ // Adlib driver
SoundDriverEntry sd;
sd.driverNum = ADLIB_DRIVER_NUM;
sd.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
@@ -136,12 +139,25 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
sd.longDescription = "3812fm";
_availableDrivers.push_back(sd);
+ // SoundBlaster entry
+ SoundDriverEntry sdFx;
+ sdFx.driverNum = SBLASTER_DRIVER_NUM;
+ sdFx.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
+ sdFx.field2 = 0;
+ sdFx.field6 = 15000;
+ sdFx.shortDescription = "SndBlast";
+ sdFx.longDescription = "SoundBlaster";
+ _availableDrivers.push_back(sdFx);
+
_driversDetected = true;
return _availableDrivers;
}
void SoundManager::installConfigDrivers() {
installDriver(ADLIB_DRIVER_NUM);
+#ifdef DEBUG
+ installDriver(SBLASTER_DRIVER_NUM);
+#endif
}
Common::List<SoundDriverEntry> &SoundManager::getDriverList(bool detectFlag) {
@@ -206,8 +222,14 @@ void SoundManager::installDriver(int driverNum) {
* Instantiate a driver class for the specified driver number
*/
SoundDriver *SoundManager::instantiateDriver(int driverNum) {
- assert(driverNum == ADLIB_DRIVER_NUM);
- return new AdlibSoundDriver();
+ switch (driverNum) {
+ case ADLIB_DRIVER_NUM:
+ return new AdlibSoundDriver();
+ case SBLASTER_DRIVER_NUM:
+ return new AdlibFxSoundDriver();
+ default:
+ error("Unknown sound driver - %d", driverNum);
+ }
}
/**
@@ -2125,7 +2147,7 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice
vtStruct->_entries[entryIndex]._type1._field4 = v0;
vtStruct->_entries[entryIndex]._type1._field5 = 0;
- driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1);
+ driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1);
}
}
@@ -2143,8 +2165,9 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice
vtStruct->_entries[entryIndex]._type1._field4 = v0;
vtStruct->_entries[entryIndex]._type1._field5 = 0;
- driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F);
- driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0);
+ int v1, v2;
+ driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F);
+ driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0, &v1, &v2);
}
break;
}
@@ -2271,11 +2294,32 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) {
vtStruct->_entries[entryIndex]._type1._field4 = *(channelData + 1);
vtStruct->_entries[entryIndex]._type1._field5 = 0;
- driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f);
+ int v1, v2;
+ driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f);
+ driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), _loop ? 1 : 0,
+ &v1, &v2);
}
} else {
+ for (uint entryIndex = 0; entryIndex < vtStruct->_entries.size(); ++entryIndex) {
+ VoiceStructEntry &vte = vtStruct->_entries[entryIndex];
+ VoiceStructEntryType1 &vse = vte._type1;
+ if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == vtStruct->_total)) {
+ SoundDriver *driver = vte._driver;
+
+ int v1, v2;
+ driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &v1, &v2);
+ if (v2) {
+ _trkState[trackIndex] = 0;
+ } else if (vtStruct->_total) {
+ _timer = 0;
+ }
+ }
+ }
+ _trkState[trackIndex] = 0;
}
+ } else {
+ _trkState[trackIndex] = 0;
}
}
}
@@ -2441,7 +2485,10 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
_mixer = _vm->_mixer;
_sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
+ _opl = OPL::Config::create();
+ assert(_opl);
+ _opl->init(_sampleRate);
+
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false);
@@ -2460,7 +2507,7 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() {
AdlibSoundDriver::~AdlibSoundDriver() {
DEALLOCATE(_patchData);
_mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
+ delete _opl;
}
bool AdlibSoundDriver::open() {
@@ -2511,7 +2558,7 @@ int AdlibSoundDriver::setMasterVolume(int volume) {
return oldVolume;
}
-void AdlibSoundDriver::proc32(int channel, int program, int v0, int v1) {
+void AdlibSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) {
if (program == -1)
return;
@@ -2578,7 +2625,7 @@ void AdlibSoundDriver::flush() {
while (!_queue.empty()) {
RegisterValue v = _queue.pop();
- OPLWriteReg(_opl, v._regNum, v._value);
+ _opl->writeReg(v._regNum, v._value);
}
}
@@ -2716,7 +2763,7 @@ void AdlibSoundDriver::update(int16 *buf, int len) {
}
samplesLeft -= count;
len -= count;
- YM3812UpdateOne(_opl, buf, count);
+ _opl->readBuffer(buf, count);
if (samplesLeft == 0) {
flush();
samplesLeft = _sampleRate / 50;
@@ -2735,14 +2782,13 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() {
_maxVersion = 0x10A;
_masterVolume = 0;
- _groupData.groupMask = 9;
+ _groupData.groupMask = 1;
_groupData.v1 = 0x3E;
_groupData.v2 = 0;
_groupData.pData = &adlib_group_data[0];
_mixer = _vm->_mixer;
_sampleRate = _mixer->getOutputRate();
- _opl = makeAdLibOPL(_sampleRate);
_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
/*
Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false);
@@ -2761,35 +2807,28 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() {
AdlibFxSoundDriver::~AdlibFxSoundDriver() {
_mixer->stopHandle(_soundHandle);
- OPLDestroy(_opl);
}
bool AdlibFxSoundDriver::open() {
+ write209();
+ write(64);
+ write(165);
+ // for (int idx = 0; idx < 5000 * 16; ++idx) al = port[21h]
- write(1, 0x20);
- if (!reset())
- return false;
-
- write(8, 0);
- for (int idx = 0x20; idx < 0xF6; ++idx)
- write(idx, 0);
+// _v45071 = 1;
+// _v4506F = 0;
- write(0xBD, 0);
return true;
}
void AdlibFxSoundDriver::close() {
- for (int idx = 0xB0; idx < 0xB8; ++idx)
- write(idx, _portContents[idx] & 0xDF);
- for (int idx = 0x40; idx < 0x55; ++idx)
- write(idx, 0x3F);
- reset();
+ write(208);
+ write211();
+
}
bool AdlibFxSoundDriver::reset() {
- write(1, 0x20);
- write(1, 0x20);
return true;
}
@@ -2798,209 +2837,81 @@ const GroupData *AdlibFxSoundDriver::getGroupData() {
return &_groupData;
}
+void AdlibFxSoundDriver::poll() {
+ if (!_masterVolume || !_channelVolume) {
+ if (_v45046)
+ write211();
+ } else {
+ if (!_v45046)
+ write209();
+ }
+}
+
int AdlibFxSoundDriver::setMasterVolume(int volume) {
int oldVolume = _masterVolume;
_masterVolume = volume;
- for (int channelNum = 0; channelNum < ADLIB_CHANNEL_COUNT; ++channelNum)
- updateChannelVolume(channelNum);
-
return oldVolume;
}
-void AdlibFxSoundDriver::proc32(int channel, int program, int v0, int v1) {
+void AdlibFxSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) {
if (program == -1)
return;
-/*
- int offset = READ_LE_UINT16(_patchData + program * 2);
- if (offset) {
- const byte *dataP = _patchData + offset;
- int id;
- for (offset = 2, id = 0; id != READ_LE_UINT16(dataP); offset += 30, ++id) {
- if ((dataP[offset] <= v0) && (dataP[offset + 1] >= v0)) {
- if (dataP[offset + 2] != 0xff)
- v0 = dataP[offset + 2];
+ if (_sound)
+ updateVoice(channel);
- _v4409E[channel] = dataP + offset - _patchData;
+ // TODO: Stuff
- // Set sustain/release
- int portNum = v440C2[v440B0[channel]] + 0x80;
- write(portNum, (_portContents[portNum] & 0xF0) | 0xF);
- portNum = v440C2[v440B9[channel]] + 0x80;
- write(portNum, (_portContents[portNum] & 0xF0) | 0xF);
- if (_channelVoiced[channel])
- clearVoice(channel);
-
- _v44067[channel] = v0;
- _v4405E[channel] = v1;
-
- updateChannel(channel);
- setFrequency(channel);
- updateChannelVolume(channel);
- setVoice(channel);
- break;
- }
- }
- }
- */
}
void AdlibFxSoundDriver::updateVoice(int channel) {
- if (_channelVoiced[channel])
- clearVoice(channel);
+ if (_sound) {
+ write(208);
+
+ _sound = NULL;
+ _v45062 = 0;
+ _v45066 = 0;
+ _v45068 = 0;
+ }
}
void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) {
if (cmd == 7) {
// Set channel volume
- _channelVolume[channel] = value;
- updateChannelVolume(channel);
+ _channelVolume = value;
}
}
-void AdlibFxSoundDriver::setPitch(int channel, int pitchBlend) {
- _pitchBlend[channel] = pitchBlend;
- setFrequency(channel);
-}
+void AdlibFxSoundDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) {
+ _v4506A = value;
+ *v1 = _v4506B;
+ *v2 = 0;
+ _v4506B = 0;
-void AdlibFxSoundDriver::write(byte reg, byte value) {
- _portContents[reg] = value;
- _queue.push(RegisterValue(reg, value));
+ if (!_sound)
+ *v2 = 1;
}
-void AdlibFxSoundDriver::flush() {
- Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex);
-
- while (!_queue.empty()) {
- RegisterValue v = _queue.pop();
- OPLWriteReg(_opl, v._regNum, v._value);
+void AdlibFxSoundDriver::write(int v) {
+ /*
+ port[adlib_port + 12] = v;
+ for (int i = 0; i < 100; ++i) {
+ if (!port[adlib_port + 12] & 0x80)
+ break;
}
-}
-
-void AdlibFxSoundDriver::updateChannelVolume(int channelNum) {
- int volume = (_masterVolume * _channelVolume[channelNum] / 127 * _v4405E[channelNum] / 127) / 2;
- int level2 = 63 - v44134[volume * _v44079[channelNum] / 63];
- int level1 = !_v44082[channelNum] ? 63 - _v44070[channelNum] :
- 63 - v44134[volume * _v44070[channelNum] / 63];
-
- int portNum = v440C2[v440B0[channelNum]] + 0x40;
- write(portNum, (_portContents[portNum] & 0x80) | level1);
-
- portNum = v440C2[v440B9[channelNum]] + 0x40;
- write(portNum, (_portContents[portNum] & 0x80) | level2);
-}
-
-void AdlibFxSoundDriver::setVoice(int channel) {
- int portNum = 0xB0 + channel;
- write(portNum, _portContents[portNum] | 0x20);
- _channelVoiced[channel] = true;
-}
-
-void AdlibFxSoundDriver::clearVoice(int channel) {
- write(0xB0 + channel, _portContents[0xB0 + channel] & ~0x20);
- _channelVoiced[channel] = false;
-}
-
-void AdlibFxSoundDriver::updateChannel(int channel) {
-/*
- const byte *dataP = _patchData + _v4409E[channel];
- int portOffset = v440C2[v440B0[channel]];
-
- int portNum = portOffset + 0x20;
- int portValue = 0;
- if (*(dataP + 4))
- portValue |= 0x80;
- if (*(dataP + 5))
- portValue |= 0x40;
- if (*(dataP + 8))
- portValue |= 0x20;
- if (*(dataP + 6))
- portValue |= 0x10;
- portValue |= *(dataP + 7);
- write(portNum, portValue);
-
- portValue = (_portContents[0x40 + portOffset] & 0x3F) | (*(dataP + 9) << 6);
- write(0x40 + portOffset, portValue);
-
- _v44070[channel] = 63 - *(dataP + 10);
- write(0x60 + portOffset, *(dataP + 12) | (*(dataP + 11) << 4));
- write(0x80 + portOffset, *(dataP + 14) | (*(dataP + 13) << 4));
- write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 15));
-
- portOffset = v440C2[v440B9[channel]];
- portNum = portOffset + 0x20;
- portValue = 0;
- if (*(dataP + 17))
- portValue |= 0x80;
- if (*(dataP + 18))
- portValue |= 0x40;
- if (*(dataP + 21))
- portValue |= 0x20;
- if (*(dataP + 19))
- portValue |= 0x10;
- portValue |= *(dataP + 20);
- write(portNum, portValue);
-
- write(0x40 + portOffset, (_portContents[0x40 + portOffset] & 0x3f) | (*(dataP + 22) << 6));
- _v44079[channel] = 0x3F - *(dataP + 23);
- write(0x60 + portOffset, *(dataP + 25) | (*(dataP + 24) << 4));
- write(0x80 + portOffset, *(dataP + 27) | (*(dataP + 26) << 4));
- write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 28));
-
- write(0xC0 + channel, (_portContents[0xC0 + channel] & 0xF0)
- | (*(dataP + 16) << 1) | *(dataP + 3));
-
- _v44082[channel] = *(dataP + 3);
*/
}
-void AdlibFxSoundDriver::setFrequency(int channel) {
- int offset, ch;
-
- int v = _pitchBlend[channel];
- if (v == 0x2000) {
- offset = 0;
- ch = _v44067[channel];
- } else if (v > 0x2000) {
- ch = _v44067[channel];
- v -= 0x2000;
- if (v == 0x1fff)
- v = 0x2000;
-
- offset = (v / 170) & 3;
- ch += (v / 170) >> 2;
-
- if (ch >= 128)
- ch = 127;
- } else {
- ch = _v44067[channel];
- int tempVal = (0x2000 - v) / 170;
- int tempVal2 = 4 - (tempVal & 3);
-
- if (tempVal2 == 4)
- offset = 0;
- else {
- offset = tempVal2;
- --ch;
- }
+void AdlibFxSoundDriver::flush() {
+ Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex);
- ch -= tempVal >> 2;
- if (ch < 0)
- ch = 0;
- }
+ // No data output yet
+}
- int var2 = ch / 12;
- if (var2)
- --var2;
- int dataWord = v440D4[((ch % 12) << 2) + offset];
- write(0xA0 + channel, dataWord & 0xff);
- write(0xB0 + channel, (_portContents[0xB0 + channel] & 0xE0) |
- ((dataWord >> 8) & 3) | (var2 << 2));
-}
int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
update(buffer, numSamples);
@@ -3008,6 +2919,7 @@ int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
}
void AdlibFxSoundDriver::update(int16 *buf, int len) {
+/*
static int samplesLeft = 0;
while (len != 0) {
int count = samplesLeft;
@@ -3023,6 +2935,17 @@ void AdlibFxSoundDriver::update(int16 *buf, int len) {
}
buf += count;
}
+*/
+}
+
+void AdlibFxSoundDriver::write209() {
+ write(209);
+ _v45046 = true;
+}
+
+void AdlibFxSoundDriver::write211() {
+ write(211);
+ _v45046 = false;
}
} // End of namespace tSage
diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h
index 27f30b9b08..6a47a1aaf5 100644
--- a/engines/tsage/sound.h
+++ b/engines/tsage/sound.h
@@ -40,6 +40,7 @@ class Sound;
#define SOUND_ARR_SIZE 16
#define ROLAND_DRIVER_NUM 2
#define ADLIB_DRIVER_NUM 3
+#define SBLASTER_DRIVER_NUM 4
struct trackInfoStruct {
int _numTracks;
@@ -106,12 +107,12 @@ public:
virtual void setProgram(int channel, int program) {} // Method #13
virtual void setVolume1(int channel, int v2, int v3, int volume) {}
virtual void setPitchBlend(int channel, int pitchBlend) {} // Method #15
- virtual void proc32(int channel, int program, int v0, int v1) {}// Method #16
+ virtual void proc32(Sound *sound, int channel, int program, int v0, int v1) {}// Method #16
virtual void updateVoice(int channel) {} // Method #17
virtual void proc36() {} // Method #18
virtual void proc38(int channel, int cmd, int value) {} // Method #19
virtual void setPitch(int channel, int pitchBlend) {} // Method #20
- virtual void proc42(int channel, int v0, int v1) {} // Method #21
+ virtual void proc42(int channel, int cmd, int value, int *v1, int *v2) {} // Method #21
};
struct VoiceStructEntryType0 {
@@ -439,7 +440,7 @@ public:
virtual const GroupData *getGroupData();
virtual void installPatch(const byte *data, int size);
virtual int setMasterVolume(int volume);
- virtual void proc32(int channel, int program, int v0, int v1);
+ virtual void proc32(Sound *sound, int channel, int program, int v0, int v1);
virtual void updateVoice(int channel);
virtual void proc38(int channel, int cmd, int value);
virtual void setPitch(int channel, int pitchBlend);
@@ -455,33 +456,27 @@ public:
class AdlibFxSoundDriver: public SoundDriver, Audio::AudioStream {
private:
+ Common::Queue<RegisterValue> _queue;
GroupData _groupData;
Audio::Mixer *_mixer;
- FM_OPL *_opl;
Audio::SoundHandle _soundHandle;
int _sampleRate;
- byte _portContents[256];
- int _masterVolume;
- Common::Queue<RegisterValue> _queue;
-
- bool _channelVoiced[ADLIB_CHANNEL_COUNT];
- int _channelVolume[ADLIB_CHANNEL_COUNT];
- int _v4405E[ADLIB_CHANNEL_COUNT];
- int _v44067[ADLIB_CHANNEL_COUNT];
- int _v44070[ADLIB_CHANNEL_COUNT];
- int _v44079[ADLIB_CHANNEL_COUNT];
- int _v44082[ADLIB_CHANNEL_COUNT + 1];
- int _pitchBlend[ADLIB_CHANNEL_COUNT];
- int _v4409E[ADLIB_CHANNEL_COUNT];
+ int _v45062;
+ int _v45066;
+ int _v45068;
+ int _v4506A;
+ int _v4506B;
+ bool _v45046;
+ byte _masterVolume;
+ byte _channelVolume;
+ Sound *_sound;
- void write(byte reg, byte value);
+ void write(int v);
void flush();
- void updateChannelVolume(int channel);
- void setVoice(int channel);
- void clearVoice(int channel);
- void updateChannel(int channel);
- void setFrequency(int channel);
+ void sub_4556E();
+ void write209();
+ void write211();
public:
AdlibFxSoundDriver();
virtual ~AdlibFxSoundDriver();
@@ -490,12 +485,12 @@ public:
virtual void close();
virtual bool reset();
virtual const GroupData *getGroupData();
- virtual void installPatch(const byte *data, int size) {}
+ virtual void poll();
virtual int setMasterVolume(int volume);
- virtual void proc32(int channel, int program, int v0, int v1);
+ virtual void proc32(Sound *sound, int channel, int program, int v0, int v1);
virtual void updateVoice(int channel);
virtual void proc38(int channel, int cmd, int value);
- virtual void setPitch(int channel, int pitchBlend);
+ virtual void proc42(int channel, int cmd, int value, int *v1, int *v2);
// AudioStream interface
virtual int readBuffer(int16 *buffer, const int numSamples);
diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp
index a5498903e2..1d4e482bf4 100644
--- a/graphics/cursorman.cpp
+++ b/graphics/cursorman.cpp
@@ -24,7 +24,9 @@
#include "common/system.h"
#include "common/stack.h"
+namespace Common {
DECLARE_SINGLETON(Graphics::CursorManager);
+}
namespace Graphics {
diff --git a/graphics/font.cpp b/graphics/font.cpp
index 0c180ee47d..3f7152a95e 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -19,775 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "common/stream.h"
-#include "common/file.h"
-#include "common/endian.h"
+#include "graphics/font.h"
+
#include "common/array.h"
-#include "common/textconsole.h"
#include "common/util.h"
-#include "graphics/font.h"
-#include "graphics/surface.h"
namespace Graphics {
-void free_font(NewFontData *pf);
-
-NewFont::~NewFont() {
- if (_font) {
- free_font(_font);
- }
-}
-
-int NewFont::getCharWidth(byte chr) const {
- // If no width table is specified, return the maximum width
- if (!_desc.width)
- return _desc.maxwidth;
- // If this character is not included in the font, use the default char.
- if (chr < _desc.firstchar || _desc.firstchar + _desc.size < chr) {
- chr = _desc.defaultchar;
- }
- return _desc.width[chr - _desc.firstchar];
-}
-
-
-template <typename PixelType>
-void drawCharIntern(byte *ptr, uint pitch, const bitmap_t *src, int h, int minX, int maxX, const PixelType color) {
- const bitmap_t maxXMask = ~((1 << (16-maxX)) - 1);
- while (h-- > 0) {
- bitmap_t buffer = READ_UINT16(src);
- src++;
-
- buffer &= maxXMask;
- buffer <<= minX;
- PixelType *tmp = (PixelType *)ptr;
- while (buffer != 0) {
- if ((buffer & 0x8000) != 0)
- *tmp = color;
- tmp++;
- buffer <<= 1;
- }
-
- ptr += pitch;
- }
-}
-
-void NewFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const {
- assert(dst != 0);
-
- assert(_desc.bits != 0 && _desc.maxwidth <= 16);
- assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2);
-
- // If this character is not included in the font, use the default char.
- if (chr < _desc.firstchar || chr >= _desc.firstchar + _desc.size) {
- chr = _desc.defaultchar;
- }
-
- chr -= _desc.firstchar;
-
- int bbw, bbh, bbx, bby;
-
- // Get the bounding box of the character
- if (!_desc.bbx) {
- bbw = _desc.fbbw;
- bbh = _desc.fbbh;
- bbx = _desc.fbbx;
- bby = _desc.fbby;
- } else {
- bbw = _desc.bbx[chr].w;
- bbh = _desc.bbx[chr].h;
- bbx = _desc.bbx[chr].x;
- bby = _desc.bbx[chr].y;
- }
-
- byte *ptr = (byte *)dst->getBasePtr(tx + bbx, ty + _desc.ascent - bby - bbh);
-
- const bitmap_t *tmp = _desc.bits + (_desc.offset ? _desc.offset[chr] : (chr * _desc.fbbh));
-
- int y = MIN(bbh, ty + _desc.ascent - bby);
- tmp += bbh - y;
- y -= MAX(0, ty + _desc.ascent - bby - dst->h);
-
- if (dst->format.bytesPerPixel == 1)
- drawCharIntern<byte>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
- else if (dst->format.bytesPerPixel == 2)
- drawCharIntern<uint16>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
-}
-
-
-#pragma mark -
-
-/* BEGIN font.h*/
-/* bitmap_t helper macros*/
-#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
-#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
-#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
-#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
-#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
-#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
-#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
-
-/* builtin C-based proportional/fixed font structure */
-/* based on The Microwindows Project http://microwindows.org */
-struct NewFontData {
- char * name; /* font name*/
- int maxwidth; /* max width in pixels*/
- int height; /* height in pixels*/
- int ascent; /* ascent (baseline) height*/
- int firstchar; /* first character in bitmap*/
- int size; /* font size in glyphs*/
- bitmap_t* bits; /* 16-bit right-padded bitmap data*/
- unsigned long* offset; /* offsets into bitmap data*/
- unsigned char* width; /* character widths or NULL if fixed*/
- BBX* bbx; /* character bounding box or NULL if fixed */
- int defaultchar; /* default char (not glyph index)*/
- long bits_size; /* # words of bitmap_t bits*/
-
- /* unused by runtime system, read in by convbdf*/
- char * facename; /* facename of font*/
- char * copyright; /* copyright info for loadable fonts*/
- int pixel_size;
- int descent;
- int fbbw, fbbh, fbbx, fbby;
-};
-/* END font.h*/
-
-#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
-#define strequal(s1,s2) (!strcmp(s1, s2))
-
-#define EXTRA 300
-
-int start_char = 0;
-int limit_char = 255;
-
-NewFontData* bdf_read_font(Common::SeekableReadStream &fp);
-int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf);
-int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf);
-char * bdf_getline(Common::SeekableReadStream &fp, char *buf, int len);
-bitmap_t bdf_hexval(unsigned char *buf);
-
-void free_font(NewFontData* pf) {
- if (!pf)
- return;
- free(pf->name);
- free(pf->facename);
- free(pf->bits);
- free(pf->offset);
- free(pf->width);
- free(pf->bbx);
- free(pf);
-}
-
-/* build incore structure from .bdf file*/
-NewFontData* bdf_read_font(Common::SeekableReadStream &fp) {
- NewFontData* pf;
- uint32 pos = fp.pos();
-
- pf = (NewFontData*)calloc(1, sizeof(NewFontData));
- if (!pf)
- goto errout;
-
- if (!bdf_read_header(fp, pf)) {
- warning("Error reading font header");
- goto errout;
- }
-
- fp.seek(pos, SEEK_SET);
-
- if (!bdf_read_bitmaps(fp, pf)) {
- warning("Error reading font bitmaps");
- goto errout;
- }
-
- return pf;
-
- errout:
- free_font(pf);
- return NULL;
-}
-
-/* read bdf font header information, return 0 on error*/
-int bdf_read_header(Common::SeekableReadStream &fp, NewFontData* pf) {
- int encoding = 0;
- int nchars = 0, maxwidth, maxheight;
- int firstchar = 65535;
- int lastchar = -1;
- char buf[256];
- char facename[256];
- char copyright[256];
- memset(facename, 0, sizeof(facename));
- memset(copyright, 0, sizeof(copyright));
-
- /* set certain values to errors for later error checking*/
- pf->defaultchar = -1;
- pf->ascent = -1;
- pf->descent = -1;
-
- for (;;) {
- if (!bdf_getline(fp, buf, sizeof(buf))) {
- warning("Error: EOF on file");
- return 0;
- }
-
- /* note: the way sscanf is used here ensures that a terminating null
- character is automatically added. Refer to:
- http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html */
-
- if (isprefix(buf, "FONT ")) { /* not required*/
- if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
- warning("Error: bad 'FONT'");
- return 0;
- }
-
- pf->facename = strdup(facename);
- continue;
- }
- if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
- if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
- warning("Error: bad 'COPYRIGHT'");
- return 0;
- }
-
- pf->copyright = strdup(copyright);
- continue;
- }
- if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
- if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
- warning("Error: bad 'DEFAULT_CHAR'");
- return 0;
- }
- }
- if (isprefix(buf, "FONT_DESCENT ")) {
- if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
- warning("Error: bad 'FONT_DESCENT'");
- return 0;
- }
- continue;
- }
- if (isprefix(buf, "FONT_ASCENT ")) {
- if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
- warning("Error: bad 'FONT_ASCENT'");
- return 0;
- }
- continue;
- }
- if (isprefix(buf, "FONTBOUNDINGBOX ")) {
- if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
- &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
- warning("Error: bad 'FONTBOUNDINGBOX'");
- return 0;
- }
- continue;
- }
- if (isprefix(buf, "CHARS ")) {
- if (sscanf(buf, "CHARS %d", &nchars) != 1) {
- warning("Error: bad 'CHARS'");
- return 0;
- }
- continue;
- }
-
- /*
- * Reading ENCODING is necessary to get firstchar/lastchar
- * which is needed to pre-calculate our offset and widths
- * array sizes.
- */
- if (isprefix(buf, "ENCODING ")) {
- if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
- warning("Error: bad 'ENCODING'");
- return 0;
- }
- if (encoding >= 0 &&
- encoding <= limit_char &&
- encoding >= start_char) {
-
- if (firstchar > encoding)
- firstchar = encoding;
- if (lastchar < encoding)
- lastchar = encoding;
- }
- continue;
- }
- if (strequal(buf, "ENDFONT"))
- break;
- }
-
- /* calc font height*/
- if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
- warning("Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING");
- return 0;
- }
- pf->height = pf->ascent + pf->descent;
-
- /* calc default char*/
- if (pf->defaultchar < 0 ||
- pf->defaultchar < firstchar ||
- pf->defaultchar > limit_char )
- pf->defaultchar = firstchar;
-
- /* calc font size (offset/width entries)*/
- pf->firstchar = firstchar;
- pf->size = lastchar - firstchar + 1;
-
- /* use the font boundingbox to get initial maxwidth*/
- /*maxwidth = pf->fbbw - pf->fbbx;*/
- maxwidth = pf->fbbw;
- maxheight = pf->fbbh;
-
- /* initially use font bounding box for bits allocation*/
- pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * maxheight;
-
- /* allocate bits, offset, and width arrays*/
- pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
- pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long));
- pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
- pf->bbx = (BBX *)malloc(pf->size * sizeof(BBX));
-
- if (!pf->bits || !pf->offset || !pf->width) {
- warning("Error: no memory for font load");
- return 0;
- }
-
- return 1;
-}
-
-/* read bdf font bitmaps, return 0 on error*/
-int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf) {
- long ofs = 0;
- int maxwidth = 0;
- int i, k, encoding = 0, width = 0;
- int bbw = 0, bbh = 0, bbx = 0, bby = 0;
- int proportional = 0;
- int need_bbx = 0;
- int encodetable = 0;
- long l;
- char buf[256];
-
- /* initially mark offsets as not used*/
- for (i = 0; i < pf->size; ++i)
- pf->offset[i] = (unsigned long)-1;
-
- for (;;) {
- if (!bdf_getline(fp, buf, sizeof(buf))) {
- warning("Error: EOF on file");
- return 0;
- }
- if (isprefix(buf, "STARTCHAR")) {
- encoding = width = bbw = bbh = bbx = bby = -1;
- continue;
- }
- if (isprefix(buf, "ENCODING ")) {
- if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
- warning("Error: bad 'ENCODING'");
- return 0;
- }
- if (encoding < start_char || encoding > limit_char)
- encoding = -1;
- continue;
- }
- if (isprefix(buf, "DWIDTH ")) {
- if (sscanf(buf, "DWIDTH %d", &width) != 1) {
- warning("Error: bad 'DWIDTH'");
- return 0;
- }
- /* use font boundingbox width if DWIDTH <= 0*/
- if (width <= 0)
- width = pf->fbbw - pf->fbbx;
- continue;
- }
- if (isprefix(buf, "BBX ")) {
- if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
- warning("Error: bad 'BBX'");
- return 0;
- }
- continue;
- }
- if (strequal(buf, "BITMAP")) {
- bitmap_t *ch_bitmap = pf->bits + ofs;
- int ch_words;
-
- if (encoding < 0)
- continue;
-
- /* set bits offset in encode map*/
- if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) {
- warning("Error: duplicate encoding for character %d (0x%02x), ignoring duplicate",
- encoding, encoding);
- continue;
- }
- pf->offset[encoding-pf->firstchar] = ofs;
- pf->width[encoding-pf->firstchar] = width;
-
- pf->bbx[encoding-pf->firstchar].w = bbw;
- pf->bbx[encoding-pf->firstchar].h = bbh;
- pf->bbx[encoding-pf->firstchar].x = bbx;
- pf->bbx[encoding-pf->firstchar].y = bby;
-
- if (width > maxwidth)
- maxwidth = width;
-
- /* clear bitmap*/
- memset(ch_bitmap, 0, BITMAP_BYTES(bbw) * bbh);
-
- ch_words = BITMAP_WORDS(bbw);
-
- /* read bitmaps*/
- for (i = 0; i < bbh; ++i) {
- if (!bdf_getline(fp, buf, sizeof(buf))) {
- warning("Error: EOF reading BITMAP data");
- return 0;
- }
- if (isprefix(buf, "ENDCHAR"))
- break;
-
- for (k = 0; k < ch_words; ++k) {
- bitmap_t value;
-
- value = bdf_hexval((unsigned char *)buf);
- if (bbw > 8) {
- WRITE_UINT16(ch_bitmap, value);
- } else {
- WRITE_UINT16(ch_bitmap, value << 8);
- }
- ch_bitmap++;
- }
- }
-
- ofs += ch_words * bbh;
- continue;
- }
- if (strequal(buf, "ENDFONT"))
- break;
- }
-
- /* set max width*/
- pf->maxwidth = maxwidth;
-
- /* change unused offset/width values to default char values*/
- for (i = 0; i < pf->size; ++i) {
- int defchar = pf->defaultchar - pf->firstchar;
-
- if (pf->offset[i] == (unsigned long)-1) {
- pf->offset[i] = pf->offset[defchar];
- pf->width[i] = pf->width[defchar];
- pf->bbx[i].w = pf->bbx[defchar].w;
- pf->bbx[i].h = pf->bbx[defchar].h;
- pf->bbx[i].x = pf->bbx[defchar].x;
- pf->bbx[i].y = pf->bbx[defchar].y;
- }
- }
-
- /* determine whether font doesn't require encode table*/
- l = 0;
- for (i = 0; i < pf->size; ++i) {
- if (pf->offset[i] != (unsigned long)l) {
- encodetable = 1;
- break;
- }
- l += BITMAP_WORDS(pf->bbx[i].w) * pf->bbx[i].h;
- }
- if (!encodetable) {
- free(pf->offset);
- pf->offset = NULL;
- }
-
- /* determine whether font is fixed-width*/
- for (i = 0; i < pf->size; ++i) {
- if (pf->width[i] != maxwidth) {
- proportional = 1;
- break;
- }
- }
- if (!proportional) {
- free(pf->width);
- pf->width = NULL;
- }
-
- /* determine if the font needs a bbx table */
- for (i = 0; i < pf->size; ++i) {
- if (pf->bbx[i].w != pf->fbbw || pf->bbx[i].h != pf->fbbh || pf->bbx[i].x != pf->fbbx || pf->bbx[i].y != pf->fbby) {
- need_bbx = 1;
- break;
- }
- }
- if (!need_bbx) {
- free(pf->bbx);
- pf->bbx = NULL;
- }
-
- /* reallocate bits array to actual bits used*/
- if (ofs < pf->bits_size) {
- bitmap_t *tmp = (bitmap_t *)realloc(pf->bits, ofs * sizeof(bitmap_t));
- if (tmp != NULL || ofs == 0)
- pf->bits = tmp;
- else
- error("bdf_read_bitmaps: Error while reallocating memory");
- pf->bits_size = ofs;
- }
- else {
- if (ofs > pf->bits_size) {
- warning("Warning: DWIDTH spec > max FONTBOUNDINGBOX");
- if (ofs > pf->bits_size+EXTRA) {
- warning("Error: Not enough bits initially allocated");
- return 0;
- }
- pf->bits_size = ofs;
- }
- }
-
- return 1;
-}
-
-/* read the next non-comment line, returns buf or NULL if EOF*/
-// TODO: Can we use SeekableReadStream::readLine instead?
-char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) {
- int c;
- char *b;
-
- for (;;) {
- b = buf;
- while (!fp.eos()) {
- c = fp.readByte();
- if (c == '\r')
- continue;
- if (c == '\n')
- break;
- if (b - buf >= (len - 1))
- break;
- *b++ = c;
- }
- *b = '\0';
- if (fp.eos() && b == buf)
- return NULL;
- if (b != buf && !isprefix(buf, "COMMENT"))
- break;
- }
- return buf;
-}
-
-/* return hex value of buffer */
-bitmap_t bdf_hexval(unsigned char *buf) {
- bitmap_t val = 0;
-
- for (unsigned char *ptr = buf; *ptr; ptr++) {
- int c = *ptr;
-
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'A' && c <= 'F')
- c = c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- c = c - 'a' + 10;
- else
- c = 0;
- val = (val << 4) | c;
- }
- return val;
-}
-
-NewFont *NewFont::loadFont(Common::SeekableReadStream &stream) {
- NewFontData *data = bdf_read_font(stream);
- if (!data || stream.err()) {
- free_font(data);
- return 0;
- }
-
- FontDesc desc;
- desc.name = data->name;
- desc.maxwidth = data->maxwidth;
- desc.height = data->height;
- desc.fbbw = data->fbbw;
- desc.fbbh = data->fbbh;
- desc.fbbx = data->fbbx;
- desc.fbby = data->fbby;
- desc.ascent = data->ascent;
- desc.firstchar = data->firstchar;
- desc.size = data->size;
- desc.bits = data->bits;
- desc.offset = data->offset;
- desc.width = data->width;
- desc.bbx = data->bbx;
- desc.defaultchar = data->defaultchar;
- desc.bits_size = data->bits_size;
-
- return new NewFont(desc, data);
-}
-
-bool NewFont::cacheFontData(const NewFont &font, const Common::String &filename) {
- Common::DumpFile cacheFile;
- if (!cacheFile.open(filename)) {
- warning("Couldn't open file '%s' for writing", filename.c_str());
- return false;
- }
-
- cacheFile.writeUint16BE(font._desc.maxwidth);
- cacheFile.writeUint16BE(font._desc.height);
- cacheFile.writeUint16BE(font._desc.fbbw);
- cacheFile.writeUint16BE(font._desc.fbbh);
- cacheFile.writeSint16BE(font._desc.fbbx);
- cacheFile.writeSint16BE(font._desc.fbby);
- cacheFile.writeUint16BE(font._desc.ascent);
- cacheFile.writeUint16BE(font._desc.firstchar);
- cacheFile.writeUint16BE(font._desc.size);
- cacheFile.writeUint16BE(font._desc.defaultchar);
- cacheFile.writeUint32BE(font._desc.bits_size);
-
- for (long i = 0; i < font._desc.bits_size; ++i) {
- cacheFile.writeUint16BE(font._desc.bits[i]);
- }
-
- if (font._desc.offset) {
- cacheFile.writeByte(1);
- for (int i = 0; i < font._desc.size; ++i) {
- cacheFile.writeUint32BE(font._desc.offset[i]);
- }
- } else {
- cacheFile.writeByte(0);
- }
-
- if (font._desc.width) {
- cacheFile.writeByte(1);
- for (int i = 0; i < font._desc.size; ++i) {
- cacheFile.writeByte(font._desc.width[i]);
- }
- } else {
- cacheFile.writeByte(0);
- }
-
- if (font._desc.bbx) {
- cacheFile.writeByte(1);
- for (int i = 0; i < font._desc.size; ++i) {
- cacheFile.writeByte(font._desc.bbx[i].w);
- cacheFile.writeByte(font._desc.bbx[i].h);
- cacheFile.writeByte(font._desc.bbx[i].x);
- cacheFile.writeByte(font._desc.bbx[i].y);
- }
- } else {
- cacheFile.writeByte(0);
- }
-
- return !cacheFile.err();
-}
-
-NewFont *NewFont::loadFromCache(Common::SeekableReadStream &stream) {
- NewFont *font = 0;
-
- NewFontData *data = (NewFontData *)malloc(sizeof(NewFontData));
- if (!data)
- return 0;
-
- memset(data, 0, sizeof(NewFontData));
-
- data->maxwidth = stream.readUint16BE();
- data->height = stream.readUint16BE();
- data->fbbw = stream.readUint16BE();
- data->fbbh = stream.readUint16BE();
- data->fbbx = stream.readSint16BE();
- data->fbby = stream.readSint16BE();
- data->ascent = stream.readUint16BE();
- data->firstchar = stream.readUint16BE();
- data->size = stream.readUint16BE();
- data->defaultchar = stream.readUint16BE();
- data->bits_size = stream.readUint32BE();
-
- data->bits = (bitmap_t *)malloc(sizeof(bitmap_t) * data->bits_size);
- if (!data->bits) {
- free(data);
- return 0;
- }
-
- for (long i = 0; i < data->bits_size; ++i) {
- data->bits[i] = stream.readUint16BE();
- }
-
- bool hasOffsetTable = (stream.readByte() != 0);
- if (hasOffsetTable) {
- data->offset = (unsigned long *)malloc(sizeof(unsigned long) * data->size);
- if (!data->offset) {
- free(data->bits);
- free(data);
- return 0;
- }
-
- for (int i = 0; i < data->size; ++i) {
- data->offset[i] = stream.readUint32BE();
- }
- }
-
- bool hasWidthTable = (stream.readByte() != 0);
- if (hasWidthTable) {
- data->width = (unsigned char *)malloc(sizeof(unsigned char) * data->size);
- if (!data->width) {
- free(data->bits);
- free(data->offset);
- free(data);
- return 0;
- }
-
- for (int i = 0; i < data->size; ++i) {
- data->width[i] = stream.readByte();
- }
- }
-
- bool hasBBXTable = (stream.readByte() != 0);
- if (hasBBXTable) {
- data->bbx = (BBX *)malloc(sizeof(BBX) * data->size);
- if (!data->bbx) {
- free(data->bits);
- free(data->offset);
- free(data->width);
- free(data);
- return 0;
- }
-
- for (int i = 0; i < data->size; ++i) {
- data->bbx[i].w = (int8)stream.readByte();
- data->bbx[i].h = (int8)stream.readByte();
- data->bbx[i].x = (int8)stream.readByte();
- data->bbx[i].y = (int8)stream.readByte();
- }
- }
-
- if (stream.err() || stream.eos()) {
- free(data->bits);
- free(data->offset);
- free(data->width);
- free(data);
- return 0;
- }
-
- FontDesc desc;
- desc.name = data->name;
- desc.maxwidth = data->maxwidth;
- desc.height = data->height;
- desc.fbbw = data->fbbw;
- desc.fbbh = data->fbbh;
- desc.fbbx = data->fbbx;
- desc.fbby = data->fbby;
- desc.ascent = data->ascent;
- desc.firstchar = data->firstchar;
- desc.size = data->size;
- desc.bits = data->bits;
- desc.offset = data->offset;
- desc.width = data->width;
- desc.bbx = data->bbx;
- desc.defaultchar = data->defaultchar;
- desc.bits_size = data->bits_size;
-
- font = new NewFont(desc, data);
- if (!font) {
- free(data->bits);
- free(data->offset);
- free(data->width);
- free(data);
- return 0;
- }
-
- return font;
-}
-
-#pragma mark -
-
-
int Font::getStringWidth(const Common::String &str) const {
int space = 0;
diff --git a/graphics/font.h b/graphics/font.h
index dc75f86e1f..9c0b4affc1 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -25,7 +25,6 @@
#include "common/str.h"
namespace Common {
-class SeekableReadStream;
template<class T> class Array;
}
@@ -114,68 +113,6 @@ public:
int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const;
};
-typedef uint16 bitmap_t; /* bitmap image unit size*/
-
-struct BBX {
- int8 w;
- int8 h;
- int8 x;
- int8 y;
-};
-
-/* builtin C-based proportional/fixed font structure */
-/* based on The Microwindows Project http://microwindows.org */
-struct FontDesc {
- const char * name; /* font name*/
- int maxwidth; /* max width in pixels*/
- int height; /* height in pixels*/
- int fbbw, fbbh, fbbx, fbby; /* max bounding box */
- int ascent; /* ascent (baseline) height*/
- int firstchar; /* first character in bitmap*/
- int size; /* font size in glyphs*/
- const bitmap_t* bits; /* 16-bit right-padded bitmap data*/
- const unsigned long* offset; /* offsets into bitmap data*/
- const unsigned char* width; /* character widths or NULL if fixed*/
- const BBX* bbx; /* character bounding box or NULL if fixed */
- int defaultchar; /* default char (not glyph index)*/
- long bits_size; /* # words of bitmap_t bits*/
-};
-
-struct NewFontData;
-
-class NewFont : public Font {
-protected:
- FontDesc _desc;
- NewFontData *_font;
-
-public:
- NewFont(const FontDesc &desc, NewFontData *font = 0) : _desc(desc), _font(font) {}
- ~NewFont();
-
- virtual int getFontHeight() const { return _desc.height; }
- virtual int getMaxCharWidth() const { return _desc.maxwidth; }
-
- virtual int getCharWidth(byte chr) const;
- virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
-
- static NewFont *loadFont(Common::SeekableReadStream &stream);
- static bool cacheFontData(const NewFont &font, const Common::String &filename);
- static NewFont *loadFromCache(Common::SeekableReadStream &stream);
-};
-
-#define DEFINE_FONT(n) \
- const NewFont *n = 0; \
- void create_##n() { \
- n = new NewFont(desc); \
- }
-
-#define FORWARD_DECLARE_FONT(n) \
- extern const NewFont *n; \
- extern void create_##n()
-
-#define INIT_FONT(n) \
- create_##n()
-
} // End of namespace Graphics
#endif
diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp
index f40cf97602..e59e5a33c5 100644
--- a/graphics/fontman.cpp
+++ b/graphics/fontman.cpp
@@ -19,11 +19,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "graphics/font.h"
#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "graphics/fonts/bdf.h"
+
#include "common/translation.h"
+namespace Common {
DECLARE_SINGLETON(Graphics::FontManager);
+}
namespace Graphics {
diff --git a/graphics/fonts/bdf.cpp b/graphics/fonts/bdf.cpp
new file mode 100644
index 0000000000..b7d0f7749e
--- /dev/null
+++ b/graphics/fonts/bdf.cpp
@@ -0,0 +1,796 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "graphics/fonts/bdf.h"
+
+#include "common/file.h"
+#include "common/endian.h"
+#include "common/textconsole.h"
+
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+void free_font(BdfFontData *pf);
+
+BdfFont::~BdfFont() {
+ if (_font) {
+ free_font(_font);
+ }
+}
+
+int BdfFont::getFontHeight() const {
+ return _desc.height;
+}
+
+int BdfFont::getMaxCharWidth() const {
+ return _desc.maxwidth;
+}
+
+int BdfFont::getCharWidth(byte chr) const {
+ // If no width table is specified, return the maximum width
+ if (!_desc.width)
+ return _desc.maxwidth;
+ // If this character is not included in the font, use the default char.
+ if (chr < _desc.firstchar || _desc.firstchar + _desc.size < chr) {
+ chr = _desc.defaultchar;
+ }
+ return _desc.width[chr - _desc.firstchar];
+}
+
+
+template<typename PixelType>
+void drawCharIntern(byte *ptr, uint pitch, const bitmap_t *src, int h, int minX, int maxX, const PixelType color) {
+ const bitmap_t maxXMask = ~((1 << (16 - maxX)) - 1);
+ while (h-- > 0) {
+ bitmap_t buffer = READ_UINT16(src);
+ src++;
+
+ buffer &= maxXMask;
+ buffer <<= minX;
+ PixelType *tmp = (PixelType *)ptr;
+ while (buffer != 0) {
+ if ((buffer & 0x8000) != 0)
+ *tmp = color;
+ tmp++;
+ buffer <<= 1;
+ }
+
+ ptr += pitch;
+ }
+}
+
+void BdfFont::drawChar(Surface *dst, byte chr, const int tx, const int ty, const uint32 color) const {
+ assert(dst != 0);
+
+ assert(_desc.bits != 0 && _desc.maxwidth <= 16);
+ assert(dst->format.bytesPerPixel == 1 || dst->format.bytesPerPixel == 2);
+
+ // If this character is not included in the font, use the default char.
+ if (chr < _desc.firstchar || chr >= _desc.firstchar + _desc.size) {
+ chr = _desc.defaultchar;
+ }
+
+ chr -= _desc.firstchar;
+
+ int bbw, bbh, bbx, bby;
+
+ // Get the bounding box of the character
+ if (!_desc.bbx) {
+ bbw = _desc.fbbw;
+ bbh = _desc.fbbh;
+ bbx = _desc.fbbx;
+ bby = _desc.fbby;
+ } else {
+ bbw = _desc.bbx[chr].w;
+ bbh = _desc.bbx[chr].h;
+ bbx = _desc.bbx[chr].x;
+ bby = _desc.bbx[chr].y;
+ }
+
+ byte *ptr = (byte *)dst->getBasePtr(tx + bbx, ty + _desc.ascent - bby - bbh);
+
+ const bitmap_t *tmp = _desc.bits + (_desc.offset ? _desc.offset[chr] : (chr * _desc.fbbh));
+
+ int y = MIN(bbh, ty + _desc.ascent - bby);
+ tmp += bbh - y;
+ y -= MAX(0, ty + _desc.ascent - bby - dst->h);
+
+ if (dst->format.bytesPerPixel == 1)
+ drawCharIntern<byte>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
+ else if (dst->format.bytesPerPixel == 2)
+ drawCharIntern<uint16>(ptr, dst->pitch, tmp, y, MAX(0, -(tx + bbx)), MIN(bbw, dst->w - tx - bbx), color);
+}
+
+
+#pragma mark -
+
+/* BEGIN font.h*/
+/* bitmap_t helper macros*/
+#define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
+#define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
+#define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
+#define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
+#define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
+#define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
+#define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
+
+/* builtin C-based proportional/fixed font structure */
+/* based on The Microwindows Project http://microwindows.org */
+struct BdfFontData {
+ char *name; /* font name */
+ int maxwidth; /* max width in pixels */
+ int height; /* height in pixels */
+ int ascent; /* ascent (baseline) height */
+ int firstchar; /* first character in bitmap */
+ int size; /* font size in glyphs */
+ bitmap_t *bits; /* 16-bit right-padded bitmap data */
+ unsigned long *offset; /* offsets into bitmap data */
+ unsigned char *width; /* character widths or NULL if fixed */
+ BBX *bbx; /* character bounding box or NULL if fixed */
+ int defaultchar; /* default char (not glyph index) */
+ long bits_size; /* # words of bitmap_t bits */
+
+ /* unused by runtime system, read in by convbdf */
+ char *facename; /* facename of font */
+ char *copyright; /* copyright info for loadable fonts */
+ int pixel_size;
+ int descent;
+ int fbbw, fbbh, fbbx, fbby;
+};
+/* END font.h */
+
+#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
+#define strequal(s1,s2) (!strcmp(s1, s2))
+
+#define EXTRA 300
+
+int start_char = 0;
+int limit_char = 255;
+
+BdfFontData *bdf_read_font(Common::SeekableReadStream &fp);
+int bdf_read_header(Common::SeekableReadStream &fp, BdfFontData *pf);
+int bdf_read_bitmaps(Common::SeekableReadStream &fp, BdfFontData *pf);
+char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len);
+bitmap_t bdf_hexval(unsigned char *buf);
+
+void free_font(BdfFontData *pf) {
+ if (!pf)
+ return;
+ free(pf->name);
+ free(pf->facename);
+ free(pf->copyright);
+ free(pf->bits);
+ free(pf->offset);
+ free(pf->width);
+ free(pf->bbx);
+ free(pf);
+}
+
+/* build incore structure from .bdf file*/
+BdfFontData *bdf_read_font(Common::SeekableReadStream &fp) {
+ BdfFontData *pf;
+ uint32 pos = fp.pos();
+
+ pf = (BdfFontData *)calloc(1, sizeof(BdfFontData));
+ if (!pf)
+ goto errout;
+
+ if (!bdf_read_header(fp, pf)) {
+ warning("Error reading font header");
+ goto errout;
+ }
+
+ fp.seek(pos, SEEK_SET);
+
+ if (!bdf_read_bitmaps(fp, pf)) {
+ warning("Error reading font bitmaps");
+ goto errout;
+ }
+
+ return pf;
+
+errout:
+ free_font(pf);
+ return NULL;
+}
+
+/* read bdf font header information, return 0 on error*/
+int bdf_read_header(Common::SeekableReadStream &fp, BdfFontData *pf) {
+ int encoding = 0;
+ int nchars = 0, maxwidth, maxheight;
+ int firstchar = 65535;
+ int lastchar = -1;
+ char buf[256];
+ char facename[256];
+ char copyright[256];
+ memset(facename, 0, sizeof(facename));
+ memset(copyright, 0, sizeof(copyright));
+
+ /* set certain values to errors for later error checking*/
+ pf->defaultchar = -1;
+ pf->ascent = -1;
+ pf->descent = -1;
+
+ for (;;) {
+ if (!bdf_getline(fp, buf, sizeof(buf))) {
+ warning("Error: EOF on file");
+ return 0;
+ }
+
+ /* note: the way sscanf is used here ensures that a terminating null
+ character is automatically added. Refer to:
+ http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html */
+
+ if (isprefix(buf, "FONT ")) { /* not required*/
+ if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
+ warning("Error: bad 'FONT'");
+ return 0;
+ }
+
+ pf->facename = strdup(facename);
+ continue;
+ }
+ if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
+ if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
+ warning("Error: bad 'COPYRIGHT'");
+ return 0;
+ }
+
+ pf->copyright = strdup(copyright);
+ continue;
+ }
+ if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
+ if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
+ warning("Error: bad 'DEFAULT_CHAR'");
+ return 0;
+ }
+ }
+ if (isprefix(buf, "FONT_DESCENT ")) {
+ if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
+ warning("Error: bad 'FONT_DESCENT'");
+ return 0;
+ }
+ continue;
+ }
+ if (isprefix(buf, "FONT_ASCENT ")) {
+ if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
+ warning("Error: bad 'FONT_ASCENT'");
+ return 0;
+ }
+ continue;
+ }
+ if (isprefix(buf, "FONTBOUNDINGBOX ")) {
+ if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
+ &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
+ warning("Error: bad 'FONTBOUNDINGBOX'");
+ return 0;
+ }
+ continue;
+ }
+ if (isprefix(buf, "CHARS ")) {
+ if (sscanf(buf, "CHARS %d", &nchars) != 1) {
+ warning("Error: bad 'CHARS'");
+ return 0;
+ }
+ continue;
+ }
+
+ /*
+ * Reading ENCODING is necessary to get firstchar/lastchar
+ * which is needed to pre-calculate our offset and widths
+ * array sizes.
+ */
+ if (isprefix(buf, "ENCODING ")) {
+ if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
+ warning("Error: bad 'ENCODING'");
+ return 0;
+ }
+ if (encoding >= 0 &&
+ encoding <= limit_char &&
+ encoding >= start_char) {
+
+ if (firstchar > encoding)
+ firstchar = encoding;
+ if (lastchar < encoding)
+ lastchar = encoding;
+ }
+ continue;
+ }
+ if (strequal(buf, "ENDFONT"))
+ break;
+ }
+
+ /* calc font height*/
+ if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
+ warning("Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING");
+ return 0;
+ }
+ pf->height = pf->ascent + pf->descent;
+
+ /* calc default char*/
+ if (pf->defaultchar < 0 ||
+ pf->defaultchar < firstchar ||
+ pf->defaultchar > limit_char)
+ pf->defaultchar = firstchar;
+
+ /* calc font size (offset/width entries)*/
+ pf->firstchar = firstchar;
+ pf->size = lastchar - firstchar + 1;
+
+ /* use the font boundingbox to get initial maxwidth*/
+ /*maxwidth = pf->fbbw - pf->fbbx;*/
+ maxwidth = pf->fbbw;
+ maxheight = pf->fbbh;
+
+ /* initially use font bounding box for bits allocation*/
+ pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * maxheight;
+
+ /* allocate bits, offset, and width arrays*/
+ pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
+ pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long));
+ pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
+ pf->bbx = (BBX *)malloc(pf->size * sizeof(BBX));
+
+ if (!pf->bits || !pf->offset || !pf->width) {
+ warning("Error: no memory for font load");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* read bdf font bitmaps, return 0 on error*/
+int bdf_read_bitmaps(Common::SeekableReadStream &fp, BdfFontData *pf) {
+ long ofs = 0;
+ int maxwidth = 0;
+ int i, k, encoding = 0, width = 0;
+ int bbw = 0, bbh = 0, bbx = 0, bby = 0;
+ int proportional = 0;
+ int need_bbx = 0;
+ int encodetable = 0;
+ long l;
+ char buf[256];
+
+ /* initially mark offsets as not used*/
+ for (i = 0; i < pf->size; ++i)
+ pf->offset[i] = (unsigned long)-1;
+
+ for (;;) {
+ if (!bdf_getline(fp, buf, sizeof(buf))) {
+ warning("Error: EOF on file");
+ return 0;
+ }
+ if (isprefix(buf, "STARTCHAR")) {
+ encoding = width = bbw = bbh = bbx = bby = -1;
+ continue;
+ }
+ if (isprefix(buf, "ENCODING ")) {
+ if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
+ warning("Error: bad 'ENCODING'");
+ return 0;
+ }
+ if (encoding < start_char || encoding > limit_char)
+ encoding = -1;
+ continue;
+ }
+ if (isprefix(buf, "DWIDTH ")) {
+ if (sscanf(buf, "DWIDTH %d", &width) != 1) {
+ warning("Error: bad 'DWIDTH'");
+ return 0;
+ }
+ /* use font boundingbox width if DWIDTH <= 0*/
+ if (width <= 0)
+ width = pf->fbbw - pf->fbbx;
+ continue;
+ }
+ if (isprefix(buf, "BBX ")) {
+ if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
+ warning("Error: bad 'BBX'");
+ return 0;
+ }
+ continue;
+ }
+ if (strequal(buf, "BITMAP")) {
+ bitmap_t *ch_bitmap = pf->bits + ofs;
+ int ch_words;
+
+ if (encoding < 0)
+ continue;
+
+ /* set bits offset in encode map*/
+ if (pf->offset[encoding - pf->firstchar] != (unsigned long)-1) {
+ warning("Error: duplicate encoding for character %d (0x%02x), ignoring duplicate",
+ encoding, encoding);
+ continue;
+ }
+ pf->offset[encoding - pf->firstchar] = ofs;
+ pf->width[encoding - pf->firstchar] = width;
+
+ pf->bbx[encoding - pf->firstchar].w = bbw;
+ pf->bbx[encoding - pf->firstchar].h = bbh;
+ pf->bbx[encoding - pf->firstchar].x = bbx;
+ pf->bbx[encoding - pf->firstchar].y = bby;
+
+ if (width > maxwidth)
+ maxwidth = width;
+
+ /* clear bitmap*/
+ memset(ch_bitmap, 0, BITMAP_BYTES(bbw) * bbh);
+
+ ch_words = BITMAP_WORDS(bbw);
+
+ /* read bitmaps*/
+ for (i = 0; i < bbh; ++i) {
+ if (!bdf_getline(fp, buf, sizeof(buf))) {
+ warning("Error: EOF reading BITMAP data");
+ return 0;
+ }
+ if (isprefix(buf, "ENDCHAR"))
+ break;
+
+ for (k = 0; k < ch_words; ++k) {
+ bitmap_t value;
+
+ value = bdf_hexval((unsigned char *)buf);
+ if (bbw > 8) {
+ WRITE_UINT16(ch_bitmap, value);
+ } else {
+ WRITE_UINT16(ch_bitmap, value << 8);
+ }
+ ch_bitmap++;
+ }
+ }
+
+ ofs += ch_words * bbh;
+ continue;
+ }
+ if (strequal(buf, "ENDFONT"))
+ break;
+ }
+
+ /* set max width*/
+ pf->maxwidth = maxwidth;
+
+ /* change unused offset/width values to default char values*/
+ for (i = 0; i < pf->size; ++i) {
+ int defchar = pf->defaultchar - pf->firstchar;
+
+ if (pf->offset[i] == (unsigned long)-1) {
+ pf->offset[i] = pf->offset[defchar];
+ pf->width[i] = pf->width[defchar];
+ pf->bbx[i].w = pf->bbx[defchar].w;
+ pf->bbx[i].h = pf->bbx[defchar].h;
+ pf->bbx[i].x = pf->bbx[defchar].x;
+ pf->bbx[i].y = pf->bbx[defchar].y;
+ }
+ }
+
+ /* determine whether font doesn't require encode table*/
+ l = 0;
+ for (i = 0; i < pf->size; ++i) {
+ if (pf->offset[i] != (unsigned long)l) {
+ encodetable = 1;
+ break;
+ }
+ l += BITMAP_WORDS(pf->bbx[i].w) * pf->bbx[i].h;
+ }
+ if (!encodetable) {
+ free(pf->offset);
+ pf->offset = NULL;
+ }
+
+ /* determine whether font is fixed-width*/
+ for (i = 0; i < pf->size; ++i) {
+ if (pf->width[i] != maxwidth) {
+ proportional = 1;
+ break;
+ }
+ }
+ if (!proportional) {
+ free(pf->width);
+ pf->width = NULL;
+ }
+
+ /* determine if the font needs a bbx table */
+ for (i = 0; i < pf->size; ++i) {
+ if (pf->bbx[i].w != pf->fbbw || pf->bbx[i].h != pf->fbbh || pf->bbx[i].x != pf->fbbx || pf->bbx[i].y != pf->fbby) {
+ need_bbx = 1;
+ break;
+ }
+ }
+ if (!need_bbx) {
+ free(pf->bbx);
+ pf->bbx = NULL;
+ }
+
+ /* reallocate bits array to actual bits used*/
+ if (ofs < pf->bits_size) {
+ bitmap_t *tmp = (bitmap_t *)realloc(pf->bits, ofs * sizeof(bitmap_t));
+ if (tmp != NULL || ofs == 0)
+ pf->bits = tmp;
+ else
+ error("bdf_read_bitmaps: Error while reallocating memory");
+ pf->bits_size = ofs;
+ } else {
+ if (ofs > pf->bits_size) {
+ warning("Warning: DWIDTH spec > max FONTBOUNDINGBOX");
+ if (ofs > pf->bits_size + EXTRA) {
+ warning("Error: Not enough bits initially allocated");
+ return 0;
+ }
+ pf->bits_size = ofs;
+ }
+ }
+
+ return 1;
+}
+
+/* read the next non-comment line, returns buf or NULL if EOF*/
+// TODO: Can we use SeekableReadStream::readLine instead?
+char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) {
+ int c;
+ char *b;
+
+ for (;;) {
+ b = buf;
+ while (!fp.eos()) {
+ c = fp.readByte();
+ if (c == '\r')
+ continue;
+ if (c == '\n')
+ break;
+ if (b - buf >= (len - 1))
+ break;
+ *b++ = c;
+ }
+ *b = '\0';
+ if (fp.eos() && b == buf)
+ return NULL;
+ if (b != buf && !isprefix(buf, "COMMENT"))
+ break;
+ }
+ return buf;
+}
+
+/* return hex value of buffer */
+bitmap_t bdf_hexval(unsigned char *buf) {
+ bitmap_t val = 0;
+
+ for (unsigned char *ptr = buf; *ptr; ptr++) {
+ int c = *ptr;
+
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'A' && c <= 'F')
+ c = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ c = c - 'a' + 10;
+ else
+ c = 0;
+ val = (val << 4) | c;
+ }
+ return val;
+}
+
+BdfFont *BdfFont::loadFont(Common::SeekableReadStream &stream) {
+ BdfFontData *data = bdf_read_font(stream);
+ if (!data || stream.err()) {
+ free_font(data);
+ return 0;
+ }
+
+ BdfFontDesc desc;
+ desc.name = data->name;
+ desc.maxwidth = data->maxwidth;
+ desc.height = data->height;
+ desc.fbbw = data->fbbw;
+ desc.fbbh = data->fbbh;
+ desc.fbbx = data->fbbx;
+ desc.fbby = data->fbby;
+ desc.ascent = data->ascent;
+ desc.firstchar = data->firstchar;
+ desc.size = data->size;
+ desc.bits = data->bits;
+ desc.offset = data->offset;
+ desc.width = data->width;
+ desc.bbx = data->bbx;
+ desc.defaultchar = data->defaultchar;
+ desc.bits_size = data->bits_size;
+
+ return new BdfFont(desc, data);
+}
+
+bool BdfFont::cacheFontData(const BdfFont &font, const Common::String &filename) {
+ Common::DumpFile cacheFile;
+ if (!cacheFile.open(filename)) {
+ warning("Couldn't open file '%s' for writing", filename.c_str());
+ return false;
+ }
+
+ cacheFile.writeUint16BE(font._desc.maxwidth);
+ cacheFile.writeUint16BE(font._desc.height);
+ cacheFile.writeUint16BE(font._desc.fbbw);
+ cacheFile.writeUint16BE(font._desc.fbbh);
+ cacheFile.writeSint16BE(font._desc.fbbx);
+ cacheFile.writeSint16BE(font._desc.fbby);
+ cacheFile.writeUint16BE(font._desc.ascent);
+ cacheFile.writeUint16BE(font._desc.firstchar);
+ cacheFile.writeUint16BE(font._desc.size);
+ cacheFile.writeUint16BE(font._desc.defaultchar);
+ cacheFile.writeUint32BE(font._desc.bits_size);
+
+ for (long i = 0; i < font._desc.bits_size; ++i) {
+ cacheFile.writeUint16BE(font._desc.bits[i]);
+ }
+
+ if (font._desc.offset) {
+ cacheFile.writeByte(1);
+ for (int i = 0; i < font._desc.size; ++i) {
+ cacheFile.writeUint32BE(font._desc.offset[i]);
+ }
+ } else {
+ cacheFile.writeByte(0);
+ }
+
+ if (font._desc.width) {
+ cacheFile.writeByte(1);
+ for (int i = 0; i < font._desc.size; ++i) {
+ cacheFile.writeByte(font._desc.width[i]);
+ }
+ } else {
+ cacheFile.writeByte(0);
+ }
+
+ if (font._desc.bbx) {
+ cacheFile.writeByte(1);
+ for (int i = 0; i < font._desc.size; ++i) {
+ cacheFile.writeByte(font._desc.bbx[i].w);
+ cacheFile.writeByte(font._desc.bbx[i].h);
+ cacheFile.writeByte(font._desc.bbx[i].x);
+ cacheFile.writeByte(font._desc.bbx[i].y);
+ }
+ } else {
+ cacheFile.writeByte(0);
+ }
+
+ return !cacheFile.err();
+}
+
+BdfFont *BdfFont::loadFromCache(Common::SeekableReadStream &stream) {
+ BdfFont *font = 0;
+
+ BdfFontData *data = (BdfFontData *)malloc(sizeof(BdfFontData));
+ if (!data)
+ return 0;
+
+ memset(data, 0, sizeof(BdfFontData));
+
+ data->maxwidth = stream.readUint16BE();
+ data->height = stream.readUint16BE();
+ data->fbbw = stream.readUint16BE();
+ data->fbbh = stream.readUint16BE();
+ data->fbbx = stream.readSint16BE();
+ data->fbby = stream.readSint16BE();
+ data->ascent = stream.readUint16BE();
+ data->firstchar = stream.readUint16BE();
+ data->size = stream.readUint16BE();
+ data->defaultchar = stream.readUint16BE();
+ data->bits_size = stream.readUint32BE();
+
+ data->bits = (bitmap_t *)malloc(sizeof(bitmap_t) * data->bits_size);
+ if (!data->bits) {
+ free(data);
+ return 0;
+ }
+
+ for (long i = 0; i < data->bits_size; ++i) {
+ data->bits[i] = stream.readUint16BE();
+ }
+
+ bool hasOffsetTable = (stream.readByte() != 0);
+ if (hasOffsetTable) {
+ data->offset = (unsigned long *)malloc(sizeof(unsigned long) * data->size);
+ if (!data->offset) {
+ free(data->bits);
+ free(data);
+ return 0;
+ }
+
+ for (int i = 0; i < data->size; ++i) {
+ data->offset[i] = stream.readUint32BE();
+ }
+ }
+
+ bool hasWidthTable = (stream.readByte() != 0);
+ if (hasWidthTable) {
+ data->width = (unsigned char *)malloc(sizeof(unsigned char) * data->size);
+ if (!data->width) {
+ free(data->bits);
+ free(data->offset);
+ free(data);
+ return 0;
+ }
+
+ for (int i = 0; i < data->size; ++i) {
+ data->width[i] = stream.readByte();
+ }
+ }
+
+ bool hasBBXTable = (stream.readByte() != 0);
+ if (hasBBXTable) {
+ data->bbx = (BBX *)malloc(sizeof(BBX) * data->size);
+ if (!data->bbx) {
+ free(data->bits);
+ free(data->offset);
+ free(data->width);
+ free(data);
+ return 0;
+ }
+
+ for (int i = 0; i < data->size; ++i) {
+ data->bbx[i].w = (int8)stream.readByte();
+ data->bbx[i].h = (int8)stream.readByte();
+ data->bbx[i].x = (int8)stream.readByte();
+ data->bbx[i].y = (int8)stream.readByte();
+ }
+ }
+
+ if (stream.err() || stream.eos()) {
+ free(data->bits);
+ free(data->offset);
+ free(data->width);
+ free(data);
+ return 0;
+ }
+
+ BdfFontDesc desc;
+ desc.name = data->name;
+ desc.maxwidth = data->maxwidth;
+ desc.height = data->height;
+ desc.fbbw = data->fbbw;
+ desc.fbbh = data->fbbh;
+ desc.fbbx = data->fbbx;
+ desc.fbby = data->fbby;
+ desc.ascent = data->ascent;
+ desc.firstchar = data->firstchar;
+ desc.size = data->size;
+ desc.bits = data->bits;
+ desc.offset = data->offset;
+ desc.width = data->width;
+ desc.bbx = data->bbx;
+ desc.defaultchar = data->defaultchar;
+ desc.bits_size = data->bits_size;
+
+ font = new BdfFont(desc, data);
+ if (!font) {
+ free(data->bits);
+ free(data->offset);
+ free(data->width);
+ free(data);
+ return 0;
+ }
+
+ return font;
+}
+
+} // End of namespace Graphics
+
diff --git a/graphics/fonts/bdf.h b/graphics/fonts/bdf.h
new file mode 100644
index 0000000000..31c009eb27
--- /dev/null
+++ b/graphics/fonts/bdf.h
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GRAPHICS_FONTS_BDF_H
+#define GRAPHICS_FONTS_BDF_H
+
+#include "common/system.h"
+
+#include "graphics/font.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+
+typedef uint16 bitmap_t; /* bitmap image unit size*/
+
+struct BBX {
+ int8 w;
+ int8 h;
+ int8 x;
+ int8 y;
+};
+
+/* builtin C-based proportional/fixed font structure */
+/* based on The Microwindows Project http://microwindows.org */
+struct BdfFontDesc {
+ const char *name; /* font name */
+ int maxwidth; /* max width in pixels */
+ int height; /* height in pixels */
+ int fbbw, fbbh, fbbx, fbby; /* max bounding box */
+ int ascent; /* ascent (baseline) height */
+ int firstchar; /* first character in bitmap */
+ int size; /* font size in glyphs */
+ const bitmap_t *bits; /* 16-bit right-padded bitmap data */
+ const unsigned long *offset; /* offsets into bitmap data */
+ const unsigned char *width; /* character widths or NULL if fixed */
+ const BBX *bbx; /* character bounding box or NULL if fixed */
+ int defaultchar; /* default char (not glyph index) */
+ long bits_size; /* # words of bitmap_t bits */
+};
+
+struct BdfFontData;
+
+class BdfFont : public Font {
+protected:
+ BdfFontDesc _desc;
+ BdfFontData *_font;
+
+public:
+ BdfFont(const BdfFontDesc &desc, BdfFontData *font = 0) : _desc(desc), _font(font) {}
+ ~BdfFont();
+
+ virtual int getFontHeight() const;
+ virtual int getMaxCharWidth() const;
+
+ virtual int getCharWidth(byte chr) const;
+ virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
+
+ static BdfFont *loadFont(Common::SeekableReadStream &stream);
+ static bool cacheFontData(const BdfFont &font, const Common::String &filename);
+ static BdfFont *loadFromCache(Common::SeekableReadStream &stream);
+};
+
+#define DEFINE_FONT(n) \
+ const BdfFont *n = 0; \
+ void create_##n() { \
+ n = new BdfFont(desc); \
+ }
+
+#define FORWARD_DECLARE_FONT(n) \
+ extern const BdfFont *n; \
+ extern void create_##n()
+
+#define INIT_FONT(n) \
+ create_##n()
+
+} // End of namespace Graphics
+
+#endif
+
diff --git a/graphics/fonts/consolefont.cpp b/graphics/fonts/consolefont.cpp
index 65ccd3ec70..5b4768327a 100644
--- a/graphics/fonts/consolefont.cpp
+++ b/graphics/fonts/consolefont.cpp
@@ -1,5 +1,5 @@
/* Generated by convbdf on Sat Jun 17 01:37:46 2006. */
-#include "graphics/font.h"
+#include "graphics/fonts/bdf.h"
/* Font information:
name: 5x8-L1
@@ -5635,7 +5635,7 @@ static const unsigned long _sysfont_offset[] = {
};
/* Exported structure definition. */
-static const FontDesc desc = {
+static const BdfFontDesc desc = {
"5x8-L1",
5,
8,
diff --git a/graphics/fonts/newfont.cpp b/graphics/fonts/newfont.cpp
index 0327c0997a..f02baba2de 100644
--- a/graphics/fonts/newfont.cpp
+++ b/graphics/fonts/newfont.cpp
@@ -1,5 +1,5 @@
/* Generated by convbdf on Sat Jun 17 01:34:15 2006. */
-#include "graphics/font.h"
+#include "graphics/fonts/bdf.h"
/* Font information:
name: clR6x12-L1
@@ -7419,7 +7419,7 @@ static const unsigned long _sysfont_offset[] = {
};
/* Exported structure definition. */
-static const FontDesc desc = {
+static const BdfFontDesc desc = {
"clR6x12-L1",
6,
12,
diff --git a/graphics/fonts/newfont_big.cpp b/graphics/fonts/newfont_big.cpp
index 7b15a6ab38..59c54a4551 100644
--- a/graphics/fonts/newfont_big.cpp
+++ b/graphics/fonts/newfont_big.cpp
@@ -1,5 +1,5 @@
/* Generated by convbdf on Tue Jun 13 00:00:22 2006. */
-#include "graphics/font.h"
+#include "graphics/fonts/bdf.h"
/* Font information:
name: helvB12-L1
@@ -5523,7 +5523,7 @@ static const BBX _sysfont_bbx[] = {
};
/* Exported structure definition. */
-static const FontDesc desc = {
+static const BdfFontDesc desc = {
"helvB12-L1",
13,
14,
diff --git a/graphics/module.mk b/graphics/module.mk
index 32658c96bd..469ee42047 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
dither.o \
font.o \
fontman.o \
+ fonts/bdf.o \
fonts/consolefont.o \
fonts/newfont_big.o \
fonts/newfont.o \
diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp
index 09e1746df4..10c780b156 100644
--- a/graphics/sjis.cpp
+++ b/graphics/sjis.cpp
@@ -46,7 +46,7 @@ FontSJIS *FontSJIS::createFont(const Common::Platform platform) {
}
// Try ScummVM's font.
- ret = new FontSjisSVM();
+ ret = new FontSjisSVM(platform);
if (ret && ret->loadData())
return ret;
delete ret;
@@ -58,6 +58,51 @@ void FontSJIS::drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32
drawChar(dst.getBasePtr(x, y), ch, dst.pitch, dst.format.bytesPerPixel, c1, c2, dst.w - x, dst.h - y);
}
+FontSJISBase::FontSJISBase()
+ : _drawMode(kDefaultMode), _flippedMode(false), _fontWidth(16), _fontHeight(16) {
+}
+
+void FontSJISBase::setDrawingMode(DrawingMode mode) {
+ _drawMode = mode;
+}
+
+void FontSJISBase::toggleFlippedMode(bool enable) {
+ _flippedMode = enable;
+}
+
+uint FontSJISBase::getFontHeight() const {
+ switch (_drawMode) {
+ case kOutlineMode:
+ return _fontHeight + 2;
+
+ case kDefaultMode:
+ return _fontHeight;
+
+ default:
+ return _fontHeight + 1;
+ }
+}
+
+uint FontSJISBase::getMaxFontWidth() const {
+ switch (_drawMode) {
+ case kOutlineMode:
+ return _fontWidth + 2;
+
+ case kDefaultMode:
+ return _fontWidth;
+
+ default:
+ return _fontWidth + 1;
+ }
+}
+
+uint FontSJISBase::getCharWidth(uint16 ch) const {
+ if (isASCII(ch))
+ return (_drawMode == kOutlineMode) ? 10 : (_drawMode == kDefaultMode ? 8 : 9);
+ else
+ return getMaxFontWidth();
+}
+
template<typename Color>
void FontSJISBase::blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const {
for (int y = 0; y < h; ++y) {
@@ -131,6 +176,9 @@ const uint8 *FontSJISBase::flipCharacter(const uint8 *glyph, const int w) const
0x0F, 0x8F, 0x4F, 0xC7, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x97, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
+ // TODO: This code looks like it will only work with 16 pixel wide
+ // characters we should really take care that we only call it on these
+ // or we fix this to support a generic width.
for (int i = 0; i < w; i++) {
_tempGlyph[i] = flipData[glyph[(w * 2 - 1) - i]];
_tempGlyph[(w * 2 - 1) - i] = flipData[glyph[i]];
@@ -146,14 +194,14 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
int outlineExtraWidth = 2, outlineExtraHeight = 2;
int outlineXOffset = 0, outlineYOffset = 0;
- if (is8x16(ch)) {
- glyphSource = getCharData8x16(ch);
+ if (isASCII(ch)) {
+ glyphSource = getCharData(ch);
width = 8;
- height = 16;
+ height = _fontHeight;
} else {
glyphSource = getCharData(ch);
- width = 16;
- height = 16;
+ width = _fontWidth;
+ height = _fontHeight;
}
if (maxW != -1 && maxW < width) {
@@ -177,6 +225,9 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
}
#ifndef DISABLE_FLIPPED_MODE
+ // TODO: This code inside flopCharater looks like it will only work with
+ // 16 pixel wide characters we should really take care that we only call
+ // it on these or we fix it to support a generic width.
if (_flippedMode)
glyphSource = flipCharacter(glyphSource, width);
#endif
@@ -220,14 +271,7 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
}
}
-uint FontSJISBase::getCharWidth(uint16 ch) const {
- if (is8x16(ch))
- return (_drawMode == kOutlineMode) ? 10 : (_drawMode == kDefaultMode ? 8 : 9);
- else
- return getMaxFontWidth();
-}
-
-bool FontSJISBase::is8x16(uint16 ch) const {
+bool FontSJISBase::isASCII(uint16 ch) const {
if (ch >= 0xFF)
return false;
else if (ch <= 0x7F || (ch >= 0xA1 && ch <= 0xDF))
@@ -253,105 +297,119 @@ bool FontTowns::loadData() {
}
const uint8 *FontTowns::getCharData(uint16 ch) const {
- uint8 f = ch & 0xFF;
- uint8 s = ch >> 8;
-
- // copied from scumm\charset.cpp
- enum {
- KANA = 0,
- KANJI = 1,
- EKANJI = 2
- };
+ if (ch < kFont8x16Chars) {
+ return _fontData8x16 + ch * 16;
+ } else {
+ uint8 f = ch & 0xFF;
+ uint8 s = ch >> 8;
+
+ // copied from scumm\charset.cpp
+ enum {
+ KANA = 0,
+ KANJI = 1,
+ EKANJI = 2
+ };
+
+ int base = s - ((s + 1) % 32);
+ int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;
+
+ if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
+ if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
+ if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;
+
+ if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
+ c = 48; //correction
+ p = -8; //correction
+ }
- int base = s - ((s + 1) % 32);
- int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;
+ if (kanjiType == KANA) {//Kana
+ chunk_f = (f - 0x81) * 2;
+ } else if (kanjiType == KANJI) {//Standard Kanji
+ p += f - 0x88;
+ chunk_f = c + 2 * p;
+ } else if (kanjiType == EKANJI) {//Enhanced Kanji
+ p += f - 0xe0;
+ chunk_f = c + 2 * p;
+ }
- if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
- if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
- if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;
+ // Base corrections
+ if (base == 0x7f && s == 0x7f)
+ base -= 0x20;
+ if (base == 0x9f && s == 0xbe)
+ base += 0x20;
+ if (base == 0xbf && s == 0xde)
+ base += 0x20;
+ //if (base == 0x7f && s == 0x9e)
+ // base += 0x20;
+
+ switch (base) {
+ case 0x3f:
+ cr = 0; //3f
+ if (kanjiType == KANA) chunk = 1;
+ else if (kanjiType == KANJI) chunk = 31;
+ else if (kanjiType == EKANJI) chunk = 111;
+ break;
+ case 0x5f:
+ cr = 0; //5f
+ if (kanjiType == KANA) chunk = 17;
+ else if (kanjiType == KANJI) chunk = 47;
+ else if (kanjiType == EKANJI) chunk = 127;
+ break;
+ case 0x7f:
+ cr = -1; //80
+ if (kanjiType == KANA) chunk = 9;
+ else if (kanjiType == KANJI) chunk = 63;
+ else if (kanjiType == EKANJI) chunk = 143;
+ break;
+ case 0x9f:
+ cr = 1; //9e
+ if (kanjiType == KANA) chunk = 2;
+ else if (kanjiType == KANJI) chunk = 32;
+ else if (kanjiType == EKANJI) chunk = 112;
+ break;
+ case 0xbf:
+ cr = 1; //be
+ if (kanjiType == KANA) chunk = 18;
+ else if (kanjiType == KANJI) chunk = 48;
+ else if (kanjiType == EKANJI) chunk = 128;
+ break;
+ case 0xdf:
+ cr = 1; //de
+ if (kanjiType == KANA) chunk = 10;
+ else if (kanjiType == KANJI) chunk = 64;
+ else if (kanjiType == EKANJI) chunk = 144;
+ break;
+ default:
+ debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
+ }
- if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
- c = 48; //correction
- p = -8; //correction
+ debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
+ const int chunkNum = (((chunk_f + chunk) * 32 + (s - base)) + cr);
+ if (chunkNum < 0 || chunkNum >= kFont16x16Chars)
+ return 0;
+ else
+ return _fontData16x16 + chunkNum * 32;
}
+}
- if (kanjiType == KANA) {//Kana
- chunk_f = (f - 0x81) * 2;
- } else if (kanjiType == KANJI) {//Standard Kanji
- p += f - 0x88;
- chunk_f = c + 2 * p;
- } else if (kanjiType == EKANJI) {//Enhanced Kanji
- p += f - 0xe0;
- chunk_f = c + 2 * p;
- }
+// ScummVM SJIS font
- // Base corrections
- if (base == 0x7f && s == 0x7f)
- base -= 0x20;
- if (base == 0x9f && s == 0xbe)
- base += 0x20;
- if (base == 0xbf && s == 0xde)
- base += 0x20;
- //if (base == 0x7f && s == 0x9e)
- // base += 0x20;
-
- switch (base) {
- case 0x3f:
- cr = 0; //3f
- if (kanjiType == KANA) chunk = 1;
- else if (kanjiType == KANJI) chunk = 31;
- else if (kanjiType == EKANJI) chunk = 111;
- break;
- case 0x5f:
- cr = 0; //5f
- if (kanjiType == KANA) chunk = 17;
- else if (kanjiType == KANJI) chunk = 47;
- else if (kanjiType == EKANJI) chunk = 127;
- break;
- case 0x7f:
- cr = -1; //80
- if (kanjiType == KANA) chunk = 9;
- else if (kanjiType == KANJI) chunk = 63;
- else if (kanjiType == EKANJI) chunk = 143;
- break;
- case 0x9f:
- cr = 1; //9e
- if (kanjiType == KANA) chunk = 2;
- else if (kanjiType == KANJI) chunk = 32;
- else if (kanjiType == EKANJI) chunk = 112;
- break;
- case 0xbf:
- cr = 1; //be
- if (kanjiType == KANA) chunk = 18;
- else if (kanjiType == KANJI) chunk = 48;
- else if (kanjiType == EKANJI) chunk = 128;
- break;
- case 0xdf:
- cr = 1; //de
- if (kanjiType == KANA) chunk = 10;
- else if (kanjiType == KANJI) chunk = 64;
- else if (kanjiType == EKANJI) chunk = 144;
- break;
- default:
- debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
- }
+FontSjisSVM::FontSjisSVM(const Common::Platform platform)
+ : _fontData16x16(0), _fontData16x16Size(0), _fontData8x16(0), _fontData8x16Size(0),
+ _fontData12x12(0), _fontData12x12Size(0) {
- debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
- const int chunkNum = (((chunk_f + chunk) * 32 + (s - base)) + cr);
- if (chunkNum < 0 || chunkNum >= kFont16x16Chars)
- return 0;
- else
- return _fontData16x16 + chunkNum * 32;
+ if (platform == Common::kPlatformPCEngine) {
+ _fontWidth = 12;
+ _fontHeight = 12;
+ }
}
-const uint8 *FontTowns::getCharData8x16(uint16 c) const {
- if (c >= kFont8x16Chars)
- return 0;
- return _fontData8x16 + c * 16;
+FontSjisSVM::~FontSjisSVM() {
+ delete[] _fontData16x16;
+ delete[] _fontData8x16;
+ delete[] _fontData12x12;
}
-// ScummVM SJIS font
-
bool FontSjisSVM::loadData() {
Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("SJIS.FNT");
if (!data)
@@ -366,23 +424,33 @@ bool FontSjisSVM::loadData() {
}
uint32 version = data->readUint32BE();
- if (version != 2) {
+ if (version != 3) {
delete data;
return false;
}
uint numChars16x16 = data->readUint16BE();
uint numChars8x16 = data->readUint16BE();
+ uint numChars12x12 = data->readUint16BE();
+
+ if (_fontWidth == 16) {
+ _fontData16x16Size = numChars16x16 * 32;
+ _fontData16x16 = new uint8[_fontData16x16Size];
+ assert(_fontData16x16);
+ data->read(_fontData16x16, _fontData16x16Size);
+
+ _fontData8x16Size = numChars8x16 * 16;
+ _fontData8x16 = new uint8[numChars8x16 * 16];
+ assert(_fontData8x16);
+ data->read(_fontData8x16, _fontData8x16Size);
+ } else {
+ data->skip(numChars16x16 * 32);
+ data->skip(numChars8x16 * 16);
- _fontData16x16Size = numChars16x16 * 32;
- _fontData16x16 = new uint8[_fontData16x16Size];
- assert(_fontData16x16);
- data->read(_fontData16x16, _fontData16x16Size);
-
- _fontData8x16Size = numChars8x16 * 16;
- _fontData8x16 = new uint8[numChars8x16 * 16];
- assert(_fontData8x16);
-
- data->read(_fontData8x16, _fontData8x16Size);
+ _fontData12x12Size = numChars12x12 * 24;
+ _fontData12x12 = new uint8[_fontData12x12Size];
+ assert(_fontData12x12);
+ data->read(_fontData12x12, _fontData12x12Size);
+ }
bool retValue = !data->err();
delete data;
@@ -390,49 +458,76 @@ bool FontSjisSVM::loadData() {
}
const uint8 *FontSjisSVM::getCharData(uint16 c) const {
- const uint8 fB = c & 0xFF;
- const uint8 sB = c >> 8;
+ if (_fontWidth == 12)
+ return getCharDataPCE(c);
+ else
+ return getCharDataDefault(c);
+}
- // We only allow 2 byte SJIS characters.
- if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
+const uint8 *FontSjisSVM::getCharDataPCE(uint16 c) const {
+ if (isASCII(c))
return 0;
- int base = fB;
- base -= 0x81;
- if (base >= 0x5F)
- base -= 0x40;
+ const uint8 fB = c & 0xFF;
+ const uint8 sB = c >> 8;
- int index = sB;
- index -= 0x40;
- if (index >= 0x3F)
- --index;
+ int base, index;
+ mapKANJIChar(fB, sB, base, index);
- // Another check if the passed character was an
- // correctly encoded SJIS character.
- if (index < 0 || index >= 0xBC || base < 0)
+ if (base == -1)
return 0;
- const uint offset = (base * 0xBC + index) * 32;
- assert(offset + 16 <= _fontData16x16Size);
- return _fontData16x16 + offset;
+ const uint offset = (base * 0xBC + index) * 24;
+ assert(offset + 16 <= _fontData12x12Size);
+ return _fontData12x12 + offset;
}
-const uint8 *FontSjisSVM::getCharData8x16(uint16 c) const {
+const uint8 *FontSjisSVM::getCharDataDefault(uint16 c) const {
const uint8 fB = c & 0xFF;
const uint8 sB = c >> 8;
- if (!is8x16(c) || sB)
- return 0;
+ if (isASCII(c)) {
+ int index = fB;
+
+ // half-width katakana
+ if (fB >= 0xA1 && fB <= 0xDF)
+ index -= 0x21;
- int index = fB;
+ const uint offset = index * 16;
+ assert(offset <= _fontData8x16Size);
+ return _fontData8x16 + offset;
+ } else {
+ int base, index;
+ mapKANJIChar(fB, sB, base, index);
- // half-width katakana
- if (fB >= 0xA1 && fB <= 0xDF)
- index -= 0x21;
+ if (base == -1)
+ return 0;
- const uint offset = index * 16;
- assert(offset <= _fontData8x16Size);
- return _fontData8x16 + offset;
+ const uint offset = (base * 0xBC + index) * 32;
+ assert(offset + 16 <= _fontData16x16Size);
+ return _fontData16x16 + offset;
+ }
+}
+
+void FontSjisSVM::mapKANJIChar(const uint8 fB, const uint8 sB, int &base, int &index) const {
+ base = index = -1;
+
+ // We only allow 2 byte SJIS characters.
+ if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
+ return;
+
+ base = fB - 0x81;
+ if (base >= 0x5F)
+ base -= 0x40;
+
+ index = sB - 0x40;
+ if (index >= 0x3F)
+ --index;
+
+ // Another check if the passed character was an
+ // correctly encoded SJIS character.
+ if (index < 0 || index >= 0xBC || base < 0)
+ base = index = -1;
}
} // End of namespace Graphics
diff --git a/graphics/sjis.h b/graphics/sjis.h
index 0c3b057cc4..62e68013da 100644
--- a/graphics/sjis.h
+++ b/graphics/sjis.h
@@ -123,30 +123,30 @@ public:
* @param bpp bytes per pixel of the destination buffer
* @param c1 forground color
* @param c2 outline color
- * @param maxW max draw width (to ensure that character drawing takes place within surface boundaries)
- * @param maxH max draw height (to ensure that character drawing takes place within surface boundaries)
+ * @param maxW max draw width (to ensure that character drawing takes place within surface boundaries), -1 = no check
+ * @param maxH max draw height (to ensure that character drawing takes place within surface boundaries), -1 = no check
*/
- virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const = 0;
+ virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW, int maxH) const = 0;
};
/**
- * A base class to render 16x16 (2 byte chars), 8x16 (1 byte chars) monochrome SJIS fonts.
+ * A base class to render monochrome SJIS fonts.
*/
class FontSJISBase : public FontSJIS {
public:
- FontSJISBase() : _drawMode(kDefaultMode), _flippedMode(false) {}
+ FontSJISBase();
- void setDrawingMode(DrawingMode mode) { _drawMode = mode; }
+ virtual void setDrawingMode(DrawingMode mode);
- void toggleFlippedMode(bool enable) { _flippedMode = enable; }
+ virtual void toggleFlippedMode(bool enable);
- uint getFontHeight() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); }
+ virtual uint getFontHeight() const;
- uint getMaxFontWidth() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); }
+ virtual uint getMaxFontWidth() const;
- uint getCharWidth(uint16 ch) const;
+ virtual uint getCharWidth(uint16 ch) const;
- void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const;
+ virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW, int maxH) const;
private:
template<typename Color>
void blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const;
@@ -161,11 +161,11 @@ private:
protected:
DrawingMode _drawMode;
bool _flippedMode;
+ int _fontWidth, _fontHeight;
- bool is8x16(uint16 ch) const;
+ bool isASCII(uint16 ch) const;
virtual const uint8 *getCharData(uint16 c) const = 0;
- virtual const uint8 *getCharData8x16(uint16 c) const = 0;
};
/**
@@ -188,8 +188,7 @@ private:
uint8 _fontData16x16[kFont16x16Chars * 32];
uint8 _fontData8x16[kFont8x16Chars * 32];
- const uint8 *getCharData(uint16 c) const;
- const uint8 *getCharData8x16(uint16 c) const;
+ virtual const uint8 *getCharData(uint16 c) const;
};
/**
@@ -197,8 +196,8 @@ private:
*/
class FontSjisSVM : public FontSJISBase {
public:
- FontSjisSVM() : _fontData16x16(0), _fontData16x16Size(0), _fontData8x16(0), _fontData8x16Size(0) {}
- ~FontSjisSVM() { delete[] _fontData16x16; delete[] _fontData8x16; }
+ FontSjisSVM(const Common::Platform platform);
+ ~FontSjisSVM();
/**
* Load the font data from "SJIS.FNT".
@@ -211,8 +210,15 @@ private:
uint8 *_fontData8x16;
uint _fontData8x16Size;
- const uint8 *getCharData(uint16 c) const;
- const uint8 *getCharData8x16(uint16 c) const;
+ uint8 *_fontData12x12;
+ uint _fontData12x12Size;
+
+ virtual const uint8 *getCharData(uint16 c) const;
+
+ const uint8 *getCharDataPCE(uint16 c) const;
+ const uint8 *getCharDataDefault(uint16 c) const;
+
+ void mapKANJIChar(const uint8 fB, const uint8 sB, int &base, int &index) const;
};
// TODO: Consider adding support for PC98 ROM
diff --git a/graphics/yuv_to_rgb.cpp b/graphics/yuv_to_rgb.cpp
index 037ea9a007..bdc481016e 100644
--- a/graphics/yuv_to_rgb.cpp
+++ b/graphics/yuv_to_rgb.cpp
@@ -189,7 +189,9 @@ const YUVToRGBLookup *YUVToRGBManager::getLookup(Graphics::PixelFormat format) {
} // End of namespace Graphics
+namespace Common {
DECLARE_SINGLETON(Graphics::YUVToRGBManager);
+}
#define YUVToRGBMan (Graphics::YUVToRGBManager::instance())
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 73c1835c9e..4a2e0a7ac5 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -33,6 +33,7 @@
#include "graphics/imagedec.h"
#include "graphics/surface.h"
#include "graphics/VectorRenderer.h"
+#include "graphics/fonts/bdf.h"
#include "gui/widget.h"
#include "gui/ThemeEngine.h"
@@ -1394,7 +1395,7 @@ const Graphics::Font *ThemeEngine::loadFontFromArchive(const Common::String &fil
if (_themeArchive)
stream = _themeArchive->createReadStreamForMember(filename);
if (stream) {
- font = Graphics::NewFont::loadFont(*stream);
+ font = Graphics::BdfFont::loadFont(*stream);
delete stream;
}
@@ -1408,7 +1409,7 @@ const Graphics::Font *ThemeEngine::loadCachedFontFromArchive(const Common::Strin
if (_themeArchive)
stream = _themeArchive->createReadStreamForMember(filename);
if (stream) {
- font = Graphics::NewFont::loadFromCache(*stream);
+ font = Graphics::BdfFont::loadFromCache(*stream);
delete stream;
}
@@ -1422,7 +1423,7 @@ const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
if (!cacheFilename.empty()) {
if (fontFile.open(cacheFilename)) {
- font = Graphics::NewFont::loadFromCache(fontFile);
+ font = Graphics::BdfFont::loadFromCache(fontFile);
}
if (font)
@@ -1434,7 +1435,7 @@ const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
// normal open
if (fontFile.open(filename)) {
- font = Graphics::NewFont::loadFont(fontFile);
+ font = Graphics::BdfFont::loadFont(fontFile);
}
if (!font) {
@@ -1443,7 +1444,7 @@ const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
if (font) {
if (!cacheFilename.empty()) {
- if (!Graphics::NewFont::cacheFontData(*(const Graphics::NewFont *)font, cacheFilename)) {
+ if (!Graphics::BdfFont::cacheFontData(*(const Graphics::BdfFont *)font, cacheFilename)) {
warning("Couldn't create cache file for font '%s'", filename.c_str());
}
}
diff --git a/gui/credits.h b/gui/credits.h
index 91ed2cb26a..cc9698195a 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -25,7 +25,6 @@ static const char *credits[] = {
"C0""Max Horn",
"C2""(retired)",
"C0""Travis Howell",
-"C2""(retired)",
"C0""Pawel Kolodziejski",
"C2""Codecs, iMUSE, Smush, etc.",
"C0""Gregory Montoir",
@@ -38,7 +37,6 @@ static const char *credits[] = {
"C0""Jonathan Gray",
"C2""(retired)",
"C0""Travis Howell",
-"C2""(retired)",
"C0""Gregory Montoir",
"C0""Eugene Sandulenko",
"",
@@ -48,6 +46,7 @@ static const char *credits[] = {
"C0""Filippos Karapetis",
"C0""Pawel Kolodziejski",
"C0""Walter van Niftrik",
+"C2""(retired)",
"C0""Kari Salminen",
"C0""Eugene Sandulenko",
"C0""David Symonds",
@@ -57,7 +56,6 @@ static const char *credits[] = {
"C0""Torbj\366rn Andersson",
"C0""Paul Gilbert",
"C0""Travis Howell",
-"C2""(retired)",
"C0""Oliver Kiehl",
"C2""(retired)",
"C0""Ludvig Strigeus",
@@ -161,6 +159,7 @@ static const char *credits[] = {
"C0""Filippos Karapetis",
"C0""Martin Kiewitz",
"C0""Walter van Niftrik",
+"C2""(retired)",
"C0""Willem Jan Palenstijn",
"C0""Jordi Vilalta Prat",
"C0""Lars Skovlund",
@@ -419,7 +418,6 @@ static const char *credits[] = {
"",
"C1""Win32",
"C0""Travis Howell",
-"C2""(retired)",
"",
"C1""Win64",
"C0""Chris Gray",
diff --git a/gui/debugger.h b/gui/debugger.h
index b74b0d6f0f..3a587d2723 100644
--- a/gui/debugger.h
+++ b/gui/debugger.h
@@ -26,6 +26,7 @@
#include "common/ptr.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
+#include "common/array.h"
namespace GUI {
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index af1852d56d..212d68430c 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -39,7 +39,9 @@
#include "graphics/cursorman.h"
+namespace Common {
DECLARE_SINGLETON(GUI::GuiManager);
+}
namespace GUI {
diff --git a/gui/saveload.cpp b/gui/saveload.cpp
index 460246e5fc..02ddf814dc 100644
--- a/gui/saveload.cpp
+++ b/gui/saveload.cpp
@@ -131,7 +131,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
if (_list->isEditable() || !_list->getSelectedString().empty()) {
_list->endEditMode();
if (!_saveList.empty()) {
- setResult(atoi(_saveList[selItem].save_slot().c_str()));
+ setResult(_saveList[selItem].getSaveSlot());
_resultString = _list->getSelectedString();
}
close();
@@ -141,7 +141,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
case kChooseCmd:
_list->endEditMode();
if (!_saveList.empty()) {
- setResult(atoi(_saveList[selItem].save_slot().c_str()));
+ setResult(_saveList[selItem].getSaveSlot());
_resultString = _list->getSelectedString();
}
close();
@@ -154,7 +154,7 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
MessageDialog alert(_("Do you really want to delete this savegame?"),
_("Delete"), _("Cancel"));
if (alert.runModal() == GUI::kMessageOK) {
- (*_plugin)->removeSaveState(_target.c_str(), atoi(_saveList[selItem].save_slot().c_str()));
+ (*_plugin)->removeSaveState(_target.c_str(), _saveList[selItem].getSaveSlot());
setResult(-1);
_list->setSelected(-1);
@@ -241,10 +241,10 @@ void SaveLoadChooser::updateSelection(bool redraw) {
_playtime->setLabel(_("No playtime saved"));
if (selItem >= 0 && !_list->getSelectedString().empty() && _metaInfoSupport) {
- SaveStateDescriptor desc = (*_plugin)->querySaveMetaInfos(_target.c_str(), atoi(_saveList[selItem].save_slot().c_str()));
+ SaveStateDescriptor desc = (*_plugin)->querySaveMetaInfos(_target.c_str(), _saveList[selItem].getSaveSlot());
- isDeletable = desc.getBool("is_deletable") && _delSupport;
- isWriteProtected = desc.getBool("is_write_protected");
+ isDeletable = desc.getDeletableFlag() && _delSupport;
+ isWriteProtected = desc.getWriteProtectedFlag();
// Don't allow the user to change the description of write protected games
if (isWriteProtected)
@@ -259,16 +259,19 @@ void SaveLoadChooser::updateSelection(bool redraw) {
}
if (_saveDateSupport) {
- if (desc.contains("save_date"))
- _date->setLabel(_("Date: ") + desc.getVal("save_date"));
+ const Common::String &saveDate = desc.getSaveDate();
+ if (!saveDate.empty())
+ _date->setLabel(_("Date: ") + saveDate);
- if (desc.contains("save_time"))
- _time->setLabel(_("Time: ") + desc.getVal("save_time"));
+ const Common::String &saveTime = desc.getSaveTime();
+ if (!saveTime.empty())
+ _time->setLabel(_("Time: ") + saveTime);
}
if (_playTimeSupport) {
- if (desc.contains("play_time"))
- _playtime->setLabel(_("Playtime: ") + desc.getVal("play_time"));
+ const Common::String &playTime = desc.getPlayTime();
+ if (!playTime.empty())
+ _playtime->setLabel(_("Playtime: ") + playTime);
}
}
@@ -326,25 +329,25 @@ void SaveLoadChooser::updateSaveList() {
ListWidget::ColorList colors;
for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
// Handle gaps in the list of save games
- saveSlot = atoi(x->save_slot().c_str());
+ saveSlot = x->getSaveSlot();
if (curSlot < saveSlot) {
while (curSlot < saveSlot) {
SaveStateDescriptor dummySave(curSlot, "");
_saveList.insert_at(curSlot, dummySave);
- saveNames.push_back(dummySave.description());
+ saveNames.push_back(dummySave.getDescription());
colors.push_back(ThemeEngine::kFontColorNormal);
curSlot++;
}
// Sync the save list iterator
for (x = _saveList.begin(); x != _saveList.end(); ++x) {
- if (atoi(x->save_slot().c_str()) == saveSlot)
+ if (x->getSaveSlot() == saveSlot)
break;
}
}
// Show "Untitled savestate" for empty/whitespace savegame descriptions
- Common::String description = x->description();
+ Common::String description = x->getDescription();
Common::String trimmedDescription = description;
trimmedDescription.trim();
if (trimmedDescription.empty()) {
diff --git a/icons/count.ico b/icons/count.ico
new file mode 100644
index 0000000000..73e399e394
--- /dev/null
+++ b/icons/count.ico
Binary files differ
diff --git a/ports.mk b/ports.mk
index 4535735b29..3481b1274a 100644
--- a/ports.mk
+++ b/ports.mk
@@ -162,39 +162,34 @@ osxsnap: bundle
scummvmwinres.o: $(srcdir)/icons/scummvm.ico $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) $(srcdir)/dists/scummvm.rc
$(QUIET_WINDRES)$(WINDRES) -DHAVE_CONFIG_H $(WINDRESFLAGS) $(DEFINES) -I. -I$(srcdir) $(srcdir)/dists/scummvm.rc scummvmwinres.o
-# Special target to prepare data files for distribution / installer creation
-win32data: $(EXECUTABLE)
- mkdir -p $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/AUTHORS $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/COPYING $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/COPYING.LGPL $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/COPYRIGHT $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/NEWS $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/README $(srcdir)/$(WIN32PATH)
- cp /usr/local/README-SDL.txt $(srcdir)/$(WIN32PATH)/README-SDL
- unix2dos $(srcdir)/$(WIN32PATH)/*.*
- $(STRIP) $(EXECUTABLE) -o $(srcdir)/$(WIN32PATH)/$(EXECUTABLE)
- cp $(DIST_FILES_THEMES) $(srcdir)/$(WIN32PATH)
-ifdef DIST_FILES_ENGINEDATA
- cp $(DIST_FILES_ENGINEDATA) $(srcdir)/$(WIN32PATH)
-endif
- cp /usr/local/bin/SDL.dll $(srcdir)/$(WIN32PATH)
-
# Special target to create a win32 snapshot binary (for Inno Setup)
-win32dist: win32data
- cp $(srcdir)/icons/scummvm.ico $(srcdir)/$(WIN32PATH)
- cp $(srcdir)/dists/win32/ScummVM.iss $(srcdir)/$(WIN32PATH)
- mv $(WIN32PATH)/AUTHORS $(srcdir)/$(WIN32PATH)/AUTHORS.txt
- mv $(WIN32PATH)/COPYING $(srcdir)/$(WIN32PATH)/COPYING.txt
- mv $(WIN32PATH)/COPYING.LGPL $(srcdir)/$(WIN32PATH)/COPYING.LGPL.txt
- mv $(WIN32PATH)/COPYRIGHT $(srcdir)/$(WIN32PATH)/COPYRIGHT.txt
- mv $(WIN32PATH)/NEWS $(srcdir)/$(WIN32PATH)/NEWS.txt
- mv $(WIN32PATH)/README $(srcdir)/$(WIN32PATH)/README.txt
- mv $(WIN32PATH)/README-SDL $(srcdir)/$(WIN32PATH)/README-SDL.txt
+win32dist: $(EXECUTABLE)
+ mkdir -p $(WIN32PATH)
+ mkdir -p $(WIN32PATH)/graphics
+ $(STRIP) $(EXECUTABLE) -o $(WIN32PATH)/$(EXECUTABLE)
+ cp $(DIST_FILES_THEMES) $(WIN32PATH)
+ifdef DIST_FILES_ENGINEDATA
+ cp $(DIST_FILES_ENGINEDATA) $(WIN32PATH)
+endif
+ cp $(srcdir)/AUTHORS $(WIN32PATH)/AUTHORS.txt
+ cp $(srcdir)/COPYING $(WIN32PATH)/COPYING.txt
+ cp $(srcdir)/COPYING.LGPL $(WIN32PATH)/COPYING.LGPL.txt
+ cp $(srcdir)/COPYRIGHT $(WIN32PATH)/COPYRIGHT.txt
+ cp $(srcdir)/NEWS $(WIN32PATH)/NEWS.txt
+ cp $(srcdir)/README $(WIN32PATH)/README.txt
+ cp /usr/local/README-SDL.txt $(WIN32PATH)
+ cp /usr/local/bin/SDL.dll $(WIN32PATH)
+ cp $(srcdir)/dists/win32/graphics/left.bmp $(WIN32PATH)/graphics
+ cp $(srcdir)/dists/win32/graphics/scummvm-install.ico $(WIN32PATH)/graphics
+ cp $(srcdir)/dists/win32/ScummVM.iss $(WIN32PATH)
+ unix2dos $(WIN32PATH)/*.txt
# Special target to create a win32 NSIS installer
-win32setup: win32data
- makensis -V2 -Dtop_srcdir="../.." -Dtext_dir="../../$(WIN32PATH)" -Dbuild_dir="../../$(WIN32PATH)" $(srcdir)/dists/nsis/scummvm.nsi
+win32setup: $(EXECUTABLE)
+ mkdir -p $(srcdir)/$(STAGINGPATH)
+ $(STRIP) $(EXECUTABLE) -o $(srcdir)/$(STAGINGPATH)/$(EXECUTABLE)
+ cp /usr/local/bin/SDL.dll $(srcdir)/$(STAGINGPATH)
+ makensis -V2 -Dtop_srcdir="../.." -Dstaging_dir="../../$(STAGINGPATH)" -Darch=$(ARCH) $(srcdir)/dists/win32/scummvm.nsi
#
# AmigaOS specific
diff --git a/video/codecs/cdtoons.cpp b/video/codecs/cdtoons.cpp
index 9bdc794fa6..528cee8094 100644
--- a/video/codecs/cdtoons.cpp
+++ b/video/codecs/cdtoons.cpp
@@ -24,6 +24,7 @@
#include "common/rect.h"
#include "common/stream.h"
#include "common/textconsole.h"
+#include "common/array.h"
namespace Video {