Merge pull request #745 from Cruel/3ds

3DS: New Backend
This commit is contained in:
Eugene Sandulenko 2016-05-16 10:05:00 +02:00
commit 2cd0a99e2b
28 changed files with 2617 additions and 13 deletions

View file

@ -302,6 +302,9 @@ ScummVM Team
Frantisek Dufka - (retired) Frantisek Dufka - (retired)
Tarek Soliman Tarek Soliman
Nintendo 3DS:
Thomas Edvalson
Nintendo 64: Nintendo 64:
Fabio Battaglia Fabio Battaglia

View file

@ -0,0 +1,64 @@
TARGET := scummvm
APP_TITLE := ScummVM
APP_DESCRIPTION := Point-and-click adventure game engines
APP_AUTHOR := ScummVM Team
APP_ICON := backends/platform/3ds/app/icon.png
APP_RSF := backends/platform/3ds/app/scummvm.rsf
APP_BANNER_IMAGE:= backends/platform/3ds/app/banner.png
APP_BANNER_AUDIO:= backends/platform/3ds/app/banner.wav
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CXXFLAGS += -std=gnu++11
ASFLAGS += -mfloat-abi=hard
LDFLAGS += -specs=3dsx.specs $(ARCH) -L$(DEVKITPRO)/libctru/lib -L$(DEVKITPRO)/portlibs/3ds/lib
.PHONY: clean_3ds
clean: clean_3ds
clean_3ds:
$(RM) $(TARGET).3dsx
$(RM) $(TARGET).cia
$(TARGET).smdh: $(APP_ICON)
@bannertool makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i $(APP_ICON) -o $@
@echo built ... $(notdir $@)
$(TARGET).3dsx: $(EXECUTABLE) $(TARGET).smdh
@3dsxtool $< $@ --smdh=$(TARGET).smdh
@echo built ... $(notdir $@)
$(TARGET).bnr: $(APP_BANNER_IMAGE) $(APP_BANNER_AUDIO)
@bannertool makebanner -o $@ -i $(APP_BANNER_IMAGE) -a $(APP_BANNER_AUDIO)
@echo built ... $(notdir $@)
$(TARGET).cia: $(EXECUTABLE) $(APP_RSF) $(TARGET).smdh $(TARGET).bnr
@makerom -f cia -target t -exefslogo -o $@ -elf $(EXECUTABLE) -rsf $(APP_RSF) -banner $(TARGET).bnr -icon $(TARGET).smdh
@echo built ... $(notdir $@)
#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval FILEPATH := $(patsubst %.shbin.o,%.shbin,$@))
$(eval FILE := $(patsubst %.shbin.o,%.shbin,$(notdir $@)))
picasso -o $(FILEPATH) $1
bin2s $(FILEPATH) | $(AS) -o $@
echo "extern const u8" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(FILEPATH) | tr . _)`.h
echo "extern const u8" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(FILEPATH) | tr . _)`.h
echo "extern const u32" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(FILEPATH) | tr . _)`.h
endef
%.shbin.o : %.v.pica %.g.pica
@echo $(notdir $^)
@$(call shader-as,$^)
%.shbin.o : %.v.pica
@echo $(notdir $<)
@$(call shader-as,$<)
%.shbin.o : %.shlist
@echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))

View file

@ -0,0 +1,185 @@
ScummVM 3DS README
------------------------------------------------------------------------
Table of Contents:
------------------
1.0) Installation
* 1.1 3DSX installation
* 1.2 CIA installation
2.0) Controls
* 2.1 Default key mappings
* 2.2 Hover mode
* 2.3 Drag mode
3.0) Supported Games
4.0) Compiling
* 4.1 Prerequisites
* * 4.1.1 Compiling third-party libraries
* 4.2 Compiling ScummVM
* 4.3 Warning for 3DSX build
1.0) Installation
-----------------
There are two possible formats to be used: 3DSX and CIA (recommended).
The 3DSX format is exclusively used by the Homebrew Launcher and its derivatives.
The CIA format can be installed directly to the 3DS home menu and can be launched
using any CFW (Custom Firmware) of your choice.
Installing the Homebrew Launcher or any CFW is beyond the scope of this README.
Look elsewhere to see how to install those if you do not already have them set up.
1.1) 3DSX installation
----------------
The CIA format is recommended for stability and maximum game support. If that is
not an option, you will need one of a collection of 3DS titles installed on your
system in order to properly launch ScummVM as a 3DSX. This is because the
Homebrew Launcher hijacks other processes to run 3DSX homebrew, and ScummVM is a
particularly large homebrew that can't be launched with the resources provided
by standard system applications.
You will need one of the following (installed or physically in cart slot):
- Youtube
- Monster Hunter 4 Ultimate Special Demo
- Monster Hunter 4 Ultimate
- Monster Hunter 4G
- Super Smash Bros. for Nintendo 3DS Demo
- Super Smash Bros. for Nintendo 3DS Special Demo
- Super Smash Bros. for Nintendo 3DS
Once you have one of the above, you need to merely extract all ScummVM 3DS files
to the root of your SD card so that all files reside in the /3ds/scummvm/ directory.
1.2) CIA installation
---------------------
The CIA format requires a DSP binary dump saved on your SD card as /3ds/dspfirm.cdc
for proper audio support. You can search online to find software to dump this.
Not having this file will cause many problems with games that need audio, sometimes
even crashing, so this is NOT considered optional.
Using any CIA installation software (search elsewhere for that), you need to install
the scummvm.cia file. Then, just like what is done with the 3DSX installation, you
need to extract all ScummVM 3DS files (scummvm.cia excluded) to the root of your SD
card so that all files reside in the /3ds/scummvm/ directory.
2.0) Controls
-------------
2.1) Default key mappings
-------------------------
The D-Pad and A/B/X/Y buttons have mirrored usage. So they do the same things
depending on if you're right or left-handed.
| Buttons | Function |
|------------|--------------------------------|
| A / D-left | Left-click |
| X / D-up | Right-click |
| B / D-down | ESC (skips cutscenes and such) |
| L | Use virtual keyboard |
| R | Toggle hover/drag modes |
| Start | Open game menu |
| Select | Open 3DS config menu |
| Circle Pad | Move the cursor |
2.2) Hover mode
---------------
When you use the touchscreen, you are simulating the mere moving of the mouse. You
can click only with taps, meaning it is impossible to drag stuff or hold down a
mouse button without using buttons mapped to right/left-click.
2.3) Drag mode
--------------
Every time you touch and release the touchscreen, you are simulating the click and
release of the mouse buttons. At the moment, this is only a left-click.
3.0) Supported Games
--------------------
The full game engine compatibility list can be found here:
http://scummvm.org/compatibility/
While all the above games should run on the 3DS (report if they do not), there are
many games which are unplayable due to the lack of CPU speed on the 3DS. So if
you play any games that run really slow, this is not considered a bug, but rather
a hardware limitation. Though possible GPU optimizations are always in the works.
The New 3DS console has much better performance, but there are still many newer and
high-resolution games that cannot be played. A list of these unplayable games and
game engines will eventually be listed here.
4.0) Compiling
--------------
4.1) Prerequisites
------------------
- devkitARM (presumably with libctru, picasso and such)
- citro3d
- Optional: You should compile third-party libraries for the 3ds (commonly referred
to as portlibs in the devkitPRO community). Some games requires these to operate
properly.
4.1.1) Compiling third-party libraries
--------------------------------------
Most libraries used can be compiled with same commands and configuration flags.
It is assumed that you have these environment variables defined:
- DEVKITPRO Your root devkitPro directory
- DEVKITARM Your root devkitARM directory (probably same as $DEVKITPRO/devkitARM)
- CTRULIB Your root libctru directory (probably same as $DEVKITPRO/libctru)
In the source directory of the library:
- $ export PORTLIBS=$DEVKITPRO/portlibs/armv6k
- $ export PATH=$DEVKITARM/bin:$PATH
- $ export PKG_CONFIG_PATH=$PORTLIBS/lib/pkgconfig
- $ export CFLAGS="-g -march=armv6k -mtune=mpcore -mfloat-abi=hard -O2
-mword-relocations -ffunction-sections -fdata-sections"
- $ export CPPFLAGS="-I$PORTLIBS/include -I$CTRULIB/include"
- $ export LDFLAGS="-L$PORTLIBS/lib"
- $ mkdir -p $PORTLIBS
- $ ./configure --prefix=$PORTLIBS --host=arm-none-eabi --disable-shared
--enable-static
- $ make
- $ make install
Useful libraries (and special config flags needed):
- zlib
- libpng
- libjpeg
- freetype2 --without-bzip2 --without-harfbuzz
- libmad
- tremor
- flac --disable-cpplibs --without-flac
- faad
4.2) Compiling ScummVM
----------------------
- $ ./configure --host=3ds
- $ make
Additionally compile to specific formats to be used on the 3ds:
- $ make scummvm.3dsx
- $ make scummvm.cia
4.3) Warning for 3DSX build
---------------------------
The above configuration command will include all game engines by default and will
likely be too massive to run using the 3DSX format. Until dynamic modules are figured
out, you should configure engines like this for 3DSX builds:
- $ ./configure --host=3ds --disable-all-engines--enable-engine=scumm-7-8,myst,riven,
sword1,sword2,sword25,sci,lure,sky,agi,agos
Choose whatever engines you want, but if the ELF's .text section exceeds ~10MB, it
won't be playable unless it's a CIA.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,219 @@
BasicInfo:
Title : ScummVM
ProductCode : ScummVM
Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem
TitleInfo:
Category : Application
UniqueId : 0xFF321
Option:
UseOnSD : true # true if App is to be installed to SD
FreeProductCode : true # Removes limitations on ProductCode
MediaFootPadding : false # If true CCI files are created with padding
EnableCrypt : false # Enables encryption for NCCH and CIA
EnableCompress : false # Compresses where applicable (currently only exefs:/.code)
AccessControlInfo:
CoreVersion : 2
# Exheader Format Version
DescVersion : 2
# Minimum Required Kernel Version (below is for 4.5.0)
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
# ExtData
UseExtSaveData : false # enables ExtData
#ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId
# FS:USER Archive Access Permissions
# Uncomment as required
FileSystemAccess:
#- CategorySystemApplication
#- CategoryHardwareCheck
#- CategoryFileSystemTool
#- Debug
#- TwlCardBackup
#- TwlNandData
#- Boss
- DirectSdmc
#- Core
#- CtrNandRo
#- CtrNandRw
#- CtrNandRoWrite
#- CategorySystemSettings
#- CardBoard
#- ExportImportIvs
#- DirectSdmcWrite
#- SwitchCleanup
#- SaveDataMove
#- Shop
#- Shell
#- CategoryHomeMenu
# Process Settings
MemoryType : Application # Application/System/Base
SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB
IdealProcessor : 0
AffinityMask : 1
Priority : 16
MaxCpu : 0 # Let system decide
HandleTableSize : 0x200
DisableDebug : false
EnableForceDebug : false
CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : true
PermitMainFunctionArgument : true
CanShareDeviceMemory : true
RunnableOnSleep : false
SpecialMemoryArrange : true
# New3DS Exclusive Process Settings
SystemModeExt : 124MB # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
CpuSpeed : 804MHz # 268MHz(Default)/804MHz
EnableL2Cache : true # false(default)/true
CanAccessCore2 : true
# Virtual Address Mappings
IORegisterMapping:
- 1ff00000-1ff7ffff # DSP memory
MemoryMapping:
- 1f000000-1f5fffff:r # VRAM
# Accessible SVCs, <Name>:<ID>
SystemCallAccess:
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreateSemaphore: 21
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdOfThread: 54
GetProcessIdealProcessor: 6
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
ReleaseMutex: 20
ReleaseSemaphore: 22
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
Backdoor: 123
# Service List
# Maximum 34 services (32 if firmware is prior to 9.3.0)
ServiceAccessControl:
- cfg:u
- fs:USER
- gsp::Gpu
- hid:USER
- ndm:u
- pxi:dev
- APT:U
- ac:u
- act:u
- am:net
- boss:U
- cam:u
- cecd:u
- dsp::DSP
- frd:u
- http:C
- ir:USER
- ir:u
- ir:rst
- ldr:ro
- mic:u
- news:u
- nim:aoc
- nwm::UDS
- ptm:u
- qtm:u
- soc:U
- ssl:C
- y2r:u
- gsp::Lcd
SystemControlInfo:
SaveDataSize: 0K
RemasterVersion: 0
StackSize: 0x40000
# Modules that run services listed above should be included below
# Maximum 48 dependencies
# If a module is listed that isn't present on the 3DS, the title will get stuck at the logo (3ds waves)
# So act, nfc and qtm are commented for 4.x support. Uncomment if you need these.
# <module name>:<module titleid>
Dependency:
ac: 0x0004013000002402
#act: 0x0004013000003802
am: 0x0004013000001502
boss: 0x0004013000003402
camera: 0x0004013000001602
cecd: 0x0004013000002602
cfg: 0x0004013000001702
codec: 0x0004013000001802
csnd: 0x0004013000002702
dlp: 0x0004013000002802
dsp: 0x0004013000001a02
friends: 0x0004013000003202
gpio: 0x0004013000001b02
gsp: 0x0004013000001c02
hid: 0x0004013000001d02
http: 0x0004013000002902
i2c: 0x0004013000001e02
ir: 0x0004013000003302
mcu: 0x0004013000001f02
mic: 0x0004013000002002
ndm: 0x0004013000002b02
news: 0x0004013000003502
#nfc: 0x0004013000004002
nim: 0x0004013000002c02
nwm: 0x0004013000002d02
pdn: 0x0004013000002102
ps: 0x0004013000003102
ptm: 0x0004013000002202
#qtm: 0x0004013020004202
ro: 0x0004013000003702
socket: 0x0004013000002e02
spi: 0x0004013000002302
ssl: 0x0004013000002f02

View file

@ -0,0 +1,87 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "osystem.h"
#include "options-dialog.h"
#include "common/config-manager.h"
#include <3ds.h>
namespace _3DS {
Config config;
static Common::String prefix = "3ds_";
static bool confGetBool(Common::String key, bool defaultVal) {
if (ConfMan.hasKey(prefix + key))
return ConfMan.getBool(prefix + key);
return defaultVal;
}
static void confSetBool(Common::String key, bool val) {
ConfMan.setBool(prefix + key, val);
}
static int confGetInt(Common::String key, int defaultVal) {
if (ConfMan.hasKey(prefix + key))
return ConfMan.getInt(prefix + key);
return defaultVal;
}
static void confSetInt(Common::String key, int val) {
ConfMan.setInt(prefix + key, val);
}
void loadConfig() {
config.showCursor = confGetBool("showcursor", true);
config.snapToBorder = confGetBool("snaptoborder", true);
config.stretchToFit = confGetBool("stretchtofit", false);
config.sensitivity = confGetInt("sensitivity", -5);
config.screen = confGetInt("screen", kScreenBoth);
// Turn off the backlight of any screen not used
if (R_SUCCEEDED(gspLcdInit())) {
if (config.screen == kScreenTop) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_TOP);
GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_BOTTOM);
} else if (config.screen == kScreenBottom) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTTOM);
GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_TOP);
} else
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
gspLcdExit();
}
OSystem_3DS *osys = (OSystem_3DS *)g_system;
osys->updateConfig();
}
void saveConfig() {
confSetBool("showcursor", config.showCursor);
confSetBool("snaptoborder", config.snapToBorder);
confSetBool("stretchtofit", config.stretchToFit);
confSetInt("sensitivity", config.sensitivity);
confSetInt("screen", config.screen);
ConfMan.flushToDisk();
}
} // namespace _3DS

View file

@ -0,0 +1,45 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef CONFIG_3DS_H
#define CONFIG_3DS_H
#include "common/str.h"
namespace _3DS {
struct Config {
bool showCursor;
bool snapToBorder;
bool stretchToFit;
int sensitivity;
int screen;
};
extern Config config;
void loadConfig();
void saveConfig();
} // namespace _3DS
#endif // CONFIG_3DS_H

View file

@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "backends/platform/3ds/gui.h"
#include "common/system.h"
StatusMessageDialog* StatusMessageDialog::_opened = 0;
StatusMessageDialog::StatusMessageDialog(const Common::String &message, uint32 duration)
: MessageDialog(message, 0, 0) {
_timer = g_system->getMillis() + duration;
if (_opened)
_opened->close();
_opened = this;
}
void StatusMessageDialog::handleTickle() {
MessageDialog::handleTickle();
if (g_system->getMillis() > _timer)
close();
}
void StatusMessageDialog::close() {
GUI::Dialog::close();
if (_opened)
_opened = 0;
}

View file

@ -0,0 +1,41 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GUI_3DS_H
#define GUI_3DS_H
#include "gui/message.h"
class StatusMessageDialog : public GUI::MessageDialog {
public:
StatusMessageDialog(const Common::String &message, uint32 duration);
void handleTickle();
protected:
virtual void close();
uint32 _timer;
static StatusMessageDialog* _opened;
};
#endif // GUI_3DS_H

View file

@ -0,0 +1,54 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "osystem.h"
#include <3ds.h>
int main(int argc, char *argv[]) {
// Initialize basic libctru stuff
gfxInitDefault();
cfguInit();
osSetSpeedupEnable(true);
// consoleInit(GFX_TOP, NULL);
g_system = new _3DS::OSystem_3DS();
assert(g_system);
// Invoke the actual ScummVM main entry point
// if (argc > 2)
// res = scummvm_main(argc-2, &argv[2]);
// else
// res = scummvm_main(argc, argv);
scummvm_main(0, nullptr);
delete dynamic_cast<_3DS::OSystem_3DS*>(g_system);
// Turn on both screen backlights before exiting.
if (R_SUCCEEDED(gspLcdInit())) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
gspLcdExit();
}
cfguExit();
gfxExit();
return 0;
}

View file

@ -0,0 +1,18 @@
MODULE := backends/platform/3ds
MODULE_OBJS := \
main.o \
shader.shbin.o \
sprite.o \
gui.o \
config.o \
options-dialog.o \
osystem.o \
osystem-graphics.o \
osystem-audio.o \
osystem-events.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
OBJS := $(MODULE_OBJS) $(OBJS)
MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))

View file

@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "options-dialog.h"
#include "config.h"
#include "gui/dialog.h"
#include "gui/gui-manager.h"
#include "gui/widgets/list.h"
#include "gui/widgets/tab.h"
#include "osystem.h"
#include "engines/scumm/scumm.h"
#include "gui/widgets/popup.h"
#include "common/translation.h"
namespace _3DS {
bool optionMenuOpened = false;
OptionsDialog::OptionsDialog() : GUI::Dialog(20, 20, 280, 200) {
optionMenuOpened = true;
new GUI::ButtonWidget(this, 120, 180, 72, 16, _("~C~lose"), 0, GUI::kCloseCmd);
new GUI::ButtonWidget(this, 200, 180, 72, 16, _("~S~ave"), 0, GUI::kOKCmd);
_showCursorCheckbox = new GUI::CheckboxWidget(this, 5, 5, 130, 20, _("Show mouse cursor"), 0, 0, 'T');
_showCursorCheckbox->setState(config.showCursor);
_snapToBorderCheckbox = new GUI::CheckboxWidget(this, 5, 22, 130, 20, _("Snap to edges"), 0, 0, 'T');
_snapToBorderCheckbox->setState(config.snapToBorder);
_stretchToFitCheckbox = new GUI::CheckboxWidget(this, 140, 5, 130, 20, _("Stretch to fit"), 0, 0, 'T');
_stretchToFitCheckbox->setState(config.stretchToFit);
new GUI::StaticTextWidget(this, 0, 60, 110, 15, _("Use Screen:"), Graphics::kTextAlignRight);
_screenRadioGroup = new GUI::RadiobuttonGroup(this, kScreenRadioGroup);
_screenTopRadioWidget = new GUI::RadiobuttonWidget(this, 120, 50, 60, 20, _screenRadioGroup, kScreenTop, _("Top"));
_screenBottomRadioWidget = new GUI::RadiobuttonWidget(this, 190, 50, 80, 20, _screenRadioGroup, kScreenBottom, _("Bottom"));
_screenBothRadioWidget = new GUI::RadiobuttonWidget(this, 155, 70, 80, 20, _screenRadioGroup, kScreenBoth, _("Both"));
_screenRadioGroup->setValue(config.screen);
new GUI::StaticTextWidget(this, 0, 100, 110, 15, _("C-Pad Sensitivity:"), Graphics::kTextAlignRight);
_sensitivity = new GUI::SliderWidget(this, 115, 100, 160, 15, "TODO: Add tooltip", 1);
_sensitivity->setMinValue(-15);
_sensitivity->setMaxValue(30);
_sensitivity->setValue(config.sensitivity);
_sensitivity->setFlags(GUI::WIDGET_CLEARBG);
}
OptionsDialog::~OptionsDialog() {
optionMenuOpened = false;
}
void OptionsDialog::updateConfigManager() {
config.showCursor = _showCursorCheckbox->getState();
config.snapToBorder = _snapToBorderCheckbox->getState();
config.stretchToFit = _stretchToFitCheckbox->getState();
config.sensitivity = _sensitivity->getValue();
config.screen = _screenRadioGroup->getValue();
saveConfig();
loadConfig();
}
void OptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch(cmd) {
case GUI::kOKCmd:
updateConfigManager();
// Fall through
case GUI::kCloseCmd:
close();
break;
default:
Dialog::handleCommand(sender, cmd, data);
break;
}
}
} // namespace _3DS

View file

@ -0,0 +1,70 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef OPTIONS_DIALOG_3DS_H
#define OPTIONS_DIALOG_3DS_H
#include "common/scummsys.h"
#include "common/str.h"
#include "gui/object.h"
#include "gui/widget.h"
#include "gui/dialog.h"
#include "gui/widgets/tab.h"
#include "scumm/dialogs.h"
namespace _3DS {
enum {
kSave = 0x10000000,
kScreenRadioGroup,
kScreenTop,
kScreenBottom,
kScreenBoth,
};
extern bool optionMenuOpened;
class OptionsDialog : public GUI::Dialog {
public:
OptionsDialog();
~OptionsDialog();
protected:
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
void updateConfigManager();
GUI::SliderWidget *_sensitivity;
GUI::CheckboxWidget *_showCursorCheckbox;
GUI::CheckboxWidget *_snapToBorderCheckbox;
GUI::CheckboxWidget *_stretchToFitCheckbox;
GUI::RadiobuttonGroup *_screenRadioGroup;
GUI::RadiobuttonWidget *_screenTopRadioWidget;
GUI::RadiobuttonWidget *_screenBottomRadioWidget;
GUI::RadiobuttonWidget *_screenBothRadioWidget;
};
} // namespace _3DS
#endif // OPTIONS_DIALOG_3DS_H

View file

@ -0,0 +1,110 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "osystem.h"
#include "audio/mixer.h"
namespace _3DS {
static bool hasAudio = false;
static void audioThreadFunc(void *arg) {
Audio::MixerImpl *mixer = (Audio::MixerImpl *)arg;
OSystem_3DS *osys = (OSystem_3DS *)g_system;
int i;
const int channel = 0;
int bufferIndex = 0;
const int bufferCount = 3;
const int bufferSize = 80000; // Can't be too small, based on delayMillis duration
const int sampleRate = mixer->getOutputRate();
int sampleLen = 0;
uint32 lastTime = osys->getMillis(true);
uint32 time = lastTime;
ndspWaveBuf buffers[bufferCount];
for (i = 0; i < bufferCount; ++i) {
memset(&buffers[i], 0, sizeof(ndspWaveBuf));
buffers[i].data_vaddr = linearAlloc(bufferSize);
buffers[i].looping = false;
buffers[i].status = NDSP_WBUF_FREE;
}
ndspChnReset(channel);
ndspChnSetInterp(channel, NDSP_INTERP_LINEAR);
ndspChnSetRate(channel, sampleRate);
ndspChnSetFormat(channel, NDSP_FORMAT_STEREO_PCM16);
while (!osys->exiting) {
osys->delayMillis(100); // Note: Increasing the delay requires a bigger buffer
time = osys->getMillis(true);
sampleLen = (time - lastTime) * 22 * 4; // sampleRate / 1000 * channelCount * sizeof(int16);
lastTime = time;
if (!osys->sleeping && sampleLen > 0) {
bufferIndex++;
bufferIndex %= bufferCount;
ndspWaveBuf *buf = &buffers[bufferIndex];
buf->nsamples = mixer->mixCallback(buf->data_adpcm, sampleLen);
if (buf->nsamples > 0) {
DSP_FlushDataCache(buf->data_vaddr, bufferSize);
ndspChnWaveBufAdd(channel, buf);
}
}
}
for (i = 0; i < bufferCount; ++i)
linearFree(buffers[i].data_pcm8);
}
void OSystem_3DS::initAudio() {
_mixer = new Audio::MixerImpl(this, 22050);
hasAudio = R_SUCCEEDED(ndspInit());
_mixer->setReady(false);
if (hasAudio) {
s32 prio = 0;
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
audioThread = threadCreate(&audioThreadFunc, _mixer, 32 * 1048, prio - 1, -2, false);
}
}
void OSystem_3DS::destroyAudio() {
if (hasAudio) {
threadJoin(audioThread, U64_MAX);
threadFree(audioThread);
ndspExit();
}
delete _mixer;
_mixer = 0;
}
Audio::Mixer *OSystem_3DS::getMixer() {
assert(_mixer);
return _mixer;
}
} // namespace _3DS

View file

@ -0,0 +1,302 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "backends/timer/default/default-timer.h"
#include "engines/engine.h"
#include "gui.h"
#include "options-dialog.h"
#include "config.h"
#include "osystem.h"
namespace _3DS {
static Common::Mutex *eventMutex;
static InputMode inputMode = MODE_DRAG;
static aptHookCookie cookie;
static bool optionMenuOpening = false;
static Common::String messageOSD;
static bool showMessageOSD = false;
static void pushEventQueue(Common::Queue<Common::Event> *queue, Common::Event &event) {
Common::StackLock lock(*eventMutex);
queue->push(event);
}
static void eventThreadFunc(void *arg) {
OSystem_3DS *osys = (OSystem_3DS *)g_system;
auto eventQueue = (Common::Queue<Common::Event> *)arg;
uint32 touchStartTime = osys->getMillis();
touchPosition lastTouch = {0, 0};
bool isRightClick = false;
float cursorX = 0;
float cursorY = 0;
float cursorDeltaX = 0;
float cursorDeltaY = 0;
int circleDeadzone = 20;
int borderSnapZone = 6;
Common::Event event;
while (!osys->exiting) {
do {
osys->delayMillis(10);
} while (osys->sleeping && !osys->exiting);
hidScanInput();
touchPosition touch;
circlePosition circle;
u32 held = hidKeysHeld();
u32 keysPressed = hidKeysDown();
u32 keysReleased = hidKeysUp();
// C-Pad used to control the cursor
hidCircleRead(&circle);
if (circle.dx < circleDeadzone && circle.dx > -circleDeadzone)
circle.dx = 0;
if (circle.dy < circleDeadzone && circle.dy > -circleDeadzone)
circle.dy = 0;
cursorDeltaX = (0.0002f + config.sensitivity / 100000.f) * circle.dx * abs(circle.dx);
cursorDeltaY = (0.0002f + config.sensitivity / 100000.f) * circle.dy * abs(circle.dy);
// Touch screen events
if (held & KEY_TOUCH) {
hidTouchRead(&touch);
if (config.snapToBorder) {
if (touch.px < borderSnapZone)
touch.px = 0;
if (touch.px > 319 - borderSnapZone)
touch.px = 319;
if (touch.py < borderSnapZone)
touch.py = 0;
if (touch.py > 239 - borderSnapZone)
touch.py = 239;
}
cursorX = touch.px;
cursorY = touch.py;
osys->transformPoint(touch);
osys->warpMouse(touch.px, touch.py);
event.mouse.x = touch.px;
event.mouse.y = touch.py;
if (keysPressed & KEY_TOUCH) {
touchStartTime = osys->getMillis();
isRightClick = (held & KEY_X || held & KEY_DUP);
if (inputMode == MODE_DRAG) {
event.type = isRightClick ? Common::EVENT_RBUTTONDOWN : Common::EVENT_LBUTTONDOWN;
pushEventQueue(eventQueue, event);
}
} else if (touch.px != lastTouch.px || touch.py != lastTouch.py) {
event.type = Common::EVENT_MOUSEMOVE;
pushEventQueue(eventQueue, event);
}
lastTouch = touch;
} else if (keysReleased & KEY_TOUCH) {
event.mouse.x = lastTouch.px;
event.mouse.y = lastTouch.py;
if (inputMode == MODE_DRAG) {
event.type = isRightClick ? Common::EVENT_RBUTTONUP : Common::EVENT_LBUTTONUP;
pushEventQueue(eventQueue, event);
} else if (osys->getMillis() - touchStartTime < 200) {
// Process click in MODE_HOVER
event.type = Common::EVENT_MOUSEMOVE;
pushEventQueue(eventQueue, event);
event.type = isRightClick ? Common::EVENT_RBUTTONDOWN : Common::EVENT_LBUTTONDOWN;
pushEventQueue(eventQueue, event);
event.type = isRightClick ? Common::EVENT_RBUTTONUP : Common::EVENT_LBUTTONUP;
pushEventQueue(eventQueue, event);
}
} else if (cursorDeltaX != 0 || cursorDeltaY != 0) {
cursorX += cursorDeltaX;
cursorY -= cursorDeltaY;
if (cursorX < 0) cursorX = 0;
if (cursorY < 0) cursorY = 0;
if (cursorX > 320) cursorX = 320;
if (cursorY > 240) cursorY = 240;
lastTouch.px = cursorX;
lastTouch.py = cursorY;
osys->transformPoint(lastTouch);
osys->warpMouse(lastTouch.px, lastTouch.py);
event.mouse.x = lastTouch.px;
event.mouse.y = lastTouch.py;
event.type = Common::EVENT_MOUSEMOVE;
pushEventQueue(eventQueue, event);
}
// Button events
if (keysPressed & KEY_R) {
if (inputMode == MODE_DRAG) {
inputMode = MODE_HOVER;
osys->displayMessageOnOSD("Hover Mode");
} else {
inputMode = MODE_DRAG;
osys->displayMessageOnOSD("Drag Mode");
}
}
if (keysPressed & KEY_A || keysPressed & KEY_DLEFT || keysReleased & KEY_A || keysReleased & KEY_DLEFT) {
// SIMULATE LEFT CLICK
event.mouse.x = lastTouch.px;
event.mouse.y = lastTouch.py;
if (keysPressed & KEY_A || keysPressed & KEY_DLEFT)
event.type = Common::EVENT_LBUTTONDOWN;
else
event.type = Common::EVENT_LBUTTONUP;
pushEventQueue(eventQueue, event);
}
if (keysPressed & KEY_X || keysPressed & KEY_DUP || keysReleased & KEY_X || keysReleased & KEY_DUP) {
// SIMULATE RIGHT CLICK
event.mouse.x = lastTouch.px;
event.mouse.y = lastTouch.py;
if (keysPressed & KEY_X || keysPressed & KEY_DUP)
event.type = Common::EVENT_RBUTTONDOWN;
else
event.type = Common::EVENT_RBUTTONUP;
pushEventQueue(eventQueue, event);
}
if (keysPressed & KEY_L) {
event.type = Common::EVENT_VIRTUAL_KEYBOARD;
pushEventQueue(eventQueue, event);
}
if (keysPressed & KEY_START) {
event.type = Common::EVENT_MAINMENU;
pushEventQueue(eventQueue, event);
}
if (keysPressed & KEY_SELECT) {
if (!optionMenuOpened)
optionMenuOpening = true;
}
if (keysPressed & KEY_B || keysReleased & KEY_B || keysPressed & KEY_DDOWN || keysReleased & KEY_DDOWN) {
if (keysPressed & KEY_B || keysPressed & KEY_DDOWN)
event.type = Common::EVENT_KEYDOWN;
else
event.type = Common::EVENT_KEYUP;
event.kbd.keycode = Common::KEYCODE_ESCAPE;
event.kbd.ascii = Common::ASCII_ESCAPE;
event.kbd.flags = 0;
pushEventQueue(eventQueue, event);
}
// TODO: EVENT_PREDICTIVE_DIALOG
// EVENT_SCREEN_CHANGED
}
}
static void aptHookFunc(APT_HookType hookType, void *param) {
OSystem_3DS *osys = (OSystem_3DS *)g_system;
switch (hookType) {
case APTHOOK_ONSUSPEND:
case APTHOOK_ONSLEEP:
if (g_engine)
g_engine->pauseEngine(true);
osys->sleeping = true;
if (R_SUCCEEDED(gspLcdInit())) {
GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
gspLcdExit();
}
break;
case APTHOOK_ONRESTORE:
case APTHOOK_ONWAKEUP:
if (g_engine)
g_engine->pauseEngine(false);
osys->sleeping = false;
loadConfig();
break;
default: {
Common::StackLock lock(*eventMutex);
Common::Event event;
event.type = Common::EVENT_QUIT;
g_system->getEventManager()->pushEvent(event);
}
}
}
static void timerThreadFunc(void *arg) {
OSystem_3DS *osys = (OSystem_3DS *)arg;
DefaultTimerManager *tm = (DefaultTimerManager *)osys->getTimerManager();
while (!osys->exiting) {
g_system->delayMillis(10);
tm->handler();
}
}
void OSystem_3DS::initEvents() {
eventMutex = new Common::Mutex();
s32 prio = 0;
svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
_timerThread = threadCreate(&timerThreadFunc, this, 32 * 1024, prio - 1, -2, false);
_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 32 * 1024, prio - 1, -2, false);
aptHook(&cookie, aptHookFunc, this);
}
void OSystem_3DS::destroyEvents() {
threadJoin(_timerThread, U64_MAX);
threadFree(_timerThread);
threadJoin(_eventThread, U64_MAX);
threadFree(_eventThread);
delete eventMutex;
}
void OSystem_3DS::transformPoint(touchPosition &point) {
if (!_overlayVisible) {
point.px = static_cast<float>(point.px) / _gameBottomTexture.getScaleX() - _gameBottomX;
point.py = static_cast<float>(point.py) / _gameBottomTexture.getScaleY() - _gameBottomY;
}
}
void OSystem_3DS::displayMessageOnOSD(const char *msg) {
messageOSD = msg;
showMessageOSD = true;
}
bool OSystem_3DS::pollEvent(Common::Event &event) {
if (showMessageOSD) {
showMessageOSD = false;
StatusMessageDialog dialog(messageOSD, 800);
dialog.runModal();
}
aptMainLoop(); // Call apt hook when necessary
if (optionMenuOpening) {
optionMenuOpening = false;
OptionsDialog dialog;
if (g_engine)
g_engine->pauseEngine(true);
dialog.runModal();
if (g_engine)
g_engine->pauseEngine(false);
}
Common::StackLock lock(*eventMutex);
if (_eventQueue.empty())
return false;
event = _eventQueue.pop();
return true;
}
} // namespace _3DS

View file

@ -0,0 +1,517 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This _program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This _program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this _program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*/
#include "backends/platform/3ds/osystem.h"
#include "backends/platform/3ds/shader_shbin.h"
#include "common/rect.h"
#include "options-dialog.h"
#include "config.h"
// Used to transfer the final rendered display to the framebuffer
#define DISPLAY_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | \
GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
namespace _3DS {
void OSystem_3DS::initGraphics() {
_pfGame = Graphics::PixelFormat::createFormatCLUT8();
_pfGameTexture = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
// Initialize the render targets
_renderTargetTop =
C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetClear(_renderTargetTop, C3D_CLEAR_ALL, 0x0000000, 0);
C3D_RenderTargetSetOutput(_renderTargetTop, GFX_TOP, GFX_LEFT,
DISPLAY_TRANSFER_FLAGS);
_renderTargetBottom =
C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetClear(_renderTargetBottom, C3D_CLEAR_ALL, 0x00000000, 0);
C3D_RenderTargetSetOutput(_renderTargetBottom, GFX_BOTTOM, GFX_LEFT,
DISPLAY_TRANSFER_FLAGS);
// Load and bind simple default shader (shader.v.pica)
_dvlb = DVLB_ParseFile((u32*)shader_shbin, shader_shbin_size);
shaderProgramInit(&_program);
shaderProgramSetVsh(&_program, &_dvlb->DVLE[0]);
C3D_BindProgram(&_program);
_projectionLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "projection");
_modelviewLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "modelView");
C3D_AttrInfo *attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
Mtx_OrthoTilt(&_projectionTop, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0);
Mtx_OrthoTilt(&_projectionBottom, 0.0, 320.0, 240.0, 0.0, 0.0, 1.0);
C3D_TexEnv *env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, 0, 0);
C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL);
C3D_CullFace(GPU_CULL_NONE);
}
void OSystem_3DS::destroyGraphics() {
_gameScreen.free();
_gameTopTexture.free();
_gameBottomTexture.free();
_overlay.free();
shaderProgramFree(&_program);
DVLB_Free(_dvlb);
C3D_RenderTargetDelete(_renderTargetTop);
C3D_RenderTargetDelete(_renderTargetBottom);
C3D_Fini();
}
bool OSystem_3DS::hasFeature(OSystem::Feature f) {
return (f == OSystem::kFeatureCursorPalette ||
f == OSystem::kFeatureOverlaySupportsAlpha);
}
void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {
switch (f) {
case OSystem::kFeatureCursorPalette:
_cursorPaletteEnabled = enable;
flushCursor();
break;
default:
break;
}
}
bool OSystem_3DS::getFeatureState(OSystem::Feature f) {
switch (f) {
case OSystem::kFeatureCursorPalette:
return _cursorPaletteEnabled;
default:
return false;
}
}
const OSystem::GraphicsMode *
OSystem_3DS::getSupportedGraphicsModes() const {
return s_graphicsModes;
}
int OSystem_3DS::getDefaultGraphicsMode() const {
return GFX_LINEAR;
}
bool OSystem_3DS::setGraphicsMode(int mode) {
return true;
}
void OSystem_3DS::resetGraphicsScale() {
debug("resetGraphicsScale");
}
int OSystem_3DS::getGraphicsMode() const {
return GFX_LINEAR;
}
void OSystem_3DS::initSize(uint width, uint height,
const Graphics::PixelFormat *format) {
debug("3ds initsize w:%d h:%d", width, height);
_gameWidth = width;
_gameHeight = height;
_gameTopTexture.create(width, height, _pfGameTexture);
_overlay.create(getOverlayWidth(), getOverlayHeight(), _pfGameTexture);
if (format) {
debug("pixelformat: %d %d %d %d %d", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());;
_pfGame = *format;
}
_gameScreen.create(width, height, _pfGame);
_focusDirty = true;
_focusRect = Common::Rect(_gameWidth, _gameHeight);
updateSize();
}
void OSystem_3DS::updateSize() {
if (config.stretchToFit) {
_gameTopX = _gameTopY = _gameBottomX = _gameBottomY = 0;
_gameTopTexture.setScale(400.f / _gameWidth, 240.f / _gameHeight);
_gameBottomTexture.setScale(320.f / _gameWidth, 240.f / _gameHeight);
} else {
float ratio = static_cast<float>(_gameWidth) / _gameHeight;
if (ratio > 400.f / 240.f) {
float r = 400.f / _gameWidth;
_gameTopTexture.setScale(r, r);
_gameTopX = 0;
_gameTopY = (240.f - r * _gameHeight) / 2.f;
} else {
float r = 240.f / _gameHeight;
_gameTopTexture.setScale(r, r);
_gameTopY = 0;
_gameTopX = (400.f - r * _gameWidth) / 2.f;
}
if (ratio > 320.f / 240.f) {
float r = 320.f / _gameWidth;
_gameBottomTexture.setScale(r, r);
_gameBottomX = 0;
_gameBottomY = (240.f - r * _gameHeight) / 2.f;
} else {
float r = 240.f / _gameHeight;
_gameBottomTexture.setScale(r, r);
_gameBottomY = 0;
_gameBottomX = (320.f - r * _gameWidth) / 2.f;
}
}
_gameTopTexture.setPosition(_gameTopX, _gameTopY);
_gameBottomTexture.setPosition(_gameBottomX, _gameBottomY);
if (_overlayVisible)
_cursorTexture.setScale(1.f, 1.f);
else if (config.screen == kScreenTop)
_cursorTexture.setScale(_gameTopTexture.getScaleX(), _gameTopTexture.getScaleY());
else
_cursorTexture.setScale(_gameBottomTexture.getScaleX(), _gameBottomTexture.getScaleY());
}
Common::List<Graphics::PixelFormat> OSystem_3DS::getSupportedFormats() const {
Common::List<Graphics::PixelFormat> list;
list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // GPU_RGBA8
list.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); // GPU_RGB565
// list.push_back(Graphics::PixelFormat(3, 0, 0, 0, 8, 0, 8, 16, 0)); // GPU_RGB8
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); // RGB555 (needed for FMTOWNS?)
list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); // GPU_RGBA5551
list.push_back(Graphics::PixelFormat::createFormatCLUT8());
return list;
}
void OSystem_3DS::beginGFXTransaction() {
//
}
OSystem::TransactionError OSystem_3DS::endGFXTransaction() {
return OSystem::kTransactionSuccess;
}
void OSystem_3DS::setPalette(const byte *colors, uint start, uint num) {
assert(start + num <= 256);
memcpy(_palette + 3 * start, colors, 3 * num);
// Manually update all color that were changed
if (_gameScreen.format.bytesPerPixel == 1) {
flushGameScreen();
}
}
void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) {
assert(start + num <= 256);
memcpy(colors, _palette + 3 * start, 3 * num);
}
void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
int y, int w, int h) {
Common::Rect rect(x, y, x+w, y+h);
_gameScreen.copyRectToSurface(buf, pitch, x, y, w, h);
Graphics::Surface subSurface = _gameScreen.getSubArea(rect);
Graphics::Surface *convertedSubSurface = subSurface.convertTo(_pfGameTexture, _palette);
_gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
convertedSubSurface->free();
delete convertedSubSurface;
_gameTopTexture.markDirty();
}
void OSystem_3DS::flushGameScreen() {
Graphics::Surface *converted = _gameScreen.convertTo(_pfGameTexture, _palette);
_gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
_gameTopTexture.markDirty();
converted->free();
delete converted;
}
Graphics::Surface *OSystem_3DS::lockScreen() {
return &_gameScreen;
}
void OSystem_3DS::unlockScreen() {
flushGameScreen();
}
void OSystem_3DS::updateScreen() {
if (sleeping || exiting)
return;
// updateFocus();
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
// Render top screen
C3D_FrameDrawOn(_renderTargetTop);
if (config.screen == kScreenTop || config.screen == kScreenBoth) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionTop);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameTopTexture.getMatrix());
_gameTopTexture.render();
_gameTopTexture.render();
if (_overlayVisible && config.screen == kScreenTop) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
_overlay.render();
}
if (_cursorVisible && config.showCursor && config.screen == kScreenTop) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _cursorTexture.getMatrix());
_cursorTexture.render();
}
}
// Render bottom screen
C3D_FrameDrawOn(_renderTargetBottom);
if (config.screen == kScreenBottom || config.screen == kScreenBoth) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionBottom);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameBottomTexture.getMatrix());
_gameTopTexture.render();
_gameTopTexture.render();
if (_overlayVisible) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
_overlay.render();
}
if (_cursorVisible && config.showCursor) {
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _cursorTexture.getMatrix());
_cursorTexture.render();
}
}
C3D_FrameEnd(0);
}
void OSystem_3DS::setShakePos(int shakeOffset) {
// TODO: implement this in overlay, top screen, and mouse too
_screenShakeOffset = shakeOffset;
_gameTopTexture.setPosition(_gameTopX, _gameTopY + _gameTopTexture.getScaleY() * shakeOffset);
_gameBottomTexture.setPosition(_gameBottomX, _gameBottomY + _gameBottomTexture.getScaleY() * shakeOffset);
}
void OSystem_3DS::setFocusRectangle(const Common::Rect &rect) {
debug("setfocus: %d %d %d %d", rect.left, rect.top, rect.width(), rect.height());
_focusRect = rect;
_focusDirty = true;
_focusClearTime = 0;
}
void OSystem_3DS::clearFocusRectangle() {
_focusClearTime = getMillis();
}
void OSystem_3DS::updateFocus() {
if (_focusClearTime && getMillis() - _focusClearTime > 5000) {
_focusClearTime = 0;
_focusDirty = true;
_focusRect = Common::Rect(_gameWidth, _gameHeight);
}
if (_focusDirty) {
float duration = 1.f / 20.f; // Focus animation in frame duration
float w = 400.f;
float h = 240.f;
float ratio = _focusRect.width() / _focusRect.height();
if (ratio > w/h) {
_focusTargetScaleX = w / _focusRect.width();
float newHeight = (float)_focusRect.width() / w/h;
_focusTargetScaleY = h / newHeight;
_focusTargetPosX = _focusTargetScaleX * _focusRect.left;
_focusTargetPosY = _focusTargetScaleY * ((float)_focusRect.top - (newHeight - _focusRect.height())/2.f);
} else {
_focusTargetScaleY = h / _focusRect.height();
float newWidth = (float)_focusRect.height() * w/h;
_focusTargetScaleX = w / newWidth;
_focusTargetPosY = _focusTargetScaleY * _focusRect.top;
_focusTargetPosX = _focusTargetScaleX * ((float)_focusRect.left - (newWidth - _focusRect.width())/2.f);
}
if (_focusTargetPosX < 0 && _focusTargetScaleY != 240.f / _gameHeight)
_focusTargetPosX = 0;
if (_focusTargetPosY < 0 && _focusTargetScaleX != 400.f / _gameWidth)
_focusTargetPosY = 0;
_focusStepPosX = duration * (_focusTargetPosX - _focusPosX);
_focusStepPosY = duration * (_focusTargetPosY - _focusPosY);
_focusStepScaleX = duration * (_focusTargetScaleX - _focusScaleX);
_focusStepScaleY = duration * (_focusTargetScaleY - _focusScaleY);
}
if (_focusDirty || _focusPosX != _focusTargetPosX || _focusPosY != _focusTargetPosY ||
_focusScaleX != _focusTargetScaleX || _focusScaleY != _focusTargetScaleY) {
_focusDirty = false;
if ((_focusStepPosX > 0 && _focusPosX > _focusTargetPosX) || (_focusStepPosX < 0 && _focusPosX < _focusTargetPosX))
_focusPosX = _focusTargetPosX;
else if (_focusPosX != _focusTargetPosX)
_focusPosX += _focusStepPosX;
if ((_focusStepPosY > 0 && _focusPosY > _focusTargetPosY) || (_focusStepPosY < 0 && _focusPosY < _focusTargetPosY))
_focusPosY = _focusTargetPosY;
else if (_focusPosY != _focusTargetPosY)
_focusPosY += _focusStepPosY;
if ((_focusStepScaleX > 0 && _focusScaleX > _focusTargetScaleX) || (_focusStepScaleX < 0 && _focusScaleX < _focusTargetScaleX))
_focusScaleX = _focusTargetScaleX;
else if (_focusScaleX != _focusTargetScaleX)
_focusScaleX += _focusStepScaleX;
if ((_focusStepScaleY > 0 && _focusScaleY > _focusTargetScaleY) || (_focusStepScaleY < 0 && _focusScaleY < _focusTargetScaleY))
_focusScaleY = _focusTargetScaleY;
else if (_focusScaleY != _focusTargetScaleY)
_focusScaleY += _focusStepScaleY;
Mtx_Identity(&_focusMatrix);
Mtx_Translate(&_focusMatrix, -_focusPosX, -_focusPosY, 0);
Mtx_Scale(&_focusMatrix, _focusScaleX, _focusScaleY, 1.f);
}
}
void OSystem_3DS::showOverlay() {
_overlayVisible = true;
updateSize();
updateScreen();
}
void OSystem_3DS::hideOverlay() {
_overlayVisible = false;
updateSize();
updateScreen();
}
Graphics::PixelFormat OSystem_3DS::getOverlayFormat() const {
return _pfGameTexture;
}
void OSystem_3DS::clearOverlay() {
_overlay.clear();
}
void OSystem_3DS::grabOverlay(void *buf, int pitch) {
for (int y = 0; y < getOverlayHeight(); ++y) {
memcpy(buf, _overlay.getBasePtr(0, y), pitch);
}
}
void OSystem_3DS::copyRectToOverlay(const void *buf, int pitch, int x,
int y, int w, int h) {
_overlay.copyRectToSurface(buf, pitch, x, y, w, h);
_overlay.markDirty();
}
int16 OSystem_3DS::getOverlayHeight() {
return 240;
}
int16 OSystem_3DS::getOverlayWidth() {
return 320;
}
bool OSystem_3DS::showMouse(bool visible) {
_cursorVisible = visible;
flushCursor();
return !visible;
}
void OSystem_3DS::warpMouse(int x, int y) {
_cursorX = x;
_cursorY = y;
warning("x:%d y:%d", x, y);
// TODO: adjust for _cursorScalable ?
int offsetx = 0;
int offsety = 0;
x -= _cursorHotspotX;
y -= _cursorHotspotY;
if (!_overlayVisible) {
offsetx += config.screen == kScreenTop ? _gameTopX : _gameBottomX;
offsety += config.screen == kScreenTop ? _gameTopY : _gameBottomY;
}
float scalex = config.screen == kScreenTop ? (float)_gameTopTexture.actualWidth / _gameWidth : 1.f;
float scaley = config.screen == kScreenTop ? (float)_gameTopTexture.actualHeight / _gameHeight : 1.f;
_cursorTexture.setPosition(scalex * x + offsetx,
scaley * y + offsety);
}
void OSystem_3DS::setCursorDelta(float deltaX, float deltaY) {
_cursorDeltaX = deltaX;
_cursorDeltaY = deltaY;
}
void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
int hotspotX, int hotspotY,
uint32 keycolor, bool dontScale,
const Graphics::PixelFormat *format) {
_cursorScalable = !dontScale;
_cursorHotspotX = hotspotX;
_cursorHotspotY = hotspotY;
_cursorKeyColor = keycolor;
_pfCursor = !format ? Graphics::PixelFormat::createFormatCLUT8() : *format;
if (w != _cursor.w || h != _cursor.h || _cursor.format != _pfCursor) {
_cursor.create(w, h, _pfCursor);
_cursorTexture.create(w, h, _pfGameTexture);
}
_cursor.copyRectToSurface(buf, w, 0, 0, w, h);
flushCursor();
warpMouse(_cursorX, _cursorY);
}
void OSystem_3DS::setCursorPalette(const byte *colors, uint start, uint num) {
assert(start + num <= 256);
memcpy(_cursorPalette + 3 * start, colors, 3 * num);
_cursorPaletteEnabled = true;
flushCursor();
}
void OSystem_3DS::flushCursor() {
if (_cursor.getPixels()) {
Graphics::Surface *converted = _cursor.convertTo(_pfGameTexture, _cursorPaletteEnabled ? _cursorPalette : _palette);
_cursorTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
_cursorTexture.markDirty();
converted->free();
delete converted;
if (_pfCursor.bytesPerPixel == 1) {
uint* dest = (uint*) _cursorTexture.getPixels();
byte* src = (byte*) _cursor.getPixels();
for (int y = 0; y < _cursor.h; ++y) {
for (int x = 0; x < _cursor.w; ++x) {
if (*src++ == _cursorKeyColor)
*dest++ = 0;
else
dest++;
}
dest += _cursorTexture.w - _cursorTexture.actualWidth;
}
}
}
}
} // namespace _3DS

View file

@ -0,0 +1,193 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#include "osystem.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
#include "backends/events/default/default-events.h"
#include "audio/mixer_intern.h"
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/str.h"
#include "config.h"
#include "backends/fs/posix/posix-fs-factory.h"
#include "backends/fs/posix/posix-fs.h"
#include <unistd.h>
#include <time.h>
namespace _3DS {
OSystem_3DS::OSystem_3DS():
_focusDirty(true),
_focusRect(Common::Rect(1, 1)),
_focusPosX(0),
_focusPosY(0),
_focusTargetPosX(0),
_focusTargetPosY(0),
_focusStepPosX(0),
_focusStepPosY(0),
_focusScaleX(1.f),
_focusScaleY(1.f),
_focusTargetScaleX(1.f),
_focusTargetScaleY(1.f),
_focusStepScaleX(0.f),
_focusStepScaleY(0.f),
_focusClearTime(0),
_cursorPaletteEnabled(false),
_cursorVisible(false),
_cursorScalable(false),
_cursorX(0),
_cursorY(0),
_cursorHotspotX(0),
_cursorHotspotY(0),
_gameTopX(0),
_gameTopY(0),
_gameBottomX(0),
_gameBottomY(0),
_gameWidth(320),
_gameHeight(240),
_overlayVisible(false),
exiting(false),
sleeping(false)
{
chdir("sdmc:/");
_fsFactory = new POSIXFilesystemFactory();
Posix::assureDirectoryExists("/3ds/scummvm/saves/");
}
OSystem_3DS::~OSystem_3DS() {
exiting = true;
destroyEvents();
destroyAudio();
destroyGraphics();
delete _timerManager;
_timerManager = 0;
}
void OSystem_3DS::quit() {
printf("OSystem_3DS::quit()\n");
}
void OSystem_3DS::initBackend() {
loadConfig();
ConfMan.registerDefault("fullscreen", true);
ConfMan.registerDefault("aspect_ratio", true);
if (!ConfMan.hasKey("vkeybd_pack_name"))
ConfMan.set("vkeybd_pack_name", "vkeybd_small");
if (!ConfMan.hasKey("vkeybdpath"))
ConfMan.set("vkeybdpath", "/3ds/scummvm/kb");
if (!ConfMan.hasKey("themepath"))
ConfMan.set("themepath", "/3ds/scummvm");
if (!ConfMan.hasKey("gui_theme"))
ConfMan.set("gui_theme", "builtin");
_timerManager = new DefaultTimerManager();
_savefileManager = new DefaultSaveFileManager("/3ds/scummvm/saves/");
initGraphics();
initAudio();
initEvents();
EventsBaseBackend::initBackend();
}
void OSystem_3DS::updateConfig() {
if (_gameScreen.getPixels()) {
updateSize();
warpMouse(_cursorX, _cursorY);
}
}
Common::String OSystem_3DS::getDefaultConfigFileName() {
return "/3ds/scummvm/scummvm.ini";
}
uint32 OSystem_3DS::getMillis(bool skipRecord) {
return svcGetSystemTick() / TICKS_PER_MSEC;
}
void OSystem_3DS::delayMillis(uint msecs) {
svcSleepThread(msecs * 1000000);
}
void OSystem_3DS::getTimeAndDate(TimeDate& td) const {
time_t curTime = time(0);
struct tm t = *localtime(&curTime);
td.tm_sec = t.tm_sec;
td.tm_min = t.tm_min;
td.tm_hour = t.tm_hour;
td.tm_mday = t.tm_mday;
td.tm_mon = t.tm_mon;
td.tm_year = t.tm_year;
td.tm_wday = t.tm_wday;
}
OSystem::MutexRef OSystem_3DS::createMutex() {
RecursiveLock *mutex = new RecursiveLock();
RecursiveLock_Init(mutex);
return (OSystem::MutexRef) mutex;
}
void OSystem_3DS::lockMutex(MutexRef mutex) {
RecursiveLock_Lock((RecursiveLock*)mutex);
}
void OSystem_3DS::unlockMutex(MutexRef mutex) {
RecursiveLock_Unlock((RecursiveLock*)mutex);
}
void OSystem_3DS::deleteMutex(MutexRef mutex) {
delete (RecursiveLock*)mutex;
}
Common::String OSystem_3DS::getSystemLanguage() const {
u8 langcode;
CFGU_GetSystemLanguage(&langcode);
switch (langcode) {
case CFG_LANGUAGE_JP: return "ja_JP";
case CFG_LANGUAGE_EN: return "en_US";
case CFG_LANGUAGE_FR: return "fr_FR";
case CFG_LANGUAGE_DE: return "de_DE";
case CFG_LANGUAGE_IT: return "it_IT";
case CFG_LANGUAGE_ES: return "es_ES";
case CFG_LANGUAGE_ZH: return "zh_CN";
case CFG_LANGUAGE_KO: return "ko_KR";
case CFG_LANGUAGE_NL: return "nl_NL";
case CFG_LANGUAGE_PT: return "pt_BR";
case CFG_LANGUAGE_RU: return "ru_RU";
case CFG_LANGUAGE_TW: return "zh_HK";
default: return "en_US";
}
}
void OSystem_3DS::fatalError() {
printf("FatalError!\n");
}
void OSystem_3DS::logMessage(LogMessageType::Type type, const char *message) {
printf("3DS log: %s\n", message);
}
} // namespace _3DS

View file

@ -0,0 +1,221 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef PLATFORM_3DS_H
#define PLATFORM_3DS_H
#include <citro3d.h>
#include "backends/mutex/mutex.h"
#include "backends/base-backend.h"
#include "graphics/palette.h"
#include "base/main.h"
#include "audio/mixer_intern.h"
#include "backends/graphics/graphics.h"
#include "backends/platform/3ds/sprite.h"
#include "common/rect.h"
#include "common/queue.h"
#define TICKS_PER_MSEC 268123
namespace _3DS {
enum {
GFX_LINEAR = 0,
GFX_NEAREST = 1
};
enum InputMode {
MODE_HOVER,
MODE_DRAG,
};
static const OSystem::GraphicsMode s_graphicsModes[] = {
{"default", "Default Test", GFX_LINEAR},
{ 0, 0, 0 }
};
class OSystem_3DS : public EventsBaseBackend, public PaletteManager {
public:
OSystem_3DS();
virtual ~OSystem_3DS();
volatile bool exiting;
volatile bool sleeping;
virtual void initBackend();
virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
virtual bool pollEvent(Common::Event &event);
virtual uint32 getMillis(bool skipRecord = false);
virtual void delayMillis(uint msecs);
virtual void getTimeAndDate(TimeDate &t) const;
virtual MutexRef createMutex();
virtual void lockMutex(MutexRef mutex);
virtual void unlockMutex(MutexRef mutex);
virtual void deleteMutex(MutexRef mutex);
virtual void logMessage(LogMessageType::Type type, const char *message);
virtual Audio::Mixer *getMixer();
virtual PaletteManager *getPaletteManager() { return this; }
virtual Common::String getSystemLanguage() const;
virtual void fatalError();
virtual void quit();
virtual Common::String getDefaultConfigFileName();
// Graphics
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
int getDefaultGraphicsMode() const;
bool setGraphicsMode(int mode);
void resetGraphicsScale();
int getGraphicsMode() const;
inline Graphics::PixelFormat getScreenFormat() const { return _pfGame; }
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
void initSize(uint width, uint height,
const Graphics::PixelFormat *format = NULL);
virtual int getScreenChangeID() const { return 0; };
void beginGFXTransaction();
OSystem::TransactionError endGFXTransaction();
int16 getHeight(){ return _gameHeight; }
int16 getWidth(){ return _gameWidth; }
void setPalette(const byte *colors, uint start, uint num);
void grabPalette(byte *colors, uint start, uint num);
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w,
int h);
Graphics::Surface *lockScreen();
void unlockScreen();
void updateScreen();
void setShakePos(int shakeOffset);
void setFocusRectangle(const Common::Rect &rect);
void clearFocusRectangle();
void showOverlay();
void hideOverlay();
Graphics::PixelFormat getOverlayFormat() const;
void clearOverlay();
void grabOverlay(void *buf, int pitch);
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w,
int h);
virtual int16 getOverlayHeight();
virtual int16 getOverlayWidth();
virtual void displayMessageOnOSD(const char *msg);
bool showMouse(bool visible);
void warpMouse(int x, int y);
void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
int hotspotY, uint32 keycolor, bool dontScale = false,
const Graphics::PixelFormat *format = NULL);
void setCursorPalette(const byte *colors, uint start, uint num);
// Transform point from touchscreen coords into gamescreen coords
void transformPoint(touchPosition &point);
void setCursorDelta(float deltaX, float deltaY);
void updateFocus();
void updateConfig();
void updateSize();
private:
void initGraphics();
void destroyGraphics();
void initAudio();
void destroyAudio();
void initEvents();
void destroyEvents();
void flushGameScreen();
void flushCursor();
protected:
Audio::MixerImpl *_mixer;
private:
u16 _gameWidth, _gameHeight;
u16 _gameTopX, _gameTopY;
u16 _gameBottomX, _gameBottomY;
// Audio
Thread audioThread;
// Graphics
Graphics::PixelFormat _pfGame;
Graphics::PixelFormat _pfGameTexture;
Graphics::PixelFormat _pfCursor;
byte _palette[3 * 256];
byte _cursorPalette[3 * 256];
Graphics::Surface _gameScreen;
Sprite _gameTopTexture;
Sprite _gameBottomTexture;
Sprite _overlay;
int _screenShakeOffset;
bool _overlayVisible;
DVLB_s *_dvlb;
shaderProgram_s _program;
int _projectionLocation;
int _modelviewLocation;
C3D_Mtx _projectionTop;
C3D_Mtx _projectionBottom;
C3D_RenderTarget* _renderTargetTop;
C3D_RenderTarget* _renderTargetBottom;
// Focus
Common::Rect _focusRect;
bool _focusDirty;
C3D_Mtx _focusMatrix;
int _focusPosX, _focusPosY;
int _focusTargetPosX, _focusTargetPosY;
float _focusStepPosX, _focusStepPosY;
float _focusScaleX, _focusScaleY;
float _focusTargetScaleX, _focusTargetScaleY;
float _focusStepScaleX, _focusStepScaleY;
uint32 _focusClearTime;
// Events
Thread _eventThread;
Thread _timerThread;
Common::Queue<Common::Event> _eventQueue;
// Cursor
Graphics::Surface _cursor;
Sprite _cursorTexture;
bool _cursorPaletteEnabled;
bool _cursorVisible;
bool _cursorScalable;
float _cursorX, _cursorY;
float _cursorDeltaX, _cursorDeltaY;
int _cursorHotspotX, _cursorHotspotY;
uint32 _cursorKeyColor;
};
} // namespace _3DS
#endif

View file

@ -0,0 +1,59 @@
;* ScummVM - Graphic Adventure Engine
;*
;* ScummVM is the legal property of its developers, whose names
;* are too numerous to list here. Please refer to the COPYRIGHT
;* file distributed with this source distribution.
;*
;* This program is free software; you can redistribute it and/or
;* modify it under the terms of the GNU General Public License
;* as published by the Free Software Foundation; either version 2
;* of the License, or (at your option) any later version.
;*
;* This program is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;* GNU General Public License for more details.
;*
;* You should have received a copy of the GNU General Public License
;* along with this program; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;*
; Uniforms
.fvec projection[4], modelView[4]
; Constants
.constf myconst(0.0, 1.0, -1.0, 0.1)
.alias zeros myconst.xxxx ; Vector full of zeros
.alias ones myconst.yyyy ; Vector full of ones
; Outputs
.out outpos position
.out outtex texcoord0
; Inputs (defined as aliases for convenience)
.alias inpos v0
.alias intex v1
.proc main
; Force the w component of inpos to be 1.0
mov r0.xyz, inpos
mov r0.w, ones
; r1 = modelView * inpos
dp4 r1.x, modelView[0], r0
dp4 r1.y, modelView[1], r0
dp4 r1.z, modelView[2], r0
dp4 r1.w, modelView[3], r0
; outpos = projection * r1
dp4 outpos.x, projection[0], r1
dp4 outpos.y, projection[1], r1
dp4 outpos.z, projection[2], r1
dp4 outpos.w, projection[3], r1
mov outtex, intex
end
.end

View file

@ -0,0 +1,144 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "backends/platform/3ds/sprite.h"
#include "common/util.h"
#include <3ds.h>
static uint nextHigher2(uint v) {
if (v == 0)
return 1;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ++v;
}
Sprite::Sprite()
: dirtyPixels(true)
, dirtyMatrix(true)
, actualWidth(0)
, actualHeight(0)
, posX(0)
, posY(0)
, scaleX(1.f)
, scaleY(1.f)
{
Mtx_Identity(&modelview);
vertices = (vertex *)linearAlloc(sizeof(vertex) * 4);
}
Sprite::~Sprite() {
//
}
void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f) {
free();
actualWidth = width;
actualHeight = height;
format = f;
w = MAX(nextHigher2(width), 64u);
h = MAX(nextHigher2(height), 64u);;
pitch = w * format.bytesPerPixel;
dirtyPixels = true;
if (width && height) {
pixels = linearAlloc(h * pitch);
C3D_TexInit(&texture, w, h, GPU_RGBA8);
C3D_TexSetFilter(&texture, GPU_LINEAR, GPU_LINEAR);
assert(pixels && texture.data);
clear();
}
float x = 0.f, y = 0.f;
float u = (float)width/w;
float v = (float)height/h;
vertex tmp[4] = {
{{x, y, 0.5f}, {0, 0}},
{{x+width, y, 0.5f}, {u, 0}},
{{x, y+height, 0.5f}, {0, v}},
{{x+width, y+height, 0.5f}, {u, v}},
};
memcpy(vertices, tmp, sizeof(vertex) * 4);
}
void Sprite::free() {
linearFree(vertices);
linearFree(pixels);
C3D_TexDelete(&texture);
pixels = 0;
w = h = pitch = 0;
actualWidth = actualHeight = 0;
format = Graphics::PixelFormat();
}
void Sprite::convertToInPlace(const Graphics::PixelFormat &dstFormat, const byte *palette) {
//
}
void Sprite::render() {
if (dirtyPixels) {
dirtyPixels = false;
GSPGPU_FlushDataCache(pixels, w * h * format.bytesPerPixel);
C3D_SafeDisplayTransfer((u32*)pixels, GX_BUFFER_DIM(w, h), (u32*)texture.data, GX_BUFFER_DIM(w, h), TEXTURE_TRANSFER_FLAGS);
gspWaitForPPF();
}
C3D_TexBind(0, &texture);
C3D_BufInfo *bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, vertices, sizeof(vertex), 2, 0x10);
C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);
}
void Sprite::clear(uint32 color) {
dirtyPixels = true;
memset(pixels, color, w * h * format.bytesPerPixel);
}
void Sprite::setScale (float x, float y) {
scaleX = x;
scaleY = y;
dirtyMatrix = true;
}
void Sprite::setPosition(int x, int y) {
posX = x;
posY = y;
dirtyMatrix = true;
}
C3D_Mtx* Sprite::getMatrix() {
if (dirtyMatrix) {
dirtyMatrix = false;
Mtx_Identity(&modelview);
Mtx_Scale(&modelview, scaleX, scaleY, 1.f);
Mtx_Translate(&modelview, posX, posY, 0);
}
return &modelview;
}

View file

@ -0,0 +1,71 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRAPHICS_SPRITE_3DS_H
#define GRAPHICS_SPRITE_3DS_H
#include <citro3d.h>
#include "graphics/surface.h"
#define TEXTURE_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
typedef struct {
float position[3];
float texcoord[2];
} vertex;
class Sprite : public Graphics::Surface {
public:
Sprite();
~Sprite();
void create(uint16 width, uint16 height, const Graphics::PixelFormat &format);
void free();
void convertToInPlace(const Graphics::PixelFormat &dstFormat, const byte *palette = 0);
void render();
void clear(uint32 color = 0);
void markDirty(){ dirtyPixels = true; }
void setPosition(int x, int y);
void setScale(float x, float y);
float getScaleX(){ return scaleX; }
float getScaleY(){ return scaleY; }
C3D_Mtx* getMatrix();
uint16 actualWidth;
uint16 actualHeight;
private:
bool dirtyPixels;
bool dirtyMatrix;
C3D_Mtx modelview;
C3D_Tex texture;
vertex* vertices;
int posX;
int posY;
float scaleX;
float scaleY;
};
#endif

View file

@ -57,7 +57,7 @@ static const char USAGE_STRING[] =
; ;
// DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :) // DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :)
#if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__) #if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__) || defined(__3DS__)
static const char HELP_STRING[] = "NoUsageString"; // save more data segment space static const char HELP_STRING[] = "NoUsageString"; // save more data segment space
#else #else
static const char HELP_STRING[] = static const char HELP_STRING[] =

View file

@ -251,6 +251,7 @@
#if defined(__DC__) || \ #if defined(__DC__) || \
defined(__DS__) || \ defined(__DS__) || \
defined(__3DS__) || \
defined(__GP32__) || \ defined(__GP32__) || \
defined(IPHONE) || \ defined(IPHONE) || \
defined(__PLAYSTATION2__) || \ defined(__PLAYSTATION2__) || \
@ -367,7 +368,7 @@
#endif #endif
#ifndef STRINGBUFLEN #ifndef STRINGBUFLEN
#if defined(__N64__) || defined(__DS__) #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
#define STRINGBUFLEN 256 #define STRINGBUFLEN 256
#else #else
#define STRINGBUFLEN 1024 #define STRINGBUFLEN 1024

71
configure vendored
View file

@ -440,7 +440,7 @@ get_system_exe_extension() {
arm-riscos) arm-riscos)
_exeext=",ff8" _exeext=",ff8"
;; ;;
dreamcast | ds | gamecube | n64 | ps2 | psp | wii) 3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
_exeext=".elf" _exeext=".elf"
;; ;;
gph-linux) gph-linux)
@ -843,9 +843,9 @@ Usage: $0 [OPTIONS]...
Configuration: Configuration:
-h, --help display this help and exit -h, --help display this help and exit
--backend=BACKEND backend to build (android, tizen, dc, dingux, ds, gcw0, --backend=BACKEND backend to build (3ds, android, dc, dingux, ds, gcw0,
gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora, gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora,
ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl] ps2, psp, samsungtv, sdl, tizen, webos, wii, wince) [sdl]
Installation directories: Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX --prefix=PREFIX install architecture-independent files in PREFIX
@ -871,10 +871,10 @@ Fine tuning of the installation directories:
Special configuration feature: Special configuration feature:
--host=HOST cross-compile to target HOST (arm-linux, ...) --host=HOST cross-compile to target HOST (arm-linux, ...)
special targets: android-arm for Android ARM special targets: 3ds for Nintendo 3DS
android-arm for Android ARM
android-mips for Android MIPS android-mips for Android MIPS
android-x86 for Android x86 android-x86 for Android x86
tizen for Samsung Tizen
caanoo for Caanoo caanoo for Caanoo
dingux for Dingux dingux for Dingux
raspberrypi for Raspberry Pi raspberrypi for Raspberry Pi
@ -897,6 +897,7 @@ Special configuration feature:
ps3 for PlayStation 3 ps3 for PlayStation 3
psp for PlayStation Portable psp for PlayStation Portable
samsungtv for Samsung TV samsungtv for Samsung TV
tizen for Samsung Tizen
webos for HP Palm WebOS webos for HP Palm WebOS
wii for Nintendo Wii wii for Nintendo Wii
wince for Windows CE wince for Windows CE
@ -1309,6 +1310,11 @@ get_system_exe_extension $guessed_host
NATIVEEXEEXT=$_exeext NATIVEEXEEXT=$_exeext
case $_host in case $_host in
3ds)
_host_os=3ds
_host_cpu=arm
_host_alias=arm-none-eabi
;;
android | android-arm | android-v7a | android-arm-v7a | ouya) android | android-arm | android-v7a | android-arm-v7a | ouya)
_host_os=android _host_os=android
_host_cpu=arm _host_cpu=arm
@ -1590,7 +1596,7 @@ android)
exit 1 exit 1
fi fi
;; ;;
ds | gamecube | wii) 3ds | ds | gamecube | wii)
if test -z "$DEVKITPRO"; then if test -z "$DEVKITPRO"; then
echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>" echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
exit 1 exit 1
@ -1846,7 +1852,7 @@ if test "$have_gcc" = yes ; then
case $_host_os in case $_host_os in
# newlib-based system include files suppress non-C89 function # newlib-based system include files suppress non-C89 function
# declarations under __STRICT_ANSI__ # declarations under __STRICT_ANSI__
amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince ) 3ds | amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
;; ;;
*) *)
append_var CXXFLAGS "-ansi" append_var CXXFLAGS "-ansi"
@ -2146,6 +2152,27 @@ esac
echo_n "Checking hosttype... " echo_n "Checking hosttype... "
echo $_host_os echo $_host_os
case $_host_os in case $_host_os in
3ds)
_optimization_level=-O2
append_var DEFINES "-D__3DS__"
append_var DEFINES "-DARM"
append_var DEFINES "-DARM11"
append_var CXXFLAGS "-march=armv6k"
append_var CXXFLAGS "-mtune=mpcore"
append_var CXXFLAGS "-mword-relocations"
append_var CXXFLAGS "-mfloat-abi=hard"
append_var CXXFLAGS "-ffunction-sections"
append_var CXXFLAGS "-fomit-frame-pointer"
append_var CXXFLAGS "-I$DEVKITPRO/libctru/include"
append_var CXXFLAGS "-I$DEVKITPRO/portlibs/3ds/include"
if test "$_dynamic_modules" = no ; then
append_var LDFLAGS "-Wl,--gc-sections"
else
append_var LDFLAGS "-Wl,--no-gc-sections"
fi
append_var LDFLAGS "-L$DEVKITPRO/portlibs/3ds/lib"
append_var LIBS "-lcitro3d -lctru"
;;
amigaos*) amigaos*)
append_var LDFLAGS "-Wl,--export-dynamic" append_var LDFLAGS "-Wl,--export-dynamic"
append_var LDFLAGS "-L/sdk/local/newlib/lib" append_var LDFLAGS "-L/sdk/local/newlib/lib"
@ -2583,6 +2610,18 @@ if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed # Cross-compiling mode - add your target here if needed
echo "Cross-compiling to $_host" echo "Cross-compiling to $_host"
case "$_host" in case "$_host" in
3ds)
append_var DEFINES "-DDISABLE_FANCY_THEMES"
append_var DEFINES "-DDISABLE_SID"
append_var DEFINES "-DDISABLE_NES_APU"
_backend="3ds"
_build_scalers=no
_vkeybd=yes
_mt32emu=no
# Should use Tremor instead of Vorbis
_vorbis=no
_port_mk="backends/platform/3ds/3ds.mk"
;;
android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya) android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya)
# we link a .so as default # we link a .so as default
append_var LDFLAGS "-shared" append_var LDFLAGS "-shared"
@ -3042,6 +3081,8 @@ fi
# Backend related stuff # Backend related stuff
# #
case $_backend in case $_backend in
3ds)
;;
android) android)
append_var DEFINES "-DREDUCE_MEMORY_USAGE" append_var DEFINES "-DREDUCE_MEMORY_USAGE"
append_var CXXFLAGS "-Wa,--noexecstack" append_var CXXFLAGS "-Wa,--noexecstack"
@ -3144,6 +3185,8 @@ case $_backend in
append_var LDFLAGS "-shared" append_var LDFLAGS "-shared"
append_var LDFLAGS "-fpic" append_var LDFLAGS "-fpic"
;; ;;
sdl)
;;
tizen) tizen)
# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included # dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT" append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
@ -3192,8 +3235,6 @@ case $_backend in
append_var DEFINES "-DSDL_BACKEND" append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1" add_line_to_config_mk "SDL_BACKEND = 1"
;; ;;
sdl)
;;
*) *)
echo "support for $_backend backend not implemented in configure script yet" echo "support for $_backend backend not implemented in configure script yet"
exit 1 exit 1
@ -3228,7 +3269,7 @@ esac
# Enable 16bit support only for backends which support it # Enable 16bit support only for backends which support it
# #
case $_backend in case $_backend in
android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) 3ds | android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
if test "$_16bit" = auto ; then if test "$_16bit" = auto ; then
_16bit=yes _16bit=yes
else else
@ -3307,7 +3348,7 @@ case $_host_os in
amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince) amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince)
_posix=no _posix=no
;; ;;
android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) 3ds | android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos)
_posix=yes _posix=yes
;; ;;
os2-emx*) os2-emx*)
@ -4561,6 +4602,14 @@ fi
# after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup # after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup
# #
case $_backend in case $_backend in
3ds)
if test "$_freetype2" = yes -a "$_png" = yes; then
append_var LIBS "-lpng"
fi
if test "$_tremor" = yes -o "$_flac" = yes; then
append_var LIBS "-logg"
fi
;;
android) android)
# ssp at this point so the cxxtests link # ssp at this point so the cxxtests link
if test "$_debug_build" = yes; then if test "$_debug_build" = yes; then

View file

@ -844,6 +844,10 @@ begin_credits("Credits");
add_person("Frantisek Dufka", "fanoush", "(retired)"); add_person("Frantisek Dufka", "fanoush", "(retired)");
add_person("Tarek Soliman", "tsoliman", ""); add_person("Tarek Soliman", "tsoliman", "");
end_section(); end_section();
begin_section("Nintendo 3DS");
add_person("Thomas Edvalson", "Cruel", "");
end_section();
begin_section("Nintendo 64"); begin_section("Nintendo 64");
add_person("Fabio Battaglia", "Hkz", ""); add_person("Fabio Battaglia", "Hkz", "");

View file

@ -366,6 +366,9 @@ static const char *credits[] = {
"C2""(retired)", "C2""(retired)",
"C0""Tarek Soliman", "C0""Tarek Soliman",
"", "",
"C1""Nintendo 3DS",
"C0""Thomas Edvalson",
"",
"C1""Nintendo 64", "C1""Nintendo 64",
"C0""Fabio Battaglia", "C0""Fabio Battaglia",
"", "",