From e2b9572a83badb7084f5b54e1a7e108af8e327f6 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Wed, 6 Apr 2016 02:12:02 -0400 Subject: 3DS: Initial commit --- backends/platform/3ds/3ds.mk | 53 ++++ backends/platform/3ds/gui.cpp | 46 +++ backends/platform/3ds/gui.h | 41 +++ backends/platform/3ds/icon.png | Bin 0 -> 3800 bytes backends/platform/3ds/main.cpp | 50 ++++ backends/platform/3ds/module.mk | 16 + backends/platform/3ds/osystem-audio.cpp | 107 +++++++ backends/platform/3ds/osystem-events.cpp | 194 ++++++++++++ backends/platform/3ds/osystem-graphics.cpp | 465 +++++++++++++++++++++++++++++ backends/platform/3ds/osystem.cpp | 173 +++++++++++ backends/platform/3ds/osystem.h | 210 +++++++++++++ backends/platform/3ds/portdefs.h | 28 ++ backends/platform/3ds/shader.v.pica | 40 +++ backends/platform/3ds/sprite.cpp | 144 +++++++++ backends/platform/3ds/sprite.h | 71 +++++ 15 files changed, 1638 insertions(+) create mode 100644 backends/platform/3ds/3ds.mk create mode 100644 backends/platform/3ds/gui.cpp create mode 100644 backends/platform/3ds/gui.h create mode 100644 backends/platform/3ds/icon.png create mode 100644 backends/platform/3ds/main.cpp create mode 100644 backends/platform/3ds/module.mk create mode 100644 backends/platform/3ds/osystem-audio.cpp create mode 100644 backends/platform/3ds/osystem-events.cpp create mode 100644 backends/platform/3ds/osystem-graphics.cpp create mode 100644 backends/platform/3ds/osystem.cpp create mode 100644 backends/platform/3ds/osystem.h create mode 100644 backends/platform/3ds/portdefs.h create mode 100644 backends/platform/3ds/shader.v.pica create mode 100644 backends/platform/3ds/sprite.cpp create mode 100644 backends/platform/3ds/sprite.h (limited to 'backends/platform') diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk new file mode 100644 index 0000000000..bd8e743e14 --- /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 0000000000..0883d5a102 --- /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 0000000000..66c6547139 --- /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 0000000000..07022fbac1 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 0000000000..4b5dbbbbd2 --- /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(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 0000000000..9c1e26b181 --- /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 0000000000..7ff788b430 --- /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 0000000000..a4ce92c394 --- /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* 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*) 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(point.px) / _gameTexture.getScaleX() - _gameX; + point.py = static_cast(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 0000000000..5e70dced73 --- /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 +#include + +// 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(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 OSystem_3DS::getSupportedFormats() const { + Common::List 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 0000000000..fa2980a361 --- /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 +#include + +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 0000000000..98d9ad0cb6 --- /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 +#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 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 _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 0000000000..f58cf5a675 --- /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 0000000000..a359768218 --- /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 0000000000..d779fa40ff --- /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 +#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 0000000000..6d88ae4ce1 --- /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 +#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 -- cgit v1.2.3 From f5d73cac8a2d21962ed34b18de5aee36c2bce9ad Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Mon, 11 Apr 2016 15:15:42 -0400 Subject: 3DS: Add CIA format build, add timer handler thread, fix APT service suspending/sleeping/exiting --- backends/platform/3ds/3ds.mk | 21 ++- backends/platform/3ds/app/banner.png | Bin 0 -> 19241 bytes backends/platform/3ds/app/banner.wav | Bin 0 -> 2212 bytes backends/platform/3ds/app/icon.png | Bin 0 -> 3800 bytes backends/platform/3ds/app/scummvm.rsf | 218 +++++++++++++++++++++++++++++ backends/platform/3ds/icon.png | Bin 3800 -> 0 bytes backends/platform/3ds/osystem-audio.cpp | 17 ++- backends/platform/3ds/osystem-events.cpp | 55 ++++++-- backends/platform/3ds/osystem-graphics.cpp | 11 +- backends/platform/3ds/osystem.cpp | 9 +- backends/platform/3ds/osystem.h | 4 + 11 files changed, 308 insertions(+), 27 deletions(-) create mode 100644 backends/platform/3ds/app/banner.png create mode 100644 backends/platform/3ds/app/banner.wav create mode 100644 backends/platform/3ds/app/icon.png create mode 100644 backends/platform/3ds/app/scummvm.rsf delete mode 100644 backends/platform/3ds/icon.png (limited to 'backends/platform') diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk index bd8e743e14..7ab58995f6 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 0000000000..a3b02150ec 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 0000000000..e0b684b62f 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 0000000000..07022fbac1 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 0000000000..d403bdbe91 --- /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, : + 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. + # : + 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 07022fbac1..0000000000 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 7ff788b430..7e4822b8e9 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 a4ce92c394..46efdd3b7a 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* 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*) 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 5e70dced73..7ee4efa0a5 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 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 fa2980a361..d3fc1c7136 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 98d9ad0cb6..a8c2a909f1 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 _eventQueue; Common::String _messageOSD; -- cgit v1.2.3 From a0cc562f1f8cbf51fb92d0f230c2d7fb0274090d Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Mon, 11 Apr 2016 15:21:58 -0400 Subject: 3DS: Use linear GPU texture downscaling for better legibility in hi-res games --- backends/platform/3ds/sprite.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/platform') diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp index d779fa40ff..0d5780ef12 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(); } -- cgit v1.2.3 From e8dcfc3a4efeeaffad0380e88223fabbc12e1423 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Tue, 19 Apr 2016 03:22:32 -0400 Subject: 3DS: Fix code styling, add license header, remove unused portdefs.h --- backends/platform/3ds/osystem-audio.cpp | 16 +++---- backends/platform/3ds/osystem-events.cpp | 41 ++++++++--------- backends/platform/3ds/osystem-graphics.cpp | 22 ++++----- backends/platform/3ds/osystem.cpp | 73 ++++++++++++++++-------------- backends/platform/3ds/portdefs.h | 28 ------------ backends/platform/3ds/shader.v.pica | 21 ++++++++- backends/platform/3ds/sprite.cpp | 28 ++++++------ 7 files changed, 106 insertions(+), 123 deletions(-) delete mode 100644 backends/platform/3ds/portdefs.h (limited to 'backends/platform') diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp index 7e4822b8e9..da74ab6d8a 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 46efdd3b7a..5135e3ac1b 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* queue, Common::Event& event) { +static void pushEventQueue(Common::Queue *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*) arg; +static void eventThreadFunc(void *arg) { + OSystem_3DS *osys = (OSystem_3DS *)g_system; + auto eventQueue = (Common::Queue *)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*) param; - OSystem_3DS* osys = (OSystem_3DS*) g_system; +static void aptHookFunc(APT_HookType hookType, void *param) { + auto eventQueue = (Common::Queue *)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 7ee4efa0a5..0e50d2b911 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 -#include +#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 d3fc1c7136..af0b7b5700 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 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 f58cf5a675..0000000000 --- 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 a359768218..2d18985622 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 0d5780ef12..a0aee385a9 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 +#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); -- cgit v1.2.3 From bfb9ecec3573ed07bc9639426efd8289d05e00a6 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Tue, 19 Apr 2016 14:52:58 -0400 Subject: 3DS: Add README --- backends/platform/3ds/README | 185 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 backends/platform/3ds/README (limited to 'backends/platform') diff --git a/backends/platform/3ds/README b/backends/platform/3ds/README new file mode 100644 index 0000000000..516e694f64 --- /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. -- cgit v1.2.3 From 1531b4ddbf685f22970b7365515318b847e4f4f3 Mon Sep 17 00:00:00 2001 From: Thomas Edvalson Date: Fri, 22 Apr 2016 16:43:59 -0400 Subject: 3DS: Add config class/dialog, c-pad cursor control, and option to disable screens --- backends/platform/3ds/app/scummvm.rsf | 1 + backends/platform/3ds/config.cpp | 87 ++++++++++++++++ backends/platform/3ds/config.h | 45 +++++++++ backends/platform/3ds/main.cpp | 14 ++- backends/platform/3ds/module.mk | 2 + backends/platform/3ds/options-dialog.cpp | 98 ++++++++++++++++++ backends/platform/3ds/options-dialog.h | 70 +++++++++++++ backends/platform/3ds/osystem-audio.cpp | 4 + backends/platform/3ds/osystem-events.cpp | 130 +++++++++++++++++++----- backends/platform/3ds/osystem-graphics.cpp | 153 +++++++++++++++++++---------- backends/platform/3ds/osystem.cpp | 24 ++++- backends/platform/3ds/osystem.h | 27 +++-- 12 files changed, 556 insertions(+), 99 deletions(-) create mode 100644 backends/platform/3ds/config.cpp create mode 100644 backends/platform/3ds/config.h create mode 100644 backends/platform/3ds/options-dialog.cpp create mode 100644 backends/platform/3ds/options-dialog.h (limited to 'backends/platform') diff --git a/backends/platform/3ds/app/scummvm.rsf b/backends/platform/3ds/app/scummvm.rsf index d403bdbe91..a4518949bb 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 0000000000..117b979d9f --- /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 0000000000..c8b75736ad --- /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 4b5dbbbbd2..6cc2c5cf5d 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(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 9c1e26b181..3eb15aef81 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 0000000000..0f8bfd0c66 --- /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 0000000000..6673b88e7b --- /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 da74ab6d8a..17e419c36d 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 5135e3ac1b..ae8a9b8b2b 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 *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 *)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(point.px) / _gameTexture.getScaleX() - _gameX; - point.py = static_cast(point.py) / _gameTexture.getScaleY() - _gameY; + point.px = static_cast(point.px) / _gameBottomTexture.getScaleX() - _gameBottomX; + point.py = static_cast(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 0e50d2b911..0cfd70c9cd 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(width) / height; - if (width > height) { - _gameX = 0; - _gameY = (240.f - 320.f / width * height) / 2.f; + float ratio = static_cast(_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 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 af0b7b5700..f6278eb16b 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 #include +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 a8c2a909f1..478085acba 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 _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 -- cgit v1.2.3