diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/fs/ds/ds-fs.cpp | 3 | ||||
-rw-r--r-- | backends/platform/ds/arm9/dist/readme_ds.txt | 840 | ||||
-rw-r--r-- | backends/platform/ds/arm9/makefile | 52 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/cdaudio.h | 2 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/dsmain.cpp | 706 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/dsmain.h | 13 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/dsoptions.cpp | 283 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/dsoptions.h | 13 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/gbampsave.cpp | 4 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/osystem_ds.cpp | 232 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/osystem_ds.h | 26 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/portdefs.h | 5 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/ramsave.cpp | 10 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/ramsave.h | 4 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/touchkeyboard.cpp | 30 | ||||
-rw-r--r-- | backends/platform/ds/arm9/source/touchkeyboard.h | 1 | ||||
-rw-r--r-- | backends/platform/ds/logog.bmp | bin | 0 -> 630 bytes | |||
-rw-r--r-- | backends/platform/ds/makefile | 20 |
18 files changed, 1936 insertions, 308 deletions
diff --git a/backends/fs/ds/ds-fs.cpp b/backends/fs/ds/ds-fs.cpp index d0686f6414..f2ed9b64e3 100644 --- a/backends/fs/ds/ds-fs.cpp +++ b/backends/fs/ds/ds-fs.cpp @@ -416,6 +416,7 @@ FILE* std_fopen(const char* name, const char* mode) { if (DS::isGBAMPAvailable()) { FAT_chdir("/"); + // Turn all back slashes into forward slashes for gba_nds_fat char* p = realName; while (*p) { if (*p == '\\') *p = '/'; @@ -441,6 +442,7 @@ FILE* std_fopen(const char* name, const char* mode) { int r = 0; while (handle[r].used) r++; +#ifdef GBA_SRAM_SAVE if (strchr(mode, 'w')) { // consolePrintf("Writing %s\n", realName); handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true); @@ -448,6 +450,7 @@ FILE* std_fopen(const char* name, const char* mode) { // consolePrintf("Reading %s\n", realName); handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false); } +#endif if (handle[r].sramFile) { handle[r].used = true; diff --git a/backends/platform/ds/arm9/dist/readme_ds.txt b/backends/platform/ds/arm9/dist/readme_ds.txt new file mode 100644 index 0000000000..f77da418c9 --- /dev/null +++ b/backends/platform/ds/arm9/dist/readme_ds.txt @@ -0,0 +1,840 @@ + + + + The official port of ScummVM + to the Nintendo DS handheld console + by Neil Millstone (agentq) + http://scummvm.drunkencoders.com +------------------------------------------------------------------------ +Visit the main ScummVM website <http://www.scummvm.org> + + + + + Contents + ------------------------------------------------------------------------ + + + + * What's New? + * What is ScummVM DS? + * Features + * Screenshots + * How to Get ScummVM DS Onto Your DS - Simple Explanation + o Using a CF/SD/Mini SD/Micro SD card reader and a DLDI driver + o Instructions for specific card readers + * What to do if saving doesn't work or your card gets corruped - + force SRAM saves + * How to use ScummVM DS + * Game Specific Controls + * DS Options Screen + * Which games are compatible with ScummVM DS + * Predictive dictionary for Sierra AGI games + * Converting your CD audio + * Converting speech to MP3 format + * Frequently Asked Questions + * Downloads + * Contributors + * Donations and Getting Help + * Building from Sources + + + + What's New? + ------------------------------------------------------------------------ + +ScummVM DS 0.12.0 + + * New games supported: Lure of the Temptress, Nippon Safes, Lost in Time. + * New laptop-style trackpad input method. Uses relative movement when you + drag on the touch screen. + * New option which allows you to drag to hover, tap the touch screen to + click, and double tap the screen to right click. + * Reorganised DS Options screen into three tabs for clearer navigation + * New top screen scaling options let you choose the scaling factor used + on startup. + * The usual round of bug fixes. + + +ScummVM DS 0.11.1 + + * Bugfix release - No new DS port features + + +ScummVM DS 0.11.0 + + * New games supported: Elvira 1 and 2, Waxworks (Amiga version) + * Software scaler for improved image quality. Turn it on using the DS options + screen (press select during the game). Thanks to Tramboi and Robin Watts for + this feature! + * Function keys added to virtual keyboard (used in AGI games) + * Plenty of bug fixes + + What is ScummVM DS? + ------------------------------------------------------------------------ + +ScummVM DS is a part of the ScummVM project. The ScummVM project is an +attempt to re-engineer many classic point and click adventure games of the +80s and 90s to run on modern computer hardware. Technology has changed a +lot since these games were written, and so ScummVM attempts to replicate the +gameplay of the original games in exacting details, without any of the original +code that the game ran on. ScummVM needs a copy of the original game, in order +to take the graphics, sound, and scripts that made the game work. + +ScummVM is written in such a way that it can be 'ported' from one type of +machine to another, and ScummVM DS is a port of ScummVM to the Nintendo DS +handheld games console. + + + Features + ------------------------------------------------------------------------ + + * Runs nearly all of Lucasarts' SCUMM games up to and including Sam + & Max Hit the Road + * Runs many non-Lucasarts point-and-click adventures too + * Supports sound + * Provides a GUI to change settings and choose games + * Supports using the DS touch screen for controls + * Suports saving games to compatible flash cards + * All games run at pretty much full speed + + + + + + How to Get ScummVM DS Onto Your DS - Simple Explanation + ------------------------------------------------------------------------ + +Nintendo don't want you to run ScummVM on your DS. They control +which companies can make games on the DS, and there is an expensive +process to go through in order to be licenced. Having to pay for +this would prevent me from giving away ScummVM for free. + +So, the result is that to run ScummVM on your DS you'll need an +unofficial card reader. There are many of these, and all are different. +Popular models at the time of writing are the R4DS and the M3DS Real, +but many different models work. You need to buy one of these, and at +MicroSD card to go with it. + +There are also slot-2 card readers which fit into the bottom slot on +your DS, usually used for Game Boy Advance games. These are less common +these days, and although they have certain advantages, the details of +these are beyond the scope of this website. Information on these is +quite easy to find by searching. + +Once you have your card reader and a MicroSD card, you will also need +a copy of the game you want to run. ScummVM can run a large variety +of games, but you must own a real boxed copy of the game. These games +are still under copyright, and it is illegal to copy them from a friend +or download them from the Internet without paying. The exception to +this are the three Revolution Software games. These are 'Beneath a +Steel Sky', 'Lure of the Temptress' and 'Flight of the Amazon Queen'. +Revolution have kindly allowed us to give these games away for free. +You can download them from the main ScummVM site at +<http://www.scummvm.org/downloads.php> + +NOTE: Previous version of ScummVM DS supported a method which used a +zip file to run games on unsupported flash card readers. This method +is no longer supported. + + + How to Get ScummVM DS Onto Your DS - Using a CF/SD/Mini SD/Micro + SD card reader and a DLDI driver + ------------------------------------------------------------------------ + +ScummVM DS needs something called a DLDI driver to run on each make +and model of card reader. Many modern card readers (R4DS, M3 DS Real) +handle this autmatically and for those, you don't have to do anything. +Just running ScummVM on the card will handle this step for you. +For others, you will need to follow the steps in this section before +ScummVM DS will work. + +All DS card readers are different in the way that they work. In order to +support many different card readers, ScummVM DS uses a DLDI driver installed +into the ScummVM DS code. This is done using a program called DLDITool +which you can download and run on your computer. Each DLDI driver is +designed to tell ScummVM DS how to use a specific type of card reader. +These drivers can be used with any homebrew program which supports the +DLDI interface. + +While each card reader should work with these instructions, there are +some exceptions. Please read the card reader notes +section to see if there is any specific information about your card reader. + +Here is what you need to do: + + * Visit the DLDI page <http://dldi.drunkencoders.com/> and + download the executable for DLDITool for your operating system + (versions are available for Windows, Linux, and MacOS) + * Download the DLDI for your card reader. This is the big table at + the top of the page. The first column marked DLDI is the one you + want. You should get a single file with a .dldi extension. + * Extract DLDITool into a folder, and put the DLDI of your choice in + the same folder. + * If you're using the command line version of DLDITool enter the + following at a command prompt: + + dlditool <dldiname> <scummvm nds name> + + + If you're using the Windows GUI version, double click on + dlditool32.exe, select your card reader from the box, drag your + ScummVM binaries (either the .nds, or the .ds.gba version + depending on your card reader. I think only Supercards use the + .ds.gba files) into the lower box, then click patch. + + Either way, you should see 'Patched Successfully'. If you don't, + you're doing something wrong. + + You need to patch one of the builds labeled A - F depending on + which game you want to run. See the table on the ScummVM DS + website to see which games are supported by which build. + + * Put the patched .nds or .ds.gba files on your flash card. If + you're using the Supercard, you will need to use the .ds.gba + files, but rename them to .nds. + * Put your game data in any folder on the card. Do NOT use a zip file. + * Boot up your DS and run ScummVM. + * Click 'Add Game', browse to the folder with your game data, click + 'Choose', then 'OK'. Click 'Start' to run the game. + +If your copy of ScummVM DS has been successfully patched, you will get a +message on the top screen that looks like this: + + DLDI Device: + GBA Movie Player (Compact Flash) + +The message should show the name of your card reader. If it is wrong, +you have used the wrong DLDI file. + +If you haven't patched your .nds file, you will get the following message + + DLDI Driver not patched! + DLDI Initialise failed. + +In this case, you've made a mistake following the above instructions, or +have patched the wrong file. + +You may also see the following message: + + DLDI Device: + GBA Movie Player (Compact Flash) + DLDI Initialise failed. + +In this case, the driver did not start up correctly. The driver is +probably broken, or you've used the wrong one for your card reader. + +In the case of the Supercard, M3 Lite and DS Link, there are several +drivers available. You might want to try one of the others. + +This version of ScummVM DS will run on any card reader that has a DLDI +driver available. If yours doesn't, you need to pressure your card +reader manufacturer to release one. + +DO NOT EMAIL ME TO ASK ME TO CREATE A DRIVER FOR YOUR CARD READER, I +CANNOT DO THIS. + + + How to Get ScummVM DS Onto Your DS - Instructions for specific + card readers + ------------------------------------------------------------------------ + + * *GBAMP CF:* You need to upload replacement firmware to your card + reader before it will work. You can download the firmware program + here <http://chishm.drunkencoders.com/NDSMP/index.html>. Name your + .nds file _BOOT_MP.nds. + * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game + Manager in order to avoid an annoying message when you boot your + M3. Use the default options to copy the file. Be sure to press 'A' + in the M3 browser to start the .nds file, and not 'Start', or it + won't work. + * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game + Manager in order to avoid an annoying message when you boot your + M3. Use the default options to copy the file. Be sure to press 'A' + in the M3 browser to start the .nds file, and not 'Start', or it + won't work. + * *Supercard CF/SD (slot-2):* Use the .ds.gba files to run ScummVM + on the Supercard. Other than that, just follow the instructions as + normal. + * *Supercard Lite (slot-2):* It has been reported that only the + standard Supercard driver and the Moonshell version work with + ScummVM DS. + * *Datel Max Media Dock: * If you haven't already, upgrade your + firmware to the latest version. The firmware that came with my Max + Media Dock was unable to run ScummVM DS at all. Click here to + visit Datel's support page and download the latest firmware + <http://us.codejunkies.com/mpds/support.htm> + * *NinjaDS*: There are firmware upgrades for this device, but for + me, ScummVM DS ran straight out of the box. Visit this page + <http://www.ninjads.com/news.html> to download the latest firmware + if you want. If you have installed FlashMe on your DS, it will + make your DS crash on boot when the NinjaDS is inserted. You can + hold the 'select' button during boot to disable FlashMe, which + will allow the NinjaDS to work. Due to this, it is not recommended + to install FlashMe if you use a NinjaDS. + * *EZ-Flash*: This card reader uses .ds.gba files from the ScummVM + archive. Rename them to .nds before patching them with the DLDI + patcher. + * *R4DS*: If you upgrade the firmware for your R4DS to version 1.10 + or later, the card will autmatically DLDI patch the game, meaning + you don't have to use dlditool to patch the .NDS file. This makes + things a lot easier! + * *M3DS Real*: This card autmatically DLDI patches the game, meaning + that you do not need to do this yourself. + + + + Which games are compatible with ScummVM DS? + ------------------------------------------------------------------------ + +I'm glad you asked. Here is a list of the compatible games in version +0.12.0. Demo versions of the games listed should work too. + +Flight of the Amazon Queen, Beneath a Steel Sky, and Lure of the +Temptress have generously been released as freeware by the original +authors, Revolution Software <http://www.revolution.co.uk/>. This is a +great thing and we should support Revolution for being so kind to us. +You can download the game data from the official ScummVM download page +<http://www.scummvm.org/downloads.php>. + +The other games on this list are commercial, and still under copyright, +which means downloading them without paying for it is illegal. You can +probably find a second-hand copy on eBay. Please don't email me to ask +for a copy, as I am unable to send it to you. + +Game Build Notes + +Manic Mansion A + +Zak McKracken and the Alien Mindbenders A + +Indiana Jones and the Last Crusade A + +Loom A + +Passport to Adventure A + +The Secret of Monkey Island A + +Monkey Island 2: LeChuck's Revenge A + +Indiana Jones and the Fate of Atlantis A + +Day of the Tentacle A + +Sam & Max Hit the Road A Some slowdown in a few scenes + when MP3 audio is enabled + +Bear Stormin' (DOS) A + +Fatty Bear's Birthday Surprise (DOS) A + +Fatty Bear's Fun Pack (DOS) A + +Putt-Putt's Fun Pack (DOS) A + +Putt-Putt Goes to the Moon (DOS) A + +Putt-Putt Joins the Parade (DOS) A Can sometimes crash due to low memory + +Beneath a Steel Sky B + +Flight of the Amazon Queen B + +Simon the Sorcerer 1 C Zoomed view does not follow the + speaking character +Simon the Sorcerer 2 C Zoomed view does not follow the + speaking character +Elvira 1 C + +Elvira 2 C + +Waxworks (Amiga version) C + +Gobliiins D + +Gobliins 2 D + +Goblins 3 D + +Ween: The Prophecy D + +Bargon Attack D + +Lost in Time D + +Future Wars D + +All Sierra AGI games. +For a complete list, see this page +<http://wiki.scummvm.org/index.php/AGI> D + +Inherit the Earth E + +The Legend of Kyrandia F Zoomed view does not follow the + speaking character + +Lure of the Temptress G + +Nippon Safes G + +There is no support for Full Throttle, The Dig, or The Curse of Monkey +Island because of memory issues. There simply is not enough RAM on the +DS to run these games. Sorry. Also there is no support for Windows Humongous +Entertainment games. The extra code required to make this work uses up +too much RAM. + + + What to do when saving doesn't work or your card gets corrupted - + forcing SRAM Saves + ------------------------------------------------------------------------ + +This method only works for cards which use the Game Boy Advance slot on the +bottom of your DS. + +If ScummVM DS cannot save games to your SD card, or it causes corruption +when it does, you can force it to use GBA SRAM to save the game. This +uses your flash cart reader's GBA features to save the game to a .sav or +.dat file (depending on the reader). Only slot-2 devices can use SRAM saves, +and only ones with support for GBA games. + +If you want to use SRAM save, just create a text file called scummvm.ini +(or scummvmb.ini, scummvmc.ini for builds B or C) in the root of your +card which contains the following: + +[ds] +forcesramsave=true + +When you boot your game, ScummVM DS will not save games to your SD card +directly, instead it will save to GBA SRAM. On most cards, you need to +transfer the data to your SD card by rebooting and using your card +reader's boot-up menu. Using this method, around four saves can me made. + +One disadvantage of forcing SRAM saves is that your settings won't be +saved. You can add games manually to the ini file so that you don't have +to select them on each boot. Just add a section like the following on +for each game on your card. + +[monkey2] +description=Monkey Island 2: LeChuck's Revenge (English/DOS) +path=mp:/MONKEY2 + + + How to Use ScummVM + ------------------------------------------------------------------------ + +Once you've booted up ScummVM, you'll see the start up screen. + + 1. Tap the 'Add' button with the pen, then browse to the folder + containing your game data. Once you have clicked on your folder, you will + not see any files inside. This is normal, as the folder selector only shows + folders! + + 2. Click the 'Choose' button. + + 3. You will get some options for the game. You can usually just click 'Ok' to + this. + + 4. Now click on the name of the game you want to play from the list and + click 'Start'. Your game will start! + +You can use the B button to skip cutscenes, and the select button to +show an options menu which will let you tweak the DS contols, including +switch between scaled and unscaled video modes. The text is clearer in +the unscaled mode, but the whole game doesn't fit on the screen. To +scroll around, hold either shoulder button and use the D-pad or drag the +screen around with the stylus. Even in scaled mode, a small amount is +missing from the top and bottom of the screen. You can scroll around to +see those areas. The top screen shows a zoomed-in view. This scrolls +around to focus on the character who's speaking, and also follows where +the pen touches the screen. You can change the zoom level by holding one +of the shoulder buttons and pressing B to zoom in and A to zoom out. + +Press the start button for the in-game menu where you can load or save +your game (this works in Lucasarts games, other games vary). Saves will +write directly to your flash card. You can choose the folder where they +are stored using the GUI that appears when you boot up. If you're using +a GBA Flash Cartridge, or an unsupported flash card adaptor, you will be +using GBA SRAM to save your game. Four or five save game will fit in +save RAM. If you save more games than will fit, a warning will appear on +the top screen. When you turn your DS off, the new save will be lost, +and only the first ones you saved will be present. + +Many of the games use both mouse buttons. Usually the right button often +performs the default action on any object you click on. To simulate this +with the DS pen, you can switch the input into one of three modes. Press +left on the D-pad to enable the left mouse button. Press right on the +D-pad to enable the right mouse button. Press up on the D-pad to enable +hover mode. In this mode, you won't click on anything, just hover the +mouse cursor over it. This lets you pick out active objects in the scene. + +An icon on the top screen will show you which mode you're in. + +In hover mode, there are some additional controls. While holding the pen +on the screen, tapping D-pad left or D-pad right (or A/Y in left handed +mode) will click the left or right mouse button. + +There is an alternative method of control which doesn't require you to +change modes with the D-pad. Press 'Select' to bring up the DS options, +and choose 'Tap for left click, double tap for right click'. In this +mode, you can quickly tap the screen to left click the mouse, and tap twice +to right click the mouse. + + +Here is a complete list of controls in right-handed mode (the default +setting): +Key Usage +Pad Left Left mouse button +Pad Right Right mouse button +Pad Up Hover mouse (no mouse button) +Pad Down Skip dialogue line (for some Lucasarts games), Show inventory + (for Beneath a Steel Sky), Show active objects (for Simon the Sorceror) +Start Pause/game menu (works in some games) +Select DS Options +B Skip cutscenes +A Swap main screen and zoomed screen +Y Show/Hide debug console +X Show/Hide on-screen keyboard +L + D-pad or L + Pen Scroll touch screen view +L + B Zoom in +L + A Zoom out + + + +And here's left-handed mode: +Key Usage +Y Left mouse button +A Right mouse button +X Hover mouse (no mouse button) +B Skip dialogue line (for some Lucasarts games), Show inventory (for + Beneath a Steel Sky), Show active objects (for Simon the Sorceror) +Start Pause/game menu (works in some games) +Select DS Options +D-pad down Skip cutscenes +D-pad up Swap main screen and zoomed screen +D-pad left Show/Hide debug console +D-pad right Show/Hide on-screen keyboard +R + D-pad or R + Pen Scroll touch screen view +R + D-pad down Zoom in +R + d-pad right Zoom out + + + + Game-specific controls + ------------------------------------------------------------------------ + + * Sam and Max Hit the Road: The current cursor mode is displayed on + the top screen. Use d-pad right to switch mode. + * Indiana Jones games: If you get into a fight, press Select, and + check the box marked 'Use Indy Fighting Controls'. + Return to the game, then use the following controls to fight: + + D-pad left: move left + D-pad right: move right + D-pad up: guard up + D-pad down: guard down + Y: guard middle + X: Punch high + A: Punch middle + B: Punch low + Left shoulder: Fight towards the left + Right shoulder: Fight towards the right + + The icon on the top screen shows which way you're currently + facing. Remember to turn the option off when the fight ends, or + the normal controls won't work! + * Beneath a Steel Sky: Press D-pad down to show your inventory. + * Simon the Sorcerer 1/2: Press D-pad down to show active objects. + * AGI games: Press Start to show the menu bar. + * Bargon Attack: Press Start to hit F1 when you need to start the + game. Use the on-screen keyboard (hit X) to press other function keys. + + + DS Options Screen + ------------------------------------------------------------------------ + +Pressing the 'select' button during any game to show the DS options +screen. This screen shows options specific to the Nintendo DS version +of ScummVM. + +Controls tab + +Indy Fight Controls - Enable fighting controls for the Indiana Jones +games. See 'Game Specific Controls' for more information. + +Left handed Mode - Switch the controls on the D-pad with the controls +on the A/B/X/Y buttons. + +Show mouse cursor - Shows the game's mouse cursor on the bottom screen. + +Snap to edges - makes it easier for the mouse controls to reach the edges +of the screen. Useful for Beneath a Steel Sky and Goblins 3. + +Touch X offset - if your screen doesn't perform properly, this setting +allows you to adjust when the cursor appears left or right relative to +the screen's measured touch position. + +Touch Y offset - if your screen doesn't perform properly, this setting +allows you to adjust when the cursor appears higher or lower relative to +the screen's measured touch position. + +Use Laptop Trackpad-style cursor control - In this mode, use the lower +screen to drag the cursor around, a bit like using a trackpad on a laptop. +When this option is enabled, the following option is also enabled. + +Tap for left click, double tap for right click - In this mode, you can +quickly tap on the screen to left click the mouse, or quickly +double tap on the screen to right click the mouse. If you find clicking +or double-clicking difficult, try and make a firmer touch on the screen, +and keep the pen down for longer. + +Sensitivity - this bar adjusts the speed of cursor movement when laptop +trackpad-style cursor control is enabled (see above). + +Graphics Tab + +Scaling options: + +Three scaling options are available for the main screen. + +Harware Scale - Scales using the DS hardware scaler using a flicker method. +Produces lower quality graphics but doesn't slow the game down. + +Software Scale - Scales using the CPU. A much higher quality image is +produced, but at the expense of speed in some games. + +Unscaled - Allows you to see the graphics as originaly displayed. This +doesn't fit on the DS screen, but you can scroll the screen around by holding +the left shoulder button and using the D-pad or touch screen. + +Top screen zoom - These three options control the zoom level of the top +screen when ScummVM is started up. Changing this option will set the zoom +to the specified level immediately. + +Initial top screen scale: + +This option controls the scaling level of the zoomed screen. In ScummVM +DS, one screen shows a zoomed-in view of the action, and this option controls +how zoomed in it is. You can also adjust this in the game by holding L and +pressing A/B. + +General Tab + +High Quality Audio - Enhance the sound quality, at the expense of some +slowdown during some games. + +Disable power off - ScummVM DS turns the power off when the game quits. +This option disables that feature. + + + + + + + Auto completion dictionary for Sierra AGI games + ------------------------------------------------------------------------ + +If you are playing a Sierra AGI game, you will be using the on-screen +keyboard quite a lot (press X to show it). To reduce the amount you have +to type, the game can automatically complete long words for you. To use +this feature, simply copy the PRED.DIC file from the ScummVM DS archive +into your game folder on your card. Now, when you use the keyboard, +possible words will be shown underneith it. To type one of those words, +simply double click on it with your stylus. + + + Converting your CD audio + ------------------------------------------------------------------------ + +ScummVM supports playing CD audio for specific games which came with +music stored as standard music CD tracks. To use this music in ScummVM +DS, they need to be ripped from the CD and stored in a specific format. +This can only be done for the CD versions of certain games, such as +Monkey Island 1, Loom, and Gobliiins. All the floppy games and CD games +that didn't have CD audio tracks for music don't require any conversion, +and will work unmodified on ScummVM DS. MP3 audio files for CD music are +not supported. + +Cdex can do the conversion very well and I recommend using it to convert +your audio files, although any CD ripping software can be used, so feel +free to use your favourite program. The format you need to use is +IMA-ADPCM 4-bit Mono. You may use any sample rate. All other formats +will be rejected, including uncompressed WAV files. + +Now I will to describe how to rip your CD tracks with Cdex, which can be +found here: Cdex Homepage <http://sourceforge.net/projects/cdexos/>. +Other software can be used to create IMA ADPCM files under Linux or +MacOS. + +To set this up in Cdex, select Settings from the Options menu. On the +Encoder tab, select 'WAV Output Encoder'. Under 'Encoder Options', +choose the following: + + Format: WAV + Compression: IMA ADPCM + Samplerate: 22050 Hz + Channels: Mono + On the fly encoding: On + +Next, go to the 'Filenames' tab and select the folder you want to save +your Wav files to. Under 'Filename format', enter 'track%3'. This should +name your WAV files in the correct way. Click OK. + +Now select all the tracks on your CD, and click 'Extract CD tracks to a +compressed audio file'. Cdex should rip all the audio off your CD. + +Now all you have to do is copy the newly created WAV files into the same +directory that your other game data is stored on your CompactFlash card. +Next time your run ScummVM DS, it should play with music! + +*Important Note:* Do not select 'Extract CD tracks to a WAV file'. This +creates uncompressed WAVs only. You want 'Extract CD tracks to a +compressed audio file'. + + + Converting Speech files to MP3 format + ------------------------------------------------------------------------ + +ScummVM supports playing back speech for talkie games in MP3 format. +Unfortunately, the DS CPU is not quite up to the task, and MP3 audio +will sometimes cause slowdown in your game. However, if your flash card +isn't big enough to fit the audio files on, you will have no choice! + +To convert your audio you will need a copy of the ScummVM Tools package +<http://sourceforge.net/project/showfiles.php?group_id=37116&package_id=67433>. +You will also need a copy of the LAME MP3 encoder +<http://www.free-codecs.com/Lame_Encoder_download.htm>. + +Once this is all installed and set up, the process to encode your audio +varies from game to game, but the Lucasarts games can all be compressed +using the following command line: + +compress_scumm_sou --mp3 monster.sou + +This produces a monster.so3 file which you can copy to your flash card +and replaces the original monster.sou. Ogg format (monster.sog) and flac +format files are not currently supported by ScummVM DS, and it is +unlikely they will ever be supported. There is no way to convert .sog or +.so3 files back to .sou files. Just dig out your original CD and copy +the file from that. + + + Frequently Asked Questions + ------------------------------------------------------------------------ + +I get a lot of email about ScummVM DS. Nearly all of them are exactly +the same. Here I'm going to try and answer the questions that everybody +asks me in the hope that I will spend less time answering questions that +are clearly in the documentation and more time helping people who have a +real problem or have discovered a real bug. + +*Q:* I can't see the bottom line of inventory items in Day of the +Tentacle, Monkey Island 2, or a few other games! What do I do? +*A:* Hold down the left shoulder button and use D-pad (or the touch +screen) to scroll the screen around. + +*Q:* I dont see a menu when I press Start in Flight of the Amazon Queen +or Simon the Sorcerer. Is ScummVM broken? +*A:* No. To save in Simon the Sorcerer, click 'use', then click on the +postcard in your inventory. In Flight of the Amazon Queen, click 'use', +then click on the journal in your inventory. + +*Q:* Why does ScummVM crash when I play Monkey Island 1? +*A:* This happens when MP3 audio tracks are present from the PC version +of ScummVM. Delete the MP3 tracks and reencode them to ADPCM WAV files +as described in the CD audio section. + +*Q:* When will you support my Mini/Micro SD card reader? I want it! +Pretty please? +*A:* ScummVM uses DLDI drivers. If your card reader manufacturer doesn't +provide a driver, there is nothing I can do about it. The people to ask +are the card reader manufacturers themselves. + +*Q:* Can't you use the extra RAM in the M3/Supercard or the official +Opera Expansion Pack to support more games like The Dig and Full +Throttle? DS Linux has done it, so why can't you? +*A:* Not at the moment. The extra RAM has certain differences to the +build in RAM which makes it difficult to use for general programs. As +ScummVM DS is an official port, the changes to the ScummVM code base +must be minimal to avoid making the code difficult to read for other +users. I do have plans to work on this some time in the future, but +don't nag me about when it'll be done. If and when there's progress with +this, I will post on the ScummVM forums about it. + + +*Q:* ScummVM DS turns off my DS when I hit 'Quit' in the game or quit +from the frontend. Why doesn't it return to the menu? +*A:* Due to bugs in the ScummVM codebase, many of the ScummVM games +cannot quit cleanly leaving the machine in the same state as when it +started. You will notice that no other versions of ScummVM can quit back +to the menu either. This will be fixed at some time in the future. + + + + + Contributors + ------------------------------------------------------------------------ + +ScummVM DS uses chishm's GBA Movie Player FAT driver. +The CPU scaler is by Tramboi and Robin Watts +The ARM code was optimised by Robin Watts +Thanks to highpass for the ScummVM DS icons. +Thanks to zhevon for the Sam & Max cursor code. +Thanks to theNinjaBunny for the M3 Adaptor guide on this site. +Thanks also to everyone on the GBADev Forums. + +This program was brought to you by caffiene, sugar, and late nights. + + + Donations and Getting Help + ------------------------------------------------------------------------ + +If you have problems getting ScummVM to work on your hardware, please +read the FAQ first. /Please/ don't ask me questions which are +answered in the FAQ, I get many emails about this program each day, and +I can't help the people who really need help if I'm answering the same +question all the time which is already answered on this page. Other than +that, feel free to post on the ScummVM DS forum <http://forums.scummvm.org> +for help. Please do your research first though. There is no way of +running this on an out-of-the box DS without extra hardware. Most of +these things are fairly inexpensive though. + +If you want to contact me, please email me on scummvm at millstone dot +demon dot co dot uk. + +If you want to help with the development of ScummVM DS, great! Download +the source code and get building. There are plenty of things left to do. + +You can also help by making a donation if you've particularly enjoyed +ScummVM DS. This uses Paypal, and is completely secure. There's no +pressure though, ScummVM DS is completely free. This is just for those +who would like to make a contribution to further development. + + + + Building from Sources + ------------------------------------------------------------------------ + +ScummVM is an open source project. This means that anyone is free to +take the source code to the project and make their own additions and fixes, +contributing them back to the authors for consideration for the next version. + +To build ScummVM DS from source, it's probably better to checkout the +latest version of the code from the ScummVM SVN repository. The ScummVM +Sourceforge.net homepage <http://sourceforge.net/projects/scummvm> has +all the information about how to do this. + +By default, ScummVM DS expects to find libmad, an MP3 compressor library +targeted for the ARM platform. If you don't have this, you must disable +libmad support by opening 'backends/platform/ds/arm9/makefile' and +commenting out the line which says USE_MAD = 1. + +Then, enter the 'backends/platform/ds' folder and type: +make SCUMM_BUILD=a + +The executable nds file will build inside 'backends/platform/ds/arm9/SCUMMVM-A'. + +For other builds, substitute the letters b - g in the above line. + + + diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index cf82090df2..e74bcf28da 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -8,25 +8,29 @@ libndsdir = $(DEVKITPRO)/libnds # Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g. # Anything else gets build a. -ifeq ($(SCUMM_BUILD),g) +ifeq ($(SCUMM_BUILD),h) + DS_BUILD_H = 1 + else + ifeq ($(SCUMM_BUILD),g) DS_BUILD_G = 1 -else - ifeq ($(SCUMM_BUILD),f) + else + ifeq ($(SCUMM_BUILD),f) DS_BUILD_F = 1 - else - ifeq ($(SCUMM_BUILD),e) - DS_BUILD_E = 1 else - ifeq ($(SCUMM_BUILD),d) - DS_BUILD_D = 1 + ifeq ($(SCUMM_BUILD),e) + DS_BUILD_E = 1 else - ifeq ($(SCUMM_BUILD),c) - DS_BUILD_C = 1 + ifeq ($(SCUMM_BUILD),d) + DS_BUILD_D = 1 else - ifeq ($(SCUMM_BUILD),b) - DS_BUILD_B = 1 + ifeq ($(SCUMM_BUILD),c) + DS_BUILD_C = 1 else + ifeq ($(SCUMM_BUILD),b) + DS_BUILD_B = 1 + else DS_BUILD_A = 1 + endif endif endif endif @@ -80,8 +84,8 @@ vpath %.s $(srcdir) # I actually had to use # ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork' LDFLAGS='C:/Progra~1/devkitpro/libnds/lib/libnds9.a' --disable-shared --disable-debugging -USE_ARM_SOUND_ASM = 1 ARM = 1 +USE_ARM_SOUND_ASM = 1 USE_ARM_COSTUME_ASM = 1 ifdef DS_BUILD_A @@ -140,6 +144,13 @@ ifdef DS_BUILD_G BUILD=scummvm-G endif +ifdef DS_BUILD_H + DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_H + LOGO = logog.bmp + ENABLE_PARALLACTION = STATIC_PLUGIN + BUILD=scummvm-H +endif + ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin ICON := -b ../../../logo.bmp "ScummVM;By Neil Millstone;" @@ -152,6 +163,7 @@ CFLAGS = -Wno-multichar -Wall\ -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\ -mthumb-interwork -DUSE_ARM_COSTUME_ASM=1 + # -ffast-math ifdef USE_DEBUGGER @@ -165,7 +177,7 @@ ifdef USE_PROFILER endif CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \ - -fno-exceptions -fno-rtti -mthumb-interwork + -fno-exceptions -fno-rtti -mthumb-interwork -ffunction-sections -fdata-sections # -mthumb @@ -185,7 +197,7 @@ ifdef USE_MAD endif -LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt +LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \ -I$(portdir)/data -I$(portdir)/../commoninclude \ @@ -237,7 +249,8 @@ endif DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o $(portdir)/data/8x8font_tga.o -COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o +COMPRESSOR_OBJS := +#$(portdir)/source/compressor/lz.o FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o\ $(portdir)/source/fat/io_fcsr.o $(portdir)/source/fat/io_m3cf.o\ @@ -257,14 +270,15 @@ FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o # $(portdir)/source/fat/io_sd_common.o $(portdir)/source/fat/io_scsd_s.o \ # $(portdir)/source/fat/io_sc_common.o $(portdir)/source/fat/io_sd_common.o -LIBCARTRESET_OBJS := $(portdir)/source/libcartreset/cartreset.o +LIBCARTRESET_OBJS := +#$(portdir)/source/libcartreset/cartreset.o # Files in this list will be optimisied for speed, otherwise they will be optimised for space OPTLIST := actor.cpp ds_main.cpp osystem_ds.cpp blitters.cpp fmopl.cpp rate.cpp mixer.cpp isomap.cpp image.cpp gfx.cpp sprite.cpp actor_path.cpp actor_walk.cpp #OPTLIST := # Compiler options for files which should be optimised for speed -OPT_SPEED := -O2 +OPT_SPEED := -O3 # Compiler options for files which should be optimised for space OPT_SIZE := -Os @@ -286,7 +300,7 @@ ndsall: include $(srcdir)/Makefile.common semiclean: - $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o + $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o $(portdir)/source/dsoptions.o clean: $(RM) $(OBJS) $(EXECUTABLE) diff --git a/backends/platform/ds/arm9/source/cdaudio.h b/backends/platform/ds/arm9/source/cdaudio.h index d237569bb7..d1897d3e5d 100644 --- a/backends/platform/ds/arm9/source/cdaudio.h +++ b/backends/platform/ds/arm9/source/cdaudio.h @@ -20,7 +20,7 @@ * */ - #ifndef _CDAUDIO_H_ +#ifndef _CDAUDIO_H_ #define _CDAUDIO_H_ namespace DS { diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index ce22ac8e71..872a196e9b 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -66,6 +66,7 @@ #include <nds.h> #include <nds/registers_alt.h> +#include <nds/arm9/exceptions.h> //#include <ARM9/console.h> //basic print funcionality @@ -76,7 +77,6 @@ #include "icons_raw.h" #include "fat/gba_nds_fat.h" #include "fat/disc_io.h" -//#include "common/config-manager.h" #include "keyboard_raw.h" #include "keyboard_pal_raw.h" #define V16(a, b) ((a << 12) | b) @@ -95,6 +95,26 @@ #endif #include "backends/fs/ds/ds-fs.h" +extern "C" u32 getExceptionAddress( u32 opcodeAddress, u32 thumbState); +extern const char __itcm_start[]; +static const char *registerNames[] = + { "r0","r1","r2","r3","r4","r5","r6","r7", + "r8 ","r9 ","r10","r11","r12","sp ","lr ","pc " }; + +/* +extern "C" void* __real_malloc(size_t size); + +extern "C" void* __wrap_malloc(size_t size) { + void* res = __real_malloc(size); + if (res) { + return res; + } else { + consolePrintf("Failed alloc %d\n", size); + return NULL; + } +} +*/ + namespace DS { // From console.c in NDSLib @@ -167,7 +187,7 @@ bool displayModeIs8Bit = false; u8 gameID; bool snapToBorder = false; -bool consoleEnable = true; +bool consoleEnable = false; bool gameScreenSwap = false; bool isCpuScalerEnabled(); //#define HEAVY_LOGGING @@ -196,6 +216,13 @@ int mouseHotspotX, mouseHotspotY; bool cursorEnable = false; bool mouseCursorVisible = true; bool rightButtonDown = false; +bool touchPadStyle = false; +int touchPadSensitivity = 8; +bool tapScreenClicks = true; + +int tapCount = 0; +int tapTimeout = 0; +int tapComplete = 0; // Dragging int dragStartX, dragStartY; @@ -212,7 +239,14 @@ int gameHeight = 200; // Scale bool twoHundredPercentFixedScale = false; bool cpuScalerEnable = false; -#define NUM_SUPPORTED_GAMES 20 + + // 100 256 + // 150 192 + // 200 128 + + // (256 << 8) / scale + + #ifdef USE_PROFILER int hBlankCount = 0; @@ -220,6 +254,7 @@ int hBlankCount = 0; u8* scalerBackBuffer = NULL; +#define NUM_SUPPORTED_GAMES 21 gameListType gameList[NUM_SUPPORTED_GAMES] = { // Unknown game - use normal SCUMM controls @@ -247,6 +282,7 @@ gameListType gameList[NUM_SUPPORTED_GAMES] = { {"elvira2", CONT_SIMON}, {"elvira1", CONT_SIMON}, {"waxworks", CONT_SIMON}, + {"parallaction", CONT_NIPPON}, }; gameListType* currentGame = NULL; @@ -259,6 +295,7 @@ bool penHeld; bool penReleased; bool penDownLastFrame; s32 penX, penY; +s32 penDownX, penDownY; int keysDownSaved; int keysReleasedSaved; int keysChangedSaved; @@ -298,9 +335,41 @@ void setCpuScalerEnable(bool enable) { cpuScalerEnable = enable; } +void setTrackPadStyleEnable(bool enable) { + touchPadStyle = enable; +} + +void setTapScreenClicksEnable(bool enable) { + tapScreenClicks = enable; +} + +void setGameScreenSwap(bool enable) { + gameScreenSwap = enable; +} + +void setSensitivity(int sensitivity) { + touchPadSensitivity = sensitivity; +} + +void setTopScreenZoom(int percentage) { + // 100 256 + // 150 192 + // 200 128 + + // (256 << 8) / scale + + s32 scale = (percentage << 8) / 100; + subScreenScale = (256 * 256) / scale; + +// consolePrintf("Scale is %d %%\n", percentage); +} // return (ConfMan.hasKey("cpu_scaler", "ds") && ConfMan.getBool("cpu_scaler", "ds")); +controlType getControlType() { + return currentGame->control; +} + //plays an 8 bit mono sample at 11025Hz void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate) @@ -428,14 +497,14 @@ void initGame() { consolePrintf("initing game..."); #endif - static bool firstTime = true; +// static bool firstTime = true; setOptions(); //strcpy(gameName, ConfMan.getActiveDomain().c_str()); strcpy(gameName, ConfMan.get("gameid").c_str()); - consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]); +// consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]); currentGame = &gameList[0]; // Default game @@ -446,16 +515,12 @@ void initGame() { } } - if (firstTime) { +/* if (firstTime) { firstTime = false; - if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) { - startSound(22050, 8192); - } else { - startSound(11025, 4096); - } } +*/ #ifdef HEAVY_LOGGING consolePrintf("done\n"); #endif @@ -630,7 +695,7 @@ void checkSleepMode() { void setShowCursor(bool enable) { - if (currentGame->control == CONT_SCUMM_SAMNMAX) + if ((currentGame) && (currentGame->control == CONT_SCUMM_SAMNMAX)) { if (cursorEnable) { sprites[1].attribute[0] = ATTR0_BMP | 150; @@ -653,23 +718,28 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, mouseHotspotX = hotspotX; mouseHotspotY = hotspotY; + //consolePrintf("Set cursor icon %d, %d\n", w, h); + { int off = 128*64; memset(SPRITE_GFX + off, 0, 32 * 32 * 2); memset(SPRITE_GFX_SUB + off, 0, 32 * 32 * 2); + for (uint y=0; y<h; y++) { for (uint x=0; x<w; x++) { int color = icon[y*w+x]; + + //consolePrintf("%d:%d ", color, OSystem_DS::instance()->getDSPaletteEntry(color)); if (color == keycolor) { SPRITE_GFX[off+(y)*32+x] = 0x0000; // black background SPRITE_GFX_SUB[off+(y)*32+x] = 0x0000; // black background } else { - SPRITE_GFX[off+(y)*32+x] = BG_PALETTE[color] | 0x8000; - SPRITE_GFX_SUB[off+(y)*32+x] = BG_PALETTE[color] | 0x8000; + SPRITE_GFX[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000; + SPRITE_GFX_SUB[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000; } } } @@ -732,6 +802,7 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX, sprites[1].attribute[1] = ATTR1_SIZE_64 | pos; sprites[1].attribute[2] = ATTR2_ALPHA(1) | 176; } + } @@ -744,6 +815,7 @@ void displayMode16Bit() { u16 buffer[32 * 32 * 2]; + releaseAllKeys(); if (displayModeIs8Bit) { // static int test = 0; @@ -1108,7 +1180,7 @@ void setKeyboardEnable(bool en) { } else { - + DS::releaseAllKeys(); // Restore the palette that the keyboard has used for (int r = 0; r < 256; r++) { BG_PALETTE_SUB[r] = BG_PALETTE[r]; @@ -1156,6 +1228,194 @@ bool getIsDisplayMode8Bit() { return displayModeIs8Bit; } +void doScreenTapMode(OSystem_DS* system) +{ + Common::Event event; + static bool left = false, right = false; + + if (left) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + left = false; + } + + if (right) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + right = false; + } + + + if (tapComplete == 1) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + tapComplete = 0; + left = true; + } else if (tapComplete == 2) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + tapComplete = 0; + right = true; + } + + + if (getKeysDown() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + if (getKeysReleased() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if (getKeysDown() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + if (getKeysReleased() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + event.type = Common::EVENT_MOUSEMOVE; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); +} + +void doButtonSelectMode(OSystem_DS* system) +{ + Common::Event event; + + + if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { + event.type = Common::EVENT_MOUSEMOVE; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + //consolePrintf("x=%d y=%d \n", getPenX(), getPenY()); + } + + static bool leftButtonDown = false; + static bool rightButtonDown = false; + + if (getPenReleased() && (leftButtonDown || rightButtonDown)) { + if (leftButtonDown) { + event.type = Common::EVENT_LBUTTONUP; + } else { + event.type = Common::EVENT_RBUTTONUP; + } + + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) { + if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { + if ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit)) { + event.type = Common::EVENT_LBUTTONDOWN; + leftButtonDown = true; + } else { + event.type = Common::EVENT_RBUTTONDOWN; + rightButtonDown = true; + } + + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + } else { + // In hover mode, D-pad left and right click the mouse when the pen is on the screen + + if (getPenHeld()) { + if (getKeysDown() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + if (getKeysReleased() & KEY_LEFT) { + event.type = Common::EVENT_LBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + + + if (getKeysDown() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONDOWN; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + if (getKeysReleased() & KEY_RIGHT) { + event.type = Common::EVENT_RBUTTONUP; + event.mouse = Common::Point(getPenX(), getPenY()); + system->addEvent(event); + } + } + } + + if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState()) && (!getKeyboardEnable())) { + + if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) { + if (getKeysDown() & KEY_LEFT) { + mouseMode = MOUSE_LEFT; + } + + if (rightButtonDown) + { + Common::Event event; + event.mouse = Common::Point(getPenX(), getPenY()); + event.type = Common::EVENT_RBUTTONUP; + system->addEvent(event); + rightButtonDown = false; + } + + + if (getKeysDown() & KEY_RIGHT) { + if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) { + mouseMode = MOUSE_RIGHT; + } else { + // If we're playing sam and max, click and release the right mouse + // button to change verb + Common::Event event; + + if (currentGame->control == CONT_FUTURE_WARS) { + event.mouse = Common::Point(320 - 128, 200 - 128); + event.type = Common::EVENT_MOUSEMOVE; + system->addEvent(event); + } else { + event.mouse = Common::Point(getPenX(), getPenY()); + } + + rightButtonDown = true; + + + event.type = Common::EVENT_RBUTTONDOWN; + system->addEvent(event); + + //event.type = Common::EVENT_RBUTTONUP; + //system->addEvent(event); + } + } + + + + if (getKeysDown() & KEY_UP) { + mouseMode = MOUSE_HOVER; + } + } + } +} + void addEventsToQueue() { #ifdef HEAVY_LOGGING consolePrintf("addEventsToQueue\n"); @@ -1285,54 +1545,6 @@ void addEventsToQueue() { } - if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) { - if (getKeysDown() & KEY_LEFT) { - mouseMode = MOUSE_LEFT; - } - - if (rightButtonDown) - { - Common::Event event; - event.mouse = Common::Point(getPenX(), getPenY()); - event.type = Common::EVENT_RBUTTONUP; - system->addEvent(event); - rightButtonDown = false; - } - - - if (getKeysDown() & KEY_RIGHT) { - if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) { - mouseMode = MOUSE_RIGHT; - } else { - // If we're playing sam and max, click and release the right mouse - // button to change verb - Common::Event event; - - if (currentGame->control == CONT_FUTURE_WARS) { - event.mouse = Common::Point(320 - 128, 200 - 128); - event.type = Common::EVENT_MOUSEMOVE; - system->addEvent(event); - } else { - event.mouse = Common::Point(getPenX(), getPenY()); - } - - rightButtonDown = true; - - - event.type = Common::EVENT_RBUTTONDOWN; - system->addEvent(event); - - //event.type = Common::EVENT_RBUTTONUP; - //system->addEvent(event); - } - } - - - - if (getKeysDown() & KEY_UP) { - mouseMode = MOUSE_HOVER; - } - } @@ -1358,52 +1570,13 @@ void addEventsToQueue() { if (!keyboardEnable) { - if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { - event.type = Common::EVENT_MOUSEMOVE; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - //consolePrintf("x=%d y=%d \n", getPenX(), getPenY()); + if ((tapScreenClicks) && (getIsDisplayMode8Bit())) + { + doScreenTapMode(system); } - - if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) { - if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) { - event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? Common::EVENT_LBUTTONDOWN: Common::EVENT_RBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - - if (getPenReleased()) { - event.type = mouseMode == MOUSE_LEFT? Common::EVENT_LBUTTONUP: Common::EVENT_RBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - } else { - // In hover mode, D-pad left and right click the mouse when the pen is on the screen - - if (getPenHeld()) { - if (getKeysDown() & KEY_LEFT) { - event.type = Common::EVENT_LBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - if (getKeysReleased() & KEY_LEFT) { - event.type = Common::EVENT_LBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - - - if (getKeysDown() & KEY_RIGHT) { - event.type = Common::EVENT_RBUTTONDOWN; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - if (getKeysReleased() & KEY_RIGHT) { - event.type = Common::EVENT_RBUTTONUP; - event.mouse = Common::Point(getPenX(), getPenY()); - system->addEvent(event); - } - } + else + { + doButtonSelectMode(system); } if (((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R)) || (indyFightState)) && (displayModeIs8Bit)) { @@ -1536,8 +1709,8 @@ void triggerIcon(int imageNum) { void setIcon(int num, int x, int y, int imageNum, int flags, bool enable) { - sprites[num].attribute[0] = ATTR0_BMP | (enable? y: 192) | (!enable? ATTR0_DISABLED: 0); - sprites[num].attribute[1] = ATTR1_SIZE_32 | x | flags; + sprites[num].attribute[0] = ATTR0_BMP | (enable? (y & 0xFF): 192) | (!enable? ATTR0_DISABLED: 0); + sprites[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags; sprites[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16); } @@ -1551,28 +1724,30 @@ void updateStatus() { int offs; if (displayModeIs8Bit) { - switch (mouseMode) { - case MOUSE_LEFT: { - offs = 1; - break; - } - case MOUSE_RIGHT: { - offs = 2; - break; - } - case MOUSE_HOVER: { - offs = 0; - break; - } - default: { - // Nothing! - offs = 0; - break; + if (!tapScreenClicks) { + switch (mouseMode) { + case MOUSE_LEFT: { + offs = 1; + break; + } + case MOUSE_RIGHT: { + offs = 2; + break; + } + case MOUSE_HOVER: { + offs = 0; + break; + } + default: { + // Nothing! + offs = 0; + break; + } } + + setIcon(0, 208, 150, offs, 0, true); } - setIcon(0, 208, 150, offs, 0, true); - if (indyFightState) { setIcon(1, (190 - 32), 150, 3, (indyFightRight? 0: ATTR1_FLIP_X), true); // consolePrintf("%d\n", indyFightRight); @@ -1630,7 +1805,7 @@ void setMainScreenScroll(int x, int y) { BG3_CX = x + (((frameCount & 1) == 0)? 64: 0); BG3_CY = y; - if (!gameScreenSwap) { + if ((!gameScreenSwap) || (touchPadStyle)) { touchX = x >> 8; touchY = y >> 8; } @@ -1659,7 +1834,7 @@ void setMainScreenScale(int x, int y) { BG3_YDY = y; } - if (!gameScreenSwap) { + if ((!gameScreenSwap) || (touchPadStyle)) { touchScX = x; touchScY = y; } @@ -1675,7 +1850,7 @@ void setZoomedScreenScroll(int x, int y, bool shake) { touchY = y >> 8; } else */{ - if (gameScreenSwap) { + if ((gameScreenSwap) && (!touchPadStyle)) { touchX = x >> 8; touchY = y >> 8; } @@ -1695,7 +1870,7 @@ void setZoomedScreenScale(int x, int y) { } else */{ - if (gameScreenSwap) { + if ((gameScreenSwap) && (!touchPadStyle)) { touchScX = x; touchScY = y; } @@ -1756,18 +1931,22 @@ void VBlankHandler(void) { frameCount++; - if ((cursorEnable) && (mouseCursorVisible)) - { + if ((cursorEnable) && (mouseCursorVisible)) { if (!keyboardEnable) { storedMouseX = penX; storedMouseY = penY; } - setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); - } - else - { + if (gameScreenSwap) { + setIcon(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); + setIconMain(3, 0, 0, 0, 0, false); + } else { + setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true); + setIcon(3, 0, 0, 0, 0, false); + } + } else { setIconMain(3, 0, 0, 0, 0, false); + setIcon(3, 0, 0, 0, 0, false); } @@ -1825,7 +2004,7 @@ void VBlankHandler(void) { SUB_BG3_YDX = 0; SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/ - static int ratio = ( 320 << 8) / SCUMM_GAME_WIDTH; + static int ratio = (320 << 8) / SCUMM_GAME_WIDTH; bool zooming = false; @@ -1850,8 +2029,12 @@ void VBlankHandler(void) { subScreenWidth = 256 >> 1; subScreenHeight = 192 >> 1; } else { - subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8; - subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; +// subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8; +// subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; + + + subScreenWidth = (256 * subScreenScale) >> 8; + subScreenHeight = (192 * subScreenScale) >> 8; if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) { subScreenWidth = 256; @@ -2214,43 +2397,141 @@ void penUpdate() { // if (getKeysHeld() & KEY_L) consolePrintf("%d, %d penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1); - if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me. + bool penDownThisFrame = (IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0); + bool firstFrame = penDownFrames == 2; + static bool moved = false; - if ((penHeld)) { - penHeld = true; - penDown = false; + if ((tapScreenClicks) && (!getKeyboardEnable()) && (getIsDisplayMode8Bit())) { - if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { - penX = IPC->touchXpx + touchXOffset; - penY = IPC->touchYpx + touchYOffset; + if ((tapTimeout >= 0)) { + tapTimeout++; + + if (((tapTimeout > 15) || (tapCount == 2)) && (tapCount > 0)) { + tapComplete = tapCount; + tapCount = 0; +// consolePrintf("Taps: %d\n", tapComplete); } + } - } else { - penDown = true; - penHeld = true; - penDownSaved = true; + - //if ( (ABS(penX - IPC->touchXpx) < 10) && (ABS(penY - IPC->touchYpx) < 10) ) { - if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { - penX = IPC->touchXpx; - penY = IPC->touchYpx; + if ((penHeld) && (!penDownThisFrame)) { + if ((touchPadStyle) || (moved) || (tapCount == 1)) { + if ((penDownFrames > 0) && (penDownFrames < 6) && ((tapTimeout == -1) || (tapTimeout > 2))) { + tapCount++; + tapTimeout = 0; +// consolePrintf("Tap! %d\n", penDownFrames); + moved = false; + } } - //} } + } - } else { - if (penHeld) { - penReleased = true; - penReleasedSaved = true; + + + if ((touchPadStyle) && (getIsDisplayMode8Bit())) { + + if ((penDownFrames > 0)) { + + + if ((penHeld)) { + + if (penDownThisFrame) + { + if (penDownFrames >= 2) { + int diffX = IPC->touchXpx - penDownX; + int diffY = IPC->touchYpx - penDownY; + + int speed = ABS(diffX) + ABS(diffY); + + if ((ABS(diffX) < 35) && (ABS(diffY) < 35)) + { + + if (speed >= 8) + { + diffX *= ((speed >> 3) * touchPadSensitivity) >> 3; + diffY *= ((speed >> 3) * touchPadSensitivity) >> 3; + } + + penX += diffX; + penY += diffY; + if (penX > 255) penX = 255; + if (penX < 0) penX = 0; + if (penY > 191) penY = 191; + if (penY < 0) penY = 0; + } + +// consolePrintf("x: %d y: %d\n", IPC->touchYpx - penDownY, IPC->touchYpx - penDownY); + penDownX = IPC->touchXpx; + penDownY = IPC->touchYpx; + + } + } + else + { + } + + + } else { + penDown = true; + penHeld = true; + penDownSaved = true; + + // First frame, so save pen positions + if (penDownThisFrame) { + penDownX = IPC->touchXpx; + penDownY = IPC->touchYpx; + } + } + } else { - penReleased = false; + if (penHeld) { + penReleased = true; + penReleasedSaved = true; + } else { + penReleased = false; + } + + penDown = false; + penHeld = false; } + } else { + if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me. + + if ((penHeld)) { + penHeld = true; + penDown = false; + } else { + penDown = true; + penHeld = true; + penDownSaved = true; + } + + if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) { + penX = IPC->touchXpx + touchXOffset; + penY = IPC->touchYpx + touchYOffset; + moved = true; + } + - penDown = false; - penHeld = false; + + } else { + if (penHeld) { + penReleased = true; + penReleasedSaved = true; + } else { + penReleased = false; + } + + penDown = false; + penHeld = false; + } + + } + if ((IPC->touchZ1 > 0) || ((penDownFrames == 2)) ) { penDownLastFrame = true; penDownFrames++; @@ -2258,7 +2539,6 @@ void penUpdate() { penDownLastFrame = false; penDownFrames = 0; } - } int leftHandedSwap(int keys) { @@ -2345,8 +2625,7 @@ int getPenX() { int x = ((penX * touchScX) >> 8) + touchX; x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x); - if (snapToBorder) - { + if (snapToBorder) { if (x < 8) x = 0; if (x > gameWidth - 8) x = gameWidth - 1; } @@ -2358,8 +2637,7 @@ int getPenY() { int y = ((penY * touchScY) >> 8) + touchY; y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y); - if (snapToBorder) - { + if (snapToBorder) { if (y < 8) y = 0; if (y > gameHeight - 8) y = gameHeight - 1; } @@ -2376,6 +2654,8 @@ GLvector getPenPos() { return v; } +#ifdef GBA_SRAM_SAVE + void formatSramOption() { consolePrintf("The following files are present in save RAM:\n"); DSSaveFileManager::instance()->listFiles(); @@ -2397,7 +2677,7 @@ void formatSramOption() { } } } - +#endif void setIndyFightState(bool st) { indyFightState = st; @@ -2495,8 +2775,6 @@ struct cardTranslate { char dldiId[5]; }; -#define NUM_CARD_READERS 7 - cardTranslate cardReaderTable[] = { {DEVICE_TYPE_M3SD, DEVICE_M3SD, "M3SD"}, {DEVICE_TYPE_M3CF, DEVICE_M3CF, "M3CF"}, @@ -2518,13 +2796,13 @@ void reboot() { consolePrintf("DLDI Device ID: %s\n", id); - for (int r = 0; r < NUM_CARD_READERS; r++) { + for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) { if (!stricmp(id, cardReaderTable[r].dldiId)) { deviceType = cardReaderTable[r].cartResetId; } } } else { - for (int r = 0; r < NUM_CARD_READERS; r++) { + for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) { if (disc_getDeviceId() == cardReaderTable[r].svmId) { deviceType = cardReaderTable[r].cartResetId; } @@ -2572,13 +2850,66 @@ void powerOff() { ///////////////// -int main(void) -{ + +void dsExceptionHandler() { + consolePrintf("Blue screen of death"); + setExceptionHandler(NULL); + + + u32 currentMode = getCPSR() & 0x1f; + u32 thumbState = ((*(u32*)0x027FFD90) & 0x20); + + u32 codeAddress, exceptionAddress = 0; + + int offset = 8; + + if ( currentMode == 0x17 ) { + consolePrintf("\x1b[10Cdata abort!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + if ( (codeAddress > 0x02000000 && codeAddress < 0x02400000) || + (codeAddress > (u32)__itcm_start && codeAddress < (u32)(__itcm_start + 32768)) ) + exceptionAddress = getExceptionAddress( codeAddress, thumbState); + else + exceptionAddress = codeAddress; + + } else { + if (thumbState) + offset = 2; + else + offset = 4; + consolePrintf("\x1b[5Cundefined instruction!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + exceptionAddress = codeAddress; + } + + consolePrintf(" pc: %08X addr: %08X\n\n",codeAddress,exceptionAddress); + + int i; + for ( i=0; i < 8; i++ ) { + consolePrintf( " %s: %08X %s: %08X\n", + registerNames[i], exceptionRegisters[i], + registerNames[i+8],exceptionRegisters[i+8]); + } +// u32 *stack = (u32 *)exceptionRegisters[13]; +// for ( i=0; i<10; i++ ) { +// consolePrintf( "\x1b[%d;2H%08X: %08X %08X", i + 14, (u32)&stack[i*2],stack[i*2], stack[(i*2)+1] ); +// } + + memoryReport(); + + while(1); +} + + + + +int main(void) { soundCallback = NULL; initHardware(); + setExceptionHandler(dsExceptionHandler); #ifdef USE_DEBUGGER for (int r = 0; r < 150; r++) { @@ -2662,36 +2993,33 @@ int main(void) consolePrintf("-------------------------------\n"); consolePrintf("ScummVM DS\n"); consolePrintf("Ported by Neil Millstone\n"); - consolePrintf("Version 0.11.1 beta2"); + consolePrintf("Version 0.13.0 SVN "); #if defined(DS_BUILD_A) consolePrintf("build A\n"); consolePrintf("Lucasarts SCUMM games (SCUMM)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_B) consolePrintf("build B\n"); consolePrintf("BASS, QUEEN\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_C) consolePrintf("build C\n"); consolePrintf("Simon/Elvira/Waxworks (AGOS)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_D) consolePrintf("build D\n"); consolePrintf("AGI, CINE, GOB\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_E) consolePrintf("build E\n"); consolePrintf("Inherit the Earth (SAGA)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_F) consolePrintf("build F\n"); consolePrintf("The Legend of Kyrandia (KYRA)\n"); - consolePrintf("-------------------------------\n"); #elif defined(DS_BUILD_G) - consolePrintf("build F\n"); - consolePrintf("Lure of the Temptress (LURE)\n"); - consolePrintf("-------------------------------\n"); + consolePrintf("build G\n"); + consolePrintf("Lure of the Tempress (LURE)\n"); +#elif defined(DS_BUILD_H) + consolePrintf("build H\n"); + consolePrintf("Nippon Safes (PARALLATION)\n"); #endif + consolePrintf("-------------------------------\n"); consolePrintf("L/R + D-pad/pen: Scroll view\n"); consolePrintf("D-pad left: Left mouse button\n"); consolePrintf("D-pad right: Right mouse button\n"); @@ -2807,9 +3135,11 @@ int main(void) g_system = new OSystem_DS(); assert(g_system); +#ifdef GBA_SRAM_SAVE if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) { formatSramOption(); } +#endif IPC->adpcm.semaphore = false; @@ -2830,6 +3160,8 @@ int main(void) const char *argv[] = {"/scummvmds", "--config=scummvmf.ini"}; #elif defined(DS_BUILD_G) const char *argv[] = {"/scummvmds", "--config=scummvmg.ini"}; +#elif defined(DS_BUILD_H) + const char *argv[] = {"/scummvmds", "--config=scummvmh.ini"}; #endif while (1) { diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h index 43258b5c5d..ab74554917 100644 --- a/backends/platform/ds/arm9/source/dsmain.h +++ b/backends/platform/ds/arm9/source/dsmain.h @@ -38,7 +38,8 @@ enum controlType { CONT_SIMON, CONT_FUTURE_WARS, CONT_AGI, - CONT_GOBLINS + CONT_GOBLINS, + CONT_NIPPON, }; struct gameListType { @@ -56,6 +57,7 @@ int getPenX(); int getPenY(); GLvector getPenPos(); void consumePenEvents(); +controlType getControlType(); // Pad reading int getKeysHeld(); @@ -64,6 +66,8 @@ int getKeysDown(); int getKeysReleased(); void consumeKeys(); int leftHandedSwap(int keys); +void setGameScreenSwap(bool enable); +void setSensitivity(int sensitivity); // Video void displayMode8Bit(); // Switch to 8-bit mode5 @@ -81,6 +85,7 @@ u16* getScalerBuffer(); void setTalkPos(int x, int y); void setTopScreenTarget(int x, int y); void set200PercentFixedScale(bool on); +void setTopScreenZoom(int percentage); // Timers void setTimerCallback(OSystem_DS::TimerProc proc, int interval); // Setup a callback function at a regular interval @@ -88,7 +93,9 @@ int getMillis(); // Return the current runtime in milliseconds void doTimerCallback(); // Call callback function if required // Sound -void doSoundCallback(); // Call function if sound buffers need more data +void doSoundCallback(); +void startSound(int freq, int buffer); // Start sound hardware +// Call function if sound buffers need more data void playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050); // Start a sound void stopSound(int channel); int getSoundFrequency(); @@ -131,6 +138,8 @@ void setIndyFightState(bool st); bool getIndyFightState(); bool isCpuScalerEnabled(); void setCpuScalerEnable(bool enable); +void setTrackPadStyleEnable(bool enable); +void setTapScreenClicksEnable(bool enable); // Display bool getIsDisplayMode8Bit(); diff --git a/backends/platform/ds/arm9/source/dsoptions.cpp b/backends/platform/ds/arm9/source/dsoptions.cpp index edb9c70580..2dbc4b842b 100644 --- a/backends/platform/ds/arm9/source/dsoptions.cpp +++ b/backends/platform/ds/arm9/source/dsoptions.cpp @@ -25,6 +25,7 @@ #include "gui/dialog.h" #include "gui/newgui.h" #include "gui/ListWidget.h" +#include "gui/TabWidget.h" #include "osystem_ds.h" #include "engines/scumm/scumm.h" #include "touchkeyboard.h" @@ -41,8 +42,67 @@ namespace Scumm { namespace DS { -DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { - addButton(this, 10, 175, "Close", GUI::kCloseCmd, 'C'); +DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(0, 0, 320 - 10, 230 - 40) { + + addButton(this, 10, 170, "Close", GUI::kCloseCmd, 'C'); + _tab = new GUI::TabWidget(this, 5, 5, 300, 230 - 20 - 40 - 10); + + _tab->addTab("Controls"); + + _leftHandedCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 130, 20, "Left handed mode", 0, 'L'); + _indyFightCheckbox = new GUI::CheckboxWidget(_tab, 5, 20, 140, 20, "Indy fight controls", 0, 'I'); + _showCursorCheckbox = new GUI::CheckboxWidget(_tab, 150, 5, 130, 20, "Show mouse cursor", 0, 'T'); + _snapToBorderCheckbox = new GUI::CheckboxWidget(_tab, 150, 20, 130, 20, "Snap to edges", 0, 'T'); + + new GUI::StaticTextWidget(_tab, 20, 35, 100, 15, "Touch X Offset", GUI::kTextAlignLeft); + _touchX = new GUI::SliderWidget(_tab, 130, 35, 130, 12, 1); + _touchX->setMinValue(-8); + _touchX->setMaxValue(+8); + _touchX->setValue(0); + _touchX->setFlags(GUI::WIDGET_CLEARBG); + + new GUI::StaticTextWidget(_tab, 20, 50, 100, 15, "Touch Y Offset", GUI::kTextAlignLeft); + _touchY = new GUI::SliderWidget(_tab, 130, 50, 130, 12, 2); + _touchY->setMinValue(-8); + _touchY->setMaxValue(+8); + _touchY->setValue(0); + _touchY->setFlags(GUI::WIDGET_CLEARBG); + + new GUI::StaticTextWidget(_tab, 130 + 65 - 10, 65, 20, 15, "0", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(_tab, 130 + 130 - 10, 65, 20, 15, "8", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(_tab, 130 - 20, 65, 20, 15, "-8", GUI::kTextAlignCenter); + + + _touchPadStyle = new GUI::CheckboxWidget(_tab, 5, 80, 270, 20, "Use laptop trackpad-style cursor control", 0x20000001, 'T'); + _screenTaps = new GUI::CheckboxWidget(_tab, 5, 95, 285, 20, "Tap for left click, double tap right click", 0x20000002, 'T'); + + _sensitivityLabel = new GUI::StaticTextWidget(_tab, 20, 110, 110, 15, "Sensitivity", GUI::kTextAlignLeft); + _sensitivity = new GUI::SliderWidget(_tab, 130, 110, 130, 12, 1); + _sensitivity->setMinValue(4); + _sensitivity->setMaxValue(16); + _sensitivity->setValue(8); + _sensitivity->setFlags(GUI::WIDGET_CLEARBG); + + _tab->addTab("Graphics"); + + new GUI::StaticTextWidget(_tab, 5, 70, 180, 15, "Initial top screen scale:", GUI::kTextAlignLeft); + + _100PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 85, 230, 20, "100%", 0x30000001, 'T'); + _150PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 100, 230, 20, "150%", 0x30000002, 'T'); + _200PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 115, 230, 20, "200%", 0x30000003, 'T'); + + new GUI::StaticTextWidget(_tab, 5, 5, 180, 15, "Main screen scaling:", GUI::kTextAlignLeft); + + _hardScaler = new GUI::CheckboxWidget(_tab, 5, 20, 270, 20, "Hardware scale (fast, but low quality)", 0x10000001, 'T'); + _cpuScaler = new GUI::CheckboxWidget(_tab, 5, 35, 270, 20, "Software scale (good quality, but slower)", 0x10000002, 'S'); + _unscaledCheckbox = new GUI::CheckboxWidget(_tab, 5, 50, 270, 20, "Unscaled (you must scroll left and right)", 0x10000003, 'S'); + + _tab->addTab("General"); + + _highQualityAudioCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 250, 20, "High quality audio (slower) (reboot)", 0, 'T'); + _disablePowerOff = new GUI::CheckboxWidget(_tab, 5, 20, 200, 20, "Disable power off", 0, 'T'); + + _tab->setActiveTab(0); _radioButtonMode = false; @@ -52,46 +112,17 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { } #endif - new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter); +// new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter); - _leftHandedCheckbox = new GUI::CheckboxWidget(this, 5, 70, 130, 20, "Left handed mode", 0, 'L'); - _indyFightCheckbox = new GUI::CheckboxWidget(this, 5, 40, 200, 20, "Indy fighting controls", 0, 'I'); - _twoHundredPercentCheckbox = new GUI::CheckboxWidget(this, 5, 55, 230, 20, "Zoomed screen at fixed 200% zoom", 0, 'T'); - _highQualityAudioCheckbox = new GUI::CheckboxWidget(this, 5, 25, 250, 20, "High quality audio (slower) (reboot)", 0, 'T'); - _disablePowerOff = new GUI::CheckboxWidget(this, 5, 85, 130, 20, "Disable power off", 0, 'T'); - _showCursorCheckbox = new GUI::CheckboxWidget(this, 5, 100, 130, 20, "Show mouse cursor", 0, 'T'); //#ifdef ALLOW_CPU_SCALER // _cpuScaler = new GUI::CheckboxWidget(this, 160, 115, 90, 20, "CPU scaler", 0, 'T'); //#endif - new GUI::StaticTextWidget(this, 180, 70, 130, 15, "Main screen:", GUI::kTextAlignLeft); - - _hardScaler = new GUI::CheckboxWidget(this, 140, 85, 170, 20, "Hardware scale (fast)", 0x10000001, 'T'); - _cpuScaler = new GUI::CheckboxWidget(this, 140, 100, 170, 20, "Software scale (quality)", 0x10000002, 'S'); - _unscaledCheckbox = new GUI::CheckboxWidget(this, 140, 115, 170, 20, "Unscaled", 0x10000003, 'S'); - _snapToBorderCheckbox = new GUI::CheckboxWidget(this, 5, 115, 120, 20, "Snap to border", 0, 'T'); - new GUI::StaticTextWidget(this, 20, 145, 110, 15, "Touch X Offset", GUI::kTextAlignLeft); - _touchX = new GUI::SliderWidget(this, 130, 145, 130, 12, 1); - _touchX->setMinValue(-8); - _touchX->setMaxValue(+8); - _touchX->setValue(0); - _touchX->setFlags(GUI::WIDGET_CLEARBG); - - new GUI::StaticTextWidget(this, 20, 160, 110, 15, "Touch Y Offset", GUI::kTextAlignLeft); - _touchY = new GUI::SliderWidget(this, 130, 160, 130, 12, 2); - _touchY->setMinValue(-8); - _touchY->setMaxValue(+8); - _touchY->setValue(0); - _touchY->setFlags(GUI::WIDGET_CLEARBG); - - new GUI::StaticTextWidget(this, 130 + 65 - 10, 175, 20, 15, "0", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 + 130 - 10, 175, 20, 15, "8", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 - 10, 175, 20, 15, "-8", GUI::kTextAlignCenter); #ifdef DS_SCUMM_BUILD _delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm); @@ -125,10 +156,36 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { _unscaledCheckbox->setState(false); } - if (ConfMan.hasKey("twohundredpercent", "ds")) { - _twoHundredPercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds")); + + if (ConfMan.hasKey("topscreenzoom", "ds")) { + + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(false); + + switch (ConfMan.getInt("topscreenzoom", "ds")) + { + case 100: { + _100PercentCheckbox->setState(true); + break; + } + + case 150: { + _150PercentCheckbox->setState(true); + break; + } + + case 200: { + _200PercentCheckbox->setState(true); + break; + } + } + + } else if (ConfMan.hasKey("twohundredpercent", "ds")) { + _200PercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds")); } else { - _twoHundredPercentCheckbox->setState(false); + // No setting + _150PercentCheckbox->setState(true); } if (ConfMan.hasKey("22khzaudio", "ds")) { @@ -165,6 +222,29 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) { _touchY->setValue(0); } + if (ConfMan.hasKey("sensitivity", "ds")) { + _sensitivity->setValue(ConfMan.getInt("sensitivity", "ds")); + } else { + _sensitivity->setValue(8); + } + + if (ConfMan.hasKey("touchpad", "ds")) { + _touchPadStyle->setState(ConfMan.getBool("touchpad", "ds")); + } else { + _touchPadStyle->setState(0); + } + + if (ConfMan.hasKey("screentaps", "ds")) { + _screenTaps->setState(ConfMan.getBool("screentaps", "ds")); + } else { + _screenTaps->setState(0); + } + + _screenTaps->setEnabled(!_touchPadStyle->getState()); + _sensitivity->setEnabled(_touchPadStyle->getState()); + _sensitivityLabel->setEnabled(_touchPadStyle->getState()); + _sensitivityLabel->draw(); + if (!_cpuScaler->getState() && !_unscaledCheckbox->getState()) { _hardScaler->setState(true); } @@ -180,7 +260,7 @@ DSOptionsDialog::~DSOptionsDialog() { void DSOptionsDialog::updateConfigManager() { ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds"); ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds"); - ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds"); +// ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds"); ConfMan.setBool("22khzaudio", _highQualityAudioCheckbox->getState(), "ds"); ConfMan.setBool("disablepoweroff", _disablePowerOff->getState(), "ds"); #ifdef ALLOW_CPU_SCALER @@ -190,6 +270,24 @@ void DSOptionsDialog::updateConfigManager() { ConfMan.setInt("yoffset", _touchY->getValue(), "ds"); ConfMan.setBool("showcursor", _showCursorCheckbox->getState(), "ds"); ConfMan.setBool("snaptoborder", _snapToBorderCheckbox->getState(), "ds"); + ConfMan.setBool("touchpad", _touchPadStyle->getState(), "ds"); + ConfMan.setBool("screentaps", _screenTaps->getState(), "ds"); + ConfMan.setInt("sensitivity", _sensitivity->getValue(), "ds"); + + u32 zoomLevel = 150; + + if (_100PercentCheckbox->getState()) { + zoomLevel = 100; + } else if (_150PercentCheckbox->getState()) { + zoomLevel = 150; + } else if (_200PercentCheckbox->getState()) { + zoomLevel = 200; + } + + consolePrintf("Saved zoom: %d\n", zoomLevel); + + ConfMan.setInt("topscreenzoom", zoomLevel, "ds"); + DS::setOptions(); } @@ -227,6 +325,70 @@ void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint } + if ((!guard) && (_radioButtonMode)) + { + guard = true; + + if ((sender == _touchPadStyle) && (cmd == 0x20000001)) { + + if (_touchPadStyle->getState()) { + // Swap screens when turning on trackpad style, it feels + // much more natural! + DS::setGameScreenSwap(true); + + _screenTaps->setState(true); + _screenTaps->setEnabled(false); + _screenTaps->draw(); + _sensitivity->setEnabled(true); + _sensitivityLabel->setEnabled(true); + _sensitivityLabel->draw(); + _sensitivity->draw(); + } else { + DS::setGameScreenSwap(false); + + _screenTaps->setEnabled(true); + _screenTaps->setState(false); + _screenTaps->draw(); + _sensitivity->setEnabled(false); + _sensitivityLabel->setEnabled(false); + _sensitivityLabel->draw(); + _sensitivity->draw(); + } + } + + guard = false; + } + + if ((!guard) && (_radioButtonMode)) { + + guard = true; + + if (cmd == 0x30000001) { + _100PercentCheckbox->setState(true); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(false); + DS::setTopScreenZoom(100); + } + + if (cmd == 0x30000002) { + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(true); + _200PercentCheckbox->setState(false); + DS::setTopScreenZoom(150); + } + + if (cmd == 0x30000003) { + _100PercentCheckbox->setState(false); + _150PercentCheckbox->setState(false); + _200PercentCheckbox->setState(true); + DS::setTopScreenZoom(200); + } + + guard = false; + + } + + if (cmd == GUI::kCloseCmd) { updateConfigManager(); close(); @@ -297,6 +459,8 @@ void showOptionsDialog() { } void setOptions() { + static bool firstLoad = true; + ConfMan.addGameDomain("ds"); if (ConfMan.hasKey("lefthanded", "ds")) { @@ -327,10 +491,16 @@ void setOptions() { DS::setUnscaledMode(false); } - if (ConfMan.hasKey("twohundredpercent", "ds")) { - DS::set200PercentFixedScale(ConfMan.getBool("twohundredpercent", "ds")); - } else { - DS::set200PercentFixedScale(false); + if (firstLoad) { + if (ConfMan.hasKey("topscreenzoom", "ds")) { + DS::setTopScreenZoom(ConfMan.getInt("topscreenzoom", "ds")); + } else { + if (ConfMan.hasKey("twohundredpercent", "ds")) { + DS::setTopScreenZoom(200); + } else { + DS::setTopScreenZoom(150); + } + } } if (ConfMan.hasKey("xoffset", "ds")) { @@ -345,6 +515,12 @@ void setOptions() { DS::setTouchXOffset(0); } + if (ConfMan.hasKey("sensitivity", "ds")) { + DS::setSensitivity(ConfMan.getInt("sensitivity", "ds")); + } else { + DS::setSensitivity(8); + } + #ifdef ALLOW_CPU_SCALER if (ConfMan.hasKey("cpu_scaler", "ds")) { DS::setCpuScalerEnable(ConfMan.getBool("cpu_scaler", "ds")); @@ -353,6 +529,33 @@ void setOptions() { } #endif + if (ConfMan.hasKey("screentaps", "ds")) { + DS::setTapScreenClicksEnable(ConfMan.getBool("screentaps", "ds")); + } else { + DS::setTapScreenClicksEnable(false); + } + + if (ConfMan.hasKey("touchpad", "ds")) { + bool enable = ConfMan.getBool("touchpad", "ds"); + + DS::setTrackPadStyleEnable(enable); + + if ((enable) and (firstLoad)) { + // If we've just booted up, want to swap screens when trackpad mode is in use + // but not every time we enter the options dialog. + DS::setGameScreenSwap(true); + } + + if (enable) { + DS::setTapScreenClicksEnable(true); + } + + } else { + DS::setTrackPadStyleEnable(false); + } + + + firstLoad = false; } } diff --git a/backends/platform/ds/arm9/source/dsoptions.h b/backends/platform/ds/arm9/source/dsoptions.h index 9cfa785ca8..e3ab2f55e0 100644 --- a/backends/platform/ds/arm9/source/dsoptions.h +++ b/backends/platform/ds/arm9/source/dsoptions.h @@ -30,6 +30,7 @@ #include "gui/object.h" #include "gui/widget.h" #include "gui/dialog.h" +#include "gui/TabWidget.h" #include "scumm/dialogs.h" namespace DS { @@ -45,11 +46,18 @@ protected: void togglePause(); void updateConfigManager(); + GUI::TabWidget* _tab; + + GUI::StaticTextWidget* _sensitivityLabel; + GUI::SliderWidget* _touchX; GUI::SliderWidget* _touchY; + GUI::SliderWidget* _sensitivity; GUI::CheckboxWidget* _leftHandedCheckbox; GUI::CheckboxWidget* _unscaledCheckbox; - GUI::CheckboxWidget* _twoHundredPercentCheckbox; + GUI::CheckboxWidget* _100PercentCheckbox; + GUI::CheckboxWidget* _150PercentCheckbox; + GUI::CheckboxWidget* _200PercentCheckbox; GUI::CheckboxWidget* _indyFightCheckbox; GUI::CheckboxWidget* _highQualityAudioCheckbox; GUI::CheckboxWidget* _disablePowerOff; @@ -59,6 +67,9 @@ protected: GUI::CheckboxWidget* _hardScaler; GUI::CheckboxWidget* _cpuScaler; + GUI::CheckboxWidget* _touchPadStyle; + GUI::CheckboxWidget* _screenTaps; + #ifdef DS_SCUMM_BUILD Scumm::SaveLoadChooser* _delDialog; #endif diff --git a/backends/platform/ds/arm9/source/gbampsave.cpp b/backends/platform/ds/arm9/source/gbampsave.cpp index ed45d02b1e..068d996e92 100644 --- a/backends/platform/ds/arm9/source/gbampsave.cpp +++ b/backends/platform/ds/arm9/source/gbampsave.cpp @@ -155,11 +155,13 @@ GBAMPSaveFile* GBAMPSaveFileManager::openSavefile(char const* name, bool saveOrL sprintf(fileSpec, "%s/%s", getSavePath(), name); } -// consolePrintf(fileSpec); +// consolePrintf("Opening the file: %s\n", fileSpec); GBAMPSaveFile* sf = new GBAMPSaveFile(fileSpec, saveOrLoad); if (sf->isOpen()) { +// consolePrintf("Ok"); return sf; } else { +// consolePrintf("Fail"); delete sf; return NULL; } diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp index 79b0c5390b..5ddcb50b15 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.cpp +++ b/backends/platform/ds/arm9/source/osystem_ds.cpp @@ -41,7 +41,8 @@ OSystem_DS* OSystem_DS::_instance = NULL; OSystem_DS::OSystem_DS() - : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false) + : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false), + _disableCursorPalette(true), _graphicsEnable(true) { // eventNum = 0; // lastPenFrame = 0; @@ -71,7 +72,13 @@ void OSystem_DS::initBackend() { _timer = new DSTimerManager(); DS::setTimerCallback(&OSystem_DS::timerHandler, 10); - _mixer->setOutputRate(11025 /*DS::getSoundFrequency()*/); + if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) { + DS::startSound(22050, 8192); + } else { + DS::startSound(11025, 4096); + } + + _mixer->setOutputRate(DS::getSoundFrequency()); _mixer->setReady(true); OSystem::initBackend(); @@ -79,7 +86,7 @@ void OSystem_DS::initBackend() { bool OSystem_DS::hasFeature(Feature f) { // consolePrintf("hasfeature\n"); - return (f == kFeatureVirtualKeyboard); + return (f == kFeatureVirtualKeyboard) || (f == kFeatureCursorHasPalette); } void OSystem_DS::setFeatureState(Feature f, bool enable) { @@ -107,7 +114,7 @@ bool OSystem_DS::setGraphicsMode(int mode) { } bool OSystem_DS::setGraphicsMode(const char *name) { -// consolePrintf("Set gfx mode %s\n", name); + consolePrintf("Set gfx mode %s\n", name); return true; } @@ -116,8 +123,15 @@ int OSystem_DS::getGraphicsMode() const { } void OSystem_DS::initSize(uint width, uint height) { -// consolePrintf("Set gfx mode %d x %d\n", width, height); - DS::setGameSize(width, height); + // For Lost in Time, the title screen is displayed in 640x400. + // In order to support this game, the screen mode is set, but + // all draw calls are ignored until the game switches to 320x200. + if ((width == 640) && (height == 400)) { + _graphicsEnable = false; + } else { + _graphicsEnable = true; + DS::setGameSize(width, height); + } } int16 OSystem_DS::getHeight() { @@ -129,9 +143,8 @@ int16 OSystem_DS::getWidth() { } void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { -// consolePrintf("Set palette %d, %d colours\n", start, num); -//return; - if (!DS::getIsDisplayMode8Bit()) return; +// consolePrintf("Setpal %d, %d\n", start, num); + for (unsigned int r = start; r < start + num; r++) { int red = *colors; int green = *(colors + 1); @@ -141,17 +154,44 @@ void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { green >>= 3; blue >>= 3; - if (r != 255) +// if (r != 255) { - BG_PALETTE[r] = red | (green << 5) | (blue << 10); - if (!DS::getKeyboardEnable()) { - BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10); + u16 paletteValue = red | (green << 5) | (blue << 10); + + if (DS::getIsDisplayMode8Bit()) { + BG_PALETTE[r] = paletteValue; + if (!DS::getKeyboardEnable()) { + BG_PALETTE_SUB[r] = paletteValue; + } } + + _palette[r] = paletteValue; } -// if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue); + // if (num == 255) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue); + + colors += 4; + } +} + +void OSystem_DS::setCursorPalette(const byte *colors, uint start, uint num) { + +// consolePrintf("Cursor palette set: start: %d, cols: %d\n", start, num); + for (unsigned int r = start; r < start + num; r++) { + int red = *colors; + int green = *(colors + 1); + int blue = *(colors + 2); + + red >>= 3; + green >>= 3; + blue >>= 3; + u16 paletteValue = red | (green << 5) | (blue << 10); + _cursorPalette[r] = paletteValue; + colors += 4; } + + _disableCursorPalette = false; } bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) { @@ -184,9 +224,11 @@ void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) { } +#define MISALIGNED16(ptr) (((u32) (ptr) & 1) != 0) + void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { -// consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h); - + //consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h); + if (!_graphicsEnable) return; if (w <= 1) return; if (h < 0) return; if (!DS::getIsDisplayMode8Bit()) return; @@ -195,6 +237,9 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int s32 stride; u16* bgSub = (u16 *) BG_GFX_SUB; + // The DS video RAM doesn't support 8-bit writes because Nintendo wanted + // to save a few pennies/euro cents on the hardware. + if (_frameBufferExists) { bg = (u16 *) _framebuffer.pixels; stride = _framebuffer.pitch; @@ -203,46 +248,117 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int stride = DS::get8BitBackBufferStride(); } - u16* src = (u16 *) buf; - - if (DS::getKeyboardEnable()) { - + if (((pitch & 1) != 0) || ((w & 1) != 0) || (((int) (buf) & 1) != 0)) { + + // Something is misaligned, so we have to use the slow but sure method + + int by = 0; + for (int dy = y; dy < y + h; dy++) { - u16* dest = bg + (dy * (stride >> 1)) + (x >> 1); - - DC_FlushRange(src, w << 1); - DC_FlushRange(dest, w << 1); - dmaCopyHalfWords(3, src, dest, w); - - src += pitch >> 1; + u8* dest = ((u8 *) (bg)) + (dy * stride) + x; + u8* destSub = ((u8 *) (bgSub)) + (dy * 512) + x; + u8* src = (u8 *) buf + (pitch * by); + + u32 dx; + + u32 pixelsLeft = w; + + if (MISALIGNED16(dest)) { + // Read modify write + + dest--; + u16 mix = *((u16 *) dest); + + mix = (mix & 0x00FF) | (*src++ << 8); + + *dest = mix; + *destSub = mix; + + dest += 2; + destSub += 2; + pixelsLeft--; + } + + // We can now assume dest is aligned + u16* dest16 = (u16 *) dest; + u16* destSub16 = (u16 *) destSub; + + for (dx = 0; dx < pixelsLeft; dx+=2) { + u16 mix; + + mix = *src + (*(src + 1) << 8); + *dest16++ = mix; + *destSub16++ = mix; + src += 2; + } + + pixelsLeft -= dx; + + // At the end we may have one pixel left over + + if (pixelsLeft != 0) { + u16 mix = *dest16; + + mix = (mix & 0x00FF) | ((*src++) << 8); + + *dest16 = mix; + *destSub16 = mix; + } + + by++; + } - + +// consolePrintf("Slow method used!\n"); + + } else { - for (int dy = y; dy < y + h; dy++) { - u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1); - u16* dest2 = bgSub + (dy << 8) + (x >> 1); + + // Stuff is aligned to 16-bit boundaries, so it's safe to do DMA. + + u16* src = (u16 *) buf; + + if (DS::getKeyboardEnable()) { + + for (int dy = y; dy < y + h; dy++) { + u16* dest = bg + (dy * (stride >> 1)) + (x >> 1); - DC_FlushRange(src, w << 1); - DC_FlushRange(dest1, w << 1); - DC_FlushRange(dest2, w << 1); - - dmaCopyHalfWords(3, src, dest1, w); - dmaCopyHalfWords(3, src, dest2, w); - - src += pitch >> 1; - } - } + DC_FlushRange(src, w << 1); + DC_FlushRange(dest, w << 1); + dmaCopyHalfWords(3, src, dest, w); -// consolePrintf("Done\n"); + while (dmaBusy(3)); + + src += pitch >> 1; + } + + } else { + for (int dy = y; dy < y + h; dy++) { + u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1); + u16* dest2 = bgSub + (dy << 8) + (x >> 1); + + DC_FlushRange(src, w << 1); + DC_FlushRange(dest1, w << 1); + DC_FlushRange(dest2, w << 1); + + dmaCopyHalfWords(3, src, dest1, w); - + if ((!_frameBufferExists) || (buf == _framebuffer.pixels)) { + dmaCopyHalfWords(2, src, dest2, w); + } + while (dmaBusy(2) || dmaBusy(3)); + + src += pitch >> 1; + } + } + } +// consolePrintf("Done\n"); } void OSystem_DS::updateScreen() { - if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit())) - { + if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit())) { _frameBufferExists = false; // Copy temp framebuffer back to screen @@ -253,6 +369,12 @@ void OSystem_DS::updateScreen() { DS::doSoundCallback(); // DS::doTimerCallback(); DS::addEventsToQueue(); + + // Force back buffer usage for Nippon Safes, as it doesn't double buffer it's output + if (DS::getControlType() == DS::CONT_NIPPON) { + OSystem_DS::instance()->lockScreen(); + OSystem_DS::instance()->unlockScreen(); + } } void OSystem_DS::setShakePos(int shakeOffset) { @@ -334,7 +456,21 @@ void OSystem_DS::warpMouse(int x, int y) { } void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) { - DS::setCursorIcon(buf, w, h, keycolor, hotspotX, hotspotY); + if ((w > 0) && (w < 64) && (h > 0) && (h < 64)) + { + memcpy(_cursorImage, buf, w * h); + _cursorW = w; + _cursorH = h; + _cursorHotX = hotspotX; + _cursorHotY = hotspotY; + _cursorKey = keycolor; + _cursorScale = targetCursorScale; + refreshCursor(); + } +} + +void OSystem_DS::refreshCursor() { + DS::setCursorIcon(_cursorImage, _cursorW, _cursorH, _cursorKey, _cursorHotX, _cursorHotY); } void OSystem_DS::addEvent(Common::Event& e) { @@ -489,7 +625,11 @@ Common::SaveFileManager* OSystem_DS::getSavefileManager() { if (DS::isGBAMPAvailable() && (!forceSram)) { return &mpSaveManager; } else { +#ifdef GBA_SRAM_SAVE return &saveManager; +#else + return NULL; +#endif } } diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index 8c8d661ad8..16c8f41491 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.h +++ b/backends/platform/ds/arm9/source/osystem_ds.h @@ -52,17 +52,32 @@ protected: Common::Event eventQueue[96]; int queuePos; +#ifdef GBA_SRAM_SAVE DSSaveFileManager saveManager; +#endif GBAMPSaveFileManager mpSaveManager; DSAudioMixer* _mixer; DSTimerManager* _timer; Graphics::Surface _framebuffer; bool _frameBufferExists; - + bool _graphicsEnable; static OSystem_DS* _instance; + + u16 _palette[256]; + u16 _cursorPalette[256]; + + u8 _cursorImage[64 * 64]; + uint _cursorW; + uint _cursorH; + int _cursorHotX; + int _cursorHotY; + byte _cursorKey; + int _cursorScale; + Graphics::Surface* createTempFrameBuffer(); + bool _disableCursorPalette; public: typedef void (*SoundProc)(byte *buf, int len); @@ -159,7 +174,16 @@ public: virtual void clearAutoComplete(); virtual void setCharactersEntered(int count); + u16 getDSPaletteEntry(u32 entry) { return _palette[entry]; } + u16 getDSCursorPaletteEntry(u32 entry) { return !_disableCursorPalette? _cursorPalette[entry]: _palette[entry]; } + + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + virtual void disableCursorPalette(bool dis) { _disableCursorPalette = dis; refreshCursor(); } + FilesystemFactory *getFilesystemFactory(); + + void refreshCursor(); }; static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { diff --git a/backends/platform/ds/arm9/source/portdefs.h b/backends/platform/ds/arm9/source/portdefs.h index de7a5795f5..16f3d8cc9b 100644 --- a/backends/platform/ds/arm9/source/portdefs.h +++ b/backends/platform/ds/arm9/source/portdefs.h @@ -81,7 +81,10 @@ void consolePrintf(const char* s, ...); #define ITCM_DATA __attribute__((section(".itcm"))) - +// Since I can't change the engine at the moment (post lockdown) this define can go here. +// This define changes the mouse-relative motion which doesn't make sense on a touch screen to +// a more conventional form of input where the menus can be clicked on. +#define LURE_CLICKABLE_MENUS //#include "common/array.h" //#include "common/str.h" diff --git a/backends/platform/ds/arm9/source/ramsave.cpp b/backends/platform/ds/arm9/source/ramsave.cpp index 30c3a06721..a9f4e3d2fc 100644 --- a/backends/platform/ds/arm9/source/ramsave.cpp +++ b/backends/platform/ds/arm9/source/ramsave.cpp @@ -19,7 +19,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ - // Save in order 1,2,3,4,larger 2,5 +#ifdef GBA_SRAM_SAVE + + #include "ramsave.h" #include "nds.h" #include "compressor/lz.h" @@ -237,7 +239,7 @@ uint32 DSSaveFile::write(const void *buf, uint32 size) { return size; } -bool DSSaveFile::matches(char* prefix, int num) { +bool DSSaveFile::matches(const char *prefix, int num) { char str[16]; if (isValid()) { sprintf(str, "%s%02d", prefix, num); @@ -251,7 +253,7 @@ bool DSSaveFile::matches(char* prefix, int num) { } } -bool DSSaveFile::matches(char* filename) { +bool DSSaveFile::matches(const char *filename) { if (isValid()) { return !strcmp(save.name, filename); } else { @@ -532,3 +534,5 @@ int DSSaveFileManager::getExtraData() { return 0; } } + +#endif diff --git a/backends/platform/ds/arm9/source/ramsave.h b/backends/platform/ds/arm9/source/ramsave.h index 98430b9d11..034e957b7f 100644 --- a/backends/platform/ds/arm9/source/ramsave.h +++ b/backends/platform/ds/arm9/source/ramsave.h @@ -78,8 +78,8 @@ public: bool isValid() { return save.isValid; } bool isTemp() { return isTempFile; } - bool matches(char* prefix, int num); - bool matches(char* filename); + bool matches(const char *prefix, int num); + bool matches(const char *filename); void clearData(); void compress(); diff --git a/backends/platform/ds/arm9/source/touchkeyboard.cpp b/backends/platform/ds/arm9/source/touchkeyboard.cpp index 11832f4e3a..85f80fac92 100644 --- a/backends/platform/ds/arm9/source/touchkeyboard.cpp +++ b/backends/platform/ds/arm9/source/touchkeyboard.cpp @@ -402,6 +402,23 @@ void createKeyEvent(int keyNum, Common::Event& event) } } +void releaseAllKeys() { + for (int r = 0; r < DS_NUM_KEYS; r++) { + if (keys[r].pressed) { + DS::setKeyHighlight(r, false); + + OSystem_DS* system = OSystem_DS::instance(); + + Common::Event event; + createKeyEvent(r, event); + event.type = Common::EVENT_KEYUP; + system->addEvent(event); + + keys[r].pressed = false; + } + } +} + void addKeyboardEvents() { bool resetShift = false; @@ -446,7 +463,7 @@ void addKeyboardEvents() { // consolePrintf("Key: %d\n", r); if ((keys[r].character == Common::KEYCODE_INVALID)) { // Close button - DS::closed = true; + //DS::closed = true; } else { createKeyEvent(r, event); } @@ -492,9 +509,14 @@ void addKeyboardEvents() { OSystem_DS* system = OSystem_DS::instance(); Common::Event event; - createKeyEvent(r, event); - event.type = Common::EVENT_KEYUP; - system->addEvent(event); + if ((keys[r].character == Common::KEYCODE_INVALID)) { + // Close button + DS::closed = true; + } else { + createKeyEvent(r, event); + event.type = Common::EVENT_KEYUP; + system->addEvent(event); + } keys[r].pressed = false; diff --git a/backends/platform/ds/arm9/source/touchkeyboard.h b/backends/platform/ds/arm9/source/touchkeyboard.h index 8a5fc728ce..91efbc1e9a 100644 --- a/backends/platform/ds/arm9/source/touchkeyboard.h +++ b/backends/platform/ds/arm9/source/touchkeyboard.h @@ -40,6 +40,7 @@ bool getKeyboardClosed(); void addAutoComplete(char* word); void clearAutoComplete(); void setCharactersEntered(int count); +void releaseAllKeys(); } diff --git a/backends/platform/ds/logog.bmp b/backends/platform/ds/logog.bmp Binary files differnew file mode 100644 index 0000000000..9c194d3f82 --- /dev/null +++ b/backends/platform/ds/logog.bmp diff --git a/backends/platform/ds/makefile b/backends/platform/ds/makefile index 3fb19e939c..a9fbb13637 100644 --- a/backends/platform/ds/makefile +++ b/backends/platform/ds/makefile @@ -36,3 +36,23 @@ allbuilds: make all SCUMM_BUILD=f make semiclean make all SCUMM_BUILD=g + make semiclean + make all SCUMM_BUILD=h + +allbuildssafe: + make clean SCUMM_BUILD=a + make all SCUMM_BUILD=a + make clean SCUMM_BUILD=b + make all SCUMM_BUILD=b + make clean SCUMM_BUILD=c + make all SCUMM_BUILD=c + make clean SCUMM_BUILD=d + make all SCUMM_BUILD=d + make clean SCUMM_BUILD=e + make all SCUMM_BUILD=e + make clean SCUMM_BUILD=f + make all SCUMM_BUILD=f + make clean SCUMM_BUILD=g + make all SCUMM_BUILD=g + make clean SCUMM_BUILD=h + make all SCUMM_BUILD=h |