aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore22
-rw-r--r--AUTHORS16
-rw-r--r--NEWS38
-rw-r--r--audio/mididrv.h11
-rw-r--r--audio/mixer.cpp26
-rw-r--r--audio/mixer_intern.h4
-rw-r--r--audio/rate_arm.cpp175
-rw-r--r--backends/base-backend.cpp3
-rw-r--r--backends/events/wincesdl/wincesdl-events.cpp332
-rw-r--r--backends/events/wincesdl/wincesdl-events.h73
-rw-r--r--backends/graphics/opengl/gltexture.cpp2
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp151
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp17
-rw-r--r--backends/graphics/sdl/sdl-graphics.cpp21
-rw-r--r--backends/graphics/wincesdl/wincesdl-graphics.cpp1639
-rw-r--r--backends/graphics/wincesdl/wincesdl-graphics.h206
-rw-r--r--backends/midi/alsa.cpp52
-rw-r--r--backends/mixer/wincesdl/wincesdl-mixer.cpp183
-rw-r--r--backends/mixer/wincesdl/wincesdl-mixer.h53
-rw-r--r--backends/module.mk3
-rw-r--r--backends/platform/android/android.cpp1450
-rw-r--r--backends/platform/android/android.h225
-rw-r--r--backends/platform/android/android.mk5
-rw-r--r--backends/platform/android/asset-archive.cpp35
-rw-r--r--backends/platform/android/asset-archive.h5
-rw-r--r--backends/platform/android/events.cpp661
-rw-r--r--backends/platform/android/gfx.cpp810
-rw-r--r--backends/platform/android/jni.cpp602
-rw-r--r--backends/platform/android/jni.h151
-rw-r--r--backends/platform/android/module.mk7
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java15
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/Event.java330
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java14
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVM.java698
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java406
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java10
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java201
-rw-r--r--backends/platform/android/org/inodes/gus/scummvm/Unpacker.java1
-rw-r--r--backends/platform/android/texture.cpp571
-rw-r--r--backends/platform/android/texture.h331
-rw-r--r--backends/platform/android/video.cpp342
-rw-r--r--backends/platform/android/video.h209
-rw-r--r--backends/platform/sdl/sdl.cpp21
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in2
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_agi.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_agos.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_base.mmp.in10
-rw-r--r--backends/platform/symbian/mmp/scummvm_cine.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_cruise.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_draci.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_drascula.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_gob.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_groovie.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_hugo.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_kyra.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_lure.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_m4.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_made.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_mohawk.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_parallaction.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_queen.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_saga.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sci.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_scumm.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sky.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sword1.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_sword2.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_teenagent.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tinsel.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_toon.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_touche.mmp.in2
-rw-r--r--backends/platform/symbian/mmp/scummvm_tucker.mmp.in2
-rw-r--r--backends/platform/wince/CEActionsPocket.cpp58
-rw-r--r--backends/platform/wince/CEActionsSmartphone.cpp169
-rw-r--r--backends/platform/wince/CEDevice.cpp31
-rw-r--r--backends/platform/wince/CEDevice.h2
-rw-r--r--backends/platform/wince/CEException.cpp22
-rw-r--r--backends/platform/wince/CELauncherDialog.cpp9
-rw-r--r--backends/platform/wince/CEgui/GUIElement.cpp9
-rw-r--r--backends/platform/wince/CEgui/ItemAction.cpp2
-rw-r--r--backends/platform/wince/CEgui/ItemSwitch.cpp6
-rw-r--r--backends/platform/wince/CEgui/Panel.cpp11
-rw-r--r--backends/platform/wince/CEgui/Panel.h2
-rw-r--r--backends/platform/wince/CEgui/PanelItem.h2
-rw-r--r--backends/platform/wince/CEgui/PanelKeyboard.cpp21
-rw-r--r--backends/platform/wince/CEgui/SDL_ImageResource.cpp4
-rw-r--r--backends/platform/wince/CEgui/SDL_ImageResource.h4
-rw-r--r--backends/platform/wince/CEgui/ToolbarHandler.cpp13
-rw-r--r--backends/platform/wince/CEgui/ToolbarHandler.h2
-rw-r--r--backends/platform/wince/CEkeys/EventsBuffer.cpp98
-rw-r--r--backends/platform/wince/CEkeys/EventsBuffer.h16
-rw-r--r--backends/platform/wince/Makefile2
-rw-r--r--backends/platform/wince/missing/io.h6
-rw-r--r--backends/platform/wince/missing/missing.cpp60
-rw-r--r--backends/platform/wince/missing/time.h7
-rw-r--r--backends/platform/wince/portdefs.h38
-rw-r--r--backends/platform/wince/wince-sdl.cpp2113
-rw-r--r--backends/platform/wince/wince-sdl.h186
-rw-r--r--base/commandLine.cpp3
-rw-r--r--common/config-manager.cpp4
-rw-r--r--common/macresman.cpp138
-rw-r--r--common/macresman.h11
-rw-r--r--common/module.mk4
-rw-r--r--common/ne_exe.cpp612
-rw-r--r--common/winexe.cpp84
-rw-r--r--common/winexe.h74
-rw-r--r--common/winexe_ne.cpp291
-rw-r--r--common/winexe_ne.h (renamed from common/ne_exe.h)100
-rw-r--r--common/winexe_pe.cpp255
-rw-r--r--common/winexe_pe.h122
-rwxr-xr-xconfigure41
-rw-r--r--dists/android/AndroidManifest.xml113
-rw-r--r--dists/android/AndroidManifest.xml.in113
-rw-r--r--dists/android/res/layout/main.xml17
-rw-r--r--dists/scummvm.rc21
-rw-r--r--dists/scummvm.rc.in21
-rw-r--r--engines/agi/agi.cpp27
-rw-r--r--engines/agi/agi.h5
-rw-r--r--engines/agi/detection_tables.h1
-rw-r--r--engines/agi/preagi.cpp3
-rw-r--r--engines/agos/agos.h2
-rw-r--r--engines/agos/animation.cpp4
-rw-r--r--engines/agos/oracle.cpp6
-rw-r--r--engines/agos/script_ff.cpp3
-rw-r--r--engines/cine/script_os.cpp2
-rw-r--r--engines/drascula/drascula.cpp5
-rw-r--r--engines/engine.cpp11
-rw-r--r--engines/gob/save/saveload.h4
-rw-r--r--engines/gob/save/saveload_inca2.cpp4
-rw-r--r--engines/gob/save/saveload_v3.cpp6
-rw-r--r--engines/gob/sound/bgatmosphere.cpp4
-rw-r--r--engines/gob/sound/bgatmosphere.h4
-rw-r--r--engines/gob/sound/sound.cpp10
-rw-r--r--engines/groovie/music.h18
-rw-r--r--engines/hugo/detection.cpp5
-rw-r--r--engines/hugo/dialogs.cpp (renamed from engines/hugo/menu.cpp)31
-rw-r--r--engines/hugo/dialogs.h (renamed from engines/hugo/menu.h)28
-rw-r--r--engines/hugo/display.cpp69
-rw-r--r--engines/hugo/display.h19
-rw-r--r--engines/hugo/file.cpp9
-rw-r--r--engines/hugo/hugo.cpp21
-rw-r--r--engines/hugo/hugo.h11
-rw-r--r--engines/hugo/intro.cpp10
-rw-r--r--engines/hugo/module.mk2
-rw-r--r--engines/hugo/object.cpp35
-rw-r--r--engines/hugo/parser.cpp7
-rw-r--r--engines/hugo/parser_v1d.cpp2
-rw-r--r--engines/hugo/parser_v1w.cpp2
-rw-r--r--engines/hugo/parser_v2d.cpp2
-rw-r--r--engines/hugo/parser_v3d.cpp2
-rw-r--r--engines/hugo/schedule.cpp368
-rw-r--r--engines/hugo/schedule.h2
-rw-r--r--engines/mohawk/cstime_game.cpp8
-rw-r--r--engines/mohawk/cursors.cpp224
-rw-r--r--engines/mohawk/cursors.h41
-rw-r--r--engines/mohawk/graphics.cpp75
-rw-r--r--engines/mohawk/graphics.h11
-rw-r--r--engines/mohawk/livingbooks.cpp21
-rw-r--r--engines/mohawk/myst.cpp14
-rw-r--r--engines/mohawk/myst.h2
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp91
-rw-r--r--engines/mohawk/myst_stacks/mechanical.h12
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp1
-rw-r--r--engines/mohawk/riven.cpp31
-rw-r--r--engines/mohawk/riven_cursors.h670
-rw-r--r--engines/mohawk/riven_external.cpp93
-rw-r--r--engines/mohawk/riven_external.h4
-rw-r--r--engines/mohawk/riven_scripts.cpp1
-rw-r--r--engines/sci/console.cpp94
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection_tables.h39
-rw-r--r--engines/sci/engine/features.cpp20
-rw-r--r--engines/sci/engine/gc.cpp44
-rw-r--r--engines/sci/engine/kernel.h5
-rw-r--r--engines/sci/engine/kernel_tables.h18
-rw-r--r--engines/sci/engine/kevent.cpp38
-rw-r--r--engines/sci/engine/kfile.cpp12
-rw-r--r--engines/sci/engine/kgraphics.cpp173
-rw-r--r--engines/sci/engine/kmenu.cpp3
-rw-r--r--engines/sci/engine/kmisc.cpp35
-rw-r--r--engines/sci/engine/kmovement.cpp58
-rw-r--r--engines/sci/engine/kparse.cpp4
-rw-r--r--engines/sci/engine/kpathing.cpp12
-rw-r--r--engines/sci/engine/kscripts.cpp38
-rw-r--r--engines/sci/engine/kstring.cpp24
-rw-r--r--engines/sci/engine/object.cpp64
-rw-r--r--engines/sci/engine/savegame.cpp10
-rw-r--r--engines/sci/engine/script.cpp34
-rw-r--r--engines/sci/engine/script_patches.cpp334
-rw-r--r--engines/sci/engine/scriptdebug.cpp29
-rw-r--r--engines/sci/engine/seg_manager.cpp45
-rw-r--r--engines/sci/engine/seg_manager.h11
-rw-r--r--engines/sci/engine/segment.cpp190
-rw-r--r--engines/sci/engine/segment.h98
-rw-r--r--engines/sci/engine/selector.cpp1
-rw-r--r--engines/sci/engine/selector.h1
-rw-r--r--engines/sci/engine/static_selectors.cpp214
-rw-r--r--engines/sci/engine/vm.cpp45
-rw-r--r--engines/sci/engine/vm_types.cpp135
-rw-r--r--engines/sci/engine/vm_types.h64
-rw-r--r--engines/sci/engine/workarounds.cpp43
-rw-r--r--engines/sci/engine/workarounds.h1
-rw-r--r--engines/sci/event.cpp340
-rw-r--r--engines/sci/event.h12
-rw-r--r--engines/sci/graphics/animate.cpp17
-rw-r--r--engines/sci/graphics/cursor.cpp27
-rw-r--r--engines/sci/graphics/frameout.cpp8
-rw-r--r--engines/sci/graphics/helpers.h18
-rw-r--r--engines/sci/graphics/maciconbar.cpp150
-rw-r--r--engines/sci/graphics/maciconbar.h15
-rw-r--r--engines/sci/graphics/menu.cpp34
-rw-r--r--engines/sci/graphics/paint.cpp3
-rw-r--r--engines/sci/graphics/paint.h1
-rw-r--r--engines/sci/graphics/paint16.cpp22
-rw-r--r--engines/sci/graphics/paint32.cpp11
-rw-r--r--engines/sci/graphics/paint32.h1
-rw-r--r--engines/sci/graphics/palette.cpp53
-rw-r--r--engines/sci/graphics/palette.h2
-rw-r--r--engines/sci/graphics/picture.cpp177
-rw-r--r--engines/sci/graphics/ports.cpp69
-rw-r--r--engines/sci/graphics/ports.h18
-rw-r--r--engines/sci/graphics/screen.cpp40
-rw-r--r--engines/sci/graphics/screen.h12
-rw-r--r--engines/sci/graphics/text16.cpp11
-rw-r--r--engines/sci/graphics/transitions.cpp7
-rw-r--r--engines/sci/graphics/transitions.h3
-rw-r--r--engines/sci/graphics/view.cpp293
-rw-r--r--engines/sci/parser/said.cpp2
-rw-r--r--engines/sci/parser/vocabulary.cpp2
-rw-r--r--engines/sci/parser/vocabulary.h3
-rw-r--r--engines/sci/resource.cpp49
-rw-r--r--engines/sci/resource.h2
-rw-r--r--engines/sci/sci.cpp140
-rw-r--r--engines/sci/sci.h30
-rw-r--r--engines/sci/sound/drivers/adlib.cpp14
-rw-r--r--engines/sci/sound/drivers/amigamac.cpp72
-rw-r--r--engines/sci/sound/drivers/midi.cpp86
-rw-r--r--engines/sci/sound/music.cpp41
-rw-r--r--engines/sci/sound/soundcmd.cpp12
-rw-r--r--engines/sci/util.cpp26
-rw-r--r--engines/sci/util.h5
-rw-r--r--engines/sci/video/robot_decoder.cpp5
-rw-r--r--engines/scumm/he/resource_he.cpp1108
-rw-r--r--engines/scumm/he/resource_he.h381
-rw-r--r--engines/sword1/mouse.cpp11
-rw-r--r--engines/sword1/mouse.h3
-rw-r--r--engines/sword2/animation.cpp40
-rw-r--r--engines/sword2/animation.h6
-rw-r--r--engines/testbed/graphics.cpp8
-rw-r--r--engines/tinsel/music.cpp28
-rw-r--r--engines/toon/anim.cpp26
-rw-r--r--engines/toon/anim.h2
-rw-r--r--engines/toon/audio.cpp63
-rw-r--r--engines/toon/audio.h9
-rw-r--r--engines/toon/character.cpp45
-rw-r--r--engines/toon/character.h2
-rw-r--r--engines/toon/conversation.cpp1
-rw-r--r--engines/toon/conversation.h4
-rw-r--r--engines/toon/drew.cpp3
-rw-r--r--engines/toon/drew.h2
-rw-r--r--engines/toon/flux.cpp2
-rw-r--r--engines/toon/flux.h1
-rw-r--r--engines/toon/font.cpp8
-rw-r--r--engines/toon/hotspot.cpp4
-rw-r--r--engines/toon/movie.cpp16
-rw-r--r--engines/toon/movie.h2
-rw-r--r--engines/toon/path.cpp9
-rw-r--r--engines/toon/path.h1
-rw-r--r--engines/toon/picture.cpp79
-rw-r--r--engines/toon/picture.h1
-rw-r--r--engines/toon/resource.cpp156
-rw-r--r--engines/toon/resource.h29
-rw-r--r--engines/toon/script.cpp3
-rw-r--r--engines/toon/script.h1
-rw-r--r--engines/toon/script_func.cpp17
-rw-r--r--engines/toon/state.cpp1
-rw-r--r--engines/toon/state.h2
-rw-r--r--engines/toon/tools.cpp6
-rw-r--r--engines/toon/tools.h4
-rw-r--r--engines/toon/toon.cpp357
-rw-r--r--engines/toon/toon.h16
-rw-r--r--graphics/fonts/winfont.cpp89
-rw-r--r--graphics/fonts/winfont.h4
-rw-r--r--graphics/module.mk3
-rw-r--r--graphics/wincursor.cpp317
-rw-r--r--graphics/wincursor.h105
-rw-r--r--gui/ThemeEngine.cpp5
-rw-r--r--gui/ThemeEngine.h4
-rw-r--r--gui/ThemeParser.cpp48
-rw-r--r--gui/credits.h22
-rw-r--r--gui/gui-manager.cpp7
-rw-r--r--gui/themes/default.inc10
-rw-r--r--gui/themes/scummclassic.zipbin91252 -> 91156 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC2
-rw-r--r--gui/themes/scummclassic/classic_gfx.stx6
-rw-r--r--gui/themes/scummclassic/classic_layout.stx2
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx2
-rw-r--r--gui/themes/scummmodern.zipbin198584 -> 198479 bytes
-rw-r--r--gui/themes/scummmodern/THEMERC2
-rw-r--r--gui/themes/scummmodern/scummmodern_gfx.stx8
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx2
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx2
-rwxr-xr-xtools/credits.pl17
305 files changed, 12775 insertions, 11266 deletions
diff --git a/.gitignore b/.gitignore
index 6e3e61134c..074a92a397 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,21 +62,21 @@ lib*.a
/dists/rpl.exe
+/dists/codeblocks/*.cbp
+/dists/codeblocks/*.depend
+/dists/codeblocks/*.layout
+/dists/codeblocks/scummvm*
+
/dists/iphone/build
/dists/iphone/scummvm.xcodeproj/*.mode1v3
/dists/iphone/scummvm.xcodeproj/*.pbxuser
-/dists/msvc8/[Dd]ebug*/
-/dists/msvc8/[Rr]elease*/
-/dists/msvc8/*.lib
-
-/dists/msvc9/[Dd]ebug*/
-/dists/msvc9/[Rr]elease*/
-/dists/msvc9/*.lib
-
-/dists/msvc10/[Dd]ebug*/
-/dists/msvc10/[Rr]elease*/
-/dists/msvc10/*.lib
+/dists/msvc*/[Dd]ebug*/
+/dists/msvc*/[Rr]elease*/
+/dists/msvc*/*.lib
+/dists/msvc*/*.SAV
+/dists/msvc*/*.dat
+/dists/msvc*/*.dll
/doc/*.aux
/doc/*.dvi
diff --git a/AUTHORS b/AUTHORS
index 758d1934cf..05e798e570 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -187,6 +187,7 @@ ScummVM Team
Backend Teams
-------------
Android:
+ Andre Heider
Angus Lees
Dreamcast:
@@ -265,6 +266,18 @@ ScummVM Team
--------------
Fredrik Wendel - (retired)
+ Website (maintenance)
+ ---------------------
+ James Brown - IRC Logs maintainer
+ Thierry Crozat - Wiki maintainer
+ Andre Heider - Buildbot maintainer
+ Max Horn - Forum, IRC channel and Mailing list maintainer
+ Joost Peters - Doxygen Project Documentation maintainer
+ Jordi Vilalta Prat - Wiki maintainer
+ Eugene Sandulenko - Forum, IRC channel, Screen Shots and Mailing
+ list maintainer
+ John Willis
+
Website (content)
-----------------
All active team members
@@ -396,6 +409,7 @@ Other contributions
David Jensen - SVG logo conversion
Jean Marc Gimenez - ScummVM logo
Raina - ScummVM forum buttons
+ William Claydon - Skins for doxygen and wiki
Code contributions
------------------
@@ -405,7 +419,7 @@ Other contributions
engine)
Paolo Costabel - PSP port contributions
Martin Doucha - CinE engine objectification
- Thomas Fach-Pedersen - ProTracker module player
+ Thomas Fach-Pedersen - ProTracker module player, Smacker video decoder
Tobias Gunkel - Sound support for C64 version of MM/Zak, Loom
PCE support
Janne Huttunen - V3 actor mask support, Dig/FT SMUSH audio
diff --git a/NEWS b/NEWS
index 09a99ff4c6..5b50b5e368 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
-For a more comprehensive changelog for the latest experimental SVN code, see:
- http://scummvm.svn.sourceforge.net/viewvc/scummvm/?view=log
+For a more comprehensive changelog of the latest experimental code, see:
+ https://github.com/scummvm/scummvm/commits/
+
1.3.0 (????-??-??)
New Games:
- Added support for Backyard Baseball.
@@ -24,14 +25,14 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
Cine:
- Corrected memory leaks and invalid memory accesses.
Future Wars should be more stable.
- - Operation Stealth is now completable, though significant
- graphical glitches remain so not official supported.
+ - Made Operation Stealth completable, though significant graphical
+ glitches remain so not official supported.
Drascula:
- Added German and French subtitles in the Von Braun cutscene (#3069981:
no subtitles in scene with "von Braun").
- Improved French translation of the game.
- - Return To Launcher now supported.
+ - Added support for "Return To Launcher".
Gob:
- Fixed "Goblin Stuck On Reload" bugs affecting Gobliiins.
@@ -41,7 +42,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
Parallaction:
- Corrected issue which could cause crash at engine exit.
- - Leak fixes in Nippon Safes Amiga.
+ - Closed memory leaks in Nippon Safes Amiga.
SCI:
- Added a CMS music driver for SCI1 - SCI1.1 games.
@@ -78,14 +79,15 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
- Improved support for FM-TOWNS versions of games.
Sky:
- - Fixed crashes on sequences for several backends
- (e.g. OpenGL, including Android)
+ - Fixed crashes on sequences for several ports (Android, OpenGL, ...)
Teenagent:
- Closed memory leaks.
Tinsel:
- Closed memory leaks in Coroutines.
+ - Added enhanced music support for the German CD "Neon Edition" re-release
+ of Discworld 1.
Touche:
- Corrected memory leaks and minor issues.
@@ -94,6 +96,14 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
- Added support for OpenGL. (GSoC Task)
- Closed memory leaks in Mouse Surfaces.
+ Android port:
+ - Switched to the official NDK toolchain for building.
+ - Fixed GFX output for various devices.
+ - Fixed various crashes.
+
+ Nintendo DS port:
+ - Added support for loadable modules.
+
PSP port:
- Added support for loadable modules.
- Added image viewer.
@@ -101,22 +111,14 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
PS2 port:
- Added support for loadable modules.
- Nintendo DS port:
- - Added support for loadable modules.
-
Wii/GameCube port:
- Added support for loadable modules.
- Fixed 16bit mouse cursors on HE games.
- Android port:
- - Switched to the official NDK toolchain for building.
- - Fixed GFX output for various devices.
- - Fixed various crashes.
-
1.2.1 (2010-12-19)
General
- - Add Hungarian translation.
- - Add Brazilian Portuguese translation.
+ - Added Hungarian translation.
+ - Added Brazilian Portuguese translation.
Cruise:
- Fixed a problem with Raoul appearing when examining the Book.
diff --git a/audio/mididrv.h b/audio/mididrv.h
index 9e649cba3d..eed8c419f3 100644
--- a/audio/mididrv.h
+++ b/audio/mididrv.h
@@ -71,9 +71,14 @@ enum MusicType {
* A set of flags to be passed to detectDevice() which can be used to
* specify what kind of music driver is preferred / accepted.
*
- * The flags (except for MDT_PREFER_MT32 and MDT_PREFER_GM) indicate whether a given driver
- * type is acceptable. E.g. the TOWNS music driver could be returned by
- * detectDevice if and only if MDT_TOWNS is specified.
+ * The flags (except for MDT_PREFER_MT32 and MDT_PREFER_GM) indicate whether a
+ * given driver type is acceptable. E.g. the TOWNS music driver could be
+ * returned by detectDevice if and only if MDT_TOWNS is specified.
+ *
+ * MDT_PREFER_MT32 and MDT_PREFER_GM indicate the MIDI device type to use when
+ * no device is selected in the music options, or when the MIDI device selected
+ * does not match the requirements of a game engine. With these flags, more
+ * priority is given to an MT-32 device, or a GM device respectively.
*
* @todo Rename MidiDriverFlags to MusicDriverFlags
*/
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index c2271b1059..dc0287e3fb 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -54,8 +54,9 @@ public:
* @param len number of sample *pairs*. So a value of
* 10 means that the buffer contains twice 10 sample, each
* 16 bits, for a total of 40 bytes.
+ * @return number of sample pairs processed (which can still be silence!)
*/
- void mix(int16 *data, uint len);
+ int mix(int16 *data, uint len);
/**
* Queries whether the channel is still playing or not.
@@ -257,7 +258,7 @@ void MixerImpl::playStream(
insertChannel(handle, chan);
}
-void MixerImpl::mixCallback(byte *samples, uint len) {
+int MixerImpl::mixCallback(byte *samples, uint len) {
assert(samples);
Common::StackLock lock(_mutex);
@@ -272,14 +273,21 @@ void MixerImpl::mixCallback(byte *samples, uint len) {
memset(buf, 0, 2 * len * sizeof(int16));
// mix all channels
+ int res = 0, tmp;
for (int i = 0; i != NUM_CHANNELS; i++)
if (_channels[i]) {
if (_channels[i]->isFinished()) {
delete _channels[i];
_channels[i] = 0;
- } else if (!_channels[i]->isPaused())
- _channels[i]->mix(buf, len);
+ } else if (!_channels[i]->isPaused()) {
+ tmp = _channels[i]->mix(buf, len);
+
+ if (tmp > res)
+ res = tmp;
+ }
}
+
+ return res;
}
void MixerImpl::stopAll() {
@@ -538,19 +546,23 @@ Timestamp Channel::getElapsedTime() {
return ts;
}
-void Channel::mix(int16 *data, uint len) {
+int Channel::mix(int16 *data, uint len) {
assert(_stream);
+ int res = 0;
+
if (_stream->endOfData()) {
// TODO: call drain method
} else {
assert(_converter);
-
_samplesConsumed = _samplesDecoded;
_mixerTimeStamp = g_system->getMillis();
_pauseTime = 0;
- _samplesDecoded += _converter->flow(*_stream, data, len, _volL, _volR);
+ res = _converter->flow(*_stream, data, len, _volL, _volR);
+ _samplesDecoded += res;
}
+
+ return res;
}
} // End of namespace Audio
diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h
index c8df9a594d..dd2746e9ea 100644
--- a/audio/mixer_intern.h
+++ b/audio/mixer_intern.h
@@ -118,8 +118,10 @@ public:
* The mixer callback function, to be called at regular intervals by
* the backend (e.g. from an audio mixing thread). All the actual mixing
* work is done from here.
+ *
+ * @return number of sample pairs processed (which can still be silence!)
*/
- void mixCallback(byte *samples, uint len);
+ int mixCallback(byte *samples, uint len);
/**
* Set the internal 'is ready' flag of the mixer.
diff --git a/audio/rate_arm.cpp b/audio/rate_arm.cpp
index 41944ef698..43172f64c8 100644
--- a/audio/rate_arm.cpp
+++ b/audio/rate_arm.cpp
@@ -60,7 +60,7 @@ namespace Audio {
* ARM routine we call doesn't respect those definitions.
*/
#define FRAC_BITS 16
-#define FRAC_ONE (1<<FRAC_BITS)
+#define FRAC_ONE (1 << FRAC_BITS)
/**
* The size of the intermediate input cache. Bigger values may increase
@@ -138,34 +138,33 @@ extern "C" {
}
extern "C" st_sample_t *ARM_SimpleRate_M(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ SimpleRateDetails *sr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
extern "C" st_sample_t *ARM_SimpleRate_S(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ SimpleRateDetails *sr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
extern "C" st_sample_t *ARM_SimpleRate_R(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" int SimpleRate_readFudge(Audio::AudioStream &input,
- int16 *a, int b)
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ SimpleRateDetails *sr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
+
+extern "C" int SimpleRate_readFudge(Audio::AudioStream &input, int16 *a, int b)
{
#ifdef DEBUG_RATECONV
debug("Reading ptr=%x n%d", a, b);
@@ -183,21 +182,22 @@ int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
if (!stereo) {
obuf = ARM_SimpleRate_M(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &sr,
+ obuf, osamp, vol_l, vol_r);
} else if (reverseStereo) {
obuf = ARM_SimpleRate_R(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &sr,
+ obuf, osamp, vol_l, vol_r);
} else {
obuf = ARM_SimpleRate_S(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &sr,
+ obuf, osamp, vol_l, vol_r);
}
- return (obuf-ostart)/2;
+
+ return (obuf - ostart) / 2;
}
/**
@@ -240,31 +240,31 @@ extern "C" {
}
extern "C" st_sample_t *ARM_LinearRate_M(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ LinearRateDetails *lr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
extern "C" st_sample_t *ARM_LinearRate_S(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ LinearRateDetails *lr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
extern "C" st_sample_t *ARM_LinearRate_R(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
+ AudioStream &input,
+ int (*fn)(Audio::AudioStream&,int16*,int),
+ LinearRateDetails *lr,
+ st_sample_t *obuf,
+ st_size_t osamp,
+ st_volume_t vol_l,
+ st_volume_t vol_r);
template<bool stereo, bool reverseStereo>
class LinearRateConverter : public RateConverter {
@@ -320,23 +320,29 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
#endif
st_sample_t *ostart = obuf;
+ if (vol_l > 0xff)
+ vol_l = 0xff;
+
+ if (vol_r > 0xff)
+ vol_r = 0xff;
+
if (!stereo) {
obuf = ARM_LinearRate_M(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &lr,
+ obuf, osamp, vol_l, vol_r);
} else if (reverseStereo) {
obuf = ARM_LinearRate_R(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &lr,
+ obuf, osamp, vol_l, vol_r);
} else {
obuf = ARM_LinearRate_S(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
+ &SimpleRate_readFudge,
+ &lr,
+ obuf, osamp, vol_l, vol_r);
}
- return (obuf-ostart)/2;
+ return (obuf - ostart) / 2;
}
@@ -355,31 +361,32 @@ extern "C" {
}
extern "C" st_sample_t *ARM_CopyRate_M(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
+ st_size_t len,
+ st_sample_t *obuf,
+ st_volume_t vol_l,
+ st_volume_t vol_r,
+ st_sample_t *_buffer);
extern "C" st_sample_t *ARM_CopyRate_S(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
+ st_size_t len,
+ st_sample_t *obuf,
+ st_volume_t vol_l,
+ st_volume_t vol_r,
+ st_sample_t *_buffer);
extern "C" st_sample_t *ARM_CopyRate_R(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
+ st_size_t len,
+ st_sample_t *obuf,
+ st_volume_t vol_l,
+ st_volume_t vol_r,
+ st_sample_t *_buffer);
template<bool stereo, bool reverseStereo>
class CopyRateConverter : public RateConverter {
st_sample_t *_buffer;
st_size_t _bufferSize;
+
public:
CopyRateConverter() : _buffer(0), _bufferSize(0) {}
~CopyRateConverter() {
@@ -393,7 +400,7 @@ public:
debug("Copy st=%d rev=%d", stereo, reverseStereo);
#endif
st_size_t len;
- st_sample_t *ostart = obuf;
+ st_sample_t *ostart = obuf;
if (stereo)
osamp *= 2;
@@ -418,8 +425,9 @@ public:
else
obuf = ARM_CopyRate_M(len, obuf, vol_l, vol_r, _buffer);
- return (obuf-ostart)/2;
+ return (obuf - ostart) / 2;
}
+
virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
return (ST_SUCCESS);
}
@@ -463,3 +471,4 @@ RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stere
}
} // End of namespace Audio
+
diff --git a/backends/base-backend.cpp b/backends/base-backend.cpp
index 42ab7b887a..f349cc8005 100644
--- a/backends/base-backend.cpp
+++ b/backends/base-backend.cpp
@@ -101,7 +101,4 @@ AudioCDManager *BaseBackend::getAudioCDManager() {
}
void BaseBackend::resetGraphicsScale() {
- // As a hack, we use 0 here. Backends should override this method
- // and provide their own.
- setGraphicsMode(0);
}
diff --git a/backends/events/wincesdl/wincesdl-events.cpp b/backends/events/wincesdl/wincesdl-events.cpp
new file mode 100644
index 0000000000..2505b0fb31
--- /dev/null
+++ b/backends/events/wincesdl/wincesdl-events.cpp
@@ -0,0 +1,332 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#ifdef _WIN32_WCE
+
+#include "common/config-manager.h"
+
+#include "backends/events/wincesdl/wincesdl-events.h"
+#include "backends/platform/wince/CEActionsPocket.h"
+#include "backends/platform/wince/CEActionsSmartphone.h"
+#include "backends/platform/wince/CEDevice.h"
+
+#include "backends/platform/sdl/sdl.h"
+
+WINCESdlEventSource::WINCESdlEventSource()
+ : _tapTime(0), _closeClick(false), _rbutton(false),
+ _freeLook(false), _graphicsMan(0) {
+}
+
+void WINCESdlEventSource::init(WINCESdlGraphicsManager *graphicsMan) {
+ assert(graphicsMan);
+ _graphicsMan = graphicsMan;
+}
+
+void WINCESdlEventSource::fillMouseEvent(Common::Event &event, int x, int y) {
+ event.mouse.x = x;
+ event.mouse.y = y;
+
+ // Update the "keyboard mouse" coords
+ _km.x = event.mouse.x;
+ _km.y = event.mouse.y;
+
+ // Adjust for the screen scaling
+ if (_graphicsMan->_zoomDown)
+ event.mouse.y += 240;
+
+ event.mouse.x = event.mouse.x * _graphicsMan->_scaleFactorXd / _graphicsMan->_scaleFactorXm;
+ event.mouse.y = event.mouse.y * _graphicsMan->_scaleFactorYd / _graphicsMan->_scaleFactorYm;
+}
+
+bool WINCESdlEventSource::pollEvent(Common::Event &event) {
+ SDL_Event ev;
+ ev.type = SDL_NOEVENT;
+ DWORD currentTime;
+ bool keyEvent = false;
+ int deltaX, deltaY;
+
+ memset(&event, 0, sizeof(Common::Event));
+
+ handleKbdMouse();
+
+ // If the screen changed, send an Common::EVENT_SCREEN_CHANGED
+ int screenID = _graphicsMan->getScreenChangeID();
+ if (screenID != _lastScreenID) {
+ _lastScreenID = screenID;
+ event.type = Common::EVENT_SCREEN_CHANGED;
+ return true;
+ }
+
+ CEDevice::wakeUp();
+
+ currentTime = GetTickCount();
+
+ while (SDL_PollEvent(&ev)) {
+ switch (ev.type) {
+ case SDL_KEYDOWN:
+ debug(1, "Key down %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym));
+ // KMOD_RESERVED is used if the key has been injected by an external buffer
+ if (ev.key.keysym.mod != KMOD_RESERVED && !GUI::Actions::Instance()->mappingActive()) {
+ keyEvent = true;
+ _graphicsMan->_lastKeyPressed = ev.key.keysym.sym;
+ _graphicsMan->_keyRepeatTime = currentTime;
+ _graphicsMan->_keyRepeat = 0;
+
+ if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, true))
+ return true;
+ }
+
+ if (GUI_Actions::Instance()->mappingActive())
+ event.kbd.flags = 0xFF;
+ else if (ev.key.keysym.sym == SDLK_PAUSE) {
+ _graphicsMan->_lastKeyPressed = 0;
+ event.type = Common::EVENT_PREDICTIVE_DIALOG;
+ return true;
+ }
+ event.type = Common::EVENT_KEYDOWN;
+ if (!GUI::Actions::Instance()->mappingActive())
+ event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
+ else
+ event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive());
+ event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive());
+
+ if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
+ event.kbd.ascii ^= 0x20;
+ event.kbd.flags = Common::KBD_SHIFT;
+ }
+
+ return true;
+
+ case SDL_KEYUP:
+ debug(1, "Key up %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym));
+ // KMOD_RESERVED is used if the key has been injected by an external buffer
+ if (ev.key.keysym.mod != KMOD_RESERVED && !GUI::Actions::Instance()->mappingActive()) {
+ keyEvent = true;
+ _graphicsMan->_lastKeyPressed = 0;
+
+ if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, false))
+ return true;
+ }
+
+ if (GUI_Actions::Instance()->mappingActive())
+ event.kbd.flags = 0xFF;
+ else if (ev.key.keysym.sym == SDLK_PAUSE) {
+ _graphicsMan->_lastKeyPressed = 0;
+ return false; // chew up the show agi dialog key up event
+ }
+
+ event.type = Common::EVENT_KEYUP;
+ if (!GUI::Actions::Instance()->mappingActive())
+ event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
+ else
+ event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive());
+ event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, GUI::Actions::Instance()->mappingActive());
+
+ if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
+ event.kbd.ascii ^= 0x20;
+ event.kbd.flags = Common::KBD_SHIFT;
+ }
+
+ return true;
+
+ case SDL_MOUSEMOTION:
+ event.type = Common::EVENT_MOUSEMOVE;
+ fillMouseEvent(event, ev.motion.x, ev.motion.y);
+ _graphicsMan->setMousePos(event.mouse.x, event.mouse.y);
+
+ return true;
+
+ case SDL_MOUSEBUTTONDOWN:
+ if (ev.button.button == SDL_BUTTON_LEFT)
+ event.type = Common::EVENT_LBUTTONDOWN;
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = Common::EVENT_RBUTTONDOWN;
+ else
+ break;
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+
+ if (event.mouse.x > _tapX)
+ deltaX = event.mouse.x - _tapX;
+ else
+ deltaX = _tapX - event.mouse.x;
+ if (event.mouse.y > _tapY)
+ deltaY = event.mouse.y - _tapY;
+ else
+ deltaY = _tapY - event.mouse.y;
+ _closeClick = (deltaX <= 5 && deltaY <= 5);
+
+ if (!_isSmartphone) {
+ // handle double-taps
+ if (_tapTime) { // second tap
+ if (_closeClick && (GetTickCount() - _tapTime < 1000)) {
+ if (event.mouse.y <= 20 &&
+ _graphicsMan->_panelInitialized) {
+ // top of screen (show panel)
+ _graphicsMan->swap_panel_visibility();
+ } else if (!_graphicsMan->_noDoubleTapRMB) {
+ // right click
+ event.type = Common::EVENT_RBUTTONDOWN;
+ _rbutton = true;
+ }
+ }
+ _tapTime = 0;
+ } else {
+ _tapTime = GetTickCount();
+ _tapX = event.mouse.x;
+ _tapY = event.mouse.y;
+ }
+ }
+
+ if (_freeLook && !_closeClick) {
+ _rbutton = false;
+ _tapTime = 0;
+ _tapX = event.mouse.x;
+ _tapY = event.mouse.y;
+ event.type = Common::EVENT_MOUSEMOVE;
+ _graphicsMan->setMousePos(event.mouse.x, event.mouse.y);
+ }
+
+
+ if (_graphicsMan->_toolbarHandler.action(event.mouse.x, event.mouse.y, true)) {
+ if (!_graphicsMan->_toolbarHandler.drawn()) {
+ _graphicsMan->_toolbarHighDrawn = false;
+ _graphicsMan->internUpdateScreen();
+ }
+ if (_graphicsMan->_newOrientation != _graphicsMan->_orientationLandscape) {
+ _graphicsMan->_orientationLandscape = _graphicsMan->_newOrientation;
+ _graphicsMan->_toolbarHighDrawn = false;
+ ConfMan.setInt("landscape", _graphicsMan->_orientationLandscape);
+ ConfMan.flushToDisk();
+ _graphicsMan->hotswapGFXMode();
+ }
+ return false;
+ }
+
+ return true;
+
+ case SDL_MOUSEBUTTONUP:
+ if (ev.button.button == SDL_BUTTON_LEFT)
+ event.type = Common::EVENT_LBUTTONUP;
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = Common::EVENT_RBUTTONUP;
+ else
+ break;
+
+ if (_rbutton) {
+ event.type = Common::EVENT_RBUTTONUP;
+ _rbutton = false;
+ }
+
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+ if (_freeLook && !_closeClick) {
+ _tapX = event.mouse.x;
+ _tapY = event.mouse.y;
+ event.type = Common::EVENT_MOUSEMOVE;
+ _graphicsMan->setMousePos(event.mouse.x, event.mouse.y);
+ }
+
+ if (_graphicsMan->_toolbarHandler.action(event.mouse.x, event.mouse.y, false)) {
+ if (!_graphicsMan->_toolbarHandler.drawn()) {
+ _graphicsMan->_toolbarHighDrawn = false;
+ _graphicsMan->internUpdateScreen();
+ }
+ return false;
+
+ }
+ return true;
+
+ case SDL_VIDEOEXPOSE:
+ // HACK: Send a fake event, handled by SdlGraphicsManager
+ event.type = (Common::EventType)OSystem_SDL::kSdlEventExpose;
+ break;
+
+ case SDL_QUIT:
+ event.type = Common::EVENT_QUIT;
+ return true;
+
+ case SDL_ACTIVEEVENT:
+ if (ev.active.state & SDL_APPMOUSEFOCUS)
+ debug(2, "%s mouse focus.", ev.active.gain ? "Got" : "Lost");
+ if (ev.active.state & SDL_APPINPUTFOCUS)
+ debug(2, "%s input focus.", ev.active.gain ? "Got" : "Lost");
+ if (ev.active.state & SDL_APPACTIVE)
+ debug(2, "%s total focus.", ev.active.gain ? "Got" : "Lost");
+ if (ev.active.state & SDL_APPINPUTFOCUS) {
+ _graphicsMan->_hasfocus = ev.active.gain;
+ SDL_PauseAudio(!_graphicsMan->_hasfocus);
+ if (_graphicsMan->_hasfocus) {
+ event.type = (Common::EventType)OSystem_SDL::kSdlEventExpose;
+ }
+ }
+ break;
+ }
+ }
+
+ // Simulate repeated key for backend
+ if (!keyEvent && _graphicsMan->_lastKeyPressed && (int)currentTime > _graphicsMan->_keyRepeatTime + _graphicsMan->_keyRepeatTrigger) {
+ _graphicsMan->_keyRepeatTime = currentTime;
+ _graphicsMan->_keyRepeat++;
+ GUI_Actions::Instance()->performMapped(_graphicsMan->_lastKeyPressed, true);
+ }
+
+ return false;
+}
+
+int WINCESdlEventSource::mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) {
+ if (GUI::Actions::Instance()->mappingActive())
+ return key;
+
+ if (unfilter) {
+ switch (key) {
+ case SDLK_ESCAPE:
+ return SDLK_BACKSPACE;
+ case SDLK_F8:
+ return SDLK_ASTERISK;
+ case SDLK_F9:
+ return SDLK_HASH;
+ default:
+ return key;
+ }
+ }
+
+ if (key >= SDLK_KP0 && key <= SDLK_KP9) {
+ return key - SDLK_KP0 + '0';
+ } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
+ return key;
+ } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
+ return 0;
+ }
+ return key;
+}
+
+void WINCESdlEventSource::swap_freeLook() {
+ _freeLook = !_freeLook;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/backends/events/wincesdl/wincesdl-events.h b/backends/events/wincesdl/wincesdl-events.h
new file mode 100644
index 0000000000..f5b1026c46
--- /dev/null
+++ b/backends/events/wincesdl/wincesdl-events.h
@@ -0,0 +1,73 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_EVENTS_SDL_WINCE_H
+#define BACKENDS_EVENTS_SDL_WINCE_H
+
+#include "common/scummsys.h"
+
+#ifdef _WIN32_WCE
+
+#include "backends/events/sdl/sdl-events.h"
+#include "backends/graphics/wincesdl/wincesdl-graphics.h"
+
+extern bool _isSmartphone;
+
+class WINCESdlEventSource : public SdlEventSource {
+public:
+ WINCESdlEventSource();
+
+ void init(WINCESdlGraphicsManager *graphicsMan);
+
+ void loadDeviceConfiguration();
+
+ // Overloaded from SDL backend (toolbar handling)
+ bool pollEvent(Common::Event &event);
+ // Overloaded from SDL backend (mouse and new scaler handling)
+ void fillMouseEvent(Common::Event &event, int x, int y);
+
+ void swap_freeLook();
+
+protected:
+
+private:
+ int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter);
+
+ WINCESdlGraphicsManager *_graphicsMan;
+
+ // Keyboard tap
+ int _tapX;
+ int _tapY;
+ long _tapTime;
+
+ bool _closeClick; // flag when taps are spatially close together
+ bool _rbutton; // double tap -> right button simulation
+ bool _freeLook; // freeLook mode (do not send mouse button events)
+
+};
+
+#endif
+
+#endif /* BACKENDS_EVENTS_SDL_WINCE_H */
diff --git a/backends/graphics/opengl/gltexture.cpp b/backends/graphics/opengl/gltexture.cpp
index cd9e23cb71..7b7d40f174 100644
--- a/backends/graphics/opengl/gltexture.cpp
+++ b/backends/graphics/opengl/gltexture.cpp
@@ -149,7 +149,7 @@ void GLTexture::updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLu
glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
// Check if the buffer has its data contiguously
- if (static_cast<int>(w) * _bytesPerPixel == pitch && w == _textureWidth) {
+ if (static_cast<int>(w) * _bytesPerPixel == pitch) {
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
_glFormat, _glType, buf); CHECK_GL_ERROR();
} else {
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index beac2f6d3e..9a2efe3eec 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -136,6 +136,8 @@ int OpenGLGraphicsManager::getDefaultGraphicsMode() const {
bool OpenGLGraphicsManager::setGraphicsMode(int mode) {
assert(_transactionMode == kTransactionActive);
+ setScale(2);
+
if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
return true;
@@ -166,11 +168,9 @@ void OpenGLGraphicsManager::resetGraphicsScale() {
}
#ifdef USE_RGB_COLOR
-
Graphics::PixelFormat OpenGLGraphicsManager::getScreenFormat() const {
return _screenFormat;
}
-
#endif
void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
@@ -308,7 +308,7 @@ int16 OpenGLGraphicsManager::getWidth() {
void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
assert(colors);
-
+
#ifdef USE_RGB_COLOR
assert(_screenFormat.bytesPerPixel == 1);
#endif
@@ -324,7 +324,7 @@ void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num)
void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
assert(colors);
-
+
#ifdef USE_RGB_COLOR
assert(_screenFormat.bytesPerPixel == 1);
#endif
@@ -341,9 +341,9 @@ void OpenGLGraphicsManager::copyRectToScreen(const byte *buf, int pitch, int x,
// Copy buffer data to game screen internal buffer
const byte *src = buf;
- byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch;
+ byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch + x * _screenData.bytesPerPixel;
for (int i = 0; i < h; i++) {
- memcpy(dst + x * _screenData.bytesPerPixel, src, w * _screenData.bytesPerPixel);
+ memcpy(dst, src, w * _screenData.bytesPerPixel);
src += pitch;
dst += _screenData.pitch;
}
@@ -367,6 +367,7 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) {
if (_gameTexture == NULL)
return;
+#ifdef USE_RGB_COLOR
if (_screenFormat.bytesPerPixel == 1) {
memset(_screenData.pixels, col, _screenData.h * _screenData.pitch);
} else if (_screenFormat.bytesPerPixel == 2) {
@@ -392,7 +393,9 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) {
pixels[i] = col;
}
}
-
+#else
+ memset(_screenData.pixels, col, _screenData.h * _screenData.pitch);
+#endif
_screenNeedsRedraw = true;
}
@@ -558,7 +561,8 @@ void OpenGLGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int
#endif
// Allocate space for cursor data
- if (_cursorData.w != w || _cursorData.h != h)
+ if (_cursorData.w != w || _cursorData.h != h ||
+ _cursorData.bytesPerPixel != _cursorFormat.bytesPerPixel)
_cursorData.create(w, h, _cursorFormat.bytesPerPixel);
// Save cursor data
@@ -754,11 +758,17 @@ void OpenGLGraphicsManager::refreshOverlay() {
void OpenGLGraphicsManager::refreshCursor() {
_cursorNeedsRedraw = false;
- if (_cursorFormat.bytesPerPixel == 1) {
- // Create a temporary RGBA8888 surface
- byte *surface = new byte[_cursorState.w * _cursorState.h * 4];
- memset(surface, 0, _cursorState.w * _cursorState.h * 4);
+ // Allocate a texture big enough for cursor
+ _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);
+ // Create a temporary RGBA8888 surface
+ byte *surface = new byte[_cursorState.w * _cursorState.h * 4];
+ memset(surface, 0, _cursorState.w * _cursorState.h * 4);
+
+ byte *dst = surface;
+
+ // Convert the paletted cursor to RGBA8888
+ if (_cursorFormat.bytesPerPixel == 1) {
// Select palette
byte *palette;
if (_cursorPaletteDisabled)
@@ -768,7 +778,6 @@ void OpenGLGraphicsManager::refreshCursor() {
// Convert the paletted cursor to RGBA8888
const byte *src = (byte *)_cursorData.pixels;
- byte *dst = surface;
for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
// Check for keycolor
if (src[i] != _cursorKeyColor) {
@@ -779,16 +788,42 @@ void OpenGLGraphicsManager::refreshCursor() {
}
dst += 4;
}
+ } else {
+ const bool gotNoAlpha = (_cursorFormat.aLoss == 8);
+
+ // Convert the RGB cursor to RGBA8888
+ if (_cursorFormat.bytesPerPixel == 2) {
+ const uint16 *src = (uint16 *)_cursorData.pixels;
+ for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
+ // Check for keycolor
+ if (src[i] != _cursorKeyColor) {
+ _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]);
+
+ if (gotNoAlpha)
+ dst[3] = 255;
+ }
+ dst += 4;
+ }
+ } else if (_cursorFormat.bytesPerPixel == 4) {
+ const uint32 *src = (uint32 *)_cursorData.pixels;
+ for (int i = 0; i < _cursorState.w * _cursorState.h; i++) {
+ // Check for keycolor
+ if (src[i] != _cursorKeyColor) {
+ _cursorFormat.colorToARGB(src[i], dst[3], dst[0], dst[1], dst[2]);
+
+ if (gotNoAlpha)
+ dst[3] = 255;
+ }
+ dst += 4;
+ }
+ }
+ }
- // Allocate a texture big enough for cursor
- _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);
-
- // Update the texture with new cursor
- _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h);
+ // Update the texture with new cursor
+ _cursorTexture->updateBuffer(surface, _cursorState.w * 4, 0, 0, _cursorState.w, _cursorState.h);
- // Free the temp surface
- delete[] surface;
- }
+ // Free the temp surface
+ delete[] surface;
}
void OpenGLGraphicsManager::refreshCursorScale() {
@@ -811,7 +846,8 @@ void OpenGLGraphicsManager::refreshCursorScale() {
} else {
// Otherwise, scale the cursor for the overlay
int targetScaleFactor = MIN(_cursorTargetScale, _videoMode.scaleFactor);
- int actualFactor = screenScaleFactor - (targetScaleFactor - 1) * 10000;
+ // We limit the maximum scale to 3 here to avoid too big cursors, for large overlay resolutions
+ int actualFactor = MIN<uint>(3, screenScaleFactor - (targetScaleFactor - 1)) * 10000;
_cursorState.rW = (int16)(_cursorState.w * actualFactor / 10000);
_cursorState.rH = (int16)(_cursorState.h * actualFactor / 10000);
_cursorState.rHotX = (int16)(_cursorState.hotX * actualFactor / 10000);
@@ -873,6 +909,11 @@ void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat,
intFormat = GL_RGBA;
glFormat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_5_5_5_1;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) { // RGB555
+ bpp = 2;
+ intFormat = GL_RGB;
+ glFormat = GL_BGRA;
+ gltype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
} else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { // RGBA4444
bpp = 2;
intFormat = GL_RGBA;
@@ -963,7 +1004,7 @@ void OpenGLGraphicsManager::internUpdateScreen() {
refreshOverlay();
// Draw the overlay
- _overlayTexture->drawTexture(_displayX, _displayY, _displayWidth, _displayHeight);
+ _overlayTexture->drawTexture(0, 0, _videoMode.overlayWidth, _videoMode.overlayHeight);
}
if (_cursorVisible) {
@@ -1059,10 +1100,14 @@ void OpenGLGraphicsManager::initGL() {
void OpenGLGraphicsManager::loadTextures() {
#ifdef USE_RGB_COLOR
- if (_transactionDetails.formatChanged && _gameTexture)
+ if (_transactionDetails.formatChanged && _gameTexture) {
delete _gameTexture;
+ _gameTexture = 0;
+ }
#endif
+ uint gameScreenBPP = 0;
+
if (!_gameTexture) {
byte bpp;
GLenum intformat;
@@ -1073,6 +1118,7 @@ void OpenGLGraphicsManager::loadTextures() {
#else
getGLPixelFormat(Graphics::PixelFormat::createFormatCLUT8(), bpp, intformat, format, type);
#endif
+ gameScreenBPP = bpp;
_gameTexture = new GLTexture(bpp, intformat, format, type);
} else
_gameTexture->refresh();
@@ -1093,7 +1139,7 @@ void OpenGLGraphicsManager::loadTextures() {
_cursorTexture = new GLTexture(4, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
else
_cursorTexture->refresh();
-
+
GLint filter = _videoMode.antialiasing ? GL_LINEAR : GL_NEAREST;
_gameTexture->setFilter(filter);
_overlayTexture->setFilter(filter);
@@ -1104,21 +1150,38 @@ void OpenGLGraphicsManager::loadTextures() {
_overlayTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight);
_cursorTexture->allocBuffer(_cursorState.w, _cursorState.h);
- if (_transactionDetails.formatChanged ||
+ if (
+#ifdef USE_RGB_COLOR
+ _transactionDetails.formatChanged ||
+#endif
_oldVideoMode.screenWidth != _videoMode.screenWidth ||
_oldVideoMode.screenHeight != _videoMode.screenHeight)
_screenData.create(_videoMode.screenWidth, _videoMode.screenHeight,
- _screenFormat.bytesPerPixel);
+#ifdef USE_RGB_COLOR
+ _screenFormat.bytesPerPixel
+#else
+ 1
+#endif
+ );
+
if (_oldVideoMode.overlayWidth != _videoMode.overlayWidth ||
_oldVideoMode.overlayHeight != _videoMode.overlayHeight)
_overlayData.create(_videoMode.overlayWidth, _videoMode.overlayHeight,
_overlayFormat.bytesPerPixel);
-
+
_screenNeedsRedraw = true;
_overlayNeedsRedraw = true;
_cursorNeedsRedraw = true;
+ // We need to setup a proper unpack alignment value here, else we will
+ // get problems with the texture updates, in case the surface data is
+ // not properly aligned.
+ // For now we use the gcd of the game screen format and 2, since 2 is
+ // the BPP value for the overlay and the OSD.
+ if (gameScreenBPP)
+ glPixelStorei(GL_UNPACK_ALIGNMENT, Common::gcd<uint>(gameScreenBPP, 2));
+
#ifdef USE_OSD
if (!_osdTexture)
_osdTexture = new GLTexture(2, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
@@ -1166,32 +1229,20 @@ uint OpenGLGraphicsManager::getAspectRatio() {
}
void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
- if (_videoMode.mode == OpenGL::GFX_NORMAL) {
- if (_videoMode.hardwareWidth != _videoMode.overlayWidth)
- x = x * _videoMode.overlayWidth / _videoMode.hardwareWidth;
- if (_videoMode.hardwareHeight != _videoMode.overlayHeight)
- y = y * _videoMode.overlayHeight / _videoMode.hardwareHeight;
-
- if (!_overlayVisible) {
- x /= _videoMode.scaleFactor;
- y /= _videoMode.scaleFactor;
- }
+ if (_overlayVisible)
+ return;
- } else {
+ if (_videoMode.mode == OpenGL::GFX_NORMAL) {
+ x /= _videoMode.scaleFactor;
+ y /= _videoMode.scaleFactor;
+ } else if (!_overlayVisible) {
x -= _displayX;
y -= _displayY;
- if (_overlayVisible) {
- if (_displayWidth != _videoMode.overlayWidth)
- x = x * _videoMode.overlayWidth / _displayWidth;
- if (_displayHeight != _videoMode.overlayHeight)
- y = y * _videoMode.overlayHeight / _displayHeight;
- } else {
- if (_displayWidth != _videoMode.screenWidth)
- x = x * _videoMode.screenWidth / _displayWidth;
- if (_displayHeight != _videoMode.screenHeight)
- y = y * _videoMode.screenHeight / _displayHeight;
- }
+ if (_displayWidth != _videoMode.screenWidth)
+ x = x * _videoMode.screenWidth / _displayWidth;
+ if (_displayHeight != _videoMode.screenHeight)
+ y = y * _videoMode.screenHeight / _displayHeight;
}
}
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index c7ce0aa7de..cbc152a4a3 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -121,6 +121,7 @@ void OpenGLSdlGraphicsManager::detectSupportedFormats() {
#endif
Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), // RGB565
Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), // RGB5551
+ Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), // RGB555
Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), // RGBA4444
#ifndef USE_GLES
Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12) // ARGB4444
@@ -344,13 +345,10 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() {
if (_aspectRatioCorrection)
_videoMode.mode = OpenGL::GFX_4_3;
- _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
- _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
-
// If the screen was resized, do not change its size
if (!_screenResized) {
- _videoMode.hardwareWidth = _videoMode.overlayWidth;
- _videoMode.hardwareHeight = _videoMode.overlayHeight;
+ _videoMode.overlayWidth = _videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
+ _videoMode.overlayHeight = _videoMode.hardwareHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
int screenAspectRatio = _videoMode.screenWidth * 10000 / _videoMode.screenHeight;
int desiredAspectRatio = getAspectRatio();
@@ -365,6 +363,9 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() {
// the width is modified it can break the overlay.
if (_videoMode.hardwareHeight > _videoMode.overlayHeight)
_videoMode.overlayHeight = _videoMode.hardwareHeight;
+ } else {
+ _videoMode.overlayWidth = _videoMode.hardwareWidth;
+ _videoMode.overlayHeight = _videoMode.hardwareHeight;
}
_screenResized = false;
@@ -376,11 +377,15 @@ bool OpenGLSdlGraphicsManager::loadGFXMode() {
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- if (_videoMode.fullscreen)
+ if (_videoMode.fullscreen) {
if (!setupFullscreenMode())
// Failed setuping a fullscreen mode
return false;
+ _videoMode.overlayWidth = _videoMode.hardwareWidth;
+ _videoMode.overlayHeight = _videoMode.hardwareHeight;
+ }
+
uint32 flags = SDL_OPENGL;
if (_videoMode.fullscreen)
diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp
index 09c4f39636..c0d93b3bf2 100644
--- a/backends/graphics/sdl/sdl-graphics.cpp
+++ b/backends/graphics/sdl/sdl-graphics.cpp
@@ -165,13 +165,6 @@ SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *sdlEventSource)
_graphicsMutex = g_system->createMutex();
-#ifdef _WIN32_WCE
- if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
- SDL_VideoInit("windib", 0);
- sdlFlags ^= SDL_INIT_VIDEO;
- }
-#endif
-
#ifdef USE_SDL_DEBUG_FOCUSRECT
if (ConfMan.hasKey("use_sdl_debug_focusrect"))
_enableFocusRectDebugCode = ConfMan.getBool("use_sdl_debug_focusrect");
@@ -1248,25 +1241,25 @@ void SdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int
error("SDL_LockSurface failed: %s", SDL_GetError());
#ifdef USE_RGB_COLOR
- byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth * _screenFormat.bytesPerPixel + x * _screenFormat.bytesPerPixel;
- if (_videoMode.screenWidth == w && pitch == w * _screenFormat.bytesPerPixel) {
- memcpy(dst, src, h*w*_screenFormat.bytesPerPixel);
+ byte *dst = (byte *)_screen->pixels + y * _screen->pitch + x * _screenFormat.bytesPerPixel;
+ if (_videoMode.screenWidth == w && pitch == _screen->pitch) {
+ memcpy(dst, src, h*pitch);
} else {
do {
memcpy(dst, src, w * _screenFormat.bytesPerPixel);
src += pitch;
- dst += _videoMode.screenWidth * _screenFormat.bytesPerPixel;
+ dst += _screen->pitch;
} while (--h);
}
#else
- byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
- if (_videoMode.screenWidth == pitch && pitch == w) {
+ byte *dst = (byte *)_screen->pixels + y * _screen->pitch + x;
+ if (_screen->pitch == pitch && pitch == w) {
memcpy(dst, src, h*w);
} else {
do {
memcpy(dst, src, w);
src += pitch;
- dst += _videoMode.screenWidth;
+ dst += _screen->pitch;
} while (--h);
}
#endif
diff --git a/backends/graphics/wincesdl/wincesdl-graphics.cpp b/backends/graphics/wincesdl/wincesdl-graphics.cpp
new file mode 100644
index 0000000000..37c6624560
--- /dev/null
+++ b/backends/graphics/wincesdl/wincesdl-graphics.cpp
@@ -0,0 +1,1639 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#ifdef _WIN32_WCE
+
+#include "common/system.h"
+#include "common/translation.h"
+#include "common/mutex.h"
+
+#include "graphics/scaler/downscaler.h"
+#include "graphics/scaler/aspect.h"
+#include "backends/graphics/wincesdl/wincesdl-graphics.h"
+#include "backends/events/wincesdl/wincesdl-events.h"
+#include "backends/platform/wince/wince-sdl.h"
+
+#include "backends/platform/wince/resource.h"
+#include "backends/platform/wince/CEActionsPocket.h"
+#include "backends/platform/wince/CEActionsSmartphone.h"
+#include "backends/platform/wince/CEDevice.h"
+#include "backends/platform/wince/CEScaler.h"
+#include "backends/platform/wince/CEgui/ItemAction.h"
+
+WINCESdlGraphicsManager::WINCESdlGraphicsManager(SdlEventSource *sdlEventSource)
+ : SdlGraphicsManager(sdlEventSource),
+ _panelInitialized(false), _noDoubleTapRMB(false),
+ _toolbarHighDrawn(false), _newOrientation(0), _orientationLandscape(0),
+ _panelVisible(true), _saveActiveToolbar(NAME_MAIN_PANEL), _panelStateForced(false),
+ _canBeAspectScaled(false), _scalersChanged(false), _saveToolbarState(false),
+ _mouseBackupOld(NULL), _mouseBackupDim(0), _mouseBackupToolbar(NULL),
+ _usesEmulatedMouse(false), _forceHideMouse(false), _hasfocus(true),
+ _zoomUp(false), _zoomDown(false) {
+ memset(&_mouseCurState, 0, sizeof(_mouseCurState));
+ if (_isSmartphone) {
+ _mouseCurState.x = 20;
+ _mouseCurState.y = 20;
+ }
+
+ loadDeviceConfigurationElement("repeatTrigger", _keyRepeatTrigger, 200);
+ loadDeviceConfigurationElement("repeatX", _repeatX, 4);
+ loadDeviceConfigurationElement("repeatY", _repeatY, 4);
+ loadDeviceConfigurationElement("stepX1", _stepX1, 2);
+ loadDeviceConfigurationElement("stepX2", _stepX2, 10);
+ loadDeviceConfigurationElement("stepX3", _stepX3, 40);
+ loadDeviceConfigurationElement("stepY1", _stepY1, 2);
+ loadDeviceConfigurationElement("stepY2", _stepY2, 10);
+ loadDeviceConfigurationElement("stepY3", _stepY3, 20);
+ ConfMan.flushToDisk();
+
+ _isSmartphone = CEDevice::isSmartphone();
+
+ // Query SDL for screen size and init screen dependent stuff
+ OSystem_WINCE3::initScreenInfos();
+ create_toolbar();
+ _hasSmartphoneResolution = CEDevice::hasSmartphoneResolution() || CEDevice::isSmartphone();
+ if (_hasSmartphoneResolution)
+ _panelVisible = false; // init correctly in smartphones
+
+ _screen = NULL;
+}
+
+// Graphics mode consts
+
+// Low end devices 240x320
+
+static const OSystem::GraphicsMode s_supportedGraphicsModesLow[] = {
+ {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
+ {0, 0, 0}
+};
+
+// High end device 480x640
+
+static const OSystem::GraphicsMode s_supportedGraphicsModesHigh[] = {
+ {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
+ {"2x", "2x", GFX_DOUBLESIZE},
+#ifndef _MSC_VER // EVC breaks template functions, and I'm tired of fixing them :)
+ {"2xsai", "2xSAI", GFX_2XSAI},
+ {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI},
+ {"supereagle", "SuperEagle", GFX_SUPEREAGLE},
+#endif
+ {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X},
+#ifndef _MSC_VER
+ {"hq2x", "HQ2x", GFX_HQ2X},
+ {"tv2x", "TV2x", GFX_TV2X},
+#endif
+ {"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
+ {0, 0, 0}
+};
+
+const OSystem::GraphicsMode *WINCESdlGraphicsManager::getSupportedGraphicsModes() const {
+ if (CEDevice::hasWideResolution())
+ return s_supportedGraphicsModesHigh;
+ else
+ return s_supportedGraphicsModesLow;
+}
+
+bool WINCESdlGraphicsManager::hasFeature(OSystem::Feature f) {
+ return (f == OSystem::kFeatureVirtualKeyboard);
+}
+
+void WINCESdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
+ switch (f) {
+ case OSystem::kFeatureFullscreenMode:
+ return;
+
+ case OSystem::kFeatureVirtualKeyboard:
+ if (_hasSmartphoneResolution)
+ return;
+ _toolbarHighDrawn = false;
+ if (enable) {
+ _panelStateForced = true;
+ if (!_toolbarHandler.visible()) swap_panel_visibility();
+ //_saveToolbarState = _toolbarHandler.visible();
+ _saveActiveToolbar = _toolbarHandler.activeName();
+ _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
+ _toolbarHandler.setVisible(true);
+ } else if (_panelStateForced) {
+ _panelStateForced = false;
+ _toolbarHandler.setActive(_saveActiveToolbar);
+ //_toolbarHandler.setVisible(_saveToolbarState);
+ }
+ return;
+
+ case OSystem::kFeatureDisableKeyFiltering:
+ if (_hasSmartphoneResolution) {
+ GUI::Actions::Instance()->beginMapping(enable);
+ }
+ return;
+
+ default:
+ SdlGraphicsManager::setFeatureState(f, enable);
+ }
+}
+
+bool WINCESdlGraphicsManager::getFeatureState(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureFullscreenMode:
+ return false;
+ case OSystem::kFeatureVirtualKeyboard:
+ return (_panelStateForced);
+ default:
+ return SdlGraphicsManager::getFeatureState(f);
+ }
+}
+
+int WINCESdlGraphicsManager::getDefaultGraphicsMode() const {
+ return GFX_NORMAL;
+}
+
+void WINCESdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
+ if (_hasSmartphoneResolution && h == 240)
+ h = 200; // mainly for the launcher
+
+ if (_isSmartphone && !ConfMan.hasKey("landscape")) {
+ ConfMan.setInt("landscape", 1);
+ ConfMan.flushToDisk();
+ }
+
+ _canBeAspectScaled = false;
+ if (w == 320 && h == 200 && !_hasSmartphoneResolution) {
+ _canBeAspectScaled = true;
+ h = 240; // use the extra 40 pixels height for the toolbar
+ }
+
+ if (h == 400) // touche engine fixup
+ h += 80;
+
+ if (!_hasSmartphoneResolution) {
+ if (h == 240)
+ _toolbarHandler.setOffset(200);
+ else
+ _toolbarHandler.setOffset(400);
+ } else {
+ if (h == 240)
+ _toolbarHandler.setOffset(200);
+ else // 176x220
+ _toolbarHandler.setOffset(0);
+ }
+
+ if (w != (uint) _videoMode.screenWidth || h != (uint) _videoMode.screenHeight)
+ _scalersChanged = false;
+
+ _videoMode.overlayWidth = w;
+ _videoMode.overlayHeight = h;
+
+ SdlGraphicsManager::initSize(w, h, format);
+
+ if (_scalersChanged) {
+ unloadGFXMode();
+ loadGFXMode();
+ _scalersChanged = false;
+ }
+
+ update_game_settings();
+}
+
+void WINCESdlGraphicsManager::loadDeviceConfigurationElement(Common::String element, int &value, int defaultValue) {
+ value = ConfMan.getInt(element, ConfMan.kApplicationDomain);
+ if (!value) {
+ value = defaultValue;
+ ConfMan.setInt(element, value, ConfMan.kApplicationDomain);
+ }
+}
+
+void WINCESdlGraphicsManager::move_cursor_up() {
+ int x, y;
+ _usesEmulatedMouse = true;
+ retrieve_mouse_location(x, y);
+ if (_keyRepeat > _repeatY)
+ y -= _stepY3;
+ else if (_keyRepeat)
+ y -= _stepY2;
+ else
+ y -= _stepY1;
+
+ if (y < 0)
+ y = 0;
+
+ EventsBuffer::simulateMouseMove(x, y);
+}
+
+void WINCESdlGraphicsManager::move_cursor_down() {
+ int x, y;
+ _usesEmulatedMouse = true;
+ retrieve_mouse_location(x, y);
+ if (_keyRepeat > _repeatY)
+ y += _stepY3;
+ else if (_keyRepeat)
+ y += _stepY2;
+ else
+ y += _stepY1;
+
+ if (y > _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd)
+ y = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;
+
+ EventsBuffer::simulateMouseMove(x, y);
+}
+
+void WINCESdlGraphicsManager::move_cursor_left() {
+ int x, y;
+ _usesEmulatedMouse = true;
+ retrieve_mouse_location(x, y);
+ if (_keyRepeat > _repeatX)
+ x -= _stepX3;
+ else if (_keyRepeat)
+ x -= _stepX2;
+ else
+ x -= _stepX1;
+
+ if (x < 0)
+ x = 0;
+
+ EventsBuffer::simulateMouseMove(x, y);
+}
+
+void WINCESdlGraphicsManager::move_cursor_right() {
+ int x, y;
+ _usesEmulatedMouse = true;
+ retrieve_mouse_location(x, y);
+ if (_keyRepeat > _repeatX)
+ x += _stepX3;
+ else if (_keyRepeat)
+ x += _stepX2;
+ else
+ x += _stepX1;
+
+ if (x > _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd)
+ x = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;
+
+ EventsBuffer::simulateMouseMove(x, y);
+}
+
+void WINCESdlGraphicsManager::retrieve_mouse_location(int &x, int &y) {
+ x = _mouseCurState.x;
+ y = _mouseCurState.y;
+
+ x = x * _scaleFactorXm / _scaleFactorXd;
+ y = y * _scaleFactorYm / _scaleFactorYd;
+
+ if (_zoomDown)
+ y -= 240;
+}
+
+void WINCESdlGraphicsManager::switch_zone() {
+ int x, y;
+ int i;
+ retrieve_mouse_location(x, y);
+
+ for (i = 0; i < TOTAL_ZONES; i++)
+ if (x >= _zones[i].x && y >= _zones[i].y &&
+ x <= _zones[i].x + _zones[i].width && y <= _zones[i].y + _zones[i].height) {
+ _mouseXZone[i] = x;
+ _mouseYZone[i] = y;
+ break;
+ }
+ _currentZone = i + 1;
+ if (_currentZone >= TOTAL_ZONES)
+ _currentZone = 0;
+
+ EventsBuffer::simulateMouseMove(_mouseXZone[_currentZone], _mouseYZone[_currentZone]);
+}
+
+void WINCESdlGraphicsManager::add_right_click(bool pushed) {
+ int x, y;
+ retrieve_mouse_location(x, y);
+ EventsBuffer::simulateMouseRightClick(x, y, pushed);
+}
+
+void WINCESdlGraphicsManager::add_left_click(bool pushed) {
+ int x, y;
+ retrieve_mouse_location(x, y);
+ EventsBuffer::simulateMouseLeftClick(x, y, pushed);
+}
+
+bool WINCESdlGraphicsManager::update_scalers() {
+ _videoMode.aspectRatioCorrection = false;
+
+ if (CEDevice::hasPocketPCResolution()) {
+ if (_videoMode.mode != GFX_NORMAL)
+ return false;
+
+ if ((!_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth))
+ || CEDevice::hasSquareQVGAResolution()) {
+ if (OSystem_WINCE3::getScreenWidth() != 320) {
+ _scaleFactorXm = 3;
+ _scaleFactorXd = 4;
+ _scaleFactorYm = 1;
+ _scaleFactorYd = 1;
+ _scalerProc = DownscaleHorizByThreeQuarters;
+ } else {
+ _scaleFactorXm = 1;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 1;
+ _scaleFactorYd = 1;
+ _scalerProc = Normal1x;
+ }
+ } else if (_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) {
+ if (!_panelVisible && !_hasSmartphoneResolution && !_overlayVisible && _canBeAspectScaled) {
+ _scaleFactorXm = 1;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 6;
+ _scaleFactorYd = 5;
+ _scalerProc = Normal1xAspect;
+ _videoMode.aspectRatioCorrection = true;
+ } else {
+ _scaleFactorXm = 1;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 1;
+ _scaleFactorYd = 1;
+ _scalerProc = Normal1x;
+ }
+ } else if (_videoMode.screenWidth == 640 && !(OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640))) {
+ _scaleFactorXm = 1;
+ _scaleFactorXd = 2;
+ _scaleFactorYm = 1;
+ _scaleFactorYd = 2;
+ _scalerProc = DownscaleAllByHalf;
+ } else if (_videoMode.screenWidth == 640 && (OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640))) {
+ _scaleFactorXm = 1;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 1;
+ _scaleFactorYd = 1;
+ _scalerProc = Normal1x;
+ }
+
+ return true;
+ } else if (CEDevice::hasWideResolution()) {
+#ifdef USE_ARM_SCALER_ASM
+ if (_videoMode.mode == GFX_DOUBLESIZE && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) {
+ if (!_panelVisible && !_overlayVisible && _canBeAspectScaled) {
+ _scaleFactorXm = 2;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 12;
+ _scaleFactorYd = 5;
+ _scalerProc = Normal2xAspect;
+ _videoMode.aspectRatioCorrection = true;
+ } else if ((_panelVisible || _overlayVisible) && _canBeAspectScaled) {
+ _scaleFactorXm = 2;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = 2;
+ _scaleFactorYd = 1;
+ _scalerProc = Normal2x;
+ }
+ return true;
+ }
+#endif
+ } else if (CEDevice::hasSmartphoneResolution()) {
+ if (_videoMode.mode != GFX_NORMAL)
+ return false;
+
+ if (_videoMode.screenWidth > 320)
+ error("Game resolution not supported on Smartphone");
+#ifdef ARM
+ _scaleFactorXm = 11;
+ _scaleFactorXd = 16;
+#else
+ _scaleFactorXm = 2;
+ _scaleFactorXd = 3;
+#endif
+ _scaleFactorYm = 7;
+ _scaleFactorYd = 8;
+ _scalerProc = SmartphoneLandscape;
+ initZones();
+ return true;
+ }
+
+ return false;
+}
+
+void WINCESdlGraphicsManager::update_game_settings() {
+ Common::String gameid(ConfMan.get("gameid"));
+
+ // Finish panel initialization
+ if (!_panelInitialized && !gameid.empty()) {
+ CEGUI::Panel *panel;
+ _panelInitialized = true;
+ // Add the main panel
+ panel = new CEGUI::Panel(0, 32);
+ panel->setBackground(IMAGE_PANEL);
+
+ // Save
+ panel->add(NAME_ITEM_OPTIONS, new CEGUI::ItemAction(ITEM_OPTIONS, POCKET_ACTION_SAVE));
+ // Skip
+ panel->add(NAME_ITEM_SKIP, new CEGUI::ItemAction(ITEM_SKIP, POCKET_ACTION_SKIP));
+ // sound
+//__XXX__ panel->add(NAME_ITEM_SOUND, new CEGUI::ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &_soundMaster));
+ panel->add(NAME_ITEM_SOUND, new CEGUI::ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &OSystem_WINCE3::_soundMaster));
+
+ // bind keys
+ panel->add(NAME_ITEM_BINDKEYS, new CEGUI::ItemAction(ITEM_BINDKEYS, POCKET_ACTION_BINDKEYS));
+ // portrait/landscape - screen dependent
+ // FIXME : will still display the portrait/landscape icon when using a scaler (but will be disabled)
+ if (ConfMan.hasKey("landscape")) {
+ if (ConfMan.get("landscape")[0] > 57) {
+ _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
+ //ConfMan.removeKey("landscape", "");
+ ConfMan.setInt("landscape", _orientationLandscape);
+ } else
+ _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
+ } else {
+ _newOrientation = _orientationLandscape = 0;
+ }
+ panel->add(NAME_ITEM_ORIENTATION, new CEGUI::ItemSwitch(ITEM_VIEW_LANDSCAPE, ITEM_VIEW_PORTRAIT, &_newOrientation, 2));
+ _toolbarHandler.add(NAME_MAIN_PANEL, *panel);
+ _toolbarHandler.setActive(NAME_MAIN_PANEL);
+ _toolbarHandler.setVisible(true);
+
+ if (_videoMode.mode == GFX_NORMAL && ConfMan.hasKey("landscape") && ConfMan.getInt("landscape")) {
+ setGraphicsMode(GFX_NORMAL);
+ hotswapGFXMode();
+ }
+
+ if (_hasSmartphoneResolution)
+ panel->setVisible(false);
+
+ _saveToolbarState = true;
+ }
+
+ if (ConfMan.hasKey("no_doubletap_rightclick"))
+ _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick");
+}
+
+void WINCESdlGraphicsManager::internUpdateScreen() {
+ SDL_Surface *srcSurf, *origSurf;
+ static bool old_overlayVisible = false;
+ int numRectsOut = 0;
+ int16 routx, routy, routw, routh, stretch, shakestretch;
+
+ assert(_hwscreen != NULL);
+
+ // bail if the application is minimized, be nice to OS
+ if (!_hasfocus) {
+ Sleep(20);
+ return;
+ }
+
+ // If the shake position changed, fill the dirty area with blackness
+ if (_currentShakePos != _newShakePos) {
+ SDL_Rect blackrect = {0, 0, _videoMode.screenWidth *_scaleFactorXm / _scaleFactorXd, _newShakePos *_scaleFactorYm / _scaleFactorYd};
+ if (_videoMode.aspectRatioCorrection)
+ blackrect.h = real2Aspect(blackrect.h - 1) + 1;
+ SDL_FillRect(_hwscreen, &blackrect, 0);
+ _currentShakePos = _newShakePos;
+ _forceFull = true;
+ }
+
+ // Make sure the mouse is drawn, if it should be drawn.
+ drawMouse();
+
+ // Check whether the palette was changed in the meantime and update the
+ // screen surface accordingly.
+ if (_paletteDirtyEnd != 0) {
+ SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, _paletteDirtyStart, _paletteDirtyEnd - _paletteDirtyStart);
+ _paletteDirtyEnd = 0;
+ _forceFull = true;
+ }
+
+ if (!_overlayVisible) {
+ origSurf = _screen;
+ srcSurf = _tmpscreen;
+ } else {
+ origSurf = _overlayscreen;
+ srcSurf = _tmpscreen2;
+ }
+
+ if (old_overlayVisible != _overlayVisible) {
+ old_overlayVisible = _overlayVisible;
+ update_scalers();
+ }
+
+ // Force a full redraw if requested
+ if (_forceFull) {
+ _numDirtyRects = 1;
+
+ _dirtyRectList[0].x = 0;
+ if (!_zoomDown)
+ _dirtyRectList[0].y = 0;
+ else
+ _dirtyRectList[0].y = _videoMode.screenHeight / 2;
+ _dirtyRectList[0].w = _videoMode.screenWidth;
+ if (!_zoomUp && !_zoomDown)
+ _dirtyRectList[0].h = _videoMode.screenHeight;
+ else
+ _dirtyRectList[0].h = _videoMode.screenHeight / 2;
+
+ _toolbarHandler.forceRedraw();
+ }
+
+ // Only draw anything if necessary
+ if (_numDirtyRects > 0) {
+
+ SDL_Rect *r, *rout;
+ SDL_Rect dst;
+ uint32 srcPitch, dstPitch;
+ SDL_Rect *last_rect = _dirtyRectList + _numDirtyRects;
+ bool toolbarVisible = _toolbarHandler.visible();
+ int toolbarOffset = _toolbarHandler.getOffset();
+
+ for (r = _dirtyRectList; r != last_rect; ++r) {
+ dst = *r;
+ dst.x++; // Shift rect by one since 2xSai needs to access the data around
+ dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
+ // NOTE: This is also known as BLACK MAGIC, copied from the sdl backend
+ if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+ }
+
+ SDL_LockSurface(srcSurf);
+ SDL_LockSurface(_hwscreen);
+
+ srcPitch = srcSurf->pitch;
+ dstPitch = _hwscreen->pitch;
+
+ for (r = _dirtyRectList, rout = _dirtyRectOut; r != last_rect; ++r) {
+
+ // always clamp to enclosing, downsampled-grid-aligned rect in the downscaled image
+ if (_scaleFactorXd != 1) {
+ stretch = r->x % _scaleFactorXd;
+ r->x -= stretch;
+ r->w += stretch;
+ r->w = (r->x + r->w + _scaleFactorXd - 1) / _scaleFactorXd * _scaleFactorXd - r->x;
+ }
+ if (_scaleFactorYd != 1) {
+ stretch = r->y % _scaleFactorYd;
+ r->y -= stretch;
+ r->h += stretch;
+ r->h = (r->y + r->h + _scaleFactorYd - 1) / _scaleFactorYd * _scaleFactorYd - r->y;
+ }
+
+ // transform
+ shakestretch = _currentShakePos * _scaleFactorYm / _scaleFactorYd;
+ routx = r->x * _scaleFactorXm / _scaleFactorXd; // locate position in scaled screen
+ routy = r->y * _scaleFactorYm / _scaleFactorYd + shakestretch; // adjust for shake offset
+ routw = r->w * _scaleFactorXm / _scaleFactorXd;
+ routh = r->h * _scaleFactorYm / _scaleFactorYd - shakestretch;
+
+ // clipping destination rectangle inside device screen (more strict, also more tricky but more stable)
+ // note that all current scalers do not make dst rect exceed left/right, unless chosen badly (FIXME)
+ if (_zoomDown) routy -= 240; // adjust for zoom position
+ if (routy + routh < 0) continue;
+ if (routy < 0) {
+ routh += routy;
+ r->y -= routy * _scaleFactorYd / _scaleFactorYm;
+ routy = 0;
+ r->h = routh * _scaleFactorYd / _scaleFactorYm;
+ }
+ if (_orientationLandscape) {
+ if (routy > OSystem_WINCE3::getScreenWidth()) continue;
+ if (routy + routh > OSystem_WINCE3::getScreenWidth()) {
+ routh = OSystem_WINCE3::getScreenWidth() - routy;
+ r->h = routh * _scaleFactorYd / _scaleFactorYm;
+ }
+ } else {
+ if (routy > OSystem_WINCE3::getScreenHeight()) continue;
+ if (routy + routh > OSystem_WINCE3::getScreenHeight()) {
+ routh = OSystem_WINCE3::getScreenHeight() - routy;
+ r->h = routh * _scaleFactorYd / _scaleFactorYm;
+ }
+ }
+
+ // check if the toolbar is overwritten
+ if (toolbarVisible && r->y + r->h >= toolbarOffset)
+ _toolbarHandler.forceRedraw();
+
+ // blit it (with added voodoo from the sdl backend, shifting the source rect again)
+ _scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
+ (byte *)_hwscreen->pixels + routx * 2 + routy * dstPitch, dstPitch,
+ r->w, r->h - _currentShakePos);
+
+ // add this rect to output
+ rout->x = routx;
+ rout->y = routy - shakestretch;
+ rout->w = routw;
+ rout->h = routh + shakestretch;
+ numRectsOut++;
+ rout++;
+
+ }
+ SDL_UnlockSurface(srcSurf);
+ SDL_UnlockSurface(_hwscreen);
+ }
+ // Add the toolbar if needed
+ SDL_Rect toolbar_rect[1];
+ if (_panelVisible && _toolbarHandler.draw(_toolbarLow, &toolbar_rect[0])) {
+ // It can be drawn, scale it
+ uint32 srcPitch, dstPitch;
+ SDL_Surface *toolbarSurface;
+ ScalerProc *toolbarScaler;
+
+ if (_videoMode.screenHeight > 240) {
+ if (!_toolbarHighDrawn) {
+ // Resize the toolbar
+ SDL_LockSurface(_toolbarLow);
+ SDL_LockSurface(_toolbarHigh);
+ Normal2x((byte *)_toolbarLow->pixels, _toolbarLow->pitch, (byte *)_toolbarHigh->pixels, _toolbarHigh->pitch, toolbar_rect[0].w, toolbar_rect[0].h);
+ SDL_UnlockSurface(_toolbarHigh);
+ SDL_UnlockSurface(_toolbarLow);
+ _toolbarHighDrawn = true;
+ }
+ toolbar_rect[0].w *= 2;
+ toolbar_rect[0].h *= 2;
+ toolbarSurface = _toolbarHigh;
+ } else
+ toolbarSurface = _toolbarLow;
+
+ drawToolbarMouse(toolbarSurface, true); // draw toolbar mouse if applicable
+
+ // Apply the appropriate scaler
+ SDL_LockSurface(toolbarSurface);
+ SDL_LockSurface(_hwscreen);
+ srcPitch = toolbarSurface->pitch;
+ dstPitch = _hwscreen->pitch;
+
+ toolbarScaler = _scalerProc;
+ if (_videoMode.scaleFactor == 2)
+ toolbarScaler = Normal2x;
+ else if (_videoMode.scaleFactor == 3)
+ toolbarScaler = Normal3x;
+ toolbarScaler((byte *)toolbarSurface->pixels, srcPitch,
+ (byte *)_hwscreen->pixels + (_toolbarHandler.getOffset() * _scaleFactorYm / _scaleFactorYd * dstPitch),
+ dstPitch, toolbar_rect[0].w, toolbar_rect[0].h);
+ SDL_UnlockSurface(toolbarSurface);
+ SDL_UnlockSurface(_hwscreen);
+
+ // And blit it
+ toolbar_rect[0].y = _toolbarHandler.getOffset();
+ toolbar_rect[0].x = toolbar_rect[0].x * _scaleFactorXm / _scaleFactorXd;
+ toolbar_rect[0].y = toolbar_rect[0].y * _scaleFactorYm / _scaleFactorYd;
+ toolbar_rect[0].w = toolbar_rect[0].w * _scaleFactorXm / _scaleFactorXd;
+ toolbar_rect[0].h = toolbar_rect[0].h * _scaleFactorYm / _scaleFactorYd;
+
+ SDL_UpdateRects(_hwscreen, 1, toolbar_rect);
+
+ drawToolbarMouse(toolbarSurface, false); // undraw toolbar mouse
+ }
+
+ // Finally, blit all our changes to the screen
+ if (numRectsOut > 0)
+ SDL_UpdateRects(_hwscreen, numRectsOut, _dirtyRectOut);
+
+ _numDirtyRects = 0;
+ _forceFull = false;
+}
+
+bool WINCESdlGraphicsManager::setGraphicsMode(int mode) {
+
+ Common::StackLock lock(_graphicsMutex);
+ int oldScaleFactorXm = _scaleFactorXm;
+ int oldScaleFactorXd = _scaleFactorXd;
+ int oldScaleFactorYm = _scaleFactorYm;
+ int oldScaleFactorYd = _scaleFactorYd;
+
+ _scaleFactorXm = -1;
+ _scaleFactorXd = -1;
+ _scaleFactorYm = -1;
+ _scaleFactorYd = -1;
+
+ if (ConfMan.hasKey("landscape"))
+ if (ConfMan.get("landscape")[0] > 57) {
+ _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
+ ConfMan.setInt("landscape", _orientationLandscape);
+ } else
+ _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
+ else
+ _newOrientation = _orientationLandscape = 0;
+
+ if (OSystem_WINCE3::isOzone() && (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640) && mode)
+ _scaleFactorXm = -1;
+
+ if (CEDevice::hasPocketPCResolution() && !CEDevice::hasWideResolution() && _orientationLandscape)
+ _videoMode.mode = GFX_NORMAL;
+ else
+ _videoMode.mode = mode;
+
+ if (_scaleFactorXm < 0) {
+ /* Standard scalers, from the SDL backend */
+ switch (_videoMode.mode) {
+ case GFX_NORMAL:
+ _videoMode.scaleFactor = 1;
+ _scalerProc = Normal1x;
+ break;
+ case GFX_DOUBLESIZE:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = Normal2x;
+ break;
+ case GFX_TRIPLESIZE:
+ _videoMode.scaleFactor = 3;
+ _scalerProc = Normal3x;
+ break;
+ case GFX_2XSAI:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = _2xSaI;
+ break;
+ case GFX_SUPER2XSAI:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = Super2xSaI;
+ break;
+ case GFX_SUPEREAGLE:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = SuperEagle;
+ break;
+ case GFX_ADVMAME2X:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = AdvMame2x;
+ break;
+ case GFX_ADVMAME3X:
+ _videoMode.scaleFactor = 3;
+ _scalerProc = AdvMame3x;
+ break;
+#ifdef USE_HQ_SCALERS
+ case GFX_HQ2X:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = HQ2x;
+ break;
+ case GFX_HQ3X:
+ _videoMode.scaleFactor = 3;
+ _scalerProc = HQ3x;
+ break;
+#endif
+ case GFX_TV2X:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = TV2x;
+ break;
+ case GFX_DOTMATRIX:
+ _videoMode.scaleFactor = 2;
+ _scalerProc = DotMatrix;
+ break;
+
+ default:
+ error("unknown gfx mode %d", mode);
+ }
+ }
+
+ // Check if the scaler can be accepted, if not get back to normal scaler
+ if (_videoMode.scaleFactor && ((_videoMode.scaleFactor * _videoMode.screenWidth > OSystem_WINCE3::getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenWidth > OSystem_WINCE3::getScreenHeight())
+ || (_videoMode.scaleFactor * _videoMode.screenHeight > OSystem_WINCE3::getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenHeight > OSystem_WINCE3::getScreenHeight()))) {
+ _videoMode.scaleFactor = 1;
+ _scalerProc = Normal1x;
+ }
+
+ // Common scaler system was used
+ if (_scaleFactorXm < 0) {
+ _scaleFactorXm = _videoMode.scaleFactor;
+ _scaleFactorXd = 1;
+ _scaleFactorYm = _videoMode.scaleFactor;
+ _scaleFactorYd = 1;
+ }
+
+ _forceFull = true;
+
+ if (oldScaleFactorXm != _scaleFactorXm ||
+ oldScaleFactorXd != _scaleFactorXd ||
+ oldScaleFactorYm != _scaleFactorYm ||
+ oldScaleFactorYd != _scaleFactorYd) {
+ _scalersChanged = true;
+ } else
+ _scalersChanged = false;
+
+
+ return true;
+
+}
+
+bool WINCESdlGraphicsManager::loadGFXMode() {
+ int displayWidth;
+ int displayHeight;
+ unsigned int flags = SDL_FULLSCREEN | SDL_SWSURFACE;
+
+ _videoMode.fullscreen = true; // forced
+ _forceFull = true;
+
+ _tmpscreen = NULL;
+
+ // Recompute scalers if necessary
+ update_scalers();
+
+ // Create the surface that contains the 8 bit game data
+ _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0);
+ if (_screen == NULL)
+ error("_screen failed (%s)", SDL_GetError());
+
+ // Create the surface that contains the scaled graphics in 16 bit mode
+ // Always use full screen mode to have a "clean screen"
+ if (!_videoMode.aspectRatioCorrection) {
+ displayWidth = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;
+ displayHeight = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;
+ } else {
+ displayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
+ displayHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
+ }
+
+ switch (_orientationLandscape) {
+ case 1:
+ flags |= SDL_LANDSCVIDEO;
+ break;
+ case 2:
+ flags |= SDL_INVLNDVIDEO;
+ break;
+ default:
+ flags |= SDL_PORTRTVIDEO;
+ }
+ _hwscreen = SDL_SetVideoMode(displayWidth, displayHeight, 16, flags);
+
+ if (_hwscreen == NULL) {
+ warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
+ g_system->quit();
+ }
+
+ // see what orientation sdl finally accepted
+ if (_hwscreen->flags & SDL_PORTRTVIDEO)
+ _orientationLandscape = _newOrientation = 0;
+ else if (_hwscreen->flags & SDL_LANDSCVIDEO)
+ _orientationLandscape = _newOrientation = 1;
+ else
+ _orientationLandscape = _newOrientation = 2;
+
+ // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
+ // Distinguish 555 and 565 mode
+ if (_hwscreen->format->Rmask == 0x7C00)
+ InitScalers(555);
+ else
+ InitScalers(565);
+ _overlayFormat.bytesPerPixel = _hwscreen->format->BytesPerPixel;
+ _overlayFormat.rLoss = _hwscreen->format->Rloss;
+ _overlayFormat.gLoss = _hwscreen->format->Gloss;
+ _overlayFormat.bLoss = _hwscreen->format->Bloss;
+ _overlayFormat.aLoss = _hwscreen->format->Aloss;
+ _overlayFormat.rShift = _hwscreen->format->Rshift;
+ _overlayFormat.gShift = _hwscreen->format->Gshift;
+ _overlayFormat.bShift = _hwscreen->format->Bshift;
+ _overlayFormat.aShift = _hwscreen->format->Ashift;
+
+ // Need some extra bytes around when using 2xSaI
+ _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
+
+ if (_tmpscreen == NULL)
+ error("_tmpscreen creation failed (%s)", SDL_GetError());
+
+ // Overlay
+ if (CEDevice::hasDesktopResolution()) {
+ _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd, 16, 0, 0, 0, 0);
+ if (_overlayscreen == NULL)
+ error("_overlayscreen failed (%s)", SDL_GetError());
+ _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd + 3, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd + 3, 16, 0, 0, 0, 0);
+ if (_tmpscreen2 == NULL)
+ error("_tmpscreen2 failed (%s)", SDL_GetError());
+ } else {
+ _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, 16, 0, 0, 0, 0);
+ if (_overlayscreen == NULL)
+ error("_overlayscreen failed (%s)", SDL_GetError());
+ _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, 16, 0, 0, 0, 0);
+ if (_tmpscreen2 == NULL)
+ error("_tmpscreen2 failed (%s)", SDL_GetError());
+ }
+
+ // Toolbar
+ _toolbarHighDrawn = false;
+ uint16 *toolbar_screen = (uint16 *)calloc(320 * 40, sizeof(uint16)); // *not* leaking memory here
+ _toolbarLow = SDL_CreateRGBSurfaceFrom(toolbar_screen, 320, 40, 16, 320 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
+
+ if (_toolbarLow == NULL)
+ error("_toolbarLow failed (%s)", SDL_GetError());
+
+ if (_videoMode.screenHeight > 240) {
+ uint16 *toolbar_screen_high = (uint16 *)calloc(640 * 80, sizeof(uint16));
+ _toolbarHigh = SDL_CreateRGBSurfaceFrom(toolbar_screen_high, 640, 80, 16, 640 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
+
+ if (_toolbarHigh == NULL)
+ error("_toolbarHigh failed (%s)", SDL_GetError());
+ } else
+ _toolbarHigh = NULL;
+
+ // keyboard cursor control, some other better place for it?
+ _sdlEventSource->resetKeyboadEmulation(_videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd - 1, _videoMode.screenHeight * _scaleFactorXm / _scaleFactorXd - 1);
+
+ return true;
+}
+
+void WINCESdlGraphicsManager::unloadGFXMode() {
+ if (_screen) {
+ SDL_FreeSurface(_screen);
+ _screen = NULL;
+ }
+
+ if (_hwscreen) {
+ SDL_FreeSurface(_hwscreen);
+ _hwscreen = NULL;
+ }
+
+ if (_tmpscreen) {
+ SDL_FreeSurface(_tmpscreen);
+ _tmpscreen = NULL;
+ }
+}
+
+bool WINCESdlGraphicsManager::hotswapGFXMode() {
+ if (!_screen)
+ return false;
+
+ // Keep around the old _screen & _tmpscreen so we can restore the screen data
+ // after the mode switch. (also for the overlay)
+ SDL_Surface *old_screen = _screen;
+ SDL_Surface *old_tmpscreen = _tmpscreen;
+ SDL_Surface *old_overlayscreen = _overlayscreen;
+ SDL_Surface *old_tmpscreen2 = _tmpscreen2;
+
+ // Release the HW screen surface
+ SDL_FreeSurface(_hwscreen);
+
+ // Release toolbars
+ free(_toolbarLow->pixels);
+ SDL_FreeSurface(_toolbarLow);
+ if (_toolbarHigh) {
+ free(_toolbarHigh->pixels);
+ SDL_FreeSurface(_toolbarHigh);
+ }
+
+ // Setup the new GFX mode
+ if (!loadGFXMode()) {
+ unloadGFXMode();
+
+ _screen = old_screen;
+ _overlayscreen = old_overlayscreen;
+
+ return false;
+ }
+
+ // reset palette
+ SDL_SetColors(_screen, _currentPalette, 0, 256);
+
+ // Restore old screen content
+ SDL_BlitSurface(old_screen, NULL, _screen, NULL);
+ SDL_BlitSurface(old_tmpscreen, NULL, _tmpscreen, NULL);
+ if (_overlayVisible) {
+ SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
+ SDL_BlitSurface(old_tmpscreen2, NULL, _tmpscreen2, NULL);
+ }
+
+ // Free the old surfaces
+ SDL_FreeSurface(old_screen);
+ SDL_FreeSurface(old_tmpscreen);
+ SDL_FreeSurface(old_overlayscreen);
+ SDL_FreeSurface(old_tmpscreen2);
+
+ // Blit everything back to the screen
+ _toolbarHighDrawn = false;
+ internUpdateScreen();
+
+ // Make sure that a Common::EVENT_SCREEN_CHANGED gets sent later -> FIXME this crashes when no game has been loaded.
+// _modeChanged = true;
+
+ return true;
+}
+
+bool WINCESdlGraphicsManager::saveScreenshot(const char *filename) {
+ assert(_hwscreen != NULL);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+ SDL_SaveBMP(_hwscreen, filename);
+ return true;
+}
+
+void WINCESdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+ assert(_transactionMode == kTransactionNone);
+
+ if (_overlayscreen == NULL)
+ return;
+
+ // Clip the coordinates
+ if (x < 0) {
+ w += x;
+ buf -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ buf -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _videoMode.overlayWidth - x) {
+ w = _videoMode.overlayWidth - x;
+ }
+
+ if (h > _videoMode.overlayHeight - y) {
+ h = _videoMode.overlayHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ // Mark the modified region as dirty
+ addDirtyRect(x, y, w, h);
+
+ undrawMouse();
+
+ if (SDL_LockSurface(_overlayscreen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
+ do {
+ memcpy(dst, buf, w * 2);
+ dst += _overlayscreen->pitch;
+ buf += pitch;
+ } while (--h);
+
+ SDL_UnlockSurface(_overlayscreen);
+}
+
+void WINCESdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
+ assert(_transactionMode == kTransactionNone);
+ assert(src);
+
+ if (_screen == NULL)
+ return;
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ /* Clip the coordinates */
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ src -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _videoMode.screenWidth - x) {
+ w = _videoMode.screenWidth - x;
+ }
+
+ if (h > _videoMode.screenHeight - y) {
+ h = _videoMode.screenHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ addDirtyRect(x, y, w, h);
+
+ undrawMouse();
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
+
+ if (_videoMode.screenWidth == pitch && pitch == w) {
+ memcpy(dst, src, h * w);
+ } else {
+ do {
+ memcpy(dst, src, w);
+ src += pitch;
+ dst += _videoMode.screenWidth;
+ } while (--h);
+ }
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+}
+
+void WINCESdlGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
+
+ undrawMouse();
+ if (w == 0 || h == 0)
+ return;
+
+ _mouseCurState.w = w;
+ _mouseCurState.h = h;
+
+ _mouseHotspotX = hotspot_x;
+ _mouseHotspotY = hotspot_y;
+
+ _mouseKeyColor = keycolor;
+
+ free(_mouseData);
+
+ _mouseData = (byte *) malloc(w * h);
+ memcpy(_mouseData, buf, w * h);
+
+ if (w > _mouseBackupDim || h > _mouseBackupDim) {
+ // mouse has been undrawn, adjust sprite backup area
+ free(_mouseBackupOld);
+ free(_mouseBackupToolbar);
+ uint16 tmp = (w > h) ? w : h;
+ _mouseBackupOld = (byte *) malloc(tmp * tmp * 2); // can hold 8bpp (playfield) or 16bpp (overlay) data
+ _mouseBackupToolbar = (uint16 *) malloc(tmp * tmp * 2); // 16 bpp
+ _mouseBackupDim = tmp;
+ }
+}
+
+void WINCESdlGraphicsManager::adjustMouseEvent(const Common::Event &event) {
+ if (!event.synthetic) {
+ Common::Event newEvent(event);
+ newEvent.synthetic = true;
+ if (!_overlayVisible) {
+ /*
+ newEvent.mouse.x = newEvent.mouse.x * _scaleFactorXd / _scaleFactorXm;
+ newEvent.mouse.y = newEvent.mouse.y * _scaleFactorYd / _scaleFactorYm;
+ newEvent.mouse.x /= _videoMode.scaleFactor;
+ newEvent.mouse.y /= _videoMode.scaleFactor;
+ */
+ if (_videoMode.aspectRatioCorrection)
+ newEvent.mouse.y = aspect2Real(newEvent.mouse.y);
+ }
+ g_system->getEventManager()->pushEvent(newEvent);
+ }
+}
+
+void WINCESdlGraphicsManager::setMousePos(int x, int y) {
+ if (x != _mouseCurState.x || y != _mouseCurState.y) {
+ undrawMouse();
+ _mouseCurState.x = x;
+ _mouseCurState.y = y;
+ updateScreen();
+ }
+}
+
+Graphics::Surface *WINCESdlGraphicsManager::lockScreen() {
+ // Make sure mouse pointer is not painted over the playfield at the time of locking
+ undrawMouse();
+ return SdlGraphicsManager::lockScreen();
+}
+
+void WINCESdlGraphicsManager::showOverlay() {
+ assert(_transactionMode == kTransactionNone);
+
+ if (_overlayVisible)
+ return;
+
+ undrawMouse();
+ _overlayVisible = true;
+ update_scalers();
+ clearOverlay();
+}
+
+void WINCESdlGraphicsManager::hideOverlay() {
+ assert(_transactionMode == kTransactionNone);
+
+ if (!_overlayVisible)
+ return;
+
+ undrawMouse();
+ _overlayVisible = false;
+ clearOverlay();
+ _forceFull = true;
+}
+
+void WINCESdlGraphicsManager::blitCursor() {
+}
+
+void WINCESdlGraphicsManager::drawToolbarMouse(SDL_Surface *surf, bool draw) {
+
+ if (!_mouseData || !_usesEmulatedMouse)
+ return;
+
+ int x = _mouseCurState.x - _mouseHotspotX;
+ int y = _mouseCurState.y - _mouseHotspotY - _toolbarHandler.getOffset();
+ int w = _mouseCurState.w;
+ int h = _mouseCurState.h;
+ byte color;
+ const byte *src = _mouseData;
+ int width;
+
+ // clip
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ src -= y * _mouseCurState.w;
+ y = 0;
+ }
+ if (w > surf->w - x)
+ w = surf->w - x;
+ if (h > surf->h - y)
+ h = surf->h - y;
+ if (w <= 0 || h <= 0)
+ return;
+
+ if (SDL_LockSurface(surf) == -1)
+ error("SDL_LockSurface failed at internDrawToolbarMouse: %s", SDL_GetError());
+
+ uint16 *bak = _mouseBackupToolbar; // toolbar surfaces are 16bpp
+ uint16 *dst;
+ dst = (uint16 *)surf->pixels + y * surf->w + x;
+
+ if (draw) { // blit it
+ while (h > 0) {
+ width = w;
+ while (width > 0) {
+ *bak++ = *dst;
+ color = *src++;
+ if (color != _mouseKeyColor) // transparent color
+ *dst = 0xFFFF;
+ dst++;
+ width--;
+ }
+ src += _mouseCurState.w - w;
+ bak += _mouseBackupDim - w;
+ dst += surf->w - w;
+ h--;
+ }
+ } else { // restore bg
+ for (y = 0; y < h; ++y, bak += _mouseBackupDim, dst += surf->w)
+ memcpy(dst, bak, w << 1);
+ }
+
+ SDL_UnlockSurface(surf);
+}
+
+void WINCESdlGraphicsManager::warpMouse(int x, int y) {
+ if (_mouseCurState.x != x || _mouseCurState.y != y) {
+ SDL_WarpMouse(x * _scaleFactorXm / _scaleFactorXd, y * _scaleFactorYm / _scaleFactorYd);
+
+ // SDL_WarpMouse() generates a mouse movement event, so
+ // set_mouse_pos() would be called eventually. However, the
+ // cannon script in CoMI calls this function twice each time
+ // the cannon is reloaded. Unless we update the mouse position
+ // immediately the second call is ignored, causing the cannon
+ // to change its aim.
+
+ setMousePos(x, y);
+ }
+}
+
+void WINCESdlGraphicsManager::unlockScreen() {
+ SdlGraphicsManager::unlockScreen();
+}
+
+void WINCESdlGraphicsManager::internDrawMouse() {
+ if (!_mouseNeedsRedraw || !_mouseVisible || !_mouseData)
+ return;
+
+ int x = _mouseCurState.x - _mouseHotspotX;
+ int y = _mouseCurState.y - _mouseHotspotY;
+ int w = _mouseCurState.w;
+ int h = _mouseCurState.h;
+ byte color;
+ const byte *src = _mouseData; // Image representing the mouse
+ int width;
+
+ // clip the mouse rect, and adjust the src pointer accordingly
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ src -= y * _mouseCurState.w;
+ y = 0;
+ }
+
+ if (w > _videoMode.screenWidth - x)
+ w = _videoMode.screenWidth - x;
+ if (h > _videoMode.screenHeight - y)
+ h = _videoMode.screenHeight - y;
+
+ // Quick check to see if anything has to be drawn at all
+ if (w <= 0 || h <= 0)
+ return;
+
+ // Draw the mouse cursor; backup the covered area in "bak"
+ if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ // Mark as dirty
+ addDirtyRect(x, y, w, h);
+
+ if (!_overlayVisible) {
+ byte *bak = _mouseBackupOld; // Surface used to backup the area obscured by the mouse
+ byte *dst; // Surface we are drawing into
+
+ dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
+ while (h > 0) {
+ width = w;
+ while (width > 0) {
+ *bak++ = *dst;
+ color = *src++;
+ if (color != _mouseKeyColor) // transparent, don't draw
+ *dst = color;
+ dst++;
+ width--;
+ }
+ src += _mouseCurState.w - w;
+ bak += _mouseBackupDim - w;
+ dst += _videoMode.screenWidth - w;
+ h--;
+ }
+
+ } else {
+ uint16 *bak = (uint16 *)_mouseBackupOld; // Surface used to backup the area obscured by the mouse
+ byte *dst; // Surface we are drawing into
+
+ dst = (byte *)_overlayscreen->pixels + (y + 1) * _overlayscreen->pitch + (x + 1) * 2;
+ while (h > 0) {
+ width = w;
+ while (width > 0) {
+ *bak++ = *(uint16 *)dst;
+ color = *src++;
+ if (color != 0xFF) // 0xFF = transparent, don't draw
+ *(uint16 *)dst = SDL_MapRGB(_overlayscreen->format, _currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b);
+ dst += 2;
+ width--;
+ }
+ src += _mouseCurState.w - w;
+ bak += _mouseBackupDim - w;
+ dst += _overlayscreen->pitch - w * 2;
+ h--;
+ }
+ }
+
+ SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
+
+ // Finally, set the flag to indicate the mouse has been drawn
+ _mouseNeedsRedraw = false;
+}
+
+void WINCESdlGraphicsManager::undrawMouse() {
+ assert(_transactionMode == kTransactionNone);
+
+ if (_mouseNeedsRedraw)
+ return;
+
+ int old_mouse_x = _mouseCurState.x - _mouseHotspotX;
+ int old_mouse_y = _mouseCurState.y - _mouseHotspotY;
+ int old_mouse_w = _mouseCurState.w;
+ int old_mouse_h = _mouseCurState.h;
+
+ // clip the mouse rect, and adjust the src pointer accordingly
+ if (old_mouse_x < 0) {
+ old_mouse_w += old_mouse_x;
+ old_mouse_x = 0;
+ }
+ if (old_mouse_y < 0) {
+ old_mouse_h += old_mouse_y;
+ old_mouse_y = 0;
+ }
+
+ if (old_mouse_w > _videoMode.screenWidth - old_mouse_x)
+ old_mouse_w = _videoMode.screenWidth - old_mouse_x;
+ if (old_mouse_h > _videoMode.screenHeight - old_mouse_y)
+ old_mouse_h = _videoMode.screenHeight - old_mouse_y;
+
+ // Quick check to see if anything has to be drawn at all
+ if (old_mouse_w <= 0 || old_mouse_h <= 0)
+ return;
+
+
+ if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ int y;
+ if (!_overlayVisible) {
+ byte *dst, *bak = _mouseBackupOld;
+
+ // No need to do clipping here, since drawMouse() did that already
+ dst = (byte *)_screen->pixels + old_mouse_y * _videoMode.screenWidth + old_mouse_x;
+ for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _videoMode.screenWidth)
+ memcpy(dst, bak, old_mouse_w);
+ } else {
+ byte *dst;
+ uint16 *bak = (uint16 *)_mouseBackupOld;
+
+ // No need to do clipping here, since drawMouse() did that already
+ dst = (byte *)_overlayscreen->pixels + (old_mouse_y + 1) * _overlayscreen->pitch + (old_mouse_x + 1) * 2;
+ for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _overlayscreen->pitch)
+ memcpy(dst, bak, old_mouse_w << 1);
+ }
+
+ addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
+
+ SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
+
+ _mouseNeedsRedraw = true;
+}
+
+void WINCESdlGraphicsManager::drawMouse() {
+ if (!(_toolbarHandler.visible() && _mouseCurState.y >= _toolbarHandler.getOffset() && !_usesEmulatedMouse) && !_forceHideMouse)
+ internDrawMouse();
+}
+
+bool WINCESdlGraphicsManager::showMouse(bool visible) {
+ if (_mouseVisible == visible)
+ return visible;
+
+ if (visible == false)
+ undrawMouse();
+
+ bool last = _mouseVisible;
+ _mouseVisible = visible;
+ _mouseNeedsRedraw = true;
+
+ return last;
+}
+
+void WINCESdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool mouseRect) {
+
+ if (_forceFull || _paletteDirtyEnd)
+ return;
+
+ SdlGraphicsManager::addDirtyRect(x, y, w, h, false);
+}
+
+void WINCESdlGraphicsManager::swap_panel_visibility() {
+ //if (!_forcePanelInvisible && !_panelStateForced) {
+ if (_zoomDown || _zoomUp)
+ return;
+
+ if (_panelVisible) {
+ if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD)
+ _panelVisible = !_panelVisible;
+ else
+ _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
+ } else {
+ _toolbarHandler.setActive(NAME_MAIN_PANEL);
+ _panelVisible = !_panelVisible;
+ }
+ _toolbarHandler.setVisible(_panelVisible);
+ _toolbarHighDrawn = false;
+
+ if (_videoMode.screenHeight > 240)
+ addDirtyRect(0, 400, 640, 80);
+ else
+ addDirtyRect(0, 200, 320, 40);
+
+ if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
+ internUpdateScreen();
+ else {
+ update_scalers();
+ hotswapGFXMode();
+ }
+ //}
+}
+
+void WINCESdlGraphicsManager::swap_panel() {
+ _toolbarHighDrawn = false;
+ //if (!_panelStateForced) {
+ if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
+ _toolbarHandler.setActive(NAME_MAIN_PANEL);
+ else
+ _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
+
+ if (_videoMode.screenHeight > 240)
+ addDirtyRect(0, 400, 640, 80);
+ else
+ addDirtyRect(0, 200, 320, 40);
+
+ _toolbarHandler.setVisible(true);
+ if (!_panelVisible) {
+ _panelVisible = true;
+ update_scalers();
+ hotswapGFXMode();
+ }
+ //}
+}
+
+void WINCESdlGraphicsManager::swap_smartphone_keyboard() {
+ _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
+ _panelVisible = !_panelVisible;
+ _toolbarHandler.setVisible(_panelVisible);
+ if (_videoMode.screenHeight > 240)
+ addDirtyRect(0, 0, 640, 80);
+ else
+ addDirtyRect(0, 0, 320, 40);
+ internUpdateScreen();
+}
+
+void WINCESdlGraphicsManager::swap_zoom_up() {
+ if (_zoomUp) {
+ // restore visibility
+ _toolbarHandler.setVisible(_saveToolbarZoom);
+ // restore scaler
+ _scaleFactorYd = 2;
+ _scalerProc = DownscaleAllByHalf;
+ _zoomUp = false;
+ _zoomDown = false;
+ } else {
+ // only active if running on a PocketPC
+ if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
+ return;
+ if (_scalerProc == DownscaleAllByHalf) {
+ _saveToolbarZoom = _toolbarHandler.visible();
+ _toolbarHandler.setVisible(false);
+ // set zoom scaler
+ _scaleFactorYd = 1;
+ _scalerProc = DownscaleHorizByHalf;
+ }
+
+ _zoomDown = false;
+ _zoomUp = true;
+ }
+ // redraw whole screen
+ addDirtyRect(0, 0, 640, 480);
+ internUpdateScreen();
+}
+
+void WINCESdlGraphicsManager::swap_zoom_down() {
+ if (_zoomDown) {
+ // restore visibility
+ _toolbarHandler.setVisible(_saveToolbarZoom);
+ // restore scaler
+ _scaleFactorYd = 2;
+ _scalerProc = DownscaleAllByHalf;
+ _zoomDown = false;
+ _zoomUp = false;
+ } else {
+ // only active if running on a PocketPC
+ if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
+ return;
+ if (_scalerProc == DownscaleAllByHalf) {
+ _saveToolbarZoom = _toolbarHandler.visible();
+ _toolbarHandler.setVisible(false);
+ // set zoom scaler
+ _scaleFactorYd = 1;
+ _scalerProc = DownscaleHorizByHalf;
+ }
+
+ _zoomUp = false;
+ _zoomDown = true;
+ }
+ // redraw whole screen
+ addDirtyRect(0, 0, 640, 480);
+ internUpdateScreen();
+}
+
+void WINCESdlGraphicsManager::swap_mouse_visibility() {
+ _forceHideMouse = !_forceHideMouse;
+ if (_forceHideMouse)
+ undrawMouse();
+}
+
+// Smartphone actions
+void WINCESdlGraphicsManager::initZones() {
+ int i;
+
+ _currentZone = 0;
+ for (i = 0; i < TOTAL_ZONES; i++) {
+ _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2)) * _scaleFactorXm / _scaleFactorXd;
+ _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2)) * _scaleFactorYm / _scaleFactorYd;
+ }
+}
+
+void WINCESdlGraphicsManager::smartphone_rotate_display() {
+ _orientationLandscape = _newOrientation = _orientationLandscape == 1 ? 2 : 1;
+ ConfMan.setInt("landscape", _orientationLandscape);
+ ConfMan.flushToDisk();
+ hotswapGFXMode();
+}
+
+void WINCESdlGraphicsManager::create_toolbar() {
+ CEGUI::PanelKeyboard *keyboard;
+
+ // Add the keyboard
+ keyboard = new CEGUI::PanelKeyboard(PANEL_KEYBOARD);
+ _toolbarHandler.add(NAME_PANEL_KEYBOARD, *keyboard);
+ _toolbarHandler.setVisible(false);
+}
+
+WINCESdlGraphicsManager::zoneDesc WINCESdlGraphicsManager::_zones[TOTAL_ZONES] = {
+ { 0, 0, 320, 145 },
+ { 0, 145, 150, 55 },
+ { 150, 145, 170, 55 }
+};
+
+#endif /* _WIN32_WCE */
+
diff --git a/backends/graphics/wincesdl/wincesdl-graphics.h b/backends/graphics/wincesdl/wincesdl-graphics.h
new file mode 100644
index 0000000000..c8d683b158
--- /dev/null
+++ b/backends/graphics/wincesdl/wincesdl-graphics.h
@@ -0,0 +1,206 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_WINCE_SDL_H
+#define BACKENDS_GRAPHICS_WINCE_SDL_H
+
+#include "backends/graphics/sdl/sdl-graphics.h"
+#include "backends/platform/wince/CEgui/CEGUI.h"
+
+// Internal GUI names
+#define NAME_MAIN_PANEL "MainPanel"
+#define NAME_PANEL_KEYBOARD "Keyboard"
+#define NAME_ITEM_OPTIONS "Options"
+#define NAME_ITEM_SKIP "Skip"
+#define NAME_ITEM_SOUND "Sound"
+#define NAME_ITEM_ORIENTATION "Orientation"
+#define NAME_ITEM_BINDKEYS "Bindkeys"
+
+#define TOTAL_ZONES 3
+
+extern bool _hasSmartphoneResolution;
+
+class WINCESdlGraphicsManager : public SdlGraphicsManager {
+public:
+ WINCESdlGraphicsManager(SdlEventSource *sdlEventSource);
+
+ const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL);
+
+ bool hasFeature(OSystem::Feature f);
+ void setFeatureState(OSystem::Feature f, bool enable);
+ bool getFeatureState(OSystem::Feature f);
+
+ int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(int mode);
+ bool loadGFXMode();
+ void unloadGFXMode();
+ bool hotswapGFXMode();
+
+ // Overloaded from SDL backend (toolbar handling)
+ void drawMouse();
+ // Overloaded from SDL backend (new scaler handling)
+ void addDirtyRect(int x, int y, int w, int h, bool mouseRect = false);
+ // Overloaded from SDL backend (new scaler handling)
+ void warpMouse(int x, int y);
+
+ // Update the dirty areas of the screen
+ void internUpdateScreen();
+ bool saveScreenshot(const char *filename);
+
+ // Overloaded from SDL_Common (FIXME)
+ void internDrawMouse();
+ void undrawMouse();
+ bool showMouse(bool visible);
+ void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend
+ void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
+ void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME)
+ Graphics::Surface *lockScreen();
+ void unlockScreen();
+ void blitCursor();
+ void showOverlay();
+ void hideOverlay();
+ void setMousePos(int x, int y);
+
+ // GUI and action stuff
+ void swap_panel_visibility();
+ void swap_panel();
+ void swap_smartphone_keyboard();
+ void swap_zoom_up();
+ void swap_zoom_down();
+ void swap_mouse_visibility();
+
+
+//#ifdef WIN32_PLATFORM_WFSP
+ void move_cursor_up();
+ void move_cursor_down();
+ void move_cursor_left();
+ void move_cursor_right();
+
+ void retrieve_mouse_location(int &x, int &y);
+ void switch_zone();
+
+ void add_right_click(bool pushed);
+ void add_left_click(bool pushed);
+
+ void initZones();
+ void smartphone_rotate_display();
+//#endif
+
+ bool _panelInitialized; // only initialize the toolbar once
+ bool _noDoubleTapRMB; // disable double tap -> rmb click
+
+ CEGUI::ToolbarHandler _toolbarHandler;
+
+ bool _toolbarHighDrawn; // cache toolbar 640x80
+ int _newOrientation; // new orientation
+ int _orientationLandscape; // current orientation
+
+ int _scaleFactorXm; // scaler X *
+ int _scaleFactorXd; // scaler X /
+ int _scaleFactorYm; // scaler Y *
+ int _scaleFactorYd; // scaler Y /
+
+ bool _hasfocus; // scummvm has the top window
+
+ bool hasPocketPCResolution();
+ bool hasDesktopResolution();
+ bool hasSquareQVGAResolution();
+ bool hasWideResolution() const;
+
+ MousePos _mouseCurState;
+
+ bool _zoomUp; // zooming up mode
+ bool _zoomDown; // zooming down mode
+
+ bool _usesEmulatedMouse; // emulated mousemove ever been used in this session
+
+ int _mouseXZone[TOTAL_ZONES];
+ int _mouseYZone[TOTAL_ZONES];
+ int _currentZone;
+
+ // Smartphone specific variables
+ int _lastKeyPressed; // last key pressed
+ int _keyRepeat; // number of time the last key was repeated
+ int _keyRepeatTime; // elapsed time since the key was pressed
+ int _keyRepeatTrigger; // minimum time to consider the key was repeated
+
+ struct zoneDesc {
+ int x;
+ int y;
+ int width;
+ int height;
+ };
+
+ static zoneDesc _zones[TOTAL_ZONES];
+
+protected:
+ virtual void adjustMouseEvent(const Common::Event &event);
+
+private:
+ bool update_scalers();
+ void update_game_settings();
+ void drawToolbarMouse(SDL_Surface *surf, bool draw);
+
+ void create_toolbar();
+ bool _panelVisible; // panel visibility
+ bool _panelStateForced; // panel visibility forced by external call
+ String _saveActiveToolbar; // save active toolbar when forced
+
+ bool _canBeAspectScaled; // game screen size allows for aspect scaling
+
+ SDL_Rect _dirtyRectOut[NUM_DIRTY_RECT];
+ bool _scalersChanged;
+
+ bool isOzone();
+
+ bool _saveToolbarState; // save visibility when forced
+ bool _saveToolbarZoom; // save visibility when zooming
+
+ SDL_Surface *_toolbarLow; // toolbar 320x40
+ SDL_Surface *_toolbarHigh; // toolbar 640x80
+
+ // Mouse
+ int _mouseHotspotX, _mouseHotspotY;
+ byte *_mouseBackupOld;
+ uint16 *_mouseBackupToolbar;
+ uint16 _mouseBackupDim;
+
+ bool _forceHideMouse; // force invisible mouse cursor
+
+ // Smartphone specific variables
+ void loadDeviceConfigurationElement(Common::String element, int &value, int defaultValue);
+ int _repeatX; // repeat trigger for left and right cursor moves
+ int _repeatY; // repeat trigger for up and down cursor moves
+ int _stepX1; // offset for left and right cursor moves (slowest)
+ int _stepX2; // offset for left and right cursor moves (faster)
+ int _stepX3; // offset for left and right cursor moves (fastest)
+ int _stepY1; // offset for up and down cursor moves (slowest)
+ int _stepY2; // offset for up and down cursor moves (faster)
+ int _stepY3; // offset for up and down cursor moves (fastest)
+};
+
+#endif /* BACKENDS_GRAPHICS_WINCE_SDL_H */
+
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 953b088958..feed60eaef 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -44,7 +44,7 @@
#if SND_LIB_MAJOR >= 1 || SND_LIB_MINOR >= 6
#define snd_seq_flush_output(x) snd_seq_drain_output(x)
-#define snd_seq_set_client_group(x,name) /*nop */
+#define snd_seq_set_client_group(x,name) /*nop */
#define my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_DUPLEX, 0)
#else
/* SND_SEQ_OPEN_OUT causes oops on early version of ALSA */
@@ -53,9 +53,8 @@
#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
-static int check_permission(snd_seq_port_info_t *pinfo)
-{
- if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) {
+static int check_permission(snd_seq_port_info_t *pinfo) {
+ if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)) {
if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT))
return 1;
}
@@ -68,7 +67,7 @@ static int check_permission(snd_seq_port_info_t *pinfo)
#define ADDR_DELIM ".:"
-class MidiDriver_ALSA:public MidiDriver_MPU401 {
+class MidiDriver_ALSA : public MidiDriver_MPU401 {
public:
MidiDriver_ALSA(int client, int port);
int open();
@@ -83,11 +82,12 @@ private:
snd_seq_t *seq_handle;
int seq_client, seq_port;
int my_client, my_port;
+ // The volume controller value of the first MIDI channel
+ int8 _channel0Volume;
};
MidiDriver_ALSA::MidiDriver_ALSA(int client, int port)
- : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0)
-{
+ : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0), _channel0Volume(127) {
memset(&ev, 0, sizeof(ev));
}
@@ -114,7 +114,7 @@ int MidiDriver_ALSA::open() {
// with those capabilities.
my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM port 0", 0,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
if (my_port < 0) {
snd_seq_close(seq_handle);
@@ -208,24 +208,41 @@ void MidiDriver_ALSA::send(uint32 b) {
case 0xB0:
/* is it this simple ? Wow... */
snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]);
+
+ // We save the volume of the first MIDI channel here to utilize it in
+ // our workaround for broken USB-MIDI cables.
+ if (chanID == 0 && midiCmd[1] == 0x07)
+ _channel0Volume = midiCmd[2];
+
send_event(1);
break;
case 0xC0:
snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]);
send_event(0);
+
+ // Send a volume change command to work around a firmware bug in common
+ // USB-MIDI cables. If the first MIDI command in a USB packet is a
+ // Cx or Dx command, the second command in the packet is dropped
+ // somewhere.
+ send(0x07B0 | (_channel0Volume << 16));
break;
case 0xD0:
snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]);
send_event(1);
+
+ // Send a volume change command to work around a firmware bug in common
+ // USB-MIDI cables. If the first MIDI command in a USB packet is a
+ // Cx or Dx command, the second command in the packet is dropped
+ // somewhere.
+ send(0x07B0 | (_channel0Volume << 16));
break;
- case 0xE0:{
- // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4;
- // snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
- long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000;
- snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
- send_event(1);
- }
- break;
+ case 0xE0: {
+ // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4;
+ // snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
+ long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000;
+ snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
+ send_event(1);
+ } break;
default:
warning("Unknown MIDI Command: %08x", (int)b);
@@ -280,6 +297,9 @@ typedef Common::List<AlsaDevice> AlsaDevices;
AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client)
: _name(name), _type(mt), _client(client) {
+ // Make sure we do not get any trailing spaces to avoid problems when
+ // storing the name in the configuration file.
+ _name.trim();
}
Common::String AlsaDevice::getName() {
diff --git a/backends/mixer/wincesdl/wincesdl-mixer.cpp b/backends/mixer/wincesdl/wincesdl-mixer.cpp
new file mode 100644
index 0000000000..fb8a7d10c7
--- /dev/null
+++ b/backends/mixer/wincesdl/wincesdl-mixer.cpp
@@ -0,0 +1,183 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifdef _WIN32_WCE
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/config-manager.h"
+#include "backends/platform/wince/wince-sdl.h"
+#include "backends/mixer/wincesdl/wincesdl-mixer.h"
+#include "common/system.h"
+
+#ifdef USE_VORBIS
+#ifndef USE_TREMOR
+#include <vorbis/vorbisfile.h>
+#else
+#include <tremor/ivorbisfile.h>
+#endif
+#endif
+
+#define SAMPLES_PER_SEC_OLD 11025
+#define SAMPLES_PER_SEC_NEW 22050
+
+WINCESdlMixerManager::WINCESdlMixerManager() {
+
+}
+
+WINCESdlMixerManager::~WINCESdlMixerManager() {
+
+}
+
+void WINCESdlMixerManager::init() {
+ SDL_AudioSpec desired;
+ int thread_priority;
+
+ uint32 sampleRate = compute_sample_rate();
+ if (sampleRate == 0)
+ warning("OSystem_WINCE3::setupMixer called with sample rate 0 - audio will not work");
+ else if (_mixer && _mixer->getOutputRate() == sampleRate) {
+ debug(1, "Skipping sound mixer re-init: samplerate is good");
+ return;
+ }
+
+ memset(&desired, 0, sizeof(desired));
+ desired.freq = sampleRate;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = 128;
+ desired.callback = private_sound_proc;
+ desired.userdata = this;
+
+ // Create the mixer instance
+ if (_mixer == 0)
+ _mixer = new Audio::MixerImpl(g_system, sampleRate);
+
+ // Add sound thread priority
+ if (!ConfMan.hasKey("sound_thread_priority"))
+ thread_priority = THREAD_PRIORITY_NORMAL;
+ else
+ thread_priority = ConfMan.getInt("sound_thread_priority");
+
+ desired.thread_priority = thread_priority;
+
+ SDL_CloseAudio();
+ if (SDL_OpenAudio(&desired, NULL) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+ _mixer->setReady(false);
+
+ } else {
+ debug(1, "Sound opened OK, mixing at %d Hz", sampleRate);
+
+ // Re-create mixer to match the output rate
+ int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
+ int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
+ int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
+ int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
+ delete _mixer;
+ _mixer = new Audio::MixerImpl(g_system, sampleRate);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4);
+ _mixer->setReady(true);
+ SDL_PauseAudio(0);
+ }
+}
+
+void WINCESdlMixerManager::private_sound_proc(void *param, byte *buf, int len) {
+ WINCESdlMixerManager *this_ = (WINCESdlMixerManager *)param;
+ assert(this_);
+
+ if (this_->_mixer)
+ this_->_mixer->mixCallback(buf, len);
+ if (!OSystem_WINCE3::_soundMaster)
+ memset(buf, 0, len);
+}
+
+uint32 WINCESdlMixerManager::compute_sample_rate() {
+ uint32 sampleRate;
+
+ // Force at least medium quality FM synthesis for FOTAQ
+ Common::String gameid(ConfMan.get("gameid"));
+ if (gameid == "queen") {
+ if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) ||
+ (ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) {
+ ConfMan.setBool("FM_medium_quality", true);
+ ConfMan.flushToDisk();
+ }
+ }
+ // See if the output frequency is forced by the game
+ if (gameid == "ft" || gameid == "dig" || gameid == "comi" || gameid == "queen" || gameid == "sword" || gameid == "agi")
+ sampleRate = SAMPLES_PER_SEC_NEW;
+ else {
+ if (ConfMan.hasKey("high_sample_rate") && ConfMan.getBool("high_sample_rate"))
+ sampleRate = SAMPLES_PER_SEC_NEW;
+ else
+ sampleRate = SAMPLES_PER_SEC_OLD;
+ }
+
+#ifdef USE_VORBIS
+ // Modify the sample rate on the fly if OGG is involved
+ if (sampleRate == SAMPLES_PER_SEC_OLD)
+ if (checkOggHighSampleRate())
+ sampleRate = SAMPLES_PER_SEC_NEW;
+#endif
+
+ return sampleRate;
+}
+
+#ifdef USE_VORBIS
+bool WINCESdlMixerManager::checkOggHighSampleRate() {
+ char trackFile[255];
+ FILE *testFile;
+ OggVorbis_File *test_ov_file = new OggVorbis_File;
+
+ // FIXME: The following sprintf assumes that "path" is always
+ // terminated by a path separator. This is *not* true in general.
+ // This code really should check for the path separator, or even
+ // better, use the FSNode API.
+ sprintf(trackFile, "%sTrack1.ogg", ConfMan.get("path").c_str());
+ // Check if we have an OGG audio track
+ testFile = fopen(trackFile, "rb");
+ if (testFile) {
+ if (!ov_open(testFile, test_ov_file, NULL, 0)) {
+ bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050);
+ ov_clear(test_ov_file);
+ delete test_ov_file;
+ return highSampleRate;
+ }
+ }
+
+ // Do not test for OGG samples - too big and too slow anyway :)
+
+ delete test_ov_file;
+ return false;
+}
+#endif
+
+#endif
+
diff --git a/backends/mixer/wincesdl/wincesdl-mixer.h b/backends/mixer/wincesdl/wincesdl-mixer.h
new file mode 100644
index 0000000000..6c2f1efeee
--- /dev/null
+++ b/backends/mixer/wincesdl/wincesdl-mixer.h
@@ -0,0 +1,53 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_MIXER_WINCE_SDL_H
+#define BACKENDS_MIXER_WINCE_SDL_H
+
+#include "backends/mixer/sdl/sdl-mixer.h"
+
+/**
+ * SDL mixer manager for WinCE
+ */
+class WINCESdlMixerManager : public SdlMixerManager {
+public:
+ WINCESdlMixerManager();
+ virtual ~WINCESdlMixerManager();
+
+ virtual void init();
+
+private:
+
+#ifdef USE_VORBIS
+ bool checkOggHighSampleRate();
+#endif
+
+ static void private_sound_proc(void *param, byte *buf, int len);
+ uint32 compute_sample_rate();
+
+};
+
+#endif
+
diff --git a/backends/module.mk b/backends/module.mk
index 5a8a63c2a2..484f804ee0 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -12,6 +12,7 @@ MODULE_OBJS := \
events/samsungtvsdl/samsungtvsdl-events.o \
events/sdl/sdl-events.o \
events/symbiansdl/symbiansdl-events.o \
+ events/wincesdl/wincesdl-events.o \
fs/abstract-fs.o \
fs/stdiostream.o \
fs/amigaos4/amigaos4-fs-factory.o \
@@ -27,6 +28,7 @@ MODULE_OBJS := \
graphics/openglsdl/openglsdl-graphics.o \
graphics/sdl/sdl-graphics.o \
graphics/symbiansdl/symbiansdl-graphics.o \
+ graphics/wincesdl/wincesdl-graphics.o \
keymapper/action.o \
keymapper/keymap.o \
keymapper/keymapper.o \
@@ -44,6 +46,7 @@ MODULE_OBJS := \
mixer/doublebuffersdl/doublebuffersdl-mixer.o \
mixer/sdl/sdl-mixer.o \
mixer/symbiansdl/symbiansdl-mixer.o \
+ mixer/wincesdl/wincesdl-mixer.o \
mutex/sdl/sdl-mutex.o \
plugins/elf/elf-loader.o \
plugins/elf/mips-loader.o \
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index c49745f8bd..4e1373a1b1 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -25,22 +25,11 @@
#if defined(__ANDROID__)
-#include "backends/base-backend.h"
-#include "base/main.h"
-#include "graphics/surface.h"
-
-#include "backends/platform/android/android.h"
-#include "backends/platform/android/video.h"
-
-#include <jni.h>
-
-#include <string.h>
-#include <unistd.h>
-#include <pthread.h>
#include <sys/time.h>
+#include <sys/resource.h>
#include <time.h>
+#include <unistd.h>
-#include "common/archive.h"
#include "common/util.h"
#include "common/rect.h"
#include "common/queue.h"
@@ -48,14 +37,12 @@
#include "common/events.h"
#include "common/config-manager.h"
-#include "backends/fs/posix/posix-fs-factory.h"
#include "backends/keymapper/keymapper.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
-#include "backends/plugins/posix/posix-provider.h"
-#include "audio/mixer_intern.h"
-#include "backends/platform/android/asset-archive.h"
+#include "backends/platform/android/jni.h"
+#include "backends/platform/android/android.h"
const char *android_log_tag = "ScummVM";
@@ -68,7 +55,8 @@ extern "C" {
expr, file, line);
}
- void __assert2(const char *file, int line, const char *func, const char *expr) {
+ void __assert2(const char *file, int line, const char *func,
+ const char *expr) {
__android_log_assert(expr, android_log_tag,
"Assertion failure: '%s' in %s:%d (%s)",
expr, file, line, func);
@@ -106,235 +94,24 @@ void checkGlError(const char *expr, const char *file, int line) {
}
#endif
-static JavaVM *cached_jvm;
-static jfieldID FID_Event_type;
-static jfieldID FID_Event_synthetic;
-static jfieldID FID_Event_kbd_keycode;
-static jfieldID FID_Event_kbd_ascii;
-static jfieldID FID_Event_kbd_flags;
-static jfieldID FID_Event_mouse_x;
-static jfieldID FID_Event_mouse_y;
-static jfieldID FID_Event_mouse_relative;
-static jfieldID FID_ScummVM_nativeScummVM;
-static jmethodID MID_Object_wait;
-
-JNIEnv *JNU_GetEnv() {
- JNIEnv *env = 0;
-
- jint res = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_2);
-
- if (res != JNI_OK) {
- LOGE("GetEnv() failed: %d", res);
- abort();
- }
-
- return env;
-}
-
-static void JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg) {
- jclass cls = env->FindClass(name);
-
- // if cls is 0, an exception has already been thrown
- if (cls != 0)
- env->ThrowNew(cls, msg);
-
- env->DeleteLocalRef(cls);
-}
-
-// floating point. use sparingly
-template <class T>
-static inline T scalef(T in, float numerator, float denominator) {
- return static_cast<float>(in) * numerator / denominator;
-}
-
-static inline GLfixed xdiv(int numerator, int denominator) {
- assert(numerator < (1 << 16));
- return (numerator << 16) / denominator;
-}
-
-#ifdef DYNAMIC_MODULES
-class AndroidPluginProvider : public POSIXPluginProvider {
-protected:
- virtual void addCustomDirectories(Common::FSList &dirs) const;
-};
-#endif
-
-class OSystem_Android : public BaseBackend, public PaletteManager {
-private:
- // back pointer to (java) peer instance
- jobject _back_ptr;
-
- jmethodID MID_displayMessageOnOSD;
- jmethodID MID_setWindowCaption;
- jmethodID MID_initBackend;
- jmethodID MID_audioSampleRate;
- jmethodID MID_showVirtualKeyboard;
- jmethodID MID_getSysArchives;
- jmethodID MID_getPluginDirectories;
- jmethodID MID_setupScummVMSurface;
- jmethodID MID_destroyScummVMSurface;
- jmethodID MID_swapBuffers;
-
- int _screen_changeid;
- int _egl_surface_width;
- int _egl_surface_height;
-
- bool _force_redraw;
-
- // Game layer
- GLESPaletteTexture *_game_texture;
- int _shake_offset;
- Common::Rect _focus_rect;
-
- // Overlay layer
- GLES4444Texture *_overlay_texture;
- bool _show_overlay;
-
- // Mouse layer
- GLESPaletteATexture *_mouse_texture;
- Common::Point _mouse_hotspot;
- int _mouse_targetscale;
- bool _show_mouse;
- bool _use_mouse_palette;
-
- Common::Queue<Common::Event> _event_queue;
- MutexRef _event_queue_lock;
-
- bool _timer_thread_exit;
- pthread_t _timer_thread;
- static void *timerThreadFunc(void *arg);
-
- bool _enable_zoning;
- bool _virtkeybd_on;
-
- Common::SaveFileManager *_savefile;
- Audio::MixerImpl *_mixer;
- Common::TimerManager *_timer;
- FilesystemFactory *_fsFactory;
- Common::Archive *_asset_archive;
- timeval _startTime;
-
- void setupScummVMSurface();
- void destroyScummVMSurface();
- void setupKeymapper();
- void _setCursorPalette(const byte *colors, uint start, uint num);
-
-public:
- OSystem_Android(jobject am);
- virtual ~OSystem_Android();
- bool initJavaHooks(JNIEnv *env, jobject self);
-
- static OSystem_Android *fromJavaObject(JNIEnv *env, jobject obj);
- virtual void initBackend();
- void addPluginDirectories(Common::FSList &dirs) const;
- void enableZoning(bool enable) { _enable_zoning = enable; }
- void setSurfaceSize(int width, int height) {
- _egl_surface_width = width;
- _egl_surface_height = height;
- }
-
- virtual bool hasFeature(Feature f);
- virtual void setFeatureState(Feature f, bool enable);
- virtual bool getFeatureState(Feature f);
- virtual const GraphicsMode *getSupportedGraphicsModes() const;
- virtual int getDefaultGraphicsMode() const;
- bool setGraphicsMode(const char *name);
- virtual bool setGraphicsMode(int mode);
- virtual int getGraphicsMode() const;
- virtual void initSize(uint width, uint height,
- const Graphics::PixelFormat *format);
-
- virtual int getScreenChangeID() const {
- return _screen_changeid;
- }
-
- virtual int16 getHeight();
- virtual int16 getWidth();
-
- virtual PaletteManager *getPaletteManager() {
- return this;
- }
-
-protected:
- // PaletteManager API
- virtual void setPalette(const byte *colors, uint start, uint num);
- virtual void grabPalette(byte *colors, uint start, uint num);
-
-public:
- virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
- virtual void updateScreen();
- virtual Graphics::Surface *lockScreen();
- virtual void unlockScreen();
- virtual void setShakePos(int shakeOffset);
- virtual void fillScreen(uint32 col);
- virtual void setFocusRectangle(const Common::Rect& rect);
- virtual void clearFocusRectangle();
-
- virtual void showOverlay();
- virtual void hideOverlay();
- virtual void clearOverlay();
- virtual void grabOverlay(OverlayColor *buf, int pitch);
- virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- virtual int16 getOverlayHeight();
- virtual int16 getOverlayWidth();
-
- // RGBA 4444
- virtual Graphics::PixelFormat getOverlayFormat() const {
- Graphics::PixelFormat format;
-
- format.bytesPerPixel = 2;
- format.rLoss = 8 - 4;
- format.gLoss = 8 - 4;
- format.bLoss = 8 - 4;
- format.aLoss = 8 - 4;
- format.rShift = 3 * 4;
- format.gShift = 2 * 4;
- format.bShift = 1 * 4;
- format.aShift = 0 * 4;
-
- return format;
- }
-
- virtual bool showMouse(bool visible);
-
- virtual void warpMouse(int x, int y);
- virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format);
- virtual void setCursorPalette(const byte *colors, uint start, uint num);
- virtual void disableCursorPalette(bool disable);
-
- virtual bool pollEvent(Common::Event &event);
- void pushEvent(const Common::Event& event);
- virtual uint32 getMillis();
- virtual void delayMillis(uint msecs);
-
- virtual MutexRef createMutex(void);
- virtual void lockMutex(MutexRef mutex);
- virtual void unlockMutex(MutexRef mutex);
- virtual void deleteMutex(MutexRef mutex);
-
- virtual void quit();
-
- virtual void setWindowCaption(const char *caption);
- virtual void displayMessageOnOSD(const char *msg);
- virtual void showVirtualKeyboard(bool enable);
-
- virtual Common::SaveFileManager *getSavefileManager();
- virtual Audio::Mixer *getMixer();
- virtual void getTimeAndDate(TimeDate &t) const;
- virtual Common::TimerManager *getTimerManager();
- virtual FilesystemFactory *getFilesystemFactory();
- virtual void logMessage(LogMessageType::Type type, const char *message);
- virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
-};
-
-OSystem_Android::OSystem_Android(jobject am) :
- _back_ptr(0),
+OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
+ _audio_sample_rate(audio_sample_rate),
+ _audio_buffer_size(audio_buffer_size),
_screen_changeid(0),
+ _egl_surface_width(0),
+ _egl_surface_height(0),
_force_redraw(false),
_game_texture(0),
_overlay_texture(0),
_mouse_texture(0),
+ _mouse_texture_palette(0),
+ _mouse_texture_rgb(0),
+ _mouse_hotspot(),
+ _mouse_keycolor(0),
_use_mouse_palette(false),
+ _fullscreen(false),
+ _graphicsMode(0),
+ _ar_correction(false),
_show_mouse(false),
_show_overlay(false),
_enable_zoning(false),
@@ -342,876 +119,288 @@ OSystem_Android::OSystem_Android(jobject am) :
_mixer(0),
_timer(0),
_fsFactory(new POSIXFilesystemFactory()),
- _asset_archive(new AndroidAssetArchive(am)),
_shake_offset(0),
- _event_queue_lock(createMutex()) {
+ _event_queue_lock(createMutex()),
+ _touch_pt_down(),
+ _touch_pt_dt(),
+ _eventScaleX(100),
+ _eventScaleY(100),
+ // TODO put these values in some option dlg?
+ _touchpad_mode(true),
+ _touchpad_scale(50),
+ _dpad_scale(4),
+ _trackball_scale(2) {
}
OSystem_Android::~OSystem_Android() {
ENTER();
- delete _game_texture;
- delete _overlay_texture;
- delete _mouse_texture;
-
- destroyScummVMSurface();
-
- JNIEnv *env = JNU_GetEnv();
- //env->DeleteWeakGlobalRef(_back_ptr);
- env->DeleteGlobalRef(_back_ptr);
-
delete _savefile;
- delete _mixer;
delete _timer;
+ delete _mixer;
delete _fsFactory;
- delete _asset_archive;
deleteMutex(_event_queue_lock);
}
-OSystem_Android *OSystem_Android::fromJavaObject(JNIEnv *env, jobject obj) {
- jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM);
- return (OSystem_Android *)peer;
-}
-
-bool OSystem_Android::initJavaHooks(JNIEnv *env, jobject self) {
- // weak global ref to allow class to be unloaded
- // ... except dalvik doesn't implement NewWeakGlobalRef (yet)
- //_back_ptr = env->NewWeakGlobalRef(self);
- _back_ptr = env->NewGlobalRef(self);
-
- jclass cls = env->GetObjectClass(_back_ptr);
-
-#define FIND_METHOD(name, signature) do { \
- MID_ ## name = env->GetMethodID(cls, #name, signature); \
- if (MID_ ## name == 0) \
- return false; \
- } while (0)
-
- FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V");
- FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V");
- FIND_METHOD(initBackend, "()V");
- FIND_METHOD(audioSampleRate, "()I");
- FIND_METHOD(showVirtualKeyboard, "(Z)V");
- FIND_METHOD(getSysArchives, "()[Ljava/lang/String;");
- FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;");
- FIND_METHOD(setupScummVMSurface, "()V");
- FIND_METHOD(destroyScummVMSurface, "()V");
- FIND_METHOD(swapBuffers, "()Z");
-
-#undef FIND_METHOD
-
- return true;
-}
-
-static void ScummVM_create(JNIEnv *env, jobject self, jobject am) {
- OSystem_Android *cpp_obj = new OSystem_Android(am);
-
- // Exception already thrown by initJavaHooks?
- if (!cpp_obj->initJavaHooks(env, self))
- return;
-
- env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj);
-
-#ifdef DYNAMIC_MODULES
- PluginManager::instance().addPluginProvider(new AndroidPluginProvider());
-#endif
-}
-
-static void ScummVM_nativeDestroy(JNIEnv *env, jobject self) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- delete cpp_obj;
-}
-
-static void ScummVM_audioMixCallback(JNIEnv *env, jobject self,
- jbyteArray jbuf) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- jsize len = env->GetArrayLength(jbuf);
- jbyte *buf = env->GetByteArrayElements(jbuf, 0);
-
- if (buf == 0) {
- warning("Unable to get Java audio byte array. Skipping");
- return;
- }
-
- Audio::MixerImpl *mixer =
- static_cast<Audio::MixerImpl *>(cpp_obj->getMixer());
- assert(mixer);
- mixer->mixCallback(reinterpret_cast<byte *>(buf), len);
-
- env->ReleaseByteArrayElements(jbuf, buf, 0);
-}
-
-static void ScummVM_setConfManInt(JNIEnv *env, jclass cls,
- jstring key_obj, jint value) {
- ENTER("%p, %d", key_obj, (int)value);
-
- const char *key = env->GetStringUTFChars(key_obj, 0);
-
- if (key == 0)
- return;
-
- ConfMan.setInt(key, value);
-
- env->ReleaseStringUTFChars(key_obj, key);
-}
-
-static void ScummVM_setConfManString(JNIEnv *env, jclass cls, jstring key_obj,
- jstring value_obj) {
- ENTER("%p, %p", key_obj, value_obj);
-
- const char *key = env->GetStringUTFChars(key_obj, 0);
-
- if (key == 0)
- return;
-
- const char *value = env->GetStringUTFChars(value_obj, 0);
-
- if (value == 0) {
- env->ReleaseStringUTFChars(key_obj, key);
- return;
- }
-
- ConfMan.set(key, value);
-
- env->ReleaseStringUTFChars(value_obj, value);
- env->ReleaseStringUTFChars(key_obj, key);
-}
-
void *OSystem_Android::timerThreadFunc(void *arg) {
OSystem_Android *system = (OSystem_Android *)arg;
DefaultTimerManager *timer = (DefaultTimerManager *)(system->_timer);
- JNIEnv *env = 0;
- jint res = cached_jvm->AttachCurrentThread(&env, 0);
+ // renice this thread to boost the audio thread
+ if (setpriority(PRIO_PROCESS, 0, 19) < 0)
+ LOGW("couldn't renice the timer thread");
- if (res != JNI_OK) {
- LOGE("AttachCurrentThread() failed: %d", res);
- abort();
- }
+ JNI::attachThread();
struct timespec tv;
tv.tv_sec = 0;
tv.tv_nsec = 100 * 1000 * 1000; // 100ms
while (!system->_timer_thread_exit) {
+ if (JNI::pause) {
+ LOGD("timer thread going to sleep");
+ sem_wait(&JNI::pause_sem);
+ LOGD("timer thread woke up");
+ }
+
timer->handler();
nanosleep(&tv, 0);
}
- res = cached_jvm->DetachCurrentThread();
-
- if (res != JNI_OK) {
- LOGE("DetachCurrentThread() failed: %d", res);
- abort();
- }
+ JNI::detachThread();
return 0;
}
-void OSystem_Android::initBackend() {
- ENTER();
-
- JNIEnv *env = JNU_GetEnv();
-
- ConfMan.setInt("autosave_period", 0);
- ConfMan.setInt("FM_medium_quality", true);
-
- // must happen before creating TimerManager to avoid race in
- // creating EventManager
- setupKeymapper();
-
- // BUG: "transient" ConfMan settings get nuked by the options
- // screen. Passing the savepath in this way makes it stick
- // (via ConfMan.registerDefault)
- _savefile = new DefaultSaveFileManager(ConfMan.get("savepath"));
- _timer = new DefaultTimerManager();
-
- gettimeofday(&_startTime, 0);
-
- jint sample_rate = env->CallIntMethod(_back_ptr, MID_audioSampleRate);
- if (env->ExceptionCheck()) {
- warning("Error finding audio sample rate - assuming 11025HZ");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
-
- sample_rate = 11025;
- }
-
- _mixer = new Audio::MixerImpl(this, sample_rate);
- _mixer->setReady(true);
-
- env->CallVoidMethod(_back_ptr, MID_initBackend);
+void *OSystem_Android::audioThreadFunc(void *arg) {
+ JNI::attachThread();
- if (env->ExceptionCheck()) {
- error("Error in Java initBackend");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
- _timer_thread_exit = false;
- pthread_create(&_timer_thread, 0, timerThreadFunc, this);
+ OSystem_Android *system = (OSystem_Android *)arg;
+ Audio::MixerImpl *mixer = system->_mixer;
- OSystem::initBackend();
+ uint buf_size = system->_audio_buffer_size;
- setupScummVMSurface();
-}
+ JNIEnv *env = JNI::getEnv();
-void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const {
- ENTER();
+ jbyteArray bufa = env->NewByteArray(buf_size);
- JNIEnv *env = JNU_GetEnv();
+ bool paused = true;
- jobjectArray array =
- (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getPluginDirectories);
- if (env->ExceptionCheck()) {
- warning("Error finding plugin directories");
+ byte *buf;
+ int offset, left, written;
+ int samples, i;
- env->ExceptionDescribe();
- env->ExceptionClear();
+ struct timespec tv_delay;
+ tv_delay.tv_sec = 0;
+ tv_delay.tv_nsec = 20 * 1000 * 1000;
- return;
- }
+ uint msecs_full = buf_size * 1000 / (mixer->getOutputRate() * 2 * 2);
- jsize size = env->GetArrayLength(array);
- for (jsize i = 0; i < size; ++i) {
- jstring path_obj = (jstring)env->GetObjectArrayElement(array, i);
+ struct timespec tv_full;
+ tv_full.tv_sec = 0;
+ tv_full.tv_nsec = msecs_full * 1000 * 1000;
- if (path_obj == 0)
- continue;
+ bool silence;
+ uint silence_count = 33;
- const char *path = env->GetStringUTFChars(path_obj, 0);
- if (path == 0) {
- warning("Error getting string characters from plugin directory");
+ while (!system->_audio_thread_exit) {
+ if (JNI::pause) {
+ JNI::setAudioStop();
- env->ExceptionClear();
- env->DeleteLocalRef(path_obj);
+ paused = true;
+ silence_count = 33;
- continue;
+ LOGD("audio thread going to sleep");
+ sem_wait(&JNI::pause_sem);
+ LOGD("audio thread woke up");
}
- dirs.push_back(Common::FSNode(path));
-
- env->ReleaseStringUTFChars(path_obj, path);
- env->DeleteLocalRef(path_obj);
- }
-}
-
-bool OSystem_Android::hasFeature(Feature f) {
- return (f == kFeatureCursorHasPalette ||
- f == kFeatureVirtualKeyboard ||
- f == kFeatureOverlaySupportsAlpha);
-}
-
-void OSystem_Android::setFeatureState(Feature f, bool enable) {
- ENTER("%d, %d", f, enable);
-
- switch (f) {
- case kFeatureVirtualKeyboard:
- _virtkeybd_on = enable;
- showVirtualKeyboard(enable);
- break;
- default:
- break;
- }
-}
-
-bool OSystem_Android::getFeatureState(Feature f) {
- switch (f) {
- case kFeatureVirtualKeyboard:
- return _virtkeybd_on;
- default:
- return false;
- }
-}
-
-const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
- static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
- { "default", "Default", 1 },
- { 0, 0, 0 },
- };
-
- return s_supportedGraphicsModes;
-}
-
-
-int OSystem_Android::getDefaultGraphicsMode() const {
- return 1;
-}
-
-bool OSystem_Android::setGraphicsMode(const char *mode) {
- ENTER("%s", mode);
- return true;
-}
-
-bool OSystem_Android::setGraphicsMode(int mode) {
- ENTER("%d", mode);
- return true;
-}
-
-int OSystem_Android::getGraphicsMode() const {
- return 1;
-}
-
-void OSystem_Android::setupScummVMSurface() {
- ENTER();
-
- JNIEnv *env = JNU_GetEnv();
- env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface);
-
- if (env->ExceptionCheck())
- return;
-
- // EGL set up with a new surface. Initialise OpenGLES context.
- GLESTexture::initGLExtensions();
-
- // Turn off anything that looks like 3D ;)
- GLCALL(glDisable(GL_CULL_FACE));
- GLCALL(glDisable(GL_DEPTH_TEST));
- GLCALL(glDisable(GL_LIGHTING));
- GLCALL(glDisable(GL_FOG));
- GLCALL(glDisable(GL_DITHER));
-
- GLCALL(glShadeModel(GL_FLAT));
- GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
-
- GLCALL(glEnable(GL_BLEND));
- GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
-
- GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
- GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
-
- GLCALL(glEnable(GL_TEXTURE_2D));
-
- if (!_game_texture)
- _game_texture = new GLESPaletteTexture();
- else
- _game_texture->reinitGL();
-
- if (!_overlay_texture)
- _overlay_texture = new GLES4444Texture();
- else
- _overlay_texture->reinitGL();
-
- if (!_mouse_texture)
- _mouse_texture = new GLESPaletteATexture();
- else
- _mouse_texture->reinitGL();
-
- GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
-
- GLCALL(glMatrixMode(GL_PROJECTION));
- GLCALL(glLoadIdentity());
- GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1));
- GLCALL(glMatrixMode(GL_MODELVIEW));
- GLCALL(glLoadIdentity());
-
- clearFocusRectangle();
-}
-
-void OSystem_Android::destroyScummVMSurface() {
- JNIEnv *env = JNU_GetEnv();
- env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface);
- // Can't use OpenGLES functions after this
-}
-
-void OSystem_Android::initSize(uint width, uint height,
- const Graphics::PixelFormat *format) {
- ENTER("%d, %d, %p", width, height, format);
-
- _game_texture->allocBuffer(width, height);
-
- // Cap at 320x200 or the ScummVM themes abort :/
- GLuint overlay_width = MIN(_egl_surface_width, 320);
- GLuint overlay_height = MIN(_egl_surface_height, 200);
- _overlay_texture->allocBuffer(overlay_width, overlay_height);
-
- // Don't know mouse size yet - it gets reallocated in
- // setMouseCursor. We need the palette allocated before
- // setMouseCursor however, so just take a guess at the desired
- // size (it's small).
- _mouse_texture->allocBuffer(20, 20);
-}
-
-int16 OSystem_Android::getHeight() {
- return _game_texture->height();
-}
-
-int16 OSystem_Android::getWidth() {
- return _game_texture->width();
-}
-
-void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
+ buf = (byte *)env->GetPrimitiveArrayCritical(bufa, 0);
+ assert(buf);
- if (!_use_mouse_palette)
- _setCursorPalette(colors, start, num);
+ samples = mixer->mixCallback(buf, buf_size);
- memcpy(_game_texture->palette() + start * 3, colors, num * 3);
-}
-
-void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
- memcpy(colors, _game_texture->palette_const() + start * 3, num * 3);
-}
-
-void OSystem_Android::copyRectToScreen(const byte *buf, int pitch,
- int x, int y, int w, int h) {
- ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
-
- _game_texture->updateBuffer(x, y, w, h, buf, pitch);
-}
-
-void OSystem_Android::updateScreen() {
- //ENTER();
-
- if (!_force_redraw &&
- !_game_texture->dirty() &&
- !_overlay_texture->dirty() &&
- !_mouse_texture->dirty())
- return;
-
- _force_redraw = false;
-
- GLCALL(glPushMatrix());
-
- if (_shake_offset != 0 ||
- (!_focus_rect.isEmpty() &&
- !Common::Rect(_game_texture->width(),
- _game_texture->height()).contains(_focus_rect))) {
- // These are the only cases where _game_texture doesn't
- // cover the entire screen.
- GLCALL(glClearColorx(0, 0, 0, 1 << 16));
- GLCALL(glClear(GL_COLOR_BUFFER_BIT));
-
- // Move everything up by _shake_offset (game) pixels
- GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
- }
-
- if (_focus_rect.isEmpty()) {
- _game_texture->drawTexture(0, 0,
- _egl_surface_width, _egl_surface_height);
- } else {
- GLCALL(glPushMatrix());
- GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
- xdiv(_egl_surface_height, _focus_rect.height()),
- 1 << 16));
- GLCALL(glTranslatex(-_focus_rect.left << 16,
- -_focus_rect.top << 16, 0));
- GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width),
- xdiv(_game_texture->height(), _egl_surface_height),
- 1 << 16));
-
- _game_texture->drawTexture(0, 0,
- _egl_surface_width, _egl_surface_height);
- GLCALL(glPopMatrix());
- }
-
- int cs = _mouse_targetscale;
-
- if (_show_overlay) {
- // ugly, but the modern theme sets a wacko factor, only god knows why
- cs = 1;
-
- GLCALL(_overlay_texture->drawTexture(0, 0,
- _egl_surface_width,
- _egl_surface_height));
- }
-
- if (_show_mouse) {
- GLCALL(glPushMatrix());
+ silence = samples < 1;
- // Scale up ScummVM -> OpenGL (pixel) coordinates
- int texwidth, texheight;
+ // looks stupid, and it is, but currently there's no way to detect
+ // silence-only buffers from the mixer
+ if (!silence) {
+ silence = true;
- if (_show_overlay) {
- texwidth = getOverlayWidth();
- texheight = getOverlayHeight();
- } else {
- texwidth = getWidth();
- texheight = getHeight();
+ for (i = 0; i < samples; i += 2)
+ // SID streams constant crap
+ if (READ_UINT16(buf + i) > 32) {
+ silence = false;
+ break;
+ }
}
- GLCALL(glScalex(xdiv(_egl_surface_width, texwidth),
- xdiv(_egl_surface_height, texheight),
- 1 << 16));
-
- GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16,
- (-_mouse_hotspot.y * cs) << 16,
- 0));
-
- // Note the extra half texel to position the mouse in
- // the middle of the x,y square:
- const Common::Point& mouse = getEventManager()->getMousePos();
- GLCALL(glTranslatex((mouse.x << 16) | 1 << 15,
- (mouse.y << 16) | 1 << 15, 0));
-
- GLCALL(glScalex(cs << 16, cs << 16, 1 << 16));
-
- _mouse_texture->drawTexture();
+ env->ReleasePrimitiveArrayCritical(bufa, buf, 0);
- GLCALL(glPopMatrix());
- }
-
- GLCALL(glPopMatrix());
+ if (silence) {
+ if (!paused)
+ silence_count++;
- JNIEnv *env = JNU_GetEnv();
- if (!env->CallBooleanMethod(_back_ptr, MID_swapBuffers)) {
- // Context lost -> need to reinit GL
- destroyScummVMSurface();
- setupScummVMSurface();
- }
-}
+ // only pause after a while to prevent toggle mania
+ if (silence_count > 32) {
+ if (!paused) {
+ LOGD("AudioTrack pause");
-Graphics::Surface *OSystem_Android::lockScreen() {
- ENTER();
+ JNI::setAudioPause();
+ paused = true;
+ }
- Graphics::Surface *surface = _game_texture->surface();
- assert(surface->pixels);
+ nanosleep(&tv_full, 0);
- return surface;
-}
+ continue;
+ }
+ }
-void OSystem_Android::unlockScreen() {
- ENTER();
+ if (paused) {
+ LOGD("AudioTrack play");
- assert(_game_texture->dirty());
-}
+ JNI::setAudioPlay();
+ paused = false;
-void OSystem_Android::setShakePos(int shake_offset) {
- ENTER("%d", shake_offset);
+ silence_count = 0;
+ }
- if (_shake_offset != shake_offset) {
- _shake_offset = shake_offset;
- _force_redraw = true;
- }
-}
+ offset = 0;
+ left = buf_size;
+ written = 0;
-void OSystem_Android::fillScreen(uint32 col) {
- ENTER("%u", col);
+ while (left > 0) {
+ written = JNI::writeAudio(env, bufa, offset, left);
- assert(col < 256);
- _game_texture->fillBuffer(col);
-}
+ if (written < 0) {
+ LOGE("AudioTrack error: %d", written);
+ break;
+ }
-void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {
- ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom);
+ // buffer full
+ if (written < left)
+ nanosleep(&tv_delay, 0);
- if (_enable_zoning) {
- _focus_rect = rect;
- _force_redraw = true;
- }
-}
+ offset += written;
+ left -= written;
+ }
-void OSystem_Android::clearFocusRectangle() {
- ENTER();
+ if (written < 0)
+ break;
- if (_enable_zoning) {
- _focus_rect = Common::Rect();
- _force_redraw = true;
+ // prepare the next buffer, and run into the blocking AudioTrack.write
}
-}
-void OSystem_Android::showOverlay() {
- ENTER();
+ JNI::setAudioStop();
- _show_overlay = true;
- _force_redraw = true;
-}
+ env->DeleteLocalRef(bufa);
-void OSystem_Android::hideOverlay() {
- ENTER();
+ JNI::detachThread();
- _show_overlay = false;
- _force_redraw = true;
+ return 0;
}
-void OSystem_Android::clearOverlay() {
+void OSystem_Android::initBackend() {
ENTER();
- _overlay_texture->fillBuffer(0);
-
- // Shouldn't need this, but works around a 'blank screen' bug on Nexus1
- updateScreen();
-}
-
-void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {
- ENTER("%p, %d", buf, pitch);
-
- // We support overlay alpha blending, so the pixel data here
- // shouldn't actually be used. Let's fill it with zeros, I'm sure
- // it will be fine...
- const Graphics::Surface *surface = _overlay_texture->surface_const();
- assert(surface->bytesPerPixel == sizeof(buf[0]));
-
- int h = surface->h;
-
- do {
- memset(buf, 0, surface->w * sizeof(buf[0]));
-
- // This 'pitch' is pixels not bytes
- buf += pitch;
- } while (--h);
-}
-
-void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch,
- int x, int y, int w, int h) {
- ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
-
- const Graphics::Surface *surface = _overlay_texture->surface_const();
- assert(surface->bytesPerPixel == sizeof(buf[0]));
-
- // This 'pitch' is pixels not bytes
- _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0]));
-
- // Shouldn't need this, but works around a 'blank screen' bug on Nexus1?
- updateScreen();
-}
+ _main_thread = pthread_self();
-int16 OSystem_Android::getOverlayHeight() {
- return _overlay_texture->height();
-}
-
-int16 OSystem_Android::getOverlayWidth() {
- return _overlay_texture->width();
-}
-
-bool OSystem_Android::showMouse(bool visible) {
- ENTER("%d", visible);
-
- _show_mouse = visible;
-
- return true;
-}
-
-void OSystem_Android::warpMouse(int x, int y) {
- ENTER("%d, %d", x, y);
-
- // We use only the eventmanager's idea of the current mouse
- // position, so there is nothing extra to do here.
-}
-
-void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
- int hotspotX, int hotspotY,
- uint32 keycolor, int cursorTargetScale,
- const Graphics::PixelFormat *format) {
- ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
- keycolor, cursorTargetScale, format);
+ ConfMan.registerDefault("fullscreen", true);
+ ConfMan.registerDefault("aspect_ratio", true);
- assert(keycolor < 256);
+ ConfMan.setInt("autosave_period", 0);
+ ConfMan.setBool("FM_high_quality", false);
+ ConfMan.setBool("FM_medium_quality", true);
- _mouse_texture->allocBuffer(w, h);
+ // TODO hackity hack
+ if (ConfMan.hasKey("multi_midi"))
+ _touchpad_mode = !ConfMan.getBool("multi_midi");
- // Update palette alpha based on keycolor
- byte *palette = _mouse_texture->palette();
- int i = 256;
+ // must happen before creating TimerManager to avoid race in
+ // creating EventManager
+ setupKeymapper();
- do {
- palette[3] = 0xff;
- palette += 4;
- } while (--i);
+ // BUG: "transient" ConfMan settings get nuked by the options
+ // screen. Passing the savepath in this way makes it stick
+ // (via ConfMan.registerDefault)
+ _savefile = new DefaultSaveFileManager(ConfMan.get("savepath"));
+ _timer = new DefaultTimerManager();
- palette = _mouse_texture->palette();
- palette[keycolor * 4 + 3] = 0x00;
+ gettimeofday(&_startTime, 0);
- _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
+ _mixer = new Audio::MixerImpl(this, _audio_sample_rate);
+ _mixer->setReady(true);
- _mouse_hotspot = Common::Point(hotspotX, hotspotY);
- _mouse_targetscale = cursorTargetScale;
-}
+ _timer_thread_exit = false;
+ pthread_create(&_timer_thread, 0, timerThreadFunc, this);
-void OSystem_Android::_setCursorPalette(const byte *colors,
- uint start, uint num) {
- byte *palette = _mouse_texture->palette() + start * 4;
+ _audio_thread_exit = false;
+ pthread_create(&_audio_thread, 0, audioThreadFunc, this);
- do {
- for (int i = 0; i < 3; ++i)
- palette[i] = colors[i];
+ initSurface();
+ initViewport();
- // Leave alpha untouched to preserve keycolor
+ _game_texture = new GLESFakePalette565Texture();
+ _overlay_texture = new GLES4444Texture();
+ _mouse_texture_palette = new GLESPalette5551Texture();
+ _mouse_texture = _mouse_texture_palette;
- palette += 4;
- colors += 3;
- } while (--num);
-}
+ initOverlay();
-void OSystem_Android::setCursorPalette(const byte *colors,
- uint start, uint num) {
- ENTER("%p, %u, %u", colors, start, num);
+ // renice this thread to boost the audio thread
+ if (setpriority(PRIO_PROCESS, 0, 19) < 0)
+ warning("couldn't renice the main thread");
- _setCursorPalette(colors, start, num);
- _use_mouse_palette = true;
+ JNI::setReadyForEvents(true);
}
-void OSystem_Android::disableCursorPalette(bool disable) {
- ENTER("%d", disable);
+void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const {
+ ENTER();
- _use_mouse_palette = !disable;
+ JNI::getPluginDirectories(dirs);
}
-void OSystem_Android::setupKeymapper() {
-#ifdef ENABLE_KEYMAPPER
- using namespace Common;
-
- Keymapper *mapper = getEventManager()->getKeymapper();
-
- HardwareKeySet *keySet = new HardwareKeySet();
-
- keySet->addHardwareKey(
- new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)",
- kTriggerLeftKeyType,
- kVirtualKeyboardActionType));
-
- mapper->registerHardwareKeySet(keySet);
-
- Keymap *globalMap = new Keymap("global");
- Action *act;
-
- act = new Action(globalMap, "VIRT", "Display keyboard",
- kVirtualKeyboardActionType);
- act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0));
-
- mapper->addGlobalKeymap(globalMap);
-
- mapper->pushKeymap("global");
-#endif
+bool OSystem_Android::hasFeature(Feature f) {
+ return (f == kFeatureFullscreenMode ||
+ f == kFeatureAspectRatioCorrection ||
+ f == kFeatureCursorHasPalette ||
+ f == kFeatureVirtualKeyboard ||
+ f == kFeatureOverlaySupportsAlpha);
}
-bool OSystem_Android::pollEvent(Common::Event &event) {
- //ENTER();
-
- lockMutex(_event_queue_lock);
-
- if (_event_queue.empty()) {
- unlockMutex(_event_queue_lock);
- return false;
- }
+void OSystem_Android::setFeatureState(Feature f, bool enable) {
+ ENTER("%d, %d", f, enable);
- event = _event_queue.pop();
- unlockMutex(_event_queue_lock);
-
- switch (event.type) {
- case Common::EVENT_MOUSEMOVE:
- // TODO: only dirty/redraw move bounds
- _force_redraw = true;
- // fallthrough
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_RBUTTONUP:
- case Common::EVENT_WHEELUP:
- case Common::EVENT_WHEELDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_MBUTTONUP: {
- // relative mouse hack
- if (event.kbd.flags == 1) {
- // Relative (trackball) mouse hack.
- const Common::Point& mouse_pos =
- getEventManager()->getMousePos();
- event.mouse.x += mouse_pos.x;
- event.mouse.y += mouse_pos.y;
- event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ?
- getOverlayWidth() : getWidth());
- event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ?
- getOverlayHeight() : getHeight());
- } else {
- // Touchscreen events need to be converted
- // from device to game coords first.
- const GLESTexture *tex = _show_overlay
- ? static_cast<GLESTexture *>(_overlay_texture)
- : static_cast<GLESTexture *>(_game_texture);
- event.mouse.x = scalef(event.mouse.x, tex->width(),
- _egl_surface_width);
- event.mouse.y = scalef(event.mouse.y, tex->height(),
- _egl_surface_height);
- event.mouse.x -= _shake_offset;
- }
+ switch (f) {
+ case kFeatureFullscreenMode:
+ _fullscreen = enable;
+ updateScreenRect();
break;
- }
- case Common::EVENT_SCREEN_CHANGED:
- debug("EVENT_SCREEN_CHANGED");
- _screen_changeid++;
- destroyScummVMSurface();
- setupScummVMSurface();
+ case kFeatureAspectRatioCorrection:
+ _ar_correction = enable;
+ updateScreenRect();
+ break;
+ case kFeatureVirtualKeyboard:
+ _virtkeybd_on = enable;
+ showVirtualKeyboard(enable);
break;
default:
break;
}
-
- return true;
-}
-
-void OSystem_Android::pushEvent(const Common::Event& event) {
- lockMutex(_event_queue_lock);
-
- // Try to combine multiple queued mouse move events
- if (event.type == Common::EVENT_MOUSEMOVE &&
- !_event_queue.empty() &&
- _event_queue.back().type == Common::EVENT_MOUSEMOVE) {
- Common::Event tail = _event_queue.back();
- if (event.kbd.flags) {
- // relative movement hack
- tail.mouse.x += event.mouse.x;
- tail.mouse.y += event.mouse.y;
- } else {
- // absolute position, clear relative flag
- tail.kbd.flags = 0;
- tail.mouse.x = event.mouse.x;
- tail.mouse.y = event.mouse.y;
- }
- } else {
- _event_queue.push(event);
- }
-
- unlockMutex(_event_queue_lock);
}
-static void ScummVM_pushEvent(JNIEnv *env, jobject self, jobject java_event) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
-
- Common::Event event;
- event.type = (Common::EventType)env->GetIntField(java_event,
- FID_Event_type);
-
- event.synthetic =
- env->GetBooleanField(java_event, FID_Event_synthetic);
-
- switch (event.type) {
- case Common::EVENT_KEYDOWN:
- case Common::EVENT_KEYUP:
- event.kbd.keycode = (Common::KeyCode)env->GetIntField(
- java_event, FID_Event_kbd_keycode);
- event.kbd.ascii = static_cast<int>(env->GetIntField(
- java_event, FID_Event_kbd_ascii));
- event.kbd.flags = static_cast<int>(env->GetIntField(
- java_event, FID_Event_kbd_flags));
- break;
- case Common::EVENT_MOUSEMOVE:
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_RBUTTONUP:
- case Common::EVENT_WHEELUP:
- case Common::EVENT_WHEELDOWN:
- case Common::EVENT_MBUTTONDOWN:
- case Common::EVENT_MBUTTONUP:
- event.mouse.x =
- env->GetIntField(java_event, FID_Event_mouse_x);
- event.mouse.y =
- env->GetIntField(java_event, FID_Event_mouse_y);
- // This is a terrible hack. We stash "relativeness"
- // in the kbd.flags field until pollEvent() can work
- // it out.
- event.kbd.flags = env->GetBooleanField(
- java_event, FID_Event_mouse_relative) ? 1 : 0;
- break;
+bool OSystem_Android::getFeatureState(Feature f) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return _fullscreen;
+ case kFeatureAspectRatioCorrection:
+ return _ar_correction;
+ case kFeatureVirtualKeyboard:
+ return _virtkeybd_on;
default:
- break;
+ return false;
}
-
- cpp_obj->pushEvent(event);
}
uint32 OSystem_Android::getMillis() {
@@ -1219,7 +408,7 @@ uint32 OSystem_Android::getMillis() {
gettimeofday(&curTime, 0);
- return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \
+ return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) +
((curTime.tv_usec - _startTime.tv_usec) / 1000));
}
@@ -1229,6 +418,7 @@ void OSystem_Android::delayMillis(uint msecs) {
OSystem::MutexRef OSystem_Android::createMutex() {
pthread_mutexattr_t attr;
+
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
@@ -1267,58 +457,38 @@ void OSystem_Android::deleteMutex(MutexRef mutex) {
void OSystem_Android::quit() {
ENTER();
+ JNI::setReadyForEvents(false);
+
+ _audio_thread_exit = true;
+ pthread_join(_audio_thread, 0);
+
_timer_thread_exit = true;
pthread_join(_timer_thread, 0);
+
+ delete _game_texture;
+ delete _overlay_texture;
+ delete _mouse_texture_palette;
+ delete _mouse_texture_rgb;
+
+ deinitSurface();
}
void OSystem_Android::setWindowCaption(const char *caption) {
ENTER("%s", caption);
- JNIEnv *env = JNU_GetEnv();
- jstring java_caption = env->NewStringUTF(caption);
- env->CallVoidMethod(_back_ptr, MID_setWindowCaption, java_caption);
-
- if (env->ExceptionCheck()) {
- warning("Failed to set window caption");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
- env->DeleteLocalRef(java_caption);
+ JNI::setWindowCaption(caption);
}
void OSystem_Android::displayMessageOnOSD(const char *msg) {
ENTER("%s", msg);
- JNIEnv *env = JNU_GetEnv();
- jstring java_msg = env->NewStringUTF(msg);
-
- env->CallVoidMethod(_back_ptr, MID_displayMessageOnOSD, java_msg);
-
- if (env->ExceptionCheck()) {
- warning("Failed to display OSD message");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
-
- env->DeleteLocalRef(java_msg);
+ JNI::displayMessageOnOSD(msg);
}
void OSystem_Android::showVirtualKeyboard(bool enable) {
ENTER("%d", enable);
- JNIEnv *env = JNU_GetEnv();
-
- env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable);
-
- if (env->ExceptionCheck()) {
- error("Error trying to show virtual keyboard");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
+ JNI::showVirtualKeyboard(enable);
}
Common::SaveFileManager *OSystem_Android::getSavefileManager() {
@@ -1355,37 +525,13 @@ FilesystemFactory *OSystem_Android::getFilesystemFactory() {
void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s,
int priority) {
- s.add("ASSET", _asset_archive, priority, false);
-
- JNIEnv *env = JNU_GetEnv();
-
- jobjectArray array =
- (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getSysArchives);
-
- if (env->ExceptionCheck()) {
- warning("Error finding system archive path");
-
- env->ExceptionDescribe();
- env->ExceptionClear();
-
- return;
- }
-
- jsize size = env->GetArrayLength(array);
- for (jsize i = 0; i < size; ++i) {
- jstring path_obj = (jstring)env->GetObjectArrayElement(array, i);
- const char *path = env->GetStringUTFChars(path_obj, 0);
-
- if (path != 0) {
- s.addDirectory(path, path, priority);
- env->ReleaseStringUTFChars(path_obj, path);
- }
+ ENTER("");
- env->DeleteLocalRef(path_obj);
- }
+ JNI::addSysArchivesToSearchSet(s, priority);
}
-void OSystem_Android::logMessage(LogMessageType::Type type, const char *message) {
+void OSystem_Android::logMessage(LogMessageType::Type type,
+ const char *message) {
switch (type) {
case LogMessageType::kDebug:
__android_log_write(ANDROID_LOG_DEBUG, android_log_tag, message);
@@ -1401,177 +547,11 @@ void OSystem_Android::logMessage(LogMessageType::Type type, const char *message)
}
}
-static jint ScummVM_scummVMMain(JNIEnv *env, jobject self, jobjectArray args) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
-
- const int MAX_NARGS = 32;
- int res = -1;
-
- int argc = env->GetArrayLength(args);
- if (argc > MAX_NARGS) {
- JNU_ThrowByName(env, "java/lang/IllegalArgumentException",
- "too many arguments");
- return 0;
- }
-
- char *argv[MAX_NARGS];
-
- // note use in cleanup loop below
- int nargs;
-
- for (nargs = 0; nargs < argc; ++nargs) {
- jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
-
- if (arg == 0) {
- argv[nargs] = 0;
- } else {
- const char *cstr = env->GetStringUTFChars(arg, 0);
-
- argv[nargs] = const_cast<char *>(cstr);
-
- // exception already thrown?
- if (cstr == 0)
- goto cleanup;
- }
-
- env->DeleteLocalRef(arg);
- }
-
- g_system = cpp_obj;
- assert(g_system);
-
- LOGI("Entering scummvm_main with %d args", argc);
-
- res = scummvm_main(argc, argv);
-
- LOGI("Exiting scummvm_main");
-
- g_system->quit();
-
-cleanup:
- nargs--;
-
- for (int i = 0; i < nargs; ++i) {
- if (argv[i] == 0)
- continue;
-
- jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
-
- // Exception already thrown?
- if (arg == 0)
- return res;
-
- env->ReleaseStringUTFChars(arg, argv[i]);
- env->DeleteLocalRef(arg);
- }
-
- return res;
-}
-
#ifdef DYNAMIC_MODULES
void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const {
- OSystem_Android *g_system_android = (OSystem_Android *)g_system;
- g_system_android->addPluginDirectories(dirs);
+ ((OSystem_Android *)g_system)->addPluginDirectories(dirs);
}
#endif
-static void ScummVM_enableZoning(JNIEnv *env, jobject self, jboolean enable) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- cpp_obj->enableZoning(enable);
-}
-
-static void ScummVM_setSurfaceSize(JNIEnv *env, jobject self,
- jint width, jint height) {
- OSystem_Android *cpp_obj = OSystem_Android::fromJavaObject(env, self);
- cpp_obj->setSurfaceSize(width, height);
-}
-
-const static JNINativeMethod gMethods[] = {
- { "create", "(Landroid/content/res/AssetManager;)V",
- (void *)ScummVM_create },
- { "nativeDestroy", "()V",
- (void *)ScummVM_nativeDestroy },
- { "scummVMMain", "([Ljava/lang/String;)I",
- (void *)ScummVM_scummVMMain },
- { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V",
- (void *)ScummVM_pushEvent },
- { "audioMixCallback", "([B)V",
- (void *)ScummVM_audioMixCallback },
- { "setConfMan", "(Ljava/lang/String;I)V",
- (void *)ScummVM_setConfManInt },
- { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V",
- (void *)ScummVM_setConfManString },
- { "enableZoning", "(Z)V",
- (void *)ScummVM_enableZoning },
- { "setSurfaceSize", "(II)V",
- (void *)ScummVM_setSurfaceSize },
-};
-
-JNIEXPORT jint JNICALL
-JNI_OnLoad(JavaVM *jvm, void *reserved) {
- cached_jvm = jvm;
-
- JNIEnv *env;
-
- if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2))
- return JNI_ERR;
-
- jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM");
- if (cls == 0)
- return JNI_ERR;
-
- if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0)
- return JNI_ERR;
-
- FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J");
- if (FID_ScummVM_nativeScummVM == 0)
- return JNI_ERR;
-
- jclass event = env->FindClass("org/inodes/gus/scummvm/Event");
- if (event == 0)
- return JNI_ERR;
-
- FID_Event_type = env->GetFieldID(event, "type", "I");
- if (FID_Event_type == 0)
- return JNI_ERR;
-
- FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z");
- if (FID_Event_synthetic == 0)
- return JNI_ERR;
-
- FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I");
- if (FID_Event_kbd_keycode == 0)
- return JNI_ERR;
-
- FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I");
- if (FID_Event_kbd_ascii == 0)
- return JNI_ERR;
-
- FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I");
- if (FID_Event_kbd_flags == 0)
- return JNI_ERR;
-
- FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I");
- if (FID_Event_mouse_x == 0)
- return JNI_ERR;
-
- FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I");
- if (FID_Event_mouse_y == 0)
- return JNI_ERR;
-
- FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z");
- if (FID_Event_mouse_relative == 0)
- return JNI_ERR;
-
- cls = env->FindClass("java/lang/Object");
- if (cls == 0)
- return JNI_ERR;
-
- MID_Object_wait = env->GetMethodID(cls, "wait", "()V");
- if (MID_Object_wait == 0)
- return JNI_ERR;
-
- return JNI_VERSION_1_2;
-}
-
#endif
+
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 855fb04b5d..7ff96186f9 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -23,8 +23,23 @@
*
*/
+#ifndef _ANDROID_H_
+#define _ANDROID_H_
+
#if defined(__ANDROID__)
+#include "common/fs.h"
+#include "common/archive.h"
+#include "audio/mixer_intern.h"
+#include "graphics/surface.h"
+#include "backends/base-backend.h"
+#include "backends/plugins/posix/posix-provider.h"
+#include "backends/fs/posix/posix-fs-factory.h"
+
+#include "backends/platform/android/texture.h"
+
+#include <pthread.h>
+
#include <android/log.h>
#include <GLES/gl.h>
@@ -46,7 +61,7 @@ extern const char *android_log_tag;
#ifdef ANDROID_DEBUG_ENTER
#define ENTER(fmt, args...) LOGD("%s(" fmt ")", __FUNCTION__, ##args)
#else
-#define ENTER(fmt, args...) /**/
+#define ENTER(fmt, args...) do { } while (false)
#endif
#ifdef ANDROID_DEBUG_GL
@@ -58,13 +73,215 @@ extern void checkGlError(const char *expr, const char *file, int line);
checkGlError(#x, __FILE__, __LINE__); \
} while (false)
+#define GLTHREADCHECK \
+ do { \
+ assert(pthread_self() == _main_thread); \
+ } while (false)
+
#else
#define GLCALL(x) do { (x); } while (false)
+#define GLTHREADCHECK do { } while (false)
+#endif
+
+#ifdef DYNAMIC_MODULES
+class AndroidPluginProvider : public POSIXPluginProvider {
+protected:
+ virtual void addCustomDirectories(Common::FSList &dirs) const;
+};
+#endif
+
+class OSystem_Android : public BaseBackend, public PaletteManager {
+private:
+ // passed from the dark side
+ int _audio_sample_rate;
+ int _audio_buffer_size;
+
+ int _screen_changeid;
+ int _egl_surface_width;
+ int _egl_surface_height;
+
+ bool _force_redraw;
+
+ // Game layer
+ GLESBaseTexture *_game_texture;
+ int _shake_offset;
+ Common::Rect _focus_rect;
+
+ // Overlay layer
+ GLES4444Texture *_overlay_texture;
+ bool _show_overlay;
+
+ // Mouse layer
+ GLESBaseTexture *_mouse_texture;
+ GLESPaletteTexture *_mouse_texture_palette;
+ GLES5551Texture *_mouse_texture_rgb;
+ Common::Point _mouse_hotspot;
+ uint32 _mouse_keycolor;
+ int _mouse_targetscale;
+ bool _show_mouse;
+ bool _use_mouse_palette;
+
+ int _graphicsMode;
+ bool _fullscreen;
+ bool _ar_correction;
+
+ pthread_t _main_thread;
+
+ bool _timer_thread_exit;
+ pthread_t _timer_thread;
+ static void *timerThreadFunc(void *arg);
+
+ bool _audio_thread_exit;
+ pthread_t _audio_thread;
+ static void *audioThreadFunc(void *arg);
+
+ bool _enable_zoning;
+ bool _virtkeybd_on;
+
+ Common::SaveFileManager *_savefile;
+ Audio::MixerImpl *_mixer;
+ Common::TimerManager *_timer;
+ FilesystemFactory *_fsFactory;
+ timeval _startTime;
+
+ void initSurface();
+ void deinitSurface();
+ void initViewport();
+
+ void initOverlay();
+
+#ifdef USE_RGB_COLOR
+ Common::String getPixelFormatName(const Graphics::PixelFormat &format) const;
+ void initTexture(GLESBaseTexture **texture, uint width, uint height,
+ const Graphics::PixelFormat *format);
+#endif
+
+ void setupKeymapper();
+ void setCursorPaletteInternal(const byte *colors, uint start, uint num);
+
+public:
+ OSystem_Android(int audio_sample_rate, int audio_buffer_size);
+ virtual ~OSystem_Android();
+
+ virtual void initBackend();
+ void addPluginDirectories(Common::FSList &dirs) const;
+ void enableZoning(bool enable) { _enable_zoning = enable; }
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+
+#ifdef USE_RGB_COLOR
+ virtual Graphics::PixelFormat getScreenFormat() const;
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
#endif
-// Fix JNIEXPORT declaration to actually do something useful
-#undef JNIEXPORT
-#define JNIEXPORT __attribute__ ((visibility("default")))
+ virtual void initSize(uint width, uint height,
+ const Graphics::PixelFormat *format);
+
+ enum FixupType {
+ kClear = 0, // glClear
+ kClearSwap, // glClear + swapBuffers
+ kClearUpdate // glClear + updateScreen
+ };
+
+ void clearScreen(FixupType type, byte count = 1);
+
+ void updateScreenRect();
+ virtual int getScreenChangeID() const;
+
+ virtual int16 getHeight();
+ virtual int16 getWidth();
+
+ virtual PaletteManager *getPaletteManager() {
+ return this;
+ }
+
+public:
+ void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5);
+
+private:
+ Common::Queue<Common::Event> _event_queue;
+ MutexRef _event_queue_lock;
+ Common::Point _touch_pt_down, _touch_pt_dt;
+ int _eventScaleX;
+ int _eventScaleY;
+ bool _touchpad_mode;
+ int _touchpad_scale;
+ int _trackball_scale;
+ int _dpad_scale;
+
+ void clipMouse(Common::Point &p);
+ void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true);
+ void updateEventScale();
+
+protected:
+ // PaletteManager API
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+
+public:
+ virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y,
+ int w, int h);
+ virtual void updateScreen();
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+ virtual void setShakePos(int shakeOffset);
+ virtual void fillScreen(uint32 col);
+ virtual void setFocusRectangle(const Common::Rect& rect);
+ virtual void clearFocusRectangle();
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void clearOverlay();
+ virtual void grabOverlay(OverlayColor *buf, int pitch);
+ virtual void copyRectToOverlay(const OverlayColor *buf, int pitch,
+ int x, int y, int w, int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+ virtual Graphics::PixelFormat getOverlayFormat() const;
+
+ virtual bool showMouse(bool visible);
+
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX,
+ int hotspotY, uint32 keycolor,
+ int cursorTargetScale,
+ const Graphics::PixelFormat *format);
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+ virtual void disableCursorPalette(bool disable);
+
+ virtual bool pollEvent(Common::Event &event);
+ virtual uint32 getMillis();
+ virtual void delayMillis(uint msecs);
+
+ virtual MutexRef createMutex(void);
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ virtual void quit();
+
+ virtual void setWindowCaption(const char *caption);
+ virtual void displayMessageOnOSD(const char *msg);
+ virtual void showVirtualKeyboard(bool enable);
+
+ virtual Common::SaveFileManager *getSavefileManager();
+ virtual Audio::Mixer *getMixer();
+ virtual void getTimeAndDate(TimeDate &t) const;
+ virtual Common::TimerManager *getTimerManager();
+ virtual FilesystemFactory *getFilesystemFactory();
+ virtual void logMessage(LogMessageType::Type type, const char *message);
+ virtual void addSysArchivesToSearchSet(Common::SearchSet &s,
+ int priority = 0);
+};
+
+#endif
#endif
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index 1bc3c3d21a..cb39f8acfe 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -6,6 +6,7 @@ ANDROID_PLUGIN_VERSIONCODE = 6
JAVA_FILES = \
ScummVM.java \
+ ScummVMEvents.java \
ScummVMApplication.java \
ScummVMActivity.java \
EditableSurfaceView.java \
@@ -163,6 +164,10 @@ release/%.apk: %.apk
androidrelease: $(addprefix release/, $(APK_MAIN) $(APK_PLUGINS))
+androidtestmain: $(APK_MAIN)
+ $(ADB) install -r $(APK_MAIN)
+ $(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker
+
androidtest: $(APK_MAIN) $(APK_PLUGINS)
@set -e; for apk in $^; do \
$(ADB) install -r $$apk; \
diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp
index 71ce25aa72..26b1a6ad39 100644
--- a/backends/platform/android/asset-archive.cpp
+++ b/backends/platform/android/asset-archive.cpp
@@ -36,10 +36,9 @@
#include "common/archive.h"
#include "common/debug.h"
+#include "backends/platform/android/jni.h"
#include "backends/platform/android/asset-archive.h"
-extern JNIEnv *JNU_GetEnv();
-
// Must match android.content.res.AssetManager.ACCESS_*
const jint ACCESS_UNKNOWN = 0;
const jint ACCESS_RANDOM = 1;
@@ -100,7 +99,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) :
{
_input_stream = env->NewGlobalRef(is);
_buflen = 8192;
- _buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen)));
+ _buf = (jbyteArray)env->NewGlobalRef(env->NewByteArray(_buflen));
jclass cls = env->GetObjectClass(_input_stream);
MID_mark = env->GetMethodID(cls, "mark", "(I)V");
@@ -124,7 +123,7 @@ JavaInputStream::JavaInputStream(JNIEnv *env, jobject is) :
}
JavaInputStream::~JavaInputStream() {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
close(env);
env->DeleteGlobalRef(_buf);
@@ -139,11 +138,11 @@ void JavaInputStream::close(JNIEnv *env) {
}
uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
if (_buflen < jint(dataSize)) {
_buflen = dataSize;
-
+
env->DeleteGlobalRef(_buf);
_buf = static_cast<jbyteArray>(env->NewGlobalRef(env->NewByteArray(_buflen)));
}
@@ -171,7 +170,7 @@ uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) {
}
bool JavaInputStream::seek(int32 offset, int whence) {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
uint32 newpos;
switch (whence) {
@@ -305,7 +304,8 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) :
_declared_len = env->CallLongMethod(_assetfd, MID_getDeclaredLength);
jmethodID MID_getFileDescriptor =
- env->GetMethodID(cls, "getFileDescriptor", "()Ljava/io/FileDescriptor;");
+ env->GetMethodID(cls, "getFileDescriptor",
+ "()Ljava/io/FileDescriptor;");
assert(MID_getFileDescriptor);
jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor);
assert(javafd);
@@ -318,7 +318,7 @@ AssetFdReadStream::AssetFdReadStream(JNIEnv *env, jobject assetfd) :
}
AssetFdReadStream::~AssetFdReadStream() {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
env->CallVoidMethod(_assetfd, MID_close);
if (env->ExceptionCheck())
@@ -369,7 +369,7 @@ bool AssetFdReadStream::seek(int32 offset, int whence) {
}
AndroidAssetArchive::AndroidAssetArchive(jobject am) {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
_am = env->NewGlobalRef(am);
jclass cls = env->GetObjectClass(_am);
@@ -377,8 +377,8 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) {
"(Ljava/lang/String;I)Ljava/io/InputStream;");
assert(MID_open);
- MID_openFd = env->GetMethodID(cls, "openFd",
- "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");
+ MID_openFd = env->GetMethodID(cls, "openFd", "(Ljava/lang/String;)"
+ "Landroid/content/res/AssetFileDescriptor;");
assert(MID_openFd);
MID_list = env->GetMethodID(cls, "list",
@@ -387,12 +387,12 @@ AndroidAssetArchive::AndroidAssetArchive(jobject am) {
}
AndroidAssetArchive::~AndroidAssetArchive() {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
env->DeleteGlobalRef(_am);
}
bool AndroidAssetArchive::hasFile(const Common::String &name) {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
jstring path = env->NewStringUTF(name.c_str());
jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN);
if (env->ExceptionCheck()) {
@@ -412,7 +412,7 @@ bool AndroidAssetArchive::hasFile(const Common::String &name) {
}
int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
Common::List<Common::String> dirlist;
dirlist.push_back("");
@@ -422,7 +422,8 @@ int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) {
dirlist.pop_back();
jstring jpath = env->NewStringUTF(dir.c_str());
- jobjectArray jpathlist = static_cast<jobjectArray>(env->CallObjectMethod(_am, MID_list, jpath));
+ jobjectArray jpathlist =
+ (jobjectArray)env->CallObjectMethod(_am, MID_list, jpath);
if (env->ExceptionCheck()) {
warning("Error while calling AssetManager->list(%s). Ignoring.",
@@ -469,7 +470,7 @@ Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &na
}
Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const {
- JNIEnv *env = JNU_GetEnv();
+ JNIEnv *env = JNI::getEnv();
jstring jpath = env->NewStringUTF(path.c_str());
// Try openFd() first ...
diff --git a/backends/platform/android/asset-archive.h b/backends/platform/android/asset-archive.h
index 28e48426e9..6ec86e4cd0 100644
--- a/backends/platform/android/asset-archive.h
+++ b/backends/platform/android/asset-archive.h
@@ -23,6 +23,9 @@
*
*/
+#ifndef _ANDROID_ASSET_H_
+#define _ANDROID_ASSET_H_
+
#if defined(__ANDROID__)
#include <jni.h>
@@ -51,3 +54,5 @@ private:
};
#endif
+#endif
+
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
new file mode 100644
index 0000000000..1715e6a8a7
--- /dev/null
+++ b/backends/platform/android/events.cpp
@@ -0,0 +1,661 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "common/events.h"
+
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/jni.h"
+
+// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h
+// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp
+// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java
+
+// event type
+enum {
+ JE_SYS_KEY = 0,
+ JE_KEY = 1,
+ JE_DOWN = 2,
+ JE_SCROLL = 3,
+ JE_TAP = 4,
+ JE_DOUBLE_TAP = 5,
+ JE_BALL = 6,
+ JE_QUIT = 0x1000
+};
+
+// action type
+enum {
+ JACTION_DOWN = 0,
+ JACTION_UP = 1,
+ JACTION_MULTIPLE = 2
+};
+
+// system keys
+enum {
+ JKEYCODE_SOFT_RIGHT = 2,
+ JKEYCODE_HOME = 3,
+ JKEYCODE_BACK = 4,
+ JKEYCODE_CALL = 5,
+ JKEYCODE_ENDCALL = 6,
+ JKEYCODE_VOLUME_UP = 24,
+ JKEYCODE_VOLUME_DOWN = 25,
+ JKEYCODE_POWER = 26,
+ JKEYCODE_CAMERA = 27,
+ JKEYCODE_HEADSETHOOK = 79,
+ JKEYCODE_FOCUS = 80,
+ JKEYCODE_MENU = 82,
+ JKEYCODE_SEARCH = 84,
+ JKEYCODE_MUTE = 91,
+ JKEYCODE_MEDIA_PLAY_PAUSE = 85,
+ JKEYCODE_MEDIA_STOP = 86,
+ JKEYCODE_MEDIA_NEXT = 87,
+ JKEYCODE_MEDIA_PREVIOUS = 88,
+ JKEYCODE_MEDIA_REWIND = 89,
+ JKEYCODE_MEDIA_FAST_FORWARD = 90
+};
+
+// five-way navigation control
+enum {
+ JKEYCODE_DPAD_UP = 19,
+ JKEYCODE_DPAD_DOWN = 20,
+ JKEYCODE_DPAD_LEFT = 21,
+ JKEYCODE_DPAD_RIGHT = 22,
+ JKEYCODE_DPAD_CENTER = 23
+};
+
+// meta modifier
+enum {
+ JMETA_SHIFT = 0x01,
+ JMETA_ALT = 0x02,
+ JMETA_SYM = 0x04,
+ JMETA_CTRL = 0x1000
+};
+
+// map android key codes to our kbd codes
+static const Common::KeyCode jkeymap[] = {
+ Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN
+ Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT
+ Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT
+ Common::KEYCODE_INVALID, // KEYCODE_HOME
+ Common::KEYCODE_INVALID, // KEYCODE_BACK
+ Common::KEYCODE_INVALID, // KEYCODE_CALL
+ Common::KEYCODE_INVALID, // KEYCODE_ENDCALL
+ Common::KEYCODE_0, // KEYCODE_0
+ Common::KEYCODE_1, // KEYCODE_1
+ Common::KEYCODE_2, // KEYCODE_2
+ Common::KEYCODE_3, // KEYCODE_3
+ Common::KEYCODE_4, // KEYCODE_4
+ Common::KEYCODE_5, // KEYCODE_5
+ Common::KEYCODE_6, // KEYCODE_6
+ Common::KEYCODE_7, // KEYCODE_7
+ Common::KEYCODE_8, // KEYCODE_8
+ Common::KEYCODE_9, // KEYCODE_9
+ Common::KEYCODE_ASTERISK, // KEYCODE_STAR
+ Common::KEYCODE_HASH, // KEYCODE_POUND
+ Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP
+ Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN
+ Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT
+ Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT
+ Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER
+ Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP
+ Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN
+ Common::KEYCODE_INVALID, // KEYCODE_POWER
+ Common::KEYCODE_INVALID, // KEYCODE_CAMERA
+ Common::KEYCODE_INVALID, // KEYCODE_CLEAR
+ Common::KEYCODE_a, // KEYCODE_A
+ Common::KEYCODE_b, // KEYCODE_B
+ Common::KEYCODE_c, // KEYCODE_C
+ Common::KEYCODE_d, // KEYCODE_D
+ Common::KEYCODE_e, // KEYCODE_E
+ Common::KEYCODE_f, // KEYCODE_F
+ Common::KEYCODE_g, // KEYCODE_G
+ Common::KEYCODE_h, // KEYCODE_H
+ Common::KEYCODE_i, // KEYCODE_I
+ Common::KEYCODE_j, // KEYCODE_J
+ Common::KEYCODE_k, // KEYCODE_K
+ Common::KEYCODE_l, // KEYCODE_L
+ Common::KEYCODE_m, // KEYCODE_M
+ Common::KEYCODE_n, // KEYCODE_N
+ Common::KEYCODE_o, // KEYCODE_O
+ Common::KEYCODE_p, // KEYCODE_P
+ Common::KEYCODE_q, // KEYCODE_Q
+ Common::KEYCODE_r, // KEYCODE_R
+ Common::KEYCODE_s, // KEYCODE_S
+ Common::KEYCODE_t, // KEYCODE_T
+ Common::KEYCODE_u, // KEYCODE_U
+ Common::KEYCODE_v, // KEYCODE_V
+ Common::KEYCODE_w, // KEYCODE_W
+ Common::KEYCODE_x, // KEYCODE_X
+ Common::KEYCODE_y, // KEYCODE_Y
+ Common::KEYCODE_z, // KEYCODE_Z
+ Common::KEYCODE_COMMA, // KEYCODE_COMMA
+ Common::KEYCODE_PERIOD, // KEYCODE_PERIOD
+ Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT
+ Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT
+ Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT
+ Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT
+ Common::KEYCODE_TAB, // KEYCODE_TAB
+ Common::KEYCODE_SPACE, // KEYCODE_SPACE
+ Common::KEYCODE_LCTRL, // KEYCODE_SYM
+ Common::KEYCODE_INVALID, // KEYCODE_EXPLORER
+ Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE
+ Common::KEYCODE_RETURN, // KEYCODE_ENTER
+ Common::KEYCODE_BACKSPACE, // KEYCODE_DEL
+ Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE
+ Common::KEYCODE_MINUS, // KEYCODE_MINUS
+ Common::KEYCODE_EQUALS, // KEYCODE_EQUALS
+ Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET
+ Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET
+ Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH
+ Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON
+ Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE
+ Common::KEYCODE_SLASH, // KEYCODE_SLASH
+ Common::KEYCODE_AT, // KEYCODE_AT
+ Common::KEYCODE_INVALID, // KEYCODE_NUM
+ Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK
+ Common::KEYCODE_INVALID, // KEYCODE_FOCUS
+ Common::KEYCODE_PLUS, // KEYCODE_PLUS
+ Common::KEYCODE_INVALID, // KEYCODE_MENU
+ Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION
+ Common::KEYCODE_INVALID, // KEYCODE_SEARCH
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND
+ Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD
+ Common::KEYCODE_INVALID, // KEYCODE_MUTE
+ Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP
+ Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN
+};
+
+// floating point. use sparingly
+template <class T>
+static inline T scalef(T in, float numerator, float denominator) {
+ return static_cast<float>(in) * numerator / denominator;
+}
+
+void OSystem_Android::setupKeymapper() {
+#ifdef ENABLE_KEYMAPPER
+ using namespace Common;
+
+ Keymapper *mapper = getEventManager()->getKeymapper();
+
+ HardwareKeySet *keySet = new HardwareKeySet();
+
+ keySet->addHardwareKey(
+ new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)",
+ kTriggerLeftKeyType,
+ kVirtualKeyboardActionType));
+
+ mapper->registerHardwareKeySet(keySet);
+
+ Keymap *globalMap = new Keymap("global");
+ Action *act;
+
+ act = new Action(globalMap, "VIRT", "Display keyboard",
+ kVirtualKeyboardActionType);
+ act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0));
+
+ mapper->addGlobalKeymap(globalMap);
+
+ mapper->pushKeymap("global");
+#endif
+}
+
+void OSystem_Android::warpMouse(int x, int y) {
+ ENTER("%d, %d", x, y);
+
+ Common::Event e;
+
+ e.type = Common::EVENT_MOUSEMOVE;
+ e.mouse.x = x;
+ e.mouse.y = y;
+
+ clipMouse(e.mouse);
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+}
+
+void OSystem_Android::clipMouse(Common::Point &p) {
+ const GLESBaseTexture *tex;
+
+ if (_show_overlay)
+ tex = _overlay_texture;
+ else
+ tex = _game_texture;
+
+ p.x = CLIP(p.x, int16(0), int16(tex->width()));
+ p.y = CLIP(p.y, int16(0), int16(tex->height()));
+}
+
+void OSystem_Android::scaleMouse(Common::Point &p, int x, int y,
+ bool deductDrawRect) {
+ const GLESBaseTexture *tex;
+
+ if (_show_overlay)
+ tex = _overlay_texture;
+ else
+ tex = _game_texture;
+
+ const Common::Rect &r = tex->getDrawRect();
+
+ if (_touchpad_mode) {
+ x = x * 100 / _touchpad_scale;
+ y = y * 100 / _touchpad_scale;
+ }
+
+ if (deductDrawRect) {
+ x -= r.left;
+ y -= r.top;
+ }
+
+ p.x = scalef(x, tex->width(), r.width());
+ p.y = scalef(y, tex->height(), r.height());
+}
+
+void OSystem_Android::updateEventScale() {
+ const GLESBaseTexture *tex;
+
+ if (_show_overlay)
+ tex = _overlay_texture;
+ else
+ tex = _game_texture;
+
+ _eventScaleY = 100 * 480 / tex->height();
+ _eventScaleX = 100 * 640 / tex->width();
+}
+
+void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
+ int arg4, int arg5) {
+ Common::Event e;
+
+ switch (type) {
+ case JE_SYS_KEY:
+ switch (arg1) {
+ case JACTION_DOWN:
+ e.type = Common::EVENT_KEYDOWN;
+ break;
+ case JACTION_UP:
+ e.type = Common::EVENT_KEYUP;
+ break;
+ default:
+ LOGE("unhandled jaction on system key: %d", arg1);
+ return;
+ }
+
+ switch (arg2) {
+ case JKEYCODE_BACK:
+ e.kbd.keycode = Common::KEYCODE_ESCAPE;
+ e.kbd.ascii = Common::ASCII_ESCAPE;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ // special case. we'll only get it's up event
+ case JKEYCODE_MENU:
+ e.type = Common::EVENT_MAINMENU;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ default:
+ LOGW("unmapped system key: %d", arg2);
+ return;
+ }
+
+ break;
+
+ case JE_KEY:
+ // five-way first
+ switch (arg2) {
+ case JKEYCODE_DPAD_UP:
+ case JKEYCODE_DPAD_DOWN:
+ case JKEYCODE_DPAD_LEFT:
+ case JKEYCODE_DPAD_RIGHT:
+ {
+ if (arg1 != JACTION_DOWN)
+ return;
+
+ e.type = Common::EVENT_MOUSEMOVE;
+ e.synthetic = true;
+
+ e.mouse = getEventManager()->getMousePos();
+
+ int16 *c;
+ int s;
+
+ if (arg2 == JKEYCODE_DPAD_UP || arg2 == JKEYCODE_DPAD_DOWN) {
+ c = &e.mouse.y;
+ s = _eventScaleY;
+ } else {
+ c = &e.mouse.x;
+ s = _eventScaleX;
+ }
+
+ // the longer the button held, the faster the pointer is
+ // TODO put these values in some option dlg?
+ int f = CLIP(arg5, 1, 8) * _dpad_scale * 100 / s;
+
+ *c += ((arg2 == JKEYCODE_DPAD_UP ||
+ arg2 == JKEYCODE_DPAD_LEFT) ? -1 : 1) * f;
+
+ clipMouse(e.mouse);
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+
+ case JKEYCODE_DPAD_CENTER:
+ switch (arg1) {
+ case JACTION_DOWN:
+ e.type = Common::EVENT_LBUTTONDOWN;
+ break;
+ case JACTION_UP:
+ e.type = Common::EVENT_LBUTTONUP;
+ break;
+ default:
+ LOGE("unhandled jaction on dpad key: %d", arg1);
+ return;
+ }
+
+ {
+ const Common::Point &m = getEventManager()->getMousePos();
+
+ e.mouse = m;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+ }
+
+ switch (arg1) {
+ case JACTION_DOWN:
+ e.type = Common::EVENT_KEYDOWN;
+ break;
+ case JACTION_UP:
+ e.type = Common::EVENT_KEYUP;
+ break;
+ default:
+ LOGE("unhandled jaction on key: %d", arg1);
+ return;
+ }
+
+ if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) {
+ LOGE("received invalid keycode: %d", arg2);
+ return;
+ }
+
+ if (arg5 > 0)
+ e.synthetic = true;
+
+ e.kbd.keycode = jkeymap[arg2];
+ e.kbd.ascii = arg3;
+
+ if (arg4 & JMETA_SHIFT)
+ e.kbd.flags |= Common::KBD_SHIFT;
+ if (arg4 & JMETA_ALT)
+ e.kbd.flags |= Common::KBD_ALT;
+ if (arg4 & (JMETA_SYM | JMETA_CTRL))
+ e.kbd.flags |= Common::KBD_CTRL;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ case JE_DOWN:
+ _touch_pt_down = getEventManager()->getMousePos();
+ break;
+
+ case JE_SCROLL:
+ e.type = Common::EVENT_MOUSEMOVE;
+
+ if (_touchpad_mode) {
+ scaleMouse(e.mouse, arg3 - arg1, arg4 - arg2, false);
+ e.mouse += _touch_pt_down;
+ clipMouse(e.mouse);
+ } else {
+ scaleMouse(e.mouse, arg3, arg4);
+ clipMouse(e.mouse);
+ }
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ case JE_TAP:
+ e.type = Common::EVENT_MOUSEMOVE;
+
+ if (_touchpad_mode) {
+ e.mouse = getEventManager()->getMousePos();
+ } else {
+ scaleMouse(e.mouse, arg1, arg2);
+ clipMouse(e.mouse);
+ }
+
+ {
+ Common::EventType down, up;
+
+ // TODO put these values in some option dlg?
+ if (arg3 > 1000) {
+ down = Common::EVENT_MBUTTONDOWN;
+ up = Common::EVENT_MBUTTONUP;
+ } else if (arg3 > 500) {
+ down = Common::EVENT_RBUTTONDOWN;
+ up = Common::EVENT_RBUTTONUP;
+ } else {
+ down = Common::EVENT_LBUTTONDOWN;
+ up = Common::EVENT_LBUTTONUP;
+ }
+
+ lockMutex(_event_queue_lock);
+
+ if (!_touchpad_mode)
+ _event_queue.push(e);
+
+ e.type = down;
+ _event_queue.push(e);
+ e.type = up;
+ _event_queue.push(e);
+
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+
+ case JE_DOUBLE_TAP:
+ e.type = Common::EVENT_MOUSEMOVE;
+
+ if (_touchpad_mode) {
+ e.mouse = getEventManager()->getMousePos();
+ } else {
+ scaleMouse(e.mouse, arg1, arg2);
+ clipMouse(e.mouse);
+ }
+
+ {
+ Common::EventType dptype = Common::EVENT_INVALID;
+
+ switch (arg3) {
+ case JACTION_DOWN:
+ dptype = Common::EVENT_LBUTTONDOWN;
+ _touch_pt_dt.x = arg1;
+ _touch_pt_dt.y = arg2;
+ break;
+ case JACTION_UP:
+ dptype = Common::EVENT_LBUTTONUP;
+ break;
+ case JACTION_MULTIPLE:
+ // held and moved
+ dptype = Common::EVENT_MOUSEMOVE;
+
+ if (_touchpad_mode) {
+ scaleMouse(e.mouse, arg1 - _touch_pt_dt.x,
+ arg2 - _touch_pt_dt.y, false);
+ e.mouse += _touch_pt_down;
+
+ clipMouse(e.mouse);
+ }
+
+ break;
+ default:
+ LOGE("unhandled jaction on double tap: %d", arg3);
+ return;
+ }
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ e.type = dptype;
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+
+ case JE_BALL:
+ e.type = Common::EVENT_MOUSEMOVE;
+
+ e.mouse = getEventManager()->getMousePos();
+
+ // already multiplied by 100
+ e.mouse.x += arg1 * _trackball_scale / _eventScaleX;
+ e.mouse.y += arg2 * _trackball_scale / _eventScaleY;
+
+ clipMouse(e.mouse);
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ case JE_QUIT:
+ e.type = Common::EVENT_QUIT;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+
+ return;
+
+ default:
+ LOGE("unknown jevent type: %d", type);
+
+ break;
+ }
+}
+
+bool OSystem_Android::pollEvent(Common::Event &event) {
+ //ENTER();
+
+ if (pthread_self() == _main_thread) {
+ if (_screen_changeid != JNI::surface_changeid) {
+ if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) {
+ if (_egl_surface_width > 0 && _egl_surface_height > 0) {
+ // surface still alive but changed
+ _screen_changeid = JNI::surface_changeid;
+ _egl_surface_width = JNI::egl_surface_width;
+ _egl_surface_height = JNI::egl_surface_height;
+
+ initViewport();
+ updateScreenRect();
+ updateEventScale();
+
+ // double buffered, flip twice
+ clearScreen(kClearUpdate, 2);
+
+ event.type = Common::EVENT_SCREEN_CHANGED;
+
+ return true;
+ } else {
+ // new surface
+ initSurface();
+ updateScreenRect();
+ updateEventScale();
+
+ // double buffered, flip twice
+ clearScreen(kClearUpdate, 2);
+
+ event.type = Common::EVENT_SCREEN_CHANGED;
+
+ return true;
+ }
+ } else {
+ // surface lost
+ deinitSurface();
+ }
+ }
+
+ if (JNI::pause) {
+ deinitSurface();
+
+ LOGD("main thread going to sleep");
+ sem_wait(&JNI::pause_sem);
+ LOGD("main thread woke up");
+ }
+ }
+
+ lockMutex(_event_queue_lock);
+
+ if (_event_queue.empty()) {
+ unlockMutex(_event_queue_lock);
+ return false;
+ }
+
+ event = _event_queue.pop();
+
+ unlockMutex(_event_queue_lock);
+
+ if (event.type == Common::EVENT_MOUSEMOVE) {
+ const Common::Point &m = getEventManager()->getMousePos();
+
+ if (m != event.mouse)
+ _force_redraw = true;
+ }
+
+ return true;
+}
+
+#endif
+
diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp
new file mode 100644
index 0000000000..d7e31fcad7
--- /dev/null
+++ b/backends/platform/android/gfx.cpp
@@ -0,0 +1,810 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "common/endian.h"
+#include "graphics/conversion.h"
+
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/jni.h"
+
+static inline GLfixed xdiv(int numerator, int denominator) {
+ assert(numerator < (1 << 16));
+ return (numerator << 16) / denominator;
+}
+
+const OSystem::GraphicsMode *OSystem_Android::getSupportedGraphicsModes() const {
+ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ { "default", "Default", 0 },
+ { "filter", "Linear filtering", 1 },
+ { 0, 0, 0 },
+ };
+
+ return s_supportedGraphicsModes;
+}
+
+int OSystem_Android::getDefaultGraphicsMode() const {
+ return 0;
+}
+
+bool OSystem_Android::setGraphicsMode(int mode) {
+ ENTER("%d", mode);
+
+ if (_game_texture)
+ _game_texture->setLinearFilter(mode == 1);
+
+ if (_overlay_texture)
+ _overlay_texture->setLinearFilter(mode == 1);
+
+ _graphicsMode = mode;
+
+ return true;
+}
+
+int OSystem_Android::getGraphicsMode() const {
+ return _graphicsMode;
+}
+
+#ifdef USE_RGB_COLOR
+Graphics::PixelFormat OSystem_Android::getScreenFormat() const {
+ return _game_texture->getPixelFormat();
+}
+
+Common::List<Graphics::PixelFormat> OSystem_Android::getSupportedFormats() const {
+ Common::List<Graphics::PixelFormat> res;
+ res.push_back(GLES565Texture::pixelFormat());
+ res.push_back(GLES5551Texture::pixelFormat());
+ res.push_back(GLES4444Texture::pixelFormat());
+ res.push_back(Graphics::PixelFormat::createFormatCLUT8());
+
+ return res;
+}
+
+Common::String OSystem_Android::getPixelFormatName(const Graphics::PixelFormat &format) const {
+ if (format.bytesPerPixel == 1)
+ return "CLUT8";
+
+ if (format.aLoss == 8)
+ return Common::String::format("RGB%u%u%u",
+ 8 - format.rLoss,
+ 8 - format.gLoss,
+ 8 - format.bLoss);
+
+ return Common::String::format("RGBA%u%u%u%u",
+ 8 - format.rLoss,
+ 8 - format.gLoss,
+ 8 - format.bLoss,
+ 8 - format.aLoss);
+}
+
+void OSystem_Android::initTexture(GLESBaseTexture **texture,
+ uint width, uint height,
+ const Graphics::PixelFormat *format) {
+ assert(texture);
+ Graphics::PixelFormat format_clut8 =
+ Graphics::PixelFormat::createFormatCLUT8();
+ Graphics::PixelFormat format_current;
+ Graphics::PixelFormat format_new;
+
+ if (*texture)
+ format_current = (*texture)->getPixelFormat();
+ else
+ format_current = Graphics::PixelFormat();
+
+ if (format)
+ format_new = *format;
+ else
+ format_new = format_clut8;
+
+ if (format_current != format_new) {
+ if (*texture)
+ LOGD("switching pixel format from: %s",
+ getPixelFormatName((*texture)->getPixelFormat()).c_str());
+
+ delete *texture;
+
+ if (format_new == GLES565Texture::pixelFormat())
+ *texture = new GLES565Texture();
+ else if (format_new == GLES5551Texture::pixelFormat())
+ *texture = new GLES5551Texture();
+ else if (format_new == GLES4444Texture::pixelFormat())
+ *texture = new GLES4444Texture();
+ else {
+ // TODO what now?
+ if (format_new != format_clut8)
+ LOGE("unsupported pixel format: %s",
+ getPixelFormatName(format_new).c_str());
+
+ *texture = new GLESFakePalette565Texture;
+ }
+
+ LOGD("new pixel format: %s",
+ getPixelFormatName((*texture)->getPixelFormat()).c_str());
+ }
+
+ (*texture)->allocBuffer(width, height);
+ (*texture)->fillBuffer(0);
+}
+#endif
+
+void OSystem_Android::initSurface() {
+ LOGD("initializing surface");
+
+ assert(!JNI::haveSurface());
+
+ _screen_changeid = JNI::surface_changeid;
+ _egl_surface_width = JNI::egl_surface_width;
+ _egl_surface_height = JNI::egl_surface_height;
+
+ assert(_egl_surface_width > 0 && _egl_surface_height > 0);
+
+ JNI::initSurface();
+
+ // Initialise OpenGLES context.
+ GLESTexture::initGLExtensions();
+
+ if (_game_texture)
+ _game_texture->reinit();
+
+ if (_overlay_texture) {
+ _overlay_texture->reinit();
+ initOverlay();
+ }
+
+ if (_mouse_texture)
+ _mouse_texture->reinit();
+}
+
+void OSystem_Android::deinitSurface() {
+ if (!JNI::haveSurface())
+ return;
+
+ LOGD("deinitializing surface");
+
+ _screen_changeid = JNI::surface_changeid;
+ _egl_surface_width = 0;
+ _egl_surface_height = 0;
+
+ // release texture resources
+ if (_game_texture)
+ _game_texture->release();
+
+ if (_overlay_texture)
+ _overlay_texture->release();
+
+ if (_mouse_texture)
+ _mouse_texture->release();
+
+ JNI::deinitSurface();
+}
+
+void OSystem_Android::initViewport() {
+ LOGD("initializing viewport");
+
+ assert(JNI::haveSurface());
+
+ // Turn off anything that looks like 3D ;)
+ GLCALL(glDisable(GL_CULL_FACE));
+ GLCALL(glDisable(GL_DEPTH_TEST));
+ GLCALL(glDisable(GL_LIGHTING));
+ GLCALL(glDisable(GL_FOG));
+ GLCALL(glDisable(GL_DITHER));
+
+ GLCALL(glShadeModel(GL_FLAT));
+ GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
+
+ GLCALL(glEnable(GL_BLEND));
+ GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+
+ GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
+ GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+
+ GLCALL(glEnable(GL_TEXTURE_2D));
+
+ GLCALL(glViewport(0, 0, _egl_surface_width, _egl_surface_height));
+
+ GLCALL(glMatrixMode(GL_PROJECTION));
+ GLCALL(glLoadIdentity());
+ GLCALL(glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1));
+ GLCALL(glMatrixMode(GL_MODELVIEW));
+ GLCALL(glLoadIdentity());
+
+ clearFocusRectangle();
+}
+
+void OSystem_Android::initOverlay() {
+ int overlay_width = _egl_surface_width;
+ int overlay_height = _egl_surface_height;
+
+ // the 'normal' theme layout uses a max height of 400 pixels. if the
+ // surface is too big we use only a quarter of the size so that the widgets
+ // don't get too small. if the surface height has less than 800 pixels, this
+ // enforces the 'lowres' layout, which will be scaled back up by factor 2x,
+ // but this looks way better than the 'normal' layout scaled by some
+ // calculated factors
+ if (overlay_height > 480) {
+ overlay_width /= 2;
+ overlay_height /= 2;
+ }
+
+ LOGI("overlay size is %ux%u", overlay_width, overlay_height);
+
+ _overlay_texture->allocBuffer(overlay_width, overlay_height);
+ _overlay_texture->fillBuffer(0);
+ _overlay_texture->setDrawRect(0, 0,
+ _egl_surface_width, _egl_surface_height);
+}
+
+void OSystem_Android::initSize(uint width, uint height,
+ const Graphics::PixelFormat *format) {
+ ENTER("%d, %d, %p", width, height, format);
+
+ GLTHREADCHECK;
+
+#ifdef USE_RGB_COLOR
+ initTexture(&_game_texture, width, height, format);
+#else
+ _game_texture->allocBuffer(width, height);
+ _game_texture->fillBuffer(0);
+#endif
+
+ updateScreenRect();
+ updateEventScale();
+
+ // Don't know mouse size yet - it gets reallocated in
+ // setMouseCursor. We need the palette allocated before
+ // setMouseCursor however, so just take a guess at the desired
+ // size (it's small).
+ _mouse_texture_palette->allocBuffer(20, 20);
+
+ clearScreen(kClear);
+}
+
+void OSystem_Android::clearScreen(FixupType type, byte count) {
+ assert(count > 0);
+
+ GLCALL(glDisable(GL_SCISSOR_TEST));
+
+ for (byte i = 0; i < count; ++i) {
+ // clear screen
+ GLCALL(glClearColorx(0, 0, 0, 1 << 16));
+ GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+
+ switch (type) {
+ case kClear:
+ break;
+
+ case kClearSwap:
+ JNI::swapBuffers();
+ break;
+
+ case kClearUpdate:
+ _force_redraw = true;
+ updateScreen();
+ break;
+ }
+ }
+
+ if (!_show_overlay)
+ GLCALL(glEnable(GL_SCISSOR_TEST));
+}
+
+void OSystem_Android::updateScreenRect() {
+ Common::Rect rect(0, 0, _egl_surface_width, _egl_surface_height);
+
+ _overlay_texture->setDrawRect(rect);
+
+ uint16 w = _game_texture->width();
+ uint16 h = _game_texture->height();
+
+ if (w && h && !_fullscreen) {
+ if (_ar_correction && w == 320 && h == 200)
+ h = 240;
+
+ float dpi[2];
+ JNI::getDPI(dpi);
+
+ float screen_ar;
+ if (dpi[0] != 0.0 && dpi[1] != 0.0) {
+ // horizontal orientation
+ screen_ar = (dpi[1] * _egl_surface_width) /
+ (dpi[0] * _egl_surface_height);
+ } else {
+ screen_ar = float(_egl_surface_width) / float(_egl_surface_height);
+ }
+
+ float game_ar = float(w) / float(h);
+
+ if (screen_ar > game_ar) {
+ rect.setWidth(round(_egl_surface_height * game_ar));
+ rect.moveTo((_egl_surface_width - rect.width()) / 2, 0);
+ } else {
+ rect.setHeight(round(_egl_surface_width / game_ar));
+ rect.moveTo((_egl_surface_height - rect.height()) / 2, 0);
+ }
+ }
+
+ glScissor(rect.left, rect.top, rect.width(), rect.height());
+
+ _game_texture->setDrawRect(rect);
+}
+
+int OSystem_Android::getScreenChangeID() const {
+ return _screen_changeid;
+}
+
+int16 OSystem_Android::getHeight() {
+ return _game_texture->height();
+}
+
+int16 OSystem_Android::getWidth() {
+ return _game_texture->width();
+}
+
+void OSystem_Android::setPalette(const byte *colors, uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+
+#ifdef USE_RGB_COLOR
+ assert(_game_texture->hasPalette());
+#endif
+
+ GLTHREADCHECK;
+
+ if (!_use_mouse_palette)
+ setCursorPaletteInternal(colors, start, num);
+
+ const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
+ byte *p = _game_texture->palette() + start * 2;
+
+ for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+ WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+}
+
+void OSystem_Android::grabPalette(byte *colors, uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+
+#ifdef USE_RGB_COLOR
+ assert(_game_texture->hasPalette());
+#endif
+
+ GLTHREADCHECK;
+
+ const Graphics::PixelFormat &pf = _game_texture->getPalettePixelFormat();
+ const byte *p = _game_texture->palette_const() + start * 2;
+
+ for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+ pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]);
+}
+
+void OSystem_Android::copyRectToScreen(const byte *buf, int pitch,
+ int x, int y, int w, int h) {
+ ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+ GLTHREADCHECK;
+
+ _game_texture->updateBuffer(x, y, w, h, buf, pitch);
+}
+
+void OSystem_Android::updateScreen() {
+ //ENTER();
+
+ GLTHREADCHECK;
+
+ if (!JNI::haveSurface())
+ return;
+
+ if (!_force_redraw &&
+ !_game_texture->dirty() &&
+ !_overlay_texture->dirty() &&
+ !_mouse_texture->dirty())
+ return;
+
+ _force_redraw = false;
+
+ // clear pointer leftovers in dead areas
+ if (_show_overlay && !_fullscreen)
+ clearScreen(kClear);
+
+ GLCALL(glPushMatrix());
+
+ if (_shake_offset != 0 ||
+ (!_focus_rect.isEmpty() &&
+ !Common::Rect(_game_texture->width(),
+ _game_texture->height()).contains(_focus_rect))) {
+ // These are the only cases where _game_texture doesn't
+ // cover the entire screen.
+ clearScreen(kClear);
+
+ // Move everything up by _shake_offset (game) pixels
+ GLCALL(glTranslatex(0, -_shake_offset << 16, 0));
+ }
+
+// TODO this doesnt work on those sucky drivers, do it differently
+// if (_show_overlay)
+// GLCALL(glColor4ub(0x9f, 0x9f, 0x9f, 0x9f));
+
+ if (_focus_rect.isEmpty()) {
+ _game_texture->drawTextureRect();
+ } else {
+ GLCALL(glPushMatrix());
+
+ GLCALL(glScalex(xdiv(_egl_surface_width, _focus_rect.width()),
+ xdiv(_egl_surface_height, _focus_rect.height()),
+ 1 << 16));
+ GLCALL(glTranslatex(-_focus_rect.left << 16,
+ -_focus_rect.top << 16, 0));
+ GLCALL(glScalex(xdiv(_game_texture->width(), _egl_surface_width),
+ xdiv(_game_texture->height(), _egl_surface_height),
+ 1 << 16));
+
+ _game_texture->drawTextureRect();
+
+ GLCALL(glPopMatrix());
+ }
+
+ int cs = _mouse_targetscale;
+
+ if (_show_overlay) {
+// TODO see above
+// GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff));
+
+ // ugly, but the modern theme sets a wacko factor, only god knows why
+ cs = 1;
+
+ GLCALL(_overlay_texture->drawTextureRect());
+ }
+
+ if (_show_mouse) {
+ GLCALL(glPushMatrix());
+
+ const Common::Point &mouse = getEventManager()->getMousePos();
+
+ // Scale up ScummVM -> OpenGL (pixel) coordinates
+ if (_show_overlay) {
+ GLCALL(glScalex(xdiv(_egl_surface_width,
+ _overlay_texture->width()),
+ xdiv(_egl_surface_height,
+ _overlay_texture->height()),
+ 1 << 16));
+ } else {
+ const Common::Rect &r = _game_texture->getDrawRect();
+
+ GLCALL(glTranslatex(r.left << 16,
+ r.top << 16,
+ 0));
+ GLCALL(glScalex(xdiv(r.width(), _game_texture->width()),
+ xdiv(r.height(), _game_texture->height()),
+ 1 << 16));
+ }
+
+ GLCALL(glTranslatex((-_mouse_hotspot.x * cs) << 16,
+ (-_mouse_hotspot.y * cs) << 16,
+ 0));
+
+ // Note the extra half texel to position the mouse in
+ // the middle of the x,y square:
+ GLCALL(glTranslatex((mouse.x << 16) | 1 << 15,
+ (mouse.y << 16) | 1 << 15, 0));
+
+ GLCALL(glScalex(cs << 16, cs << 16, 1 << 16));
+
+ _mouse_texture->drawTextureOrigin();
+
+ GLCALL(glPopMatrix());
+ }
+
+ GLCALL(glPopMatrix());
+
+ if (!JNI::swapBuffers())
+ LOGW("swapBuffers failed: 0x%x", glGetError());
+}
+
+Graphics::Surface *OSystem_Android::lockScreen() {
+ ENTER();
+
+ GLTHREADCHECK;
+
+ Graphics::Surface *surface = _game_texture->surface();
+ assert(surface->pixels);
+
+ return surface;
+}
+
+void OSystem_Android::unlockScreen() {
+ ENTER();
+
+ GLTHREADCHECK;
+
+ assert(_game_texture->dirty());
+}
+
+void OSystem_Android::setShakePos(int shake_offset) {
+ ENTER("%d", shake_offset);
+
+ if (_shake_offset != shake_offset) {
+ _shake_offset = shake_offset;
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::fillScreen(uint32 col) {
+ ENTER("%u", col);
+
+ GLTHREADCHECK;
+
+ _game_texture->fillBuffer(col);
+}
+
+void OSystem_Android::setFocusRectangle(const Common::Rect& rect) {
+ ENTER("%d, %d, %d, %d", rect.left, rect.top, rect.right, rect.bottom);
+
+ if (_enable_zoning) {
+ _focus_rect = rect;
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::clearFocusRectangle() {
+ ENTER();
+
+ if (_enable_zoning) {
+ _focus_rect = Common::Rect();
+ _force_redraw = true;
+ }
+}
+
+void OSystem_Android::showOverlay() {
+ ENTER();
+
+ _show_overlay = true;
+ _force_redraw = true;
+
+ updateEventScale();
+
+ warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
+
+ GLCALL(glDisable(GL_SCISSOR_TEST));
+}
+
+void OSystem_Android::hideOverlay() {
+ ENTER();
+
+ clearScreen(kClear);
+
+ _show_overlay = false;
+ _force_redraw = true;
+
+ updateEventScale();
+
+ warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
+
+ GLCALL(glEnable(GL_SCISSOR_TEST));
+}
+
+void OSystem_Android::clearOverlay() {
+ ENTER();
+
+ GLTHREADCHECK;
+
+ _overlay_texture->fillBuffer(0);
+
+ // breaks more than it fixes, disabled for now
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1
+ //updateScreen();
+}
+
+void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) {
+ ENTER("%p, %d", buf, pitch);
+
+ GLTHREADCHECK;
+
+ const Graphics::Surface *surface = _overlay_texture->surface_const();
+ assert(surface->bytesPerPixel == sizeof(buf[0]));
+
+ const byte *src = (const byte *)surface->pixels;
+ uint h = surface->h;
+
+ do {
+ memcpy(buf, src, surface->w * surface->bytesPerPixel);
+ src += surface->pitch;
+ // This 'pitch' is pixels not bytes
+ buf += pitch;
+ } while (--h);
+}
+
+void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch,
+ int x, int y, int w, int h) {
+ ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h);
+
+ GLTHREADCHECK;
+
+ // This 'pitch' is pixels not bytes
+ _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0]));
+
+ // Shouldn't need this, but works around a 'blank screen' bug on Nexus1?
+ //updateScreen();
+}
+
+int16 OSystem_Android::getOverlayHeight() {
+ return _overlay_texture->height();
+}
+
+int16 OSystem_Android::getOverlayWidth() {
+ return _overlay_texture->width();
+}
+
+Graphics::PixelFormat OSystem_Android::getOverlayFormat() const {
+ return _overlay_texture->getPixelFormat();
+}
+
+bool OSystem_Android::showMouse(bool visible) {
+ ENTER("%d", visible);
+
+ _show_mouse = visible;
+
+ return true;
+}
+
+void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
+ int hotspotX, int hotspotY,
+ uint32 keycolor, int cursorTargetScale,
+ const Graphics::PixelFormat *format) {
+ ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY,
+ keycolor, cursorTargetScale, format);
+
+ GLTHREADCHECK;
+
+#ifdef USE_RGB_COLOR
+ if (format && format->bytesPerPixel > 1) {
+ if (_mouse_texture != _mouse_texture_rgb)
+ LOGD("switching to rgb mouse cursor");
+
+ _mouse_texture_rgb = new GLES5551Texture();
+ _mouse_texture = _mouse_texture_rgb;
+ } else {
+ if (_mouse_texture != _mouse_texture_palette)
+ LOGD("switching to paletted mouse cursor");
+
+ _mouse_texture = _mouse_texture_palette;
+
+ delete _mouse_texture_rgb;
+ _mouse_texture_rgb = 0;
+ }
+#endif
+
+ _mouse_texture->allocBuffer(w, h);
+
+ if (_mouse_texture == _mouse_texture_palette) {
+ assert(keycolor < 256);
+
+ byte *p = _mouse_texture_palette->palette() + _mouse_keycolor * 2;
+
+ WRITE_UINT16(p, READ_UINT16(p) | 1);
+ _mouse_keycolor = keycolor;
+ WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0);
+ }
+
+ if (w == 0 || h == 0) {
+ _show_mouse = false;
+ return;
+ }
+
+ if (_mouse_texture == _mouse_texture_palette) {
+ _mouse_texture->updateBuffer(0, 0, w, h, buf, w);
+ } else {
+ uint16 pitch = _mouse_texture->pitch();
+
+ byte *tmp = new byte[pitch * h];
+
+ // meh, a 16bit cursor without alpha bits... this is so silly
+ if (!crossBlit(tmp, buf, pitch, w * 2, w, h,
+ _mouse_texture->getPixelFormat(),
+ *format)) {
+ LOGE("crossblit failed");
+
+ delete[] tmp;
+
+ _show_mouse = false;
+
+ return;
+ }
+
+ uint16 *s = (uint16 *)buf;
+ uint16 *d = (uint16 *)tmp;
+ for (uint16 y = 0; y < h; ++y, d += pitch / 2 - w)
+ for (uint16 x = 0; x < w; ++x, d++)
+ if (*s++ != (keycolor & 0xffff))
+ *d |= 1;
+
+ _mouse_texture->updateBuffer(0, 0, w, h, tmp, pitch);
+
+ delete[] tmp;
+ }
+
+ _mouse_hotspot = Common::Point(hotspotX, hotspotY);
+ _mouse_targetscale = cursorTargetScale;
+}
+
+void OSystem_Android::setCursorPaletteInternal(const byte *colors,
+ uint start, uint num) {
+ const Graphics::PixelFormat &pf =
+ _mouse_texture_palette->getPalettePixelFormat();
+ byte *p = _mouse_texture_palette->palette() + start * 2;
+
+ for (uint i = 0; i < num; ++i, colors += 3, p += 2)
+ WRITE_UINT16(p, pf.RGBToColor(colors[0], colors[1], colors[2]));
+
+ WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0);
+}
+
+void OSystem_Android::setCursorPalette(const byte *colors,
+ uint start, uint num) {
+ ENTER("%p, %u, %u", colors, start, num);
+
+ GLTHREADCHECK;
+
+ if (!_mouse_texture->hasPalette()) {
+ LOGD("switching to paletted mouse cursor");
+
+ _mouse_texture = _mouse_texture_palette;
+
+ delete _mouse_texture_rgb;
+ _mouse_texture_rgb = 0;
+ }
+
+ setCursorPaletteInternal(colors, start, num);
+ _use_mouse_palette = true;
+}
+
+void OSystem_Android::disableCursorPalette(bool disable) {
+ ENTER("%d", disable);
+
+ // when disabling the cursor palette, and we're running a clut8 game,
+ // it expects the game palette to be used for the cursor
+ if (disable && _game_texture->hasPalette()) {
+ const byte *src = _game_texture->palette_const();
+ byte *dst = _mouse_texture_palette->palette();
+
+ const Graphics::PixelFormat &pf_src =
+ _game_texture->getPalettePixelFormat();
+ const Graphics::PixelFormat &pf_dst =
+ _mouse_texture_palette->getPalettePixelFormat();
+
+ uint8 r, g, b;
+
+ for (uint i = 0; i < 256; ++i, src += 2, dst += 2) {
+ pf_src.colorToRGB(READ_UINT16(src), r, g, b);
+ WRITE_UINT16(dst, pf_dst.RGBToColor(r, g, b));
+ }
+
+ WRITE_UINT16(_mouse_texture_palette->palette() + _mouse_keycolor * 2, 0);
+ }
+
+ _use_mouse_palette = !disable;
+}
+
+#endif
+
diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp
new file mode 100644
index 0000000000..92cb04904c
--- /dev/null
+++ b/backends/platform/android/jni.cpp
@@ -0,0 +1,602 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "base/main.h"
+#include "common/config-manager.h"
+#include "engines/engine.h"
+
+#include "backends/platform/android/android.h"
+#include "backends/platform/android/asset-archive.h"
+#include "backends/platform/android/jni.h"
+
+__attribute__ ((visibility("default")))
+jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
+ return JNI::onLoad(vm);
+}
+
+JavaVM *JNI::_vm = 0;
+jobject JNI::_jobj = 0;
+jobject JNI::_jobj_audio_track = 0;
+jobject JNI::_jobj_egl = 0;
+jobject JNI::_jobj_egl_display = 0;
+jobject JNI::_jobj_egl_surface = 0;
+
+Common::Archive *JNI::_asset_archive = 0;
+OSystem_Android *JNI::_system = 0;
+
+bool JNI::pause = false;
+sem_t JNI::pause_sem = { 0 };
+
+int JNI::surface_changeid = 0;
+int JNI::egl_surface_width = 0;
+int JNI::egl_surface_height = 0;
+bool JNI::_ready_for_events = 0;
+
+jmethodID JNI::_MID_getDPI = 0;
+jmethodID JNI::_MID_displayMessageOnOSD = 0;
+jmethodID JNI::_MID_setWindowCaption = 0;
+jmethodID JNI::_MID_showVirtualKeyboard = 0;
+jmethodID JNI::_MID_getSysArchives = 0;
+jmethodID JNI::_MID_getPluginDirectories = 0;
+jmethodID JNI::_MID_initSurface = 0;
+jmethodID JNI::_MID_deinitSurface = 0;
+
+jmethodID JNI::_MID_EGL10_eglSwapBuffers = 0;
+
+jmethodID JNI::_MID_AudioTrack_flush = 0;
+jmethodID JNI::_MID_AudioTrack_pause = 0;
+jmethodID JNI::_MID_AudioTrack_play = 0;
+jmethodID JNI::_MID_AudioTrack_stop = 0;
+jmethodID JNI::_MID_AudioTrack_write = 0;
+
+const JNINativeMethod JNI::_natives[] = {
+ { "create", "(Landroid/content/res/AssetManager;"
+ "Ljavax/microedition/khronos/egl/EGL10;"
+ "Ljavax/microedition/khronos/egl/EGLDisplay;"
+ "Landroid/media/AudioTrack;II)V",
+ (void *)JNI::create },
+ { "destroy", "()V",
+ (void *)JNI::destroy },
+ { "setSurface", "(II)V",
+ (void *)JNI::setSurface },
+ { "main", "([Ljava/lang/String;)I",
+ (void *)JNI::main },
+ { "pushEvent", "(IIIIII)V",
+ (void *)JNI::pushEvent },
+ { "enableZoning", "(Z)V",
+ (void *)JNI::enableZoning },
+ { "setPause", "(Z)V",
+ (void *)JNI::setPause }
+};
+
+JNI::JNI() {
+}
+
+JNI::~JNI() {
+}
+
+jint JNI::onLoad(JavaVM *vm) {
+ _vm = vm;
+
+ JNIEnv *env;
+
+ if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2))
+ return JNI_ERR;
+
+ jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM");
+ if (cls == 0)
+ return JNI_ERR;
+
+ if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 0)
+ return JNI_ERR;
+
+ return JNI_VERSION_1_2;
+}
+
+JNIEnv *JNI::getEnv() {
+ JNIEnv *env = 0;
+
+ jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2);
+
+ if (res != JNI_OK) {
+ LOGE("GetEnv() failed: %d", res);
+ abort();
+ }
+
+ return env;
+}
+
+void JNI::attachThread() {
+ JNIEnv *env = 0;
+
+ jint res = _vm->AttachCurrentThread(&env, 0);
+
+ if (res != JNI_OK) {
+ LOGE("AttachCurrentThread() failed: %d", res);
+ abort();
+ }
+}
+
+void JNI::detachThread() {
+ jint res = _vm->DetachCurrentThread();
+
+ if (res != JNI_OK) {
+ LOGE("DetachCurrentThread() failed: %d", res);
+ abort();
+ }
+}
+
+void JNI::setReadyForEvents(bool ready) {
+ _ready_for_events = ready;
+}
+
+void JNI::throwByName(JNIEnv *env, const char *name, const char *msg) {
+ jclass cls = env->FindClass(name);
+
+ // if cls is 0, an exception has already been thrown
+ if (cls != 0)
+ env->ThrowNew(cls, msg);
+
+ env->DeleteLocalRef(cls);
+}
+
+void JNI::throwRuntimeException(JNIEnv *env, const char *msg) {
+ throwByName(env, "java/lang/RuntimeException", msg);
+}
+
+// calls to the dark side
+
+void JNI::getDPI(float *values) {
+ values[0] = 0.0;
+ values[1] = 0.0;
+
+ JNIEnv *env = JNI::getEnv();
+
+ jfloatArray array = env->NewFloatArray(2);
+
+ env->CallVoidMethod(_jobj, _MID_getDPI, array);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Failed to get DPIs");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ } else {
+ jfloat *res = env->GetFloatArrayElements(array, 0);
+
+ if (res) {
+ values[0] = res[0];
+ values[1] = res[1];
+
+ env->ReleaseFloatArrayElements(array, res, 0);
+ }
+ }
+
+ env->DeleteLocalRef(array);
+}
+
+void JNI::displayMessageOnOSD(const char *msg) {
+ JNIEnv *env = JNI::getEnv();
+ jstring java_msg = env->NewStringUTF(msg);
+
+ env->CallVoidMethod(_jobj, _MID_displayMessageOnOSD, java_msg);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Failed to display OSD message");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ env->DeleteLocalRef(java_msg);
+}
+
+void JNI::setWindowCaption(const char *caption) {
+ JNIEnv *env = JNI::getEnv();
+ jstring java_caption = env->NewStringUTF(caption);
+
+ env->CallVoidMethod(_jobj, _MID_setWindowCaption, java_caption);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Failed to set window caption");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ env->DeleteLocalRef(java_caption);
+}
+
+void JNI::showVirtualKeyboard(bool enable) {
+ JNIEnv *env = JNI::getEnv();
+
+ env->CallVoidMethod(_jobj, _MID_showVirtualKeyboard, enable);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error trying to show virtual keyboard");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+void JNI::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
+ JNIEnv *env = JNI::getEnv();
+
+ s.add("ASSET", _asset_archive, priority, false);
+
+ jobjectArray array =
+ (jobjectArray)env->CallObjectMethod(_jobj, _MID_getSysArchives);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error finding system archive path");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ return;
+ }
+
+ jsize size = env->GetArrayLength(array);
+ for (jsize i = 0; i < size; ++i) {
+ jstring path_obj = (jstring)env->GetObjectArrayElement(array, i);
+ const char *path = env->GetStringUTFChars(path_obj, 0);
+
+ if (path != 0) {
+ s.addDirectory(path, path, priority);
+ env->ReleaseStringUTFChars(path_obj, path);
+ }
+
+ env->DeleteLocalRef(path_obj);
+ }
+}
+
+void JNI::getPluginDirectories(Common::FSList &dirs) {
+ JNIEnv *env = JNI::getEnv();
+
+ jobjectArray array =
+ (jobjectArray)env->CallObjectMethod(_jobj, _MID_getPluginDirectories);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error finding plugin directories");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ return;
+ }
+
+ jsize size = env->GetArrayLength(array);
+ for (jsize i = 0; i < size; ++i) {
+ jstring path_obj = (jstring)env->GetObjectArrayElement(array, i);
+
+ if (path_obj == 0)
+ continue;
+
+ const char *path = env->GetStringUTFChars(path_obj, 0);
+
+ if (path == 0) {
+ LOGE("Error getting string characters from plugin directory");
+
+ env->ExceptionClear();
+ env->DeleteLocalRef(path_obj);
+
+ continue;
+ }
+
+ dirs.push_back(Common::FSNode(path));
+
+ env->ReleaseStringUTFChars(path_obj, path);
+ env->DeleteLocalRef(path_obj);
+ }
+}
+
+bool JNI::initSurface() {
+ JNIEnv *env = JNI::getEnv();
+
+ jobject obj = env->CallObjectMethod(_jobj, _MID_initSurface);
+
+ if (!obj || env->ExceptionCheck()) {
+ LOGE("initSurface failed");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ return false;
+ }
+
+ _jobj_egl_surface = env->NewGlobalRef(obj);
+
+ return true;
+}
+
+void JNI::deinitSurface() {
+ JNIEnv *env = JNI::getEnv();
+
+ env->CallVoidMethod(_jobj, _MID_deinitSurface);
+
+ if (env->ExceptionCheck()) {
+ LOGE("deinitSurface failed");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ env->DeleteGlobalRef(_jobj_egl_surface);
+ _jobj_egl_surface = 0;
+}
+
+void JNI::setAudioPause() {
+ JNIEnv *env = JNI::getEnv();
+
+ env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_flush);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error flushing AudioTrack");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+
+ env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_pause);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error setting AudioTrack: pause");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+void JNI::setAudioPlay() {
+ JNIEnv *env = JNI::getEnv();
+
+ env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_play);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error setting AudioTrack: play");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+void JNI::setAudioStop() {
+ JNIEnv *env = JNI::getEnv();
+
+ env->CallVoidMethod(_jobj_audio_track, _MID_AudioTrack_stop);
+
+ if (env->ExceptionCheck()) {
+ LOGE("Error setting AudioTrack: stop");
+
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+}
+
+// natives for the dark side
+
+void JNI::create(JNIEnv *env, jobject self, jobject asset_manager,
+ jobject egl, jobject egl_display,
+ jobject at, jint audio_sample_rate, jint audio_buffer_size) {
+ assert(!_system);
+
+ pause = false;
+ // initial value of zero!
+ sem_init(&pause_sem, 0, 0);
+
+ _asset_archive = new AndroidAssetArchive(asset_manager);
+ assert(_asset_archive);
+
+ _system = new OSystem_Android(audio_sample_rate, audio_buffer_size);
+ assert(_system);
+
+ // weak global ref to allow class to be unloaded
+ // ... except dalvik implements NewWeakGlobalRef only on froyo
+ //_jobj = env->NewWeakGlobalRef(self);
+
+ _jobj = env->NewGlobalRef(self);
+
+ jclass cls = env->GetObjectClass(_jobj);
+
+#define FIND_METHOD(prefix, name, signature) do { \
+ _MID_ ## prefix ## name = env->GetMethodID(cls, #name, signature); \
+ if (_MID_ ## prefix ## name == 0) \
+ return; \
+ } while (0)
+
+ FIND_METHOD(, setWindowCaption, "(Ljava/lang/String;)V");
+ FIND_METHOD(, getDPI, "([F)V");
+ FIND_METHOD(, displayMessageOnOSD, "(Ljava/lang/String;)V");
+ FIND_METHOD(, showVirtualKeyboard, "(Z)V");
+ FIND_METHOD(, getSysArchives, "()[Ljava/lang/String;");
+ FIND_METHOD(, getPluginDirectories, "()[Ljava/lang/String;");
+ FIND_METHOD(, initSurface, "()Ljavax/microedition/khronos/egl/EGLSurface;");
+ FIND_METHOD(, deinitSurface, "()V");
+
+ _jobj_egl = env->NewGlobalRef(egl);
+ _jobj_egl_display = env->NewGlobalRef(egl_display);
+
+ cls = env->GetObjectClass(_jobj_egl);
+
+ FIND_METHOD(EGL10_, eglSwapBuffers,
+ "(Ljavax/microedition/khronos/egl/EGLDisplay;"
+ "Ljavax/microedition/khronos/egl/EGLSurface;)Z");
+
+ _jobj_audio_track = env->NewGlobalRef(at);
+
+ cls = env->GetObjectClass(_jobj_audio_track);
+
+ FIND_METHOD(AudioTrack_, flush, "()V");
+ FIND_METHOD(AudioTrack_, pause, "()V");
+ FIND_METHOD(AudioTrack_, play, "()V");
+ FIND_METHOD(AudioTrack_, stop, "()V");
+ FIND_METHOD(AudioTrack_, write, "([BII)I");
+
+#undef FIND_METHOD
+
+ g_system = _system;
+}
+
+void JNI::destroy(JNIEnv *env, jobject self) {
+ delete _asset_archive;
+ _asset_archive = 0;
+
+ delete _system;
+ g_system = 0;
+ _system = 0;
+
+ sem_destroy(&pause_sem);
+
+ // see above
+ //JNI::getEnv()->DeleteWeakGlobalRef(_jobj);
+
+ JNI::getEnv()->DeleteGlobalRef(_jobj_egl_display);
+ JNI::getEnv()->DeleteGlobalRef(_jobj_egl);
+ JNI::getEnv()->DeleteGlobalRef(_jobj_audio_track);
+ JNI::getEnv()->DeleteGlobalRef(_jobj);
+}
+
+void JNI::setSurface(JNIEnv *env, jobject self, jint width, jint height) {
+ egl_surface_width = width;
+ egl_surface_height = height;
+ surface_changeid++;
+}
+
+jint JNI::main(JNIEnv *env, jobject self, jobjectArray args) {
+ assert(_system);
+
+ const int MAX_NARGS = 32;
+ int res = -1;
+
+ int argc = env->GetArrayLength(args);
+ if (argc > MAX_NARGS) {
+ throwByName(env, "java/lang/IllegalArgumentException",
+ "too many arguments");
+ return 0;
+ }
+
+ char *argv[MAX_NARGS];
+
+ // note use in cleanup loop below
+ int nargs;
+
+ for (nargs = 0; nargs < argc; ++nargs) {
+ jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
+
+ if (arg == 0) {
+ argv[nargs] = 0;
+ } else {
+ const char *cstr = env->GetStringUTFChars(arg, 0);
+
+ argv[nargs] = const_cast<char *>(cstr);
+
+ // exception already thrown?
+ if (cstr == 0)
+ goto cleanup;
+ }
+
+ env->DeleteLocalRef(arg);
+ }
+
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new AndroidPluginProvider());
+#endif
+
+ LOGI("Entering scummvm_main with %d args", argc);
+
+ res = scummvm_main(argc, argv);
+
+ LOGI("scummvm_main exited with code %d", res);
+
+ _system->quit();
+
+cleanup:
+ nargs--;
+
+ for (int i = 0; i < nargs; ++i) {
+ if (argv[i] == 0)
+ continue;
+
+ jstring arg = (jstring)env->GetObjectArrayElement(args, nargs);
+
+ // Exception already thrown?
+ if (arg == 0)
+ return res;
+
+ env->ReleaseStringUTFChars(arg, argv[i]);
+ env->DeleteLocalRef(arg);
+ }
+
+ return res;
+}
+
+void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2,
+ int arg3, int arg4, int arg5) {
+ // drop events until we're ready and after we quit
+ if (!_ready_for_events) {
+ LOGW("dropping event");
+ return;
+ }
+
+ assert(_system);
+
+ _system->pushEvent(type, arg1, arg2, arg3, arg4, arg5);
+}
+
+void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) {
+ assert(_system);
+
+ _system->enableZoning(enable);
+}
+
+void JNI::setPause(JNIEnv *env, jobject self, jboolean value) {
+ if (!_system)
+ return;
+
+ if (g_engine) {
+ LOGD("pauseEngine: %d", value);
+
+ g_engine->pauseEngine(value);
+
+ if (value &&
+ g_engine->hasFeature(Engine::kSupportsSavingDuringRuntime) &&
+ g_engine->canSaveGameStateCurrently())
+ g_engine->saveGameState(0, "Android parachute");
+ }
+
+ pause = value;
+
+ if (!pause) {
+ // wake up all threads
+ for (uint i = 0; i < 3; ++i)
+ sem_post(&pause_sem);
+ }
+}
+
+#endif
+
diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h
new file mode 100644
index 0000000000..d029f1a2a8
--- /dev/null
+++ b/backends/platform/android/jni.h
@@ -0,0 +1,151 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef _ANDROID_JNI_H_
+#define _ANDROID_JNI_H_
+
+#if defined(__ANDROID__)
+
+#include <jni.h>
+#include <semaphore.h>
+
+#include "common/fs.h"
+#include "common/archive.h"
+
+class OSystem_Android;
+
+class JNI {
+private:
+ JNI();
+ virtual ~JNI();
+
+public:
+ static bool pause;
+ static sem_t pause_sem;
+
+ static int surface_changeid;
+ static int egl_surface_width;
+ static int egl_surface_height;
+
+ static jint onLoad(JavaVM *vm);
+
+ static JNIEnv *getEnv();
+
+ static void attachThread();
+ static void detachThread();
+
+ static void setReadyForEvents(bool ready);
+
+ static void getPluginDirectories(Common::FSList &dirs);
+ static void setWindowCaption(const char *caption);
+ static void getDPI(float *values);
+ static void displayMessageOnOSD(const char *msg);
+ static void showVirtualKeyboard(bool enable);
+ static void addSysArchivesToSearchSet(Common::SearchSet &s, int priority);
+
+ static inline bool haveSurface();
+ static inline bool swapBuffers();
+ static bool initSurface();
+ static void deinitSurface();
+
+ static void setAudioPause();
+ static void setAudioPlay();
+ static void setAudioStop();
+
+ static inline int writeAudio(JNIEnv *env, jbyteArray &data, int offset,
+ int size);
+
+private:
+ static JavaVM *_vm;
+ // back pointer to (java) peer instance
+ static jobject _jobj;
+ static jobject _jobj_audio_track;
+ static jobject _jobj_egl;
+ static jobject _jobj_egl_display;
+ static jobject _jobj_egl_surface;
+
+ static Common::Archive *_asset_archive;
+ static OSystem_Android *_system;
+
+ static bool _ready_for_events;
+
+ static jmethodID _MID_getDPI;
+ static jmethodID _MID_displayMessageOnOSD;
+ static jmethodID _MID_setWindowCaption;
+ static jmethodID _MID_showVirtualKeyboard;
+ static jmethodID _MID_getSysArchives;
+ static jmethodID _MID_getPluginDirectories;
+ static jmethodID _MID_initSurface;
+ static jmethodID _MID_deinitSurface;
+
+ static jmethodID _MID_EGL10_eglSwapBuffers;
+
+ static jmethodID _MID_AudioTrack_flush;
+ static jmethodID _MID_AudioTrack_pause;
+ static jmethodID _MID_AudioTrack_play;
+ static jmethodID _MID_AudioTrack_stop;
+ static jmethodID _MID_AudioTrack_write;
+
+ static const JNINativeMethod _natives[];
+
+ static void throwByName(JNIEnv *env, const char *name, const char *msg);
+ static void throwRuntimeException(JNIEnv *env, const char *msg);
+
+ // natives for the dark side
+ static void create(JNIEnv *env, jobject self, jobject asset_manager,
+ jobject egl, jobject egl_display,
+ jobject at, jint audio_sample_rate,
+ jint audio_buffer_size);
+ static void destroy(JNIEnv *env, jobject self);
+
+ static void setSurface(JNIEnv *env, jobject self, jint width, jint height);
+ static jint main(JNIEnv *env, jobject self, jobjectArray args);
+
+ static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,
+ int arg2, int arg3, int arg4, int arg5);
+ static void enableZoning(JNIEnv *env, jobject self, jboolean enable);
+
+ static void setPause(JNIEnv *env, jobject self, jboolean value);
+};
+
+inline bool JNI::haveSurface() {
+ return _jobj_egl_surface != 0;
+}
+
+inline bool JNI::swapBuffers() {
+ JNIEnv *env = JNI::getEnv();
+
+ return env->CallBooleanMethod(_jobj_egl, _MID_EGL10_eglSwapBuffers,
+ _jobj_egl_display, _jobj_egl_surface);
+}
+
+inline int JNI::writeAudio(JNIEnv *env, jbyteArray &data, int offset, int size) {
+ return env->CallIntMethod(_jobj_audio_track, _MID_AudioTrack_write, data,
+ offset, size);
+}
+
+#endif
+#endif
+
diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk
index 8b120b21ff..2fe4b40585 100644
--- a/backends/platform/android/module.mk
+++ b/backends/platform/android/module.mk
@@ -1,9 +1,12 @@
MODULE := backends/platform/android
MODULE_OBJS := \
- android.o \
+ jni.o \
+ texture.o \
asset-archive.o \
- video.o
+ android.o \
+ gfx.o \
+ events.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java
index 5b71d4a3a5..cede7eedd4 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java
@@ -19,13 +19,13 @@ public class EditableSurfaceView extends SurfaceView {
}
public EditableSurfaceView(Context context, AttributeSet attrs,
- int defStyle) {
+ int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onCheckIsTextEditor() {
- return true;
+ return false;
}
private class MyInputConnection extends BaseInputConnection {
@@ -40,7 +40,9 @@ public class EditableSurfaceView extends SurfaceView {
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindowToken(), 0);
}
- return super.performEditorAction(actionCode); // Sends enter key
+
+ // Sends enter key
+ return super.performEditorAction(actionCode);
}
}
@@ -49,11 +51,12 @@ public class EditableSurfaceView extends SurfaceView {
outAttrs.initialCapsMode = 0;
outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
outAttrs.inputType = (InputType.TYPE_CLASS_TEXT |
- InputType.TYPE_TEXT_VARIATION_NORMAL |
- InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
+ InputType.TYPE_TEXT_VARIATION_NORMAL |
+ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
outAttrs.imeOptions = (EditorInfo.IME_ACTION_DONE |
- EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+ EditorInfo.IME_FLAG_NO_EXTRACT_UI);
return new MyInputConnection();
}
}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/Event.java b/backends/platform/android/org/inodes/gus/scummvm/Event.java
deleted file mode 100644
index f9c7aba93b..0000000000
--- a/backends/platform/android/org/inodes/gus/scummvm/Event.java
+++ /dev/null
@@ -1,330 +0,0 @@
-package org.inodes.gus.scummvm;
-
-import android.view.KeyEvent;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class Event {
- // Common::EventType enum.
- // Must be kept in sync with common/events.h
- public final static int EVENT_INVALID = 0;
- public final static int EVENT_KEYDOWN = 1;
- public final static int EVENT_KEYUP = 2;
- public final static int EVENT_MOUSEMOVE = 3;
- public final static int EVENT_LBUTTONDOWN = 4;
- public final static int EVENT_LBUTTONUP = 5;
- public final static int EVENT_RBUTTONDOWN = 6;
- public final static int EVENT_RBUTTONUP = 7;
- public final static int EVENT_WHEELUP = 8;
- public final static int EVENT_WHEELDOWN = 9;
- public final static int EVENT_QUIT = 10;
- public final static int EVENT_SCREEN_CHANGED = 11;
- public final static int EVENT_PREDICTIVE_DIALOG = 12;
- public final static int EVENT_MBUTTONDOWN = 13;
- public final static int EVENT_MBUTTONUP = 14;
- public final static int EVENT_MAINMENU = 15;
- public final static int EVENT_RTL = 16;
-
- // common/keyboard.h
- public final static int ASCII_F1 = 315;
- public final static int ASCII_F2 = 316;
- public final static int ASCII_F3 = 317;
- public final static int ASCII_F4 = 318;
- public final static int ASCII_F5 = 319;
- public final static int ASCII_F6 = 320;
- public final static int ASCII_F7 = 321;
- public final static int ASCII_F8 = 322;
- public final static int ASCII_F9 = 323;
- public final static int ASCII_F10 = 324;
- public final static int ASCII_F11 = 325;
- public final static int ASCII_F12 = 326;
- public final static int KBD_CTRL = 1 << 0;
- public final static int KBD_ALT = 1 << 1;
- public final static int KBD_SHIFT = 1 << 2;
-
- public final static int KEYCODE_INVALID = 0;
- public final static int KEYCODE_BACKSPACE = 8;
- public final static int KEYCODE_TAB = 9;
- public final static int KEYCODE_CLEAR = 12;
- public final static int KEYCODE_RETURN = 13;
- public final static int KEYCODE_PAUSE = 19;
- public final static int KEYCODE_ESCAPE = 27;
- public final static int KEYCODE_SPACE = 32;
- public final static int KEYCODE_EXCLAIM = 33;
- public final static int KEYCODE_QUOTEDBL = 34;
- public final static int KEYCODE_HASH = 35;
- public final static int KEYCODE_DOLLAR = 36;
- public final static int KEYCODE_AMPERSAND = 38;
- public final static int KEYCODE_QUOTE = 39;
- public final static int KEYCODE_LEFTPAREN = 40;
- public final static int KEYCODE_RIGHTPAREN = 41;
- public final static int KEYCODE_ASTERISK = 42;
- public final static int KEYCODE_PLUS = 43;
- public final static int KEYCODE_COMMA = 44;
- public final static int KEYCODE_MINUS = 45;
- public final static int KEYCODE_PERIOD = 46;
- public final static int KEYCODE_SLASH = 47;
- public final static int KEYCODE_0 = 48;
- public final static int KEYCODE_1 = 49;
- public final static int KEYCODE_2 = 50;
- public final static int KEYCODE_3 = 51;
- public final static int KEYCODE_4 = 52;
- public final static int KEYCODE_5 = 53;
- public final static int KEYCODE_6 = 54;
- public final static int KEYCODE_7 = 55;
- public final static int KEYCODE_8 = 56;
- public final static int KEYCODE_9 = 57;
- public final static int KEYCODE_COLON = 58;
- public final static int KEYCODE_SEMICOLON = 59;
- public final static int KEYCODE_LESS = 60;
- public final static int KEYCODE_EQUALS = 61;
- public final static int KEYCODE_GREATER = 62;
- public final static int KEYCODE_QUESTION = 63;
- public final static int KEYCODE_AT = 64;
- public final static int KEYCODE_LEFTBRACKET = 91;
- public final static int KEYCODE_BACKSLASH = 92;
- public final static int KEYCODE_RIGHTBRACKET = 93;
- public final static int KEYCODE_CARET = 94;
- public final static int KEYCODE_UNDERSCORE = 95;
- public final static int KEYCODE_BACKQUOTE = 96;
- public final static int KEYCODE_a = 97;
- public final static int KEYCODE_b = 98;
- public final static int KEYCODE_c = 99;
- public final static int KEYCODE_d = 100;
- public final static int KEYCODE_e = 101;
- public final static int KEYCODE_f = 102;
- public final static int KEYCODE_g = 103;
- public final static int KEYCODE_h = 104;
- public final static int KEYCODE_i = 105;
- public final static int KEYCODE_j = 106;
- public final static int KEYCODE_k = 107;
- public final static int KEYCODE_l = 108;
- public final static int KEYCODE_m = 109;
- public final static int KEYCODE_n = 110;
- public final static int KEYCODE_o = 111;
- public final static int KEYCODE_p = 112;
- public final static int KEYCODE_q = 113;
- public final static int KEYCODE_r = 114;
- public final static int KEYCODE_s = 115;
- public final static int KEYCODE_t = 116;
- public final static int KEYCODE_u = 117;
- public final static int KEYCODE_v = 118;
- public final static int KEYCODE_w = 119;
- public final static int KEYCODE_x = 120;
- public final static int KEYCODE_y = 121;
- public final static int KEYCODE_z = 122;
- public final static int KEYCODE_DELETE = 127;
- // Numeric keypad
- public final static int KEYCODE_KP0 = 256;
- public final static int KEYCODE_KP1 = 257;
- public final static int KEYCODE_KP2 = 258;
- public final static int KEYCODE_KP3 = 259;
- public final static int KEYCODE_KP4 = 260;
- public final static int KEYCODE_KP5 = 261;
- public final static int KEYCODE_KP6 = 262;
- public final static int KEYCODE_KP7 = 263;
- public final static int KEYCODE_KP8 = 264;
- public final static int KEYCODE_KP9 = 265;
- public final static int KEYCODE_KP_PERIOD = 266;
- public final static int KEYCODE_KP_DIVIDE = 267;
- public final static int KEYCODE_KP_MULTIPLY = 268;
- public final static int KEYCODE_KP_MINUS = 269;
- public final static int KEYCODE_KP_PLUS = 270;
- public final static int KEYCODE_KP_ENTER = 271;
- public final static int KEYCODE_KP_EQUALS = 272;
- // Arrows + Home/End pad
- public final static int KEYCODE_UP = 273;
- public final static int KEYCODE_DOWN = 274;
- public final static int KEYCODE_RIGHT = 275;
- public final static int KEYCODE_LEFT = 276;
- public final static int KEYCODE_INSERT = 277;
- public final static int KEYCODE_HOME = 278;
- public final static int KEYCODE_END = 279;
- public final static int KEYCODE_PAGEUP = 280;
- public final static int KEYCODE_PAGEDOWN = 281;
- // Function keys
- public final static int KEYCODE_F1 = 282;
- public final static int KEYCODE_F2 = 283;
- public final static int KEYCODE_F3 = 284;
- public final static int KEYCODE_F4 = 285;
- public final static int KEYCODE_F5 = 286;
- public final static int KEYCODE_F6 = 287;
- public final static int KEYCODE_F7 = 288;
- public final static int KEYCODE_F8 = 289;
- public final static int KEYCODE_F9 = 290;
- public final static int KEYCODE_F10 = 291;
- public final static int KEYCODE_F11 = 292;
- public final static int KEYCODE_F12 = 293;
- public final static int KEYCODE_F13 = 294;
- public final static int KEYCODE_F14 = 295;
- public final static int KEYCODE_F15 = 296;
- // Key state modifier keys
- public final static int KEYCODE_NUMLOCK = 300;
- public final static int KEYCODE_CAPSLOCK = 301;
- public final static int KEYCODE_SCROLLOCK = 302;
- public final static int KEYCODE_RSHIFT = 303;
- public final static int KEYCODE_LSHIFT = 304;
- public final static int KEYCODE_RCTRL = 305;
- public final static int KEYCODE_LCTRL = 306;
- public final static int KEYCODE_RALT = 307;
- public final static int KEYCODE_LALT = 308;
- public final static int KEYCODE_RMETA = 309;
- public final static int KEYCODE_LMETA = 310;
- public final static int KEYCODE_LSUPER = 311; // Left "Windows" key
- public final static int KEYCODE_RSUPER = 312; // Right "Windows" key
- public final static int KEYCODE_MODE = 313; // "Alt Gr" key
- public final static int KEYCODE_COMPOSE = 314; // Multi-key compose key
- // Miscellaneous function keys
- public final static int KEYCODE_HELP = 315;
- public final static int KEYCODE_PRINT = 316;
- public final static int KEYCODE_SYSREQ = 317;
- public final static int KEYCODE_BREAK = 318;
- public final static int KEYCODE_MENU = 319;
- public final static int KEYCODE_POWER = 320; // Power Macintosh power key
- public final static int KEYCODE_EURO = 321; // Some european keyboards
- public final static int KEYCODE_UNDO = 322; // Atari keyboard has Undo
-
- // Android KeyEvent keycode -> ScummVM keycode
- public final static Map<Integer, Integer> androidKeyMap;
- static {
- Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
- map.put(KeyEvent.KEYCODE_DEL, KEYCODE_BACKSPACE);
- map.put(KeyEvent.KEYCODE_TAB, KEYCODE_TAB);
- map.put(KeyEvent.KEYCODE_CLEAR, KEYCODE_CLEAR);
- map.put(KeyEvent.KEYCODE_ENTER, KEYCODE_RETURN);
- //map.put(??, KEYCODE_PAUSE);
- map.put(KeyEvent.KEYCODE_BACK, KEYCODE_ESCAPE);
- map.put(KeyEvent.KEYCODE_SPACE, KEYCODE_SPACE);
- //map.put(??, KEYCODE_EXCLAIM);
- //map.put(??, KEYCODE_QUOTEDBL);
- map.put(KeyEvent.KEYCODE_POUND, KEYCODE_HASH);
- //map.put(??, KEYCODE_DOLLAR);
- //map.put(??, KEYCODE_AMPERSAND);
- map.put(KeyEvent.KEYCODE_APOSTROPHE, KEYCODE_QUOTE);
- //map.put(??, KEYCODE_LEFTPAREN);
- //map.put(??, KEYCODE_RIGHTPAREN);
- //map.put(??, KEYCODE_ASTERISK);
- map.put(KeyEvent.KEYCODE_PLUS, KEYCODE_PLUS);
- map.put(KeyEvent.KEYCODE_COMMA, KEYCODE_COMMA);
- map.put(KeyEvent.KEYCODE_MINUS, KEYCODE_MINUS);
- map.put(KeyEvent.KEYCODE_PERIOD, KEYCODE_PERIOD);
- map.put(KeyEvent.KEYCODE_SLASH, KEYCODE_SLASH);
- map.put(KeyEvent.KEYCODE_0, KEYCODE_0);
- map.put(KeyEvent.KEYCODE_1, KEYCODE_1);
- map.put(KeyEvent.KEYCODE_2, KEYCODE_2);
- map.put(KeyEvent.KEYCODE_3, KEYCODE_3);
- map.put(KeyEvent.KEYCODE_4, KEYCODE_4);
- map.put(KeyEvent.KEYCODE_5, KEYCODE_5);
- map.put(KeyEvent.KEYCODE_6, KEYCODE_6);
- map.put(KeyEvent.KEYCODE_7, KEYCODE_7);
- map.put(KeyEvent.KEYCODE_8, KEYCODE_8);
- map.put(KeyEvent.KEYCODE_9, KEYCODE_9);
- //map.put(??, KEYCODE_COLON);
- map.put(KeyEvent.KEYCODE_SEMICOLON, KEYCODE_SEMICOLON);
- //map.put(??, KEYCODE_LESS);
- map.put(KeyEvent.KEYCODE_EQUALS, KEYCODE_EQUALS);
- //map.put(??, KEYCODE_GREATER);
- //map.put(??, KEYCODE_QUESTION);
- map.put(KeyEvent.KEYCODE_AT, KEYCODE_AT);
- map.put(KeyEvent.KEYCODE_LEFT_BRACKET, KEYCODE_LEFTBRACKET);
- map.put(KeyEvent.KEYCODE_BACKSLASH, KEYCODE_BACKSLASH);
- map.put(KeyEvent.KEYCODE_RIGHT_BRACKET, KEYCODE_RIGHTBRACKET);
- //map.put(??, KEYCODE_CARET);
- //map.put(??, KEYCODE_UNDERSCORE);
- //map.put(??, KEYCODE_BACKQUOTE);
- map.put(KeyEvent.KEYCODE_A, KEYCODE_a);
- map.put(KeyEvent.KEYCODE_B, KEYCODE_b);
- map.put(KeyEvent.KEYCODE_C, KEYCODE_c);
- map.put(KeyEvent.KEYCODE_D, KEYCODE_d);
- map.put(KeyEvent.KEYCODE_E, KEYCODE_e);
- map.put(KeyEvent.KEYCODE_F, KEYCODE_f);
- map.put(KeyEvent.KEYCODE_G, KEYCODE_g);
- map.put(KeyEvent.KEYCODE_H, KEYCODE_h);
- map.put(KeyEvent.KEYCODE_I, KEYCODE_i);
- map.put(KeyEvent.KEYCODE_J, KEYCODE_j);
- map.put(KeyEvent.KEYCODE_K, KEYCODE_k);
- map.put(KeyEvent.KEYCODE_L, KEYCODE_l);
- map.put(KeyEvent.KEYCODE_M, KEYCODE_m);
- map.put(KeyEvent.KEYCODE_N, KEYCODE_n);
- map.put(KeyEvent.KEYCODE_O, KEYCODE_o);
- map.put(KeyEvent.KEYCODE_P, KEYCODE_p);
- map.put(KeyEvent.KEYCODE_Q, KEYCODE_q);
- map.put(KeyEvent.KEYCODE_R, KEYCODE_r);
- map.put(KeyEvent.KEYCODE_S, KEYCODE_s);
- map.put(KeyEvent.KEYCODE_T, KEYCODE_t);
- map.put(KeyEvent.KEYCODE_U, KEYCODE_u);
- map.put(KeyEvent.KEYCODE_V, KEYCODE_v);
- map.put(KeyEvent.KEYCODE_W, KEYCODE_w);
- map.put(KeyEvent.KEYCODE_X, KEYCODE_x);
- map.put(KeyEvent.KEYCODE_Y, KEYCODE_y);
- map.put(KeyEvent.KEYCODE_Z, KEYCODE_z);
- //map.put(KeyEvent.KEYCODE_DEL, KEYCODE_DELETE); use BACKSPACE instead
- //map.put(??, KEYCODE_KP_*);
- map.put(KeyEvent.KEYCODE_DPAD_UP, KEYCODE_UP);
- map.put(KeyEvent.KEYCODE_DPAD_DOWN, KEYCODE_DOWN);
- map.put(KeyEvent.KEYCODE_DPAD_RIGHT, KEYCODE_RIGHT);
- map.put(KeyEvent.KEYCODE_DPAD_LEFT, KEYCODE_LEFT);
- //map.put(??, KEYCODE_INSERT);
- //map.put(??, KEYCODE_HOME);
- //map.put(??, KEYCODE_END);
- //map.put(??, KEYCODE_PAGEUP);
- //map.put(??, KEYCODE_PAGEDOWN);
- //map.put(??, KEYCODE_F{1-15});
- map.put(KeyEvent.KEYCODE_NUM, KEYCODE_NUMLOCK);
- //map.put(??, KEYCODE_CAPSLOCK);
- //map.put(??, KEYCODE_SCROLLLOCK);
- map.put(KeyEvent.KEYCODE_SHIFT_RIGHT, KEYCODE_RSHIFT);
- map.put(KeyEvent.KEYCODE_SHIFT_LEFT, KEYCODE_LSHIFT);
- //map.put(??, KEYCODE_RCTRL);
- //map.put(??, KEYCODE_LCTRL);
- map.put(KeyEvent.KEYCODE_ALT_RIGHT, KEYCODE_RALT);
- map.put(KeyEvent.KEYCODE_ALT_LEFT, KEYCODE_LALT);
- // ?? META, SUPER
- // ?? MODE, COMPOSE
- // ?? HELP, PRINT, SYSREQ, BREAK, EURO, UNDO
- map.put(KeyEvent.KEYCODE_MENU, KEYCODE_MENU);
- map.put(KeyEvent.KEYCODE_POWER, KEYCODE_POWER);
-
- androidKeyMap = Collections.unmodifiableMap(map);
- }
-
- public int type;
- public boolean synthetic;
- public int kbd_keycode;
- public int kbd_ascii;
- public int kbd_flags;
- public int mouse_x;
- public int mouse_y;
- public boolean mouse_relative; // Used for trackball events
-
- public Event() {
- type = EVENT_INVALID;
- synthetic = false;
- }
-
- public Event(int type) {
- this.type = type;
- synthetic = false;
- }
-
- public static Event KeyboardEvent(int type, int keycode, int ascii,
- int flags) {
- Event e = new Event();
- e.type = type;
- e.kbd_keycode = keycode;
- e.kbd_ascii = ascii;
- e.kbd_flags = flags;
- return e;
- }
-
- public static Event MouseEvent(int type, int x, int y) {
- Event e = new Event();
- e.type = type;
- e.mouse_x = x;
- e.mouse_y = y;
- return e;
- }
-}
diff --git a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java
index c94ab0a3ff..3c91d9f5dc 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java
@@ -28,7 +28,7 @@ public class PluginProvider extends BroadcastReceiver {
try {
info = context.getPackageManager()
.getReceiverInfo(new ComponentName(context, this.getClass()),
- PackageManager.GET_META_DATA);
+ PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
Log.e(LOG_TAG, "Error finding my own info?", e);
return;
@@ -38,17 +38,17 @@ public class PluginProvider extends BroadcastReceiver {
if (mylib != null) {
ArrayList<String> all_libs =
extras.getStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS);
-
all_libs.add(new Uri.Builder()
- .scheme("plugin")
- .authority(context.getPackageName())
- .path(mylib)
- .toString());
+ .scheme("plugin")
+ .authority(context.getPackageName())
+ .path(mylib)
+ .toString());
extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS,
- all_libs);
+ all_libs);
}
setResultExtras(extras);
}
}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index 0e905f43a5..fe225af48b 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -1,446 +1,427 @@
package org.inodes.gus.scummvm;
-import android.content.Context;
+import android.util.Log;
import android.content.res.AssetManager;
+import android.view.SurfaceHolder;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
-import java.util.concurrent.Semaphore;
-import java.util.Map;
import java.util.LinkedHashMap;
+public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
+ final protected static String LOG_TAG = "ScummVM";
+ final private AssetManager _asset_manager;
+ final private Object _sem_surface;
+
+ private EGL10 _egl;
+ private EGLDisplay _egl_display = EGL10.EGL_NO_DISPLAY;
+ private EGLConfig _egl_config;
+ private EGLContext _egl_context = EGL10.EGL_NO_CONTEXT;
+ private EGLSurface _egl_surface = EGL10.EGL_NO_SURFACE;
+
+ private SurfaceHolder _surface_holder;
+ private AudioTrack _audio_track;
+ private int _sample_rate = 0;
+ private int _buffer_size = 0;
+
+ private String[] _args;
+
+ final private native void create(AssetManager _asset_manager,
+ EGL10 egl, EGLDisplay egl_display,
+ AudioTrack audio_track,
+ int sample_rate, int buffer_size);
+ final private native void destroy();
+ final private native void setSurface(int width, int height);
+ final private native int main(String[] args);
+
+ // pause the engine and all native threads
+ final public native void setPause(boolean pause);
+ final public native void enableZoning(boolean enable);
+ // Feed an event to ScummVM. Safe to call from other threads.
+ final public native void pushEvent(int type, int arg1, int arg2, int arg3,
+ int arg4, int arg5);
-// At least in Android 2.1, eglCreateWindowSurface() requires an
-// EGLNativeWindowSurface object, which is hidden deep in the bowels
-// of libui. Until EGL is properly exposed, it's probably safer to
-// use the Java versions of most EGL functions :(
-
-public class ScummVM implements SurfaceHolder.Callback {
- protected final static String LOG_TAG = "ScummVM";
+ // Callbacks from C++ peer instance
+ abstract protected void getDPI(float[] values);
+ abstract protected void displayMessageOnOSD(String msg);
+ abstract protected void setWindowCaption(String caption);
+ abstract protected String[] getPluginDirectories();
+ abstract protected void showVirtualKeyboard(boolean enable);
+ abstract protected String[] getSysArchives();
- private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo
- public static class AudioSetupException extends Exception {}
+ public ScummVM(AssetManager asset_manager, SurfaceHolder holder) {
+ _asset_manager = asset_manager;
+ _sem_surface = new Object();
- private long nativeScummVM; // native code hangs itself here
- boolean scummVMRunning = false;
+ holder.addCallback(this);
+ }
- private native void create(AssetManager am);
+ // SurfaceHolder callback
+ final public void surfaceCreated(SurfaceHolder holder) {
+ Log.d(LOG_TAG, "surfaceCreated");
- public ScummVM(Context context) {
- create(context.getAssets()); // Init C++ code, set nativeScummVM
+ // no need to do anything, surfaceChanged() will be called in any case
}
- private native void nativeDestroy();
+ // SurfaceHolder callback
+ final public void surfaceChanged(SurfaceHolder holder, int format,
+ int width, int height) {
+ Log.d(LOG_TAG, String.format("surfaceChanged: %dx%d (%d)",
+ width, height, format));
- public synchronized void destroy() {
- if (nativeScummVM != 0) {
- nativeDestroy();
- nativeScummVM = 0;
+ synchronized(_sem_surface) {
+ _surface_holder = holder;
+ _sem_surface.notifyAll();
}
- }
- protected void finalize() {
- destroy();
- }
- // Surface creation:
- // GUI thread: create surface, release lock
- // ScummVM thread: acquire lock (block), read surface
- //
- // Surface deletion:
- // GUI thread: post event, acquire lock (block), return
- // ScummVM thread: read event, free surface, release lock
- //
- // In other words, ScummVM thread does this:
- // acquire lock
- // setup surface
- // when SCREEN_CHANGED arrives:
- // destroy surface
- // release lock
- // back to acquire lock
- static final int configSpec[] = {
- EGL10.EGL_RED_SIZE, 5,
- EGL10.EGL_GREEN_SIZE, 5,
- EGL10.EGL_BLUE_SIZE, 5,
- EGL10.EGL_DEPTH_SIZE, 0,
- EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
- EGL10.EGL_NONE,
- };
- EGL10 egl;
- EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY;
- EGLConfig eglConfig;
- EGLContext eglContext = EGL10.EGL_NO_CONTEXT;
- EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
- Semaphore surfaceLock = new Semaphore(0, true);
- SurfaceHolder nativeSurface;
-
- public void surfaceCreated(SurfaceHolder holder) {
- nativeSurface = holder;
- surfaceLock.release();
+ // store values for the native code
+ setSurface(width, height);
}
- public void surfaceChanged(SurfaceHolder holder, int format,
- int width, int height) {
- // Disabled while I debug GL problems
- pushEvent(new Event(Event.EVENT_SCREEN_CHANGED));
- }
+ // SurfaceHolder callback
+ final public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.d(LOG_TAG, "surfaceDestroyed");
- public void surfaceDestroyed(SurfaceHolder holder) {
- try {
- surfaceLock.acquire();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e);
+ synchronized(_sem_surface) {
+ _surface_holder = null;
+ _sem_surface.notifyAll();
}
+
+ // clear values for the native code
+ setSurface(0, 0);
}
- // For debugging
- private static final Map<String, Integer> attribs;
- static {
- attribs = new LinkedHashMap<String, Integer>();
- attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID);
- attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE);
- attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE);
- attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE);
- attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE);
- attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE);
- //attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB);
- //attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA);
- attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT);
- attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE);
- attribs.put("LEVEL", EGL10.EGL_LEVEL);
- attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH);
- attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT);
- attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS);
- //attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL);
- //attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL);
- attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE);
- attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID);
- attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE);
- attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS);
- attribs.put("SAMPLES", EGL10.EGL_SAMPLES);
- attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE);
- attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE);
- attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE);
- attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE);
- attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE);
- attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE);
+ final public void setArgs(String[] args) {
+ _args = args;
}
- private void dumpEglConfig(EGLConfig config) {
- int[] value = new int[1];
- for (Map.Entry<String, Integer> entry : attribs.entrySet()) {
- egl.eglGetConfigAttrib(eglDisplay, config,
- entry.getValue(), value);
- if (value[0] == EGL10.EGL_NONE)
- Log.d(LOG_TAG, entry.getKey() + ": NONE");
- else
- Log.d(LOG_TAG, String.format("%s: %d", entry.getKey(), value[0]));
+
+ final public void run() {
+ try {
+ initAudio();
+ initEGL();
+
+ // wait for the surfaceChanged callback
+ synchronized(_sem_surface) {
+ while (_surface_holder == null)
+ _sem_surface.wait();
+ }
+ } catch (Exception e) {
+ deinitEGL();
+ deinitAudio();
+
+ throw new RuntimeException("Error preparing the ScummVM thread", e);
}
+
+ create(_asset_manager, _egl, _egl_display,
+ _audio_track, _sample_rate, _buffer_size);
+
+ int res = main(_args);
+
+ destroy();
+
+ deinitEGL();
+ deinitAudio();
+
+ // On exit, tear everything down for a fresh restart next time.
+ System.exit(res);
}
- // Called by ScummVM thread (from initBackend)
- private void createScummVMGLContext() {
- egl = (EGL10)EGLContext.getEGL();
- eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ final private void initEGL() throws Exception {
+ _egl = (EGL10)EGLContext.getEGL();
+ _egl_display = _egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
int[] version = new int[2];
- egl.eglInitialize(eglDisplay, version);
+ _egl.eglInitialize(_egl_display, version);
+
int[] num_config = new int[1];
- egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config);
+ _egl.eglGetConfigs(_egl_display, null, 0, num_config);
final int numConfigs = num_config[0];
+
if (numConfigs <= 0)
- throw new IllegalArgumentException("No configs match configSpec");
+ throw new IllegalArgumentException("No EGL configs");
EGLConfig[] configs = new EGLConfig[numConfigs];
- egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs,
- num_config);
-
- if (false) {
- Log.d(LOG_TAG, String.format("Found %d EGL configurations.", numConfigs));
- for (EGLConfig config : configs)
- dumpEglConfig(config);
- }
+ _egl.eglGetConfigs(_egl_display, configs, numConfigs, num_config);
// Android's eglChooseConfig is busted in several versions and
- // devices so we have to filter/rank the configs again ourselves.
- eglConfig = chooseEglConfig(configs);
- if (false) {
- Log.d(LOG_TAG, String.format("Chose EGL config from %d possibilities.", numConfigs));
- dumpEglConfig(eglConfig);
- }
+ // devices so we have to filter/rank the configs ourselves.
+ _egl_config = chooseEglConfig(configs);
- eglContext = egl.eglCreateContext(eglDisplay, eglConfig,
- EGL10.EGL_NO_CONTEXT, null);
- if (eglContext == EGL10.EGL_NO_CONTEXT)
- throw new RuntimeException("Failed to create context");
- }
+ _egl_context = _egl.eglCreateContext(_egl_display, _egl_config,
+ EGL10.EGL_NO_CONTEXT, null);
- private EGLConfig chooseEglConfig(EGLConfig[] configs) {
- int best = 0;
- int bestScore = -1;
- int[] value = new int[1];
+ if (_egl_context == EGL10.EGL_NO_CONTEXT)
+ throw new Exception(String.format("Failed to create context: 0x%x",
+ _egl.eglGetError()));
+ }
- for (int i = 0; i < configs.length; i++) {
- EGLConfig config = configs[i];
- int score = 10000;
- egl.eglGetConfigAttrib(eglDisplay, config,
- EGL10.EGL_SURFACE_TYPE, value);
- if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0)
- continue; // must have
-
- egl.eglGetConfigAttrib(eglDisplay, config,
- EGL10.EGL_CONFIG_CAVEAT, value);
- if (value[0] != EGL10.EGL_NONE)
- score -= 1000;
+ // Callback from C++ peer instance
+ final protected EGLSurface initSurface() throws Exception {
+ _egl_surface = _egl.eglCreateWindowSurface(_egl_display, _egl_config,
+ _surface_holder, null);
- // Must be at least 555, but then smaller is better
- final int[] colorBits = {EGL10.EGL_RED_SIZE,
- EGL10.EGL_GREEN_SIZE,
- EGL10.EGL_BLUE_SIZE,
- EGL10.EGL_ALPHA_SIZE};
- for (int component : colorBits) {
- egl.eglGetConfigAttrib(eglDisplay, config,
- component, value);
- if (value[0] >= 5)
- score += 10; // boost if >5 bits accuracy
- score -= value[0]; // penalize for wasted bits
- }
+ if (_egl_surface == EGL10.EGL_NO_SURFACE)
+ throw new Exception(String.format(
+ "eglCreateWindowSurface failed: 0x%x", _egl.eglGetError()));
- egl.eglGetConfigAttrib(eglDisplay, config,
- EGL10.EGL_DEPTH_SIZE, value);
- score -= value[0]; // penalize for wasted bits
+ _egl.eglMakeCurrent(_egl_display, _egl_surface, _egl_surface,
+ _egl_context);
- if (score > bestScore) {
- best = i;
- bestScore = score;
- }
- }
+ GL10 gl = (GL10)_egl_context.getGL();
- if (bestScore < 0) {
- Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness.");
- return configs[0];
- }
+ Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)",
+ _egl.eglQueryString(_egl_display, EGL10.EGL_VERSION),
+ _egl.eglQueryString(_egl_display, EGL10.EGL_VENDOR),
+ gl.glGetString(GL10.GL_VERSION),
+ gl.glGetString(GL10.GL_RENDERER),
+ gl.glGetString(GL10.GL_VENDOR)));
- return configs[best];
+ return _egl_surface;
}
- // Called by ScummVM thread
- static private boolean _log_version = true;
- protected void setupScummVMSurface() {
- try {
- surfaceLock.acquire();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted while waiting for surface lock", e);
- return;
- }
- eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig,
- nativeSurface, null);
- if (eglSurface == EGL10.EGL_NO_SURFACE)
- Log.e(LOG_TAG, "CreateWindowSurface failed!");
- egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
-
- GL10 gl = (GL10)eglContext.getGL();
-
- if (_log_version) {
- Log.i(LOG_TAG, String.format("Using EGL %s (%s); GL %s/%s (%s)",
- egl.eglQueryString(eglDisplay, EGL10.EGL_VERSION),
- egl.eglQueryString(eglDisplay, EGL10.EGL_VENDOR),
- gl.glGetString(GL10.GL_VERSION),
- gl.glGetString(GL10.GL_RENDERER),
- gl.glGetString(GL10.GL_VENDOR)));
- _log_version = false; // only log this once
+ // Callback from C++ peer instance
+ final protected void deinitSurface() {
+ if (_egl_display != EGL10.EGL_NO_DISPLAY) {
+ _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+
+ if (_egl_surface != EGL10.EGL_NO_SURFACE)
+ _egl.eglDestroySurface(_egl_display, _egl_surface);
}
- int[] value = new int[1];
- egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_WIDTH, value);
- int width = value[0];
- egl.eglQuerySurface(eglDisplay, eglSurface, EGL10.EGL_HEIGHT, value);
- int height = value[0];
- Log.i(LOG_TAG, String.format("New surface is %dx%d", width, height));
- setSurfaceSize(width, height);
+ _egl_surface = EGL10.EGL_NO_SURFACE;
}
- // Called by ScummVM thread
- protected void destroyScummVMSurface() {
- if (eglSurface != null) {
- egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- egl.eglDestroySurface(eglDisplay, eglSurface);
- eglSurface = EGL10.EGL_NO_SURFACE;
+ final private void deinitEGL() {
+ if (_egl_display != EGL10.EGL_NO_DISPLAY) {
+ _egl.eglMakeCurrent(_egl_display, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+
+ if (_egl_surface != EGL10.EGL_NO_SURFACE)
+ _egl.eglDestroySurface(_egl_display, _egl_surface);
+
+ if (_egl_context != EGL10.EGL_NO_CONTEXT)
+ _egl.eglDestroyContext(_egl_display, _egl_context);
+
+ _egl.eglTerminate(_egl_display);
}
- surfaceLock.release();
+ _egl_surface = EGL10.EGL_NO_SURFACE;
+ _egl_context = EGL10.EGL_NO_CONTEXT;
+ _egl_config = null;
+ _egl_display = EGL10.EGL_NO_DISPLAY;
+ _egl = null;
}
- public void setSurface(SurfaceHolder holder) {
- holder.addCallback(this);
- }
+ final private void initAudio() throws Exception {
+ _sample_rate = AudioTrack.getNativeOutputSampleRate(
+ AudioManager.STREAM_MUSIC);
+ _buffer_size = AudioTrack.getMinBufferSize(_sample_rate,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO,
+ AudioFormat.ENCODING_PCM_16BIT);
+
+ // ~50ms
+ int buffer_size_want = (_sample_rate * 2 * 2 / 20) & ~1023;
- final public boolean swapBuffers() {
- if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {
- int error = egl.eglGetError();
- Log.w(LOG_TAG, String.format("eglSwapBuffers exited with error 0x%x", error));
- if (error == EGL11.EGL_CONTEXT_LOST)
- return false;
+ if (_buffer_size < buffer_size_want) {
+ Log.w(LOG_TAG, String.format(
+ "adjusting audio buffer size (was: %d)", _buffer_size));
+
+ _buffer_size = buffer_size_want;
}
- return true;
- }
- // Set scummvm config options
- final public native static void loadConfigFile(String path);
- final public native static void setConfMan(String key, int value);
- final public native static void setConfMan(String key, String value);
- final public native void enableZoning(boolean enable);
- final public native void setSurfaceSize(int width, int height);
+ Log.i(LOG_TAG, String.format("Using %d bytes buffer for %dHz audio",
+ _buffer_size, _sample_rate));
- // Feed an event to ScummVM. Safe to call from other threads.
- final public native void pushEvent(Event e);
+ _audio_track = new AudioTrack(AudioManager.STREAM_MUSIC,
+ _sample_rate,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO,
+ AudioFormat.ENCODING_PCM_16BIT,
+ _buffer_size,
+ AudioTrack.MODE_STREAM);
- final private native void audioMixCallback(byte[] buf);
+ if (_audio_track.getState() != AudioTrack.STATE_INITIALIZED)
+ throw new Exception(
+ String.format("Error initialising AudioTrack: %d",
+ _audio_track.getState()));
+ }
- // Runs the actual ScummVM program and returns when it does.
- // This should not be called from multiple threads simultaneously...
- final public native int scummVMMain(String[] argv);
+ final private void deinitAudio() {
+ if (_audio_track != null)
+ _audio_track.stop();
- // Callbacks from C++ peer instance
- //protected GraphicsMode[] getSupportedGraphicsModes() {}
- protected void displayMessageOnOSD(String msg) {}
- protected void setWindowCaption(String caption) {}
- protected void showVirtualKeyboard(boolean enable) {}
- protected String[] getSysArchives() { return new String[0]; }
- protected String[] getPluginDirectories() { return new String[0]; }
- protected void initBackend() throws AudioSetupException {
- createScummVMGLContext();
- initAudio();
+ _audio_track = null;
+ _buffer_size = 0;
+ _sample_rate = 0;
}
- private static class AudioThread extends Thread {
- final private int buf_size;
- private boolean is_paused = false;
- final private ScummVM scummvm;
- final private AudioTrack audio_track;
-
- AudioThread(ScummVM scummvm, AudioTrack audio_track, int buf_size) {
- super("AudioThread");
- this.scummvm = scummvm;
- this.audio_track = audio_track;
- this.buf_size = buf_size;
- setPriority(Thread.MAX_PRIORITY);
- setDaemon(true);
- }
+ private static final int[] s_eglAttribs = {
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE
+ };
- public void pauseAudio() {
- synchronized (this) {
- is_paused = true;
+ final private class EglAttribs extends LinkedHashMap<Integer, Integer> {
+ public EglAttribs(EGLConfig config) {
+ super(s_eglAttribs.length);
+
+ int[] value = new int[1];
+
+ for (int i : s_eglAttribs) {
+ _egl.eglGetConfigAttrib(_egl_display, config, i, value);
+
+ put(i, value[0]);
}
- audio_track.pause();
}
- public void resumeAudio() {
- synchronized (this) {
- is_paused = false;
- notifyAll();
- }
- audio_track.play();
+ private int weightBits(int attr, int size) {
+ final int value = get(attr);
+
+ int score = 0;
+
+ if (value == size || (size > 0 && value > size))
+ score += 10;
+
+ // penalize for wasted bits
+ score -= value - size;
+
+ return score;
}
- public void run() {
- byte[] buf = new byte[buf_size];
- audio_track.play();
- int offset = 0;
- try {
- while (true) {
- synchronized (this) {
- while (is_paused)
- wait();
- }
-
- if (offset == buf.length) {
- // Grab new audio data
- scummvm.audioMixCallback(buf);
- offset = 0;
- }
- int len = buf.length - offset;
- int ret = audio_track.write(buf, offset, len);
- if (ret < 0) {
- Log.w(LOG_TAG, String.format(
- "AudioTrack.write(%dB) returned error %d",
- buf.length, ret));
- break;
- } else if (ret != len) {
- Log.w(LOG_TAG, String.format(
- "Short audio write. Wrote %dB, not %dB",
- ret, buf.length));
- // Buffer is full, so yield cpu for a while
- Thread.sleep(100);
- }
- offset += ret;
- }
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Audio thread interrupted", e);
- }
+ public int weight() {
+ int score = 10000;
+
+ if (get(EGL10.EGL_CONFIG_CAVEAT) != EGL10.EGL_NONE)
+ score -= 1000;
+
+ // less MSAA is better
+ score -= get(EGL10.EGL_SAMPLES) * 100;
+
+ // Must be at least 565, but then smaller is better
+ score += weightBits(EGL10.EGL_RED_SIZE, 5);
+ score += weightBits(EGL10.EGL_GREEN_SIZE, 6);
+ score += weightBits(EGL10.EGL_BLUE_SIZE, 5);
+ score += weightBits(EGL10.EGL_ALPHA_SIZE, 0);
+ score += weightBits(EGL10.EGL_DEPTH_SIZE, 0);
+ score += weightBits(EGL10.EGL_STENCIL_SIZE, 0);
+
+ return score;
}
- }
- private AudioThread audio_thread;
- final public int audioSampleRate() {
- return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
- }
+ public String toString() {
+ String s;
- private void initAudio() throws AudioSetupException {
- int sample_rate = audioSampleRate();
- int buf_size =
- AudioTrack.getMinBufferSize(sample_rate,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO,
- AudioFormat.ENCODING_PCM_16BIT);
- if (buf_size < 0) {
- int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio
- Log.w(LOG_TAG, String.format(
- "Unable to get min audio buffer size (error %d). Guessing %dB.",
- buf_size, guess));
- buf_size = guess;
+ if (get(EGL10.EGL_ALPHA_SIZE) > 0)
+ s = String.format("[%d] RGBA%d%d%d%d",
+ get(EGL10.EGL_CONFIG_ID),
+ get(EGL10.EGL_RED_SIZE),
+ get(EGL10.EGL_GREEN_SIZE),
+ get(EGL10.EGL_BLUE_SIZE),
+ get(EGL10.EGL_ALPHA_SIZE));
+ else
+ s = String.format("[%d] RGB%d%d%d",
+ get(EGL10.EGL_CONFIG_ID),
+ get(EGL10.EGL_RED_SIZE),
+ get(EGL10.EGL_GREEN_SIZE),
+ get(EGL10.EGL_BLUE_SIZE));
+
+ if (get(EGL10.EGL_DEPTH_SIZE) > 0)
+ s += String.format(" D%d", get(EGL10.EGL_DEPTH_SIZE));
+
+ if (get(EGL10.EGL_STENCIL_SIZE) > 0)
+ s += String.format(" S%d", get(EGL10.EGL_STENCIL_SIZE));
+
+ if (get(EGL10.EGL_SAMPLES) > 0)
+ s += String.format(" MSAAx%d", get(EGL10.EGL_SAMPLES));
+
+ if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) > 0)
+ s += " W";
+ if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PBUFFER_BIT) > 0)
+ s += " P";
+ if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PIXMAP_BIT) > 0)
+ s += " X";
+
+ switch (get(EGL10.EGL_CONFIG_CAVEAT)) {
+ case EGL10.EGL_NONE:
+ break;
+
+ case EGL10.EGL_SLOW_CONFIG:
+ s += " SLOW";
+ break;
+
+ case EGL10.EGL_NON_CONFORMANT_CONFIG:
+ s += " NON_CONFORMANT";
+
+ default:
+ s += String.format(" unknown CAVEAT 0x%x",
+ get(EGL10.EGL_CONFIG_CAVEAT));
+ }
+
+ return s;
}
- Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio",
- buf_size, sample_rate));
- AudioTrack audio_track =
- new AudioTrack(AudioManager.STREAM_MUSIC,
- sample_rate,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO,
- AudioFormat.ENCODING_PCM_16BIT,
- buf_size,
- AudioTrack.MODE_STREAM);
- if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) {
- Log.e(LOG_TAG, "Error initialising Android audio system.");
- throw new AudioSetupException();
+ };
+
+ final private EGLConfig chooseEglConfig(EGLConfig[] configs) {
+ EGLConfig res = configs[0];
+ int bestScore = -1;
+
+ Log.d(LOG_TAG, "EGL configs:");
+
+ for (EGLConfig config : configs) {
+ EglAttribs attr = new EglAttribs(config);
+
+ // must have
+ if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0)
+ continue;
+
+ int score = attr.weight();
+
+ Log.d(LOG_TAG, String.format("%s (%d)", attr.toString(), score));
+
+ if (score > bestScore) {
+ res = config;
+ bestScore = score;
+ }
}
- audio_thread = new AudioThread(this, audio_track, buf_size);
- audio_thread.start();
- }
+ if (bestScore < 0)
+ Log.e(LOG_TAG,
+ "Unable to find an acceptable EGL config, expect badness.");
- public void pause() {
- audio_thread.pauseAudio();
- // TODO: need to pause engine too
- }
+ Log.d(LOG_TAG, String.format("Chosen EGL config: %s",
+ new EglAttribs(res).toString()));
- public void resume() {
- // TODO: need to resume engine too
- audio_thread.resumeAudio();
+ return res;
}
static {
@@ -448,15 +429,16 @@ public class ScummVM implements SurfaceHolder.Callback {
final boolean sleep_for_debugger = false;
if (sleep_for_debugger) {
try {
- Thread.sleep(20*1000);
+ Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
}
}
- //System.loadLibrary("scummvm");
File cache_dir = ScummVMApplication.getLastCacheDir();
String libname = System.mapLibraryName("scummvm");
File libpath = new File(cache_dir, libname);
+
System.load(libpath.getPath());
}
}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
index fae35b6695..1978b690d0 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
@@ -3,41 +3,27 @@ package org.inodes.gus.scummvm;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
-import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewConfiguration;
+import android.view.SurfaceHolder;
+import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
-import java.io.IOException;
-
public class ScummVMActivity extends Activity {
- private boolean _do_right_click;
- private boolean _last_click_was_right;
-
- // game pixels to move per trackball/dpad event.
- // FIXME: replace this with proper mouse acceleration
- private final static int TRACKBALL_SCALE = 2;
private class MyScummVM extends ScummVM {
- private boolean scummvmRunning = false;
-
private boolean usingSmallScreen() {
// Multiple screen sizes came in with Android 1.6. Have
// to use reflection in order to continue supporting 1.5
// devices :(
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
+
try {
// This 'density' term is very confusing.
int DENSITY_LOW = metrics.getClass().getField("DENSITY_LOW").getInt(null);
@@ -48,27 +34,22 @@ public class ScummVMActivity extends Activity {
}
}
- public MyScummVM() {
- super(ScummVMActivity.this);
+ public MyScummVM(SurfaceHolder holder) {
+ super(ScummVMActivity.this.getAssets(), holder);
// Enable ScummVM zoning on 'small' screens.
- enableZoning(usingSmallScreen());
+ // FIXME make this optional for the user
+ // disabled for now since it crops too much
+ //enableZoning(usingSmallScreen());
}
@Override
- protected void initBackend() throws ScummVM.AudioSetupException {
- synchronized (this) {
- scummvmRunning = true;
- notifyAll();
- }
- super.initBackend();
- }
+ protected void getDPI(float[] values) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
- public void waitUntilRunning() throws InterruptedException {
- synchronized (this) {
- while (!scummvmRunning)
- wait();
- }
+ values[0] = metrics.xdpi;
+ values[1] = metrics.ydpi;
}
@Override
@@ -95,24 +76,28 @@ public class ScummVMActivity extends Activity {
@Override
protected void showVirtualKeyboard(final boolean enable) {
- if (getResources().getConfiguration().keyboard ==
- Configuration.KEYBOARD_NOKEYS) {
- runOnUiThread(new Runnable() {
- public void run() {
- showKeyboard(enable);
- }
- });
- }
+ runOnUiThread(new Runnable() {
+ public void run() {
+ showKeyboard(enable);
+ }
+ });
+ }
+
+ @Override
+ protected String[] getSysArchives() {
+ return new String[0];
}
+
}
- private MyScummVM scummvm;
- private Thread scummvm_thread;
+
+ private MyScummVM _scummvm;
+ private ScummVMEvents _events;
+ private Thread _scummvm_thread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- _do_right_click = false;
setVolumeControlStream(AudioManager.STREAM_MUSIC);
setContentView(R.layout.main);
@@ -126,336 +111,110 @@ public class ScummVMActivity extends Activity {
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.no_sdcard)
.setNegativeButton(R.string.quit,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog,
- int which) {
- finish();
- }
- })
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+ finish();
+ }
+ })
.show();
+
return;
}
SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface);
-
- main_surface.setOnTouchListener(new View.OnTouchListener() {
- public boolean onTouch(View v, MotionEvent event) {
- return onTouchEvent(event);
- }
- });
- main_surface.setOnKeyListener(new View.OnKeyListener() {
- public boolean onKey(View v, int code, KeyEvent ev) {
- return onKeyDown(code, ev);
- }
- });
+
main_surface.requestFocus();
- // Start ScummVM
- scummvm = new MyScummVM();
- scummvm_thread = new Thread(new Runnable() {
- public void run() {
- try {
- runScummVM();
- } catch (Exception e) {
- Log.e(ScummVM.LOG_TAG, "Fatal error in ScummVM thread", e);
- new AlertDialog.Builder(ScummVMActivity.this)
- .setTitle("Error")
- .setMessage(e.toString())
- .setIcon(android.R.drawable.ic_dialog_alert)
- .show();
- finish();
- }
- }
- }, "ScummVM");
- scummvm_thread.start();
-
- // Block UI thread until ScummVM has started. In particular,
- // this means that surface and event callbacks should be safe
- // after this point.
- try {
- scummvm.waitUntilRunning();
- } catch (InterruptedException e) {
- Log.e(ScummVM.LOG_TAG, "Interrupted while waiting for ScummVM.initBackend", e);
- finish();
- }
+ getFilesDir().mkdirs();
- scummvm.setSurface(main_surface.getHolder());
- }
+ // Start ScummVM
+ _scummvm = new MyScummVM(main_surface.getHolder());
- // Runs in another thread
- private void runScummVM() throws IOException {
- getFilesDir().mkdirs();
- String[] args = {
- "ScummVM-lib",
+ _scummvm.setArgs(new String[] {
+ "ScummVM",
"--config=" + getFileStreamPath("scummvmrc").getPath(),
"--path=" + Environment.getExternalStorageDirectory().getPath(),
"--gui-theme=scummmodern",
"--savepath=" + getDir("saves", 0).getPath()
- };
+ });
- int ret = scummvm.scummVMMain(args);
+ _events = new ScummVMEvents(this, _scummvm);
- // On exit, tear everything down for a fresh
- // restart next time.
- System.exit(ret);
- }
+ main_surface.setOnKeyListener(_events);
+ main_surface.setOnTouchListener(_events);
- private boolean was_paused = false;
+ _scummvm_thread = new Thread(_scummvm, "ScummVM");
+ _scummvm_thread.start();
+ }
@Override
- public void onPause() {
- if (scummvm != null) {
- was_paused = true;
- scummvm.pause();
- }
- super.onPause();
+ public void onStart() {
+ Log.d(ScummVM.LOG_TAG, "onStart");
+
+ super.onStart();
}
@Override
public void onResume() {
+ Log.d(ScummVM.LOG_TAG, "onResume");
+
super.onResume();
- if (scummvm != null && was_paused)
- scummvm.resume();
- was_paused = false;
+
+ if (_scummvm != null)
+ _scummvm.setPause(false);
}
@Override
- public void onStop() {
- if (scummvm != null) {
- scummvm.pushEvent(new Event(Event.EVENT_QUIT));
- try {
- scummvm_thread.join(1000); // 1s timeout
- } catch (InterruptedException e) {
- Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e);
- }
- }
- super.onStop();
- }
+ public void onPause() {
+ Log.d(ScummVM.LOG_TAG, "onPause");
- static final int MSG_MENU_LONG_PRESS = 1;
- private final Handler keycodeMenuTimeoutHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_MENU_LONG_PRESS) {
- InputMethodManager imm = (InputMethodManager)
- getSystemService(INPUT_METHOD_SERVICE);
- if (imm != null)
- imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
- }
- }
- };
+ super.onPause();
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent kevent) {
- return onKeyDown(keyCode, kevent);
+ if (_scummvm != null)
+ _scummvm.setPause(true);
}
@Override
- public boolean onKeyMultiple(int keyCode, int repeatCount,
- KeyEvent kevent) {
- return onKeyDown(keyCode, kevent);
+ public void onStop() {
+ Log.d(ScummVM.LOG_TAG, "onStop");
+
+ super.onStop();
}
@Override
- public boolean onKeyDown(int keyCode, KeyEvent kevent) {
- // Filter out "special" keys
- switch (keyCode) {
- case KeyEvent.KEYCODE_MENU:
- // Have to reimplement hold-down-menu-brings-up-softkeybd
- // ourselves, since we are otherwise hijacking the menu
- // key :(
- // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel()
- // for the usual Android implementation of this feature.
- if (kevent.getRepeatCount() > 0)
- // Ignore keyrepeat for menu
- return false;
- boolean timeout_fired = false;
- if (getResources().getConfiguration().keyboard ==
- Configuration.KEYBOARD_NOKEYS) {
- timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS);
- keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
- if (kevent.getAction() == KeyEvent.ACTION_DOWN) {
- keycodeMenuTimeoutHandler.sendMessageDelayed(
- keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS),
- ViewConfiguration.getLongPressTimeout());
- return true;
- }
- }
- if (kevent.getAction() == KeyEvent.ACTION_UP) {
- if (!timeout_fired)
- scummvm.pushEvent(new Event(Event.EVENT_MAINMENU));
- return true;
- }
- return false;
- case KeyEvent.KEYCODE_CAMERA:
- case KeyEvent.KEYCODE_SEARCH:
- _do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN);
- return true;
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT: {
- // HTC Hero doesn't seem to generate
- // MotionEvent.ACTION_DOWN events on trackball press :(
- // We'll have to just fake one here.
- // Some other handsets lack a trackball, so the DPAD is
- // the only way of moving the cursor.
- int motion_action;
- // FIXME: this logic is a mess.
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- switch (kevent.getAction()) {
- case KeyEvent.ACTION_DOWN:
- motion_action = MotionEvent.ACTION_DOWN;
- break;
- case KeyEvent.ACTION_UP:
- motion_action = MotionEvent.ACTION_UP;
- break;
- default: // ACTION_MULTIPLE
- return false;
- }
- } else
- motion_action = MotionEvent.ACTION_MOVE;
-
- Event e = new Event(getEventType(motion_action));
- e.mouse_x = 0;
- e.mouse_y = 0;
- e.mouse_relative = true;
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- e.mouse_y = -TRACKBALL_SCALE;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- e.mouse_y = TRACKBALL_SCALE;
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- e.mouse_x = -TRACKBALL_SCALE;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- e.mouse_x = TRACKBALL_SCALE;
- break;
- }
- scummvm.pushEvent(e);
- return true;
- }
- case KeyEvent.KEYCODE_BACK:
- // skip isSystem() check and fall through to main code
- break;
- default:
- if (kevent.isSystem())
- return false;
- }
+ public void onDestroy() {
+ Log.d(ScummVM.LOG_TAG, "onDestroy");
- // FIXME: what do I need to do for composed characters?
-
- Event e = new Event();
-
- switch (kevent.getAction()) {
- case KeyEvent.ACTION_DOWN:
- e.type = Event.EVENT_KEYDOWN;
- e.synthetic = false;
- break;
- case KeyEvent.ACTION_UP:
- e.type = Event.EVENT_KEYUP;
- e.synthetic = false;
- break;
- case KeyEvent.ACTION_MULTIPLE:
- // e.type is handled below
- e.synthetic = true;
- break;
- default:
- return false;
- }
+ super.onDestroy();
- e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ?
- Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID;
- e.kbd_ascii = kevent.getUnicodeChar();
- if (e.kbd_ascii == 0)
- e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii
-
-
- e.kbd_flags = 0;
- if (kevent.isAltPressed())
- e.kbd_flags |= Event.KBD_ALT;
- if (kevent.isSymPressed()) // no ctrl key in android, so use sym (?)
- e.kbd_flags |= Event.KBD_CTRL;
- if (kevent.isShiftPressed()) {
- if (keyCode >= KeyEvent.KEYCODE_0 &&
- keyCode <= KeyEvent.KEYCODE_9) {
- // Shift+number -> convert to F* key
- int offset = keyCode == KeyEvent.KEYCODE_0 ?
- 10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10
- e.kbd_keycode = Event.KEYCODE_F1 + offset;
- e.kbd_ascii = Event.ASCII_F1 + offset;
- } else
- e.kbd_flags |= Event.KBD_SHIFT;
- }
+ if (_events != null) {
+ _events.sendQuitEvent();
- if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) {
- for (int i = 0; i <= kevent.getRepeatCount(); i++) {
- e.type = Event.EVENT_KEYDOWN;
- scummvm.pushEvent(e);
- e.type = Event.EVENT_KEYUP;
- scummvm.pushEvent(e);
+ try {
+ // 1s timeout
+ _scummvm_thread.join(1000);
+ } catch (InterruptedException e) {
+ Log.i(ScummVM.LOG_TAG, "Error while joining ScummVM thread", e);
}
- } else
- scummvm.pushEvent(e);
-
- return true;
- }
- private int getEventType(int action) {
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- _last_click_was_right = _do_right_click;
- return _last_click_was_right ?
- Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN;
- case MotionEvent.ACTION_UP:
- return _last_click_was_right ?
- Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP;
- case MotionEvent.ACTION_MOVE:
- return Event.EVENT_MOUSEMOVE;
- default:
- return Event.EVENT_INVALID;
+ _scummvm = null;
}
}
@Override
- public boolean onTrackballEvent(MotionEvent event) {
- int type = getEventType(event.getAction());
- if (type == Event.EVENT_INVALID)
- return false;
-
- Event e = new Event(type);
- e.mouse_x =
- (int)(event.getX() * event.getXPrecision()) * TRACKBALL_SCALE;
- e.mouse_y =
- (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE;
- e.mouse_relative = true;
- scummvm.pushEvent(e);
-
- return true;
- }
+ public boolean onTrackballEvent(MotionEvent e) {
+ if (_events != null)
+ return _events.onTrackballEvent(e);
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int type = getEventType(event.getAction());
- if (type == Event.EVENT_INVALID)
- return false;
-
- Event e = new Event(type);
- e.mouse_x = (int)event.getX();
- e.mouse_y = (int)event.getY();
- e.mouse_relative = false;
- scummvm.pushEvent(e);
-
- return true;
+ return false;
}
private void showKeyboard(boolean show) {
SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface);
InputMethodManager imm = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
+
if (show)
imm.showSoftInput(main_surface, InputMethodManager.SHOW_IMPLICIT);
else
@@ -463,3 +222,4 @@ public class ScummVMActivity extends Activity {
InputMethodManager.HIDE_IMPLICIT_ONLY);
}
}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java
index 37a9d09e1a..f9eec72eac 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java
@@ -8,22 +8,24 @@ public class ScummVMApplication extends Application {
public final static String ACTION_PLUGIN_QUERY = "org.inodes.gus.scummvm.action.PLUGIN_QUERY";
public final static String EXTRA_UNPACK_LIBS = "org.inodes.gus.scummvm.extra.UNPACK_LIBS";
- private static File cache_dir;
+ private static File _cache_dir;
@Override
public void onCreate() {
super.onCreate();
+
// This is still on /data :(
- cache_dir = getCacheDir();
+ _cache_dir = getCacheDir();
// This is mounted noexec :(
//cache_dir = new File(Environment.getExternalStorageDirectory(),
- // "/.ScummVM.tmp");
+ // "/.ScummVM.tmp");
// This is owned by download manager and requires special
// permissions to access :(
//cache_dir = Environment.getDownloadCacheDirectory();
}
public static File getLastCacheDir() {
- return cache_dir;
+ return _cache_dir;
}
}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java
new file mode 100644
index 0000000000..3d3fdeece4
--- /dev/null
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java
@@ -0,0 +1,201 @@
+package org.inodes.gus.scummvm;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.content.Context;
+import android.view.KeyEvent;
+import android.view.KeyCharacterMap;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.GestureDetector;
+import android.view.inputmethod.InputMethodManager;
+
+public class ScummVMEvents implements
+ android.view.View.OnKeyListener,
+ android.view.View.OnTouchListener,
+ android.view.GestureDetector.OnGestureListener,
+ android.view.GestureDetector.OnDoubleTapListener {
+
+ public static final int JE_SYS_KEY = 0;
+ public static final int JE_KEY = 1;
+ public static final int JE_DOWN = 2;
+ public static final int JE_SCROLL = 3;
+ public static final int JE_TAP = 4;
+ public static final int JE_DOUBLE_TAP = 5;
+ public static final int JE_BALL = 6;
+ public static final int JE_QUIT = 0x1000;
+
+ final protected Context _context;
+ final protected ScummVM _scummvm;
+ final protected GestureDetector _gd;
+ final protected int _longPress;
+ final protected int _slop;
+
+ public ScummVMEvents(Context context, ScummVM scummvm) {
+ _context = context;
+ _scummvm = scummvm;
+
+ _gd = new GestureDetector(context, this);
+ _gd.setOnDoubleTapListener(this);
+ _gd.setIsLongpressEnabled(false);
+
+ _longPress = ViewConfiguration.getLongPressTimeout();
+ _slop = ViewConfiguration.get(context).getScaledTouchSlop();
+
+ }
+
+ final public void sendQuitEvent() {
+ _scummvm.pushEvent(JE_QUIT, 0, 0, 0, 0, 0);
+ }
+
+ public boolean onTrackballEvent(MotionEvent e) {
+ _scummvm.pushEvent(JE_BALL, (int)(e.getX() * e.getXPrecision() * 100),
+ (int)(e.getY() * e.getYPrecision() * 100), 0, 0, 0);
+ return true;
+ }
+
+ final static int MSG_MENU_LONG_PRESS = 1;
+
+ final private Handler keyHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_MENU_LONG_PRESS) {
+ InputMethodManager imm = (InputMethodManager)
+ _context.getSystemService(_context.INPUT_METHOD_SERVICE);
+
+ if (imm != null)
+ imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
+ }
+ }
+ };
+
+ // OnKeyListener
+ final public boolean onKey(View v, int keyCode, KeyEvent e) {
+ final int action = e.getAction();
+
+ if (e.isSystem()) {
+ // filter what we handle
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ case KeyEvent.KEYCODE_MENU:
+ break;
+
+ default:
+ return false;
+ }
+
+ // no repeats for system keys
+ if (e.getRepeatCount() > 0)
+ return false;
+
+ // Have to reimplement hold-down-menu-brings-up-softkeybd
+ // ourselves, since we are otherwise hijacking the menu key :(
+ // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel()
+ // for the usual Android implementation of this feature.
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ final boolean fired =
+ !keyHandler.hasMessages(MSG_MENU_LONG_PRESS);
+
+ keyHandler.removeMessages(MSG_MENU_LONG_PRESS);
+
+ if (action == KeyEvent.ACTION_DOWN) {
+ keyHandler.sendMessageDelayed(keyHandler.obtainMessage(
+ MSG_MENU_LONG_PRESS), _longPress);
+ return true;
+ }
+
+ if (fired)
+ return true;
+
+ // only send up events of the menu button to the native side
+ if (action != KeyEvent.ACTION_UP)
+ return true;
+ }
+
+ _scummvm.pushEvent(JE_SYS_KEY, action, keyCode, 0, 0, 0);
+
+ return true;
+ }
+
+ // sequence of characters
+ if (action == KeyEvent.ACTION_MULTIPLE &&
+ keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+ KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId());
+
+ for (KeyEvent s : m.getEvents(e.getCharacters().toCharArray())) {
+ _scummvm.pushEvent(JE_KEY, s.getAction(), s.getKeyCode(),
+ s.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK,
+ s.getMetaState(), s.getRepeatCount());
+ }
+
+ return true;
+ }
+
+ _scummvm.pushEvent(JE_KEY, action, keyCode,
+ e.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK,
+ e.getMetaState(), e.getRepeatCount());
+
+ return true;
+ }
+
+ // OnTouchListener
+ final public boolean onTouch(View v, MotionEvent e) {
+ return _gd.onTouchEvent(e);
+ }
+
+ // OnGestureListener
+ final public boolean onDown(MotionEvent e) {
+ _scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0);
+ return true;
+ }
+
+ final public boolean onFling(MotionEvent e1, MotionEvent e2,
+ float velocityX, float velocityY) {
+ //Log.d(ScummVM.LOG_TAG, String.format("onFling: %s -> %s (%.3f %.3f)",
+ // e1.toString(), e2.toString(),
+ // velocityX, velocityY));
+
+ return true;
+ }
+
+ final public void onLongPress(MotionEvent e) {
+ // disabled, interferes with drag&drop
+ }
+
+ final public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ _scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(),
+ (int)e2.getX(), (int)e2.getY(), _slop);
+
+ return true;
+ }
+
+ final public void onShowPress(MotionEvent e) {
+ }
+
+ final public boolean onSingleTapUp(MotionEvent e) {
+ _scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(),
+ (int)(e.getEventTime() - e.getDownTime()), 0, 0);
+
+ return true;
+ }
+
+ // OnDoubleTapListener
+ final public boolean onDoubleTap(MotionEvent e) {
+ return true;
+ }
+
+ final public boolean onDoubleTapEvent(MotionEvent e) {
+ _scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(),
+ e.getAction(), _slop, 0);
+
+ return true;
+ }
+
+ final public boolean onSingleTapConfirmed(MotionEvent e) {
+ return true;
+ }
+}
+
diff --git a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java
index 8811b1f3ae..c4b2ad7f5d 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java
@@ -370,3 +370,4 @@ public class Unpacker extends Activity {
}
}
}
+
diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp
new file mode 100644
index 0000000000..691c384a18
--- /dev/null
+++ b/backends/platform/android/texture.cpp
@@ -0,0 +1,571 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(__ANDROID__)
+
+#include "base/main.h"
+#include "graphics/surface.h"
+
+#include "common/rect.h"
+#include "common/array.h"
+#include "common/util.h"
+#include "common/tokenizer.h"
+
+#include "backends/platform/android/texture.h"
+#include "backends/platform/android/android.h"
+
+// Supported GL extensions
+static bool npot_supported = false;
+#ifdef GL_OES_draw_texture
+static bool draw_tex_supported = false;
+#endif
+
+static inline GLfixed xdiv(int numerator, int denominator) {
+ assert(numerator < (1 << 16));
+ return (numerator << 16) / denominator;
+}
+
+template <class T>
+static T nextHigher2(T k) {
+ if (k == 0)
+ return 1;
+ --k;
+
+ for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
+ k = k | k >> i;
+
+ return k + 1;
+}
+
+void GLESBaseTexture::initGLExtensions() {
+ const char *ext_string =
+ reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+
+ LOGI("Extensions: %s", ext_string);
+
+ Common::StringTokenizer tokenizer(ext_string, " ");
+ while (!tokenizer.empty()) {
+ Common::String token = tokenizer.nextToken();
+
+ if (token == "GL_ARB_texture_non_power_of_two")
+ npot_supported = true;
+
+#ifdef GL_OES_draw_texture
+ if (token == "GL_OES_draw_texture")
+ draw_tex_supported = true;
+#endif
+ }
+}
+
+GLESBaseTexture::GLESBaseTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat) :
+ _glFormat(glFormat),
+ _glType(glType),
+ _glFilter(GL_NEAREST),
+ _texture_name(0),
+ _surface(),
+ _texture_width(0),
+ _texture_height(0),
+ _draw_rect(),
+ _all_dirty(false),
+ _dirty_rect(),
+ _pixelFormat(pixelFormat),
+ _palettePixelFormat()
+{
+ GLCALL(glGenTextures(1, &_texture_name));
+}
+
+GLESBaseTexture::~GLESBaseTexture() {
+ release();
+}
+
+void GLESBaseTexture::release() {
+ LOGD("Destroying texture %u", _texture_name);
+
+ GLCALL(glDeleteTextures(1, &_texture_name));
+ _texture_name = 0;
+}
+
+void GLESBaseTexture::reinit() {
+ GLCALL(glGenTextures(1, &_texture_name));
+
+ initSize();
+
+ setDirty();
+}
+
+void GLESBaseTexture::initSize() {
+ // Allocate room for the texture now, but pixel data gets uploaded
+ // later (perhaps with multiple TexSubImage2D operations).
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+ GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glFormat,
+ _texture_width, _texture_height,
+ 0, _glFormat, _glType, 0));
+}
+
+void GLESBaseTexture::setLinearFilter(bool value) {
+ if (value)
+ _glFilter = GL_LINEAR;
+ else
+ _glFilter = GL_NEAREST;
+
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+}
+
+void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) {
+ _surface.w = w;
+ _surface.h = h;
+ _surface.bytesPerPixel = _pixelFormat.bytesPerPixel;
+
+ if (w == _texture_width && h == _texture_height)
+ return;
+
+ if (npot_supported) {
+ _texture_width = _surface.w;
+ _texture_height = _surface.h;
+ } else {
+ _texture_width = nextHigher2(_surface.w);
+ _texture_height = nextHigher2(_surface.h);
+ }
+
+ initSize();
+}
+
+void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+#ifdef GL_OES_draw_texture
+ // Great extension, but only works under specific conditions.
+ // Still a work-in-progress - disabled for now.
+ if (false && draw_tex_supported && !hasPalette()) {
+ //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
+ const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h };
+
+ GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop));
+
+ // Android GLES bug?
+ GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff));
+
+ GLCALL(glDrawTexiOES(x, y, 0, w, h));
+ } else
+#endif
+ {
+ const GLfixed tex_width = xdiv(_surface.w, _texture_width);
+ const GLfixed tex_height = xdiv(_surface.h, _texture_height);
+ const GLfixed texcoords[] = {
+ 0, 0,
+ tex_width, 0,
+ 0, tex_height,
+ tex_width, tex_height,
+ };
+
+ GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords));
+
+ const GLshort vertices[] = {
+ x, y,
+ x + w, y,
+ x, y + h,
+ x + w, y + h,
+ };
+
+ GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices));
+
+ assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords));
+ GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2));
+ }
+
+ clearDirty();
+}
+
+const Graphics::PixelFormat &GLESBaseTexture::getPixelFormat() const {
+ return _pixelFormat;
+}
+
+GLESTexture::GLESTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat) :
+ GLESBaseTexture(glFormat, glType, pixelFormat),
+ _pixels(0),
+ _buf(0) {
+}
+
+GLESTexture::~GLESTexture() {
+ delete[] _buf;
+ delete[] _pixels;
+}
+
+void GLESTexture::allocBuffer(GLuint w, GLuint h) {
+ GLuint oldw = _surface.w;
+ GLuint oldh = _surface.h;
+
+ GLESBaseTexture::allocBuffer(w, h);
+
+ if (_surface.w == oldw && _surface.h == oldh)
+ return;
+
+ delete[] _buf;
+ delete[] _pixels;
+
+ _pixels = new byte[w * h * _surface.bytesPerPixel];
+ assert(_pixels);
+
+ _surface.pixels = _pixels;
+ _surface.pitch = w * _pixelFormat.bytesPerPixel;
+
+ _buf = new byte[w * h * _surface.bytesPerPixel];
+ assert(_buf);
+}
+
+void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
+ const void *buf, int pitch_buf) {
+ setDirtyRect(Common::Rect(x, y, x + w, y + h));
+
+ const byte *src = (const byte *)buf;
+ byte *dst = _pixels + y * _surface.pitch + x * _surface.bytesPerPixel;
+
+ do {
+ memcpy(dst, src, w * _surface.bytesPerPixel);
+ dst += _surface.pitch;
+ src += pitch_buf;
+ } while (--h);
+}
+
+void GLESTexture::fillBuffer(uint32 color) {
+ assert(_surface.pixels);
+
+ if (_pixelFormat.bytesPerPixel == 1 ||
+ ((color & 0xff) == ((color >> 8) & 0xff)))
+ memset(_pixels, color & 0xff, _surface.pitch * _surface.h);
+ else
+ Common::set_to(_pixels, _pixels + _surface.pitch * _surface.h,
+ (uint16)color);
+
+ setDirty();
+}
+
+void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
+ if (_all_dirty) {
+ _dirty_rect.top = 0;
+ _dirty_rect.left = 0;
+ _dirty_rect.bottom = _surface.h;
+ _dirty_rect.right = _surface.w;
+
+ _all_dirty = false;
+ }
+
+ if (!_dirty_rect.isEmpty()) {
+ byte *_tex;
+
+ int16 dwidth = _dirty_rect.width();
+ int16 dheight = _dirty_rect.height();
+
+ if (dwidth == _surface.w) {
+ _tex = _pixels + _dirty_rect.top * _surface.pitch;
+ } else {
+ _tex = _buf;
+
+ byte *src = _pixels + _dirty_rect.top * _surface.pitch +
+ _dirty_rect.left * _surface.bytesPerPixel;
+ byte *dst = _buf;
+
+ uint16 l = dwidth * _surface.bytesPerPixel;
+
+ for (uint16 i = 0; i < dheight; ++i) {
+ memcpy(dst, src, l);
+ src += _surface.pitch;
+ dst += l;
+ }
+ }
+
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+ GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+
+ GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
+ _dirty_rect.left, _dirty_rect.top,
+ dwidth, dheight, _glFormat, _glType, _tex));
+ }
+
+ GLESBaseTexture::drawTexture(x, y, w, h);
+}
+
+GLES4444Texture::GLES4444Texture() :
+ GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixelFormat()) {
+}
+
+GLES4444Texture::~GLES4444Texture() {
+}
+
+GLES5551Texture::GLES5551Texture() :
+ GLESTexture(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixelFormat()) {
+}
+
+GLES5551Texture::~GLES5551Texture() {
+}
+
+GLES565Texture::GLES565Texture() :
+ GLESTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixelFormat()) {
+}
+
+GLES565Texture::~GLES565Texture() {
+}
+
+GLESPaletteTexture::GLESPaletteTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat palettePixelFormat) :
+ GLESBaseTexture(glFormat, glType,
+ Graphics::PixelFormat::createFormatCLUT8()),
+ _texture(0)
+{
+ _palettePixelFormat = palettePixelFormat;
+ _paletteSize = _palettePixelFormat.bytesPerPixel * 256;
+}
+
+GLESPaletteTexture::~GLESPaletteTexture() {
+ delete[] _texture;
+}
+
+void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
+ GLuint oldw = _surface.w;
+ GLuint oldh = _surface.h;
+
+ GLESBaseTexture::allocBuffer(w, h);
+
+ if (_surface.w == oldw && _surface.h == oldh)
+ return;
+
+ byte *new_buffer = new byte[_paletteSize +
+ _texture_width * _texture_height];
+ assert(new_buffer);
+
+ if (_texture) {
+ // preserve palette
+ memcpy(new_buffer, _texture, _paletteSize);
+ delete[] _texture;
+ }
+
+ _texture = new_buffer;
+ _surface.pixels = _texture + _paletteSize;
+ _surface.pitch = _texture_width;
+}
+
+void GLESPaletteTexture::fillBuffer(uint32 color) {
+ assert(_surface.pixels);
+ memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h);
+ setDirty();
+}
+
+void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
+ const void *buf, int pitch_buf) {
+ setDirtyRect(Common::Rect(x, y, x + w, y + h));
+
+ const byte * src = static_cast<const byte *>(buf);
+ byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y));
+
+ do {
+ memcpy(dst, src, w);
+ dst += _surface.pitch;
+ src += pitch_buf;
+ } while (--h);
+}
+
+void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
+ GLshort h) {
+ if (dirty()) {
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+ const size_t texture_size = _paletteSize +
+ _texture_width * _texture_height;
+
+ GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, _glType,
+ _texture_width, _texture_height,
+ 0, texture_size, _texture));
+ }
+
+ GLESBaseTexture::drawTexture(x, y, w, h);
+}
+
+GLESPalette888Texture::GLESPalette888Texture() :
+ GLESPaletteTexture(GL_RGB, GL_PALETTE8_RGB8_OES,
+ Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)) {
+}
+
+GLESPalette888Texture::~GLESPalette888Texture() {
+}
+
+GLESPalette8888Texture::GLESPalette8888Texture() :
+ GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA8_OES,
+ Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) {
+}
+
+GLESPalette8888Texture::~GLESPalette8888Texture() {
+}
+
+GLESPalette565Texture::GLESPalette565Texture() :
+ GLESPaletteTexture(GL_RGB, GL_PALETTE8_R5_G6_B5_OES,
+ Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) {
+}
+
+GLESPalette565Texture::~GLESPalette565Texture() {
+}
+
+GLESPalette4444Texture::GLESPalette4444Texture() :
+ GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGBA4_OES,
+ Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) {
+}
+
+GLESPalette4444Texture::~GLESPalette4444Texture() {
+}
+
+GLESPalette5551Texture::GLESPalette5551Texture() :
+ GLESPaletteTexture(GL_RGBA, GL_PALETTE8_RGB5_A1_OES,
+ Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) {
+}
+
+GLESPalette5551Texture::~GLESPalette5551Texture() {
+}
+
+GLESFakePaletteTexture::GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat) :
+ GLESBaseTexture(glFormat, glType, pixelFormat),
+ _palette(0),
+ _pixels(0),
+ _buf(0)
+{
+ _palettePixelFormat = pixelFormat;
+ _fake_format = Graphics::PixelFormat::createFormatCLUT8();
+
+ _palette = new uint16[256];
+ assert(_palette);
+
+ memset(_palette, 0, 256 * 2);
+}
+
+GLESFakePaletteTexture::~GLESFakePaletteTexture() {
+ delete[] _buf;
+ delete[] _pixels;
+ delete[] _palette;
+}
+
+void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
+ GLuint oldw = _surface.w;
+ GLuint oldh = _surface.h;
+
+ GLESBaseTexture::allocBuffer(w, h);
+
+ if (_surface.w == oldw && _surface.h == oldh)
+ return;
+
+ delete[] _buf;
+ delete[] _pixels;
+
+ _pixels = new byte[w * h];
+ assert(_pixels);
+
+ // fixup surface, for the outside this is a CLUT8 surface
+ _surface.pixels = _pixels;
+ _surface.bytesPerPixel = 1;
+ _surface.pitch = w;
+
+ _buf = new uint16[w * h];
+ assert(_buf);
+}
+
+void GLESFakePaletteTexture::fillBuffer(uint32 color) {
+ assert(_surface.pixels);
+ memset(_surface.pixels, color & 0xff, _surface.pitch * _surface.h);
+ setDirty();
+}
+
+void GLESFakePaletteTexture::updateBuffer(GLuint x, GLuint y, GLuint w,
+ GLuint h, const void *buf,
+ int pitch_buf) {
+ setDirtyRect(Common::Rect(x, y, x + w, y + h));
+
+ const byte *src = (const byte *)buf;
+ byte *dst = _pixels + y * _surface.pitch + x;
+
+ do {
+ memcpy(dst, src, w);
+ dst += _surface.pitch;
+ src += pitch_buf;
+ } while (--h);
+}
+
+void GLESFakePaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w,
+ GLshort h) {
+ if (_all_dirty) {
+ _dirty_rect.top = 0;
+ _dirty_rect.left = 0;
+ _dirty_rect.bottom = _surface.h;
+ _dirty_rect.right = _surface.w;
+
+ _all_dirty = false;
+ }
+
+ if (!_dirty_rect.isEmpty()) {
+ int16 dwidth = _dirty_rect.width();
+ int16 dheight = _dirty_rect.height();
+
+ byte *src = _pixels + _dirty_rect.top * _surface.pitch +
+ _dirty_rect.left;
+ uint16 *dst = _buf;
+ uint pitch_delta = _surface.pitch - dwidth;
+
+ for (uint16 j = 0; j < dheight; ++j) {
+ for (uint16 i = 0; i < dwidth; ++i)
+ *dst++ = _palette[*src++];
+ src += pitch_delta;
+ }
+
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
+
+ GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0,
+ _dirty_rect.left, _dirty_rect.top,
+ dwidth, dheight, _glFormat, _glType, _buf));
+ }
+
+ GLESBaseTexture::drawTexture(x, y, w, h);
+}
+
+const Graphics::PixelFormat &GLESFakePaletteTexture::getPixelFormat() const {
+ return _fake_format;
+}
+
+GLESFakePalette565Texture::GLESFakePalette565Texture() :
+ GLESFakePaletteTexture(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
+ GLES565Texture::pixelFormat()) {
+}
+
+GLESFakePalette565Texture::~GLESFakePalette565Texture() {
+}
+
+#endif
+
diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h
new file mode 100644
index 0000000000..64489da0a4
--- /dev/null
+++ b/backends/platform/android/texture.h
@@ -0,0 +1,331 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef _ANDROID_TEXTURE_H_
+#define _ANDROID_TEXTURE_H_
+
+#if defined(__ANDROID__)
+
+#include <GLES/gl.h>
+
+#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
+
+#include "common/rect.h"
+#include "common/array.h"
+
+class GLESBaseTexture {
+public:
+ static void initGLExtensions();
+
+protected:
+ GLESBaseTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat);
+
+public:
+ virtual ~GLESBaseTexture();
+
+ void release();
+ void reinit();
+ void initSize();
+
+ void setLinearFilter(bool value);
+
+ virtual void allocBuffer(GLuint w, GLuint h);
+
+ virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+ const void *buf, int pitch_buf) = 0;
+ virtual void fillBuffer(uint32 color) = 0;
+
+ virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
+
+ inline void setDrawRect(const Common::Rect &rect) {
+ _draw_rect = rect;
+ }
+
+ inline void setDrawRect(int16 w, int16 h) {
+ _draw_rect = Common::Rect(w, h);
+ }
+
+ inline void setDrawRect(int16 x1, int16 y1, int16 x2, int16 y2) {
+ _draw_rect = Common::Rect(x1, y1, x2, y2);
+ }
+
+ inline const Common::Rect &getDrawRect() const {
+ return _draw_rect;
+ }
+
+ inline void drawTextureRect() {
+ drawTexture(_draw_rect.left, _draw_rect.top,
+ _draw_rect.width(), _draw_rect.height());
+ }
+
+ inline void drawTextureOrigin() {
+ drawTexture(0, 0, _surface.w, _surface.h);
+ }
+
+ inline GLuint width() const {
+ return _surface.w;
+ }
+
+ inline GLuint height() const {
+ return _surface.h;
+ }
+
+ inline uint16 pitch() const {
+ return _surface.pitch;
+ }
+
+ inline const Graphics::Surface *surface_const() const {
+ return &_surface;
+ }
+
+ inline Graphics::Surface *surface() {
+ setDirty();
+ return &_surface;
+ }
+
+ virtual const byte *palette_const() const {
+ return 0;
+ };
+
+ virtual byte *palette() {
+ return 0;
+ };
+
+ inline bool hasPalette() const {
+ return _palettePixelFormat.bytesPerPixel > 0;
+ }
+
+ inline bool dirty() const {
+ return _all_dirty || !_dirty_rect.isEmpty();
+ }
+
+ virtual const Graphics::PixelFormat &getPixelFormat() const;
+
+ inline const Graphics::PixelFormat &getPalettePixelFormat() const {
+ return _palettePixelFormat;
+ }
+
+protected:
+ inline void setDirty() {
+ _all_dirty = true;
+ }
+
+ inline void clearDirty() {
+ _all_dirty = false;
+ _dirty_rect.top = 0;
+ _dirty_rect.left = 0;
+ _dirty_rect.bottom = 0;
+ _dirty_rect.right = 0;
+ }
+
+ inline void setDirtyRect(const Common::Rect& r) {
+ if (!_all_dirty) {
+ if (_dirty_rect.isEmpty())
+ _dirty_rect = r;
+ else
+ _dirty_rect.extend(r);
+ }
+ }
+
+ GLenum _glFormat;
+ GLenum _glType;
+ GLint _glFilter;
+
+ GLuint _texture_name;
+ Graphics::Surface _surface;
+ GLuint _texture_width;
+ GLuint _texture_height;
+
+ Common::Rect _draw_rect;
+
+ bool _all_dirty;
+ Common::Rect _dirty_rect;
+
+ Graphics::PixelFormat _pixelFormat;
+ Graphics::PixelFormat _palettePixelFormat;
+};
+
+class GLESTexture : public GLESBaseTexture {
+protected:
+ GLESTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat);
+
+public:
+ virtual ~GLESTexture();
+
+ virtual void allocBuffer(GLuint w, GLuint h);
+
+ virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+ const void *buf, int pitch_buf);
+ virtual void fillBuffer(uint32 color);
+
+ virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
+
+protected:
+ byte *_pixels;
+ byte *_buf;
+};
+
+// RGBA4444 texture
+class GLES4444Texture : public GLESTexture {
+public:
+ GLES4444Texture();
+ virtual ~GLES4444Texture();
+
+ static Graphics::PixelFormat pixelFormat() {
+ return Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0);
+ }
+};
+
+// RGBA5551 texture
+class GLES5551Texture : public GLESTexture {
+public:
+ GLES5551Texture();
+ virtual ~GLES5551Texture();
+
+ static inline Graphics::PixelFormat pixelFormat() {
+ return Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0);
+ }
+};
+
+// RGB565 texture
+class GLES565Texture : public GLESTexture {
+public:
+ GLES565Texture();
+ virtual ~GLES565Texture();
+
+ static inline Graphics::PixelFormat pixelFormat() {
+ return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
+ }
+};
+
+class GLESPaletteTexture : public GLESBaseTexture {
+protected:
+ GLESPaletteTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat palettePixelFormat);
+
+public:
+ virtual ~GLESPaletteTexture();
+
+ virtual void allocBuffer(GLuint w, GLuint h);
+ virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+ const void *buf, int pitch_buf);
+ virtual void fillBuffer(uint32 color);
+
+ virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
+
+ virtual const byte *palette_const() const {
+ return _texture;
+ };
+
+ virtual byte *palette() {
+ setDirty();
+ return _texture;
+ };
+
+protected:
+ byte *_texture;
+ size_t _paletteSize;
+};
+
+// RGB888 256-entry paletted texture
+class GLESPalette888Texture : public GLESPaletteTexture {
+public:
+ GLESPalette888Texture();
+ virtual ~GLESPalette888Texture();
+};
+
+// RGBA8888 256-entry paletted texture
+class GLESPalette8888Texture : public GLESPaletteTexture {
+public:
+ GLESPalette8888Texture();
+ virtual ~GLESPalette8888Texture();
+};
+
+// RGB565 256-entry paletted texture
+class GLESPalette565Texture : public GLESPaletteTexture {
+public:
+ GLESPalette565Texture();
+ virtual ~GLESPalette565Texture();
+};
+
+// RGBA4444 256-entry paletted texture
+class GLESPalette4444Texture : public GLESPaletteTexture {
+public:
+ GLESPalette4444Texture();
+ virtual ~GLESPalette4444Texture();
+};
+
+// RGBA5551 256-entry paletted texture
+class GLESPalette5551Texture : public GLESPaletteTexture {
+public:
+ GLESPalette5551Texture();
+ virtual ~GLESPalette5551Texture();
+};
+
+class GLESFakePaletteTexture : public GLESBaseTexture {
+protected:
+ GLESFakePaletteTexture(GLenum glFormat, GLenum glType,
+ Graphics::PixelFormat pixelFormat);
+
+public:
+ virtual ~GLESFakePaletteTexture();
+
+ virtual void allocBuffer(GLuint w, GLuint h);
+ virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
+ const void *buf, int pitch_buf);
+ virtual void fillBuffer(uint32 color);
+
+ virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
+
+ virtual const byte *palette_const() const {
+ return (byte *)_palette;
+ };
+
+ virtual byte *palette() {
+ setDirty();
+ return (byte *)_palette;
+ };
+
+ virtual const Graphics::PixelFormat &getPixelFormat() const;
+
+protected:
+ Graphics::PixelFormat _fake_format;
+ uint16 *_palette;
+ byte *_pixels;
+ uint16 *_buf;
+};
+
+class GLESFakePalette565Texture : public GLESFakePaletteTexture {
+public:
+ GLESFakePalette565Texture();
+ virtual ~GLESFakePalette565Texture();
+};
+
+#endif
+#endif
+
diff --git a/backends/platform/android/video.cpp b/backends/platform/android/video.cpp
deleted file mode 100644
index f8427c2ac8..0000000000
--- a/backends/platform/android/video.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(__ANDROID__)
-
-#include "base/main.h"
-#include "graphics/surface.h"
-
-#include "common/rect.h"
-#include "common/array.h"
-#include "common/util.h"
-#include "common/tokenizer.h"
-
-#include "backends/platform/android/android.h"
-#include "backends/platform/android/video.h"
-
-// Unfortunately, Android devices are too varied to make broad assumptions :/
-#define TEXSUBIMAGE_IS_EXPENSIVE 0
-
-// Supported GL extensions
-static bool npot_supported = false;
-#ifdef GL_OES_draw_texture
-static bool draw_tex_supported = false;
-#endif
-
-static inline GLfixed xdiv(int numerator, int denominator) {
- assert(numerator < (1 << 16));
- return (numerator << 16) / denominator;
-}
-
-template <class T>
-static T nextHigher2(T k) {
- if (k == 0)
- return 1;
- --k;
-
- for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
- k = k | k >> i;
-
- return k + 1;
-}
-
-void GLESTexture::initGLExtensions() {
- const char *ext_string =
- reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
-
- LOGI("Extensions: %s", ext_string);
-
- Common::StringTokenizer tokenizer(ext_string, " ");
- while (!tokenizer.empty()) {
- Common::String token = tokenizer.nextToken();
-
- if (token == "GL_ARB_texture_non_power_of_two")
- npot_supported = true;
-
-#ifdef GL_OES_draw_texture
- if (token == "GL_OES_draw_texture")
- draw_tex_supported = true;
-#endif
- }
-}
-
-GLESTexture::GLESTexture() :
- _texture_width(0),
- _texture_height(0),
- _all_dirty(true)
-{
- GLCALL(glGenTextures(1, &_texture_name));
-
- // This all gets reset later in allocBuffer:
- _surface.w = 0;
- _surface.h = 0;
- _surface.pitch = _texture_width;
- _surface.pixels = 0;
- _surface.bytesPerPixel = 0;
-}
-
-GLESTexture::~GLESTexture() {
- debug("Destroying texture %u", _texture_name);
- GLCALL(glDeleteTextures(1, &_texture_name));
-}
-
-void GLESTexture::reinitGL() {
- GLCALL(glDeleteTextures(1, &_texture_name));
- GLCALL(glGenTextures(1, &_texture_name));
-
- // bypass allocBuffer() shortcut to reinit the texture properly
- _texture_width = 0;
- _texture_height = 0;
-
- allocBuffer(_surface.w, _surface.h);
- setDirty();
-}
-
-void GLESTexture::allocBuffer(GLuint w, GLuint h) {
- int bpp = bytesPerPixel();
- _surface.w = w;
- _surface.h = h;
- _surface.bytesPerPixel = bpp;
-
- // Already allocated a sufficiently large buffer?
- if (w <= _texture_width && h <= _texture_height)
- return;
-
- if (npot_supported) {
- _texture_width = _surface.w;
- _texture_height = _surface.h;
- } else {
- _texture_width = nextHigher2(_surface.w);
- _texture_height = nextHigher2(_surface.h);
- }
-
- _surface.pitch = _texture_width * bpp;
-
- // Allocate room for the texture now, but pixel data gets uploaded
- // later (perhaps with multiple TexSubImage2D operations).
- GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
- GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, glFormat(),
- _texture_width, _texture_height,
- 0, glFormat(), glType(), 0));
-}
-
-void GLESTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h,
- const void *buf, int pitch) {
- ENTER("%u, %u, %u, %u, %p, %d", x, y, w, h, buf, pitch);
-
- GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
- GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
-
- setDirtyRect(Common::Rect(x, y, x+w, y+h));
-
- if (static_cast<int>(w) * bytesPerPixel() == pitch) {
- GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
- glFormat(), glType(), buf));
- } else {
- // GLES removed the ability to specify pitch, so we
- // have to do this ourselves.
- if (h == 0)
- return;
-
-#if TEXSUBIMAGE_IS_EXPENSIVE
- byte tmpbuf[w * h * bytesPerPixel()];
- const byte *src = static_cast<const byte *>(buf);
- byte *dst = tmpbuf;
- GLuint count = h;
-
- do {
- memcpy(dst, src, w * bytesPerPixel());
- dst += w * bytesPerPixel();
- src += pitch;
- } while (--count);
-
- GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
- glFormat(), glType(), tmpbuf));
-#else
- // This version avoids the intermediate copy at the expense of
- // repeat glTexSubImage2D calls. On some devices this is worse.
- const byte *src = static_cast<const byte *>(buf);
- do {
- GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
- w, 1, glFormat(), glType(), src));
- ++y;
- src += pitch;
- } while (--h);
-#endif
- }
-}
-
-void GLESTexture::fillBuffer(byte x) {
- int rowbytes = _surface.w * bytesPerPixel();
- byte tmpbuf[_surface.h * rowbytes];
- memset(tmpbuf, x, _surface.h * rowbytes);
- updateBuffer(0, 0, _surface.w, _surface.h, tmpbuf, rowbytes);
-}
-
-void GLESTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
- GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
-
-#ifdef GL_OES_draw_texture
- // Great extension, but only works under specific conditions.
- // Still a work-in-progress - disabled for now.
- if (false && draw_tex_supported && paletteSize() == 0) {
- //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE));
- const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h };
-
- GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop));
-
- // Android GLES bug?
- GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff));
-
- GLCALL(glDrawTexiOES(x, y, 0, w, h));
- } else
-#endif
- {
- const GLfixed tex_width = xdiv(_surface.w, _texture_width);
- const GLfixed tex_height = xdiv(_surface.h, _texture_height);
- const GLfixed texcoords[] = {
- 0, 0,
- tex_width, 0,
- 0, tex_height,
- tex_width, tex_height,
- };
-
- GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords));
-
- const GLshort vertices[] = {
- x, y,
- x + w, y,
- x, y + h,
- x + w, y + h,
- };
-
- GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices));
-
- assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords));
- GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2));
- }
-
- _all_dirty = false;
- _dirty_rect = Common::Rect();
-}
-
-GLESPaletteTexture::GLESPaletteTexture() :
- GLESTexture(),
- _texture(0)
-{
-}
-
-GLESPaletteTexture::~GLESPaletteTexture() {
- delete[] _texture;
-}
-
-void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
- int bpp = bytesPerPixel();
- _surface.w = w;
- _surface.h = h;
- _surface.bytesPerPixel = bpp;
-
- // Already allocated a sufficiently large buffer?
- if (w <= _texture_width && h <= _texture_height)
- return;
-
- if (npot_supported) {
- _texture_width = _surface.w;
- _texture_height = _surface.h;
- } else {
- _texture_width = nextHigher2(_surface.w);
- _texture_height = nextHigher2(_surface.h);
- }
- _surface.pitch = _texture_width * bpp;
-
- // Texture gets uploaded later (from drawTexture())
-
- byte *new_buffer = new byte[paletteSize() +
- _texture_width * _texture_height * bytesPerPixel()];
- if (_texture) {
- // preserve palette
- memcpy(new_buffer, _texture, paletteSize());
- delete[] _texture;
- }
-
- _texture = new_buffer;
- _surface.pixels = _texture + paletteSize();
-}
-
-void GLESPaletteTexture::fillBuffer(byte x) {
- assert(_surface.pixels);
- memset(_surface.pixels, x, _surface.pitch * _surface.h);
- setDirty();
-}
-
-void GLESPaletteTexture::updateBuffer(GLuint x, GLuint y,
- GLuint w, GLuint h,
- const void *buf, int pitch) {
- _all_dirty = true;
-
- const byte * src = static_cast<const byte *>(buf);
- byte *dst = static_cast<byte *>(_surface.getBasePtr(x, y));
-
- do {
- memcpy(dst, src, w * bytesPerPixel());
- dst += _surface.pitch;
- src += pitch;
- } while (--h);
-}
-
-void GLESPaletteTexture::uploadTexture() const {
- const size_t texture_size =
- paletteSize() + _texture_width * _texture_height * bytesPerPixel();
-
- GLCALL(glCompressedTexImage2D(GL_TEXTURE_2D, 0, glType(),
- _texture_width, _texture_height,
- 0, texture_size, _texture));
-}
-
-void GLESPaletteTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
- if (_all_dirty) {
- GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- GL_NEAREST));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_NEAREST));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
- GL_CLAMP_TO_EDGE));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
- GL_CLAMP_TO_EDGE));
- uploadTexture();
- _all_dirty = false;
- }
-
- GLESTexture::drawTexture(x, y, w, h);
-}
-
-#endif
-
diff --git a/backends/platform/android/video.h b/backends/platform/android/video.h
deleted file mode 100644
index da42ea876d..0000000000
--- a/backends/platform/android/video.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(__ANDROID__)
-
-#include <GLES/gl.h>
-
-#include "graphics/surface.h"
-
-#include "common/rect.h"
-#include "common/array.h"
-
-class GLESTexture {
-public:
- static void initGLExtensions();
-
- GLESTexture();
- virtual ~GLESTexture();
-
- virtual void reinitGL();
- virtual void allocBuffer(GLuint width, GLuint height);
-
- virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
- const void *buf, int pitch);
- virtual void fillBuffer(byte x);
-
- virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
-
- inline GLuint width() const {
- return _surface.w;
- }
-
- inline GLuint height() const {
- return _surface.h;
- }
-
- inline GLuint texture_name() const {
- return _texture_name;
- }
-
- inline const Graphics::Surface *surface_const() const {
- return &_surface;
- }
-
- inline Graphics::Surface *surface() {
- setDirty();
- return &_surface;
- }
-
- inline bool dirty() const {
- return _all_dirty || !_dirty_rect.isEmpty();
- }
-
- inline void drawTexture() {
- drawTexture(0, 0, _surface.w, _surface.h);
- }
-
-protected:
- virtual byte bytesPerPixel() const = 0;
- virtual GLenum glFormat() const = 0;
- virtual GLenum glType() const = 0;
-
- virtual size_t paletteSize() const {
- return 0;
- }
-
- inline void setDirty() {
- _all_dirty = true;
- _dirty_rect = Common::Rect();
- }
-
- inline void setDirtyRect(const Common::Rect& r) {
- if (!_all_dirty) {
- if (_dirty_rect.isEmpty())
- _dirty_rect = r;
- else
- _dirty_rect.extend(r);
- }
- }
-
- GLuint _texture_name;
- Graphics::Surface _surface;
- GLuint _texture_width;
- GLuint _texture_height;
- bool _all_dirty;
-
- // Covers dirty area
- Common::Rect _dirty_rect;
-};
-
-// RGBA4444 texture
-class GLES4444Texture : public GLESTexture {
-protected:
- virtual byte bytesPerPixel() const {
- return 2;
- }
-
- virtual GLenum glFormat() const {
- return GL_RGBA;
- }
-
- virtual GLenum glType() const {
- return GL_UNSIGNED_SHORT_4_4_4_4;
- }
-};
-
-// RGB565 texture
-class GLES565Texture : public GLESTexture {
-protected:
- virtual byte bytesPerPixel() const {
- return 2;
- }
-
- virtual GLenum glFormat() const {
- return GL_RGB;
- }
-
- virtual GLenum glType() const {
- return GL_UNSIGNED_SHORT_5_6_5;
- }
-};
-
-// RGB888 256-entry paletted texture
-class GLESPaletteTexture : public GLESTexture {
-public:
- GLESPaletteTexture();
- virtual ~GLESPaletteTexture();
-
- virtual void allocBuffer(GLuint width, GLuint height);
- virtual void updateBuffer(GLuint x, GLuint y, GLuint width, GLuint height,
- const void *buf, int pitch);
- virtual void fillBuffer(byte x);
-
- virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h);
-
- inline void drawTexture() {
- drawTexture(0, 0, _surface.w, _surface.h);
- }
-
- inline const byte *palette_const() const {
- return _texture;
- };
-
- inline byte *palette() {
- setDirty();
- return _texture;
- };
-
-protected:
- virtual byte bytesPerPixel() const {
- return 1;
- }
-
- virtual GLenum glFormat() const {
- return GL_RGB;
- }
-
- virtual GLenum glType() const {
- return GL_PALETTE8_RGB8_OES;
- }
-
- virtual size_t paletteSize() const {
- return 256 * 3;
- }
-
- void uploadTexture() const;
-
- byte *_texture;
-};
-
-// RGBA8888 256-entry paletted texture
-class GLESPaletteATexture : public GLESPaletteTexture {
-protected:
- virtual GLenum glFormat() const {
- return GL_RGBA;
- }
-
- virtual GLenum glType() const {
- return GL_PALETTE8_RGBA8_OES;
- }
-
- virtual size_t paletteSize() const {
- return 256 * 4;
- }
-};
-
-#endif
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index dc91bd9fe7..bddb48ca95 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -125,10 +125,10 @@ void OSystem_SDL::init() {
if (_timerManager == 0)
_timerManager = new SdlTimerManager();
- #ifdef USE_OPENGL
- // Setup a list with both SDL and OpenGL graphics modes
- setupGraphicsModes();
- #endif
+#ifdef USE_OPENGL
+ // Setup a list with both SDL and OpenGL graphics modes
+ setupGraphicsModes();
+#endif
}
void OSystem_SDL::initBackend() {
@@ -148,11 +148,15 @@ void OSystem_SDL::initBackend() {
Common::String gfxMode(ConfMan.get("gfx_mode"));
bool use_opengl = false;
const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
+ int i = 0;
while (mode->name) {
- if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0)
+ if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) {
+ _graphicsMode = i + _sdlModesCount;
use_opengl = true;
+ }
mode++;
+ ++i;
}
// If the gfx_mode is from OpenGL, create the OpenGL graphics manager
@@ -464,6 +468,7 @@ int OSystem_SDL::getDefaultGraphicsMode() const {
bool OSystem_SDL::setGraphicsMode(int mode) {
const OSystem::GraphicsMode *srcMode;
int i;
+
// Check if mode is from SDL or OpenGL
if (mode < _sdlModesCount) {
srcMode = SdlGraphicsManager::supportedGraphicsModes();
@@ -472,28 +477,34 @@ bool OSystem_SDL::setGraphicsMode(int mode) {
srcMode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
i = _sdlModesCount;
}
+
// Loop through modes
while (srcMode->name) {
if (i == mode) {
// If the new mode and the current mode are not from the same graphics
// manager, delete and create the new mode graphics manager
if (_graphicsMode >= _sdlModesCount && mode < _sdlModesCount) {
+ debug(1, "switching to plain SDL graphics");
delete _graphicsManager;
_graphicsManager = new SdlGraphicsManager(_eventSource);
((SdlGraphicsManager *)_graphicsManager)->initEventObserver();
_graphicsManager->beginGFXTransaction();
} else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) {
+ debug(1, "switching to OpenGL graphics");
delete _graphicsManager;
_graphicsManager = new OpenGLSdlGraphicsManager();
((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
_graphicsManager->beginGFXTransaction();
}
+
_graphicsMode = mode;
return _graphicsManager->setGraphicsMode(srcMode->id);
}
+
i++;
srcMode++;
}
+
return false;
}
diff --git a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
index c7623d09a8..12b4cb3610 100644
--- a/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_A0000658_S60v3.mmp.in
@@ -91,7 +91,7 @@ STATICLIBRARY esdl.lib
// *** Include paths
USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines
-USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\sound
+USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\audio
SYSTEMINCLUDE \epoc32\include\ESDL
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
index 6f14e858b0..9af6535b22 100644
--- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
@@ -91,7 +91,7 @@ STATICLIBRARY esdl.lib
// *** Include paths
USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\engines
-USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\sound
+USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl ..\..\..\..\audio
SYSTEMINCLUDE \epoc32\include\ESDL
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
diff --git a/backends/platform/symbian/mmp/scummvm_agi.mmp.in b/backends/platform/symbian/mmp/scummvm_agi.mmp.in
index 044326405d..e2d98b9ae4 100644
--- a/backends/platform/symbian/mmp/scummvm_agi.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_agi.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\agi
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_agos.mmp.in b/backends/platform/symbian/mmp/scummvm_agos.mmp.in
index e2d1e5eff4..077111d783 100644
--- a/backends/platform/symbian/mmp/scummvm_agos.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_agos.mmp.in
@@ -65,6 +65,6 @@ SOURCEPATH ..\..\..\..\engines\agos
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in
index d25cef4ffe..b3bfbab530 100644
--- a/backends/platform/symbian/mmp/scummvm_base.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in
@@ -51,7 +51,7 @@ ALWAYS_BUILD_AS_ARM
// *** Include paths
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio
USERINCLUDE ..\..\..\..\backends\fs ..\src ..\..\..\..\backends\platform\sdl
SYSTEMINCLUDE \epoc32\include\ESDL
@@ -95,7 +95,7 @@ SOURCEPATH ..\..\..\..\gui
//SOURCE KeysDialog.cpp
//SOURCE Actions.cpp
-SOURCEPATH ..\..\..\..\sound
+SOURCEPATH ..\..\..\..\audio
//START_AUTO_OBJECTS_SOUND_//
// empty base file, will be updated by Perl build scripts
@@ -110,6 +110,12 @@ SOURCE rate_arm.cpp // ARM version: add ASM .cpp wrapper
SOURCE rate_arm_asm.s // ARM version: add ASM routines
#endif
+SOURCEPATH ..\..\..\..\video
+//START_AUTO_OBJECTS_VIDEO_//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_OBJECTS_VIDEO_//
// add a few files manually, since they are not parsed from modules.mk files
SOURCEPATH ..\..\..\..
diff --git a/backends/platform/symbian/mmp/scummvm_cine.mmp.in b/backends/platform/symbian/mmp/scummvm_cine.mmp.in
index d114ec554b..2c8118ef13 100644
--- a/backends/platform/symbian/mmp/scummvm_cine.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cine.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\cine
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
index e4c836a68b..b43a867da3 100644
--- a/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_cruise.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\cruise
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_draci.mmp.in b/backends/platform/symbian/mmp/scummvm_draci.mmp.in
index b10eb0b5a8..9f24927f27 100644
--- a/backends/platform/symbian/mmp/scummvm_draci.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_draci.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\draci
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
index 529eeb9e0b..d8cc6da6ae 100644
--- a/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_drascula.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\drascula
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_gob.mmp.in b/backends/platform/symbian/mmp/scummvm_gob.mmp.in
index fa2ce0dedf..ce94f85283 100644
--- a/backends/platform/symbian/mmp/scummvm_gob.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_gob.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\gob
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
index 7a03cc1745..7229edf4aa 100644
--- a/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_groovie.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\groovie
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
index 301d23cab4..b3f9edd1e6 100644
--- a/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_hugo.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\hugo
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
index 5fa5fdac6a..654632c229 100644
--- a/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_kyra.mmp.in
@@ -65,5 +65,5 @@ SOURCEPATH ..\..\..\..\engines\kyra
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
index a297137f02..418730c064 100644
--- a/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_lastexpress.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\lastexpress
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_lure.mmp.in b/backends/platform/symbian/mmp/scummvm_lure.mmp.in
index c4a3900a05..e1a63b602b 100644
--- a/backends/platform/symbian/mmp/scummvm_lure.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_lure.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\lure
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_m4.mmp.in b/backends/platform/symbian/mmp/scummvm_m4.mmp.in
index f4430f2e58..c2e1ce4e8b 100644
--- a/backends/platform/symbian/mmp/scummvm_m4.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_m4.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\m4
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_made.mmp.in b/backends/platform/symbian/mmp/scummvm_made.mmp.in
index bf50157224..91b9ca756d 100644
--- a/backends/platform/symbian/mmp/scummvm_made.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_made.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\made
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
index 78e931b06f..0edba5eb4d 100644
--- a/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_mohawk.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\mohawk
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
index e96ab907cd..744a756f4e 100644
--- a/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_parallaction.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\parallaction
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_queen.mmp.in b/backends/platform/symbian/mmp/scummvm_queen.mmp.in
index 4f9d9319e0..bf88744701 100644
--- a/backends/platform/symbian/mmp/scummvm_queen.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_queen.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\queen
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_saga.mmp.in b/backends/platform/symbian/mmp/scummvm_saga.mmp.in
index e5beefc0c5..a95ee1e7fd 100644
--- a/backends/platform/symbian/mmp/scummvm_saga.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_saga.mmp.in
@@ -71,5 +71,5 @@ SOURCEPATH ..\..\..\..\engines\saga
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_sci.mmp.in b/backends/platform/symbian/mmp/scummvm_sci.mmp.in
index eb0d1b020f..ca9e712f3f 100644
--- a/backends/platform/symbian/mmp/scummvm_sci.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sci.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\sci
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
index 6b5d249422..0a3cd9bb7d 100644
--- a/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_scumm.mmp.in
@@ -82,7 +82,7 @@ SOURCE smush/codec47ARM.s // ARM version: add ASM routines
// *** Include paths
USERINCLUDE ..\..\..\..\engines ..\..\..\..\engines\scumm\smush ..\..\..\..\engines\scumm\insane
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include\libc
diff --git a/backends/platform/symbian/mmp/scummvm_sky.mmp.in b/backends/platform/symbian/mmp/scummvm_sky.mmp.in
index d1d222b1fa..1bc2301745 100644
--- a/backends/platform/symbian/mmp/scummvm_sky.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sky.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sky
// *** Include paths
USERINCLUDE ..\..\..\..\engines ..\..\..\..\engines\sky\music
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
index 0aaf9d504b..6bf543070b 100644
--- a/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sword1.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sword1
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
index 4a7181709f..cee4143f94 100644
--- a/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_sword2.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\sword2
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
index 7832fc4880..fa4ef79692 100644
--- a/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_teenagent.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\teenagent
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
index 6190ec8152..569b79ba3c 100644
--- a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
@@ -59,5 +59,5 @@ SOURCEPATH ..\..\..\..\engines\tinsel
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_toon.mmp.in b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
index f2301c4ae2..f309e6d0fa 100644
--- a/backends/platform/symbian/mmp/scummvm_toon.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_toon.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\toon
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_touche.mmp.in b/backends/platform/symbian/mmp/scummvm_touche.mmp.in
index 9e4c3d0496..ab42afe304 100644
--- a/backends/platform/symbian/mmp/scummvm_touche.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_touche.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\touche
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
index d193ac49a9..434072bc96 100644
--- a/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_tucker.mmp.in
@@ -59,6 +59,6 @@ SOURCEPATH ..\..\..\..\engines\tucker
// *** Include paths
USERINCLUDE ..\..\..\..\engines
-USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\audio ..\src
SYSTEMINCLUDE \epoc32\include\ZLIB // before \epoc32\include because symbian already has older version
SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp
index 99d0be2bdc..3895c7d6fa 100644
--- a/backends/platform/wince/CEActionsPocket.cpp
+++ b/backends/platform/wince/CEActionsPocket.cpp
@@ -38,7 +38,7 @@
#ifdef _WIN32_WCE
-#define KEY_ALL_SKIP 3457
+#define KEY_ALL_SKIP 3457
#endif
const Common::String pocketActionNames[] = {
@@ -85,14 +85,14 @@ int CEActionsPocket::version() {
}
CEActionsPocket::CEActionsPocket(const Common::String &gameid) :
-GUI::Actions() {
+ GUI::Actions() {
int i;
_right_click_needed = false;
_hide_toolbar_needed = false;
_zoom_needed = false;
- for (i=0; i<POCKET_ACTION_LAST; i++) {
+ for (i = 0; i < POCKET_ACTION_LAST; i++) {
_action_mapping[i] = 0;
_action_enabled[i] = false;
}
@@ -112,7 +112,7 @@ GUI::Actions() {
void CEActionsPocket::initInstanceMain(OSystem *mainSystem) {
// Nothing generic to do for Pocket PC
- _CESystem = static_cast<OSystem_WINCE3*>(mainSystem);
+ _CESystem = static_cast<OSystem_WINCE3 *>(mainSystem);
GUI_Actions::initInstanceMain(mainSystem);
}
@@ -126,7 +126,7 @@ void CEActionsPocket::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra", 4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
@@ -134,7 +134,7 @@ void CEActionsPocket::initInstanceGame() {
bool is_parallaction = (gameid == "parallaction");
bool is_lure = (gameid == "lure");
bool is_feeble = (gameid == "feeble");
- bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0);
+ bool is_drascula = (strncmp(gameid.c_str(), "drascula", 8) == 0);
bool is_tucker = (gameid == "tucker");
bool is_groovie = (gameid == "groovie");
bool is_tinsel = (gameid == "tinsel");
@@ -145,7 +145,7 @@ void CEActionsPocket::initInstanceGame() {
// See if a right click mapping could be needed
if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel ||
- is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise)
+ is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise)
_right_click_needed = true;
// See if a "hide toolbar" mapping could be needed
@@ -187,7 +187,7 @@ void CEActionsPocket::initInstanceGame() {
if (!is_cine && !is_parallaction && !is_groovie && !is_cruise && !is_made)
_action_enabled[POCKET_ACTION_SKIP] = true;
if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel ||
- is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker)
+ is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker)
_key_action[POCKET_ACTION_SKIP].setKey(VK_ESCAPE);
else
_key_action[POCKET_ACTION_SKIP].setKey(KEY_ALL_SKIP);
@@ -239,10 +239,12 @@ bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) {
if (!pushed) {
switch (action) {
case POCKET_ACTION_RIGHTCLICK:
- _CESystem->add_right_click(false);
+ //_CESystem->add_right_click(false);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(false);
return true;
case POCKET_ACTION_LEFTCLICK:
- _CESystem->add_left_click(false);
+ //_CESystem->add_left_click(false);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(false);
return true;
case POCKET_ACTION_PAUSE:
case POCKET_ACTION_SAVE:
@@ -272,43 +274,55 @@ bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) {
EventsBuffer::simulateKey(&_key_action[action], true);
return true;
case POCKET_ACTION_KEYBOARD:
- _CESystem->swap_panel();
+ //_CESystem->swap_panel();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_panel();
return true;
case POCKET_ACTION_HIDE:
- _CESystem->swap_panel_visibility();
+ //_CESystem->swap_panel_visibility();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_panel_visibility();
return true;
case POCKET_ACTION_SOUND:
_CESystem->swap_sound_master();
return true;
case POCKET_ACTION_RIGHTCLICK:
- _CESystem->add_right_click(true);
+ //_CESystem->add_right_click(true);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(true);
return true;
case POCKET_ACTION_CURSOR:
- _CESystem->swap_mouse_visibility();
+ //_CESystem->swap_mouse_visibility();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_mouse_visibility();
return true;
case POCKET_ACTION_FREELOOK:
- _CESystem->swap_freeLook();
+ //_CESystem->swap_freeLook();
+ ((WINCESdlEventSource *)((OSystem_SDL *)g_system)->getEventManager())->swap_freeLook();
return true;
case POCKET_ACTION_ZOOM_UP:
- _CESystem->swap_zoom_up();
+ //_CESystem->swap_zoom_up();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_zoom_up();
return true;
case POCKET_ACTION_ZOOM_DOWN:
- _CESystem->swap_zoom_down();
+ //_CESystem->swap_zoom_down();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_zoom_down();
return true;
case POCKET_ACTION_LEFTCLICK:
- _CESystem->add_left_click(true);
+ //_CESystem->add_left_click(true);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(true);
return true;
case POCKET_ACTION_UP:
- _CESystem->move_cursor_up();
+ //_CESystem->move_cursor_up();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_up();
return true;
case POCKET_ACTION_DOWN:
- _CESystem->move_cursor_down();
+ //_CESystem->move_cursor_down();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_down();
return true;
case POCKET_ACTION_LEFT:
- _CESystem->move_cursor_left();
+ //_CESystem->move_cursor_left();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_left();
return true;
case POCKET_ACTION_RIGHT:
- _CESystem->move_cursor_right();
+ //_CESystem->move_cursor_right();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_right();
return true;
case POCKET_ACTION_QUIT:
if (!quitdialog) {
diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp
index 5c7feb4950..413c52af2b 100644
--- a/backends/platform/wince/CEActionsSmartphone.cpp
+++ b/backends/platform/wince/CEActionsSmartphone.cpp
@@ -36,7 +36,7 @@
#include "common/translation.h"
-#define KEY_ALL_SKIP 3457
+#define KEY_ALL_SKIP 3457
const String smartphoneActionNames[] = {
_s("Up"),
@@ -79,10 +79,10 @@ int CEActionsSmartphone::version() {
}
CEActionsSmartphone::CEActionsSmartphone()
-: GUI::Actions() {
+ : GUI::Actions() {
int i;
- for (i=0; i<SMARTPHONE_ACTION_LAST; i++) {
+ for (i = 0; i < SMARTPHONE_ACTION_LAST; i++) {
_action_mapping[i] = ACTIONS_SMARTPHONE_DEFAULT[i];
_action_enabled[i] = false;
}
@@ -90,7 +90,7 @@ CEActionsSmartphone::CEActionsSmartphone()
}
void CEActionsSmartphone::initInstanceMain(OSystem *mainSystem) {
- _CESystem = static_cast<OSystem_WINCE3*>(mainSystem);
+ _CESystem = static_cast<OSystem_WINCE3 *>(mainSystem);
GUI_Actions::initInstanceMain(mainSystem);
@@ -117,7 +117,7 @@ void CEActionsSmartphone::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra", 4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
@@ -125,7 +125,7 @@ void CEActionsSmartphone::initInstanceGame() {
bool is_parallaction = (gameid == "parallaction");
bool is_lure = (gameid == "lure");
bool is_feeble = (gameid == "feeble");
- bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0);
+ bool is_drascula = (strncmp(gameid.c_str(), "drascula", 8) == 0);
bool is_tucker = (gameid == "tucker");
bool is_groovie = (gameid == "groovie");
bool is_tinsel = (gameid == "tinsel");
@@ -136,7 +136,7 @@ void CEActionsSmartphone::initInstanceGame() {
// See if a right click mapping could be needed
if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_tinsel ||
- is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise)
+ is_samnmax || is_cine || is_touche || is_parallaction || is_drascula || is_cruise)
_right_click_needed = true;
// Initialize keys for different actions
@@ -168,8 +168,8 @@ void CEActionsSmartphone::initInstanceGame() {
// Skip
_action_enabled[SMARTPHONE_ACTION_SKIP] = true;
if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_tinsel ||
- is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker ||
- is_groovie || is_cruise || is_made)
+ is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula || is_tucker ||
+ is_groovie || is_cruise || is_made)
_key_action[SMARTPHONE_ACTION_SKIP].setKey(VK_ESCAPE);
else
_key_action[SMARTPHONE_ACTION_SKIP].setKey(KEY_ALL_SKIP);
@@ -204,81 +204,92 @@ bool CEActionsSmartphone::perform(GUI::ActionType action, bool pushed) {
if (!pushed) {
switch (action) {
- case SMARTPHONE_ACTION_RIGHTCLICK:
- _CESystem->add_right_click(false);
- return true;
- case SMARTPHONE_ACTION_LEFTCLICK:
- _CESystem->add_left_click(false);
- return true;
- case SMARTPHONE_ACTION_SAVE:
- case SMARTPHONE_ACTION_SKIP:
- case SMARTPHONE_ACTION_MULTI:
- EventsBuffer::simulateKey(&_key_action[action], false);
- return true;
- }
- return false;
- }
-
- switch (action) {
- case SMARTPHONE_ACTION_SAVE:
- case SMARTPHONE_ACTION_SKIP:
- case SMARTPHONE_ACTION_MULTI:
- if (action == SMARTPHONE_ACTION_SAVE && ConfMan.get("gameid") == "parallaction") {
- // FIXME: This is a temporary solution. The engine should handle its own menus.
- // Note that the user can accomplish this via the virtual keyboard as well, this is just for convenience
- GUI::MessageDialog alert(_("Do you want to load or save the game?"), _("Load"), _("Save"));
- if (alert.runModal() == GUI::kMessageOK)
- _key_action[action].setKey(SDLK_l);
- else
- _key_action[action].setKey(SDLK_s);
- }
- EventsBuffer::simulateKey(&_key_action[action], true);
- return true;
case SMARTPHONE_ACTION_RIGHTCLICK:
- _CESystem->add_right_click(true);
+ //_CESystem->add_right_click(false);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(false);
return true;
case SMARTPHONE_ACTION_LEFTCLICK:
- _CESystem->add_left_click(true);
- return true;
- case SMARTPHONE_ACTION_UP:
- _CESystem->move_cursor_up();
- return true;
- case SMARTPHONE_ACTION_DOWN:
- _CESystem->move_cursor_down();
- return true;
- case SMARTPHONE_ACTION_LEFT:
- _CESystem->move_cursor_left();
- return true;
- case SMARTPHONE_ACTION_RIGHT:
- _CESystem->move_cursor_right();
- return true;
- case SMARTPHONE_ACTION_ZONE:
- _CESystem->switch_zone();
+ //_CESystem->add_left_click(false);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(false);
return true;
- case SMARTPHONE_ACTION_BINDKEYS:
- if (!keydialogrunning) {
- keydialogrunning = true;
- GUI::KeysDialog *keysDialog = new GUI::KeysDialog();
- keysDialog->runModal();
- delete keysDialog;
- keydialogrunning = false;
- }
- return true;
- case SMARTPHONE_ACTION_KEYBOARD:
- _CESystem->swap_smartphone_keyboard();
- return true;
- case SMARTPHONE_ACTION_ROTATE:
- _CESystem->smartphone_rotate_display();
- return true;
- case SMARTPHONE_ACTION_QUIT:
- if (!quitdialog) {
- quitdialog = true;
- GUI::MessageDialog alert(_(" Are you sure you want to quit ? "), _("Yes"), _("No"));
- if (alert.runModal() == GUI::kMessageOK)
- _mainSystem->quit();
- quitdialog = false;
- }
+ case SMARTPHONE_ACTION_SAVE:
+ case SMARTPHONE_ACTION_SKIP:
+ case SMARTPHONE_ACTION_MULTI:
+ EventsBuffer::simulateKey(&_key_action[action], false);
return true;
+ }
+ return false;
+ }
+
+ switch (action) {
+ case SMARTPHONE_ACTION_SAVE:
+ case SMARTPHONE_ACTION_SKIP:
+ case SMARTPHONE_ACTION_MULTI:
+ if (action == SMARTPHONE_ACTION_SAVE && ConfMan.get("gameid") == "parallaction") {
+ // FIXME: This is a temporary solution. The engine should handle its own menus.
+ // Note that the user can accomplish this via the virtual keyboard as well, this is just for convenience
+ GUI::MessageDialog alert(_("Do you want to load or save the game?"), _("Load"), _("Save"));
+ if (alert.runModal() == GUI::kMessageOK)
+ _key_action[action].setKey(SDLK_l);
+ else
+ _key_action[action].setKey(SDLK_s);
+ }
+ EventsBuffer::simulateKey(&_key_action[action], true);
+ return true;
+ case SMARTPHONE_ACTION_RIGHTCLICK:
+ //_CESystem->add_right_click(true);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_right_click(true);
+ return true;
+ case SMARTPHONE_ACTION_LEFTCLICK:
+ //_CESystem->add_left_click(true);
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->add_left_click(true);
+ return true;
+ case SMARTPHONE_ACTION_UP:
+ //_CESystem->move_cursor_up();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_up();
+ return true;
+ case SMARTPHONE_ACTION_DOWN:
+ //_CESystem->move_cursor_down();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_down();
+ return true;
+ case SMARTPHONE_ACTION_LEFT:
+ //_CESystem->move_cursor_left();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_left();
+ return true;
+ case SMARTPHONE_ACTION_RIGHT:
+ //_CESystem->move_cursor_right();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->move_cursor_right();
+ return true;
+ case SMARTPHONE_ACTION_ZONE:
+ //_CESystem->switch_zone();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->switch_zone();
+ return true;
+ case SMARTPHONE_ACTION_BINDKEYS:
+ if (!keydialogrunning) {
+ keydialogrunning = true;
+ GUI::KeysDialog *keysDialog = new GUI::KeysDialog();
+ keysDialog->runModal();
+ delete keysDialog;
+ keydialogrunning = false;
+ }
+ return true;
+ case SMARTPHONE_ACTION_KEYBOARD:
+ //_CESystem->swap_smartphone_keyboard();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->swap_smartphone_keyboard();
+ return true;
+ case SMARTPHONE_ACTION_ROTATE:
+ //_CESystem->smartphone_rotate_display();
+ ((WINCESdlGraphicsManager *)((OSystem_SDL *)g_system)->getGraphicsManager())->smartphone_rotate_display();
+ return true;
+ case SMARTPHONE_ACTION_QUIT:
+ if (!quitdialog) {
+ quitdialog = true;
+ GUI::MessageDialog alert(_(" Are you sure you want to quit ? "), _("Yes"), _("No"));
+ if (alert.runModal() == GUI::kMessageOK)
+ _mainSystem->quit();
+ quitdialog = false;
+ }
+ return true;
}
return false;
diff --git a/backends/platform/wince/CEDevice.cpp b/backends/platform/wince/CEDevice.cpp
index d94ce6cde7..ffe2523b47 100644
--- a/backends/platform/wince/CEDevice.cpp
+++ b/backends/platform/wince/CEDevice.cpp
@@ -29,22 +29,22 @@
#include "backends/platform/wince/wince-sdl.h"
-static void (WINAPI* _SHIdleTimerReset)(void) = NULL;
-static HANDLE (WINAPI* _SetPowerRequirement)(PVOID,int,ULONG,PVOID,ULONG) = NULL;
-static DWORD (WINAPI* _ReleasePowerRequirement)(HANDLE) = NULL;
+static void (WINAPI *_SHIdleTimerReset)(void) = NULL;
+static HANDLE(WINAPI *_SetPowerRequirement)(PVOID, int, ULONG, PVOID, ULONG) = NULL;
+static DWORD (WINAPI *_ReleasePowerRequirement)(HANDLE) = NULL;
static HANDLE _hPowerManagement = NULL;
static DWORD _lastTime = 0;
static DWORD REG_bat = 0, REG_ac = 0, REG_disp = 0, bat_timeout = 0;
static bool REG_tampered = false;
#ifdef __GNUC__
extern "C" void WINAPI SystemIdleTimerReset(void);
-#define SPI_SETBATTERYIDLETIMEOUT 251
-#define SPI_GETBATTERYIDLETIMEOUT 252
+#define SPI_SETBATTERYIDLETIMEOUT 251
+#define SPI_GETBATTERYIDLETIMEOUT 252
#endif
#define TIMER_TRIGGER 9000
-DWORD CEDevice::reg_access(TCHAR *key, TCHAR *val, DWORD data) {
+DWORD CEDevice::reg_access(const TCHAR *key, const TCHAR *val, DWORD data) {
HKEY regkey;
DWORD tmpval, cbdata;
@@ -70,7 +70,7 @@ DWORD CEDevice::reg_access(TCHAR *key, TCHAR *val, DWORD data) {
void CEDevice::backlight_xchg() {
HANDLE h;
- REG_bat = reg_access(TEXT("ControlPanel\\BackLight"), TEXT("BatteryTimeout"), REG_bat);
+ REG_bat = reg_access(TEXT("ControlPanel\\BackLight"), (const TCHAR *)TEXT("BatteryTimeout"), REG_bat);
REG_ac = reg_access(TEXT("ControlPanel\\BackLight"), TEXT("ACTimeout"), REG_ac);
REG_disp = reg_access(TEXT("ControlPanel\\Power"), TEXT("Display"), REG_disp);
@@ -85,20 +85,19 @@ void CEDevice::init() {
// 2003+ power management code borrowed from MoDaCo & Betaplayer. Thanks !
HINSTANCE dll = LoadLibrary(TEXT("aygshell.dll"));
if (dll) {
- *(FARPROC*)&_SHIdleTimerReset = GetProcAddress(dll, MAKEINTRESOURCE(2006));
+ _SHIdleTimerReset = (void (*)())GetProcAddress(dll, MAKEINTRESOURCE(2006));
}
dll = LoadLibrary(TEXT("coredll.dll"));
if (dll) {
- *(FARPROC*)&_SetPowerRequirement = GetProcAddress(dll, TEXT("SetPowerRequirement"));
- *(FARPROC*)&_ReleasePowerRequirement = GetProcAddress(dll, TEXT("ReleasePowerRequirement"));
-
+ _SetPowerRequirement = (HANDLE (*)(PVOID, int, ULONG, PVOID, ULONG))GetProcAddress(dll, TEXT("SetPowerRequirement"));
+ _ReleasePowerRequirement = (DWORD (*)(HANDLE))GetProcAddress(dll, TEXT("ReleasePowerRequirement"));
}
if (_SetPowerRequirement)
_hPowerManagement = _SetPowerRequirement((PVOID) TEXT("BKL1:"), 0, 1, (PVOID) NULL, 0);
_lastTime = GetTickCount();
// older devices
- REG_bat = REG_ac = REG_disp = 2 * 60 * 60 * 1000; // 2hrs should do it
+ REG_bat = REG_ac = REG_disp = 2 * 60 * 60 * 1000; // 2hrs should do it
backlight_xchg();
REG_tampered = true;
SystemParametersInfo(SPI_GETBATTERYIDLETIMEOUT, 0, (void *) &bat_timeout, 0);
@@ -127,6 +126,10 @@ bool CEDevice::hasSquareQVGAResolution() {
return (OSystem_WINCE3::getScreenWidth() == 240 && OSystem_WINCE3::getScreenHeight() == 240);
}
+bool CEDevice::hasWideResolution() {
+ return (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640);
+}
+
bool CEDevice::hasPocketPCResolution() {
if (OSystem_WINCE3::isOzone() && hasWideResolution())
return true;
@@ -139,10 +142,6 @@ bool CEDevice::hasDesktopResolution() {
return (OSystem_WINCE3::getScreenWidth() > 320);
}
-bool CEDevice::hasWideResolution() {
- return (OSystem_WINCE3::getScreenWidth() >= 640 || OSystem_WINCE3::getScreenHeight() >= 640);
-}
-
bool CEDevice::hasSmartphoneResolution() {
return (OSystem_WINCE3::getScreenWidth() < 240);
}
diff --git a/backends/platform/wince/CEDevice.h b/backends/platform/wince/CEDevice.h
index b2b20d05ce..24dffca0b3 100644
--- a/backends/platform/wince/CEDevice.h
+++ b/backends/platform/wince/CEDevice.h
@@ -43,7 +43,7 @@ public:
static bool isSmartphone();
private:
- static DWORD reg_access(TCHAR *key, TCHAR *val, DWORD data);
+ static DWORD reg_access(const TCHAR *key, const TCHAR *val, DWORD data);
static void backlight_xchg();
};
diff --git a/backends/platform/wince/CEException.cpp b/backends/platform/wince/CEException.cpp
index 421db4960c..08a327136f 100644
--- a/backends/platform/wince/CEException.cpp
+++ b/backends/platform/wince/CEException.cpp
@@ -36,7 +36,7 @@ void CEException::writeBreak(HANDLE file) {
int i;
memset(tempo, 0, sizeof(tempo));
- for (i=0; i<40; i++)
+ for (i = 0; i < 40; i++)
tempo[i] = '-';
writeString(file, tempo);
}
@@ -51,23 +51,23 @@ void CEException::dumpContext(HANDLE file, HANDLE hProcess, CONTEXT *context) {
writeBreak(file);
writeString(file, "Context dump");
sprintf(tempo, "R0=%.8x R1=%.8x R2=%.8x R3=%.8x R4=%.8x", context->R0, context->R1,
- context->R2, context->R3, context->R4);
+ context->R2, context->R3, context->R4);
writeString(file, tempo);
sprintf(tempo, "R5=%.8x R6=%.8x R7=%.8x R8=%.8x R9=%.8x", context->R5, context->R6,
- context->R7, context->R8, context->R9);
+ context->R7, context->R8, context->R9);
writeString(file, tempo);
sprintf(tempo, "R10=%.8x R11=%.8x R12=%.8x", context->R10, context->R11,
- context->R12);
+ context->R12);
writeString(file, tempo);
sprintf(tempo, "Sp=%.8x Lr=%.8x Pc=%.8x Psr=%.8x", context->Sp, context->Lr,
- context->Pc, context->Psr);
+ context->Pc, context->Psr);
writeString(file, tempo);
writeBreak(file);
sprintf(tempo, "Memory dump at %.8x", context->Pc - (sizeof(memoryDump) / 2));
writeString(file, tempo);
if (ReadProcessMemory(hProcess, (LPCVOID)(context->Pc - (sizeof(memoryDump) / 2)), memoryDump, sizeof(memoryDump), &size)) {
- for (i=0; i<size; i+=8) {
+ for (i = 0; i < size; i += 8) {
int j;
char digit[4];
int max;
@@ -75,7 +75,7 @@ void CEException::dumpContext(HANDLE file, HANDLE hProcess, CONTEXT *context) {
if (max > 8)
max = 8;
tempo[0] = '\0';
- for (j=0; j<max; j++) {
+ for (j = 0; j < max; j++) {
sprintf(digit, "%.2x ", memoryDump[i + j]);
strcat(tempo, digit);
}
@@ -121,10 +121,10 @@ void CEException::dumpException(HANDLE file, EXCEPTION_RECORD *exceptionRecord)
break;
}
sprintf(tempo, "Exception %s Flags %.8x Address %.8x", exceptionName, exceptionRecord->ExceptionFlags,
- exceptionRecord->ExceptionAddress);
+ exceptionRecord->ExceptionAddress);
writeString(file, tempo);
if (exceptionRecord->NumberParameters) {
- for (i=0; i<exceptionRecord->NumberParameters; i++) {
+ for (i = 0; i < exceptionRecord->NumberParameters; i++) {
sprintf(tempo, "Parameter %d %.8x", i, exceptionRecord->ExceptionInformation[i]);
writeString(file, tempo);
}
@@ -144,8 +144,8 @@ bool CEException::writeException(TCHAR *path, EXCEPTION_POINTERS *exceptionPoint
GetSystemTime(&systemTime);
wsprintf(dumpFileName, TEXT("%s_%.2d_%.2d_%.4d_%.2d_%.2d_%.2d.txt"),
- path, systemTime.wDay, systemTime.wMonth, systemTime.wYear,
- systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
+ path, systemTime.wDay, systemTime.wMonth, systemTime.wYear,
+ systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
dumpFile = CreateFile(dumpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (dumpFile == INVALID_HANDLE_VALUE)
return false;
diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp
index de1bb2f1f6..8824af732f 100644
--- a/backends/platform/wince/CELauncherDialog.cpp
+++ b/backends/platform/wince/CELauncherDialog.cpp
@@ -48,14 +48,14 @@ using namespace Common;
class CEAboutDialog : public Dialog {
public:
CEAboutDialog()
- : Dialog(10, 60, 300, 77) {
+ : Dialog(10, 60, 300, 77) {
char tempo[100];
// FIXME: Fingolfin asks: why is there a FIXME here? Please either clarify what
// needs fixing, or remove it!
const int buttonWidth = g_gui.xmlEval()->getVar("Globals.Button.Width", 0);
const int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0);
- new ButtonWidget(this, (_w - buttonWidth) / 2, 45, buttonWidth, buttonHeight, _("OK"), 0, kCloseCmd, '\r'); // Close dialog - FIXME
+ new ButtonWidget(this, (_w - buttonWidth) / 2, 45, buttonWidth, buttonHeight, _("OK"), 0, kCloseCmd, '\r'); // Close dialog - FIXME
Common::String videoDriver(_("Using SDL driver "));
SDL_VideoDriverName(tempo, sizeof(tempo));
@@ -106,14 +106,13 @@ void CELauncherDialog::addGame() {
MessageDialog alert(_("Do you want to perform an automatic scan ?"), _("Yes"), _("No"));
if (alert.runModal() == kMessageOK && _browser->runModal() > 0) {
// Clear existing domains
- ConfigManager::DomainMap &domains = (ConfigManager::DomainMap&)ConfMan.getGameDomains();
+ ConfigManager::DomainMap &domains = (ConfigManager::DomainMap &)ConfMan.getGameDomains();
domains.clear();
ConfMan.flushToDisk();
automaticScanDirectory(_browser->getResult());
ConfMan.flushToDisk();
updateListing();
draw();
- }
- else
+ } else
GUILauncherDialog::addGame();
}
diff --git a/backends/platform/wince/CEgui/GUIElement.cpp b/backends/platform/wince/CEgui/GUIElement.cpp
index dd463c22a1..e7ffc8d473 100644
--- a/backends/platform/wince/CEgui/GUIElement.cpp
+++ b/backends/platform/wince/CEgui/GUIElement.cpp
@@ -32,7 +32,7 @@
namespace CEGUI {
GUIElement::GUIElement(int x, int y, int width, int height) :
-_background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) {
+ _background(0), _drawn(false), _visible(true), _x(x), _y(y), _width(width), _height(height) {
}
bool GUIElement::setBackground(WORD backgroundReference) {
@@ -45,9 +45,7 @@ bool GUIElement::setBackground(WORD backgroundReference) {
if (!_height && !_width) {
_height = _background->height();
_width = _background->width();
- }
- else
- if (_background->height() != _height || _background->width() != _width) {
+ } else if (_background->height() != _height || _background->width() != _width) {
delete _background;
_background = NULL;
return false;
@@ -74,8 +72,7 @@ bool GUIElement::draw(SDL_Surface *surface) {
_drawn = true;
return true;
- }
- else
+ } else
return false;
}
diff --git a/backends/platform/wince/CEgui/ItemAction.cpp b/backends/platform/wince/CEgui/ItemAction.cpp
index 55805744e6..efbc43ce00 100644
--- a/backends/platform/wince/CEgui/ItemAction.cpp
+++ b/backends/platform/wince/CEgui/ItemAction.cpp
@@ -28,7 +28,7 @@
namespace CEGUI {
ItemAction::ItemAction(WORD reference, GUI::ActionType action) :
-PanelItem(reference) {
+ PanelItem(reference) {
_action = action;
if (!GUI::Actions::Instance()->isEnabled(_action))
_visible = false;
diff --git a/backends/platform/wince/CEgui/ItemSwitch.cpp b/backends/platform/wince/CEgui/ItemSwitch.cpp
index d4648f7556..8eb62bf365 100644
--- a/backends/platform/wince/CEgui/ItemSwitch.cpp
+++ b/backends/platform/wince/CEgui/ItemSwitch.cpp
@@ -40,7 +40,7 @@ void ItemSwitch::init(WORD referenceTrue, WORD referenceFalse) {
}
ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, bool *item) :
-PanelItem(referenceTrue) {
+ PanelItem(referenceTrue) {
init(referenceTrue, referenceFalse);
_item = item;
_itemmax = -1;
@@ -49,8 +49,8 @@ PanelItem(referenceTrue) {
}
ItemSwitch::ItemSwitch(WORD referenceTrue, WORD referenceFalse, int *item, int max) :
-PanelItem(referenceTrue) {
- init(referenceTrue, referenceFalse);
+ PanelItem(referenceTrue) {
+ init(referenceTrue, referenceFalse);
_itemmultiple = item;
_itemmax = max;
if (!*item)
diff --git a/backends/platform/wince/CEgui/Panel.cpp b/backends/platform/wince/CEgui/Panel.cpp
index dfdd6526be..576da23029 100644
--- a/backends/platform/wince/CEgui/Panel.cpp
+++ b/backends/platform/wince/CEgui/Panel.cpp
@@ -34,7 +34,7 @@ Panel::Panel(int interleave_first, int interleave) : Toolbar() {
bool Panel::add(const String &name, const PanelItem *item) {
- _itemsMap[name] = (PanelItem*)item;
+ _itemsMap[name] = (PanelItem *)item;
_itemsMap[name]->move(_currentItem, _y + 10);
_itemsMap[name]->setPanel(this);
_currentItem += _interleave;
@@ -47,11 +47,10 @@ bool Panel::draw(SDL_Surface *surface) {
if (!_drawn && _visible) {
GUIElement::draw(surface);
for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator) {
- ((GUIElement*)(iterator->_value))->draw(surface);
+ ((GUIElement *)(iterator->_value))->draw(surface);
}
return true;
- }
- else
+ } else
return false;
}
@@ -59,7 +58,7 @@ void Panel::forceRedraw() {
ItemMap::const_iterator iterator;
GUIElement::forceRedraw();
for (iterator = _itemsMap.begin(); iterator != _itemsMap.end(); ++iterator)
- ((GUIElement*)(iterator->_value))->forceRedraw();
+ ((GUIElement *)(iterator->_value))->forceRedraw();
}
bool Panel::action(int x, int y, bool pushed) {
@@ -69,7 +68,7 @@ bool Panel::action(int x, int y, bool pushed) {
return false;
for (iterator = _itemsMap.begin(); !result && iterator != _itemsMap.end(); ++iterator)
- result = ((GUIElement*)(iterator->_value))->action(x, y, pushed);
+ result = ((GUIElement *)(iterator->_value))->action(x, y, pushed);
return result;
}
diff --git a/backends/platform/wince/CEgui/Panel.h b/backends/platform/wince/CEgui/Panel.h
index e6b693360d..1a8a580dba 100644
--- a/backends/platform/wince/CEgui/Panel.h
+++ b/backends/platform/wince/CEgui/Panel.h
@@ -51,7 +51,7 @@ public:
virtual bool action(int x, int y, bool pushed);
private:
- typedef HashMap<String, PanelItem*, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap;
+ typedef HashMap<String, PanelItem *, Common::IgnoreCase_Hash , Common::IgnoreCase_EqualTo> ItemMap;
ItemMap _itemsMap;
int _interleave;
diff --git a/backends/platform/wince/CEgui/PanelItem.h b/backends/platform/wince/CEgui/PanelItem.h
index 14b62f0f20..9968aa8d5e 100644
--- a/backends/platform/wince/CEgui/PanelItem.h
+++ b/backends/platform/wince/CEgui/PanelItem.h
@@ -36,7 +36,7 @@ namespace CEGUI {
class Panel;
class PanelItem : public GUIElement {
-friend class Panel;
+ friend class Panel;
public:
PanelItem(WORD reference);
virtual ~PanelItem();
diff --git a/backends/platform/wince/CEgui/PanelKeyboard.cpp b/backends/platform/wince/CEgui/PanelKeyboard.cpp
index 5ca125898d..3512b34da3 100644
--- a/backends/platform/wince/CEgui/PanelKeyboard.cpp
+++ b/backends/platform/wince/CEgui/PanelKeyboard.cpp
@@ -30,8 +30,9 @@ namespace CEGUI {
const char KEYBOARD_MAPPING_ALPHA[][14] = { {"abcdefghijklm"}, {"nopqrstuvwxyz"} };
const char KEYBOARD_MAPPING_NUMERIC[][6] = { {"12345"}, {"67890"} };
-const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1,SDLK_ESCAPE}, {224,SDLK_UP}, {32,SDLK_SPACE} },
- { {224,SDLK_LEFT}, {224,SDLK_DOWN}, {224,SDLK_RIGHT} } };
+const int KEYBOARD_MAPPING_SPECIAL[][3][2] = { { {1, SDLK_ESCAPE}, {224, SDLK_UP}, {32, SDLK_SPACE} },
+ { {224, SDLK_LEFT}, {224, SDLK_DOWN}, {224, SDLK_RIGHT} }
+};
PanelKeyboard::PanelKeyboard(WORD reference) : Toolbar() {
setBackground(reference);
@@ -51,21 +52,23 @@ bool PanelKeyboard::action(int x, int y, bool pushed) {
int keyCode = 0;
if (x < 185) {
// Alpha selection
- keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y+20][((x + 10) / 14) - 1];
+ keyCode = keyAscii = KEYBOARD_MAPPING_ALPHA[y >= _y + 20][((x + 10) / 14) - 1];
} else if (x >= 186 && x <= 255) {
// Numeric selection
- keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y+20][((x - 187 + 10) / 14) - 1];
+ keyCode = keyAscii = KEYBOARD_MAPPING_NUMERIC[y >= _y + 20][((x - 187 + 10) / 14) - 1];
} else if (x >= 258 && x <= 300) {
// Special keys
- keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][0];
- keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y+20][((x - 259 + 10) / 14) - 1][1];
+ keyAscii = KEYBOARD_MAPPING_SPECIAL[y >= _y + 20][((x - 259 + 10) / 14) - 1][0];
+ keyCode = KEYBOARD_MAPPING_SPECIAL[y >= _y + 20][((x - 259 + 10) / 14) - 1][1];
} else if (x >= 302 && x <= 316) {
- if (y < _y +20) {
+ if (y < _y + 20) {
// Backspace
- keyAscii = VK_BACK; keyCode = keyAscii;
+ keyAscii = VK_BACK;
+ keyCode = keyAscii;
} else {
// Enter
- keyAscii = 13; keyCode = 13;
+ keyAscii = 13;
+ keyCode = 13;
}
}
diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.cpp b/backends/platform/wince/CEgui/SDL_ImageResource.cpp
index 8dad5f0a0c..872b94a442 100644
--- a/backends/platform/wince/CEgui/SDL_ImageResource.cpp
+++ b/backends/platform/wince/CEgui/SDL_ImageResource.cpp
@@ -32,7 +32,7 @@ SDL_ImageResource::SDL_ImageResource() :
_surface(0) {
}
-SDL_Surface* SDL_ImageResource::load(WORD resourceID) {
+SDL_Surface *SDL_ImageResource::load(WORD resourceID) {
HRSRC resource;
HGLOBAL resourceGlobal;
LPVOID resourcePointer;
@@ -62,7 +62,7 @@ SDL_Surface* SDL_ImageResource::load(WORD resourceID) {
return _surface;
}
-SDL_Surface* SDL_ImageResource::get() {
+SDL_Surface *SDL_ImageResource::get() {
return _surface;
}
diff --git a/backends/platform/wince/CEgui/SDL_ImageResource.h b/backends/platform/wince/CEgui/SDL_ImageResource.h
index 5affd5c33c..397ced1434 100644
--- a/backends/platform/wince/CEgui/SDL_ImageResource.h
+++ b/backends/platform/wince/CEgui/SDL_ImageResource.h
@@ -36,8 +36,8 @@ namespace CEGUI {
class SDL_ImageResource {
public:
SDL_ImageResource();
- SDL_Surface* load(WORD resourceID);
- SDL_Surface* get();
+ SDL_Surface *load(WORD resourceID);
+ SDL_Surface *get();
int height();
int width();
virtual ~SDL_ImageResource();
diff --git a/backends/platform/wince/CEgui/ToolbarHandler.cpp b/backends/platform/wince/CEgui/ToolbarHandler.cpp
index 78f69119c3..ed2a72245a 100644
--- a/backends/platform/wince/CEgui/ToolbarHandler.cpp
+++ b/backends/platform/wince/CEgui/ToolbarHandler.cpp
@@ -29,15 +29,15 @@
namespace CEGUI {
ToolbarHandler::ToolbarHandler():
-_current(""), _active(NULL) {
+ _current(""), _active(NULL) {
}
bool ToolbarHandler::add(const String &name, const Toolbar &toolbar) {
- _toolbarMap[name] = (Toolbar*)&toolbar;
+ _toolbarMap[name] = (Toolbar *)&toolbar;
if (!_active) {
- _active = &((Toolbar&)toolbar);
+ _active = &((Toolbar &)toolbar);
_current = name;
}
@@ -53,7 +53,7 @@ bool ToolbarHandler::setActive(const String &name) {
return false;
if (_current == name)
return true;
- _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel)
+ _active->action(0, 0, false); // make sure any items are unpushed when changing toolbars (e.g. forced VK->main panel)
_current = name;
_active = _toolbarMap[name];
_active->forceRedraw();
@@ -67,8 +67,7 @@ bool ToolbarHandler::action(int x, int y, bool pushed) {
return _active->action(x / 2, (y - _offset) / 2, pushed);
else
return _active->action(x, y - _offset, pushed);
- }
- else
+ } else
return false;
}
@@ -118,7 +117,7 @@ int ToolbarHandler::getOffset() {
return _offset;
}
-Toolbar* ToolbarHandler::active() {
+Toolbar *ToolbarHandler::active() {
return _active;
}
diff --git a/backends/platform/wince/CEgui/ToolbarHandler.h b/backends/platform/wince/CEgui/ToolbarHandler.h
index e3bf590768..0f794d7d61 100644
--- a/backends/platform/wince/CEgui/ToolbarHandler.h
+++ b/backends/platform/wince/CEgui/ToolbarHandler.h
@@ -57,7 +57,7 @@ public:
virtual ~ToolbarHandler();
private:
- HashMap<String, Toolbar*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap;
+ HashMap<String, Toolbar *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _toolbarMap;
String _current;
Toolbar *_active;
int _offset;
diff --git a/backends/platform/wince/CEkeys/EventsBuffer.cpp b/backends/platform/wince/CEkeys/EventsBuffer.cpp
index c9f4af2304..beea272d2b 100644
--- a/backends/platform/wince/CEkeys/EventsBuffer.cpp
+++ b/backends/platform/wince/CEkeys/EventsBuffer.cpp
@@ -29,55 +29,55 @@
namespace CEKEYS {
- bool EventsBuffer::simulateKey(GUI::Key *key, bool pushed) {
- SDL_Event ev = {0};
-
- if (!key->keycode())
- key->setKey(key->ascii(), key->ascii());
- else if (!key->ascii())
- key->setKey(key->keycode());
-
- ev.type = (pushed ? SDL_KEYDOWN : SDL_KEYUP);
- ev.key.keysym.unicode = (SDLMod)key->flags(); // HACK: put the flags into the unused unicode field
- ev.key.keysym.sym = (SDLKey)key->keycode();
- ev.key.keysym.mod = KMOD_RESERVED;
- return (SDL_PushEvent(&ev) == 0);
- }
-
- bool EventsBuffer::simulateMouseMove(int x, int y) {
- SDL_Event ev = {0};
-
- ev.type = SDL_MOUSEMOTION;
- ev.motion.x = x;
- ev.motion.y = y;
- return (SDL_PushEvent(&ev) == 0);
- }
-
- bool EventsBuffer::simulateMouseLeftClick(int x, int y, bool pushed) {
- SDL_Event ev = {0};
- static bool state = false;
-
- if (pushed == state) return 0;
- state = pushed;
- ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP);
- ev.button.button = SDL_BUTTON_LEFT;
- ev.button.x = x;
- ev.button.y = y;
- return (SDL_PushEvent(&ev) == 0);
- }
-
- bool EventsBuffer::simulateMouseRightClick(int x, int y, bool pushed) {
- SDL_Event ev = {0};
- static bool state = false;
-
- if (pushed == state) return 0;
- state = pushed;
- ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP);
- ev.button.button = SDL_BUTTON_RIGHT;
- ev.button.x = x;
- ev.button.y = y;
- return (SDL_PushEvent(&ev) == 0);
- }
+bool EventsBuffer::simulateKey(GUI::Key *key, bool pushed) {
+ SDL_Event ev = {0};
+
+ if (!key->keycode())
+ key->setKey(key->ascii(), key->ascii());
+ else if (!key->ascii())
+ key->setKey(key->keycode());
+
+ ev.type = (pushed ? SDL_KEYDOWN : SDL_KEYUP);
+ ev.key.keysym.unicode = (SDLMod)key->flags(); // HACK: put the flags into the unused unicode field
+ ev.key.keysym.sym = (SDLKey)key->keycode();
+ ev.key.keysym.mod = KMOD_RESERVED;
+ return (SDL_PushEvent(&ev) == 0);
+}
+
+bool EventsBuffer::simulateMouseMove(int x, int y) {
+ SDL_Event ev = {0};
+
+ ev.type = SDL_MOUSEMOTION;
+ ev.motion.x = x;
+ ev.motion.y = y;
+ return (SDL_PushEvent(&ev) == 0);
+}
+
+bool EventsBuffer::simulateMouseLeftClick(int x, int y, bool pushed) {
+ SDL_Event ev = {0};
+ static bool state = false;
+
+ if (pushed == state) return 0;
+ state = pushed;
+ ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP);
+ ev.button.button = SDL_BUTTON_LEFT;
+ ev.button.x = x;
+ ev.button.y = y;
+ return (SDL_PushEvent(&ev) == 0);
+}
+
+bool EventsBuffer::simulateMouseRightClick(int x, int y, bool pushed) {
+ SDL_Event ev = {0};
+ static bool state = false;
+
+ if (pushed == state) return 0;
+ state = pushed;
+ ev.type = (pushed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP);
+ ev.button.button = SDL_BUTTON_RIGHT;
+ ev.button.x = x;
+ ev.button.y = y;
+ return (SDL_PushEvent(&ev) == 0);
+}
}
diff --git a/backends/platform/wince/CEkeys/EventsBuffer.h b/backends/platform/wince/CEkeys/EventsBuffer.h
index 22590db03c..9b766c6ca9 100644
--- a/backends/platform/wince/CEkeys/EventsBuffer.h
+++ b/backends/platform/wince/CEkeys/EventsBuffer.h
@@ -34,14 +34,14 @@
namespace CEKEYS {
- class EventsBuffer {
- public:
- static bool simulateKey(GUI::Key *key, bool pushed);
- static bool simulateMouseMove(int x, int y);
- static bool simulateMouseLeftClick(int x, int y, bool pushed);
- static bool simulateMouseRightClick(int x, int y, bool pushed);
-
- };
+class EventsBuffer {
+public:
+ static bool simulateKey(GUI::Key *key, bool pushed);
+ static bool simulateMouseMove(int x, int y);
+ static bool simulateMouseLeftClick(int x, int y, bool pushed);
+ static bool simulateMouseRightClick(int x, int y, bool pushed);
+
+};
}
#endif
diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile
index 8ad134648b..21bff06f95 100644
--- a/backends/platform/wince/Makefile
+++ b/backends/platform/wince/Makefile
@@ -113,7 +113,7 @@ INCLUDES := -I$(srcdir) -I. -I$(srcdir)/engines -Imissing/gcc -Ilibs/include -Il
CFLAGS :=
ifndef UNOPTIMIZED_BUILD
-CFLAGS += -O3 -march=armv4 -mtune=xscale
+CFLAGS += -O3 -fno-inline-functions -march=armv4 -mtune=xscale
endif
LDFLAGS := -Wl,-Map,scummvm.exe.map -Wl,--stack,65536
diff --git a/backends/platform/wince/missing/io.h b/backends/platform/wince/missing/io.h
index 8c66e9405b..96bc6a9ea1 100644
--- a/backends/platform/wince/missing/io.h
+++ b/backends/platform/wince/missing/io.h
@@ -5,9 +5,9 @@
#define strdup _strdup
#ifndef _FILE_DEFINED
- typedef void FILE;
- #define _FILE_DEFINED
+typedef void FILE;
+#define _FILE_DEFINED
#endif
-FILE* wce_fopen(const char* fname, const char* fmode);
+FILE *wce_fopen(const char *fname, const char *fmode);
#define fopen wce_fopen
diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp
index 92af3e6961..c855247ae1 100644
--- a/backends/platform/wince/missing/missing.cpp
+++ b/backends/platform/wince/missing/missing.cpp
@@ -50,7 +50,7 @@ char *strdup(const char *strSource);
// common missing functions required by both gcc and evc
void *bsearch(const void *key, const void *base, size_t nmemb,
- size_t size, int (*compar)(const void *, const void *)) {
+ size_t size, int (*compar)(const void *, const void *)) {
// Perform binary search
size_t lo = 0;
size_t hi = nmemb;
@@ -63,17 +63,17 @@ void *bsearch(const void *key, const void *base, size_t nmemb,
else if (tmp > 0)
lo = mid + 1;
else
- return (void *)p;
+ return const_cast<void *>(p);
}
return NULL;
}
-static char cwd[MAX_PATH+1] = "";
+static char cwd[MAX_PATH + 1] = "";
EXT_C char *getcwd(char *buffer, int maxlen) {
- TCHAR fileUnc[MAX_PATH+1];
- char* plast;
+ TCHAR fileUnc[MAX_PATH + 1];
+ char *plast;
if (cwd[0] == 0) {
GetModuleFileName(NULL, fileUnc, MAX_PATH);
@@ -94,7 +94,7 @@ EXT_C char *getcwd(char *buffer, int maxlen) {
#undef GetCurrentDirectory
#endif
EXT_C void GetCurrentDirectory(int len, char *buf) {
- getcwd(buf,len);
+ getcwd(buf, len);
}
/*
@@ -103,8 +103,8 @@ fully qualified paths refer to root folder rather
than current folder (concept not implemented in CE).
*/
#undef fopen
-EXT_C FILE *wce_fopen(const char* fname, const char* fmode) {
- char fullname[MAX_PATH+1];
+EXT_C FILE *wce_fopen(const char *fname, const char *fmode) {
+ char fullname[MAX_PATH + 1];
if (!fname || fname[0] == '\0')
return NULL;
@@ -118,8 +118,8 @@ EXT_C FILE *wce_fopen(const char* fname, const char* fmode) {
}
/* Remove file by name */
-int remove(const char* path) {
- TCHAR pathUnc[MAX_PATH+1];
+int remove(const char *path) {
+ TCHAR pathUnc[MAX_PATH + 1];
MultiByteToWideChar(CP_ACP, 0, path, -1, pathUnc, MAX_PATH);
return !DeleteFile(pathUnc);
}
@@ -128,15 +128,15 @@ int remove(const char* path) {
/* check out file access permissions */
int _access(const char *path, int mode) {
TCHAR fname[MAX_PATH];
- char fullname[MAX_PATH+1];
+ char fullname[MAX_PATH + 1];
if (path[0] != '\\' && path[0] != '/') {
getcwd(fullname, MAX_PATH);
strcat(fullname, "\\");
strcat(fullname, path);
- MultiByteToWideChar(CP_ACP, 0, fullname, -1, fname, sizeof(fname)/sizeof(TCHAR));
+ MultiByteToWideChar(CP_ACP, 0, fullname, -1, fname, sizeof(fname) / sizeof(TCHAR));
} else
- MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname)/sizeof(TCHAR));
+ MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname) / sizeof(TCHAR));
WIN32_FIND_DATA ffd;
HANDLE h = FindFirstFile(fname, &ffd);
@@ -144,10 +144,10 @@ int _access(const char *path, int mode) {
if (h == INVALID_HANDLE_VALUE) {
// WORKAROUND: WinCE 3.0 doesn't find paths ending in '\'
- if (path[strlen(path)-1] == '\\') {
+ if (path[strlen(path) - 1] == '\\') {
char p2[MAX_PATH];
- strncpy(p2, path, strlen(path)-1);
- p2[strlen(path) - 1]= '\0';
+ strncpy(p2, path, strlen(path) - 1);
+ p2[strlen(path) - 1] = '\0';
return _access(p2, mode);
} else
return -1; //Can't find file
@@ -158,7 +158,7 @@ int _access(const char *path, int mode) {
// hits for files that don't exist. TRIPLE checking for the same fname
// seems to weed out those false positives.
// Exhibited in kyra engine.
- HANDLE h = FindFirstFile(fname, &ffd);
+ h = FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
@@ -170,13 +170,13 @@ int _access(const char *path, int mode) {
return 0; //Always return success if target is directory and exists
}
switch (mode) {
- case 00: //Check existence
- return 0;
- case 06: //Check Read & Write permission
- case 02: //Check Write permission
- return ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? -1 : 0;
- case 04: //Check Read permission
- return 0; //Assume always have read permission
+ case 00: //Check existence
+ return 0;
+ case 06: //Check Read & Write permission
+ case 02: //Check Write permission
+ return ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? -1 : 0;
+ case 04: //Check Read permission
+ return 0; //Assume always have read permission
}
//Bad mode value supplied, return failure
return -1;
@@ -188,7 +188,7 @@ int _access(const char *path, int mode) {
char *strdup(const char *strSource) {
char *buffer;
size_z len = strlen(strSource) + 1;
- buffer = (char*)malloc(len);
+ buffer = (char *)malloc(len);
if (buffer)
memcpy(buffer, strSource, len);
return buffer;
@@ -199,25 +199,25 @@ char *strdup(const char *strSource) {
#ifndef __MINGW32CE__
int islower(int c) {
- return (c>='a' && c<='z');
+ return (c >= 'a' && c <= 'z');
}
int isspace(int c) {
- return (c==' ' || c=='\f' || c=='\n' || c=='\r' || c=='\t' || c=='\v');
+ return (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v');
}
int isalpha(int c) {
- return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}
int isalnum(int c) {
- return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'));
}
int isprint(int c) {
//static const char punct[] = "!\"#%&'();<=>?[\\]*+,-./:^_{|}~";
//return (isalnum(c) || strchr(punct, c));
- return (32 <= c && c <= 126); // based on BSD manpage
+ return (32 <= c && c <= 126); // based on BSD manpage
}
#endif
diff --git a/backends/platform/wince/missing/time.h b/backends/platform/wince/missing/time.h
index f2bc5e4f89..a0ba6c246e 100644
--- a/backends/platform/wince/missing/time.h
+++ b/backends/platform/wince/missing/time.h
@@ -6,8 +6,7 @@
#include <stdlib.h>
#ifndef __MINGW32CE__
-struct tm
-{
+struct tm {
short tm_year;
short tm_mon;
short tm_mday;
@@ -23,8 +22,8 @@ struct tm
#define EXT_C
#endif
-EXT_C time_t time(time_t* dummy);
-EXT_C struct tm* localtime(time_t* dummy);
+EXT_C time_t time(time_t *dummy);
+EXT_C struct tm *localtime(time_t *dummy);
unsigned int clock();
diff --git a/backends/platform/wince/portdefs.h b/backends/platform/wince/portdefs.h
index cbf2006be2..8ad643946f 100644
--- a/backends/platform/wince/portdefs.h
+++ b/backends/platform/wince/portdefs.h
@@ -34,10 +34,10 @@ int isprint(int c);
int isspace(int c);
char *strrchr(const char *s, int c);
char *strdup(const char *s);
-int _stricmp( const char *string1, const char *string2 );
-int stricmp( const char *string1, const char *string2 );
-void assert( void* expression );
-void assert( int expression );
+int _stricmp(const char *string1, const char *string2);
+int stricmp(const char *string1, const char *string2);
+void assert(void *expression);
+void assert(int expression);
long int strtol(const char *nptr, char **endptr, int base);
char *_strdup(const char *s);
char *strpbrk(const char *s, const char *accept);
@@ -47,20 +47,20 @@ char *strpbrk(const char *s, const char *accept);
#ifdef _WIN32_WCE
#ifndef __GNUC__
- void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *));
- char *getcwd(char *buf, int size);
- typedef int ptrdiff_t;
- void GetCurrentDirectory(int len, char *buf);
- #define INVALID_FILE_ATTRIBUTES 0xffffffff
+void *bsearch(const void *, const void *, size_t, size_t, int (*x)(const void *, const void *));
+char *getcwd(char *buf, int size);
+typedef int ptrdiff_t;
+void GetCurrentDirectory(int len, char *buf);
+#define INVALID_FILE_ATTRIBUTES 0xffffffff
#else
- #include <math.h>
- #undef GetCurrentDirectory
- extern "C" void GetCurrentDirectory(int len, char *buf);
- #define stricmp _stricmp
- #define strnicmp _strnicmp
- #define snprintf _snprintf
- #define strdup _strdup
- #define fopen wce_fopen
+#include <math.h>
+#undef GetCurrentDirectory
+extern "C" void GetCurrentDirectory(int len, char *buf);
+#define stricmp _stricmp
+#define strnicmp _strnicmp
+#define snprintf _snprintf
+#define strdup _strdup
+#define fopen wce_fopen
#endif
#include <windows.h>
@@ -75,12 +75,12 @@ char *strpbrk(const char *s, const char *accept);
//#include <direct.h>
#ifdef __MINGW32CE__
- void *bsearch(const void *, const void *, size_t, size_t, int (*x) (const void *, const void *));
+void *bsearch(const void *, const void *, size_t, size_t, int (*x)(const void *, const void *));
#endif
int remove(const char *path);
int _access(const char *path, int mode);
-void drawError(char*);
+void drawError(char *);
#define vsnprintf _vsnprintf
diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp
index ade90b2dfb..b829686cb0 100644
--- a/backends/platform/wince/wince-sdl.cpp
+++ b/backends/platform/wince/wince-sdl.cpp
@@ -23,6 +23,7 @@
*
*/
+
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
@@ -43,13 +44,12 @@
#include "audio/mixer_intern.h"
#include "audio/fmopl.h"
-#include "backends/timer/default/default-timer.h"
+#include "backends/timer/sdl/sdl-timer.h"
#include "gui/Actions.h"
#include "gui/KeysDialog.h"
#include "gui/message.h"
-#include "backends/platform/wince/resource.h"
#include "backends/platform/wince/CEActionsPocket.h"
#include "backends/platform/wince/CEActionsSmartphone.h"
#include "backends/platform/wince/CEgui/ItemAction.h"
@@ -60,39 +60,22 @@
#include "backends/platform/wince/CEException.h"
#include "backends/platform/wince/CEScaler.h"
-#ifdef USE_VORBIS
-#ifndef USE_TREMOR
-#include <vorbis/vorbisfile.h>
-#else
-#include <tremor/ivorbisfile.h>
-#endif
-#endif
+#include "backends/graphics/wincesdl/wincesdl-graphics.h"
+#include "backends/events/wincesdl/wincesdl-events.h"
+#include "backends/mixer/wincesdl/wincesdl-mixer.h"
#ifdef DYNAMIC_MODULES
#include "backends/plugins/win32/win32-provider.h"
#endif
#ifdef __GNUC__
-extern "C" _CRTIMP FILE* __cdecl _wfreopen (const wchar_t*, const wchar_t*, FILE*);
+extern "C" _CRTIMP FILE *__cdecl _wfreopen(const wchar_t *, const wchar_t *, FILE *);
#endif
-#define SAMPLES_PER_SEC_OLD 11025
-#define SAMPLES_PER_SEC_NEW 22050
-
using namespace CEGUI;
// ********************************************************************************************
-// Internal GUI names
-
-#define NAME_MAIN_PANEL "MainPanel"
-#define NAME_PANEL_KEYBOARD "Keyboard"
-#define NAME_ITEM_OPTIONS "Options"
-#define NAME_ITEM_SKIP "Skip"
-#define NAME_ITEM_SOUND "Sound"
-#define NAME_ITEM_ORIENTATION "Orientation"
-#define NAME_ITEM_BINDKEYS "Bindkeys"
-
// stdin/err redirection
#define STDOUT_FNAME "\\scummvm_stdout.txt"
#define STDERR_FNAME "\\scummvm_stderr.txt"
@@ -106,34 +89,6 @@ bool OSystem_WINCE3::_soundMaster = true;
bool _isSmartphone = false;
bool _hasSmartphoneResolution = false;
-// Graphics mode consts
-
-// Low end devices 240x320
-
-static const OSystem::GraphicsMode s_supportedGraphicsModesLow[] = {
- {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
- {0, 0, 0}
-};
-
-// High end device 480x640
-
-static const OSystem::GraphicsMode s_supportedGraphicsModesHigh[] = {
- {"1x", _s("Normal (no scaling)"), GFX_NORMAL},
- {"2x", "2x", GFX_DOUBLESIZE},
-#ifndef _MSC_VER // EVC breaks template functions, and I'm tired of fixing them :)
- {"2xsai", "2xSAI", GFX_2XSAI},
- {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI},
- {"supereagle", "SuperEagle", GFX_SUPEREAGLE},
-#endif
- {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X},
-#ifndef _MSC_VER
- {"hq2x", "HQ2x", GFX_HQ2X},
- {"tv2x", "TV2x", GFX_TV2X},
-#endif
- {"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
- {0, 0, 0}
-};
-
#define DEFAULT_CONFIG_FILE "scummvm.ini"
// ********************************************************************************************
@@ -144,7 +99,7 @@ bool isSmartphone() {
}
const TCHAR *ASCIItoUnicode(const char *str) {
- static TCHAR ustr[MAX_PATH]; // size good enough
+ static TCHAR ustr[MAX_PATH]; // size good enough
MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, ustr, sizeof(ustr) / sizeof(TCHAR));
return ustr;
@@ -173,7 +128,7 @@ int SDL_main(int argc, char **argv) {
// thanks to joostp and DJWillis
extern void (*__CTOR_LIST__)();
void (**constructor)() = &__CTOR_LIST__;
- constructor++; // First item in list of constructors has special meaning (platform dependent), ignore it.
+ constructor++; // First item in list of constructors has special meaning (platform dependent), ignore it.
while (*constructor) {
(*constructor)();
constructor++;
@@ -238,10 +193,10 @@ int SDL_main(int argc, char **argv) {
res = scummvm_main(argc, argv);
// Free OSystem
- delete (OSystem_WINCE3 *)g_system;
+ delete(OSystem_WINCE3 *)g_system;
#if !defined(DEBUG) && !defined(__GNUC__)
}
- __except (handleException(GetExceptionInformation())) {
+ __except(handleException(GetExceptionInformation())) {
}
#endif
@@ -264,22 +219,22 @@ int console_main(int argc, char *argv[]) {
char *bufp, *appname;
appname = argv[0];
- if ( (bufp=strrchr(argv[0], '\\')) != NULL )
+ if ((bufp = strrchr(argv[0], '\\')) != NULL)
appname = bufp + 1;
- else if ( (bufp=strrchr(argv[0], '/')) != NULL )
+ else if ((bufp = strrchr(argv[0], '/')) != NULL)
appname = bufp + 1;
- if ( (bufp=strrchr(appname, '.')) == NULL )
+ if ((bufp = strrchr(appname, '.')) == NULL)
n = strlen(appname);
else
- n = (bufp-appname);
+ n = (bufp - appname);
bufp = (char *) alloca(n + 1);
strncpy(bufp, appname, n);
bufp[n] = '\0';
appname = bufp;
- if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
+ if (SDL_Init(SDL_INIT_NOPARACHUTE) < 0) {
error("WinMain() error: %d", SDL_GetError());
return(FALSE);
}
@@ -344,31 +299,31 @@ int dynamic_modules_main(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int
int nLen;
if (wcsncmp(szCmdLine, TEXT("\\"), 1)) {
- nLen = wcslen(szCmdLine)+128+1;
- bufp = (wchar_t *) alloca(nLen*2);
- wcscpy (bufp, TEXT("\""));
- GetModuleFileName(NULL, bufp+1, 128-3);
- wcscpy (bufp+wcslen(bufp), TEXT("\" "));
- wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp));
+ nLen = wcslen(szCmdLine) + 128 + 1;
+ bufp = (wchar_t *) alloca(nLen * 2);
+ wcscpy(bufp, TEXT("\""));
+ GetModuleFileName(NULL, bufp + 1, 128 - 3);
+ wcscpy(bufp + wcslen(bufp), TEXT("\" "));
+ wcsncpy(bufp + wcslen(bufp), szCmdLine, nLen - wcslen(bufp));
} else
bufp = szCmdLine;
- nLen = wcslen(bufp)+1;
+ nLen = wcslen(bufp) + 1;
cmdline = (char *) alloca(nLen);
WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
// Parse command line into argv and argc
argc = ParseCommandLine(cmdline, NULL);
- argv = (char **) alloca((argc+1)*(sizeof *argv));
+ argv = (char **) alloca((argc + 1) * (sizeof * argv));
ParseCommandLine(cmdline, argv);
// fix gdb-emulator combo
while (argc > 1 && !strstr(argv[0], ".exe")) {
OutputDebugString(TEXT("SDL: gdb argv[0] fixup\n"));
- *(argv[1]-1) = ' ';
+ *(argv[1] - 1) = ' ';
int i;
- for (i=1; i<argc; i++)
- argv[i] = argv[i+1];
+ for (i = 1; i < argc; i++)
+ argv[i] = argv[i + 1];
argc--;
}
@@ -380,7 +335,6 @@ int dynamic_modules_main(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int
// ********************************************************************************************
-
// ********************************************************************************************
void pumpMessages() {
@@ -407,47 +361,53 @@ static Uint32 timer_handler_wrapper(Uint32 interval) {
}
void OSystem_WINCE3::initBackend() {
- // Instantiate our own sound mixer
- // mixer init is rerun when a game engine is selected.
- setupMixer();
+
+ assert(!_inited);
+
+ // Create the backend custom managers
+ if (_eventSource == 0)
+ _eventSource = new WINCESdlEventSource();
+
+ if (_mixerManager == 0) {
+ _mixerManager = new WINCESdlMixerManager();
+
+ // Setup and start mixer
+ _mixerManager->init();
+ }
+
+ if (_graphicsManager == 0)
+ _graphicsManager = new WINCESdlGraphicsManager(_eventSource);
+
+ ((WINCESdlEventSource *)_eventSource)->init((WINCESdlGraphicsManager *)_graphicsManager);
// Create the timer. CE SDL does not support multiple timers (SDL_AddTimer).
// We work around this by using the SetTimer function, since we only use
// one timer in scummvm (for the time being)
_timer = _int_timer = new DefaultTimerManager();
- _timerID = NULL; // OSystem_SDL will call removetimer with this, it's ok
+ //_timerID = NULL; // OSystem_SDL will call removetimer with this, it's ok
SDL_SetTimer(10, &timer_handler_wrapper);
// Chain init
OSystem_SDL::initBackend();
- // Query SDL for screen size and init screen dependent stuff
- OSystem_WINCE3::initScreenInfos();
- _isSmartphone = CEDevice::isSmartphone();
- create_toolbar();
- _hasSmartphoneResolution = CEDevice::hasSmartphoneResolution() || CEDevice::isSmartphone();
- if (_hasSmartphoneResolution)
- _panelVisible = false; // init correctly in smartphones
-
// Initialize global key mapping
GUI::Actions::init();
GUI_Actions::Instance()->initInstanceMain(this);
- if (!GUI_Actions::Instance()->loadMapping()) { // error during loading means not present/wrong version
+ if (!GUI_Actions::Instance()->loadMapping()) { // error during loading means not present/wrong version
warning("Setting default action mappings");
- GUI_Actions::Instance()->saveMapping(); // write defaults
+ GUI_Actions::Instance()->saveMapping(); // write defaults
}
- loadDeviceConfiguration();
+ // Call parent implementation of this method
+ //OSystem_SDL::initBackend();
+
+ _inited = true;
}
int OSystem_WINCE3::getScreenWidth() {
return _platformScreenWidth;
}
-int OSystem_WINCE3::getScreenHeight() {
- return _platformScreenHeight;
-}
-
void OSystem_WINCE3::initScreenInfos() {
// sdl port ensures that we use correctly full screen
_isOzone = 0;
@@ -457,6 +417,10 @@ void OSystem_WINCE3::initScreenInfos() {
_platformScreenHeight = r[0]->h;
}
+int OSystem_WINCE3::getScreenHeight() {
+ return _platformScreenHeight;
+}
+
bool OSystem_WINCE3::isOzone() {
return _isOzone;
}
@@ -473,496 +437,37 @@ Common::String OSystem_WINCE3::getDefaultConfigFileName() {
OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(),
- _orientationLandscape(0), _newOrientation(0), _panelInitialized(false), _canBeAspectScaled(false),
- _panelVisible(true), _panelStateForced(false), _forceHideMouse(false), _unfilteredkeys(false),
- _freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false),
- _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), _noDoubleTapRMB(false),
- _saveToolbarState(false), _saveActiveToolbar(NAME_MAIN_PANEL), _rbutton(false), _hasfocus(true),
- _usesEmulatedMouse(false), _mouseBackupOld(NULL), _mouseBackupToolbar(NULL), _mouseBackupDim(0)
-{
- memset(&_mouseCurState, 0, sizeof(_mouseCurState));
- if (_isSmartphone) {
- _mouseCurState.x = 20;
- _mouseCurState.y = 20;
- }
-
+ _forcePanelInvisible(false) {
+ // Initialze File System Factory
+ _fsFactory = new WindowsFilesystemFactory();
_mixer = 0;
- _screen = NULL;
}
-void OSystem_WINCE3::swap_panel_visibility() {
- //if (!_forcePanelInvisible && !_panelStateForced) {
- if (_zoomDown || _zoomUp) return;
-
- if (_panelVisible) {
- if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD)
- _panelVisible = !_panelVisible;
- else
- _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
- } else {
- _toolbarHandler.setActive(NAME_MAIN_PANEL);
- _panelVisible = !_panelVisible;
- }
- _toolbarHandler.setVisible(_panelVisible);
- _toolbarHighDrawn = false;
-
- if (_videoMode.screenHeight > 240)
- addDirtyRect(0, 400, 640, 80);
- else
- addDirtyRect(0, 200, 320, 40);
-
- if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
- internUpdateScreen();
- else {
- update_scalers();
- hotswapGFXMode();
- }
- //}
+OSystem_WINCE3::~OSystem_WINCE3() {
+ delete _fsFactory;
+ delete _mixer;
}
-void OSystem_WINCE3::swap_panel() {
- _toolbarHighDrawn = false;
- //if (!_panelStateForced) {
- if (_toolbarHandler.activeName() == NAME_PANEL_KEYBOARD && _panelVisible)
- _toolbarHandler.setActive(NAME_MAIN_PANEL);
- else
- _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
-
- if (_videoMode.screenHeight > 240)
- addDirtyRect(0, 400, 640, 80);
- else
- addDirtyRect(0, 200, 320, 40);
-
- _toolbarHandler.setVisible(true);
- if (!_panelVisible) {
- _panelVisible = true;
- update_scalers();
- hotswapGFXMode();
- }
- //}
-}
-
-void OSystem_WINCE3::swap_smartphone_keyboard() {
- _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
- _panelVisible = !_panelVisible;
- _toolbarHandler.setVisible(_panelVisible);
- if (_videoMode.screenHeight > 240)
- addDirtyRect(0, 0, 640, 80);
- else
- addDirtyRect(0, 0, 320, 40);
- internUpdateScreen();
-}
-
-void OSystem_WINCE3::smartphone_rotate_display() {
- _orientationLandscape = _newOrientation = _orientationLandscape == 1 ? 2 : 1;
- ConfMan.setInt("landscape", _orientationLandscape);
- ConfMan.flushToDisk();
- hotswapGFXMode();
+FilesystemFactory *OSystem_WINCE3::getFilesystemFactory() {
+ return _fsFactory;
}
void OSystem_WINCE3::swap_sound_master() {
_soundMaster = !_soundMaster;
- if (_toolbarHandler.activeName() == NAME_MAIN_PANEL)
- _toolbarHandler.forceRedraw(); // redraw sound icon
-}
-
-void OSystem_WINCE3::add_right_click(bool pushed) {
- int x, y;
- retrieve_mouse_location(x, y);
- EventsBuffer::simulateMouseRightClick(x, y, pushed);
-}
-
-void OSystem_WINCE3::swap_mouse_visibility() {
- _forceHideMouse = !_forceHideMouse;
- if (_forceHideMouse)
- undrawMouse();
-}
-
-void OSystem_WINCE3::swap_freeLook() {
- _freeLook = !_freeLook;
-}
-void OSystem_WINCE3::swap_zoom_up() {
- if (_zoomUp) {
- // restore visibility
- _toolbarHandler.setVisible(_saveToolbarZoom);
- // restore scaler
- _scaleFactorYd = 2;
- _scalerProc = DownscaleAllByHalf;
- _zoomUp = false;
- _zoomDown = false;
- } else {
- // only active if running on a PocketPC
- if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
- return;
- if (_scalerProc == DownscaleAllByHalf) {
- _saveToolbarZoom = _toolbarHandler.visible();
- _toolbarHandler.setVisible(false);
- // set zoom scaler
- _scaleFactorYd = 1;
- _scalerProc = DownscaleHorizByHalf;
- }
+ //WINCESdlGraphicsManager _graphicsManager
- _zoomDown = false;
- _zoomUp = true;
- }
- // redraw whole screen
- addDirtyRect(0, 0, 640, 480);
- internUpdateScreen();
+ if (((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.activeName() == NAME_MAIN_PANEL)
+ ((WINCESdlGraphicsManager *)_graphicsManager)->_toolbarHandler.forceRedraw(); // redraw sound icon
}
-void OSystem_WINCE3::swap_zoom_down() {
- if (_zoomDown) {
- // restore visibility
- _toolbarHandler.setVisible(_saveToolbarZoom);
- // restore scaler
- _scaleFactorYd = 2;
- _scalerProc = DownscaleAllByHalf;
- _zoomDown = false;
- _zoomUp = false;
- } else {
- // only active if running on a PocketPC
- if (_scalerProc != DownscaleAllByHalf && _scalerProc != DownscaleHorizByHalf)
- return;
- if (_scalerProc == DownscaleAllByHalf) {
- _saveToolbarZoom = _toolbarHandler.visible();
- _toolbarHandler.setVisible(false);
- // set zoom scaler
- _scaleFactorYd = 1;
- _scalerProc = DownscaleHorizByHalf;
- }
-
- _zoomUp = false;
- _zoomDown = true;
- }
- // redraw whole screen
- addDirtyRect(0, 0, 640, 480);
- internUpdateScreen();
-}
-
-// Smartphone actions
-void OSystem_WINCE3::initZones() {
- int i;
-
- _currentZone = 0;
- for (i = 0; i < TOTAL_ZONES; i++) {
- _mouseXZone[i] = (_zones[i].x + (_zones[i].width / 2)) * _scaleFactorXm / _scaleFactorXd;
- _mouseYZone[i] = (_zones[i].y + (_zones[i].height / 2)) * _scaleFactorYm / _scaleFactorYd;
- }
-}
-
-void OSystem_WINCE3::loadDeviceConfigurationElement(String element, int &value, int defaultValue) {
- value = ConfMan.getInt(element, ConfMan.kApplicationDomain);
- if (!value) {
- value = defaultValue;
- ConfMan.setInt(element, value, ConfMan.kApplicationDomain);
- }
-}
-
-void OSystem_WINCE3::loadDeviceConfiguration() {
- loadDeviceConfigurationElement("repeatTrigger", _keyRepeatTrigger, 200);
- loadDeviceConfigurationElement("repeatX", _repeatX, 4);
- loadDeviceConfigurationElement("repeatY", _repeatY, 4);
- loadDeviceConfigurationElement("stepX1", _stepX1, 2);
- loadDeviceConfigurationElement("stepX2", _stepX2, 10);
- loadDeviceConfigurationElement("stepX3", _stepX3, 40);
- loadDeviceConfigurationElement("stepY1", _stepY1, 2);
- loadDeviceConfigurationElement("stepY2", _stepY2, 10);
- loadDeviceConfigurationElement("stepY3", _stepY3, 20);
- ConfMan.flushToDisk();
-}
-
-void OSystem_WINCE3::add_left_click(bool pushed) {
- int x, y;
- retrieve_mouse_location(x, y);
- EventsBuffer::simulateMouseLeftClick(x, y, pushed);
-}
-
-void OSystem_WINCE3::move_cursor_up() {
- int x, y;
- _usesEmulatedMouse = true;
- retrieve_mouse_location(x, y);
- if (_keyRepeat > _repeatY)
- y -= _stepY3;
- else if (_keyRepeat)
- y -= _stepY2;
- else
- y -= _stepY1;
-
- if (y < 0)
- y = 0;
-
- EventsBuffer::simulateMouseMove(x, y);
-}
-
-void OSystem_WINCE3::move_cursor_down() {
- int x, y;
- _usesEmulatedMouse = true;
- retrieve_mouse_location(x, y);
- if (_keyRepeat > _repeatY)
- y += _stepY3;
- else if (_keyRepeat)
- y += _stepY2;
- else
- y += _stepY1;
-
- if (y > _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd)
- y = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;
-
- EventsBuffer::simulateMouseMove(x, y);
-}
-
-void OSystem_WINCE3::move_cursor_left() {
- int x, y;
- _usesEmulatedMouse = true;
- retrieve_mouse_location(x, y);
- if (_keyRepeat > _repeatX)
- x -= _stepX3;
- else if (_keyRepeat)
- x -= _stepX2;
- else
- x -= _stepX1;
-
- if (x < 0)
- x = 0;
-
- EventsBuffer::simulateMouseMove(x, y);
-}
-
-void OSystem_WINCE3::move_cursor_right() {
- int x, y;
- _usesEmulatedMouse = true;
- retrieve_mouse_location(x, y);
- if (_keyRepeat > _repeatX)
- x += _stepX3;
- else if (_keyRepeat)
- x += _stepX2;
- else
- x += _stepX1;
-
- if (x > _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd)
- x = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;
-
- EventsBuffer::simulateMouseMove(x, y);
-}
-
-void OSystem_WINCE3::switch_zone() {
- int x, y;
- int i;
- retrieve_mouse_location(x, y);
-
- for (i = 0; i < TOTAL_ZONES; i++)
- if (x >= _zones[i].x && y >= _zones[i].y &&
- x <= _zones[i].x + _zones[i].width && y <= _zones[i].y + _zones[i].height) {
- _mouseXZone[i] = x;
- _mouseYZone[i] = y;
- break;
- }
- _currentZone = i + 1;
- if (_currentZone >= TOTAL_ZONES)
- _currentZone = 0;
-
- EventsBuffer::simulateMouseMove(_mouseXZone[_currentZone], _mouseYZone[_currentZone]);
-}
-
-void OSystem_WINCE3::create_toolbar() {
- PanelKeyboard *keyboard;
-
- // Add the keyboard
- keyboard = new PanelKeyboard(PANEL_KEYBOARD);
- _toolbarHandler.add(NAME_PANEL_KEYBOARD, *keyboard);
- _toolbarHandler.setVisible(false);
-}
-
-void OSystem_WINCE3::setupMixer() {
- SDL_AudioSpec desired;
- int thread_priority;
-
- uint32 sampleRate = compute_sample_rate();
- if (sampleRate == 0)
- warning("OSystem_WINCE3::setupMixer called with sample rate 0 - audio will not work");
- else if (_mixer && _mixer->getOutputRate() == sampleRate) {
- debug(1, "Skipping sound mixer re-init: samplerate is good");
- return;
- }
-
- memset(&desired, 0, sizeof(desired));
- desired.freq = sampleRate;
- desired.format = AUDIO_S16SYS;
- desired.channels = 2;
- desired.samples = 128;
- desired.callback = private_sound_proc;
- desired.userdata = this;
-
- // Create the mixer instance
- if (_mixer == 0)
- _mixer = new Audio::MixerImpl(this, sampleRate);
-
- // Add sound thread priority
- if (!ConfMan.hasKey("sound_thread_priority"))
- thread_priority = THREAD_PRIORITY_NORMAL;
- else
- thread_priority = ConfMan.getInt("sound_thread_priority");
-
- desired.thread_priority = thread_priority;
-
- SDL_CloseAudio();
- if (SDL_OpenAudio(&desired, NULL) != 0) {
- warning("Could not open audio device: %s", SDL_GetError());
- _mixer->setReady(false);
-
- } else {
- debug(1, "Sound opened OK, mixing at %d Hz", sampleRate);
-
- // Re-create mixer to match the output rate
- int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
- int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
- int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
- int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
- delete _mixer;
- _mixer = new Audio::MixerImpl(this, sampleRate);
- _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1);
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2);
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3);
- _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4);
- _mixer->setReady(true);
- SDL_PauseAudio(0);
- }
-}
-
-void OSystem_WINCE3::private_sound_proc(void *param, byte *buf, int len) {
- OSystem_WINCE3 *this_ = (OSystem_WINCE3 *)param;
- assert(this_);
-
- if (this_->_mixer)
- this_->_mixer->mixCallback(buf, len);
- if (!_soundMaster)
- memset(buf, 0, len);
-}
-
-#ifdef USE_VORBIS
-bool OSystem_WINCE3::checkOggHighSampleRate() {
- char trackFile[255];
- FILE *testFile;
- OggVorbis_File *test_ov_file = new OggVorbis_File;
-
- // FIXME: The following sprintf assumes that "path" is always
- // terminated by a path separator. This is *not* true in general.
- // This code really should check for the path separator, or even
- // better, use the FSNode API.
- sprintf(trackFile, "%sTrack1.ogg", ConfMan.get("path").c_str());
- // Check if we have an OGG audio track
- testFile = fopen(trackFile, "rb");
- if (testFile) {
- if (!ov_open(testFile, test_ov_file, NULL, 0)) {
- bool highSampleRate = (ov_info(test_ov_file, -1)->rate == 22050);
- ov_clear(test_ov_file);
- delete test_ov_file;
- return highSampleRate;
- }
- }
-
- // Do not test for OGG samples - too big and too slow anyway :)
-
- delete test_ov_file;
- return false;
-}
-#endif
-
-uint32 OSystem_WINCE3::compute_sample_rate() {
- uint32 sampleRate;
-
- // Force at least medium quality FM synthesis for FOTAQ
- Common::String gameid(ConfMan.get("gameid"));
- if (gameid == "queen") {
- if (!((ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) ||
- (ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")))) {
- ConfMan.setBool("FM_medium_quality", true);
- ConfMan.flushToDisk();
- }
- }
- // See if the output frequency is forced by the game
- if (gameid == "ft" || gameid == "dig" || gameid == "comi" || gameid == "queen" || gameid == "sword" || gameid == "agi")
- sampleRate = SAMPLES_PER_SEC_NEW;
- else {
- if (ConfMan.hasKey("high_sample_rate") && ConfMan.getBool("high_sample_rate"))
- sampleRate = SAMPLES_PER_SEC_NEW;
- else
- sampleRate = SAMPLES_PER_SEC_OLD;
- }
-
-#ifdef USE_VORBIS
- // Modify the sample rate on the fly if OGG is involved
- if (sampleRate == SAMPLES_PER_SEC_OLD)
- if (checkOggHighSampleRate())
- sampleRate = SAMPLES_PER_SEC_NEW;
-#endif
-
- return sampleRate;
-}
void OSystem_WINCE3::engineInit() {
check_mappings(); // called here to initialize virtual keys handling
//update_game_settings();
// finalize mixer init
- setupMixer();
-}
-
-const OSystem::GraphicsMode *OSystem_WINCE3::getSupportedGraphicsModes() const {
- if (CEDevice::hasWideResolution())
- return s_supportedGraphicsModesHigh;
- else
- return s_supportedGraphicsModesLow;
-}
-
-bool OSystem_WINCE3::hasFeature(Feature f) {
- return (f == kFeatureVirtualKeyboard);
-}
-
-void OSystem_WINCE3::setFeatureState(Feature f, bool enable) {
- switch (f) {
- case kFeatureFullscreenMode:
- return;
-
- case kFeatureVirtualKeyboard:
- if (_hasSmartphoneResolution)
- return;
- _toolbarHighDrawn = false;
- if (enable) {
- _panelStateForced = true;
- if (!_toolbarHandler.visible()) swap_panel_visibility();
- //_saveToolbarState = _toolbarHandler.visible();
- _saveActiveToolbar = _toolbarHandler.activeName();
- _toolbarHandler.setActive(NAME_PANEL_KEYBOARD);
- _toolbarHandler.setVisible(true);
- } else
- if (_panelStateForced) {
- _panelStateForced = false;
- _toolbarHandler.setActive(_saveActiveToolbar);
- //_toolbarHandler.setVisible(_saveToolbarState);
- }
- return;
-
- case kFeatureDisableKeyFiltering:
- if (_hasSmartphoneResolution)
- _unfilteredkeys = enable;
- return;
-
- default:
- OSystem_SDL::setFeatureState(f, enable);
- }
-}
-
-bool OSystem_WINCE3::getFeatureState(Feature f) {
- switch (f) {
- case kFeatureFullscreenMode:
- return false;
- case kFeatureVirtualKeyboard:
- return (_panelStateForced);
- default:
- return OSystem_SDL::getFeatureState(f);
- }
+ _mixerManager->init();
}
void OSystem_WINCE3::check_mappings() {
@@ -974,7 +479,7 @@ void OSystem_WINCE3::check_mappings() {
return;
GUI_Actions::Instance()->initInstanceGame();
- instance = (CEActionsPocket*)GUI_Actions::Instance();
+ instance = (CEActionsPocket *)GUI_Actions::Instance();
// Some games need to map the right click button, signal it here if it wasn't done
if (instance->needsRightClickMapping()) {
@@ -1014,1472 +519,39 @@ void OSystem_WINCE3::check_mappings() {
// Extra warning for Zak Mc Kracken
if (strncmp(gameid.c_str(), "zak", 3) == 0 &&
- !GUI_Actions::Instance()->getMapping(POCKET_ACTION_HIDE)) {
+ !GUI_Actions::Instance()->getMapping(POCKET_ACTION_HIDE)) {
GUI::MessageDialog alert(_("Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"));
alert.runModal();
}
}
-void OSystem_WINCE3::update_game_settings() {
- Common::String gameid(ConfMan.get("gameid"));
-
- // Finish panel initialization
- if (!_panelInitialized && !gameid.empty()) {
- Panel *panel;
- _panelInitialized = true;
- // Add the main panel
- panel = new Panel(0, 32);
- panel->setBackground(IMAGE_PANEL);
- // Save
- panel->add(NAME_ITEM_OPTIONS, new ItemAction(ITEM_OPTIONS, POCKET_ACTION_SAVE));
- // Skip
- panel->add(NAME_ITEM_SKIP, new ItemAction(ITEM_SKIP, POCKET_ACTION_SKIP));
- // sound
- panel->add(NAME_ITEM_SOUND, new ItemSwitch(ITEM_SOUND_OFF, ITEM_SOUND_ON, &_soundMaster));
- // bind keys
- panel->add(NAME_ITEM_BINDKEYS, new ItemAction(ITEM_BINDKEYS, POCKET_ACTION_BINDKEYS));
- // portrait/landscape - screen dependent
- // FIXME : will still display the portrait/landscape icon when using a scaler (but will be disabled)
- if (ConfMan.hasKey("landscape")) {
- if (ConfMan.get("landscape")[0] > 57) {
- _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
- //ConfMan.removeKey("landscape", "");
- ConfMan.setInt("landscape", _orientationLandscape);
- } else
- _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
- } else {
- _newOrientation = _orientationLandscape = 0;
- }
- panel->add(NAME_ITEM_ORIENTATION, new ItemSwitch(ITEM_VIEW_LANDSCAPE, ITEM_VIEW_PORTRAIT, &_newOrientation, 2));
- _toolbarHandler.add(NAME_MAIN_PANEL, *panel);
- _toolbarHandler.setActive(NAME_MAIN_PANEL);
- _toolbarHandler.setVisible(true);
-
- if (_videoMode.mode == GFX_NORMAL && ConfMan.hasKey("landscape") && ConfMan.getInt("landscape")) {
- setGraphicsMode(GFX_NORMAL);
- hotswapGFXMode();
- }
-
- if (_hasSmartphoneResolution)
- panel->setVisible(false);
-
- _saveToolbarState = true;
- }
-
- if (ConfMan.hasKey("no_doubletap_rightclick"))
- _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick");
-}
-
-void OSystem_WINCE3::initSize(uint w, uint h, const Graphics::PixelFormat *format) {
- if (_hasSmartphoneResolution && h == 240)
- h = 200; // mainly for the launcher
-
- if (_isSmartphone && !ConfMan.hasKey("landscape")) {
- ConfMan.setInt("landscape", 1);
- ConfMan.flushToDisk();
- }
-
- _canBeAspectScaled = false;
- if (w == 320 && h == 200 && !_hasSmartphoneResolution) {
- _canBeAspectScaled = true;
- h = 240; // use the extra 40 pixels height for the toolbar
- }
-
- if (h == 400) // touche engine fixup
- h += 80;
-
- if (!_hasSmartphoneResolution) {
- if (h == 240)
- _toolbarHandler.setOffset(200);
- else
- _toolbarHandler.setOffset(400);
- } else {
- if (h == 240)
- _toolbarHandler.setOffset(200);
- else // 176x220
- _toolbarHandler.setOffset(0);
- }
-
- if (w != (uint) _videoMode.screenWidth || h != (uint) _videoMode.screenHeight)
- _scalersChanged = false;
-
- _videoMode.overlayWidth = w;
- _videoMode.overlayHeight = h;
-
- OSystem_SDL::initSize(w, h, format);
-
- if (_scalersChanged) {
- unloadGFXMode();
- loadGFXMode();
- _scalersChanged = false;
- }
-
- update_game_settings();
-}
-
-
-int OSystem_WINCE3::getDefaultGraphicsMode() const {
- return GFX_NORMAL;
-}
-
void OSystem_WINCE3::setGraphicsModeIntern() {
// Scalers have been pre-selected for the desired mode.
// No further tuning required.
}
-bool OSystem_WINCE3::update_scalers() {
- _videoMode.aspectRatioCorrection = false;
-
- if (CEDevice::hasPocketPCResolution()) {
- if (_videoMode.mode != GFX_NORMAL)
- return false;
-
- if ((!_orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth))
- || CEDevice::hasSquareQVGAResolution() ) {
- if (getScreenWidth() != 320) {
- _scaleFactorXm = 3;
- _scaleFactorXd = 4;
- _scaleFactorYm = 1;
- _scaleFactorYd = 1;
- _scalerProc = DownscaleHorizByThreeQuarters;
- } else {
- _scaleFactorXm = 1;
- _scaleFactorXd = 1;
- _scaleFactorYm = 1;
- _scaleFactorYd = 1;
- _scalerProc = Normal1x;
- }
- } else if ( _orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) {
- if (!_panelVisible && !_hasSmartphoneResolution && !_overlayVisible && _canBeAspectScaled) {
- _scaleFactorXm = 1;
- _scaleFactorXd = 1;
- _scaleFactorYm = 6;
- _scaleFactorYd = 5;
- _scalerProc = Normal1xAspect;
- _videoMode.aspectRatioCorrection = true;
- } else {
- _scaleFactorXm = 1;
- _scaleFactorXd = 1;
- _scaleFactorYm = 1;
- _scaleFactorYd = 1;
- _scalerProc = Normal1x;
- }
- } else if (_videoMode.screenWidth == 640 && !(isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) {
- _scaleFactorXm = 1;
- _scaleFactorXd = 2;
- _scaleFactorYm = 1;
- _scaleFactorYd = 2;
- _scalerProc = DownscaleAllByHalf;
- } else if (_videoMode.screenWidth == 640 && (isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) {
- _scaleFactorXm = 1;
- _scaleFactorXd = 1;
- _scaleFactorYm = 1;
- _scaleFactorYd = 1;
- _scalerProc = Normal1x;
- }
-
- return true;
- } else if (CEDevice::hasWideResolution()) {
-#ifdef USE_ARM_SCALER_ASM
- if ( _videoMode.mode == GFX_DOUBLESIZE && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth) ) {
- if ( !_panelVisible && !_overlayVisible && _canBeAspectScaled ) {
- _scaleFactorXm = 2;
- _scaleFactorXd = 1;
- _scaleFactorYm = 12;
- _scaleFactorYd = 5;
- _scalerProc = Normal2xAspect;
- _videoMode.aspectRatioCorrection = true;
- } else if ( (_panelVisible || _overlayVisible) && _canBeAspectScaled ) {
- _scaleFactorXm = 2;
- _scaleFactorXd = 1;
- _scaleFactorYm = 2;
- _scaleFactorYd = 1;
- _scalerProc = Normal2x;
- }
- return true;
- }
-#endif
- } else if (CEDevice::hasSmartphoneResolution()) {
- if (_videoMode.mode != GFX_NORMAL)
- return false;
-
- if (_videoMode.screenWidth > 320)
- error("Game resolution not supported on Smartphone");
-#ifdef ARM
- _scaleFactorXm = 11;
- _scaleFactorXd = 16;
-#else
- _scaleFactorXm = 2;
- _scaleFactorXd = 3;
-#endif
- _scaleFactorYm = 7;
- _scaleFactorYd = 8;
- _scalerProc = SmartphoneLandscape;
- initZones();
- return true;
- }
-
- return false;
-}
-
-bool OSystem_WINCE3::setGraphicsMode(int mode) {
-
- Common::StackLock lock(_graphicsMutex);
- int oldScaleFactorXm = _scaleFactorXm;
- int oldScaleFactorXd = _scaleFactorXd;
- int oldScaleFactorYm = _scaleFactorYm;
- int oldScaleFactorYd = _scaleFactorYd;
-
- _scaleFactorXm = -1;
- _scaleFactorXd = -1;
- _scaleFactorYm = -1;
- _scaleFactorYd = -1;
-
- if (ConfMan.hasKey("landscape"))
- if (ConfMan.get("landscape")[0] > 57) {
- _newOrientation = _orientationLandscape = ConfMan.getBool("landscape");
- ConfMan.setInt("landscape", _orientationLandscape);
- } else
- _newOrientation = _orientationLandscape = ConfMan.getInt("landscape");
- else
- _newOrientation = _orientationLandscape = 0;
-
- if (isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640) && mode)
- _scaleFactorXm = -1;
-
- if (CEDevice::hasPocketPCResolution() && !CEDevice::hasWideResolution() && _orientationLandscape)
- _videoMode.mode = GFX_NORMAL;
- else
- _videoMode.mode = mode;
-
- if (_scaleFactorXm < 0) {
- /* Standard scalers, from the SDL backend */
- switch (_videoMode.mode) {
- case GFX_NORMAL:
- _videoMode.scaleFactor = 1;
- _scalerProc = Normal1x;
- break;
- case GFX_DOUBLESIZE:
- _videoMode.scaleFactor = 2;
- _scalerProc = Normal2x;
- break;
- case GFX_TRIPLESIZE:
- _videoMode.scaleFactor = 3;
- _scalerProc = Normal3x;
- break;
- case GFX_2XSAI:
- _videoMode.scaleFactor = 2;
- _scalerProc = _2xSaI;
- break;
- case GFX_SUPER2XSAI:
- _videoMode.scaleFactor = 2;
- _scalerProc = Super2xSaI;
- break;
- case GFX_SUPEREAGLE:
- _videoMode.scaleFactor = 2;
- _scalerProc = SuperEagle;
- break;
- case GFX_ADVMAME2X:
- _videoMode.scaleFactor = 2;
- _scalerProc = AdvMame2x;
- break;
- case GFX_ADVMAME3X:
- _videoMode.scaleFactor = 3;
- _scalerProc = AdvMame3x;
- break;
-#ifdef USE_HQ_SCALERS
- case GFX_HQ2X:
- _videoMode.scaleFactor = 2;
- _scalerProc = HQ2x;
- break;
- case GFX_HQ3X:
- _videoMode.scaleFactor = 3;
- _scalerProc = HQ3x;
- break;
-#endif
- case GFX_TV2X:
- _videoMode.scaleFactor = 2;
- _scalerProc = TV2x;
- break;
- case GFX_DOTMATRIX:
- _videoMode.scaleFactor = 2;
- _scalerProc = DotMatrix;
- break;
-
- default:
- error("unknown gfx mode %d", mode);
- }
- }
-
- // Check if the scaler can be accepted, if not get back to normal scaler
- if (_videoMode.scaleFactor && ((_videoMode.scaleFactor * _videoMode.screenWidth > getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenWidth > getScreenHeight())
- || (_videoMode.scaleFactor * _videoMode.screenHeight > getScreenWidth() && _videoMode.scaleFactor * _videoMode.screenHeight > getScreenHeight()))) {
- _videoMode.scaleFactor = 1;
- _scalerProc = Normal1x;
- }
-
- // Common scaler system was used
- if (_scaleFactorXm < 0) {
- _scaleFactorXm = _videoMode.scaleFactor;
- _scaleFactorXd = 1;
- _scaleFactorYm = _videoMode.scaleFactor;
- _scaleFactorYd = 1;
- }
-
- _forceFull = true;
-
- if (oldScaleFactorXm != _scaleFactorXm ||
- oldScaleFactorXd != _scaleFactorXd ||
- oldScaleFactorYm != _scaleFactorYm ||
- oldScaleFactorYd != _scaleFactorYd) {
- _scalersChanged = true;
- }
- else
- _scalersChanged = false;
-
-
- return true;
-
-}
-
-bool OSystem_WINCE3::loadGFXMode() {
- int displayWidth;
- int displayHeight;
- unsigned int flags = SDL_FULLSCREEN | SDL_SWSURFACE;
-
- _videoMode.fullscreen = true; // forced
- _forceFull = true;
-
- _tmpscreen = NULL;
-
- // Recompute scalers if necessary
- update_scalers();
-
- // Create the surface that contains the 8 bit game data
- _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0);
- if (_screen == NULL)
- error("_screen failed (%s)", SDL_GetError());
-
- // Create the surface that contains the scaled graphics in 16 bit mode
- // Always use full screen mode to have a "clean screen"
- if (!_videoMode.aspectRatioCorrection) {
- displayWidth = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd;
- displayHeight = _videoMode.screenHeight * _scaleFactorYm / _scaleFactorYd;
- } else {
- displayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
- displayHeight = _videoMode.screenHeight* _videoMode.scaleFactor;
- }
-
- switch (_orientationLandscape) {
- case 1:
- flags |= SDL_LANDSCVIDEO;
- break;
- case 2:
- flags |= SDL_INVLNDVIDEO;
- break;
- default:
- flags |= SDL_PORTRTVIDEO;
- }
- _hwscreen = SDL_SetVideoMode(displayWidth, displayHeight, 16, flags);
-
- if (_hwscreen == NULL) {
- warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
- quit();
- }
-
- // see what orientation sdl finally accepted
- if (_hwscreen->flags & SDL_PORTRTVIDEO)
- _orientationLandscape = _newOrientation = 0;
- else if (_hwscreen->flags & SDL_LANDSCVIDEO)
- _orientationLandscape = _newOrientation = 1;
- else
- _orientationLandscape = _newOrientation = 2;
-
- // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
- // Distinguish 555 and 565 mode
- if (_hwscreen->format->Rmask == 0x7C00)
- InitScalers(555);
- else
- InitScalers(565);
- _overlayFormat.bytesPerPixel = _hwscreen->format->BytesPerPixel;
- _overlayFormat.rLoss = _hwscreen->format->Rloss;
- _overlayFormat.gLoss = _hwscreen->format->Gloss;
- _overlayFormat.bLoss = _hwscreen->format->Bloss;
- _overlayFormat.aLoss = _hwscreen->format->Aloss;
- _overlayFormat.rShift = _hwscreen->format->Rshift;
- _overlayFormat.gShift = _hwscreen->format->Gshift;
- _overlayFormat.bShift = _hwscreen->format->Bshift;
- _overlayFormat.aShift = _hwscreen->format->Ashift;
-
- // Need some extra bytes around when using 2xSaI
- _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
-
- if (_tmpscreen == NULL)
- error("_tmpscreen creation failed (%s)", SDL_GetError());
-
- // Overlay
- if (CEDevice::hasDesktopResolution()) {
- _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd, 16, 0, 0, 0, 0);
- if (_overlayscreen == NULL)
- error("_overlayscreen failed (%s)", SDL_GetError());
- _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth * _scaleFactorXm / _scaleFactorXd + 3, _videoMode.overlayHeight * _scaleFactorYm / _scaleFactorYd + 3, 16, 0, 0, 0, 0);
- if (_tmpscreen2 == NULL)
- error("_tmpscreen2 failed (%s)", SDL_GetError());
- } else {
- _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, 16, 0, 0, 0, 0);
- if (_overlayscreen == NULL)
- error("_overlayscreen failed (%s)", SDL_GetError());
- _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, 16, 0, 0, 0, 0);
- if (_tmpscreen2 == NULL)
- error("_tmpscreen2 failed (%s)", SDL_GetError());
- }
-
- // Toolbar
- _toolbarHighDrawn = false;
- uint16 *toolbar_screen = (uint16 *)calloc(320 * 40, sizeof(uint16)); // *not* leaking memory here
- _toolbarLow = SDL_CreateRGBSurfaceFrom(toolbar_screen, 320, 40, 16, 320 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
-
- if (_toolbarLow == NULL)
- error("_toolbarLow failed (%s)", SDL_GetError());
-
- if (_videoMode.screenHeight > 240) {
- uint16 *toolbar_screen = (uint16 *)calloc(640 * 80, sizeof(uint16));
- _toolbarHigh = SDL_CreateRGBSurfaceFrom(toolbar_screen, 640, 80, 16, 640 * 2, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask);
-
- if (_toolbarHigh == NULL)
- error("_toolbarHigh failed (%s)", SDL_GetError());
- } else
- _toolbarHigh = NULL;
-
-
- // keyboard cursor control, some other better place for it?
- _km.x_max = _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd - 1;
- _km.y_max = _videoMode.screenHeight * _scaleFactorXm / _scaleFactorXd - 1;
- _km.delay_time = 25;
- _km.last_time = 0;
-
- return true;
-}
-
-void OSystem_WINCE3::unloadGFXMode() {
- if (_screen) {
- SDL_FreeSurface(_screen);
- _screen = NULL;
- }
-
- if (_hwscreen) {
- SDL_FreeSurface(_hwscreen);
- _hwscreen = NULL;
- }
-
- if (_tmpscreen) {
- SDL_FreeSurface(_tmpscreen);
- _tmpscreen = NULL;
- }
-}
-
-bool OSystem_WINCE3::hotswapGFXMode() {
- if (!_screen)
- return false;
-
- // Keep around the old _screen & _tmpscreen so we can restore the screen data
- // after the mode switch. (also for the overlay)
- SDL_Surface *old_screen = _screen;
- SDL_Surface *old_tmpscreen = _tmpscreen;
- SDL_Surface *old_overlayscreen = _overlayscreen;
- SDL_Surface *old_tmpscreen2 = _tmpscreen2;
-
- // Release the HW screen surface
- SDL_FreeSurface(_hwscreen);
-
- // Release toolbars
- free(_toolbarLow->pixels);
- SDL_FreeSurface(_toolbarLow);
- if (_toolbarHigh) {
- free(_toolbarHigh->pixels);
- SDL_FreeSurface(_toolbarHigh);
- }
-
- // Setup the new GFX mode
- if (!loadGFXMode()) {
- unloadGFXMode();
-
- _screen = old_screen;
- _overlayscreen = old_overlayscreen;
-
- return false;
- }
-
- // reset palette
- SDL_SetColors(_screen, _currentPalette, 0, 256);
-
- // Restore old screen content
- SDL_BlitSurface(old_screen, NULL, _screen, NULL);
- SDL_BlitSurface(old_tmpscreen, NULL, _tmpscreen, NULL);
- if (_overlayVisible) {
- SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
- SDL_BlitSurface(old_tmpscreen2, NULL, _tmpscreen2, NULL);
- }
-
- // Free the old surfaces
- SDL_FreeSurface(old_screen);
- SDL_FreeSurface(old_tmpscreen);
- SDL_FreeSurface(old_overlayscreen);
- SDL_FreeSurface(old_tmpscreen2);
-
- // Blit everything back to the screen
- _toolbarHighDrawn = false;
- internUpdateScreen();
-
- // Make sure that a Common::EVENT_SCREEN_CHANGED gets sent later -> FIXME this crashes when no game has been loaded.
-// _modeChanged = true;
-
- return true;
-}
-
-void OSystem_WINCE3::internUpdateScreen() {
- SDL_Surface *srcSurf, *origSurf;
- static bool old_overlayVisible = false;
- int numRectsOut = 0;
- int16 routx, routy, routw, routh, stretch, shakestretch;
-
- assert(_hwscreen != NULL);
-
- // bail if the application is minimized, be nice to OS
- if (!_hasfocus) {
- Sleep(20);
- return;
- }
-
- // If the shake position changed, fill the dirty area with blackness
- if (_currentShakePos != _newShakePos) {
- SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _scaleFactorXm / _scaleFactorXd, _newShakePos * _scaleFactorYm / _scaleFactorYd};
- if (_videoMode.aspectRatioCorrection)
- blackrect.h = real2Aspect(blackrect.h - 1) + 1;
- SDL_FillRect(_hwscreen, &blackrect, 0);
- _currentShakePos = _newShakePos;
- _forceFull = true;
- }
-
- // Make sure the mouse is drawn, if it should be drawn.
- drawMouse();
-
- // Check whether the palette was changed in the meantime and update the
- // screen surface accordingly.
- if (_paletteDirtyEnd != 0) {
- SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, _paletteDirtyStart, _paletteDirtyEnd - _paletteDirtyStart);
- _paletteDirtyEnd = 0;
- _forceFull = true;
- }
+void OSystem_WINCE3::initSDL() {
+ // Check if SDL has not been initialized
+ if (!_initedSDL) {
+ uint32 sdlFlags = SDL_INIT_EVENTTHREAD;
+ if (ConfMan.hasKey("disable_sdl_parachute"))
+ sdlFlags |= SDL_INIT_NOPARACHUTE;
- if (!_overlayVisible) {
- origSurf = _screen;
- srcSurf = _tmpscreen;
- } else {
- origSurf = _overlayscreen;
- srcSurf = _tmpscreen2;
- }
-
- if (old_overlayVisible != _overlayVisible) {
- old_overlayVisible = _overlayVisible;
- update_scalers();
- }
-
- // Force a full redraw if requested
- if (_forceFull) {
- _numDirtyRects = 1;
-
- _dirtyRectList[0].x = 0;
- if (!_zoomDown)
- _dirtyRectList[0].y = 0;
- else
- _dirtyRectList[0].y = _videoMode.screenHeight / 2;
- _dirtyRectList[0].w = _videoMode.screenWidth;
- if (!_zoomUp && !_zoomDown)
- _dirtyRectList[0].h = _videoMode.screenHeight;
- else
- _dirtyRectList[0].h = _videoMode.screenHeight / 2;
-
- _toolbarHandler.forceRedraw();
- }
-
- // Only draw anything if necessary
- if (_numDirtyRects > 0) {
-
- SDL_Rect *r, *rout;
- SDL_Rect dst;
- uint32 srcPitch, dstPitch;
- SDL_Rect *last_rect = _dirtyRectList + _numDirtyRects;
- bool toolbarVisible = _toolbarHandler.visible();
- int toolbarOffset = _toolbarHandler.getOffset();
-
- for (r = _dirtyRectList; r != last_rect; ++r) {
- dst = *r;
- dst.x++; // Shift rect by one since 2xSai needs to access the data around
- dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
- // NOTE: This is also known as BLACK MAGIC, copied from the sdl backend
- if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
- error("SDL_BlitSurface failed: %s", SDL_GetError());
+ if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) {
+ SDL_VideoInit("windib", 0);
+ sdlFlags ^= SDL_INIT_VIDEO;
}
- SDL_LockSurface(srcSurf);
- SDL_LockSurface(_hwscreen);
-
- srcPitch = srcSurf->pitch;
- dstPitch = _hwscreen->pitch;
-
- for (r = _dirtyRectList, rout = _dirtyRectOut; r != last_rect; ++r) {
-
- // always clamp to enclosing, downsampled-grid-aligned rect in the downscaled image
- if (_scaleFactorXd != 1) {
- stretch = r->x % _scaleFactorXd;
- r->x -= stretch;
- r->w += stretch;
- r->w = (r->x + r->w + _scaleFactorXd - 1) / _scaleFactorXd * _scaleFactorXd - r->x;
- }
- if (_scaleFactorYd != 1) {
- stretch = r->y % _scaleFactorYd;
- r->y -= stretch;
- r->h += stretch;
- r->h = (r->y + r->h + _scaleFactorYd - 1) / _scaleFactorYd * _scaleFactorYd - r->y;
- }
-
- // transform
- shakestretch = _currentShakePos * _scaleFactorYm / _scaleFactorYd;
- routx = r->x * _scaleFactorXm / _scaleFactorXd; // locate position in scaled screen
- routy = r->y * _scaleFactorYm / _scaleFactorYd + shakestretch; // adjust for shake offset
- routw = r->w * _scaleFactorXm / _scaleFactorXd;
- routh = r->h * _scaleFactorYm / _scaleFactorYd - shakestretch;
-
- // clipping destination rectangle inside device screen (more strict, also more tricky but more stable)
- // note that all current scalers do not make dst rect exceed left/right, unless chosen badly (FIXME)
- if (_zoomDown) routy -= 240; // adjust for zoom position
- if (routy + routh < 0) continue;
- if (routy < 0) {
- routh += routy;
- r->y -= routy * _scaleFactorYd / _scaleFactorYm;
- routy = 0;
- r->h = routh * _scaleFactorYd / _scaleFactorYm;
- }
- if (_orientationLandscape) {
- if (routy > _platformScreenWidth) continue;
- if (routy + routh > _platformScreenWidth) {
- routh = _platformScreenWidth - routy;
- r->h = routh * _scaleFactorYd / _scaleFactorYm;
- }
- } else {
- if (routy > _platformScreenHeight) continue;
- if (routy + routh > _platformScreenHeight) {
- routh = _platformScreenHeight - routy;
- r->h = routh * _scaleFactorYd / _scaleFactorYm;
- }
- }
-
- // check if the toolbar is overwritten
- if (toolbarVisible && r->y + r->h >= toolbarOffset)
- _toolbarHandler.forceRedraw();
+ // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
+ if (SDL_Init(sdlFlags) == -1)
+ error("Could not initialize SDL: %s", SDL_GetError());
- // blit it (with added voodoo from the sdl backend, shifting the source rect again)
- _scalerProc( (byte *)srcSurf->pixels + (r->x * 2 + 2)+ (r->y + 1) * srcPitch, srcPitch,
- (byte *)_hwscreen->pixels + routx * 2 + routy * dstPitch, dstPitch,
- r->w, r->h - _currentShakePos);
+ // Enable unicode support if possible
+ SDL_EnableUNICODE(1);
- // add this rect to output
- rout->x = routx; rout->y = routy - shakestretch;
- rout->w = routw; rout->h = routh + shakestretch;
- numRectsOut++;
- rout++;
-
- }
- SDL_UnlockSurface(srcSurf);
- SDL_UnlockSurface(_hwscreen);
- }
- // Add the toolbar if needed
- SDL_Rect toolbar_rect[1];
- if (_panelVisible && _toolbarHandler.draw(_toolbarLow, &toolbar_rect[0])) {
- // It can be drawn, scale it
- uint32 srcPitch, dstPitch;
- SDL_Surface *toolbarSurface;
- ScalerProc *toolbarScaler;
-
- if (_videoMode.screenHeight > 240) {
- if (!_toolbarHighDrawn) {
- // Resize the toolbar
- SDL_LockSurface(_toolbarLow);
- SDL_LockSurface(_toolbarHigh);
- Normal2x((byte*)_toolbarLow->pixels, _toolbarLow->pitch, (byte*)_toolbarHigh->pixels, _toolbarHigh->pitch, toolbar_rect[0].w, toolbar_rect[0].h);
- SDL_UnlockSurface(_toolbarHigh);
- SDL_UnlockSurface(_toolbarLow);
- _toolbarHighDrawn = true;
- }
- toolbar_rect[0].w *= 2;
- toolbar_rect[0].h *= 2;
- toolbarSurface = _toolbarHigh;
- }
- else
- toolbarSurface = _toolbarLow;
-
- drawToolbarMouse(toolbarSurface, true); // draw toolbar mouse if applicable
-
- // Apply the appropriate scaler
- SDL_LockSurface(toolbarSurface);
- SDL_LockSurface(_hwscreen);
- srcPitch = toolbarSurface->pitch;
- dstPitch = _hwscreen->pitch;
-
- toolbarScaler = _scalerProc;
- if (_videoMode.scaleFactor == 2)
- toolbarScaler = Normal2x;
- else if (_videoMode.scaleFactor == 3)
- toolbarScaler = Normal3x;
- toolbarScaler((byte *)toolbarSurface->pixels, srcPitch,
- (byte *)_hwscreen->pixels + (_toolbarHandler.getOffset() * _scaleFactorYm / _scaleFactorYd * dstPitch),
- dstPitch, toolbar_rect[0].w, toolbar_rect[0].h);
- SDL_UnlockSurface(toolbarSurface);
- SDL_UnlockSurface(_hwscreen);
-
- // And blit it
- toolbar_rect[0].y = _toolbarHandler.getOffset();
- toolbar_rect[0].x = toolbar_rect[0].x * _scaleFactorXm / _scaleFactorXd;
- toolbar_rect[0].y = toolbar_rect[0].y * _scaleFactorYm / _scaleFactorYd;
- toolbar_rect[0].w = toolbar_rect[0].w * _scaleFactorXm / _scaleFactorXd;
- toolbar_rect[0].h = toolbar_rect[0].h * _scaleFactorYm / _scaleFactorYd;
-
- SDL_UpdateRects(_hwscreen, 1, toolbar_rect);
-
- drawToolbarMouse(toolbarSurface, false); // undraw toolbar mouse
- }
-
- // Finally, blit all our changes to the screen
- if (numRectsOut > 0)
- SDL_UpdateRects(_hwscreen, numRectsOut, _dirtyRectOut);
-
- _numDirtyRects = 0;
- _forceFull = false;
-}
-
-Graphics::Surface *OSystem_WINCE3::lockScreen() {
- // Make sure mouse pointer is not painted over the playfield at the time of locking
- undrawMouse();
- return OSystem_SDL::lockScreen();
-}
-
-void OSystem_WINCE3::unlockScreen() {
- OSystem_SDL::unlockScreen();
-}
-
-bool OSystem_WINCE3::saveScreenshot(const char *filename) {
- assert(_hwscreen != NULL);
-
- Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
- SDL_SaveBMP(_hwscreen, filename);
- return true;
-}
-
-void OSystem_WINCE3::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
- assert (_transactionMode == kTransactionNone);
-
- if (_overlayscreen == NULL)
- return;
-
- // Clip the coordinates
- if (x < 0) {
- w += x;
- buf -= x;
- x = 0;
- }
-
- if (y < 0) {
- h += y; buf -= y * pitch;
- y = 0;
+ _initedSDL = true;
}
-
- if (w > _videoMode.overlayWidth - x) {
- w = _videoMode.overlayWidth - x;
- }
-
- if (h > _videoMode.overlayHeight - y) {
- h = _videoMode.overlayHeight - y;
- }
-
- if (w <= 0 || h <= 0)
- return;
-
- // Mark the modified region as dirty
- addDirtyRect(x, y, w, h);
-
- undrawMouse();
-
- if (SDL_LockSurface(_overlayscreen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
-
- byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
- do {
- memcpy(dst, buf, w * 2);
- dst += _overlayscreen->pitch;
- buf += pitch;
- } while (--h);
-
- SDL_UnlockSurface(_overlayscreen);
-}
-
-void OSystem_WINCE3::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
- assert (_transactionMode == kTransactionNone);
- assert(src);
-
- if (_screen == NULL)
- return;
-
- Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
-
- /* Clip the coordinates */
- if (x < 0) {
- w += x;
- src -= x;
- x = 0;
- }
-
- if (y < 0) {
- h += y;
- src -= y * pitch;
- y = 0;
- }
-
- if (w > _videoMode.screenWidth - x) {
- w = _videoMode.screenWidth - x;
- }
-
- if (h > _videoMode.screenHeight - y) {
- h = _videoMode.screenHeight - y;
- }
-
- if (w <= 0 || h <= 0)
- return;
-
- addDirtyRect(x, y, w, h);
-
- undrawMouse();
-
- // Try to lock the screen surface
- if (SDL_LockSurface(_screen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
-
- byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
-
- if (_videoMode.screenWidth == pitch && pitch == w) {
- memcpy(dst, src, h*w);
- } else {
- do {
- memcpy(dst, src, w);
- src += pitch;
- dst += _videoMode.screenWidth;
- } while (--h);
- }
-
- // Unlock the screen surface
- SDL_UnlockSurface(_screen);
-}
-
-void OSystem_WINCE3::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
-
- undrawMouse();
- if (w == 0 || h == 0)
- return;
-
- _mouseCurState.w = w;
- _mouseCurState.h = h;
-
- _mouseHotspotX = hotspot_x;
- _mouseHotspotY = hotspot_y;
-
- _mouseKeyColor = keycolor;
-
- free(_mouseData);
-
- _mouseData = (byte *) malloc(w * h);
- memcpy(_mouseData, buf, w * h);
-
- if (w > _mouseBackupDim || h > _mouseBackupDim) {
- // mouse has been undrawn, adjust sprite backup area
- free(_mouseBackupOld);
- free(_mouseBackupToolbar);
- uint16 tmp = (w > h) ? w : h;
- _mouseBackupOld = (byte *) malloc(tmp * tmp * 2); // can hold 8bpp (playfield) or 16bpp (overlay) data
- _mouseBackupToolbar = (uint16 *) malloc(tmp * tmp * 2); // 16 bpp
- _mouseBackupDim = tmp;
- }
-}
-
-void OSystem_WINCE3::setMousePos(int x, int y) {
- if (x != _mouseCurState.x || y != _mouseCurState.y) {
- undrawMouse();
- _mouseCurState.x = x;
- _mouseCurState.y = y;
- updateScreen();
- }
-}
-
-
-void OSystem_WINCE3::internDrawMouse() {
- if (!_mouseNeedsRedraw || !_mouseVisible || !_mouseData)
- return;
-
- int x = _mouseCurState.x - _mouseHotspotX;
- int y = _mouseCurState.y - _mouseHotspotY;
- int w = _mouseCurState.w;
- int h = _mouseCurState.h;
- byte color;
- const byte *src = _mouseData; // Image representing the mouse
- int width;
-
- // clip the mouse rect, and adjust the src pointer accordingly
- if (x < 0) {
- w += x;
- src -= x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- src -= y * _mouseCurState.w;
- y = 0;
- }
-
- if (w > _videoMode.screenWidth - x)
- w = _videoMode.screenWidth - x;
- if (h > _videoMode.screenHeight - y)
- h = _videoMode.screenHeight - y;
-
- // Quick check to see if anything has to be drawn at all
- if (w <= 0 || h <= 0)
- return;
-
- // Draw the mouse cursor; backup the covered area in "bak"
- if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
-
- // Mark as dirty
- addDirtyRect(x, y, w, h);
-
- if (!_overlayVisible) {
- byte *bak = _mouseBackupOld; // Surface used to backup the area obscured by the mouse
- byte *dst; // Surface we are drawing into
-
- dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x;
- while (h > 0) {
- width = w;
- while (width > 0) {
- *bak++ = *dst;
- color = *src++;
- if (color != _mouseKeyColor) // transparent, don't draw
- *dst = color;
- dst++;
- width--;
- }
- src += _mouseCurState.w - w;
- bak += _mouseBackupDim - w;
- dst += _videoMode.screenWidth - w;
- h--;
- }
-
- } else {
- uint16 *bak = (uint16 *)_mouseBackupOld; // Surface used to backup the area obscured by the mouse
- byte *dst; // Surface we are drawing into
-
- dst = (byte *)_overlayscreen->pixels + (y + 1) * _overlayscreen->pitch + (x + 1) * 2;
- while (h > 0) {
- width = w;
- while (width > 0) {
- *bak++ = *(uint16 *)dst;
- color = *src++;
- if (color != 0xFF) // 0xFF = transparent, don't draw
- *(uint16 *)dst = SDL_MapRGB(_overlayscreen->format, _currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b);
- dst += 2;
- width--;
- }
- src += _mouseCurState.w - w;
- bak += _mouseBackupDim - w;
- dst += _overlayscreen->pitch - w * 2;
- h--;
- }
- }
-
- SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
-
- // Finally, set the flag to indicate the mouse has been drawn
- _mouseNeedsRedraw = false;
-}
-
-void OSystem_WINCE3::undrawMouse() {
- assert (_transactionMode == kTransactionNone);
-
- if (_mouseNeedsRedraw)
- return;
-
- int old_mouse_x = _mouseCurState.x - _mouseHotspotX;
- int old_mouse_y = _mouseCurState.y - _mouseHotspotY;
- int old_mouse_w = _mouseCurState.w;
- int old_mouse_h = _mouseCurState.h;
-
- // clip the mouse rect, and adjust the src pointer accordingly
- if (old_mouse_x < 0) {
- old_mouse_w += old_mouse_x;
- old_mouse_x = 0;
- }
- if (old_mouse_y < 0) {
- old_mouse_h += old_mouse_y;
- old_mouse_y = 0;
- }
-
- if (old_mouse_w > _videoMode.screenWidth - old_mouse_x)
- old_mouse_w = _videoMode.screenWidth - old_mouse_x;
- if (old_mouse_h > _videoMode.screenHeight - old_mouse_y)
- old_mouse_h = _videoMode.screenHeight - old_mouse_y;
-
- // Quick check to see if anything has to be drawn at all
- if (old_mouse_w <= 0 || old_mouse_h <= 0)
- return;
-
-
- if (SDL_LockSurface(_overlayVisible ? _overlayscreen : _screen) == -1)
- error("SDL_LockSurface failed: %s", SDL_GetError());
-
- int y;
- if (!_overlayVisible) {
- byte *dst, *bak = _mouseBackupOld;
-
- // No need to do clipping here, since drawMouse() did that already
- dst = (byte *)_screen->pixels + old_mouse_y * _videoMode.screenWidth + old_mouse_x;
- for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _videoMode.screenWidth)
- memcpy(dst, bak, old_mouse_w);
- } else {
- byte *dst;
- uint16 *bak = (uint16 *)_mouseBackupOld;
-
- // No need to do clipping here, since drawMouse() did that already
- dst = (byte *)_overlayscreen->pixels + (old_mouse_y + 1) * _overlayscreen->pitch + (old_mouse_x + 1) * 2;
- for (y = 0; y < old_mouse_h; ++y, bak += _mouseBackupDim, dst += _overlayscreen->pitch)
- memcpy(dst, bak, old_mouse_w << 1);
- }
-
- addDirtyRect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
-
- SDL_UnlockSurface(_overlayVisible ? _overlayscreen : _screen);
-
- _mouseNeedsRedraw = true;
-}
-
-bool OSystem_WINCE3::showMouse(bool visible) {
- if (_mouseVisible == visible)
- return visible;
-
- if (visible == false)
- undrawMouse();
-
- bool last = _mouseVisible;
- _mouseVisible = visible;
- _mouseNeedsRedraw = true;
-
- return last;
-}
-
-void OSystem_WINCE3::drawToolbarMouse(SDL_Surface *surf, bool draw) {
-
- if (!_mouseData || !_usesEmulatedMouse)
- return;
-
- int x = _mouseCurState.x - _mouseHotspotX;
- int y = _mouseCurState.y - _mouseHotspotY - _toolbarHandler.getOffset();
- int w = _mouseCurState.w;
- int h = _mouseCurState.h;
- byte color;
- const byte *src = _mouseData;
- int width;
-
- // clip
- if (x < 0) {
- w += x;
- src -= x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- src -= y * _mouseCurState.w;
- y = 0;
- }
- if (w > surf->w - x)
- w = surf->w - x;
- if (h > surf->h - y)
- h = surf->h - y;
- if (w <= 0 || h <= 0)
- return;
-
- if (SDL_LockSurface(surf) == -1)
- error("SDL_LockSurface failed at internDrawToolbarMouse: %s", SDL_GetError());
-
- uint16 *bak = _mouseBackupToolbar; // toolbar surfaces are 16bpp
- uint16 *dst;
- dst = (uint16 *)surf->pixels + y * surf->w + x;
-
- if (draw) { // blit it
- while (h > 0) {
- width = w;
- while (width > 0) {
- *bak++ = *dst;
- color = *src++;
- if (color != _mouseKeyColor) // transparent color
- *dst = 0xFFFF;
- dst++;
- width--;
- }
- src += _mouseCurState.w - w;
- bak += _mouseBackupDim - w;
- dst += surf->w - w;
- h--;
- }
- } else { // restore bg
- for (y = 0; y < h; ++y, bak += _mouseBackupDim, dst += surf->w)
- memcpy(dst, bak, w << 1);
- }
-
- SDL_UnlockSurface(surf);
-}
-
-void OSystem_WINCE3::blitCursor() {
-}
-
-void OSystem_WINCE3::showOverlay() {
- assert (_transactionMode == kTransactionNone);
-
- if (_overlayVisible)
- return;
-
- undrawMouse();
- _overlayVisible = true;
- update_scalers();
- clearOverlay();
-}
-
-void OSystem_WINCE3::hideOverlay() {
- assert (_transactionMode == kTransactionNone);
-
- if (!_overlayVisible)
- return;
-
- undrawMouse();
- _overlayVisible = false;
- clearOverlay();
- _forceFull = true;
-}
-
-void OSystem_WINCE3::drawMouse() {
- if (!(_toolbarHandler.visible() && _mouseCurState.y >= _toolbarHandler.getOffset() && !_usesEmulatedMouse) && !_forceHideMouse)
- internDrawMouse();
-}
-
-void OSystem_WINCE3::fillMouseEvent(Common::Event &event, int x, int y) {
- event.mouse.x = x;
- event.mouse.y = y;
-
- // Update the "keyboard mouse" coords
- _km.x = event.mouse.x;
- _km.y = event.mouse.y;
-
- // Adjust for the screen scaling
- if (_zoomDown)
- event.mouse.y += 240;
-
- event.mouse.x = event.mouse.x * _scaleFactorXd / _scaleFactorXm;
- event.mouse.y = event.mouse.y * _scaleFactorYd / _scaleFactorYm;
-}
-
-void OSystem_WINCE3::retrieve_mouse_location(int &x, int &y) {
- x = _mouseCurState.x;
- y = _mouseCurState.y;
-
- x = x * _scaleFactorXm / _scaleFactorXd;
- y = y * _scaleFactorYm / _scaleFactorYd;
-
- if (_zoomDown)
- y -= 240;
-}
-
-void OSystem_WINCE3::warpMouse(int x, int y) {
- if (_mouseCurState.x != x || _mouseCurState.y != y) {
- SDL_WarpMouse(x * _scaleFactorXm / _scaleFactorXd, y * _scaleFactorYm / _scaleFactorYd);
-
- // SDL_WarpMouse() generates a mouse movement event, so
- // set_mouse_pos() would be called eventually. However, the
- // cannon script in CoMI calls this function twice each time
- // the cannon is reloaded. Unless we update the mouse position
- // immediately the second call is ignored, causing the cannon
- // to change its aim.
-
- setMousePos(x, y);
- }
-}
-
-void OSystem_WINCE3::addDirtyRect(int x, int y, int w, int h, bool mouseRect) {
-
- if (_forceFull || _paletteDirtyEnd)
- return;
-
- OSystem_SDL::addDirtyRect(x, y, w, h, false);
-}
-
-static int mapKeyCE(SDLKey key, SDLMod mod, Uint16 unicode, bool unfilter) {
- if (GUI::Actions::Instance()->mappingActive())
- return key;
-
- if (unfilter) {
- switch (key) {
- case SDLK_ESCAPE:
- return SDLK_BACKSPACE;
- case SDLK_F8:
- return SDLK_ASTERISK;
- case SDLK_F9:
- return SDLK_HASH;
- default:
- return key;
- }
- }
-
- if (key >= SDLK_KP0 && key <= SDLK_KP9) {
- return key - SDLK_KP0 + '0';
- } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
- return key;
- } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
- return 0;
- }
- return key;
-}
-
-bool OSystem_WINCE3::pollEvent(Common::Event &event) {
- SDL_Event ev;
- ev.type = SDL_NOEVENT;
- DWORD currentTime;
- bool keyEvent = false;
- int deltaX, deltaY;
-
- memset(&event, 0, sizeof(Common::Event));
-
- handleKbdMouse();
-
- // If the screen mode changed, send an Common::EVENT_SCREEN_CHANGED
- if (_modeChanged) {
- _modeChanged = false;
- event.type = Common::EVENT_SCREEN_CHANGED;
- _screenChangeCount++;
- return true;
- }
-
- CEDevice::wakeUp();
-
- currentTime = GetTickCount();
-
- while (SDL_PollEvent(&ev)) {
- switch (ev.type) {
- case SDL_KEYDOWN:
- debug(1, "Key down %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym));
- // KMOD_RESERVED is used if the key has been injected by an external buffer
- if (ev.key.keysym.mod != KMOD_RESERVED && !_unfilteredkeys) {
- keyEvent = true;
- _lastKeyPressed = ev.key.keysym.sym;
- _keyRepeatTime = currentTime;
- _keyRepeat = 0;
-
- if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, true))
- return true;
- }
-
- if (GUI_Actions::Instance()->mappingActive())
- event.kbd.flags = 0xFF;
- else if (ev.key.keysym.sym == SDLK_PAUSE) {
- _lastKeyPressed = 0;
- event.type = Common::EVENT_PREDICTIVE_DIALOG;
- return true;
- } event.type = Common::EVENT_KEYDOWN;
- if (!_unfilteredkeys)
- event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
- else
- event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
- event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
-
- if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
- event.kbd.ascii ^= 0x20;
- event.kbd.flags = Common::KBD_SHIFT;
- }
-
- return true;
-
- case SDL_KEYUP:
- debug(1, "Key up %X %s", ev.key.keysym.sym, SDL_GetKeyName((SDLKey)ev.key.keysym.sym));
- // KMOD_RESERVED is used if the key has been injected by an external buffer
- if (ev.key.keysym.mod != KMOD_RESERVED && !_unfilteredkeys) {
- keyEvent = true;
- _lastKeyPressed = 0;
-
- if (!GUI_Actions::Instance()->mappingActive() && GUI_Actions::Instance()->performMapped(ev.key.keysym.sym, false))
- return true;
- }
-
- if (GUI_Actions::Instance()->mappingActive())
- event.kbd.flags = 0xFF;
- else if (ev.key.keysym.sym == SDLK_PAUSE) {
- _lastKeyPressed = 0;
- return false; // chew up the show agi dialog key up event
- }
-
- event.type = Common::EVENT_KEYUP;
- if (!_unfilteredkeys)
- event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
- else
- event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
- event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
-
- if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
- event.kbd.ascii ^= 0x20;
- event.kbd.flags = Common::KBD_SHIFT;
- }
-
- return true;
-
- case SDL_MOUSEMOTION:
- event.type = Common::EVENT_MOUSEMOVE;
- fillMouseEvent(event, ev.motion.x, ev.motion.y);
- setMousePos(event.mouse.x, event.mouse.y);
- return true;
-
- case SDL_MOUSEBUTTONDOWN:
- if (ev.button.button == SDL_BUTTON_LEFT)
- event.type = Common::EVENT_LBUTTONDOWN;
- else if (ev.button.button == SDL_BUTTON_RIGHT)
- event.type = Common::EVENT_RBUTTONDOWN;
- else
- break;
- fillMouseEvent(event, ev.button.x, ev.button.y);
-
-
- if (event.mouse.x > _tapX)
- deltaX = event.mouse.x - _tapX;
- else
- deltaX = _tapX - event.mouse.x;
- if (event.mouse.y > _tapY)
- deltaY = event.mouse.y - _tapY;
- else
- deltaY = _tapY - event.mouse.y;
- _closeClick = (deltaX <= 5 && deltaY <= 5);
-
- if (!_isSmartphone) {
- // handle double-taps
- if (_tapTime) { // second tap
- if (_closeClick && (GetTickCount() - _tapTime < 1000)) {
- if (event.mouse.y <= 20 && _panelInitialized) { // top of screen (show panel)
- swap_panel_visibility();
- } else if (!_noDoubleTapRMB) { // right click
- event.type = Common::EVENT_RBUTTONDOWN;
- _rbutton = true;
- }
- }
- _tapTime = 0;
- } else {
- _tapTime = GetTickCount();
- _tapX = event.mouse.x;
- _tapY = event.mouse.y;
- }
- }
-
- if (_freeLook && !_closeClick) {
- _rbutton = false;
- _tapTime = 0;
- _tapX = event.mouse.x;
- _tapY = event.mouse.y;
- event.type = Common::EVENT_MOUSEMOVE;
- setMousePos(event.mouse.x, event.mouse.y);
- }
-
-
- if (_toolbarHandler.action(event.mouse.x, event.mouse.y, true)) {
- if (!_toolbarHandler.drawn()) {
- _toolbarHighDrawn = false;
- internUpdateScreen();
- }
- if (_newOrientation != _orientationLandscape){
- _orientationLandscape = _newOrientation;
- _toolbarHighDrawn = false;
- ConfMan.setInt("landscape", _orientationLandscape);
- ConfMan.flushToDisk();
- hotswapGFXMode();
- }
- return false;
- }
-
- return true;
-
- case SDL_MOUSEBUTTONUP:
- if (ev.button.button == SDL_BUTTON_LEFT)
- event.type = Common::EVENT_LBUTTONUP;
- else if (ev.button.button == SDL_BUTTON_RIGHT)
- event.type = Common::EVENT_RBUTTONUP;
- else
- break;
-
- if (_rbutton) {
- event.type = Common::EVENT_RBUTTONUP;
- _rbutton = false;
- }
-
- fillMouseEvent(event, ev.button.x, ev.button.y);
-
- if (_freeLook && !_closeClick) {
- _tapX = event.mouse.x;
- _tapY = event.mouse.y;
- event.type = Common::EVENT_MOUSEMOVE;
- setMousePos(event.mouse.x, event.mouse.y);
- }
-
- if (_toolbarHandler.action(event.mouse.x, event.mouse.y, false)) {
- if (!_toolbarHandler.drawn()) {
- _toolbarHighDrawn = false;
- internUpdateScreen();
- }
- return false;
-
- }
- return true;
-
- case SDL_VIDEOEXPOSE:
- _forceFull = true;
- break;
-
- case SDL_QUIT:
- event.type = Common::EVENT_QUIT;
- return true;
-
- case SDL_ACTIVEEVENT:
- if (ev.active.state & SDL_APPMOUSEFOCUS)
- debug(2, "%s mouse focus.", ev.active.gain ? "Got" : "Lost");
- if (ev.active.state & SDL_APPINPUTFOCUS)
- debug(2, "%s input focus.", ev.active.gain ? "Got" : "Lost");
- if (ev.active.state & SDL_APPACTIVE)
- debug(2, "%s total focus.", ev.active.gain ? "Got" : "Lost");
- if (ev.active.state & SDL_APPINPUTFOCUS) {
- _hasfocus = ev.active.gain;
- SDL_PauseAudio(!_hasfocus);
- _forceFull |= _hasfocus;
- }
- break;
- }
- }
-
- // Simulate repeated key for backend
- if (!keyEvent && _lastKeyPressed && currentTime > _keyRepeatTime + _keyRepeatTrigger) {
- _keyRepeatTime = currentTime;
- _keyRepeat++;
- GUI_Actions::Instance()->performMapped(_lastKeyPressed, true);
- }
-
- return false;
}
void OSystem_WINCE3::quit() {
@@ -2497,19 +569,14 @@ void OSystem_WINCE3::getTimeAndDate(TimeDate &t) const {
SYSTEMTIME systime;
GetLocalTime(&systime);
- t.tm_year = systime.wYear - 1900;
- t.tm_mon = systime.wMonth - 1;
- t.tm_mday = systime.wDay;
- t.tm_hour = systime.wHour;
- t.tm_min = systime.wMinute;
- t.tm_sec = systime.wSecond;
+ t.tm_year = systime.wYear - 1900;
+ t.tm_mon = systime.wMonth - 1;
+ t.tm_mday = systime.wDay;
+ t.tm_hour = systime.wHour;
+ t.tm_min = systime.wMinute;
+ t.tm_sec = systime.wSecond;
}
int OSystem_WINCE3::_platformScreenWidth;
int OSystem_WINCE3::_platformScreenHeight;
bool OSystem_WINCE3::_isOzone;
-OSystem_WINCE3::zoneDesc OSystem_WINCE3::_zones[TOTAL_ZONES] = {
- { 0, 0, 320, 145 },
- { 0, 145, 150, 55 },
- { 150, 145, 170, 55 }
-};
diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h
index 6cc6e538e1..d7ede8ca81 100644
--- a/backends/platform/wince/wince-sdl.h
+++ b/backends/platform/wince/wince-sdl.h
@@ -35,7 +35,10 @@
#include "backends/platform/wince/CEkeys/CEKeys.h"
#include "backends/platform/wince/CEDevice.h"
-#define TOTAL_ZONES 3
+#include "backends/graphics/wincesdl/wincesdl-graphics.h"
+#include "backends/events/wincesdl/wincesdl-events.h"
+#include "backends/timer/default/default-timer.h"
+#include "backends/fs/windows/windows-fs-factory.h"
// defines used for implementing the raw frame buffer access method (2003+)
#define GETRAWFRAMEBUFFER 0x00020001
@@ -46,202 +49,45 @@
class OSystem_WINCE3 : public OSystem_SDL {
public:
OSystem_WINCE3();
-
- // Update the dirty areas of the screen
- void internUpdateScreen();
+ virtual ~OSystem_WINCE3();
void setGraphicsModeIntern();
- void initSize(uint w, uint h, const Graphics::PixelFormat *format);
void initBackend();
- // Overloaded from SDL backend (toolbar handling)
- bool pollEvent(Common::Event &event);
- // Overloaded from SDL backend (toolbar handling)
- void drawMouse();
- // Overloaded from SDL backend (mouse and new scaler handling)
- void fillMouseEvent(Common::Event &event, int x, int y);
- // Overloaded from SDL backend (new scaler handling)
- void addDirtyRect(int x, int y, int w, int h, bool mouseRect = false);
- // Overloaded from SDL backend (new scaler handling)
- void warpMouse(int x, int y);
// Overloaded from SDL backend
void quit();
- // Overloaded from SDL backend (master volume and sample rate subtleties)
- void setupMixer();
// Overloaded from OSystem
void engineInit();
void getTimeAndDate(TimeDate &t) const;
virtual Common::String getDefaultConfigFileName();
+ virtual FilesystemFactory *getFilesystemFactory();
-
- // Overloaded from SDL_Common (FIXME)
- void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); // overloaded by CE backend
- void undrawMouse();
- void blitCursor();
- bool showMouse(bool visible);
- void setMousePos(int x, int y);
- void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME)
- void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h);
- void showOverlay();
- void hideOverlay();
- Graphics::Surface *lockScreen();
- void unlockScreen();
-
- // GUI and action stuff
- void swap_panel_visibility();
- void swap_panel();
void swap_sound_master();
- void add_right_click(bool pushed);
- void swap_mouse_visibility();
- void swap_freeLook();
- void swap_zoom_up();
- void swap_zoom_down();
- void swap_smartphone_keyboard();
-
-//#ifdef WIN32_PLATFORM_WFSP
- // Smartphone actions
-
- void initZones();
- void loadDeviceConfigurationElement(String element, int &value, int defaultValue);
- void loadDeviceConfiguration();
- void add_left_click(bool pushed);
- void move_cursor_up();
- void move_cursor_down();
- void move_cursor_left();
- void move_cursor_right();
- void switch_zone();
- void smartphone_rotate_display();
-//#endif
static int getScreenWidth();
static int getScreenHeight();
static void initScreenInfos();
static bool isOzone();
-protected:
- bool loadGFXMode();
- void unloadGFXMode();
- bool hotswapGFXMode();
- bool saveScreenshot(const char *filename);
-
+ static bool _soundMaster; // turn off sound after all calculations
+ // static since needed by the SDL callback
- const GraphicsMode *getSupportedGraphicsModes() const;
- bool setGraphicsMode(int mode);
- //int getGraphicsMode() const;
- int getDefaultGraphicsMode() const;
-
- bool hasFeature(Feature f);
- void setFeatureState(Feature f, bool enable);
- bool getFeatureState(Feature f);
-
- void internDrawMouse();
- void drawToolbarMouse(SDL_Surface *surf, bool draw);
+protected:
+ void initSDL();
+ Audio::MixerImpl *_mixer;
+ DefaultTimerManager *_timer;
+ FilesystemFactory *_fsFactory;
private:
-
-#ifdef USE_VORBIS
- bool checkOggHighSampleRate();
-#endif
-
- static void private_sound_proc(void *param, byte *buf, int len);
-
- bool update_scalers();
- void create_toolbar();
- void update_game_settings();
void check_mappings();
- uint32 compute_sample_rate();
-
- void retrieve_mouse_location(int &x, int &y);
-
- CEGUI::ToolbarHandler _toolbarHandler;
- SDL_Surface *_toolbarLow; // toolbar 320x40
- SDL_Surface *_toolbarHigh; // toolbar 640x80
- bool _toolbarHighDrawn; // cache toolbar 640x80
-
- bool _freeLook; // freeLook mode (do not send mouse button events)
-
- bool _forceHideMouse; // force invisible mouse cursor
-
- bool _forcePanelInvisible; // force panel visibility for some cases
- bool _panelVisible; // panel visibility
- bool _panelStateForced; // panel visibility forced by external call
-
- bool _panelInitialized; // only initialize the toolbar once
-
- bool _unfilteredkeys; // discard key mapping temporarily (agi pred. dialog)
- static bool _soundMaster; // turn off sound after all calculations
- // static since needed by the SDL callback
- int _orientationLandscape; // current orientation
- int _newOrientation; // new orientation
-
- bool _saveToolbarState; // save visibility when forced
- String _saveActiveToolbar; // save active toolbar when forced
-
- bool _saveToolbarZoom; // save visibility when zooming
- bool _zoomUp; // zooming up mode
- bool _zoomDown; // zooming down mode
-
- bool _noDoubleTapRMB; // disable double tap -> rmb click
- bool _rbutton; // double tap -> right button simulation
- bool _closeClick; // flag when taps are spatially close together
-
- bool _usesEmulatedMouse; // emulated mousemove ever been used in this session
-
- bool _canBeAspectScaled; // game screen size allows for aspect scaling
-
- int _scaleFactorXm; // scaler X *
- int _scaleFactorXd; // scaler X /
- int _scaleFactorYm; // scaler Y *
- int _scaleFactorYd; // scaler Y /
- SDL_Rect _dirtyRectOut[NUM_DIRTY_RECT];
- bool _scalersChanged;
- bool _hasfocus; // scummvm has the top window
+ bool _forcePanelInvisible; // force panel visibility for some cases
static int _platformScreenWidth;
static int _platformScreenHeight;
- static bool _isOzone; // true if running on Windows 2003 SE
-
- // Keyboard tap
- int _tapX;
- int _tapY;
- long _tapTime;
-
- // Mouse
- int _mouseHotspotX, _mouseHotspotY;
- byte *_mouseBackupOld;
- uint16 *_mouseBackupToolbar;
- uint16 _mouseBackupDim;
-
- // Smartphone specific variables
-
- int _lastKeyPressed; // last key pressed
- int _keyRepeat; // number of time the last key was repeated
- int _keyRepeatTime; // elapsed time since the key was pressed
- int _keyRepeatTrigger; // minimum time to consider the key was repeated
-
- int _repeatX; // repeat trigger for left and right cursor moves
- int _repeatY; // repeat trigger for up and down cursor moves
- int _stepX1; // offset for left and right cursor moves (slowest)
- int _stepX2; // offset for left and right cursor moves (faster)
- int _stepX3; // offset for left and right cursor moves (fastest)
- int _stepY1; // offset for up and down cursor moves (slowest)
- int _stepY2; // offset for up and down cursor moves (faster)
- int _stepY3; // offset for up and down cursor moves (fastest)
-
- int _mouseXZone[TOTAL_ZONES];
- int _mouseYZone[TOTAL_ZONES];
- int _currentZone;
-
- struct zoneDesc {
- int x;
- int y;
- int width;
- int height;
- };
-
- static zoneDesc _zones[TOTAL_ZONES];
+ static bool _isOzone; // true if running on Windows 2003 SE
+
};
#endif
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 36218376c8..f920dd0170 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -178,6 +178,9 @@ void registerDefaults() {
ConfMan.registerDefault("midi_gain", 100);
// ConfMan.registerDefault("music_driver", ???);
+ ConfMan.registerDefault("mt32_device", "null");
+ ConfMan.registerDefault("gm_device", "null");
+
ConfMan.registerDefault("cdrom", 0);
// Game specific
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index 0561f390a4..c8c0999a25 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -103,9 +103,9 @@ void ConfigManager::loadConfigFile(const String &filename) {
FSNode node(filename);
File cfg_file;
if (!cfg_file.open(node)) {
- debug("Creating configuration file: %s\n", filename.c_str());
+ debug("Creating configuration file: %s", filename.c_str());
} else {
- debug("Using configuration file: %s\n", _filename.c_str());
+ debug("Using configuration file: %s", _filename.c_str());
loadFromStream(cfg_file);
}
}
diff --git a/common/macresman.cpp b/common/macresman.cpp
index 4fd4e72ee3..e7d4a30789 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -550,118 +550,110 @@ void MacResManager::readMap() {
}
}
-void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
- MemoryReadStream dis(data, datasize);
- int i, b;
- byte imageByte;
- byte *iconData;
- int pixelsPerByte, bpp;
- int ctSize;
- byte bitmask;
- int iconRowBytes, iconBounds[4];
- int iconDataSize;
-
- dis.readUint16BE(); // type
- dis.readUint32BE(); // offset to pixel map
- dis.readUint32BE(); // offset to pixel data
- dis.readUint32BE(); // expanded cursor data
- dis.readUint16BE(); // expanded data depth
- dis.readUint32BE(); // reserved
+void MacResManager::convertCrsrCursor(SeekableReadStream *data, byte **cursor, int &w, int &h, int &hotspotX,
+ int &hotspotY, int &keycolor, bool colored, byte **palette, int &palSize) {
+
+ data->readUint16BE(); // type
+ data->readUint32BE(); // offset to pixel map
+ data->readUint32BE(); // offset to pixel data
+ data->readUint32BE(); // expanded cursor data
+ data->readUint16BE(); // expanded data depth
+ data->readUint32BE(); // reserved
// Grab B/W icon data
- *cursor = (byte *)malloc(16 * 16);
- for (i = 0; i < 32; i++) {
- imageByte = dis.readByte();
- for (b = 0; b < 8; b++)
- cursor[0][i*8+b] = (byte)((imageByte & (0x80 >> b)) > 0? 0x0F: 0x00);
+ *cursor = new byte[16 * 16];
+ for (int i = 0; i < 32; i++) {
+ byte imageByte = data->readByte();
+ for (int b = 0; b < 8; b++)
+ cursor[0][i * 8 + b] = (byte)((imageByte & (0x80 >> b)) > 0 ? 0x0F : 0x00);
}
// Apply mask data
- for (i = 0; i < 32; i++) {
- imageByte = dis.readByte();
- for (b = 0; b < 8; b++)
+ for (int i = 0; i < 32; i++) {
+ byte imageByte = data->readByte();
+ for (int b = 0; b < 8; b++)
if ((imageByte & (0x80 >> b)) == 0)
- cursor[0][i*8+b] = 0xff;
+ cursor[0][i * 8 + b] = 0xff;
}
- *hotspot_y = dis.readUint16BE();
- *hotspot_x = dis.readUint16BE();
- *w = *h = 16;
- *keycolor = 0xff;
+ hotspotY = data->readUint16BE();
+ hotspotX = data->readUint16BE();
+ w = h = 16;
+ keycolor = 0xff;
// Use b/w cursor on backends which don't support cursor palettes
if (!colored)
return;
- dis.readUint32BE(); // reserved
- dis.readUint32BE(); // cursorID
+ data->readUint32BE(); // reserved
+ data->readUint32BE(); // cursorID
// Color version of cursor
- dis.readUint32BE(); // baseAddr
+ data->readUint32BE(); // baseAddr
// Keep only lowbyte for now
- dis.readByte();
- iconRowBytes = dis.readByte();
+ data->readByte();
+ int iconRowBytes = data->readByte();
if (!iconRowBytes)
return;
- iconBounds[0] = dis.readUint16BE();
- iconBounds[1] = dis.readUint16BE();
- iconBounds[2] = dis.readUint16BE();
- iconBounds[3] = dis.readUint16BE();
+ int iconBounds[4];
+ iconBounds[0] = data->readUint16BE();
+ iconBounds[1] = data->readUint16BE();
+ iconBounds[2] = data->readUint16BE();
+ iconBounds[3] = data->readUint16BE();
- dis.readUint16BE(); // pmVersion
- dis.readUint16BE(); // packType
- dis.readUint32BE(); // packSize
+ data->readUint16BE(); // pmVersion
+ data->readUint16BE(); // packType
+ data->readUint32BE(); // packSize
- dis.readUint32BE(); // hRes
- dis.readUint32BE(); // vRes
+ data->readUint32BE(); // hRes
+ data->readUint32BE(); // vRes
- dis.readUint16BE(); // pixelType
- dis.readUint16BE(); // pixelSize
- dis.readUint16BE(); // cmpCount
- dis.readUint16BE(); // cmpSize
+ data->readUint16BE(); // pixelType
+ data->readUint16BE(); // pixelSize
+ data->readUint16BE(); // cmpCount
+ data->readUint16BE(); // cmpSize
- dis.readUint32BE(); // planeByte
- dis.readUint32BE(); // pmTable
- dis.readUint32BE(); // reserved
+ data->readUint32BE(); // planeByte
+ data->readUint32BE(); // pmTable
+ data->readUint32BE(); // reserved
// Pixel data for cursor
- iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]);
- iconData = (byte *)malloc(iconDataSize);
- dis.read(iconData, iconDataSize);
+ int iconDataSize = iconRowBytes * (iconBounds[3] - iconBounds[1]);
+ byte *iconData = new byte[iconDataSize];
+ data->read(iconData, iconDataSize);
// Color table
- dis.readUint32BE(); // ctSeed
- dis.readUint16BE(); // ctFlag
- ctSize = dis.readUint16BE() + 1;
+ data->readUint32BE(); // ctSeed
+ data->readUint16BE(); // ctFlag
+ uint16 ctSize = data->readUint16BE() + 1;
- *palette = (byte *)malloc(ctSize * 3);
+ *palette = new byte[ctSize * 3];
// Read just high byte of 16-bit color
for (int c = 0; c < ctSize; c++) {
// We just use indices 0..ctSize, so ignore color ID
- dis.readUint16BE(); // colorID[c]
+ data->readUint16BE(); // colorID[c]
- palette[0][c * 3 + 0] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 0] = data->readByte();
+ data->readByte();
- palette[0][c * 3 + 1] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 1] = data->readByte();
+ data->readByte();
- palette[0][c * 3 + 2] = dis.readByte();
- dis.readByte();
+ palette[0][c * 3 + 2] = data->readByte();
+ data->readByte();
}
- *palSize = ctSize;
+ palSize = ctSize;
- pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
- bpp = 8 / pixelsPerByte;
+ int pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
+ int bpp = 8 / pixelsPerByte;
// build a mask to make sure the pixels are properly shifted out
- bitmask = 0;
+ int bitmask = 0;
for (int m = 0; m < bpp; m++) {
bitmask <<= 1;
bitmask |= 1;
@@ -669,16 +661,16 @@ void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, i
// Extract pixels from bytes
for (int j = 0; j < iconDataSize; j++)
- for (b = 0; b < pixelsPerByte; b++) {
+ for (int b = 0; b < pixelsPerByte; b++) {
int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b);
if (cursor[0][idx] != 0xff) // if mask is not there
cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask);
}
- free(iconData);
+ delete[] iconData;
- assert(datasize - dis.pos() == 0);
+ assert(data->size() - data->pos() == 0);
}
} // End of namespace Common
diff --git a/common/macresman.h b/common/macresman.h
index 1cbebbcf4b..2ad0b608a1 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -154,14 +154,13 @@ public:
/**
* Convert cursor from crsr format to format suitable for feeding to CursorMan
- * @param data Pointer to the cursor data
- * @param datasize Size of the cursor data
+ * @param data Pointer to the cursor datax
* @param cursor Pointer to memory where result cursor will be stored. The memory
* block will be malloc()'ed
* @param w Pointer to int where the cursor width will be stored
* @param h Pointer to int where the cursor height will be stored
- * @param hotspot_x Storage for cursor hotspot X coordinate
- * @param hotspot_Y Storage for cursor hotspot Y coordinate
+ * @param hotspotX Storage for cursor hotspot X coordinate
+ * @param hotspotY Storage for cursor hotspot Y coordinate
* @param keycolor Pointer to int where the transpared color value will be stored
* @param colored If set to true then colored cursor will be returned (if any).
* b/w version will be used otherwise
@@ -169,8 +168,8 @@ public:
* The memory will be malloc()'ed
* @param palSize Pointer to integer where the palette size will be stored.
*/
- static void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize);
+ static void convertCrsrCursor(SeekableReadStream *data, byte **cursor, int &w, int &h, int &hotspotX,
+ int &hotspotY, int &keycolor, bool colored, byte **palette, int &palSize);
/**
* Return list of resource IDs with specified type ID
diff --git a/common/module.mk b/common/module.mk
index a4cea5c23f..a57de6a4b8 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -17,7 +17,6 @@ MODULE_OBJS := \
memorypool.o \
md5.o \
mutex.o \
- ne_exe.o \
random.o \
rational.o \
str.o \
@@ -29,6 +28,9 @@ MODULE_OBJS := \
unarj.o \
unzip.o \
util.o \
+ winexe.o \
+ winexe_ne.o \
+ winexe_pe.o \
xmlparser.o \
zlib.o
diff --git a/common/ne_exe.cpp b/common/ne_exe.cpp
deleted file mode 100644
index 34bb551b06..0000000000
--- a/common/ne_exe.cpp
+++ /dev/null
@@ -1,612 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/debug.h"
-#include "common/file.h"
-#include "common/memstream.h"
-#include "common/ne_exe.h"
-#include "common/str.h"
-#include "common/stream.h"
-
-namespace Common {
-
-NECursor::NECursor() {
- _width = 0;
- _height = 0;
- _hotspotX = 0;
- _hotspotY = 0;
- _surface = 0;
- memset(_palette, 0, 256 * 3);
-}
-
-NECursor::~NECursor() {
- clear();
-}
-
-uint16 NECursor::getWidth() const {
- return _width;
-}
-
-uint16 NECursor::getHeight() const {
- return _height;
-}
-
-uint16 NECursor::getHotspotX() const {
- return _hotspotX;
-}
-
-uint16 NECursor::getHotspotY() const {
- return _hotspotY;
-}
-
-void NECursor::setDimensions(uint16 width, uint16 height) {
- _width = width;
- _height = height;
-}
-
-void NECursor::setHotspot(uint16 x, uint16 y) {
- _hotspotX = x;
- _hotspotY = y;
-}
-
-bool NECursor::readCursor(SeekableReadStream &stream, uint32 count) {
- clear();
-
- SeekableReadStream *bitmap = stream.readStream(count);
- _surface = new byte[_width * _height];
-
- uint32 width = _width;
- uint32 height = _height * 2;
-
- // Sanity checks
- assert((width > 0) && (height > 0));
-
- // Check header size
- if (bitmap->readUint32LE() != 40)
- return false;
-
- // Check dimensions
- if (bitmap->readUint32LE() != width)
- return false;
- if (bitmap->readUint32LE() != height)
- return false;
-
- // Color planes
- if (bitmap->readUint16LE() != 1)
- return false;
- // Bits per pixel
- if (bitmap->readUint16LE() != 1)
- return false;
- // Compression
- if (bitmap->readUint32LE() != 0)
- return false;
-
- // Image size + X resolution + Y resolution
- bitmap->skip(12);
-
- uint32 numColors = bitmap->readUint32LE();
-
- if (numColors == 0)
- numColors = 2;
- else if (numColors > 2)
- return false;
-
- // Assert that enough data is there for the whole cursor
- if ((uint32)bitmap->size() < 40 + numColors * 4 + width * height / 8)
- return false;
-
- // Height includes AND-mask and XOR-mask
- height /= 2;
-
- // Standard palette: transparent, black, white
- _palette[6] = 0xff;
- _palette[7] = 0xff;
- _palette[8] = 0xff;
-
- // Reading the palette
- bitmap->seek(40);
- for (uint32 i = 0 ; i < numColors; i++) {
- _palette[(i + 1) * 3 + 2] = bitmap->readByte();
- _palette[(i + 1) * 3 + 1] = bitmap->readByte();
- _palette[(i + 1) * 3 + 0] = bitmap->readByte();
- bitmap->readByte();
- }
-
- // Reading the bitmap data
- uint32 dataSize = bitmap->size() - 40 - numColors * 4;
- byte *initialSource = new byte[dataSize];
- bitmap->read(initialSource, dataSize);
- const byte *srcP = initialSource;
- const byte *srcM = srcP + ((width * height) / 8);
- byte *dest = _surface + width * (height - 1);
-
- for (uint32 i = 0; i < height; i++) {
- byte *rowDest = dest;
-
- for (uint32 j = 0; j < (width / 8); j++) {
- byte p = srcP[j];
- byte m = srcM[j];
-
- for (int k = 0; k < 8; k++, rowDest++, p <<= 1, m <<= 1) {
- if ((m & 0x80) != 0x80) {
- if ((p & 0x80) == 0x80)
- *rowDest = 2;
- else
- *rowDest = 1;
- } else
- *rowDest = 0;
- }
- }
-
- dest -= width;
- srcP += width / 8;
- srcM += width / 8;
- }
-
- delete bitmap;
- delete[] initialSource;
- return true;
-}
-
-void NECursor::clear() {
- delete[] _surface; _surface = 0;
-}
-
-NEResourceID &NEResourceID::operator=(String string) {
- _name = string;
- _idType = kIDTypeString;
- return *this;
-}
-
-NEResourceID &NEResourceID::operator=(uint16 x) {
- _id = x;
- _idType = kIDTypeNumerical;
- return *this;
-}
-
-bool NEResourceID::operator==(const String &x) const {
- return _idType == kIDTypeString && _name.equalsIgnoreCase(x);
-}
-
-bool NEResourceID::operator==(const uint16 &x) const {
- return _idType == kIDTypeNumerical && _id == x;
-}
-
-bool NEResourceID::operator==(const NEResourceID &x) const {
- if (_idType != x._idType)
- return false;
- if (_idType == kIDTypeString)
- return _name.equalsIgnoreCase(x._name);
- if (_idType == kIDTypeNumerical)
- return _id == x._id;
- return true;
-}
-
-String NEResourceID::getString() const {
- if (_idType != kIDTypeString)
- return "";
-
- return _name;
-}
-
-uint16 NEResourceID::getID() const {
- if (_idType != kIDTypeNumerical)
- return 0xffff;
-
- return _idType;
-}
-
-String NEResourceID::toString() const {
- if (_idType == kIDTypeString)
- return _name;
- else if (_idType == kIDTypeNumerical)
- return String::format("%04x", _id);
-
- return "";
-}
-
-NEResources::NEResources() {
- _exe = 0;
-}
-
-NEResources::~NEResources() {
- clear();
-}
-
-void NEResources::clear() {
- if (_exe) {
- delete _exe;
- _exe = 0;
- }
-
- _resources.clear();
-
- for (uint32 i = 0; i < _cursors.size(); i++)
- for (uint32 j = 0; j < _cursors[i].cursors.size(); j++)
- delete _cursors[i].cursors[j];
-
- _cursors.clear();
-}
-
-const Array<NECursorGroup> &NEResources::getCursors() const {
- return _cursors;
-}
-
-bool NEResources::loadFromEXE(const String &fileName) {
- if (fileName.empty())
- return false;
-
- File *file = new File();
-
- if (!file->open(fileName)) {
- delete file;
- return false;
- }
-
- return loadFromEXE(file);
-}
-
-bool NEResources::loadFromEXE(SeekableReadStream *stream) {
- clear();
-
- if (!stream)
- return false;
-
- _exe = stream;
-
- uint32 offsetResourceTable = getResourceTableOffset();
- if (offsetResourceTable == 0xFFFFFFFF)
- return false;
- if (offsetResourceTable == 0)
- return true;
-
- if (!readResourceTable(offsetResourceTable))
- return false;
-
- if (!readCursors())
- return false;
-
- return true;
-}
-
-bool NEResources::loadFromCompressedEXE(const String &fileName) {
- // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html
-
- File file;
-
- if (!file.open(fileName))
- return false;
-
- // First part of the signature
- if (file.readUint32BE() != MKID_BE('SZDD'))
- return false;
-
- // Second part of the signature
- if (file.readUint32BE() != 0x88F02733)
- return false;
-
- // Compression mode must be 'A'
- if (file.readByte() != 'A')
- return false;
-
- file.readByte(); // file name character change
- uint32 unpackedLength = file.readUint32LE();
-
- byte *window = new byte[0x1000];
- int pos = 0x1000 - 16;
- memset(window, 0x20, 0x1000); // Initialize to all spaces
-
- byte *unpackedData = (byte *)malloc(unpackedLength);
- byte *dataPos = unpackedData;
-
- // Apply simple LZSS decompression
- for (;;) {
- byte controlByte = file.readByte();
-
- if (file.eos())
- break;
-
- for (byte i = 0; i < 8; i++) {
- if (controlByte & (1 << i)) {
- *dataPos++ = window[pos++] = file.readByte();
- pos &= 0xFFF;
- } else {
- int matchPos = file.readByte();
- int matchLen = file.readByte();
- matchPos |= (matchLen & 0xF0) << 4;
- matchLen = (matchLen & 0xF) + 3;
- while (matchLen--) {
- *dataPos++ = window[pos++] = window[matchPos++];
- pos &= 0xFFF;
- matchPos &= 0xFFF;
- }
- }
-
- }
- }
-
- delete[] window;
- SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength);
-
- return loadFromEXE(stream);
-}
-
-uint32 NEResources::getResourceTableOffset() {
- if (!_exe)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(0))
- return 0xFFFFFFFF;
-
- // 'MZ'
- if (_exe->readUint16BE() != 0x4D5A)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(60))
- return 0xFFFFFFFF;
-
- uint32 offsetSegmentEXE = _exe->readUint16LE();
- if (!_exe->seek(offsetSegmentEXE))
- return 0xFFFFFFFF;
-
- // 'NE'
- if (_exe->readUint16BE() != 0x4E45)
- return 0xFFFFFFFF;
-
- if (!_exe->seek(offsetSegmentEXE + 36))
- return 0xFFFFFFFF;
-
- uint32 offsetResourceTable = _exe->readUint16LE();
- if (offsetResourceTable == 0)
- // No resource table
- return 0;
-
- // Offset relative to the segment _exe header
- offsetResourceTable += offsetSegmentEXE;
- if (!_exe->seek(offsetResourceTable))
- return 0xFFFFFFFF;
-
- return offsetResourceTable;
-}
-
-static const char *s_resTypeNames[] = {
- "", "cursor", "bitmap", "icon", "menu", "dialog", "string",
- "font_dir", "font", "accelerator", "rc_data", "msg_table",
- "group_cursor", "group_icon", "version", "dlg_include",
- "plug_play", "vxd", "ani_cursor", "ani_icon", "html",
- "manifest"
-};
-
-bool NEResources::readResourceTable(uint32 offset) {
- if (!_exe)
- return false;
-
- if (!_exe->seek(offset))
- return false;
-
- uint32 align = 1 << _exe->readUint16LE();
-
- uint16 typeID = _exe->readUint16LE();
- while (typeID != 0) {
- uint16 resCount = _exe->readUint16LE();
-
- _exe->skip(4); // reserved
-
- for (int i = 0; i < resCount; i++) {
- Resource res;
-
- // Resource properties
- res.offset = _exe->readUint16LE() * align;
- res.size = _exe->readUint16LE() * align;
- res.flags = _exe->readUint16LE();
- uint16 id = _exe->readUint16LE();
- res.handle = _exe->readUint16LE();
- res.usage = _exe->readUint16LE();
-
- res.type = typeID;
-
- if ((id & 0x8000) == 0)
- res.id = getResourceString(*_exe, offset + id);
- else
- res.id = id & 0x7FFF;
-
- if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames)))
- debug(2, "Found resource %s %s", s_resTypeNames[typeID & 0x7FFF], res.id.toString().c_str());
- else
- debug(2, "Found resource %04x %s", typeID, res.id.toString().c_str());
-
- _resources.push_back(res);
- }
-
- typeID = _exe->readUint16LE();
- }
-
- return true;
-}
-
-String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) {
- uint32 curPos = exe.pos();
-
- if (!exe.seek(offset)) {
- exe.seek(curPos);
- return "";
- }
-
- uint8 length = exe.readByte();
-
- String string;
- for (uint16 i = 0; i < length; i++)
- string += (char)exe.readByte();
-
- exe.seek(curPos);
- return string;
-}
-
-const NEResources::Resource *NEResources::findResource(uint16 type, NEResourceID id) const {
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == type && it->id == id)
- return &*it;
-
- return 0;
-}
-
-SeekableReadStream *NEResources::getResource(uint16 type, NEResourceID id) {
- const Resource *res = findResource(type, id);
-
- if (!res)
- return 0;
-
- _exe->seek(res->offset);
- return _exe->readStream(res->size);
-}
-
-const Array<NEResourceID> NEResources::getIDList(uint16 type) const {
- Array<NEResourceID> idArray;
-
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == type)
- idArray.push_back(it->id);
-
- return idArray;
-}
-
-bool NEResources::readCursors() {
- uint32 cursorCount = 0;
-
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
- if (it->type == kNEGroupCursor)
- cursorCount++;
-
- if (cursorCount == 0) {
- _cursors.clear();
- return true;
- }
-
- _cursors.resize(cursorCount);
-
- Array<NECursorGroup>::iterator cursorGroup = _cursors.begin();
- for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it) {
- if (it->type == kNEGroupCursor) {
- if (!readCursorGroup(*cursorGroup, *it))
- return false;
-
- ++cursorGroup;
- }
- }
-
- return true;
-}
-
-bool NEResources::readCursorGroup(NECursorGroup &group, const Resource &resource) {
- if (!_exe)
- return false;
-
- if (resource.size <= 6)
- return false;
-
- if (!_exe->seek(resource.offset))
- return false;
-
- byte *data = new byte[resource.size];
-
- if (!_exe->read(data, resource.size)) {
- delete[] data;
- return false;
- }
-
- uint32 cursorCount = READ_LE_UINT16(data + 4);
- if (resource.size < (6 + cursorCount * 16)) {
- delete[] data;
- return false;
- }
-
- group.cursors.resize(cursorCount);
-
- uint32 offset = 6;
- for (uint32 i = 0; i < cursorCount; i++) {
- group.cursors[i] = new NECursor();
- NECursor *cursor = group.cursors[i];
-
- // Plane count
- if (READ_LE_UINT16(data + offset + 4) != 1) {
- delete[] data;
- return false;
- }
-
- // Bit count
- if (READ_LE_UINT16(data + offset + 6) != 1) {
- delete[] data;
- return false;
- }
-
- uint32 id = READ_LE_UINT32(data + offset + 12);
- const Resource *cursorResource = findResource(kNECursor, id);
- if (!cursorResource) {
- delete[] data;
- return false;
- }
-
- cursor->setDimensions(READ_LE_UINT16(data + offset), READ_LE_UINT16(data + offset + 2) / 2);
-
- uint32 dataSize = READ_LE_UINT32(data + offset + 8);
- if (!readCursor(*cursor, *cursorResource, dataSize)) {
- delete[] data;
- return false;
- }
-
- offset += 16;
- }
-
- group.id = resource.id;
-
- delete[] data;
- return true;
-}
-
-bool NEResources::readCursor(NECursor &cursor, const Resource &resource, uint32 size) {
- if (!_exe)
- return false;
-
- if (size <= 4)
- return false;
- if (resource.size < size)
- return false;
-
- if (!_exe->seek(resource.offset))
- return false;
-
- uint32 hotspotX = _exe->readUint16LE();
- uint32 hotspotY = _exe->readUint16LE();
- cursor.setHotspot(hotspotX, hotspotY);
-
- size -= 4;
-
- if (!cursor.readCursor(*_exe, size))
- return false;
-
- return true;
-}
-
-} // End of namespace Common
diff --git a/common/winexe.cpp b/common/winexe.cpp
new file mode 100644
index 0000000000..9602e84c88
--- /dev/null
+++ b/common/winexe.cpp
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/str.h"
+#include "common/winexe.h"
+
+namespace Common {
+
+WinResourceID &WinResourceID::operator=(const String &x) {
+ _name = x;
+ _idType = kIDTypeString;
+ return *this;
+}
+
+WinResourceID &WinResourceID::operator=(uint32 x) {
+ _id = x;
+ _idType = kIDTypeNumerical;
+ return *this;
+}
+
+bool WinResourceID::operator==(const String &x) const {
+ return _idType == kIDTypeString && _name.equalsIgnoreCase(x);
+}
+
+bool WinResourceID::operator==(const uint32 &x) const {
+ return _idType == kIDTypeNumerical && _id == x;
+}
+
+bool WinResourceID::operator==(const WinResourceID &x) const {
+ if (_idType != x._idType)
+ return false;
+ if (_idType == kIDTypeString)
+ return _name.equalsIgnoreCase(x._name);
+ if (_idType == kIDTypeNumerical)
+ return _id == x._id;
+ return true;
+}
+
+String WinResourceID::getString() const {
+ if (_idType != kIDTypeString)
+ return "";
+
+ return _name;
+}
+
+uint32 WinResourceID::getID() const {
+ if (_idType != kIDTypeNumerical)
+ return 0xffffffff;
+
+ return _id;
+}
+
+String WinResourceID::toString() const {
+ if (_idType == kIDTypeString)
+ return _name;
+ else if (_idType == kIDTypeNumerical)
+ return String::format("%08x", _id);
+
+ return "";
+}
+
+} // End of namespace Common
diff --git a/common/winexe.h b/common/winexe.h
new file mode 100644
index 0000000000..af0d70c555
--- /dev/null
+++ b/common/winexe.h
@@ -0,0 +1,74 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef COMMON_WINEXE_H
+#define COMMON_WINEXE_H
+
+#include "common/hash-str.h"
+
+namespace Common {
+
+class String;
+
+class WinResourceID {
+public:
+ WinResourceID() { _idType = kIDTypeNull; }
+ WinResourceID(String x) { _idType = kIDTypeString; _name = x; }
+ WinResourceID(uint32 x) { _idType = kIDTypeNumerical; _id = x; }
+
+ WinResourceID &operator=(const String &x);
+ WinResourceID &operator=(uint32 x);
+
+ bool operator==(const String &x) const;
+ bool operator==(const uint32 &x) const;
+ bool operator==(const WinResourceID &x) const;
+
+ String getString() const;
+ uint32 getID() const;
+ String toString() const;
+
+private:
+ /** An ID Type. */
+ enum IDType {
+ kIDTypeNull, ///< No type set
+ kIDTypeNumerical, ///< A numerical ID.
+ kIDTypeString ///< A string ID.
+ } _idType;
+
+ String _name; ///< The resource's string ID.
+ uint32 _id; ///< The resource's numerical ID.
+};
+
+struct WinResourceID_Hash {
+ uint operator()(const WinResourceID &id) const { return hashit(id.toString()); }
+};
+
+struct WinResourceID_EqualTo {
+ bool operator()(const WinResourceID &id1, const WinResourceID &id2) const { return id1 == id2; }
+};
+
+} // End of namespace Common
+
+#endif
diff --git a/common/winexe_ne.cpp b/common/winexe_ne.cpp
new file mode 100644
index 0000000000..24e51f1c9e
--- /dev/null
+++ b/common/winexe_ne.cpp
@@ -0,0 +1,291 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_ne.h"
+
+namespace Common {
+
+NEResources::NEResources() {
+ _exe = 0;
+}
+
+NEResources::~NEResources() {
+ clear();
+}
+
+void NEResources::clear() {
+ if (_exe) {
+ delete _exe;
+ _exe = 0;
+ }
+
+ _resources.clear();
+}
+
+bool NEResources::loadFromEXE(const String &fileName) {
+ if (fileName.empty())
+ return false;
+
+ File *file = new File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ return loadFromEXE(file);
+}
+
+bool NEResources::loadFromEXE(SeekableReadStream *stream) {
+ clear();
+
+ if (!stream)
+ return false;
+
+ _exe = stream;
+
+ uint32 offsetResourceTable = getResourceTableOffset();
+ if (offsetResourceTable == 0xFFFFFFFF)
+ return false;
+ if (offsetResourceTable == 0)
+ return true;
+
+ if (!readResourceTable(offsetResourceTable))
+ return false;
+
+ return true;
+}
+
+bool NEResources::loadFromCompressedEXE(const String &fileName) {
+ // Based on http://www.cabextract.org.uk/libmspack/doc/szdd_kwaj_format.html
+
+ // TODO: Merge this with with loadFromEXE() so the handling of the compressed
+ // EXE's is transparent
+
+ File file;
+
+ if (!file.open(fileName))
+ return false;
+
+ // First part of the signature
+ if (file.readUint32BE() != MKID_BE('SZDD'))
+ return false;
+
+ // Second part of the signature
+ if (file.readUint32BE() != 0x88F02733)
+ return false;
+
+ // Compression mode must be 'A'
+ if (file.readByte() != 'A')
+ return false;
+
+ file.readByte(); // file name character change
+ uint32 unpackedLength = file.readUint32LE();
+
+ byte *window = new byte[0x1000];
+ int pos = 0x1000 - 16;
+ memset(window, 0x20, 0x1000); // Initialize to all spaces
+
+ byte *unpackedData = (byte *)malloc(unpackedLength);
+ assert(unpackedData);
+ byte *dataPos = unpackedData;
+
+ // Apply simple LZSS decompression
+ for (;;) {
+ byte controlByte = file.readByte();
+
+ if (file.eos())
+ break;
+
+ for (byte i = 0; i < 8; i++) {
+ if (controlByte & (1 << i)) {
+ *dataPos++ = window[pos++] = file.readByte();
+ pos &= 0xFFF;
+ } else {
+ int matchPos = file.readByte();
+ int matchLen = file.readByte();
+ matchPos |= (matchLen & 0xF0) << 4;
+ matchLen = (matchLen & 0xF) + 3;
+ while (matchLen--) {
+ *dataPos++ = window[pos++] = window[matchPos++];
+ pos &= 0xFFF;
+ matchPos &= 0xFFF;
+ }
+ }
+
+ }
+ }
+
+ delete[] window;
+ SeekableReadStream *stream = new MemoryReadStream(unpackedData, unpackedLength);
+
+ return loadFromEXE(stream);
+}
+
+uint32 NEResources::getResourceTableOffset() {
+ if (!_exe)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(0))
+ return 0xFFFFFFFF;
+
+ // 'MZ'
+ if (_exe->readUint16BE() != 0x4D5A)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(60))
+ return 0xFFFFFFFF;
+
+ uint32 offsetSegmentEXE = _exe->readUint16LE();
+ if (!_exe->seek(offsetSegmentEXE))
+ return 0xFFFFFFFF;
+
+ // 'NE'
+ if (_exe->readUint16BE() != 0x4E45)
+ return 0xFFFFFFFF;
+
+ if (!_exe->seek(offsetSegmentEXE + 36))
+ return 0xFFFFFFFF;
+
+ uint32 offsetResourceTable = _exe->readUint16LE();
+ if (offsetResourceTable == 0)
+ // No resource table
+ return 0;
+
+ // Offset relative to the segment _exe header
+ offsetResourceTable += offsetSegmentEXE;
+ if (!_exe->seek(offsetResourceTable))
+ return 0xFFFFFFFF;
+
+ return offsetResourceTable;
+}
+
+static const char *s_resTypeNames[] = {
+ "", "cursor", "bitmap", "icon", "menu", "dialog", "string",
+ "font_dir", "font", "accelerator", "rc_data", "msg_table",
+ "group_cursor", "group_icon", "version", "dlg_include",
+ "plug_play", "vxd", "ani_cursor", "ani_icon", "html",
+ "manifest"
+};
+
+bool NEResources::readResourceTable(uint32 offset) {
+ if (!_exe)
+ return false;
+
+ if (!_exe->seek(offset))
+ return false;
+
+ uint32 align = 1 << _exe->readUint16LE();
+
+ uint16 typeID = _exe->readUint16LE();
+ while (typeID != 0) {
+ uint16 resCount = _exe->readUint16LE();
+
+ _exe->skip(4); // reserved
+
+ for (int i = 0; i < resCount; i++) {
+ Resource res;
+
+ // Resource properties
+ res.offset = _exe->readUint16LE() * align;
+ res.size = _exe->readUint16LE() * align;
+ res.flags = _exe->readUint16LE();
+ uint16 id = _exe->readUint16LE();
+ res.handle = _exe->readUint16LE();
+ res.usage = _exe->readUint16LE();
+
+ res.type = typeID;
+
+ if ((id & 0x8000) == 0)
+ res.id = getResourceString(*_exe, offset + id);
+ else
+ res.id = id & 0x7FFF;
+
+ if (typeID & 0x8000 && ((typeID & 0x7FFF) < ARRAYSIZE(s_resTypeNames)))
+ debug(2, "Found resource %s %s", s_resTypeNames[typeID & 0x7FFF], res.id.toString().c_str());
+ else
+ debug(2, "Found resource %04x %s", typeID, res.id.toString().c_str());
+
+ _resources.push_back(res);
+ }
+
+ typeID = _exe->readUint16LE();
+ }
+
+ return true;
+}
+
+String NEResources::getResourceString(SeekableReadStream &exe, uint32 offset) {
+ uint32 curPos = exe.pos();
+
+ if (!exe.seek(offset)) {
+ exe.seek(curPos);
+ return "";
+ }
+
+ uint8 length = exe.readByte();
+
+ String string;
+ for (uint16 i = 0; i < length; i++)
+ string += (char)exe.readByte();
+
+ exe.seek(curPos);
+ return string;
+}
+
+const NEResources::Resource *NEResources::findResource(uint16 type, WinResourceID id) const {
+ for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
+ if (it->type == type && it->id == id)
+ return &*it;
+
+ return 0;
+}
+
+SeekableReadStream *NEResources::getResource(uint16 type, WinResourceID id) {
+ const Resource *res = findResource(type, id);
+
+ if (!res)
+ return 0;
+
+ _exe->seek(res->offset);
+ return _exe->readStream(res->size);
+}
+
+const Array<WinResourceID> NEResources::getIDList(uint16 type) const {
+ Array<WinResourceID> idArray;
+
+ for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
+ if (it->type == type)
+ idArray.push_back(it->id);
+
+ return idArray;
+}
+
+} // End of namespace Common
diff --git a/common/ne_exe.h b/common/winexe_ne.h
index 545c8e5eff..c1d04080ba 100644
--- a/common/ne_exe.h
+++ b/common/winexe_ne.h
@@ -23,11 +23,12 @@
*
*/
-#ifndef COMMON_NE_EXE_H
-#define COMMON_NE_EXE_H
+#ifndef COMMON_WINEXE_NE_H
+#define COMMON_WINEXE_NE_H
#include "common/array.h"
#include "common/list.h"
+#include "common/winexe.h"
namespace Common {
@@ -35,80 +36,6 @@ class MemoryReadStream;
class SeekableReadStream;
class String;
-/** A New Executable cursor. */
-class NECursor {
-public:
- NECursor();
- ~NECursor();
-
- /** Return the cursor's width. */
- uint16 getWidth() const;
- /** Return the cursor's height. */
- uint16 getHeight() const;
- /** Return the cursor's hotspot's x coordinate. */
- uint16 getHotspotX() const;
- /** Return the cursor's hotspot's y coordinate. */
- uint16 getHotspotY() const;
-
- const byte *getSurface() const { return _surface; }
- const byte *getPalette() const { return _palette; }
-
- /** Set the cursor's dimensions. */
- void setDimensions(uint16 width, uint16 height);
- /** Set the cursor's hotspot. */
- void setHotspot(uint16 x, uint16 y);
-
- /** Read the cursor's data out of a stream. */
- bool readCursor(SeekableReadStream &stream, uint32 count);
-
-private:
- byte *_surface;
- byte _palette[256 * 3];
-
- uint16 _width; ///< The cursor's width.
- uint16 _height; ///< The cursor's height.
- uint16 _hotspotX; ///< The cursor's hotspot's x coordinate.
- uint16 _hotspotY; ///< The cursor's hotspot's y coordinate.
-
- /** Clear the cursor. */
- void clear();
-};
-
-class NEResourceID {
-public:
- NEResourceID() { _idType = kIDTypeNull; }
- NEResourceID(String x) { _idType = kIDTypeString; _name = x; }
- NEResourceID(uint16 x) { _idType = kIDTypeNumerical; _id = x; }
-
- NEResourceID &operator=(String string);
- NEResourceID &operator=(uint16 x);
-
- bool operator==(const String &x) const;
- bool operator==(const uint16 &x) const;
- bool operator==(const NEResourceID &x) const;
-
- String getString() const;
- uint16 getID() const;
- String toString() const;
-
-private:
- /** An ID Type. */
- enum IDType {
- kIDTypeNull, ///< No type set
- kIDTypeNumerical, ///< A numerical ID.
- kIDTypeString ///< A string ID.
- } _idType;
-
- String _name; ///< The resource's string ID.
- uint16 _id; ///< The resource's numerical ID.
-};
-
-/** A New Executable cursor group. */
-struct NECursorGroup {
- NEResourceID id;
- Array<NECursor *> cursors; ///< The cursors.
-};
-
/** The default Windows resources. */
enum NEResourceType {
kNECursor = 0x8001,
@@ -157,19 +84,16 @@ public:
/** Load from a stream. */
bool loadFromEXE(SeekableReadStream *stream);
- /** Get all cursor's read from the New Executable. */
- const Array<NECursorGroup> &getCursors() const;
-
/** Return a list of resources for a given type. */
- const Array<NEResourceID> getIDList(uint16 type) const;
+ const Array<WinResourceID> getIDList(uint16 type) const;
/** Return a stream to the specified resource (or 0 if non-existent). */
- SeekableReadStream *getResource(uint16 type, NEResourceID id);
+ SeekableReadStream *getResource(uint16 type, WinResourceID id);
private:
/** A resource. */
struct Resource {
- NEResourceID id;
+ WinResourceID id;
uint16 type; ///< Type of the resource.
@@ -186,21 +110,13 @@ private:
/** All resources. */
List<Resource> _resources;
- /** All cursor resources. */
- Array<NECursorGroup> _cursors;
-
/** Read the offset to the resource table. */
uint32 getResourceTableOffset();
/** Read the resource table. */
bool readResourceTable(uint32 offset);
- // Cursor reading helpers
- bool readCursors();
- bool readCursorGroup(NECursorGroup &group, const Resource &resource);
- bool readCursor(NECursor &cursor, const Resource &resource, uint32 size);
-
/** Find a specific resource. */
- const Resource *findResource(uint16 type, NEResourceID id) const;
+ const Resource *findResource(uint16 type, WinResourceID id) const;
/** Read a resource string. */
static String getResourceString(SeekableReadStream &exe, uint32 offset);
@@ -208,4 +124,4 @@ private:
} // End of namespace Common
-#endif // COMMON_NE_EXE_H
+#endif
diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp
new file mode 100644
index 0000000000..456093f5b4
--- /dev/null
+++ b/common/winexe_pe.cpp
@@ -0,0 +1,255 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_pe.h"
+
+namespace Common {
+
+PEResources::PEResources() {
+ _exe = 0;
+}
+
+PEResources::~PEResources() {
+ clear();
+}
+
+void PEResources::clear() {
+ _sections.clear();
+ _resources.clear();
+ delete _exe; _exe = 0;
+}
+
+bool PEResources::loadFromEXE(const String &fileName) {
+ if (fileName.empty())
+ return false;
+
+ File *file = new File();
+
+ if (!file->open(fileName)) {
+ delete file;
+ return false;
+ }
+
+ return loadFromEXE(file);
+}
+
+bool PEResources::loadFromEXE(SeekableReadStream *stream) {
+ clear();
+
+ if (!stream)
+ return false;
+
+ if (stream->readUint16BE() != 'MZ')
+ return false;
+
+ stream->skip(58);
+
+ uint32 peOffset = stream->readUint32LE();
+
+ if (!peOffset || peOffset >= (uint32)stream->size())
+ return false;
+
+ stream->seek(peOffset);
+
+ if (stream->readUint32BE() != MKID_BE('PE\0\0'))
+ return false;
+
+ stream->skip(2);
+ uint16 sectionCount = stream->readUint16LE();
+ stream->skip(12);
+ uint16 optionalHeaderSize = stream->readUint16LE();
+ stream->skip(optionalHeaderSize + 2);
+
+ // Read in all the sections
+ for (uint16 i = 0; i < sectionCount; i++) {
+ char sectionName[9];
+ stream->read(sectionName, 8);
+ sectionName[8] = 0;
+
+ Section section;
+ stream->skip(4);
+ section.virtualAddress = stream->readUint32LE();
+ section.size = stream->readUint32LE();
+ section.offset = stream->readUint32LE();
+ stream->skip(16);
+
+ _sections[sectionName] = section;
+ }
+
+ // Currently, we require loading a resource section
+ if (!_sections.contains(".rsrc")) {
+ clear();
+ return false;
+ }
+
+ _exe = stream;
+
+ Section &resSection = _sections[".rsrc"];
+ parseResourceLevel(resSection, resSection.offset, 0);
+
+ return true;
+}
+
+void PEResources::parseResourceLevel(Section &section, uint32 offset, int level) {
+ _exe->seek(offset + 12);
+
+ uint16 namedEntryCount = _exe->readUint16LE();
+ uint16 intEntryCount = _exe->readUint16LE();
+
+ for (uint32 i = 0; i < namedEntryCount + intEntryCount; i++) {
+ uint32 value = _exe->readUint32LE();
+
+ WinResourceID id;
+
+ if (value & 0x80000000) {
+ value &= 0x7fffffff;
+
+ uint32 startPos = _exe->pos();
+ _exe->seek(section.offset + (value & 0x7fffffff));
+
+ // Read in the name, truncating from unicode to ascii
+ Common::String name;
+ uint16 nameLength = _exe->readUint16LE();
+ while (nameLength--)
+ name += (char)(_exe->readUint16LE() & 0xff);
+
+ _exe->seek(startPos);
+
+ id = name;
+ } else {
+ id = value;
+ }
+
+ uint32 nextOffset = _exe->readUint32LE();
+ uint32 lastOffset = _exe->pos();
+
+ if (level == 0)
+ _curType = id;
+ else if (level == 1)
+ _curName = id;
+ else if (level == 2)
+ _curLang = id;
+
+ if (level < 2) {
+ // Time to dive down further
+ parseResourceLevel(section, section.offset + (nextOffset & 0x7fffffff), level + 1);
+ } else {
+ _exe->seek(section.offset + nextOffset);
+
+ Resource resource;
+ resource.offset = _exe->readUint32LE() + section.offset - section.virtualAddress;
+ resource.size = _exe->readUint32LE();
+
+ debug(4, "Found resource '%s' '%s' '%s' at %d of size %d", _curType.toString().c_str(),
+ _curName.toString().c_str(), _curLang.toString().c_str(), resource.offset, resource.size);
+
+ _resources[_curType][_curName][_curLang] = resource;
+ }
+
+ _exe->seek(lastOffset);
+ }
+}
+
+const Array<WinResourceID> PEResources::getTypeList() const {
+ Array<WinResourceID> array;
+
+ if (!_exe)
+ return array;
+
+ for (TypeMap::const_iterator it = _resources.begin(); it != _resources.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+const Array<WinResourceID> PEResources::getNameList(const WinResourceID &type) const {
+ Array<WinResourceID> array;
+
+ if (!_exe || !_resources.contains(type))
+ return array;
+
+ const NameMap &nameMap = _resources[type];
+
+ for (NameMap::const_iterator it = nameMap.begin(); it != nameMap.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+const Array<WinResourceID> PEResources::getLangList(const WinResourceID &type, const WinResourceID &name) const {
+ Array<WinResourceID> array;
+
+ if (!_exe || !_resources.contains(type))
+ return array;
+
+ const NameMap &nameMap = _resources[type];
+
+ if (!nameMap.contains(name))
+ return array;
+
+ const LangMap &langMap = nameMap[name];
+
+ for (LangMap::const_iterator it = langMap.begin(); it != langMap.end(); it++)
+ array.push_back(it->_key);
+
+ return array;
+}
+
+SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name) {
+ Array<WinResourceID> langList = getLangList(type, name);
+
+ if (langList.empty())
+ return 0;
+
+ const Resource &resource = _resources[type][name][langList[0]];
+ _exe->seek(resource.offset);
+ return _exe->readStream(resource.size);
+}
+
+SeekableReadStream *PEResources::getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang) {
+ if (!_exe || !_resources.contains(type))
+ return 0;
+
+ const NameMap &nameMap = _resources[type];
+
+ if (!nameMap.contains(name))
+ return 0;
+
+ const LangMap &langMap = nameMap[name];
+
+ if (!langMap.contains(lang))
+ return 0;
+
+ const Resource &resource = langMap[lang];
+ _exe->seek(resource.offset);
+ return _exe->readStream(resource.size);
+}
+
+} // End of namespace Common
diff --git a/common/winexe_pe.h b/common/winexe_pe.h
new file mode 100644
index 0000000000..5298e993ad
--- /dev/null
+++ b/common/winexe_pe.h
@@ -0,0 +1,122 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef COMMON_WINEXE_PE_H
+#define COMMON_WINEXE_PE_H
+
+#include "common/array.h"
+#include "common/hashmap.h"
+#include "common/winexe.h"
+
+namespace Common {
+
+class SeekableReadStream;
+class String;
+
+/** The default Windows PE resources. */
+enum PEResourceType {
+ kPECursor = 0x01,
+ kPEBitmap = 0x02,
+ kPEIcon = 0x03,
+ kPEMenu = 0x04,
+ kPEDialog = 0x05,
+ kPEString = 0x06,
+ kPEFontDir = 0x07,
+ kPEFont = 0x08,
+ kPEAccelerator = 0x09,
+ kPERCData = 0x0A,
+ kPEMessageTable = 0x0B,
+ kPEGroupCursor = 0x0C,
+ kPEGroupIcon = 0x0E,
+ kPEVersion = 0x10,
+ kPEDlgInclude = 0x11,
+ kPEPlugPlay = 0x13,
+ kPEVXD = 0x14,
+ kPEAniCursor = 0x15,
+ kPEAniIcon = 0x16
+};
+
+/**
+ * A class able to load resources from a Windows Portable Executable, such
+ * as cursors, bitmaps, and sounds.
+ */
+class PEResources {
+public:
+ PEResources();
+ ~PEResources();
+
+ /** Clear all information. */
+ void clear();
+
+ /** Load from an EXE file. */
+ bool loadFromEXE(const String &fileName);
+
+ /** Load from a stream. */
+ bool loadFromEXE(SeekableReadStream *stream);
+
+ /** Return a list of resource types. */
+ const Array<WinResourceID> getTypeList() const;
+
+ /** Return a list of names for a given type. */
+ const Array<WinResourceID> getNameList(const WinResourceID &type) const;
+
+ /** Return a list of languages for a given type and name. */
+ const Array<WinResourceID> getLangList(const WinResourceID &type, const WinResourceID &name) const;
+
+ /** Return a stream to the specified resource, taking the first language found (or 0 if non-existent). */
+ SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name);
+
+ /** Return a stream to the specified resource (or 0 if non-existent). */
+ SeekableReadStream *getResource(const WinResourceID &type, const WinResourceID &name, const WinResourceID &lang);
+
+private:
+ struct Section {
+ uint32 virtualAddress;
+ uint32 size;
+ uint32 offset;
+ };
+
+ HashMap<String, Section, IgnoreCase_Hash, IgnoreCase_EqualTo> _sections;
+
+ SeekableReadStream *_exe;
+
+ void parseResourceLevel(Section &section, uint32 offset, int level);
+ WinResourceID _curType, _curName, _curLang;
+
+ struct Resource {
+ uint32 offset;
+ uint32 size;
+ };
+
+ typedef HashMap<WinResourceID, Resource, WinResourceID_Hash, WinResourceID_EqualTo> LangMap;
+ typedef HashMap<WinResourceID, LangMap, WinResourceID_Hash, WinResourceID_EqualTo> NameMap;
+ typedef HashMap<WinResourceID, NameMap, WinResourceID_Hash, WinResourceID_EqualTo> TypeMap;
+
+ TypeMap _resources;
+};
+
+} // End of namespace Common
+
+#endif
diff --git a/configure b/configure
index 5c291dd560..eeafe93966 100755
--- a/configure
+++ b/configure
@@ -976,7 +976,7 @@ get_system_exe_extension $guessed_host
NATIVEEXEEXT=$_exeext
case $_host in
-android)
+android | android-v7a)
_host_os=android
_host_cpu=arm
_host_alias=arm-linux-androideabi
@@ -1504,15 +1504,23 @@ case $_host_os in
add_line_to_config_mk 'AMIGAOS = 1'
;;
android)
+ case $_host in
+ android)
+ CXXFLAGS="$CXXFLAGS -march=armv5te -mtune=xscale -msoft-float"
+ ;;
+ android-v7a)
+ CXXFLAGS="$CXXFLAGS -march=armv7-a -mfloat-abi=softfp -mfpu=vfp"
+ LDFLAGS="$LDFLAGS -Wl,--fix-cortex-a8"
+ ;;
+ esac
CXXFLAGS="$CXXFLAGS --sysroot=$ANDROID_NDK/platforms/android-4/arch-arm"
- CXXFLAGS="$CXXFLAGS -march=armv5te -mtune=xscale -msoft-float"
CXXFLAGS="$CXXFLAGS -fpic -ffunction-sections -funwind-tables"
- if test "$_release_build" = yes; then
- CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -fstrict-aliasing"
+ if test "$_debug_build" = yes; then
+ CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer -fno-strict-aliasing"
else
- CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer -fno-strict-aliasing"
+ CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -fstrict-aliasing"
fi
- CXXFLAGS="$CXXFLAGS -finline-limit=300"
+ CXXFLAGS="$CXXFLAGS -finline-limit=300"
CXXFLAGS="$CXXFLAGS -Os -mthumb-interwork"
CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__"
CXXFLAGS="$CXXFLAGS -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__"
@@ -1559,8 +1567,8 @@ case $_host_os in
CXXFLAGS="$CXXFLAGS -fuse-cxa-atexit"
LDFLAGS="$LDFLAGS -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt"
if test "$_dynamic_modules" = no ; then
- LDFLAGS="$LDFLAGS -Wl,--gc-sections"
- else
+ LDFLAGS="$LDFLAGS -Wl,--gc-sections"
+ else
LDFLAGS="$LDFLAGS -Wl,--no-gc-sections"
# TODO automate this required 2 step linking phase
# LDFLAGS="$LDFLAGS -Wl,--retain-symbols-file,ds.syms"
@@ -1653,7 +1661,7 @@ case $_host_os in
fi
;;
wince)
- CXXFLAGS="$CXXFLAGS -O3 -march=armv4 -mtune=xscale"
+ CXXFLAGS="$CXXFLAGS -O3 -fno-inline-functions -march=armv4 -mtune=xscale"
DEFINES="$DEFINES -D_WIN32_WCE=300 -D__ARM__ -D_ARM_ -DUNICODE -DFPM_DEFAULT -DNONSTANDARD_PORT"
DEFINES="$DEFINES -DWIN32 -Dcdecl= -D__cdecl__="
;;
@@ -1668,7 +1676,7 @@ if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed
echo "Cross-compiling to $_host"
case "$_host" in
- android)
+ android | android-v7a)
_unix=yes
_need_memalign=yes
# we link a .so as default
@@ -2104,7 +2112,7 @@ fi
# Enable 16bit support only for backends which support it
#
case $_backend in
- dingux | dreamcast | gph | openpandora | psp | samsungtv | sdl | wii)
+ android | dingux | dreamcast | gph | openpandora | psp | samsungtv | sdl | wii)
if test "$_16bit" = auto ; then
_16bit=yes
else
@@ -2965,7 +2973,12 @@ fi
case $_backend in
android)
# ssp at this point so the cxxtests link
- CXXFLAGS="$CXXFLAGS -fstack-protector -Wa,--noexecstack"
+ if test "$_debug_build" = yes; then
+ CXXFLAGS="$CXXFLAGS -fstack-protector"
+ else
+ CXXFLAGS="$CXXFLAGS -fno-stack-protector"
+ fi
+ CXXFLAGS="$CXXFLAGS -Wa,--noexecstack"
LDFLAGS="$LDFLAGS -Wl,-z,noexecstack"
static_libs=''
@@ -3052,8 +3065,8 @@ case $_backend in
DEFINES="$DEFINES -D_EE -DFORCE_RTL"
INCLUDES="$INCLUDES -I$PS2SDK/ee/include -I$PS2SDK/common/include -I$PS2SDK/ports/include"
if test "$_dynamic_modules" = no ; then
- LDFLAGS="$LDFLAGS -mno-crt0 $PS2SDK/ee/startup/crt0.o -T $PS2SDK/ee/startup/linkfile"
- fi
+ LDFLAGS="$LDFLAGS -mno-crt0 $PS2SDK/ee/startup/crt0.o -T $PS2SDK/ee/startup/linkfile"
+ fi
LDFLAGS="$LDFLAGS -L$PS2SDK/ee/lib -L$PS2SDK/ports/lib"
LIBS="$LIBS -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lm -lc -lfileXio -lkernel -lstdc++ "
;;
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index 2ea2b484ac..68c58d9aea 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -1,58 +1,61 @@
-<?xml version="1.0" encoding="utf-8"?> <!-- -*- xml -*- -->
+<?xml version="1.0" encoding="utf-8"?>
<!-- NB: android:versionCode needs to be bumped for formal releases -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.inodes.gus.scummvm"
- android:versionCode="6" android:versionName="1.3.0git"
- android:installLocation="preferExternal">
-
- <!-- This version works on Android 1.5 (SDK 3) and newer, but we
- want Android 2.2 (SDK 8) defaults and features.
- -->
- <uses-sdk android:minSdkVersion="3"
- android:targetSdkVersion="8" />
-
- <application android:name=".ScummVMApplication"
- android:label="@string/app_name"
- android:description="@string/app_desc"
- android:icon="@drawable/scummvm"
- android:persistent="true">
- <activity android:name=".ScummVMActivity"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:screenOrientation="landscape"
- android:configChanges="orientation|keyboardHidden"
- android:windowSoftInputMode="adjustResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
- <activity android:name=".Unpacker"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:screenOrientation="landscape"
- android:configChanges="orientation|keyboardHidden">
- <meta-data android:name="org.inodes.gus.unpacker.nextActivity"
- android:value="org.inodes.gus.scummvm/.ScummVMActivity" />
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-
- <permission android:name="org.inodes.gus.scummvm.permission.SCUMMVM_PLUGIN"
- android:label="@string/scummvm_perm_plugin_label"
- android:description="@string/scummvm_perm_plugin_desc"
- android:protectionLevel="signature" />
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-
- <!-- Always needs some sort of qwerty keyboard.
- Can work with a D-pad / trackball -->
- <uses-configuration android:reqFiveWayNav="true"
- android:reqKeyboardType="qwerty"/>
- <!-- .. or touchscreen -->
- <uses-configuration android:reqTouchScreen="finger"
- android:reqKeyboardType="qwerty"/>
- <uses-configuration android:reqTouchScreen="stylus"
- android:reqKeyboardType="qwerty"/>
+ package="org.inodes.gus.scummvm"
+ android:versionCode="6"
+ android:versionName="1.3.0git"
+ android:installLocation="preferExternal">
+
+ <!-- This version works on Android 1.5 (SDK 3) and newer, but we
+ want Android 2.2 (SDK 8) defaults and features. -->
+ <uses-sdk android:minSdkVersion="3"
+ android:targetSdkVersion="8"/>
+
+ <application android:name=".ScummVMApplication"
+ android:label="@string/app_name"
+ android:description="@string/app_desc"
+ android:icon="@drawable/scummvm">
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden"
+ android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".Unpacker"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden">
+ <meta-data android:name="org.inodes.gus.unpacker.nextActivity"
+ android:value="org.inodes.gus.scummvm/.ScummVMActivity"/>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <permission android:name="org.inodes.gus.scummvm.permission.SCUMMVM_PLUGIN"
+ android:label="@string/scummvm_perm_plugin_label"
+ android:description="@string/scummvm_perm_plugin_desc"
+ android:protectionLevel="signature"/>
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <!-- Always needs some sort of qwerty keyboard.
+ Can work with a D-pad / trackball -->
+ <uses-configuration android:reqFiveWayNav="true"
+ android:reqKeyboardType="qwerty"/>
+
+ <!-- .. or touchscreen -->
+ <uses-configuration android:reqTouchScreen="finger"
+ android:reqKeyboardType="qwerty"/>
+
+ <uses-configuration android:reqTouchScreen="stylus"
+ android:reqKeyboardType="qwerty"/>
</manifest>
+
diff --git a/dists/android/AndroidManifest.xml.in b/dists/android/AndroidManifest.xml.in
index 26a94f957b..7a75b6fd0b 100644
--- a/dists/android/AndroidManifest.xml.in
+++ b/dists/android/AndroidManifest.xml.in
@@ -1,58 +1,61 @@
-<?xml version="1.0" encoding="utf-8"?> <!-- -*- xml -*- -->
+<?xml version="1.0" encoding="utf-8"?>
<!-- NB: android:versionCode needs to be bumped for formal releases -->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.inodes.gus.scummvm"
- android:versionCode="6" android:versionName="@VERSION@"
- android:installLocation="preferExternal">
-
- <!-- This version works on Android 1.5 (SDK 3) and newer, but we
- want Android 2.2 (SDK 8) defaults and features.
- -->
- <uses-sdk android:minSdkVersion="3"
- android:targetSdkVersion="8" />
-
- <application android:name=".ScummVMApplication"
- android:label="@string/app_name"
- android:description="@string/app_desc"
- android:icon="@drawable/scummvm"
- android:persistent="true">
- <activity android:name=".ScummVMActivity"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:screenOrientation="landscape"
- android:configChanges="orientation|keyboardHidden"
- android:windowSoftInputMode="adjustResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
- <activity android:name=".Unpacker"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:screenOrientation="landscape"
- android:configChanges="orientation|keyboardHidden">
- <meta-data android:name="org.inodes.gus.unpacker.nextActivity"
- android:value="org.inodes.gus.scummvm/.ScummVMActivity" />
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-
- <permission android:name="org.inodes.gus.scummvm.permission.SCUMMVM_PLUGIN"
- android:label="@string/scummvm_perm_plugin_label"
- android:description="@string/scummvm_perm_plugin_desc"
- android:protectionLevel="signature" />
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-
- <!-- Always needs some sort of qwerty keyboard.
- Can work with a D-pad / trackball -->
- <uses-configuration android:reqFiveWayNav="true"
- android:reqKeyboardType="qwerty"/>
- <!-- .. or touchscreen -->
- <uses-configuration android:reqTouchScreen="finger"
- android:reqKeyboardType="qwerty"/>
- <uses-configuration android:reqTouchScreen="stylus"
- android:reqKeyboardType="qwerty"/>
+ package="org.inodes.gus.scummvm"
+ android:versionCode="6"
+ android:versionName="@VERSION@"
+ android:installLocation="preferExternal">
+
+ <!-- This version works on Android 1.5 (SDK 3) and newer, but we
+ want Android 2.2 (SDK 8) defaults and features. -->
+ <uses-sdk android:minSdkVersion="3"
+ android:targetSdkVersion="8"/>
+
+ <application android:name=".ScummVMApplication"
+ android:label="@string/app_name"
+ android:description="@string/app_desc"
+ android:icon="@drawable/scummvm">
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden"
+ android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".Unpacker"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|keyboardHidden">
+ <meta-data android:name="org.inodes.gus.unpacker.nextActivity"
+ android:value="org.inodes.gus.scummvm/.ScummVMActivity"/>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <permission android:name="org.inodes.gus.scummvm.permission.SCUMMVM_PLUGIN"
+ android:label="@string/scummvm_perm_plugin_label"
+ android:description="@string/scummvm_perm_plugin_desc"
+ android:protectionLevel="signature"/>
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+ <!-- Always needs some sort of qwerty keyboard.
+ Can work with a D-pad / trackball -->
+ <uses-configuration android:reqFiveWayNav="true"
+ android:reqKeyboardType="qwerty"/>
+
+ <!-- .. or touchscreen -->
+ <uses-configuration android:reqTouchScreen="finger"
+ android:reqKeyboardType="qwerty"/>
+
+ <uses-configuration android:reqTouchScreen="stylus"
+ android:reqKeyboardType="qwerty"/>
</manifest>
+
diff --git a/dists/android/res/layout/main.xml b/dists/android/res/layout/main.xml
index f5276ce41b..b6164edc96 100644
--- a/dists/android/res/layout/main.xml
+++ b/dists/android/res/layout/main.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
+
<org.inodes.gus.scummvm.EditableSurfaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:id="@+id/main_surface"
- android:gravity="center"
- android:keepScreenOn="true"
- android:focusable="true"
- android:focusableInTouchMode="true"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_surface"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:keepScreenOn="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
/>
+
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index 34e1ff2ed8..61981b30c5 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -7,21 +7,21 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico"
#endif
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,3,0,0
- PRODUCTVERSION 1,3,0,0
- FILEFLAGSMASK 0x3fL
+ FILEVERSION 1,3,0,0
+ PRODUCTVERSION 1,3,0,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS VS_FF_DEBUG
#else
- FILEFLAGS 0x0L
+ FILEFLAGS 0
#endif
- FILEOS 0x40004L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
- BLOCK "040904b0"
+ BLOCK "040904b0" // US English, Unicode
BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
VALUE "FileDescription", "http://www.scummvm.org/\0"
@@ -34,8 +34,9 @@ BEGIN
VALUE "ProductVersion", "1.3.0git\0"
END
END
+
BLOCK "VarFileInfo"
BEGIN
- VALUE "Translation", 0x409, 1200
+ VALUE "Translation", 0x409, 1200 // US English, Unicode
END
END
diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in
index 17415f3d12..a0fcf82dbb 100644
--- a/dists/scummvm.rc.in
+++ b/dists/scummvm.rc.in
@@ -7,21 +7,21 @@ IDI_ICON ICON DISCARDABLE "../../icons/scummvm.ico"
#endif
VS_VERSION_INFO VERSIONINFO
- FILEVERSION @VER_MAJOR@,@VER_MINOR@,@VER_PATCH@,0
- PRODUCTVERSION @VER_MAJOR@,@VER_MINOR@,@VER_PATCH@,0
- FILEFLAGSMASK 0x3fL
+ FILEVERSION @VER_MAJOR@,@VER_MINOR@,@VER_PATCH@,0
+ PRODUCTVERSION @VER_MAJOR@,@VER_MINOR@,@VER_PATCH@,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
- FILEFLAGS 0x1L
+ FILEFLAGS VS_FF_DEBUG
#else
- FILEFLAGS 0x0L
+ FILEFLAGS 0
#endif
- FILEOS 0x40004L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
- BLOCK "040904b0"
+ BLOCK "040904b0" // US English, Unicode
BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
VALUE "FileDescription", "http://www.scummvm.org/\0"
@@ -34,8 +34,9 @@ BEGIN
VALUE "ProductVersion", "@VERSION@\0"
END
END
+
BLOCK "VarFileInfo"
BEGIN
- VALUE "Translation", 0x409, 1200
+ VALUE "Translation", 0x409, 1200 // US English, Unicode
END
END
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index fdc05f0ba9..632587f7f7 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -273,23 +273,16 @@ void AgiEngine::processEvents() {
}
void AgiEngine::pollTimer() {
- uint32 dm;
+ _lastTick += 50;
- if (_tickTimer < _lastTickTimer)
- _lastTickTimer = 0;
-
- while ((dm = _tickTimer - _lastTickTimer) < 5) {
+ while (_system->getMillis() < _lastTick) {
processEvents();
_console->onFrame();
_system->delayMillis(10);
_system->updateScreen();
}
- _lastTickTimer = _tickTimer;
-}
-void AgiEngine::agiTimerFunctionLow(void *refCon) {
- AgiEngine *self = (AgiEngine *)refCon;
- self->_tickTimer++;
+ _lastTick = _system->getMillis();
}
void AgiEngine::pause(uint32 msec) {
@@ -361,12 +354,12 @@ int AgiEngine::agiInit() {
switch (getVersion() >> 12) {
case 2:
- debug("Emulating Sierra AGI v%x.%03x\n",
+ debug("Emulating Sierra AGI v%x.%03x",
(int)(getVersion() >> 12) & 0xF,
(int)(getVersion()) & 0xFFF);
break;
case 3:
- debug("Emulating Sierra AGI v%x.002.%03x\n",
+ debug("Emulating Sierra AGI v%x.002.%03x",
(int)(getVersion() >> 12) & 0xF,
(int)(getVersion()) & 0xFFF);
break;
@@ -532,9 +525,6 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_allowSynthetic = false;
- _tickTimer = 0;
- _lastTickTimer = 0;
-
_intobj = NULL;
_menu = NULL;
@@ -646,11 +636,10 @@ void AgiEngine::initialize() {
_lastSaveTime = 0;
- _timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, this);
+ _lastTick = _system->getMillis();
debugC(2, kDebugLevelMain, "Detect game");
-
if (agiDetectGame() == errOK) {
_game.state = STATE_LOADED;
debugC(2, kDebugLevelMain, "game loaded");
@@ -662,8 +651,6 @@ void AgiEngine::initialize() {
}
AgiEngine::~AgiEngine() {
- _timer->removeTimerProc(agiTimerFunctionLow);
-
// If the engine hasn't been initialized yet via AgiEngine::initialize(), don't attempt to free any resources,
// as they haven't been allocated. Fixes bug #1742432 - AGI: Engine crashes if no game is detected
if (_game.state == STATE_INIT) {
@@ -719,7 +706,7 @@ void AgiEngine::parseFeatures() {
/* FIXME: Seems this method doesn't really do anything. It might
be a leftover that could be removed, except that some of its
intended purpose may still need to be reimplemented.
-
+
[0:29] <Fingolfin> can you tell me what the point behind AgiEngine::parseFeatures() is?
[0:30] <_sev> when games are created with WAGI studio
[0:31] <_sev> it creates .wag site with game-specific features such as full game title, whether to use AGIMOUSE etc
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 89b116daec..df19f55b52 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -810,9 +810,7 @@ public:
Common::Error saveGameState(int slot, const char *desc);
private:
-
- uint32 _tickTimer;
- uint32 _lastTickTimer;
+ uint32 _lastTick;
int _keyQueue[KEY_QUEUE_SIZE];
int _keyQueueStart;
@@ -883,7 +881,6 @@ public:
virtual bool isKeypress();
virtual void clearKeyQueue();
- static void agiTimerFunctionLow(void *refCon);
void initPriTable();
void newInputMode(InputMode mode);
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index 711701f55a..fb1b830e24 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -569,6 +569,7 @@ static const AGIGameDescription gameDescriptions[] = {
GAME_PS("xmascard", "", "25ad35e9628fc77e5e0dd35852a272b6", 768, 0x2440, GID_XMASCARD, Common::kPlatformCoCo3),
FANMADE_F("2 Player Demo", "4279f46b3cebd855132496476b1d2cca", GF_AGIMOUSE),
+ FANMADE("AGI Combat", "0be6a8a9e19203dcca0067d280798871"),
FANMADE("AGI Contest 1 Template", "d879aed25da6fc655564b29567358ae2"),
FANMADE("AGI Contest 2 Template", "5a2fb2894207eff36c72f5c1b08bcc07"),
FANMADE("AGI Mouse Demo 0.60 demo 1", "c07e2519de674c67386cb2cc6f2e3904"),
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index fe864d7659..1aa6ef5cc4 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -122,9 +122,6 @@ void PreAgiEngine::initialize() {
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
_speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- //_timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, NULL);
-
debugC(2, kDebugLevelMain, "Detect game");
// clear all resources and events
diff --git a/engines/agos/agos.h b/engines/agos/agos.h
index 7201dfd9d3..9c2a2929e3 100644
--- a/engines/agos/agos.h
+++ b/engines/agos/agos.h
@@ -2018,7 +2018,7 @@ protected:
void scrollOracleUp();
void scrollOracleDown();
- void listSaveGames(int n);
+ void listSaveGamesFeeble();
void saveUserGame(int slot);
void windowBackSpace(WindowBlock *window);
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index d39ca377dc..10d3d7f1ff 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -368,7 +368,7 @@ void MoviePlayerDXA::handleNextFrame() {
bool MoviePlayerDXA::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
- copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
+ copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch);
_vm->_system->unlockScreen();
Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000);
@@ -482,7 +482,7 @@ void MoviePlayerSMK::nextFrame() {
bool MoviePlayerSMK::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
- copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
+ copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch);
_vm->_system->unlockScreen();
uint32 waitTime = getTimeToNextFrame();
diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp
index 0a4ab8246f..8ff79965e4 100644
--- a/engines/agos/oracle.cpp
+++ b/engines/agos/oracle.cpp
@@ -369,7 +369,7 @@ void AGOSEngine_Feeble::swapCharacterLogo() {
}
}
-void AGOSEngine_Feeble::listSaveGames(int n) {
+void AGOSEngine_Feeble::listSaveGamesFeeble() {
char b[108];
Common::InSaveFile *in;
uint16 j, k, z, maxFiles;
@@ -377,8 +377,8 @@ void AGOSEngine_Feeble::listSaveGames(int n) {
memset(b, 0, 108);
maxFiles = countSaveGames() - 1;
- j = maxFiles - n + 1;
- k = maxFiles - j + 1;
+ j = maxFiles;
+ k = 1;
z = maxFiles;
if (getBitFlag(95)) {
j++;
diff --git a/engines/agos/script_ff.cpp b/engines/agos/script_ff.cpp
index 3198b1b499..dbd89cebf5 100644
--- a/engines/agos/script_ff.cpp
+++ b/engines/agos/script_ff.cpp
@@ -430,8 +430,7 @@ void AGOSEngine_Feeble::off_loadUserGame() {
}
void AGOSEngine_Feeble::off_listSaveGames() {
- // 134: dummy opcode?
- listSaveGames(1);
+ listSaveGamesFeeble();
}
void AGOSEngine_Feeble::off_checkCD() {
diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp
index ab1ad7ff9c..9ee3a892a9 100644
--- a/engines/cine/script_os.cpp
+++ b/engines/cine/script_os.cpp
@@ -124,7 +124,7 @@ void OSScript::setupTable() {
{ 0, 0 },
{ &FWScript::o2_loadPart, "s" },
/* 40 */
- { 0, 0 }, /* o1_closePart, triggered by some scripts (STARTA.PRC 4 for ex.) */
+ { &FWScript::o1_closePart, "" },
{ &FWScript::o1_loadNewPrcName, "bs" },
{ &FWScript::o1_requestCheckPendingDataLoad, "" },
{ 0, 0 },
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index e84e80ccd3..b59ab6f566 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -512,7 +512,7 @@ bool DrasculaEngine::runCurrentChapter() {
checkObjects();
#ifdef _WIN32_WCE
- if (rightMouseButton)
+ if (rightMouseButton) {
if (_menuScreen) {
#else
if (rightMouseButton == 1 && _menuScreen) {
@@ -570,6 +570,9 @@ bool DrasculaEngine::runCurrentChapter() {
#endif
selectVerb(kVerbNone);
}
+#ifdef _WIN32_WCE
+ }
+#endif
if (leftMouseButton == 1 && _menuBar) {
delay(100);
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 0d92c1aef1..d773f370f5 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -145,7 +145,11 @@ void initCommonGFX(bool defaultTo1XScaler) {
assert(transientDomain);
const bool useDefaultGraphicsMode =
- !transientDomain->contains("gfx_mode") &&
+ (!transientDomain->contains("gfx_mode") ||
+ !scumm_stricmp(transientDomain->getVal("gfx_mode").c_str(), "normal") ||
+ !scumm_stricmp(transientDomain->getVal("gfx_mode").c_str(), "default")
+ )
+ &&
(
!gameDomain ||
!gameDomain->contains("gfx_mode") ||
@@ -155,10 +159,7 @@ void initCommonGFX(bool defaultTo1XScaler) {
// See if the game should default to 1x scaler
if (useDefaultGraphicsMode && defaultTo1XScaler) {
- // FIXME: As a hack, we use "1x" here. Would be nicer to use
- // getDefaultGraphicsMode() instead, but right now, we do not specify
- // whether that is a 1x scaler or not...
- g_system->setGraphicsMode("1x");
+ g_system->resetGraphicsScale();
} else {
// Override global scaler with any game-specific define
if (ConfMan.hasKey("gfx_mode")) {
diff --git a/engines/gob/save/saveload.h b/engines/gob/save/saveload.h
index c231c1dbbb..dc1c184504 100644
--- a/engines/gob/save/saveload.h
+++ b/engines/gob/save/saveload.h
@@ -305,7 +305,7 @@ protected:
int getSlot(int32 offset) const;
int getSlotRemainder(int32 offset) const;
- void buildIndex(byte *buffer) const;
+ void buildScreenshotIndex(byte *buffer) const;
protected:
uint32 _shotSize;
@@ -430,7 +430,7 @@ protected:
int getSlot(int32 offset) const;
int getSlotRemainder(int32 offset) const;
- void buildIndex(byte *buffer) const;
+ void buildScreenshotIndex(byte *buffer) const;
};
File *_file;
diff --git a/engines/gob/save/saveload_inca2.cpp b/engines/gob/save/saveload_inca2.cpp
index 68c76c3f2b..5fa1b69fa7 100644
--- a/engines/gob/save/saveload_inca2.cpp
+++ b/engines/gob/save/saveload_inca2.cpp
@@ -260,7 +260,7 @@ int SaveLoad_Inca2::ScreenshotHandler::File::getSlotRemainder(int32 offset) cons
return (offset - 80) % 15168;
}
-void SaveLoad_Inca2::ScreenshotHandler::File::buildIndex(byte *buffer) const {
+void SaveLoad_Inca2::ScreenshotHandler::File::buildScreenshotIndex(byte *buffer) const {
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *in;
@@ -306,7 +306,7 @@ bool SaveLoad_Inca2::ScreenshotHandler::load(int16 dataVar, int32 size, int32 of
}
// Create/Fake the index
- _file->buildIndex(_index + 40);
+ _file->buildScreenshotIndex(_index + 40);
_vm->_inter->_variables->copyFrom(dataVar, _index + offset, size);
diff --git a/engines/gob/save/saveload_v3.cpp b/engines/gob/save/saveload_v3.cpp
index 098b8e1160..39edddb66f 100644
--- a/engines/gob/save/saveload_v3.cpp
+++ b/engines/gob/save/saveload_v3.cpp
@@ -367,7 +367,7 @@ int SaveLoad_v3::ScreenshotHandler::File::getSlotRemainder(int32 offset) const {
return ((offset - _shotIndexSize) % _shotSize);
}
-void SaveLoad_v3::ScreenshotHandler::File::buildIndex(byte *buffer) const {
+void SaveLoad_v3::ScreenshotHandler::File::buildScreenshotIndex(byte *buffer) const {
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *in;
@@ -418,12 +418,12 @@ bool SaveLoad_v3::ScreenshotHandler::load(int16 dataVar, int32 size, int32 offse
if (_sShotType == kScreenshotTypeGob3) {
// Create/Fake the index
- _file->buildIndex(_index + 40);
+ _file->buildScreenshotIndex(_index + 40);
// The last 10 bytes are 0
memset(_index + 70, 0, 10);
} else if (_sShotType == kScreenshotTypeLost) {
// Create/Fake the index
- _file->buildIndex(_index);
+ _file->buildScreenshotIndex(_index);
// The last byte is 0
_index[30] = 0;
}
diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp
index f0977aa45b..8850a727d3 100644
--- a/engines/gob/sound/bgatmosphere.cpp
+++ b/engines/gob/sound/bgatmosphere.cpp
@@ -47,7 +47,7 @@ BackgroundAtmosphere::~BackgroundAtmosphere() {
queueClear();
}
-void BackgroundAtmosphere::play() {
+void BackgroundAtmosphere::playBA() {
Common::StackLock slock(_mutex);
_queuePos = -1;
@@ -59,7 +59,7 @@ void BackgroundAtmosphere::play() {
SoundMixer::play(*_queue[_queuePos], 1, 0);
}
-void BackgroundAtmosphere::stop() {
+void BackgroundAtmosphere::stopBA() {
SoundMixer::stop(0);
}
diff --git a/engines/gob/sound/bgatmosphere.h b/engines/gob/sound/bgatmosphere.h
index 71a2263341..7e58c0b4e9 100644
--- a/engines/gob/sound/bgatmosphere.h
+++ b/engines/gob/sound/bgatmosphere.h
@@ -46,8 +46,8 @@ public:
BackgroundAtmosphere(Audio::Mixer &mixer);
~BackgroundAtmosphere();
- void play();
- void stop();
+ void playBA();
+ void stopBA();
void setPlayMode(PlayMode mode);
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 5950388c28..1aa63eb940 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -648,7 +648,7 @@ void Sound::bgPlay(const char *file, SoundType type) {
debugC(1, kDebugSound, "BackgroundAtmosphere: Playing \"%s\"", file);
- _bgatmos->stop();
+ _bgatmos->stopBA();
_bgatmos->queueClear();
SoundDesc *sndDesc = new SoundDesc;
@@ -658,7 +658,7 @@ void Sound::bgPlay(const char *file, SoundType type) {
}
_bgatmos->queueSample(*sndDesc);
- _bgatmos->play();
+ _bgatmos->playBA();
}
void Sound::bgPlay(const char *base, const char *ext, SoundType type, int count) {
@@ -667,7 +667,7 @@ void Sound::bgPlay(const char *base, const char *ext, SoundType type, int count)
debugC(1, kDebugSound, "BackgroundAtmosphere: Playing \"%s\" (%d)", base, count);
- _bgatmos->stop();
+ _bgatmos->stopBA();
_bgatmos->queueClear();
int length = strlen(base) + 7;
@@ -684,7 +684,7 @@ void Sound::bgPlay(const char *base, const char *ext, SoundType type, int count)
delete sndDesc;
}
- _bgatmos->play();
+ _bgatmos->playBA();
}
void Sound::bgStop() {
@@ -693,7 +693,7 @@ void Sound::bgStop() {
debugC(1, kDebugSound, "BackgroundAtmosphere: Stopping playback");
- _bgatmos->stop();
+ _bgatmos->stopBA();
_bgatmos->queueClear();
}
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index 74bb6f98e5..5974559c53 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -94,14 +94,14 @@ public:
~MusicPlayerMidi();
// MidiDriver interface
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length);
- void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
- uint32 getBaseTempo();
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel();
+ virtual int open();
+ virtual void close();
+ virtual void send(uint32 b);
+ virtual void metaEvent(byte type, byte *data, uint16 length);
+ virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+ virtual uint32 getBaseTempo();
+ virtual MidiChannel *allocateChannel();
+ virtual MidiChannel *getPercussionChannel();
private:
// Channel volumes
@@ -115,7 +115,7 @@ protected:
MidiParser *_midiParser;
MidiDriver *_driver;
- void onTimerInternal();
+ virtual void onTimerInternal();
void updateVolume();
void unload();
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index c99db2433f..e862e339ce 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -292,6 +292,11 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s
desc.setSaveTime(hour, minutes);
+ // Slot 0 is used for the 'restart game' save in all Hugo games, thus
+ // we prevent it from being deleted.
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+
delete file;
return desc;
}
diff --git a/engines/hugo/menu.cpp b/engines/hugo/dialogs.cpp
index 428a3e096a..ead432c5df 100644
--- a/engines/hugo/menu.cpp
+++ b/engines/hugo/dialogs.cpp
@@ -196,8 +196,6 @@ void TopMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 d
case kCmdLoad:
close();
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- _vm->getGameStatus().viewState = kViewPlay;
break;
case kCmdRecall:
close();
@@ -232,4 +230,33 @@ void TopMenu::handleMouseUp(int x, int y, int button, int clickCount) {
Dialog::handleMouseUp(x, y, button, clickCount);
}
+EntryDialog::EntryDialog(const Common::String &title, const Common::String &buttonLabel, const Common::String &defaultValue) : GUI::Dialog(20, 20, 100, 50) {
+ new GUI::StaticTextWidget(this, 0, 0, 10, 10, title, Graphics::kTextAlignCenter);
+
+ _text = new GUI::EditTextWidget(this, 0, 0, 50, 10, "");
+ _text->setEditString(defaultValue);
+
+ new GUI::ButtonWidget(this, 20, 20, 30, 10, buttonLabel, 0, kCmdButton);
+}
+
+EntryDialog::~EntryDialog() {
+}
+
+void EntryDialog::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 data) {
+ switch (command) {
+ case kCmdButton:
+ close();
+ break;
+ default:
+ Dialog::handleCommand(sender, command, data);
+ }
+}
+
+void EntryDialog::reflowLayout() {
+}
+
+void EntryDialog::init() {
+}
+
+
} // End of namespace Hugo
diff --git a/engines/hugo/menu.h b/engines/hugo/dialogs.h
index 6e2a9063bc..1ef196a708 100644
--- a/engines/hugo/menu.h
+++ b/engines/hugo/dialogs.h
@@ -23,10 +23,11 @@
*
*/
-#ifndef HUGO_TOPMENU_H
-#define HUGO_TOPMENU_H
+#ifndef HUGO_DIALOGS_H
+#define HUGO_DIALOGS_H
#include "gui/dialog.h"
+#include "gui/widgets/edittext.h"
namespace Hugo {
@@ -54,6 +55,7 @@ enum {
};
enum {
+ // TopMenu commands
kCmdWhat = 'WHAT',
kCmdMusic = 'MUZK',
kCmdSoundFX = 'SOUN',
@@ -62,7 +64,10 @@ enum {
kCmdRecall = 'RECL',
kCmdTurbo = 'TURB',
kCmdLook = 'LOOK',
- kCmdInvent = 'INVT'
+ kCmdInvent = 'INVT',
+
+ // EntryDialog commands
+ kCmdButton = 'BTNP'
};
class TopMenu : public GUI::Dialog {
@@ -95,6 +100,21 @@ protected:
uint16 arraySize;
};
+class EntryDialog : public GUI::Dialog {
+ EntryDialog(const Common::String &title, const Common::String &buttonLabel, const Common::String &defaultValue);
+ virtual ~EntryDialog();
+
+ void reflowLayout();
+ void handleCommand(GUI::CommandSender *sender, uint32 command, uint32 data);
+
+ const Common::String &getEditString() const { return _text->getEditString(); }
+
+protected:
+ void init();
+
+ GUI::EditTextWidget *_text;
+};
+
}
-#endif // HUGO_TOPMENU_H
+#endif // HUGO_DIALOGS_H
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index 0210eb8f04..aa4d4384c1 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -189,13 +189,13 @@ void Screen::displayRect(const int16 x, const int16 y, const int16 dx, const int
* Alse save the new color in the current palette.
*/
void Screen::remapPal(const uint16 oldIndex, const uint16 newIndex) {
- debugC(1, kDebugDisplay, "Remap_pal(%d, %d)", oldIndex, newIndex);
+ debugC(1, kDebugDisplay, "RemapPal(%d, %d)", oldIndex, newIndex);
_curPalette[3 * oldIndex + 0] = _mainPalette[newIndex * 3 + 0];
_curPalette[3 * oldIndex + 1] = _mainPalette[newIndex * 3 + 1];
_curPalette[3 * oldIndex + 2] = _mainPalette[newIndex * 3 + 2];
- g_system->getPaletteManager()->setPalette(_curPalette, oldIndex, 1);
+ g_system->getPaletteManager()->setPalette(_curPalette, 0, _paletteSize / 3);
}
/**
@@ -214,10 +214,10 @@ void Screen::savePal(Common::WriteStream *f) const {
void Screen::restorePal(Common::ReadStream *f) {
debugC(1, kDebugDisplay, "restorePal()");
- for (int i = 0; i < _paletteSize; i++) {
+ for (int i = 0; i < _paletteSize; i++)
_curPalette[i] = f->readByte();
- g_system->getPaletteManager()->setPalette(_curPalette, i, 1);
- }
+
+ g_system->getPaletteManager()->setPalette(_curPalette, 0, _paletteSize / 3);
}
@@ -233,24 +233,6 @@ void Screen::setBackgroundColor(const uint16 color) {
}
/**
- * Return the overlay state (Foreground/Background) of the currently
- * processed object by looking down the current column for an overlay
- * base bit set (in which case the object is foreground).
- */
-overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
- debugC(4, kDebugDisplay, "findOvl()");
-
- for (; y < seq_p->lines; y++) { // Each line in object
- byte ovb = _vm->_object->getBaseBoundary((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits
- if (ovb & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set
- return kOvlForeground; // Found a bit - must be foreground
- dst_p += kXPix;
- }
-
- return kOvlBackground; // No bits set, must be background
-}
-
-/**
* Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
* If fore TRUE, force object above any overlay
*/
@@ -261,7 +243,7 @@ void Screen::displayFrame(const int sx, const int sy, seq_t *seq, const bool for
image_pt subFrontBuffer = &_frontBuffer[sy * kXPix + sx]; // Ptr to offset in _frontBuffer
int16 frontBufferwrap = kXPix - seq->x2 - 1; // Wraps dest_p after each line
int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1;
- overlayState_t overlayState = kOvlUndef; // Overlay state of object
+ overlayState_t overlayState = (foreFl) ? kOvlForeground : kOvlUndef; // Overlay state of object
for (uint16 y = 0; y < seq->lines; y++) { // Each line in object
for (uint16 x = 0; x <= seq->x2; x++) {
if (*image) { // Non-transparent
@@ -269,7 +251,7 @@ void Screen::displayFrame(const int sx, const int sy, seq_t *seq, const bool for
if (ovlBound & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
if (overlayState == kOvlUndef) // Overlay defined yet?
overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
- if (foreFl || overlayState == kOvlForeground) // Object foreground
+ if (overlayState == kOvlForeground) // Object foreground
*subFrontBuffer = *image; // Copy pixel
} else { // No overlay
*subFrontBuffer = *image; // Copy pixel
@@ -740,6 +722,25 @@ void Screen_v1d::loadFontArr(Common::ReadStream &in) {
}
}
+/**
+ * Return the overlay state (Foreground/Background) of the currently
+ * processed object by looking down the current column for an overlay
+ * base byte set (in which case the object is foreground).
+ */
+overlayState_t Screen_v1d::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
+ debugC(4, kDebugDisplay, "findOvl()");
+
+ uint16 index = (uint16)(dst_p - _frontBuffer) >> 3;
+
+ for (int i = 0; i < seq_p->lines-y; i++) { // Each line in object
+ if (_vm->_object->getBaseBoundary(index)) // If any overlay base byte is non-zero then the object is foreground, else back.
+ return kOvlForeground;
+ index += kCompLineSize;
+ }
+
+ return kOvlBackground; // No bits set, must be background
+}
+
Screen_v1w::Screen_v1w(HugoEngine *vm) : Screen(vm) {
}
@@ -790,5 +791,23 @@ void Screen_v1w::loadFontArr(Common::ReadStream &in) {
}
}
+/**
+ * Return the overlay state (Foreground/Background) of the currently
+ * processed object by looking down the current column for an overlay
+ * base bit set (in which case the object is foreground).
+ */
+overlayState_t Screen_v1w::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
+ debugC(4, kDebugDisplay, "findOvl()");
+
+ for (; y < seq_p->lines; y++) { // Each line in object
+ byte ovb = _vm->_object->getBaseBoundary((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits
+ if (ovb & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set
+ return kOvlForeground; // Found a bit - must be foreground
+ dst_p += kXPix;
+ }
+
+ return kOvlBackground; // No bits set, must be background
+}
+
} // End of namespace Hugo
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index f234f76019..91e1752df0 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -101,10 +101,6 @@ protected:
static const byte stdMouseCursorHeight = 20;
static const byte stdMouseCursorWidth = 12;
- inline bool isInX(const int16 x, const rect_t *rect) const;
- inline bool isInY(const int16 y, const rect_t *rect) const;
- inline bool isOverlapping(const rect_t *rectA, const rect_t *rectB) const;
-
bool fontLoadedFl[kNumFonts];
// Fonts used in dib (non-GDI)
@@ -115,6 +111,14 @@ protected:
byte *_mainPalette;
int16 _arrayFontSize[kNumFonts];
+ viewdib_t _frontBuffer;
+
+ inline bool isInX(const int16 x, const rect_t *rect) const;
+ inline bool isInY(const int16 y, const rect_t *rect) const;
+ inline bool isOverlapping(const rect_t *rectA, const rect_t *rectB) const;
+
+ virtual overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) = 0;
+
private:
byte *_curPalette;
byte _iconImage[kInvDx * kInvDy];
@@ -125,9 +129,6 @@ private:
int16 mergeLists(rect_t *list, rect_t *blist, const int16 len, int16 blen);
int16 center(const char *s) const;
- overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y);
-
- viewdib_t _frontBuffer;
viewdib_t _backBuffer;
viewdib_t _GUIBuffer; // User interface images
viewdib_t _backBufferBackup; // Backup _backBuffer during inventory
@@ -151,6 +152,8 @@ public:
void loadFont(int16 fontId);
void loadFontArr(Common::ReadStream &in);
+protected:
+ overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y);
};
class Screen_v1w : public Screen {
@@ -160,6 +163,8 @@ public:
void loadFont(int16 fontId);
void loadFontArr(Common::ReadStream &in);
+protected:
+ overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y);
};
} // End of namespace Hugo
diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp
index 740513d7b2..94e1756a0d 100644
--- a/engines/hugo/file.cpp
+++ b/engines/hugo/file.cpp
@@ -411,6 +411,8 @@ bool FileManager::saveGame(const int16 slot, const Common::String &descrip) {
out->writeSint16BE(_vm->_maze.x4);
out->writeByte(_vm->_maze.firstScreenIndex);
+ out->writeByte((byte)_vm->getGameStatus().viewState);
+
out->finalize();
delete out;
@@ -507,6 +509,11 @@ bool FileManager::restoreGame(const int16 slot) {
_vm->_maze.x4 = in->readSint16BE();
_vm->_maze.firstScreenIndex = in->readByte();
+ _vm->_scheduler->restoreScreen(*_vm->_screen_p);
+ if ((_vm->getGameStatus().viewState = (vstate_t) in->readByte()) != kViewPlay)
+ _vm->_screen->hideCursor();
+
+
delete in;
return true;
}
@@ -563,6 +570,8 @@ void FileManager::readBootFile() {
if (_vm->_gameVariant == kGameVariantH1Dos) {
//TODO initialize properly _boot structure
warning("readBootFile - Skipping as H1 Dos may be a freeware");
+ memset(_vm->_boot.distrib, '\0', sizeof(_vm->_boot.distrib));
+ _vm->_boot.registered = kRegFreeware;
return;
} else {
error("Missing startup file");
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index 2143b8cfde..231b2a5d51 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -28,6 +28,7 @@
#include "common/events.h"
#include "common/EventRecorder.h"
#include "common/debug-channels.h"
+#include "common/config-manager.h"
#include "hugo/hugo.h"
#include "hugo/game.h"
@@ -253,14 +254,20 @@ Common::Error HugoEngine::run() {
// Start the state machine
_status.viewState = kViewIntroInit;
-
_status.doQuitFl = false;
+ int16 loadSlot = Common::ConfigManager::instance().getInt("save_slot");
+ if (loadSlot >= 0) {
+ _status.skipIntroFl = true;
+ _file->restoreGame(loadSlot);
+ } else {
+ _file->saveGame(0, "New Game");
+ }
while (!_status.doQuitFl) {
_screen->drawBoundaries();
-
g_system->updateScreen();
runMachine();
+
// Handle input
Common::Event event;
while (_eventMan->pollEvent(event)) {
@@ -285,6 +292,7 @@ Common::Error HugoEngine::run() {
break;
}
}
+
_mouse->mouseHandler(); // Mouse activity - adds to display list
_screen->displayList(kDisplayDisplay); // Blit the display list to screen
_status.doQuitFl |= shouldQuit(); // update game quit flag
@@ -623,6 +631,13 @@ void HugoEngine::readScreenFiles(const int screenNum) {
_file->readBackground(screenNum); // Scenery file
memcpy(_screen->getBackBuffer(), _screen->getFrontBuffer(), sizeof(_screen->getFrontBuffer())); // Make a copy
+
+ // Workaround for graphic glitches in DOS versions. Cleaning the overlays fix the problem
+ memset(_object->_objBound, '\0', sizeof(overlay_t));
+ memset(_object->_boundary, '\0', sizeof(overlay_t));
+ memset(_object->_overlay, '\0', sizeof(overlay_t));
+ memset(_object->_ovlBase, '\0', sizeof(overlay_t));
+
_file->readOverlay(screenNum, _object->_boundary, kOvlBoundary); // Boundary file
_file->readOverlay(screenNum, _object->_overlay, kOvlOverlay); // Overlay file
_file->readOverlay(screenNum, _object->_ovlBase, kOvlBase); // Overlay base file
@@ -658,7 +673,7 @@ void HugoEngine::calcMaxScore() {
void HugoEngine::endGame() {
debugC(1, kDebugEngine, "endGame");
- if (!_boot.registered)
+ if (_boot.registered != kRegRegistered)
Utils::Box(kBoxAny, "%s", _text->getTextEngine(kEsAdvertise));
Utils::Box(kBoxAny, "%s\n%s", _episode, getCopyrightString());
_status.viewState = kViewExit;
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index b2739c829e..a137df786f 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -29,7 +29,7 @@
#include "engines/engine.h"
#include "common/file.h"
#include "hugo/console.h"
-#include "hugo/menu.h"
+#include "hugo/dialogs.h"
// This include is here temporarily while the engine is being refactored.
#include "hugo/game.h"
@@ -58,7 +58,7 @@ class RandomSource;
*/
namespace Hugo {
-static const int kSavegameVersion = 3;
+static const int kSavegameVersion = 6;
static const int kInvDx = 32; // Width of an inventory icon
static const int kInvDy = 32; // Height of inventory icon
static const int kMaxTunes = 16; // Max number of tunes
@@ -125,6 +125,12 @@ enum HugoDebugChannels {
kDebugMusic = 1 << 9
};
+enum HugoRegistered {
+ kRegShareware = 0,
+ kRegRegistered,
+ kRegFreeware
+};
+
/**
* Ways to dismiss a text/prompt box
*/
@@ -242,7 +248,6 @@ public:
object_t *_hero;
byte *_screen_p;
byte _heroImage;
-
byte *_screenStates;
command_t _line; // Line of user text input
config_t _config; // User's config
diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp
index 689dfbfd7c..7551476300 100644
--- a/engines/hugo/intro.cpp
+++ b/engines/hugo/intro.cpp
@@ -119,15 +119,19 @@ bool intro_v1d::introPlay() {
error("Unable to load font TMSRB.FON, face 'Tms Rmn', size 8");
char buffer[80];
- if (_vm->_boot.registered)
+ if (_vm->_boot.registered == kRegRegistered)
strcpy(buffer, "Registered Version");
- else
+ else if (_vm->_boot.registered == kRegShareware)
strcpy(buffer, "Shareware Version");
+ else if (_vm->_boot.registered == kRegFreeware)
+ strcpy(buffer, "Freeware Version");
+ else
+ error("Unknown registration flag in hugo.bsf: %d", _vm->_boot.registered);
font.drawString(&surf, buffer, 0, 163, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter);
font.drawString(&surf, _vm->getCopyrightString(), 0, 176, 320, _TLIGHTMAGENTA, Graphics::kTextAlignCenter);
- if (scumm_stricmp(_vm->_boot.distrib, "David P. Gray")) {
+ if ((*_vm->_boot.distrib != '\0') && (scumm_stricmp(_vm->_boot.distrib, "David P. Gray"))) {
sprintf(buffer, "Distributed by %s.", _vm->_boot.distrib);
font.drawString(&surf, buffer, 0, 75, 320, _TMAGENTA, Graphics::kTextAlignCenter);
}
diff --git a/engines/hugo/module.mk b/engines/hugo/module.mk
index 3a1ceded73..2ded997437 100644
--- a/engines/hugo/module.mk
+++ b/engines/hugo/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/hugo
MODULE_OBJS := \
console.o \
detection.o \
+ dialogs.o \
display.o \
file.o \
file_v1d.o \
@@ -13,7 +14,6 @@ MODULE_OBJS := \
hugo.o \
intro.o \
inventory.o \
- menu.o \
mouse.o \
object.o \
object_v1d.o \
diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp
index 04e3449cbb..f82a6a53c6 100644
--- a/engines/hugo/object.cpp
+++ b/engines/hugo/object.cpp
@@ -418,20 +418,25 @@ void ObjectHandler::readUse(Common::ReadStream &in, uses_t &curUse) {
*/
void ObjectHandler::loadObjectUses(Common::ReadStream &in) {
uses_t tmpUse;
+ tmpUse.targets = 0;
+
//Read _uses
for (int varnt = 0; varnt < _vm->_numVariant; varnt++) {
- tmpUse.targets = 0;
uint16 numElem = in.readUint16BE();
if (varnt == _vm->_gameVariant) {
_usesSize = numElem;
_uses = (uses_t *)malloc(sizeof(uses_t) * numElem);
}
- for (int i = 0; i < numElem; i++)
- readUse(in, (varnt == _vm->_gameVariant) ? _uses[i] : tmpUse);
-
- if (tmpUse.targets)
- free(tmpUse.targets);
+ for (int i = 0; i < numElem; i++) {
+ if (varnt == _vm->_gameVariant)
+ readUse(in, _uses[i]);
+ else {
+ readUse(in, tmpUse);
+ free(tmpUse.targets);
+ tmpUse.targets = 0;
+ }
+ }
}
}
@@ -497,20 +502,26 @@ void ObjectHandler::readObject(Common::ReadStream &in, object_t &curObject) {
void ObjectHandler::loadObjectArr(Common::ReadStream &in) {
debugC(6, kDebugObject, "loadObject(&in)");
object_t tmpObject;
+ tmpObject.stateDataIndex = 0;
for (int varnt = 0; varnt < _vm->_numVariant; varnt++) {
uint16 numElem = in.readUint16BE();
- tmpObject.stateDataIndex = 0;
+
if (varnt == _vm->_gameVariant) {
_objCount = numElem;
_objects = (object_t *)malloc(sizeof(object_t) * numElem);
}
- for (int i = 0; i < numElem; i++)
- readObject(in, (varnt == _vm->_gameVariant) ? _objects[i] : tmpObject);
-
- if (tmpObject.stateDataIndex)
- free(tmpObject.stateDataIndex);
+ for (int i = 0; i < numElem; i++) {
+ if (varnt == _vm->_gameVariant)
+ readObject(in, _objects[i]);
+ else {
+ // Skip over uneeded objects.
+ readObject(in, tmpObject);
+ free(tmpObject.stateDataIndex);
+ tmpObject.stateDataIndex = 0;
+ }
+ }
}
}
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index c845e03eee..a0a3ee3350 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -286,11 +286,10 @@ void Parser::keyHandler(Common::Event event) {
break;
case Common::KEYCODE_l:
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
break;
case Common::KEYCODE_n:
- warning("STUB: CTRL-N (WIN) - New Game");
+ if (Utils::Box(kBoxYesNo, "%s", "Are you sure you want to start a new game?") != 0)
+ _vm->_file->restoreGame(0);
break;
case Common::KEYCODE_s:
if (gameStatus.viewState == kViewPlay) {
@@ -360,8 +359,6 @@ void Parser::keyHandler(Common::Event event) {
break;
case Common::KEYCODE_F5: // Restore game
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
break;
case Common::KEYCODE_F6: // Inventory
showInventory();
diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp
index 424ca66b38..df3a73feb8 100644
--- a/engines/hugo/parser_v1d.cpp
+++ b/engines/hugo/parser_v1d.cpp
@@ -380,8 +380,6 @@ void Parser_v1d::lineHandler() {
if (!strcmp("restore", _vm->_line)) {
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
return;
}
diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp
index 5d901e8ffe..d3424274f8 100644
--- a/engines/hugo/parser_v1w.cpp
+++ b/engines/hugo/parser_v1w.cpp
@@ -132,8 +132,6 @@ void Parser_v1w::lineHandler() {
if (!strcmp("restore", _vm->_line) && (gameStatus.viewState == kViewPlay || gameStatus.viewState == kViewIdle)) {
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
return;
}
diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp
index 580d78100d..d19b8b1091 100644
--- a/engines/hugo/parser_v2d.cpp
+++ b/engines/hugo/parser_v2d.cpp
@@ -132,8 +132,6 @@ void Parser_v2d::lineHandler() {
if (!strcmp("restore", _vm->_line)) {
_vm->_config.soundFl = false;
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
return;
}
diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp
index b3d0125d20..fcd937808b 100644
--- a/engines/hugo/parser_v3d.cpp
+++ b/engines/hugo/parser_v3d.cpp
@@ -134,8 +134,6 @@ void Parser_v3d::lineHandler() {
if (!strcmp("restore", _vm->_line)) {
_vm->_config.soundFl = false;
_vm->_file->restoreGame(-1);
- _vm->_scheduler->restoreScreen(*_vm->_screen_p);
- gameStatus.viewState = kViewPlay;
return;
}
diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp
index 5843c2317e..1556f3a154 100644
--- a/engines/hugo/schedule.cpp
+++ b/engines/hugo/schedule.cpp
@@ -708,21 +708,19 @@ void Scheduler::saveEvents(Common::WriteStream *f) {
f->writeSint16BE(tailIndex);
// Convert event ptrs to indexes
- event_t saveEventArr[kMaxEvents]; // Convert event ptrs to indexes
for (int16 i = 0; i < kMaxEvents; i++) {
event_t *wrkEvent = &_events[i];
- saveEventArr[i] = *wrkEvent;
- // fix up action pointer (to do better)
+ // fix up action pointer (to do better)
int16 index, subElem;
- findAction(saveEventArr[i].action, &index, &subElem);
- saveEventArr[i].action = (act*)((index << 16)| subElem);
-
- saveEventArr[i].prevEvent = (wrkEvent->prevEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
- saveEventArr[i].nextEvent = (wrkEvent->nextEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->nextEvent - _events);
+ findAction(wrkEvent->action, &index, &subElem);
+ f->writeSint16BE(index);
+ f->writeSint16BE(subElem);
+ f->writeByte((wrkEvent->localActionFl) ? 1 : 0);
+ f->writeUint32BE(wrkEvent->time);
+ f->writeSint16BE((wrkEvent->prevEvent == 0) ? -1 : (wrkEvent->prevEvent - _events));
+ f->writeSint16BE((wrkEvent->nextEvent == 0) ? -1 : (wrkEvent->nextEvent - _events));
}
-
- f->write(saveEventArr, sizeof(saveEventArr));
}
/**
@@ -730,27 +728,11 @@ void Scheduler::saveEvents(Common::WriteStream *f) {
*/
void Scheduler::restoreActions(Common::ReadStream *f) {
-
for (int i = 0; i < _actListArrSize; i++) {
-
- // read all the sub elems
- int j = 0;
- do {
-
- // handle special case for a3, keep list pointer
- int* responsePtr = 0;
- if (_actListArr[i][j].a3.actType == PROMPT) {
- responsePtr = _actListArr[i][j].a3.responsePtr;
- }
-
- f->read(&_actListArr[i][j], sizeof(act));
-
- // handle special case for a3, reset list pointer
- if (_actListArr[i][j].a3.actType == PROMPT) {
- _actListArr[i][j].a3.responsePtr = responsePtr;
- }
- j++;
- } while (_actListArr[i][j-1].a0.actType != ANULL);
+ uint16 numSubElem = f->readUint16BE();
+ for (int j = 0; j < numSubElem; j++) {
+ readAct(*f, _actListArr[i][j]);
+ }
}
}
@@ -764,23 +746,301 @@ int16 Scheduler::calcMaxPoints() const {
/*
* Save the action data in the file with handle f
*/
-void Scheduler::saveActions(Common::WriteStream* f) const {
+void Scheduler::saveActions(Common::WriteStream *f) const {
+ byte subElemType;
+ int16 nbrCpt;
+ uint16 nbrSubElem;
+
for (int i = 0; i < _actListArrSize; i++) {
// write all the sub elems data
-
- int j = 0;
- do {
- f->write(&_actListArr[i][j], sizeof(act));
- j++;
- } while (_actListArr[i][j-1].a0.actType != ANULL);
+ for (nbrSubElem = 1; _actListArr[i][nbrSubElem - 1].a0.actType != ANULL; nbrSubElem++)
+ ;
+
+ f->writeUint16BE(nbrSubElem);
+ for (int j = 0; j < nbrSubElem; j++) {
+ subElemType = _actListArr[i][j].a0.actType;
+ f->writeByte(subElemType);
+ switch (subElemType) {
+ case ANULL: // -1
+ break;
+ case ASCHEDULE: // 0
+ f->writeSint16BE(_actListArr[i][j].a0.timer);
+ f->writeUint16BE(_actListArr[i][j].a0.actIndex);
+ break;
+ case START_OBJ: // 1
+ f->writeSint16BE(_actListArr[i][j].a1.timer);
+ f->writeSint16BE(_actListArr[i][j].a1.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a1.cycleNumb);
+ f->writeByte(_actListArr[i][j].a1.cycle);
+ break;
+ case INIT_OBJXY: // 2
+ f->writeSint16BE(_actListArr[i][j].a2.timer);
+ f->writeSint16BE(_actListArr[i][j].a2.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a2.x);
+ f->writeSint16BE(_actListArr[i][j].a2.y);
+ break;
+ case PROMPT: // 3
+ f->writeSint16BE(_actListArr[i][j].a3.timer);
+ f->writeSint16BE(_actListArr[i][j].a3.promptIndex);
+ for (nbrCpt = 0; _actListArr[i][j].a3.responsePtr[nbrCpt] != -1; nbrCpt++)
+ ;
+ nbrCpt++;
+ f->writeUint16BE(nbrCpt);
+ for (int k = 0; k < nbrCpt; k++)
+ f->writeSint16BE(_actListArr[i][j].a3.responsePtr[k]);
+ f->writeUint16BE(_actListArr[i][j].a3.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a3.actFailIndex);
+ f->writeByte((_actListArr[i][j].a3.encodedFl) ? 1 : 0);
+ break;
+ case BKGD_COLOR: // 4
+ f->writeSint16BE(_actListArr[i][j].a4.timer);
+ f->writeUint32BE(_actListArr[i][j].a4.newBackgroundColor);
+ break;
+ case INIT_OBJVXY: // 5
+ f->writeSint16BE(_actListArr[i][j].a5.timer);
+ f->writeSint16BE(_actListArr[i][j].a5.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a5.vx);
+ f->writeSint16BE(_actListArr[i][j].a5.vy);
+ break;
+ case INIT_CARRY: // 6
+ f->writeSint16BE(_actListArr[i][j].a6.timer);
+ f->writeSint16BE(_actListArr[i][j].a6.objIndex);
+ f->writeByte((_actListArr[i][j].a6.carriedFl) ? 1 : 0);
+ break;
+ case INIT_HF_COORD: // 7
+ f->writeSint16BE(_actListArr[i][j].a7.timer);
+ f->writeSint16BE(_actListArr[i][j].a7.objIndex);
+ break;
+ case NEW_SCREEN: // 8
+ f->writeSint16BE(_actListArr[i][j].a8.timer);
+ f->writeSint16BE(_actListArr[i][j].a8.screenIndex);
+ break;
+ case INIT_OBJSTATE: // 9
+ f->writeSint16BE(_actListArr[i][j].a9.timer);
+ f->writeSint16BE(_actListArr[i][j].a9.objIndex);
+ f->writeByte(_actListArr[i][j].a9.newState);
+ break;
+ case INIT_PATH: // 10
+ f->writeSint16BE(_actListArr[i][j].a10.timer);
+ f->writeSint16BE(_actListArr[i][j].a10.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a10.newPathType);
+ f->writeByte(_actListArr[i][j].a10.vxPath);
+ f->writeByte(_actListArr[i][j].a10.vyPath);
+ break;
+ case COND_R: // 11
+ f->writeSint16BE(_actListArr[i][j].a11.timer);
+ f->writeSint16BE(_actListArr[i][j].a11.objIndex);
+ f->writeByte(_actListArr[i][j].a11.stateReq);
+ f->writeUint16BE(_actListArr[i][j].a11.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a11.actFailIndex);
+ break;
+ case TEXT: // 12
+ f->writeSint16BE(_actListArr[i][j].a12.timer);
+ f->writeSint16BE(_actListArr[i][j].a12.stringIndex);
+ break;
+ case SWAP_IMAGES: // 13
+ f->writeSint16BE(_actListArr[i][j].a13.timer);
+ f->writeSint16BE(_actListArr[i][j].a13.objIndex1);
+ f->writeSint16BE(_actListArr[i][j].a13.objIndex2);
+ break;
+ case COND_SCR: // 14
+ f->writeSint16BE(_actListArr[i][j].a14.timer);
+ f->writeSint16BE(_actListArr[i][j].a14.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a14.screenReq);
+ f->writeUint16BE(_actListArr[i][j].a14.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a14.actFailIndex);
+ break;
+ case AUTOPILOT: // 15
+ f->writeSint16BE(_actListArr[i][j].a15.timer);
+ f->writeSint16BE(_actListArr[i][j].a15.objIndex1);
+ f->writeSint16BE(_actListArr[i][j].a15.objIndex2);
+ f->writeByte(_actListArr[i][j].a15.dx);
+ f->writeByte(_actListArr[i][j].a15.dy);
+ break;
+ case INIT_OBJ_SEQ: // 16
+ f->writeSint16BE(_actListArr[i][j].a16.timer);
+ f->writeSint16BE(_actListArr[i][j].a16.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a16.seqIndex);
+ break;
+ case SET_STATE_BITS: // 17
+ f->writeSint16BE(_actListArr[i][j].a17.timer);
+ f->writeSint16BE(_actListArr[i][j].a17.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a17.stateMask);
+ break;
+ case CLEAR_STATE_BITS: // 18
+ f->writeSint16BE(_actListArr[i][j].a18.timer);
+ f->writeSint16BE(_actListArr[i][j].a18.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a18.stateMask);
+ break;
+ case TEST_STATE_BITS: // 19
+ f->writeSint16BE(_actListArr[i][j].a19.timer);
+ f->writeSint16BE(_actListArr[i][j].a19.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a19.stateMask);
+ f->writeUint16BE(_actListArr[i][j].a19.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a19.actFailIndex);
+ break;
+ case DEL_EVENTS: // 20
+ f->writeSint16BE(_actListArr[i][j].a20.timer);
+ f->writeByte(_actListArr[i][j].a20.actTypeDel);
+ break;
+ case GAMEOVER: // 21
+ f->writeSint16BE(_actListArr[i][j].a21.timer);
+ break;
+ case INIT_HH_COORD: // 22
+ f->writeSint16BE(_actListArr[i][j].a22.timer);
+ f->writeSint16BE(_actListArr[i][j].a22.objIndex);
+ break;
+ case EXIT: // 23
+ f->writeSint16BE(_actListArr[i][j].a23.timer);
+ break;
+ case BONUS: // 24
+ f->writeSint16BE(_actListArr[i][j].a24.timer);
+ f->writeSint16BE(_actListArr[i][j].a24.pointIndex);
+ break;
+ case COND_BOX: // 25
+ f->writeSint16BE(_actListArr[i][j].a25.timer);
+ f->writeSint16BE(_actListArr[i][j].a25.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a25.x1);
+ f->writeSint16BE(_actListArr[i][j].a25.y1);
+ f->writeSint16BE(_actListArr[i][j].a25.x2);
+ f->writeSint16BE(_actListArr[i][j].a25.y2);
+ f->writeUint16BE(_actListArr[i][j].a25.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a25.actFailIndex);
+ break;
+ case SOUND: // 26
+ f->writeSint16BE(_actListArr[i][j].a26.timer);
+ f->writeSint16BE(_actListArr[i][j].a26.soundIndex);
+ break;
+ case ADD_SCORE: // 27
+ f->writeSint16BE(_actListArr[i][j].a27.timer);
+ f->writeSint16BE(_actListArr[i][j].a27.objIndex);
+ break;
+ case SUB_SCORE: // 28
+ f->writeSint16BE(_actListArr[i][j].a28.timer);
+ f->writeSint16BE(_actListArr[i][j].a28.objIndex);
+ break;
+ case COND_CARRY: // 29
+ f->writeSint16BE(_actListArr[i][j].a29.timer);
+ f->writeSint16BE(_actListArr[i][j].a29.objIndex);
+ f->writeUint16BE(_actListArr[i][j].a29.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a29.actFailIndex);
+ break;
+ case INIT_MAZE: // 30
+ f->writeSint16BE(_actListArr[i][j].a30.timer);
+ f->writeByte(_actListArr[i][j].a30.mazeSize);
+ f->writeSint16BE(_actListArr[i][j].a30.x1);
+ f->writeSint16BE(_actListArr[i][j].a30.y1);
+ f->writeSint16BE(_actListArr[i][j].a30.x2);
+ f->writeSint16BE(_actListArr[i][j].a30.y2);
+ f->writeSint16BE(_actListArr[i][j].a30.x3);
+ f->writeSint16BE(_actListArr[i][j].a30.x4);
+ f->writeByte(_actListArr[i][j].a30.firstScreenIndex);
+ break;
+ case EXIT_MAZE: // 31
+ f->writeSint16BE(_actListArr[i][j].a31.timer);
+ break;
+ case INIT_PRIORITY: // 32
+ f->writeSint16BE(_actListArr[i][j].a32.timer);
+ f->writeSint16BE(_actListArr[i][j].a32.objIndex);
+ f->writeByte(_actListArr[i][j].a32.priority);
+ break;
+ case INIT_SCREEN: // 33
+ f->writeSint16BE(_actListArr[i][j].a33.timer);
+ f->writeSint16BE(_actListArr[i][j].a33.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a33.screenIndex);
+ break;
+ case AGSCHEDULE: // 34
+ f->writeSint16BE(_actListArr[i][j].a34.timer);
+ f->writeUint16BE(_actListArr[i][j].a34.actIndex);
+ break;
+ case REMAPPAL: // 35
+ f->writeSint16BE(_actListArr[i][j].a35.timer);
+ f->writeSint16BE(_actListArr[i][j].a35.oldColorIndex);
+ f->writeSint16BE(_actListArr[i][j].a35.newColorIndex);
+ break;
+ case COND_NOUN: // 36
+ f->writeSint16BE(_actListArr[i][j].a36.timer);
+ f->writeUint16BE(_actListArr[i][j].a36.nounIndex);
+ f->writeUint16BE(_actListArr[i][j].a36.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a36.actFailIndex);
+ break;
+ case SCREEN_STATE: // 37
+ f->writeSint16BE(_actListArr[i][j].a37.timer);
+ f->writeSint16BE(_actListArr[i][j].a37.screenIndex);
+ f->writeByte(_actListArr[i][j].a37.newState);
+ break;
+ case INIT_LIPS: // 38
+ f->writeSint16BE(_actListArr[i][j].a38.timer);
+ f->writeSint16BE(_actListArr[i][j].a38.lipsObjIndex);
+ f->writeSint16BE(_actListArr[i][j].a38.objIndex);
+ f->writeByte(_actListArr[i][j].a38.dxLips);
+ f->writeByte(_actListArr[i][j].a38.dyLips);
+ break;
+ case INIT_STORY_MODE: // 39
+ f->writeSint16BE(_actListArr[i][j].a39.timer);
+ f->writeByte((_actListArr[i][j].a39.storyModeFl) ? 1 : 0);
+ break;
+ case WARN: // 40
+ f->writeSint16BE(_actListArr[i][j].a40.timer);
+ f->writeSint16BE(_actListArr[i][j].a40.stringIndex);
+ break;
+ case COND_BONUS: // 41
+ f->writeSint16BE(_actListArr[i][j].a41.timer);
+ f->writeSint16BE(_actListArr[i][j].a41.BonusIndex);
+ f->writeUint16BE(_actListArr[i][j].a41.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a41.actFailIndex);
+ break;
+ case TEXT_TAKE: // 42
+ f->writeSint16BE(_actListArr[i][j].a42.timer);
+ f->writeSint16BE(_actListArr[i][j].a42.objIndex);
+ break;
+ case YESNO: // 43
+ f->writeSint16BE(_actListArr[i][j].a43.timer);
+ f->writeSint16BE(_actListArr[i][j].a43.promptIndex);
+ f->writeUint16BE(_actListArr[i][j].a43.actYesIndex);
+ f->writeUint16BE(_actListArr[i][j].a43.actNoIndex);
+ break;
+ case STOP_ROUTE: // 44
+ f->writeSint16BE(_actListArr[i][j].a44.timer);
+ break;
+ case COND_ROUTE: // 45
+ f->writeSint16BE(_actListArr[i][j].a45.timer);
+ f->writeSint16BE(_actListArr[i][j].a45.routeIndex);
+ f->writeUint16BE(_actListArr[i][j].a45.actPassIndex);
+ f->writeUint16BE(_actListArr[i][j].a45.actFailIndex);
+ break;
+ case INIT_JUMPEXIT: // 46
+ f->writeSint16BE(_actListArr[i][j].a46.timer);
+ f->writeByte((_actListArr[i][j].a46.jumpExitFl) ? 1 : 0);
+ break;
+ case INIT_VIEW: // 47
+ f->writeSint16BE(_actListArr[i][j].a47.timer);
+ f->writeSint16BE(_actListArr[i][j].a47.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a47.viewx);
+ f->writeSint16BE(_actListArr[i][j].a47.viewy);
+ f->writeSint16BE(_actListArr[i][j].a47.direction);
+ break;
+ case INIT_OBJ_FRAME: // 48
+ f->writeSint16BE(_actListArr[i][j].a48.timer);
+ f->writeSint16BE(_actListArr[i][j].a48.objIndex);
+ f->writeSint16BE(_actListArr[i][j].a48.seqIndex);
+ f->writeSint16BE(_actListArr[i][j].a48.frameIndex);
+ break;
+ case OLD_SONG: // 49, Added by Strangerke for DOS versions
+ f->writeSint16BE(_actListArr[i][j].a49.timer);
+ f->writeUint16BE(_actListArr[i][j].a49.songIndex);
+ break;
+ default:
+ error("Unknown action %d", subElemType);
+ }
+ }
}
}
/*
* Find the index in the action list to be able to serialize the action to save game
*/
-
-void Scheduler::findAction(act* action, int16* index, int16* subElem) {
+void Scheduler::findAction(const act* action, int16* index, int16* subElem) {
assert(index && subElem);
if (!action) {
@@ -831,28 +1091,30 @@ void Scheduler::restoreSchedulerData(Common::ReadStream *in) {
void Scheduler::restoreEvents(Common::ReadStream *f) {
debugC(1, kDebugSchedule, "restoreEvents");
- event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
-
uint32 saveTime = f->readUint32BE(); // time of save
int16 freeIndex = f->readSint16BE(); // Free list index
int16 headIndex = f->readSint16BE(); // Head of list index
int16 tailIndex = f->readSint16BE(); // Tail of list index
- f->read(savedEvents, sizeof(savedEvents));
- event_t *wrkEvent;
// Restore events indexes to pointers
for (int i = 0; i < kMaxEvents; i++) {
- wrkEvent = &savedEvents[i];
- _events[i] = *wrkEvent;
+ int16 index = f->readSint16BE();
+ int16 subElem = f->readSint16BE();
+
// fix up action pointer (to do better)
- int32 val = (size_t)_events[i].action;
- if ((val & 0xffff) == 0xffff) {
+ if ((index == -1) && (subElem == -1))
_events[i].action = 0;
- } else {
- _events[i].action = (act*)&_actListArr[val >> 16][val & 0xffff];
- }
- _events[i].prevEvent = (wrkEvent->prevEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->prevEvent ];
- _events[i].nextEvent = (wrkEvent->nextEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->nextEvent ];
+ else
+ _events[i].action = (act*)&_actListArr[index][subElem];
+
+ _events[i].localActionFl = (f->readByte() == 1) ? true : false;
+ _events[i].time = f->readUint32BE();
+
+ int16 prevIndex = f->readSint16BE();
+ int16 nextIndex = f->readSint16BE();
+
+ _events[i].prevEvent = (prevIndex == -1) ? (event_t *)0 : &_events[prevIndex];
+ _events[i].nextEvent = (nextIndex == -1) ? (event_t *)0 : &_events[nextIndex];
}
_freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex];
_headEvent = (headIndex == -1) ? 0 : &_events[headIndex];
@@ -860,7 +1122,7 @@ void Scheduler::restoreEvents(Common::ReadStream *f) {
// Adjust times to fit our time
uint32 curTime = getTicks();
- wrkEvent = _headEvent; // The earliest event
+ event_t *wrkEvent = _headEvent; // The earliest event
while (wrkEvent) { // While mature events found
wrkEvent->time = wrkEvent->time - saveTime + curTime;
wrkEvent = wrkEvent->nextEvent;
diff --git a/engines/hugo/schedule.h b/engines/hugo/schedule.h
index 953e9affea..a066fc63c4 100644
--- a/engines/hugo/schedule.h
+++ b/engines/hugo/schedule.h
@@ -583,7 +583,7 @@ protected:
void delEventType(const action_t actTypeDel);
void delQueue(event_t *curEvent);
- void findAction(act* action, int16* index, int16* subElem);
+ void findAction(const act* action, int16* index, int16* subElem);
void insertAction(act *action);
void readAct(Common::ReadStream &in, act &curAct);
void restoreActions(Common::ReadStream *f);
diff --git a/engines/mohawk/cstime_game.cpp b/engines/mohawk/cstime_game.cpp
index 5dfc9c4cf6..14e5d99e51 100644
--- a/engines/mohawk/cstime_game.cpp
+++ b/engines/mohawk/cstime_game.cpp
@@ -470,8 +470,8 @@ void CSTimeConversation::end(bool useLastClicked, bool runEvents) {
_vm->getCase()->getCurrScene()->getChar(_sourceChar)->setupAmbientAnims(true);
}
- CSTimeInterface *interface = _vm->getInterface();
- CSTimeInventoryDisplay *invDisplay = interface->getInventoryDisplay();
+ CSTimeInterface *iface = _vm->getInterface();
+ CSTimeInventoryDisplay *invDisplay = iface->getInventoryDisplay();
if (invDisplay->getState() == 4) {
invDisplay->hide();
invDisplay->setState(0);
@@ -480,8 +480,8 @@ void CSTimeConversation::end(bool useLastClicked, bool runEvents) {
setState((uint)~0);
_currHover = 0xffff;
- interface->clearTextLine();
- interface->clearDialogArea();
+ iface->clearTextLine();
+ iface->clearDialogArea();
invDisplay->show();
// TODO: stupid case 20 stuff
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index eb11eb175e..4a9fcb2ff2 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -28,12 +28,13 @@
#include "mohawk/resource.h"
#include "mohawk/graphics.h"
#include "mohawk/myst.h"
-#include "mohawk/riven_cursors.h"
#include "common/macresman.h"
-#include "common/ne_exe.h"
#include "common/system.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
#include "graphics/cursorman.h"
+#include "graphics/wincursor.h"
namespace Mohawk {
@@ -83,15 +84,16 @@ void CursorManager::setCursor(uint16 id) {
setDefaultCursor();
}
-void CursorManager::decodeMacXorCursor(Common::SeekableReadStream *stream, byte *cursor) {
+void CursorManager::setMacXorCursor(Common::SeekableReadStream *stream) {
assert(stream);
- assert(cursor);
+
+ byte cursorBitmap[16 * 16];
// Get black and white data
for (int i = 0; i < 32; i++) {
byte imageByte = stream->readByte();
for (int b = 0; b < 8; b++)
- cursor[i * 8 + b] = (imageByte & (0x80 >> b)) ? 1 : 2;
+ cursorBitmap[i * 8 + b] = (imageByte & (0x80 >> b)) ? 1 : 2;
}
// Apply mask data
@@ -99,28 +101,18 @@ void CursorManager::decodeMacXorCursor(Common::SeekableReadStream *stream, byte
byte imageByte = stream->readByte();
for (int b = 0; b < 8; b++)
if ((imageByte & (0x80 >> b)) == 0)
- cursor[i * 8 + b] = 0;
+ cursorBitmap[i * 8 + b] = 0;
}
-}
-void CursorManager::setStandardCursor(Common::SeekableReadStream *stream) {
- // The Broderbund devs decided to rip off the Mac format, it seems.
- // However, they reversed the x/y hotspot. That makes it totally different!!!!
- assert(stream);
-
- byte cursorBitmap[16 * 16];
- decodeMacXorCursor(stream, cursorBitmap);
uint16 hotspotY = stream->readUint16BE();
uint16 hotspotX = stream->readUint16BE();
CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, 0);
CursorMan.replaceCursorPalette(s_bwPalette, 1, 2);
-
- delete stream;
}
void DefaultCursorManager::setCursor(uint16 id) {
- setStandardCursor(_vm->getResource(_tag, id));
+ setMacXorCursor(_vm->getResource(_tag, id));
}
MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) {
@@ -167,119 +159,6 @@ void MystCursorManager::setDefaultCursor() {
setCursor(kDefaultMystCursor);
}
-void RivenCursorManager::setCursor(uint16 id) {
- // All of Riven's cursors are hardcoded. See riven_cursors.h for these definitions.
-
- switch (id) {
- case 1002:
- // Zip Mode
- CursorMan.replaceCursor(s_zipModeCursor, 16, 16, 8, 8, 0);
- CursorMan.replaceCursorPalette(s_zipModeCursorPalette, 1, ARRAYSIZE(s_zipModeCursorPalette) / 3);
- break;
- case 2003:
- // Hand Over Object
- CursorMan.replaceCursor(s_objectHandCursor, 16, 16, 8, 8, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 2004:
- // Grabbing/Using Object
- CursorMan.replaceCursor(s_grabbingHandCursor, 13, 13, 6, 6, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3000:
- // Standard Hand
- CursorMan.replaceCursor(s_standardHandCursor, 15, 16, 6, 0, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3001:
- // Pointing Left
- CursorMan.replaceCursor(s_pointingLeftCursor, 15, 13, 0, 3, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3002:
- // Pointing Right
- CursorMan.replaceCursor(s_pointingRightCursor, 15, 13, 14, 3, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3003:
- // Pointing Down (Palm Up)
- CursorMan.replaceCursor(s_pointingDownCursorPalmUp, 13, 16, 3, 15, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3004:
- // Pointing Up (Palm Up)
- CursorMan.replaceCursor(s_pointingUpCursorPalmUp, 13, 16, 3, 0, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3005:
- // Pointing Left (Curved)
- CursorMan.replaceCursor(s_pointingLeftCursorBent, 15, 13, 0, 5, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3006:
- // Pointing Right (Curved)
- CursorMan.replaceCursor(s_pointingRightCursorBent, 15, 13, 14, 5, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 3007:
- // Pointing Down (Palm Down)
- CursorMan.replaceCursor(s_pointingDownCursorPalmDown, 15, 16, 7, 15, 0);
- CursorMan.replaceCursorPalette(s_handCursorPalette, 1, ARRAYSIZE(s_handCursorPalette) / 3);
- break;
- case 4001:
- // Red Marble
- CursorMan.replaceCursor(s_redMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_redMarbleCursorPalette, 1, ARRAYSIZE(s_redMarbleCursorPalette) / 3);
- break;
- case 4002:
- // Orange Marble
- CursorMan.replaceCursor(s_orangeMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_orangeMarbleCursorPalette, 1, ARRAYSIZE(s_orangeMarbleCursorPalette) / 3);
- break;
- case 4003:
- // Yellow Marble
- CursorMan.replaceCursor(s_yellowMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_yellowMarbleCursorPalette, 1, ARRAYSIZE(s_yellowMarbleCursorPalette) / 3);
- break;
- case 4004:
- // Green Marble
- CursorMan.replaceCursor(s_greenMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_greenMarbleCursorPalette, 1, ARRAYSIZE(s_greenMarbleCursorPalette) / 3);
- break;
- case 4005:
- // Blue Marble
- CursorMan.replaceCursor(s_blueMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_blueMarbleCursorPalette, 1, ARRAYSIZE(s_blueMarbleCursorPalette) / 3);
- break;
- case 4006:
- // Violet Marble
- CursorMan.replaceCursor(s_violetMarbleCursor, 12, 12, 5, 5, 0);
- CursorMan.replaceCursorPalette(s_violetMarbleCursorPalette, 1, ARRAYSIZE(s_violetMarbleCursorPalette) / 3);
- break;
- case 5000:
- // Pellet
- CursorMan.replaceCursor(s_pelletCursor, 8, 8, 4, 4, 0);
- CursorMan.replaceCursorPalette(s_pelletCursorPalette, 1, ARRAYSIZE(s_pelletCursorPalette) / 3);
- break;
- case 9000:
- // Hide Cursor
- CursorMan.showMouse(false);
- break;
- default:
- error("Cursor %d does not exist!", id);
- }
-
- if (id != 9000) // Show Cursor
- CursorMan.showMouse(true);
-
- // Should help in cases where we need to hide the cursor immediately.
- g_system->updateScreen();
-}
-
-void RivenCursorManager::setDefaultCursor() {
- setCursor(kRivenMainCursor);
-}
-
NECursorManager::NECursorManager(const Common::String &appName) {
_exe = new Common::NEResources();
@@ -295,16 +174,14 @@ NECursorManager::~NECursorManager() {
}
void NECursorManager::setCursor(uint16 id) {
- if (!_exe) {
- Common::Array<Common::NECursorGroup> cursors = _exe->getCursors();
-
- for (uint32 i = 0; i < cursors.size(); i++) {
- if (cursors[i].id == id) {
- Common::NECursor *cursor = cursors[i].cursors[0];
- CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), 0);
- CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
- return;
- }
+ if (_exe) {
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
+
+ if (cursorGroup) {
+ Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ return;
}
}
@@ -321,6 +198,8 @@ MacCursorManager::MacCursorManager(const Common::String &appName) {
delete _resFork;
_resFork = 0;
}
+ } else {
+ _resFork = 0;
}
}
@@ -334,22 +213,33 @@ void MacCursorManager::setCursor(uint16 id) {
return;
}
- Common::SeekableReadStream *stream = _resFork->getResource(MKID_BE('CURS'), id);
+ // Try a color cursor first
+ Common::SeekableReadStream *stream = _resFork->getResource(MKID_BE('crsr'), id);
- if (!stream) {
- setDefaultCursor();
+ if (stream) {
+ byte *cursor, *palette;
+ int width, height, hotspotX, hotspotY, keyColor, palSize;
+
+ _resFork->convertCrsrCursor(stream, &cursor, width, height, hotspotX, hotspotY, keyColor, true, &palette, palSize);
+
+ CursorMan.replaceCursor(cursor, width, height, hotspotX, hotspotY, keyColor);
+ CursorMan.replaceCursorPalette(palette, 0, palSize);
+
+ delete[] cursor;
+ delete[] palette;
+ delete stream;
return;
}
- byte cursorBitmap[16 * 16];
- decodeMacXorCursor(stream, cursorBitmap);
- uint16 hotspotX = stream->readUint16BE();
- uint16 hotspotY = stream->readUint16BE();
+ // Fall back to b&w cursors
+ stream = _resFork->getResource(MKID_BE('CURS'), id);
- CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, 0);
- CursorMan.replaceCursorPalette(s_bwPalette, 1, 2);
-
- delete stream;
+ if (stream) {
+ setMacXorCursor(stream);
+ delete stream;
+ } else {
+ setDefaultCursor();
+ }
}
LivingBooksCursorManager_v2::LivingBooksCursorManager_v2() {
@@ -368,10 +258,40 @@ LivingBooksCursorManager_v2::~LivingBooksCursorManager_v2() {
void LivingBooksCursorManager_v2::setCursor(uint16 id) {
if (_sysArchive && _sysArchive->hasResource(ID_TCUR, id)) {
- setStandardCursor(_sysArchive->getResource(ID_TCUR, id));
+ setMacXorCursor(_sysArchive->getResource(ID_TCUR, id));
} else {
// TODO: Handle generated cursors
}
}
+PECursorManager::PECursorManager(const Common::String &appName) {
+ _exe = new Common::PEResources();
+
+ if (!_exe->loadFromEXE(appName)) {
+ // Not all have cursors anyway, so this is not a problem
+ delete _exe;
+ _exe = 0;
+ }
+}
+
+PECursorManager::~PECursorManager() {
+ delete _exe;
+}
+
+void PECursorManager::setCursor(uint16 id) {
+ if (_exe) {
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
+
+ if (cursorGroup) {
+ Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ return;
+ }
+ }
+
+ // Last resort (not all have cursors)
+ setDefaultCursor();
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index a542ddb7c3..e6c417948f 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -31,6 +31,7 @@
namespace Common {
class MacResManager;
class NEResources;
+ class PEResources;
class SeekableReadStream;
class String;
}
@@ -80,13 +81,11 @@ public:
virtual void hideCursor();
virtual void setCursor(uint16 id);
virtual void setDefaultCursor();
+ virtual bool hasSource() const { return false; }
protected:
- // Handles the Mac version of the xor/and map cursor
- void decodeMacXorCursor(Common::SeekableReadStream *stream, byte *cursor);
-
- // Set a tCUR resource as the current cursor
- void setStandardCursor(Common::SeekableReadStream *stream);
+ // Set a Mac XOR/AND map cursor to the screen
+ void setMacXorCursor(Common::SeekableReadStream *stream);
};
// The default Mohawk cursor manager
@@ -97,6 +96,7 @@ public:
~DefaultCursorManager() {}
void setCursor(uint16 id);
+ bool hasSource() const { return true; }
private:
MohawkEngine *_vm;
@@ -114,31 +114,21 @@ public:
void hideCursor();
void setCursor(uint16 id);
void setDefaultCursor();
+ bool hasSource() const { return true; }
private:
MohawkEngine_Myst *_vm;
MystBitmap *_bmpDecoder;
};
-
-// The cursor manager for Riven
-// Uses hardcoded cursors
-class RivenCursorManager : public CursorManager {
-public:
- RivenCursorManager() {}
- ~RivenCursorManager() {}
-
- void setCursor(uint16 id);
- void setDefaultCursor();
-};
-
-// The cursor manager for NE exe's
+// The cursor manager for NE EXE's
class NECursorManager : public CursorManager {
public:
NECursorManager(const Common::String &appName);
~NECursorManager();
void setCursor(uint16 id);
+ bool hasSource() const { return _exe != 0; }
private:
Common::NEResources *_exe;
@@ -151,6 +141,7 @@ public:
~MacCursorManager();
void setCursor(uint16 id);
+ bool hasSource() const { return _resFork != 0; }
private:
Common::MacResManager *_resFork;
@@ -164,11 +155,25 @@ public:
~LivingBooksCursorManager_v2();
void setCursor(uint16 id);
+ bool hasSource() const { return _sysArchive != 0; }
private:
MohawkArchive *_sysArchive;
};
+// The cursor manager for PE EXE's
+class PECursorManager : public CursorManager {
+public:
+ PECursorManager(const Common::String &appName);
+ ~PECursorManager();
+
+ void setCursor(uint16 id);
+ bool hasSource() const { return _exe != 0; }
+
+private:
+ Common::PEResources *_exe;
+};
+
} // End of namespace Mohawk
#endif
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index 897ca79d0e..19882c4f1c 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -246,6 +246,13 @@ void GraphicsManager::copyAnimImageSectionToScreen(MohawkSurface *image, Common:
getVM()->_system->unlockScreen();
}
+void GraphicsManager::addImageToCache(uint16 id, MohawkSurface *surface) {
+ if (_cache.contains(id))
+ error("Image %d already in cache", id);
+
+ _cache[id] = surface;
+}
+
MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
_bmpDecoder = new MystBitmap();
@@ -630,6 +637,9 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm
_scheduledTransition = -1; // no transition
_dirtyScreen = false;
_inventoryDrawn = false;
+
+ _creditsImage = 302;
+ _creditsPos = 0;
}
RivenGraphics::~RivenGraphics() {
@@ -840,6 +850,17 @@ void RivenGraphics::runScheduledTransition() {
_scheduledTransition = -1; // Clear scheduled transition
}
+void RivenGraphics::clearMainScreen() {
+ _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0));
+}
+
+void RivenGraphics::fadeToBlack() {
+ // Self-explanatory
+ scheduleTransition(16);
+ clearMainScreen();
+ runScheduledTransition();
+}
+
void RivenGraphics::showInventory() {
// Don't redraw the inventory
if (_inventoryDrawn)
@@ -955,6 +976,60 @@ void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) {
_dirtyScreen = true;
}
+void RivenGraphics::beginCredits() {
+ // Clear the old cache
+ clearCache();
+
+ // Now cache all the credits images
+ for (uint16 i = 302; i <= 320; i++) {
+ MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i));
+ surface->convertToTrueColor();
+ addImageToCache(i, surface);
+ }
+
+ // And clear our screen too
+ clearMainScreen();
+}
+
+void RivenGraphics::updateCredits() {
+ if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0)
+ fadeToBlack();
+
+ if (_creditsImage < 304) {
+ // For the first two credit images, they are faded from black to the image and then out again
+ scheduleTransition(16);
+
+ Graphics::Surface *frame = findImage(_creditsImage++)->getSurface();
+
+ for (int y = 0; y < frame->h; y++)
+ memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch);
+
+ runScheduledTransition();
+ } else {
+ // Otheriwse, we're scrolling
+ // Move the screen up one row
+ memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1));
+
+ // Only update as long as we're not before the last frame
+ // Otherwise, we're just moving up a row (which we already did)
+ if (_creditsImage <= 320) {
+ // Copy the next row to the bottom of the screen
+ Graphics::Surface *frame = findImage(_creditsImage)->getSurface();
+ memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch);
+ _creditsPos++;
+
+ if (_creditsPos == _mainScreen->h) {
+ _creditsImage++;
+ _creditsPos = 0;
+ }
+ }
+
+ // Now flush the new screen
+ _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h);
+ _vm->_system->updateScreen();
+ }
+}
+
LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) {
_bmpDecoder = _vm->isPreMohawk() ? new OldMohawkBitmap() : new MohawkBitmap();
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index 89189d442a..fbac2f2ea1 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -110,6 +110,7 @@ protected:
virtual Common::Array<MohawkSurface *> decodeImages(uint16 id);
virtual MohawkEngine *getVM() = 0;
+ void addImageToCache(uint16 id, MohawkSurface *surface);
private:
// An image cache that stores images until clearCache() is called
@@ -195,11 +196,17 @@ public:
// Transitions
void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392));
void runScheduledTransition();
+ void fadeToBlack();
// Inventory
void showInventory();
void hideInventory();
+ // Credits
+ void beginCredits();
+ void updateCredits();
+ uint getCurCreditsImage() { return _creditsImage; }
+
protected:
MohawkSurface *decodeImage(uint16 id);
MohawkEngine *getVM() { return (MohawkEngine *)_vm; }
@@ -224,6 +231,10 @@ private:
Graphics::Surface *_mainScreen;
bool _dirtyScreen;
Graphics::PixelFormat _pixelFormat;
+ void clearMainScreen();
+
+ // Credits
+ uint _creditsImage, _creditsPos;
};
class LBGraphics : public GraphicsManager {
diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp
index 20f7684521..482aade99d 100644
--- a/engines/mohawk/livingbooks.cpp
+++ b/engines/mohawk/livingbooks.cpp
@@ -555,8 +555,9 @@ void MohawkEngine_LivingBooks::queueDelayedEvent(DelayedEvent event) {
uint16 MohawkEngine_LivingBooks::getResourceVersion() {
Common::SeekableReadStream *versionStream = getResource(ID_VRSN, 1000);
+ // FIXME: some V2 games have very strange version entries
if (versionStream->size() != 2)
- warning("Version Record size mismatch");
+ debug(1, "Version Record size mismatch");
uint16 version = versionStream->readUint16BE();
@@ -864,7 +865,6 @@ void MohawkEngine_LivingBooks::handleUIPoetryMenuClick(uint controlId) {
break;
case 7:
- case 0xA:
item = getItemById(10);
if (item)
item->destroySelf();
@@ -874,7 +874,18 @@ void MohawkEngine_LivingBooks::handleUIPoetryMenuClick(uint controlId) {
item = getItemById(12);
if (item) {
item->setVisible(true);
- item->togglePlaying(controlId == 7);
+ item->togglePlaying(true);
+ }
+ break;
+
+ case 0xA:
+ item = getItemById(10);
+ if (item)
+ item->destroySelf();
+ item = getItemById(11);
+ if (item) {
+ item->setVisible(true);
+ item->togglePlaying(true);
}
break;
@@ -1251,7 +1262,7 @@ NodeState LBAnimationNode::update(bool seeking) {
uint16 strLen = READ_BE_UINT16(entry.data + 2);
if (strLen)
- error("String length for unnamed wave file");
+ warning("Named wave file encountered");
switch (entry.opcode) {
case kLBAnimOpPlaySound:
@@ -2433,7 +2444,7 @@ void LBItem::runScriptEntry(LBScriptEntry *entry) {
break;
case kLBOpRewind:
- target->seek(0);
+ target->seek(1);
break;
case kLBOpStop:
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index f842269893..1aba820fed 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -1143,20 +1143,6 @@ void MohawkEngine_Myst::loadResources() {
delete rlstStream;
}
-void MohawkEngine_Myst::runLoadDialog() {
- const Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- pauseEngine(true);
- int slot = _loadDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
- if (slot >= 0) {
- // TODO
- }
- pauseEngine(false);
-}
-
Common::Error MohawkEngine_Myst::loadGameState(int slot) {
if (_gameState->load(_gameState->generateSaveGameList()[slot]))
return Common::kNoError;
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 919509384b..47e8a6562c 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -155,8 +155,6 @@ public:
Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack);
void reloadSaveList();
- void runLoadDialog();
- void runSaveDialog();
void changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound);
void changeToCard(uint16 card, bool updateScreen);
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index 01390f0ea6..3dab2f7939 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -59,7 +59,7 @@ void Mechanical::setupOpcodes() {
OPCODE(107, o_elevatorRotationMove);
OPCODE(108, o_elevatorRotationStop);
OPCODE(121, o_elevatorWindowMovie);
- OPCODE(122, opcode_122);
+ OPCODE(122, o_elevatorGoMiddle);
OPCODE(123, o_elevatorTopMovie);
OPCODE(124, opcode_124);
OPCODE(125, o_mystStaircaseMovie);
@@ -82,7 +82,7 @@ void Mechanical::setupOpcodes() {
OPCODE(209, opcode_209);
// "Exit" Opcodes
- OPCODE(300, opcode_300);
+ OPCODE(300, NOP);
}
#undef OPCODE
@@ -92,6 +92,7 @@ void Mechanical::disablePersistentScripts() {
opcode_205_disable();
opcode_206_disable();
opcode_209_disable();
+ _elevatorGoingMiddle = false;
}
void Mechanical::runPersistentScripts() {
@@ -100,6 +101,9 @@ void Mechanical::runPersistentScripts() {
if (_elevatorRotationLeverMoving)
elevatorRotation_run();
+ if (_elevatorGoingMiddle)
+ elevatorGoMiddle_run();
+
opcode_205_run();
opcode_206_run();
opcode_209_run();
@@ -139,8 +143,13 @@ uint16 Mechanical::getVar(uint16 var) {
return _state.elevatorRotation;
case 12: // Fortress Elevator Rotation Cog Position
return 5 - (uint16)(_elevatorRotationGearPosition + 0.5) % 6;
+ case 13: // Elevator position
+ return _elevatorPosition;
case 14: // Elevator going down when at top
- return _elevatorGoingDown; // TODO add too late value (2)
+ if (_elevatorGoingDown && _elevatorTooLate)
+ return 2;
+ else
+ return _elevatorGoingDown;
case 15: // Code Lock Execute Button Script
if (_mystStaircaseState)
return 0;
@@ -187,6 +196,9 @@ void Mechanical::toggleVar(uint16 var) {
case 19: // Code Lock Shape #4 - Right
_state.codeShape[var - 16] = (_state.codeShape[var - 16] + 1) % 10;
break;
+ case 23: // Elevator player is in cabin
+ _elevatorInCabin = false;
+ break;
case 102: // Red page
if (!(_globals.redPagesInBook & 4)) {
if (_globals.heldPage == 9)
@@ -213,6 +225,8 @@ bool Mechanical::setVarValue(uint16 var, uint16 value) {
bool refresh = false;
switch (var) {
+ case 13:
+ _elevatorPosition = value;
case 14: // Elevator going down when at top
_elevatorGoingDown = value;
break;
@@ -342,14 +356,63 @@ void Mechanical::o_elevatorWindowMovie(uint16 op, uint16 var, uint16 argc, uint1
_vm->_video->waitUntilMovieEnds(window);
}
-void Mechanical::opcode_122(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- if (argc == 0) {
- // Used on Card 6120 (Elevator)
- // Called when Exit Midde Button Pressed
-
- // TODO: hcelev? Movie of Elevator?
- } else
- unknown(op, var, argc, argv);
+void Mechanical::o_elevatorGoMiddle(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
+ debugC(kDebugScript, "Opcode %d: Elevator go middle from top", op);
+
+ _elevatorTooLate = false;
+ _elevatorTopCounter = 5;
+ _elevatorGoingMiddle = true;
+ _elevatorInCabin = true;
+ _elevatorNextTime = _vm->_system->getMillis() + 1000;
+}
+
+void Mechanical::elevatorGoMiddle_run() {
+ uint32 time = _vm->_system->getMillis();
+ if (_elevatorNextTime < time) {
+ _elevatorNextTime = time + 1000;
+ _elevatorTopCounter--;
+
+ if (_elevatorTopCounter > 0) {
+ // Draw button pressed
+ if (_elevatorInCabin) {
+ _vm->_gfx->copyImageSectionToScreen(6332, Common::Rect(0, 35, 51, 63), Common::Rect(10, 137, 61, 165));
+ _vm->_system->updateScreen();
+ }
+
+ // Blip
+ _vm->_sound->playSoundBlocking(14120);
+
+ // Restore button
+ if (_elevatorInCabin) {
+ _vm->_gfx->copyBackBufferToScreen(Common::Rect(10, 137, 61, 165));
+ _vm->_system->updateScreen();
+ }
+ } else if (_elevatorInCabin) {
+ _elevatorTooLate = true;
+
+ // Elevator going to middle animation
+ _vm->_cursor->hideCursor();
+ _vm->_sound->playSoundBlocking(11120);
+ _vm->_gfx->copyImageToBackBuffer(6118, Common::Rect(544, 333));
+ _vm->_sound->replaceSoundMyst(12120);
+ _vm->_gfx->runTransition(2, Common::Rect(177, 0, 370, 333), 25, 0);
+ _vm->_sound->playSoundBlocking(13120);
+ _vm->_sound->replaceSoundMyst(8120);
+ _vm->_gfx->copyImageToBackBuffer(6327, Common::Rect(544, 333));
+ _vm->_system->delayMillis(500);
+ _vm->_sound->replaceSoundMyst(9120);
+ static uint16 moviePos[2] = { 3540, 5380 };
+ o_elevatorWindowMovie(121, 0, 2, moviePos);
+ _vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
+ _vm->_sound->replaceSoundMyst(10120);
+ _vm->_cursor->showCursor();
+
+ _elevatorGoingMiddle = false;
+ _elevatorPosition = 1;
+
+ _vm->changeToCard(6327, true);
+ }
+ }
}
void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -600,11 +663,5 @@ void Mechanical::opcode_209(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
unknown(op, var, argc, argv);
}
-void Mechanical::opcode_300(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
- // Used in Card 6156 (Fortress Elevator View)
- varUnusedCheck(op, var);
- // TODO: Fill in Logic. Clearing Variable for View?
-}
-
} // End of namespace MystStacks
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_stacks/mechanical.h b/engines/mohawk/myst_stacks/mechanical.h
index 24c6c73471..6a0aa30f5c 100644
--- a/engines/mohawk/myst_stacks/mechanical.h
+++ b/engines/mohawk/myst_stacks/mechanical.h
@@ -55,6 +55,7 @@ private:
void opcode_202_run();
void opcode_202_disable();
void elevatorRotation_run();
+ void elevatorGoMiddle_run();
void opcode_205_run();
void opcode_205_disable();
void opcode_206_run();
@@ -69,7 +70,7 @@ private:
DECLARE_OPCODE(o_elevatorRotationMove);
DECLARE_OPCODE(o_elevatorRotationStop);
DECLARE_OPCODE(o_elevatorWindowMovie);
- DECLARE_OPCODE(opcode_122);
+ DECLARE_OPCODE(o_elevatorGoMiddle);
DECLARE_OPCODE(o_elevatorTopMovie);
DECLARE_OPCODE(opcode_124);
DECLARE_OPCODE(o_mystStaircaseMovie);
@@ -90,8 +91,6 @@ private:
DECLARE_OPCODE(opcode_206);
DECLARE_OPCODE(opcode_209);
- DECLARE_OPCODE(opcode_300);
-
MystGameState::Mechanical &_state;
bool _mystStaircaseState; // 76
@@ -105,6 +104,13 @@ private:
uint16 _elevatorRotationSoundId; // 128
bool _elevatorRotationLeverMoving; // 184
+ bool _elevatorGoingMiddle; // 148
+ bool _elevatorTooLate;
+ uint16 _elevatorPosition; // 104
+ bool _elevatorInCabin; // 108
+ uint16 _elevatorTopCounter;
+ uint32 _elevatorNextTime;
+
uint16 _crystalLit; // 130
MystResourceType6 *_snakeBox; // 156
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index 29048eab39..caadf09f56 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -50,6 +50,7 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_towerRotationBlinkLabel = false;
_libraryBookcaseChanged = false;
_dockVaultState = 0;
+ _cabinDoorOpened = 0;
_cabinMatchState = 2;
_matchBurning = false;
_tree = 0;
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index abc7f5304e..e9742e0bc2 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -120,21 +120,44 @@ Common::Error MohawkEngine_Riven::run() {
_externalScriptHandler = new RivenExternal(this);
_optionsDialog = new RivenOptionsDialog(this);
_scriptMan = new RivenScriptManager(this);
- _cursor = new RivenCursorManager();
_rnd = new Common::RandomSource();
g_eventRec.registerRandomSource(*_rnd, "riven");
+ // Create the cursor manager
+ if (Common::File::exists("rivendmo.exe"))
+ _cursor = new PECursorManager("rivendmo.exe");
+ else if (Common::File::exists("riven.exe"))
+ _cursor = new PECursorManager("riven.exe");
+ else // last resort: try the Mac executable
+ _cursor = new MacCursorManager("Riven");
+
initVars();
+ // We need to have a cursor source, or the game won't work
+ if (!_cursor->hasSource()) {
+ Common::String message = "You're missing a Riven executable. The Windows executable is 'riven.exe' or 'rivendmo.exe'. ";
+ message += "Using the 'arcriven.z' installer file also works. In addition, you can use the Mac 'Riven' executable.";
+ GUIErrorMessage(message);
+ warning("%s", message.c_str());
+ return Common::kNoGameDataFoundError;
+ }
+
// Open extras.mhk for common images
_extrasFile = new MohawkArchive();
- if (!_extrasFile->open("extras.mhk"))
- error("Could not open extras.mhk");
+ // We need extras.mhk for inventory images, marble images, and credits images
+ if (!_extrasFile->open("extras.mhk")) {
+ Common::String message = "You're missing 'extras.mhk'. Using the 'arcriven.z' installer file also works.";
+ GUIErrorMessage(message);
+ warning("%s", message.c_str());
+ return Common::kNoGameDataFoundError;
+ }
// Start at main cursor
_cursor->setCursor(kRivenMainCursor);
+ _cursor->showCursor();
+ _system->updateScreen();
// Let's begin, shall we?
if (getFeatures() & GF_DEMO) {
@@ -488,10 +511,12 @@ void MohawkEngine_Riven::checkHotspotChange() {
if (_curHotspot != hotspotIndex) {
_curHotspot = hotspotIndex;
_cursor->setCursor(_hotspots[_curHotspot].mouse_cursor);
+ _system->updateScreen();
}
} else {
_curHotspot = -1;
_cursor->setCursor(kRivenMainCursor);
+ _system->updateScreen();
}
}
diff --git a/engines/mohawk/riven_cursors.h b/engines/mohawk/riven_cursors.h
deleted file mode 100644
index dadfdf0549..0000000000
--- a/engines/mohawk/riven_cursors.h
+++ /dev/null
@@ -1,670 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-namespace Mohawk {
-
-//////////////////////////////////////////////
-// Cursors and Cursor Palettes
-//////////////////////////////////////////////
-
-////////////////////////////////////////
-// Zip Mode Cursor (16x16):
-// Shown when a zip mode spot is active
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Yellow (0xDCFF00)
-////////////////////////////////////////
-static const byte s_zipModeCursor[] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 1, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 2, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 1, 2, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 1, 2, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
-};
-
-
-////////////////////////////////////////
-// Zip Mode Cursor Palette:
-// Palette For The Zip Mode Cursor
-////////////////////////////////////////
-static const byte s_zipModeCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xDC, 0xFF, 0x00 // Yellow
-};
-
-
-////////////////////////////////////////
-// Hand Over Object Cursor (16x16):
-// Shown when over a hotspot that's interactive
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_objectHandCursor[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 1, 2, 3, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 0, 0, 0,
- 0, 0, 1, 2, 3, 1, 1, 4, 3, 1, 2, 3, 1, 0, 1, 0,
- 0, 0, 0, 1, 2, 3, 1, 2, 3, 1, 4, 3, 1, 1, 2, 1,
- 0, 0, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1,
- 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 3, 1, 2, 3, 1,
- 1, 2, 2, 1, 1, 2, 2, 2, 4, 2, 4, 2, 2, 4, 2, 1,
- 1, 3, 4, 2, 1, 2, 4, 2, 2, 2, 2, 2, 4, 4, 1, 0,
- 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 1, 0,
- 0, 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 0, 0,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Grabbing Hand Cursor (13x13):
-// Shown when interacting with an object
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_grabbingHandCursor[] = {
- 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 1, 2, 3, 1, 1, 1, 0, 0, 0,
- 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 0,
- 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1, 2, 1,
- 0, 1, 1, 2, 2, 2, 4, 2, 4, 2, 2, 4, 1,
- 1, 2, 1, 2, 4, 2, 2, 2, 2, 2, 4, 4, 1,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 3, 1,
- 1, 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 0,
- 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0,
- 0, 0, 0, 1, 2, 2, 2, 2, 4, 3, 1, 0, 0
-};
-
-
-////////////////////////////////////////
-// Standard Hand Cursor (15x16):
-// Standard Cursor
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_standardHandCursor[] = {
- 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 0, 0, 1, 2, 4, 1, 1, 1, 1, 1, 0, 0,
- 1, 4, 2, 1, 0, 1, 2, 4, 1, 4, 1, 4, 1, 1, 1,
- 0, 1, 3, 2, 1, 1, 2, 4, 1, 4, 1, 4, 1, 4, 1,
- 0, 0, 1, 4, 2, 1, 2, 2, 4, 2, 4, 2, 1, 4, 1,
- 0, 0, 1, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1,
- 0, 0, 0, 1, 4, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 4, 3, 1,
- 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 3, 1, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 4, 3, 1, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Left Cursor (15x13):
-// Cursor When Over A Hotspot That Allows You To Move Left
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingLeftCursor[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1,
- 1, 4, 2, 2, 2, 2, 1, 2, 3, 2, 2, 2, 4, 4, 4,
- 1, 4, 4, 4, 4, 4, 1, 2, 1, 3, 4, 2, 2, 2, 2,
- 0, 1, 1, 1, 1, 1, 1, 2, 1, 3, 3, 4, 2, 2, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 4, 4, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 4, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 4, 2, 4,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Right Cursor (15x13):
-// Cursor When Over A Hotspot That Allows You To Move Right
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingRightCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0,
- 4, 4, 4, 2, 2, 2, 3, 2, 1, 4, 4, 4, 4, 4, 1,
- 2, 2, 2, 2, 4, 3, 1, 2, 1, 2, 2, 2, 2, 4, 1,
- 2, 2, 2, 4, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 0,
- 2, 4, 4, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 4, 2, 4, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Down Cursor (Palm Up)(13x16):
-// Cursor When Over A Hotspot That Allows You To Move Down
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingDownCursorPalmUp[] = {
- 0, 0, 1, 4, 2, 2, 2, 2, 2, 4, 1, 0, 0,
- 0, 0, 1, 4, 2, 2, 4, 2, 2, 2, 4, 1, 0,
- 0, 1, 3, 4, 2, 2, 4, 4, 4, 4, 4, 1, 0,
- 0, 1, 4, 2, 2, 4, 3, 3, 3, 1, 1, 1, 1,
- 1, 2, 2, 2, 4, 3, 3, 1, 1, 2, 1, 2, 1,
- 1, 2, 2, 2, 3, 3, 3, 4, 1, 2, 1, 2, 1,
- 1, 2, 2, 3, 1, 1, 1, 2, 1, 2, 1, 2, 1,
- 1, 3, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1,
- 0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1,
- 0, 0, 1, 2, 4, 1, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Up Cursor (Palm Up)(13x16):
-// Cursor When Over A Hotspot That Allows You To Move Up
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingUpCursorPalmUp[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 1, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 2, 4, 1, 0, 0,
- 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 0,
- 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 3, 1,
- 1, 2, 1, 2, 1, 2, 1, 1, 1, 3, 2, 2, 1,
- 1, 2, 1, 2, 1, 4, 3, 3, 3, 2, 2, 2, 1,
- 1, 2, 1, 2, 1, 1, 3, 3, 4, 2, 2, 2, 1,
- 1, 1, 1, 1, 3, 3, 3, 4, 2, 2, 4, 1, 0,
- 0, 1, 4, 4, 4, 4, 4, 2, 2, 4, 3, 1, 0,
- 0, 1, 4, 2, 2, 2, 4, 2, 2, 4, 1, 0, 0,
- 0, 0, 1, 4, 2, 2, 2, 2, 2, 4, 1, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Left Cursor (Bent)(15x13):
-// Cursor When Over A Hotspot That Allows You To Turn Left 180 Degrees
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingLeftCursorBent[] = {
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 2, 2, 1, 1, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 3, 1, 1,
- 1, 3, 2, 4, 4, 2, 1, 2, 3, 3, 2, 2, 4, 4, 4,
- 1, 2, 4, 3, 3, 4, 1, 2, 1, 3, 4, 2, 2, 2, 2,
- 1, 4, 4, 1, 1, 1, 1, 2, 1, 1, 3, 4, 2, 2, 2,
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 3, 3, 3, 4, 4, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 4, 1, 3, 4, 3, 2,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 4, 2, 2,
- 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 4, 2, 4,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1,
- 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Right Cursor (Bent)(15x13):
-// Cursor When Over A Hotspot That Allows You To Turn Right 180 Degrees
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingRightCursorBent[] = {
- 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 3, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0,
- 4, 4, 4, 2, 2, 3, 3, 2, 1, 2, 4, 4, 2, 3, 1,
- 2, 2, 2, 2, 4, 3, 1, 2, 1, 4, 3, 3, 4, 2, 1,
- 2, 2, 2, 4, 3, 1, 1, 2, 1, 1, 1, 1, 4, 4, 1,
- 2, 4, 4, 3, 3, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1,
- 2, 3, 4, 3, 1, 4, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 2, 2, 4, 3, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 4, 2, 4, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Pointing Down Cursor (Palm Down)(15x16):
-// Similar to Standard Cursor
-//
-// 0 = Transparent
-// 1 = Black (0x000000)
-// 2 = Light Peach (0xEDCD96)
-// 3 = Brown (0x8A672F)
-// 4 = Dark Peach (0xE89A62)
-////////////////////////////////////////
-static const byte s_pointingDownCursorPalmDown[] = {
- 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 1, 3, 4, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
- 0, 1, 3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 1, 3, 4, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
- 1, 3, 4, 2, 2, 2, 2, 2, 2, 2, 4, 1, 0, 0, 0,
- 1, 3, 2, 3, 2, 2, 2, 2, 2, 1, 2, 4, 1, 0, 0,
- 1, 4, 1, 2, 2, 3, 2, 3, 2, 1, 2, 4, 1, 0, 0,
- 1, 4, 1, 4, 1, 4, 1, 4, 4, 1, 1, 2, 3, 1, 0,
- 0, 1, 1, 4, 1, 4, 1, 4, 2, 1, 0, 1, 2, 4, 1,
- 0, 0, 1, 1, 1, 1, 1, 4, 2, 1, 0, 0, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 3, 2, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 4, 4, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Hand Cursor Palette:
-// Palette For All Hand Cursors
-////////////////////////////////////////
-static const byte s_handCursorPalette[] = {
- 0x00, 0x00, 0x00, // Black
- 0xED, 0xCD, 0x96, // Light Peach
- 0x8A, 0x67, 0x2F, // Brown
- 0xE8, 0x9A, 0x62 // Dark Peach
-};
-
-
-////////////////////////////////////////
-// Pellet Cursor (8x8):
-// Cursor When Using The Pellet In The Frog Trap
-//
-// 0 = Transparent
-// 1 = Light Olive Green (0x5D6730)
-// 2 = Maroon (0x5E3333)
-// 3 = Light Gray (0x555555)
-// 4 = Medium Gray (0x444444)
-// 5 = Dark Gray (0x333333)
-// 6 = Dark Green (0x2D3300)
-// 7 = Darkest Gray (0x222222)
-////////////////////////////////////////
-static const byte s_pelletCursor[] = {
- 0, 0, 1, 1, 2, 3, 0, 0,
- 0, 2, 1, 4, 1, 2, 5, 0,
- 4, 1, 4, 1, 2, 1, 5, 4,
- 4, 2, 1, 2, 1, 1, 2, 6,
- 6, 4, 2, 1, 4, 4, 1, 5,
- 5, 6, 5, 2, 1, 2, 4, 4,
- 0, 7, 5, 5, 4, 2, 5, 0,
- 0, 0, 5, 6, 6, 5, 0, 0
-};
-
-////////////////////////////////////////
-// Pellet Cursor Palette:
-// Palette For The Pellet Cursor
-////////////////////////////////////////
-static const byte s_pelletCursorPalette[] = {
- 0x5D, 0x67, 0x30,
- 0x5E, 0x33, 0x33,
- 0x55, 0x55, 0x55,
- 0x44, 0x44, 0x44,
- 0x33, 0x33, 0x33,
- 0x2D, 0x33, 0x00,
- 0x22, 0x22, 0x22
-};
-
-////////////////////////////////////////
-// Red Marble Cursor (12x12):
-// Cursor When Holding The Red Marble
-////////////////////////////////////////
-static const byte s_redMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 2, 5, 2, 2, 2, 2, 0, 0,
- 0, 6, 1, 1, 2, 2, 5, 2, 2, 2, 2, 0,
- 0, 6, 3, 4, 5, 2, 2, 7, 8, 5, 2, 0,
- 9, 6, 10,11,2, 2, 2, 12,13,2, 2, 2,
- 14,10,6, 4, 1, 2, 8, 2, 2, 5, 2, 2,
- 15,16,6, 3, 1, 2, 2, 2, 2, 2, 2, 5,
- 17,9,18, 3, 4, 4, 4, 5, 2, 5, 1, 2,
- 0, 16,9, 6, 6, 19,1, 20,1, 4, 11,0,
- 0, 17,15,18,9, 10,6, 10,3, 21,4, 0,
- 0, 0, 18,15,9, 18,6, 22,10,23,0, 0,
- 0, 0, 0, 0, 15,15,16,9, 0, 0, 0, 0
-};
-
-
-////////////////////////////////////////
-// Red Marble Cursor Palette:
-// Palette For The Red Marble Cursor
-////////////////////////////////////////
-static const byte s_redMarbleCursorPalette[] = {
- 0xb8, 0x33, 0x32,
- 0xe5, 0x33, 0x31,
- 0x98, 0x06, 0x00,
- 0xb8, 0x00, 0x34,
- 0xe6, 0x00, 0x34,
- 0x7a, 0x04, 0x00,
- 0xe8, 0x9a, 0x62,
- 0xea, 0x31, 0x67,
- 0x6a, 0x03, 0x00,
- 0x8c, 0x00, 0x35,
- 0xb6, 0x36, 0x00,
- 0xed, 0xcd, 0x96,
- 0xe9, 0x66, 0x65,
- 0x5b, 0x35, 0x00,
- 0x5b, 0x02, 0x00,
- 0x5f, 0x00, 0x35,
- 0x4c, 0x01, 0x00,
- 0x5e, 0x33, 0x33,
- 0x89, 0x05, 0x00,
- 0xb6, 0x08, 0x00,
- 0xa7, 0x07, 0x00,
- 0x88, 0x36, 0x00,
- 0x8b, 0x33, 0x33
-};
-
-////////////////////////////////////////
-// Orange Marble Cursor (12x12):
-// Cursor When Holding The Orange Marble
-////////////////////////////////////////
-static const byte s_orangeMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 2, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 2, 3, 3, 3, 3, 0, 0,
- 0, 6, 7, 4, 2, 1, 2, 2, 3, 3, 3, 0,
- 0, 6, 6, 7, 1, 2, 3, 8, 9, 2, 10,0,
- 11,12,7, 4, 2, 3, 3, 13,9, 2, 2, 1,
- 14,15,6, 4, 2, 16,3, 3, 2, 1, 1, 1,
- 14,14,12,17,4, 2, 2, 1, 2, 1, 2, 1,
- 14,18,12,6, 4, 4, 4, 19,2, 19,20,4,
- 0, 14,14,15,6, 15,6, 4, 4, 4, 4, 0,
- 0, 14,11,14,14,12,12,12,17,6, 17,0,
- 0, 0, 14,14,17,14,17,6, 6, 17,0, 0,
- 0, 0, 0, 0, 14,11,14,11,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Orange Marble Cursor Palette:
-// Palette For The Orange Marble Cursor
-////////////////////////////////////////
-static const byte s_orangeMarbleCursorPalette[] = {
- 0xe1, 0x9e, 0x00,
- 0xe3, 0x9b, 0x28,
- 0xe2, 0xcf, 0x20,
- 0xb5, 0x6a, 0x00,
- 0xb6, 0x9b, 0x29,
- 0x87, 0x69, 0x00,
- 0xb7, 0x67, 0x2f,
- 0xe9, 0xff, 0x93,
- 0xe1, 0xff, 0x5a,
- 0xe0, 0xd0, 0x00,
- 0x5e, 0x33, 0x33,
- 0x88, 0x36, 0x00,
- 0xf3, 0xff, 0xc9,
- 0x5b, 0x35, 0x00,
- 0x8b, 0x33, 0x33,
- 0xe6, 0xce, 0x5f,
- 0x8a, 0x67, 0x2f,
- 0x5d, 0x67, 0x30,
- 0xe2, 0x6a, 0x00,
- 0xb3, 0x9d, 0x00
-};
-
-////////////////////////////////////////
-// Yellow Marble Cursor (12x12):
-// Cursor When Holding The Yellow Marble
-////////////////////////////////////////
-static const byte s_yellowMarbleCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 1, 1, 1, 5, 6, 6, 0, 0,
- 0, 3, 3, 7, 1, 1, 1, 1, 2, 1, 6, 0,
- 0, 3, 3, 3, 3, 1, 1, 8, 6, 1, 6, 0,
- 9, 9, 3, 3, 1, 1, 2, 10,8, 1, 1, 2,
- 11,9, 3, 3, 1, 1, 1, 1, 1, 1, 5, 1,
- 9, 9, 12,3, 3, 1, 1, 1, 1, 1, 1, 1,
- 9, 9, 9, 3, 3, 3, 3, 3, 1, 1, 1, 1,
- 0, 11,9, 9, 12,3, 3, 3, 3, 3, 3, 0,
- 0, 9, 9, 13,9, 14,12,3, 3, 3, 3, 0,
- 0, 0, 9, 9, 9, 12,14,3, 13,3, 0, 0,
- 0, 0, 0, 0, 11,9, 11,9, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Yellow Marble Cursor Palette:
-// Palette For The Yellow Marble Cursor
-////////////////////////////////////////
-static const byte s_yellowMarbleCursorPalette[] = {
- 0xb3, 0xd0, 0x00,
- 0xb0, 0xff, 0x00,
- 0x86, 0x9c, 0x00,
- 0x87, 0xd0, 0x00,
- 0xe0, 0xd0, 0x00,
- 0xdc, 0xff, 0x00,
- 0xb3, 0x9d, 0x00,
- 0xdc, 0xff, 0x11,
- 0x5a, 0x68, 0x00,
- 0xe1, 0xff, 0x5a,
- 0x5d, 0x67, 0x30,
- 0x87, 0x69, 0x00,
- 0x88, 0x9b, 0x2a,
- 0x5a, 0x9c, 0x00
-};
-
-////////////////////////////////////////
-// Green Marble Cursor (12x12):
-// Cursor When Holding The Green Marble
-////////////////////////////////////////
-static const byte s_greenMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 1, 2, 3, 6, 6, 0, 0,
- 0, 7, 5, 8, 8, 1, 1, 2, 3, 6, 6, 0,
- 0, 7, 7, 4, 8, 1, 2, 9, 6, 2, 6, 0,
- 10,7, 7, 4, 1, 2, 3, 11,12,2, 2, 3,
- 13,13,7, 4, 1, 2, 3, 2, 1, 2, 2, 3,
- 14,13,7, 7, 5, 1, 1, 8, 2, 1, 1, 2,
- 15,16,13,7, 4, 4, 5, 5, 1, 8, 1, 1,
- 0, 15,13,7, 7, 7, 4, 4, 4, 5, 8, 0,
- 0, 14,16,15,13, 7, 7, 7, 4,17,5, 0,
- 0, 0, 10,16,13,13,13,17,18,17,0, 0,
- 0, 0, 0, 0, 15,10,19,10,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Green Marble Cursor Palette:
-// Palette For The Green Marble Cursor
-////////////////////////////////////////
-static const byte s_greenMarbleCursorPalette[] = {
- 0x0e, 0xd0, 0x00,
- 0x0f, 0xe1, 0x00,
- 0x10, 0xf2, 0x00,
- 0x0b, 0x9c, 0x00,
- 0x0c, 0xad, 0x00,
- 0x11, 0xff, 0x00,
- 0x09, 0x8a, 0x00,
- 0x0d, 0xbe, 0x00,
- 0x30, 0xff, 0x5a,
- 0x0d, 0x67, 0x30,
- 0x6b, 0xff, 0x92,
- 0x00, 0xff, 0x28,
- 0x08, 0x79, 0x00,
- 0x05, 0x57, 0x00,
- 0x30, 0x67, 0x30,
- 0x06, 0x68, 0x00,
- 0x00, 0x9b, 0x2c,
- 0x2e, 0x9c, 0x00,
- 0x2e, 0x68, 0x00
-};
-
-////////////////////////////////////////
-// Blue Marble Cursor (12x12):
-// Cursor When Holding The Blue Marble
-////////////////////////////////////////
-static const byte s_blueMarbleCursor[] = {
- 0, 0, 0, 0, 1, 2, 3, 3, 0, 0, 0, 0,
- 0, 0, 4, 5, 2, 2, 6, 3, 7, 3, 0, 0,
- 0, 8, 9, 5, 10,11,2, 6, 3, 3, 7, 0,
- 0, 12,13,9, 10,11,6, 14,7, 6, 3, 0,
- 15,8, 4, 13,2, 6, 3, 16,17,6, 6, 3,
- 18,15,19,13,10,7, 3, 6, 2, 2, 6, 7,
- 20,8, 18,4, 21,11,2, 10,6, 2, 2, 2,
- 15,15,18,8, 13,9, 21,5, 11,10,2, 1,
- 0, 8, 15,19,15,13,13,21,21,5, 9, 0,
- 0, 22,20,15, 8,19,15,19,4, 9, 4, 0,
- 0, 0, 15,20,15,15,19,15,9, 15,0, 0,
- 0, 0, 0, 0, 20,15, 8,15,0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Blue Marble Cursor Palette:
-// Palette For The Blue Marble Cursor
-////////////////////////////////////////
-static const byte s_blueMarbleCursorPalette[] = {
- 0x6b, 0x00, 0xd2,
- 0x66, 0x00, 0xe3,
- 0x72, 0x00, 0xff,
- 0x53, 0x2d, 0x9d,
- 0x4e, 0x00, 0xaf,
- 0x6d, 0x00, 0xf5,
- 0x7d, 0x00, 0xff,
- 0x44, 0x00, 0x69,
- 0x56, 0x00, 0x9d,
- 0x56, 0x00, 0xc0,
- 0x5e, 0x00, 0xd2,
- 0x2b, 0x31, 0x68,
- 0x3f, 0x00, 0x8c,
- 0x91, 0x22, 0xff,
- 0x41, 0x31, 0x68,
- 0xd7, 0x95, 0xff,
- 0x77, 0x22, 0xff,
- 0x2f, 0x00, 0x69,
- 0x37, 0x00, 0x7a,
- 0x27, 0x00, 0x58,
- 0x46, 0x00, 0x9d,
- 0x33, 0x33, 0x33
-};
-
-////////////////////////////////////////
-// Violet Marble Cursor (12x12):
-// Cursor When Holding The Violet Marble
-////////////////////////////////////////
-static const byte s_violetMarbleCursor[] = {
- 0, 0, 0, 0, 1, 1, 1, 2, 0, 0, 0, 0,
- 0, 0, 3, 3, 1, 1, 1, 4, 2, 4, 0, 0,
- 0, 3, 3, 3, 1, 5, 1, 1, 4, 2, 4, 0,
- 0, 3, 3, 3, 3, 1, 1, 6, 4, 1, 2, 0,
- 3, 7, 8, 3, 1, 1, 4, 9, 4, 1, 1, 4,
- 8, 7, 8, 3, 10,4, 1, 1, 1, 1, 4, 1,
- 8, 3, 8, 7, 3, 1, 1, 5, 1, 1, 1, 1,
- 7, 7, 11,3, 3, 3, 3, 3, 1, 3, 1, 1,
- 0, 8, 7, 7, 8, 8, 7, 3, 3, 3, 1, 0,
- 0, 7, 8, 3, 11,7, 3, 11,3, 10,3, 0,
- 0, 0, 8, 7, 3, 3, 7, 3, 3, 3, 0, 0,
- 0, 0, 0, 0, 8, 7, 11,3, 0, 0, 0, 0
-};
-
-////////////////////////////////////////
-// Violet Marble Cursor Palette:
-// Palette For The Violet Marble Cursor
-////////////////////////////////////////
-static const byte s_violetMarbleCursorPalette[] = {
- 0xaa, 0x00, 0xd1,
- 0xd8, 0x00, 0xff,
- 0x76, 0x00, 0x9d,
- 0xb5, 0x00, 0xff,
- 0x87, 0x00, 0xd2,
- 0xd7, 0x22, 0xff,
- 0x68, 0x00, 0x69,
- 0x44, 0x00, 0x69,
- 0xd7, 0x5e, 0xff,
- 0x9c, 0x00, 0x9d,
- 0x56, 0x00, 0x9d
-};
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 7da5515411..5424a07a3c 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -216,20 +216,37 @@ void RivenExternal::runDemoBoundaryDialog() {
dialog.runModal();
}
-void RivenExternal::runEndGame(uint16 video) {
+void RivenExternal::runEndGame(uint16 video, uint32 delay) {
_vm->_sound->stopAllSLST();
_vm->_video->playMovieRiven(video);
- runCredits(video);
+ runCredits(video, delay);
}
-void RivenExternal::runCredits(uint16 video) {
- // TODO: Play until the last frame and then run the credits
+void RivenExternal::runCredits(uint16 video, uint32 delay) {
+ // Initialize our credits state
+ _vm->_cursor->hideCursor();
+ _vm->_gfx->beginCredits();
+ uint nextCreditsFrameStart = 0;
VideoHandle videoHandle = _vm->_video->findVideoHandleRiven(video);
- while (!_vm->_video->endOfVideo(videoHandle) && !_vm->shouldQuit()) {
- if (_vm->_video->updateMovies())
- _vm->_system->updateScreen();
+ while (!_vm->shouldQuit() && _vm->_gfx->getCurCreditsImage() <= 320) {
+ if (_vm->_video->getCurFrame(videoHandle) >= (int32)_vm->_video->getFrameCount(videoHandle) - 1) {
+ if (nextCreditsFrameStart == 0) {
+ // Set us up to start after delay ms
+ nextCreditsFrameStart = _vm->_system->getMillis() + delay;
+ } else if (_vm->_system->getMillis() >= nextCreditsFrameStart) {
+ // the first two frames stay on for 5 seconds
+ // the rest of the scroll updates happen at 30Hz
+ if (_vm->_gfx->getCurCreditsImage() < 304)
+ nextCreditsFrameStart = _vm->_system->getMillis() + 5000;
+ else
+ nextCreditsFrameStart = _vm->_system->getMillis() + 1000 / 30;
+
+ _vm->_gfx->updateCredits();
+ }
+ } else if (_vm->_video->updateMovies())
+ _vm->_system->updateScreen();
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event))
@@ -316,6 +333,7 @@ void RivenExternal::checkSliderCursorChange(uint16 startHotspot) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
break;
}
}
@@ -341,6 +359,7 @@ void RivenExternal::dragDomeSlider(uint16 soundId, uint16 resetSlidersHotspot, u
// We've clicked down, so show the closed hand cursor
_vm->_cursor->setCursor(kRivenClosedHandCursor);
+ _vm->_system->updateScreen();
bool done = false;
while (!done) {
@@ -862,6 +881,7 @@ void RivenExternal::xbcheckcatch(uint16 argc, uint16 *argv) {
void RivenExternal::xbait(uint16 argc, uint16 *argv) {
// Set the cursor to the pellet
_vm->_cursor->setCursor(kRivenPelletCursor);
+ _vm->_system->updateScreen();
// Loop until the player lets go (or quits)
Common::Event event;
@@ -881,6 +901,7 @@ void RivenExternal::xbait(uint16 argc, uint16 *argv) {
// Set back the cursor
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
// Set the bait if we put it on the plate
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -899,8 +920,8 @@ void RivenExternal::xbfreeytram(uint16 argc, uint16 *argv) {
void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) {
// Remove the pellet from the plate and put it in your hand
_vm->_gfx->drawPLST(3);
- _vm->_gfx->updateScreen();
_vm->_cursor->setCursor(kRivenPelletCursor);
+ _vm->_gfx->updateScreen();
// Loop until the player lets go (or quits)
Common::Event event;
@@ -920,6 +941,7 @@ void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) {
// Set back the cursor
_vm->_cursor->setCursor(kRivenMainCursor);
+ _vm->_system->updateScreen();
// Set the bait if we put it on the plate, remove otherwise
if (_vm->_hotspots[9].rect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -988,23 +1010,27 @@ void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) {
if (*valve == 0 && changeY <= -10) {
*valve = 1;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(2);
_vm->refreshCard();
} else if (*valve == 1) {
if (changeX >= 0 && changeY >= 10) {
*valve = 0;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(3);
_vm->refreshCard();
} else if (changeX <= -10 && changeY <= 10) {
*valve = 2;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(1);
_vm->refreshCard();
}
} else if (*valve == 2 && changeX >= 10) {
*valve = 1;
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(4);
_vm->refreshCard();
}
@@ -1219,6 +1245,7 @@ void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) {
void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) {
// Play the deactivation of a pool if one is active and a different one is activated
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_video->playMovieBlockingRiven(*_vm->getVar("glkbtns") * 2);
}
@@ -1522,11 +1549,13 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) {
// Run the gallows's carriage
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
- _vm->_video->playMovieBlockingRiven(1); // Play handle movie
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(1); // Play handle movie
_vm->_gfx->scheduleTransition(15); // Set pan down transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18e77)); // Change to card facing up
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor (again)
- _vm->_video->playMovieBlockingRiven(4); // Play carriage beginning to drop
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(4); // Play carriage beginning to drop
_vm->_gfx->scheduleTransition(14); // Set pan up transition
_vm->changeToCard(_vm->matchRMAPToCard(0x183a9)); // Change to card looking straight again
_vm->_video->playMovieBlockingRiven(2);
@@ -1560,19 +1589,22 @@ void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) {
}
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
+ _vm->_system->updateScreen(); // Update
if (gotClick) {
_vm->_gfx->scheduleTransition(16); // Schedule dissolve transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18d4d)); // Move forward
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
+ _vm->_system->updateScreen(); // Update
_vm->_system->delayMillis(500); // Delay a half second before changing again
_vm->_gfx->scheduleTransition(12); // Schedule pan left transition
_vm->changeToCard(_vm->matchRMAPToCard(0x18ab5)); // Turn right
_vm->_cursor->setCursor(kRivenHideCursor); // Hide the cursor
- _vm->_video->playMovieBlockingRiven(1); // Play carriage ride movie
+ _vm->_system->updateScreen(); // Update
+ _vm->_video->playMovieBlockingRiven(1); // Play carriage ride movie
_vm->changeToCard(_vm->matchRMAPToCard(0x17167)); // We have arrived at the top
} else
- _vm->_video->playMovieBlockingRiven(3); // Too slow!
+ _vm->_video->playMovieBlockingRiven(3); // Too slow!
}
void RivenExternal::xjdome25_resetsliders(uint16 argc, uint16 *argv) {
@@ -1603,6 +1635,7 @@ int RivenExternal::jspitElevatorLoop() {
_vm->_cursor->setCursor(kRivenClosedHandCursor);
_vm->_system->updateScreen();
+
for (;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch (event.type) {
@@ -1766,6 +1799,7 @@ void RivenExternal::xschool280_playwhark(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// Play the spin movie
_vm->_video->playMovieBlockingRiven(spinMLST);
@@ -1821,16 +1855,17 @@ void RivenExternal::xorollcredittime(uint16 argc, uint16 *argv) {
uint32 *gehnState = _vm->getVar("agehn");
if (*gehnState == 0) // Gehn who?
- runEndGame(1);
+ runEndGame(1, 9500);
else if (*gehnState == 4) // You freed him? Are you kidding me?
- runEndGame(2);
+ runEndGame(2, 12000);
else // You already spoke with Gehn. What were you thinking?
- runEndGame(3);
+ runEndGame(3, 8000);
}
void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// Let's hook onto our video
VideoHandle video = _vm->_video->findVideoHandleRiven(argv[0]);
@@ -1873,6 +1908,8 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
+
+ _vm->_system->updateScreen();
// OK, Gehn has opened the trap book and has asked us to go in. Let's watch
// and see what the player will do...
@@ -1887,7 +1924,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_cursor->setCursor(kRivenOpenHandCursor);
else
_vm->_cursor->setCursor(kRivenMainCursor);
- updateScreen = false; // Don't update twice, changing the cursor already updates the screen
+ updateScreen = true;
break;
case Common::EVENT_LBUTTONUP:
if (hotspotRect.contains(_vm->_system->getEventManager()->getMousePos())) {
@@ -1899,11 +1936,11 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
_vm->_gfx->updateScreen(); // Update the screen
_vm->_sound->playSound(0); // Play the link sound
_vm->_video->activateMLST(7, _vm->getCurCard()); // Activate Gehn Link Video
- _vm->_video->playMovieBlockingRiven(1); // Play Gehn Link Video
+ _vm->_video->playMovieBlockingRiven(1); // Play Gehn Link Video
*_vm->getVar("agehn") = 4; // Set Gehn to the trapped state
*_vm->getVar("atrapbook") = 1; // We've got the trap book again
_vm->_sound->playSound(0); // Play the link sound again
- _vm->changeToCard(_vm->matchRMAPToCard(0x2885)); // Link out! (TODO: Shouldn't this card change?)
+ _vm->changeToCard(_vm->matchRMAPToCard(0x2885)); // Link out!
return;
}
break;
@@ -1924,13 +1961,14 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) {
// Hide the cursor again
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
// If there was no click and this is the third time Gehn asks us to
// use the trap book, he will shoot the player. Dead on arrival.
// Run the credits from here.
if (*_vm->getVar("agehn") == 3) {
_vm->_scriptMan->stopAllScripts();
- runCredits(argv[0]);
+ runCredits(argv[0], 5000);
return;
}
@@ -2012,6 +2050,7 @@ uint16 RivenExternal::getComboDigit(uint32 correctCombo, uint32 digit) {
void RivenExternal::xgwatch(uint16 argc, uint16 *argv) {
// Hide the cursor
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
uint32 *prisonCombo = _vm->getVar("pcorrectorder");
uint32 soundTime = _vm->_system->getMillis() - 500; // Start the first sound instantly
@@ -2104,7 +2143,7 @@ void RivenExternal::xrcredittime(uint16 argc, uint16 *argv) {
// For the record, when agehn == 4, Gehn will thank you for
// showing him the rebel age and then leave you to die.
// Otherwise, the rebels burn the book. Epic fail either way.
- runEndGame(1);
+ runEndGame(1, 1500);
}
void RivenExternal::xrshowinventory(uint16 argc, uint16 *argv) {
@@ -2144,35 +2183,32 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) {
if (*_vm->getVar("pcage") == 2) {
// The best ending: Catherine is free, Gehn is trapped, Atrus comes to rescue you.
// And now we fall back to Earth... all the way...
- warning("xtexterior300_telescopedown: Good ending");
_vm->_video->activateMLST(8, _vm->getCurCard());
- runEndGame(8);
+ runEndGame(8, 5000);
} else if (*_vm->getVar("agehn") == 4) {
// The ok ending: Catherine is still trapped, Gehn is trapped, Atrus comes to rescue you.
// Nice going! Catherine and the islanders are all dead now! Just go back to your home...
- warning("xtexterior300_telescopedown: OK ending");
_vm->_video->activateMLST(9, _vm->getCurCard());
- runEndGame(9);
+ runEndGame(9, 5000);
} else if (*_vm->getVar("atrapbook") == 1) {
// The bad ending: Catherine is trapped, Gehn is free, Atrus gets shot by Gehn,
// And then you get shot by Cho. Nice going! Catherine and the islanders are dead
// and you have just set Gehn free from Riven, not to mention you're dead.
- warning("xtexterior300_telescopedown: Bad ending");
_vm->_video->activateMLST(10, _vm->getCurCard());
- runEndGame(10);
+ runEndGame(10, 5000);
} else {
// The impossible ending: You don't have Catherine's journal and yet you were somehow
// able to open the hatch on the telescope. The game provides an ending for those who
// cheat, load a saved game with the combo, or just guess the telescope combo. Atrus
// doesn't come and you just fall into the fissure.
- warning("xtexterior300_telescopedown: Wtf ending");
_vm->_video->activateMLST(11, _vm->getCurCard());
- runEndGame(11);
+ runEndGame(11, 5000);
}
} else {
// ...the telescope can't move down anymore.
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_sound->playSoundBlocking(13);
}
} else {
@@ -2206,6 +2242,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) {
if (*telescopePos == 5) {
// Play the sound of not being able to move
_vm->_cursor->setCursor(kRivenHideCursor);
+ _vm->_system->updateScreen();
_vm->_sound->playSoundBlocking(13);
return;
}
diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h
index 818bc06c54..90fdc664c1 100644
--- a/engines/mohawk/riven_external.h
+++ b/engines/mohawk/riven_external.h
@@ -61,8 +61,8 @@ private:
// Supplementary Functions
int jspitElevatorLoop();
void runDemoBoundaryDialog();
- void runEndGame(uint16 video);
- void runCredits(uint16 video);
+ void runEndGame(uint16 video, uint32 delay);
+ void runCredits(uint16 video, uint32 delay);
void runDomeCheck();
void runDomeButtonMovie();
void resetDomeSliders(uint16 soundId, uint16 startHotspot);
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index 5d459354e9..98452e1e09 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -424,6 +424,7 @@ void RivenScript::stopSound(uint16 op, uint16 argc, uint16 *argv) {
void RivenScript::changeCursor(uint16 op, uint16 argc, uint16 *argv) {
debug(2, "Change to cursor %d", argv[0]);
_vm->_cursor->setCursor(argv[0]);
+ _vm->_system->updateScreen();
}
// Command 14: pause script execution (delay in ms, u1)
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index d77ac858c8..db93333b81 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -40,12 +40,14 @@
#include "sci/sound/music.h"
#include "sci/sound/drivers/mididriver.h"
#include "sci/sound/drivers/map-mt32-to-gm.h"
+#include "sci/graphics/cache.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint.h"
#include "sci/graphics/paint16.h"
#include "sci/graphics/paint32.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/view.h"
#include "sci/parser/vocabulary.h"
@@ -1434,7 +1436,7 @@ bool Console::cmdSaid(int argc, const char **argv) {
_engine->getVocabulary()->dumpParseTree();
_engine->getVocabulary()->parserIsValid = true;
- int ret = said(_engine->_gamestate, (byte*)spec, true);
+ int ret = said((byte*)spec, true);
DebugPrintf("kSaid: %s\n", (ret == SAID_NO_MATCH ? "No match" : "Match"));
}
@@ -1503,7 +1505,14 @@ bool Console::cmdDrawCel(int argc, const char **argv) {
uint16 loopNo = atoi(argv[2]);
uint16 celNo = atoi(argv[3]);
- _engine->_gfxPaint->kernelDrawCel(resourceId, loopNo, celNo, 50, 50, 0, 0, false, NULL_REG);
+ if (_engine->_gfxPaint16) {
+ _engine->_gfxPaint16->kernelDrawCel(resourceId, loopNo, celNo, 50, 50, 0, 0, 128, 128, false, NULL_REG);
+ } else {
+ GfxView *view = _engine->_gfxCache->getView(resourceId);
+ Common::Rect celRect(50, 50, 50 + view->getWidth(loopNo, celNo), 50 + view->getHeight(loopNo, celNo));
+ view->draw(celRect, celRect, celRect, loopNo, celNo, 255, 0, false);
+ _engine->_gfxScreen->copyRectToScreen(celRect);
+ }
return true;
}
@@ -2189,7 +2198,7 @@ bool Console::cmdStack(int argc, const char **argv) {
return true;
}
- ExecStack &xs = _engine->_gamestate->_executionStack.back();
+ const ExecStack &xs = _engine->_gamestate->_executionStack.back();
int nr = atoi(argv[1]);
for (int i = nr; i > 0; i--) {
@@ -2438,12 +2447,12 @@ bool Console::cmdScriptSteps(int argc, const char **argv) {
bool Console::cmdBacktrace(int argc, const char **argv) {
DebugPrintf("Call stack (current base: 0x%x):\n", _engine->_gamestate->executionStackBase);
- Common::List<ExecStack>::iterator iter;
+ Common::List<ExecStack>::const_iterator iter;
uint i = 0;
for (iter = _engine->_gamestate->_executionStack.begin();
iter != _engine->_gamestate->_executionStack.end(); ++iter, ++i) {
- ExecStack &call = *iter;
+ const ExecStack &call = *iter;
const char *objname = _engine->_gamestate->_segMan->getObjectName(call.sendp);
int paramc, totalparamc;
@@ -2607,7 +2616,7 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
int selectorId = _engine->getKernel()->findSelector(argv[2]);
- reg_t addr;
+ reg_t addr = NULL_REG;
if (!obj) {
DebugPrintf("Not an object.");
@@ -2626,13 +2635,22 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
for (int i = 3; i < argc; i++) {
if (!scumm_stricmp(argv[i], "bwt"))
- printBytecode = true;
- else if (!scumm_stricmp(argv[i], "bc"))
printBWTag = true;
+ else if (!scumm_stricmp(argv[i], "bc"))
+ printBytecode = true;
}
+ reg_t farthestTarget = addr;
do {
+ reg_t prevAddr = addr;
+ reg_t jumpTarget;
+ if (isJumpOpcode(_engine->_gamestate, addr, jumpTarget)) {
+ if (jumpTarget > farthestTarget)
+ farthestTarget = jumpTarget;
+ }
addr = disassemble(_engine->_gamestate, addr, printBWTag, printBytecode);
+ if (addr.isNull() && prevAddr < farthestTarget)
+ addr = prevAddr + 1; // skip past the ret
} while (addr.offset > 0);
return true;
@@ -2699,26 +2717,29 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) {
int scriptSegment;
Script *script;
- SegManager *segMan = _engine->getEngineState()->_segMan;
+ // Create a custom segment manager here, so that the game's segment
+ // manager won't be affected by loading and unloading scripts here.
+ SegManager *customSegMan = new SegManager(_engine->getResMan());
while (itr != resources->end()) {
- if (_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) {
- // Ignore script 980 in KQ5. Seems to be a leftover, as it
- // uses a superclass from script 988, which doesn't exist
+ // Ignore specific leftover scripts, which require other non-existing scripts
+ if ((_engine->getGameId() == GID_HOYLE3 && itr->getNumber() == 995) ||
+ (_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) ||
+ (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947)) {
itr++;
continue;
}
// Load script
- scriptSegment = segMan->instantiateScript(itr->getNumber());
- script = segMan->getScript(scriptSegment);
+ scriptSegment = customSegMan->instantiateScript(itr->getNumber());
+ script = customSegMan->getScript(scriptSegment);
// Iterate through all the script's objects
ObjMap::iterator it;
const ObjMap::iterator end = script->_objects.end();
for (it = script->_objects.begin(); it != end; ++it) {
- const Object *obj = segMan->getObject(it->_value.getPos());
- const char *objName = segMan->getObjectName(it->_value.getPos());
+ const Object *obj = customSegMan->getObject(it->_value.getPos());
+ const char *objName = customSegMan->getObjectName(it->_value.getPos());
// Now dissassemble each method of the script object
for (uint16 i = 0; i < obj->getMethodCount(); i++) {
@@ -2761,10 +2782,12 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) {
} // for (uint16 i = 0; i < obj->getMethodCount(); i++)
} // for (it = script->_objects.begin(); it != end; ++it)
- segMan->uninstantiateScript(itr->getNumber());
+ customSegMan->uninstantiateScript(itr->getNumber());
++itr;
}
+ delete customSegMan;
+
delete resources;
}
@@ -3758,11 +3781,16 @@ int Console::printObject(reg_t pos) {
return 0;
}
+static void printChar(byte c) {
+ if (c < 32 || c >= 127)
+ c = '.';
+ debugN("%c", c);
+}
+
void Console::hexDumpReg(const reg_t *data, int len, int regsPerLine, int startOffset, bool isArray) {
// reg_t version of Common::hexdump
assert(1 <= regsPerLine && regsPerLine <= 8);
int i;
- byte c;
int offset = startOffset;
while (len >= regsPerLine) {
debugN("%06x: ", offset);
@@ -3771,14 +3799,13 @@ void Console::hexDumpReg(const reg_t *data, int len, int regsPerLine, int startO
}
debugN(" |");
for (i = 0; i < regsPerLine; i++) {
- c = data[i].toUint16() & 0xff;
- if (c < 32 || c >= 127)
- c = '.';
- debugN("%c", c);
- c = data[i].toUint16() >> 8;
- if (c < 32 || c >= 127)
- c = '.';
- debugN("%c", c);
+ if (g_sci->isBE()) {
+ printChar(data[i].toUint16() >> 8);
+ printChar(data[i].toUint16() & 0xff);
+ } else {
+ printChar(data[i].toUint16() & 0xff);
+ printChar(data[i].toUint16() >> 8);
+ }
}
debugN("|\n");
data += regsPerLine;
@@ -3798,14 +3825,13 @@ void Console::hexDumpReg(const reg_t *data, int len, int regsPerLine, int startO
}
debugN(" |");
for (i = 0; i < len; i++) {
- c = data[i].toUint16() & 0xff;
- if (c < 32 || c >= 127)
- c = '.';
- debugN("%c", c);
- c = data[i].toUint16() >> 8;
- if (c < 32 || c >= 127)
- c = '.';
- debugN("%c", c);
+ if (g_sci->isBE()) {
+ printChar(data[i].toUint16() >> 8);
+ printChar(data[i].toUint16() & 0xff);
+ } else {
+ printChar(data[i].toUint16() & 0xff);
+ printChar(data[i].toUint16() >> 8);
+ }
}
for (; i < regsPerLine; i++)
debugN(" ");
diff --git a/engines/sci/console.h b/engines/sci/console.h
index b0a1de6ebd..d45454376a 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -37,6 +37,7 @@ class SciEngine;
struct List;
reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode);
+bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpOffset);
class Console : public GUI::Debugger {
public:
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index c1c13a0894..923d35fe16 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -1992,31 +1992,31 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
- // Larry 6 - English/German/French DOS CD - LORES
+ // Larry 6 - English/German/French DOS CD - LOWRES
// SCI interpreter version 1.001.115
{"lsl6", "", {
{"resource.map", 0, "0b91234b7112782962cb480b7791b6e2", 7263},
{"resource.000", 0, "57d5fe8bb9e044158514476ea7678eb0", 5754790},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
+ Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO_NONE },
- // Larry 6 - German DOS CD - LORES (provided by richiefs in bug report #2670691)
+ // Larry 6 - German DOS CD - LOWRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 1.001.115
{"lsl6", "", {
{"resource.map", 0, "bafe85f32738854135991d4324ad147e", 7268},
{"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5773160},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformPC, 0, GUIO_NONE },
+ Common::DE_DEU, Common::kPlatformPC, ADGF_CD, GUIO_NONE },
- // Larry 6 - French DOS CD - LORES (provided by richiefs in bug report #2670691)
+ // Larry 6 - French DOS CD - LOWRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 1.001.115
{"lsl6", "", {
{"resource.map", 0, "97797ea775baaf18a1907d357d3c0ea6", 7268},
{"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5776092},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NONE },
+ Common::FR_FRA, Common::kPlatformPC, ADGF_CD, GUIO_NONE },
- // Larry 6 - Spanish DOS - LORES (from the Leisure Suit Larry Collection)
+ // Larry 6 - Spanish DOS - LOWRES (from the Leisure Suit Larry Collection)
// Executable scanning reports "1.001.113", VERSION file reports "1.000, 11.06.93, FIVE PATCHES ADDED TO DISK 6 ON 11-18-93"
{"lsl6", "", {
{"resource.map", 0, "633bf8f42170b6271019917c8009989b", 6943},
@@ -2628,6 +2628,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
+ // Police Quest: SWAT - English DOS (from GOG.com)
+ // Executable scanning reports "2.100.002", VERSION file reports "1.0c"
+ {"pqswat", "", {
+ {"resmap.000", 0, "1c2563fee189885e29d9348f37306d94", 12175},
+ {"ressci.000", 0, "b2e1826ca81ce2e7e764587f5a14eee9", 127149181},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NONE },
+
// Police Quest: SWAT - English Windows (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
// Original DOS/Windows release VERSION file reports "1.000" is the same
@@ -2641,7 +2649,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.004", 0, "4228038906f041623e65789500b22285", 6835},
{"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NOSPEECH },
+ Common::EN_ANY, Common::kPlatformWindows, 0, GUIO_NONE },
#endif // ENABLE_SCI32
// Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784)
@@ -2656,6 +2664,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+ // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by alonzotg in bug report #3206006)
+ {"qfg1", "", {
+ {"resource.map", 0, "85512508ed4e4ef1e3b309adabceeda9", 6486},
+ {"resource.000", 0, "481b034132106390cb5160fe61dd5f58", 80334},
+ {"resource.001", 0, "4d67acf52833ff45c7f753d6663532e8", 462729},
+ {"resource.002", 0, "439ba9b6dde216e6eb97ef3a9830fbe4", 647244},
+ {"resource.003", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 642203},
+ {"resource.004", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 641688},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH },
+
// Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by markcoolio in bug report #2723843)
// Executable scanning reports "0.000.566"
{"qfg1", "", {
@@ -2709,7 +2728,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH },
- // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes english language)
+ // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes English language)
// Executable scanning reports "S.old.201"
{"qfg1", "8 Colors", {
{"resource.map", 0, "5cbeb95dd2a4b7cb242b415cc6ec1c47", 6444},
@@ -2719,7 +2738,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO_NOSPEECH },
- // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes english language)
+ // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes English language)
// Executable scanning reports "S.old.201"
{"qfg1", "16 Colors", {
{"resource.map", 0, "3ecaba33bf77cb434067a0b8aee15097", 6444},
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 206624f87e..964097f57d 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -285,20 +285,16 @@ SciVersion GameFeatures::detectLofsType() {
}
// Find a function of the "Game" object (which is the game super class) which invokes lofsa/lofss
- reg_t gameSuperClass = g_sci->getGameSuperClassAddress();
+ const Object *gameObject = _segMan->getObject(g_sci->getGameObject());
+ const Object *gameSuperObject = _segMan->getObject(gameObject->getSuperClassSelector());
bool found = false;
- if (!gameSuperClass.isNull()) {
- Common::String gameSuperClassName = _segMan->getObjectName(gameSuperClass);
- const Object *gameSuperObject = _segMan->getObject(gameSuperClass);
+ if (gameSuperObject) {
+ Common::String gameSuperClassName = _segMan->getObjectName(gameObject->getSuperClassSelector());
- if (gameSuperObject) {
- for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) {
- found = autoDetectLofsType(gameSuperClassName, m);
- if (found)
- break;
- }
- } else {
- warning("detectLofsType(): Could not get superclass object");
+ for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) {
+ found = autoDetectLofsType(gameSuperClassName, m);
+ if (found)
+ break;
}
} else {
warning("detectLofsType(): Could not find superclass of game object");
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index 7692613ee5..d205763051 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -25,11 +25,30 @@
#include "sci/engine/gc.h"
#include "common/array.h"
+#include "sci/graphics/ports.h"
namespace Sci {
//#define GC_DEBUG_CODE
+#ifdef GC_DEBUG_CODE
+const char *segmentTypeNames[] = {
+ "invalid", // 0
+ "script", // 1
+ "clones", // 2
+ "locals", // 3
+ "stack", // 4
+ "obsolete", // 5: obsolete system strings
+ "lists", // 6
+ "nodes", // 7
+ "hunk", // 8
+ "dynmem", // 9
+ "obsolete", // 10: obsolete string fragments
+ "array", // 11: SCI32 arrays
+ "string" // 12: SCI32 strings
+};
+#endif
+
struct WorklistManager {
Common::Array<reg_t> _worklist;
AddrSet _map; // used for 2 contains() calls, inside push() and run_gc()
@@ -84,6 +103,18 @@ static void processWorkList(SegManager *segMan, WorklistManager &wm, const Commo
}
}
+static void processEngineHunkList(WorklistManager &wm) {
+ PortList windowList = g_sci->_gfxPorts->_windowList;
+
+ for (PortList::const_iterator it = windowList.begin(); it != windowList.end(); ++it) {
+ if ((*it)->isWindow()) {
+ Window *wnd = ((Window *)*it);
+ wm.push(wnd->hSaved1);
+ wm.push(wnd->hSaved2);
+ }
+ }
+}
+
AddrSet *findAllActiveReferences(EngineState *s) {
assert(!s->_executionStack.empty());
@@ -95,7 +126,7 @@ AddrSet *findAllActiveReferences(EngineState *s) {
// Initialize value stack
// We do this one by hand since the stack doesn't know the current execution stack
- Common::List<ExecStack>::iterator iter = s->_executionStack.reverse_begin();
+ Common::List<ExecStack>::const_iterator iter = s->_executionStack.reverse_begin();
// Skip fake kernel stack frame if it's on top
if ((*iter).type == EXEC_STACK_TYPE_KERNEL)
@@ -103,9 +134,9 @@ AddrSet *findAllActiveReferences(EngineState *s) {
assert((iter != s->_executionStack.end()) && ((*iter).type != EXEC_STACK_TYPE_KERNEL));
- ExecStack &xs = *iter;
+ const StackPtr sp = iter->sp;
- for (reg_t *pos = s->stack_base; pos < xs.sp; pos++)
+ for (reg_t *pos = s->stack_base; pos < sp; pos++)
wm.push(*pos);
debugC(kDebugLevelGC, "[GC] -- Finished adding value stack");
@@ -113,7 +144,7 @@ AddrSet *findAllActiveReferences(EngineState *s) {
// Init: Execution Stack
for (iter = s->_executionStack.begin();
iter != s->_executionStack.end(); ++iter) {
- ExecStack &es = *iter;
+ const ExecStack &es = *iter;
if (es.type != EXEC_STACK_TYPE_KERNEL) {
wm.push(es.objp);
@@ -143,6 +174,9 @@ AddrSet *findAllActiveReferences(EngineState *s) {
processWorkList(s->_segMan, wm, heap);
+ if (getSciVersion() <= SCI_VERSION_1_1)
+ processEngineHunkList(wm);
+
return normalizeAddresses(s->_segMan, wm._map);
}
@@ -170,7 +204,7 @@ void run_gc(EngineState *s) {
if (mobj != NULL) {
#ifdef GC_DEBUG_CODE
const SegmentType type = mobj->getType();
- segnames[type] = SegmentObj::getSegmentTypeName(type);
+ segnames[type] = segmentTypeNames[type];
#endif
// Get a list of all deallocatable objects in this segment,
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 202fc40ba4..9a55ef630b 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -255,6 +255,11 @@ private:
Common::StringArray checkStaticSelectorNames();
/**
+ * Automatically find specific selectors
+ */
+ void findSpecificSelectors(Common::StringArray &selectorNames);
+
+ /**
* Maps special selectors.
*/
void mapSelectors();
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 71892a8bea..16d56d10a8 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -56,7 +56,7 @@ struct SciKernelMapSubEntry {
#define SIG_SCIALL SCI_VERSION_NONE, SCI_VERSION_NONE
#define SIG_SCI0 SCI_VERSION_NONE, SCI_VERSION_01
-#define SIG_SCI1 SCI_VERSION_1_EGA, SCI_VERSION_1_LATE
+#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE
#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1
#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE
#define SIG_SCI21 SCI_VERSION_2_1, SCI_VERSION_3
@@ -348,7 +348,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds },
{ MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL },
{ MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL },
- { MAP_CALL(Format), SIG_EVERYWHERE, "r(.*)", NULL, NULL },
+ { MAP_CALL(Format), SIG_EVERYWHERE, "r[ri](.*)", NULL, NULL },
{ MAP_CALL(GameIsRestarting), SIG_EVERYWHERE, "(i)", NULL, NULL },
{ MAP_CALL(GetAngle), SIG_EVERYWHERE, "iiii", NULL, kGetAngle_workarounds },
{ MAP_CALL(GetCWD), SIG_EVERYWHERE, "r", NULL, NULL },
@@ -434,7 +434,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL },
{ MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds },
- { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, kStrCat_workarounds },
+ { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL },
{ MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL },
{ MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL },
@@ -490,6 +490,12 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ListFirstTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
{ MAP_CALL(ListIndexOf), SIG_EVERYWHERE, "l[o0]", NULL, NULL },
{ "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL },
+ // Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
+ // memory") are available when the current room changes. This is similar to the SCI0-SCI1.1 FlushResources
+ // call, with the added functionality of ensuring that a specific amount of memory is available. We have
+ // our own memory manager and garbage collector, thus we simply call FlushResources, which in turn invokes
+ // our garbage collector (i.e. the SCI0-SCI1.1 semantics).
+ { "Purge", kFlushResources, SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(RepaintPlane), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL },
{ MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL },
@@ -508,12 +514,6 @@ static SciKernelMapEntry s_kernelMap[] = {
// MakeSaveCatName - used in the Save/Load dialog of GK1CD (SRDialog, script 64990)
// MakeSaveFileName - used in the Save/Load dialog of GK1CD (SRDialog, script 64990)
- // SCI2 empty functions
-
- // Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
- // memory") are available. We have our own memory manager and garbage collector, thus we ignore this call.
- { MAP_EMPTY(Purge), SIG_EVERYWHERE, "i", NULL, NULL },
-
// Unused / debug SCI2 unused functions, always mapped to kDummy
{ MAP_DUMMY(InspectObject), SIG_EVERYWHERE, "(.*)", NULL, NULL },
// Profiler (same as SCI0-SCI1.1)
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index e5a9931605..725b78341b 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -35,6 +35,7 @@
#include "sci/event.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/cursor.h"
+#include "sci/graphics/maciconbar.h"
namespace Sci {
@@ -46,17 +47,25 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
Common::Point mousePos;
- // Limit the mouse cursor position, if necessary
- g_sci->_gfxCursor->refreshPosition();
- mousePos = g_sci->_gfxCursor->getPosition();
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1)
- g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
-#endif
+ // For Mac games with an icon bar, handle possible icon bar events first
+ if (g_sci->hasMacIconBar()) {
+ reg_t iconObj = g_sci->_gfxMacIconBar->handleEvents();
+ if (!iconObj.isNull())
+ invokeSelector(s, iconObj, SELECTOR(select), argc, argv, 0, NULL);
+ }
// If there's a simkey pending, and the game wants a keyboard event, use the
// simkey instead of a normal event
if (g_debug_simulated_key && (mask & SCI_EVENT_KEYBOARD)) {
+ // In case we use a simulated event we query the current mouse position
+ mousePos = g_sci->_gfxCursor->getPosition();
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2_1)
+ g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
+#endif
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
+
writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
writeSelectorValue(segMan, obj, SELECTOR(message), g_debug_simulated_key);
writeSelectorValue(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
@@ -68,6 +77,15 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
curEvent = g_sci->getEventManager()->getSciEvent(mask);
+ // For a real event we use its associated mouse position
+ mousePos = curEvent.mousePos;
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2_1)
+ g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
+#endif
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
+
if (g_sci->getVocabulary())
g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
@@ -135,7 +153,11 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
break;
default:
- s->r_acc = NULL_REG; // Unknown or no event
+ // Return a null event
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_NONE);
+ writeSelectorValue(segMan, obj, SELECTOR(message), 0);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ s->r_acc = NULL_REG;
}
if ((s->r_acc.offset) && (g_sci->_debugState.stopOnEvent)) {
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index f6dec5da64..82522a6e77 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -253,6 +253,7 @@ reg_t kFGets(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelFile, "kFGets(%d, %d)", handle, maxsize);
int readBytes = fgets_wrapper(s, buf, maxsize, handle);
s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
+ delete[] buf;
return readBytes ? argv[0] : NULL_REG;
}
@@ -1155,15 +1156,14 @@ reg_t kCD(EngineState *s, int argc, reg_t *argv) {
reg_t kSave(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
- case 0: // Called by kq7 when starting chapters
+ case 0:
return kSaveGame(s, argc - 1,argv + 1);
- case 2: // GetSaveDir
- // Yay! Reusing the old kernel function!
+ case 1:
+ return kRestoreGame(s, argc - 1,argv + 1);
+ case 2:
return kGetSaveDir(s, argc - 1, argv + 1);
case 5:
- // TODO
- // 3 parameters: game ID, a string and an array
- return s->r_acc;
+ return kGetSaveFiles(s, argc - 1, argv + 1);
case 8:
// TODO
// This is a timer callback, with 1 parameter: the timer object
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 9034bd1d5c..c7a2a26c3d 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -58,6 +58,17 @@
namespace Sci {
+static int16 adjustGraphColor(int16 color) {
+ // WORKAROUND: SCI1 EGA and Amiga games can set invalid colors (above 0 - 15).
+ // Colors above 15 are all white in SCI1 EGA games, which is why this was never
+ // observed. We clip them all to (0, 15) instead, as colors above 15 are used
+ // for the undithering algorithm in EGA games - bug #3048908.
+ if (getSciVersion() >= SCI_VERSION_1_EARLY && g_sci->getResMan()->getViewType() == kViewEga)
+ return color & 0x0F; // 0 - 15
+ else
+ return color;
+}
+
void showScummVMDialog(const Common::String &message) {
GUI::MessageDialog dialog(message, "OK");
dialog.runModal();
@@ -242,23 +253,14 @@ reg_t kGraph(EngineState *s, int argc, reg_t *argv) {
}
reg_t kGraphGetColorCount(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isAmiga32color())
- return make_reg(0, 32);
- return make_reg(0, !g_sci->getResMan()->isVGA() ? 16 : 256);
+ return make_reg(0, g_sci->_gfxPalette->getTotalColorCount());
}
reg_t kGraphDrawLine(EngineState *s, int argc, reg_t *argv) {
- int16 color = argv[4].toSint16();
+ int16 color = adjustGraphColor(argv[4].toSint16());
int16 priority = (argc > 5) ? argv[5].toSint16() : -1;
int16 control = (argc > 6) ? argv[6].toSint16() : -1;
- // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
- // Colors above 15 are all white in SCI1 EGA games, which is why this was never
- // observed. We clip them all to (0, 15) instead, as colors above 15 are used
- // for the undithering algorithm in EGA games - bug #3048908.
- if (g_sci->getResMan()->getViewType() == kViewEga && getSciVersion() >= SCI_VERSION_1_EARLY)
- color &= 0x0F;
-
g_sci->_gfxPaint16->kernelGraphDrawLine(getGraphPoint(argv), getGraphPoint(argv + 2), color, priority, control);
return s->r_acc;
}
@@ -290,17 +292,10 @@ reg_t kGraphFillBoxForeground(EngineState *s, int argc, reg_t *argv) {
reg_t kGraphFillBoxAny(EngineState *s, int argc, reg_t *argv) {
Common::Rect rect = getGraphRect(argv);
int16 colorMask = argv[4].toUint16();
- int16 color = argv[5].toSint16();
+ int16 color = adjustGraphColor(argv[5].toSint16());
int16 priority = argv[6].toSint16(); // yes, we may read from stack sometimes here
int16 control = argv[7].toSint16(); // sierra did the same
- // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
- // Colors above 15 are all white in SCI1 EGA games, which is why this was never
- // observed. We clip them all to (0, 15) instead, as colors above 15 are used
- // for the undithering algorithm in EGA games - bug #3048908.
- if (g_sci->getResMan()->getViewType() == kViewEga && getSciVersion() >= SCI_VERSION_1_EARLY)
- color &= 0x0F;
-
g_sci->_gfxPaint16->kernelGraphFillBox(rect, colorMask, color, priority, control);
return s->r_acc;
}
@@ -364,6 +359,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
if (!g_sci->_gfxText16) {
// TODO: Implement this
textWidth = 0; textHeight = 0;
+ warning("TODO: implement kTextSize for SCI32");
} else
#endif
g_sci->_gfxText16->kernelTextSize(g_sci->strSplit(text.c_str(), sep).c_str(), font_nr, maxwidth, &textWidth, &textHeight);
@@ -553,8 +549,6 @@ reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-// we are called on EGA/amiga games as well, this doesnt make sense.
-// doing this would actually break the system EGA/amiga palette
reg_t kPalette(EngineState *s, int argc, reg_t *argv) {
if (!s)
return make_reg(0, getSciVersion());
@@ -562,86 +556,85 @@ reg_t kPalette(EngineState *s, int argc, reg_t *argv) {
}
reg_t kPaletteSetFromResource(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- GuiResourceId resourceId = argv[0].toUint16();
- bool force = false;
- if (argc == 2)
- force = argv[1].toUint16() == 2 ? true : false;
- g_sci->_gfxPalette->kernelSetFromResource(resourceId, force);
- }
+ GuiResourceId resourceId = argv[0].toUint16();
+ bool force = false;
+ if (argc == 2)
+ force = argv[1].toUint16() == 2 ? true : false;
+
+ // Non-VGA games don't use palette resources.
+ // This has been changed to 64 colors because Longbow Amiga does have
+ // one palette (palette 999).
+ if (g_sci->_gfxPalette->getTotalColorCount() < 64)
+ return s->r_acc;
+
+ g_sci->_gfxPalette->kernelSetFromResource(resourceId, force);
return s->r_acc;
}
reg_t kPaletteSetFlag(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
- uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
- uint16 flags = argv[2].toUint16();
- g_sci->_gfxPalette->kernelSetFlag(fromColor, toColor, flags);
- }
+ uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
+ uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
+ uint16 flags = argv[2].toUint16();
+ g_sci->_gfxPalette->kernelSetFlag(fromColor, toColor, flags);
return s->r_acc;
}
reg_t kPaletteUnsetFlag(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
- uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
- uint16 flags = argv[2].toUint16();
- g_sci->_gfxPalette->kernelUnsetFlag(fromColor, toColor, flags);
- }
+ uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
+ uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
+ uint16 flags = argv[2].toUint16();
+ g_sci->_gfxPalette->kernelUnsetFlag(fromColor, toColor, flags);
return s->r_acc;
}
reg_t kPaletteSetIntensity(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
- uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
- uint16 intensity = argv[2].toUint16();
- bool setPalette = (argc < 4) ? true : (argv[3].isNull()) ? true : false;
+ uint16 fromColor = CLIP<uint16>(argv[0].toUint16(), 1, 255);
+ uint16 toColor = CLIP<uint16>(argv[1].toUint16(), 1, 255);
+ uint16 intensity = argv[2].toUint16();
+ bool setPalette = (argc < 4) ? true : (argv[3].isNull()) ? true : false;
- g_sci->_gfxPalette->kernelSetIntensity(fromColor, toColor, intensity, setPalette);
- }
+ // Palette intensity in non-VGA SCI1 games has been removed
+ if (g_sci->_gfxPalette->getTotalColorCount() < 256)
+ return s->r_acc;
+
+ g_sci->_gfxPalette->kernelSetIntensity(fromColor, toColor, intensity, setPalette);
return s->r_acc;
}
reg_t kPaletteFindColor(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- uint16 r = argv[0].toUint16();
- uint16 g = argv[1].toUint16();
- uint16 b = argv[2].toUint16();
- return make_reg(0, g_sci->_gfxPalette->kernelFindColor(r, g, b));
- }
- return NULL_REG;
+ uint16 r = argv[0].toUint16();
+ uint16 g = argv[1].toUint16();
+ uint16 b = argv[2].toUint16();
+ return make_reg(0, g_sci->_gfxPalette->kernelFindColor(r, g, b));
}
reg_t kPaletteAnimate(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- int16 argNr;
- bool paletteChanged = false;
- for (argNr = 0; argNr < argc; argNr += 3) {
- uint16 fromColor = argv[argNr].toUint16();
- uint16 toColor = argv[argNr + 1].toUint16();
- int16 speed = argv[argNr + 2].toSint16();
- if (g_sci->_gfxPalette->kernelAnimate(fromColor, toColor, speed))
- paletteChanged = true;
- }
- if (paletteChanged)
- g_sci->_gfxPalette->kernelAnimateSet();
+ int16 argNr;
+ bool paletteChanged = false;
+
+ // Palette animation in non-VGA SCI1 games has been removed
+ if (g_sci->_gfxPalette->getTotalColorCount() < 256)
+ return s->r_acc;
+
+ for (argNr = 0; argNr < argc; argNr += 3) {
+ uint16 fromColor = argv[argNr].toUint16();
+ uint16 toColor = argv[argNr + 1].toUint16();
+ int16 speed = argv[argNr + 2].toSint16();
+ if (g_sci->_gfxPalette->kernelAnimate(fromColor, toColor, speed))
+ paletteChanged = true;
}
+ if (paletteChanged)
+ g_sci->_gfxPalette->kernelAnimateSet();
+
return s->r_acc;
}
reg_t kPaletteSave(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- return g_sci->_gfxPalette->kernelSave();
- }
- return NULL_REG;
+ return g_sci->_gfxPalette->kernelSave();
}
reg_t kPaletteRestore(EngineState *s, int argc, reg_t *argv) {
- if (g_sci->getResMan()->isVGA()) {
- g_sci->_gfxPalette->kernelRestore(argv[0]);
- }
+ g_sci->_gfxPalette->kernelRestore(argv[0]);
return argv[0];
}
@@ -1082,22 +1075,11 @@ reg_t kNewWindow(EngineState *s, int argc, reg_t *argv) {
int argextra = argc >= 13 ? 4 : 0; // Triggers in PQ3 and SCI1.1 games, argc 13 for DOS argc 15 for mac
int style = argv[5 + argextra].toSint16();
int priority = (argc > 6 + argextra) ? argv[6 + argextra].toSint16() : -1;
- int colorPen = (argc > 7 + argextra) ? argv[7 + argextra].toSint16() : 0;
- int colorBack = (argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255;
+ int colorPen = adjustGraphColor((argc > 7 + argextra) ? argv[7 + argextra].toSint16() : 0);
+ int colorBack = adjustGraphColor((argc > 8 + argextra) ? argv[8 + argextra].toSint16() : 255);
- // WORKAROUND: SCI1 EGA games can set invalid colors (above 0 - 15).
- // Colors above 15 are all white in SCI1 EGA games, which is why this was never
- // observed. We clip them all to (0, 15) instead, as colors above 15 are used
- // for the undithering algorithm in EGA games - bug #3048908.
- if (g_sci->getResMan()->getViewType() == kViewEga && getSciVersion() >= SCI_VERSION_1_EARLY) {
- colorPen &= 0x0F;
- colorBack &= 0x0F;
- }
-
- // const char *title = argv[4 + argextra].segment ? kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL;
- if (argc>=13) {
+ if (argc >= 13)
rect2 = Common::Rect (argv[5].toSint16(), argv[4].toSint16(), argv[7].toSint16(), argv[6].toSint16());
- }
Common::String title;
if (argv[4 + argextra].segment) {
@@ -1220,12 +1202,19 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
}
break;
case 2: { // remap by percent
- // NOTE: This adjusts the alpha value of a specific color, and it operates on
- // an RGBA palette
- int16 color = argv[1].toSint16(); // this is subtracted from a maximum color value, and can be offset by 10
+ // This adjusts the alpha value of a specific color, and it operates on
+ // an RGBA palette. Since we're operating on an RGB palette, we just
+ // modify the color intensity instead
+ // TODO: From what I understand, palette remapping should be placed
+ // separately, so that it can be reset by case 0 above. Thus, we
+ // should adjust the functionality of the Palette class accordingly.
+ int16 color = argv[1].toSint16();
+ if (color >= 10)
+ color -= 10;
uint16 percent = argv[2].toUint16(); // 0 - 100
- uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0;
- warning("kRemapColors: RemapByPercent color %d by %d percent (unk3 = %d)", color, percent, unk3);
+ if (argc >= 4)
+ warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
+ g_sci->_gfxPalette->kernelSetIntensity(color, 255, percent, false);
}
break;
case 3: { // remap to gray
diff --git a/engines/sci/engine/kmenu.cpp b/engines/sci/engine/kmenu.cpp
index 428c27ca73..3986966a71 100644
--- a/engines/sci/engine/kmenu.cpp
+++ b/engines/sci/engine/kmenu.cpp
@@ -29,6 +29,7 @@
#include "sci/engine/kernel.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/menu.h"
+#include "sci/graphics/screen.h"
namespace Sci {
@@ -71,7 +72,7 @@ reg_t kDrawStatus(EngineState *s, int argc, reg_t *argv) {
reg_t textReference = argv[0];
Common::String text;
int16 colorPen = (argc > 1) ? argv[1].toSint16() : 0;
- int16 colorBack = (argc > 2) ? argv[2].toSint16() : g_sci->getResMan()->isVGA() ? 255 : 15;
+ int16 colorBack = (argc > 2) ? argv[2].toSint16() : g_sci->_gfxScreen->getColorWhite();
if (!textReference.isNull()) {
// Sometimes this is called without giving text, if thats the case dont process it.
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 6d7c4580e6..723aece819 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -298,12 +298,9 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
error("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
- if (ref.isRaw) {
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- return make_reg(0, (int16)READ_BE_UINT16(ref.raw)); // Amiga versions are BE
- else
- return make_reg(0, (int16)READ_LE_UINT16(ref.raw));
- } else {
+ if (ref.isRaw)
+ return make_reg(0, (int16)READ_SCIENDIAN_UINT16(ref.raw));
+ else {
if (ref.skipByte)
error("Attempt to peek memory at odd offset %04X:%04X", PRINT_REG(argv[1]));
return *(ref.reg);
@@ -323,10 +320,7 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
error("Attempt to poke memory reference %04x:%04x to %04x:%04x", PRINT_REG(argv[2]), PRINT_REG(argv[1]));
return s->r_acc;
}
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- WRITE_BE_UINT16(ref.raw, argv[2].offset); // Amiga versions are BE
- else
- WRITE_LE_UINT16(ref.raw, argv[2].offset);
+ WRITE_SCIENDIAN_UINT16(ref.raw, argv[2].offset); // Amiga versions are BE
} else {
if (ref.skipByte)
error("Attempt to poke memory at odd offset %04X:%04X", PRINT_REG(argv[1]));
@@ -365,23 +359,22 @@ reg_t kIconBar(EngineState *s, int argc, reg_t *argv) {
case 0: // InitIconBar
for (int i = 0; i < argv[1].toUint16(); i++)
g_sci->_gfxMacIconBar->addIcon(argv[i + 2]);
-
- // TODO: Should return icon bar handle
- // Said handle is then used by DisposeIconBar
break;
case 1: // DisposeIconBar
warning("kIconBar(Dispose)");
break;
- case 2: // EnableIconBar (0xffff = all)
- debug(0, "kIconBar(Enable, %d)", argv[1].toUint16());
- g_sci->_gfxMacIconBar->setIconEnabled(argv[1].toUint16(), true);
+ case 2: // EnableIconBar (-1 = all)
+ debug(0, "kIconBar(Enable, %i)", argv[1].toSint16());
+ g_sci->_gfxMacIconBar->setIconEnabled(argv[1].toSint16(), true);
break;
- case 3: // DisableIconBar (0xffff = all)
- debug(0, "kIconBar(Disable, %d)", argv[1].toUint16());
- g_sci->_gfxMacIconBar->setIconEnabled(argv[1].toUint16(), false);
+ case 3: // DisableIconBar (-1 = all)
+ debug(0, "kIconBar(Disable, %i)", argv[1].toSint16());
+ g_sci->_gfxMacIconBar->setIconEnabled(argv[1].toSint16(), false);
break;
case 4: // SetIconBarIcon
- warning("kIconBar(SetIcon, %d, %d)", argv[1].toUint16(), argv[2].toUint16());
+ debug(0, "kIconBar(SetIcon, %d, %d)", argv[1].toUint16(), argv[2].toUint16());
+ if (argv[2].toSint16() == -1)
+ g_sci->_gfxMacIconBar->setInventoryIcon(argv[2].toSint16());
break;
default:
error("Unknown kIconBar(%d)", argv[0].toUint16());
@@ -503,7 +496,7 @@ reg_t kStub(EngineState *s, int argc, reg_t *argv) {
Kernel *kernel = g_sci->getKernel();
int kernelCallNr = -1;
- Common::List<ExecStack>::iterator callIterator = s->_executionStack.end();
+ Common::List<ExecStack>::const_iterator callIterator = s->_executionStack.end();
if (callIterator != s->_executionStack.begin()) {
callIterator--;
ExecStack lastCall = *callIterator;
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 3c516f63f2..49d2900835 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -166,17 +166,6 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-// TODO/FIXME: There is a notable regression with the new kInitBresed/kDoBresen
-// functions below in a death scene of LB1 - the shower scene, room 215 (bug
-// #3122075). There is a hack to get around this bug by modifying the actor's
-// position for that scene in kScriptID. The actual bug should be found, but
-// since only this death scene has an issue, it's not really worth the effort.
-// The new kInitBresen/kDoBresen functions have been enabled in r52467. The
-// old ones are based on observations, so there are many differences in the
-// way that they behave. Check the hack in kScriptID for more info. Note that
-// the actual issue might not be with kInitBresen/kDoBresen, and there might
-// be another underlying problem here.
-
reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
@@ -275,7 +264,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
bool completed = false;
bool handleMoveCount = g_sci->_features->handleMoveCount();
- if (getSciVersion() >= SCI_VERSION_1_EGA) {
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) {
uint client_signal = readSelectorValue(segMan, client, SELECTOR(signal));
writeSelectorValue(segMan, client, SELECTOR(signal), client_signal & ~kSignalHitObstacle);
}
@@ -292,8 +281,6 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
mover_moveCnt = 0;
int16 client_x = readSelectorValue(segMan, client, SELECTOR(x));
int16 client_y = readSelectorValue(segMan, client, SELECTOR(y));
- int16 client_org_x = client_x;
- int16 client_org_y = client_y;
int16 mover_x = readSelectorValue(segMan, mover, SELECTOR(x));
int16 mover_y = readSelectorValue(segMan, mover, SELECTOR(y));
int16 mover_xAxis = readSelectorValue(segMan, mover, SELECTOR(b_xAxis));
@@ -307,12 +294,19 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
int16 mover_org_i2 = mover_i2;
int16 mover_org_di = mover_di;
- if ((getSciVersion() >= SCI_VERSION_1_EGA)) {
+ if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY)) {
// save current position into mover
writeSelectorValue(segMan, mover, SELECTOR(xLast), client_x);
writeSelectorValue(segMan, mover, SELECTOR(yLast), client_y);
}
- // sierra sci saves full client selector variables here
+
+ // Store backups of all client selector variables. We will restore them
+ // in case of a collision.
+ Object* clientObject = segMan->getObject(client);
+ uint clientVarNum = clientObject->getVarCount();
+ reg_t* clientBackup = new reg_t[clientVarNum];
+ for (uint i = 0; i < clientVarNum; ++i)
+ clientBackup[i] = clientObject->getVariable(i);
if (mover_xAxis) {
if (ABS(mover_x - client_x) < ABS(mover_dx))
@@ -360,9 +354,10 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
}
if (collision) {
- // sierra restores full client variables here, seems that restoring x/y is enough
- writeSelectorValue(segMan, client, SELECTOR(x), client_org_x);
- writeSelectorValue(segMan, client, SELECTOR(y), client_org_y);
+ // We restore the backup of the client variables
+ for (uint i = 0; i < clientVarNum; ++i)
+ clientObject->getVariableRef(i) = clientBackup[i];
+
mover_i1 = mover_org_i1;
mover_i2 = mover_org_i2;
mover_di = mover_org_di;
@@ -370,30 +365,29 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
uint16 client_signal = readSelectorValue(segMan, client, SELECTOR(signal));
writeSelectorValue(segMan, client, SELECTOR(signal), client_signal | kSignalHitObstacle);
}
+ delete[] clientBackup;
+
writeSelectorValue(segMan, mover, SELECTOR(b_i1), mover_i1);
writeSelectorValue(segMan, mover, SELECTOR(b_i2), mover_i2);
writeSelectorValue(segMan, mover, SELECTOR(b_di), mover_di);
- if ((getSciVersion() >= SCI_VERSION_1_EGA)) {
- // this calling code here was right before the last return in
- // sci1ega and got changed to this position since sci1early
- // this was an uninitialized issue in sierra sci
- if ((handleMoveCount) && (getSciVersion() >= SCI_VERSION_1_EARLY))
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) {
+ // In sci1egaonly this block of code was outside of the main if,
+ // but client_x/client_y aren't set there, so it was an
+ // uninitialized read in SSCI. (This issue was fixed in sci1early.)
+ if (handleMoveCount)
writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), mover_moveCnt);
// We need to compare directly in here, complete may have happened during
// the current move
if ((client_x == mover_x) && (client_y == mover_y))
invokeSelector(s, mover, SELECTOR(moveDone), argc, argv);
- if (getSciVersion() >= SCI_VERSION_1_EARLY)
- return s->r_acc;
+ return s->r_acc;
}
}
- if (handleMoveCount) {
- if (getSciVersion() <= SCI_VERSION_1_EGA)
- writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), mover_moveCnt);
- else
- writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), client_moveSpeed);
- }
+
+ if (handleMoveCount)
+ writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), mover_moveCnt);
+
return s->r_acc;
}
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index e8f8ee7152..09cf7744b2 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -70,7 +70,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
- new_lastmatch = said(s, said_block, debug_parser);
+ new_lastmatch = said(said_block, debug_parser);
if (new_lastmatch != SAID_NO_MATCH) { /* Build and possibly display a parse tree */
#ifdef DEBUG_PARSER
@@ -169,7 +169,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
Vocabulary *voc = g_sci->getVocabulary();
// Only SCI0-SCI1 EGA games had a parser. In newer versions, this is a stub
- if (getSciVersion() > SCI_VERSION_1_EGA)
+ if (getSciVersion() > SCI_VERSION_1_EGA_ONLY)
return s->r_acc;
voc->clearSynonyms();
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index cb70cf91e0..7786f9b093 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -264,9 +264,9 @@ struct PathfindingState {
static Common::Point readPoint(SegmentRef list_r, int offset) {
Common::Point point;
- if (list_r.isRaw) {
- point.x = (int16)READ_LE_UINT16(list_r.raw + offset * POLY_POINT_SIZE);
- point.y = (int16)READ_LE_UINT16(list_r.raw + offset * POLY_POINT_SIZE + 2);
+ if (list_r.isRaw) { // dynmem blocks are raw
+ point.x = (int16)READ_SCIENDIAN_UINT16(list_r.raw + offset * POLY_POINT_SIZE);
+ point.y = (int16)READ_SCIENDIAN_UINT16(list_r.raw + offset * POLY_POINT_SIZE + 2);
} else {
point.x = list_r.reg[offset * 2].toUint16();
point.y = list_r.reg[offset * 2 + 1].toUint16();
@@ -275,9 +275,9 @@ static Common::Point readPoint(SegmentRef list_r, int offset) {
}
static void writePoint(SegmentRef ref, int offset, const Common::Point &point) {
- if (ref.isRaw) {
- WRITE_LE_UINT16(ref.raw + offset * POLY_POINT_SIZE, point.x);
- WRITE_LE_UINT16(ref.raw + offset * POLY_POINT_SIZE + 2, point.y);
+ if (ref.isRaw) { // dynmem blocks are raw
+ WRITE_SCIENDIAN_UINT16(ref.raw + offset * POLY_POINT_SIZE, point.x);
+ WRITE_SCIENDIAN_UINT16(ref.raw + offset * POLY_POINT_SIZE + 2, point.y);
} else {
ref.reg[offset * 2] = make_reg(0, point.x);
ref.reg[offset * 2 + 1] = make_reg(0, point.y);
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 810e8a13ee..b9baa3540a 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -56,14 +56,6 @@ reg_t kUnLoad(EngineState *s, int argc, reg_t *argv) {
ResourceType restype = g_sci->getResMan()->convertResType(argv[0].toUint16());
reg_t resnr = argv[1];
- // WORKAROUND for a broken script in room 320 in Castle of Dr. Brain.
- // Script 377 tries to free the hunk memory allocated for the saved area
- // (underbits) beneath the pop up window, which results in having the
- // window stay on screen even when it's closed. Ignore this request here.
- if (restype == kResourceTypeMemory && g_sci->getGameId() == GID_CASTLEBRAIN &&
- s->currentRoomNumber() == 320)
- return s->r_acc;
-
if (restype == kResourceTypeMemory)
s->_segMan->freeHunkEntry(resnr);
}
@@ -257,33 +249,9 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
// is used for timing during the intro, and in the problematic version it's
// initialized to 0, whereas it's 6 in other versions. Thus, we assign it
// to 6 here, fixing the speed of the introduction. Refer to bug #3102071.
- if (g_sci->getGameId() == GID_PQ2 && script == 200) {
- if (s->variables[VAR_GLOBAL][3].isNull()) {
- warning("Fixing speed in the intro of PQ2, version 1.002.011");
- s->variables[VAR_GLOBAL][3] = make_reg(0, 6);
- }
- }
-
- // HACK: Prevent the murderer from getting stuck behind the door in
- // Colonel's Bequest, room 215. A temporary fix for bug #3122075.
- // TODO/FIXME: Add a proper fix for this. There is a regression in this
- // scene with the new kInitBresen and kDoBresen functions (r52467). Using
- // just the "old" kInitBresen works. This hack is added for now because the
- // two functions are quite complex. The "old" versions were created based
- // on observations, and not on the interpreter itself, thus they have a lot
- // of differences in the way they behave and set variables to the mover object.
- // Since this is just a death scene where Laura is supposed to die anyway,
- // figuring out the exact cause of this is just not worth the effort.
- // Differences between the new and the old kInitBresen to the MoveTo object:
- // dy: 1 (new) - 2 (old)
- // b-i1: 20 (new) - 12 (old)
- // b-di: 65526 (new) - 65516 (old)
- // Performing the changes above to MoveTo (0017:033a) allows the killer to
- // move. Note that the actual issue might not be with kInitBresen/kDoBresen,
- // and there might be another underlying problem here.
- if (g_sci->getGameId() == GID_LAURABOW && script == 215) {
- warning("Moving actor position for the shower scene of Colonel's Bequest");
- writeSelectorValue(s->_segMan, s->_segMan->findObjectByName("killer"), SELECTOR(x), 6);
+ if (g_sci->getGameId() == GID_PQ2 && script == 200 &&
+ s->variables[VAR_GLOBAL][3].isNull()) {
+ s->variables[VAR_GLOBAL][3] = make_reg(0, 6);
}
return make_reg(scriptSeg, address);
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 5c6ef06910..d9bb1c3531 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -113,7 +113,7 @@ reg_t kStrAt(EngineState *s, int argc, reg_t *argv) {
reg_t &tmp = dest_r.reg[offset / 2];
bool oddOffset = offset & 1;
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
+ if (g_sci->isBE())
oddOffset = !oddOffset;
if (!oddOffset) {
@@ -159,17 +159,9 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
source++;
}
while (*source) {
- if ((*source < '0') || (*source > '9')) {
- // Sierra's atoi stopped processing at anything which is not
- // a digit. Sometimes the input has a trailing space, that's
- // fine (example: lsl3)
- if (*source != ' ') {
- // TODO: this happens in lsl5 right in the intro -> we get '1' '3' 0xCD 0xCD 0xCD 0xCD 0xCD
- // find out why this happens and fix it
- warning("Invalid character in kReadNumber input");
- }
+ if ((*source < '0') || (*source > '9'))
+ // Stop if we encounter anything other than a digit (like atoi)
break;
- }
result *= 10;
result += *source - 0x30;
source++;
@@ -198,7 +190,6 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
char targetbuf[4096];
char *target = targetbuf;
reg_t position = argv[1]; /* source */
- int index = argv[2].toUint16();
int mode = 0;
int paramindex = 0; /* Next parameter to evaluate */
char xfer;
@@ -209,9 +200,16 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
if (position.segment)
startarg = 2;
- else
+ else {
+ // WORKAROUND: QFG1 VGA Mac calls this without the first parameter (dest). It then
+ // treats the source as the dest and overwrites the source string with an empty string.
+ if (argc < 3)
+ return NULL_REG;
+
startarg = 3; /* First parameter to use for formatting */
+ }
+ int index = (startarg == 3) ? argv[2].toUint16() : 0;
Common::String source_str = g_sci->getKernel()->lookupText(position, index);
const char* source = source_str.c_str();
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp
index bc79e30129..267ba35e3c 100644
--- a/engines/sci/engine/object.cpp
+++ b/engines/sci/engine/object.cpp
@@ -172,11 +172,73 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClas
const Object *baseObj = segMan->getObject(getSpeciesSelector());
if (baseObj) {
- _variables.resize(baseObj->getVarCount());
+ uint originalVarCount = _variables.size();
+
+ if (_variables.size() != baseObj->getVarCount())
+ _variables.resize(baseObj->getVarCount());
// Copy base from species class, as we need its selector IDs
_baseObj = baseObj->_baseObj;
if (doInitSuperClass)
initSuperClass(segMan, addr);
+
+ if (_variables.size() != originalVarCount) {
+ // These objects are probably broken.
+ // An example is 'witchCage' in script 200 in KQ5 (#3034714),
+ // but also 'girl' in script 216 and 'door' in script 22.
+ // In LSL3 a number of sound objects trigger this right away.
+ // SQ4-floppy's bug #3037938 also seems related.
+
+ // The effect is that a number of its method selectors may be
+ // treated as variable selectors, causing unpredictable effects.
+ int objScript = segMan->getScript(_pos.segment)->getScriptNumber();
+
+ // We have to do a little bit of work to get the name of the object
+ // before any relocations are done.
+ reg_t nameReg = getNameSelector();
+ const char *name;
+ if (nameReg.isNull()) {
+ name = "<no name>";
+ } else {
+ nameReg.segment = _pos.segment;
+ name = segMan->derefString(nameReg);
+ if (!name)
+ name = "<invalid name>";
+ }
+
+ warning("Object %04x:%04x (name %s, script %d) varnum doesn't "
+ "match baseObj's: obj %d, base %d", PRINT_REG(_pos),
+ name, objScript, originalVarCount, baseObj->getVarCount());
+
+#if 0
+ // We enumerate the methods selectors which could be hidden here
+ if (getSciVersion() <= SCI_VERSION_2_1) {
+ const SegmentRef objRef = segMan->dereference(baseObj->_pos);
+ assert(objRef.isRaw);
+ uint segBound = objRef.maxSize/2 - baseObj->getVarCount();
+ const byte* buf = (const byte *)baseObj->_baseVars;
+ if (!buf) {
+ // While loading this may happen due to objects being loaded
+ // out of order, and we can't proceed then, unfortunately.
+ segBound = 0;
+ }
+ for (uint i = baseObj->getVarCount();
+ i < originalVarCount && i < segBound; ++i) {
+ uint16 slc = READ_SCI11ENDIAN_UINT16(buf + 2*i);
+ // Skip any numbers which happen to be varselectors too
+ bool found = false;
+ for (uint j = 0; j < baseObj->getVarCount() && !found; ++j)
+ found = READ_SCI11ENDIAN_UINT16(buf + 2*j) == slc;
+ if (found) continue;
+ // Skip any selectors which aren't method selectors,
+ // so couldn't be mistaken for varselectors
+ if (lookupSelector(segMan, _pos, slc, 0, 0) != kSelectorMethod) continue;
+ warning(" Possibly affected selector: %02x (%s)", slc,
+ g_sci->getKernel()->getSelectorName(slc).c_str());
+ }
+ }
+#endif
+ }
+
return true;
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index ab355cebb4..43d00ebc15 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -328,14 +328,14 @@ void Object::saveLoadWithSerializer(Common::Serializer &s) {
}
template <>
-void syncWithSerializer(Common::Serializer &s, Table<Clone>::Entry &obj) {
+void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Clone>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
syncWithSerializer<Object>(s, obj);
}
template <>
-void syncWithSerializer(Common::Serializer &s, Table<List>::Entry &obj) {
+void syncWithSerializer(Common::Serializer &s, SegmentObjTable<List>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
syncWithSerializer(s, obj.first);
@@ -343,7 +343,7 @@ void syncWithSerializer(Common::Serializer &s, Table<List>::Entry &obj) {
}
template <>
-void syncWithSerializer(Common::Serializer &s, Table<Node>::Entry &obj) {
+void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Node>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
syncWithSerializer(s, obj.pred);
@@ -354,7 +354,7 @@ void syncWithSerializer(Common::Serializer &s, Table<Node>::Entry &obj) {
#ifdef ENABLE_SCI32
template <>
-void syncWithSerializer(Common::Serializer &s, Table<SciArray<reg_t> >::Entry &obj) {
+void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciArray<reg_t> >::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
byte type = 0;
@@ -390,7 +390,7 @@ void syncWithSerializer(Common::Serializer &s, Table<SciArray<reg_t> >::Entry &o
}
template <>
-void syncWithSerializer(Common::Serializer &s, Table<SciString>::Entry &obj) {
+void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciString>::Entry &obj) {
s.syncAsSint32LE(obj.next_free);
uint32 size = 0;
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 6719b73aa5..fb96518f19 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -70,7 +70,7 @@ void Script::init(int script_nr, ResourceManager *resMan) {
Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
if (!script)
- error("Script %d not found\n", script_nr);
+ error("Script %d not found", script_nr);
_localsOffset = 0;
_localsBlock = NULL;
@@ -129,6 +129,17 @@ void Script::load(ResourceManager *resMan) {
Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
assert(script != 0);
+ uint extraLocalsWorkaround = 0;
+ if (g_sci->getGameId() == GID_FANMADE && _nr == 1 && script->size == 11140) {
+ // WORKAROUND: Script 1 in Ocean Battle doesn't have enough locals to
+ // fit the string showing how many shots are left (a nasty script bug,
+ // corrupting heap memory). We add 10 more locals so that it has enough
+ // space to use as the target for its kFormat operation. Fixes bug
+ // #3059871.
+ extraLocalsWorkaround = 10;
+ }
+ _bufSize += extraLocalsWorkaround * 2;
+
_buf = (byte *)malloc(_bufSize);
assert(_buf);
@@ -187,6 +198,9 @@ void Script::load(ResourceManager *resMan) {
_localsOffset = 24 + _numExports * 2;
}
+ // WORKAROUND: Increase locals, if needed (check above)
+ _localsCount += extraLocalsWorkaround;
+
if (getSciVersion() == SCI_VERSION_0_EARLY) {
// SCI0 early
// Old script block. There won't be a localvar block in this case.
@@ -202,7 +216,7 @@ void Script::load(ResourceManager *resMan) {
if (_localsOffset + _localsCount * 2 + 1 >= (int)_bufSize) {
error("Locals extend beyond end of script: offset %04x, count %d vs size %d", _localsOffset, _localsCount, _bufSize);
- _localsCount = (_bufSize - _localsOffset) >> 1;
+ //_localsCount = (_bufSize - _localsOffset) >> 1;
}
}
}
@@ -243,9 +257,8 @@ Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
- VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
-
- VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+ if (obj_pos.offset >= _bufSize)
+ error("Attempt to initialize object beyond end of script");
// Get the object at the specified position and init it. This will
// automatically "allocate" space for it in the _objects map if necessary.
@@ -313,8 +326,9 @@ void Script::relocateSci0Sci21(reg_t block) {
heapOffset = _scriptSize;
}
- VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
- "Relocation block outside of script\n");
+ if (block.offset >= (uint16)heapSize ||
+ READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset >= (uint16)heapSize)
+ error("Relocation block outside of script");
int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
int exportIndex = 0;
@@ -404,7 +418,8 @@ uint16 Script::validateExportFunc(int pubfunct, bool relocate) {
offset = relocateOffsetSci3(pubfunct * 2 + 22);
}
- VERIFY(offset < _bufSize, "invalid export function pointer");
+ if (offset >= _bufSize)
+ error("Invalid export function pointer");
// Check if the offset found points to a second export table (e.g. script 912
// in Camelot and script 306 in KQ4). Such offsets are usually small (i.e. < 10),
@@ -418,7 +433,8 @@ uint16 Script::validateExportFunc(int pubfunct, bool relocate) {
if (secondExportTable) {
secondExportTable += 3; // skip header plus 2 bytes (secondExportTable is a uint16 pointer)
offset = READ_SCI11ENDIAN_UINT16(secondExportTable + pubfunct);
- VERIFY(offset < _bufSize, "invalid export function pointer");
+ if (offset >= _bufSize)
+ error("Invalid export function pointer");
}
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index a5679fac54..33e62b21ae 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -60,55 +60,6 @@ struct SciScriptSignature {
// - if not EOS, an adjust offset and the actual bytes
// - rinse and repeat
-#if 0
-
-// ===========================================================================
-// Castle of Dr. Brain
-// cipher::init (script 391) is called on room 380 init. This resets the word
-// cipher puzzle. The puzzle sadly operates on some hep strings, which aren't
-// saved in our sci. So saving/restoring in this room will break the puzzle
-// Because of this issue, we just init the puzzle each time it's accessed.
-// this is not 100% sierra behaviour, in fact we will actually reset the puzzle
-// during each access which makes it impossible to cheat.
-const byte castlebrainSignatureCipherPuzzle[] = {
- 22,
- 0x35, 0x00, // ldi 00
- 0xa3, 0x26, // sal local[26]
- 0xa3, 0x25, // sal local[25]
- 0x35, 0x00, // ldi 00
- 0xa3, 0x2a, // sal local[2a] (local is not used)
- 0xa3, 0x29, // sal local[29] (local is not used)
- 0x35, 0xff, // ldi ff
- 0xa3, 0x2c, // sal local[2c]
- 0xa3, 0x2b, // sal local[2b]
- 0x35, 0x00, // ldi 00
- 0x65, 0x16, // aTop highlightedIcon
- 0
-};
-
-const uint16 castlebrainPatchCipherPuzzle[] = {
- 0x39, 0x6b, // pushi 6b (selector init)
- 0x76, // push0
- 0x55, 0x04, // self 04
- 0x35, 0x00, // ldi 00
- 0xa3, 0x25, // sal local[25]
- 0xa3, 0x26, // sal local[26]
- 0xa3, 0x29, // sal local[29]
- 0x65, 0x16, // aTop highlightedIcon
- 0x34, 0xff, 0xff, // ldi ffff
- 0xa3, 0x2b, // sal local[2b]
- 0xa3, 0x2c, // sal local[2c]
- PATCH_END
-};
-
-// script, description, magic DWORD, adjust
-const SciScriptSignature castlebrainSignatures[] = {
- { 391, "cipher puzzle save/restore break", 1, PATCH_MAGICDWORD(0xa3, 0x26, 0xa3, 0x25), -2, castlebrainSignatureCipherPuzzle, castlebrainPatchCipherPuzzle },
- SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#endif
-
// ===========================================================================
// stayAndHelp::changeState (0) is called when ego swims to the left or right
// boundaries of room 660. Normally a textbox is supposed to get on screen
@@ -497,74 +448,6 @@ const SciScriptSignature gk1Signatures[] = {
SCI_SIGNATUREENTRY_TERMINATOR
};
-#if 0
-
-// ===========================================================================
-// this here gets called on entry and when going out of game windows
-// uEvt::port will not get changed after kDisposeWindow but a bit later, so
-// we would get an invalid port handle to a kSetPort call. We just patch in
-// resetting of the port selector. We destroy the stop/fade code in there,
-// it seems it isn't used at all in the game.
-const byte hoyle4SignaturePortFix[] = {
- 28,
- 0x39, 0x09, // pushi 09
- 0x89, 0x0b, // lsg 0b
- 0x39, 0x64, // pushi 64
- 0x38, 0xc8, 0x00, // pushi 00c8
- 0x38, 0x2c, 0x01, // pushi 012c
- 0x38, 0x90, 0x01, // pushi 0190
- 0x38, 0xf4, 0x01, // pushi 01f4
- 0x38, 0x58, 0x02, // pushi 0258
- 0x38, 0xbc, 0x02, // pushi 02bc
- 0x38, 0x20, 0x03, // pushi 0320
- 0x46, // calle [xxxx] [xxxx] [xx]
- +5, 43, // [skip 5 bytes]
- 0x30, 0x27, 0x00, // bnt 0027 -> end of routine
- 0x87, 0x00, // lap 00
- 0x30, 0x19, 0x00, // bnt 0019 -> fade out
- 0x87, 0x01, // lap 01
- 0x30, 0x14, 0x00, // bnt 0014 -> fade out
- 0x38, 0xa7, 0x00, // pushi 00a7
- 0x76, // push0
- 0x80, 0x29, 0x01, // lag 0129
- 0x4a, 0x04, // send 04 - call song::stop
- 0x39, 0x27, // pushi 27
- 0x78, // push1
- 0x8f, 0x01, // lsp 01
- 0x51, 0x54, // class 54
- 0x4a, 0x06, // send 06 - call PlaySong::play
- 0x33, 0x09, // jmp 09 -> end of routine
- 0x38, 0xaa, 0x00, // pushi 00aa
- 0x76, // push0
- 0x80, 0x29, 0x01, // lag 0129
- 0x4a, 0x04, // send 04
- 0x48, // ret
- 0
-};
-
-const uint16 hoyle4PatchPortFix[] = {
- PATCH_ADDTOOFFSET | +33,
- 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent)
- 0x76, // push0
- 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User")
- 0x4a, 0x04, // send 04 - read User::curEvent
-
- 0x38, 0x93, 0x00, // pushi 0093 (selector port)
- 0x78, // push1
- 0x76, // push0
- 0x4a, 0x06, // send 06 - write 0 to that object::port
- 0x48, // ret
- PATCH_END
-};
-
-// script, description, magic DWORD, adjust
-const SciScriptSignature hoyle4Signatures[] = {
- { 0, "port fix when disposing windows", PATCH_MAGICDWORD(0x64, 0x38, 0xC8, 0x00), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix },
- { 0, NULL, 0, 0, NULL, NULL }
-};
-
-#endif
-
// ===========================================================================
// at least during harpy scene export 29 of script 0 is called in kq5cd and
// has an issue for those calls, where temp 3 won't get inititialized, but
@@ -615,9 +498,45 @@ const uint16 kq5PatchCdHarpyVolume[] = {
PATCH_END
};
+// This is a heap patch, and it modifies the properties of an object, instead
+// of patching script code.
+//
+// The witchCage object in script 200 is broken and claims to have 12
+// variables instead of the 8 it should have because it is a Cage.
+// Additionally its top,left,bottom,right properties are set to 0 rather
+// than the right values. We fix the object by setting the right values.
+// If they are all zero, this causes an impossible position check in
+// witch::cantBeHere and an infinite loop when entering room 22 (bug #3034714).
+//
+// This bug is accidentally not triggered in SSCI because the invalid number
+// of variables effectively hides witchCage::doit, causing this position check
+// to be bypassed entirely.
+// See also the warning+comment in Object::initBaseObject
+const byte kq5SignatureWitchCageInit[] = {
+ 16,
+ 0x00, 0x00, // top
+ 0x00, 0x00, // left
+ 0x00, 0x00, // bottom
+ 0x00, 0x00, // right
+ 0x00, 0x00, // extra property #1
+ 0x7a, 0x00, // extra property #2
+ 0xc8, 0x00, // extra property #3
+ 0xa3, 0x00, // extra property #4
+ 0
+};
+
+const uint16 kq5PatchWitchCageInit[] = {
+ 0x00, 0x00, // top
+ 0x7a, 0x00, // left
+ 0xc8, 0x00, // bottom
+ 0xa3, 0x00, // right
+ PATCH_END
+};
+
// script, description, magic DWORD, adjust
const SciScriptSignature kq5Signatures[] = {
{ 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ { 200, "CD: witch cage init", 1, PATCH_MAGICDWORD(0x7a, 0x00, 0xc8, 0x00), -10, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -652,6 +571,52 @@ const SciScriptSignature kq6Signatures[] = {
};
// ===========================================================================
+// Script 210 in the German version of Longbow handles the case where Robin
+// hands out the scroll to Marion and then types his name using the hand code.
+// The German version script contains a typo (probably a copy/paste error),
+// and the function that is used to show each letter is called twice. The
+// second time that the function is called, the second parameter passed to
+// the function is undefined, thus kStrCat() that is called inside the function
+// reads a random pointer and crashes. We patch all of the 5 function calls
+// (one for each letter typed from "R", "O", "B", "I", "N") so that they are
+// the same as the English version. Fixes bug #3048054.
+const byte longbowSignatureShowHandCode[] = {
+ 3,
+ 0x78, // push1
+ 0x78, // push1
+ 0x72, // lofsa
+ +2, 2, // skip 2 bytes, offset of lofsa (the letter typed)
+ 0x36, // push
+ 0x40, // call
+ +2, 3, // skip 2 bytes, offset of call
+ 0x02, // perform the call above with 2 parameters
+ 0x36, // push
+ 0x40, // call
+ +2, 8, // skip 2 bytes, offset of call
+ 0x02, // perform the call above with 2 parameters
+ 0x38, 0x1c, 0x01, // pushi 011c (setMotion)
+ 0x39, 0x04, // pushi 04 (x)
+ 0x51, 0x1e, // class MoveTo
+ 0
+};
+
+const uint16 longbowPatchShowHandCode[] = {
+ 0x39, 0x01, // pushi 1 (combine the two push1's in one, like in the English version)
+ PATCH_ADDTOOFFSET | +3, // leave the lofsa call untouched
+ // The following will remove the duplicate call
+ 0x32, 0x02, 0x00, // jmp 02 - skip 2 bytes (the remainder of the first call)
+ 0x48, // ret (dummy, should never be reached)
+ 0x48, // ret (dummy, should never be reached)
+ PATCH_END
+};
+
+// script, description, magic DWORD, adjust
+const SciScriptSignature longbowSignatures[] = {
+ { 210, "hand code crash", 5, PATCH_MAGICDWORD(0x02, 0x38, 0x1c, 0x01), -14, longbowSignatureShowHandCode, longbowPatchShowHandCode },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
// this is called on every death dialog. Problem is at least the german
// version of lsl6 gets title text that is far too long for the
// available temp space resulting in temp space corruption
@@ -703,7 +668,7 @@ const SciScriptSignature larry6Signatures[] = {
};
// ===========================================================================
-// rm560::doit was supposed to close the painting, when heimlich enters the
+// rm560::doit was supposed to close the painting, when Heimlich enters the
// room. The code is buggy, so it actually closes the painting, when heimlich
// is not in the room. We fix that.
const byte laurabow2SignaturePaintingClosing[] = {
@@ -826,44 +791,10 @@ const uint16 qfg1vgaPatchFightEvents[] = {
PATCH_END
};
-// When QFG1VGA and QFG3 dispose of a child window. For example, when choosing
-// a spell (parent window), if the spell can't be casted, a subsequent window
-// opens, notifying that it can't be casted. When showing the child window, the
-// scripts restore the area below the parent window, draw the child window, and
-// then attempt to redraw the parent window, which leads to the background
-// picture (which has just been restored) overwriting the child window. It
-// appers that kGraph(redrawBox) is different in QFG1VGA and QFG3. However, we
-// can just remove the window redraw and update calls when the window is
-// supposed to be disposed, and the window is disposed of correctly. Fixes bug
-// #3053093.
-const byte qfg1vgaWindowDispose[] = {
- 17,
- 0x39, 0x05, // pushi 05
- 0x39, 0x0d, // pushi 0d
- 0x67, 0x2e, // pTos 2e
- 0x67, 0x30, // pTos 30
- 0x67, 0x32, // pTos 32
- 0x67, 0x34, // pTos 34
- 0x43, 0x6c, 0x0a, // callk kGraph 10
- 0x39, 0x06, // pushi 06
- 0
-};
-
-const uint16 qfg1vgaPatchWindowDispose[] = {
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x33, 0x3e, // jmp 0x3e (skip 62 bytes - this skips the subsequent 2 kGraph(update) calls, before kDisposeWindow is invoked)
- PATCH_END
-};
-
// script, description, magic DWORD, adjust
const SciScriptSignature qfg1vgaSignatures[] = {
{ 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
- { 559, "window dispose", 1, PATCH_MAGICDWORD(0x39, 0x05, 0x39, 0x0d), 0, qfg1vgaWindowDispose, qfg1vgaPatchWindowDispose },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -927,37 +858,6 @@ const uint16 qfg3PatchImportDialog[] = {
PATCH_END
};
-// When QFG1VGA and QFG3 dispose of a child window. For example, when choosing
-// a spell (parent window), if the spell can't be casted, a subsequent window
-// opens, notifying that it can't be casted. When showing the child window, the
-// scripts restore the area below the parent window, draw the child window, and
-// then attempt to redraw the parent window, which leads to the background
-// picture (which has just been restored) overwriting the child window. It
-// appers that kGraph(redrawBox) is different in QFG1VGA and QFG3. However, we
-// can just remove the window redraw and update calls when the window is
-// supposed to be disposed, and the window is disposed of correctly. Fixes bug
-// #3053093.
-const byte qfg3WindowDispose[] = {
- 15,
- 0x39, 0x05, // pushi 05
- 0x39, 0x0d, // pushi 0d
- 0x67, 0x2e, // pTos 2e
- 0x67, 0x30, // pTos 30
- 0x67, 0x32, // pTos 32
- 0x67, 0x34, // pTos 34
- 0x43, 0x6c, 0x0a, // callk kGraph 10
- 0
-};
-
-const uint16 qfg3PatchWindowDispose[] = {
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- PATCH_END
-};
-
// Script 23 in QFG3 has a typo/bug which makes it loop endlessly and
// read garbage. Fixes bug #3040722.
const byte qfg3DialogCrash[] = {
@@ -976,7 +876,6 @@ const uint16 qfg3PatchDialogCrash[] = {
// script, description, magic DWORD, adjust
const SciScriptSignature qfg3Signatures[] = {
- { 22, "window dispose", 1, PATCH_MAGICDWORD(0x39, 0x05, 0x39, 0x0d), 0, qfg3WindowDispose, qfg3PatchWindowDispose },
{ 23, "dialog crash", 1, PATCH_MAGICDWORD(0xe7, 0x03, 0x22, 0x33), -1, qfg3DialogCrash, qfg3PatchDialogCrash },
{ 944, "import dialog continuous calls", 1, PATCH_MAGICDWORD(0x2a, 0x31, 0x0b, 0x7a), -1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
SCI_SIGNATUREENTRY_TERMINATOR
@@ -1095,55 +994,6 @@ const SciScriptSignature sq4Signatures[] = {
SCI_SIGNATUREENTRY_TERMINATOR
};
-// ===========================================================================
-// It seems to scripts warp ego outside the screen somehow (or maybe kDoBresen?)
-// ego::mover is set to 0 and rm119::doit will crash in that case. This here
-// fixes part of the problem and actually checks ego::mover to be 0 and skips
-// TODO: this should get further investigated by waltervn and maybe properly
-// patched. For now ego will shortly disappear and reappear a bit after
-// this isn't good, but sierra sci also "crashed" (endless looped) so this
-// is at least better than the original code
-const byte sq5SignatureScrubbing[] = {
- 19,
- 0x18, // not
- 0x31, 0x37, // bnt 37
- 0x78, // push1 (selector x)
- 0x76, // push0
- 0x39, 0x38, // pushi 38 (selector mover)
- 0x76, // push0
- 0x81, 0x00, // lag 00
- 0x4a, 0x04, // send 04 - read ego::mover
- 0x4a, 0x04, // send 04 - read ego::mover::x
- 0x36, // push
- 0x34, 0xa0, 0x00, // ldi 00a0
- 0x1c, // ne?
- 0
-};
-
-const uint16 sq5PatchScrubbing[] = {
- 0x18, // not
- 0x31, 0x37, // bnt 37
-// 0x2f, 0x38, // bt 37 (would save another byte, isn't needed
- 0x39, 0x38, // pushi 38 (selector mover)
- 0x76, // push0
- 0x81, 0x00, // lag 00
- 0x4a, 0x04, // send 04 - read ego::mover
- 0x31, 0x2e, // bnt 2e (jump if ego::mover is 0)
- 0x78, // push1 (selector x)
- 0x76, // push0
- 0x4a, 0x04, // send 04 - read ego::mover::x
- 0x39, 0xa0, // pushi a0 (saving 2 bytes)
- 0x1c, // ne?
- PATCH_END
-};
-
-// script, description, magic DWORD, adjust
-const SciScriptSignature sq5Signatures[] = {
- { 119, "scrubbing send crash", 1, PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing },
- SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-
// will actually patch previously found signature area
void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) {
byte orgData[PATCH_VALUELIMIT];
@@ -1236,12 +1086,6 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
const SciScriptSignature *signatureTable = NULL;
switch (g_sci->getGameId()) {
- // Dr. Brain now works because we properly maintain the state of the string heap in savegames
-#if 0
- case GID_CASTLEBRAIN:
- signatureTable = castlebrainSignatures;
- break;
-#endif
case GID_ECOQUEST:
signatureTable = ecoquest1Signatures;
break;
@@ -1257,12 +1101,6 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
case GID_GK1:
signatureTable = gk1Signatures;
break;
- // hoyle4 now works due to workaround inside GfxPorts
-#if 0
- case GID_HOYLE4:
- signatureTable = hoyle4Signatures;
- break;
-#endif
case GID_KQ5:
signatureTable = kq5Signatures;
break;
@@ -1272,6 +1110,9 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
case GID_LAURABOW2:
signatureTable = laurabow2Signatures;
break;
+ case GID_LONGBOW:
+ signatureTable = longbowSignatures;
+ break;
case GID_LSL6:
signatureTable = larry6Signatures;
break;
@@ -1290,9 +1131,6 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
case GID_SQ4:
signatureTable = sq4Signatures;
break;
- case GID_SQ5:
- signatureTable = sq5Signatures;
- break;
default:
break;
}
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 184f81bb99..76490217c3 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -281,6 +281,35 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode
return retval;
}
+bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget)
+{
+ SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT);
+ if (!mobj)
+ return false;
+ Script *script_entity = (Script *)mobj;
+
+ const byte *scr = script_entity->getBuf();
+ int scr_size = script_entity->getBufSize();
+
+ if (pos.offset >= scr_size)
+ return false;
+
+ int16 opparams[4];
+ byte opsize;
+ int bytecount = readPMachineInstruction(scr + pos.offset, opsize, opparams);
+ const byte opcode = opsize >> 1;
+
+ switch (opcode) {
+ case op_bt:
+ case op_bnt:
+ case op_jmp:
+ jumpTarget = pos + bytecount + opparams[0];
+ return true;
+ default:
+ return false;
+ }
+}
+
void SciEngine::scriptDebug() {
EngineState *s = _gamestate;
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index ffc81f0fde..0dc245a991 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -63,7 +63,7 @@ void SegManager::resetSegMan() {
// Free memory
for (uint i = 0; i < _heap.size(); i++) {
if (_heap[i])
- deallocate(i, false);
+ deallocate(i);
}
_heap.clear();
@@ -151,16 +151,17 @@ Script *SegManager::allocateScript(int script_nr, SegmentId *segid) {
return (Script *)mem;
}
-void SegManager::deallocate(SegmentId seg, bool recursive) {
- VERIFY(check(seg), "invalid seg id");
+void SegManager::deallocate(SegmentId seg) {
+ if (!check(seg))
+ error("SegManager::deallocate(): invalid segment ID");
SegmentObj *mobj = _heap[seg];
if (mobj->getType() == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
_scriptSegMap.erase(scr->getScriptNumber());
- if (recursive && scr->_localsSegment)
- deallocate(scr->_localsSegment, recursive);
+ if (scr->_localsSegment)
+ deallocate(scr->_localsSegment);
}
delete mobj;
@@ -176,8 +177,7 @@ bool SegManager::isHeapObject(reg_t pos) const {
}
void SegManager::deallocateScript(int script_nr) {
- SegmentId seg = getScriptSegment(script_nr);
- deallocate(seg, true);
+ deallocate(getScriptSegment(script_nr));
}
Script *SegManager::getScript(const SegmentId seg) {
@@ -360,9 +360,8 @@ LocalVariables *SegManager::allocLocalsSegment(Script *scr) {
if (scr->_localsSegment) {
locals = (LocalVariables *)_heap[scr->_localsSegment];
- VERIFY(locals != NULL, "Re-used locals segment was NULL'd out");
- VERIFY(locals->getType() == SEG_TYPE_LOCALS, "Re-used locals segment did not consist of local variables");
- VERIFY(locals->script_id == scr->getScriptNumber(), "Re-used locals segment belonged to other script");
+ if (!locals || locals->getType() != SEG_TYPE_LOCALS || locals->script_id != scr->getScriptNumber())
+ error("Invalid script locals segment while allocating locals");
} else
locals = (LocalVariables *)allocSegment(new LocalVariables(), &scr->_localsSegment);
@@ -403,7 +402,7 @@ void SegManager::freeHunkEntry(reg_t addr) {
return;
}
- ht->freeEntry(addr.offset);
+ ht->freeEntryContents(addr.offset);
}
reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
@@ -602,13 +601,13 @@ static inline char getChar(const SegmentRef &ref, uint offset) {
warning("Attempt to read character from non-raw data");
bool oddOffset = offset & 1;
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- oddOffset = !oddOffset; // Amiga versions are BE
+ if (g_sci->isBE())
+ oddOffset = !oddOffset;
return (oddOffset ? val.offset >> 8 : val.offset & 0xff);
}
-static inline void setChar(const SegmentRef &ref, uint offset, char value) {
+static inline void setChar(const SegmentRef &ref, uint offset, byte value) {
if (ref.skipByte)
offset++;
@@ -617,8 +616,8 @@ static inline void setChar(const SegmentRef &ref, uint offset, char value) {
val->segment = 0;
bool oddOffset = offset & 1;
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- oddOffset = !oddOffset; // Amiga versions are BE
+ if (g_sci->isBE())
+ oddOffset = !oddOffset;
if (oddOffset)
val->offset = (val->offset & 0x00ff) | (value << 8);
@@ -864,7 +863,7 @@ bool SegManager::freeDynmem(reg_t addr) {
if (addr.segment < 1 || addr.segment >= _heap.size() || !_heap[addr.segment] || _heap[addr.segment]->getType() != SEG_TYPE_DYNMEM)
return false; // error
- deallocate(addr.segment, true);
+ deallocate(addr.segment);
return true; // OK
}
@@ -1022,7 +1021,7 @@ void SegManager::uninstantiateScript(int script_nr) {
SegmentId segmentId = getScriptSegment(script_nr);
Script *scr = getScriptIfLoaded(segmentId);
- if (!scr) { // Is it already unloaded?
+ if (!scr || scr->isMarkedAsDeleted()) { // Is it already unloaded?
//warning("unloading script 0x%x requested although not loaded", script_nr);
// This is perfectly valid SCI behaviour
return;
@@ -1079,15 +1078,7 @@ void SegManager::uninstantiateScriptSci0(int script_nr) {
if (scr->getLockers())
scr->decrementLockers(); // Decrease lockers if this is us ourselves
} else {
- if (g_sci->getGameId() == GID_HOYLE3 && (superclass_script == 0 || superclass_script >= 990)) {
- // HACK for Hoyle 3: when exiting Checkers or Pachisi, scripts 0, 999 and some others
- // are deleted but are never instantiated again. We ignore deletion of these scripts
- // here for Hoyle 3 - bug #3038837
- // TODO/FIXME: find out why this happens, seems like there is a problem with the object
- // lock code
- } else {
- uninstantiateScript(superclass_script);
- }
+ uninstantiateScript(superclass_script);
}
// Recurse to assure that the superclass lockers number gets decreased
}
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 61fa2e2245..d402afbf1a 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -36,15 +36,6 @@
namespace Sci {
/**
- * Verify the the given condition is true, output the message if condition is false, and exit.
- * @param cond condition to be verified
- * @param msg the message to be printed if condition fails
- */
-#define VERIFY( cond, msg ) if (!(cond)) {\
- error("%s, line, %d, %s", __FILE__, __LINE__, msg); \
- }
-
-/**
* Parameters for getScriptSegment().
*/
enum ScriptLoadType {
@@ -477,7 +468,7 @@ private:
private:
SegmentObj *allocSegment(SegmentObj *mem, SegmentId *segid);
- void deallocate(SegmentId seg, bool recursive);
+ void deallocate(SegmentId seg);
void createClassTable();
SegmentId findFreeSegment() const;
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index 05d914cffb..2bb77c707a 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -39,7 +39,6 @@ namespace Sci {
//#define GC_DEBUG // Debug garbage collection
//#define GC_DEBUG_VERBOSE // Debug garbage verbosely
-
SegmentObj *SegmentObj::createSegmentObj(SegmentType type) {
SegmentObj *mem = 0;
switch (type) {
@@ -85,116 +84,12 @@ SegmentObj *SegmentObj::createSegmentObj(SegmentType type) {
return mem;
}
-const char *SegmentObj::getSegmentTypeName(SegmentType type) {
- switch (type) {
- case SEG_TYPE_SCRIPT:
- return "script";
- break;
- case SEG_TYPE_CLONES:
- return "clones";
- break;
- case SEG_TYPE_LOCALS:
- return "locals";
- break;
- case SEG_TYPE_STACK:
- return "stack";
- break;
- case SEG_TYPE_HUNK:
- return "hunk";
- break;
- case SEG_TYPE_LISTS:
- return "lists";
- break;
- case SEG_TYPE_NODES:
- return "nodes";
- break;
- case SEG_TYPE_DYNMEM:
- return "dynmem";
- break;
-#ifdef ENABLE_SCI32
- case SEG_TYPE_ARRAY:
- return "array";
- break;
- case SEG_TYPE_STRING:
- return "string";
- break;
-#endif
- default:
- error("Unknown SegmentObj type %d", type);
- break;
- }
- return NULL;
-}
-
SegmentRef SegmentObj::dereference(reg_t pointer) {
error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment",
PRINT_REG(pointer));
return SegmentRef();
}
-
-bool LocalVariables::isValidOffset(uint16 offset) const {
- return offset < _locals.size() * 2;
-}
-
-SegmentRef LocalVariables::dereference(reg_t pointer) {
- SegmentRef ret;
- ret.isRaw = false; // reg_t based data!
- ret.maxSize = (_locals.size() - pointer.offset / 2) * 2;
-
- if (pointer.offset & 1) {
- ret.maxSize -= 1;
- ret.skipByte = true;
- }
-
- if (ret.maxSize > 0) {
- ret.reg = &_locals[pointer.offset / 2];
- } else {
- if ((g_sci->getEngineState()->currentRoomNumber() == 660 || g_sci->getEngineState()->currentRoomNumber() == 660)
- && g_sci->getGameId() == GID_LAURABOW2) {
- // Happens in two places during the intro of LB2CD, both from kMemory(peek):
- // - room 160: Heap 160 has 83 local variables (0-82), and the game
- // asks for variables at indices 83 - 90 too.
- // - room 220: Heap 220 has 114 local variables (0-113), and the
- // game asks for variables at indices 114-120 too.
- } else {
- error("LocalVariables::dereference: Offset at end or out of bounds %04x:%04x", PRINT_REG(pointer));
- }
- ret.reg = 0;
- }
- return ret;
-}
-
-bool DataStack::isValidOffset(uint16 offset) const {
- return offset < _capacity * 2;
-}
-
-SegmentRef DataStack::dereference(reg_t pointer) {
- SegmentRef ret;
- ret.isRaw = false; // reg_t based data!
- ret.maxSize = (_capacity - pointer.offset / 2) * 2;
-
- if (pointer.offset & 1) {
- ret.maxSize -= 1;
- ret.skipByte = true;
- }
-
- ret.reg = &_entries[pointer.offset / 2];
- return ret;
-}
-
-bool DynMem::isValidOffset(uint16 offset) const {
- return offset < _size;
-}
-
-SegmentRef DynMem::dereference(reg_t pointer) {
- SegmentRef ret;
- ret.isRaw = true;
- ret.maxSize = _size - pointer.offset;
- ret.raw = _buf + pointer.offset;
- return ret;
-}
-
//-------------------- clones --------------------
Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const {
@@ -220,8 +115,6 @@ Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const {
void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
#ifdef GC_DEBUG
- // assert(addr.segment == _segId);
-
Object *victim_obj = &(_table[addr.offset]);
if (!(victim_obj->_flags & OBJECT_FLAG_FREED))
@@ -229,30 +122,54 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
#ifdef GC_DEBUG_VERBOSE
else
warning("[GC-DEBUG] Clone %04x:%04x: Freeing", PRINT_REG(addr));
+
+ warning("[GC] Clone had pos %04x:%04x", PRINT_REG(victim_obj->pos));
#endif
#endif
- /*
- warning("[GC] Clone %04x:%04x: Freeing", PRINT_REG(addr));
- warning("[GC] Clone had pos %04x:%04x", PRINT_REG(victim_obj->pos));
- */
+
freeEntry(addr.offset);
}
//-------------------- locals --------------------
+
+SegmentRef LocalVariables::dereference(reg_t pointer) {
+ SegmentRef ret;
+ ret.isRaw = false; // reg_t based data!
+ ret.maxSize = (_locals.size() - pointer.offset / 2) * 2;
+
+ if (pointer.offset & 1) {
+ ret.maxSize -= 1;
+ ret.skipByte = true;
+ }
+
+ if (ret.maxSize > 0) {
+ ret.reg = &_locals[pointer.offset / 2];
+ } else {
+ if ((g_sci->getEngineState()->currentRoomNumber() == 660 || g_sci->getEngineState()->currentRoomNumber() == 660)
+ && g_sci->getGameId() == GID_LAURABOW2) {
+ // Happens in two places during the intro of LB2CD, both from kMemory(peek):
+ // - room 160: Heap 160 has 83 local variables (0-82), and the game
+ // asks for variables at indices 83 - 90 too.
+ // - room 220: Heap 220 has 114 local variables (0-113), and the
+ // game asks for variables at indices 114-120 too.
+ } else {
+ error("LocalVariables::dereference: Offset at end or out of bounds %04x:%04x", PRINT_REG(pointer));
+ }
+ ret.reg = 0;
+ }
+ return ret;
+}
+
reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
// Reference the owning script
SegmentId owner_seg = segMan->getScriptSegment(script_id);
-
assert(owner_seg > 0);
-
return make_reg(owner_seg, 0);
}
Common::Array<reg_t> LocalVariables::listAllOutgoingReferences(reg_t addr) const {
Common::Array<reg_t> tmp;
-// assert(addr.segment == _segId);
-
for (uint i = 0; i < _locals.size(); i++)
tmp.push_back(_locals[i]);
@@ -261,9 +178,19 @@ Common::Array<reg_t> LocalVariables::listAllOutgoingReferences(reg_t addr) const
//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
- addr.offset = 0;
- return addr;
+
+SegmentRef DataStack::dereference(reg_t pointer) {
+ SegmentRef ret;
+ ret.isRaw = false; // reg_t based data!
+ ret.maxSize = (_capacity - pointer.offset / 2) * 2;
+
+ if (pointer.offset & 1) {
+ ret.maxSize -= 1;
+ ret.skipByte = true;
+ }
+
+ ret.reg = &_entries[pointer.offset / 2];
+ return ret;
}
Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const {
@@ -274,11 +201,7 @@ Common::Array<reg_t> DataStack::listAllOutgoingReferences(reg_t object) const {
return tmp;
}
-
//-------------------- lists --------------------
-void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- freeEntry(sub_addr.offset);
-}
Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const {
Common::Array<reg_t> tmp;
@@ -296,11 +219,7 @@ Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const {
return tmp;
}
-
//-------------------- nodes --------------------
-void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- freeEntry(sub_addr.offset);
-}
Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const {
Common::Array<reg_t> tmp;
@@ -321,14 +240,12 @@ Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const {
//-------------------- dynamic memory --------------------
-reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
- addr.offset = 0;
- return addr;
-}
-
-Common::Array<reg_t> DynMem::listAllDeallocatable(SegmentId segId) const {
- const reg_t r = make_reg(segId, 0);
- return Common::Array<reg_t>(&r, 1);
+SegmentRef DynMem::dereference(reg_t pointer) {
+ SegmentRef ret;
+ ret.isRaw = true;
+ ret.maxSize = _size - pointer.offset;
+ ret.raw = _buf + pointer.offset;
+ return ret;
}
#ifdef ENABLE_SCI32
@@ -393,11 +310,6 @@ SegmentRef StringTable::dereference(reg_t pointer) {
return ret;
}
-void StringTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- _table[sub_addr.offset].destroy();
- freeEntry(sub_addr.offset);
-}
-
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 9aaa3a4b08..ffde01f934 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -84,7 +84,6 @@ struct SegmentObj : public Common::Serializable {
public:
static SegmentObj *createSegmentObj(SegmentType type);
- static const char *getSegmentTypeName(SegmentType type);
public:
SegmentObj(SegmentType type) : _type(type) {}
@@ -150,11 +149,11 @@ struct LocalVariables : public SegmentObj {
Common::Array<reg_t> _locals;
public:
- LocalVariables(): SegmentObj(SEG_TYPE_LOCALS) {
- script_id = 0;
- }
+ LocalVariables(): SegmentObj(SEG_TYPE_LOCALS), script_id(0) { }
- virtual bool isValidOffset(uint16 offset) const;
+ virtual bool isValidOffset(uint16 offset) const {
+ return offset < _locals.size() * 2;
+ }
virtual SegmentRef dereference(reg_t pointer);
virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
@@ -168,18 +167,19 @@ struct DataStack : SegmentObj {
reg_t *_entries;
public:
- DataStack() : SegmentObj(SEG_TYPE_STACK) {
- _capacity = 0;
- _entries = NULL;
- }
+ DataStack() : SegmentObj(SEG_TYPE_STACK), _capacity(0), _entries(NULL) { }
~DataStack() {
free(_entries);
_entries = NULL;
}
- virtual bool isValidOffset(uint16 offset) const;
+ virtual bool isValidOffset(uint16 offset) const {
+ return offset < _capacity * 2;
+ }
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const {
+ return make_reg(addr.segment, 0);
+ }
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
@@ -211,7 +211,7 @@ struct Hunk {
};
template<typename T>
-struct Table : public SegmentObj {
+struct SegmentObjTable : public SegmentObj {
typedef T value_type;
struct Entry : public T {
int next_free; /* Only used for free entries */
@@ -225,7 +225,7 @@ struct Table : public SegmentObj {
Common::Array<Entry> _table;
public:
- Table(SegmentType type) : SegmentObj(type) {
+ SegmentObjTable(SegmentType type) : SegmentObj(type) {
initTable();
}
@@ -279,8 +279,8 @@ public:
/* CloneTable */
-struct CloneTable : public Table<Clone> {
- CloneTable() : Table<Clone>(SEG_TYPE_CLONES) {}
+struct CloneTable : public SegmentObjTable<Clone> {
+ CloneTable() : SegmentObjTable<Clone>(SEG_TYPE_CLONES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
@@ -290,10 +290,12 @@ struct CloneTable : public Table<Clone> {
/* NodeTable */
-struct NodeTable : public Table<Node> {
- NodeTable() : Table<Node>(SEG_TYPE_NODES) {}
+struct NodeTable : public SegmentObjTable<Node> {
+ NodeTable() : SegmentObjTable<Node>(SEG_TYPE_NODES) {}
- virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
+ freeEntry(sub_addr.offset);
+ }
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
@@ -301,10 +303,12 @@ struct NodeTable : public Table<Node> {
/* ListTable */
-struct ListTable : public Table<List> {
- ListTable() : Table<List>(SEG_TYPE_LISTS) {}
+struct ListTable : public SegmentObjTable<List> {
+ ListTable() : SegmentObjTable<List>(SEG_TYPE_LISTS) {}
- virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
+ freeEntry(sub_addr.offset);
+ }
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
@@ -312,18 +316,23 @@ struct ListTable : public Table<List> {
/* HunkTable */
-struct HunkTable : public Table<Hunk> {
- HunkTable() : Table<Hunk>(SEG_TYPE_HUNK) {}
-
- virtual void freeEntry(int idx) {
- Table<Hunk>::freeEntry(idx);
+struct HunkTable : public SegmentObjTable<Hunk> {
+ HunkTable() : SegmentObjTable<Hunk>(SEG_TYPE_HUNK) {}
- if (!_table[idx].mem)
- warning("Attempt to free an already freed hunk");
+ void freeEntryContents(int idx) {
free(_table[idx].mem);
_table[idx].mem = 0;
}
+ virtual void freeEntry(int idx) {
+ SegmentObjTable<Hunk>::freeEntry(idx);
+ freeEntryContents(idx);
+ }
+
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
+ freeEntry(sub_addr.offset);
+ }
+
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -341,10 +350,17 @@ public:
_buf = NULL;
}
- virtual bool isValidOffset(uint16 offset) const;
+ virtual bool isValidOffset(uint16 offset) const {
+ return offset < _size;
+ }
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
- virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const;
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t addr) const {
+ return make_reg(addr.segment, 0);
+ }
+ virtual Common::Array<reg_t> listAllDeallocatable(SegmentId segId) const {
+ const reg_t r = make_reg(segId, 0);
+ return Common::Array<reg_t>(&r, 1);
+ }
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -354,12 +370,7 @@ public:
template <typename T>
class SciArray {
public:
- SciArray() {
- _type = -1;
- _data = NULL;
- _size = 0;
- _actualSize = 0;
- }
+ SciArray() : _type(-1), _data(NULL), _size(0), _actualSize(0) { }
SciArray(const SciArray<T> &array) {
_type = array._type;
@@ -474,8 +485,8 @@ public:
void fromString(const Common::String &string);
};
-struct ArrayTable : public Table<SciArray<reg_t> > {
- ArrayTable() : Table<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
+struct ArrayTable : public SegmentObjTable<SciArray<reg_t> > {
+ ArrayTable() : SegmentObjTable<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
virtual Common::Array<reg_t> listAllOutgoingReferences(reg_t object) const;
@@ -484,10 +495,13 @@ struct ArrayTable : public Table<SciArray<reg_t> > {
SegmentRef dereference(reg_t pointer);
};
-struct StringTable : public Table<SciString> {
- StringTable() : Table<SciString>(SEG_TYPE_STRING) {}
+struct StringTable : public SegmentObjTable<SciString> {
+ StringTable() : SegmentObjTable<SciString>(SEG_TYPE_STRING) {}
- virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
+ virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
+ _table[sub_addr.offset].destroy();
+ freeEntry(sub_addr.offset);
+ }
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 798dbf529c..957a836e3e 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -165,6 +165,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(vanishingX);
FIND_SELECTOR(vanishingY);
FIND_SELECTOR(iconIndex);
+ FIND_SELECTOR(select);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 6038ad0c36..8a47984204 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -130,6 +130,7 @@ struct SelectorCache {
// SCI1.1 Mac icon bar selectors
Selector iconIndex; ///< Used to index icon bar objects
+ Selector select;
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp
index 4bb61a0658..23241de330 100644
--- a/engines/sci/engine/static_selectors.cpp
+++ b/engines/sci/engine/static_selectors.cpp
@@ -28,6 +28,7 @@
#include "sci/engine/kernel.h"
#include "sci/engine/seg_manager.h"
+#include "sci/engine/vm.h"
namespace Sci {
@@ -118,6 +119,33 @@ static const SelectorRemap sciSelectorRemap[] = {
{ SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 }
};
+struct ClassReference {
+ int script;
+ const char *className;
+ const char *selectorName;
+ SelectorType selectorType;
+ uint selectorOffset;
+};
+
+// For variable selectors, we ignore the global selectors and start off from
+// the object's selectors (i.e. from the name selector onwards). Thus, the
+// following are not taken into consideration when calculating the indices of
+// variable selectors in this array:
+// SCI0 - SCI1: species, superClass, -info-
+// SCI1.1: -objID-, -size-, -propDict-, -methDict-, -classScript-, -script-,
+// -super-, -info-
+static const ClassReference classReferences[] = {
+ { 0, "Character", "say", kSelectorMethod, 5 }, // Crazy Nick's Soft Picks
+ { 928, "Narrator", "say", kSelectorMethod, 4 },
+ { 928, "Narrator", "startText", kSelectorMethod, 5 },
+ { 929, "Sync", "syncTime", kSelectorVariable, 1 },
+ { 929, "Sync", "syncCue", kSelectorVariable, 2 },
+ { 981, "SysWindow", "open", kSelectorMethod, 1 },
+ { 999, "Script", "init", kSelectorMethod, 0 },
+ { 999, "Script", "dispose", kSelectorMethod, 2 },
+ { 999, "Script", "changeState", kSelectorMethod, 3 }
+};
+
Common::StringArray Kernel::checkStaticSelectorNames() {
Common::StringArray names;
const int offset = (getSciVersion() < SCI_VERSION_1_1) ? 3 : 0;
@@ -158,133 +186,115 @@ Common::StringArray Kernel::checkStaticSelectorNames() {
names[i] = sci11Selectors[i - count - countSci1];
}
- // Now, we need to find out selectors which keep changing place...
- // We do that by dissecting game objects, and looking for selectors at
- // specified locations.
+ findSpecificSelectors(names);
- // We need to initialize script 0 here, to make sure that it's always
- // located at segment 1.
- _segMan->instantiateScript(0);
-
- // The Actor class contains the init, xLast and yLast selectors, which
- // we reference directly. It's always in script 998, so we need to
- // explicitly load it here.
- if (_resMan->testResource(ResourceId(kResourceTypeScript, 998))) {
- _segMan->instantiateScript(998);
-
- const Object *actorClass = _segMan->getObject(_segMan->findObjectByName("Actor"));
-
- if (actorClass) {
- // The init selector is always the first function
- int initSelectorPos = actorClass->getFuncSelector(0);
+#ifdef ENABLE_SCI32
+ } else {
+ // SCI2+
+ for (int i = 0; i < count; i++)
+ names[i] = sci2Selectors[i];
+#endif
+ }
- if (names.size() < (uint32)initSelectorPos + 2)
- names.resize((uint32)initSelectorPos + 2);
+ for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) {
+ if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) {
+ const uint32 slot = selectorRemap->slot;
+ if (slot >= names.size())
+ names.resize(slot + 1);
+ names[slot] = selectorRemap->name;
+ }
+ }
- names[initSelectorPos] = "init";
- // dispose comes right after init
- names[initSelectorPos + 1] = "dispose";
+ return names;
+}
- if ((getSciVersion() >= SCI_VERSION_1_EGA)) {
- // Find the xLast and yLast selectors, used in kDoBresen
+void Kernel::findSpecificSelectors(Common::StringArray &selectorNames) {
+ // Now, we need to find out selectors which keep changing place...
+ // We do that by dissecting game objects, and looking for selectors at
+ // specified locations.
- // xLast and yLast always come between illegalBits and xStep
- int illegalBitsSelectorPos = actorClass->locateVarSelector(_segMan, 15 + offset); // illegalBits
- int xStepSelectorPos = actorClass->locateVarSelector(_segMan, 51 + offset); // xStep
- if (xStepSelectorPos - illegalBitsSelectorPos != 3) {
- error("illegalBits and xStep selectors aren't found in "
- "known locations. illegalBits = %d, xStep = %d",
- illegalBitsSelectorPos, xStepSelectorPos);
- }
+ // We need to initialize script 0 here, to make sure that it's always
+ // located at segment 1.
+ _segMan->instantiateScript(0);
- int xLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 1);
- int yLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 2);
+ // The Actor class contains the init, xLast and yLast selectors, which
+ // we reference directly. It's always in script 998, so we need to
+ // explicitly load it here.
+ if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY)) {
+ if (_resMan->testResource(ResourceId(kResourceTypeScript, 998))) {
+ _segMan->instantiateScript(998);
- if (names.size() < (uint32)yLastSelectorPos + 1)
- names.resize((uint32)yLastSelectorPos + 1);
+ const Object *actorClass = _segMan->getObject(_segMan->findObjectByName("Actor"));
- names[xLastSelectorPos] = "xLast";
- names[yLastSelectorPos] = "yLast";
- } // if ((getSciVersion() >= SCI_VERSION_1_EGA))
+ if (actorClass) {
+ // Find the xLast and yLast selectors, used in kDoBresen
+
+ const int offset = (getSciVersion() < SCI_VERSION_1_1) ? 3 : 0;
+ // xLast and yLast always come between illegalBits and xStep
+ int illegalBitsSelectorPos = actorClass->locateVarSelector(_segMan, 15 + offset); // illegalBits
+ int xStepSelectorPos = actorClass->locateVarSelector(_segMan, 51 + offset); // xStep
+ if (xStepSelectorPos - illegalBitsSelectorPos != 3) {
+ error("illegalBits and xStep selectors aren't found in "
+ "known locations. illegalBits = %d, xStep = %d",
+ illegalBitsSelectorPos, xStepSelectorPos);
+ }
+
+ int xLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 1);
+ int yLastSelectorPos = actorClass->getVarSelector(illegalBitsSelectorPos + 2);
+
+ if (selectorNames.size() < (uint32)yLastSelectorPos + 1)
+ selectorNames.resize((uint32)yLastSelectorPos + 1);
+
+ selectorNames[xLastSelectorPos] = "xLast";
+ selectorNames[yLastSelectorPos] = "yLast";
} // if (actorClass)
_segMan->uninstantiateScript(998);
} // if (_resMan->testResource(ResourceId(kResourceTypeScript, 998)))
+ } // if ((getSciVersion() >= SCI_VERSION_1_EGA_ONLY))
+
+ // Find selectors from specific classes
+
+ for (int i = 0; i < ARRAYSIZE(classReferences); i++) {
+ if (!_resMan->testResource(ResourceId(kResourceTypeScript, classReferences[i].script)))
+ continue;
- if (_resMan->testResource(ResourceId(kResourceTypeScript, 981))) {
- // The SysWindow class contains the open selectors, which we
- // reference directly. It's always in script 981, so we need to
- // explicitly load it here
- _segMan->instantiateScript(981);
+ _segMan->instantiateScript(classReferences[i].script);
- const Object *sysWindowClass = _segMan->getObject(_segMan->findObjectByName("SysWindow"));
+ const Object *targetClass = _segMan->getObject(_segMan->findObjectByName(classReferences[i].className));
+ int targetSelectorPos = 0;
+ uint selectorOffset = classReferences[i].selectorOffset;
- if (sysWindowClass) {
- if (sysWindowClass->getMethodCount() < 2)
- error("The SysWindow class has less than 2 methods");
+ if (targetClass) {
+ if (classReferences[i].selectorType == kSelectorMethod) {
+ if (targetClass->getMethodCount() < selectorOffset + 1)
+ error("The %s class has less than %d methods (%d)",
+ classReferences[i].className, selectorOffset + 1,
+ targetClass->getMethodCount());
- // The open selector is always the second function
- int openSelectorPos = sysWindowClass->getFuncSelector(1);
+ targetSelectorPos = targetClass->getFuncSelector(selectorOffset);
+ } else {
+ // Add the global selectors to the selector ID
+ selectorOffset += (getSciVersion() <= SCI_VERSION_1_LATE) ? 3 : 8;
- if (names.size() < (uint32)openSelectorPos + 1)
- names.resize((uint32)openSelectorPos + 1);
+ if (targetClass->getVarCount() < selectorOffset + 1)
+ error("The %s class has less than %d variables (%d)",
+ classReferences[i].className, selectorOffset + 1,
+ targetClass->getVarCount());
- names[openSelectorPos] = "open";
+ targetSelectorPos = targetClass->getVarSelector(selectorOffset);
}
- _segMan->uninstantiateScript(981);
- } // if (_resMan->testResource(ResourceId(kResourceTypeScript, 981)))
-
- if (g_sci->getGameId() == GID_HOYLE4) {
- // The demo of Hoyle 4 is one of the few demos with lip syncing and no selector vocabulary.
- // This needs two selectors, "syncTime" and "syncCue", which keep changing positions in each
- // game. Usually, games with speech and lip sync have a selector vocabulary, so we don't need
- // to set these two selectors, but we need for Hoyle...
- if (names.size() < 276)
- names.resize(276);
-
- names[274] = "syncTime";
- names[275] = "syncCue";
- } else if (g_sci->getGameId() == GID_PEPPER) {
- // Same as above for the non-interactive demo of Pepper
- if (names.size() < 539)
- names.resize(539);
-
- names[263] = "syncTime";
- names[264] = "syncCue";
- names[538] = "startText";
- } else if (g_sci->getGameId() == GID_LAURABOW2) {
- // The floppy of version needs the changeState selector set to match up with the
- // CD version's workarounds.
- if (names.size() < 251)
- names.resize(251);
-
- names[144] = "changeState";
- } else if (g_sci->getGameId() == GID_CNICK_KQ) {
- if (names.size() < 447)
- names.resize(447);
-
- names[446] = "say";
- }
+ if (selectorNames.size() < (uint32)targetSelectorPos + 1)
+ selectorNames.resize((uint32)targetSelectorPos + 1);
-#ifdef ENABLE_SCI32
- } else {
- // SCI2+
- for (int i = 0; i < count; i++)
- names[i] = sci2Selectors[i];
-#endif
- }
- for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) {
- if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) {
- const uint32 slot = selectorRemap->slot;
- if (slot >= names.size())
- names.resize(slot + 1);
- names[slot] = selectorRemap->name;
+ selectorNames[targetSelectorPos] = classReferences[i].selectorName;
}
}
- return names;
+ // Reset the segment manager
+ _segMan->resetSegMan();
}
} // End of namespace Sci
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 43d38a4979..24f3c96f62 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -118,8 +118,8 @@ static reg_t &validate_property(EngineState *s, Object *obj, int index) {
if (index < 0 || (uint)index >= obj->getVarCount()) {
// This is same way sierra does it and there are some games, that contain such scripts like
// iceman script 998 (fred::canBeHere, executed right at the start)
- debugC(kDebugLevelVM, "[VM] Invalid property #%d (out of [0..%d]) requested!",
- index, obj->getVarCount());
+ debugC(kDebugLevelVM, "[VM] Invalid property #%d (out of [0..%d]) requested from object %04x:%04x (%s)",
+ index, obj->getVarCount(), PRINT_REG(obj->getPos()), s->_segMan->getObjectName(obj->getPos()));
return dummyReg;
}
@@ -632,18 +632,41 @@ static void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunct
debugN(" (%s)", s->_segMan->getObjectName(argv[parmNr]));
break;
case SIG_TYPE_REFERENCE:
- if (kernelCall->function == kSaid) {
- SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]);
- if (saidSpec.isRaw) {
- debugN(" ('");
- g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw);
- debugN("')");
+ {
+ SegmentObj *mobj = s->_segMan->getSegmentObj(argv[parmNr].segment);
+ switch (mobj->getType()) {
+ case SEG_TYPE_HUNK:
+ {
+ HunkTable *ht = (HunkTable*)mobj;
+ int index = argv[parmNr].offset;
+ if (ht->isValidEntry(index)) {
+ // NOTE: This ", deleted" isn't as useful as it could
+ // be because it prints the status _after_ the kernel
+ // call.
+ debugN(" ('%s' hunk%s)", ht->_table[index].type, ht->_table[index].mem ? "" : ", deleted");
+ } else
+ debugN(" (INVALID hunk ref)");
+ break;
+ }
+ default:
+ // TODO: Any other segment types which could
+ // use special handling?
+
+ if (kernelCall->function == kSaid) {
+ SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]);
+ if (saidSpec.isRaw) {
+ debugN(" ('");
+ g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw);
+ debugN("')");
+ } else {
+ debugN(" (non-raw said-spec)");
+ }
} else {
- debugN(" (non-raw said-spec)");
+ debugN(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str());
}
- } else {
- debugN(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str());
+ break;
}
+ }
default:
break;
}
diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp
index dea4d63bf0..e606fa1f86 100644
--- a/engines/sci/engine/vm_types.cpp
+++ b/engines/sci/engine/vm_types.cpp
@@ -31,13 +31,11 @@
namespace Sci {
-extern const char *opcodeNames[]; // from scriptdebug.cpp
-
reg_t reg_t::lookForWorkaround(const reg_t right) const {
SciTrackOriginReply originReply;
SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, arithmeticWorkarounds, &originReply);
if (solution.type == WORKAROUND_NONE)
- error("arithmetic operation on non-integer (%04x:%04x, %04x:%04x) from method %s::%s (script %d, room %d, localCall %x)",
+ error("Invalid arithmetic operation (params: %04x:%04x and %04x:%04x) from method %s::%s (script %d, room %d, localCall %x)",
PRINT_REG(*this), PRINT_REG(right), originReply.objectName.c_str(),
originReply.methodName.c_str(), originReply.scriptNr, g_sci->getEngineState()->currentRoomNumber(),
originReply.localCallOffset);
@@ -46,7 +44,7 @@ reg_t reg_t::lookForWorkaround(const reg_t right) const {
}
reg_t reg_t::operator+(const reg_t right) const {
- if (isPointer() && isInitialized()) {
+ if (isPointer() && right.isNumber()) {
// Pointer arithmetics. Only some pointer types make sense here
SegmentObj *mobj = g_sci->getEngineState()->_segMan->getSegmentObj(segment);
@@ -58,29 +56,18 @@ reg_t reg_t::operator+(const reg_t right) const {
case SEG_TYPE_SCRIPT:
case SEG_TYPE_STACK:
case SEG_TYPE_DYNMEM:
- // Make sure that we are adding an offset to the pointer
- if (right.isPointer())
- return lookForWorkaround(right);
return make_reg(segment, offset + right.toSint16());
default:
return lookForWorkaround(right);
}
- } else if (isNumber() && isInitialized() && right.isPointer()) {
+ } else if (isNumber() && right.isPointer()) {
// Adding a pointer to a number, flip the order
return right + *this;
+ } else if (isNumber() && right.isNumber()) {
+ // Normal arithmetics
+ return make_reg(0, toSint16() + right.toSint16());
} else {
- // Normal arithmetics. Make sure we're adding a number
- if (right.isPointer())
- return lookForWorkaround(right);
- // If the current variable is uninitialized, it'll be set
- // to zero in order to perform the operation. Such a case
- // happens in SQ1, room 28, when throwing the water at Orat.
- if (!isInitialized())
- return make_reg(0, right.toSint16());
- else if (!right.isInitialized())
- return *this;
- else
- return make_reg(0, toSint16() + right.toSint16());
+ return lookForWorkaround(right);
}
}
@@ -97,24 +84,19 @@ reg_t reg_t::operator-(const reg_t right) const {
reg_t reg_t::operator*(const reg_t right) const {
if (isNumber() && right.isNumber())
return make_reg(0, toSint16() * right.toSint16());
- else if (!isInitialized() || !right.isInitialized())
- return NULL_REG; // unitialized variables - always return 0
else
return lookForWorkaround(right);
}
reg_t reg_t::operator/(const reg_t right) const {
- if (isNumber() && right.isNumber()) {
- if (right.isNull())
- return NULL_REG; // division by zero
- else
- return make_reg(0, toSint16() / right.toSint16());
- } else
+ if (isNumber() && right.isNumber() && !right.isNull())
+ return make_reg(0, toSint16() / right.toSint16());
+ else
return lookForWorkaround(right);
}
reg_t reg_t::operator%(const reg_t right) const {
- if (isNumber() && right.isNumber()) {
+ if (isNumber() && right.isNumber() && !right.isNull()) {
// Support for negative numbers was added in Iceman, and perhaps in
// SCI0 0.000.685 and later. Theoretically, this wasn't really used
// in SCI0, so the result is probably unpredictable. Such a case
@@ -125,7 +107,7 @@ reg_t reg_t::operator%(const reg_t right) const {
warning("Modulo of a negative number has been requested for SCI0. This *could* lead to issues");
int16 value = toSint16();
int16 modulo = ABS(right.toSint16());
- int16 result = (modulo != 0 ? value % modulo : 0);
+ int16 result = value % modulo;
if (result < 0)
result += modulo;
return make_reg(0, result);
@@ -159,6 +141,8 @@ uint16 reg_t::requireUint16() const {
if (isNumber())
return toUint16();
else
+ // The right parameter is NULL_REG because
+ // we're not comparing *this with anything here.
return lookForWorkaround(NULL_REG).toUint16();
}
@@ -166,6 +150,8 @@ int16 reg_t::requireSint16() const {
if (isNumber())
return toSint16();
else
+ // The right parameter is NULL_REG because
+ // we're not comparing *this with anything here.
return lookForWorkaround(NULL_REG).toSint16();
}
@@ -190,76 +176,51 @@ reg_t reg_t::operator^(const reg_t right) const {
return lookForWorkaround(right);
}
-bool reg_t::operator>(const reg_t right) const {
- if (isNumber() && right.isNumber())
- return toSint16() > right.toSint16();
- else if (isPointer() && segment == right.segment)
- return toUint16() > right.toUint16(); // pointer comparison
- else if (pointerComparisonWithInteger(right))
- return true;
- else if (right.pointerComparisonWithInteger(*this))
- return false;
- else
- return lookForWorkaround(right).toSint16();
-}
-
-bool reg_t::operator<(const reg_t right) const {
- if (isNumber() && right.isNumber())
- return toSint16() < right.toSint16();
- else if (isPointer() && segment == right.segment)
- return toUint16() < right.toUint16(); // pointer comparison
- else if (pointerComparisonWithInteger(right))
- return false;
- else if (right.pointerComparisonWithInteger(*this))
- return true;
- else
- return lookForWorkaround(right).toSint16();
-}
-
-bool reg_t::gtU(const reg_t right) const {
- if (isNumber() && right.isNumber())
- return toUint16() > right.toUint16();
- else if (isPointer() && segment == right.segment)
- return toUint16() > right.toUint16(); // pointer comparison
- else if (pointerComparisonWithInteger(right))
- return true;
- else if (right.pointerComparisonWithInteger(*this))
- return false;
- else
- return lookForWorkaround(right).toSint16();
-}
-
-bool reg_t::ltU(const reg_t right) const {
- if (isNumber() && right.isNumber())
- return toUint16() < right.toUint16();
- else if (isPointer() && segment == right.segment)
- return toUint16() < right.toUint16(); // pointer comparison
- else if (pointerComparisonWithInteger(right))
- return false;
- else if (right.pointerComparisonWithInteger(*this))
- return true;
- else
+int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
+ if (segment == right.segment) { // can compare things in the same segment
+ if (treatAsUnsigned || !isNumber())
+ return toUint16() - right.toUint16();
+ else
+ return toSint16() - right.toSint16();
+ } else if (pointerComparisonWithInteger(right)) {
+ return 1;
+ } else if (right.pointerComparisonWithInteger(*this)) {
+ return -1;
+ } else
return lookForWorkaround(right).toSint16();
}
bool reg_t::pointerComparisonWithInteger(const reg_t right) const {
- // SCI0 - SCI1.1 scripts use this to check whether a parameter is a pointer
- // or a far text reference. It is used e.g. by the standard library Print
- // function to distinguish two ways of calling it:
+ // This function handles the case where a script tries to compare a pointer
+ // to a number. Normally, we would not want to allow that. However, SCI0 -
+ // SCI1.1 scripts do this in order to distinguish references to
+ // external resources (which are numbers) from pointers. In
+ // our SCI implementation, such a check may seem pointless, as
+ // one can simply use the segment value to achieve this goal.
+ // But Sierra's SCI did not have the notion of segment IDs, so
+ // both pointer and numbers were simple integers.
+ //
+ // But for some things, scripts had (and have) to distinguish between
+ // numbers and pointers. Lacking the segment information, Sierra's
+ // developers resorted to a hack: If an integer is smaller than a certain
+ // bound, it can be assumed to be a number, otherwise it is assumed to be a
+ // pointer. This allowed them to implement polymorphic functions, such as
+ // the Print function, which can be called in two different ways, with a
+ // pointer or a far text reference:
//
// (Print "foo") // Pointer to a string
// (Print 420 5) // Reference to the fifth message in text resource 420
// It works because in those games, the maximum resource number is 999,
// so any parameter value above that threshold must be a pointer.
// PQ2 japanese compares pointers to 2000 to find out if its a pointer
- // or a resource ID.
- // There are cases where game scripts check for arbitrary numbers against
- // pointers, e.g.:
+ // or a resource ID. Thus, we check for all integers <= 2000.
+ //
+ // Some examples where game scripts check for arbitrary numbers against
+ // pointers:
// Hoyle 3, Pachisi, when any opponent is about to talk
// SQ1, room 28, when throwing water at the Orat
// SQ1, room 58, when giving the ID card to the robot
- // QFG3, room 440, when talking to Uhura
- // Thus we check for all integers <= 2000
+ // SQ4 CD, at the first game screen, when the narrator is about to speak
return (isPointer() && right.isNumber() && right.offset <= 2000 && getSciVersion() <= SCI_VERSION_1_1);
}
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index ac23bbe7dc..b927df339e 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -37,20 +37,20 @@ struct reg_t {
SegmentId segment;
uint16 offset;
- bool isNull() const {
- return !(offset || segment);
+ inline bool isNull() const {
+ return (offset | segment) == 0;
}
- uint16 toUint16() const {
+ inline uint16 toUint16() const {
return offset;
}
- int16 toSint16() const {
- return (int16) offset;
+ inline int16 toSint16() const {
+ return (int16)offset;
}
bool isNumber() const {
- return !segment;
+ return segment == 0;
}
bool isPointer() const {
@@ -60,7 +60,7 @@ struct reg_t {
uint16 requireUint16() const;
int16 requireSint16() const;
- bool isInitialized() const {
+ inline bool isInitialized() const {
return segment != 0xFFFF;
}
@@ -73,35 +73,39 @@ struct reg_t {
return (offset != x.offset) || (segment != x.segment);
}
- bool operator>(const reg_t right) const;
+ bool operator>(const reg_t right) const {
+ return cmp(right, false) > 0;
+ }
+
bool operator>=(const reg_t right) const {
- if (*this == right)
- return true;
- return *this > right;
+ return cmp(right, false) >= 0;
+ }
+
+ bool operator<(const reg_t right) const {
+ return cmp(right, false) < 0;
}
- bool operator<(const reg_t right) const;
+
bool operator<=(const reg_t right) const {
- if (*this == right)
- return true;
- return *this < right;
+ return cmp(right, false) <= 0;
}
// Same as the normal operators, but perform unsigned
// integer checking
- bool gtU(const reg_t right) const;
+ bool gtU(const reg_t right) const {
+ return cmp(right, true) > 0;
+ }
+
bool geU(const reg_t right) const {
- if (*this == right)
- return true;
- return gtU(right);
+ return cmp(right, true) >= 0;
}
- bool ltU(const reg_t right) const;
- bool leU(const reg_t right) const {
- if (*this == right)
- return true;
- return ltU(right);
+
+ bool ltU(const reg_t right) const {
+ return cmp(right, true) < 0;
}
- bool pointerComparisonWithInteger(const reg_t right) const;
+ bool leU(const reg_t right) const {
+ return cmp(right, true) <= 0;
+ }
// Arithmetic operators
reg_t operator+(const reg_t right) const;
@@ -125,7 +129,17 @@ struct reg_t {
reg_t operator|(const reg_t right) const;
reg_t operator^(const reg_t right) const;
+private:
+ /**
+ * Compares two reg_t's.
+ * Returns:
+ * - a positive number if *this > right
+ * - 0 if *this == right
+ * - a negative number if *this < right
+ */
+ int cmp(const reg_t right, bool treatAsUnsigned) const;
reg_t lookForWorkaround(const reg_t right) const;
+ bool pointerComparisonWithInteger(const reg_t right) const;
};
static inline reg_t make_reg(SegmentId segment, uint16 offset) {
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 64cbc5ec90..17c9f9fa0f 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -44,8 +44,6 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {
{ GID_MOTHERGOOSEHIRES,90, 90, 0, "newGameButton", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue.
{ GID_QFG1VGA, 301, 928, 0, "Blink", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_div: when entering the inn, gets called with 1 parameter, but 2nd parameter is used for div which happens to be an object
{ GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer bug #3039879
- // TODO: The SQ5 workaround below may no longer be necessary
- { GID_SQ5, 200, 939, 0, "Osc", "cycleDone", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_dpToa: when going back to bridge the crew is goofing off, we get an object as cycle count
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -120,6 +118,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_MOTHERGOOSEHIRES,-1,64950, 1, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // see above
{ GID_PEPPER, -1, 894, 0, "Package", "doVerb", -1, 3, { WORKAROUND_FAKE, 0 } }, // using the hand on the book in the inventory - bug #3040012
{ GID_PEPPER, 150, 928, 0, "Narrator", "startText", -1, 0, { WORKAROUND_FAKE, 0 } }, // happens during the non-interactive demo of Pepper
+ { GID_PQSWAT, -1, 64950, 0, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // Using the menu in the beginning
{ GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbd0, 0, { WORKAROUND_FAKE, 0 } }, // hq1: going to the brigands hideout
{ GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbe4, 0, { WORKAROUND_FAKE, 0 } }, // qfg1: going to the brigands hideout
{ GID_QFG1VGA, 16, 16, 0, "lassoFailed", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // qfg1vga: casting the "fetch" spell in the screen with the flowers, temps 0 and 1 - bug #3053268
@@ -273,10 +272,6 @@ const SciWorkaroundEntry kGraphSaveBox_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kGraphRestoreBox_workarounds[] = {
- { GID_LSL6, -1, 85, 0, "rScroller", "hide", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens when restoring (sometimes), same as the one below
- { GID_LSL6, -1, 85, 0, "lScroller", "hide", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens when restoring (sometimes), same as the one below
- { GID_LSL6, -1, 86, 0, "LL6Inv", "show", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens when restoring, is called with hunk segment, but hunk is not allocated at that time
- // ^^ TODO: check, if this is really a script error or an issue with our restore code
{ GID_LSL6, -1, 86, 0, "LL6Inv", "hide", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens during the game, gets called with 1 extra parameter
{ GID_SQ5, 850, 850, 0, NULL, "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // happens while playing Battle Cruiser (invalid segment) - bug #3056811
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -316,7 +311,7 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = {
const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = {
{ GID_ECOQUEST2, 100, 333, 0, "showEcorder", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // necessary workaround for our ecorder script patch, because there isn't enough space to patch the function
{ GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
- { GID_PQ3, 202, 202, 0, "MapEdit", "addPt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
+ { GID_PQ3, 202, 202, 0, "MapEdit", "addPt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -330,7 +325,7 @@ const SciWorkaroundEntry kIsObject_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kMemory_workarounds[] = {
- { GID_LAURABOW2, -1, 999, 0, "", "export 6", -1, 0, { WORKAROUND_FAKE, 0 } }, // during the intro, when exiting the train, talking to Mr. Augustini, etc. - bug #3034490
+ { GID_LAURABOW2, -1, 999, 0, "", "export 6", -1, 0, { WORKAROUND_FAKE, 0 } }, // during the intro, when exiting the train (room 160), talking to Mr. Augustini, etc. - bug #3034490
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -361,7 +356,7 @@ const SciWorkaroundEntry kSetCursor_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kSetPort_workarounds[] = {
{ GID_LSL6, 740, 740, 0, "rm740", "drawPic", -1, 0, { WORKAROUND_IGNORE, 0 } }, // ending scene, is called with additional 3 (!) parameters
- { GID_QFG3, 830, 830, 0, "portalOpens", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when the portal appears during the end, bug #3040844
+ { GID_QFG3, 830, 830, 0, "portalOpens", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when the portal appears during the end, gets called with 4 parameters (bug #3040844)
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -373,12 +368,6 @@ const SciWorkaroundEntry kStrAt_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
-const SciWorkaroundEntry kStrCat_workarounds[] = {
- { GID_LONGBOW, 210, 210, 0, "giveScroll", "changeState",0x3294, 0, { WORKAROUND_FAKE, 0 } }, // German version, when handing the scroll with the druid hand code to Marion - bug #3048054
- SCI_WORKAROUNDENTRY_TERMINATOR
-};
-
-// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kStrLen_workarounds[] = {
{ GID_QFG2, 210, 2, 0, "", "export 21", 0xdeb, 0, { WORKAROUND_FAKE, 0 } }, // When saying something incorrect at the WIT, an integer is passed instead of a reference - bug #3100292
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -386,23 +375,13 @@ const SciWorkaroundEntry kStrLen_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kUnLoad_workarounds[] = {
- { GID_CAMELOT, 921, 921, 1, "Script", "changeState", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: While showing Camelot (and other places), the reference is invalid - bug #3035000
- { GID_CAMELOT, 921, 921, 1, "Script", "init", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When being attacked by the boar (and other places), the reference is invalid - bug #3035000
- { GID_CASTLEBRAIN, 320, 377, 0, "SWord", "upDate", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after solving the cross-word-puzzle, trying to unload invalid reference
- { GID_CASTLEBRAIN, 320, 377, 0, "theWord", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // 2nd word puzzle, when exiting before solving, trying to unload invalid reference - bug #3034473
- { GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after talking to the dolphin the first time
- { GID_ECOQUEST, 380, 69, 0, "lookAtBlackBoard", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // German version, when closing the blackboard closeup in the dolphin room - bug #3098353
- { GID_LAURABOW2, 1, 1, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902
- { GID_LAURABOW2, 2, 2, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902
- { GID_LAURABOW2, 4, 4, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: inside the museum, a 3rd parameter is passed by accident - bug #3034902
- { GID_LAURABOW2, 6, 6, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: after the murder, a 3rd parameter is passed by accident - bug #3034902
- { GID_LAURABOW2, 7, 7, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: after the logo is shown, a 3rd parameter is passed by accident - bug #3034902
+ { GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // CD version: after talking to the dolphin the first time, a 3rd parameter is passed by accident
+ { GID_ECOQUEST, 380, 69, 0, "lookAtBlackBoard", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // German version, when closing the blackboard closeup in the dolphin room, a 3rd parameter is passed by accident - bug #3098353
+ { GID_LAURABOW2, -1, 1, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902
{ GID_LSL6, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident
{ GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident
{ GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident
- { GID_PQ3, 877, 998, 0, "View", "delete", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when getting run over on the freeway, the reference is invalid
{ GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error
- { GID_SQ3, 2, 998, 0, "View", "delete", -1, 0, { WORKAROUND_IGNORE, 0 } }, // clicking the mouse button during the intro, after the escape pod gets pulled into the garbage freighter, the reference is invalid - bug #3050856
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -416,14 +395,14 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
return sci3IgnoreForNow;
}
- EngineState *state = g_sci->getEngineState();
+ const EngineState *state = g_sci->getEngineState();
ExecStack *lastCall = state->xs;
- Script *local_script = state->_segMan->getScriptIfLoaded(lastCall->local_segment);
- int curScriptNr = local_script->getScriptNumber();
+ const Script *localScript = state->_segMan->getScriptIfLoaded(lastCall->local_segment);
+ int curScriptNr = localScript->getScriptNumber();
if (lastCall->debugLocalCallOffset != -1) {
// if lastcall was actually a local call search back for a real call
- Common::List<ExecStack>::iterator callIterator = state->_executionStack.end();
+ Common::List<ExecStack>::const_iterator callIterator = state->_executionStack.end();
while (callIterator != state->_executionStack.begin()) {
callIterator--;
ExecStack loopCall = *callIterator;
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index 7ab73cdff2..c7721aa787 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -95,7 +95,6 @@ extern const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[];
extern const SciWorkaroundEntry kSetCursor_workarounds[];
extern const SciWorkaroundEntry kSetPort_workarounds[];
extern const SciWorkaroundEntry kStrAt_workarounds[];
-extern const SciWorkaroundEntry kStrCat_workarounds[];
extern const SciWorkaroundEntry kStrLen_workarounds[];
extern const SciWorkaroundEntry kUnLoad_workarounds[];
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index d607a5314f..50244919c9 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -32,15 +32,10 @@
#include "sci/console.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
+#include "sci/graphics/screen.h"
namespace Sci {
-EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended), _modifierStates(0) {
-}
-
-EventManager::~EventManager() {
-}
-
struct ScancodeRow {
int offset;
const char *keys;
@@ -52,27 +47,6 @@ const ScancodeRow s_scancodeRows[] = {
{ 0x2c, "ZXCVBNM,./" }
};
-static int altify(int ch) {
- // Calculates a PC keyboard scancode from a character */
- int row;
- int c = toupper((char)ch);
-
- for (row = 0; row < ARRAYSIZE(s_scancodeRows); row++) {
- const char *keys = s_scancodeRows[row].keys;
- int offset = s_scancodeRows[row].offset;
-
- while (*keys) {
- if (*keys == c)
- return offset << 8;
-
- offset++;
- keys++;
- }
- }
-
- return ch;
-}
-
const byte codepagemap_88591toDOS[0x80] = {
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
@@ -120,147 +94,182 @@ const SciKeyConversion keyMappings[] = {
{ Common::KEYCODE_KP_DIVIDE , '/' , '/' },
};
+struct MouseEventConversion {
+ Common::EventType commonType;
+ short sciType;
+ short data;
+};
+
+const MouseEventConversion mouseEventMappings[] = {
+ { Common::EVENT_LBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 1 },
+ { Common::EVENT_RBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 2 },
+ { Common::EVENT_MBUTTONDOWN, SCI_EVENT_MOUSE_PRESS, 3 },
+ { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 1 },
+ { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 2 },
+ { Common::EVENT_LBUTTONUP, SCI_EVENT_MOUSE_RELEASE, 3 }
+};
+
+EventManager::EventManager(bool fontIsExtended) : _fontIsExtended(fontIsExtended) {
+}
+
+EventManager::~EventManager() {
+}
+
+static int altify(int ch) {
+ // Calculates a PC keyboard scancode from a character */
+ int row;
+ int c = toupper((char)ch);
+
+ for (row = 0; row < ARRAYSIZE(s_scancodeRows); row++) {
+ const char *keys = s_scancodeRows[row].keys;
+ int offset = s_scancodeRows[row].offset;
+
+ while (*keys) {
+ if (*keys == c)
+ return offset << 8;
+
+ offset++;
+ keys++;
+ }
+ }
+
+ return ch;
+}
+
SciEvent EventManager::getScummVMEvent() {
- SciEvent input = { SCI_EVENT_NONE, 0, 0, 0 };
+ SciEvent input = { SCI_EVENT_NONE, 0, 0, 0, Common::Point(0, 0) };
+ SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, 0, Common::Point(0, 0) };
Common::EventManager *em = g_system->getEventManager();
Common::Event ev;
bool found = em->pollEvent(ev);
- Common::Point p = ev.mouse;
// Don't generate events for mouse movement
- while (found && ev.type == Common::EVENT_MOUSEMOVE) {
+ while (found && ev.type == Common::EVENT_MOUSEMOVE)
found = em->pollEvent(ev);
+
+ // Save the mouse position
+ //
+ // We call getMousePos of the event manager here, since we also want to
+ // store the mouse position in case of keyboard events, which do not feature
+ // any mouse position information itself.
+ // This should be safe, since the mouse position in the event manager should
+ // only be updated when a mouse related event has been taken from the queue
+ // via pollEvent.
+ // We also adjust the position based on the scaling of the screen.
+ Common::Point mousePos = em->getMousePos();
+ g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x);
+
+ noEvent.mousePos = input.mousePos = mousePos;
+
+ if (!found || ev.type == Common::EVENT_MOUSEMOVE)
+ return noEvent;
+
+ if (ev.type == Common::EVENT_QUIT) {
+ input.type = SCI_EVENT_QUIT;
+ return input;
}
- if (found && ev.type != Common::EVENT_MOUSEMOVE) {
- int modifiers = em->getModifierState();
- bool numlockOn = (ev.kbd.flags & Common::KBD_NUM);
-
- // We add the modifier key status to buckybits
- //TODO: SCI_EVM_INSERT
-
- input.modifiers =
- ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) |
- ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) |
- ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0) |
- ((ev.kbd.flags & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) |
- ((ev.kbd.flags & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) |
- _modifierStates;
-
- switch (ev.type) {
- // Keyboard events
- case Common::EVENT_KEYDOWN:
- input.data = ev.kbd.keycode;
- input.character = ev.kbd.ascii;
-
- // Debug console
- if (ev.kbd.hasFlags(Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d) {
- // Open debug console
- Console *con = g_sci->getSciDebugger();
- con->attach();
-
- // Clear keyboard event
- input.type = SCI_EVENT_NONE;
- input.character = 0;
- input.data = 0;
- input.modifiers = 0;
-
- return input;
- }
+ // Handle mouse events
+ for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) {
+ if (mouseEventMappings[i].commonType == ev.type) {
+ input.type = mouseEventMappings[i].sciType;
+ input.data = mouseEventMappings[i].data;
+ return input;
+ }
+ }
- if (!(input.data & 0xFF00)) {
- // Directly accept most common keys without conversion
- input.type = SCI_EVENT_KEYBOARD;
- if ((input.character >= 0x80) && (input.character <= 0xFF)) {
- // If there is no extended font, we will just clear the current event
- // Sierra SCI actually accepted those characters, but didn't display them inside textedit-controls
- // because the characters were missing inside the font(s)
- // We filter them out for non-multilingual games because of that
- if (!_fontIsExtended) {
- input.type = SCI_EVENT_NONE;
- input.character = 0;
- input.data = 0;
- input.modifiers = 0;
- return input;
- }
- // We get a 8859-1 character, we need dos (cp850/437) character for multilingual sci01 games
- input.character = codepagemap_88591toDOS[input.character & 0x7f];
- }
- if (input.data == Common::KEYCODE_TAB) {
- // Tab
- input.type = SCI_EVENT_KEYBOARD;
- input.data = SCI_KEY_TAB;
- if (input.modifiers & (SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT))
- input.character = SCI_KEY_SHIFT_TAB;
- else
- input.character = SCI_KEY_TAB;
- }
- if (input.data == Common::KEYCODE_DELETE) {
- // Delete key
- input.type = SCI_EVENT_KEYBOARD;
- input.data = input.character = SCI_KEY_DELETE;
- }
- } else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) {
- // F1-F10
- input.type = SCI_EVENT_KEYBOARD;
- // SCI_K_F1 == 59 << 8
- // SCI_K_SHIFT_F1 == 84 << 8
- input.data = SCI_KEY_F1 + ((input.data - Common::KEYCODE_F1)<<8);
- if (input.modifiers & (SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT))
- input.character = input.data + 0x1900;
- else
- input.character = input.data;
- } else {
- // Special keys that need conversion
- input.type = SCI_EVENT_KEYBOARD;
- for (int i = 0; i < ARRAYSIZE(keyMappings); i++) {
- if (keyMappings[i].scummVMKey == ev.kbd.keycode) {
- input.data = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff;
- break;
- }
- }
- input.character = input.data;
- }
- break;
+ // If we reached here, make sure that it's a keydown event
+ if (ev.type != Common::EVENT_KEYDOWN)
+ return noEvent;
- // Mouse events
- case Common::EVENT_LBUTTONDOWN:
- input.type = SCI_EVENT_MOUSE_PRESS;
- input.data = 1;
- break;
- case Common::EVENT_RBUTTONDOWN:
- input.type = SCI_EVENT_MOUSE_PRESS;
- input.data = 2;
- break;
- case Common::EVENT_MBUTTONDOWN:
- input.type = SCI_EVENT_MOUSE_PRESS;
- input.data = 3;
- break;
- case Common::EVENT_LBUTTONUP:
- input.type = SCI_EVENT_MOUSE_RELEASE;
- input.data = 1;
- break;
- case Common::EVENT_RBUTTONUP:
- input.type = SCI_EVENT_MOUSE_RELEASE;
- input.data = 2;
- break;
- case Common::EVENT_MBUTTONUP:
- input.type = SCI_EVENT_MOUSE_RELEASE;
- input.data = 3;
- break;
-
- // Misc events
- case Common::EVENT_QUIT:
- input.type = SCI_EVENT_QUIT;
- break;
+ // Check for Control-D (debug console)
+ if (ev.kbd.hasFlags(Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d) {
+ // Open debug console
+ Console *con = g_sci->getSciDebugger();
+ con->attach();
+ return noEvent;
+ }
- default:
- break;
+ // Process keyboard events
+
+ int modifiers = em->getModifierState();
+ bool numlockOn = (ev.kbd.flags & Common::KBD_NUM);
+
+ input.data = ev.kbd.keycode;
+ input.character = ev.kbd.ascii;
+ input.type = SCI_EVENT_KEYBOARD;
+
+ input.modifiers =
+ ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) |
+ ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) |
+ ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0);
+
+ // Caps lock and Scroll lock have been removed, cause we already handle upper
+ // case keys ad Scroll lock doesn't seem to be used anywhere
+ //((ev.kbd.flags & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) |
+ //((ev.kbd.flags & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) |
+
+ if (!(input.data & 0xFF00)) {
+ // Directly accept most common keys without conversion
+ if ((input.character >= 0x80) && (input.character <= 0xFF)) {
+ // If there is no extended font, we will just clear the
+ // current event.
+ // Sierra SCI actually accepted those characters, but
+ // didn't display them inside text edit controls because
+ // the characters were missing inside the font(s).
+ // We filter them out for non-multilingual games because
+ // of that.
+ if (!_fontIsExtended)
+ return noEvent;
+ // Convert 8859-1 characters to DOS (cp850/437) for
+ // multilingual SCI01 games
+ input.character = codepagemap_88591toDOS[input.character & 0x7f];
+ }
+ if (input.data == Common::KEYCODE_TAB) {
+ input.character = input.data = SCI_KEY_TAB;
+ if (modifiers & Common::KBD_SHIFT)
+ input.character = SCI_KEY_SHIFT_TAB;
+ }
+ if (input.data == Common::KEYCODE_DELETE)
+ input.data = input.character = SCI_KEY_DELETE;
+ } else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) {
+ // SCI_K_F1 == 59 << 8
+ // SCI_K_SHIFT_F1 == 84 << 8
+ input.character = input.data = SCI_KEY_F1 + ((input.data - Common::KEYCODE_F1)<<8);
+ if (modifiers & Common::KBD_SHIFT)
+ input.character = input.data + 0x1900;
+ } else {
+ // Special keys that need conversion
+ for (int i = 0; i < ARRAYSIZE(keyMappings); i++) {
+ if (keyMappings[i].scummVMKey == ev.kbd.keycode) {
+ input.character = input.data = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff;
+ break;
+ }
}
}
+
+ // When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give
+ // us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway
+ // we support the other case as well
+ if ((modifiers & Common::KBD_SHIFT) && input.character > 0 && input.character < 27)
+ input.character += 96; // 0x01 -> 'a'
+
+ if (getSciVersion() <= SCI_VERSION_1_MIDDLE) {
+ // TODO: find out if altify is also not needed for sci1late+, couldnt find any game that uses those keys
+ // Scancodify if appropriate
+ if (modifiers & Common::KBD_ALT)
+ input.character = altify(input.character);
+ else if ((modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27)
+ input.character += 96; // 0x01 -> 'a'
+ }
+ // If no actual key was pressed (e.g. if only a modifier key was pressed),
+ // ignore the event
+ if (!input.character)
+ return noEvent;
+
return input;
}
@@ -282,8 +291,7 @@ void EventManager::updateScreen() {
}
SciEvent EventManager::getSciEvent(unsigned int mask) {
- //sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 };
- SciEvent event = { 0, 0, 0, 0 };
+ SciEvent event = { 0, 0, 0, 0, Common::Point(0, 0) };
EventManager::updateScreen();
@@ -304,9 +312,8 @@ SciEvent EventManager::getSciEvent(unsigned int mask) {
event = *iter;
// If not peeking at the queue, remove the event
- if (!(mask & SCI_EVENT_PEEK)) {
+ if (!(mask & SCI_EVENT_PEEK))
_events.erase(iter);
- }
} else {
// No event found: we must return a SCI_EVT_NONE event.
@@ -314,29 +321,6 @@ SciEvent EventManager::getSciEvent(unsigned int mask) {
// there is no need to change it.
}
- if (event.type == SCI_EVENT_KEYBOARD) {
- // Do we still have to translate the key?
-
- // When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give
- // us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway
- // we support the other case as well
- if (event.modifiers & SCI_KEYMOD_ALT) {
- if (event.character < 27)
- event.character += 96; // 0x01 -> 'a'
- }
-
- if (getSciVersion() <= SCI_VERSION_1_MIDDLE) {
- // TODO: find out if altify is also not needed for sci1late+, couldnt find any game that uses those keys
- // Scancodify if appropriate
- if (event.modifiers & SCI_KEYMOD_ALT) {
- event.character = altify(event.character);
- } else if (event.modifiers & SCI_KEYMOD_CTRL) {
- if (event.character < 27)
- event.character += 96; // 0x01 -> 'a'
- }
- }
- }
-
return event;
}
diff --git a/engines/sci/event.h b/engines/sci/event.h
index 7c83476294..be0322f2a4 100644
--- a/engines/sci/event.h
+++ b/engines/sci/event.h
@@ -27,6 +27,7 @@
#define SCI_EVENT_H
#include "common/list.h"
+#include "common/rect.h"
namespace Sci {
@@ -46,6 +47,13 @@ struct SciEvent {
* PC keyboard scancodes.
*/
short character;
+
+ /**
+ * The mouse position at the time the event was created.
+ *
+ * These are display coordinates!
+ */
+ Common::Point mousePos;
};
/*Values for type*/
@@ -56,11 +64,8 @@ struct SciEvent {
#define SCI_EVENT_DIRECTION (1<<6)
#define SCI_EVENT_SAID (1<<7)
/*Fake values for other events*/
-#define SCI_EVENT_ERROR (1<<10)
#define SCI_EVENT_QUIT (1<<11)
#define SCI_EVENT_PEEK (1<<15)
-/* The QUIT event may be used to signal an external 'quit' command being
-** issued to the gfx driver. */
#define SCI_EVENT_ANY 0x7fff
/* Keycodes of special keys: */
@@ -121,7 +126,6 @@ private:
SciEvent getScummVMEvent();
const bool _fontIsExtended;
- int _modifierStates;
Common::List<SciEvent> _events;
};
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 5f9c5b86d6..e02b27c788 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -352,14 +352,7 @@ void GfxAnimate::update() {
it->signal &= ~(kSignalViewUpdated | kSignalNoUpdate);
} else if (it->signal & kSignalStopUpdate) {
it->signal &= ~kSignalStopUpdate;
- if (g_sci->getGameId() == GID_HOYLE3 && g_sci->isDemo()) {
- // WORKAROUND: The demo of Hoyle 3 doesn't seem to set this
- // flag in this case. Not setting this fixes a large number
- // of incorrect animate entries being drawn on top of dialog
- // boxes (bug #3036763)
- } else {
- it->signal |= kSignalNoUpdate;
- }
+ it->signal |= kSignalNoUpdate;
}
}
@@ -371,7 +364,7 @@ void GfxAnimate::update() {
it->showBitsFlag = true;
it->signal &= ~(kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
- if ((it->signal & kSignalIgnoreActor) == 0) {
+ if (!(it->signal & kSignalIgnoreActor)) {
rect = it->celRect;
rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
@@ -563,7 +556,7 @@ void GfxAnimate::addToPicDrawCels() {
// draw corresponding cel
_paint16->drawCel(view, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
- if ((it->signal & kSignalIgnoreActor) == 0) {
+ if (!(it->signal & kSignalIgnoreActor)) {
it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1);
_paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
}
@@ -637,10 +630,10 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t
// beginUpdate()/endUpdate() were introduced SCI1.
// Calling those for SCI0 will work most of the time but breaks minor
// stuff like percentage bar of qfg1ega at the character skill screen.
- if (getSciVersion() >= SCI_VERSION_1_EGA)
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
_ports->beginUpdate(_ports->_picWind);
update();
- if (getSciVersion() >= SCI_VERSION_1_EGA)
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
_ports->endUpdate(_ports->_picWind);
}
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index b085654d02..3b95a5c955 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -26,6 +26,7 @@
#include "common/config-manager.h"
#include "common/events.h"
#include "common/macresman.h"
+#include "common/memstream.h"
#include "common/system.h"
#include "common/util.h"
#include "graphics/cursorman.h"
@@ -38,6 +39,7 @@
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/view.h"
#include "sci/graphics/cursor.h"
+#include "sci/graphics/maciconbar.h"
namespace Sci {
@@ -434,9 +436,17 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
if (_macCursorRemap.empty()) {
// QFG1/Freddy/Hoyle4 use a straight viewNum->cursor ID mapping
- // KQ6 seems to use this mapping for its cursors
- if (g_sci->getGameId() == GID_KQ6)
- viewNum = loopNum * 1000 + celNum;
+ // KQ6 uses this mapping for its cursors
+ if (g_sci->getGameId() == GID_KQ6) {
+ if (viewNum == 990) // Inventory Cursors
+ viewNum = loopNum * 16 + celNum + 2000;
+ else if (viewNum == 998) // Regular Cursors
+ viewNum = celNum + 1000;
+ else // Unknown cursor, ignored
+ return;
+ }
+ if (g_sci->hasMacIconBar())
+ g_sci->_gfxMacIconBar->setInventoryIcon(viewNum);
} else {
// If we do have the list, we'll be using a remap based on what the
// scripts have given us.
@@ -485,8 +495,8 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
cursorBitmap[i * 8 + b] = 0; // Doesn't matter, just is transparent
}
- uint16 hotspotX = READ_BE_UINT16(data);
- uint16 hotspotY = READ_BE_UINT16(data + 2);
+ uint16 hotspotY = READ_BE_UINT16(data);
+ uint16 hotspotX = READ_BE_UINT16(data + 2);
static const byte cursorPalette[] = { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff };
@@ -498,11 +508,12 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu
// Mac crsr cursor
byte *cursorBitmap, *palette;
int width, height, hotspotX, hotspotY, palSize, keycolor;
- Common::MacResManager::convertCrsrCursor(resource->data, resource->size, &cursorBitmap, &width, &height, &hotspotX, &hotspotY, &keycolor, true, &palette, &palSize);
+ Common::MemoryReadStream resStream(resource->data, resource->size);
+ Common::MacResManager::convertCrsrCursor(&resStream, &cursorBitmap, width, height, hotspotX, hotspotY, keycolor, true, &palette, palSize);
CursorMan.replaceCursor(cursorBitmap, width, height, hotspotX, hotspotY, keycolor);
CursorMan.replaceCursorPalette(palette, 0, palSize);
- free(cursorBitmap);
- free(palette);
+ delete[] cursorBitmap;
+ delete[] palette;
}
kernelShow();
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index ab4a2c9c1a..fbfd140e6b 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -337,6 +337,8 @@ static int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font) {
maxChars = curCharCount; // return count up to (but not including) breaking space
break;
}
+ if (width + font->getCharWidth(curChar) > maxWidth)
+ break;
width += font->getCharWidth(curChar);
curCharCount++;
}
@@ -592,9 +594,9 @@ void GfxFrameout::kernelFrameout() {
const char *txt = text.c_str();
// HACK. The plane sometimes doesn't contain the correct width. This
// hack breaks the dialog options when speaking with Grace, but it's
- // the best we got up to now.
- // TODO: Remove this, and figure out why the plane in question isn't
- // initialized correctly (its width is 0).
+ // the best we got up to now. This happens because of the unimplemented
+ // kTextWidth function in SCI32.
+ // TODO: Remove this once kTextWidth has been implemented.
uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10;
int16 charCount;
diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h
index f6cb214a2b..343f3c7e6e 100644
--- a/engines/sci/graphics/helpers.h
+++ b/engines/sci/graphics/helpers.h
@@ -45,6 +45,10 @@ typedef int GuiResourceId; // is a resource-number and -1 means no parameter giv
typedef int16 TextAlignment;
+#define PORTS_FIRSTWINDOWID 2
+#define PORTS_FIRSTSCRIPTWINDOWID 3
+
+
struct Port {
uint16 id;
int16 top, left;
@@ -62,6 +66,8 @@ struct Port {
fontHeight(0), fontId(0), greyedOutput(false),
penClr(0), backClr(0xFF), penMode(0), counterTillFree(0) {
}
+
+ bool isWindow() const { return id >= PORTS_FIRSTWINDOWID && id != 0xFFFF; }
};
struct Window : public Port, public Common::Serializable {
@@ -132,12 +138,14 @@ struct PalSchedule {
uint32 schedule;
};
+// Game view types, sorted by the number of colors
enum ViewType {
- kViewUnknown,
- kViewEga,
- kViewVga,
- kViewVga11,
- kViewAmiga
+ kViewUnknown, // uninitialized, or non-SCI
+ kViewEga, // EGA SCI0/SCI1 and Amiga SCI0/SCI1 ECS 16 colors
+ kViewAmiga, // Amiga SCI1 ECS 32 colors
+ kViewAmiga64, // Amiga SCI1 AGA 64 colors (i.e. Longbow)
+ kViewVga, // VGA SCI1 256 colors
+ kViewVga11 // VGA SCI1.1 and newer 256 colors
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
index f0931e0121..6cf4f269a7 100644
--- a/engines/sci/graphics/maciconbar.cpp
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -27,6 +27,7 @@
#include "sci/engine/kernel.h"
#include "sci/engine/selector.h"
#include "sci/engine/state.h"
+#include "sci/event.h"
#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/screen.h"
@@ -40,9 +41,22 @@ namespace Sci {
GfxMacIconBar::GfxMacIconBar() {
_lastX = 0;
+
+ if (g_sci->getGameId() == GID_FREDDYPHARKAS)
+ _inventoryIndex = 5;
+ else
+ _inventoryIndex = 4;
+
+ _inventoryIcon = 0;
+ _allDisabled = true;
}
GfxMacIconBar::~GfxMacIconBar() {
+ if (_inventoryIcon) {
+ _inventoryIcon->free();
+ delete _inventoryIcon;
+ }
+
for (uint32 i = 0; i < _iconBarItems.size(); i++) {
if (_iconBarItems[i].nonSelectedImage) {
_iconBarItems[i].nonSelectedImage->free();
@@ -62,7 +76,12 @@ void GfxMacIconBar::addIcon(reg_t obj) {
item.object = obj;
item.nonSelectedImage = createImage(iconIndex, false);
- item.selectedImage = createImage(iconIndex, true);
+
+ if (iconIndex != _inventoryIndex)
+ item.selectedImage = createImage(iconIndex, true);
+ else
+ item.selectedImage = 0;
+
item.enabled = true;
// Start after the main viewing window and add a two pixel buffer
@@ -82,17 +101,33 @@ void GfxMacIconBar::drawIcons() {
// Draw the icons to the bottom of the screen
for (uint32 i = 0; i < _iconBarItems.size(); i++)
- redrawIcon(i);
+ drawIcon(i, false);
}
-void GfxMacIconBar::redrawIcon(uint16 iconIndex) {
+void GfxMacIconBar::drawIcon(uint16 iconIndex, bool selected) {
if (iconIndex >= _iconBarItems.size())
return;
- if (_iconBarItems[iconIndex].enabled)
- drawEnabledImage(_iconBarItems[iconIndex].nonSelectedImage, _iconBarItems[iconIndex].rect);
- else
- drawDisabledImage(_iconBarItems[iconIndex].nonSelectedImage, _iconBarItems[iconIndex].rect);
+ Common::Rect rect = _iconBarItems[iconIndex].rect;
+
+ if (isIconEnabled(iconIndex)) {
+ if (selected)
+ drawEnabledImage(_iconBarItems[iconIndex].selectedImage, rect);
+ else
+ drawEnabledImage(_iconBarItems[iconIndex].nonSelectedImage, rect);
+ } else
+ drawDisabledImage(_iconBarItems[iconIndex].nonSelectedImage, rect);
+
+ if ((iconIndex == _inventoryIndex) && _inventoryIcon) {
+ Common::Rect invRect = Common::Rect(0, 0, _inventoryIcon->w, _inventoryIcon->h);
+ invRect.moveTo(rect.left, rect.top);
+ invRect.translate((rect.width() - invRect.width()) / 2, (rect.height() - invRect.height()) / 2);
+
+ if (isIconEnabled(iconIndex))
+ drawEnabledImage(_inventoryIcon, invRect);
+ else
+ drawDisabledImage(_inventoryIcon, invRect);
+ }
}
void GfxMacIconBar::drawEnabledImage(Graphics::Surface *surface, const Common::Rect &rect) {
@@ -128,30 +163,49 @@ void GfxMacIconBar::drawDisabledImage(Graphics::Surface *surface, const Common::
void GfxMacIconBar::drawSelectedImage(uint16 iconIndex) {
assert(iconIndex <= _iconBarItems.size());
- // TODO
+ drawEnabledImage(_iconBarItems[iconIndex].selectedImage, _iconBarItems[iconIndex].rect);
}
bool GfxMacIconBar::isIconEnabled(uint16 iconIndex) const {
if (iconIndex >= _iconBarItems.size())
return false;
- return _iconBarItems[iconIndex].enabled;
+ return !_allDisabled && _iconBarItems[iconIndex].enabled;
}
-void GfxMacIconBar::setIconEnabled(uint16 iconIndex, bool enabled) {
- if (iconIndex == 0xffff) {
- for (uint32 i = 0; i < _iconBarItems.size(); i++)
- _iconBarItems[i].enabled = enabled;
- } else if (iconIndex < _iconBarItems.size()) {
+void GfxMacIconBar::setIconEnabled(int16 iconIndex, bool enabled) {
+ if (iconIndex < 0)
+ _allDisabled = !enabled;
+ else if (iconIndex < (int)_iconBarItems.size()) {
_iconBarItems[iconIndex].enabled = enabled;
}
}
-Graphics::Surface *GfxMacIconBar::createImage(uint32 iconIndex, bool isSelected) {
- Graphics::PictDecoder pictDecoder(Graphics::PixelFormat::createFormatCLUT8());
- ResourceType type = isSelected ? kResourceTypeMacIconBarPictS : kResourceTypeMacIconBarPictN;
+void GfxMacIconBar::setInventoryIcon(int16 icon) {
+ Graphics::Surface *surface = 0;
+
+ if (icon >= 0)
+ surface = loadPict(ResourceId(kResourceTypeMacPict, icon));
+
+ if (_inventoryIcon) {
+ // Free old inventory icon if we're removing the inventory icon
+ // or setting a new one.
+ if ((icon < 0) || surface) {
+ _inventoryIcon->free();
+ delete _inventoryIcon;
+ _inventoryIcon = 0;
+ }
+ }
- Resource *res = g_sci->getResMan()->findResource(ResourceId(type, iconIndex + 1), false);
+ if (surface)
+ _inventoryIcon = surface;
+
+ drawIcon(_inventoryIndex, false);
+}
+
+Graphics::Surface *GfxMacIconBar::loadPict(ResourceId id) {
+ Graphics::PictDecoder pictDecoder(Graphics::PixelFormat::createFormatCLUT8());
+ Resource *res = g_sci->getResMan()->findResource(id, false);
if (!res || res->size == 0)
return 0;
@@ -165,6 +219,11 @@ Graphics::Surface *GfxMacIconBar::createImage(uint32 iconIndex, bool isSelected)
return surface;
}
+Graphics::Surface *GfxMacIconBar::createImage(uint32 iconIndex, bool isSelected) {
+ ResourceType type = isSelected ? kResourceTypeMacIconBarPictS : kResourceTypeMacIconBarPictN;
+ return loadPict(ResourceId(type, iconIndex + 1));
+}
+
void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) {
byte *pixels = (byte *)surf->pixels;
@@ -180,4 +239,59 @@ void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) {
}
}
+bool GfxMacIconBar::pointOnIcon(uint32 iconIndex, Common::Point point) {
+ return _iconBarItems[iconIndex].rect.contains(point);
+}
+
+reg_t GfxMacIconBar::handleEvents() {
+ // Peek event queue for a mouse button press
+ EventManager *evtMgr = g_sci->getEventManager();
+ SciEvent evt = evtMgr->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+
+ // No mouse press found
+ if (evt.type == SCI_EVENT_NONE)
+ return NULL_REG;
+
+ // If the mouse is not over the icon bar, return
+ if (evt.mousePos.y < g_sci->_gfxScreen->getHeight())
+ return NULL_REG;
+
+ // Remove event from queue
+ evtMgr->getSciEvent(SCI_EVENT_MOUSE_PRESS);
+
+ // Mouse press on the icon bar, check the icon rectangles
+ uint iconNr;
+ for (iconNr = 0; iconNr < _iconBarItems.size(); iconNr++) {
+ if (pointOnIcon(iconNr, evt.mousePos) && isIconEnabled(iconNr))
+ break;
+ }
+
+ // Mouse press not on an icon
+ if (iconNr == _iconBarItems.size())
+ return NULL_REG;
+
+ drawIcon(iconNr, true);
+ bool isSelected = true;
+
+ // Wait for mouse release
+ while (evt.type != SCI_EVENT_MOUSE_RELEASE) {
+ // Mimic behavior of SSCI when moving mouse with button held down
+ if (isSelected != pointOnIcon(iconNr, evt.mousePos)) {
+ isSelected = !isSelected;
+ drawIcon(iconNr, isSelected);
+ }
+
+ evt = evtMgr->getSciEvent(SCI_EVENT_MOUSE_RELEASE);
+ g_system->delayMillis(10);
+ }
+
+ drawIcon(iconNr, false);
+
+ // If user moved away from the icon, we do nothing
+ if (pointOnIcon(iconNr, evt.mousePos))
+ return _iconBarItems[iconNr].object;
+
+ return NULL_REG;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h
index 0db9454eb7..3ac5475147 100644
--- a/engines/sci/graphics/maciconbar.h
+++ b/engines/sci/graphics/maciconbar.h
@@ -43,10 +43,9 @@ public:
void addIcon(reg_t obj);
void drawIcons();
- void redrawIcon(uint16 index);
- void drawSelectedImage(uint16 index);
- bool isIconEnabled(uint16 index) const;
- void setIconEnabled(uint16 index, bool enabled);
+ void setIconEnabled(int16 index, bool enabled);
+ void setInventoryIcon(int16 icon);
+ reg_t handleEvents();
private:
struct IconBarItem {
@@ -59,12 +58,20 @@ private:
Common::Array<IconBarItem> _iconBarItems;
uint32 _lastX;
+ uint16 _inventoryIndex;
+ Graphics::Surface *_inventoryIcon;
+ bool _allDisabled;
+ Graphics::Surface *loadPict(ResourceId id);
Graphics::Surface *createImage(uint32 iconIndex, bool isSelected);
void remapColors(Graphics::Surface *surf, byte *palette);
+ void drawIcon(uint16 index, bool selected);
+ void drawSelectedImage(uint16 index);
+ bool isIconEnabled(uint16 index) const;
void drawEnabledImage(Graphics::Surface *surface, const Common::Rect &rect);
void drawDisabledImage(Graphics::Surface *surface, const Common::Rect &rect);
+ bool pointOnIcon(uint32 iconIndex, Common::Point point);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 3b9119c52f..50ba77e832 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -399,12 +399,10 @@ void GfxMenu::calculateMenuAndItemWidth() {
reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
int16 eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
int16 keyPress, keyModifier;
- Common::Point mousePosition;
GuiMenuItemList::iterator itemIterator = _itemList.begin();
GuiMenuItemList::iterator itemEnd = _itemList.end();
GuiMenuItemEntry *itemEntry = NULL;
bool forceClaimed = false;
- EngineState *s;
switch (eventType) {
case SCI_EVENT_KEYBOARD:
@@ -438,8 +436,6 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
break;
case SCI_EVENT_SAID:
- // HACK: should be removed as soon as said() is cleaned up
- s = g_sci->getEngineState();
while (itemIterator != itemEnd) {
itemEntry = *itemIterator;
@@ -451,7 +447,7 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
continue;
}
- if (said(s, saidSpec, 0) != SAID_NO_MATCH)
+ if (said(saidSpec, 0) != SAID_NO_MATCH)
break;
}
itemIterator++;
@@ -460,15 +456,17 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject, bool pauseSound) {
itemEntry = NULL;
break;
- case SCI_EVENT_MOUSE_PRESS:
- mousePosition = _cursor->getPosition();
+ case SCI_EVENT_MOUSE_PRESS: {
+ Common::Point mousePosition;
+ mousePosition.x = readSelectorValue(_segMan, eventObject, SELECTOR(x));
+ mousePosition.y = readSelectorValue(_segMan, eventObject, SELECTOR(y));
if (mousePosition.y < 10) {
interactiveStart(pauseSound);
itemEntry = interactiveWithMouse();
interactiveEnd(pauseSound);
forceClaimed = true;
}
- break;
+ } break;
}
if (!_menuSaveHandle.isNull()) {
@@ -718,7 +716,6 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
uint16 newItemId = _curItemId;
GuiMenuItemEntry *curItemEntry = findItem(_curMenuId, _curItemId);
GuiMenuItemEntry *newItemEntry = curItemEntry;
- Common::Point mousePosition;
// We don't 100% follow Sierra here: we select last item instead of
// selecting first item of first menu every time. Also sierra sci didn't
@@ -796,9 +793,9 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
}
break;
- case SCI_EVENT_MOUSE_PRESS:
- mousePosition = _cursor->getPosition();
- if (_cursor->getPosition().y < 10) {
+ case SCI_EVENT_MOUSE_PRESS: {
+ Common::Point mousePosition = curEvent.mousePos;
+ if (mousePosition.y < 10) {
// Somewhere on the menubar
newMenuId = mouseFindMenuSelection(mousePosition);
if (newMenuId) {
@@ -827,7 +824,8 @@ GuiMenuItemEntry *GfxMenu::interactiveWithKeyboard() {
}
newItemId = curItemEntry->id;
}
- break;
+ } break;
+
case SCI_EVENT_NONE:
g_sci->sleep(2500 / 1000);
break;
@@ -843,7 +841,6 @@ GuiMenuItemEntry *GfxMenu::interactiveWithMouse() {
SciEvent curEvent;
uint16 newMenuId = 0, newItemId = 0;
uint16 curMenuId = 0, curItemId = 0;
- Common::Point mousePosition = _cursor->getPosition();
bool firstMenuChange = true;
GuiMenuItemEntry *curItemEntry = NULL;
@@ -874,7 +871,7 @@ GuiMenuItemEntry *GfxMenu::interactiveWithMouse() {
}
// Find out where mouse is currently pointing to
- mousePosition = _cursor->getPosition();
+ Common::Point mousePosition = curEvent.mousePos;
if (mousePosition.y < 10) {
// Somewhere on the menubar
newMenuId = mouseFindMenuSelection(mousePosition);
@@ -914,6 +911,13 @@ void GfxMenu::kernelDrawStatus(const char *text, int16 colorPen, int16 colorBack
_ports->moveTo(0, 1);
_text16->DrawStatus(text);
_paint16->bitsShow(_ports->_menuBarRect);
+ // Also draw the line under the status bar. Normally, this is never drawn,
+ // but we need it to be drawn because Dr. Brain 1 Mac draws over it when
+ // it displays the icon bar. SSCI used negative rectangles to erase the
+ // area after drawing the icon bar, but this is a much cleaner way of
+ // achieving the same effect.
+ _paint16->fillRect(_ports->_menuLine, 1, 0);
+ _paint16->bitsShow(_ports->_menuLine);
_ports->setPort(oldPort);
}
diff --git a/engines/sci/graphics/paint.cpp b/engines/sci/graphics/paint.cpp
index 50b0534ba7..c347da3c0f 100644
--- a/engines/sci/graphics/paint.cpp
+++ b/engines/sci/graphics/paint.cpp
@@ -43,9 +43,6 @@ GfxPaint::~GfxPaint() {
void GfxPaint::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
}
-void GfxPaint::kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle) {
-}
-
void GfxPaint::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
}
diff --git a/engines/sci/graphics/paint.h b/engines/sci/graphics/paint.h
index 994bc4e5e9..a79e8993c2 100644
--- a/engines/sci/graphics/paint.h
+++ b/engines/sci/graphics/paint.h
@@ -36,7 +36,6 @@ public:
virtual ~GfxPaint();
virtual void kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
- virtual void kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle);
virtual void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control);
};
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index 935dd4e62e..33986f1196 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -360,7 +360,7 @@ void GfxPaint16::bitsRestore(reg_t memoryHandle) {
if (memoryPtr) {
_screen->bitsRestore(memoryPtr);
- _segMan->freeHunkEntry(memoryHandle);
+ bitsFree(memoryHandle);
}
}
}
@@ -532,20 +532,7 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
case SCI_DISPLAY_RESTOREUNDER:
bitsGetRect(argv[0], &rect);
rect.translate(-_ports->getPort()->left, -_ports->getPort()->top);
- if (g_sci->getGameId() == GID_PQ3 && g_sci->getEngineState()->currentRoomNumber() == 29) {
- // WORKAROUND: PQ3 calls this without calling the associated
- // kDisplay(SCI_DISPLAY_SAVEUNDER) call before. Theoretically,
- // this would result in no rect getting restored. However, we
- // still maintain a pointer from the previous room, resulting
- // in invalidated content being restored on screen, and causing
- // graphics glitches. Thus, we simply don't restore a rect in
- // that room. The correct fix for this would be to erase hunk
- // pointers when changing rooms, but this will suffice for now,
- // as restoring from a totally invalid pointer is very rare.
- // Fixes bug #3037945.
- } else {
- bitsRestore(argv[0]);
- }
+ bitsRestore(argv[0]);
kernelGraphRedrawBox(rect);
// finishing loop
argc = 0;
@@ -581,7 +568,10 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
// now drawing the text
_text16->Size(rect, text, -1, width);
rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop);
- if (getSciVersion() >= SCI_VERSION_1_LATE) {
+ // Note: This code has been found in SCI1 middle and newer games. It was
+ // previously only for SCI1 late and newer, but the LSL1 interpreter contains
+ // this code.
+ if (getSciVersion() >= SCI_VERSION_1_MIDDLE) {
int16 leftPos = rect.right <= _screen->getWidth() ? 0 : _screen->getWidth() - rect.right;
int16 topPos = rect.bottom <= _screen->getHeight() ? 0 : _screen->getHeight() - rect.bottom;
_ports->move(leftPos, topPos);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index aa3bf8dfb3..69a278eb8b 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -65,17 +65,6 @@ void GfxPaint32::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, b
delete picture;
}
-// This is "hacked" together, because its only used by debug command
-void GfxPaint32::kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle) {
- GfxView *view = _cache->getView(viewId);
- Common::Rect celRect(50, 50, 50, 50);
- Common::Rect translatedRect;
- celRect.bottom += view->getHeight(loopNo, celNo);
- celRect.right += view->getWidth(loopNo, celNo);
- view->draw(celRect, celRect, celRect, loopNo, celNo, 255, 0, false);
- _screen->copyRectToScreen(celRect);
-}
-
void GfxPaint32::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
_screen->drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, color, priority, control);
}
diff --git a/engines/sci/graphics/paint32.h b/engines/sci/graphics/paint32.h
index 3fa9d11d9b..e412bdf1c4 100644
--- a/engines/sci/graphics/paint32.h
+++ b/engines/sci/graphics/paint32.h
@@ -45,7 +45,6 @@ public:
void fillRect(Common::Rect rect, byte color);
void kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
- void kernelDrawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle);
void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control);
private:
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 0f95a3f2fb..5a6b1859cd 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -76,6 +76,24 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool useMergi
#ifdef ENABLE_SCI32
_clutTable = 0;
#endif
+
+ switch (_resMan->getViewType()) {
+ case kViewEga:
+ _totalScreenColors = 16;
+ break;
+ case kViewAmiga:
+ _totalScreenColors = 32;
+ break;
+ case kViewAmiga64:
+ _totalScreenColors = 64;
+ break;
+ case kViewVga:
+ case kViewVga11:
+ _totalScreenColors = 256;
+ break;
+ default:
+ error("GfxPalette: Unknown view type");
+ }
}
GfxPalette::~GfxPalette() {
@@ -97,7 +115,7 @@ bool GfxPalette::isMerging() {
void GfxPalette::setDefault() {
if (_resMan->getViewType() == kViewEga)
setEGA();
- else if (_resMan->isAmiga32color())
+ else if (_resMan->getViewType() == kViewAmiga)
setAmiga();
else
kernelSetFromResource(999, true);
@@ -418,10 +436,6 @@ void GfxPalette::getSys(Palette *pal) {
}
void GfxPalette::setOnScreen() {
- // We dont change palette at all times for amiga
- if (_resMan->isAmiga32color())
- return;
-
copySysPaletteToScreen();
}
@@ -847,19 +861,28 @@ void GfxPalette::palVaryProcess(int signal, bool setPalette) {
}
}
+static inline uint getMacColorDiff(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) {
+ // Use the difference of the top 4 bits and add together the differences
+ return ABS((r2 & 0xf0) - (r1 & 0xf0)) + ABS((g2 & 0xf0) - (g1 & 0xf0)) + ABS((b2 & 0xf0) - (b1 & 0xf0));
+}
+
byte GfxPalette::findMacIconBarColor(byte r, byte g, byte b) {
// Find the best color for use with the Mac icon bar
+ // Check white, then the palette colors, and then black
- byte found = 0xFF;
- uint diff = 0xFFFFFFFF;
+ // Try white first
+ byte found = 0xff;
+ uint diff = getMacColorDiff(r, g, b, 0xff, 0xff, 0xff);
+
+ if (diff == 0)
+ return found;
- for (uint16 i = 0; i < 256; i++) {
- // Use the difference of the top 4 bits
- int dr = (_macClut[i * 3 ] & 0xf0) - (r & 0xf0);
- int dg = (_macClut[i * 3 + 1] & 0xf0) - (g & 0xf0);
- int db = (_macClut[i * 3 + 2] & 0xf0) - (b & 0xf0);
+ // Go through the main colors of the CLUT
+ for (uint16 i = 1; i < 255; i++) {
+ if (!colorIsFromMacClut(i))
+ continue;
- uint cdiff = ABS(dr) + ABS(dg) + ABS(db);
+ uint cdiff = getMacColorDiff(r, g, b, _macClut[i * 3], _macClut[i * 3 + 1], _macClut[i * 3 + 2]);
if (cdiff == 0)
return i;
@@ -869,6 +892,10 @@ byte GfxPalette::findMacIconBarColor(byte r, byte g, byte b) {
}
}
+ // Also check black here
+ if (getMacColorDiff(r, g, b, 0, 0, 0) < diff)
+ return 0;
+
return found;
}
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 317401ac1f..d2e5151d6a 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -54,6 +54,7 @@ public:
bool merge(Palette *pFrom, bool force, bool forceRealMerge);
uint16 matchColor(byte r, byte g, byte b);
void getSys(Palette *pal);
+ uint16 getTotalColorCount() const { return _totalScreenColors; }
void setOnScreen();
void copySysPaletteToScreen();
@@ -123,6 +124,7 @@ private:
uint16 _palVaryTicks;
int _palVaryPaused;
int _palVarySignal;
+ uint16 _totalScreenColors;
void loadMacIconBarPalette();
byte *_macClut;
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 7e71c1a258..38742b2510 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -36,6 +36,8 @@
namespace Sci {
+//#define DEBUG_PICTURE_DRAW
+
GfxPicture::GfxPicture(ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxPorts *ports, GfxScreen *screen, GfxPalette *palette, GuiResourceId resourceId, bool EGAdrawingVisualize)
: _resMan(resMan), _coordAdjuster(coordAdjuster), _ports(ports), _screen(screen), _palette(palette), _resourceId(resourceId), _EGAdrawingVisualize(EGAdrawingVisualize) {
assert(resourceId != -1);
@@ -222,19 +224,20 @@ void GfxPicture::drawSci32Vga(int16 celNo, int16 drawX, int16 drawY, int16 pictu
}
#endif
+extern void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData);
+
void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 drawX, int16 drawY, int16 pictureX) {
byte *celBitmap = NULL;
byte *ptr = NULL;
byte *headerPtr = inbuffer + headerPos;
byte *rlePtr = inbuffer + rlePos;
- byte *literalPtr = inbuffer + literalPos;
int16 displaceX, displaceY;
byte priority = _addToFlag ? _priority : 0;
byte clearColor;
bool compression = true;
- byte curByte, runLength;
+ byte curByte;
int16 y, lastY, x, leftX, rightX;
- int pixelNr, pixelCount;
+ int pixelCount;
uint16 width, height;
#ifdef ENABLE_SCI32
@@ -245,12 +248,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
height = READ_LE_UINT16(headerPtr + 2);
displaceX = (signed char)headerPtr[4];
displaceY = (unsigned char)headerPtr[5];
- if (_resourceType == SCI_PICTURE_TYPE_SCI11) {
+ if (_resourceType == SCI_PICTURE_TYPE_SCI11)
// SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
clearColor = _screen->getColorWhite();
- } else {
+ else
clearColor = headerPtr[6];
- }
#ifdef ENABLE_SCI32
} else {
width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);
@@ -266,91 +268,18 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
if (displaceX || displaceY)
error("unsupported embedded cel-data in picture");
+ // We will unpack cel-data into a temporary buffer and then plot it to screen
+ // That needs to be done cause a mirrored picture may be requested
pixelCount = width * height;
celBitmap = new byte[pixelCount];
if (!celBitmap)
error("Unable to allocate temporary memory for picture drawing");
- if (compression) {
- // We will unpack cel-data into a temporary buffer and then plot it to screen
- // That needs to be done cause a mirrored picture may be requested
- memset(celBitmap, clearColor, pixelCount);
- pixelNr = 0;
- ptr = celBitmap;
- if (literalPos == 0) {
- // decompression for data that has only one stream (vecor embedded view data)
- switch (_resMan->getViewType()) {
- case kViewEga:
- while (pixelNr < pixelCount) {
- curByte = *rlePtr++;
- runLength = curByte >> 4;
- memset(ptr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr));
- pixelNr += runLength;
- }
- break;
- case kViewVga:
- case kViewVga11:
- while (pixelNr < pixelCount) {
- curByte = *rlePtr++;
- runLength = curByte & 0x3F;
- switch (curByte & 0xC0) {
- case 0: // copy bytes as-is
- while (runLength-- && pixelNr < pixelCount)
- ptr[pixelNr++] = *rlePtr++;
- break;
- case 0x80: // fill with color
- memset(ptr + pixelNr, *rlePtr++, MIN<uint16>(runLength, pixelCount - pixelNr));
- pixelNr += runLength;
- break;
- case 0xC0: // fill with transparent
- pixelNr += runLength;
- break;
- }
- }
- break;
- case kViewAmiga:
- while (pixelNr < pixelCount) {
- curByte = *rlePtr++;
- if (curByte & 0x07) { // fill with color
- runLength = curByte & 0x07;
- curByte = curByte >> 3;
- while (runLength-- && pixelNr < pixelCount) {
- ptr[pixelNr++] = curByte;
- }
- } else { // fill with transparent
- runLength = curByte >> 3;
- pixelNr += runLength;
- }
- }
- break;
-
- default:
- error("Unsupported picture viewtype");
- }
- } else {
- // decompression for data that has two separate streams (probably SCI 1.1 picture)
- while (pixelNr < pixelCount) {
- curByte = *rlePtr++;
- runLength = curByte & 0x3F;
- switch (curByte & 0xC0) {
- case 0: // copy bytes as-is
- while (runLength-- && pixelNr < pixelCount)
- ptr[pixelNr++] = *literalPtr++;
- break;
- case 0x80: // fill with color
- memset(ptr + pixelNr, *literalPtr++, MIN<uint16>(runLength, pixelCount - pixelNr));
- pixelNr += runLength;
- break;
- case 0xC0: // fill with transparent
- pixelNr += runLength;
- break;
- }
- }
- }
- } else {
+ if (compression)
+ unpackCelData(inbuffer, celBitmap, clearColor, pixelCount, rlePos, literalPos, _resMan->getViewType(), width, false);
+ else
// No compression (some SCI32 pictures)
memcpy(celBitmap, rlePtr, pixelCount);
- }
Common::Rect displayArea = _coordAdjuster->pictureGetDisplayArea();
@@ -443,6 +372,7 @@ enum {
PIC_OP_OPX = 0xfe,
PIC_OP_TERMINATE = 0xff
};
+
#define PIC_OP_FIRST PIC_OP_SET_COLOR
enum {
@@ -465,6 +395,47 @@ enum {
PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4
};
+#ifdef DEBUG_PICTURE_DRAW
+const char *picOpcodeNames[] = {
+ "Set color",
+ "Disable visual",
+ "Set priority",
+ "Disable priority",
+ "Short patterns",
+ "Medium lines",
+ "Long lines",
+ "Short lines",
+ "Fill",
+ "Set pattern",
+ "Absolute pattern",
+ "Set control",
+ "Disable control",
+ "Medium patterns",
+ "Extended opcode",
+ "Terminate"
+};
+
+const char *picExOpcodeNamesEGA[] = {
+ "Set palette entries",
+ "Set palette",
+ "Mono0",
+ "Mono1",
+ "Mono2",
+ "Mono3",
+ "Mono4",
+ "Embedded view",
+ "Set priority table"
+};
+
+const char *picExOpcodeNamesVGA[] = {
+ "Set palette entries",
+ "Embedded view",
+ "Set palette",
+ "Set priority table (eqdist)",
+ "Set priority table (explicit)"
+};
+#endif
+
#define PIC_EGAPALETTE_COUNT 4
#define PIC_EGAPALETTE_SIZE 40
#define PIC_EGAPALETTE_TOTALSIZE PIC_EGAPALETTE_COUNT*PIC_EGAPALETTE_SIZE
@@ -543,7 +514,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
// Drawing
while (curPos < dataSize) {
- //warning("%X at %d", data[curPos], curPos);
+#ifdef DEBUG_PICTURE_DRAW
+ debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos);
+#endif
switch (pic_op = data[curPos++]) {
case PIC_OP_SET_COLOR:
pic_color = data[curPos++];
@@ -681,6 +654,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
case PIC_OP_OPX: // Extended functions
if (isEGA) {
+#ifdef DEBUG_PICTURE_DRAW
+ debug("* Picture ex op: %X (%s) at %d", data[curPos], picExOpcodeNamesEGA[data[curPos]], curPos);
+#endif
switch (pic_op = data[curPos++]) {
case PIC_OPX_EGA_SET_PALETTE_ENTRIES:
while (vectorIsNonOpcode(data[curPos])) {
@@ -726,6 +702,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
error("Unsupported sci1 extended pic-operation %X", pic_op);
}
} else {
+#ifdef DEBUG_PICTURE_DRAW
+ debug("* Picture ex op: %X (%s) at %d", data[curPos], picExOpcodeNamesVGA[data[curPos]], curPos);
+#endif
switch (pic_op = data[curPos++]) {
case PIC_OPX_VGA_SET_PALETTE_ENTRIES:
while (vectorIsNonOpcode(data[curPos])) {
@@ -733,7 +712,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OPX_VGA_SET_PALETTE:
- if (_resMan->isAmiga32color()) {
+ if (_resMan->getViewType() == kViewAmiga || _resMan->getViewType() == kViewAmiga64) {
if ((data[curPos] == 0x00) && (data[curPos + 1] == 0x01) && ((data[curPos + 32] & 0xF0) != 0xF0)) {
// Left-Over VGA palette, we simply ignore it
curPos += 256 + 4 + 1024;
@@ -780,7 +759,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
case GID_SQ3:
switch (_resourceId) {
case 154: // SQ3: intro, ship gets sucked in
- _screen->ditherForceMemorial(0xD0);
+ _screen->ditherForceDitheredColor(0xD0);
break;
default:
break;
@@ -866,6 +845,8 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
byte matchedMask, matchMask;
int16 w, e, a_set, b_set;
+ bool isEGA = (_resMan->getViewType() == kViewEga);
+
p.x = x + curPort->left;
p.y = y + curPort->top;
stack.push(p);
@@ -874,6 +855,18 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
byte searchPriority = _screen->getPriority(p.x, p.y);
byte searchControl = _screen->getControl(p.x, p.y);
+ if (isEGA) {
+ // In EGA games a pixel in the framebuffer is only 4 bits. We store
+ // a full byte per pixel to allow undithering, but when comparing
+ // pixels for flood-fill purposes, we should only compare the
+ // visible color of a pixel.
+
+ if ((x ^ y) & 1)
+ searchColor = (searchColor ^ (searchColor >> 4)) & 0x0F;
+ else
+ searchColor = searchColor & 0x0F;
+ }
+
// This logic was taken directly from sierra sci, floodfill will get aborted on various occations
if (screenMask & GFX_SCREEN_MASK_VISUAL) {
if ((color == _screen->getColorWhite()) || (searchColor != _screen->getColorWhite()))
@@ -913,20 +906,20 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
int b = curPort->rect.bottom + curPort->top - 1;
while (stack.size()) {
p = stack.pop();
- if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl)) == 0) // already filled
+ if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)) == 0) // already filled
continue;
_screen->putPixel(p.x, p.y, screenMask, color, priority, control);
w = p.x;
e = p.x;
// moving west and east pointers as long as there is a matching color to fill
- while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl)))
+ while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
_screen->putPixel(--w, p.y, screenMask, color, priority, control);
- while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl)))
+ while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)))
_screen->putPixel(++e, p.y, screenMask, color, priority, control);
// checking lines above and below for possible flood targets
a_set = b_set = 0;
while (w <= e) {
- if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl))) { // one line above
+ if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line above
if (a_set == 0) {
p1.x = w;
p1.y = p.y - 1;
@@ -936,7 +929,7 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by
} else
a_set = 0;
- if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl))) { // one line below
+ if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line below
if (b_set == 0) {
p1.x = w;
p1.y = p.y + 1;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 57c76126c0..9ac8d103fc 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -246,8 +246,10 @@ void GfxPorts::beginUpdate(Window *wnd) {
PortList::iterator it = _windowList.reverse_begin();
const PortList::iterator end = Common::find(_windowList.begin(), _windowList.end(), wnd);
while (it != end) {
- // FIXME: We also store Port objects in the window list.
- // We should add a check that we really only pass windows here...
+ // We also store Port objects in the window list, but they
+ // shouldn't be encountered during this iteration.
+ assert((*it)->isWindow());
+
updateWindow((Window *)*it);
--it;
}
@@ -263,11 +265,16 @@ void GfxPorts::endUpdate(Window *wnd) {
assert(it != end);
while (++it != end) {
- // FIXME: We also store Port objects in the window list.
- // We should add a check that we really only pass windows here...
+ // We also store Port objects in the window list, but they
+ // shouldn't be encountered during this iteration.
+ assert((*it)->isWindow());
+
updateWindow((Window *)*it);
}
+ if (getSciVersion() < SCI_VERSION_1_EGA_ONLY)
+ g_sci->_gfxPaint16->kernelGraphRedrawBox(_curPort->rect);
+
setPort(oldPort);
}
@@ -300,7 +307,14 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
}
_windowsById[id] = pwnd;
- if (style & SCI_WINDOWMGR_STYLE_TOPMOST)
+
+ // KQ1sci, KQ4, iceman, QfG2 always add windows to the back of the list.
+ // KQ5CD checks style.
+ // Hoyle3-demo also always adds to the back (#3036763).
+ bool forceToBack = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ||
+ (g_sci->getGameId() == GID_HOYLE3 && g_sci->isDemo());
+
+ if (!forceToBack && (style & SCI_WINDOWMGR_STYLE_TOPMOST))
_windowList.push_front(pwnd);
else
_windowList.push_back(pwnd);
@@ -311,7 +325,7 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
// bit of the left dimension in their interpreter. It seems Sierra did it
// for EGA byte alignment (EGA uses 1 byte for 2 pixels) and left it in
// their interpreter even in the newer VGA games.
- r.left = r.left & 0x7FFE;
+ r.left = r.left & 0xFFFE;
if (r.width() > _screen->getWidth()) {
// We get invalid dimensions at least at the end of sq3 (script bug!).
@@ -347,25 +361,50 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
}
pwnd->dims = r;
- const Common::Rect *wmprect = &_wmgrPort->rect;
+
+ // Clip window, if needed
+ Common::Rect wmprect = _wmgrPort->rect;
+ // Handle a special case for Dr. Brain 1 Mac. When hovering the mouse cursor
+ // over the status line on top, the game scripts try to draw the game's icon
+ // bar above the current port, by specifying a negative window top, so that
+ // the end result will be drawn 10 pixels above the current port. This is a
+ // hack by Sierra, and is only limited to user style windows. Normally, we
+ // should not clip, same as what Sierra does. However, this will result in
+ // having invalid rectangles with negative coordinates. For this reason, we
+ // adjust the containing rectangle instead.
+ if (pwnd->dims.top < 0 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
+ (style & SCI_WINDOWMGR_STYLE_USER) && _wmgrPort->top + pwnd->dims.top >= 0) {
+ // Offset the final rect top by the requested pixels
+ wmprect.top += pwnd->dims.top;
+ }
+
int16 oldtop = pwnd->dims.top;
int16 oldleft = pwnd->dims.left;
- if (wmprect->top > pwnd->dims.top)
- pwnd->dims.moveTo(pwnd->dims.left, wmprect->top);
- if (wmprect->bottom < pwnd->dims.bottom)
- pwnd->dims.moveTo(pwnd->dims.left, wmprect->bottom - pwnd->dims.bottom + pwnd->dims.top);
+ if (wmprect.top > pwnd->dims.top)
+ pwnd->dims.moveTo(pwnd->dims.left, wmprect.top);
+
+ if (wmprect.bottom < pwnd->dims.bottom)
+ pwnd->dims.moveTo(pwnd->dims.left, wmprect.bottom - pwnd->dims.bottom + pwnd->dims.top);
- if (wmprect->right < pwnd->dims.right)
- pwnd->dims.moveTo(wmprect->right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top);
+ if (wmprect.right < pwnd->dims.right)
+ pwnd->dims.moveTo(wmprect.right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top);
- if (wmprect->left > pwnd->dims.left)
- pwnd->dims.moveTo(wmprect->left, pwnd->dims.top);
+ if (wmprect.left > pwnd->dims.left)
+ pwnd->dims.moveTo(wmprect.left, pwnd->dims.top);
pwnd->rect.moveTo(pwnd->rect.left + pwnd->dims.left - oldleft, pwnd->rect.top + pwnd->dims.top - oldtop);
+
if (restoreRect == 0)
pwnd->restoreRect = pwnd->dims;
+ if (pwnd->restoreRect.top < 0 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
+ (style & SCI_WINDOWMGR_STYLE_USER) && _wmgrPort->top + pwnd->restoreRect.top >= 0) {
+ // Special case for Dr. Brain 1 Mac (check above), applied to the
+ // restore rectangle.
+ pwnd->restoreRect.moveTo(pwnd->restoreRect.left, wmprect.top);
+ }
+
if (draw)
drawWindow(pwnd);
setPort((Port *)pwnd);
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index 21c6d31ebd..9faee2be8d 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -37,9 +37,6 @@ class GfxPaint16;
class GfxScreen;
class GfxText16;
-#define PORTS_FIRSTWINDOWID 2
-#define PORTS_FIRSTSCRIPTWINDOWID 3
-
// window styles
enum {
SCI_WINDOWMGR_STYLE_TRANSPARENT = (1 << 0),
@@ -49,6 +46,9 @@ enum {
SCI_WINDOWMGR_STYLE_USER = (1 << 7)
};
+typedef Common::List<Port *> PortList;
+typedef Common::Array<Port *> PortArray;
+
/**
* Ports class, includes all port managment for SCI0->SCI1.1 games. Ports are some sort of windows in SCI
* this class also handles adjusting coordinates to a specific port
@@ -115,8 +115,12 @@ public:
virtual void saveLoadWithSerializer(Common::Serializer &ser);
+ /** The list of open 'windows' (and ports), in visual order. */
+ PortList _windowList;
+
private:
- typedef Common::List<Port *> PortList;
+ /** The list of all open 'windows' (and ports), ordered by their id. */
+ PortArray _windowsById;
SegManager *_segMan;
GfxPaint16 *_paint16;
@@ -130,12 +134,6 @@ private:
// counts windows that got disposed but are not freed yet
uint16 _freeCounter;
- /** The list of open 'windows' (and ports), in visual order. */
- PortList _windowList;
-
- /** The list of all open 'windows' (and ports), ordered by their id. */
- Common::Array<Port *> _windowsById;
-
Common::Rect _bounds;
// Priority Bands related variables
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index b019853a2b..89463badd0 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -113,7 +113,7 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
_unditherState = true;
_fontIsUpscaled = false;
- if (_resMan->isVGA() || (_resMan->isAmiga32color())) {
+ if (_resMan->getViewType() != kViewEga) {
// It is not 100% accurate to set white to be 255 for Amiga 32-color
// games. But 255 is defined as white in our SCI at all times, so it
// doesn't matter.
@@ -353,12 +353,30 @@ byte GfxScreen::getControl(int x, int y) {
return _controlScreen[y * _width + x];
}
-byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con) {
+byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) {
int offset = y * _width + x;
byte match = 0;
- if ((screenMask & GFX_SCREEN_MASK_VISUAL) && *(_visualScreen + offset) == t_color)
- match |= GFX_SCREEN_MASK_VISUAL;
+ // FIXME:
+ if (screenMask & GFX_SCREEN_MASK_VISUAL) {
+ if (!isEGA) {
+ if (*(_visualScreen + offset) == t_color)
+ match |= GFX_SCREEN_MASK_VISUAL;
+ } else {
+ // In EGA games a pixel in the framebuffer is only 4 bits. We store
+ // a full byte per pixel to allow undithering, but when comparing
+ // pixels for flood-fill purposes, we should only compare the
+ // visible color of a pixel.
+
+ byte c = *(_visualScreen + offset);
+ if ((x ^ y) & 1)
+ c = (c ^ (c >> 4)) & 0x0F;
+ else
+ c = c & 0x0F;
+ if (c == t_color)
+ match |= GFX_SCREEN_MASK_VISUAL;
+ }
+ }
if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == t_pri)
match |= GFX_SCREEN_MASK_PRIORITY;
if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == t_con)
@@ -565,7 +583,7 @@ void GfxScreen::dither(bool addToFlag) {
}
} else {
if (!addToFlag)
- memset(&_unditherMemorial, 0, sizeof(_unditherMemorial));
+ memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors));
// Do dithering on visual screen and put decoded but undithered byte onto display-screen
for (y = 0; y < _height; y++) {
for (x = 0; x < _width; x++) {
@@ -573,7 +591,7 @@ void GfxScreen::dither(bool addToFlag) {
if (color & 0xF0) {
color ^= color << 4;
// remember dither combination for cel-undithering
- _unditherMemorial[color]++;
+ _ditheredPicColors[color]++;
// if decoded color wants do dither with black on left side, we turn it around
// otherwise the normal ega color would get used for display
if (color & 0xF0) {
@@ -600,18 +618,17 @@ void GfxScreen::dither(bool addToFlag) {
}
}
-// Force a color combination into memorial
-void GfxScreen::ditherForceMemorial(byte color) {
- _unditherMemorial[color] = 256;
+void GfxScreen::ditherForceDitheredColor(byte color) {
+ _ditheredPicColors[color] = 256;
}
void GfxScreen::debugUnditherSetState(bool flag) {
_unditherState = flag;
}
-int16 *GfxScreen::unditherGetMemorial() {
+int16 *GfxScreen::unditherGetDitheredBgColors() {
if (_unditherState)
- return (int16 *)&_unditherMemorial;
+ return (int16 *)&_ditheredPicColors;
else
return NULL;
}
@@ -725,6 +742,7 @@ uint16 GfxScreen::getLowResScreenHeight() {
case GID_FREDDYPHARKAS:
case GID_KQ5:
case GID_KQ6:
+ case GID_SQ1:
return 190;
default:
break;
diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h
index fc1f38ed41..0bb15eddf3 100644
--- a/engines/sci/graphics/screen.h
+++ b/engines/sci/graphics/screen.h
@@ -51,7 +51,7 @@ enum GfxScreenMasks {
};
enum {
- SCI_SCREEN_UNDITHERMEMORIAL_SIZE = 256
+ DITHERED_BG_COLORS_SIZE = 256
};
/**
@@ -99,7 +99,7 @@ public:
byte getVisual(int x, int y);
byte getPriority(int x, int y);
byte getControl(int x, int y);
- byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con);
+ byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con, bool isEGA);
int bitsGetDataSize(Common::Rect rect, byte mask);
void bitsSave(Common::Rect rect, byte mask, byte *memoryPtr);
@@ -112,9 +112,11 @@ public:
void adjustBackUpscaledCoordinates(int16 &y, int16 &x);
void dither(bool addToFlag);
- void ditherForceMemorial(byte color);
+
+ // Force a color combination as a dithered color
+ void ditherForceDitheredColor(byte color);
void debugUnditherSetState(bool flag);
- int16 *unditherGetMemorial();
+ int16 *unditherGetDitheredBgColors();
void debugShowMap(int mapNo);
@@ -146,7 +148,7 @@ private:
void setVerticalShakePos(uint16 shakePos);
bool _unditherState;
- int16 _unditherMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE];
+ int16 _ditheredPicColors[DITHERED_BG_COLORS_SIZE];
// These screens have the real resolution of the game engine (320x200 for
// SCI0/SCI1/SCI11 games, 640x480 for SCI2 games). SCI0 games will be
diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp
index 21605ccb8e..6269a58492 100644
--- a/engines/sci/graphics/text16.cpp
+++ b/engines/sci/graphics/text16.cpp
@@ -204,19 +204,24 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF
maxChars = curCharCount; // return count up to (but not including) breaking space
break;
}
+ // Sometimes this can go off the screen, like for example bug #3040161.
+ // However, we only perform this for non-Japanese games, as these require
+ // special handling, done after this loop.
+ if (width + _font->getCharWidth(curChar) > maxWidth && g_sci->getLanguage() != Common::JA_JPN)
+ break;
width += _font->getCharWidth(curChar);
curCharCount++;
}
+
+ // Text without spaces, probably Kanji/Japanese
if (maxChars == 0) {
- // Text w/o space, supposingly kanji
maxChars = curCharCount;
uint16 nextChar;
// We remove the last char only, if maxWidth was actually equal width
// before adding the last char. Otherwise we won't get the same cutting
- // as in sierra pc98 sci. Note: changing the while() instead will NOT
- // WORK. it would break all sorts of regular sci games.
+ // as in sierra pc98 sci.
if (maxWidth == (width - _font->getCharWidth(curChar))) {
maxChars--;
if (curChar > 0xFF)
diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp
index e025a2f9ab..fac9a97efe 100644
--- a/engines/sci/graphics/transitions.cpp
+++ b/engines/sci/graphics/transitions.cpp
@@ -39,8 +39,8 @@ namespace Sci {
//#define DISABLE_TRANSITIONS // uncomment to disable room transitions (for development only! helps in testing games quickly)
-GfxTransitions::GfxTransitions(GfxScreen *screen, GfxPalette *palette, bool isVGA)
- : _screen(screen), _palette(palette), _isVGA(isVGA) {
+GfxTransitions::GfxTransitions(GfxScreen *screen, GfxPalette *palette)
+ : _screen(screen), _palette(palette) {
init();
}
@@ -124,6 +124,7 @@ void GfxTransitions::setup(int16 number, bool blackoutFlag) {
_number = SCI_TRANSITIONS_NONE;
#endif
_blackoutFlag = blackoutFlag;
+ debugC(kDebugLevelGraphics, "Transition %d, blackout %d", number, blackoutFlag);
}
}
@@ -271,7 +272,7 @@ void GfxTransitions::doTransition(int16 number, bool blackoutFlag) {
}
void GfxTransitions::setNewPalette(bool blackoutFlag) {
- if (!blackoutFlag && _isVGA)
+ if (!blackoutFlag)
_palette->setOnScreen();
}
diff --git a/engines/sci/graphics/transitions.h b/engines/sci/graphics/transitions.h
index 674b7a8173..a8f0ca6f07 100644
--- a/engines/sci/graphics/transitions.h
+++ b/engines/sci/graphics/transitions.h
@@ -65,7 +65,7 @@ class Screen;
*/
class GfxTransitions {
public:
- GfxTransitions(GfxScreen *screen, GfxPalette *palette, bool isVGA);
+ GfxTransitions(GfxScreen *screen, GfxPalette *palette);
~GfxTransitions();
void setup(int16 number, bool blackoutFlag);
@@ -97,7 +97,6 @@ private:
GfxScreen *_screen;
GfxPalette *_palette;
- bool _isVGA;
const GfxTransitionTranslateEntry *_translationTable;
int16 _number;
bool _blackoutFlag;
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 3c1f417740..b5ab6182ad 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -104,9 +104,10 @@ void GfxView::initData(GuiResourceId resourceId) {
}
switch (curViewType) {
- case kViewEga: // View-format SCI0 (and Amiga 16 colors)
+ case kViewEga: // SCI0 (and Amiga 16 colors)
isEGA = true;
- case kViewAmiga: // View-format Amiga (32 colors)
+ case kViewAmiga: // Amiga ECS (32 colors)
+ case kViewAmiga64: // Amiga AGA (64 colors)
case kViewVga: // View-format SCI1
// LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD...
@@ -132,7 +133,7 @@ void GfxView::initData(GuiResourceId resourceId) {
// SCI1 VGA conversion games (which will get detected as SCI1EARLY/MIDDLE/LATE) have some views
// with broken mapping tables. I guess those games won't use the mapping, so I rather disable it
// for them
- if (getSciVersion() == SCI_VERSION_1_EGA) {
+ if (getSciVersion() == SCI_VERSION_1_EGA_ONLY) {
_EGAmapping = &_resourceData[palOffset];
for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) {
if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE) != 0)
@@ -370,22 +371,157 @@ void GfxView::getCelScaledRect(int16 loopNo, int16 celNo, int16 x, int16 y, int1
outRect.top = outRect.bottom - scaledHeight;
}
+void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCount, int rlePos, int literalPos, ViewType viewType, uint16 width, bool isMacSci11ViewData) {
+ byte *outPtr = celBitmap;
+ byte curByte, runLength;
+ byte *rlePtr = inBuffer + rlePos;
+ // The existence of a literal position pointer signifies data with two
+ // separate streams, most likely a SCI1.1 view
+ byte *literalPtr = inBuffer + literalPos;
+ int pixelNr = 0;
+
+ memset(celBitmap, clearColor, pixelCount);
+
+ // View unpacking:
+ //
+ // EGA:
+ // Each byte is like XXXXYYYY (XXXX: 0 - 15, YYYY: 0 - 15)
+ // Set the next XXXX pixels to YYYY
+ //
+ // Amiga:
+ // Each byte is like XXXXXYYY (XXXXX: 0 - 31, YYY: 0 - 7)
+ // - Case A: YYY != 0
+ // Set the next YYY pixels to XXXXX
+ // - Case B: YYY == 0
+ // Skip the next XXXXX pixels (i.e. transparency)
+ //
+ // Amiga 64:
+ // Each byte is like XXYYYYYY (XX: 0 - 3, YYYYYY: 0 - 63)
+ // - Case A: XX != 0
+ // Set the next XX pixels to YYYYYY
+ // - Case B: XX == 0
+ // Skip the next YYYYYY pixels (i.e. transparency)
+ //
+ // VGA:
+ // Each byte is like XXYYYYYY (YYYYY: 0 - 63)
+ // - Case A: XX == 00 (binary)
+ // Copy next YYYYYY bytes as-is
+ // - Case B: XX == 01 (binary)
+ // Same as above, copy YYYYYY + 64 bytes as-is
+ // - Case C: XX == 10 (binary)
+ // Set the next YYYYY pixels to the next byte value
+ // - Case D: XX == 11 (binary)
+ // Skip the next YYYYY pixels (i.e. transparency)
+
+ if (literalPos && isMacSci11ViewData) {
+ // KQ6/Freddy Pharkas use byte lengths, all others use uint16
+ // The SCI devs must have realized that a max of 255 pixels wide
+ // was not very good for 320 or 640 width games.
+ bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS);
+
+ // compression for SCI1.1+ Mac
+ while (pixelNr < pixelCount) {
+ uint32 pixelLine = pixelNr;
+
+ if (hasByteLengths) {
+ pixelNr += *rlePtr++;
+ runLength = *rlePtr++;
+ } else {
+ pixelNr += READ_BE_UINT16(rlePtr);
+ runLength = READ_BE_UINT16(rlePtr + 2);
+ rlePtr += 4;
+ }
+
+ while (runLength-- && pixelNr < pixelCount)
+ outPtr[pixelNr++] = *literalPtr++;
+
+ pixelNr = pixelLine + width;
+ }
+ return;
+ }
+
+ switch (viewType) {
+ case kViewEga:
+ while (pixelNr < pixelCount) {
+ curByte = *rlePtr++;
+ runLength = curByte >> 4;
+ memset(outPtr + pixelNr, curByte & 0x0F, MIN<uint16>(runLength, pixelCount - pixelNr));
+ pixelNr += runLength;
+ }
+ break;
+ case kViewAmiga:
+ while (pixelNr < pixelCount) {
+ curByte = *rlePtr++;
+ if (curByte & 0x07) { // fill with color
+ runLength = curByte & 0x07;
+ curByte = curByte >> 3;
+ memset(outPtr + pixelNr, curByte, MIN<uint16>(runLength, pixelCount - pixelNr));
+ } else { // skip the next pixels (transparency)
+ runLength = curByte >> 3;
+ }
+ pixelNr += runLength;
+ }
+ break;
+ case kViewAmiga64:
+ while (pixelNr < pixelCount) {
+ curByte = *rlePtr++;
+ if (curByte & 0xC0) { // fill with color
+ runLength = curByte >> 6;
+ memset(outPtr + pixelNr, curByte & 0x3F, MIN<uint16>(runLength, pixelCount - pixelNr));
+ } else { // skip the next pixels (transparency)
+ runLength = curByte & 0x3F;
+ }
+ pixelNr += runLength;
+ }
+ break;
+ case kViewVga:
+ case kViewVga11:
+ // If we have no RLE data, the image is just uncompressed
+ if (rlePos == 0) {
+ memcpy(outPtr, literalPtr, pixelCount);
+ break;
+ }
+
+ while (pixelNr < pixelCount) {
+ curByte = *rlePtr++;
+ runLength = curByte & 0x3F;
+
+ switch (curByte & 0xC0) {
+ case 0x40: // copy bytes as is (In copy case, runLength can go up to 127 i.e. pixel & 0x40). Fixes bug #3135872.
+ runLength += 64;
+ case 0x00: // copy bytes as-is
+ if (!literalPos) {
+ memcpy(outPtr + pixelNr, rlePtr, MIN<uint16>(runLength, pixelCount - pixelNr));
+ rlePtr += runLength;
+ } else {
+ memcpy(outPtr + pixelNr, literalPtr, MIN<uint16>(runLength, pixelCount - pixelNr));
+ literalPtr += runLength;
+ }
+ break;
+ case 0x80: // fill with color
+ if (!literalPos)
+ memset(outPtr + pixelNr, *rlePtr++, MIN<uint16>(runLength, pixelCount - pixelNr));
+ else
+ memset(outPtr + pixelNr, *literalPtr++, MIN<uint16>(runLength, pixelCount - pixelNr));
+ break;
+ case 0xC0: // skip the next pixels (transparency)
+ break;
+ }
+
+ pixelNr += runLength;
+ }
+ break;
+ default:
+ error("Unsupported picture viewtype");
+ }
+}
+
void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount) {
const CelInfo *celInfo = getCelInfo(loopNo, celNo);
- byte *rlePtr;
- byte *literalPtr;
- uint32 pixelNo = 0, runLength;
- byte pixel;
if (celInfo->offsetEGA) {
// decompression for EGA views
- literalPtr = _resourceData + _loop[loopNo].cel[celNo].offsetEGA;
- while (pixelNo < pixelCount) {
- pixel = *literalPtr++;
- runLength = pixel >> 4;
- memset(outPtr + pixelNo, pixel & 0x0F, MIN<uint32>(runLength, pixelCount - pixelNo));
- pixelNo += runLength;
- }
+ unpackCelData(_resourceData, outPtr, 0, pixelCount, celInfo->offsetEGA, 0, _resMan->getViewType(), celInfo->width, false);
} else {
// We fill the buffer with transparent pixels, so that we can later skip
// over pixels to automatically have them transparent
@@ -408,100 +544,8 @@ void GfxView::unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCou
clearColor = 0;
}
- memset(outPtr, clearColor, pixelCount);
-
- rlePtr = _resourceData + celInfo->offsetRLE;
- if (!celInfo->offsetLiteral) { // no additional literal data
- if (_resMan->isAmiga32color()) {
- // decompression for amiga views
- while (pixelNo < pixelCount) {
- pixel = *rlePtr++;
- if (pixel & 0x07) { // fill with color
- runLength = pixel & 0x07;
- pixel = pixel >> 3;
- while (runLength-- && pixelNo < pixelCount) {
- outPtr[pixelNo++] = pixel;
- }
- } else { // fill with transparent
- runLength = pixel >> 3;
- pixelNo += runLength;
- }
- }
- } else {
- // decompression for data that has just one combined stream
- while (pixelNo < pixelCount) {
- pixel = *rlePtr++;
- runLength = pixel & 0x3F;
- switch (pixel & 0xC0) {
- case 0x40: // copy bytes as is (In copy case, runLength can go upto 127 i.e. pixel & 0x40)
- runLength += 64;
- case 0x00: // copy bytes as-is
- while (runLength-- && pixelNo < pixelCount)
- outPtr[pixelNo++] = *rlePtr++;
- break;
- case 0x80: // fill with color
- memset(outPtr + pixelNo, *rlePtr++, MIN<uint32>(runLength, pixelCount - pixelNo));
- pixelNo += runLength;
- break;
- case 0xC0: // fill with transparent
- pixelNo += runLength;
- break;
- }
- }
- }
- } else {
- literalPtr = _resourceData + celInfo->offsetLiteral;
- if (celInfo->offsetRLE) {
- if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1) {
- // KQ6/Freddy Pharkas use byte lengths, all others use uint16
- // The SCI devs must have realized that a max of 255 pixels wide
- // was not very good for 320 or 640 width games.
- bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS);
-
- // compression for SCI1.1+ Mac
- while (pixelNo < pixelCount) {
- uint32 pixelLine = pixelNo;
-
- if (hasByteLengths) {
- pixelNo += *rlePtr++;
- runLength = *rlePtr++;
- } else {
- pixelNo += READ_BE_UINT16(rlePtr);
- runLength = READ_BE_UINT16(rlePtr + 2);
- rlePtr += 4;
- }
-
- while (runLength-- && pixelNo < pixelCount)
- outPtr[pixelNo++] = *literalPtr++;
-
- pixelNo = pixelLine + celInfo->width;
- }
- } else {
- // decompression for data that has separate rle and literal streams
- while (pixelNo < pixelCount) {
- pixel = *rlePtr++;
- runLength = pixel & 0x3F;
- switch (pixel & 0xC0) {
- case 0: // copy bytes as-is
- while (runLength-- && pixelNo < pixelCount)
- outPtr[pixelNo++] = *literalPtr++;
- break;
- case 0x80: // fill with color
- memset(outPtr + pixelNo, *literalPtr++, MIN<uint32>(runLength, pixelCount - pixelNo));
- pixelNo += runLength;
- break;
- case 0xC0: // fill with transparent
- pixelNo += runLength;
- break;
- }
- }
- }
- } else {
- // literal stream only, so no compression
- memcpy(outPtr, literalPtr, pixelCount);
- pixelNo = pixelCount;
- }
- }
+ bool isMacSci11ViewData = g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() == SCI_VERSION_1_1;
+ unpackCelData(_resourceData, outPtr, clearColor, pixelCount, celInfo->offsetRLE, celInfo->offsetLiteral, _resMan->getViewType(), celInfo->width, isMacSci11ViewData);
// Swap 0 and 0xff pixels for Mac SCI1.1+ games (see above)
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) {
@@ -531,9 +575,8 @@ const byte *GfxView::getBitmap(int16 loopNo, int16 celNo) {
// unpack the actual cel bitmap data
unpackCel(loopNo, celNo, pBitmap, pixelCount);
- if (!_resMan->isVGA()) {
+ if (_resMan->getViewType() == kViewEga)
unditherBitmap(pBitmap, width, height, _loop[loopNo].cel[celNo].clearKey);
- }
// mirroring the cel if needed
if (_loop[loopNo].mirrorFlag) {
@@ -549,19 +592,15 @@ const byte *GfxView::getBitmap(int16 loopNo, int16 celNo) {
* cel if the dithering in here matches dithering used by the current picture.
*/
void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) {
- int16 *unditherMemorial = _screen->unditherGetMemorial();
-
- // It makes no sense to go further, if no memorial data from current picture
- // is available
- if (!unditherMemorial)
- return;
+ int16 *ditheredPicColors = _screen->unditherGetDitheredBgColors();
- // Makes no sense to process bitmaps that are 3 pixels wide or less
- if (width <= 3)
+ // It makes no sense to go further, if there isn't any dithered color data
+ // available for the current picture
+ if (!ditheredPicColors)
return;
- // We need at least 2 pixel lines
- if (height < 2)
+ // We need at least a 4x2 bitmap for this algorithm to work
+ if (width < 4 || height < 2)
return;
// If EGA mapping is used for this view, dont do undithering as well
@@ -569,13 +608,13 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
return;
// Walk through the bitmap and remember all combinations of colors
- int16 bitmapMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE];
+ int16 ditheredBitmapColors[DITHERED_BG_COLORS_SIZE];
byte *curPtr;
byte color1, color2;
byte nextColor1, nextColor2;
int16 y, x;
- memset(&bitmapMemorial, 0, sizeof(bitmapMemorial));
+ memset(&ditheredBitmapColors, 0, sizeof(ditheredBitmapColors));
// Count all seemingly dithered pixel-combinations as soon as at least 4
// pixels are adjacent and check pixels in the following line as well to
@@ -594,17 +633,17 @@ void GfxView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte cl
nextColor1 = (nextColor1 >> 4) | (nextColor2 << 4);
nextColor2 = (nextColor2 >> 4) | *nextPtr++ << 4;
if ((color1 == color2) && (color1 == nextColor1) && (color1 == nextColor2))
- bitmapMemorial[color1]++;
+ ditheredBitmapColors[color1]++;
}
}
- // Now compare both memorial tables to find out matching
- // dithering-combinations
- bool unditherTable[SCI_SCREEN_UNDITHERMEMORIAL_SIZE];
+ // Now compare both dither color tables to find out matching dithered color
+ // combinations
+ bool unditherTable[DITHERED_BG_COLORS_SIZE];
byte color, unditherCount = 0;
memset(&unditherTable, false, sizeof(unditherTable));
for (color = 0; color < 255; color++) {
- if ((bitmapMemorial[color] > 5) && (unditherMemorial[color] > 200)) {
+ if ((ditheredBitmapColors[color] > 5) && (ditheredPicColors[color] > 200)) {
// match found, check if colorKey is contained -> if so, we ignore
// of course
color1 = color & 0x0F; color2 = color >> 4;
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index e9c6d9847f..666a235cf9 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -1020,7 +1020,7 @@ static int augment_parse_nodes(ParseTreeNode *parseT, ParseTreeNode *saidT) {
/**** Main code ****/
/*******************/
-int said(EngineState *s, const byte *spec, bool verbose) {
+int said(const byte *spec, bool verbose) {
int retval;
Vocabulary *voc = g_sci->getVocabulary();
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index 8d59df5d58..25043401cc 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -63,7 +63,7 @@ Vocabulary::Vocabulary(ResourceManager *resMan, bool foreign) : _resMan(resMan),
_resourceIdBranches += 10;
}
- if (getSciVersion() <= SCI_VERSION_1_EGA && loadParserWords()) {
+ if (getSciVersion() <= SCI_VERSION_1_EGA_ONLY && loadParserWords()) {
loadSuffixes();
if (loadBranches())
// Now build a GNF grammar out of this
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index 3d644d88f7..6d3e0b301e 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -383,12 +383,11 @@ void vocab_dump_parse_tree(const char *tree_name, ParseTreeNode *nodes);
/**
* Builds a parse tree from a spec and compares it to a parse tree.
- * @param s The affected state
* @param spec Pointer to the spec to build
* @param verbose Whether to display the parse tree after building it
* @return 1 on a match, 0 otherwise
*/
-int said(EngineState *s, const byte *spec, bool verbose);
+int said(const byte *spec, bool verbose);
} // End of namespace Sci
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index a16f7126c3..61df02acf9 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -67,7 +67,7 @@ const char *getSciVersionDesc(SciVersion version) {
return "Late SCI0";
case SCI_VERSION_01:
return "SCI01";
- case SCI_VERSION_1_EGA:
+ case SCI_VERSION_1_EGA_ONLY:
return "SCI1 EGA";
case SCI_VERSION_1_EARLY:
return "Early SCI1";
@@ -948,15 +948,18 @@ void ResourceManager::init(bool initFromFallbackDetector) {
case kViewEga:
debugC(1, kDebugLevelResMan, "resMan: Detected EGA graphic resources");
break;
+ case kViewAmiga:
+ debugC(1, kDebugLevelResMan, "resMan: Detected Amiga ECS graphic resources");
+ break;
+ case kViewAmiga64:
+ debugC(1, kDebugLevelResMan, "resMan: Detected Amiga AGA graphic resources");
+ break;
case kViewVga:
debugC(1, kDebugLevelResMan, "resMan: Detected VGA graphic resources");
break;
case kViewVga11:
debugC(1, kDebugLevelResMan, "resMan: Detected SCI1.1 VGA graphic resources");
break;
- case kViewAmiga:
- debugC(1, kDebugLevelResMan, "resMan: Detected Amiga graphic resources");
- break;
default:
#ifdef ENABLE_SCI32
error("resMan: Couldn't determine view type");
@@ -1535,10 +1538,18 @@ void ResourceManager::readResourcePatches() {
mask += s_resourceTypeSuffixes[i];
SearchMan.listMatchingMembers(files, mask);
- if (i == kResourceTypeScript && files.size() == 0) {
- // SCI3 (we can't use getSciVersion() at this point)
- mask = "*.csc";
- SearchMan.listMatchingMembers(files, mask);
+ if (i == kResourceTypeView) {
+ SearchMan.listMatchingMembers(files, "*.v16"); // EGA SCI1 view patches
+ SearchMan.listMatchingMembers(files, "*.v32"); // Amiga SCI1 view patches
+ SearchMan.listMatchingMembers(files, "*.v64"); // Amiga AGA SCI1 (i.e. Longbow) view patches
+ } else if (i == kResourceTypePic) {
+ SearchMan.listMatchingMembers(files, "*.p16"); // EGA SCI1 picture patches
+ SearchMan.listMatchingMembers(files, "*.p32"); // Amiga SCI1 picture patches
+ SearchMan.listMatchingMembers(files, "*.p64"); // Amiga AGA SCI1 (i.e. Longbow) picture patches
+ } else if (i == kResourceTypeScript) {
+ if (files.size() == 0)
+ // SCI3 (we can't use getSciVersion() at this point)
+ SearchMan.listMatchingMembers(files, "*.csc");
}
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
@@ -2049,7 +2060,13 @@ ViewType ResourceManager::detectViewType() {
switch (res->data[1]) {
case 128:
- // If the 2nd byte is 128, it's a VGA game
+ // If the 2nd byte is 128, it's a VGA game.
+ // However, Longbow Amiga (AGA, 64 colors), also sets this byte
+ // to 128, but it's a mixed VGA/Amiga format. Detect this from
+ // the platform here.
+ if (g_sci && g_sci->getPlatform() == Common::kPlatformAmiga)
+ return kViewAmiga64;
+
return kViewVga;
case 0:
// EGA or Amiga, try to read as Amiga view
@@ -2127,9 +2144,9 @@ void ResourceManager::detectSciVersion() {
if (viewCompression != kCompLZW) {
// If it's a different compression type from kCompLZW, the game is probably
- // SCI_VERSION_1_EGA or later. If the views are uncompressed, it is
+ // SCI_VERSION_1_EGA_ONLY or later. If the views are uncompressed, it is
// likely not an early disk game.
- s_sciVersion = SCI_VERSION_1_EGA;
+ s_sciVersion = SCI_VERSION_1_EGA_ONLY;
oldDecompressors = false;
}
@@ -2243,9 +2260,9 @@ void ResourceManager::detectSciVersion() {
return;
}
- // New decompressors. It's either SCI_VERSION_1_EGA or SCI_VERSION_1_EARLY.
+ // New decompressors. It's either SCI_VERSION_1_EGA_ONLY or SCI_VERSION_1_EARLY.
if (hasSci1Voc900()) {
- s_sciVersion = SCI_VERSION_1_EGA;
+ s_sciVersion = SCI_VERSION_1_EGA_ONLY;
return;
}
@@ -2255,6 +2272,12 @@ void ResourceManager::detectSciVersion() {
case kResVersionSci1Middle:
case kResVersionKQ5FMT:
s_sciVersion = SCI_VERSION_1_MIDDLE;
+ // Amiga SCI1 middle games are actually SCI1 late
+ if (_viewType == kViewAmiga || _viewType == kViewAmiga64)
+ s_sciVersion = SCI_VERSION_1_LATE;
+ // Same goes for Mac SCI1 middle games
+ if (g_sci && g_sci->getPlatform() == Common::kPlatformMacintosh)
+ s_sciVersion = SCI_VERSION_1_LATE;
return;
case kResVersionSci1Late:
if (_volVersion == kResVersionSci11) {
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 76b5a421ee..e941f666d9 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -331,8 +331,6 @@ public:
int getAudioLanguage() const;
void changeAudioDirectory(Common::String path);
bool isGMTrackIncluded();
- bool isVGA() const { return (_viewType == kViewVga) || (_viewType == kViewVga11); }
- bool isAmiga32color() const { return _viewType == kViewAmiga; }
bool isSci11Mac() const { return _volVersion == kResVersionSci11Mac; }
ViewType getViewType() const { return _viewType; }
const char *getMapVersionDesc() const { return versionDescription(_mapVersion); }
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index b8a04066ac..bcbb005eb0 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -213,7 +213,6 @@ Common::Error SciEngine::run() {
// Add the after market GM patches for the specified game, if they exist
_resMan->addNewGMPatch(_gameId);
_gameObjectAddress = _resMan->findGameObject();
- _gameSuperClassAddress = NULL_REG;
SegManager *segMan = new SegManager(_resMan);
@@ -227,7 +226,7 @@ Common::Error SciEngine::run() {
_features = new GameFeatures(segMan, _kernel);
// Only SCI0, SCI01 and SCI1 EGA games used a parser
- _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA) ? new Vocabulary(_resMan, false) : NULL;
+ _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ? new Vocabulary(_resMan, false) : NULL;
// Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135
if (getGameId() == GID_CHRISTMAS1990)
_vocabulary = new Vocabulary(_resMan, false);
@@ -250,7 +249,6 @@ Common::Error SciEngine::run() {
warning("Could not get game object, aborting...");
return Common::kUnknownError;
}
- _gameSuperClassAddress = gameObject->getSuperClassSelector();
script_adjust_opcode_formats();
@@ -267,8 +265,6 @@ Common::Error SciEngine::run() {
// Initialize all graphics related subsystems
initGraphics();
- debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()));
-
// Patch in our save/restore code, so that dialogs are replaced
patchGameSaveRestore();
setLauncherLanguage();
@@ -427,7 +423,7 @@ static byte patchGameRestoreSave[] = {
0x76, // push0
0x38, 0xff, 0xff, // pushi -1
0x76, // push0
- 0x43, 0xff, 0x06, // callk kRestoreGame/kSaveGame (will get fixed directly)
+ 0x43, 0xff, 0x06, // callk kRestoreGame/kSaveGame (will get changed afterwards)
0x48, // ret
};
@@ -437,34 +433,56 @@ static byte patchGameRestoreSaveSci2[] = {
0x76, // push0
0x38, 0xff, 0xff, // pushi -1
0x76, // push0
- 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get fixed directly)
+ 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get changed afterwards)
0x48, // ret
};
+// SCI21 version: Same as above, but the second parameter to callk is a word
+static byte patchGameRestoreSaveSci21[] = {
+ 0x39, 0x04, // pushi 04
+ 0x76, // push0 // 0: save, 1: restore (will get changed afterwards)
+ 0x76, // push0
+ 0x38, 0xff, 0xff, // pushi -1
+ 0x76, // push0
+ 0x43, 0xff, 0x08, 0x00, // callk kSave (will get changed afterwards)
+ 0x48, // ret
+};
+
+static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) {
+ Script *script = segMan->getScript(methodAddress.segment);
+ byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset));
+ if (getSciVersion() <= SCI_VERSION_1_1)
+ memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
+ else // SCI2+
+ memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
+ patchPtr[8] = id;
+}
+
+static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) {
+ Script *script = segMan->getScript(methodAddress.segment);
+ byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset));
+ memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21));
+ if (doRestore)
+ patchPtr[2] = 0x78; // push1
+ patchPtr[9] = id;
+}
+
void SciEngine::patchGameSaveRestore() {
SegManager *segMan = _gamestate->_segMan;
const Object *gameObject = segMan->getObject(_gameObjectAddress);
- const uint16 gameMethodCount = gameObject->getMethodCount();
- const Object *gameSuperObject = segMan->getObject(_gameSuperClassAddress);
+ const Object *gameSuperObject = segMan->getObject(gameObject->getSuperClassSelector());
if (!gameSuperObject)
gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510
- const uint16 gameSuperMethodCount = gameSuperObject->getMethodCount();
- reg_t methodAddress;
- const uint16 kernelCount = _kernel->getKernelNamesSize();
- const byte *scriptRestorePtr = NULL;
byte kernelIdRestore = 0;
- const byte *scriptSavePtr = NULL;
byte kernelIdSave = 0;
- // This feature is currently not supported in SCI21 or SCI3
- if (getSciVersion() >= SCI_VERSION_2_1)
- return;
-
switch (_gameId) {
- case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs
- case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required
case GID_HOYLE1: // gets confused, although the game doesnt support saving/restoring at all
case GID_HOYLE2: // gets confused, see hoyle1
+ case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required
+ case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs
+ case GID_PHANTASMAGORIA: // has custom save/load code
+ case GID_SHIVERS: // has custom save/load code
return;
default:
break;
@@ -473,69 +491,53 @@ void SciEngine::patchGameSaveRestore() {
if (ConfMan.getBool("sci_originalsaveload"))
return;
- for (uint16 kernelNr = 0; kernelNr < kernelCount; kernelNr++) {
+ uint16 kernelNamesSize = _kernel->getKernelNamesSize();
+ for (uint16 kernelNr = 0; kernelNr < kernelNamesSize; kernelNr++) {
Common::String kernelName = _kernel->getKernelName(kernelNr);
if (kernelName == "RestoreGame")
kernelIdRestore = kernelNr;
if (kernelName == "SaveGame")
kernelIdSave = kernelNr;
+ if (kernelName == "Save")
+ kernelIdSave = kernelIdRestore = kernelNr;
}
- // Search for gameobject-superclass ::restore
- for (uint16 methodNr = 0; methodNr < gameSuperMethodCount; methodNr++) {
+ // Search for gameobject superclass ::restore
+ uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount();
+ for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) {
uint16 selectorId = gameSuperObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "restore") {
- methodAddress = gameSuperObject->getFunction(methodNr);
- Script *script = segMan->getScript(methodAddress.segment);
- scriptRestorePtr = script->getBuf(methodAddress.offset);
+ if (kernelIdSave != kernelIdRestore)
+ patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore);
+ else
+ patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true);
}
- if (methodName == "save") {
- methodAddress = gameSuperObject->getFunction(methodNr);
- Script *script = segMan->getScript(methodAddress.segment);
- scriptSavePtr = script->getBuf(methodAddress.offset);
+ else if (methodName == "save") {
+ if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
+ if (kernelIdSave != kernelIdRestore)
+ patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
+ else
+ patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
+ }
}
}
- // Search for gameobject ::save, if there is one patch that one instead
- for (uint16 methodNr = 0; methodNr < gameMethodCount; methodNr++) {
+ // Search for gameobject ::save, if there is one patch that one too
+ uint16 gameObjectMethodCount = gameObject->getMethodCount();
+ for (uint16 methodNr = 0; methodNr < gameObjectMethodCount; methodNr++) {
uint16 selectorId = gameObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "save") {
- methodAddress = gameObject->getFunction(methodNr);
- Script *script = segMan->getScript(methodAddress.segment);
- scriptSavePtr = script->getBuf(methodAddress.offset);
+ if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
+ if (kernelIdSave != kernelIdRestore)
+ patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave);
+ else
+ patchGameSaveRestoreCodeSci21(segMan, gameObject->getFunction(methodNr), kernelIdSave, false);
+ }
break;
}
}
-
- switch (_gameId) {
- case GID_FAIRYTALES: // fairy tales automatically saves w/o dialog
- scriptSavePtr = NULL;
- default:
- break;
- }
-
- if (scriptRestorePtr) {
- // Now patch in our code
- byte *patchPtr = const_cast<byte *>(scriptRestorePtr);
- if (getSciVersion() <= SCI_VERSION_1_1)
- memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
- else if (getSciVersion() == SCI_VERSION_2)
- memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
- // TODO: SCI21/SCI3
- patchPtr[8] = kernelIdRestore;
- }
- if (scriptSavePtr) {
- // Now patch in our code
- byte *patchPtr = const_cast<byte *>(scriptSavePtr);
- if (getSciVersion() <= SCI_VERSION_1_1)
- memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
- else if (getSciVersion() == SCI_VERSION_2)
- memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
- // TODO: SCI21/SCI3
- patchPtr[8] = kernelIdSave;
- }
}
bool SciEngine::initGame() {
@@ -641,7 +643,7 @@ void SciEngine::initGraphics() {
_gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts);
_gfxCursor->init(_gfxCoordAdjuster, _eventMan);
_gfxCompare = new GfxCompare(_gamestate->_segMan, _kernel, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
- _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette, _resMan->isVGA());
+ _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette);
_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _kernel, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette, _gfxTransitions, _audio);
_gfxPaint = _gfxPaint16;
_gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette, _gfxCursor, _gfxTransitions);
@@ -776,6 +778,16 @@ bool SciEngine::isCD() const {
return _gameDescription->flags & ADGF_CD;
}
+bool SciEngine::isBE() const{
+ switch(_gameDescription->platform) {
+ case Common::kPlatformAmiga:
+ case Common::kPlatformMacintosh:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool SciEngine::hasMacIconBar() const {
return _resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1 &&
(getGameId() == GID_KQ6 || getGameId() == GID_FREDDYPHARKAS);
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index b3e398325f..26ddb00a01 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -180,20 +180,24 @@ enum SciGameId {
GID_FANMADE // FIXME: Do we really need/want this?
};
-/** SCI versions */
+/**
+ * SCI versions
+ * For more information, check here:
+ * http://wiki.scummvm.org/index.php/Sierra_Game_Versions#SCI_Games
+ */
enum SciVersion {
SCI_VERSION_NONE,
- SCI_VERSION_0_EARLY, // Early KQ4, 1988 xmas card
+ SCI_VERSION_0_EARLY, // KQ4 early, LSL2 early, XMAS card 1988
SCI_VERSION_0_LATE, // KQ4, LSL2, LSL3, SQ3 etc
SCI_VERSION_01, // KQ1 and multilingual games (S.old.*)
- SCI_VERSION_1_EGA, // EGA with parser, QFG2
- SCI_VERSION_1_EARLY, // KQ5. (EGA/VGA)
- SCI_VERSION_1_MIDDLE, // LSL1, JONESCD. (EGA?/VGA)
- SCI_VERSION_1_LATE, // ECO1, LSL5. (EGA/VGA)
- SCI_VERSION_1_1, // KQ6, ECO2
- SCI_VERSION_2, // GK1, PQ4 (Floppy), QFG4 (Floppy)
- SCI_VERSION_2_1, // GK2, KQ7, SQ6, Torin
- SCI_VERSION_3 // LSL7, RAMA, Lighthouse
+ SCI_VERSION_1_EGA_ONLY, // SCI 1 EGA with parser (i.e. QFG2 only)
+ SCI_VERSION_1_EARLY, // KQ5 floppy, SQ4 floppy, XMAS card 1990, Fairy tales, Jones floppy
+ SCI_VERSION_1_MIDDLE, // LSL1, Jones CD
+ SCI_VERSION_1_LATE, // Dr. Brain 1, EcoQuest 1, Longbow, PQ3, SQ1, LSL5, KQ5 CD
+ SCI_VERSION_1_1, // Dr. Brain 2, EcoQuest 1 CD, EcoQuest 2, KQ6, QFG3, SQ4CD, XMAS 1992 and many more
+ SCI_VERSION_2, // GK1, PQ4 floppy, QFG4 floppy
+ SCI_VERSION_2_1, // GK2, KQ7, LSL6 hires, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
+ SCI_VERSION_3 // LSL7, Lighthouse, RAMA, Phantasmagoria 2
};
/** Supported languages */
@@ -234,6 +238,10 @@ public:
Common::Platform getPlatform() const;
bool isDemo() const;
bool isCD() const;
+
+ /** Returns true if the game's original platform is big-endian. */
+ bool isBE() const;
+
bool hasMacIconBar() const;
inline ResourceManager *getResMan() const { return _resMan; }
@@ -242,7 +250,6 @@ public:
inline Vocabulary *getVocabulary() const { return _vocabulary; }
inline EventManager *getEventManager() const { return _eventMan; }
inline reg_t getGameObject() const { return _gameObjectAddress; }
- inline reg_t getGameSuperClassAddress() const { return _gameSuperClassAddress; }
Common::RandomSource &getRNG() { return _rng; }
@@ -371,7 +378,6 @@ private:
int16 _vocabularyLanguage;
EventManager *_eventMan;
reg_t _gameObjectAddress; /**< Pointer to the game object */
- reg_t _gameSuperClassAddress; // Address of the super class of the game object
Console *_console;
Common::RandomSource _rng;
Common::MacResManager _macExecutable;
diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp
index 057b7c177f..65a8e2e3da 100644
--- a/engines/sci/sound/drivers/adlib.cpp
+++ b/engines/sci/sound/drivers/adlib.cpp
@@ -55,7 +55,7 @@ public:
virtual ~MidiDriver_AdLib() { }
// MidiDriver
- int open(bool isSCI0);
+ int openAdLib(bool isSCI0);
void close();
void send(uint32 b);
MidiChannel *allocateChannel() { return NULL; }
@@ -215,7 +215,7 @@ static const int ym3812_note[13] = {
0x2ae
};
-int MidiDriver_AdLib::open(bool isSCI0) {
+int MidiDriver_AdLib::openAdLib(bool isSCI0) {
int rate = _mixer->getOutputRate();
_stereo = STEREO;
@@ -273,10 +273,6 @@ void MidiDriver_AdLib::send(uint32 b) {
case 0x90:
noteOn(channel, op1, op2);
break;
- case 0xe0:
- _channels[channel].pitchWheel = (op1 & 0x7f) | ((op2 & 0x7f) << 7);
- renewNotes(channel, true);
- break;
case 0xb0:
switch (op1) {
case 0x07:
@@ -321,7 +317,9 @@ void MidiDriver_AdLib::send(uint32 b) {
case 0xa0: // Polyphonic key pressure (aftertouch)
case 0xd0: // Channel pressure (aftertouch)
break;
- case 0xf0: // SysEx, ignore it
+ case 0xe0:
+ _channels[channel].pitchWheel = (op1 & 0x7f) | ((op2 & 0x7f) << 7);
+ renewNotes(channel, true);
break;
default:
warning("ADLIB: Unknown event %02x", command);
@@ -828,7 +826,7 @@ int MidiPlayer_AdLib::open(ResourceManager *resMan) {
return -1;
}
- return static_cast<MidiDriver_AdLib *>(_driver)->open(_version <= SCI_VERSION_0_LATE);
+ return static_cast<MidiDriver_AdLib *>(_driver)->openAdLib(_version <= SCI_VERSION_0_LATE);
}
void MidiPlayer_AdLib::close() {
diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp
index 0ec4c283f7..d64dfac23c 100644
--- a/engines/sci/sound/drivers/amigamac.cpp
+++ b/engines/sci/sound/drivers/amigamac.cpp
@@ -34,7 +34,7 @@
namespace Sci {
-/* #define DEBUG */
+//#define DEBUG
class MidiDriver_AmigaMac : public MidiDriver_Emulated {
public:
@@ -289,9 +289,9 @@ void MidiDriver_AmigaMac::playInstrument(int16 *dest, Voice *channel, int count)
void MidiDriver_AmigaMac::changeInstrument(int channel, int instrument) {
#ifdef DEBUG
if (_bank.instruments[instrument][0])
- debugN("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument);
+ debugN("Amiga/Mac driver: Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument].name, instrument);
else
- warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel);
+ warning("Amiga/Mac driver: instrument %i does not exist (channel %i)", instrument, channel);
#endif
_channels[channel].instrument = instrument;
}
@@ -326,7 +326,7 @@ void MidiDriver_AmigaMac::stopNote(int ch, int note) {
if (channel == kChannels) {
#ifdef DEBUG
- warning("[sfx:seq:amiga] cannot stop note %i on channel %i", note, ch);
+ warning("Amiga/Mac driver: cannot stop note %i on channel %i", note, ch);
#endif
return;
}
@@ -366,7 +366,7 @@ void MidiDriver_AmigaMac::setOutputFrac(int voice) {
fnote += instrument->transpose;
if (fnote < 0 || fnote > 127) {
- warning("[sfx:seq:amiga] illegal note %i", fnote);
+ warning("Amiga/Mac driver: illegal note %i", fnote);
return;
}
} else
@@ -403,14 +403,14 @@ void MidiDriver_AmigaMac::startNote(int ch, int note, int velocity) {
int channel;
if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) {
- warning("[sfx:seq:amiga] invalid instrument %i on channel %i", _channels[ch].instrument, ch);
+ warning("Amiga/Mac driver: invalid instrument %i on channel %i", _channels[ch].instrument, ch);
return;
}
InstrumentSample *instrument = findInstrument(_channels[ch].instrument, note);
if (!instrument) {
- warning("[sfx:seq:amiga] instrument %i does not exist", _channels[ch].instrument);
+ warning("Amiga/Mac driver: instrument %i does not exist", _channels[ch].instrument);
return;
}
@@ -419,7 +419,7 @@ void MidiDriver_AmigaMac::startNote(int ch, int note, int velocity) {
break;
if (channel == kChannels) {
- warning("[sfx:seq:amiga] could not find a free channel");
+ warning("Amiga/Mac driver: could not find a free channel");
return;
}
@@ -447,14 +447,14 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C
byte header[61];
if (file.read(header, 61) < 61) {
- warning("[sfx:seq:amiga] failed to read instrument header");
+ warning("Amiga/Mac driver: failed to read instrument header");
return NULL;
}
int seg_size[3];
- seg_size[0] = READ_BE_UINT16(header + 35) * 2;
- seg_size[1] = READ_BE_UINT16(header + 41) * 2;
- seg_size[2] = READ_BE_UINT16(header + 47) * 2;
+ seg_size[0] = (int16)READ_BE_UINT16(header + 35) * 2;
+ seg_size[1] = (int16)READ_BE_UINT16(header + 41) * 2;
+ seg_size[2] = (int16)READ_BE_UINT16(header + 47) * 2;
InstrumentSample *instrument = new InstrumentSample;
@@ -489,18 +489,18 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C
instrument->name[29] = 0;
#ifdef DEBUG
- debugN("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n",
+ debugN("Amiga/Mac driver: Reading instrument %i: \"%s\" (%i bytes)\n",
*id, instrument->name, size);
debugN(" Mode: %02x\n", instrument->mode);
debugN(" Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off");
debugN(" Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off");
debugN(" Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]);
- debugN(" Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43));
+ debugN(" Segment offsets: 0 %i %i\n", loop_offset, (int32)READ_BE_UINT32(header + 43));
#endif
instrument->samples = (int8 *) malloc(size + 1);
if (file.read(instrument->samples, size) < (unsigned int)size) {
- warning("[sfx:seq:amiga] failed to read instrument samples");
+ warning("Amiga/Mac driver: failed to read instrument samples");
free(instrument->samples);
delete instrument;
return NULL;
@@ -512,14 +512,14 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C
if (instrument->mode & kModeLoop) {
if (loop_offset + seg_size[1] > size) {
#ifdef DEBUG
- warning("[sfx:seq:amiga] looping samples extend %i bytes past end of sample block",
+ warning("Amiga/Mac driver: looping samples extend %i bytes past end of sample block",
loop_offset + seg_size[1] - size);
#endif
seg_size[1] = size - loop_offset;
}
if (seg_size[1] < 0) {
- warning("[sfx:seq:amiga] invalid looping point");
+ warning("Amiga/Mac driver: invalid looping point");
free(instrument->samples);
delete instrument;
return NULL;
@@ -666,26 +666,42 @@ void MidiDriver_AmigaMac::send(uint32 b) {
case 0x07:
_channels[channel].volume = op2;
break;
- case 0x0a:
+ case 0x0a: // pan
+ // TODO
#ifdef DEBUG
- warning("[sfx:seq:amiga] ignoring pan 0x%02x event for channel %i", op2, channel);
+ warning("Amiga/Mac driver: ignoring pan 0x%02x event for channel %i", op2, channel);
#endif
break;
+ case 0x40: // hold
+ // TODO
+#ifdef DEBUG
+ warning("Amiga/Mac driver: ignoring hold 0x%02x event for channel %i", op2, channel);
+#endif
+ break;
+ case 0x4b: // voice mapping
+ break;
+ case 0x4e: // velocity
+ break;
case 0x7b:
stopChannel(channel);
break;
default:
- warning("[sfx:seq:amiga] unknown control event 0x%02x", op1);
+ //warning("Amiga/Mac driver: unknown control event 0x%02x", op1);
+ break;
}
break;
case 0xc0:
changeInstrument(channel, op1);
break;
+ // The original MIDI driver from sierra ignores aftertouch completely, so should we
+ case 0xa0: // Polyphonic key pressure (aftertouch)
+ case 0xd0: // Channel pressure (aftertouch)
+ break;
case 0xe0:
pitchWheel(channel, (op2 << 7) | op1);
break;
default:
- warning("[sfx:seq:amiga] unknown event %02x", command);
+ warning("Amiga/Mac driver: unknown event %02x", command);
}
}
@@ -738,7 +754,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
byte header[40];
if (file.read(header, 40) < 40) {
- warning("[sfx:seq:amiga] failed to read header of file bank.001");
+ warning("Amiga/Mac driver: failed to read header of file bank.001");
return false;
}
@@ -746,7 +762,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
strncpy(_bank.name, (char *) header + 8, 29);
_bank.name[29] = 0;
#ifdef DEBUG
- debugN("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+ debugN("Amiga/Mac driver: Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
#endif
for (uint i = 0; i < _bank.size; i++) {
@@ -754,12 +770,12 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
InstrumentSample *instrument = readInstrumentSCI0(file, &id);
if (!instrument) {
- warning("[sfx:seq:amiga] failed to read bank.001");
+ warning("Amiga/Mac driver: failed to read bank.001");
return false;
}
if (id < 0 || id > 255) {
- warning("[sfx:seq:amiga] Error: instrument ID out of bounds");
+ warning("Amiga/Mac driver: Error: instrument ID out of bounds");
return false;
}
@@ -777,7 +793,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &fil
byte header[40];
if (file.read(header, 40) < 40) {
- warning("[sfx:seq:amiga] failed to read header of file patch.200");
+ warning("Amiga/Mac driver: failed to read header of file patch.200");
return false;
}
@@ -785,7 +801,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &fil
strncpy(_bank.name, (char *) header + 8, 29);
_bank.name[29] = 0;
#ifdef DEBUG
- debugN("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
+ debugN("Amiga/Mac driver: Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
#endif
Common::Array<uint32> instrumentOffsets;
@@ -848,7 +864,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &fil
instrument->samples = (int8 *)malloc(size + 1);
if (file.read(instrument->samples, size) < size) {
- warning("[sfx:seq:amiga] failed to read instrument sample");
+ warning("Amiga/Mac driver: failed to read instrument sample");
free(instrument->samples);
delete instrument;
continue;
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index 08e93d3213..d16655928e 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -248,11 +248,17 @@ void MidiPlayer_Midi::controlChange(int channel, int control, int value) {
_channels[channel].hold = value;
break;
+ case 0x4b: // voice mapping
+ break;
+ case 0x4e: // velocity
+ break;
case 0x7b:
if (!_channels[channel].playing)
return;
_channels[channel].playing = false;
+ default:
+ break;
}
_driver->send(0xb0 | channel, control, value);
@@ -604,41 +610,83 @@ void MidiPlayer_Midi::readMt32DrvData() {
if (f.open("MT32.DRV")) {
int size = f.size();
- assert(size >= 166);
-
- // Send before-SysEx text
- f.seek(0x59);
+ // Skip before-SysEx text
+ if (size == 1773 || size == 1759) // XMAS88 / KQ4 early
+ f.seek(0x59);
+ else if (size == 2771) // LSL2 early
+ f.seek(0x29);
+ else
+ error("Unknown MT32.DRV size (%d)", size);
// Skip 2 extra 0 bytes in some drivers
if (f.readUint16LE() != 0)
f.seek(-2, SEEK_CUR);
+ // Send before-SysEx text
sendMt32SysEx(0x200000, static_cast<Common::SeekableReadStream *>(&f), 20);
- // Send after-SysEx text (SSCI sends this before every song)
- sendMt32SysEx(0x200000, static_cast<Common::SeekableReadStream *>(&f), 20);
+ if (size != 2271) {
+ // Send after-SysEx text (SSCI sends this before every song).
+ // There aren't any SysEx calls in old drivers, so this can
+ // be sent right after the before-SysEx text.
+ sendMt32SysEx(0x200000, static_cast<Common::SeekableReadStream *>(&f), 20);
+ } else {
+ // Skip the after-SysEx text in the newer patch version, we'll send
+ // it after the SysEx messages are sent.
+ f.skip(20);
+ }
- // Save goodbye message
+ // Save goodbye message. This isn't a C string, so it may not be
+ // nul-terminated.
f.read(_goodbyeMsg, 20);
// Set volume
byte volume = CLIP<uint16>(f.readUint16LE(), 0, 100);
setMt32Volume(volume);
- byte reverbSysEx[13];
- // This old driver should have a full reverb SysEx
- if ((f.read(reverbSysEx, 13) != 13) || (reverbSysEx[0] != 0xf0) || (reverbSysEx[12] != 0xf7))
- error("Error reading MT32.DRV");
+ if (size == 2771) {
+ // MT32.DRV in LSL2 early contains more data, like a normal patch
+ byte reverb = f.readByte();
- // Send reverb SysEx
- sysEx(reverbSysEx + 1, 11);
- _hasReverb = false;
+ _hasReverb = true;
- f.seek(0x29);
+ // Skip reverb SysEx message
+ f.skip(11);
- // Read AdLib->MT-32 patch map
- for (int i = 0; i < 48; i++) {
- _patchMap[i] = f.readByte();
+ // Read reverb data (stored vertically - patch #3117434)
+ for (int j = 0; j < 3; ++j) {
+ for (int i = 0; i < kReverbConfigNr; i++) {
+ _reverbConfig[i][j] = f.readByte();
+ }
+ }
+
+ f.skip(2235); // skip driver code
+
+ // Patches 1-48
+ sendMt32SysEx(0x50000, static_cast<Common::SeekableReadStream *>(&f), 256);
+ sendMt32SysEx(0x50200, static_cast<Common::SeekableReadStream *>(&f), 128);
+
+ setReverb(reverb);
+
+ // Send the after-SysEx text
+ f.seek(0x3d);
+ sendMt32SysEx(0x200000, static_cast<Common::SeekableReadStream *>(&f), 20);
+ } else {
+ byte reverbSysEx[13];
+ // This old driver should have a full reverb SysEx
+ if ((f.read(reverbSysEx, 13) != 13) || (reverbSysEx[0] != 0xf0) || (reverbSysEx[12] != 0xf7))
+ error("Error reading MT32.DRV");
+
+ // Send reverb SysEx
+ sysEx(reverbSysEx + 1, 11);
+ _hasReverb = false;
+
+ f.seek(0x29);
+
+ // Read AdLib->MT-32 patch map
+ for (int i = 0; i < 48; i++) {
+ _patchMap[i] = f.readByte();
+ }
}
f.close();
@@ -913,7 +961,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) {
// TODO: The MT-32 <-> GM mapping hasn't been worked on for SCI1 games. Throw
// a warning to the user
- if (getSciVersion() >= SCI_VERSION_1_EGA)
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY)
warning("The automatic mapping for General MIDI hasn't been worked on for "
"SCI1 games. Music might sound wrong or broken. Please choose another "
"music driver for this game (e.g. Adlib or MT-32) if you are "
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index f0963e7d64..a028617e74 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -75,7 +75,7 @@ void SciMusic::init() {
deviceFlags |= MDT_PREFER_GM;
// Currently our CMS implementation only supports SCI1(.1)
- if (getSciVersion() >= SCI_VERSION_1_EGA && getSciVersion() <= SCI_VERSION_1_1)
+ if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY && getSciVersion() <= SCI_VERSION_1_1)
deviceFlags |= MDT_CMS;
uint32 dev = MidiDriver::detectDevice(deviceFlags);
@@ -318,8 +318,21 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
pSnd->pMidiParser->mainThreadBegin();
+ // loadMusic() below calls jumpToTick.
+ // Disable sound looping and hold before jumpToTick is called,
+ // otherwise the song may keep looping forever when it ends in
+ // jumpToTick (e.g. LSL3, when going left from room 210).
+ uint16 prevLoop = pSnd->loop;
+ int16 prevHold = pSnd->hold;
+ pSnd->loop = 0;
+ pSnd->hold = -1;
+
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
pSnd->reverb = pSnd->pMidiParser->getSongReverb();
+
+ // Restore looping and hold
+ pSnd->loop = prevLoop;
+ pSnd->hold = prevHold;
pSnd->pMidiParser->mainThreadEnd();
_mutex.unlock();
}
@@ -434,18 +447,26 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
if (pSnd->status != kSoundPaused)
pSnd->pMidiParser->sendInitCommands();
pSnd->pMidiParser->setVolume(pSnd->volume);
- if (pSnd->status == kSoundStopped) {
+
+ // Disable sound looping and hold before jumpToTick is called,
+ // otherwise the song may keep looping forever when it ends in jumpToTick.
+ // This is needed when loading saved games, or when a game
+ // stops the same sound twice (e.g. LSL3 Amiga, going left from
+ // room 210 to talk with Kalalau). Fixes bugs #3083151 and #3106107.
+ uint16 prevLoop = pSnd->loop;
+ int16 prevHold = pSnd->hold;
+ pSnd->loop = 0;
+ pSnd->hold = -1;
+
+ if (pSnd->status == kSoundStopped)
pSnd->pMidiParser->jumpToTick(0);
- } else {
- // Disable sound looping before fast forwarding to the last position,
- // when loading a saved game. Fixes bug #3083151.
- uint16 prevLoop = pSnd->loop;
- pSnd->loop = 0;
+ else
// Fast forward to the last position and perform associated events when loading
pSnd->pMidiParser->jumpToTick(pSnd->ticker, true, true, true);
- // Restore looping
- pSnd->loop = prevLoop;
- }
+
+ // Restore looping and hold
+ pSnd->loop = prevLoop;
+ pSnd->hold = prevHold;
pSnd->pMidiParser->mainThreadEnd();
_mutex.unlock();
}
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 45a3e09453..1e6d0aef87 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -445,8 +445,16 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {
if (musicSlot->fadeCompleted) {
musicSlot->fadeCompleted = false;
- // We need signal for sci0 at least in iceman as well (room 14, fireworks)
- writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ // We need signal for sci0 at least in iceman as well (room 14,
+ // fireworks).
+ // It is also needed in other games, e.g. LSL6 when talking to the
+ // receptionist (bug #3192166).
+ if (g_sci->getGameId() == GID_LONGBOW && g_sci->getEngineState()->currentRoomNumber() == 95) {
+ // HACK: Don't set a signal here in the intro of Longbow, as that makes some dialog
+ // boxes disappear too soon (bug #3044844).
+ } else {
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ }
if (_soundVersion <= SCI_VERSION_0_LATE) {
processStopSound(obj, false);
} else {
diff --git a/engines/sci/util.cpp b/engines/sci/util.cpp
index f6a2465682..f346adddeb 100644
--- a/engines/sci/util.cpp
+++ b/engines/sci/util.cpp
@@ -30,25 +30,39 @@
namespace Sci {
+uint16 READ_SCIENDIAN_UINT16(const void *ptr) {
+ if (g_sci->isBE())
+ return READ_BE_UINT16(ptr);
+ else
+ return READ_LE_UINT16(ptr);
+}
+
+void WRITE_SCIENDIAN_UINT16(void *ptr, uint16 val) {
+ if (g_sci->isBE())
+ WRITE_BE_UINT16(ptr, val);
+ else
+ WRITE_LE_UINT16(ptr, val);
+}
+
uint16 READ_SCI11ENDIAN_UINT16(const void *ptr) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1)
return READ_BE_UINT16(ptr);
-
- return READ_LE_UINT16(ptr);
+ else
+ return READ_LE_UINT16(ptr);
}
uint16 READ_SCI32ENDIAN_UINT16(const void *ptr) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1)
return READ_BE_UINT16(ptr);
-
- return READ_LE_UINT16(ptr);
+ else
+ return READ_LE_UINT16(ptr);
}
uint32 READ_SCI11ENDIAN_UINT32(const void *ptr) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1)
return READ_BE_UINT32(ptr);
-
- return READ_LE_UINT32(ptr);
+ else
+ return READ_LE_UINT32(ptr);
}
void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val) {
diff --git a/engines/sci/util.h b/engines/sci/util.h
index d9ced5c9f6..7a2abb1873 100644
--- a/engines/sci/util.h
+++ b/engines/sci/util.h
@@ -30,6 +30,11 @@
namespace Sci {
+// Wrappers for reading/writing 16-bit values in the endianness
+// of the original game platform.
+uint16 READ_SCIENDIAN_UINT16(const void *ptr);
+void WRITE_SCIENDIAN_UINT16(void *ptr, uint16 val);
+
// Wrappers for reading integer values for SCI1.1+.
// Mac versions have big endian data for some fields.
uint16 READ_SCI11ENDIAN_UINT16(const void *ptr);
diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp
index bf52de67d5..ecdce3bd6b 100644
--- a/engines/sci/video/robot_decoder.cpp
+++ b/engines/sci/video/robot_decoder.cpp
@@ -251,6 +251,11 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() {
_fileStream->skip(4); // unknown, almost always 0
uint16 frameX = _fileStream->readUint16();
uint16 frameY = _fileStream->readUint16();
+ // TODO: In v4 robot files, frameX and frameY have a different meaning.
+ // Set them both to 0 for v4 for now, so that robots in PQ:SWAT show up
+ // correctly.
+ if (_header.version == 4)
+ frameX = frameY = 0;
uint16 compressedSize = _fileStream->readUint16();
uint16 frameFragments = _fileStream->readUint16();
_fileStream->skip(4); // unknown
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index 72e7052034..9349e70eb9 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -4,10 +4,6 @@
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
- * Parts of this code are heavily based on:
- * icoutils - A set of programs dealing with MS Windows icons and cursors.
- * Copyright (C) 1998-2001 Oskar Liljeblad
- *
* 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
@@ -36,6 +32,7 @@
#include "audio/decoders/wave.h"
#include "graphics/cursorman.h"
+#include "graphics/wincursor.h"
#include "common/archive.h"
#include "common/memstream.h"
@@ -43,14 +40,6 @@
namespace Scumm {
-#if defined(SCUMM_LITTLE_ENDIAN)
-#define LE16(x)
-#define LE32(x)
-#elif defined(SCUMM_BIG_ENDIAN)
-#define LE16(x) ((x) = TO_LE_16(x))
-#define LE32(x) ((x) = TO_LE_32(x))
-#endif
-
ResExtractor::ResExtractor(ScummEngine_v70he *scumm)
: _vm(scumm) {
@@ -65,1092 +54,112 @@ ResExtractor::~ResExtractor() {
free(cc->palette);
}
}
+
memset(_cursorCache, 0, sizeof(_cursorCache));
}
ResExtractor::CachedCursor *ResExtractor::findCachedCursor(int id) {
- for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
- CachedCursor *cc = &_cursorCache[i];
- if (cc->valid && cc->id == id) {
- return cc;
- }
- }
+ for (int i = 0; i < MAX_CACHED_CURSORS; ++i)
+ if (_cursorCache[i].valid && _cursorCache[i].id == id)
+ return &_cursorCache[i];
+
return NULL;
}
ResExtractor::CachedCursor *ResExtractor::getCachedCursorSlot() {
- uint32 min_last_used = 0;
+ uint32 minLastUsed = 0;
CachedCursor *r = NULL;
+
for (int i = 0; i < MAX_CACHED_CURSORS; ++i) {
CachedCursor *cc = &_cursorCache[i];
- if (!cc->valid) {
+ if (!cc->valid)
return cc;
- } else {
- if (min_last_used == 0 || cc->last_used < min_last_used) {
- min_last_used = cc->last_used;
- r = cc;
- }
+
+ if (minLastUsed == 0 || cc->lastUsed < minLastUsed) {
+ minLastUsed = cc->lastUsed;
+ r = cc;
}
}
+
assert(r);
- free(r->bitmap);
- free(r->palette);
+ delete[] r->bitmap;
+ delete[] r->palette;
memset(r, 0, sizeof(CachedCursor));
return r;
}
void ResExtractor::setCursor(int id) {
- byte *cursorRes = 0;
- int cursorsize;
- int keycolor = 0;
CachedCursor *cc = findCachedCursor(id);
+
if (cc != NULL) {
debug(7, "Found cursor %d in cache slot %lu", id, (long)(cc - _cursorCache));
} else {
cc = getCachedCursorSlot();
assert(cc && !cc->valid);
- cursorsize = extractResource(id, &cursorRes);
- convertIcons(cursorRes, cursorsize, &cc->bitmap, &cc->w, &cc->h, &cc->hotspot_x, &cc->hotspot_y, &keycolor, &cc->palette, &cc->palSize);
+
+ if (!extractResource(id, cc))
+ error("Could not extract cursor %d", id);
+
debug(7, "Adding cursor %d to cache slot %lu", id, (long)(cc - _cursorCache));
- free(cursorRes);
+
cc->valid = true;
cc->id = id;
- cc->last_used = g_system->getMillis();
+ cc->lastUsed = g_system->getMillis();
}
if (cc->palette)
CursorMan.replaceCursorPalette(cc->palette, 0, cc->palSize);
- _vm->setCursorHotspot(cc->hotspot_x, cc->hotspot_y);
- _vm->setCursorFromBuffer(cc->bitmap, cc->w, cc->h, cc->w);
+ _vm->setCursorHotspot(cc->hotspotX, cc->hotspotY);
+ _vm->setCursorFromBuffer(cc->bitmap, cc->width, cc->height, cc->width);
}
-/*
- * Static variables
- */
-const char *res_types[] = {
- /* 0x01: */
- "cursor", "bitmap", "icon", "menu", "dialog", "string",
- "fontdir", "font", "accelerator", "rcdata", "messagelist",
- "group_cursor", NULL, "group_icon", NULL,
- /* the following are not defined in winbase.h, but found in wrc. */
- /* 0x10: */
- "version", "dlginclude", NULL, "plugplay", "vxd",
- "anicursor", "aniicon"
-};
-#define RES_TYPE_COUNT (sizeof(res_types)/sizeof(char *))
-
Win32ResExtractor::Win32ResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
}
-int Win32ResExtractor::extractResource(int resId, byte **data) {
- char buf[20];
-
- snprintf(buf, sizeof(buf), "%d", resId);
-
- return extractResource_("group_cursor", buf, data);
-}
-
-int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte **data) {
- char *arg_language = NULL;
- const char *arg_type = resType;
- char *arg_name = resName;
- int ressize = 0;
-
- _arg_raw = false;
-
- /* translate --type option from resource type string to integer */
- arg_type = res_type_string_to_id(arg_type);
-
- WinLibrary fi;
-
- /* initiate stuff */
- fi.memory = NULL;
- fi.file = NULL;
-
+bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) {
if (_fileName.empty()) { // We are running for the first time
_fileName = _vm->generateFilename(-3);
- }
-
- /* get file size */
- fi.file = SearchMan.createReadStreamForMember(_fileName);
- if (!fi.file) {
- error("Cannot open file %s", _fileName.c_str());
- }
-
- fi.total_size = fi.file->size();
- if (fi.total_size == -1) {
- error("Cannot get size of file %s", _fileName.c_str());
- goto cleanup;
- }
- if (fi.total_size == 0) {
- error("%s: file has a size of 0", _fileName.c_str());
- goto cleanup;
- }
-
- /* read all of file */
- fi.memory = (byte *)malloc(fi.total_size);
- if (fi.file->read(fi.memory, fi.total_size) == 0) {
- error("Cannot read from file %s", _fileName.c_str());
- goto cleanup;
- }
-
- /* identify file and find resource table */
- if (!read_library(&fi)) {
- /* error reported by read_library */
- goto cleanup;
- }
-
- /* errors will be printed by the callback */
- ressize = do_resources(&fi, arg_type, arg_name, arg_language, data);
-
- /* free stuff and close file */
- cleanup:
- delete fi.file;
- free(fi.memory);
-
- return ressize;
-}
-
-
-/**
- * Translate a numeric resource type to it's corresponding string type.
- * (For informative-ness.)
- */
-const char *Win32ResExtractor::res_type_id_to_string(int id) {
- if (id == 241)
- return "toolbar";
- if (id > 0 && id <= (int)RES_TYPE_COUNT)
- return res_types[id-1];
- return NULL;
-}
-
-/**
- * Translate a resource type string to integer.
- * (Used to convert the --type option.)
- */
-const char *Win32ResExtractor::res_type_string_to_id(const char *type) {
- static const char *res_type_ids[] = {
- "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10",
- "-11", "-12", NULL, "-14", NULL, "-16", "-17", NULL, "-19",
- "-20", "-21", "-22"
- };
- int c;
-
- if (type == NULL)
- return NULL;
-
- for (c = 0; c < (int)RES_TYPE_COUNT; c++) {
- if (res_types[c] != NULL && !scumm_stricmp(type, res_types[c]))
- return res_type_ids[c];
- }
-
- return type;
-}
-
-/**
- * Return the resource id quoted if it is a string, otherwise (i.e. if
- * it is numeric) just return it.
- */
-Common::String Win32ResExtractor::WinResource::getQuotedResourceId() const {
- if (numeric_id || id[0] == '\0')
- return id;
- return '"' + Common::String(id) + '"';
-}
-
-int Win32ResExtractor::extract_resources(WinLibrary *fi, WinResource *wr,
- WinResource *type_wr, WinResource *name_wr,
- WinResource *lang_wr, byte **data) {
- int size;
- bool free_it;
- const char *type;
- int32 id;
-
- if (*data) {
- error("Win32ResExtractor::extract_resources() more than one cursor");
- return 0;
- }
-
- *data = extract_resource(fi, wr, &size, &free_it, type_wr->id, (lang_wr == NULL ? NULL : lang_wr->id), _arg_raw);
-
- if (data == NULL) {
- error("Win32ResExtractor::extract_resources() problem with resource extraction");
- return 0;
- }
-
- /* get named resource type if possible */
- type = NULL;
- if ((id = strtol(type_wr->id, 0, 10)) != 0)
- type = res_type_id_to_string(id);
-
- if (lang_wr != NULL && lang_wr->id[0] != '\0') {
- debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s language: %s [size=%d]",
- name_wr->getQuotedResourceId().c_str(), lang_wr->getQuotedResourceId().c_str(), size);
- } else {
- debugC(DEBUG_RESOURCE, "extractCursor(). Found cursor name: %s [size=%d]",
- name_wr->getQuotedResourceId().c_str(), size);
- }
- return size;
-}
-
-/**
- * Extract a resource, returning pointer to data.
- */
-byte *Win32ResExtractor::extract_resource(WinLibrary *fi, WinResource *wr, int *size,
- bool *free_it, char *type, char *lang, bool raw) {
- char *str;
- int32 intval;
-
- /* just return pointer to data if raw */
- if (raw) {
- *free_it = false;
- /* get_resource_entry will print possible error */
- return get_resource_entry(fi, wr, size);
- }
-
- /* find out how to extract */
- str = type;
- if (str != NULL && (intval = strtol(STRIP_RES_ID_FORMAT(str), 0, 10))) {
- if (intval == (int)RT_GROUP_ICON) {
- *free_it = true;
- return extract_group_icon_cursor_resource(fi, wr, lang, size, true);
- }
- if (intval == (int)RT_GROUP_CURSOR) {
- *free_it = true;
- return extract_group_icon_cursor_resource(fi, wr, lang, size, false);
- }
- }
-
- return NULL;
-}
-
-/**
- * Create a complete RT_GROUP_ICON resource, that can be written to
- * an `.ico' file without modifications. Returns an allocated
- * memory block that should be freed with free() once used.
- *
- * `root' is the offset in file that specifies the resource.
- * `base' is the offset that string pointers are calculated from.
- * `ressize' should point to an integer variable where the size of
- * the returned memory block will be placed.
- * `is_icon' indicates whether resource to be extracted is icon
- * or cursor group.
- */
-byte *Win32ResExtractor::extract_group_icon_cursor_resource(WinLibrary *fi, WinResource *wr, char *lang,
- int *ressize, bool is_icon) {
- Win32CursorIconDir *icondir;
- Win32CursorIconFileDir *fileicondir;
- byte *memory;
- int c, offset, skipped;
- int size;
-
- /* get resource data and size */
- icondir = (Win32CursorIconDir *)get_resource_entry(fi, wr, &size);
- if (icondir == NULL) {
- /* get_resource_entry will print error */
- return NULL;
- }
-
- /* calculate total size of output file */
- RETURN_IF_BAD_POINTER(NULL, icondir->count);
- skipped = 0;
- for (c = 0; c < FROM_LE_16(icondir->count); c++) {
- int level;
- int iconsize;
- char name[14];
- WinResource *fwr;
-
- RETURN_IF_BAD_POINTER(NULL, icondir->entries[c]);
- /*debug("%d. bytes_in_res=%d width=%d height=%d planes=%d bit_count=%d", c,
- FROM_LE_32(icondir->entries[c].bytes_in_res),
- (is_icon ? icondir->entries[c].res_info.icon.width : FROM_LE_16(icondir->entries[c].res_info.cursor.width)),
- (is_icon ? icondir->entries[c].res_info.icon.height : FROM_LE_16(icondir->entries[c].res_info.cursor.height)),
- FROM_LE_16(icondir->entries[c].plane_count),
- FROM_LE_16(icondir->entries[c].bit_count));*/
-
- /* find the corresponding icon resource */
- snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
- fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
- if (fwr == NULL) {
- error("%s: could not find `%s' in `%s' resource.",
- _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
- return NULL;
- }
-
- if (get_resource_entry(fi, fwr, &iconsize) != NULL) {
- if (iconsize == 0) {
- debugC(DEBUG_RESOURCE, "%s: icon resource `%s' is empty, skipping", _fileName.c_str(), name);
- skipped++;
- continue;
- }
- if ((uint32)iconsize != FROM_LE_32(icondir->entries[c].bytes_in_res)) {
- debugC(DEBUG_RESOURCE, "%s: mismatch of size in icon resource `%s' and group (%d != %d)",
- _fileName.c_str(), name, iconsize, FROM_LE_32(icondir->entries[c].bytes_in_res));
- }
- size += iconsize; /* size += FROM_LE_32(icondir->entries[c].bytes_in_res); */
- /* cursor resources have two additional WORDs that contain
- * hotspot info */
- if (!is_icon)
- size -= sizeof(uint16)*2;
- }
- }
- offset = sizeof(Win32CursorIconFileDir) + (FROM_LE_16(icondir->count)-skipped) * sizeof(Win32CursorIconFileDirEntry);
- size += offset;
- *ressize = size;
-
- /* allocate that much memory */
- memory = (byte *)malloc(size);
- fileicondir = (Win32CursorIconFileDir *)memory;
-
- /* transfer Win32CursorIconDir structure members */
- fileicondir->reserved = icondir->reserved;
- fileicondir->type = icondir->type;
- fileicondir->count = TO_LE_16(FROM_LE_16(icondir->count) - skipped);
-
- /* transfer each cursor/icon: Win32CursorIconDirEntry and data */
- skipped = 0;
- for (c = 0; c < FROM_LE_16(icondir->count); c++) {
- int level;
- char name[14];
- WinResource *fwr;
- byte *data;
-
- /* find the corresponding icon resource */
- snprintf(name, sizeof(name)/sizeof(char), "-%d", FROM_LE_16(icondir->entries[c].res_id));
- fwr = find_resource(fi, (is_icon ? "-3" : "-1"), name, lang, &level);
- if (fwr == NULL) {
- error("%s: could not find `%s' in `%s' resource.",
- _fileName.c_str(), &name[1], (is_icon ? "group_icon" : "group_cursor"));
- return NULL;
- }
-
- /* get data and size of that resource */
- data = (byte *)get_resource_entry(fi, fwr, &size);
- if (data == NULL) {
- /* get_resource_entry has printed error */
- return NULL;
- }
- if (size == 0) {
- skipped++;
- continue;
- }
-
- /* copy ICONDIRENTRY (not including last dwImageOffset) */
- memcpy(&fileicondir->entries[c-skipped], &icondir->entries[c],
- sizeof(Win32CursorIconFileDirEntry)-sizeof(uint32));
-
- /* special treatment for cursors */
- if (!is_icon) {
- fileicondir->entries[c-skipped].width = icondir->entries[c].res_info.cursor.width;
- fileicondir->entries[c-skipped].height = TO_LE_16(FROM_LE_16(icondir->entries[c].res_info.cursor.height) / 2);
- fileicondir->entries[c-skipped].color_count = 0;
- fileicondir->entries[c-skipped].reserved = 0;
- }
-
- /* set image offset and increase it */
- fileicondir->entries[c-skipped].dib_offset = TO_LE_32(offset);
-
- /* transfer resource into file memory */
- if (is_icon) {
- memcpy(&memory[offset], data, FROM_LE_32(icondir->entries[c].bytes_in_res));
- } else {
- fileicondir->entries[c-skipped].hotspot_x = ((uint16 *) data)[0];
- fileicondir->entries[c-skipped].hotspot_y = ((uint16 *) data)[1];
- memcpy(&memory[offset], data+sizeof(uint16)*2,
- FROM_LE_32(icondir->entries[c].bytes_in_res)-sizeof(uint16)*2);
- offset -= sizeof(uint16)*2;
- }
-
- /* increase the offset pointer */
- offset += FROM_LE_32(icondir->entries[c].bytes_in_res);
+ if (!_exe.loadFromEXE(_fileName))
+ error("Cannot open file %s", _fileName.c_str());
}
- return memory;
-}
-
-/**
- * Check if a chunk of data (determined by offset and size)
- * is within the bounds of the WinLibrary file.
- * Usually not called directly.
- */
-bool Win32ResExtractor::check_offset(byte *memory, int total_size, const char *name, void *offset, int size) {
- int need_size = (int)((byte *)offset - memory + size);
-
- debugC(DEBUG_RESOURCE, "check_offset: size=%x vs %x offset=%x size=%x",
- need_size, total_size, (uint)((byte *)offset - memory), size);
+ Graphics::WinCursorGroup *group = Graphics::WinCursorGroup::createCursorGroup(_exe, id);
- if (need_size < 0 || need_size > total_size) {
- error("%s: premature end", name);
+ if (!group)
return false;
- }
-
- return true;
-}
-
-
-/**
- * Do something for each resource matching type, name and lang.
- */
-int Win32ResExtractor::do_resources(WinLibrary *fi, const char *type, char *name, char *lang, byte **data) {
- WinResource *type_wr;
- WinResource *name_wr;
- WinResource *lang_wr;
- int size;
-
- type_wr = (WinResource *)calloc(3, sizeof(WinResource));
- name_wr = type_wr + 1;
- lang_wr = type_wr + 2;
-
- size = do_resources_recurs(fi, NULL, type_wr, name_wr, lang_wr, type, name, lang, data);
-
- free(type_wr);
-
- return size;
-}
-
-/* what is each entry in this directory level for? type, name or language? */
-#define WINRESOURCE_BY_LEVEL(x) ((x)==0 ? type_wr : ((x)==1 ? name_wr : lang_wr))
-
-/* does the id of this entry match the specified id? */
-#define LEVEL_MATCHES(x) (x == NULL || x ## _wr->id[0] == '\0' || compare_resource_id(x ## _wr, x))
-int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base,
- WinResource *type_wr, WinResource *name_wr, WinResource *lang_wr,
- const char *type, char *name, char *lang, byte **data) {
- int c, rescnt;
- WinResource *wr;
- uint32 size = 0;
+ Graphics::WinCursor *cursor = group->cursors[0].cursor;
- /* get a list of all resources at this level */
- wr = list_resources(fi, base, &rescnt);
- if (wr == NULL) {
- return size;
- }
-
- /* process each resource listed */
- for (c = 0; c < rescnt; c++) {
- /* (over)write the corresponding WinResource holder with the current */
- memcpy(WINRESOURCE_BY_LEVEL(wr[c].level), wr+c, sizeof(WinResource));
-
- /* go deeper unless there is something that does NOT match */
- if (LEVEL_MATCHES(type) && LEVEL_MATCHES(name) && LEVEL_MATCHES(lang)) {
- if (wr->is_directory)
- size = do_resources_recurs(fi, wr+c, type_wr, name_wr, lang_wr, type, name, lang, data);
- else
- size = extract_resources(fi, wr+c, type_wr, name_wr, lang_wr, data);
- }
- }
-
- /* since we're moving back one level after this, unset the
- * WinResource holder used on this level */
- memset(WINRESOURCE_BY_LEVEL(wr[0].level), 0, sizeof(WinResource));
-
- return size;
-}
-
-bool Win32ResExtractor::compare_resource_id(WinResource *wr, const char *id) {
- if (wr->numeric_id) {
- int32 cmp1, cmp2;
- if (id[0] == '+')
- return false;
- if (id[0] == '-')
- id++;
- cmp1 = strtol(wr->id, 0, 10);
- cmp2 = strtol(id, 0, 10);
- if (!cmp1 || !cmp2 || cmp1 != cmp2)
- return false;
- } else {
- if (id[0] == '-')
- return false;
- if (id[0] == '+')
- id++;
- if (strcmp(wr->id, id))
- return false;
- }
+ cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()];
+ cc->width = cursor->getWidth();
+ cc->height = cursor->getHeight();
+ cc->hotspotX = cursor->getHotspotX();
+ cc->hotspotY = cursor->getHotspotY();
- return true;
-}
+ // Convert from the paletted format to the SCUMM palette
+ const byte *srcBitmap = cursor->getSurface();
-bool Win32ResExtractor::decode_pe_resource_id(WinLibrary *fi, WinResource *wr, uint32 value) {
- if (value & IMAGE_RESOURCE_NAME_IS_STRING) { /* numeric id */
- int c, len;
- uint16 *mem = (uint16 *)
- (fi->first_resource + (value & ~IMAGE_RESOURCE_NAME_IS_STRING));
-
- /* copy each char of the string, and terminate it */
- RETURN_IF_BAD_POINTER(false, *mem);
- len = FROM_LE_16(mem[0]);
- RETURN_IF_BAD_OFFSET(false, &mem[1], sizeof(uint16) * len);
-
- len = MIN(FROM_LE_16(mem[0]), (uint16)WINRES_ID_MAXLEN);
- for (c = 0; c < len; c++)
- wr->id[c] = FROM_LE_16(mem[c+1]) & 0x00FF;
- wr->id[len] = '\0';
- wr->numeric_id = false;
- } else { /* Unicode string id */
- /* translate id into a string */
- snprintf(wr->id, WINRES_ID_MAXLEN, "%d", value);
- wr->numeric_id = true;
+ for (int i = 0; i < cursor->getWidth() * cursor->getHeight(); i++) {
+ if (srcBitmap[i] == cursor->getKeyColor()) // Transparent
+ cc->bitmap[i] = 255;
+ else if (srcBitmap[i] == 0) // Black
+ cc->bitmap[i] = 253;
+ else // White
+ cc->bitmap[i] = 254;
}
+ delete group;
return true;
}
-byte *Win32ResExtractor::get_resource_entry(WinLibrary *fi, WinResource *wr, int *size) {
- byte *result;
-
- Win32ImageResourceDataEntry *dataent;
-
- dataent = (Win32ImageResourceDataEntry *) wr->children;
- RETURN_IF_BAD_POINTER(NULL, *dataent);
- *size = FROM_LE_32(dataent->size);
-
- result = fi->memory + FROM_LE_32(dataent->offset_to_data);
-
- RETURN_IF_BAD_OFFSET(NULL, result, *size);
-
- return result;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary *fi, Win32ImageResourceDirectory *pe_res, int level, int *count) {
- WinResource *wr;
- int c, rescnt;
- Win32ImageResourceDirectoryEntry *dirent
- = (Win32ImageResourceDirectoryEntry *)(pe_res + 1);
-
- /* count number of `type' resources */
- RETURN_IF_BAD_POINTER(NULL, *dirent);
- rescnt = FROM_LE_16(pe_res->number_of_named_entries) + FROM_LE_16(pe_res->number_of_id_entries);
- *count = rescnt;
-
- /* allocate WinResource's */
- wr = (WinResource *)malloc(sizeof(WinResource) * rescnt);
-
- /* fill in the WinResource's */
- for (c = 0; c < rescnt; c++) {
- RETURN_IF_BAD_POINTER(NULL, dirent[c]);
- wr[c].this_ = pe_res;
- wr[c].level = level;
- wr[c].is_directory = ((FROM_LE_32(dirent[c].offset_to_data) & IMAGE_RESOURCE_DATA_IS_DIRECTORY) != 0);
- wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
-
- /* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
- free(wr);
- return NULL;
- }
- }
-
- return wr;
-}
-
-
-/**
- * Return an array of WinResource's in the current
- * resource level specified by _res->
- */
-Win32ResExtractor::WinResource *Win32ResExtractor::list_resources(WinLibrary *fi, WinResource *res, int *count) {
- if (res != NULL && !res->is_directory)
- return NULL;
-
- return list_pe_resources(fi, (Win32ImageResourceDirectory *)
- (res == NULL ? fi->first_resource : res->children),
- (res == NULL ? 0 : res->level+1),
- count);
-}
-
-/**
- * Read header and get resource directory offset in a Windows library
- * (AKA module).
- */
-bool Win32ResExtractor::read_library(WinLibrary *fi) {
- /* check for DOS header signature `MZ' */
- RETURN_IF_BAD_POINTER(false, MZ_HEADER(fi->memory)->magic);
- if (FROM_LE_16(MZ_HEADER(fi->memory)->magic) == IMAGE_DOS_SIGNATURE) {
- DOSImageHeader *mz_header = MZ_HEADER(fi->memory);
-
- RETURN_IF_BAD_POINTER(false, mz_header->lfanew);
-
- // Apply endian fix (currently only lfanew is used from the DOSImageHeader,
- // so we don't bother to 'fix' the rest).
- LE32(mz_header->lfanew);
-
- if (mz_header->lfanew < sizeof(DOSImageHeader)) {
- error("%s: not a Windows library", _fileName.c_str());
- return false;
- }
- }
-
- /* check for NT header signature `PE' */
- RETURN_IF_BAD_POINTER(false, PE_HEADER(fi->memory)->signature);
- if (FROM_LE_32(PE_HEADER(fi->memory)->signature) == IMAGE_NT_SIGNATURE) {
- Win32ImageNTHeaders *pe_header;
- int d;
-
- // Fix image header endianess
- fix_win32_image_header_endian(PE_HEADER(fi->memory));
-
- /* allocate new memory */
- fi->total_size = calc_vma_size(fi);
- if (fi->total_size == 0) {
- /* calc_vma_size has reported error */
- return false;
- }
- byte *ptr = (byte *)realloc(fi->memory, fi->total_size);
- assert(ptr);
- fi->memory = ptr;
-
- /* relocate memory, start from last section */
- pe_header = PE_HEADER(fi->memory);
- RETURN_IF_BAD_POINTER(false, pe_header->file_header.number_of_sections);
-
- /* we don't need to do OFFSET checking for the sections.
- * calc_vma_size has already done that */
- for (d = pe_header->file_header.number_of_sections - 1; d >= 0; d--) {
- Win32ImageSectionHeader *pe_sec = PE_SECTIONS(fi->memory) + d;
-
- if (pe_sec->characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- continue;
-
- //if (pe_sec->virtual_address + pe_sec->size_of_raw_data > fi->total_size)
-
- RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->virtual_address, pe_sec->size_of_raw_data);
- RETURN_IF_BAD_OFFSET(0, fi->memory + pe_sec->pointer_to_raw_data, pe_sec->size_of_raw_data);
- if (FROM_LE_32(pe_sec->virtual_address) != pe_sec->pointer_to_raw_data) {
- memmove(fi->memory + pe_sec->virtual_address,
- fi->memory + pe_sec->pointer_to_raw_data,
- pe_sec->size_of_raw_data);
- }
- }
-
- /* find resource directory */
- RETURN_IF_BAD_POINTER(false, pe_header->optional_header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
- Win32ImageDataDirectory *dir = pe_header->optional_header.data_directory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
- if (dir->size == 0) {
- error("%s: file contains no resources", _fileName.c_str());
- return false;
- }
-
- fix_win32_image_data_directory(dir);
-
- fi->first_resource = fi->memory + dir->virtual_address;
- return true;
- }
-
- /* other (unknown) header signature was found */
- error("%s: not a Windows library", _fileName.c_str());
- return false;
-}
-
-/**
- * Calculate the total amount of memory needed for a 32-bit Windows
- * module. Returns -1 if file was too small.
- */
-int Win32ResExtractor::calc_vma_size(WinLibrary *fi) {
- Win32ImageSectionHeader *seg;
- int c, segcount, size;
-
- size = 0;
- RETURN_IF_BAD_POINTER(-1, PE_HEADER(fi->memory)->file_header.number_of_sections);
- segcount = PE_HEADER(fi->memory)->file_header.number_of_sections;
-
- /* If there are no segments, just process file like it is.
- * This is (probably) not the right thing to do, but problems
- * will be delt with later anyway.
- */
- if (segcount == 0)
- return fi->total_size;
-
- seg = PE_SECTIONS(fi->memory);
- RETURN_IF_BAD_POINTER(-1, *seg);
- for (c = 0; c < segcount; c++) {
- RETURN_IF_BAD_POINTER(0, *seg);
- fix_win32_image_section_header(seg);
-
- size = MAX((uint32)size, seg->virtual_address + seg->size_of_raw_data);
- /* I have no idea what misc.virtual_size is for... */
- size = MAX((uint32)size, seg->virtual_address + seg->misc.virtual_size);
- seg++;
- }
-
- return size;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::find_with_resource_array(WinLibrary *fi, WinResource *wr, const char *id) {
- int c, rescnt;
- WinResource *return_wr;
-
- wr = list_resources(fi, wr, &rescnt);
- if (wr == NULL)
- return NULL;
-
- for (c = 0; c < rescnt; c++) {
- if (compare_resource_id(&wr[c], id)) {
- /* duplicate WinResource and return it */
- return_wr = (WinResource *)malloc(sizeof(WinResource));
- memcpy(return_wr, &wr[c], sizeof(WinResource));
-
- /* free old WinResource */
- free(wr);
- return return_wr;
- }
- }
-
- return NULL;
-}
-
-Win32ResExtractor::WinResource *Win32ResExtractor::find_resource(WinLibrary *fi, const char *type, const char *name, const char *language, int *level) {
- WinResource *wr;
-
- *level = 0;
- if (type == NULL)
- return NULL;
- wr = find_with_resource_array(fi, NULL, type);
- if (wr == NULL || !wr->is_directory)
- return wr;
-
- *level = 1;
- if (name == NULL)
- return wr;
- wr = find_with_resource_array(fi, wr, name);
- if (wr == NULL || !wr->is_directory)
- return wr;
-
- *level = 2;
- if (language == NULL)
- return wr;
- wr = find_with_resource_array(fi, wr, language);
- return wr;
-}
-
-#define ROW_BYTES(bits) ((((bits) + 31) >> 5) << 2)
-
-
-int Win32ResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **pal, int *palSize) {
- Win32CursorIconFileDir dir;
- Win32CursorIconFileDirEntry *entries = NULL;
- uint32 offset;
- uint32 c, d;
- int completed;
- int matched = 0;
- Common::MemoryReadStream *in = new Common::MemoryReadStream(data, datasize);
-
- if (!in->read(&dir, sizeof(Win32CursorIconFileDir)- sizeof(Win32CursorIconFileDirEntry)))
- goto cleanup;
- fix_win32_cursor_icon_file_dir_endian(&dir);
-
- if (dir.reserved != 0) {
- error("not an icon or cursor file (reserved non-zero)");
- goto cleanup;
- }
- if (dir.type != 1 && dir.type != 2) {
- error("not an icon or cursor file (wrong type)");
- goto cleanup;
- }
-
- entries = (Win32CursorIconFileDirEntry *)malloc(dir.count * sizeof(Win32CursorIconFileDirEntry));
- for (c = 0; c < dir.count; c++) {
- if (!in->read(&entries[c], sizeof(Win32CursorIconFileDirEntry)))
- goto cleanup;
- fix_win32_cursor_icon_file_dir_entry_endian(&entries[c]);
- if (entries[c].reserved != 0)
- error("reserved is not zero");
- }
-
- offset = sizeof(Win32CursorIconFileDir) + (dir.count - 1) * (sizeof(Win32CursorIconFileDirEntry));
-
- for (completed = 0; completed < dir.count; ) {
- uint32 min_offset = 0x7fffffff;
- int previous = completed;
-
- for (c = 0; c < dir.count; c++) {
- if (entries[c].dib_offset == offset) {
- Win32BitmapInfoHeader bitmap;
- Win32RGBQuad *palette = NULL;
- uint32 palette_count = 0;
- uint32 image_size, mask_size;
- uint32 width, height;
- byte *image_data = NULL, *mask_data = NULL;
- byte *row = NULL;
-
- if (!in->read(&bitmap, sizeof(Win32BitmapInfoHeader)))
- goto local_cleanup;
-
- fix_win32_bitmap_info_header_endian(&bitmap);
- if (bitmap.size < sizeof(Win32BitmapInfoHeader)) {
- error("bitmap header is too short");
- goto local_cleanup;
- }
- if (bitmap.compression != 0) {
- error("compressed image data not supported");
- goto local_cleanup;
- }
- if (bitmap.x_pels_per_meter != 0)
- error("x_pels_per_meter field in bitmap should be zero");
- if (bitmap.y_pels_per_meter != 0)
- error("y_pels_per_meter field in bitmap should be zero");
- if (bitmap.clr_important != 0)
- error("clr_important field in bitmap should be zero");
- if (bitmap.planes != 1)
- error("planes field in bitmap should be one");
- if (bitmap.size != sizeof(Win32BitmapInfoHeader)) {
- uint32 skip = bitmap.size - sizeof(Win32BitmapInfoHeader);
- error("skipping %d bytes of extended bitmap header", skip);
- in->seek(skip, SEEK_CUR);
- }
- offset += bitmap.size;
-
- if (bitmap.clr_used != 0 || bitmap.bit_count < 24) {
- palette_count = (bitmap.clr_used != 0 ? bitmap.clr_used : 1 << bitmap.bit_count);
- palette = (Win32RGBQuad *)malloc(sizeof(Win32RGBQuad) * palette_count);
- if (!in->read(palette, sizeof(Win32RGBQuad) * palette_count))
- goto local_cleanup;
- offset += sizeof(Win32RGBQuad) * palette_count;
- }
-
- width = bitmap.width;
- height = ABS(bitmap.height)/2;
-
- image_size = height * ROW_BYTES(width * bitmap.bit_count);
- mask_size = height * ROW_BYTES(width);
-
- if (entries[c].dib_size != bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
- debugC(DEBUG_RESOURCE, "incorrect total size of bitmap (%d specified; %d real)",
- entries[c].dib_size,
- (int)(bitmap.size + image_size + mask_size + palette_count * sizeof(Win32RGBQuad))
- );
-
- image_data = (byte *)malloc(image_size);
- if (!in->read(image_data, image_size))
- goto local_cleanup;
-
- mask_data = (byte *)malloc(mask_size);
- if (!in->read(mask_data, mask_size))
- goto local_cleanup;
-
- offset += image_size;
- offset += mask_size;
- completed++;
- matched++;
-
- *hotspot_x = entries[c].hotspot_x;
- *hotspot_y = entries[c].hotspot_y;
- *w = width;
- *h = height;
- *keycolor = 0;
- *cursor = (byte *)malloc(width * height);
-
- row = (byte *)malloc(width * 4);
-
- for (d = 0; d < height; d++) {
- uint32 x;
- uint32 y = (bitmap.height < 0 ? d : height - d - 1);
- uint32 imod = y * (image_size / height) * 8 / bitmap.bit_count;
- uint32 mmod = y * (mask_size / height) * 8;
-
- for (x = 0; x < width; x++) {
-
- uint32 color = simple_vec(image_data, x + imod, bitmap.bit_count);
-
- // We set up cursor palette for default cursor, so use it
- if (!simple_vec(mask_data, x + mmod, 1)) {
- if (color) {
- cursor[0][width * d + x] = 254; // white
- } else {
- cursor[0][width * d + x] = 253; // black
- }
- } else {
- cursor[0][width * d + x] = 255; // transparent
- }
- /*
-
- if (bitmap.bit_count <= 16) {
- if (color >= palette_count) {
- error("color out of range in image data");
- goto local_cleanup;
- }
- row[4*x+0] = palette[color].red;
- row[4*x+1] = palette[color].green;
- row[4*x+2] = palette[color].blue;
-
- } else {
- row[4*x+0] = (color >> 16) & 0xFF;
- row[4*x+1] = (color >> 8) & 0xFF;
- row[4*x+2] = (color >> 0) & 0xFF;
- }
- if (bitmap.bit_count == 32)
- row[4*x+3] = (color >> 24) & 0xFF;
- else
- row[4*x+3] = simple_vec(mask_data, x + mmod, 1) ? 0 : 0xFF;
- */
- }
-
- }
-
- free(row);
- free(palette);
- if (image_data != NULL) {
- free(image_data);
- free(mask_data);
- }
- continue;
-
- local_cleanup:
-
- free(row);
- free(palette);
- if (image_data != NULL) {
- free(image_data);
- free(mask_data);
- }
- goto cleanup;
- } else {
- if (entries[c].dib_offset > offset)
- min_offset = MIN(min_offset, entries[c].dib_offset);
- }
- }
-
- if (previous == completed) {
- if (min_offset < offset) {
- error("offset of bitmap header incorrect (too low)");
- goto cleanup;
- }
- assert(min_offset != 0x7fffffff);
- debugC(DEBUG_RESOURCE, "skipping %d bytes of garbage at %d", min_offset-offset, offset);
- in->seek(min_offset - offset, SEEK_CUR);
- offset = min_offset;
- }
- }
-
- free(entries);
- return matched;
-
-cleanup:
-
- free(entries);
- return -1;
-}
-
-uint32 Win32ResExtractor::simple_vec(byte *data, uint32 ofs, byte size) {
- switch (size) {
- case 1:
- return (data[ofs/8] >> (7 - ofs%8)) & 1;
- case 2:
- return (data[ofs/4] >> ((3 - ofs%4) << 1)) & 3;
- case 4:
- return (data[ofs/2] >> ((1 - ofs%2) << 2)) & 15;
- case 8:
- return data[ofs];
- case 16:
- return data[2*ofs] | data[2*ofs+1] << 8;
- case 24:
- return data[3*ofs] | data[3*ofs+1] << 8 | data[3*ofs+2] << 16;
- case 32:
- return data[4*ofs] | data[4*ofs+1] << 8 | data[4*ofs+2] << 16 | data[4*ofs+3] << 24;
- }
-
- return 0;
-}
-
-void Win32ResExtractor::fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj) {
- LE16(obj->reserved);
- LE16(obj->type);
- LE16(obj->count);
-}
-
-void Win32ResExtractor::fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj) {
- LE32(obj->size);
- LE32(obj->width);
- LE32(obj->height);
- LE16(obj->planes);
- LE16(obj->bit_count);
- LE32(obj->compression);
- LE32(obj->size_image);
- LE32(obj->x_pels_per_meter);
- LE32(obj->y_pels_per_meter);
- LE32(obj->clr_used);
- LE32(obj->clr_important);
-}
-
-void Win32ResExtractor::fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj) {
- LE16(obj->hotspot_x);
- LE16(obj->hotspot_y);
- LE32(obj->dib_size);
- LE32(obj->dib_offset);
-}
-
-void Win32ResExtractor::fix_win32_image_section_header(Win32ImageSectionHeader *obj) {
- LE32(obj->misc.physical_address);
- LE32(obj->virtual_address);
- LE32(obj->size_of_raw_data);
- LE32(obj->pointer_to_raw_data);
- LE32(obj->pointer_to_relocations);
- LE32(obj->pointer_to_linenumbers);
- LE16(obj->number_of_relocations);
- LE16(obj->number_of_linenumbers);
- LE32(obj->characteristics);
-}
-
-/* fix_win32_image_header_endian:
- * NOTE: This assumes that the optional header is always available.
- */
-void Win32ResExtractor::fix_win32_image_header_endian(Win32ImageNTHeaders *obj) {
- LE32(obj->signature);
- LE16(obj->file_header.machine);
- LE16(obj->file_header.number_of_sections);
- LE32(obj->file_header.time_date_stamp);
- LE32(obj->file_header.pointer_to_symbol_table);
- LE32(obj->file_header.number_of_symbols);
- LE16(obj->file_header.size_of_optional_header);
- LE16(obj->file_header.characteristics);
-
- // FIXME: Does this assert ever trigger? If so, we should modify this function
- // to properly deal with it.
- assert(obj->file_header.size_of_optional_header >= sizeof(obj->optional_header));
- LE16(obj->optional_header.magic);
- LE32(obj->optional_header.size_of_code);
- LE32(obj->optional_header.size_of_initialized_data);
- LE32(obj->optional_header.size_of_uninitialized_data);
- LE32(obj->optional_header.address_of_entry_point);
- LE32(obj->optional_header.base_of_code);
- LE32(obj->optional_header.base_of_data);
- LE32(obj->optional_header.image_base);
- LE32(obj->optional_header.section_alignment);
- LE32(obj->optional_header.file_alignment);
- LE16(obj->optional_header.major_operating_system_version);
- LE16(obj->optional_header.minor_operating_system_version);
- LE16(obj->optional_header.major_image_version);
- LE16(obj->optional_header.minor_image_version);
- LE16(obj->optional_header.major_subsystem_version);
- LE16(obj->optional_header.minor_subsystem_version);
- LE32(obj->optional_header.win32_version_value);
- LE32(obj->optional_header.size_of_image);
- LE32(obj->optional_header.size_of_headers);
- LE32(obj->optional_header.checksum);
- LE16(obj->optional_header.subsystem);
- LE16(obj->optional_header.dll_characteristics);
- LE32(obj->optional_header.size_of_stack_reserve);
- LE32(obj->optional_header.size_of_stack_commit);
- LE32(obj->optional_header.size_of_heap_reserve);
- LE32(obj->optional_header.size_of_heap_commit);
- LE32(obj->optional_header.loader_flags);
- LE32(obj->optional_header.number_of_rva_and_sizes);
-}
-
-void Win32ResExtractor::fix_win32_image_data_directory(Win32ImageDataDirectory *obj) {
- LE32(obj->virtual_address);
- LE32(obj->size);
-}
-
-
MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) {
_resMgr = NULL;
}
-int MacResExtractor::extractResource(int id, byte **buf) {
+bool MacResExtractor::extractResource(int id, CachedCursor *cc) {
// Create the MacResManager if not created already
if (_resMgr == NULL) {
_resMgr = new Common::MacResManager();
@@ -1158,25 +167,18 @@ int MacResExtractor::extractResource(int id, byte **buf) {
error("Cannot open file %s", _fileName.c_str());
}
- Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', 1000 + id);
+ Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', id + 1000);
if (!dataStream)
- error("There is no cursor ID #%d", 1000 + id);
-
- uint32 size = dataStream->size();
- *buf = (byte *)malloc(size);
- dataStream->read(*buf, size);
- delete dataStream;
+ return false;
- return size;
-}
+ int keyColor; // HACK: key color is ignored
+ _resMgr->convertCrsrCursor(dataStream, &cc->bitmap, cc->width, cc->height, cc->hotspotX, cc->hotspotY,
+ keyColor, _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette),
+ &cc->palette, cc->palSize);
-int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) {
-
- _resMgr->convertCrsrCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor,
- _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize);
- return 1;
+ delete dataStream;
+ return true;
}
void ScummEngine_v70he::readRoomsOffsets() {
diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h
index 6b4c3fe493..5d7c70db76 100644
--- a/engines/scumm/he/resource_he.h
+++ b/engines/scumm/he/resource_he.h
@@ -4,10 +4,6 @@
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
- * Parts of this code are heavily based on:
- * icoutils - A set of programs dealing with MS Windows icons and cursors.
- * Copyright (C) 1998-2001 Oskar Liljeblad
- *
* 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
@@ -31,89 +27,10 @@
#define SCUMM_HE_RESOURCE_HE_H
#include "common/macresman.h"
+#include "common/winexe_pe.h"
namespace Scumm {
-#define WINRES_ID_MAXLEN (256)
-
-/*
- * Definitions
- */
-
-#define MZ_HEADER(x) ((DOSImageHeader *)(x))
-
-#define STRIP_RES_ID_FORMAT(x) (x != NULL && (x[0] == '-' || x[0] == '+') ? ++x : x)
-
-#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
-#define IMAGE_SIZEOF_SHORT_NAME 8
-
-#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
-#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
-
-#define PE_HEADER(module) \
- ((Win32ImageNTHeaders*)((byte *)(module) + \
- (((DOSImageHeader*)(module))->lfanew)))
-
-#define PE_SECTIONS(module) \
- ((Win32ImageSectionHeader *)((byte *) &PE_HEADER(module)->optional_header + \
- PE_HEADER(module)->file_header.size_of_optional_header))
-
-#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
-#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
-
-/* The following symbols below and another group a few lines below are defined in
- * the windows header, at least in wince and most likely in plain win32 as well.
- * Defining them out silences a redefinition warning in gcc.
- * If the same problem arises in win32 builds as well, please replace
- * _WIN32_WCE with _WIN32 which is also defined in the wince platform.
- */
-#ifndef _WIN32_WCE
-#define IMAGE_SCN_CNT_CODE 0x00000020
-#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
-#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
-#endif
-
-// Only IMAGE_DIRECTORY_ENTRY_RESOURCE is used:
-#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
-#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
-#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
-#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
-#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
-#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
-#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
-#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
-#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */
-#define IMAGE_DIRECTORY_ENTRY_TLS 9
-#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
-#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
-#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */
-#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
-#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
-
-#ifndef _WIN32_WCE
-// Only RT_GROUP_CURSOR and RT_GROUP_ICON are used
-#define RT_CURSOR 1
-#define RT_BITMAP 2
-#define RT_ICON 3
-#define RT_MENU 4
-#define RT_DIALOG 5
-#define RT_STRING 6
-#define RT_FONTDIR 7
-#define RT_FONT 8
-#define RT_ACCELERATOR 9
-#define RT_RCDATA 10
-#define RT_MESSAGELIST 11
-#define RT_GROUP_CURSOR 12
-#define RT_GROUP_ICON 14
-#endif
-
-#define RETURN_IF_BAD_POINTER(r, x) \
- if (!check_offset(fi->memory, fi->total_size, _fileName.c_str(), &(x), sizeof(x))) \
- return (r);
-#define RETURN_IF_BAD_OFFSET(r, x, s) \
- if (!check_offset(fi->memory, fi->total_size, _fileName.c_str(), x, s)) \
- return (r);
-
class ScummEngine_v70he;
class ResExtractor {
@@ -123,312 +40,54 @@ public:
void setCursor(int id);
- virtual int extractResource(int id, byte **buf) { return 0; }
- virtual int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor,
- byte **palette, int *palSize) { return 0; }
-
- enum {
- MAX_CACHED_CURSORS = 10
- };
-
+protected:
struct CachedCursor {
bool valid;
int id;
byte *bitmap;
- int w, h;
- int hotspot_x, hotspot_y;
- uint32 last_used;
+ int width, height;
+ int hotspotX, hotspotY;
+ uint32 lastUsed;
byte *palette;
int palSize;
};
+ Common::String _fileName;
ScummEngine_v70he *_vm;
+ virtual bool extractResource(int id, CachedCursor *cc) = 0;
+
+private:
+ enum {
+ MAX_CACHED_CURSORS = 10
+ };
+
ResExtractor::CachedCursor *findCachedCursor(int id);
ResExtractor::CachedCursor *getCachedCursorSlot();
-
- bool _arg_raw;
- Common::String _fileName;
+
CachedCursor _cursorCache[MAX_CACHED_CURSORS];
};
class Win32ResExtractor : public ResExtractor {
- public:
+public:
Win32ResExtractor(ScummEngine_v70he *scumm);
~Win32ResExtractor() {}
- int extractResource(int id, byte **data);
- void setCursor(int id);
- int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize);
- private:
- int extractResource_(const char *resType, char *resName, byte **data);
-/*
- * Structures
- */
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
- struct WinLibrary {
- Common::SeekableReadStream *file;
- byte *memory;
- byte *first_resource;
- int total_size;
- } PACKED_STRUCT;
-
- struct WinResource {
- char id[256];
- void *this_;
- void *children;
- int level;
- bool numeric_id;
- bool is_directory;
-
- Common::String getQuotedResourceId() const;
- } PACKED_STRUCT;
-
-
- struct Win32IconResDir {
- byte width;
- byte height;
- byte color_count;
- byte reserved;
- } PACKED_STRUCT;
-
- struct Win32CursorDir {
- uint16 width;
- uint16 height;
- } PACKED_STRUCT;
-
- struct Win32CursorIconDirEntry {
- union {
- Win32IconResDir icon;
- Win32CursorDir cursor;
- } res_info;
- uint16 plane_count;
- uint16 bit_count;
- uint32 bytes_in_res;
- uint16 res_id;
- } PACKED_STRUCT;
-
- struct Win32CursorIconDir {
- uint16 reserved;
- uint16 type;
- uint16 count;
- Win32CursorIconDirEntry entries[1];
- } PACKED_STRUCT;
-
- struct Win32CursorIconFileDirEntry {
- byte width;
- byte height;
- byte color_count;
- byte reserved;
- uint16 hotspot_x;
- uint16 hotspot_y;
- uint32 dib_size;
- uint32 dib_offset;
- } PACKED_STRUCT;
-
- struct Win32CursorIconFileDir {
- uint16 reserved;
- uint16 type;
- uint16 count;
- Win32CursorIconFileDirEntry entries[1];
- } PACKED_STRUCT;
-
- struct Win32BitmapInfoHeader {
- uint32 size;
- int32 width;
- int32 height;
- uint16 planes;
- uint16 bit_count;
- uint32 compression;
- uint32 size_image;
- int32 x_pels_per_meter;
- int32 y_pels_per_meter;
- uint32 clr_used;
- uint32 clr_important;
- } PACKED_STRUCT;
-
- struct Win32RGBQuad {
- byte blue;
- byte green;
- byte red;
- byte reserved;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDirectoryEntry {
- uint32 name;
- uint32 offset_to_data;
- } PACKED_STRUCT;
-
- struct Win16NETypeInfo {
- uint16 type_id;
- uint16 count;
- uint32 resloader; // FARPROC16 - smaller? uint16?
- } PACKED_STRUCT;
-
- struct DOSImageHeader {
- uint16 magic;
- uint16 cblp;
- uint16 cp;
- uint16 crlc;
- uint16 cparhdr;
- uint16 minalloc;
- uint16 maxalloc;
- uint16 ss;
- uint16 sp;
- uint16 csum;
- uint16 ip;
- uint16 cs;
- uint16 lfarlc;
- uint16 ovno;
- uint16 res[4];
- uint16 oemid;
- uint16 oeminfo;
- uint16 res2[10];
- uint32 lfanew;
- } PACKED_STRUCT;
-
- struct Win32ImageFileHeader {
- uint16 machine;
- uint16 number_of_sections;
- uint32 time_date_stamp;
- uint32 pointer_to_symbol_table;
- uint32 number_of_symbols;
- uint16 size_of_optional_header;
- uint16 characteristics;
- } PACKED_STRUCT;
-
- struct Win32ImageDataDirectory {
- uint32 virtual_address;
- uint32 size;
- } PACKED_STRUCT;
-
- struct Win32ImageOptionalHeader {
- uint16 magic;
- byte major_linker_version;
- byte minor_linker_version;
- uint32 size_of_code;
- uint32 size_of_initialized_data;
- uint32 size_of_uninitialized_data;
- uint32 address_of_entry_point;
- uint32 base_of_code;
- uint32 base_of_data;
- uint32 image_base;
- uint32 section_alignment;
- uint32 file_alignment;
- uint16 major_operating_system_version;
- uint16 minor_operating_system_version;
- uint16 major_image_version;
- uint16 minor_image_version;
- uint16 major_subsystem_version;
- uint16 minor_subsystem_version;
- uint32 win32_version_value;
- uint32 size_of_image;
- uint32 size_of_headers;
- uint32 checksum;
- uint16 subsystem;
- uint16 dll_characteristics;
- uint32 size_of_stack_reserve;
- uint32 size_of_stack_commit;
- uint32 size_of_heap_reserve;
- uint32 size_of_heap_commit;
- uint32 loader_flags;
- uint32 number_of_rva_and_sizes;
- Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
- } PACKED_STRUCT;
-
- struct Win32ImageNTHeaders {
- uint32 signature;
- Win32ImageFileHeader file_header;
- Win32ImageOptionalHeader optional_header;
- } PACKED_STRUCT;
-
- struct Win32ImageSectionHeader {
- byte name[IMAGE_SIZEOF_SHORT_NAME];
- union {
- uint32 physical_address;
- uint32 virtual_size;
- } misc;
- uint32 virtual_address;
- uint32 size_of_raw_data;
- uint32 pointer_to_raw_data;
- uint32 pointer_to_relocations;
- uint32 pointer_to_linenumbers;
- uint16 number_of_relocations;
- uint16 number_of_linenumbers;
- uint32 characteristics;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDataEntry {
- uint32 offset_to_data;
- uint32 size;
- uint32 code_page;
- uint32 resource_handle;
- } PACKED_STRUCT;
-
- struct Win32ImageResourceDirectory {
- uint32 characteristics;
- uint32 time_date_stamp;
- uint16 major_version;
- uint16 minor_version;
- uint16 number_of_named_entries;
- uint16 number_of_id_entries;
- } PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
-/*
- * Function Prototypes
- */
-
- WinResource *list_resources(WinLibrary *, WinResource *, int *);
- bool read_library(WinLibrary *);
- WinResource *find_resource(WinLibrary *, const char *, const char *, const char *, int *);
- byte *get_resource_entry(WinLibrary *, WinResource *, int *);
- int do_resources(WinLibrary *, const char *, char *, char *, byte **);
- bool compare_resource_id(WinResource *, const char *);
- const char *res_type_string_to_id(const char *);
-
- const char *res_type_id_to_string(int);
- char *get_destination_name(WinLibrary *, char *, char *, char *);
-
- byte *extract_resource(WinLibrary *, WinResource *, int *, bool *, char *, char *, bool);
- int extract_resources(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, byte **);
- byte *extract_group_icon_cursor_resource(WinLibrary *, WinResource *, char *, int *, bool);
-
- bool decode_pe_resource_id(WinLibrary *, WinResource *, uint32);
- WinResource *list_pe_resources(WinLibrary *, Win32ImageResourceDirectory *, int, int *);
- int calc_vma_size(WinLibrary *);
- int do_resources_recurs(WinLibrary *, WinResource *, WinResource *, WinResource *, WinResource *, const char *, char *, char *, byte **);
- WinResource *find_with_resource_array(WinLibrary *, WinResource *, const char *);
-
- bool check_offset(byte *, int, const char *, void *, int);
-
- uint32 simple_vec(byte *data, uint32 ofs, byte size);
+private:
+ Common::PEResources _exe;
- void fix_win32_cursor_icon_file_dir_endian(Win32CursorIconFileDir *obj);
- void fix_win32_bitmap_info_header_endian(Win32BitmapInfoHeader *obj);
- void fix_win32_cursor_icon_file_dir_entry_endian(Win32CursorIconFileDirEntry *obj);
- void fix_win32_image_section_header(Win32ImageSectionHeader *obj);
- void fix_win32_image_header_endian(Win32ImageNTHeaders *obj);
- void fix_win32_image_data_directory(Win32ImageDataDirectory *obj);
+ bool extractResource(int id, CachedCursor *cc);
};
class MacResExtractor : public ResExtractor {
-
public:
MacResExtractor(ScummEngine_v70he *scumm);
- ~MacResExtractor() { }
+ ~MacResExtractor() {}
private:
Common::MacResManager *_resMgr;
- int extractResource(int id, byte **buf);
- int convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
- int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize);
+ bool extractResource(int id, CachedCursor *cc);
};
} // End of namespace Scumm
diff --git a/engines/sword1/mouse.cpp b/engines/sword1/mouse.cpp
index 751b27efc0..87e476e504 100644
--- a/engines/sword1/mouse.cpp
+++ b/engines/sword1/mouse.cpp
@@ -197,6 +197,7 @@ void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
free(_currentPtr);
_currentPtr = NULL;
}
+
if (ptrId) {
MousePtr *lugg = NULL;
MousePtr *ptr = (MousePtr*)_resMan->openFetchRes(ptrId);
@@ -284,6 +285,7 @@ void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
void Mouse::setPointer(uint32 resId, uint32 rate) {
_currentPtrId = resId;
_frame = 0;
+ _activeFrame = -1;
createPointer(resId, _currentLuggageId);
@@ -298,15 +300,24 @@ void Mouse::setPointer(uint32 resId, uint32 rate) {
void Mouse::setLuggage(uint32 resId, uint32 rate) {
_currentLuggageId = resId;
_frame = 0;
+ _activeFrame = -1;
+
createPointer(_currentPtrId, resId);
}
void Mouse::animate() {
if ((Logic::_scriptVars[MOUSE_STATUS] == 1) || (_mouseOverride && _currentPtr)) {
_frame = (_frame + 1) % _currentPtr->numFrames;
+
+ if (_activeFrame == _frame)
+ return;
+
uint8 *ptrData = (uint8*)_currentPtr + sizeof(MousePtr);
ptrData += _frame * _currentPtr->sizeX * _currentPtr->sizeY;
+
CursorMan.replaceCursor(ptrData, _currentPtr->sizeX, _currentPtr->sizeY, _currentPtr->hotSpotX, _currentPtr->hotSpotY, 255);
+
+ _activeFrame = _frame;
}
}
diff --git a/engines/sword1/mouse.h b/engines/sword1/mouse.h
index 50b7431c48..1b4ca12183 100644
--- a/engines/sword1/mouse.h
+++ b/engines/sword1/mouse.h
@@ -99,8 +99,9 @@ private:
ObjectMan *_objMan;
Common::Point _mouse;
- uint32 _currentPtrId, _currentLuggageId, _frame;
+ uint32 _currentPtrId, _currentLuggageId;
MousePtr *_currentPtr;
+ int _frame, _activeFrame;
uint16 _numObjs;
uint16 _lastState, _state;
uint32 _getOff;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 3c506c0dae..8d1a9836f4 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -110,7 +110,7 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI
terminated = !playVideo();
- closeTextObject(_currentMovieText, NULL);
+ closeTextObject(_currentMovieText, NULL, 0);
if (terminated) {
_snd->stopHandle(*_bgSoundHandle);
@@ -165,7 +165,7 @@ void MoviePlayer::openTextObject(uint32 index) {
}
}
-void MoviePlayer::closeTextObject(uint32 index, byte *screen) {
+void MoviePlayer::closeTextObject(uint32 index, byte *screen, uint16 pitch) {
if (index < _numMovieTexts) {
MovieText *text = &_movieTexts[index];
@@ -182,20 +182,21 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen) {
int frameHeight = _decoder->getHeight();
int frameX = (_system->getWidth() - frameWidth) / 2;
int frameY = (_system->getHeight() - frameHeight) / 2;
+ byte black = findBlackPalIndex();
- byte *dst = screen + _textY * _system->getWidth();
+ byte *dst = screen + _textY * pitch;
for (int y = 0; y < text->_textSprite.h; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, findBlackPalIndex(), text->_textSprite.w);
+ memset(dst + _textX, black, text->_textSprite.w);
} else {
if (frameX > _textX)
- memset(dst + _textX, findBlackPalIndex(), frameX - _textX);
+ memset(dst + _textX, black, frameX - _textX);
if (frameX + frameWidth < _textX + text->_textSprite.w)
- memset(dst + frameX + frameWidth, findBlackPalIndex(), _textX + text->_textSprite.w - (frameX + frameWidth));
+ memset(dst + frameX + frameWidth, black, _textX + text->_textSprite.w - (frameX + frameWidth));
}
- dst += _system->getWidth();
+ dst += pitch;
}
}
@@ -205,7 +206,7 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen) {
}
}
-void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
+void MoviePlayer::drawTextObject(uint32 index, byte *screen, uint16 pitch) {
MovieText *text = &_movieTexts[index];
byte white = findWhitePalIndex();
@@ -217,14 +218,15 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
uint16 height = text->_textSprite.h;
// Resize text sprites for PSX version
+ byte *psxSpriteBuffer = 0;
if (Sword2Engine::isPsx()) {
height *= 2;
- byte *buffer = (byte *)malloc(width * height);
- Screen::resizePsxSprite(buffer, src, width, height);
- src = buffer;
+ psxSpriteBuffer = (byte *)malloc(width * height);
+ Screen::resizePsxSprite(psxSpriteBuffer, src, width, height);
+ src = psxSpriteBuffer;
}
- byte *dst = screen + _textY * RENDERWIDE + _textX;
+ byte *dst = screen + _textY * pitch + _textX;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
@@ -234,12 +236,16 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
dst[x] = white;
}
src += width;
- dst += RENDERWIDE;
+ dst += pitch;
}
+
+ // Free buffer used to resize psx sprite
+ if (Sword2Engine::isPsx())
+ free(psxSpriteBuffer);
}
}
-void MoviePlayer::performPostProcessing(byte *screen) {
+void MoviePlayer::performPostProcessing(byte *screen, uint16 pitch) {
MovieText *text;
int frame = _decoder->getCurFrame();
@@ -261,9 +267,9 @@ void MoviePlayer::performPostProcessing(byte *screen) {
_vm->_sound->playCompSpeech(text->_speechId, 16, 0);
}
if (frame < text->_endFrame) {
- drawTextObject(_currentMovieText, screen);
+ drawTextObject(_currentMovieText, screen, pitch);
} else {
- closeTextObject(_currentMovieText, screen);
+ closeTextObject(_currentMovieText, screen, pitch);
_currentMovieText++;
}
}
@@ -313,7 +319,7 @@ bool MoviePlayer::playVideo() {
}
Graphics::Surface *screen = _vm->_system->lockScreen();
- performPostProcessing((byte *)screen->pixels);
+ performPostProcessing((byte *)screen->pixels, screen->pitch);
_vm->_system->unlockScreen();
_vm->_system->updateScreen();
}
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 550ac0fac4..afe7dfcc68 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -96,12 +96,12 @@ protected:
uint32 _leadOut;
int _leadOutFrame;
- void performPostProcessing(byte *screen);
+ void performPostProcessing(byte *screen, uint16 pitch);
bool playVideo();
void openTextObject(uint32 index);
- void closeTextObject(uint32 index, byte *screen);
- void drawTextObject(uint32 index, byte *screen);
+ void closeTextObject(uint32 index, byte *screen, uint16 pitch);
+ void drawTextObject(uint32 index, byte *screen, uint16 pitch);
byte findBlackPalIndex();
byte findWhitePalIndex();
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index a0e2754fe4..3cdff5f432 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -229,16 +229,16 @@ void rotatePalette(byte *palette, int size) {
// Rotate the colors starting from address palette "size" times
// take a temporary palette color
- byte tColor[4] = {0};
+ byte tColor[3] = {0};
// save first color in it.
- memcpy(tColor, &palette[0], 4 * sizeof(byte));
+ memcpy(tColor, &palette[0], 3 * sizeof(byte));
// Move each color upward by 1
for (int i = 0; i < size - 1; i++) {
- memcpy(&palette[i * 4], &palette[(i + 1) * 4], 4 * sizeof(byte));
+ memcpy(&palette[i * 3], &palette[(i + 1) * 3], 3 * sizeof(byte));
}
// Assign last color to tcolor
- memcpy(&palette[(size - 1) * 4], tColor, 4 * sizeof(byte));
+ memcpy(&palette[(size - 1) * 3], tColor, 3 * sizeof(byte));
}
/**
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 29d4dbc92d..7461cfca72 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -115,26 +115,6 @@ static const int enhancedAudioSCNVersion[] = {
97, 98, 99, 99 // 151-154
};
-// TODO. This mapping is wrong
-static const int enhancedAudioSCNVersionALT[] = {
- 301, 302, 2, 1, 1, 301, 302, 3, 3, 4, // 1-10
- 4, 5, 6, 1, 7, 8, 9, 10, 8, 11, // 11-20
- 11, 12, 13, 13, 13, 13, 13, 14, 13, 13, // 21-30
- 15, 16, 17, 15, 18, 19, 20, 338, 21, 21, // 31-40
- 341, 342, 22, 22, 23, 24, 25, 26, 27, 28, // 41-50
- 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, // 51-60
- 38, 39, 39, 39, 39, 40, 39, 41, 41, 42, // 61-70
- 43, 42, 44, 45, 41, 46, 48, 47, 48, 49, // 71-80
- 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, // 81-90
- 60, 61, 62, 63, 61, 64, 65, 66, 67, 68, // 91-100
- 69, 70, 68, 71, 72, 73, 74, 75, 12, 76, // 101-110
- 77, 78, 79, 80, 4, 4, 82, 83, 77, 4, // 111-120
- 84, 85, 86, 3124, 88, 89, 90, 88, 2, 2, // 121-130
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 131-140
- 3142, 91, 92, 93, 94, 94, 95, 96, 52, 4, // 141-150
- 97, 98, 99 // 151-153
-};
-
int GetTrackNumber(SCNHANDLE hMidi) {
for (int i = 0; i < ARRAYSIZE(midiOffsets); i++)
if (midiOffsets[i] == hMidi)
@@ -179,11 +159,13 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
// Support for external music from the music enhancement project
if (_vm->getFeatures() & GF_ENHANCED_AUDIO_SUPPORT) {
int trackNumber = GetTrackNumber(dwFileOffset);
+ // Track 8 has been removed in the German CD re-release "Neon Edition"
+ if ((_vm->getFeatures() & GF_ALT_MIDI) && trackNumber >= 8)
+ trackNumber++;
+
int track = 0;
if (trackNumber >= 0) {
- if (_vm->getFeatures() & GF_ALT_MIDI)
- track = enhancedAudioSCNVersionALT[trackNumber];
- else if (_vm->getFeatures() & GF_SCNFILES)
+ if (_vm->getFeatures() & GF_SCNFILES)
track = enhancedAudioSCNVersion[trackNumber];
else
track = enhancedAudioGRAVersion[trackNumber];
diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp
index 2e63d89f37..6004aacead 100644
--- a/engines/toon/anim.cpp
+++ b/engines/toon/anim.cpp
@@ -99,7 +99,7 @@ bool Animation::loadAnimation(Common::String file) {
_frames[e]._data = new uint8[decompressedSize];
if (compressedSize < decompressedSize) {
decompressLZSS(imageData, _frames[e]._data, decompressedSize);
- } else {
+ } else {
memcpy(_frames[e]._data, imageData, compressedSize);
}
}
@@ -151,6 +151,8 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int
int32 offsX = 0;
int32 offsY = 0;
+ _vm->addDirtyRect(xx + _x1 + _frames[frame]._x1, yy + _y1 + _frames[frame]._y1, xx + rectX + _x1 + _frames[frame]._x1 , yy + rectY + _y1 + _frames[frame]._y1);
+
if (xx + _x1 + _frames[frame]._x1 < 0) {
offsX = -(xx + _x1 + _frames[frame]._x1);
}
@@ -212,14 +214,14 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram
int32 finalWidth = rectX * scale / 1024;
int32 finalHeight = rectY * scale / 1024;
- // compute final x1,y1,x2,y2
+ // compute final x1, y1, x2, y2
int32 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024;
int32 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024;
int32 xx2 = xx1 + finalWidth;
int32 yy2 = yy1 + finalHeight;
int32 w = _frames[frame]._x2 - _frames[frame]._x1;
-// Strangerke - Commented (not used)
-// int32 h = _frames[frame]._y2 - _frames[frame]._y1;
+
+ _vm->addDirtyRect(xx1, yy1, xx2, yy2);
int32 destPitch = surface.pitch;
int32 destPitchMask = mask->getWidth();
@@ -442,7 +444,6 @@ AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type)
_layerZ = 0;
}
-
void AnimationInstance::render() {
debugC(5, kDebugAnim, "render()");
if (_visible && _animation) {
@@ -574,7 +575,7 @@ void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) cons
int32 finalWidth = rectX * _scale / 1024;
int32 finalHeight = rectY * _scale / 1024;
- // compute final x1,y1,x2,y2
+ // compute final x1, y1, x2, y2
*x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024;
*y1 = _y + _animation->_y1 + _animation->_frames[_currentFrame]._y1 * _scale / 1024;
*x2 = *x1 + finalWidth;
@@ -604,7 +605,7 @@ void AnimationInstance::setZ(int32 z, bool relative) {
void AnimationInstance::setLayerZ(int32 z) {
_layerZ = z;
- if (_vm->getAnimationManager()->hasInstance(this))
+ if (_vm->getAnimationManager()->hasInstance(this))
_vm->getAnimationManager()->updateInstance(this);
}
@@ -665,8 +666,6 @@ void AnimationInstance::load(Common::ReadStream *stream) {
_useMask = stream->readSint32LE();
}
-
-
void AnimationInstance::setLooping(bool enable) {
debugC(6, kDebugAnim, "setLooping(%d)", (enable) ? 1 : 0);
_looping = enable;
@@ -682,7 +681,7 @@ AnimationManager::AnimationManager(ToonEngine *vm) : _vm(vm) {
bool AnimationManager::hasInstance(AnimationInstance* instance) {
for (uint32 i = 0; i < _instances.size(); i++) {
- if(_instances[i] == instance)
+ if(_instances[i] == instance)
return true;
}
return false;
@@ -698,12 +697,12 @@ void AnimationManager::addInstance(AnimationInstance *instance) {
// if the instance already exists, we skip the add
for (uint32 i = 0; i < _instances.size(); i++) {
- if(_instances[i] == instance)
+ if(_instances[i] == instance)
return;
}
-
+
int found = -1;
-
+
// here we now do an ordered insert (closer to the original game)
for (uint32 i = 0; i < _instances.size(); i++) {
if (_instances[i]->getLayerZ() >= instance->getLayerZ()) {
@@ -717,7 +716,6 @@ void AnimationManager::addInstance(AnimationInstance *instance) {
} else {
_instances.insert_at(found, instance);
}
-
}
void AnimationManager::removeInstance(AnimationInstance *instance) {
diff --git a/engines/toon/anim.h b/engines/toon/anim.h
index d7f64ab687..dfb6842b0e 100644
--- a/engines/toon/anim.h
+++ b/engines/toon/anim.h
@@ -161,7 +161,7 @@ public:
AnimationInstance *createNewInstance(AnimationInstanceType type);
void addInstance(AnimationInstance *instance);
void removeInstance(AnimationInstance *instance);
- void updateInstance(AnimationInstance* instance);
+ void updateInstance(AnimationInstance* instance);
void removeAllInstances(AnimationInstanceType type);
void render();
void update(int32 timeIncrement);
diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp
index e5e5b85832..d76a63c1ae 100644
--- a/engines/toon/audio.cpp
+++ b/engines/toon/audio.cpp
@@ -48,7 +48,7 @@ AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixe
for (int32 i = 0; i < 16; i++)
_channels[i] = NULL;
- for (int32 i = 0; i < 4; i++)
+ for (int32 i = 0; i < 4; i++)
_audioPacks[i] = NULL;
for (int32 i = 0; i < 4; i++) {
@@ -63,6 +63,8 @@ AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixe
_voiceMuted = false;
_musicMuted = false;
_sfxMuted = false;
+
+ _currentMusicChannel = 0;
}
AudioManager::~AudioManager(void) {
@@ -113,24 +115,23 @@ void AudioManager::playMusic(Common::String dir, Common::String music) {
return;
// see what channel to take
- if (_channels[0] && _channels[0]->isPlaying() && _channels[1] && _channels[1]->isPlaying()) {
- // take the one that is fading
- if (_channels[0]->isFading()) {
- _channels[0]->stop(false);
- _channels[1]->stop(true);
- _currentMusicChannel = 0;
- } else {
- _channels[1]->stop(false);
- _channels[0]->stop(true);
- _currentMusicChannel = 1;
+ // if the current channel didn't really start. reuse this one
+ if (_channels[_currentMusicChannel] && _channels[_currentMusicChannel]->isPlaying()) {
+ if (_channels[_currentMusicChannel]->getPlayedSampleCount() < 500) {
+ _channels[_currentMusicChannel]->stop(false);
+ _currentMusicChannel = 1 - _currentMusicChannel;
+ }
+ else
+ {
+ _channels[_currentMusicChannel]->stop(true);
}
- } else if (_channels[0] && _channels[0]->isPlaying()) {
- _channels[0]->stop(true);
- _currentMusicChannel = 1;
- } else {
- if (_channels[1] && _channels[1]->isPlaying())
- _channels[1]->stop(true);
- _currentMusicChannel = 0;
+ }
+ // go to the next channel
+ _currentMusicChannel = 1 - _currentMusicChannel;
+
+ // if it's already playing.. stop it quickly (no fade)
+ if (_channels[_currentMusicChannel] && _channels[_currentMusicChannel]->isPlaying()) {
+ _channels[_currentMusicChannel]->stop(false);
}
// no need to delete instance here it will automatically deleted by the mixer is done with it
@@ -208,7 +209,6 @@ void AudioManager::stopCurrentVoice() {
_channels[2]->stop(false);
}
-
void AudioManager::closeAudioPack(int32 id) {
delete _audioPacks[id];
_audioPacks[id] = NULL;
@@ -261,6 +261,7 @@ AudioStreamInstance::AudioStreamInstance(AudioManager *man, Audio::Mixer *mixer,
_looping = looping;
_musicAttenuation = 1000;
_deleteFileStream = deleteFileStreamAtEnd;
+ _playedSamples = 0;
// preload one packet
if (_totalSize > 0) {
@@ -286,7 +287,7 @@ AudioStreamInstance::~AudioStreamInstance() {
int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) {
debugC(5, kDebugAudio, "readBuffer(buffer, %d)", numSamples);
- if(_stopped)
+ if(_stopped)
return 0;
handleFade(numSamples);
@@ -309,6 +310,8 @@ int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) {
_bufferOffset += leftSamples;
}
+ _playedSamples += numSamples;
+
return numSamples;
}
@@ -423,7 +426,7 @@ void AudioStreamInstance::handleFade(int32 numSamples) {
debugC(5, kDebugAudio, "handleFade(%d)", numSamples);
// Fading enabled only for music
- if (_soundType != Audio::Mixer::kMusicSoundType)
+ if (_soundType != Audio::Mixer::kMusicSoundType)
return;
int32 finalVolume = _volume;
@@ -457,7 +460,7 @@ void AudioStreamInstance::handleFade(int32 numSamples) {
_musicAttenuation = 250;
} else {
_musicAttenuation += numSamples >> 5;
- if (_musicAttenuation > 1000)
+ if (_musicAttenuation > 1000)
_musicAttenuation = 1000;
}
@@ -468,9 +471,11 @@ void AudioStreamInstance::stop(bool fade /*= false*/) {
debugC(1, kDebugAudio, "stop(%d)", (fade) ? 1 : 0);
if (fade) {
- _fadingIn = false;
- _fadingOut = true;
- _fadeTime = 0;
+ if (!_fadingOut) {
+ _fadingIn = false;
+ _fadingOut = true;
+ _fadeTime = 0;
+ }
} else {
stopNow();
}
@@ -551,7 +556,7 @@ void AudioManager::startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volu
}
}
- if (found < 0)
+ if (found < 0)
return;
_ambientSFXs[found]._lastTimer = _vm->getOldMilli() - 1;
@@ -610,13 +615,14 @@ void AudioManager::killAllAmbientSFX()
void AudioManager::updateAmbientSFX()
{
- if (_vm->getMoviePlayer()->isPlaying()) return;
+ if (_vm->getMoviePlayer()->isPlaying())
+ return;
for (int32 i = 0; i < 4; i++) {
AudioAmbientSFX* ambient = &_ambientSFXs[i];
if (ambient->_enabled && (ambient->_channel < 0 || !(_channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()))) {
if(ambient->_mode == 1) {
- if (_vm->randRange(0, 32767) < ambient->_delay) {
+ if (_vm->randRange(0, 32767) < ambient->_delay) {
ambient->_channel = playSFX(ambient->_id, ambient->_volume, false);
}
} else {
@@ -629,6 +635,5 @@ void AudioManager::updateAmbientSFX()
}
}
-
} // End of namespace Toon
diff --git a/engines/toon/audio.h b/engines/toon/audio.h
index 7c1eedfee9..5feae9c5a1 100644
--- a/engines/toon/audio.h
+++ b/engines/toon/audio.h
@@ -52,6 +52,10 @@ public:
return _fadingIn || _fadingOut;
}
+ int32 getPlayedSampleCount() {
+ return _playedSamples;
+ }
+
void setVolume(int32 volume);
protected:
int readBuffer(int16 *buffer, const int numSamples);
@@ -93,6 +97,7 @@ protected:
int32 _volume;
int32 _musicAttenuation;
bool _deleteFileStream;
+ int32 _playedSamples;
};
class AudioStreamPackage {
@@ -133,14 +138,14 @@ public:
void playVoice(int32 id, bool genericVoice);
int32 playSFX(int32 id, int volume, bool genericSFX);
void stopCurrentVoice();
- void stopAllSfxs();
+ void stopAllSfxs();
void setMusicVolume(int32 volume);
void stopMusic();
void muteVoice(bool mute);
void muteMusic(bool mute);
void muteSfx(bool mute);
bool isVoiceMuted() { return _voiceMuted; }
- bool isMusicMuted() { return _musicMuted; }
+ bool isMusicMuted() { return _musicMuted; }
bool isSfxMuted() { return _sfxMuted; }
void startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume);
diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp
index f1f246e549..a1bd3334c5 100644
--- a/engines/toon/character.cpp
+++ b/engines/toon/character.cpp
@@ -104,7 +104,7 @@ void Character::setFacing(int32 facing) {
_lastWalkTime = _vm->getSystem()->getMillis();
if ((_facing - facing + 8) % 8 > (facing - _facing + 8) % 8)
dir = 1;
- else
+ else
dir = -1;
while (_facing != facing) {
@@ -125,14 +125,13 @@ void Character::setFacing(int32 facing) {
if (_currentPathNode == 0)
playStandingAnim();
else
- playWalkAnim(0,0);
+ playWalkAnim(0, 0);
_vm->doFrame();
};
_flags &= ~2;
}
-
_facing = facing;
}
@@ -140,7 +139,7 @@ void Character::forcePosition(int32 x, int32 y) {
debugC(5, kDebugCharacter, "forcePosition(%d, %d)", x, y);
- setPosition(x,y);
+ setPosition(x, y);
_finalX = x;
_finalY = y;
}
@@ -176,7 +175,6 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) {
if (_x == _finalX && _y == _finalY)
return true;
-
if (_vm->getPathFinding()->findPath(_x, _y, _finalX, _finalY)) {
int32 localFinalX = _finalX;
@@ -191,7 +189,7 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) {
_currentPathNodeCount = _vm->getPathFinding()->getPathNodeCount();
_currentPathNode = 0;
stopSpecialAnim();
-
+
_lastWalkTime = _vm->getSystem()->getMillis();
_numPixelToWalk = 0;
@@ -327,11 +325,6 @@ void Character::updateTimers(int32 relativeAdd) {
void Character::stopSpecialAnim() {
debugC(4, kDebugCharacter, "stopSpecialAnim()");
-// Strangerke - Commented (not used)
-#if 0
- if (_animSpecialId != _animSpecialDefaultId)
- delete anim;
-#endif
if (_animScriptId != -1)
_vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = false;
@@ -388,7 +381,6 @@ void Character::update(int32 timeIncrement) {
if ((_flags & 4) == 0)
return;
-
if (_animScriptId != -1) {
_animationInstance = _vm->getSceneAnimation(this->)
#endif
@@ -423,19 +415,9 @@ void Character::update(int32 timeIncrement) {
return;
}
-// Strangerke - Commented (not used)
-#if 0
- if (_animFlags & 8) {
- if (anim->_flags7 == 0xff && anim->_flags9 == 0xff) {
- // start voice
- }
- }
-#endif
-
if (_animScriptId != -1)
_vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
-
-
+
// TODO setup backup //
_animFlags |= 0x10;
@@ -494,17 +476,6 @@ void Character::update(int32 timeIncrement) {
}
} else {
nextFrame = currentFrame + 1;
-// Strangerke - Commented (not used)
-#if 0
- if (!_vm->getAudioManager()->voiceStillPlaying()) {
- if (_animFlags & 8) {
- if ((anim->_flags9 == 0xff && nextFrame == anim->_flags6) ||
- (anim->_flags9 != 0xff && nextFrame >= anim->_flags9)) {
- // start really talking
- }
- }
- }
-#endif
if (nextFrame == anim->_flags7 + 1 && (_animFlags & 0x40) == 0) {
if (anim->_flags8 != 1 && (_vm->randRange(0, 1) || anim->_flags8 == 2)) {
_animFlags |= 0x20;
@@ -525,7 +496,6 @@ void Character::update(int32 timeIncrement) {
//label78
-
#if 0
if (_id == 0)
debug(" drew animation name %s / flag %d / frame %d", _specialAnim->_name, _animFlags, nextFrame);
@@ -611,7 +581,6 @@ int32 Character::getScale() {
}
void Character::playWalkAnim(int32 startFrame, int32 endFrame) {
-
}
void Character::setId(int32 id) {
@@ -677,7 +646,6 @@ int32 Character::getAnimScript() {
}
void Character::playTalkAnim() {
-
}
void Character::stopWalk() {
@@ -1046,7 +1014,6 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) {
*strchr(animName, '?') = '0' + facing;
strcat(animName, ".CAF");
-
if (_animScriptId != -1 && (flags & 8) == 0)
_vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
@@ -1068,11 +1035,9 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) {
}
}
-
if (_sceneAnimationId > -1)
setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance);
-
_animFlags |= flags;
delete _specialAnim;
diff --git a/engines/toon/character.h b/engines/toon/character.h
index d4079d82ef..e870d81813 100644
--- a/engines/toon/character.h
+++ b/engines/toon/character.h
@@ -49,7 +49,6 @@ struct SpecialCharacterAnimation {
byte _flags9; // 25
};
-
class Character {
public:
Character(ToonEngine *vm);
@@ -106,7 +105,6 @@ public:
int32 getFacingFromDirection(int32 dx, int32 dy);
static const SpecialCharacterAnimation *getSpecialAnimation(int32 characterId, int32 animationId);
-
protected:
ToonEngine *_vm;
diff --git a/engines/toon/conversation.cpp b/engines/toon/conversation.cpp
index 4678ccc1c8..fc846288ef 100644
--- a/engines/toon/conversation.cpp
+++ b/engines/toon/conversation.cpp
@@ -45,5 +45,4 @@ void Conversation::load(Common::ReadStream *stream, int16 *conversationDataBase)
}
}
-
}
diff --git a/engines/toon/conversation.h b/engines/toon/conversation.h
index 784c681055..0380210e02 100644
--- a/engines/toon/conversation.h
+++ b/engines/toon/conversation.h
@@ -33,10 +33,10 @@ namespace Toon {
class Conversation {
public:
- int32 _enable; // 00
+ int32 _enable; // 00
struct ConvState {
- int32 _data2; // 04
+ int32 _data2; // 04
int16 _data3; // 08
void *_data4; // 10
} state[10];
diff --git a/engines/toon/drew.cpp b/engines/toon/drew.cpp
index eefb4b8efa..4f8152833b 100644
--- a/engines/toon/drew.cpp
+++ b/engines/toon/drew.cpp
@@ -111,11 +111,10 @@ void CharacterDrew::update(int32 timeIncrement) {
_scale = _currentScale;
} else if (_currentScale < _scale) {
_scale -= timeIncrement * 2;
- if (_scale < _currentScale)
+ if (_scale < _currentScale)
_scale = _currentScale;
}
setPosition(_x, _y);
-
}
int32 CharacterDrew::getRandomIdleAnim() {
diff --git a/engines/toon/drew.h b/engines/toon/drew.h
index d8091f2225..f248e4aa51 100644
--- a/engines/toon/drew.h
+++ b/engines/toon/drew.h
@@ -28,7 +28,6 @@
#include "toon/character.h"
-
namespace Toon {
class ToonEngine;
@@ -46,7 +45,6 @@ public:
int32 getRandomIdleAnim();
protected:
int32 _currentScale;
-
};
} // End of namespace Toon
diff --git a/engines/toon/flux.cpp b/engines/toon/flux.cpp
index 2b5551732b..034332af56 100644
--- a/engines/toon/flux.cpp
+++ b/engines/toon/flux.cpp
@@ -96,7 +96,7 @@ int32 CharacterFlux::fixFacingForAnimation(int32 originalFacing, int32 animation
if (!facingMask)
break;
}
-
+
return finalFacing;
}
diff --git a/engines/toon/flux.h b/engines/toon/flux.h
index a90853cb02..136dedd415 100644
--- a/engines/toon/flux.h
+++ b/engines/toon/flux.h
@@ -26,7 +26,6 @@
#ifndef TOON_FLUX_H
#define TOON_FLUX_H
-
#include "toon/character.h"
class ToonEngine;
diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp
index 8455ca7b61..8192a6f6f1 100644
--- a/engines/toon/font.cpp
+++ b/engines/toon/font.cpp
@@ -81,6 +81,8 @@ void FontRenderer::renderText(int32 x, int32 y, Common::String origText, int32 m
x -= xx / 2;
}
+ _vm->addDirtyRect(x, y, x + xx, y + yy);
+
int32 curX = x;
int32 curY = y;
int32 height = 0;
@@ -263,8 +265,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText
if (x - 30 - maxWidth / 2 < 0)
x = maxWidth / 2 + 30;
- if (x + 30 + (maxWidth / 2) > 640)
- x = 640 - (maxWidth / 2) - 30;
+ if (x + 30 + (maxWidth / 2) > TOON_SCREEN_WIDTH)
+ x = TOON_SCREEN_WIDTH - (maxWidth / 2) - 30;
// we have good coordinates now, we can render the multi line
int32 curX = x;
@@ -273,6 +275,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText
for (int32 i = 0; i < numLines; i++) {
const byte *line = lines[i];
curX = x - lineSize[i] / 2;
+ _vm->addDirtyRect(curX + _vm->state()->_currentScrollValue, y, curX + lineSize[i] + _vm->state()->_currentScrollValue, curY + height);
+
while (*line) {
byte curChar = textToFont(*line);
if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor);
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
index 687ea6ee83..df55eadd05 100644
--- a/engines/toon/hotspot.cpp
+++ b/engines/toon/hotspot.cpp
@@ -78,8 +78,6 @@ int32 Hotspots::Find(int32 x, int32 y) {
debugC(6, kDebugHotspot, "Find(%d, %d)", x, y);
int32 priority = -1;
-// Strangerke - Commented (not used)
-// bool found = false;
int32 foundId = -1;
int32 testId = -1;
@@ -91,8 +89,6 @@ int32 Hotspots::Find(int32 x, int32 y) {
testId = i;
if (_items[testId].getPriority() > priority) {
-// Strangerke - Commented (not used)
-// found = true;
foundId = testId;
priority = _items[testId].getPriority();
}
diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp
index c6b57d96e2..4305abb62b 100644
--- a/engines/toon/movie.cpp
+++ b/engines/toon/movie.cpp
@@ -38,8 +38,8 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui
Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize);
}
-bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename, int forcedflags) {
- debugC(1, kDebugMovie, "loadFile(%s, %d)", filename.c_str(), forcedflags);
+bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) {
+ debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str());
_lowRes = false;
@@ -56,8 +56,6 @@ bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename, int forc
return true;
}
-
-
return false;
}
@@ -88,7 +86,7 @@ void Movie::play(Common::String video, int32 flags) {
_playing = true;
if (flags & 1)
_vm->getAudioManager()->setMusicVolume(0);
- _decoder->loadFile(video.c_str(), flags);
+ _decoder->loadFile(video.c_str());
playVideo(isFirstIntroVideo);
_vm->flushPalette(false);
if (flags & 1)
@@ -107,9 +105,9 @@ bool Movie::playVideo(bool isFirstIntroVideo) {
if (_decoder->isLowRes()) {
// handle manually 2x scaling here
Graphics::Surface* surf = _vm->getSystem()->lockScreen();
- for (int y = 0; y < frame->h/2; y++) {
- memcpy(surf->getBasePtr(0, y*2+0), frame->getBasePtr(0, y), frame->pitch);
- memcpy(surf->getBasePtr(0, y*2+1), frame->getBasePtr(0, y), frame->pitch);
+ for (int y = 0; y < frame->h / 2; y++) {
+ memcpy(surf->getBasePtr(0, y * 2 + 0), frame->getBasePtr(0, y), frame->pitch);
+ memcpy(surf->getBasePtr(0, y * 2 + 1), frame->getBasePtr(0, y), frame->pitch);
}
_vm->getSystem()->unlockScreen();
} else {
@@ -135,11 +133,13 @@ bool Movie::playVideo(bool isFirstIntroVideo) {
Common::Event event;
while (_vm->getSystem()->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
+ _vm->dirtyAllScreen();
return false;
}
_vm->getSystem()->delayMillis(10);
}
+ _vm->dirtyAllScreen();
return !_vm->shouldQuit();
}
diff --git a/engines/toon/movie.h b/engines/toon/movie.h
index 2a9173850f..bed2ceceae 100644
--- a/engines/toon/movie.h
+++ b/engines/toon/movie.h
@@ -36,7 +36,7 @@ public:
ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
virtual ~ToonstruckSmackerDecoder() {}
void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize);
- bool loadFile(const Common::String &filename, int forcedflags);
+ bool loadFile(const Common::String &filename);
bool isLowRes() { return _lowRes; }
protected:
bool _lowRes;
diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp
index 3f948679f4..e0cdf87502 100644
--- a/engines/toon/path.cpp
+++ b/engines/toon/path.cpp
@@ -186,7 +186,7 @@ int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32
for (int y = 0; y < _height; y++) {
for (int x = 0; x < _width; x++) {
- if (isWalkable(x, y) && isLikelyWalkable(x,y)) {
+ if (isWalkable(x, y) && isLikelyWalkable(x, y)) {
int32 ndist = (x - xx) * (x - xx) + (y - yy) * (y - yy);
int32 ndist2 = (x - origX) * (x - origX) + (y - origY) * (y - origY);
if (currentFound < 0 || ndist < dist || (ndist == dist && ndist2 < dist2)) {
@@ -283,8 +283,8 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
}
// first test direct line
- if (lineIsWalkable(x,y,destx,desty)) {
- walkLine(x,y,destx,desty);
+ if (lineIsWalkable(x, y, destx, desty)) {
+ walkLine(x, y, destx, desty);
return true;
}
@@ -317,7 +317,7 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
int32 curPNode = px + py * _width;
if (isWalkable(px, py)) { // walkable ?
- int sum = sq[curNode] + wei * (1 + (isLikelyWalkable(px,py) ? 5 : 0));
+ int sum = sq[curNode] + wei * (1 + (isLikelyWalkable(px, py) ? 5 : 0));
if (sq[curPNode] > sum || !sq[curPNode]) {
int newWeight = abs(destx - px) + abs(desty - py);
sq[curPNode] = sum;
@@ -438,7 +438,6 @@ void PathFinding::addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h) {
_numBlockingRects++;
}
-
int32 PathFinding::getPathNodeCount() const {
return _gridPathCount;
}
diff --git a/engines/toon/path.h b/engines/toon/path.h
index a2b1b7bf92..03d2b188e5 100644
--- a/engines/toon/path.h
+++ b/engines/toon/path.h
@@ -91,7 +91,6 @@ protected:
int32 _gridPathCount;
ToonEngine *_vm;
-
};
} // End of namespace Toon
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
index 18e6a8cf7f..b0932bd32a 100644
--- a/engines/toon/picture.cpp
+++ b/engines/toon/picture.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "toon/picture.h"
#include "toon/tools.h"
#include "common/stack.h"
@@ -32,7 +31,7 @@ namespace Toon {
bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
debugC(1, kDebugPicture, "loadPicture(%s, %d)", file.c_str(), (totalPalette) ? 1 : 0);
-
+
uint32 size = 0;
uint8 *fileData = _vm->resources()->getFileData(file, &size);
if (!fileData)
@@ -49,12 +48,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
decompressLZSS(fileData + 8, _data, dstsize);
// size can only be 640x400 or 1280x400
- if (dstsize > 640 * 400 + 768)
- _width = 1280;
+ if (dstsize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768)
+ _width = TOON_BACKBUFFER_WIDTH;
else
- _width = 640;
+ _width = TOON_SCREEN_WIDTH;
- _height = 400;
+ _height = TOON_SCREEN_HEIGHT;
// do we have a palette ?
_paletteEntries = (dstsize & 0x7ff) / 3;
@@ -69,7 +68,7 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
}
case kCompSPCN: {
uint32 decSize = READ_LE_UINT32(fileData + 10);
- _data = new uint8[decSize+100];
+ _data = new uint8[decSize + 100];
_paletteEntries = READ_LE_UINT16(fileData + 14) / 3;
if (_paletteEntries) {
@@ -79,12 +78,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
}
// size can only be 640x400 or 1280x400
- if (decSize > 640 * 400 + 768)
- _width = 1280;
+ if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768)
+ _width = TOON_BACKBUFFER_WIDTH;
else
- _width = 640;
+ _width = TOON_SCREEN_WIDTH;
- _height = 400;
+ _height = TOON_SCREEN_HEIGHT;
// decompress the picture into our buffer
decompressSPCN(fileData + 16 + _paletteEntries * 3, _data, decSize);
@@ -101,12 +100,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
rnc.unpackM1(fileData, _data);
// size can only be 640x400 or 1280x400
- if (decSize > 640 * 400 + 768)
- _width = 1280;
+ if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768)
+ _width = TOON_BACKBUFFER_WIDTH;
else
- _width = 640;
+ _width = TOON_SCREEN_WIDTH;
- _height = 400;
+ _height = TOON_SCREEN_HEIGHT;
return true;
}
case kCompRNC2: {
@@ -119,12 +118,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
decSize = rnc.unpackM2(fileData, _data);
- if (decSize > 640 * 400 + 768)
- _width = 1280;
+ if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768)
+ _width = TOON_BACKBUFFER_WIDTH;
else
- _width = 640;
+ _width = TOON_SCREEN_WIDTH;
- _height = 400;
+ _height = TOON_SCREEN_HEIGHT;
return true;
}
}
@@ -187,6 +186,41 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i
}
}
+void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray) {
+
+ int32 rx = MIN(_width, surface.w - x);
+ int32 ry = MIN(_height, surface.h - y);
+
+ if (rx < 0 || ry < 0)
+ return;
+
+ int32 destPitch = surface.pitch;
+ int32 srcPitch = _width;
+
+ for (uint32 i = 0; i < rectArray.size(); i++) {
+
+ Common::Rect rect = rectArray[i];
+
+ int32 fillRx = MIN<int32>(rx, rect.right - rect.left);
+ int32 fillRy = MIN<int32>(ry, rect.bottom - rect.top);
+
+ uint8 *c = _data + _width * (dy + rect.top) + (dx + rect.left);
+ uint8 *curRow = (uint8 *)surface.pixels + (y + rect.top) * destPitch + (x + rect.left);
+
+ for (int32 yy = 0; yy < fillRy; yy++) {
+ uint8 *curSrc = c;
+ uint8 *cur = curRow;
+ for (int32 xx = 0; xx < fillRx; xx++) {
+ *cur = *curSrc;
+ curSrc++;
+ cur++;
+ }
+ curRow += destPitch;
+ c += srcPitch;
+ }
+ }
+}
+
void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) {
debugC(6, kDebugPicture, "draw(surface, %d, %d, %d, %d)", x, y, dx, dy);
@@ -279,7 +313,6 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable
else
t = adx;
-
int32 cdx = (dx << 16) / t;
int32 cdy = (dy << 16) / t;
@@ -289,15 +322,15 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable
int32 rx = bx >> 16;
int32 ry = by >> 16;
- if( rx >= 0 && rx < _width-1 && ry >= 0 && ry < _height) { // sanity check: some lines in the game
+ if( rx >= 0 && rx < _width-1 && ry >= 0 && ry < _height) { // sanity check: some lines in the game
// were drawing outside the screen causing corruption
if (!walkable) {
_data[_width * ry + rx] &= 0xe0;
- _data[_width * ry + rx+1] &= 0xe0;
+ _data[_width * ry + rx + 1] &= 0xe0;
} else {
int32 v = _data[_width * (by >> 16) + rx - 1];
_data[_width * ry + rx] = v;
- _data[_width * ry + rx+1] = v;
+ _data[_width * ry + rx + 1] = v;
}
}
diff --git a/engines/toon/picture.h b/engines/toon/picture.h
index 1b0fd7f550..6aca408364 100644
--- a/engines/toon/picture.h
+++ b/engines/toon/picture.h
@@ -44,6 +44,7 @@ public:
bool loadPicture(Common::String file, bool totalPalette = false);
void setupPalette();
void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
+ void drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray);
void drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
void drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable);
void floodFillNotWalkableOnMask(int32 x, int32 y);
diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp
index 61e3ffb111..b29aa3b72d 100644
--- a/engines/toon/resource.cpp
+++ b/engines/toon/resource.cpp
@@ -29,13 +29,20 @@
#include "common/substream.h"
#include "toon/toon.h"
-
namespace Toon {
-Resources::Resources(ToonEngine *vm) : _vm(vm) {
+Resources::Resources(ToonEngine *vm) : _vm(vm), _cacheSize(0) {
+ _resourceCache.clear();
}
Resources::~Resources() {
+
+ while (!_resourceCache.empty()) {
+ CacheEntry *temp = _resourceCache.back();
+ _resourceCache.pop_back();
+ delete temp;
+ }
+
while(!_pakFiles.empty()) {
PakFile *temp = _pakFiles.back();
_pakFiles.pop_back();
@@ -45,8 +52,73 @@ Resources::~Resources() {
purgeFileData();
}
-void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) {
- debugC(1, kDebugResource, "openPackage(%s, %d)", fileName.c_str(), (preloadEntirePackage) ? 1 : 0);
+void Resources::removePackageFromCache(Common::String packName) {
+ // I'm not sure what's a good strategy here. It seems unnecessary to
+ // actually remove the cached resources, because the player may be
+ // wandering back and forth between rooms. So for now, do nothing.
+}
+
+bool Resources::getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData) {
+ for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
+ if ((*entry)->_data && (*entry)->_fileName.compareToIgnoreCase(fileName) == 0) {
+ debugC(5, kDebugResource, "getFromCache(%s) - Got %d bytes from %s", fileName.c_str(), (*entry)->_size, (*entry)->_packName.c_str());
+ (*entry)->_age = 0;
+ *fileSize = (*entry)->_size;
+ *fileData = (*entry)->_data;
+ return true;
+ }
+ }
+ return false;
+}
+
+void Resources::addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData) {
+ debugC(5, kDebugResource, "addToCache(%s, %s, %d) - Total Size: %d", packName.c_str(), fileName.c_str(), fileSize, _cacheSize + fileSize);
+ for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
+ if ((*entry)->_data) {
+ (*entry)->_age++;
+ }
+ }
+ _cacheSize += fileSize;
+
+ while (_cacheSize > MAX_CACHE_SIZE) {
+ CacheEntry *bestEntry = 0;
+ for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
+ if ((*entry)->_data) {
+ if (!bestEntry || ((*entry)->_age >= bestEntry->_age && (*entry)->_size >= bestEntry->_size)) {
+ bestEntry = *entry;
+ }
+ }
+ }
+ if (!bestEntry)
+ break;
+
+ free(bestEntry->_data);
+ bestEntry->_data = 0;
+ _cacheSize -= bestEntry->_size;
+ debugC(5, kDebugResource, "Freed %s (%s) to reclaim %d bytes", bestEntry->_fileName.c_str(), bestEntry->_packName.c_str(), bestEntry->_size);
+ }
+
+ for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) {
+ if (!(*entry)->_data) {
+ (*entry)->_packName = packName;
+ (*entry)->_fileName = fileName;
+ (*entry)->_age = 0;
+ (*entry)->_size = fileSize;
+ (*entry)->_data = fileData;
+ return;
+ }
+ }
+
+ CacheEntry *entry = new CacheEntry();
+ entry->_packName = packName;
+ entry->_fileName = fileName;
+ entry->_size = fileSize;
+ entry->_data = fileData;
+ _resourceCache.push_back(entry);
+}
+
+void Resources::openPackage(Common::String fileName) {
+ debugC(1, kDebugResource, "openPackage(%s)", fileName.c_str());
Common::File file;
bool opened = file.open(fileName);
@@ -55,15 +127,16 @@ void Resources::openPackage(Common::String fileName, bool preloadEntirePackage)
return;
PakFile *pakFile = new PakFile();
- pakFile->open(&file, fileName, preloadEntirePackage);
+ pakFile->open(&file, fileName);
- if (preloadEntirePackage)
- file.close();
+ file.close();
_pakFiles.push_back(pakFile);
}
void Resources::closePackage(Common::String fileName) {
+
+ removePackageFromCache(fileName);
for (uint32 i = 0; i < _pakFiles.size(); i++) {
if (_pakFiles[i]->getPackName() == fileName) {
delete _pakFiles[i];
@@ -91,13 +164,21 @@ uint8 *Resources::getFileData(Common::String fileName, uint32 *fileSize) {
_allocatedFileData.push_back(memory);
return memory;
} else {
+
+ uint32 locFileSize = 0;
+ uint8 *locFileData = 0;
+
+ if (getFromCache(fileName, &locFileSize, &locFileData)) {
+ *fileSize = locFileSize;
+ return locFileData;
+ }
+
for (uint32 i = 0; i < _pakFiles.size(); i++) {
- uint32 locFileSize = 0;
- uint8 *locFileData = 0;
locFileData = _pakFiles[i]->getFileData(fileName, &locFileSize);
if (locFileData) {
*fileSize = locFileSize;
+ addToCache(_pakFiles[i]->getPackName(), fileName, locFileSize, locFileData);
return locFileData;
}
}
@@ -136,25 +217,16 @@ void Resources::purgeFileData() {
}
_allocatedFileData.clear();
}
+
Common::SeekableReadStream *PakFile::createReadStream(Common::String fileName) {
debugC(1, kDebugResource, "createReadStream(%s)", fileName.c_str());
- int32 offset = 0;
- int32 size = 0;
- for (uint32 i = 0; i < _numFiles; i++) {
- if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
- size = _files[i]._size;
- offset = _files[i]._offset;
- break;
- }
- }
- if (!size)
- return 0;
-
- if (_fileHandle)
- return new Common::SeekableSubReadStream(_fileHandle, offset, offset + size);
+ uint32 fileSize = 0;
+ uint8 *buffer = getFileData(fileName, &fileSize);
+ if (buffer)
+ return new Common::MemoryReadStream(buffer, fileSize, DisposeAfterUse::YES);
else
- return new Common::MemoryReadStream(_buffer + offset, size);
+ return 0;
}
uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) {
@@ -162,16 +234,26 @@ uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) {
for (uint32 i = 0; i < _numFiles; i++) {
if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
- *fileSize = _files[i]._size;
- return _buffer + _files[i]._offset;
+ Common::File file;
+ if (file.open(_packName)) {
+ *fileSize = _files[i]._size;
+ file.seek(_files[i]._offset);
+
+ // Use malloc() because that's what MemoryReadStream
+ // uses to dispose of the memory when it's done.
+ uint8 *buffer = (uint8 *)malloc(*fileSize);
+ file.read(buffer, *fileSize);
+ file.close();
+ return buffer;
+ }
}
}
return 0;
}
-void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage) {
- debugC(1, kDebugResource, "open(rs, %d)", (preloadEntirePackage) ? 1 : 0);
+void PakFile::open(Common::SeekableReadStream *rs, Common::String packName) {
+ debugC(1, kDebugResource, "open(rs)");
char buffer[64];
int32 currentPos = 0;
@@ -199,30 +281,12 @@ void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool
_numFiles++;
_files.push_back(newFile);
}
-
- if (preloadEntirePackage) {
- _bufferSize = rs->size();
- delete[] _buffer;
- _buffer = new uint8[_bufferSize];
- rs->seek(0);
- rs->read(_buffer, _bufferSize);
- }
}
void PakFile::close() {
- delete[] _buffer;
-
- if (_fileHandle) {
- _fileHandle->close();
- delete _fileHandle;
- }
}
PakFile::PakFile() {
- _bufferSize = 0;
- _buffer = NULL;
-
- _fileHandle = NULL;
}
PakFile::~PakFile() {
diff --git a/engines/toon/resource.h b/engines/toon/resource.h
index e117c8e259..d6ed29b81b 100644
--- a/engines/toon/resource.h
+++ b/engines/toon/resource.h
@@ -31,6 +31,8 @@
#include "common/file.h"
#include "common/stream.h"
+#define MAX_CACHE_SIZE (4 * 1024 * 1024)
+
namespace Toon {
class PakFile {
@@ -38,7 +40,7 @@ public:
PakFile();
~PakFile();
- void open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage);
+ void open(Common::SeekableReadStream *rs, Common::String packName);
uint8 *getFileData(Common::String fileName, uint32 *fileSize);
Common::String getPackName() { return _packName; }
Common::SeekableReadStream *createReadStream(Common::String fileName);
@@ -52,9 +54,6 @@ protected:
};
Common::String _packName;
- uint8 *_buffer;
- int32 _bufferSize;
-
uint32 _numFiles;
Common::Array<File> _files;
Common::File *_fileHandle;
@@ -62,11 +61,25 @@ protected:
class ToonEngine;
+class CacheEntry {
+public:
+ CacheEntry() : _age(0), _size(0), _data(0) {}
+ ~CacheEntry() {
+ free(_data);
+ }
+
+ Common::String _packName;
+ Common::String _fileName;
+ uint32 _age;
+ uint32 _size;
+ uint8 *_data;
+};
+
class Resources {
public:
Resources(ToonEngine *vm);
~Resources();
- void openPackage(Common::String file, bool preloadEntirePackage);
+ void openPackage(Common::String file);
void closePackage(Common::String fileName);
Common::SeekableReadStream *openFile(Common::String file);
uint8 *getFileData(Common::String fileName, uint32 *fileSize); // this memory must be copied to your own structures!
@@ -76,6 +89,12 @@ protected:
ToonEngine *_vm;
Common::Array<uint8 *> _allocatedFileData;
Common::Array<PakFile *> _pakFiles;
+ uint32 _cacheSize;
+ Common::Array<CacheEntry *> _resourceCache;
+
+ void removePackageFromCache(Common::String packName);
+ bool getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData);
+ void addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData);
};
} // End of namespace Toon
diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp
index 3cd56761f6..376b1db621 100644
--- a/engines/toon/script.cpp
+++ b/engines/toon/script.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "common/endian.h"
#include "common/stream.h"
#include "common/util.h"
@@ -177,7 +176,7 @@ bool EMCInterpreter::start(EMCState *script, int function) {
if (functionOffset == 0xFFFF)
return false;
- script->ip = &script->dataPtr->data[functionOffset+1];
+ script->ip = &script->dataPtr->data[functionOffset + 1];
return true;
}
diff --git a/engines/toon/script.h b/engines/toon/script.h
index 6c46238238..2a74f9084f 100644
--- a/engines/toon/script.h
+++ b/engines/toon/script.h
@@ -31,7 +31,6 @@
#include "common/func.h"
#include "common/iff_container.h"
-
// Based on Kyra script interpretor
namespace Toon {
diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp
index adf3a1c9cc..b181591bf0 100644
--- a/engines/toon/script_func.cpp
+++ b/engines/toon/script_func.cpp
@@ -265,7 +265,6 @@ int32 ScriptFunc::sys_Cmd_Draw_Actor_Standing(EMCState *state) {
arg1 = 1;
}
-
if (arg2 > -1)
_vm->getDrew()->forceFacing(arg2);
@@ -461,7 +460,7 @@ int32 ScriptFunc::sys_Cmd_Actor_Talks(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Say_Lines(EMCState *state) {
-
+
// WORKAROUND: In the scene 4 (Castle), if you click twice on the closed door, Drew disappears
// the script makes him disappear for the custom animation and not reappear.
if (_vm->state()->_currentScene == 4 && stackPos(1) == 562) {
@@ -491,11 +490,11 @@ int32 ScriptFunc::sys_Cmd_Empty_Inventory(EMCState *state) {
int32 ScriptFunc::sys_Cmd_Set_Anim_Scale_Size(EMCState *state) {
int32 animID = stackPos(0);
int32 scale = stackPos(1);
-
+
SceneAnimation *sceneAnim = _vm->getSceneAnimation(animID);
if (sceneAnim) {
sceneAnim->_animInstance->setUseMask(true);
- sceneAnim->_animInstance->setScale(scale,true);
+ sceneAnim->_animInstance->setScale(scale, true);
}
return 0;
}
@@ -939,8 +938,6 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) {
sceneAnim->_animInstance->setAnimationRange(stackPos(11), stackPos(11));
sceneAnim->_animInstance->setFrame(stackPos(11));
-
-
debugC(0, 0xfff, "Init Anim %s %d %d %d %d %d %d %d %d %d %d %d %d %d\n", GetText(12, state), stackPos(0), stackPos(1), stackPos(2), stackPos(3),
stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12));
@@ -950,7 +947,7 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) {
int32 layerZ = stackPos(3);
if (dx == -2)
- sceneAnim->_animInstance->moveRelative(640, 0, 0);
+ sceneAnim->_animInstance->moveRelative(TOON_SCREEN_WIDTH, 0, 0);
else if (dx < 0) {
dx = sceneAnim->_animation->_x1;
}
@@ -1028,7 +1025,7 @@ int32 ScriptFunc::sys_Cmd_Draw_Scene_Anim_WSA_Frame(EMCState *state) {
else if (animId == 20 || animId == 15 || animId == 21 || animId == 16 || animId == 17 || animId == 18)
_vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 1);
else if (animId == 9) {
- _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 6);
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 3);
}
}
@@ -1091,13 +1088,13 @@ int32 ScriptFunc::sys_Cmd_Proceed_To_Next_Chapter(EMCState *state) {
}
int32 ScriptFunc::sys_Cmd_Play_Sfx_Plus(EMCState *state) {
- //debugC(0,0xfff, "playSfx ( %d , %d, %d, %d, %d )", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ //debugC(0, 0xfff, "playSfx ( %d , %d, %d, %d, %d )", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
_vm->playSFX(stackPos(0), stackPos(1));
return 0;
}
int32 ScriptFunc::sys_Cmd_Play_Sfx(EMCState *state) {
- //debugC(0,0xfff, "playSfx ( %d , %d)", stackPos(0), stackPos(1));
+ //debugC(0, 0xfff, "playSfx ( %d , %d)", stackPos(0), stackPos(1));
_vm->playSFX(stackPos(0), stackPos(1));
return 0;
}
diff --git a/engines/toon/state.cpp b/engines/toon/state.cpp
index f676a65025..0d6977842d 100644
--- a/engines/toon/state.cpp
+++ b/engines/toon/state.cpp
@@ -119,7 +119,6 @@ State::State(void) {
}
State::~State(void) {
-
}
int32 State::getGameFlag(int32 flagId) {
diff --git a/engines/toon/state.h b/engines/toon/state.h
index d31ff4f3c2..63505fd5fb 100644
--- a/engines/toon/state.h
+++ b/engines/toon/state.h
@@ -81,7 +81,6 @@ public:
int32 _nextSpecialEnterX;
int32 _nextSpecialEnterY;
-
bool _timerEnabled[2];
int32 _timerTimeout[2];
int32 _timerDelay[2];
@@ -94,7 +93,6 @@ public:
void loadConversations(Common::ReadStream *stream);
void saveConversations(Common::WriteStream *stream);
-
};
} // End of namespace Toon
diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp
index a03a2d57ce..e1478645db 100644
--- a/engines/toon/tools.cpp
+++ b/engines/toon/tools.cpp
@@ -125,7 +125,6 @@ uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize) {
return (dstp - dst);
}
-
//return codes
#define NOT_PACKED 0
#define PACKED_CRC -1
@@ -296,7 +295,6 @@ int32 RncDecoder::unpackM1(const void *input, void *output) {
uint16 crcUnpacked = 0;
uint16 crcPacked = 0;
-
_bitBuffl = 0;
_bitBuffh = 0;
_bitCount = 0;
@@ -397,9 +395,6 @@ int32 RncDecoder::unpackM2(const void *input, void *output) {
uint16 crcUnpacked = 0;
uint16 crcPacked = 0;
-// Strangerke - Commented (not used)
-// uint16 counts = 0;
-
_bitBuffl = 0;
_bitCount = 0;
@@ -429,7 +424,6 @@ int32 RncDecoder::unpackM2(const void *input, void *output) {
_srcPtr = inputptr;
_dstPtr = (uint8 *)output;
-
uint16 ofs, len;
byte ofs_hi, ofs_lo;
diff --git a/engines/toon/tools.h b/engines/toon/tools.h
index 05fc5c9cda..1d8b4a6a5b 100644
--- a/engines/toon/tools.h
+++ b/engines/toon/tools.h
@@ -42,8 +42,8 @@ const uint32 kCompRNC2 = 0x524E4302;
#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x)
#define READ_LE_INT32(x) (int32) READ_LE_UINT32(x)
-#define WRITE_LE_INT16(x,y) WRITE_LE_UINT16(x,(int16)y)
-#define WRITE_LE_INT32(x,y) WRITE_LE_UINT32(x,(int32)y)
+#define WRITE_LE_INT16(x, y) WRITE_LE_UINT16(x, (int16)y)
+#define WRITE_LE_INT32(x, y) WRITE_LE_UINT32(x, (int32)y)
uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize);
uint32 decompressLZSS(byte *src, byte *dst, int dstsize);
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index d65230df85..0c7989f317 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -49,7 +49,6 @@
namespace Toon {
-
void ToonEngine::init() {
_currentScriptRegion = 0;
_resources = new Resources(this);
@@ -58,7 +57,7 @@ void ToonEngine::init() {
_hotspots = new Hotspots(this);
_mainSurface = new Graphics::Surface();
- _mainSurface->create(1280, 400, 1);
+ _mainSurface->create(TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_HEIGHT, 1);
_finalPalette = new uint8[768];
_backupPalette = new uint8[768];
@@ -101,14 +100,13 @@ void ToonEngine::init() {
SearchMan.addSubDirectoryMatching(gameDataDir, "ACT1");
SearchMan.addSubDirectoryMatching(gameDataDir, "ACT2");
-
syncSoundSettings();
_pathFinding = new PathFinding(this);
- resources()->openPackage("LOCAL.PAK", true);
- resources()->openPackage("ONETIME.PAK", true);
- resources()->openPackage("DREW.PAK", true);
+ resources()->openPackage("LOCAL.PAK");
+ resources()->openPackage("ONETIME.PAK");
+ resources()->openPackage("DREW.PAK");
for (int32 i = 0; i < 32; i++)
_characters[i] = NULL;
@@ -262,7 +260,6 @@ void ToonEngine::parseInput() {
selectHotspot();
clickEvent();
}
-
}
void ToonEngine::enableTimer(int32 timerId) {
@@ -325,8 +322,8 @@ void ToonEngine::updateScrolling(bool force, int32 timeIncrement) {
if ((_gameState->_locations[_gameState->_currentScene]._flags & 0x80) == 0) {
if (desiredScrollValue < 0)
desiredScrollValue = 0;
- if (desiredScrollValue >= _currentPicture->getWidth() - 640)
- desiredScrollValue = _currentPicture->getWidth() - 640;
+ if (desiredScrollValue >= _currentPicture->getWidth() - TOON_SCREEN_WIDTH)
+ desiredScrollValue = _currentPicture->getWidth() - TOON_SCREEN_WIDTH;
if (force) {
_gameState->_currentScrollValue = desiredScrollValue;
@@ -378,12 +375,23 @@ void ToonEngine::updateTimer(int32 timeIncrement) {
}
void ToonEngine::render() {
- if (_gameState->_inCutaway)
- _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0);
- else
- _currentPicture->draw(*_mainSurface, 0, 0, 0, 0);
- //_currentMask->drawMask(*_mainSurface,0,0,0,0);
+ if (_dirtyAll) {
+ if (_gameState->_inCutaway)
+ _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0);
+ else
+ _currentPicture->draw(*_mainSurface, 0, 0, 0, 0);
+ _dirtyRects.push_back(Common::Rect(0, 0, TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_HEIGHT));
+ } else {
+ if (_gameState->_inCutaway)
+ _currentCutaway->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects);
+ else
+ _currentPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects);
+ }
+
+ clearDirtyRects();
+
+ //_currentMask->drawMask(*_mainSurface, 0, 0, 0, 0);
_animationManager->render();
drawInfoLine();
@@ -399,7 +407,7 @@ void ToonEngine::render() {
sprintf(test, "%d %d / mask %d layer %d z %d", _mouseX, _mouseY, getMask()->getData(_mouseX, _mouseY), getLayerAtPoint(_mouseX, _mouseY), getZAtPoint(_mouseX, _mouseY));
int32 c = *(uint8 *)_mainSurface->getBasePtr(_mouseX, _mouseY);
- sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c*3+0], _finalPalette[c*3+1], _finalPalette[c*3+2]);
+ sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c * 3 + 0], _finalPalette[c * 3 + 1], _finalPalette[c * 3 + 2]);
_fontRenderer->setFont(_fontToon);
_fontRenderer->renderText(40, 150, Common::String(test), 0);
@@ -422,8 +430,8 @@ void ToonEngine::render() {
// add a little sleep here
int32 newMillis = (int32)_system->getMillis();
int32 sleepMs = 1; // Minimum delay to allow thread scheduling
- if ((newMillis - _lastRenderTime) < _tickLength)
- sleepMs = _tickLength - (newMillis - _lastRenderTime);
+ if ((newMillis - _lastRenderTime) < _tickLength * 2)
+ sleepMs = _tickLength * 2 - (newMillis - _lastRenderTime);
assert(sleepMs >= 0);
_system->delayMillis(sleepMs);
_lastRenderTime = _system->getMillis();
@@ -454,24 +462,24 @@ void ToonEngine::doMagnifierEffect() {
11, 11, 11, 11, 12
};
- byte tempBuffer[25*25];
+ byte tempBuffer[25 * 25];
for (int32 y = -12; y <= 12; y++) {
for (int32 x = -12; x <= 12; x++) {
int32 destPitch = surface.pitch;
uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
- tempBuffer[(y+12) * 25 + x + 12] = *curRow;
+ tempBuffer[(y + 12) * 25 + x + 12] = *curRow;
}
}
for (int32 y = -12; y <= 12; y++) {
for (int32 x = -12; x <= 12; x++) {
int32 dist = y * y + x * x;
- if (dist > 144)
+ if (dist > 144)
continue;
int32 destPitch = surface.pitch;
uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
int32 lerp = (512 + intSqrt[dist] * 256 / 12);
- *curRow = tempBuffer[(y*lerp/1024+12) * 25 + x*lerp/1024 + 12];
+ *curRow = tempBuffer[(y * lerp / 1024 + 12) * 25 + x * lerp / 1024 + 12];
}
}
}
@@ -484,7 +492,50 @@ void ToonEngine::copyToVirtualScreen(bool updateScreen) {
_cursorAnimationInstance->setPosition(_mouseX - 40 + state()->_currentScrollValue - _cursorOffsetX, _mouseY - 40 - _cursorOffsetY, 0, false);
_cursorAnimationInstance->render();
}
- _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, 1280, 0, 0, 640, 400);
+
+ // Handle dirty rects here
+ static int32 lastScroll = 0;
+
+ if (_dirtyAll || _gameState->_currentScrollValue != lastScroll) {
+ // we have to refresh everything in case of scrolling.
+ _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, TOON_BACKBUFFER_WIDTH, 0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT);
+ } else {
+
+ int32 offX = 0;
+ for (uint i = 0; i < _oldDirtyRects.size(); i++) {
+ Common::Rect rect = _oldDirtyRects[i];
+ rect.translate(-state()->_currentScrollValue, 0);
+ offX = 0;
+ if(rect.right <= 0)
+ continue;
+ if (rect.left < 0) {
+ offX = -rect.left;
+ rect.left = 0;
+ }
+ rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT);
+ if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) {
+ _system->copyRectToScreen((byte *)_mainSurface->pixels + _oldDirtyRects[i].left + offX + _oldDirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ }
+
+ for (uint i = 0; i < _dirtyRects.size(); i++) {
+ Common::Rect rect = _dirtyRects[i];
+ rect.translate(-state()->_currentScrollValue, 0);
+ offX = 0;
+ if (rect.right <= 0)
+ continue;
+ if (rect.left < 0) {
+ offX = -rect.left;
+ rect.left = 0;
+ }
+ rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT);
+ if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) {
+ _system->copyRectToScreen((byte *)_mainSurface->pixels + _dirtyRects[i].left + offX + _dirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ }
+ }
+ lastScroll = _gameState->_currentScrollValue;
+
if (updateScreen) {
_system->updateScreen();
_shouldQuit = shouldQuit(); // update game quit flag - this shouldn't be called all the time, as it's a virtual function
@@ -589,6 +640,7 @@ bool ToonEngine::showMainmenu(bool &loadedGame) {
bool musicPlaying = false;
_gameState->_inMenu = true;
+ dirtyAllScreen();
while (!doExit) {
clickingOn = MAINMENUHOTSPOT_NONE;
@@ -607,7 +659,15 @@ bool ToonEngine::showMainmenu(bool &loadedGame) {
}
while (!clickRelease) {
- mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0);
+
+ if(_dirtyAll) {
+ mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0);
+ addDirtyRect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT);
+ } else {
+ mainmenuPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects);
+ }
+
+ clearDirtyRects();
for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) {
if (entries[entryNr].menuMask & menuMask) {
@@ -719,7 +779,7 @@ Common::Error ToonEngine::run() {
g_eventRec.registerRandomSource(_rnd, "toon");
- initGraphics(640, 400, true);
+ initGraphics(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT, true);
init();
// do we need to load directly a game?
@@ -817,7 +877,20 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
_inventoryIcons = NULL;
_inventoryIconSlots = NULL;
_genericTexts = NULL;
- _audioManager = NULL;
+ _audioManager = NULL;
+ _gameState = NULL;
+
+ _locationDirNotVisited = NULL;
+ _locationDirVisited = NULL;
+ _specialInfoLine = NULL;
+
+ for (int i = 0; i < 64; i++) {
+ _sceneAnimations[i]._active = false;
+ }
+
+ for (int i = 0; i < 32; i++) {
+ _characters[i] = NULL;
+ }
memset(&_scriptData, 0, sizeof(EMCData));
@@ -859,7 +932,7 @@ ToonEngine::~ToonEngine() {
_mainSurface->free();
delete _mainSurface;
}
-
+
delete[] _finalPalette;
delete[] _backupPalette;
delete[] _additionalPalette1;
@@ -888,7 +961,6 @@ ToonEngine::~ToonEngine() {
delete _pathFinding;
-
for (int32 i = 0; i < 64; i++) {
if (_sceneAnimations[i]._active) {
// see if one character shares this instance
@@ -950,8 +1022,6 @@ void ToonEngine::simpleUpdate(bool waitCharacterToTalk) {
_animationManager->update(elapsedTime);
_audioManager->updateAmbientSFX();
render();
-
-
}
void ToonEngine::fixPaletteEntries(uint8 *palette, int num) {
@@ -967,13 +1037,8 @@ void ToonEngine::fixPaletteEntries(uint8 *palette, int num) {
// adapted from KyraEngine
void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) {
-
-
static int32 numReentrant = 0;
numReentrant++;
-
-// Strangerke - Commented (not used)
-// uint32 nextTime = _system->getMillis() + _tickLength;
const int startScript = _lastProcessedSceneScript;
_updatingSceneScriptRunFlag = true;
@@ -1006,10 +1071,8 @@ void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) {
} while (_lastProcessedSceneScript != startScript && !_shouldQuit);
-
_updatingSceneScriptRunFlag = false;
numReentrant--;
-
}
void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
@@ -1077,10 +1140,9 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_mouseButton = 0;
_lastMouseButton = 0x3;
-
// load package
strcpy(temp, createRoomFilename(Common::String::format("%s.PAK", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
- resources()->openPackage(temp, true);
+ resources()->openPackage(temp);
strcpy(temp, state()->_locations[SceneId]._name);
strcat(temp, ".NPP");
@@ -1198,6 +1260,9 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
state()->_mouseHidden = false;
+ clearDirtyRects();
+ dirtyAllScreen();
+
if (!forGameLoad) {
_script->start(&_scriptState[0], 0);
@@ -1215,7 +1280,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
_gameState->_nextSpecialEnterX = -1;
_gameState->_nextSpecialEnterY = -1;
}
-
+
_script->start(&_scriptState[0], 3);
while (_script->run(&_scriptState[0]))
@@ -1290,7 +1355,6 @@ void ToonEngine::initChapter() {
_script->unload(&data);
setupGeneralPalette();
-
}
void ToonEngine::loadCursor() {
@@ -1412,10 +1476,9 @@ void ToonEngine::clickEvent() {
return;
}
-
int32 mouseX = _mouseX;
if (_gameState->_inCutaway) {
- mouseX += 1280;
+ mouseX += TOON_BACKBUFFER_WIDTH;
}
// find hotspot
@@ -1443,7 +1506,6 @@ void ToonEngine::clickEvent() {
}
}
-
if (!currentHot) {
int32 xx, yy;
@@ -1471,9 +1533,6 @@ void ToonEngine::clickEvent() {
int16 command = currentHot->getData(commandId);
int16 argument = currentHot->getData(commandId + 1);
int16 priority = currentHot->getPriority();
-// Strangerke - Commented (not used)
-// int16 ref = currentHot->getRef();
-// int16 pad1 = currentHot->getData(6);
if (!_gameState->_inCutaway && !_gameState->_inCloseUp) {
if (leftButton && (currentHot->getData(4) != 2 || _gameState->_mouseState >= 0) && currentHot->getData(5) != -1) {
@@ -1515,8 +1574,6 @@ void ToonEngine::clickEvent() {
break;
case 7:
// switch to CloseUp
-// Strangerke - Commented (not used)
-// int closeup = 1;
break;
case 8:
// face flux
@@ -1524,11 +1581,6 @@ void ToonEngine::clickEvent() {
break;
case 9:
case 10:
-// Strangerke - Commented (not used)
-// if (rand() % 1 == 1) {
-// } else {
-// }
- // setFluxFacingPoint(x,y)
sayLines(2, argument);
break;
case 11:
@@ -1552,7 +1604,6 @@ void ToonEngine::clickEvent() {
int32 val = _scriptState[_currentScriptRegion].regs[4];
currentHot->setData(4, currentHot->getData(4) & val);
}
-
}
void ToonEngine::selectHotspot() {
@@ -1564,7 +1615,7 @@ void ToonEngine::selectHotspot() {
int32 mouseX = _mouseX;
if (_gameState->_inCutaway)
- mouseX += 1280;
+ mouseX += TOON_BACKBUFFER_WIDTH;
if (_gameState->_sackVisible) {
if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) {
@@ -1722,7 +1773,6 @@ void ToonEngine::exitScene() {
strcpy(temp, createRoomFilename(Common::String::format("%s.PAK", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
resources()->closePackage(temp);
-
_drew->stopWalk();
_flux->stopWalk();
@@ -1734,7 +1784,7 @@ void ToonEngine::flipScreens() {
_gameState->_inCloseUp = !_gameState->_inCloseUp;
if (_gameState->_inCloseUp) {
- _gameState->_currentScrollValue = 640;
+ _gameState->_currentScrollValue = TOON_SCREEN_WIDTH;
setPaletteEntries(_cutawayPalette, 1, 128);
setPaletteEntries(_additionalPalette2, 232, 23);
} else {
@@ -1750,9 +1800,9 @@ void ToonEngine::fadeIn(int32 numFrames) {
uint8 vmpalette[3 * 256];
for (int32 i = 0; i < 256; i++) {
- vmpalette[i*3+0] = f * _finalPalette[i*3+0] / (numFrames - 1);
- vmpalette[i*3+1] = f * _finalPalette[i*3+1] / (numFrames - 1);
- vmpalette[i*3+2] = f * _finalPalette[i*3+2] / (numFrames - 1);
+ vmpalette[i * 3 + 0] = f * _finalPalette[i * 3 + 0] / (numFrames - 1);
+ vmpalette[i * 3 + 1] = f * _finalPalette[i * 3 + 1] / (numFrames - 1);
+ vmpalette[i * 3 + 2] = f * _finalPalette[i * 3 + 2] / (numFrames - 1);
}
_system->getPaletteManager()->setPalette(vmpalette, 0, 256);
_system->updateScreen();
@@ -1768,9 +1818,9 @@ void ToonEngine::fadeOut(int32 numFrames) {
for (int32 f = 0; f < numFrames; f++) {
uint8 vmpalette[3 * 256];
for (int32 i = 0; i < 256; i++) {
- vmpalette[i*3+0] = (numFrames - f - 1) * oldpalette[i*3+0] / (numFrames - 1);
- vmpalette[i*3+1] = (numFrames - f - 1) * oldpalette[i*3+1] / (numFrames - 1);
- vmpalette[i*3+2] = (numFrames - f - 1) * oldpalette[i*3+2] / (numFrames - 1);
+ vmpalette[i * 3 + 0] = (numFrames - f - 1) * oldpalette[i * 3 + 0] / (numFrames - 1);
+ vmpalette[i * 3 + 1] = (numFrames - f - 1) * oldpalette[i * 3 + 1] / (numFrames - 1);
+ vmpalette[i * 3 + 2] = (numFrames - f - 1) * oldpalette[i * 3 + 2] / (numFrames - 1);
}
_system->getPaletteManager()->setPalette(vmpalette, 0, 256);
_system->updateScreen();
@@ -1824,11 +1874,11 @@ int32 ToonEngine::getScaleAtPoint(int32 x, int32 y) {
return 1024;
// clamp values
- x = MIN<int32>(1279, MAX<int32>(0, x));
- y = MIN<int32>(399, MAX<int32>(0, y));
+ x = MIN<int32>(TOON_BACKBUFFER_WIDTH - 1, MAX<int32>(0, x));
+ y = MIN<int32>(TOON_BACKBUFFER_HEIGHT - 1, MAX<int32>(0, y));
int32 maskData = _currentMask->getData(x, y) & 0x1f;
- return _roomScaleData[maskData+2] * 1024 / 100;
+ return _roomScaleData[maskData + 2] * 1024 / 100;
}
int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) {
@@ -1836,11 +1886,11 @@ int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) {
return 0;
// clamp values
- x = MIN<int32>(1279, MAX<int32>(0, x));
- y = MIN<int32>(399, MAX<int32>(0, y));
+ x = MIN<int32>(TOON_BACKBUFFER_WIDTH - 1, MAX<int32>(0, x));
+ y = MIN<int32>(TOON_BACKBUFFER_HEIGHT - 1, MAX<int32>(0, y));
int32 maskData = _currentMask->getData(x, y) & 0x1f;
- return _roomScaleData[maskData+130] << 5;
+ return _roomScaleData[maskData + 130] << 5;
}
int32 ToonEngine::getZAtPoint(int32 x, int32 y) {
@@ -1917,25 +1967,11 @@ void ToonEngine::sayLines(int numLines, int dialogId) {
if (oldShowMouse)
Game.MouseHiddenCount = 0;
#endif
-
}
int32 ToonEngine::simpleCharacterTalk(int32 dialogid) {
int32 myId = 0;
-// Strangerke - Commented (not used)
-#if 0
- char *myLine;
- if (dialogid < 1000) {
- myLine = _roomTexts->getText(dialogid);
- myId = dialogid;
- } else {
- myLine = _genericTexts->getText(dialogid - 1000);
- myId = dialogid - 1000;
- }
- debugC(0, 0xfff, "Talker = %d will say '%s' \n", READ_LE_UINT16(c - 2), myLine);
-#endif
-
if (_audioManager->voiceStillPlaying())
_audioManager->stopCurrentVoice();
@@ -1952,14 +1988,6 @@ int32 ToonEngine::simpleCharacterTalk(int32 dialogid) {
void ToonEngine::playTalkAnimOnCharacter(int32 animID, int32 characterId, bool talker) {
if (animID || talker) {
-// Strangerke - Commented (not used)
-#if 0
- if (_gameState->_inCutaway || _gameState->_inInventory) {
- if (talker) {
- // character talks
- }
- } else
-#endif
if (characterId == 0) {
_drew->playAnim(animID, 0, (talker ? 8 : 0) + 2);
} else if (characterId == 1) {
@@ -2009,7 +2037,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
_gameState->_mouseHidden = true;
}
-
// get what is before the string
int a = READ_LE_UINT16(myLine - 2);
char *b = myLine - 2 - 4 * a;
@@ -2020,14 +2047,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
char *e = c - 2 - 4 * numParticipants;
READ_LE_UINT16(e);
-// Strangerke - Commented (not used)
-// char *g = e - 2 * f;
-
- // flag as talking
-// Strangerke - Commented (not used)
-// char *h = c;
-
-
// if one voice is still playing, wait !
if (blocking) {
while (_audioManager->voiceStillPlaying() && !_shouldQuit)
@@ -2085,8 +2104,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
_currentTextLine = myLine;
_currentTextLineCharacterId = talkerId;
_currentTextLineId = dialogid;
-
-
} else {
Character *character = getCharacterById(talkerId);
if (character)
@@ -2095,7 +2112,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
debugC(0, 0xfff, "Talker = %d (num participants : %d) will say '%s'", (int)talkerId , (int)numParticipants, myLine);
-
getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY);
if (dialogid < 1000) {
@@ -2115,8 +2131,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
if (character)
character->setTalking(false);
}
-
-
return 1;
}
@@ -2131,7 +2145,7 @@ void ToonEngine::haveAConversation(int32 convId) {
_gameState->_currentConversationId = convId;
// change the music to the "conversation" music if needed.
- playRoomMusic();
+ playRoomMusic();
if (conv->_enable) {
// fix dialog script based on new flags
@@ -2149,7 +2163,6 @@ void ToonEngine::haveAConversation(int32 convId) {
doFrame();
}
-
_mouseButton = 0;
_gameState->_firstConverstationLine = true;
@@ -2178,11 +2191,13 @@ void ToonEngine::haveAConversation(int32 convId) {
a++;
}
}
- if (_shouldQuit) return;
+
+ if (_shouldQuit)
+ return;
+
_gameState->_showConversationIcons = false;
_gameState->_mouseHidden = 1;
-
if (selected < 0 || selected == 1 || selected == 3) {
if (_gameState->_firstConverstationLine)
processConversationClick(conv, 3);
@@ -2194,9 +2209,6 @@ void ToonEngine::haveAConversation(int32 convId) {
}
}
-// Strangerke - Commented (not used)
-// int cur = 0;
-
for (int i = 0; i < 10; i++) {
if (conv->state[i]._data2 == 2) {
if (i != 3)
@@ -2211,8 +2223,7 @@ void ToonEngine::haveAConversation(int32 convId) {
_gameState->_sackVisible = true;
// switch back to original music
- playRoomMusic();
-
+ playRoomMusic();
}
void ToonEngine::drawConversationIcons() {
@@ -2334,7 +2345,6 @@ retry:
break;
}
}
-
}
// hardcoded conversation flag to know if one dialogue icon must be displayed or not
@@ -2495,7 +2505,7 @@ int32 ToonEngine::runConversationCommand(int16 **command) {
int16 *v5 = *command;
int v2 = READ_LE_INT16(v5);
- int v4 = READ_LE_INT16(v5+1);
+ int v4 = READ_LE_INT16(v5 + 1);
int result = v2 - 100;
switch (v2) {
case 100:
@@ -2528,9 +2538,6 @@ int32 ToonEngine::runConversationCommand(int16 **command) {
}
int32 ToonEngine::waitTicks(int32 numTicks, bool breakOnMouseClick) {
-// Strangerke - Commented (not used)
-// Common::EventManager *_event = _system->getEventManager();
-
uint32 nextTime = _system->getMillis() + numTicks * _tickLength;
while (_system->getMillis() < nextTime || numTicks == -1) {
//if (!_animationSceneScriptRunFlag)
@@ -2549,7 +2556,13 @@ void ToonEngine::renderInventory() {
if (!_gameState->_inInventory)
return;
- _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0);
+ if (!_dirtyAll) {
+ _inventoryPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects);
+ } else {
+ _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0);
+ _dirtyRects.push_back(Common::Rect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT));
+ }
+ clearDirtyRects();
// draw items on screen
for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
@@ -2577,13 +2590,13 @@ void ToonEngine::renderInventory() {
int32 ToonEngine::showInventory() {
int32 oldScrollValue = _gameState->_currentScrollValue;
-// Strangerke - Commented (not used)
-// Common::EventManager *_event = _system->getEventManager();
+
delete _inventoryPicture;
_inventoryPicture = new Picture(this);
fadeOut(5);
_inventoryPicture->loadPicture("SACK128.CPS", true);
_inventoryPicture->setupPalette();
+ dirtyAllScreen();
if (_gameState->_mouseState >= 0) {
setCursor(_gameState->_mouseState, true, -18, -14);
@@ -2632,7 +2645,6 @@ int32 ToonEngine::showInventory() {
int32 modItem = getSpecialInventoryItem(item);
if (modItem) {
-
if (modItem == -1) {
_gameState->_mouseState = item;
_gameState->_inventory[foundObj] = 0;
@@ -2681,7 +2693,7 @@ int32 ToonEngine::showInventory() {
}
_gameState->_currentScrollValue = oldScrollValue;
- _gameState->_inInventory = false;
+ _gameState->_inInventory = false;
_mouseButton = 0;
_lastMouseButton = 0x3;
@@ -2697,6 +2709,7 @@ int32 ToonEngine::showInventory() {
setupGeneralPalette();
}
flushPalette();
+ dirtyAllScreen();
_firstFrame = true;
return 0;
@@ -2771,6 +2784,7 @@ void ToonEngine::showCutaway(Common::String cutawayPicture) {
_currentCutaway->setupPalette();
_oldScrollValue = _gameState->_currentScrollValue;
_gameState->_currentScrollValue = 0;
+ dirtyAllScreen();
flushPalette();
}
@@ -2781,6 +2795,7 @@ void ToonEngine::hideCutaway() {
_gameState->_currentScrollValue = _oldScrollValue;
_currentCutaway = 0;
_currentPicture->setupPalette();
+ dirtyAllScreen();
flushPalette();
}
@@ -2805,7 +2820,7 @@ void ToonEngine::rearrangeInventory() {
if (_gameState->_inventory[i] == 0) {
// move all the following items from one
for (int32 j = i + 1; j < _gameState->_numInventoryItems; j++) {
- _gameState->_inventory[j-1] = _gameState->_inventory[j];
+ _gameState->_inventory[j - 1] = _gameState->_inventory[j];
}
_gameState->_numInventoryItems--;
}
@@ -2826,7 +2841,6 @@ void ToonEngine::newGame() {
}
}
-
void ToonEngine::playSFX(int32 id, int32 volume) {
if (id < 0)
_audioManager->playSFX(-id + 1, volume, true);
@@ -2852,7 +2866,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
// drew
int32 x = _drew->getX();
int32 y = _drew->getY();
- if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) {
+ if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) {
if (!_gameState->_inCutaway && !_gameState->_inInventory) {
*retX = x;
*retY = y - ((_drew->getScale() * 256 / 1024) >> 1) - 45;
@@ -2862,7 +2876,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
// flux
int32 x = _flux->getX();
int32 y = _flux->getY();
- if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) {
+ if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) {
if (!_gameState->_inCutaway) {
*retX = x;
*retY = y - ((_drew->getScale() * 100 / 1024) >> 1) - 30;
@@ -2892,7 +2906,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
Character *character = getCharacterById(characterId);
if (character && !_gameState->_inCutaway) {
if (character->getAnimationInstance()) {
- if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + 640) {
+ if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) {
int32 x1, y1, x2, y2;
character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2);
*retX = (x1 + x2) / 2;
@@ -2921,7 +2935,7 @@ void ToonEngine::drawConversationLine() {
}
void ToonEngine::pauseEngineIntern(bool pause) {
-
+
Engine::pauseEngineIntern(pause);
static int32 pauseStart = 0;
@@ -3013,7 +3027,6 @@ bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) {
saveFile->writeUint32BE(saveDate);
saveFile->writeUint16BE(saveTime);
-
// save global state
_gameState->save(saveFile);
_gameState->saveConversations(saveFile);
@@ -3040,7 +3053,6 @@ bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) {
_sceneAnimations[i].save(this, saveFile);
}
-
for (int32 i = 0; i < 8; i++) {
if (_characters[i]) {
saveFile->writeSByte(i);
@@ -3120,7 +3132,7 @@ bool ToonEngine::loadGame(int32 slot) {
_sceneAnimationScripts[i]._frozen = loadFile->readByte();
_sceneAnimationScripts[i]._frozenForConversation = false;
int32 oldTimer = loadFile->readSint32BE();
- _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0,oldTimer + timerDiff);
+ _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0, oldTimer + timerDiff);
_script->loadState(&_sceneAnimationScripts[i]._state, loadFile);
}
@@ -3159,7 +3171,7 @@ bool ToonEngine::loadGame(int32 slot) {
// load "command buffer"
int32 size = loadFile->readSint16BE();
if (size) {
- uint8 *buf = new uint8[size+2];
+ uint8 *buf = new uint8[size + 2];
loadFile->read(buf, size + 2);
Common::MemoryReadStream rStr(buf, size + 2);
@@ -3278,10 +3290,6 @@ void ToonEngine::initCharacter(int32 characterId, int32 animScriptId, int32 scen
return;
}
-// Strangerke - Commented (not used)
-// if (_characters[characterIndex])
-// delete current char
-
_characters[characterIndex] = new Character(this);
_characters[characterIndex]->setId(characterId);
_characters[characterIndex]->setAnimScript(animScriptId);
@@ -3405,6 +3413,7 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD
Picture *pic = new Picture(this);
pic->loadPicture(str, false);
pic->setupPalette();
+ dirtyAllScreen();
flushPalette();
if (lineId) {
@@ -3428,7 +3437,13 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD
break;
}
- pic->draw(*_mainSurface, 0, 0, 0, 0);
+ if (!_dirtyAll) {
+ pic->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects);
+ } else {
+ pic->draw(*_mainSurface, 0, 0, 0, 0);
+ _dirtyRects.push_back(Common::Rect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT));
+ }
+ clearDirtyRects();
drawConversationLine();
if (!_audioManager->voiceStillPlaying()) {
@@ -3447,11 +3462,11 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD
}
fadeOut(5);
+ dirtyAllScreen();
restorePalette();
_firstFrame = true;
_gameState->_currentScrollValue = oldScrollValue;
delete pic;
-
}
int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) {
@@ -3493,7 +3508,7 @@ int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) {
case 11:
if (itemSrc == 0xb) {
_gameState->_mouseState = -1;
- replaceItemFromInventory(11,12);
+ replaceItemFromInventory(11, 12);
setCursor(0, false, 0, 0);
rearrangeInventory();
return 1;
@@ -4506,9 +4521,9 @@ void ToonEngine::createShadowLUT() {
for (int32 i = 0; i < 255; i++) {
// goal color
- uint32 destR = _finalPalette[i*3+0] * scaleNum / scaleDenom;
- uint32 destG = _finalPalette[i*3+1] * scaleNum / scaleDenom;
- uint32 destB = _finalPalette[i*3+2] * scaleNum / scaleDenom;
+ uint32 destR = _finalPalette[i * 3 + 0] * scaleNum / scaleDenom;
+ uint32 destG = _finalPalette[i * 3 + 1] * scaleNum / scaleDenom;
+ uint32 destB = _finalPalette[i * 3 + 2] * scaleNum / scaleDenom;
// search only in the "picture palette" which is in colors 1-128 and 200-255
int32 colorDist = 0xffffff;
@@ -4516,9 +4531,9 @@ void ToonEngine::createShadowLUT() {
for (int32 c = 1; c < 129; c++) {
- int32 diffR = _finalPalette[c*3+0] - destR;
- int32 diffG = _finalPalette[c*3+1] - destG;
- int32 diffB = _finalPalette[c*3+2] - destB;
+ int32 diffR = _finalPalette[c * 3 + 0] - destR;
+ int32 diffG = _finalPalette[c * 3 + 1] - destG;
+ int32 diffB = _finalPalette[c * 3 + 2] - destB;
if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) {
colorDist = diffR * diffR + diffG * diffG + diffB * diffB;
@@ -4528,9 +4543,9 @@ void ToonEngine::createShadowLUT() {
for (int32 c = 200; c < 256; c++) {
- int32 diffR = _finalPalette[c*3+0] - destR;
- int32 diffG = _finalPalette[c*3+1] - destG;
- int32 diffB = _finalPalette[c*3+2] - destB;
+ int32 diffR = _finalPalette[c * 3 + 0] - destR;
+ int32 diffG = _finalPalette[c * 3 + 1] - destG;
+ int32 diffB = _finalPalette[c * 3 + 2] - destB;
if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) {
colorDist = diffR * diffR + diffG * diffG + diffB * diffB;
@@ -4660,6 +4675,47 @@ void ToonEngine::playRoomMusic() {
_audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, _gameState->_locations[_gameState->_currentScene]._music);
}
+void ToonEngine::dirtyAllScreen()
+{
+ _dirtyRects.clear();
+ _dirtyAll = true;
+}
+
+void ToonEngine::addDirtyRect( int32 left, int32 top, int32 right, int32 bottom ) {
+ left = MIN<int32>(MAX<int32>(left, 0), TOON_BACKBUFFER_WIDTH);
+ right = MIN<int32>(MAX<int32>(right, 0), TOON_BACKBUFFER_WIDTH);
+ top = MIN<int32>(MAX<int32>(top, 0), TOON_BACKBUFFER_HEIGHT);
+ bottom = MIN<int32>(MAX<int32>(bottom, 0), TOON_BACKBUFFER_HEIGHT);
+
+ Common::Rect rect(left, top, right, bottom);
+
+ if (bottom - top <= 0 || right - left <= 0)
+ return;
+
+ for (uint32 i = 0; i < _dirtyRects.size(); i++) {
+ if (_dirtyRects[i].contains(rect))
+ return;
+ if (rect.contains(_dirtyRects[i])) {
+ _dirtyRects.remove_at(i);
+ i--;
+ }
+ }
+
+ // check also in the old rect (of the old frame)
+ for (int32 i = _oldDirtyRects.size() - 1 ; i >= 0; i--) {
+ if (rect.contains(_oldDirtyRects[i])) {
+ _oldDirtyRects.remove_at(i);
+ }
+ }
+
+ _dirtyRects.push_back(rect);
+}
+
+void ToonEngine::clearDirtyRects() {
+ _oldDirtyRects = _dirtyRects;
+ _dirtyRects.clear();
+ _dirtyAll = false;
+}
void SceneAnimation::save(ToonEngine *vm, Common::WriteStream *stream) {
stream->writeByte(_active);
stream->writeSint32BE(_id);
@@ -4686,7 +4742,6 @@ void SceneAnimation::load(ToonEngine *vm, Common::ReadStream *stream) {
_active = stream->readByte();
_id = stream->readSint32BE();
-
if (!_active)
return;
diff --git a/engines/toon/toon.h b/engines/toon/toon.h
index f3370aed5e..3554900684 100644
--- a/engines/toon/toon.h
+++ b/engines/toon/toon.h
@@ -52,6 +52,11 @@ class MemoryWriteStreamDynamic;
#define TOON_SAVEGAME_VERSION 4
#define DATAALIGNMENT 4
+#define TOON_SCREEN_WIDTH 640
+#define TOON_SCREEN_HEIGHT 400
+#define TOON_BACKBUFFER_WIDTH 1280
+#define TOON_BACKBUFFER_HEIGHT 400
+
/**
* This is the namespace of the Toon engine.
*
@@ -206,8 +211,6 @@ public:
void waitForScriptStep();
void doMagnifierEffect();
-
-
bool canSaveGameStateCurrently();
bool canLoadGameStateCurrently();
void pauseEngineIntern(bool pause);
@@ -334,6 +337,10 @@ public:
(f == kSupportsSavingDuringRuntime);
}
+ void dirtyAllScreen();
+ void addDirtyRect(int32 left, int32 top, int32 right, int32 bottom);
+ void clearDirtyRects();
+
protected:
OSystem *_system;
int32 _tickLength;
@@ -371,6 +378,11 @@ protected:
bool _updatingSceneScriptRunFlag;
Graphics::Surface *_mainSurface;
+ Common::Array<Common::Rect> _dirtyRects;
+ Common::Array<Common::Rect> _oldDirtyRects;
+
+ bool _dirtyAll;
+
AnimationInstance *_cursorAnimationInstance;
Animation *_cursorAnimation;
diff --git a/graphics/fonts/winfont.cpp b/graphics/fonts/winfont.cpp
index fb37c8ddef..12509fd9e1 100644
--- a/graphics/fonts/winfont.cpp
+++ b/graphics/fonts/winfont.cpp
@@ -23,8 +23,9 @@
*/
#include "common/file.h"
-#include "common/ne_exe.h"
#include "common/str.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
#include "graphics/fonts/winfont.h"
namespace Graphics {
@@ -75,8 +76,15 @@ static WinFontDirEntry readDirEntry(Common::SeekableReadStream &stream) {
}
bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
- // TODO: PE libraries (If it's used anywhere by a ScummVM game)
+ // First try loading via the NE code
+ if (loadFromNE(fileName, dirEntry))
+ return true;
+ // Then try loading via the PE code
+ return loadFromPE(fileName, dirEntry);
+}
+
+bool WinFont::loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
Common::NEResources exe;
if (!exe.loadFromEXE(fileName))
@@ -89,44 +97,53 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry
return false;
}
- uint16 numFonts = fontDirectory->readUint16LE();
+ uint32 fontId = getFontIndex(*fontDirectory, dirEntry);
+
+ delete fontDirectory;
- // Probably not possible, so this is really a sanity check
- if (numFonts == 0) {
- warning("No fonts in '%s'", fileName.c_str());
+ // Couldn't match the face name
+ if (fontId == 0xffffffff) {
+ warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
return false;
}
- // Scour the directory for our matching name
- int fontId = -1;
- for (uint16 i = 0; i < numFonts; i++) {
- uint16 id = fontDirectory->readUint16LE();
+ // Actually go get our font now...
+ Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId);
+ if (!fontStream) {
+ warning("Could not find font %d in %s", fontId, fileName.c_str());
+ return false;
+ }
- if (dirEntry.faceName.empty()) {
- // Use the first name when empty
- fontId = id;
- break;
- }
+ bool ok = loadFromFNT(*fontStream);
+ delete fontStream;
+ return ok;
+}
- WinFontDirEntry entry = readDirEntry(*fontDirectory);
+bool WinFont::loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
+ Common::PEResources exe;
- if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) {
- // Match!
- fontId = id;
- break;
- }
+ if (!exe.loadFromEXE(fileName))
+ return false;
+
+ // Let's pull out the font directory
+ Common::SeekableReadStream *fontDirectory = exe.getResource(Common::kPEFontDir, Common::String("FONTDIR"));
+ if (!fontDirectory) {
+ warning("No font directory in '%s'", fileName.c_str());
+ return false;
}
+ uint32 fontId = getFontIndex(*fontDirectory, dirEntry);
+
delete fontDirectory;
// Couldn't match the face name
- if (fontId < 0) {
+ if (fontId == 0xffffffff) {
warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
return false;
}
// Actually go get our font now...
- Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId);
+ Common::SeekableReadStream *fontStream = exe.getResource(Common::kPEFont, fontId);
if (!fontStream) {
warning("Could not find font %d in %s", fontId, fileName.c_str());
return false;
@@ -137,6 +154,32 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry
return ok;
}
+uint32 WinFont::getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry) {
+ uint16 numFonts = stream.readUint16LE();
+
+ // Probably not possible, so this is really a sanity check
+ if (numFonts == 0) {
+ warning("No fonts in exe");
+ return 0xffffffff;
+ }
+
+ // Scour the directory for our matching name
+ for (uint16 i = 0; i < numFonts; i++) {
+ uint16 id = stream.readUint16LE();
+
+ // Use the first name when empty
+ if (dirEntry.faceName.empty())
+ return id;
+
+ WinFontDirEntry entry = readDirEntry(stream);
+
+ if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) // Match!
+ return id;
+ }
+
+ return 0xffffffff;
+}
+
bool WinFont::loadFromFNT(const Common::String &fileName) {
Common::File file;
diff --git a/graphics/fonts/winfont.h b/graphics/fonts/winfont.h
index b23455e2d5..fbe4a778e2 100644
--- a/graphics/fonts/winfont.h
+++ b/graphics/fonts/winfont.h
@@ -69,6 +69,10 @@ public:
void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
private:
+ bool loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry);
+ bool loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry);
+
+ uint32 getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry);
bool loadFromFNT(Common::SeekableReadStream &stream);
char indexToCharacter(uint16 index) const;
uint16 characterToIndex(byte character) const;
diff --git a/graphics/module.mk b/graphics/module.mk
index c962f0617d..cb3a07e691 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -23,7 +23,8 @@ MODULE_OBJS := \
surface.o \
thumbnail.o \
VectorRenderer.o \
- VectorRendererSpec.o
+ VectorRendererSpec.o \
+ wincursor.o
ifdef USE_SCALERS
MODULE_OBJS += \
diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp
new file mode 100644
index 0000000000..d3c9414e03
--- /dev/null
+++ b/graphics/wincursor.cpp
@@ -0,0 +1,317 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/ptr.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/winexe_ne.h"
+#include "common/winexe_pe.h"
+
+#include "graphics/wincursor.h"
+
+namespace Graphics {
+
+WinCursor::WinCursor() {
+ _width = 0;
+ _height = 0;
+ _hotspotX = 0;
+ _hotspotY = 0;
+ _surface = 0;
+ _keyColor = 0;
+ memset(_palette, 0, 256 * 3);
+}
+
+WinCursor::~WinCursor() {
+ clear();
+}
+
+uint16 WinCursor::getWidth() const {
+ return _width;
+}
+
+uint16 WinCursor::getHeight() const {
+ return _height;
+}
+
+uint16 WinCursor::getHotspotX() const {
+ return _hotspotX;
+}
+
+uint16 WinCursor::getHotspotY() const {
+ return _hotspotY;
+}
+
+byte WinCursor::getKeyColor() const {
+ return _keyColor;
+}
+
+bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
+ clear();
+
+ _hotspotX = stream.readUint16LE();
+ _hotspotY = stream.readUint16LE();
+
+ // Check header size
+ if (stream.readUint32LE() != 40)
+ return false;
+
+ // Check dimensions
+ _width = stream.readUint32LE();
+ _height = stream.readUint32LE() / 2;
+
+ if (_width & 3) {
+ // Cursors should always be a power of 2
+ // Of course, it wouldn't be hard to handle but if we have no examples...
+ warning("Non-divisible-by-4 width cursor found");
+ return false;
+ }
+
+ // Color planes
+ if (stream.readUint16LE() != 1)
+ return false;
+
+ // Only 1bpp and 8bpp supported
+ uint16 bitsPerPixel = stream.readUint16LE();
+ if (bitsPerPixel != 1 && bitsPerPixel != 8)
+ return false;
+
+ // Compression
+ if (stream.readUint32LE() != 0)
+ return false;
+
+ // Image size + X resolution + Y resolution
+ stream.skip(12);
+
+ uint32 numColors = stream.readUint32LE();
+
+ // If the color count is 0, then it uses up the maximum amount
+ if (numColors == 0)
+ numColors = 1 << bitsPerPixel;
+
+ // Reading the palette
+ stream.seek(40 + 4);
+ for (uint32 i = 0 ; i < numColors; i++) {
+ _palette[i * 3 + 2] = stream.readByte();
+ _palette[i * 3 + 1] = stream.readByte();
+ _palette[i * 3 ] = stream.readByte();
+ stream.readByte();
+ }
+
+ // Reading the bitmap data
+ uint32 dataSize = stream.size() - stream.pos();
+ byte *initialSource = new byte[dataSize];
+ stream.read(initialSource, dataSize);
+
+ // Parse the XOR map
+ const byte *src = initialSource;
+ _surface = new byte[_width * _height];
+ byte *dest = _surface + _width * (_height - 1);
+ uint32 imagePitch = _width * bitsPerPixel / 8;
+
+ for (uint32 i = 0; i < _height; i++) {
+ byte *rowDest = dest;
+
+ if (bitsPerPixel == 1) {
+ // 1bpp
+ for (uint32 j = 0; j < (_width / 8); j++) {
+ byte p = src[j];
+
+ for (int k = 0; k < 8; k++, rowDest++, p <<= 1) {
+ if ((p & 0x80) == 0x80)
+ *rowDest = 1;
+ else
+ *rowDest = 0;
+ }
+ }
+ } else {
+ // 8bpp
+ memcpy(rowDest, src, _width);
+ }
+
+ dest -= _width;
+ src += imagePitch;
+ }
+
+ // Calculate our key color
+ if (numColors < 256) {
+ // If we're not using the maximum colors in a byte, we can fit it in
+ _keyColor = numColors;
+ } else {
+ // HACK: Try to find a color that's not being used so it can become
+ // our keycolor. It's quite impossible to fit 257 entries into 256...
+ for (uint32 i = 0; i < 256; i++) {
+ for (int j = 0; j < _width * _height; j++) {
+ // TODO: Also check to see if the space is transparent
+
+ if (_surface[j] == i)
+ break;
+
+ if (j == _width * _height - 1) {
+ _keyColor = i;
+ i = 256;
+ break;
+ }
+ }
+ }
+ }
+
+ // Now go through and apply the AND map to get the transparency
+ uint32 andWidth = (_width + 7) / 8;
+ src += andWidth * (_height - 1);
+
+ for (uint32 y = 0; y < _height; y++) {
+ for (uint32 x = 0; x < _width; x++)
+ if (src[x / 8] & (1 << (7 - x % 8)))
+ _surface[y * _width + x] = _keyColor;
+
+ src -= andWidth;
+ }
+
+ delete[] initialSource;
+ return true;
+}
+
+void WinCursor::clear() {
+ delete[] _surface; _surface = 0;
+}
+
+WinCursorGroup::WinCursorGroup() {
+}
+
+WinCursorGroup::~WinCursorGroup() {
+ for (uint32 i = 0; i < cursors.size(); i++)
+ delete cursors[i].cursor;
+}
+
+WinCursorGroup *WinCursorGroup::createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kNEGroupCursor, id));
+
+ if (!stream || stream->size() <= 6)
+ return 0;
+
+ stream->skip(4);
+ uint32 cursorCount = stream->readUint16LE();
+ if ((uint32)stream->size() < (6 + cursorCount * 16))
+ return 0;
+
+ WinCursorGroup *group = new WinCursorGroup();
+ group->cursors.reserve(cursorCount);
+
+ for (uint32 i = 0; i < cursorCount; i++) {
+ stream->readUint16LE(); // width
+ stream->readUint16LE(); // height
+
+ // Plane count
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ // Bits per pixel
+ // NE cursors can only be 1bpp
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ stream->readUint32LE(); // data size
+ uint32 cursorId = stream->readUint32LE();
+
+ Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kNECursor, cursorId));
+ if (!cursorStream) {
+ delete group;
+ return 0;
+ }
+
+ WinCursor *cursor = new WinCursor();
+ if (!cursor->readFromStream(*cursorStream)) {
+ delete cursor;
+ delete group;
+ return 0;
+ }
+
+ CursorItem item;
+ item.id = cursorId;
+ item.cursor = cursor;
+ group->cursors.push_back(item);
+ }
+
+ return group;
+}
+
+WinCursorGroup *WinCursorGroup::createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kPEGroupCursor, id));
+
+ if (!stream || stream->size() <= 6)
+ return 0;
+
+ stream->skip(4);
+ uint32 cursorCount = stream->readUint16LE();
+ if ((uint32)stream->size() < (6 + cursorCount * 14))
+ return 0;
+
+ WinCursorGroup *group = new WinCursorGroup();
+ group->cursors.reserve(cursorCount);
+
+ for (uint32 i = 0; i < cursorCount; i++) {
+ stream->readUint16LE(); // width
+ stream->readUint16LE(); // height
+
+ // Plane count
+ if (stream->readUint16LE() != 1) {
+ delete group;
+ return 0;
+ }
+
+ stream->readUint16LE(); // bits per pixel
+ stream->readUint32LE(); // data size
+ uint32 cursorId = stream->readUint16LE();
+
+ Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kPECursor, cursorId));
+ if (!cursorStream) {
+ delete group;
+ return 0;
+ }
+
+ WinCursor *cursor = new WinCursor();
+ if (!cursor->readFromStream(*cursorStream)) {
+ delete cursor;
+ delete group;
+ return 0;
+ }
+
+ CursorItem item;
+ item.id = cursorId;
+ item.cursor = cursor;
+ group->cursors.push_back(item);
+ }
+
+ return group;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/wincursor.h b/graphics/wincursor.h
new file mode 100644
index 0000000000..ca0abf6fe1
--- /dev/null
+++ b/graphics/wincursor.h
@@ -0,0 +1,105 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_WINCURSOR_H
+#define GRAPHICS_WINCURSOR_H
+
+#include "common/array.h"
+#include "common/winexe.h"
+
+namespace Common {
+ class NEResources;
+ class PEResources;
+ class SeekableReadStream;
+}
+
+namespace Graphics {
+
+/** A Windows cursor. */
+class WinCursor {
+public:
+ WinCursor();
+ ~WinCursor();
+
+ /** Return the cursor's width. */
+ uint16 getWidth() const;
+ /** Return the cursor's height. */
+ uint16 getHeight() const;
+ /** Return the cursor's hotspot's x coordinate. */
+ uint16 getHotspotX() const;
+ /** Return the cursor's hotspot's y coordinate. */
+ uint16 getHotspotY() const;
+ /** Return the cursor's transparent key. */
+ byte getKeyColor() const;
+
+ const byte *getSurface() const { return _surface; }
+ const byte *getPalette() const { return _palette; }
+
+ /** Read the cursor's data out of a stream. */
+ bool readFromStream(Common::SeekableReadStream &stream);
+
+private:
+ byte *_surface;
+ byte _palette[256 * 3];
+
+ uint16 _width; ///< The cursor's width.
+ uint16 _height; ///< The cursor's height.
+ uint16 _hotspotX; ///< The cursor's hotspot's x coordinate.
+ uint16 _hotspotY; ///< The cursor's hotspot's y coordinate.
+ byte _keyColor; ///< The cursor's transparent key
+
+ /** Clear the cursor. */
+ void clear();
+};
+
+/**
+ * A structure holding an array of cursors from a single Windows Executable cursor group.
+ *
+ * Windows lumps different versions of the same cursors/icons together and decides which one
+ * to use based on the screen's color depth and resolution. For instance, one cursor group
+ * could hold a 1bpp 16x16 cursorand a 8bpp 16x16 cursor. This will hold all cursors in the
+ * group. This class should be used to actually parse the cursors, whereas WinCursor is just
+ * the representation used by this struct to store the cursors.
+ */
+struct WinCursorGroup {
+ WinCursorGroup();
+ ~WinCursorGroup();
+
+ struct CursorItem {
+ Common::WinResourceID id;
+ WinCursor *cursor;
+ };
+
+ Common::Array<CursorItem> cursors;
+
+ /** Create a cursor group from an NE EXE, returns 0 on failure */
+ static WinCursorGroup *createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id);
+ /** Create a cursor group from an PE EXE, returns 0 on failure */
+ static WinCursorGroup *createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id);
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index ee83ca620c..026370abf1 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -1193,7 +1193,7 @@ void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) {
/**********************************************************
* Screen/overlay management
*********************************************************/
-void ThemeEngine::updateScreen() {
+void ThemeEngine::updateScreen(bool render) {
if (!_bufferQueue.empty()) {
_vectorRenderer->setSurface(&_backBuffer);
@@ -1218,7 +1218,8 @@ void ThemeEngine::updateScreen() {
_screenQueue.clear();
}
- renderDirtyScreen();
+ if (render)
+ renderDirtyScreen();
}
void ThemeEngine::addDirtyRect(Common::Rect r) {
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index e852760e44..78ea06f3b6 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -32,7 +32,7 @@
#include "graphics/surface.h"
#include "graphics/font.h"
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.2"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.3"
namespace Graphics {
struct DrawStep;
@@ -280,7 +280,7 @@ public:
* It processes all the drawing queues and then copies dirty rects
* in the current Screen surface to the overlay.
*/
- void updateScreen();
+ void updateScreen(bool render = true);
/** @name FONT MANAGEMENT METHODS */
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index 70d81a962e..e3523d11e8 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -861,30 +861,50 @@ bool ThemeParser::resolutionCheck(const Common::String &resolution) {
return true;
Common::StringTokenizer globTokenizer(resolution, ", ");
- Common::String cur, w, h;
- bool definedRes = false;
+ Common::String cur;
while (!globTokenizer.empty()) {
- bool ignore = false;
cur = globTokenizer.nextToken();
- if (cur[0] == '-') {
- ignore = true;
- cur.deleteChar(0);
+ bool lt;
+ int val;
+
+ if (cur.size() < 5) {
+ warning("Invalid theme 'resolution' token '%s'", resolution.c_str());
+ return false;
+ }
+
+ if (cur[0] == 'x') {
+ val = g_system->getOverlayWidth();
+ } else if (cur[0] == 'y') {
+ val = g_system->getOverlayHeight();
+ } else {
+ warning("Error parsing theme 'resolution' token '%s'", resolution.c_str());
+ return false;
+ }
+
+ if (cur[1] == '<') {
+ lt = true;
+ } else if (cur[1] == '>') {
+ lt = false;
} else {
- definedRes = true;
+ warning("Error parsing theme 'resolution' token '%s'", resolution.c_str());
+ return false;
}
- Common::StringTokenizer resTokenizer(cur, "x");
- w = resTokenizer.nextToken();
- h = resTokenizer.nextToken();
+ int token = atoi(cur.c_str() + 2);
- if ((w == "X" || atoi(w.c_str()) == g_system->getOverlayWidth()) &&
- (h == "Y" || atoi(h.c_str()) == g_system->getOverlayHeight()))
- return !ignore;
+ // check inverse for unfulfilled requirements
+ if (lt) {
+ if (val >= token)
+ return false;
+ } else {
+ if (val <= token)
+ return false;
+ }
}
- return !definedRes;
+ return true;
}
} // End of namespace GUI
diff --git a/gui/credits.h b/gui/credits.h
index 926adf4c9c..93ce99acb6 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -210,6 +210,7 @@ static const char *credits[] = {
"",
"C1""Backend Teams",
"C1""Android",
+"C0""Andre Heider",
"C0""Angus Lees",
"",
"C1""Dreamcast",
@@ -294,6 +295,23 @@ static const char *credits[] = {
"C0""Fredrik Wendel",
"C2""(retired)",
"",
+"C1""Website (maintenance)",
+"C0""James Brown",
+"C2""IRC Logs maintainer",
+"C0""Thierry Crozat",
+"C2""Wiki maintainer",
+"C0""Andre Heider",
+"C2""Buildbot maintainer",
+"C0""Max Horn",
+"C2""Forum, IRC channel and Mailing list maintainer",
+"C0""Joost Peters",
+"C2""Doxygen Project Documentation maintainer",
+"C0""Jordi Vilalta Prat",
+"C2""Wiki maintainer",
+"C0""Eugene Sandulenko",
+"C2""Forum, IRC channel, Screen Shots and Mailing list maintainer",
+"C0""John Willis",
+"",
"C1""Website (content)",
"C0""All active team members",
"C0""",
@@ -445,6 +463,8 @@ static const char *credits[] = {
"C2""ScummVM logo",
"C0""Raina",
"C2""ScummVM forum buttons",
+"C0""William Claydon",
+"C2""Skins for doxygen and wiki",
"",
"C1""Code contributions",
"C0""Ori Avtalion",
@@ -456,7 +476,7 @@ static const char *credits[] = {
"C0""Martin Doucha",
"C2""CinE engine objectification",
"C0""Thomas Fach-Pedersen",
-"C2""ProTracker module player",
+"C2""ProTracker module player, Smacker video decoder",
"C0""Tobias Gunkel",
"C2""Sound support for C64 version of MM/Zak, Loom PCE support",
"C0""Janne Huttunen",
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 7644cbe7b2..3ad4b2ee18 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -201,14 +201,15 @@ void GuiManager::redraw() {
_theme->clearAll();
_theme->openDialog(true, ThemeEngine::kShadingNone);
- for (i = 0; i < _dialogStack.size() - 1; i++) {
+ for (i = 0; i < _dialogStack.size() - 1; i++)
_dialogStack[i]->drawDialog();
- }
_theme->finishBuffering();
+ // fall through
+
case kRedrawOpenDialog:
- _theme->updateScreen();
+ _theme->updateScreen(false);
_theme->openDialog(true, shading);
_dialogStack.top()->drawDialog();
_theme->finishBuffering();
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 3236071055..2716e6ca72 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1,5 +1,5 @@
"<?xml version = '1.0'?>"
-"<layout_info resolution='-320xY,-256x240,-Xx272,-544x332,-Xx350'> "
+"<layout_info resolution='y>399'> "
"<globals> "
"<def var='Line.Height' value='16' /> "
"<def var='Font.Height' value='16' /> "
@@ -789,7 +789,7 @@
"</layout> "
"</dialog> "
"</layout_info> "
-"<layout_info resolution='320xY,256x240,Xx272,544x332,Xx350'> "
+"<layout_info resolution='y<400'> "
"<globals> "
"<def var='Line.Height' value='12' /> "
"<def var='Font.Height' value='10' /> "
@@ -1602,21 +1602,21 @@
"<font id='text_default' "
"file='helvb12.bdf' "
"/> "
-"<font resolution='320xY,256x240' "
+"<font resolution='y<400' "
"id='text_default' "
"file='clR6x12.bdf' "
"/> "
"<font id='text_button' "
"file='helvb12.bdf' "
"/> "
-"<font resolution='320xY,256x240' "
+"<font resolution='y<400' "
"id='text_button' "
"file='clR6x12.bdf' "
"/> "
"<font id='text_normal' "
"file='helvb12.bdf' "
"/> "
-"<font resolution='320xY,256x240' "
+"<font resolution='y<400' "
"id='text_normal' "
"file='clR6x12.bdf' "
"/> "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 9fd2c187fd..4dbedd4f14 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index f0276969fe..17e934d5ef 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.2:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.8.3:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_gfx.stx b/gui/themes/scummclassic/classic_gfx.stx
index d672db2540..3fd00abbb9 100644
--- a/gui/themes/scummclassic/classic_gfx.stx
+++ b/gui/themes/scummclassic/classic_gfx.stx
@@ -46,21 +46,21 @@
<font id = 'text_default'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_default'
file = 'clR6x12.bdf'
/>
<font id = 'text_button'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_button'
file = 'clR6x12.bdf'
/>
<font id = 'text_normal'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_normal'
file = 'clR6x12.bdf'
/>
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 416ffb30eb..f09c29e360 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -23,7 +23,7 @@
- $Id$
-
-->
-<layout_info resolution = '-320xY, -256x240, -Xx272, -544x332, -Xx350'>
+<layout_info resolution = 'y>399'>
<globals>
<def var = 'Line.Height' value = '16' />
<def var = 'Font.Height' value = '16' />
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index fe0eb66b8d..a440be7694 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -23,7 +23,7 @@
- $Id$
-
-->
-<layout_info resolution = "320xY, 256x240, Xx272, 544x332, Xx350">
+<layout_info resolution = 'y<400'>
<globals>
<def var = 'Line.Height' value = '12' />
<def var = 'Font.Height' value = '10' />
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index f4e18ef00c..77951475e6 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index b8f41fc207..f947a5685a 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.2:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.8.3:ScummVM Modern Theme:No Author]
diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx
index cfe00a7016..a325d4982b 100644
--- a/gui/themes/scummmodern/scummmodern_gfx.stx
+++ b/gui/themes/scummmodern/scummmodern_gfx.stx
@@ -108,21 +108,21 @@
<font id = 'text_default'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_default'
file = 'clR6x12.bdf'
/>
<font id = 'text_button'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_button'
file = 'clR6x12.bdf'
/>
<font id = 'text_normal'
file = 'helvb12.bdf'
/>
- <font resolution = '320xY, 256x240'
+ <font resolution = 'y<400'
id = 'text_normal'
file = 'clR6x12.bdf'
/>
@@ -178,7 +178,7 @@
<!-- <defaults fill = 'gradient' fg_color = 'white'/> -->
<cursor file = 'cursor.bmp' hotspot = '0, 0' scale = '3'/>
- <cursor resolution = '320xY, 256x240' file = 'cursor_small.bmp' hotspot = '0, 0' scale = '3'/>
+ <cursor resolution = 'y<400' file = 'cursor_small.bmp' hotspot = '0, 0' scale = '3'/>
<!-- Selection (text or list items) -->
<drawdata id = 'text_selection' cache = 'false'>
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 879be2aafe..32d6d19d1a 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -23,7 +23,7 @@
- $Id$
-
-->
-<layout_info resolution = '-320xY, -256x240, -Xx272, -544x332, -Xx350'>
+<layout_info resolution = 'y>399'>
<globals>
<def var = 'Line.Height' value = '16' />
<def var = 'Font.Height' value = '16' />
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 3a7a4b63b9..06916a80f1 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -23,7 +23,7 @@
- $Id$
-
-->
-<layout_info resolution = "320xY, 256x240, Xx272, 544x332, Xx350">
+<layout_info resolution = 'y<400'>
<globals>
<def var = 'Line.Height' value = '12' />
<def var = 'Font.Height' value = '10' />
diff --git a/tools/credits.pl b/tools/credits.pl
index b72d38bcd1..bd1060fb76 100755
--- a/tools/credits.pl
+++ b/tools/credits.pl
@@ -702,6 +702,7 @@ begin_credits("Credits");
begin_section("Backend Teams");
begin_section("Android");
+ add_person("Andre Heider", "dhewg", "");
add_person("Angus Lees", "Gus", "");
end_section();
@@ -796,6 +797,19 @@ begin_credits("Credits");
add_person("Fredrik Wendel", "", "(retired)");
end_persons();
end_section();
+
+ begin_section("Website (maintenance)");
+ begin_persons();
+ add_person("James Brown", "Ender", "IRC Logs maintainer");
+ add_person("Thierry Crozat", "criezy", "Wiki maintainer");
+ add_person("Andre Heider", "dhewg", "Buildbot maintainer");
+ add_person("Max Horn", "Fingolfin", "Forum, IRC channel and Mailing list maintainer");
+ add_person("Joost Peters", "JoostP", "Doxygen Project Documentation maintainer");
+ add_person("Jordi Vilalta Prat", "jvprat", "Wiki maintainer");
+ add_person("Eugene Sandulenko", "sev", "Forum, IRC channel, Screen Shots and Mailing list maintainer");
+ add_person("John Willis", "DJWillis", "");
+ end_persons();
+ end_section();
begin_section("Website (content)");
add_paragraph("All active team members");
@@ -949,6 +963,7 @@ begin_credits("Credits");
add_person("David Jensen", "Tyst", "SVG logo conversion");
add_person("Jean Marc Gimenez", "", "ScummVM logo");
add_person("", "Raina", "ScummVM forum buttons");
+ add_person("William Claydon", "billwashere", "Skins for doxygen and wiki");
end_persons();
end_section();
@@ -958,7 +973,7 @@ begin_credits("Credits");
add_person("Stuart Caie", "", "Decoders for Amiga and AtariST data files (AGOS engine)");
add_person("Paolo Costabel", "", "PSP port contributions");
add_person("Martin Doucha", "next_ghost", "CinE engine objectification");
- add_person("Thomas Fach-Pedersen", "madmoose", "ProTracker module player");
+ add_person("Thomas Fach-Pedersen", "madmoose", "ProTracker module player, Smacker video decoder");
add_person("Tobias Gunkel", "hennymcc", "Sound support for C64 version of MM/Zak, Loom PCE support");
add_person("Janne Huttunen", "", "V3 actor mask support, Dig/FT SMUSH audio");
add_person("Kov&aacute;cs Endre J&aacute;nos", "", "Several fixes for Simon1");