[Scummvm-cvs-logs] scummvm branch-1-8 -> 64fd77d91a5abfefafb88a7d99a463bf8d8af271

sev- sev at scummvm.org
Tue May 17 19:37:39 CEST 2016


This automated email contains information about 11 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
cd1e129fab 3DS: Initial commit
4cc051d90a 3DS: Add to backend configuration list
7b8db0b848 3DS: Add CIA format build, add timer handler thread, fix APT service suspending/sleeping/exiting
68a15b9594 3DS: Use linear GPU texture downscaling for better legibility in hi-res games
e35d05ca9d 3DS: Add backend author to credits
e53e63df77 3DS: Maintain alphabetical order in configure file
182d59b6a7 3DS: Fix code styling, add license header, remove unused portdefs.h
8d37ac81b0 3DS: Add README
4eb7fc1314 3DS: Add config class/dialog, c-pad cursor control, and option to disable screens
5f95868576 CREDITS: Add Lubomyr to Android porters
64fd77d91a NEWS: Mention 3DS port


Commit: cd1e129fabab2e5f9007a4cb13d6e4297071a32a
    https://github.com/scummvm/scummvm/commit/cd1e129fabab2e5f9007a4cb13d6e4297071a32a
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Initial commit

Changed paths:
  A backends/platform/3ds/3ds.mk
  A backends/platform/3ds/gui.cpp
  A backends/platform/3ds/gui.h
  A backends/platform/3ds/icon.png
  A backends/platform/3ds/main.cpp
  A backends/platform/3ds/module.mk
  A backends/platform/3ds/osystem-audio.cpp
  A backends/platform/3ds/osystem-events.cpp
  A backends/platform/3ds/osystem-graphics.cpp
  A backends/platform/3ds/osystem.cpp
  A backends/platform/3ds/osystem.h
  A backends/platform/3ds/portdefs.h
  A backends/platform/3ds/shader.v.pica
  A backends/platform/3ds/sprite.cpp
  A backends/platform/3ds/sprite.h
    base/commandLine.cpp
    common/scummsys.h
    configure
    gui/credits.h



diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk
new file mode 100644
index 0000000..bd8e743
--- /dev/null
+++ b/backends/platform/3ds/3ds.mk
@@ -0,0 +1,53 @@
+TARGET := scummvm
+
+APP_TITLE       := ScummVM
+APP_DESCRIPTION := Point-and-click adventure game engines
+APP_AUTHOR      := ScummVM Team
+APP_ICON        := backends/platform/3ds/icon.png
+
+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
+
+all: $(TARGET).3dsx
+
+clean: clean_3ds
+
+clean_3ds:
+	$(RM) $(TARGET).3dsx
+
+$(TARGET).smdh: $(APP_ICON) $(MAKEFILE_LIST)
+	@smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
+	@echo built ... $(notdir $@)
+
+$(TARGET).3dsx: $(EXECUTABLE) $(TARGET).smdh
+	@3dsxtool $< $@ --smdh=$(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)))
diff --git a/backends/platform/3ds/gui.cpp b/backends/platform/3ds/gui.cpp
new file mode 100644
index 0000000..0883d5a
--- /dev/null
+++ b/backends/platform/3ds/gui.cpp
@@ -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;
+}
diff --git a/backends/platform/3ds/gui.h b/backends/platform/3ds/gui.h
new file mode 100644
index 0000000..66c6547
--- /dev/null
+++ b/backends/platform/3ds/gui.h
@@ -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
diff --git a/backends/platform/3ds/icon.png b/backends/platform/3ds/icon.png
new file mode 100644
index 0000000..07022fb
Binary files /dev/null and b/backends/platform/3ds/icon.png differ
diff --git a/backends/platform/3ds/main.cpp b/backends/platform/3ds/main.cpp
new file mode 100644
index 0000000..4b5dbbb
--- /dev/null
+++ b/backends/platform/3ds/main.cpp
@@ -0,0 +1,50 @@
+/* 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_ALLOW_ALL
+
+#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 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<OSystem_3DS*>(g_system);
+
+	cfguExit();
+	gfxExit();
+	return 0;
+}
diff --git a/backends/platform/3ds/module.mk b/backends/platform/3ds/module.mk
new file mode 100644
index 0000000..9c1e26b
--- /dev/null
+++ b/backends/platform/3ds/module.mk
@@ -0,0 +1,16 @@
+MODULE := backends/platform/3ds
+
+MODULE_OBJS := \
+	main.o \
+	shader.shbin.o \
+	sprite.o \
+	gui.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)))
diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
new file mode 100644
index 0000000..7ff788b
--- /dev/null
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -0,0 +1,107 @@
+/* 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"
+
+static bool exitAudioThread = false;
+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 = 22050;
+	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(!exitAudioThread) {
+		bufferIndex++;
+		bufferIndex %= bufferCount;
+		ndspWaveBuf* buf = &buffers[bufferIndex];
+		
+		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 (sampleLen > 0) {
+			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) {
+		exitAudioThread = true;
+		threadJoin(audioThread, U64_MAX);
+		threadFree(audioThread);
+		ndspExit();
+	}
+	
+	delete _mixer;
+	_mixer = 0;
+}
+
+Audio::Mixer *OSystem_3DS::getMixer() {
+	assert(_mixer);
+	return _mixer;
+}
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
new file mode 100644
index 0000000..a4ce92c
--- /dev/null
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -0,0 +1,194 @@
+/* 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_ALLOW_ALL
+#include "backends/platform/3ds/gui.h"
+#include "osystem.h"
+
+static Common::Mutex *eventMutex;
+static bool exitEventThread = false;
+static InputMode inputMode = MODE_DRAG;
+
+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;
+	Common::Event event;
+	
+	while(!exitEventThread) {
+		osys->delayMillis(10);
+		
+		hidScanInput();
+		touchPosition touch;
+		u32 held = hidKeysHeld();
+		u32 keysPressed = hidKeysDown();
+		u32 keysReleased = hidKeysUp();
+		
+		if (!aptMainLoop()) {
+			event.type = Common::EVENT_QUIT;
+			pushEventQueue(eventQueue, event);
+		}
+		if (held & KEY_TOUCH) {
+			hidTouchRead(&touch);
+			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;
+			printf("clicked %u, %u\n", lastTouch.px, 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);
+			}
+		}
+		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) {
+			// SIMULATE LEFT CLICK
+			event.mouse.x = lastTouch.px;
+			event.mouse.y = lastTouch.py;
+			event.type = Common::EVENT_LBUTTONDOWN;
+			pushEventQueue(eventQueue, event);
+			event.type = Common::EVENT_LBUTTONUP;
+			pushEventQueue(eventQueue, event);
+		}
+		if (keysPressed & KEY_X || keysPressed & KEY_DUP) {
+			// SIMULATE RIGHT CLICK
+			event.mouse.x = lastTouch.px;
+			event.mouse.y = lastTouch.py;
+			event.type = Common::EVENT_RBUTTONDOWN;
+			pushEventQueue(eventQueue, event);
+			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) {
+			event.type = Common::EVENT_RTL;
+			pushEventQueue(eventQueue, event);
+		}
+		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
+	}
+}
+
+void OSystem_3DS::initEvents() {
+	eventMutex = new Common::Mutex();
+	s32 prio = 0;
+	svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+	_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 2048, prio-1, -2, false);
+}
+
+void OSystem_3DS::destroyEvents() {
+	exitEventThread = true;
+	threadJoin(_eventThread, U64_MAX);
+	threadFree(_eventThread);
+	delete eventMutex;
+}
+
+void OSystem_3DS::transformPoint(touchPosition &point) {
+	if (!_overlayVisible) {
+		point.px = static_cast<float>(point.px) / _gameTexture.getScaleX() - _gameX;
+		point.py = static_cast<float>(point.py) / _gameTexture.getScaleY() - _gameY;
+	}
+}
+
+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();
+	}
+	
+	Common::StackLock lock(*eventMutex);
+	
+	if (_eventQueue.empty())
+		return false;
+	
+	event = _eventQueue.pop();
+	return true;
+}
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
new file mode 100644
index 0000000..5e70dce
--- /dev/null
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -0,0 +1,465 @@
+/* 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_ALLOW_ALL
+#include "backends/platform/3ds/osystem.h"
+#include "backends/platform/3ds/shader_shbin.h"
+#include <common/rect.h>
+#include <algorithm>
+
+// 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))
+
+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();
+	_gameTexture.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::kFeatureFullscreenMode ||
+	        f == OSystem::kFeatureCursorPalette ||
+	        f == OSystem::kFeatureOverlaySupportsAlpha);
+}
+
+void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {
+	switch (f) {
+	case OSystem::kFeatureFullscreenMode:
+		_isFullscreen = enable;
+		break;
+	case OSystem::kFeatureCursorPalette:
+		_cursorPaletteEnabled = enable;
+		flushCursor();
+		break;
+	default:
+		break;
+	}
+}
+
+bool OSystem_3DS::getFeatureState(OSystem::Feature f) {
+	switch (f) {
+	case OSystem::kFeatureFullscreenMode:
+		return _isFullscreen;
+	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() {
+	printf("resetGraphicsScale\n");
+}
+
+int OSystem_3DS::getGraphicsMode() const {
+	return GFX_LINEAR;
+}
+void OSystem_3DS::initSize(uint width, uint height,
+                                   const Graphics::PixelFormat *format) {
+	printf("3ds initsize w:%d h:%d\n", width, height);
+	_gameWidth = width;
+	_gameHeight = height;
+	_gameTexture.create(width, height, _pfGameTexture);
+	_overlay.create(getOverlayWidth(), getOverlayHeight(), _pfGameTexture);
+	
+	if (format) {
+		printf("pixelformat: %d %d %d %d %d\n", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());;
+		_pfGame = *format;
+	}
+
+	_gameScreen.create(width, height, _pfGame);
+	
+	_focusDirty = true;
+	_focusRect = Common::Rect(_gameWidth, _gameHeight);
+
+	if (_isFullscreen) {
+		_gameRatio = 320.f / 240.f;
+		_gameX = _gameY = 0;
+		_gameTexture.setScale(320.f / width, 240.f / height);
+	} else {
+		_gameRatio = static_cast<float>(width) / height;
+		if (width > height) {
+			_gameX = 0;
+			_gameY = (240.f - 320.f / width * height) / 2.f;
+		} else {
+			_gameY = 0;
+			_gameX = (320.f - 240.f / height * width) / 2.f;
+		}
+		_gameTexture.setScale((width > 320) ? 320.f / width : 1.f,
+		                      (height > 240) ? 240.f / height : 1.f);
+	}
+	_gameTexture.setPosition(_gameX, _gameY);
+	_cursorTexture.setScale(_gameTexture.getScaleX(), _gameTexture.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) {
+// 	printf("setPalette\n");
+	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) {
+// 	printf("grabPalette\n");
+	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);
+	_gameTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
+	
+	convertedSubSurface->free();
+	delete convertedSubSurface;
+	_gameTexture.markDirty();
+}
+
+void OSystem_3DS::flushGameScreen() {
+	Graphics::Surface *converted = _gameScreen.convertTo(_pfGameTexture, _palette);
+	_gameTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+	_gameTexture.markDirty();
+	converted->free();
+	delete converted;
+}
+
+Graphics::Surface *OSystem_3DS::lockScreen() {
+	printf("lockScreen\n");
+	return &_gameScreen;
+}
+void OSystem_3DS::unlockScreen() {
+	printf("unlockScreen\n");
+	flushGameScreen();
+}
+
+void OSystem_3DS::updateScreen() {
+	
+	updateFocus();
+
+	C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
+		// Render top screen
+		C3D_FrameDrawOn(_renderTargetTop);
+		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionTop);
+		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, &_focusMatrix);
+		_gameTexture.render();
+		_gameTexture.render();
+		
+		// Render bottom screen
+		C3D_FrameDrawOn(_renderTargetBottom);
+		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionBottom);
+		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameTexture.getMatrix());
+		_gameTexture.render();
+		if (_overlayVisible) {
+			C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
+			_overlay.render();
+		}
+		if (_cursorVisible) {
+			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;
+	_gameTexture.setPosition(_gameX, _gameY + shakeOffset);
+}
+
+void OSystem_3DS::setFocusRectangle(const Common::Rect &rect) {
+// 	printf("setfocus: %d %d %d %d\n", 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;
+	_cursorTexture.setScale(1.f, 1.f);
+	updateScreen();
+}
+
+void OSystem_3DS::hideOverlay() {
+	_overlayVisible = false;
+	_cursorTexture.setScale(_gameTexture.getScaleX(), _gameTexture.getScaleY());
+	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;
+	// TODO: adjust for _cursorScalable ?
+	_cursorTexture.setPosition(x - _cursorHotspotX + (_overlayVisible ? 0 : _gameX),
+							   y - _cursorHotspotY + (_overlayVisible ? 0 : _gameY));
+}
+
+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;
+			}
+		}
+	}
+}
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
new file mode 100644
index 0000000..fa2980a
--- /dev/null
+++ b/backends/platform/3ds/osystem.cpp
@@ -0,0 +1,173 @@
+/* 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_ALLOW_ALL
+
+#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 "backends/fs/posix/posix-fs-factory.h"
+#include "backends/fs/posix/posix-fs.h"
+#include <unistd.h>
+#include <time.h>
+
+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),
+_showMessageOSD(false),
+_isFullscreen(false),
+_cursorVisible(false),
+_cursorScalable(false),
+_cursorPaletteEnabled(false),
+_cursorX(0),
+_cursorY(0),
+_cursorHotspotX(0),
+_cursorHotspotY(0),
+_gameX(0),
+_gameY(0),
+_gameWidth(320),
+_gameHeight(240) {
+	chdir("/");
+	_fsFactory = new POSIXFilesystemFactory();
+	Posix::assureDirectoryExists("/3ds/scummvm/saves/");
+}
+
+OSystem_3DS::~OSystem_3DS() {
+	destroyEvents();
+	destroyAudio();
+	destroyGraphics();
+	
+	delete _timerManager;
+	_timerManager = 0;
+}
+
+void OSystem_3DS::quit() {
+	//
+}
+
+void OSystem_3DS::initBackend() {
+	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();
+}
+
+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);
+}
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
new file mode 100644
index 0000000..98d9ad0
--- /dev/null
+++ b/backends/platform/3ds/osystem.h
@@ -0,0 +1,210 @@
+/* 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
+	
+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();
+	~OSystem_3DS();
+
+	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);
+	
+	void transformPoint(touchPosition &point);
+	
+	void updateFocus();
+	
+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 _gameX, _gameY;
+	float _gameRatio;
+	
+	// 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 _gameTexture;
+	Sprite _overlay;
+	
+	int _screenShakeOffset;
+	bool _overlayVisible;
+	bool _isFullscreen;
+	
+	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;
+	Common::Queue<Common::Event> _eventQueue;
+
+	Common::String _messageOSD;
+	bool _showMessageOSD;
+	
+	// Cursor
+	Graphics::Surface _cursor;
+	Sprite _cursorTexture;
+	bool _cursorPaletteEnabled;
+	bool _cursorVisible;
+	bool _cursorScalable;
+	int _cursorX, _cursorY;
+	int _cursorHotspotX, _cursorHotspotY;
+	uint32 _cursorKeyColor;
+};
+
+#endif
diff --git a/backends/platform/3ds/portdefs.h b/backends/platform/3ds/portdefs.h
new file mode 100644
index 0000000..f58cf5a
--- /dev/null
+++ b/backends/platform/3ds/portdefs.h
@@ -0,0 +1,28 @@
+/* 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 _PORTDEFS_H_
+#define _PORTDEFS_H_
+
+#define LURE_CLICKABLE_MENUS
+
+#endif
diff --git a/backends/platform/3ds/shader.v.pica b/backends/platform/3ds/shader.v.pica
new file mode 100644
index 0000000..a359768
--- /dev/null
+++ b/backends/platform/3ds/shader.v.pica
@@ -0,0 +1,40 @@
+; PICA200 vertex shader
+
+; 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
+
diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
new file mode 100644
index 0000000..d779fa4
--- /dev/null
+++ b/backends/platform/3ds/sprite.cpp
@@ -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.
+ *
+ */
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "backends/platform/3ds/sprite.h"
+#include <algorithm>
+#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 = std::max(nextHigher2(width), 64u);
+	h = std::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_NEAREST);
+		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;
+}
diff --git a/backends/platform/3ds/sprite.h b/backends/platform/3ds/sprite.h
new file mode 100644
index 0000000..6d88ae4
--- /dev/null
+++ b/backends/platform/3ds/sprite.h
@@ -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
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 19702ea..dfc40eb 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -57,7 +57,7 @@ static const char USAGE_STRING[] =
 ;
 
 // 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
 #else
 static const char HELP_STRING[] =
diff --git a/common/scummsys.h b/common/scummsys.h
index 7c2978f..5e1069f 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -251,6 +251,7 @@
 
 	#if defined(__DC__) || \
 		  defined(__DS__) || \
+		  defined(__3DS__) || \
 		  defined(__GP32__) || \
 		  defined(IPHONE) || \
 		  defined(__PLAYSTATION2__) || \
@@ -367,7 +368,7 @@
 #endif
 
 #ifndef STRINGBUFLEN
-	#if defined(__N64__) || defined(__DS__)
+	#if defined(__N64__) || defined(__DS__) || defined(__3DS__)
 		#define STRINGBUFLEN 256
 	#else
 		#define STRINGBUFLEN 1024
diff --git a/configure b/configure
index 1a869cc..aa2d0a9 100755
--- a/configure
+++ b/configure
@@ -441,7 +441,7 @@ get_system_exe_extension() {
 	arm-riscos)
 		_exeext=",ff8"
 		;;
-	dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
+	dreamcast | ds | 3ds | gamecube | n64 | ps2 | psp | wii)
 		_exeext=".elf"
 		;;
 	gph-linux)
@@ -844,7 +844,7 @@ Usage: $0 [OPTIONS]...
 
 Configuration:
   -h, --help              display this help and exit
-  --backend=BACKEND       backend to build (android, tizen, dc, dingux, ds, gcw0,
+  --backend=BACKEND       backend to build (android, tizen, dc, dingux, ds, 3ds, gcw0,
                           gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora,
                           ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl]
 
@@ -881,6 +881,7 @@ Special configuration feature:
                                            raspberrypi for Raspberry Pi
                                            dreamcast for Sega Dreamcast
                                            ds for Nintendo DS
+                                           3ds for Nintendo 3DS
                                            gamecube for Nintendo GameCube
                                            gcw0 for GCW Zero
                                            gp2x for GP2X
@@ -1356,6 +1357,11 @@ ds)
 	_host_cpu=arm
 	_host_alias=arm-eabi
 	;;
+3ds)
+	_host_os=3ds
+	_host_cpu=arm
+	_host_alias=arm-none-eabi
+	;;
 gamecube)
 	_host_os=gamecube
 	_host_cpu=powerpc
@@ -1589,7 +1595,7 @@ android)
 		exit 1
 	fi
 	;;
-ds | gamecube | wii)
+ds | 3ds | gamecube | wii)
 	if test -z "$DEVKITPRO"; then
 		echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
 		exit 1
@@ -1845,7 +1851,7 @@ if test "$have_gcc" = yes ; then
 			case $_host_os in
 			# newlib-based system include files suppress non-C89 function
 			# declarations under __STRICT_ANSI__
-			amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
+			amigaos* | android | dreamcast | ds | 3ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
 				;;
 			*)
 				append_var CXXFLAGS "-ansi"
@@ -2405,6 +2411,27 @@ case $_host_os in
 		append_var LDFLAGS "-L$DEVKITPRO/libnds/lib"
 		append_var LIBS "-lnds9"
 		;;
+	3ds)
+		_optimization_level=-O2
+		append_var DEFINES "-D__3DS__"
+		append_var DEFINES "-D_3DS"
+		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 "-isystem $DEVKITPRO/libctru/include"
+		append_var CXXFLAGS "-isystem $DEVKITPRO/devkitARM/arm-none-eabi/include"
+		append_var CXXFLAGS "-isystem $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 LIBS "-lcitro3d -lctru"
+		;;
 	freebsd*)
 		append_var LDFLAGS "-L/usr/local/lib"
 		append_var CXXFLAGS "-I/usr/local/include"
@@ -2711,6 +2738,25 @@ if test -n "$_host"; then
 			_mt32emu=no
 			_port_mk="backends/platform/ds/ds.mk"
 			;;
+		3ds)
+			append_var DEFINES "-DDISABLE_FANCY_THEMES"
+			append_var DEFINES "-DDISABLE_SID"
+			append_var DEFINES "-DDISABLE_NES_APU"
+			append_var DEFINES "-DDISABLE_NES_APU"
+			append_var DEFINES "-DSTREAM_AUDIO_FROM_DISK"
+			_backend="3ds"
+			_build_scalers=no
+			_vkeybd=yes
+			_mt32emu=no
+			_vorbis=no
+			_tremor=yes
+			_mad=yes
+			_zlib=yes
+			_jpeg=yes
+			_png=yes
+			_freetype2=yes
+			_port_mk="backends/platform/3ds/3ds.mk"
+			;;
 		gamecube)
 			_backend="wii"
 			_build_scalers=no
@@ -3224,7 +3270,7 @@ esac
 # Enable 16bit support only for backends which support it
 #
 case $_backend in
-	android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
+	android | dingux | dc | 3ds | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
 		if test "$_16bit" = auto ; then
 			_16bit=yes
 		else
@@ -3303,7 +3349,7 @@ case $_host_os in
 	amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince)
 		_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
 		;;
 	os2-emx*)
diff --git a/gui/credits.h b/gui/credits.h
index cb9a10f..a560209 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -366,6 +366,9 @@ static const char *credits[] = {
 "C2""(retired)",
 "C0""Tarek Soliman",
 "",
+"C1""Nintendo 3DS",
+"C0""Thomas Edvalson",
+"",
 "C1""Nintendo 64",
 "C0""Fabio Battaglia",
 "",


Commit: 4cc051d90a5e10558f6632098edbba03f4b57306
    https://github.com/scummvm/scummvm/commit/4cc051d90a5e10558f6632098edbba03f4b57306
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Add to backend configuration list

Changed paths:
    configure



diff --git a/configure b/configure
index aa2d0a9..6abc5dc 100755
--- a/configure
+++ b/configure
@@ -3234,6 +3234,8 @@ case $_backend in
 		append_var DEFINES "-DSDL_BACKEND"
 		add_line_to_config_mk "SDL_BACKEND = 1"
 		;;
+	3ds)
+		;;
 	sdl)
 		;;
 	*)


Commit: 7b8db0b84839108b75a33af8a062302252cb0b7a
    https://github.com/scummvm/scummvm/commit/7b8db0b84839108b75a33af8a062302252cb0b7a
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Add CIA format build, add timer handler thread, fix APT service suspending/sleeping/exiting

Changed paths:
  A backends/platform/3ds/app/banner.png
  A backends/platform/3ds/app/banner.wav
  A backends/platform/3ds/app/icon.png
  A backends/platform/3ds/app/scummvm.rsf
  R backends/platform/3ds/icon.png
    backends/platform/3ds/3ds.mk
    backends/platform/3ds/osystem-audio.cpp
    backends/platform/3ds/osystem-events.cpp
    backends/platform/3ds/osystem-graphics.cpp
    backends/platform/3ds/osystem.cpp
    backends/platform/3ds/osystem.h
    configure



diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk
index bd8e743..7ab5899 100644
--- a/backends/platform/3ds/3ds.mk
+++ b/backends/platform/3ds/3ds.mk
@@ -3,7 +3,11 @@ TARGET := scummvm
 APP_TITLE       := ScummVM
 APP_DESCRIPTION := Point-and-click adventure game engines
 APP_AUTHOR      := ScummVM Team
-APP_ICON        := backends/platform/3ds/icon.png
+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
@@ -12,20 +16,27 @@ LDFLAGS  += -specs=3dsx.specs $(ARCH) -L$(DEVKITPRO)/libctru/lib -L$(DEVKITPRO)/
 
 .PHONY: clean_3ds
 
-all: $(TARGET).3dsx
-
 clean: clean_3ds
 
 clean_3ds:
 	$(RM) $(TARGET).3dsx
+	$(RM) $(TARGET).cia
 
-$(TARGET).smdh: $(APP_ICON) $(MAKEFILE_LIST)
-	@smdhtool --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
+$(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
diff --git a/backends/platform/3ds/app/banner.png b/backends/platform/3ds/app/banner.png
new file mode 100644
index 0000000..a3b0215
Binary files /dev/null and b/backends/platform/3ds/app/banner.png differ
diff --git a/backends/platform/3ds/app/banner.wav b/backends/platform/3ds/app/banner.wav
new file mode 100644
index 0000000..e0b684b
Binary files /dev/null and b/backends/platform/3ds/app/banner.wav differ
diff --git a/backends/platform/3ds/app/icon.png b/backends/platform/3ds/app/icon.png
new file mode 100644
index 0000000..07022fb
Binary files /dev/null and b/backends/platform/3ds/app/icon.png differ
diff --git a/backends/platform/3ds/app/scummvm.rsf b/backends/platform/3ds/app/scummvm.rsf
new file mode 100644
index 0000000..d403bdb
--- /dev/null
+++ b/backends/platform/3ds/app/scummvm.rsf
@@ -0,0 +1,218 @@
+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
+
+
+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
diff --git a/backends/platform/3ds/icon.png b/backends/platform/3ds/icon.png
deleted file mode 100644
index 07022fb..0000000
Binary files a/backends/platform/3ds/icon.png and /dev/null differ
diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
index 7ff788b..7e4822b 100644
--- a/backends/platform/3ds/osystem-audio.cpp
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -21,8 +21,8 @@
  */
 
 #include "osystem.h"
+#include "audio/mixer.h"
 
-static bool exitAudioThread = false;
 static bool hasAudio = false;
 
 static void audioThreadFunc(void* arg) {
@@ -34,7 +34,7 @@ static void audioThreadFunc(void* arg) {
 	int bufferIndex = 0;
 	const int bufferCount = 3;
 	const int bufferSize = 80000; // Can't be too small, based on delayMillis duration
-	const int sampleRate = 22050;
+	const int sampleRate = mixer->getOutputRate();
 	int sampleLen = 0;
 	uint32 lastTime = osys->getMillis(true);
 	uint32 time = lastTime;
@@ -52,18 +52,18 @@ static void audioThreadFunc(void* arg) {
 	ndspChnSetRate(channel, sampleRate);
 	ndspChnSetFormat(channel, NDSP_FORMAT_STEREO_PCM16);
 
-	while(!exitAudioThread) {
-		bufferIndex++;
-		bufferIndex %= bufferCount;
-		ndspWaveBuf* buf = &buffers[bufferIndex];
-		
+	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 (sampleLen > 0) {
+		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);
@@ -91,7 +91,6 @@ void OSystem_3DS::initAudio() {
 
 void OSystem_3DS::destroyAudio() {
 	if (hasAudio) {
-		exitAudioThread = true;
 		threadJoin(audioThread, U64_MAX);
 		threadFree(audioThread);
 		ndspExit();
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
index a4ce92c..46efdd3 100644
--- a/backends/platform/3ds/osystem-events.cpp
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -21,12 +21,13 @@
  */
 
 #define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "backends/timer/default/default-timer.h"
 #include "backends/platform/3ds/gui.h"
 #include "osystem.h"
 
 static Common::Mutex *eventMutex;
-static bool exitEventThread = false;
 static InputMode inputMode = MODE_DRAG;
+static aptHookCookie cookie;
 
 static void pushEventQueue(Common::Queue<Common::Event>* queue, Common::Event& event) {
 	Common::StackLock lock(*eventMutex);
@@ -42,8 +43,10 @@ static void eventThreadFunc(void* arg) {
 	bool isRightClick = false;
 	Common::Event event;
 	
-	while(!exitEventThread) {
-		osys->delayMillis(10);
+	while(!osys->exiting) {
+		do {
+			osys->delayMillis(10);
+		} while (osys->sleeping && !osys->exiting);
 		
 		hidScanInput();
 		touchPosition touch;
@@ -51,10 +54,6 @@ static void eventThreadFunc(void* arg) {
 		u32 keysPressed = hidKeysDown();
 		u32 keysReleased = hidKeysUp();
 		
-		if (!aptMainLoop()) {
-			event.type = Common::EVENT_QUIT;
-			pushEventQueue(eventQueue, event);
-		}
 		if (held & KEY_TOUCH) {
 			hidTouchRead(&touch);
 			osys->transformPoint(touch);
@@ -151,15 +150,53 @@ static void eventThreadFunc(void* arg) {
 	}
 }
 
+static void aptHookFunc(APT_HookType hookType, void* param) {
+	auto eventQueue = (Common::Queue<Common::Event>*) param;
+	OSystem_3DS* osys = (OSystem_3DS*) g_system;
+	Common::Event event;
+	
+	switch (hookType) {
+		case APTHOOK_ONSUSPEND:
+		case APTHOOK_ONSLEEP:
+			event.type = Common::EVENT_MAINMENU;
+			pushEventQueue(eventQueue, event);
+			osys->sleeping = true;
+			break;
+		case APTHOOK_ONRESTORE:
+		case APTHOOK_ONWAKEUP:
+			osys->sleeping = false;
+			break;
+		default:
+			event.type = Common::EVENT_QUIT;
+			pushEventQueue(eventQueue, event);
+			break;
+	}
+}
+
+static void timerThreadFunc(void *arg) {
+	OSystem_3DS* osys = (OSystem_3DS*) arg;
+	DefaultTimerManager *tm = (DefaultTimerManager *) osys->getTimerManager();
+	while (!osys->exiting) {
+		tm->handler();
+		g_system->delayMillis(10);
+		aptMainLoop(); // Call apt hook when necessary
+	}
+}
+
 void OSystem_3DS::initEvents() {
 	eventMutex = new Common::Mutex();
 	s32 prio = 0;
 	svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
-	_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 2048, prio-1, -2, false);
+	_timerThread = threadCreate(&timerThreadFunc, this, 32*1024, prio-1, -2, false);
+	_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 32*1024, prio-1, -2, false);
+	
+	aptHook(&cookie, aptHookFunc, &_eventQueue);
 }
 
 void OSystem_3DS::destroyEvents() {
-	exitEventThread = true;
+	threadJoin(_timerThread, U64_MAX);
+	threadFree(_timerThread);
+
 	threadJoin(_eventThread, U64_MAX);
 	threadFree(_eventThread);
 	delete eventMutex;
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 5e70dce..7ee4efa 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -180,6 +180,12 @@ void OSystem_3DS::initSize(uint width, uint height,
 	}
 	_gameTexture.setPosition(_gameX, _gameY);
 	_cursorTexture.setScale(_gameTexture.getScaleX(), _gameTexture.getScaleY());
+	
+	float ratio = 400.f / _gameWidth;
+	int y = (_gameHeight * ratio - 240.f) / 2;
+	Mtx_Identity(&_focusMatrix);
+	Mtx_Translate(&_focusMatrix, 0, -y, 0);
+	Mtx_Scale(&_focusMatrix, ratio, ratio, 1.f);
 }
 
 Common::List<Graphics::PixelFormat> OSystem_3DS::getSupportedFormats() const {
@@ -248,8 +254,11 @@ void OSystem_3DS::unlockScreen() {
 }
 
 void OSystem_3DS::updateScreen() {
+
+	if (sleeping || exiting)
+		return;
 	
-	updateFocus();
+// 	updateFocus();
 
 	C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
 		// Render top screen
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index fa2980a..d3fc1c7 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -65,13 +65,16 @@ _cursorHotspotY(0),
 _gameX(0),
 _gameY(0),
 _gameWidth(320),
-_gameHeight(240) {
-	chdir("/");
+_gameHeight(240),
+exiting(false),
+sleeping(false) {
+	chdir("sdmc:/");
 	_fsFactory = new POSIXFilesystemFactory();
 	Posix::assureDirectoryExists("/3ds/scummvm/saves/");
 }
 
 OSystem_3DS::~OSystem_3DS() {
+	exiting = true;
 	destroyEvents();
 	destroyAudio();
 	destroyGraphics();
@@ -81,7 +84,7 @@ OSystem_3DS::~OSystem_3DS() {
 }
 
 void OSystem_3DS::quit() {
-	//
+	printf("OSystem_3DS::quit()\n");
 }
 
 void OSystem_3DS::initBackend() {
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index 98d9ad0..a8c2a90 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -55,6 +55,9 @@ class OSystem_3DS : public EventsBaseBackend, public PaletteManager {
 public:
 	OSystem_3DS();
 	~OSystem_3DS();
+	
+	volatile bool exiting;
+	volatile bool sleeping;
 
 	virtual void initBackend();
 	
@@ -191,6 +194,7 @@ private:
 	
 	// Events
 	Thread _eventThread;
+	Thread _timerThread;
 	Common::Queue<Common::Event> _eventQueue;
 
 	Common::String _messageOSD;
diff --git a/configure b/configure
index 6abc5dc..9f70822 100755
--- a/configure
+++ b/configure
@@ -2414,7 +2414,7 @@ case $_host_os in
 	3ds)
 		_optimization_level=-O2
 		append_var DEFINES "-D__3DS__"
-		append_var DEFINES "-D_3DS"
+		append_var DEFINES "-DARM"
 		append_var DEFINES "-DARM11"
 		append_var CXXFLAGS "-march=armv6k"
 		append_var CXXFLAGS "-mtune=mpcore"
@@ -2742,8 +2742,6 @@ if test -n "$_host"; then
 			append_var DEFINES "-DDISABLE_FANCY_THEMES"
 			append_var DEFINES "-DDISABLE_SID"
 			append_var DEFINES "-DDISABLE_NES_APU"
-			append_var DEFINES "-DDISABLE_NES_APU"
-			append_var DEFINES "-DSTREAM_AUDIO_FROM_DISK"
 			_backend="3ds"
 			_build_scalers=no
 			_vkeybd=yes
@@ -2754,6 +2752,8 @@ if test -n "$_host"; then
 			_zlib=yes
 			_jpeg=yes
 			_png=yes
+			_flac=yes
+			_faad=yes
 			_freetype2=yes
 			_port_mk="backends/platform/3ds/3ds.mk"
 			;;
@@ -4637,6 +4637,9 @@ case $_backend in
 		# during linking stage
 		append_var LIBS "-lc -lgcc -lnosys"
 		;;
+	3ds)
+		append_var LIBS "-logg -lpng"
+		;;
 esac
 
 


Commit: 68a15b95945983e8a6440e2ece8b798a137af751
    https://github.com/scummvm/scummvm/commit/68a15b95945983e8a6440e2ece8b798a137af751
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Use linear GPU texture downscaling for better legibility in hi-res games

Changed paths:
    backends/platform/3ds/sprite.cpp



diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
index d779fa4..0d5780e 100644
--- a/backends/platform/3ds/sprite.cpp
+++ b/backends/platform/3ds/sprite.cpp
@@ -69,7 +69,7 @@ void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f)
 	if (width && height) {
 		pixels = linearAlloc(h * pitch);
 		C3D_TexInit(&texture, w, h, GPU_RGBA8);
-		C3D_TexSetFilter(&texture, GPU_LINEAR, GPU_NEAREST);
+		C3D_TexSetFilter(&texture, GPU_LINEAR, GPU_LINEAR);
 		assert(pixels && texture.data);
 		clear();
 	}


Commit: e35d05ca9d7e45ad2b4580ce64d6c239e09d500a
    https://github.com/scummvm/scummvm/commit/e35d05ca9d7e45ad2b4580ce64d6c239e09d500a
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Add backend author to credits

Changed paths:
    AUTHORS
    devtools/credits.pl



diff --git a/AUTHORS b/AUTHORS
index eff485c..22d6e37 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -302,6 +302,9 @@ ScummVM Team
        Frantisek Dufka              - (retired)
        Tarek Soliman
 
+    Nintendo 3DS:
+       Thomas Edvalson
+
     Nintendo 64:
        Fabio Battaglia
 
diff --git a/devtools/credits.pl b/devtools/credits.pl
index c67793c..9e0fcc6 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -844,6 +844,10 @@ begin_credits("Credits");
 				add_person("Frantisek Dufka", "fanoush", "(retired)");
 				add_person("Tarek Soliman", "tsoliman", "");
 			end_section();
+			
+			begin_section("Nintendo 3DS");
+				add_person("Thomas Edvalson", "Cruel", "");
+			end_section();
 
 			begin_section("Nintendo 64");
 				add_person("Fabio Battaglia", "Hkz", "");


Commit: e53e63df77d1993b0a0ce31e904fc57f9f5165ef
    https://github.com/scummvm/scummvm/commit/e53e63df77d1993b0a0ce31e904fc57f9f5165ef
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:13+02:00

Commit Message:
3DS: Maintain alphabetical order in configure file

Changed paths:
    configure



diff --git a/configure b/configure
index 9f70822..f8d6797 100755
--- a/configure
+++ b/configure
@@ -441,7 +441,7 @@ get_system_exe_extension() {
 	arm-riscos)
 		_exeext=",ff8"
 		;;
-	dreamcast | ds | 3ds | gamecube | n64 | ps2 | psp | wii)
+	3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
 		_exeext=".elf"
 		;;
 	gph-linux)
@@ -844,9 +844,9 @@ Usage: $0 [OPTIONS]...
 
 Configuration:
   -h, --help              display this help and exit
-  --backend=BACKEND       backend to build (android, tizen, dc, dingux, ds, 3ds, gcw0,
+  --backend=BACKEND       backend to build (3ds, android, dc, dingux, ds, gcw0,
                           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:
   --prefix=PREFIX         install architecture-independent files in PREFIX
@@ -872,16 +872,15 @@ Fine tuning of the installation directories:
 
 Special configuration feature:
   --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-x86 for Android x86
-                                           tizen for Samsung Tizen
                                            caanoo for Caanoo
                                            dingux for Dingux
                                            raspberrypi for Raspberry Pi
                                            dreamcast for Sega Dreamcast
                                            ds for Nintendo DS
-                                           3ds for Nintendo 3DS
                                            gamecube for Nintendo GameCube
                                            gcw0 for GCW Zero
                                            gp2x for GP2X
@@ -899,6 +898,7 @@ Special configuration feature:
                                            ps3 for PlayStation 3
                                            psp for PlayStation Portable
                                            samsungtv for Samsung TV
+                                           tizen for Samsung Tizen
                                            webos for HP Palm WebOS
                                            wii for Nintendo Wii
                                            wince for Windows CE
@@ -1309,6 +1309,11 @@ get_system_exe_extension $guessed_host
 NATIVEEXEEXT=$_exeext
 
 case $_host in
+3ds)
+	_host_os=3ds
+	_host_cpu=arm
+	_host_alias=arm-none-eabi
+	;;
 android | android-arm | android-v7a | android-arm-v7a | ouya)
 	_host_os=android
 	_host_cpu=arm
@@ -1357,11 +1362,6 @@ ds)
 	_host_cpu=arm
 	_host_alias=arm-eabi
 	;;
-3ds)
-	_host_os=3ds
-	_host_cpu=arm
-	_host_alias=arm-none-eabi
-	;;
 gamecube)
 	_host_os=gamecube
 	_host_cpu=powerpc
@@ -1595,7 +1595,7 @@ android)
 		exit 1
 	fi
 	;;
-ds | 3ds | gamecube | wii)
+3ds | ds | gamecube | wii)
 	if test -z "$DEVKITPRO"; then
 		echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
 		exit 1
@@ -1851,7 +1851,7 @@ if test "$have_gcc" = yes ; then
 			case $_host_os in
 			# newlib-based system include files suppress non-C89 function
 			# declarations under __STRICT_ANSI__
-			amigaos* | android | dreamcast | ds | 3ds | 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"
@@ -2151,6 +2151,27 @@ esac
 echo_n "Checking hosttype... "
 echo $_host_os
 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*)
 		append_var LDFLAGS "-Wl,--export-dynamic"
 		append_var LDFLAGS "-L/sdk/local/newlib/lib"
@@ -2411,27 +2432,6 @@ case $_host_os in
 		append_var LDFLAGS "-L$DEVKITPRO/libnds/lib"
 		append_var LIBS "-lnds9"
 		;;
-	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 "-isystem $DEVKITPRO/libctru/include"
-		append_var CXXFLAGS "-isystem $DEVKITPRO/devkitARM/arm-none-eabi/include"
-		append_var CXXFLAGS "-isystem $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 LIBS "-lcitro3d -lctru"
-		;;
 	freebsd*)
 		append_var LDFLAGS "-L/usr/local/lib"
 		append_var CXXFLAGS "-I/usr/local/include"
@@ -2609,6 +2609,18 @@ if test -n "$_host"; then
 	# Cross-compiling mode - add your target here if needed
 	echo "Cross-compiling to $_host"
 	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)
 			# we link a .so as default
 			append_var LDFLAGS "-shared"
@@ -2738,25 +2750,6 @@ if test -n "$_host"; then
 			_mt32emu=no
 			_port_mk="backends/platform/ds/ds.mk"
 			;;
-		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
-			_vorbis=no
-			_tremor=yes
-			_mad=yes
-			_zlib=yes
-			_jpeg=yes
-			_png=yes
-			_flac=yes
-			_faad=yes
-			_freetype2=yes
-			_port_mk="backends/platform/3ds/3ds.mk"
-			;;
 		gamecube)
 			_backend="wii"
 			_build_scalers=no
@@ -3084,6 +3077,8 @@ fi
 # Backend related stuff
 #
 case $_backend in
+	3ds)
+		;;
 	android)
 		append_var DEFINES "-DREDUCE_MEMORY_USAGE"
 		append_var CXXFLAGS "-Wa,--noexecstack"
@@ -3186,6 +3181,8 @@ case $_backend in
 		append_var LDFLAGS "-shared"
 		append_var LDFLAGS "-fpic"
 		;;
+	sdl)
+		;;
 	tizen)
 		# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
 		append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
@@ -3234,10 +3231,6 @@ case $_backend in
 		append_var DEFINES "-DSDL_BACKEND"
 		add_line_to_config_mk "SDL_BACKEND = 1"
 		;;
-	3ds)
-		;;
-	sdl)
-		;;
 	*)
 		echo "support for $_backend backend not implemented in configure script yet"
 		exit 1
@@ -3272,7 +3265,7 @@ esac
 # Enable 16bit support only for backends which support it
 #
 case $_backend in
-	android | dingux | dc | 3ds | 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
 			_16bit=yes
 		else
@@ -4606,6 +4599,14 @@ fi
 # after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup
 #
 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)
 		# ssp at this point so the cxxtests link
 		if test "$_debug_build" = yes; then
@@ -4637,9 +4638,6 @@ case $_backend in
 		# during linking stage
 		append_var LIBS "-lc -lgcc -lnosys"
 		;;
-	3ds)
-		append_var LIBS "-logg -lpng"
-		;;
 esac
 
 


Commit: 182d59b6a75fd09042f5ab5adbf23ee02452e3a8
    https://github.com/scummvm/scummvm/commit/182d59b6a75fd09042f5ab5adbf23ee02452e3a8
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:14+02:00

Commit Message:
3DS: Fix code styling, add license header, remove unused portdefs.h

Changed paths:
  R backends/platform/3ds/portdefs.h
    backends/platform/3ds/osystem-audio.cpp
    backends/platform/3ds/osystem-events.cpp
    backends/platform/3ds/osystem-graphics.cpp
    backends/platform/3ds/osystem.cpp
    backends/platform/3ds/shader.v.pica
    backends/platform/3ds/sprite.cpp



diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
index 7e4822b..da74ab6 100644
--- a/backends/platform/3ds/osystem-audio.cpp
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -25,9 +25,9 @@
 
 static bool hasAudio = false;
 
-static void audioThreadFunc(void* arg) {
-	Audio::MixerImpl *mixer = (Audio::MixerImpl *) arg;
-	OSystem_3DS *osys = (OSystem_3DS*)g_system;
+static void audioThreadFunc(void *arg) {
+	Audio::MixerImpl *mixer = (Audio::MixerImpl *)arg;
+	OSystem_3DS *osys = (OSystem_3DS *)g_system;
 
 	int i;
 	const int channel = 0;
@@ -40,7 +40,7 @@ static void audioThreadFunc(void* arg) {
 	uint32 time = lastTime;
 	ndspWaveBuf buffers[bufferCount];
 	
-	for(i = 0; i < bufferCount; ++i) {
+	for (i = 0; i < bufferCount; ++i) {
 		memset(&buffers[i], 0, sizeof(ndspWaveBuf));
 		buffers[i].data_vaddr = linearAlloc(bufferSize);
 		buffers[i].looping = false;
@@ -52,7 +52,7 @@ static void audioThreadFunc(void* arg) {
 	ndspChnSetRate(channel, sampleRate);
 	ndspChnSetFormat(channel, NDSP_FORMAT_STEREO_PCM16);
 
-	while(!osys->exiting) {		
+	while (!osys->exiting) {		
 		osys->delayMillis(100); // Note: Increasing the delay requires a bigger buffer
 		
 		time = osys->getMillis(true);
@@ -62,7 +62,7 @@ static void audioThreadFunc(void* arg) {
 		if (!osys->sleeping && sampleLen > 0) {
 			bufferIndex++;
 			bufferIndex %= bufferCount;
-			ndspWaveBuf* buf = &buffers[bufferIndex];
+			ndspWaveBuf *buf = &buffers[bufferIndex];
 		
 			buf->nsamples = mixer->mixCallback(buf->data_adpcm, sampleLen);
 			if (buf->nsamples > 0) {
@@ -72,7 +72,7 @@ static void audioThreadFunc(void* arg) {
 		}
 	}
 	
-	for(i = 0; i < bufferCount; ++i)
+	for (i = 0; i < bufferCount; ++i)
 		linearFree(buffers[i].data_pcm8);
 }
 
@@ -85,7 +85,7 @@ void OSystem_3DS::initAudio() {
 	if (hasAudio) {
 		s32 prio = 0;
 		svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
-		audioThread = threadCreate(&audioThreadFunc, _mixer, 32*1048, prio-1, -2, false);
+		audioThread = threadCreate(&audioThreadFunc, _mixer, 32 * 1048, prio - 1, -2, false);
 	}
 }
 
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
index 46efdd3..5135e3a 100644
--- a/backends/platform/3ds/osystem-events.cpp
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -20,30 +20,29 @@
  *
  */
 
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
 #include "backends/timer/default/default-timer.h"
-#include "backends/platform/3ds/gui.h"
+#include "gui.h"
 #include "osystem.h"
 
 static Common::Mutex *eventMutex;
 static InputMode inputMode = MODE_DRAG;
 static aptHookCookie cookie;
 
-static void pushEventQueue(Common::Queue<Common::Event>* queue, Common::Event& event) {
+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;
+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};
+	touchPosition lastTouch = {0, 0};
 	bool isRightClick = false;
 	Common::Event event;
 	
-	while(!osys->exiting) {
+	while (!osys->exiting) {
 		do {
 			osys->delayMillis(10);
 		} while (osys->sleeping && !osys->exiting);
@@ -69,23 +68,19 @@ static void eventThreadFunc(void* arg) {
 					event.type = isRightClick ? Common::EVENT_RBUTTONDOWN : Common::EVENT_LBUTTONDOWN;
 					pushEventQueue(eventQueue, event);
 				}
-			}
-			else if (touch.px != lastTouch.px || touch.py != lastTouch.py) {
+			} 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) {
+		} else if (keysReleased & KEY_TOUCH) {
 			event.mouse.x = lastTouch.px;
 			event.mouse.y = lastTouch.py;
-			printf("clicked %u, %u\n", lastTouch.px, lastTouch.py);
 			if (inputMode == MODE_DRAG) {
 				event.type = isRightClick ? Common::EVENT_RBUTTONUP : Common::EVENT_LBUTTONUP;
 				pushEventQueue(eventQueue, event);
-			}
-			else if (osys->getMillis() - touchStartTime < 200) {
+			} else if (osys->getMillis() - touchStartTime < 200) {
 				// Process click in MODE_HOVER
 				event.type = Common::EVENT_MOUSEMOVE;
 				pushEventQueue(eventQueue, event);
@@ -144,15 +139,15 @@ static void eventThreadFunc(void* arg) {
 			event.kbd.flags = 0;
 			pushEventQueue(eventQueue, event);
 		}
-
+		
 		// TODO: EVENT_PREDICTIVE_DIALOG
 		// EVENT_SCREEN_CHANGED
 	}
 }
 
-static void aptHookFunc(APT_HookType hookType, void* param) {
-	auto eventQueue = (Common::Queue<Common::Event>*) param;
-	OSystem_3DS* osys = (OSystem_3DS*) g_system;
+static void aptHookFunc(APT_HookType hookType, void *param) {
+	auto eventQueue = (Common::Queue<Common::Event> *)param;
+	OSystem_3DS *osys = (OSystem_3DS *)g_system;
 	Common::Event event;
 	
 	switch (hookType) {
@@ -174,8 +169,8 @@ static void aptHookFunc(APT_HookType hookType, void* param) {
 }
 
 static void timerThreadFunc(void *arg) {
-	OSystem_3DS* osys = (OSystem_3DS*) arg;
-	DefaultTimerManager *tm = (DefaultTimerManager *) osys->getTimerManager();
+	OSystem_3DS *osys = (OSystem_3DS *)arg;
+	DefaultTimerManager *tm = (DefaultTimerManager *)osys->getTimerManager();
 	while (!osys->exiting) {
 		tm->handler();
 		g_system->delayMillis(10);
@@ -187,8 +182,8 @@ 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);
+	_timerThread = threadCreate(&timerThreadFunc, this, 32 * 1024, prio - 1, -2, false);
+	_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 32 * 1024, prio - 1, -2, false);
 	
 	aptHook(&cookie, aptHookFunc, &_eventQueue);
 }
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 7ee4efa..0e50d2b 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -21,11 +21,9 @@
  *
  */
 
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
 #include "backends/platform/3ds/osystem.h"
 #include "backends/platform/3ds/shader_shbin.h"
-#include <common/rect.h>
-#include <algorithm>
+#include "common/rect.h"
 
 // Used to transfer the final rendered display to the framebuffer
 #define DISPLAY_TRANSFER_FLAGS                                                 \
@@ -62,7 +60,7 @@ void OSystem_3DS::initGraphics() {
 	_projectionLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "projection");
 	_modelviewLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "modelView");
 	
-	C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
+	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
@@ -70,7 +68,7 @@ void OSystem_3DS::initGraphics() {
 	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_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);
@@ -138,7 +136,7 @@ bool OSystem_3DS::setGraphicsMode(int mode) {
 }
 
 void OSystem_3DS::resetGraphicsScale() {
-	printf("resetGraphicsScale\n");
+	debug("resetGraphicsScale");
 }
 
 int OSystem_3DS::getGraphicsMode() const {
@@ -146,14 +144,14 @@ int OSystem_3DS::getGraphicsMode() const {
 }
 void OSystem_3DS::initSize(uint width, uint height,
                                    const Graphics::PixelFormat *format) {
-	printf("3ds initsize w:%d h:%d\n", width, height);
+	debug("3ds initsize w:%d h:%d", width, height);
 	_gameWidth = width;
 	_gameHeight = height;
 	_gameTexture.create(width, height, _pfGameTexture);
 	_overlay.create(getOverlayWidth(), getOverlayHeight(), _pfGameTexture);
 	
 	if (format) {
-		printf("pixelformat: %d %d %d %d %d\n", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());;
+		debug("pixelformat: %d %d %d %d %d", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());;
 		_pfGame = *format;
 	}
 
@@ -207,7 +205,6 @@ OSystem::TransactionError OSystem_3DS::endGFXTransaction() {
 }
 
 void OSystem_3DS::setPalette(const byte *colors, uint start, uint num) {
-// 	printf("setPalette\n");
 	assert(start + num <= 256);
 	memcpy(_palette + 3 * start, colors, 3 * num);
 	
@@ -217,7 +214,6 @@ void OSystem_3DS::setPalette(const byte *colors, uint start, uint num) {
 	}
 }
 void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) {
-// 	printf("grabPalette\n");
 	assert(start + num <= 256);
 	memcpy(colors, _palette + 3 * start, 3 * num);
 }
@@ -245,11 +241,9 @@ void OSystem_3DS::flushGameScreen() {
 }
 
 Graphics::Surface *OSystem_3DS::lockScreen() {
-	printf("lockScreen\n");
 	return &_gameScreen;
 }
 void OSystem_3DS::unlockScreen() {
-	printf("unlockScreen\n");
 	flushGameScreen();
 }
 
@@ -291,7 +285,7 @@ void OSystem_3DS::setShakePos(int shakeOffset) {
 }
 
 void OSystem_3DS::setFocusRectangle(const Common::Rect &rect) {
-// 	printf("setfocus: %d %d %d %d\n", rect.left, rect.top, rect.width(), rect.height());
+	debug("setfocus: %d %d %d %d", rect.left, rect.top, rect.width(), rect.height());
 	_focusRect = rect;
 	_focusDirty = true;
 	_focusClearTime = 0;
@@ -388,7 +382,7 @@ void OSystem_3DS::clearOverlay() {
 }
 
 void OSystem_3DS::grabOverlay(void *buf, int pitch) {
-	for(int y = 0; y < getOverlayHeight(); ++y) {
+	for (int y = 0; y < getOverlayHeight(); ++y) {
 		memcpy(buf, _overlay.getBasePtr(0, y), pitch);
 	}
 }
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index d3fc1c7..af0b7b5 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -20,7 +20,9 @@
  *
  */
 
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
 
 #include "osystem.h"
 
@@ -38,36 +40,37 @@
 #include <time.h>
 
 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),
-_showMessageOSD(false),
-_isFullscreen(false),
-_cursorVisible(false),
-_cursorScalable(false),
-_cursorPaletteEnabled(false),
-_cursorX(0),
-_cursorY(0),
-_cursorHotspotX(0),
-_cursorHotspotY(0),
-_gameX(0),
-_gameY(0),
-_gameWidth(320),
-_gameHeight(240),
-exiting(false),
-sleeping(false) {
+	_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),
+	_showMessageOSD(false),
+	_isFullscreen(false),
+	_cursorVisible(false),
+	_cursorScalable(false),
+	_cursorPaletteEnabled(false),
+	_cursorX(0),
+	_cursorY(0),
+	_cursorHotspotX(0),
+	_cursorHotspotY(0),
+	_gameX(0),
+	_gameY(0),
+	_gameWidth(320),
+	_gameHeight(240),
+	exiting(false),
+	sleeping(false)
+{
 	chdir("sdmc:/");
 	_fsFactory = new POSIXFilesystemFactory();
 	Posix::assureDirectoryExists("/3ds/scummvm/saves/");
@@ -133,18 +136,18 @@ void OSystem_3DS::getTimeAndDate(TimeDate& td) const {
 }
 
 OSystem::MutexRef OSystem_3DS::createMutex() {
-	RecursiveLock* mutex = new RecursiveLock();
+	RecursiveLock *mutex = new RecursiveLock();
 	RecursiveLock_Init(mutex);
 	return (OSystem::MutexRef) mutex;
 }
 void OSystem_3DS::lockMutex(MutexRef mutex) {
-	RecursiveLock_Lock((RecursiveLock *)mutex);
+	RecursiveLock_Lock((RecursiveLock*)mutex);
 }
 void OSystem_3DS::unlockMutex(MutexRef mutex) {
-	RecursiveLock_Unlock((RecursiveLock *)mutex);
+	RecursiveLock_Unlock((RecursiveLock*)mutex);
 }
 void OSystem_3DS::deleteMutex(MutexRef mutex) {
-	delete (RecursiveLock *)mutex;
+	delete (RecursiveLock*)mutex;
 }
 
 Common::String OSystem_3DS::getSystemLanguage() const {
diff --git a/backends/platform/3ds/portdefs.h b/backends/platform/3ds/portdefs.h
deleted file mode 100644
index f58cf5a..0000000
--- a/backends/platform/3ds/portdefs.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef _PORTDEFS_H_
-#define _PORTDEFS_H_
-
-#define LURE_CLICKABLE_MENUS
-
-#endif
diff --git a/backends/platform/3ds/shader.v.pica b/backends/platform/3ds/shader.v.pica
index a359768..2d18985 100644
--- a/backends/platform/3ds/shader.v.pica
+++ b/backends/platform/3ds/shader.v.pica
@@ -1,4 +1,23 @@
-; PICA200 vertex shader
+;* 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]
diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
index 0d5780e..a0aee38 100644
--- a/backends/platform/3ds/sprite.cpp
+++ b/backends/platform/3ds/sprite.cpp
@@ -19,9 +19,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  */
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
 #include "backends/platform/3ds/sprite.h"
-#include <algorithm>
+#include "common/util.h"
 #include <3ds.h>
 
 static uint nextHigher2(uint v) {
@@ -37,18 +37,18 @@ static uint nextHigher2(uint v) {
 }
 
 Sprite::Sprite()
-: dirtyPixels(true)
-, dirtyMatrix(true)
-, actualWidth(0)
-, actualHeight(0)
-, posX(0)
-, posY(0)
-, scaleX(1.f)
-, scaleY(1.f)
+	: 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);
+	vertices = (vertex *)linearAlloc(sizeof(vertex) * 4);
 }
 
 Sprite::~Sprite() {
@@ -61,8 +61,8 @@ void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f)
 	actualWidth = width;
 	actualHeight = height;
 	format = f;
-	w = std::max(nextHigher2(width), 64u);
-	h = std::max(nextHigher2(height), 64u);;
+	w = MAX(nextHigher2(width), 64u);
+	h = MAX(nextHigher2(height), 64u);;
 	pitch = w * format.bytesPerPixel;
 	dirtyPixels = true;
 
@@ -110,7 +110,7 @@ void Sprite::render() {
 	}
 	C3D_TexBind(0, &texture);
 
-	C3D_BufInfo* bufInfo = C3D_GetBufInfo();
+	C3D_BufInfo *bufInfo = C3D_GetBufInfo();
 	BufInfo_Init(bufInfo);
 	BufInfo_Add(bufInfo, vertices, sizeof(vertex), 2, 0x10);
 	C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);


Commit: 8d37ac81b0bf76ad7912cf4f08dcf153dd587011
    https://github.com/scummvm/scummvm/commit/8d37ac81b0bf76ad7912cf4f08dcf153dd587011
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:14+02:00

Commit Message:
3DS: Add README

Changed paths:
  A backends/platform/3ds/README



diff --git a/backends/platform/3ds/README b/backends/platform/3ds/README
new file mode 100644
index 0000000..516e694
--- /dev/null
+++ b/backends/platform/3ds/README
@@ -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.


Commit: 4eb7fc13144b2e63fe15663ef23060807ae59e22
    https://github.com/scummvm/scummvm/commit/4eb7fc13144b2e63fe15663ef23060807ae59e22
Author: Thomas Edvalson (machin3 at gmail.com)
Date: 2016-05-17T19:36:14+02:00

Commit Message:
3DS: Add config class/dialog, c-pad cursor control, and option to disable screens

Changed paths:
  A backends/platform/3ds/config.cpp
  A backends/platform/3ds/config.h
  A backends/platform/3ds/options-dialog.cpp
  A backends/platform/3ds/options-dialog.h
    backends/platform/3ds/app/scummvm.rsf
    backends/platform/3ds/main.cpp
    backends/platform/3ds/module.mk
    backends/platform/3ds/osystem-audio.cpp
    backends/platform/3ds/osystem-events.cpp
    backends/platform/3ds/osystem-graphics.cpp
    backends/platform/3ds/osystem.cpp
    backends/platform/3ds/osystem.h



diff --git a/backends/platform/3ds/app/scummvm.rsf b/backends/platform/3ds/app/scummvm.rsf
index d403bdb..a451894 100644
--- a/backends/platform/3ds/app/scummvm.rsf
+++ b/backends/platform/3ds/app/scummvm.rsf
@@ -170,6 +170,7 @@ AccessControlInfo:
    - soc:U
    - ssl:C
    - y2r:u
+   - gsp::Lcd
 
 
 SystemControlInfo:
diff --git a/backends/platform/3ds/config.cpp b/backends/platform/3ds/config.cpp
new file mode 100644
index 0000000..117b979
--- /dev/null
+++ b/backends/platform/3ds/config.cpp
@@ -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
diff --git a/backends/platform/3ds/config.h b/backends/platform/3ds/config.h
new file mode 100644
index 0000000..c8b7573
--- /dev/null
+++ b/backends/platform/3ds/config.h
@@ -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
diff --git a/backends/platform/3ds/main.cpp b/backends/platform/3ds/main.cpp
index 4b5dbbb..6cc2c5c 100644
--- a/backends/platform/3ds/main.cpp
+++ b/backends/platform/3ds/main.cpp
@@ -20,8 +20,6 @@
  *
  */
 
-#define FORBIDDEN_SYMBOL_ALLOW_ALL
-
 #include "osystem.h"
 #include <3ds.h>
 
@@ -32,7 +30,7 @@ int main(int argc, char *argv[]) {
 	osSetSpeedupEnable(true);
 // 	consoleInit(GFX_TOP, NULL);
 
-	g_system = new OSystem_3DS();
+	g_system = new _3DS::OSystem_3DS();
 	assert(g_system);
 
 	// Invoke the actual ScummVM main entry point
@@ -42,8 +40,14 @@ int main(int argc, char *argv[]) {
 // 		res = scummvm_main(argc, argv);
 	scummvm_main(0, nullptr);
 
-	delete dynamic_cast<OSystem_3DS*>(g_system);
-
+	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;
diff --git a/backends/platform/3ds/module.mk b/backends/platform/3ds/module.mk
index 9c1e26b..3eb15ae 100644
--- a/backends/platform/3ds/module.mk
+++ b/backends/platform/3ds/module.mk
@@ -5,6 +5,8 @@ MODULE_OBJS := \
 	shader.shbin.o \
 	sprite.o \
 	gui.o \
+	config.o \
+	options-dialog.o \
 	osystem.o \
 	osystem-graphics.o \
 	osystem-audio.o \
diff --git a/backends/platform/3ds/options-dialog.cpp b/backends/platform/3ds/options-dialog.cpp
new file mode 100644
index 0000000..0f8bfd0
--- /dev/null
+++ b/backends/platform/3ds/options-dialog.cpp
@@ -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
diff --git a/backends/platform/3ds/options-dialog.h b/backends/platform/3ds/options-dialog.h
new file mode 100644
index 0000000..6673b88
--- /dev/null
+++ b/backends/platform/3ds/options-dialog.h
@@ -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
diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
index da74ab6..17e419c 100644
--- a/backends/platform/3ds/osystem-audio.cpp
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -23,6 +23,8 @@
 #include "osystem.h"
 #include "audio/mixer.h"
 
+namespace _3DS {
+
 static bool hasAudio = false;
 
 static void audioThreadFunc(void *arg) {
@@ -104,3 +106,5 @@ Audio::Mixer *OSystem_3DS::getMixer() {
 	assert(_mixer);
 	return _mixer;
 }
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
index 5135e3a..ae8a9b8 100644
--- a/backends/platform/3ds/osystem-events.cpp
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -21,12 +21,20 @@
  */
 
 #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);
@@ -40,6 +48,12 @@ static void eventThreadFunc(void *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) {
@@ -49,12 +63,35 @@ static void eventThreadFunc(void *arg) {
 		
 		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);
@@ -89,7 +126,24 @@ static void eventThreadFunc(void *arg) {
 				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;
@@ -99,22 +153,24 @@ static void eventThreadFunc(void *arg) {
 				osys->displayMessageOnOSD("Drag Mode");
 			}
 		}
-		if (keysPressed & KEY_A || keysPressed & KEY_DLEFT) {
+		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;
-			event.type = Common::EVENT_LBUTTONDOWN;
-			pushEventQueue(eventQueue, event);
-			event.type = Common::EVENT_LBUTTONUP;
+			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) {
+		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;
-			event.type = Common::EVENT_RBUTTONDOWN;
-			pushEventQueue(eventQueue, event);
-			event.type = Common::EVENT_RBUTTONUP;
+			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) {
@@ -126,8 +182,8 @@ static void eventThreadFunc(void *arg) {
 			pushEventQueue(eventQueue, event);
 		}
 		if (keysPressed & KEY_SELECT) {
-			event.type = Common::EVENT_RTL;
-			pushEventQueue(eventQueue, event);
+			if (!optionMenuOpened)
+				optionMenuOpening = true;
 		}
 		if (keysPressed & KEY_B || keysReleased & KEY_B || keysPressed & KEY_DDOWN || keysReleased & KEY_DDOWN) {
 			if (keysPressed & KEY_B || keysPressed & KEY_DDOWN)
@@ -146,25 +202,32 @@ static void eventThreadFunc(void *arg) {
 }
 
 static void aptHookFunc(APT_HookType hookType, void *param) {
-	auto eventQueue = (Common::Queue<Common::Event> *)param;
 	OSystem_3DS *osys = (OSystem_3DS *)g_system;
-	Common::Event event;
 	
 	switch (hookType) {
 		case APTHOOK_ONSUSPEND:
 		case APTHOOK_ONSLEEP:
-			event.type = Common::EVENT_MAINMENU;
-			pushEventQueue(eventQueue, event);
+			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:
+		default: {
+			Common::StackLock lock(*eventMutex);
+			Common::Event event;
 			event.type = Common::EVENT_QUIT;
-			pushEventQueue(eventQueue, event);
-			break;
+			g_system->getEventManager()->pushEvent(event);
+		}
 	}
 }
 
@@ -172,9 +235,8 @@ static void timerThreadFunc(void *arg) {
 	OSystem_3DS *osys = (OSystem_3DS *)arg;
 	DefaultTimerManager *tm = (DefaultTimerManager *)osys->getTimerManager();
 	while (!osys->exiting) {
-		tm->handler();
 		g_system->delayMillis(10);
-		aptMainLoop(); // Call apt hook when necessary
+		tm->handler();
 	}
 }
 
@@ -185,7 +247,7 @@ void OSystem_3DS::initEvents() {
 	_timerThread = threadCreate(&timerThreadFunc, this, 32 * 1024, prio - 1, -2, false);
 	_eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 32 * 1024, prio - 1, -2, false);
 	
-	aptHook(&cookie, aptHookFunc, &_eventQueue);
+	aptHook(&cookie, aptHookFunc, this);
 }
 
 void OSystem_3DS::destroyEvents() {
@@ -199,21 +261,33 @@ void OSystem_3DS::destroyEvents() {
 
 void OSystem_3DS::transformPoint(touchPosition &point) {
 	if (!_overlayVisible) {
-		point.px = static_cast<float>(point.px) / _gameTexture.getScaleX() - _gameX;
-		point.py = static_cast<float>(point.py) / _gameTexture.getScaleY() - _gameY;
+		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;
+	messageOSD = msg;
+	showMessageOSD = true;
 }
 
 bool OSystem_3DS::pollEvent(Common::Event &event) {
-	if (_showMessageOSD) {
-		_showMessageOSD = false;
-		StatusMessageDialog dialog(_messageOSD, 800);
+	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);
@@ -224,3 +298,5 @@ bool OSystem_3DS::pollEvent(Common::Event &event) {
 	event = _eventQueue.pop();
 	return true;
 }
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index 0e50d2b..0cfd70c 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -24,6 +24,8 @@
 #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                                                 \
@@ -32,6 +34,8 @@
 	 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);
@@ -79,7 +83,8 @@ void OSystem_3DS::initGraphics() {
 
 void OSystem_3DS::destroyGraphics() {
 	_gameScreen.free();
-	_gameTexture.free();
+	_gameTopTexture.free();
+	_gameBottomTexture.free();
 	_overlay.free();
 
 	shaderProgramFree(&_program);
@@ -92,16 +97,12 @@ void OSystem_3DS::destroyGraphics() {
 }
 
 bool OSystem_3DS::hasFeature(OSystem::Feature f) {
-	return (f == OSystem::kFeatureFullscreenMode ||
-	        f == OSystem::kFeatureCursorPalette ||
+	return (f == OSystem::kFeatureCursorPalette ||
 	        f == OSystem::kFeatureOverlaySupportsAlpha);
 }
 
 void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {
 	switch (f) {
-	case OSystem::kFeatureFullscreenMode:
-		_isFullscreen = enable;
-		break;
 	case OSystem::kFeatureCursorPalette:
 		_cursorPaletteEnabled = enable;
 		flushCursor();
@@ -113,8 +114,6 @@ void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {
 
 bool OSystem_3DS::getFeatureState(OSystem::Feature f) {
 	switch (f) {
-	case OSystem::kFeatureFullscreenMode:
-		return _isFullscreen;
 	case OSystem::kFeatureCursorPalette:
 		return _cursorPaletteEnabled;
 	default:
@@ -147,7 +146,7 @@ void OSystem_3DS::initSize(uint width, uint height,
 	debug("3ds initsize w:%d h:%d", width, height);
 	_gameWidth = width;
 	_gameHeight = height;
-	_gameTexture.create(width, height, _pfGameTexture);
+	_gameTopTexture.create(width, height, _pfGameTexture);
 	_overlay.create(getOverlayWidth(), getOverlayHeight(), _pfGameTexture);
 	
 	if (format) {
@@ -160,30 +159,48 @@ void OSystem_3DS::initSize(uint width, uint height,
 	_focusDirty = true;
 	_focusRect = Common::Rect(_gameWidth, _gameHeight);
 
-	if (_isFullscreen) {
-		_gameRatio = 320.f / 240.f;
-		_gameX = _gameY = 0;
-		_gameTexture.setScale(320.f / width, 240.f / height);
+	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 {
-		_gameRatio = static_cast<float>(width) / height;
-		if (width > height) {
-			_gameX = 0;
-			_gameY = (240.f - 320.f / width * height) / 2.f;
+		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 {
-			_gameY = 0;
-			_gameX = (320.f - 240.f / height * width) / 2.f;
+			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;
 		}
-		_gameTexture.setScale((width > 320) ? 320.f / width : 1.f,
-		                      (height > 240) ? 240.f / height : 1.f);
 	}
-	_gameTexture.setPosition(_gameX, _gameY);
-	_cursorTexture.setScale(_gameTexture.getScaleX(), _gameTexture.getScaleY());
-	
-	float ratio = 400.f / _gameWidth;
-	int y = (_gameHeight * ratio - 240.f) / 2;
-	Mtx_Identity(&_focusMatrix);
-	Mtx_Translate(&_focusMatrix, 0, -y, 0);
-	Mtx_Scale(&_focusMatrix, ratio, ratio, 1.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 {
@@ -225,17 +242,17 @@ void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
 	Graphics::Surface subSurface = _gameScreen.getSubArea(rect);
 	
 	Graphics::Surface *convertedSubSurface = subSurface.convertTo(_pfGameTexture, _palette);
-	_gameTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
+	_gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
 	
 	convertedSubSurface->free();
 	delete convertedSubSurface;
-	_gameTexture.markDirty();
+	_gameTopTexture.markDirty();
 }
 
 void OSystem_3DS::flushGameScreen() {
 	Graphics::Surface *converted = _gameScreen.convertTo(_pfGameTexture, _palette);
-	_gameTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
-	_gameTexture.markDirty();
+	_gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+	_gameTopTexture.markDirty();
 	converted->free();
 	delete converted;
 }
@@ -257,23 +274,36 @@ void OSystem_3DS::updateScreen() {
 	C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
 		// Render top screen
 		C3D_FrameDrawOn(_renderTargetTop);
-		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionTop);
-		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, &_focusMatrix);
-		_gameTexture.render();
-		_gameTexture.render();
+		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);
-		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionBottom);
-		C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameTexture.getMatrix());
-		_gameTexture.render();
-		if (_overlayVisible) {
-			C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
-			_overlay.render();
-		}
-		if (_cursorVisible) {
-			C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _cursorTexture.getMatrix());
-			_cursorTexture.render();
+		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);
 }
@@ -281,7 +311,8 @@ void OSystem_3DS::updateScreen() {
 void OSystem_3DS::setShakePos(int shakeOffset) {
 	// TODO: implement this in overlay, top screen, and mouse too
 	_screenShakeOffset = shakeOffset;
-	_gameTexture.setPosition(_gameX, _gameY + shakeOffset);
+	_gameTopTexture.setPosition(_gameTopX, _gameTopY + _gameTopTexture.getScaleY() * shakeOffset);
+	_gameBottomTexture.setPosition(_gameBottomX, _gameBottomY + _gameBottomTexture.getScaleY() * shakeOffset);
 }
 
 void OSystem_3DS::setFocusRectangle(const Common::Rect &rect) {
@@ -363,13 +394,13 @@ void OSystem_3DS::updateFocus() {
 
 void OSystem_3DS::showOverlay() {
 	_overlayVisible = true;
-	_cursorTexture.setScale(1.f, 1.f);
+	updateSize();
 	updateScreen();
 }
 
 void OSystem_3DS::hideOverlay() {
 	_overlayVisible = false;
-	_cursorTexture.setScale(_gameTexture.getScaleX(), _gameTexture.getScaleY());
+	updateSize();
 	updateScreen();
 }
 
@@ -410,9 +441,25 @@ bool OSystem_3DS::showMouse(bool visible) {
 void OSystem_3DS::warpMouse(int x, int y) {
 	_cursorX = x;
 	_cursorY = y;
+	warning("x:%d y:%d", x, y);
 	// TODO: adjust for _cursorScalable ?
-	_cursorTexture.setPosition(x - _cursorHotspotX + (_overlayVisible ? 0 : _gameX),
-							   y - _cursorHotspotY + (_overlayVisible ? 0 : _gameY));
+	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,
@@ -466,3 +513,5 @@ void OSystem_3DS::flushCursor() {
 		}
 	}
 }
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
index af0b7b5..f6278eb 100644
--- a/backends/platform/3ds/osystem.cpp
+++ b/backends/platform/3ds/osystem.cpp
@@ -33,12 +33,15 @@
 #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)),
@@ -55,19 +58,20 @@ OSystem_3DS::OSystem_3DS():
 	_focusStepScaleX(0.f),
 	_focusStepScaleY(0.f),
 	_focusClearTime(0),
-	_showMessageOSD(false),
-	_isFullscreen(false),
+	_cursorPaletteEnabled(false),
 	_cursorVisible(false),
 	_cursorScalable(false),
-	_cursorPaletteEnabled(false),
 	_cursorX(0),
 	_cursorY(0),
 	_cursorHotspotX(0),
 	_cursorHotspotY(0),
-	_gameX(0),
-	_gameY(0),
+	_gameTopX(0),
+	_gameTopY(0),
+	_gameBottomX(0),
+	_gameBottomY(0),
 	_gameWidth(320),
 	_gameHeight(240),
+	_overlayVisible(false),
 	exiting(false),
 	sleeping(false)
 {
@@ -91,6 +95,7 @@ void OSystem_3DS::quit() {
 }
 
 void OSystem_3DS::initBackend() {
+	loadConfig();
 	ConfMan.registerDefault("fullscreen", true);
 	ConfMan.registerDefault("aspect_ratio", true);
 	if (!ConfMan.hasKey("vkeybd_pack_name"))
@@ -111,6 +116,13 @@ void OSystem_3DS::initBackend() {
 	EventsBaseBackend::initBackend();
 }
 
+void OSystem_3DS::updateConfig() {
+	if (_gameScreen.getPixels()) {
+		updateSize();
+		warpMouse(_cursorX, _cursorY);
+	}
+}
+
 Common::String OSystem_3DS::getDefaultConfigFileName() {
 	return "/3ds/scummvm/scummvm.ini";
 }
@@ -177,3 +189,5 @@ void OSystem_3DS::fatalError() {
 void OSystem_3DS::logMessage(LogMessageType::Type type, const char *message) {
 	printf("3DS log: %s\n", message);
 }
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
index a8c2a90..478085a 100644
--- a/backends/platform/3ds/osystem.h
+++ b/backends/platform/3ds/osystem.h
@@ -35,7 +35,9 @@
 #include "common/queue.h"
 
 #define TICKS_PER_MSEC 268123
-	
+
+namespace _3DS {
+
 enum {
 	GFX_LINEAR = 0,
 	GFX_NEAREST = 1
@@ -54,7 +56,7 @@ static const OSystem::GraphicsMode s_graphicsModes[] = {
 class OSystem_3DS : public EventsBaseBackend, public PaletteManager {
 public:
 	OSystem_3DS();
-	~OSystem_3DS();
+	virtual ~OSystem_3DS();
 	
 	volatile bool exiting;
 	volatile bool sleeping;
@@ -130,9 +132,14 @@ public:
 	                    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();
@@ -150,8 +157,8 @@ protected:
 	
 private:
 	u16 _gameWidth, _gameHeight;
-	u16 _gameX, _gameY;
-	float _gameRatio;
+	u16 _gameTopX, _gameTopY;
+	u16 _gameBottomX, _gameBottomY;
 	
 	// Audio
 	Thread audioThread;
@@ -164,12 +171,12 @@ private:
 	byte _cursorPalette[3 * 256];
 	
 	Graphics::Surface _gameScreen;
-	Sprite _gameTexture;
+	Sprite _gameTopTexture;
+	Sprite _gameBottomTexture;
 	Sprite _overlay;
 	
 	int _screenShakeOffset;
 	bool _overlayVisible;
-	bool _isFullscreen;
 	
 	DVLB_s *_dvlb;
 	shaderProgram_s _program;
@@ -196,9 +203,6 @@ private:
 	Thread _eventThread;
 	Thread _timerThread;
 	Common::Queue<Common::Event> _eventQueue;
-
-	Common::String _messageOSD;
-	bool _showMessageOSD;
 	
 	// Cursor
 	Graphics::Surface _cursor;
@@ -206,9 +210,12 @@ private:
 	bool _cursorPaletteEnabled;
 	bool _cursorVisible;
 	bool _cursorScalable;
-	int _cursorX, _cursorY;
+	float _cursorX, _cursorY;
+	float _cursorDeltaX, _cursorDeltaY;
 	int _cursorHotspotX, _cursorHotspotY;
 	uint32 _cursorKeyColor;
 };
 
+} // namespace _3DS
+
 #endif


Commit: 5f95868576d36bfca321e4ce00934095e7657c5d
    https://github.com/scummvm/scummvm/commit/5f95868576d36bfca321e4ce00934095e7657c5d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-17T19:36:29+02:00

Commit Message:
CREDITS: Add Lubomyr to Android porters

Changed paths:
    AUTHORS
    devtools/credits.pl
    gui/credits.h



diff --git a/AUTHORS b/AUTHORS
index 22d6e37..c9be8da 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -281,6 +281,7 @@ ScummVM Team
     Android:
        Andre Heider
        Angus Lees
+       Lubomyr Lisen
 
     Dreamcast:
        Marcus Comstedt
diff --git a/devtools/credits.pl b/devtools/credits.pl
index 9e0fcc6..d9c8bf6 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -817,6 +817,7 @@ begin_credits("Credits");
 			begin_section("Android");
 				add_person("Andre Heider", "dhewg", "");
 				add_person("Angus Lees", "Gus", "");
+				add_person("Lubomyr Lisen", "", "");
 			end_section();
 
 			begin_section("Dreamcast");
@@ -844,7 +845,7 @@ begin_credits("Credits");
 				add_person("Frantisek Dufka", "fanoush", "(retired)");
 				add_person("Tarek Soliman", "tsoliman", "");
 			end_section();
-			
+
 			begin_section("Nintendo 3DS");
 				add_person("Thomas Edvalson", "Cruel", "");
 			end_section();
diff --git a/gui/credits.h b/gui/credits.h
index a560209..874a793 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -343,6 +343,7 @@ static const char *credits[] = {
 "C1""Android",
 "C0""Andre Heider",
 "C0""Angus Lees",
+"C0""Lubomyr Lisen",
 "",
 "C1""Dreamcast",
 "C0""Marcus Comstedt",


Commit: 64fd77d91a5abfefafb88a7d99a463bf8d8af271
    https://github.com/scummvm/scummvm/commit/64fd77d91a5abfefafb88a7d99a463bf8d8af271
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-17T19:37:17+02:00

Commit Message:
NEWS: Mention 3DS port

Changed paths:
    NEWS



diff --git a/NEWS b/NEWS
index 041e73c..b46ff10 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@ For a more comprehensive changelog of the latest experimental code, see:
         https://github.com/scummvm/scummvm/commits/
 
 1.8.1 (2016-05-25)
+ New ports:
+   - Added Nintendo 3DS port.
+
  General:
    - Removed TESTING flag from several supported games.
    - Added Chinese Pinyin translation.






More information about the Scummvm-git-logs mailing list