├── .gitignore ├── LICENSE.txt ├── README.md ├── libstarlight ├── Makefile ├── source │ └── starlight │ │ ├── Application.cpp │ │ ├── Application.h │ │ ├── ConfigManager.cpp │ │ ├── ConfigManager.h │ │ ├── GFXManager.cpp │ │ ├── GFXManager.h │ │ ├── InputManager.cpp │ │ ├── InputManager.h │ │ ├── ThemeManager.cpp │ │ ├── ThemeManager.h │ │ ├── _global.h │ │ ├── _incLib │ │ ├── _stringfix.h │ │ ├── json.hpp │ │ ├── json_extensions.hpp │ │ ├── json_fwd.hpp │ │ ├── lodepng.cpp │ │ └── lodepng.h │ │ ├── datatypes │ │ ├── Color.cpp │ │ ├── Color.h │ │ ├── OptRef.h │ │ ├── Optional.h │ │ ├── VRect.cpp │ │ ├── VRect.h │ │ ├── Vector2.cpp │ │ └── Vector2.h │ │ ├── dialog │ │ ├── Backdrop.cpp │ │ ├── Backdrop.h │ │ ├── MessageBox.cpp │ │ ├── MessageBox.h │ │ ├── OSK.cpp │ │ ├── OSK.h │ │ └── osk │ │ │ ├── InputHandler.cpp │ │ │ └── InputHandler.h │ │ ├── gfx │ │ ├── BitmapFont.cpp │ │ ├── BitmapFont.h │ │ ├── DisplayList.cpp │ │ ├── DisplayList.h │ │ ├── DrawContext.cpp │ │ ├── DrawContext.h │ │ ├── DrawContextCanvas.cpp │ │ ├── DrawContextCanvas.h │ │ ├── DrawContextTopScreen.cpp │ │ ├── DrawContextTopScreen.h │ │ ├── DrawContextTouchscreen.cpp │ │ ├── DrawContextTouchscreen.h │ │ ├── Drawable.cpp │ │ ├── Drawable.h │ │ ├── DrawableImage.cpp │ │ ├── DrawableImage.h │ │ ├── DrawableNinePatch.cpp │ │ ├── DrawableNinePatch.h │ │ ├── DrawableTest.cpp │ │ ├── DrawableTest.h │ │ ├── Enums.h │ │ ├── Font.cpp │ │ ├── Font.h │ │ ├── FontBMF.cpp │ │ ├── FontBMF.h │ │ ├── FontNull.h │ │ ├── RenderCore.cpp │ │ ├── RenderCore.h │ │ ├── ThemeRef.h │ │ └── basic_shader.v.pica │ │ ├── threading │ │ ├── Thread.cpp │ │ └── Thread.h │ │ ├── ui │ │ ├── Button.cpp │ │ ├── Button.h │ │ ├── DebugConsole.cpp │ │ ├── DebugConsole.h │ │ ├── DrawLayerProxy.cpp │ │ ├── DrawLayerProxy.h │ │ ├── Form.cpp │ │ ├── Form.h │ │ ├── Image.cpp │ │ ├── Image.h │ │ ├── Label.cpp │ │ ├── Label.h │ │ ├── ParallaxLayer.cpp │ │ ├── ParallaxLayer.h │ │ ├── ScrollField.cpp │ │ ├── ScrollField.h │ │ ├── TextBox.cpp │ │ ├── TextBox.h │ │ ├── TopScreenCanvas.cpp │ │ ├── TopScreenCanvas.h │ │ ├── TouchScreenCanvas.cpp │ │ ├── TouchScreenCanvas.h │ │ ├── UICanvas.cpp │ │ ├── UICanvas.h │ │ ├── UIContainer.cpp │ │ ├── UIContainer.h │ │ ├── UIElement.cpp │ │ └── UIElement.h │ │ └── util │ │ ├── FSHelper.cpp │ │ ├── FSHelper.h │ │ ├── FrameTimer.cpp │ │ ├── FrameTimer.h │ │ ├── JsonConversions.cpp │ │ ├── JsonConversions.h │ │ ├── Path.cpp │ │ ├── Path.h │ │ ├── Profiler.cpp │ │ ├── Profiler.h │ │ ├── WorkerThread.cpp │ │ └── WorkerThread.h └── todo.txt ├── maketest.sh ├── testbed ├── Makefile ├── resources │ ├── audio_3ds.wav │ ├── banner.bnr │ ├── banner_3ds.png │ ├── logo.bcma.lz │ └── starlight-testbed.rsf ├── source │ ├── Core.cpp │ ├── Core.h │ ├── ThreadTest.cpp │ ├── ThreadTest.h │ └── main.cpp └── starlight-testbed.xml └── themes └── default ├── about.txt ├── controls ├── button.idle.json ├── button.idle.png ├── button.press.json ├── button.press.png ├── button.xcf ├── textBox.json ├── textBox.png └── textBox.xcf ├── decorations ├── dialog.modal-cover.png ├── dialog.modal-cover.xcf ├── generic backdrop.png ├── generic backdrop.xcf ├── osk.background.png ├── osk.background.xcf ├── panel.bg.json └── panel.bg.png ├── fonts ├── credit.txt ├── default.12.border.png ├── default.12.json ├── default.12.png ├── default.16.border.png ├── default.16.json ├── default.16.png ├── mono.12.border.png ├── mono.12.json ├── mono.12.png ├── mono.16.border.png ├── mono.16.json └── mono.16.png ├── glyphs ├── backspace.large.png ├── backspace.small.png ├── backspace.xcf ├── enter.large.png ├── enter.small.png ├── enter.xcf ├── shift.large.png ├── shift.small.png └── shift.xcf └── metrics.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | *.elf 34 | *.3dsx 35 | *.cia 36 | # ...and icons 37 | *.smdh 38 | 39 | # section-specifics 40 | 41 | # libstarlight main 42 | libstarlight/build/ 43 | libstarlight/lib/ 44 | libstarlight/include/ 45 | libstarlight/lib*.tar.bz2 46 | 47 | # testbed 48 | testbed/build/ 49 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Beau Jessee ("zetaPRIME") 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | // Bundled dependencies (see _incLib) have their own terms and/or notices, as listed in their respective files. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | #

- libstarlight - 3 | 4 | ###

3DS Homebrew Application Framework 5 | --- 6 | (Pardon the dust, both the library and this readme are still a work in progress) 7 | 8 | ## What is this? 9 | libstarlight is a fully-featured application framework for 3DS homebrew written in C++14. 10 | 11 | Features include: 12 | * Fully themable UI framework with rich widgets designed for the 3DS's touchscreen 13 | * Underlying graphics framework built on citro3d, using premultiplied alpha blending 14 |
(textures automatically converted on load) 15 | * Streamlined, easy-to-use onscreen keyboard 16 | * Centralized configuration system for application-specific settings and storage, complete with optional auto-saving on exit 17 | * Filesystem helpers to streamline working with SD and romfs contents 18 | * Various basic datatypes for convenience and interoperability 19 | 20 | Please keep in mind that while libstarlight is still in beta (pre-1.0.0) not everything is final. Expect occasional (usually minor) breaking changes as things settle. 21 | 22 | ## Requirements 23 | libstarlight requires devkitARM r46 or later, along with: 24 | * reasonably up-to-date libctru 25 | * citro3d 26 | 27 | Additionally, libstarlight contains versions of the following bundled within: 28 | * [lodepng](https://github.com/lvandeve/lodepng) 29 | * [nlohmann::json (JSON For Modern C++)](https://github.com/nlohmann/json) 30 | 31 | ## Okay, so how do I use this? 32 | (section WIP, take a look at the testbed for a slightly scattered example) 33 | 34 | To ensure your application runs properly without themes installed to the SD card, it is recommended to include a copy of the default theme (or any theme with no fallback) at `romfs:/.fallback_theme/`. 35 | 36 | (Themes on SD go in `sdmc:/.starlight/themes/`) 37 | 38 | ## License 39 | * MIT (see [license.md](license.md)) 40 | 41 | Bundled dependencies (see [\_incLib](libstarlight/source/starlight/_incLib)) have their own terms and/or notices, as listed in their respective files. 42 | -------------------------------------------------------------------------------- /libstarlight/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | include $(DEVKITARM)/3ds_rules 10 | 11 | VERSION := 0.1.0 12 | 13 | #--------------------------------------------------------------------------------- 14 | # TARGET is the name of the output 15 | # BUILD is the directory where object files & intermediate files will be placed 16 | # SOURCES is a list of directories containing source code 17 | # DATA is a list of directories containing data files 18 | # INCLUDES is a list of directories containing header files 19 | #--------------------------------------------------------------------------------- 20 | TARGET := starlight 21 | BUILD := build 22 | SOURCES := $(sort $(dir $(wildcard source/*/ source/*/*/ source/*/*/*/ source/*/*/*/*/ source/*/*/*/*/*/))) 23 | 24 | DATA := data 25 | INCLUDES := include 26 | 27 | #--------------------------------------------------------------------------------- 28 | # options for code generation 29 | #--------------------------------------------------------------------------------- 30 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft 31 | 32 | # why was -Werror here? 33 | CFLAGS := -g -Wall -Wno-psabi -O2 -mword-relocations \ 34 | -ffunction-sections \ 35 | -fomit-frame-pointer \ 36 | $(ARCH) 37 | 38 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS 39 | 40 | # json requires exception support, nuke -fno-exceptions 41 | CXXFLAGS := $(CFLAGS) -fno-rtti -std=c++17 42 | 43 | ASFLAGS := -g $(ARCH) 44 | 45 | LIBS := -lcitro3d -lctru -lm 46 | 47 | #--------------------------------------------------------------------------------- 48 | # list of directories containing libraries, this must be the top level containing 49 | # include and lib 50 | #--------------------------------------------------------------------------------- 51 | LIBDIRS := $(CTRULIB) $(PORTLIBS) 52 | 53 | #--------------------------------------------------------------------------------- 54 | # no real need to edit anything past this point unless you need to add additional 55 | # rules for different file extensions 56 | #--------------------------------------------------------------------------------- 57 | ifneq ($(BUILD),$(notdir $(CURDIR))) 58 | #--------------------------------------------------------------------------------- 59 | 60 | export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a 61 | 62 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 63 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 64 | 65 | export DEPSDIR := $(CURDIR)/$(BUILD) 66 | 67 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 68 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 69 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 70 | PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica))) 71 | SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist))) 72 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 73 | 74 | #--------------------------------------------------------------------------------- 75 | # use CXX for linking C++ projects, CC for standard C 76 | #--------------------------------------------------------------------------------- 77 | ifeq ($(strip $(CPPFILES)),) 78 | #--------------------------------------------------------------------------------- 79 | export LD := $(CC) 80 | #--------------------------------------------------------------------------------- 81 | else 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CXX) 84 | #--------------------------------------------------------------------------------- 85 | endif 86 | #--------------------------------------------------------------------------------- 87 | 88 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 89 | $(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \ 90 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 91 | 92 | export INCLUDE := -I$(CURDIR)/source $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 93 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 94 | -I$(CURDIR)/$(BUILD) 95 | 96 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 97 | 98 | .PHONY: $(BUILD) clean all 99 | 100 | #--------------------------------------------------------------------------------- 101 | all: $(BUILD) 102 | 103 | dist-bin: all 104 | @rm -rf include/ 105 | @rsync -a --include '*/' --include '*.h' --include '*.hpp' --exclude '*' source/ include/ 106 | @tar --exclude=*~ -cjf libstarlight-$(VERSION).tar.bz2 include lib 107 | 108 | dist-src: 109 | @rm -rf include/ 110 | @rsync -a --include '*/' --include '*.h' --include '*.hpp' --exclude '*' source/ include/ 111 | @tar --exclude=*~ -cjf libstarlight-src-$(VERSION).tar.bz2 include source data Makefile Doxyfile Doxyfile.internal 112 | 113 | dist: dist-src dist-bin 114 | 115 | install: dist-bin 116 | @rm -rf $(DEVKITPRO)/libstarlight 117 | @mkdir -p $(DEVKITPRO)/libstarlight 118 | bzip2 -cd libstarlight-$(VERSION).tar.bz2 | tar -xf - -C $(DEVKITPRO)/libstarlight 119 | 120 | dox: 121 | @doxygen Doxyfile 122 | @doxygen Doxyfile.internal 123 | 124 | lib: 125 | @[ -d $@ ] || mkdir -p $@ 126 | 127 | $(BUILD): lib 128 | @[ -d $@ ] || mkdir -p $@ 129 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 130 | 131 | #--------------------------------------------------------------------------------- 132 | clean: 133 | @echo clean ... 134 | @rm -fr $(BUILD) lib include docs internal_docs 135 | 136 | #--------------------------------------------------------------------------------- 137 | else 138 | 139 | DEPENDS := $(OFILES:.o=.d) 140 | 141 | #--------------------------------------------------------------------------------- 142 | # main targets 143 | #--------------------------------------------------------------------------------- 144 | $(OUTPUT) : $(OFILES) 145 | 146 | #--------------------------------------------------------------------------------- 147 | %.bin.o : %.bin 148 | #--------------------------------------------------------------------------------- 149 | @echo $(notdir $<) 150 | @$(bin2o) 151 | 152 | #--------------------------------------------------------------------------------- 153 | # rules for assembling GPU shaders 154 | #--------------------------------------------------------------------------------- 155 | define shader-as 156 | $(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@))) 157 | picasso -o $(CURBIN) $1 158 | bin2s $(CURBIN) | $(AS) -o $@ 159 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h 160 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h 161 | echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h 162 | endef 163 | 164 | %.shbin.o : %.v.pica %.g.pica 165 | @echo $(notdir $^) 166 | @$(call shader-as,$^) 167 | 168 | %.shbin.o : %.v.pica 169 | @echo $(notdir $<) 170 | @$(call shader-as,$<) 171 | 172 | %.shbin.o : %.shlist 173 | @echo $(notdir $<) 174 | @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file))) 175 | 176 | -include $(DEPENDS) 177 | 178 | #--------------------------------------------------------------------------------------- 179 | endif 180 | #--------------------------------------------------------------------------------------- 181 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/Application.cpp: -------------------------------------------------------------------------------- 1 | #include "Application.h" 2 | 3 | #include <3ds.h> 4 | 5 | #include "starlight/GFXManager.h" 6 | #include "starlight/ConfigManager.h" 7 | #include "starlight/ThemeManager.h" 8 | #include "starlight/InputManager.h" 9 | #include "starlight/gfx/RenderCore.h" 10 | 11 | using std::string; 12 | 13 | using starlight::GFXManager; 14 | using starlight::ConfigManager; 15 | using starlight::Config; 16 | using starlight::ThemeManager; 17 | using starlight::InputManager; 18 | using starlight::gfx::RenderCore; 19 | 20 | using starlight::threading::Thread; 21 | using starlight::threading::ThreadState; 22 | 23 | using starlight::ui::TouchScreenCanvas; 24 | using starlight::ui::TopScreenCanvas; 25 | 26 | using starlight::ui::Form; 27 | using starlight::ui::FormFlags; 28 | 29 | using starlight::Application; 30 | 31 | //////////////////// 32 | // STATIC MEMBERS // 33 | //////////////////// 34 | 35 | Application* Application::_currentApp = nullptr; 36 | unsigned long long Application::ftime = 0; 37 | 38 | bool Application::Quit() { 39 | if (_currentApp == nullptr) return false; 40 | _currentApp->_appQuit = true; 41 | return _currentApp->_appQuit; 42 | } 43 | 44 | Config& Application::GetConfig(const string& path) { 45 | const string& appId = (_currentApp != nullptr) ? _currentApp->appId : "null"; 46 | string np(path.length() + appId.length() + 4 + 1, ' '); 47 | np.clear(); 48 | np.append("app/"); np.append(appId); np.append("/"); np.append(path); 49 | return ConfigManager::Get(np); 50 | } 51 | 52 | string Application::AppName() { 53 | return (_currentApp != nullptr) ? _currentApp->appId : "null"; 54 | } 55 | 56 | ////////////////////// 57 | // INSTANCE MEMBERS // 58 | ////////////////////// 59 | 60 | void Application::Run() { 61 | if (_currentApp != nullptr) return; // don't run two at once! 62 | _currentApp = this; 63 | 64 | _init(); 65 | while (!_appQuit && aptMainLoop()) _mainLoop(); 66 | _end(); 67 | 68 | _currentApp = nullptr; 69 | } 70 | 71 | void Application::_init() { 72 | srand(time(NULL)); 73 | romfsInit(); 74 | ConfigManager::Init(); 75 | RenderCore::Open(); 76 | ThemeManager::Init(); 77 | 78 | touchScreen = std::make_shared(); 79 | topScreen = std::make_shared(); 80 | formTouchScreen = touchScreen.get(); 81 | formTopScreen = topScreen.get(); 82 | 83 | Init(); 84 | } 85 | 86 | void Application::_end() { 87 | End(); 88 | 89 | for (auto& thread : threads) thread->Exit(); 90 | threads.clear(); 91 | 92 | //for (auto& f : forms) f->Close(); 93 | forms.clear(); // not sure why, but not doing this results in a data abort if any forms are active 94 | 95 | // force cleanup! let's not softlock, mmkay? 96 | formTouchScreen = nullptr; 97 | formTopScreen = nullptr; 98 | touchScreen.reset(); 99 | topScreen.reset(); 100 | 101 | ThemeManager::End(); 102 | RenderCore::Close(); 103 | ConfigManager::End(); 104 | } 105 | 106 | void Application::_mainLoop() { 107 | RenderCore::SyncFrame(); // sync to vblank here for more accurate timing 108 | frameTimer.FrameStart(); 109 | 110 | if (!forms.empty()) { 111 | if (_sFormState) { 112 | _sFormState = false; 113 | 114 | // sort open forms 115 | forms.sort(Form::OrderedCompare); 116 | 117 | // reconstruct ui container heirarchy 118 | bool otouch = false, otop = false; 119 | formTouchScreen->RemoveAll(); 120 | formTopScreen->RemoveAll(); 121 | 122 | for (auto it = forms.rbegin(); it != forms.rend(); ++it) { 123 | if ((*it)->IsVisible()) { 124 | if (!otouch) formTouchScreen->Add((*it)->touchScreen, true); 125 | if (!otop) formTopScreen->Add((*it)->topScreen, true); 126 | if ((*it)->GetFlag(FormFlags::canOcclude)) { 127 | if ((*it)->GetFlag(FormFlags::occludeTouch)) otouch = true; 128 | if ((*it)->GetFlag(FormFlags::occludeTop)) otop = true; 129 | } 130 | } 131 | } 132 | // 133 | } 134 | } 135 | 136 | // update step 137 | ftime = osGetTime(); 138 | 139 | InputManager::Update(); 140 | Update(); 141 | { // update loop for forms, guarded from snap-outs 142 | auto it = forms.begin(); 143 | while (it != forms.end()) { 144 | auto next = std::next(it); 145 | (*it)->Update(*it == forms.back()); 146 | it = next; 147 | } 148 | } 149 | touchScreen->Update(); 150 | topScreen->Update(); 151 | PostUpdate(); 152 | 153 | // draw step 154 | RenderCore::BeginFrame(); 155 | RenderCore::targetBottom->Clear(clearColor); 156 | RenderCore::targetTopLeft->Clear(clearColor); 157 | RenderCore::targetTopRight->Clear(clearColor); 158 | 159 | Draw(); 160 | touchScreen->PreDraw(); 161 | topScreen->PreDraw(); 162 | touchScreen->Draw(); 163 | topScreen->Draw(); 164 | PostDraw(); 165 | RenderCore::EndFrame(); 166 | 167 | while (!threads.empty() && frameTimer.GetSubframe() < 0.9) { 168 | auto thread = threads.front(); 169 | thread->Resume(); 170 | if (thread->state != ThreadState::Finished) threads.splice(threads.end(), threads, threads.begin()); // move to back of queue 171 | else threads.pop_front(); // or just discard if already exited 172 | } 173 | } 174 | 175 | void Application::EnqueueThread(std::shared_ptr thread) { 176 | threads.push_back(thread); 177 | thread->Start(); 178 | } 179 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/Application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "starlight/datatypes/Vector2.h" 9 | #include "starlight/datatypes/VRect.h" 10 | #include "starlight/datatypes/Color.h" 11 | 12 | #include "starlight/util/FrameTimer.h" 13 | 14 | #include "starlight/threading/Thread.h" 15 | 16 | #include "starlight/ui/TouchScreenCanvas.h" 17 | #include "starlight/ui/TopScreenCanvas.h" 18 | 19 | #include "starlight/ui/Form.h" 20 | 21 | #include "starlight/ConfigManager.h" 22 | 23 | namespace starlight { 24 | class Application { 25 | //////////////////// 26 | // STATIC MEMBERS // 27 | //////////////////// 28 | private: 29 | static Application* _currentApp; 30 | static unsigned long long ftime; 31 | 32 | public: 33 | static bool Quit(); 34 | static Config& GetConfig(const std::string& path); 35 | static std::string AppName(); 36 | static inline Application* Current() { return _currentApp; } 37 | static inline unsigned long long GetTime() { return ftime; } 38 | 39 | ////////////////////// 40 | // INSTANCE MEMBERS // 41 | ////////////////////// 42 | private: 43 | bool _appQuit = false; 44 | bool _sFormState = false; 45 | void _init(); 46 | void _mainLoop(); 47 | void _end(); 48 | 49 | std::list> threads; 50 | util::FrameTimer frameTimer; 51 | 52 | public: 53 | const std::string appId; 54 | 55 | Color clearColor = Color::black; 56 | 57 | std::shared_ptr touchScreen = nullptr; 58 | std::shared_ptr topScreen = nullptr; 59 | 60 | std::list> forms; 61 | ui::UIContainer* formTouchScreen = nullptr; 62 | ui::UIContainer* formTopScreen = nullptr; 63 | 64 | Application() = delete; 65 | Application(std::string id) : appId(id) { } 66 | virtual ~Application() = default; 67 | 68 | void Run(); 69 | 70 | void EnqueueThread(std::shared_ptr thread); 71 | inline void SignalFormState() { _sFormState = true; } 72 | 73 | virtual void Init() { } 74 | virtual void Update() { } 75 | virtual void PostUpdate() { } 76 | virtual void Draw() { } 77 | virtual void PostDraw() { } 78 | virtual void End() { } 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/ConfigManager.cpp: -------------------------------------------------------------------------------- 1 | #include "ConfigManager.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "starlight/_incLib/json.hpp" 10 | 11 | #include "starlight/Application.h" 12 | 13 | #include "starlight/util/FSHelper.h" 14 | 15 | using std::string; 16 | using std::ifstream; 17 | using std::ofstream; 18 | 19 | using starlight::Application; 20 | 21 | using starlight::util::FSHelper; 22 | using starlight::util::Path; 23 | 24 | using starlight::Config; 25 | using starlight::ConfigManager; 26 | 27 | // helper stuff 28 | namespace { 29 | // 30 | } 31 | 32 | //////////// 33 | // Config // 34 | //////////// 35 | 36 | Config::Config(const string& path) : path(path) { 37 | /*static const constexpr char* cpfx = "sdmc:/.starlight/config/"; 38 | constexpr std::size_t cpfx_s = std::strlen(cpfx); 39 | // reserve string size 40 | string xfsPath(path.length() + cpfx_s + 5, ' '); xfsPath.clear(); 41 | // and build 42 | xfsPath.append(cpfx); xfsPath.append(path); xfsPath.append(".json"); 43 | fsPath = Path(xfsPath);*/ 44 | fsPath = Path("sdmc:/.starlight/config", true).Combine(path + ".json"); 45 | 46 | // init json 47 | this->json = std::make_shared(); 48 | 49 | Reload(); 50 | } 51 | Config::~Config() { } 52 | 53 | void Config::Reload() { 54 | ifstream load = fsPath.OpenI(); 55 | if (load.good()) load >> *json; 56 | } 57 | 58 | void Config::Save() { 59 | ofstream save = fsPath.OpenO(); 60 | if (save.good()) save << *json; 61 | } 62 | 63 | /////////////////// 64 | // ConfigManager // 65 | /////////////////// 66 | 67 | std::unordered_map> ConfigManager::cfg; 68 | 69 | void ConfigManager::Init() { 70 | //FSHelper::AssertDirPath("sdmc:/.starlight/config/app/" + Application::AppName()); 71 | Get("user").autoSave = true; 72 | } 73 | 74 | void ConfigManager::End() { 75 | for (auto it : cfg) { 76 | auto& c = *it.second.get(); 77 | if (c.autoSave) c.Save(); 78 | } 79 | // actualy, don't clear in case something uses a static get 80 | // in the future, perhaps discard contents 81 | } 82 | 83 | Config& ConfigManager::Get(const string& path) { 84 | auto const& itr = cfg.find(path); 85 | if (itr == cfg.end()) { 86 | return *cfg.insert(std::make_pair(path, std::make_shared(path))).first->second; 87 | } else return *itr->second; 88 | } 89 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/ConfigManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | #include 6 | 7 | //#include "starlight/_incLib/json_fwd.hpp" 8 | #include "starlight/_incLib/json.hpp" 9 | 10 | #include "starlight/util/Path.h" 11 | 12 | //#include "starlight/gfx/DrawContext.h" 13 | 14 | namespace starlight { 15 | class Config { 16 | private: 17 | util::Path fsPath; 18 | std::shared_ptr json; 19 | public: 20 | const std::string path; 21 | bool autoSave = false; 22 | 23 | Config(const std::string& path); 24 | ~Config(); 25 | 26 | void Reload(); 27 | void Save(); 28 | 29 | nlohmann::json& Json() { return *json; } 30 | 31 | template 32 | T Get(const std::string& path, T defVal, bool writeDefault = false) { 33 | auto jp = nlohmann::json::json_pointer(path); 34 | auto& js = (*json)[jp]; 35 | if (js.is_null()) { 36 | if (writeDefault) js = defVal; 37 | return defVal; 38 | } 39 | return js; 40 | } 41 | 42 | template 43 | void Set(const std::string& path, T val) { 44 | (*json)[nlohmann::json::json_pointer(path)] = val; 45 | } 46 | }; 47 | 48 | class ConfigManager { 49 | private: 50 | static std::unordered_map> cfg; 51 | 52 | public: 53 | ConfigManager() = delete; 54 | 55 | static void Init(); 56 | static void End(); 57 | 58 | static Config& Get(const std::string& path); 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/GFXManager.cpp: -------------------------------------------------------------------------------- 1 | #include "GFXManager.h" 2 | 3 | using starlight::Vector2; 4 | using starlight::GFXManager; 5 | using starlight::gfx::DrawContext; 6 | 7 | std::forward_list GFXManager::ctxStack; 8 | std::forward_list GFXManager::offsetStack; 9 | 10 | float GFXManager::parallax = 0; 11 | 12 | void GFXManager::PushContext(DrawContext* context) { 13 | if (!ctxStack.empty()) ctxStack.front()->Close(); 14 | ctxStack.push_front(context); 15 | context->Open(); 16 | PushOffset(Vector2::zero); 17 | } 18 | 19 | DrawContext* GFXManager::PopContext() { 20 | //if (ctxStack.empty()) return nullptr; 21 | DrawContext* context = ctxStack.front(); 22 | PopOffset(); 23 | context->Close(); 24 | ctxStack.pop_front(); 25 | if (!ctxStack.empty()) ctxStack.front()->Open(); 26 | return context; 27 | } 28 | 29 | DrawContext* GFXManager::GetContext() { return !ctxStack.empty() ? ctxStack.front() : nullptr; } 30 | 31 | void GFXManager::PushOffset(Vector2 offset) { offsetStack.push_front(offset); } 32 | void GFXManager::PushOffsetAdd(Vector2 add) { offsetStack.push_front(GetOffset() + add); } 33 | Vector2 GFXManager::PopOffset() { 34 | Vector2 r = GetOffset(); 35 | offsetStack.pop_front(); 36 | return r; 37 | } 38 | Vector2 GFXManager::GetOffset() { return !offsetStack.empty() ? offsetStack.front() : Vector2::zero; } 39 | 40 | void GFXManager::Reset() { 41 | ctxStack.clear(); 42 | offsetStack.clear(); 43 | } 44 | 45 | bool GFXManager::PrepareForDrawing() { 46 | if (ctxStack.empty()) return false; 47 | auto context = ctxStack.front(); 48 | if (context->drawReady) return true; 49 | return context->Prepare(); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/GFXManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | 6 | #include "starlight/gfx/DrawContext.h" 7 | 8 | namespace starlight { 9 | class GFXManager { 10 | private: 11 | static std::forward_list ctxStack; 12 | static std::forward_list offsetStack; 13 | public: 14 | static float parallax; 15 | 16 | GFXManager() = delete; 17 | 18 | static void PushContext(gfx::DrawContext* context); 19 | static gfx::DrawContext* PopContext(); 20 | static gfx::DrawContext* GetContext(); 21 | 22 | static void PushOffset(Vector2 offset); 23 | static void PushOffsetAdd(Vector2 add); 24 | static Vector2 PopOffset(); 25 | static Vector2 GetOffset(); 26 | 27 | static void Reset(); 28 | 29 | static bool PrepareForDrawing(); 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/InputManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include <3ds.h> 8 | 9 | #include "starlight/datatypes/Vector2.h" 10 | 11 | #include "starlight/dialog/OSK.h" 12 | 13 | #include "InputManager.h" 14 | 15 | using starlight::Vector2; 16 | using starlight::ui::UIElement; 17 | 18 | using starlight::dialog::OSK; 19 | using starlight::dialog::osk::InputHandler; 20 | 21 | using starlight::DragHandle; 22 | using starlight::InputManager; 23 | 24 | namespace { 25 | unsigned int heldLast = 0; 26 | unsigned int heldNow = 0; 27 | 28 | Vector2 stickLeftLast; 29 | Vector2 stickLeftNow; 30 | Vector2 stickRightLast; 31 | Vector2 stickRightNow; 32 | 33 | Vector2 touchLast; 34 | Vector2 touchNow; 35 | Vector2 touchStart; 36 | int touchTime; 37 | 38 | Vector2 stickVec(circlePosition cpos) { 39 | Vector2 v (cpos.dx, -cpos.dy); 40 | 41 | float mag = std::min(v.Length() / 150.0f, 1.0f); 42 | mag = std::max(mag * 1.1f - 0.1f, 0.0f); 43 | 44 | v = v.Normalized() * mag; 45 | 46 | return v; 47 | } 48 | } 49 | 50 | void InputManager::Update() { 51 | hidScanInput(); 52 | circlePosition cp; 53 | touchPosition tp; 54 | 55 | heldLast = heldNow; 56 | heldNow = hidKeysHeld(); 57 | 58 | stickLeftLast = stickLeftNow; 59 | hidCircleRead(&cp); 60 | stickLeftNow = stickVec(cp); 61 | stickRightLast = stickRightNow; 62 | hidCstickRead(&cp); 63 | stickRightNow = stickVec(cp); 64 | 65 | touchLast = touchNow; 66 | hidTouchRead(&tp); 67 | if (Held(Keys::Touch)) touchNow = Vector2(tp.px, tp.py); 68 | 69 | if (Pressed(Keys::Touch)) touchStart = touchLast = touchNow; 70 | 71 | if (!Held(Keys::Touch) && !Released(Keys::Touch)) touchTime = 0; 72 | else touchTime++; 73 | 74 | } 75 | 76 | float InputManager::DepthSlider() { return (*(float*)0x1FF81080); } 77 | 78 | Vector2 InputManager::CirclePad() { return stickLeftNow; } 79 | Vector2 InputManager::CStick() { return stickRightNow; } 80 | 81 | bool InputManager::Held(unsigned int mask) { return heldNow & mask; } 82 | bool InputManager::Pressed(unsigned int mask) { return (heldNow & ~heldLast) & mask; } 83 | bool InputManager::Released(unsigned int mask) { return (heldLast & ~heldNow) & mask; } 84 | 85 | Vector2 InputManager::TouchPos() { return touchNow; } 86 | Vector2 InputManager::TouchDelta() { return touchNow - touchLast; } 87 | Vector2 InputManager::TouchStart() { return touchStart; } 88 | Vector2 InputManager::TouchDragDist() { return touchNow - touchStart; } 89 | int InputManager::TouchTime() { return touchTime; } 90 | 91 | // drag stuff! 92 | DragHandle InputManager::drag; 93 | DragHandle& DragHandle::Grab(UIElement* e) { 94 | if (rptr == e) return *this; 95 | Release(); 96 | rptr = e; 97 | wptr = e->shared_from_this(); 98 | e->OnDragStart(); 99 | return *this; 100 | } 101 | 102 | DragHandle& DragHandle::PassUp(bool releaseOnFail) { 103 | if (!valid()) return *this; // invalid 104 | UIElement* e = rptr; 105 | while (true) { 106 | if (auto p = e->parent.lock()) { 107 | e = p.get(); 108 | if (e->OnDragPassed()) { 109 | return Grab(e); 110 | } 111 | continue; 112 | } else { 113 | if (releaseOnFail) Release(); 114 | return *this; 115 | } 116 | break; 117 | } 118 | } 119 | 120 | #define err(nth, wat) *((unsigned int*)0x00100000+(nth))=wat; 121 | #define ded(wat) err(0,wat) 122 | void DragHandle::Release() { 123 | if (!valid()) return; // nothing to release 124 | UIElement* e = rptr; 125 | rptr = nullptr; 126 | wptr = std::shared_ptr(nullptr); 127 | e->OnDragRelease(); 128 | } 129 | 130 | void InputManager::OpenKeyboard(InputHandler* handler) { 131 | // todo: open different keyboard type depending on user settings 132 | OSK::New(handler)->Open(); 133 | } 134 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/InputManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | 6 | #include "starlight/datatypes/Vector2.h" 7 | 8 | #include "starlight/ui/UIElement.h" 9 | 10 | // based on ctrulib's enum 11 | #ifndef BIT 12 | #define BIT(n) (1U<<(n)) 13 | #endif 14 | enum class Keys : unsigned int { 15 | A = BIT(0), ///< A 16 | B = BIT(1), ///< B 17 | Select = BIT(2), ///< Select 18 | Start = BIT(3), ///< Start 19 | DPadRight = BIT(4), ///< D-Pad Right 20 | DPadLeft = BIT(5), ///< D-Pad Left 21 | DPadUp = BIT(6), ///< D-Pad Up 22 | DPadDown = BIT(7), ///< D-Pad Down 23 | R = BIT(8), ///< R 24 | L = BIT(9), ///< L 25 | X = BIT(10), ///< X 26 | Y = BIT(11), ///< Y 27 | ZL = BIT(14), ///< ZL (New 3DS only) 28 | ZR = BIT(15), ///< ZR (New 3DS only) 29 | Touch = BIT(20), ///< Touch (Not actually provided by HID) 30 | CStickRight = BIT(24), ///< C-Stick Right (New 3DS only) 31 | CStickLeft = BIT(25), ///< C-Stick Left (New 3DS only) 32 | CStickUp = BIT(26), ///< C-Stick Up (New 3DS only) 33 | CStickDown = BIT(27), ///< C-Stick Down (New 3DS only) 34 | CPadRight = BIT(28), ///< Circle Pad Right 35 | CPadLeft = BIT(29), ///< Circle Pad Left 36 | CPadUp = BIT(30), ///< Circle Pad Up 37 | CPadDown = BIT(31), ///< Circle Pad Down 38 | 39 | // Generic catch-all directions 40 | Up = DPadUp | CPadUp, ///< D-Pad Up or Circle Pad Up 41 | Down = DPadDown | CPadDown, ///< D-Pad Down or Circle Pad Down 42 | Left = DPadLeft | CPadLeft, ///< D-Pad Left or Circle Pad Left 43 | Right = DPadRight | CPadRight, ///< D-Pad Right or Circle Pad Right 44 | }; 45 | 46 | inline constexpr unsigned int operator*(Keys k) { return static_cast(k); } 47 | inline constexpr Keys operator|(Keys k1, Keys k2) { return static_cast(*k1 | *k2); } 48 | 49 | namespace starlight { 50 | // forward declare this for OpenKeyboard 51 | namespace dialog { 52 | namespace osk { 53 | class InputHandler; 54 | } 55 | } 56 | 57 | class InputManager; 58 | class DragHandle { 59 | friend class starlight::InputManager; 60 | private: 61 | 62 | protected: 63 | 64 | public: 65 | std::weak_ptr wptr; 66 | starlight::ui::UIElement* rptr = nullptr; 67 | 68 | DragHandle() { } 69 | DragHandle(const DragHandle&) = delete; 70 | ~DragHandle() { } 71 | 72 | DragHandle& Grab(starlight::ui::UIElement* e); 73 | DragHandle& PassUp(bool releaseOnFail = false); 74 | void Release(); 75 | 76 | inline starlight::ui::UIElement* get() const { if (wptr.expired()) return nullptr; return rptr; } 77 | inline bool valid() const { return rptr != nullptr && !wptr.expired(); }; 78 | 79 | inline explicit operator bool() const { return rptr != nullptr && !wptr.expired(); } 80 | inline bool operator ==(starlight::ui::UIElement* e) const { return rptr == e; } 81 | //starlight::ui::UIElement& operator *() const { return *rptr; } // as with optref, do *not* call without checking first 82 | }; 83 | 84 | class InputManager { 85 | private: 86 | static DragHandle drag; 87 | 88 | public: 89 | static constexpr const float dragThreshold = 8.0f; 90 | static constexpr const float flingThreshold = 5.0f; 91 | 92 | static void Update(); 93 | 94 | static float DepthSlider(); 95 | 96 | static Vector2 CirclePad(); 97 | static Vector2 CStick(); 98 | 99 | static bool Held(unsigned int mask); 100 | static inline bool Held(Keys mask) { return Held(*mask); } 101 | static bool Pressed(unsigned int mask); 102 | static inline bool Pressed(Keys mask) { return Pressed(*mask); } 103 | static bool Released(unsigned int mask); 104 | static inline bool Released(Keys mask) { return Released(*mask); } 105 | 106 | static Vector2 TouchPos(); 107 | static Vector2 TouchDelta(); 108 | static Vector2 TouchStart(); 109 | static Vector2 TouchDragDist(); 110 | static int TouchTime(); 111 | 112 | static DragHandle& GetDragHandle() { return InputManager::drag; } 113 | 114 | static void OpenKeyboard(dialog::osk::InputHandler* handler); 115 | 116 | private: 117 | InputManager() {} 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/ThemeManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "starlight/_incLib/json_fwd.hpp" 11 | 12 | #include "starlight/util/Path.h" 13 | 14 | #include "starlight/gfx/Drawable.h" 15 | #include "starlight/gfx/Font.h" 16 | 17 | namespace starlight { 18 | // forward declare 19 | namespace gfx { 20 | template class ThemeRefContainer; 21 | template class ThemeRef; 22 | } 23 | 24 | struct ThemeInfo { 25 | public: 26 | std::string name; 27 | util::Path basePath; 28 | 29 | std::shared_ptr meta; 30 | std::shared_ptr metrics; 31 | 32 | ThemeInfo() = default; 33 | ThemeInfo(const std::string& name); 34 | ThemeInfo(const util::Path& path, const std::string& name = ""); 35 | ~ThemeInfo() = default; 36 | }; 37 | 38 | class ThemeManager { 39 | template 40 | friend class starlight::gfx::ThemeRefContainer; 41 | private: 42 | static std::unordered_map> drawables; 43 | static std::unordered_map> fonts; 44 | static std::list> tq; 45 | protected: 46 | static std::list themeData; 47 | 48 | static void Fulfill(gfx::ThemeRefContainer& ref); 49 | static void Fulfill(gfx::ThemeRefContainer& ref); 50 | 51 | static std::shared_ptr LoadAsset(std::string& path, gfx::ThemeRefContainer& ref); 52 | public: 53 | ThemeManager() = delete; // "static" class 54 | 55 | static void Init(); 56 | static void End(); 57 | 58 | static void GC(); 59 | 60 | static gfx::ThemeRef GetAsset(const std::string& name); 61 | static gfx::ThemeRef GetFont(const std::string& name); 62 | 63 | static void LoadProc(); 64 | 65 | static std::string ResolveAssetPath(const std::string& id); 66 | static std::string ResolveFontPath(const std::string& id); 67 | 68 | static inline std::string GetThemeName() { return themeData.front().name; } 69 | static nlohmann::json& GetMetric(const std::string& path); 70 | template static T GetMetric(const std::string& path, const T& defaultValue); 71 | template static T GetMetric(const std::string& path); 72 | }; 73 | } 74 | 75 | // post-include dependency 76 | #include "starlight/gfx/ThemeRef.h" 77 | 78 | // and some metrics types depending on ThemeRef 79 | namespace starlight { 80 | struct TextConfig { 81 | gfx::ThemeRef font = ThemeManager::GetFont("default.12"); 82 | Color textColor = Color::white; 83 | Color borderColor = Color::transparent; 84 | Vector2 justification = Vector2::zero; 85 | 86 | TextConfig() = default; 87 | TextConfig(const std::string& fontName, Color text, Color border = Color::transparent); 88 | ~TextConfig() = default; 89 | 90 | TextConfig(const TextConfig& o) : textColor(o.textColor), borderColor(o.borderColor), justification(o.justification) { font = o.font; } 91 | TextConfig(const TextConfig&& o) : textColor(o.textColor), borderColor(o.borderColor), justification(o.justification) { font = o.font; } 92 | TextConfig& operator =(const TextConfig& o) { 93 | font = o.font; textColor = o.textColor; borderColor = o.borderColor; justification = o.justification; 94 | return *this; 95 | } 96 | TextConfig& operator =(const TextConfig&& o) { 97 | font = o.font; textColor = o.textColor; borderColor = o.borderColor; justification = o.justification; 98 | return *this; 99 | } 100 | 101 | void Print(Vector2 position, const std::string& text, Vector2 justification = Vector2::invalid); 102 | void Print(VRect rect, const std::string& text, Vector2 justification = Vector2::invalid); 103 | 104 | Vector2 Measure(const std::string& text, float maxWidth = 65536*64); 105 | 106 | Vector2 GetCursorPosition(VRect rect, const std::string& text, unsigned int end); 107 | unsigned int GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt); 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/_global.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // set up namespace shorthand 4 | namespace starlight {} 5 | namespace sl = starlight; 6 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/_incLib/_stringfix.h: -------------------------------------------------------------------------------- 1 | // okay, this is super ugly, but as of right now devkitARM seems to be missing some string conversion functions :( 2 | 3 | #pragma once 4 | 5 | // !! UNCOMMENT if using devkitARM r45 or earlier !! 6 | //#include 7 | //#include 8 | 9 | // add in missing string functions 10 | #if defined(_GLIBCXX_STRING) && !defined(_GLIBCXX_USE_C99) 11 | // !! UNCOMMENT if using devkitARM r45 or earlier !! 12 | /*namespace std { // whee ugly hacks! 13 | template 14 | std::string to_string(T value) { 15 | std::ostringstream os; 16 | os << value; 17 | return os.str(); 18 | } 19 | int stoi(const string& str) { 20 | stringstream ss(str); 21 | int N; 22 | ss<>N; 24 | return N; 25 | } 26 | float strtof(const string& str) { 27 | stringstream ss(str); 28 | float N; 29 | ss<>N; 31 | return N; 32 | } 33 | double strtod(const string& str) { 34 | stringstream ss(str); 35 | double N; 36 | ss<>N; 38 | return N; 39 | } 40 | long double strtold(const string& str) { 41 | stringstream ss(str); 42 | long double N; 43 | ss<>N; 45 | return N; 46 | } 47 | }//*/ 48 | #endif 49 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/_incLib/json_extensions.hpp: -------------------------------------------------------------------------------- 1 | // libstarlight extensions for nlohmann::json (include nested within basic_json) 2 | 3 | // try_get: reads out if applicable, else leaves the target alone 4 | void try_get(int& v) { if (is_number()) v = get(); } 5 | void try_get(float& v) { if (is_number()) v = get(); } 6 | void try_get(std::string& v) { if (is_string()) v = get(); } 7 | 8 | /*bool has(std::string& idx) const { 9 | return find(idx) != end(); 10 | }*/ 11 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/_incLib/json_fwd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NLOHMANN_JSON_FWD_HPP 4 | #define NLOHMANN_JSON_FWD_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace nlohmann 13 | { 14 | 15 | template < 16 | template class ObjectType, 17 | template class ArrayType, 18 | class StringType, 19 | class BooleanType, 20 | class NumberIntegerType, 21 | class NumberUnsignedType, 22 | class NumberFloatType, 23 | template class AllocatorType, 24 | template class JSONSerializer 25 | > 26 | class basic_json; 27 | 28 | template 29 | struct adl_serializer; 30 | 31 | using json = basic_json; 33 | 34 | } // namespace nlohmann 35 | 36 | #endif // NLOHMANN_JSON_FWD_HPP 37 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/Color.cpp: -------------------------------------------------------------------------------- 1 | #include "Color.h" 2 | 3 | #include 4 | 5 | #include "starlight/_incLib/json.hpp" 6 | 7 | using starlight::Color; 8 | 9 | const Color Color::invalid = Color(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); 10 | 11 | const Color Color::transparent = Color(0.0f, 0.0f, 0.0f, 0.0f); 12 | const Color Color::white = Color(1.0f, 1.0f, 1.0f); 13 | const Color Color::black = Color(0.0f, 0.0f, 0.0f); 14 | const Color Color::lightGray = Color(0.75f, 0.75f, 0.75f); 15 | const Color Color::midGray = Color(0.5f, 0.5f, 0.5f); 16 | const Color Color::darkGray = Color(0.25f, 0.25f, 0.25f); 17 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/Color.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | namespace starlight { 5 | class Color { 6 | private: 7 | // 8 | 9 | public: 10 | float r = 1.0f; 11 | float g = 1.0f; 12 | float b = 1.0f; 13 | float a = 1.0f; 14 | 15 | constexpr Color() : r(0), g(0), b(0), a(0) { } 16 | constexpr Color(float r, float g, float b, float a) : r(r), g(g), b(b), a(a) { } 17 | constexpr Color(float r, float g, float b) : r(r), g(g), b(b), a(1.0f) { } 18 | ~Color() = default; 19 | 20 | inline Color Alpha(float alpha) const { return Color(r,g,b,alpha); } 21 | 22 | inline Color Premultiplied() const { return Color(r*a,g*a,b*a,a); } 23 | 24 | inline bool operator == (const Color& o) const { return r == o.r && g == o.g && b == o.b && a == o.a; } 25 | inline bool operator != (const Color& o) const { return r != o.r || g != o.g || b != o.b || a != o.a; } 26 | 27 | inline Color operator * (const Color& o) const { return Color(r * o.r, g * o.g, b * o.b, a * o.a); } 28 | //inline Color operator * (const float m) const { return Color(r * m, g * m, b * m, a * m); } 29 | 30 | // hmm. I guess this will do ¯\_(ツ)_/¯ don't really want to force cstdint 31 | inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(b*255))&0xFF)<<16) | ((((int)(g*255))&0xFF)<<8) | ((((int)(r*255))&0xFF)<<0)); } 32 | // premult: inline operator unsigned int() const { return (((((int)(a*255))&0xFF)<<24) | ((((int)(a*b*255))&0xFF)<<16) | ((((int)(a*g*255))&0xFF)<<8) | ((((int)(a*r*255))&0xFF)<<0)); } 33 | 34 | inline bool Valid() const { return a == a && r == r && g == g && b == b; } 35 | inline explicit operator bool() const { return a == a && r == r && g == g && b == b; } 36 | 37 | static const Color invalid; 38 | 39 | static const Color transparent; 40 | static const Color white; 41 | static const Color black; 42 | static const Color lightGray; 43 | static const Color midGray; 44 | static const Color darkGray; 45 | 46 | // 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/OptRef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | namespace starlight { 5 | template 6 | class OptRef { 7 | private: 8 | T* ref; 9 | public: 10 | OptRef() : ref(nullptr) { } 11 | OptRef(decltype(nullptr) nul) : ref(nullptr) { } 12 | OptRef(const T& ref) : ref(const_cast(&ref)) { } // whatever, const cast, I know what I'm doing 13 | ~OptRef() { } 14 | 15 | const T& get() { return *ref; } // ... I guess :( 16 | 17 | inline explicit operator bool() const { return ref != nullptr; } 18 | inline const T& operator ->() { return *ref; } // meh, technically unsafe but it's not meant to be used without explicit checking 19 | inline operator const T&() { return *ref; } // same here 20 | }; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/Optional.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace starlight { 8 | template 9 | class Optional { 10 | private: 11 | std::unique_ptr p = nullptr; 12 | std::function* getdef = nullptr; 13 | 14 | inline void initp() { 15 | if (!p) { 16 | p = std::make_unique(); 17 | if (getdef) *p = (*getdef)(); 18 | } 19 | } 20 | 21 | public: 22 | Optional() = default; 23 | Optional(std::function* getDefault) : getdef(getDefault) { } 24 | Optional(nullptr_t) : p(nullptr) { } 25 | Optional(const Optional& o) { // copy operator *actually copies the inner object* 26 | if (o.p) { 27 | p = std::make_unique(); 28 | *p = *o.p; 29 | } 30 | getdef = o.getdef; 31 | } 32 | 33 | Optional& operator=(const nullptr_t&) { p.reset(); return *this; } 34 | Optional& operator=(const T& o) { // assign by type's assignment operator if passed a "value" 35 | if (!p) p = std::make_unique(); 36 | *p = o; 37 | return *this; 38 | } 39 | 40 | T& operator *() { 41 | initp(); 42 | return *p; 43 | } 44 | 45 | T* operator ->() { 46 | initp(); 47 | return &*p; 48 | } 49 | 50 | inline T& Get(T& defaultRef) { 51 | if (p) return *p; 52 | return defaultRef; 53 | } 54 | 55 | inline T& ROGet() { 56 | if (p) return *p; 57 | if (getdef) return (*getdef)(); 58 | static T fb; return fb; // meh, hackish but you shouldn't do this without a getdef anyway 59 | // todo: clean this up somehow ^ (throw instead? or maybe have a static unique_ptr instead so we save memory when this is never called for a type) 60 | } 61 | 62 | // 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/VRect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "VRect.h" 7 | 8 | using starlight::Vector2; 9 | using starlight::VRect; 10 | 11 | Vector2 VRect::Center() const { return pos + (size * 0.5f); } 12 | Vector2 VRect::TopLeft() const { return pos; } 13 | Vector2 VRect::TopRight() const { return Vector2(pos.x + size.x, pos.y); } 14 | Vector2 VRect::BottomLeft() const { return Vector2(pos.x, pos.y + size.y); } 15 | Vector2 VRect::BottomRight() const { return pos + size; } 16 | 17 | bool VRect::Overlaps(const VRect & o) const { 18 | Vector2 c = Center(); 19 | Vector2 oc = o.Center(); 20 | return fabsf(c.x - oc.x) * 2.0f < size.x + o.size.x && fabsf(c.y - oc.y) * 2.0f < size.y + o.size.y; 21 | } 22 | bool VRect::Contains(const Vector2 & vec) const { 23 | // not sure which implementation is faster 24 | return (pos.x <= vec.x && vec.x <= pos.x + size.x && pos.y <= vec.y && vec.y <= pos.y + size.y); 25 | //Vector2 c = Center(); 26 | //return fabsf(c.x - vec.x) < size.x * 0.5f && fabsf(c.y - vec.y) < size.y * 0.5f; 27 | } 28 | 29 | VRect VRect::IntSnap() const { return VRect(pos.IntSnap(), size.IntSnap()); } 30 | 31 | VRect VRect::Intersect(const VRect & o) const { 32 | Vector2 tl ( std::max(pos.x, o.pos.x), std::max(pos.y, o.pos.y) ); 33 | Vector2 br ( std::min(pos.x + size.x, o.pos.x + o.size.x), std::min(pos.y + size.y, o.pos.y + o.size.y) ); 34 | VRect res (tl, br - tl); 35 | if (res.size.x <= 0.0f || res.size.y <= 0.0f) return VRect(); // invalid area represented as a zero-rect 36 | return res; 37 | } 38 | 39 | VRect VRect::Expand(const Vector2& amount, const Vector2& bias) const { 40 | return VRect(pos + amount * bias * -2, size + amount * 2); 41 | } 42 | 43 | VRect VRect::Include(const Vector2& point) const { // could probably be more optimized 44 | Vector2 tl = TopLeft(), br = BottomRight(); 45 | if (point.x < tl.x) tl.x = point.x; 46 | else if (point.x > br.x) br.x = point.x; 47 | if (point.y < tl.y) tl.y = point.y; 48 | else if (point.y > br.y) br.y = point.y; 49 | return VRect(tl, br - tl); 50 | } 51 | 52 | VRect VRect::TopEdge(float width) const { return VRect(pos.x, pos.y, size.x, width); } 53 | VRect VRect::BottomEdge(float width) const { return VRect(pos.x, pos.y + size.y - width, size.x, width); } 54 | VRect VRect::LeftEdge(float width) const { return VRect(pos.x, pos.y, width, size.y); } 55 | VRect VRect::RightEdge(float width) const { return VRect(pos.x + size.x - width, pos.y, width, size.y); } 56 | 57 | // constants 58 | const VRect VRect::invalid = VRect(Vector2::invalid, Vector2::invalid); 59 | 60 | const VRect VRect::zero = VRect(); // should initialize to 0,0,0,0 61 | 62 | const VRect VRect::touchScreen = VRect(0, 0, 320, 240); 63 | const VRect VRect::topScreen = VRect(0, 0, 400, 240); 64 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/VRect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include "Vector2.h" 5 | 6 | namespace starlight { 7 | class VRect { 8 | private: 9 | // 10 | 11 | public: 12 | Vector2 pos; 13 | Vector2 size; 14 | 15 | constexpr VRect() = default; 16 | constexpr VRect(float x, float y, float w, float h) : pos(x, y), size(w, h) { } 17 | constexpr VRect(Vector2 pos, Vector2 size) : pos(pos), size(size) { } 18 | ~VRect() = default; 19 | 20 | Vector2 Center() const; 21 | Vector2 TopLeft() const; 22 | Vector2 TopRight() const; 23 | Vector2 BottomLeft() const; 24 | Vector2 BottomRight() const; 25 | 26 | bool Overlaps(const VRect & o) const; 27 | bool Contains(const Vector2 & vec) const; 28 | 29 | inline float Area() const { return size.Area(); } 30 | VRect IntSnap() const; 31 | 32 | VRect Intersect(const VRect & o) const; 33 | VRect Expand(const Vector2& amount, const Vector2& bias) const; 34 | VRect Expand(const Vector2& amount) const { return Expand(amount, Vector2::half); } 35 | VRect Expand(float x, float y) const { return Expand(Vector2(x, y)); } 36 | 37 | VRect Include(const Vector2& point) const; 38 | 39 | VRect TopEdge(float width) const; 40 | VRect BottomEdge(float width) const; 41 | VRect LeftEdge(float width) const; 42 | VRect RightEdge(float width) const; 43 | 44 | inline bool operator == (const VRect & o) const { return pos == o.pos && size == o.size; } 45 | inline bool operator != (const VRect & o) const { return pos != o.pos || size != o.size; } 46 | 47 | // add/sub to move... 48 | inline VRect operator + (const Vector2 & vec) const { return VRect(pos + vec, size); } 49 | inline VRect operator - (const Vector2 & vec) const { return VRect(pos - vec, size); } 50 | // mul/div to scale to a different mapping 51 | inline VRect operator * (const Vector2 & vec) const { return VRect(pos * vec, size * vec); } 52 | inline VRect operator / (const Vector2 & vec) const { return VRect(pos / vec, size / vec); } 53 | 54 | inline VRect & operator += (const Vector2 & vec) { pos += vec; return *this; } 55 | inline VRect & operator -= (const Vector2 & vec) { pos -= vec; return *this; } 56 | 57 | inline explicit operator bool() { return pos && size; } 58 | 59 | static const VRect invalid; 60 | static const VRect zero; 61 | 62 | static const VRect touchScreen; 63 | static const VRect topScreen; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/Vector2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Vector2.h" 8 | 9 | using starlight::Vector2; 10 | 11 | // maths 12 | float Vector2::Length() const { return sqrtf(x * x + y * y); } 13 | Vector2 Vector2::Normalized() const { float m = Length(); return m == 0.0f ? Vector2::zero : Vector2(x / m, y / m); } 14 | 15 | Vector2 Vector2::ClampLength(float max) const { 16 | float len = Length(); 17 | return *this * (std::min(len, max) / len); 18 | } 19 | 20 | Vector2 Vector2::Reciprocal() const { return Vector2(y, x); } 21 | Vector2 Vector2::IntSnap() const { return Vector2(roundf(x), roundf(y)); } 22 | 23 | Vector2 Vector2::CardinalAxis() const { 24 | if (fabsf(x) > fabsf(y)) return h; 25 | return v; 26 | } 27 | Vector2 Vector2::Cardinal() const { return *this * CardinalAxis(); } 28 | 29 | Vector2 Vector2::Rotate(float angle) const { 30 | float s = sin(angle), c = cos(angle); 31 | return Vector2(x * c - y * s, x * s + y * c); 32 | } 33 | Vector2 Vector2::RotateAround(const Vector2& anchor, float angle) const { return (*this - anchor).Rotate(angle) + anchor; } 34 | 35 | // operators! 36 | //inline Vector2 operator *(const Vector2* vec, const float scalar) { return Vector2(vec.x * scalar, vec.y * scalar); } 37 | 38 | // constants 39 | const Vector2 Vector2::invalid = Vector2(std::numeric_limits::quiet_NaN()); 40 | 41 | const Vector2 Vector2::zero = Vector2(0.0f, 0.0f); 42 | const Vector2 Vector2::one = Vector2(1.0f, 1.0f); 43 | const Vector2 Vector2::half = Vector2(0.5f, 0.5f); 44 | 45 | const Vector2 Vector2::h = Vector2(1, 0); 46 | const Vector2 Vector2::v = Vector2(0, 1); 47 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/datatypes/Vector2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | namespace starlight { 5 | class Vector2 { 6 | private: 7 | // 8 | 9 | public: 10 | float x = 0.0f; 11 | float y = 0.0f; 12 | 13 | constexpr Vector2() = default; 14 | constexpr Vector2(float x, float y) : x(x), y(y) { } 15 | constexpr Vector2(float mag) : x(mag), y(mag) { } 16 | ~Vector2() = default; 17 | 18 | float Length() const; 19 | Vector2 Normalized() const; 20 | inline float Area() const { return x * y; } 21 | 22 | Vector2 ClampLength(float max = 1) const; 23 | 24 | Vector2 Reciprocal() const; 25 | Vector2 IntSnap() const; 26 | 27 | Vector2 CardinalAxis() const; 28 | Vector2 Cardinal() const; 29 | 30 | Vector2 Rotate(float angle) const; 31 | Vector2 RotateAround(const Vector2& anchor, float angle) const; 32 | 33 | inline bool operator == (const Vector2 & o) const { return x == o.x && y == o.y; } 34 | inline bool operator != (const Vector2 & o) const { return x != o.x || y != o.y; } 35 | 36 | inline Vector2 operator - () const { return *this * -1.0f; } 37 | 38 | inline Vector2 operator * (const float scalar) const { return Vector2(x * scalar, y * scalar); } 39 | inline Vector2 operator / (const float scalar) const { return Vector2(x / scalar, y / scalar); } 40 | 41 | inline Vector2 operator + (const Vector2 & o) const { return Vector2(x + o.x, y + o.y); } 42 | inline Vector2 operator - (const Vector2 & o) const { return Vector2(x - o.x, y - o.y); } 43 | inline Vector2 operator * (const Vector2 & o) const { return Vector2(x * o.x, y * o.y); } 44 | inline Vector2 operator / (const Vector2 & o) const { return Vector2(x / o.x, y / o.y); } 45 | 46 | inline Vector2 & operator *= (const float scalar) { x *= scalar; y *= scalar; return *this; } 47 | inline Vector2 & operator /= (const float scalar) { x /= scalar; y /= scalar; return *this; } // maybe reciprocate then multiply instead? maybe the compiler does that 48 | 49 | inline Vector2 & operator += (const Vector2 & o) { x += o.x; y += o.y; return *this; } 50 | inline Vector2 & operator -= (const Vector2 & o) { x -= o.x; y -= o.y; return *this; } 51 | inline Vector2 & operator *= (const Vector2 & o) { x *= o.x; y *= o.y; return *this; } 52 | 53 | inline bool Valid() const { return x == x && y == y; } 54 | inline explicit operator bool() const { return x == x && y == y; } 55 | 56 | static const Vector2 invalid; 57 | static const Vector2 zero; 58 | static const Vector2 one; 59 | static const Vector2 half; 60 | static const Vector2 h; 61 | static const Vector2 v; 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/dialog/Backdrop.cpp: -------------------------------------------------------------------------------- 1 | #include "Backdrop.h" 2 | 3 | #include "starlight/ui/Image.h" 4 | 5 | using starlight::ui::Image; 6 | 7 | using starlight::ui::Form; 8 | 9 | using starlight::dialog::Backdrop; 10 | 11 | Backdrop::Backdrop(std::string imgPath) : Form(true) { 12 | priority = -1000000; // it is, after all, a backdrop 13 | auto img = std::make_shared(VRect(0, 0, 400, 480), imgPath); 14 | topScreen->Add(img); 15 | touchScreen->Add(img); 16 | touchScreen->scrollOffset = Vector2(40, 240); 17 | } 18 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/dialog/Backdrop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "starlight/_global.h" 3 | 4 | #include 5 | 6 | #include "starlight/ThemeManager.h" 7 | 8 | #include "starlight/ui/Form.h" 9 | 10 | namespace starlight { 11 | namespace dialog { 12 | class Backdrop : public ui::Form, public ui::FormCreator { 13 | private: 14 | // 15 | 16 | public: 17 | Backdrop(std::string imgPath = "decorations/generic backdrop"); 18 | //~Backdrop() override { }; 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libstarlight/source/starlight/dialog/MessageBox.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageBox.h" 2 | 3 | #include "starlight/ThemeManager.h" 4 | #include "starlight/InputManager.h" 5 | 6 | #include "starlight/ui/Image.h" 7 | #include "starlight/ui/Button.h" 8 | #include "starlight/ui/Label.h" 9 | #include "starlight/ui/ScrollField.h" 10 | 11 | using starlight::InputManager; 12 | 13 | using starlight::ui::Image; 14 | using starlight::ui::Button; 15 | using starlight::ui::Label; 16 | using starlight::ui::ScrollField; 17 | 18 | using starlight::ui::Form; 19 | 20 | using starlight::dialog::MessageBox; 21 | 22 | MessageBox::MessageBox(Mode m, const std::string& msg, std::function onSelect) : Form(true) { 23 | priority = 10; 24 | eOnSelect = onSelect; 25 | 26 | VRect boxArea = VRect(160, 120, 0, 0).Expand(ThemeManager::GetMetric("/dialogs/messageBox/size")*.5); 27 | 28 | auto cover = std::make_shared(touchScreen->rect.Expand(4), "decorations/dialog.modal-cover"); 29 | cover->blockTouch = true; 30 | touchScreen->Add(cover); 31 | 32 | auto bg = std::make_shared(boxArea, "decorations/panel.bg"); 33 | touchScreen->Add(bg); 34 | auto scroll = std::make_shared(boxArea.Expand(-8, -8).TopEdge(boxArea.size.y - 16 - 32 - 8)); 35 | touchScreen->Add(scroll); 36 | auto label = std::make_shared