Compare commits

..

No commits in common. "master" and "v0.5.0" have entirely different histories.

69 changed files with 249 additions and 1346 deletions

1
.gitignore vendored
View File

@ -32,7 +32,6 @@
*.app *.app
*.elf *.elf
*.3dsx *.3dsx
*.cia
# ...and icons # ...and icons
*.smdh *.smdh

View File

@ -29,11 +29,9 @@ Additionally, libstarlight contains versions of the following bundled within:
* [nlohmann::json (JSON For Modern C++)](https://github.com/nlohmann/json) * [nlohmann::json (JSON For Modern C++)](https://github.com/nlohmann/json)
## Okay, so how do I use this? ## Okay, so how do I use this?
(section WIP, take a look at the testbed for a slightly scattered example) (section WIP, take a look at the testbed for a somewhat messy example)
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/`. 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`.
(Themes on SD go in `sdmc:/.starlight/themes/`)
## License ## License
* MIT (see [license.md](license.md)) * MIT (see [license.md](license.md))

View File

@ -30,7 +30,7 @@ INCLUDES := include
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
# why was -Werror here? # why was -Werror here?
CFLAGS := -g -Wall -Wno-psabi -O2 -mword-relocations \ CFLAGS := -g -Wall -O2 -mword-relocations \
-ffunction-sections \ -ffunction-sections \
-fomit-frame-pointer \ -fomit-frame-pointer \
$(ARCH) $(ARCH)
@ -38,7 +38,7 @@ CFLAGS := -g -Wall -Wno-psabi -O2 -mword-relocations \
CFLAGS += $(INCLUDE) -DARM11 -D_3DS CFLAGS += $(INCLUDE) -DARM11 -D_3DS
# json requires exception support, nuke -fno-exceptions # json requires exception support, nuke -fno-exceptions
CXXFLAGS := $(CFLAGS) -fno-rtti -std=c++17 CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++14
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)

View File

@ -17,9 +17,6 @@ using starlight::ThemeManager;
using starlight::InputManager; using starlight::InputManager;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
using starlight::threading::Thread;
using starlight::threading::ThreadState;
using starlight::ui::TouchScreenCanvas; using starlight::ui::TouchScreenCanvas;
using starlight::ui::TopScreenCanvas; using starlight::ui::TopScreenCanvas;
@ -33,7 +30,6 @@ using starlight::Application;
//////////////////// ////////////////////
Application* Application::_currentApp = nullptr; Application* Application::_currentApp = nullptr;
unsigned long long Application::ftime = 0;
bool Application::Quit() { bool Application::Quit() {
if (_currentApp == nullptr) return false; if (_currentApp == nullptr) return false;
@ -86,9 +82,6 @@ void Application::_init() {
void Application::_end() { void Application::_end() {
End(); End();
for (auto& thread : threads) thread->Exit();
threads.clear();
//for (auto& f : forms) f->Close(); //for (auto& f : forms) f->Close();
forms.clear(); // not sure why, but not doing this results in a data abort if any forms are active forms.clear(); // not sure why, but not doing this results in a data abort if any forms are active
@ -104,9 +97,6 @@ void Application::_end() {
} }
void Application::_mainLoop() { void Application::_mainLoop() {
RenderCore::SyncFrame(); // sync to vblank here for more accurate timing
frameTimer.FrameStart();
if (!forms.empty()) { if (!forms.empty()) {
if (_sFormState) { if (_sFormState) {
_sFormState = false; _sFormState = false;
@ -134,8 +124,6 @@ void Application::_mainLoop() {
} }
// update step // update step
ftime = osGetTime();
InputManager::Update(); InputManager::Update();
Update(); Update();
{ // update loop for forms, guarded from snap-outs { // update loop for forms, guarded from snap-outs
@ -163,16 +151,4 @@ void Application::_mainLoop() {
topScreen->Draw(); topScreen->Draw();
PostDraw(); PostDraw();
RenderCore::EndFrame(); RenderCore::EndFrame();
while (!threads.empty() && frameTimer.GetSubframe() < 0.9) {
auto thread = threads.front();
thread->Resume();
if (thread->state != ThreadState::Finished) threads.splice(threads.end(), threads, threads.begin()); // move to back of queue
else threads.pop_front(); // or just discard if already exited
}
}
void Application::EnqueueThread(std::shared_ptr<starlight::threading::Thread> thread) {
threads.push_back(thread);
thread->Start();
} }

View File

@ -3,16 +3,11 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <list>
#include "starlight/datatypes/Vector2.h" #include "starlight/datatypes/Vector2.h"
#include "starlight/datatypes/VRect.h" #include "starlight/datatypes/VRect.h"
#include "starlight/datatypes/Color.h" #include "starlight/datatypes/Color.h"
#include "starlight/util/FrameTimer.h"
#include "starlight/threading/Thread.h"
#include "starlight/ui/TouchScreenCanvas.h" #include "starlight/ui/TouchScreenCanvas.h"
#include "starlight/ui/TopScreenCanvas.h" #include "starlight/ui/TopScreenCanvas.h"
@ -27,14 +22,12 @@ namespace starlight {
//////////////////// ////////////////////
private: private:
static Application* _currentApp; static Application* _currentApp;
static unsigned long long ftime;
public: public:
static bool Quit(); static bool Quit();
static Config& GetConfig(const std::string& path); static Config& GetConfig(const std::string& path);
static std::string AppName(); static std::string AppName();
static inline Application* Current() { return _currentApp; } static inline Application* Current() { return _currentApp; }
static inline unsigned long long GetTime() { return ftime; }
////////////////////// //////////////////////
// INSTANCE MEMBERS // // INSTANCE MEMBERS //
@ -46,9 +39,6 @@ namespace starlight {
void _mainLoop(); void _mainLoop();
void _end(); void _end();
std::list<std::shared_ptr<threading::Thread>> threads;
util::FrameTimer frameTimer;
public: public:
const std::string appId; const std::string appId;
@ -67,14 +57,13 @@ namespace starlight {
void Run(); void Run();
void EnqueueThread(std::shared_ptr<threading::Thread> thread);
inline void SignalFormState() { _sFormState = true; }
virtual void Init() { } virtual void Init() { }
virtual void Update() { } virtual void Update() { }
virtual void PostUpdate() { } virtual void PostUpdate() { }
virtual void Draw() { } virtual void Draw() { }
virtual void PostDraw() { } virtual void PostDraw() { }
virtual void End() { } virtual void End() { }
inline void SignalFormState() { _sFormState = true; }
}; };
} }

View File

@ -43,9 +43,6 @@ enum class Keys : unsigned int {
Right = DPadRight | CPadRight, ///< D-Pad Right or Circle Pad Right Right = DPadRight | CPadRight, ///< D-Pad Right or Circle Pad Right
}; };
inline constexpr unsigned int operator*(Keys k) { return static_cast<unsigned int>(k); }
inline constexpr Keys operator|(Keys k1, Keys k2) { return static_cast<Keys>(*k1 | *k2); }
namespace starlight { namespace starlight {
// forward declare this for OpenKeyboard // forward declare this for OpenKeyboard
namespace dialog { namespace dialog {
@ -97,11 +94,11 @@ namespace starlight {
static Vector2 CStick(); static Vector2 CStick();
static bool Held(unsigned int mask); static bool Held(unsigned int mask);
static inline bool Held(Keys mask) { return Held(*mask); } static inline bool Held(Keys mask) { return Held(static_cast<unsigned int>(mask)); }
static bool Pressed(unsigned int mask); static bool Pressed(unsigned int mask);
static inline bool Pressed(Keys mask) { return Pressed(*mask); } static inline bool Pressed(Keys mask) { return Pressed(static_cast<unsigned int>(mask)); }
static bool Released(unsigned int mask); static bool Released(unsigned int mask);
static inline bool Released(Keys mask) { return Released(*mask); } static inline bool Released(Keys mask) { return Released(static_cast<unsigned int>(mask)); }
static Vector2 TouchPos(); static Vector2 TouchPos();
static Vector2 TouchDelta(); static Vector2 TouchDelta();

View File

@ -19,17 +19,12 @@
#include "starlight/gfx/DrawableNinePatch.h" #include "starlight/gfx/DrawableNinePatch.h"
#include "starlight/gfx/DrawableTest.h" #include "starlight/gfx/DrawableTest.h"
#include "starlight/gfx/FontBMF.h" #include "starlight/gfx/FontBMF.h"
#include "starlight/gfx/FontNull.h"
#include "starlight/gfx/RenderCore.h" #include "starlight/gfx/RenderCore.h"
#include "starlight/gfx/BitmapFont.h" #include "starlight/gfx/BitmapFont.h"
#include "starlight/util/JsonConversions.h" #include "starlight/util/JsonConversions.h"
#include "starlight/util/Profiler.h"
using starlight::util::Profiler;
#include <sstream>
using std::string; using std::string;
using std::shared_ptr; using std::shared_ptr;
using std::make_shared; using std::make_shared;
@ -80,48 +75,40 @@ namespace {
} }
CTexture* LoadPNG(const std::string& path, bool isPremult = false) { CTexture* LoadPNG(const std::string& path, bool isPremult = false) {
//Profiler::TaskStart();
unsigned char* imgbuf; unsigned char* imgbuf;
unsigned width, height; unsigned width, height;
lodepng::State state;
lodepng_decode32_file(&imgbuf, &width, &height, path.c_str()); lodepng_decode32_file(&imgbuf, &width, &height, path.c_str());
if (state.info_png.color.colortype != 6) isPremult = true; // expect no alpha if not rgba
/*{
std::stringstream ss; ss << "loaded png, ";
ss << width; ss << "x"; ss << height;
Profiler::TaskFinish(ss.str());
}*/
unsigned bw = NextPow2(width), bh = NextPow2(height); unsigned bw = NextPow2(width), bh = NextPow2(height);
u8* gpubuf = static_cast<u8*>(linearAlloc(bw*bh*4)); u8* gpubuf = static_cast<u8*>(linearAlloc(bw*bh*4));
//Profiler::TaskStart();
//memset(gpubuf, 0, bw*bh*4);
//Profiler::TaskFinish("cleared canvas");
u8* src = static_cast<u8*>(imgbuf); u8* dst = static_cast<u8*>(gpubuf);
//Profiler::TaskStart();
if (isPremult) { if (isPremult) {
u32* src = reinterpret_cast<u32*>(imgbuf); u32* dst = reinterpret_cast<u32*>(gpubuf);
// just convert endianness // just convert endianness
for(unsigned iy = 0; iy < height; iy++) { for(unsigned iy = 0; iy < height; iy++) {
for (unsigned ix = 0; ix < width; ix++) { for (unsigned ix = 0; ix < width; ix++) {
u32 clr = *src; int r = *src++;
*dst = __builtin_bswap32(clr); int g = *src++;
int b = *src++;
int a = *src++;
src+=4; dst+=4; *dst++ = a;
*dst++ = b;
*dst++ = g;
*dst++ = r;
} }
dst += (bw - width) * 4; // skip the difference dst += (bw - width) * 4; // skip the difference
} }
} else { } else {
u8* src = static_cast<u8*>(imgbuf); u8* dst = static_cast<u8*>(gpubuf);
// convert and premultiply // convert and premultiply
for(unsigned iy = 0; iy < height; iy++) { for(unsigned iy = 0; iy < height; iy++) {
for (unsigned ix = 0; ix < width; ix++) { for (unsigned ix = 0; ix < width; ix++) {
u8 r = *src++; int r = *src++;
u8 g = *src++; int g = *src++;
u8 b = *src++; int b = *src++;
u8 a = *src++; int a = *src++;
float aa = (1.0f / 255.0f) * a; float aa = (1.0f / 255.0f) * a;
@ -133,14 +120,11 @@ namespace {
dst += (bw - width) * 4; // skip the difference dst += (bw - width) * 4; // skip the difference
} }
} }
//Profiler::TaskFinish("made into canvas, flipped and premult");
// completely skipping over the difference instead of erasing might eventually lead to garbage outside of frame, // completely skipping over the difference instead of erasing might eventually lead to garbage outside of frame,
// but meh; that'll only be visible if you intentionally push the UVs outside the image proper // but meh; that'll only be visible if you intentionally push the UVs outside the image proper
//Profiler::TaskStart();
CTexture* tx = RenderCore::LoadTexture(static_cast<void*>(gpubuf), bw, bh); CTexture* tx = RenderCore::LoadTexture(static_cast<void*>(gpubuf), bw, bh);
tx->size = Vector2(width, height); // and for now just fix the size after the fact tx->size = Vector2(width, height); // and for now just fix the size after the fact
//Profiler::TaskFinish("copied into linear");
std::free(imgbuf); std::free(imgbuf);
linearFree(gpubuf); linearFree(gpubuf);
@ -195,20 +179,6 @@ void ThemeManager::End() {
} }
void ThemeManager::GC() {
constexpr const int keepCycles = 5; // how many gc sweeps a drawable gets to stay loaded without being used
std::vector<string> rem;
// WIP
for (auto& d : drawables) {
if (++d.second.lastAccess > keepCycles) {
d.second.Unload();
if (d.second.refCount <= 0) rem.push_back(d.first); // mark for full removal when no references exist
}
}
for (auto& s : rem) drawables.erase(s); // and remove everything queued
}
ThemeRef<Drawable> ThemeManager::GetAsset(const std::string& name) { ThemeRef<Drawable> ThemeManager::GetAsset(const std::string& name) {
auto const& itr = drawables.find(name); auto const& itr = drawables.find(name);
if (itr == drawables.end()) { if (itr == drawables.end()) {
@ -225,14 +195,14 @@ ThemeRef<Font> ThemeManager::GetFont(const std::string& name) {
void ThemeManager::Fulfill(ThemeRefContainer<Drawable>& ref) { void ThemeManager::Fulfill(ThemeRefContainer<Drawable>& ref) {
string path = ResolveAssetPath(ref.name); string path = ResolveAssetPath(ref.name);
ref.ptr = LoadAsset(path, ref); ref.ptr = LoadAsset(path);
} }
shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Drawable>& ref) { shared_ptr<Drawable> ThemeManager::LoadAsset(string& path) {
static shared_ptr<Drawable> nulldrw = make_shared<starlight::gfx::DrawableTest>(); static shared_ptr<Drawable> nulldrw = make_shared<starlight::gfx::DrawableTest>();
string ext = FindExtension(path); string ext = FindExtension(path);
//printf("load: %s (%s)\n", path.c_str(), ext.c_str()); printf("load: %s (%s)\n", path.c_str(), ext.c_str());
/**/ if (ext == "png") { /**/ if (ext == "png") {
return make_shared<DrawableImage>(LoadPNG(path)); return make_shared<DrawableImage>(LoadPNG(path));
} }
@ -243,7 +213,7 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
fs >> j; fs >> j;
} }
auto st = j.dump(); auto st = j.dump();
//printf("file contents: %s\n", st.c_str()); printf("file contents: %s\n", st.c_str());
string type = j["assetType"]; string type = j["assetType"];
/**/ if (type == "ninepatch") { /**/ if (type == "ninepatch") {
@ -255,8 +225,9 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
// else if (type == "") { } // else if (type == "") { }
else if (type == "link") { else if (type == "link") {
string npath = ResolveAssetPath(j["path"]); string npath = ResolveAssetPath(j["path"]);
ref.redir = const_cast<ThemeRefContainer<Drawable>*>(GetAsset(npath).cptr); // link containers directly //return LoadAsset(npath);
return nulldrw; // doesn't really matter what's inside, it'll never get used return GetAsset(npath).GetShared(); // I guess this works; may need to be altered for asynchronity if I do that later
// (perhaps by--wait no, making it the same ThemeRefContainer would require a full rearchitecture of this part @.@)
} }
return nulldrw; return nulldrw;
} }
@ -265,10 +236,6 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
void ThemeManager::Fulfill(ThemeRefContainer<Font>& ref) { void ThemeManager::Fulfill(ThemeRefContainer<Font>& ref) {
string path = ResolveFontPath(ref.name); string path = ResolveFontPath(ref.name);
if (path == "") { // no fonts found, emergency fallback
ref.ptr = make_shared<starlight::gfx::FontNull>();
return;
}
auto font = make_shared<starlight::gfx::FontBMF>(); auto font = make_shared<starlight::gfx::FontBMF>();
{ // using: { // using:
json j; json j;
@ -291,100 +258,54 @@ void ThemeManager::LoadProc() {
} }
string ThemeManager::ResolveAssetPath(const string& id) { string ThemeManager::ResolveAssetPath(const string& id) {
string pfx = ""; //struct stat buf;
//string path(id.length() + 64, ' '); // preallocate buffer space
size_t cpos = id.find(":/"); static const string pfxLocal = "app:/";
if (cpos != string::npos) { if (id.compare(0, pfxLocal.length(), pfxLocal) == 0) {
pfx = id.substr(0, cpos);
cpos += 2;
} else cpos = 0;
if (pfx == "app") {
string sid = id.substr(cpos); // strip off the "app:/"
// app-local asset // app-local asset
// check if present in theme/app/[appname]/, else check in romfs // check if present in theme/app/[appname]/, else check in romfs
for (auto thm : themeData) { for (auto thm : themeData) {
Path bp = thm.basePath.Combine("app").Combine(Application::AppName()); Path bp = thm.basePath.Combine("app").Combine(Application::AppName());
Path p = bp.Combine(sid); Path p = bp.Combine(id+".json");
if (p.IsFile()) return p; if (p.IsFile()) return p;
p = bp.Combine(sid+".json"); p = bp.Combine(id+".png");
if (p.IsFile()) return p;
p = bp.Combine(sid+".png");
if (p.IsFile()) return p; if (p.IsFile()) return p;
} }
// TBD - directly in romfs, or in an assets folder? // TBD - directly in romfs, or in an assets folder?
Path bp = Path("romfs:/"); Path bp = Path("romfs:");
Path p = bp.Combine(sid); Path p = bp.Combine(id+".json");
if (p.IsFile()) return p; if (p.IsFile()) return p;
p = bp.Combine(sid+".json"); p = bp.Combine(id+".png");
if (p.IsFile()) return p;
p = bp.Combine(sid+".png");
if (p.IsFile()) return p;
}
else if (pfx == "sdmc" || pfx == "romfs") {
Path p = Path(id);
if (p.IsFile()) return p;
p = Path(id + ".json");
if (p.IsFile()) return p;
p = Path(id + ".png");
if (p.IsFile()) return p; if (p.IsFile()) return p;
} }
else { else {
// theme asset; check in each theme from selected to most-fallback // theme asset; check in each theme from selected to most-fallback
for (auto thm : themeData) { for (auto thm : themeData) {
Path p = thm.basePath.Combine(id); Path p = thm.basePath.Combine(id+".json");
if (p.IsFile()) return p;
p = thm.basePath.Combine(id+".json");
if (p.IsFile()) return p; if (p.IsFile()) return p;
p = thm.basePath.Combine(id+".png"); p = thm.basePath.Combine(id+".png");
if (p.IsFile()) return p; if (p.IsFile()) return p;
} }
} }
/*path.clear(); path.append("romfs:/"); path.append(id); path.append(".json");
printf("attempt: %s\n", path.c_str());
if (stat(path.c_str(), &buf) == 0) return path;
path.erase(path.end()-5, path.end()); path.append(".png");
printf("attempt: %s\n", path.c_str());
if (stat(path.c_str(), &buf) == 0) return path;//*/
return string(); return string();
} }
string ThemeManager::ResolveFontPath(const string& id) { // there we go, nice and simple string ThemeManager::ResolveFontPath(const string& id) { // there we go, nice and simple
string pfx = ""; for (auto thm : themeData) {
Path p = thm.basePath.Combine("fonts").Combine(id+".json");
size_t cpos = id.find(":/");
if (cpos != string::npos) {
pfx = id.substr(0, cpos);
cpos += 2;
} else cpos = 0;
if (pfx == "app") {
string sid = id.substr(cpos); // strip off the "app:/"
// app-local asset
// check if present in theme/app/[appname]/fonts/, else check in romfs
for (auto thm : themeData) {
Path bp = thm.basePath.Combine("app").Combine(Application::AppName()).Combine("fonts");
Path p = bp.Combine(sid+".json");
if (p.IsFile()) return p;
}
// TBD - directly in romfs, or in an assets folder?
Path bp = Path("romfs:/fonts/");
Path p = bp.Combine(sid+".json");
if (p.IsFile()) return p; if (p.IsFile()) return p;
} }
else if (pfx == "sdmc" || pfx == "romfs") {
// no forced "fonts" here, of course; this is an actual path
Path p = Path(id + ".json");
if (p.IsFile()) return p;
}
else {
// theme asset; check in each theme from selected to most-fallback
for (auto thm : themeData) {
Path p = thm.basePath.Combine("fonts").Combine(id+".json");
if (p.IsFile()) return p;
}
}
// I guess fall back to 12px monospace if it's just nowhere to be found return string();
const string fallback = "mono.12";
if (id != fallback) return ResolveFontPath(fallback);
return string(); // fallback not found; no themes on sdmc or romfs, probably
} }
json& ThemeManager::GetMetric(const string& path) { json& ThemeManager::GetMetric(const string& path) {

View File

@ -48,15 +48,13 @@ namespace starlight {
static void Fulfill(gfx::ThemeRefContainer<gfx::Drawable>& ref); static void Fulfill(gfx::ThemeRefContainer<gfx::Drawable>& ref);
static void Fulfill(gfx::ThemeRefContainer<gfx::Font>& ref); static void Fulfill(gfx::ThemeRefContainer<gfx::Font>& ref);
static std::shared_ptr<gfx::Drawable> LoadAsset(std::string& path, gfx::ThemeRefContainer<gfx::Drawable>& ref); static std::shared_ptr<gfx::Drawable> LoadAsset(std::string& path);
public: public:
ThemeManager() = delete; // "static" class ThemeManager() = delete; // "static" class
static void Init(); static void Init();
static void End(); static void End();
static void GC();
static gfx::ThemeRef<gfx::Drawable> GetAsset(const std::string& name); static gfx::ThemeRef<gfx::Drawable> GetAsset(const std::string& name);
static gfx::ThemeRef<gfx::Font> GetFont(const std::string& name); static gfx::ThemeRef<gfx::Font> GetFont(const std::string& name);
@ -87,17 +85,6 @@ namespace starlight {
TextConfig(const std::string& fontName, Color text, Color border = Color::transparent); TextConfig(const std::string& fontName, Color text, Color border = Color::transparent);
~TextConfig() = default; ~TextConfig() = default;
TextConfig(const TextConfig& o) : textColor(o.textColor), borderColor(o.borderColor), justification(o.justification) { font = o.font; }
TextConfig(const TextConfig&& o) : textColor(o.textColor), borderColor(o.borderColor), justification(o.justification) { font = o.font; }
TextConfig& operator =(const TextConfig& o) {
font = o.font; textColor = o.textColor; borderColor = o.borderColor; justification = o.justification;
return *this;
}
TextConfig& operator =(const TextConfig&& o) {
font = o.font; textColor = o.textColor; borderColor = o.borderColor; justification = o.justification;
return *this;
}
void Print(Vector2 position, const std::string& text, Vector2 justification = Vector2::invalid); void Print(Vector2 position, const std::string& text, Vector2 justification = Vector2::invalid);
void Print(VRect rect, const std::string& text, Vector2 justification = Vector2::invalid); void Print(VRect rect, const std::string& text, Vector2 justification = Vector2::invalid);

View File

@ -1,13 +1,9 @@
#include "Color.h" #include "Color.h"
#include <limits>
#include "starlight/_incLib/json.hpp" #include "starlight/_incLib/json.hpp"
using starlight::Color; using starlight::Color;
const Color Color::invalid = Color(std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN());
const Color Color::transparent = Color(0.0f, 0.0f, 0.0f, 0.0f); const Color Color::transparent = Color(0.0f, 0.0f, 0.0f, 0.0f);
const Color Color::white = Color(1.0f, 1.0f, 1.0f); const Color Color::white = Color(1.0f, 1.0f, 1.0f);
const Color Color::black = Color(0.0f, 0.0f, 0.0f); const Color Color::black = Color(0.0f, 0.0f, 0.0f);

View File

@ -25,17 +25,11 @@ namespace starlight {
inline bool operator != (const Color& o) const { return r != o.r || g != o.g || b != o.b || a != o.a; } inline bool operator != (const Color& o) const { return r != o.r || g != o.g || b != o.b || a != o.a; }
inline Color operator * (const Color& o) const { return Color(r * o.r, g * o.g, b * o.b, a * o.a); } inline Color operator * (const Color& o) const { return Color(r * o.r, g * o.g, b * o.b, a * o.a); }
//inline Color operator * (const float m) const { return Color(r * m, g * m, b * m, a * m); }
// hmm. I guess this will do ¯\_(ツ)_/¯ don't really want to force cstdint // hmm. I guess this will do ¯\_(ツ)_/¯ don't really want to force cstdint
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)); } 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)); }
// 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)); } // 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)); }
inline bool Valid() const { return a == a && r == r && g == g && b == b; }
inline explicit operator bool() const { return a == a && r == r && g == g && b == b; }
static const Color invalid;
static const Color transparent; static const Color transparent;
static const Color white; static const Color white;
static const Color black; static const Color black;

View File

@ -1,64 +0,0 @@
#pragma once
#include "starlight/_global.h"
#include <memory>
#include <functional>
namespace starlight {
template<typename T>
class Optional {
private:
std::unique_ptr<T> p = nullptr;
std::function<T&()>* getdef = nullptr;
inline void initp() {
if (!p) {
p = std::make_unique<T>();
if (getdef) *p = (*getdef)();
}
}
public:
Optional<T>() = default;
Optional<T>(std::function<T&()>* getDefault) : getdef(getDefault) { }
Optional<T>(nullptr_t) : p(nullptr) { }
Optional<T>(const Optional<T>& o) { // copy operator *actually copies the inner object*
if (o.p) {
p = std::make_unique<T>();
*p = *o.p;
}
getdef = o.getdef;
}
Optional<T>& operator=(const nullptr_t&) { p.reset(); return *this; }
Optional<T>& operator=(const T& o) { // assign by type's assignment operator if passed a "value"
if (!p) p = std::make_unique<T>();
*p = o;
return *this;
}
T& operator *() {
initp();
return *p;
}
T* operator ->() {
initp();
return &*p;
}
inline T& Get(T& defaultRef) {
if (p) return *p;
return defaultRef;
}
inline T& ROGet() {
if (p) return *p;
if (getdef) return (*getdef)();
static T fb; return fb; // meh, hackish but you shouldn't do this without a getdef anyway
// 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)
}
//
};
}

View File

@ -1,6 +1,5 @@
#include <cstdlib> #include <cstdlib>
#include <cmath> #include <cmath>
#include <algorithm>
#include <fastmath.h> #include <fastmath.h>
#include <limits> #include <limits>
@ -12,11 +11,6 @@ using starlight::Vector2;
float Vector2::Length() const { return sqrtf(x * x + y * y); } float Vector2::Length() const { return sqrtf(x * x + y * y); }
Vector2 Vector2::Normalized() const { float m = Length(); return m == 0.0f ? Vector2::zero : Vector2(x / m, y / m); } Vector2 Vector2::Normalized() const { float m = Length(); return m == 0.0f ? Vector2::zero : Vector2(x / m, y / m); }
Vector2 Vector2::ClampLength(float max) const {
float len = Length();
return *this * (std::min(len, max) / len);
}
Vector2 Vector2::Reciprocal() const { return Vector2(y, x); } Vector2 Vector2::Reciprocal() const { return Vector2(y, x); }
Vector2 Vector2::IntSnap() const { return Vector2(roundf(x), roundf(y)); } Vector2 Vector2::IntSnap() const { return Vector2(roundf(x), roundf(y)); }

View File

@ -19,8 +19,6 @@ namespace starlight {
Vector2 Normalized() const; Vector2 Normalized() const;
inline float Area() const { return x * y; } inline float Area() const { return x * y; }
Vector2 ClampLength(float max = 1) const;
Vector2 Reciprocal() const; Vector2 Reciprocal() const;
Vector2 IntSnap() const; Vector2 IntSnap() const;
@ -49,8 +47,7 @@ namespace starlight {
inline Vector2 & operator += (const Vector2 & o) { x += o.x; y += o.y; return *this; } inline Vector2 & operator += (const Vector2 & o) { x += o.x; y += o.y; return *this; }
inline Vector2 & operator -= (const Vector2 & o) { x -= o.x; y -= o.y; return *this; } inline Vector2 & operator -= (const Vector2 & o) { x -= o.x; y -= o.y; return *this; }
inline Vector2 & operator *= (const Vector2 & o) { x *= o.x; y *= o.y; return *this; } inline Vector2 & operator *= (const Vector2 & o) { x *= o.x; y *= o.y; return *this; }
inline bool Valid() const { return x == x && y == y; }
inline explicit operator bool() const { return x == x && y == y; } inline explicit operator bool() const { return x == x && y == y; }
static const Vector2 invalid; static const Vector2 invalid;

View File

@ -37,10 +37,6 @@ namespace {
return tc; return tc;
} }
inline bool ShiftScroll(Keys k) {
return InputManager::Pressed(k) || (InputManager::Held(Keys::L | Keys::R) && InputManager::Held(k));
}
const constexpr float textHang = 4; const constexpr float textHang = 4;
} }
@ -48,13 +44,14 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
priority = 1000; // probably don't want all that much displaying above the keyboard priority = 1000; // probably don't want all that much displaying above the keyboard
handler->parent = this; handler->parent = this;
auto cover = touchScreen->AddNew<Image>(touchScreen->rect, "decorations/osk.background"); auto cover = std::make_shared<Image>(touchScreen->rect, "decorations/osk.background");
cover->blockTouch = true; cover->blockTouch = true;
touchScreen->Add(cover);
// build keyboard // wip
//setContainer = touchScreen->AddNew<ui::UIContainer>(VRect::touchScreen); // kept as a test case setContainer = std::make_shared<ui::UIContainer>(VRect::touchScreen);
setContainer = touchScreen->AddNew<ui::UICanvas>(VRect::touchScreen); // but this is much more efficient touchScreen->Add(setContainer);
auto actSym = [this](Button& key){ auto actSym = [this](Button& key){
this->handler->InputSymbol(key.label); this->handler->InputSymbol(key.label);
@ -77,16 +74,18 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
bpen = bpstart + Vector2(linestart[line] * bs.x, bs.y * line); bpen = bpstart + Vector2(linestart[line] * bs.x, bs.y * line);
} else { } else {
// lower // lower
auto key = setContainer->AddNew<Button>(VRect(bpen, bs)); auto key = std::make_shared<Button>(VRect(bpen, bs));
if (c == ' ') key->rect.size.x *= 6; if (c == ' ') key->rect.size.x *= 6;
key->SetText(string(1, c)); key->SetText(string(1, c));
key->eOnTap = actSym; key->eOnTap = actSym;
setContainer->Add(key);
// upper // upper
key = setContainer->AddNew<Button>(VRect(bpen + Vector2(0, 1000), bs)); key = std::make_shared<Button>(VRect(bpen + Vector2(0, 1000), bs));
if (C == ' ') key->rect.size.x *= 6; if (C == ' ') key->rect.size.x *= 6;
key->SetText(string(1, C)); key->SetText(string(1, C));
key->eOnTap = actSym; key->eOnTap = actSym;
setContainer->Add(key);
// and after // and after
bpen.x += key->rect.size.x; bpen.x += key->rect.size.x;
@ -95,30 +94,26 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
// backspace // backspace
bpen = bpstart + bs * Vector2(linestart[3] + 10, 3); bpen = bpstart + bs * Vector2(linestart[3] + 10, 3);
auto key = touchScreen->AddNew<Button>(VRect(bpen, bs)); auto key = std::make_shared<Button>(VRect(bpen, bs));
key->rect.size.x *= 1.25; key->rect.size.x *= 1.25;
key->style.glyph = ThemeManager::GetAsset("glyphs/backspace.small"); key->SetText("< <");
key->eOnTap = [this](auto& btn){ this->handler->Backspace(); this->OnKey(); }; key->eOnTap = [this](auto& btn){ this->handler->Backspace(); this->OnKey(); };
touchScreen->Add(key);
// enter // enter
bpen = bpstart + bs * Vector2(linestart[4] + 8, 4); bpen = bpstart + bs * Vector2(linestart[4] + 8, 4);
key = touchScreen->AddNew<Button>(VRect(bpen, bs)); key = std::make_shared<Button>(VRect(bpen, bs));
key->rect.size.x *= 2.5; key->rect.size.x *= 2.5;
key->style.glyph = ThemeManager::GetAsset("glyphs/enter.large"); key->SetText("Enter");
key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); }; key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); };
touchScreen->Add(key);
// shift previewSc = std::make_shared<ScrollField>(VRect(VRect::touchScreen.TopEdge(66)));
bpen = bpstart + bs * Vector2(linestart[0] + .25, 4); touchScreen->Add(previewSc);
key = touchScreen->AddNew<Button>(VRect(bpen, bs));
key->rect.size.x = bs.x * (linestart[4] - linestart[0] - .25);
key->style.glyph = ThemeManager::GetAsset("glyphs/shift.large");
key->eOnTap = [this](auto& btn){ this->shiftLock ^= true; };
shiftKey = key;
previewSc = touchScreen->AddNew<ScrollField>(VRect(VRect::touchScreen.TopEdge(66))); preview = std::make_shared<DrawLayerProxy>(VRect::touchScreen.TopEdge(66).Expand(-2, 0), [this](auto& layer){ this->DrawPreview(layer); }, true);
preview = previewSc->AddNew<DrawLayerProxy>(VRect::touchScreen.TopEdge(66).Expand(-2, 0), [this](auto& layer){ this->DrawPreview(layer); }, true);
preview->eOnTap = [this](auto& layer){ this->OnPreviewTap(layer); }; preview->eOnTap = [this](auto& layer){ this->OnPreviewTap(layer); };
previewSc->Add(preview);
RefreshPreview(); RefreshPreview();
} }
@ -129,57 +124,46 @@ void OSK::Update(bool focused) {
return; return;
} }
if (focused) { if (focused) {
if (InputManager::Pressed(Keys::B | Keys::Start)) handler->Done(); if (InputManager::Pressed(Keys::B)) handler->Done();
if (handler->showPreview) { if (handler->showPreview) {
auto& tc = PreviewTC(); if (InputManager::Pressed(Keys::DPadLeft)) {
bool refresh = false;
if (ShiftScroll(Keys::DPadLeft)) {
auto c = handler->GetCursor(); auto c = handler->GetCursor();
if (c > 0) handler->SetCursor(c - 1); if (c > 0) handler->SetCursor(c - 1);
refresh = true; RefreshPreview();
} }
if (ShiftScroll(Keys::DPadRight)) { if (InputManager::Pressed(Keys::DPadRight)) {
handler->SetCursor(handler->GetCursor() + 1); handler->SetCursor(handler->GetCursor() + 1);
refresh = true; RefreshPreview();
} }
if (ShiftScroll(Keys::DPadUp)) {
auto& tc = PreviewTC();
if (InputManager::Pressed(Keys::DPadUp)) {
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor()); Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
pt.y -= tc.Measure("|").y * 0.5f; pt.y -= tc.Measure("|").y * 0.5f;
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt)); handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
refresh = true; RefreshPreview();
} }
if (ShiftScroll(Keys::DPadDown)) { if (InputManager::Pressed(Keys::DPadDown)) {
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor()); Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
pt.y += tc.Measure("|").y * 1.5f; pt.y += tc.Measure("|").y * 1.5f;
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt)); handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
refresh = true; RefreshPreview();
} }
if (refresh) RefreshPreview();
} }
float& s = setContainer->scrollOffset.y; float& s = setContainer->scrollOffset.y;
float ts = 0; float ts = 0;
if (InputManager::Held(Keys::L) || InputManager::Held(Keys::R)) { if (InputManager::Held(Keys::L) || InputManager::Held(Keys::R)) {
ts = 1000; ts = 1000;
shiftLock = false; }
} else if (shiftLock) ts = 1000;
if (s != ts) { if (s != ts) {
s = ts; s = ts;
setContainer->MarkForRedraw(); setContainer->MarkForRedraw();
if (ts > 0) {
static TextConfig stc = ThemeManager::GetMetric<starlight::TextConfig>("/dialogs/OSK/keyHighlight");
shiftKey->style.textConfig = stc;
} else {
shiftKey->style.textConfig = nullptr;
}
} }
} }
} }
void OSK::OnKey() { void OSK::OnKey() {
shiftLock = false;
RefreshPreview(); RefreshPreview();
} }

View File

@ -6,7 +6,6 @@
#include <memory> #include <memory>
#include "starlight/ui/Form.h" #include "starlight/ui/Form.h"
#include "starlight/ui/Button.h"
#include "starlight/ui/ScrollField.h" #include "starlight/ui/ScrollField.h"
#include "starlight/ui/DrawLayerProxy.h" #include "starlight/ui/DrawLayerProxy.h"
@ -20,10 +19,7 @@ namespace starlight {
std::shared_ptr<ui::ScrollField> previewSc; std::shared_ptr<ui::ScrollField> previewSc;
std::shared_ptr<ui::DrawLayerProxy> preview; std::shared_ptr<ui::DrawLayerProxy> preview;
std::shared_ptr<ui::Button> shiftKey;
//Vector2 cursorPos; //Vector2 cursorPos;
bool shiftLock = false;
public: public:
std::unique_ptr<osk::InputHandler> handler; std::unique_ptr<osk::InputHandler> handler;

View File

@ -45,7 +45,7 @@ void DrawContextCanvas::Clear(Color color) {
void DrawContextCanvas::Clear() { Clear(Color(0,0,0,0)); } void DrawContextCanvas::Clear() { Clear(Color(0,0,0,0)); }
// drawable stuff // drawable stuff
void DrawContextCanvas::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale, BlendMode mode) { void DrawContextCanvas::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
target->Bind(color ? color.get() : Color(1,1,1,1)); target->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : this->rect; const VRect& sr = sampleRect ? sampleRect.get() : this->rect;
@ -54,7 +54,7 @@ void DrawContextCanvas::Draw(const Vector2& position, const Vector2& origin, Opt
} }
} }
void DrawContextCanvas::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color, BlendMode mode) { void DrawContextCanvas::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
target->Bind(color ? color.get() : Color(1,1,1,1)); target->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : this->rect; const VRect& sr = sampleRect ? sampleRect.get() : this->rect;

View File

@ -23,8 +23,8 @@ namespace starlight {
DrawContextCanvas(Vector2 size); DrawContextCanvas(Vector2 size);
~DrawContextCanvas(); ~DrawContextCanvas();
void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one, BlendMode mode = BlendMode::Normal) override; void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) override;
void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, BlendMode mode = BlendMode::Normal) override; void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr) override;
Vector2 Size() override; Vector2 Size() override;
@ -32,4 +32,4 @@ namespace starlight {
void Clear() override; void Clear() override;
}; };
} }
} }

View File

@ -7,8 +7,6 @@
#include "starlight/datatypes/OptRef.h" #include "starlight/datatypes/OptRef.h"
#include "starlight/gfx/Enums.h"
namespace starlight { namespace starlight {
namespace gfx { namespace gfx {
class Drawable { class Drawable {
@ -19,14 +17,16 @@ namespace starlight {
// pattern after: // pattern after:
// public abstract void Draw(DrawContext context, PxRect rect, PxRect? sampleRect = null, DrawColor? color = null); // public abstract void Draw(DrawContext context, PxRect rect, PxRect? sampleRect = null, DrawColor? color = null);
// public abstract void Draw(DrawContext context, FxVector position, FxVector? align = null, PxRect? sampleRect = null, DrawColor? color = null, float rotation = 0, FxVector? scale = null); // public abstract void Draw(DrawContext context, FxVector position, FxVector? align = null, PxRect? sampleRect = null, DrawColor? color = null, float rotation = 0, FxVector? scale = null);
virtual void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one, BlendMode mode = BlendMode::Normal) = 0; virtual void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) = 0;
void Draw(const Vector2& position, OptRef<Vector2> hotspot, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, float scale, BlendMode mode = BlendMode::Normal) { void Draw(const Vector2& position, OptRef<Vector2> hotspot, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, float scale) {
Draw(position, hotspot, sampleRect, color, rotation, Vector2(scale, scale), mode); Draw(position, hotspot, sampleRect, color, rotation, Vector2(scale, scale));
} }
virtual void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, BlendMode mode = BlendMode::Normal) = 0; virtual void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr) = 0;
virtual Vector2 Size() = 0; virtual Vector2 Size() = 0;
}; };
} }
} }

View File

@ -15,18 +15,18 @@ using starlight::gfx::DrawableImage;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
using starlight::gfx::CRenderTarget; using starlight::gfx::CRenderTarget;
void DrawableImage::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale, BlendMode mode) { void DrawableImage::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
texture->Bind(color ? color.get() : Color(1,1,1,1), mode); texture->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size); const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size);
VRect rect(position - (texture->size * origin) * scale, sr.size * scale); VRect rect(position - origin * scale, sr.size * scale);
RenderCore::DrawQuad(rect, position, rotation, sr / texture->txSize); RenderCore::DrawQuad(rect, position, rotation, sr / texture->txSize);
} }
} }
void DrawableImage::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color, BlendMode mode) { void DrawableImage::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
texture->Bind(color ? color.get() : Color(1,1,1,1), mode); texture->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size); const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size);
RenderCore::DrawQuad(rect, sr / texture->txSize); RenderCore::DrawQuad(rect, sr / texture->txSize);
} }

View File

@ -15,10 +15,11 @@ namespace starlight {
DrawableImage(CTexture* texture) : texture(texture) { } DrawableImage(CTexture* texture) : texture(texture) { }
~DrawableImage() override { } ~DrawableImage() override { }
void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one, BlendMode mode = BlendMode::Normal) override; void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) override;
void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, BlendMode mode = BlendMode::Normal) override; void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr) override;
Vector2 Size() override; Vector2 Size() override;
}; };
} }
} }

View File

@ -15,9 +15,9 @@ using starlight::gfx::DrawableNinePatch;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
using starlight::gfx::CRenderTarget; using starlight::gfx::CRenderTarget;
void DrawableNinePatch::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color, BlendMode mode) { void DrawableNinePatch::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
texture->Bind(color ? color.get() : Color(1,1,1,1), mode); texture->Bind(color ? color.get() : Color(1,1,1,1));
VRect rr = rect.IntSnap(); VRect rr = rect.IntSnap();
const VRect& sr = (sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size)).IntSnap(); const VRect& sr = (sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size)).IntSnap();

View File

@ -16,7 +16,7 @@ namespace starlight {
~DrawableNinePatch() override { } ~DrawableNinePatch() override { }
//void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) override; //void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) override;
void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, BlendMode mode = BlendMode::Normal) override; void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr) override;
}; };
} }
} }

View File

@ -11,16 +11,17 @@ using starlight::gfx::DrawableTest;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
void DrawableTest::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale, BlendMode mode) { void DrawableTest::Draw(const Vector2& position, const Vector2& origin, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, const Vector2& scale) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
//static u32 col = Color(0, 0.5f, 1); //static u32 col = Color(0, 0.5f, 1);
//sf2d_draw_rectangle_rotate(position.x, position.y, 16, 16, col, rotation); //sf2d_draw_rectangle_rotate(position.x, position.y, 16, 16, col, rotation);
} }
} }
void DrawableTest::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color, BlendMode mode) { void DrawableTest::Draw(const VRect& rect, OptRef<VRect> sampleRect, OptRef<Color> color) {
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
RenderCore::BindColor(color ? color.get() : Color(1,1,1,1), mode); RenderCore::BindColor(color ? color.get() : Color(1,1,1,1));
RenderCore::DrawQuad(rect, VRect()); RenderCore::DrawQuad(rect, VRect());
} }
} }

View File

@ -10,10 +10,11 @@ namespace starlight {
DrawableTest() { } DrawableTest() { }
~DrawableTest() override { } ~DrawableTest() override { }
void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one, BlendMode mode = BlendMode::Normal) override; void Draw(const Vector2& position, const Vector2& origin = Vector2::zero, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, float rotation = 0, const Vector2& scale = Vector2::one) override;
void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, BlendMode mode = BlendMode::Normal) override; void Draw(const VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr) override;
Vector2 Size() override { return Vector2::zero; } Vector2 Size() override { return Vector2::zero; }
}; };
} }
} }

View File

@ -1,14 +0,0 @@
#pragma once
#include "starlight/_global.h"
namespace starlight {
namespace gfx {
enum class BlendMode {
Blend,
Mask,
Replace,
Normal = Blend
};
}
}

View File

@ -14,6 +14,8 @@ namespace starlight {
namespace gfx { namespace gfx {
class Font { class Font {
public: public:
static constexpr const int defaultSize = 16;
Font() { } Font() { }
virtual ~Font() { } virtual ~Font() { }

View File

@ -1,21 +0,0 @@
#pragma once
#include "starlight/_global.h"
namespace starlight {
namespace gfx {
class FontNull : public Font {
public:
FontNull() { }
~FontNull() override { }
void Print(Vector2 position, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override {}
void Print(VRect rect, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override {}
Vector2 Measure(const std::string& text, float scale = 1, float maxWidth = 400) override { return Vector2::zero; }
Vector2 GetCursorPosition(VRect rect, const std::string& text, unsigned int end, float scale = 1) override { return Vector2::zero; }
unsigned int GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt, float scale = 1) override { return 0; }
};
}
}

View File

@ -16,7 +16,6 @@ using starlight::Vector2;
using starlight::VRect; using starlight::VRect;
using starlight::Color; using starlight::Color;
using starlight::util::WorkerThread; using starlight::util::WorkerThread;
using starlight::gfx::BlendMode;
using starlight::gfx::CTexture; using starlight::gfx::CTexture;
using starlight::gfx::CRenderTarget; using starlight::gfx::CRenderTarget;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
@ -25,33 +24,41 @@ namespace { // internals
typedef struct { typedef struct {
float x, y, z, u, v; float x, y, z, u, v;
} vbo_xyzuv; } vbo_xyzuv;
void setXYZUV(vbo_xyzuv& vbo, float x, float y, float z, float u, float v) {
vbo_xyzuv* vboArray = nullptr; vbo.x = x;
size_t vboIndex = 0; vbo.y = y;
size_t vboSize = 0; vbo.z = z;
vbo.u = u;
void addVertXYZUV(float x, float y, float z, float u, float v) { vbo.v = v;
// TODO: maybe add bounds check
vbo_xyzuv* vert = &vboArray[vboIndex++];
vert->x = x; vert->y = y; vert->z = z;
vert->u = u; vert->v = v;
} }
void addVertXYZUV(Vector2 xy, Vector2 uv) { addVertXYZUV(xy.x, xy.y, 0, uv.x, uv.y); } void setXYZUV(vbo_xyzuv& vbo, Vector2 xy, Vector2 uv) { setXYZUV(vbo, xy.x, xy.y, 0, uv.x, uv.y); }
void* bufferStart = nullptr;
size_t bufferInd = 0;
size_t bufferSize = 0;
DVLB_s* dvlb = nullptr; DVLB_s* dvlb = nullptr;
shaderProgram_s shader; shaderProgram_s shader;
int sLocProjection = -1; int sLocProjection = -1;
C3D_AttrInfo* attrInfo = nullptr; void ResetBuffer() { bufferInd = 0; }
inline unsigned int NextPow2(unsigned int x) { void* AllocBuffer(size_t size, size_t align = 1) {
bufferInd += align - (bufferInd % align); // prealign
void* b = reinterpret_cast<void*>(reinterpret_cast<size_t>(bufferStart) + bufferInd);
bufferInd += size;
if (bufferInd > bufferSize) return nullptr;
return b;
}
inline int NextPow2(unsigned int x) {
--x; --x;
x |= x >> 1; x |= x >> 1;
x |= x >> 2; x |= x >> 2;
x |= x >> 4; x |= x >> 4;
x |= x >> 8; x |= x >> 8;
x |= x >> 16; x |= x >> 16;
return std::min(std::max(++x, 64U), 1024U); // clamp size to keep gpu from locking return ++x >= 64 ? x : 64; // min size to keep gpu from locking
} }
class CRawTexture : public CTexture { class CRawTexture : public CTexture {
@ -70,8 +77,8 @@ namespace { // internals
C3D_TexDelete(texture); C3D_TexDelete(texture);
delete texture; delete texture;
} }
void Bind(Color color = Color::white, BlendMode mode = BlendMode::Normal) override { void Bind(Color color = Color::white) override {
RenderCore::BindTexture(texture, color, mode); RenderCore::BindTexture(texture, color);
} }
}; };
} }
@ -87,21 +94,9 @@ void RenderCore::Open() {
gfxSet3D(true); gfxSet3D(true);
C3D_Init(0x80000*8); C3D_Init(0x80000*8);
// allocate and initialize VBO bufferSize = 0x80000;
vboSize = 0x80000; bufferStart = linearAlloc(bufferSize);
void* vboAddr = linearAlloc(vboSize); bufferInd = 0;
vboArray = reinterpret_cast<vbo_xyzuv*>(vboAddr);
vboIndex = 0;
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, vboAddr, sizeof(vbo_xyzuv), 2, 0x10);
// set up shader attribute passing
attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3);
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2);
// set up screen targets // set up screen targets
targetTopLeft = std::make_unique<CRenderTarget>(240, 400, true); targetTopLeft = std::make_unique<CRenderTarget>(240, 400, true);
@ -124,7 +119,7 @@ void RenderCore::Open() {
// set up mode defaults // set up mode defaults
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // premult C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // premult
C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL); // hmm. C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); // hmm.
C3D_CullFace(GPU_CULL_NONE); C3D_CullFace(GPU_CULL_NONE);
} }
@ -134,75 +129,45 @@ void RenderCore::Close() {
targetTopRight.reset(nullptr); targetTopRight.reset(nullptr);
targetBottom.reset(nullptr); targetBottom.reset(nullptr);
linearFree(reinterpret_cast<void*>(vboArray)); linearFree(bufferStart);
C3D_Fini(); C3D_Fini();
gfxExit(); gfxExit();
} }
void RenderCore::SyncFrame() {
C3D_FrameSync();
}
void RenderCore::BeginFrame() { void RenderCore::BeginFrame() {
C3D_FrameBegin(0/*C3D_FRAME_SYNCDRAW*/); ResetBuffer();
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
vboIndex = 0;
} }
void RenderCore::EndFrame() { void RenderCore::EndFrame() {
C3D_FrameEnd(0); C3D_FrameEnd(0);
} }
namespace { void RenderCore::BindTexture(C3D_Tex* tex, const Color& color) {
void ApplyBlendMode(C3D_TexEnv* env, BlendMode mode) {
switch(mode) {
case BlendMode::Mask: // multiplies the buffer contents by the mask texture
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ZERO, GPU_SRC_COLOR, GPU_ZERO, GPU_SRC_ALPHA); // zero + (buffer * texel)
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0); // and the rest is the same as blend
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
case BlendMode::Replace:
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ZERO, GPU_ONE, GPU_ZERO); // flat replace
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE);
break;
default:
case BlendMode::Blend:
C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // premult
C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0); // for color, the second op was 0... but that's the same value so whatever
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); // and for color, this was REPLACE, not sure if that actually matters
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
break;
}
}
}
void RenderCore::BindTexture(C3D_Tex* tex, const Color& color, BlendMode mode) {
C3D_TexBind(0, tex); // 0 should be correct C3D_TexBind(0, tex); // 0 should be correct
C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_CONSTANT, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_CONSTANT, 0);
ApplyBlendMode(env, mode); C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, GPU_TEVOP_A_SRC_ALPHA, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE);//REPLACE); // let's see...
C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
C3D_TexEnvColor(env, color.Premultiplied()); C3D_TexEnvColor(env, color.Premultiplied());
} }
void RenderCore::BindColor(const Color& color, BlendMode mode) { void RenderCore::BindColor(const Color& color) {
C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvSrc(env, C3D_Both, GPU_CONSTANT, 0, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_CONSTANT, 0, 0);
ApplyBlendMode(env, mode); C3D_TexEnvOp(env, C3D_RGB, 0, 0, 0);
C3D_TexEnvOp(env, C3D_Alpha, GPU_TEVOP_A_SRC_ALPHA, 0, 0);
C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);//REPLACE); // let's see...
C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE);
C3D_TexEnvColor(env, color.Premultiplied()); C3D_TexEnvColor(env, color.Premultiplied());
} }
void RenderCore::DrawQuad(const VRect& rect, const VRect& src, bool noSnap) { void RenderCore::DrawQuad(const VRect& rect, const VRect& src, bool noSnap) {
size_t vboNum = vboIndex; vbo_xyzuv* verts = static_cast<vbo_xyzuv*>(AllocBuffer(4 * sizeof(vbo_xyzuv), 8));
VRect r = noSnap ? rect : rect.IntSnap(); // screen-space snap VRect r = noSnap ? rect : rect.IntSnap(); // screen-space snap
@ -214,23 +179,41 @@ void RenderCore::DrawQuad(const VRect& rect, const VRect& src, bool noSnap) {
// let's make this recalculate things a bit less // let's make this recalculate things a bit less
float rl = r.pos.x, rr = rl + r.size.x, rt = r.pos.y, rb = rt + r.size.y; float rl = r.pos.x, rr = rl + r.size.x, rt = r.pos.y, rb = rt + r.size.y;
float srl = src.pos.x, srr = srl + src.size.x, srt = src.pos.y, srb = srt + src.size.y; float srl = src.pos.x, srr = srl + src.size.x, srt = src.pos.y, srb = srt + src.size.y;
addVertXYZUV(rl, rt, 0, srl, srt); setXYZUV(verts[0], rl, rt, 0, srl, srt);
addVertXYZUV(rr, rt, 0, srr, srt); setXYZUV(verts[1], rr, rt, 0, srr, srt);
addVertXYZUV(rl, rb, 0, srl, srb); setXYZUV(verts[2], rl, rb, 0, srl, srb);
addVertXYZUV(rr, rb, 0, srr, srb); setXYZUV(verts[3], rr, rb, 0, srr, srb);
C3D_DrawArrays(GPU_TRIANGLE_STRIP, vboNum, 4); C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3);
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2);
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, verts, sizeof(vbo_xyzuv), 2, 0x10);
C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);
} }
void RenderCore::DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src) { void RenderCore::DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src) {
size_t vboNum = vboIndex; vbo_xyzuv* verts = static_cast<vbo_xyzuv*>(AllocBuffer(4 * sizeof(vbo_xyzuv), 8));
addVertXYZUV(rect.TopLeft().RotateAround(anchor, angle), src.TopLeft()); setXYZUV(verts[0], rect.TopLeft().RotateAround(anchor, angle), src.TopLeft());
addVertXYZUV(rect.TopRight().RotateAround(anchor, angle), src.TopRight()); setXYZUV(verts[1], rect.TopRight().RotateAround(anchor, angle), src.TopRight());
addVertXYZUV(rect.BottomLeft().RotateAround(anchor, angle), src.BottomLeft()); setXYZUV(verts[2], rect.BottomLeft().RotateAround(anchor, angle), src.BottomLeft());
addVertXYZUV(rect.BottomRight().RotateAround(anchor, angle), src.BottomRight()); setXYZUV(verts[3], rect.BottomRight().RotateAround(anchor, angle), src.BottomRight());
C3D_DrawArrays(GPU_TRIANGLE_STRIP, vboNum, 4); C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3);
AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2);
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, verts, sizeof(vbo_xyzuv), 2, 0x10);
C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);
} }
// specifically RGBA // specifically RGBA
@ -251,7 +234,7 @@ CTexture* RenderCore::LoadTexture(void* src, int width, int height) {
C3D_TexBind(0, tex->texture); C3D_TexBind(0, tex->texture);
//printf("loaded image w %i (%i) h %i (%i)\n", width, owidth, height, oheight); printf("loaded image w %i (%i) h %i (%i)\n", width, owidth, height, oheight);
return tex; return tex;
} }
@ -265,22 +248,9 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) {
auto w = forceExact ? width : NextPow2(width), auto w = forceExact ? width : NextPow2(width),
h = forceExact ? height : NextPow2(height); h = forceExact ? height : NextPow2(height);
txSize = Vector2(w, h); txSize = Vector2(w, h);
tgt = C3D_RenderTargetCreate(w, h, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); // though actually, do we really need stenciling? could drop to 16 if we don't
tgt = C3D_RenderTargetCreate(w, h, GPU_RB_RGBA8, -1/*GPU_RB_DEPTH24_STENCIL8*/); // I don't think we need a depth buffer >.>
//tgt = C3D_RenderTargetCreateFromTex(&tex, GPU_TEXFACE_2D, -1, -1); // create target from texture, actually
C3D_TexInit(&tex, w, h, GPU_RGBA8);
//memset(tex.data, 0, w*h*4); // manually zero out; TODO: optimize this
C3D_TexDelete(&tex); tex.data = tgt->frameBuf.colorBuf; // replace stuff...
Mtx_Ortho(&projection, 0.0f, w, 0.0f, h, 0.0f, 1.0f, true); Mtx_Ortho(&projection, 0.0f, w, 0.0f, h, 0.0f, 1.0f, true);
//Mtx_OrthoTilt(&projection, 0.0f, h, 0.0f, w, 0.0f, 1.0f, true); //Mtx_OrthoTilt(&projection, 0.0f, h, 0.0f, w, 0.0f, 1.0f, true);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_ALL, 0, 0);
//Clear(Color::transparent);
//RenderCore::BindTexture(&tex, Color::white);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, 0, 0);
C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0);
} }
CRenderTarget::~CRenderTarget() { CRenderTarget::~CRenderTarget() {
@ -288,33 +258,17 @@ CRenderTarget::~CRenderTarget() {
} }
void CRenderTarget::Clear(Color color) { void CRenderTarget::Clear(Color color) {
//unsigned int c = color; unsigned int c = color;
//c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
//C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0); C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0);
clearColor = color;
} }
void CRenderTarget::BindTarget() { void CRenderTarget::BindTarget() {
if (clearColor.Valid()) { // clear if color valid
unsigned int c = clearColor;
c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
//C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), c, 0);
//C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0);
}
C3D_FrameDrawOn(tgt); C3D_FrameDrawOn(tgt);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection);
if (!firstClearDone) { firstClearDone = true; // workaround for faulty clearing; just draw a quad in replace mode to force the matter!
if (clearColor.Valid()) {
RenderCore::BindColor(clearColor, BlendMode::Replace);
RenderCore::DrawQuad(VRect(Vector2::zero, txSize), VRect::zero, false);
}
}
} }
void CRenderTarget::Bind(Color color, BlendMode mode) { void CRenderTarget::Bind(Color color) {
//C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0); // don't clear again until marked to C3D_RenderTargetSetClear(tgt, 0, 0, 0); // don't clear again until marked to
RenderCore::BindTexture(&tex, color, mode); RenderCore::BindTexture(&(tgt->renderBuf.colorBuf), color);
} }

View File

@ -9,13 +9,12 @@
#include "starlight/datatypes/VRect.h" #include "starlight/datatypes/VRect.h"
#include "starlight/datatypes/Color.h" #include "starlight/datatypes/Color.h"
#include "starlight/gfx/Enums.h"
#include "starlight/util/WorkerThread.h" #include "starlight/util/WorkerThread.h"
namespace starlight { namespace starlight {
namespace gfx { namespace gfx {
class RenderCore; class RenderCore;
class CTexture { class CTexture {
protected: protected:
CTexture() = default; CTexture() = default;
@ -25,16 +24,13 @@ namespace starlight {
Vector2 txSize; Vector2 txSize;
virtual ~CTexture() = default; virtual ~CTexture() = default;
virtual void Bind(Color color = Color::white, BlendMode mode = BlendMode::Normal) = 0; virtual void Bind(Color color = Color::white) = 0;
}; };
class CRenderTarget : public CTexture { class CRenderTarget : public CTexture {
friend class starlight::gfx::RenderCore; friend class starlight::gfx::RenderCore;
protected: protected:
C3D_RenderTarget* tgt; C3D_RenderTarget* tgt;
C3D_Tex tex;
Color clearColor = Color::transparent;
bool firstClearDone = false;
public: public:
C3D_Mtx projection; C3D_Mtx projection;
@ -45,7 +41,7 @@ namespace starlight {
void Clear(Color color); void Clear(Color color);
void BindTarget(); void BindTarget();
void Bind(Color color = Color::white, BlendMode mode = BlendMode::Normal) override; void Bind(Color color = Color::white) override;
}; };
class RenderCore { class RenderCore {
@ -61,12 +57,11 @@ namespace starlight {
static void Open(); static void Open();
static void Close(); static void Close();
static void SyncFrame();
static void BeginFrame(); static void BeginFrame();
static void EndFrame(); static void EndFrame();
static void BindTexture(C3D_Tex* tex, const Color& color, BlendMode mode = BlendMode::Normal); static void BindTexture(C3D_Tex* tex, const Color& color);
static void BindColor(const Color& color, BlendMode mode = BlendMode::Normal); static void BindColor(const Color& color);
static void DrawQuad(const VRect& rect, const VRect& src, bool noSnap = false); static void DrawQuad(const VRect& rect, const VRect& src, bool noSnap = false);
static void DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src); static void DrawQuad(const VRect& rect, const Vector2& anchor, float angle, const VRect& src);

View File

@ -16,30 +16,21 @@ namespace starlight {
protected: protected:
const std::string name; const std::string name;
std::shared_ptr<T> ptr = nullptr; std::shared_ptr<T> ptr = nullptr;
ThemeRefContainer* redir = nullptr; void Unload() {
unsigned int lastAccess = 0; // how many gc sweeps since last use
volatile int refCount = 0;
void Unload(bool full = false) {
ptr.reset(); ptr.reset();
if (full) redir = nullptr;
} }
ThemeRefContainer(std::string name, std::shared_ptr<T> ptr) : name(name), ptr(ptr) { } ThemeRefContainer(std::string name, std::shared_ptr<T> ptr) : name(name), ptr(ptr) { }
ThemeRefContainer(std::string name, T* ptr) : name(name), ptr(ptr) { } ThemeRefContainer(std::string name, T* ptr) : name(name), ptr(ptr) { }
ThemeRefContainer(std::string name) : name(name) { } ThemeRefContainer(std::string name) : name(name) { }
inline std::shared_ptr<T>& _getptr() {
lastAccess = 0;
if (!redir && !ptr) ThemeManager::Fulfill(*this); // call thememanager to grab things
if (redir) return redir->_getptr();
return ptr;
}
inline std::shared_ptr<T>& getptr() const { return const_cast<ThemeRefContainer<T>&>(*this)._getptr(); }
public: public:
~ThemeRefContainer() { } ~ThemeRefContainer() { }
T* operator ->() const { T* operator ->() const {
return &*(getptr()); if (ptr == nullptr) {
ThemeManager::Fulfill(const_cast<ThemeRefContainer<T>&>(*this)); // call thememanager to grab things
}
return &*ptr;
} }
/*T& operator *() const { /*T& operator *() const {
@ -53,32 +44,15 @@ namespace starlight {
template <class T> template <class T>
class ThemeRef { class ThemeRef {
friend class starlight::ThemeManager; private:
protected: const ThemeRefContainer<T>* cptr;
ThemeRefContainer<T>* cptr;
public: public:
ThemeRef() : cptr(nullptr) { } ThemeRef() : cptr(nullptr) { }
ThemeRef(ThemeRefContainer<T>* c) : cptr(c) { if (cptr) cptr->refCount++; } ThemeRef(ThemeRefContainer<T>* c) : cptr(c) { }
ThemeRef(ThemeRef<T>& o) : cptr(o.cptr) { if (cptr) cptr->refCount++; } ~ThemeRef() { }
ThemeRef(ThemeRef<T>&& o) : cptr(o.cptr) { if (cptr) cptr->refCount++; } inline const ThemeRefContainer<T>& operator ->() const { return *cptr; }
~ThemeRef() { if (cptr) cptr->refCount--; }
ThemeRef<T>& operator =(const ThemeRef<T>& o) {
if (cptr) cptr->refCount--;
cptr = o.cptr;
if (cptr) cptr->refCount++;
return *this;
}
ThemeRef<T>& operator =(const ThemeRef<T>&& o) {
if (cptr) cptr->refCount--;
cptr = o.cptr;
if (cptr) cptr->refCount++;
return *this;
}
inline const ThemeRefContainer<T>& operator ->() const { return const_cast<const ThemeRefContainer<T>&>(*cptr); }
inline explicit operator bool() const { return cptr != nullptr; } inline explicit operator bool() const { return cptr != nullptr; }
inline std::shared_ptr<T> GetShared() const { return (*cptr).getptr(); } inline std::shared_ptr<T> GetShared() const { return (*cptr).ptr; }
inline const std::string& GetName() const { return (*cptr).name; } inline const std::string& GetName() const { return (*cptr).name; }
}; };
} }

View File

@ -1,77 +0,0 @@
#include "Thread.h"
#include "3ds.h"
#include "starlight/Application.h"
using starlight::threading::Thread;
using SysThread = ::Thread;
using SThread = starlight::threading::Thread;
namespace {
void _ThreadEnter(void* arg) {
// cast to thread and start up
static_cast<SThread*>(arg)->_FinishStart();
}
}
Thread::~Thread() {
// ...threadjoin? something like that??
if (event != 0) svcCloseHandle(event);
}
void Thread::Enqueue() {
if (state != ThreadState::Unqueued) return; // don't double enqueue, you derp
Application::Current()->EnqueueThread(shared_from_this());
}
void Thread::Start() {
state = ThreadState::Init;
svcCreateEvent(&event, RESET_ONESHOT);
sthread = static_cast<void*>(threadCreate(_ThreadEnter, static_cast<void*>(this), 4*1024, 0x3F, -2, false));
}
void Thread::_FinishStart() {
// lock out once already done
if (state != ThreadState::Init) return;
state = ThreadState::Running;
Yield();
Body();
state = ThreadState::Finished;
OnExit();
threadExit(0);
}
void Thread::Yield() {
if (state != ThreadState::Running) return; // not executing this right now, this would just futz it up
state = ThreadState::Idle;
svcWaitSynchronization(event, -1 /*U64_MAX*/);
//svcWaitSynchronization(event, 65536);
svcClearEvent(event);
if (state == ThreadState::Finished && OnExit()) {
threadExit(0);
}
state = ThreadState::Running;
}
void Thread::Exit() {
if (state == ThreadState::Idle) { // exited from outside
state = ThreadState::Finished;
Resume();
threadJoin(static_cast<SysThread>(sthread), -1);
} else if (state == ThreadState::Running) { // exited self
state = ThreadState::Finished;
OnExit();
threadExit(0);
}
}
void Thread::Resume() {
if (state != ThreadState::Idle && state != ThreadState::Finished) return; // not applicable
svcSignalEvent(event);
}
bool Thread::OnExit() { return true; } // default to "trivial" (no cleanup necessary)
//

View File

@ -1,39 +0,0 @@
#pragma once
#include "starlight/_global.h"
#include <memory>
namespace starlight {
class Application;
namespace threading {
enum class ThreadState : unsigned char {
Unqueued, Init, Idle, Running, Finished
};
class Thread : public std::enable_shared_from_this<Thread> {
friend class starlight::Application;
protected:
volatile ThreadState state = ThreadState::Unqueued;
void* sthread;
long unsigned int event = 0;
void Start();
public:
~Thread();
inline ThreadState State() { return state; }
void _FinishStart();
void Enqueue();
void Yield();
void Resume();
void Exit();
virtual void Body() = 0;
virtual bool OnExit();
};
}
}

View File

@ -15,15 +15,8 @@ using starlight::InputManager;
using starlight::GFXManager; using starlight::GFXManager;
using starlight::ThemeManager; using starlight::ThemeManager;
using starlight::TextConfig;
using starlight::ui::Button; using starlight::ui::Button;
std::function<TextConfig&()> Button::defCfg = []() -> TextConfig& {
static TextConfig _tc = ThemeManager::GetMetric("/controls/button/text", TextConfig());
return _tc;
};
void Button::SetText(const std::string& text) { void Button::SetText(const std::string& text) {
label = text; label = text;
MarkForRedraw(); MarkForRedraw();
@ -35,18 +28,18 @@ void Button::Draw() {
static auto idle = ThemeManager::GetAsset("controls/button.idle"); static auto idle = ThemeManager::GetAsset("controls/button.idle");
static auto press = ThemeManager::GetAsset("controls/button.press"); static auto press = ThemeManager::GetAsset("controls/button.press");
TextConfig& tc = style.textConfig.ROGet(); static TextConfig tc = ThemeManager::GetMetric("/controls/button/text", TextConfig());
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap(); auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
if (InputManager::GetDragHandle() == this) { if (InputManager::GetDragHandle() == this) {
(style.press ? style.press : press)->Draw(rect); press->Draw(rect);
} else { } else {
(style.idle ? style.idle : idle)->Draw(rect); idle->Draw(rect);
} }
//font->Print(rect, label, 1, cl/*Color::white*/, Vector2(0.5f, 0.5f), Color::black);
tc.Print(rect, label); tc.Print(rect, label);
if (style.glyph) style.glyph->Draw(rect.Center(), Vector2::half, nullptr, tc.textColor);
} }
void Button::OnTouchOn() { void Button::OnTouchOn() {

View File

@ -4,30 +4,15 @@
#include <string> #include <string>
#include <functional> #include <functional>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h"
#include "starlight/ui/UIElement.h" #include "starlight/ui/UIElement.h"
namespace starlight { namespace starlight {
namespace ui { namespace ui {
class Button : public UIElement { class Button : public UIElement {
public:
struct Style {
gfx::ThemeRef<gfx::Drawable>
idle = nullptr,
press = nullptr,
glyph = nullptr;
Optional<TextConfig> textConfig = &Button::defCfg;
};
private: private:
static std::function<TextConfig&()> defCfg; //
public: public:
Style style;
std::string label = ""; std::string label = "";
std::function<void(Button&)> eOnTap; std::function<void(Button&)> eOnTap;

View File

@ -1,102 +0,0 @@
#include "DebugConsole.h"
#include "starlight/GFXManager.h"
#include "starlight/gfx/RenderCore.h"
#include "sys/iosupport.h"
using starlight::GFXManager;
using starlight::TextConfig;
using starlight::gfx::RenderCore;
using starlight::ui::DebugConsole;
namespace {
bool csInit = false;
//std::weak_ptr<DebugConsole> curDC = std::shared_ptr<DebugConsole>(nullptr);
DebugConsole* cs = nullptr;
ssize_t consoleWrite(struct _reent* r, void* fd, const char* ptr, size_t len) {
if (!ptr) return -1;
//if (curDC.expired()) return -1;
//auto cs = curDC.lock();
if (cs == nullptr) return -1; // nullref but not expired???
cs->text.append(ptr, len);
cs->dirty = true;
return len;
}
const devoptab_t devoptab_console = {
"con",
0,
NULL,
NULL,
consoleWrite,
NULL,
NULL,
NULL
};
}
DebugConsole::DebugConsole(VRect rect) {
this->rect = rect;
}
DebugConsole::~DebugConsole() {
if (cs == this) cs = nullptr;
}
void DebugConsole::Start() {
//curDC = std::static_pointer_cast<DebugConsole>(shared_from_this());
cs = this;
if (!csInit) {
csInit = true;
devoptab_list[STD_OUT] = &devoptab_console;
devoptab_list[STD_ERR] = &devoptab_console;
setvbuf(stdout, NULL , _IONBF, 0);
setvbuf(stderr, NULL , _IONBF, 0);
}
}
void DebugConsole::PreDrawOffscreen() {
buffer.reset(); // I guess?
}
void DebugConsole::PreDraw() {
if (dirty || !buffer) {
dirty = false;
static TextConfig textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
textConfig.font = ThemeManager::GetFont("mono.12");
textConfig.justification = Vector2(0, 1);
textConfig.borderColor = Color::black;
// clip text at top left corner
Vector2 measure = textConfig.Measure(text, rect.size.x);
if (measure.y > rect.size.y) {
unsigned int cfp = textConfig.GetCursorFromPoint(rect, text, Vector2(0, measure.y - (rect.size.y + 16)));
text = text.substr(cfp);
}
if (!buffer) buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8));
buffer->Clear();
GFXManager::PushContext(buffer.get());
GFXManager::PrepareForDrawing(); // force clear even if nothing to write
textConfig.Print(buffer->rect, text);
GFXManager::PopContext();
}
}
void DebugConsole::Draw() {
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
if (buffer) {
buffer->Draw(VRect(rect.pos, buffer->rect.size));
}
}

View File

@ -1,39 +0,0 @@
#pragma once
#include "starlight/_global.h"
#include <string>
#include <memory>
#include <functional>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h"
#include "starlight/gfx/DrawContextCanvas.h"
#include "starlight/ui/UIElement.h"
namespace starlight {
namespace ui {
class DebugConsole : public UIElement {
private:
//
public:
std::string text = "";
std::unique_ptr<gfx::DrawContextCanvas> buffer;
bool dirty = false;
DebugConsole(VRect rect);
~DebugConsole() override;
void Start();
void PreDrawOffscreen() override;
void PreDraw() override;
void Draw() override;
};
}
}

View File

@ -3,22 +3,17 @@
#include "starlight/GFXManager.h" #include "starlight/GFXManager.h"
using starlight::GFXManager; using starlight::GFXManager;
using starlight::TextConfig;
using starlight::ui::Label; using starlight::ui::Label;
std::function<TextConfig&()> Label::defCfg = []() -> TextConfig& {
static TextConfig _tc = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
return _tc;
};
Label::Label(VRect rect) { Label::Label(VRect rect) {
this->rect = rect; this->rect = rect;
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
} }
void Label::AutoSize() { void Label::AutoSize() {
if (autoSizeV) { if (autoSizeV) {
float h = textConfig.ROGet().font->Measure(text, 1, rect.size.x).y; float h = textConfig.font->Measure(text, 1, rect.size.x).y;
Resize(rect.size.x, h); Resize(rect.size.x, h);
} }
@ -33,13 +28,12 @@ void Label::SetText(const std::string& text) {
} }
void Label::SetFont(const std::string& fontName) { void Label::SetFont(const std::string& fontName) {
textConfig->font = ThemeManager::GetFont(fontName); textConfig.font = ThemeManager::GetFont(fontName);
textConfig->Measure(""); // force load
AutoSize(); AutoSize();
} }
void Label::SetPreset(const std::string& name) { void Label::SetPreset(const std::string& name) {
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig.ROGet()); textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig);
AutoSize(); AutoSize();
} }
@ -54,8 +48,7 @@ void Label::PreDraw() {
buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8)); buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8));
buffer->Clear(); buffer->Clear();
GFXManager::PushContext(buffer.get()); GFXManager::PushContext(buffer.get());
GFXManager::PrepareForDrawing(); // force clear even if nothing to write textConfig.Print(buffer->rect, text);
textConfig.ROGet().Print(buffer->rect, text);
GFXManager::PopContext(); GFXManager::PopContext();
} }
} }
@ -65,6 +58,6 @@ void Label::Draw() {
if (buffer) { if (buffer) {
buffer->Draw(VRect(rect.pos, buffer->rect.size)); buffer->Draw(VRect(rect.pos, buffer->rect.size));
} else { } else {
textConfig.ROGet().Print(rect, text); textConfig.Print(rect, text);
} }
} }

View File

@ -4,8 +4,6 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h" #include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h" #include "starlight/gfx/ThemeRef.h"
@ -17,13 +15,11 @@ namespace starlight {
namespace ui { namespace ui {
class Label : public UIElement { class Label : public UIElement {
private: private:
static std::function<TextConfig&()> defCfg;
void AutoSize(); void AutoSize();
public: public:
std::string text = ""; std::string text = "";
Optional<TextConfig> textConfig = &defCfg; TextConfig textConfig;
std::unique_ptr<gfx::DrawContextCanvas> buffer; std::unique_ptr<gfx::DrawContextCanvas> buffer;

View File

@ -35,7 +35,6 @@ void UICanvas::PreDraw() {
drawContext->Clear(); drawContext->Clear();
GFXManager::PushContext(drawContext.get()); GFXManager::PushContext(drawContext.get());
GFXManager::PushOffsetAdd(-scrollOffset); GFXManager::PushOffsetAdd(-scrollOffset);
GFXManager::PrepareForDrawing(); // force clear to take so you don't get garbage if nothing renders
VRect vr = ViewportRect(); VRect vr = ViewportRect();
@ -52,3 +51,4 @@ void UICanvas::PreDraw() {
void UICanvas::Draw() { void UICanvas::Draw() {
static_cast<DrawContextCanvas*>(drawContext.get())->Draw(rect + GFXManager::GetOffset()); static_cast<DrawContextCanvas*>(drawContext.get())->Draw(rect + GFXManager::GetOffset());
} }

View File

@ -47,9 +47,9 @@ void UIContainer::_Dive(std::function<bool(UIElement*)>& func, bool consumable,
} }
void UIContainer::Add(std::shared_ptr<UIElement> elem, bool front) { void UIContainer::Add(std::shared_ptr<UIElement> elem, bool front) {
if (front) children.push_front(elem);
else children.push_back(elem);
elem->parent = std::weak_ptr<UIContainer>(std::static_pointer_cast<UIContainer>(this->shared_from_this())); elem->parent = std::weak_ptr<UIContainer>(std::static_pointer_cast<UIContainer>(this->shared_from_this()));
if (front) children.push_front(std::move(elem));
else children.push_back(std::move(elem));
MarkForRedraw(); MarkForRedraw();
} }
//void UIContainer::Add(UIElement* elem) { //void UIContainer::Add(UIElement* elem) {
@ -71,7 +71,6 @@ void UIContainer::RemoveAll() {
it->parent = std::weak_ptr<UIContainer>(); // clear parent it->parent = std::weak_ptr<UIContainer>(); // clear parent
} }
children.clear(); children.clear();
MarkForRedraw();
} }
void UIContainer::Update() { void UIContainer::Update() {

View File

@ -35,11 +35,6 @@ namespace starlight {
void Dive(std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true); void Dive(std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
void Add(std::shared_ptr<UIElement> elem, bool front = false); void Add(std::shared_ptr<UIElement> elem, bool front = false);
template<class E, typename ... Args>
inline std::shared_ptr<E> AddNew(Args... args) {
auto n = std::make_shared<E>(args...);
Add(n); return n;
}
//void Add(UIElement* elem); //void Add(UIElement* elem);
void Remove(std::shared_ptr<UIElement> elem); void Remove(std::shared_ptr<UIElement> elem);
void RemoveAll(); void RemoveAll();

View File

@ -1,19 +0,0 @@
#include "FrameTimer.h"
#include "3ds.h"
using starlight::util::FrameTimer;
FrameTimer::FrameTimer() {
osTickCounterStart(reinterpret_cast<TickCounter*>(&tc));
}
void FrameTimer::FrameStart() {
osTickCounterUpdate(reinterpret_cast<TickCounter*>(&tc));
}
double FrameTimer::GetSubframe() {
TickCounter tmp = *(reinterpret_cast<TickCounter*>(&tc));
osTickCounterUpdate(&tmp);
return osTickCounterRead(&tmp) * (60.0/1000.0);
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "starlight/_global.h"
namespace starlight {
namespace util {
class FrameTimer {
private:
struct TickCount {
unsigned long long int elapsed;
unsigned long long int ref;
};
TickCount tc;
public:
FrameTimer();
void FrameStart();
double GetSubframe();
};
}
}

View File

@ -1,19 +0,0 @@
#include "Profiler.h"
#include <cstdio>
#include "3ds.h"
using starlight::util::Profiler;
Profiler::TickCount Profiler::tc = Profiler::TickCount();
void Profiler::TaskStart() {
osTickCounterUpdate(reinterpret_cast<TickCounter*>(&tc));
}
void Profiler::TaskFinish(const std::string& msg) {
osTickCounterUpdate(reinterpret_cast<TickCounter*>(&tc));
double tm = osTickCounterRead(reinterpret_cast<TickCounter*>(&tc));
printf("T:%f - %s\n", tm, msg.c_str());
}

View File

@ -1,22 +0,0 @@
#pragma once
#include "starlight/_global.h"
#include <string>
namespace starlight {
namespace util {
class Profiler {
private:
struct TickCount {
unsigned long long int elapsed;
unsigned long long int ref;
};
static TickCount tc;
Profiler() {};
public:
static void TaskStart();
static void TaskFinish(const std::string& msg);
};
}
}

View File

@ -1,89 +1,18 @@
roadmap to v0.5.1 { roadmap to first release, in no particular order {
- make font-not-found not outright crash the app (hopefully) - ding!
- fix UICanvas garbage-on-empty
make asset gc actually sweep every 5sec
maybe entirely replace clearing with transparent knockout on bind?
implement more blend modes??
make button glyphs usable in conjunction with text (left edge, margin etc.)
give glyphs a color mode where they aren't set to text color
predrawoffscreen on hidden forms
paged field
figure out why first-draw in a given font sometimes derps up?
^ mitigate with a force-load-on-set for now
- libctru console as ui element
- pngcrush the biggest assets (default and osk backdrops etc.)
- profile image loading (for large images, loading the png and spanned copy/premult take about the same time; memset to preclear is only ~2ms with a 512x512)
- fix the hang on osk when pressing (L|R)+up+left
figure out what (else) to put on the left side of the keyboard (opposite backspace and enter)
temporary drawable loading, local themeref, discard etc.
^ both png and raw load
maybe rgb565 for smdh icon loading?
some examples (minesweeper?)
fix `, ' and " glyph spacing/offset
adjust /\ some?
proper thread dispatch? {
- Application main loop keeps a(n abstracted) libctru TickCounter and keeps track of frame time
- thread objects are held in a std::list, Application dispatches resume events and splice()s them to the end until frame time reaches some proportion of 1/60s
- thread gets a yield function that calls svcWaitSynchronization on its resume event
...and some mechanism for allowing it to opt out of the rest of the cycle
Trackable sideclass for threads; float progress 0..1, etc.
^ make progress bar and use it for a progress/"please wait" dialog
- MAKE THREADS END CLEANLY
^ observed a single instance of being stalled on redscreen, not really sure what that was about
lambda task thread
}
} then by v0.5.5 {
refactor ResolveAsset/FontPath to use Path objects for cleaner code
event propagation system of some sort; threadsafe to whatever extent is needed on 3DS
figure out how to *actually* fix the clear bug...?
some sort of tagging for longer retention for large drawables such as backgrounds (particularly for the OSK)
convert the profiler from "single static thing" to "here, have an instance on the stack"
} then consider these before 1.0 "gold" { } then consider these before 1.0 "gold" {
replace some of the OptRef stuffs on invalidatable types with invalid checks; add implicit conversions from nullptr to invalid
make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list) make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list)
garbage collection for not-recently-used theme assets { add customization for Button (alternate idle/press images, optional glyph drawable)
- keep track of last-use in ThemeRefContainer ^ use that to spice up the OSK
have ThemeManager sweep gc every so often
- rework redirects (proxy drawable I guess...?) or a pointer to another container
}
HANDLE CANVAS OVERRUNS FOR LABELS AND OSK PREVIEW {
- well, it doesn't actually *crash* anymore... or at least nowhere near as fast
use a "windowed" approach; only cache a bit more than is visible and redraw when the viewport changes enough
have a way for text rendering to skip lines that won't be visible, and use that with windowing to cut down render times further
}
actual cursor image for OSK instead of just using a | glypyh actual cursor image for OSK instead of just using a | glypyh
input prompt dialog input prompt dialog
make the panel background not just the button image
"shortcut" overloads for InputManager::OpenKeyboard "shortcut" overloads for InputManager::OpenKeyboard
language config and atlas support language config and atlas support
maybe implement some way of "knocking out" and replacing metrics during runtime for theme switching maybe implement some way of "knocking out" and replacing metrics during runtime for theme switching
fix font glyph padding to eliminate slight "crosstalk" in bordered variants fix font glyph padding to eliminate slight "crosstalk" in bordered variants
SOUND.
UI heirarchy from json
quick includes for all UI elements, etc.
cross-app integrations {
app icon and manifest.json in romfs, copied into .starlight on launch {
app name, description etc.
themeLevel: 0 (default) as fallback only, 1 or 2 to override user theme unless opted out, 1 for "just by default", 2 for "this doesn't look so good otherwise"
}
settings pane data for each app, contained in manifest.json and used by Starlight Settings to provide centralized configuration, iOS-style
some standard means of passing parameters into another application, which works on a cia (probably a json file)
}
} }
today's agenda { today's agenda {

View File

@ -1,4 +1,4 @@
The MIT License (MIT) ### MIT License
Copyright (c) 2017 Beau Jessee ("zetaPRIME") Copyright (c) 2017 Beau Jessee ("zetaPRIME")
@ -20,4 +20,4 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
// Bundled dependencies (see _incLib) have their own terms and/or notices, as listed in their respective files. // Bundled dependencies (see [\_incLib](libstarlight/source/starlight/_incLib)) have their own terms and/or notices, as listed in their respective files.

4
maketest.sh Executable file → Normal file
View File

@ -4,9 +4,7 @@ function abort {
exit exit
} }
mode=send mode=send
if [ "$1" = "sc" ]; then if [ "$1" = "c" ]; then
mode=send-cia
elif [ "$1" = "c" ]; then
mode=run mode=run
fi fi
cd libstarlight cd libstarlight

View File

@ -44,8 +44,6 @@ APP_TITLE := Starlight Testbed
APP_DESCRIPTION := Test application for libstarlight APP_DESCRIPTION := Test application for libstarlight
APP_AUTHOR := zetaPRIME APP_AUTHOR := zetaPRIME
3DSIP := 10.0.0.6
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# options for code generation # options for code generation
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
@ -58,7 +56,7 @@ CFLAGS := -g -Wall -O2 -mword-relocations \
CFLAGS += $(INCLUDE) -DARM11 -D_3DS CFLAGS += $(INCLUDE) -DARM11 -D_3DS
# was gnu++11; -fno-rtti -fno-exceptions (why no-exceptions???) # was gnu++11; -fno-rtti -fno-exceptions (why no-exceptions???)
CXXFLAGS := $(CFLAGS) -fno-rtti -std=c++17 CXXFLAGS := $(CFLAGS) -fno-rtti -std=gnu++14
# on second thought, let's not use -D_GLIBCXX_USE_C99 # on second thought, let's not use -D_GLIBCXX_USE_C99
#CXXFLAGS := $(CFLAGS) -std=gnu++14 #CXXFLAGS := $(CFLAGS) -std=gnu++14
@ -89,7 +87,6 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) $(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD) export DEPSDIR := $(CURDIR)/$(BUILD)
export ROMFS_ROOT := $(CURDIR)/$(ROMFS)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
@ -165,19 +162,14 @@ cci: $(TARGET)-strip.elf
@echo "built ... sf2d_sample.3ds" @echo "built ... sf2d_sample.3ds"
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
cia: $(TARGET)-strip.elf cia: $(TARGET)-strip.elf
@makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -icon $(TARGET).smdh -banner resources/banner.bnr -logo resources/logo.bcma.lz -exefslogo -target t @makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -icon resources/icon.icn -banner resources/banner.bnr -exefslogo -target t
@echo "built ... $(TARGET).cia" @echo "built ... $(TARGET).cia"
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
send: $(BUILD) send: $(BUILD)
#@3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx @3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx
@while true; do 3dslink -a $(3DSIP) $(TARGET).3dsx && break; done
#---------------------------------------------------------------------------------
send-cia: $(TARGET)-strip.elf
@makerom -f cia -o $(TARGET).cia -elf $(TARGET)-strip.elf -rsf resources/$(TARGET).rsf -icon $(TARGET).smdh -banner resources/banner.bnr -logo resources/logo.bcma.lz -exefslogo -target t
@sockme $(TARGET).cia $(3DSIP) || sockme $(TARGET).cia $(3DSIP) || sockme $(TARGET).cia $(3DSIP)
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
run: $(BUILD) run: $(BUILD)
@citra-qt $(TARGET).3dsx @citra $(TARGET).3dsx
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
copy_cia: $(TARGET).cia copy_cia: $(TARGET).cia
@cp $(TARGET).cia /mnt/3DS @cp $(TARGET).cia /mnt/3DS

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

View File

@ -1,242 +0,0 @@
BasicInfo:
Title : "starlight-testbed"
CompanyCode : "00"
ProductCode : "CTR-N-SLTB"
ContentType : Application # Application / SystemUpdate / Manual / Child / Trial
Logo : Homebrew # Nintendo / Licensed / Distributed / iQue / iQueForSystem
RomFs:
# Specifies the root path of the file system to include in the ROM.
RootPath : "../themes/default"
TitleInfo:
UniqueId : 0xf1001 # same as sf2d test because meh
Category : Application # Application / SystemApplication / Applet / Firmware / Base / DlpChild / Demo / Contents / SystemContents / SharedContents / AddOnContents / Patch / AutoUpdateContents
#CardInfo:
# MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB / 8GB / 16GB / 32GB
# MediaType : Card1 # Card1 / Card2
# CardDevice : None # NorFlash / None
Option:
UseOnSD : true # true if App is to be installed to SD
EnableCompress : false # Compresses exefs code
FreeProductCode : true # Removes limitations on ProductCode
EnableCrypt : false # Enables encryption for NCCH and CIA
MediaFootPadding : false # If true CCI files are created with padding
#ExeFs: # these are the program segments from the ELF, check your elf for the appropriate segment names
# ReadOnly:
# - .rodata
# - RO
# ReadWrite:
# - .data
# - RO
# Text:
# - .init
# - .text
# - STUP_ENTRY
#PlainRegion: # only used with SDK ELFs
# # - .module_id
AccessControlInfo:
# UseOtherVariationSaveData : true
# UseExtSaveData : true
# ExtSaveDataId: 0xffffffff
# SystemSaveDataId1: 0x220
# SystemSaveDataId2: 0x00040010
# OtherUserSaveDataId1: 0x220
# OtherUserSaveDataId2: 0x330
# OtherUserSaveDataId3: 0x440
# UseExtendedSaveDataAccessControl: true
# AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606]
FileSystemAccess:
# - CategorySystemApplication
# - CategoryHardwareCheck
# - CategoryFileSystemTool
- Debug
# - TwlCardBackup
# - TwlNandData
# - Boss
- DirectSdmc
# - Core
# - CtrNandRo
# - CtrNandRw
# - CtrNandRoWrite
# - CategorySystemSettings
# - CardBoard
# - ExportImportIvs
# - DirectSdmcWrite
# - SwitchCleanup
# - SaveDataMove
# - Shop
# - Shell
# - CategoryHomeMenu
IoAccessControl:
# - FsMountNand
# - FsMountNandRoWrite
# - FsMountTwln
# - FsMountWnand
# - FsMountCardSpi
# - UseSdif3
# - CreateSeed
# - UseCardSpi
IdealProcessor : 0
AffinityMask : 1
Priority : 16
MaxCpu : 0x9E # Default
# New3DS Exclusive Process Settings
SystemModeExt : Legacy # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
CpuSpeed : 804MHz # 268MHz(Default)/804MHz
EnableL2Cache : true # false(default)/true
CanAccessCore2 : true
DisableDebug : true
EnableForceDebug : false
CanWriteSharedPage : true
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : true
PermitMainFunctionArgument : true
CanShareDeviceMemory : true
RunnableOnSleep : false
SpecialMemoryArrange : true
CoreVersion : 2
DescVersion : 2
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
MemoryType : Application # Application / System / Base
HandleTableSize: 512
IORegisterMapping:
- 1ff50000-1ff57fff
- 1ff70000-1ff77fff
MemoryMapping:
- 1f000000-1f5fffff:r
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
InterruptNumbers:
ServiceAccessControl:
- APT:U
- $hioFIO
- $hostio0
- $hostio1
- ac:u
- boss:U
- cam:u
- cecd:u
- cfg:u
- dlp:FKCL
- dlp:SRVR
- dsp::DSP
- frd:u
- fs:USER
- gsp::Gpu
- hid:USER
- http:C
- mic:u
- ndm:u
- news:u
- nwm::UDS
- ptm:u
- pxi:dev
- soc:U
- ssl:C
- y2r:u
- ldr:ro
- ir:USER
SystemControlInfo:
SaveDataSize: 0KB # It doesn't use any save data.
RemasterVersion: 2
StackSize: 0x40000
# JumpId: 0
Dependency:
ac: 0x0004013000002402L
am: 0x0004013000001502L
boss: 0x0004013000003402L
camera: 0x0004013000001602L
cecd: 0x0004013000002602L
cfg: 0x0004013000001702L
codec: 0x0004013000001802L
csnd: 0x0004013000002702L
dlp: 0x0004013000002802L
dsp: 0x0004013000001a02L
friends: 0x0004013000003202L
gpio: 0x0004013000001b02L
gsp: 0x0004013000001c02L
hid: 0x0004013000001d02L
http: 0x0004013000002902L
i2c: 0x0004013000001e02L
ir: 0x0004013000003302L
mcu: 0x0004013000001f02L
mic: 0x0004013000002002L
ndm: 0x0004013000002b02L
news: 0x0004013000003502L
nim: 0x0004013000002c02L
nwm: 0x0004013000002d02L
pdn: 0x0004013000002102L
ps: 0x0004013000003102L
ptm: 0x0004013000002202L
ro: 0x0004013000003702L
socket: 0x0004013000002e02L
spi: 0x0004013000002302L
ssl: 0x0004013000002f02L

View File

@ -11,22 +11,17 @@
#include "starlight/gfx/RenderCore.h" #include "starlight/gfx/RenderCore.h"
#include "starlight/util/Path.h" #include "starlight/util/Path.h"
#include "starlight/util/Profiler.h"
#include "starlight/ui/ParallaxLayer.h" #include "starlight/ui/ParallaxLayer.h"
#include "starlight/ui/ScrollField.h" #include "starlight/ui/ScrollField.h"
#include "starlight/ui/Button.h" #include "starlight/ui/Button.h"
#include "starlight/ui/TextBox.h" #include "starlight/ui/TextBox.h"
#include "starlight/ui/Label.h" #include "starlight/ui/Label.h"
#include "starlight/ui/Image.h"
#include "starlight/ui/DebugConsole.h"
#include "starlight/dialog/Backdrop.h" #include "starlight/dialog/Backdrop.h"
#include "starlight/dialog/MessageBox.h" #include "starlight/dialog/MessageBox.h"
#include "starlight/dialog/OSK.h" #include "starlight/dialog/OSK.h"
#include "ThreadTest.h"
using starlight::Vector2; using starlight::Vector2;
using starlight::VRect; using starlight::VRect;
using starlight::Color; using starlight::Color;
@ -37,24 +32,19 @@ using starlight::GFXManager;
using starlight::gfx::RenderCore; using starlight::gfx::RenderCore;
using starlight::util::Path; using starlight::util::Path;
using starlight::util::Profiler;
using starlight::Application; using starlight::Application;
void Core::Init() { void Core::Init() {
/*clearColor = Color(0,0,0.5); //consoleInit(GFX_TOP, consoleGetDefault());
auto img = touchScreen->AddNew<sl::ui::Image>(Vector2(32, 32), "sdmc:/snes9x_3ds_top.png");
auto lbl = touchScreen->AddNew<sl::ui::Label>(VRect(0,0,320,240));
lbl->SetText("text go here\ntest test test\nnickelpickle");
return;*/
auto container = std::make_shared<sl::ui::ScrollField>(VRect(0,0,320-0,240-0)); auto container = std::make_shared<sl::ui::ScrollField>(VRect(0,0,320-0,240-0));
touchScreen->Add(container); touchScreen->Add(container);
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0)); auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
label->textConfig->justification = Vector2::half; label->textConfig.justification = Vector2::half;
label->autoSizeV = true; label->autoSizeV = true;
label->SetText("~libstarlight UI test~\n\nHello. I'm a label.\nI have multiple lines and can resize to fit my content. Did you know that miles per gallon is actually a measure of volume? " + std::to_string(sizeof(unsigned long long))); label->SetText("~libstardust UI test~\n\nHello. I'm a label.\nI have multiple lines and can resize to fit my content. Did you know that miles per gallon is actually a measure of volume?");
container->Add(label); container->Add(label);
auto button = std::make_shared<sl::ui::Button>(VRect(64,80,128,32)); auto button = std::make_shared<sl::ui::Button>(VRect(64,80,128,32));
@ -63,20 +53,11 @@ void Core::Init() {
// assemble and open a basic form // assemble and open a basic form
auto form = std::make_shared<sl::ui::Form>(true); auto form = std::make_shared<sl::ui::Form>(true);
auto tbtn = form->touchScreen->AddNew<sl::ui::Button>(VRect(4, 28, 80, 24)); auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
tbtn->SetText("print something"); label->textConfig.justification = Vector2::half;
tbtn->eOnTap = [](auto& btn){
printf("pickles!\n");
};
/*auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
label->textConfig->justification = Vector2::half;
label->autoSizeV = true; label->autoSizeV = true;
label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops."); label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops.");
form->touchScreen->Add(label);*/ form->touchScreen->Add(label);
auto console = form->topScreen->AddNew<sl::ui::DebugConsole>(VRect::topScreen);
console->Start();
auto xbtn = std::make_shared<sl::ui::Button>(VRect(320-96,28,32,24)); auto xbtn = std::make_shared<sl::ui::Button>(VRect(320-96,28,32,24));
xbtn->eOnTap = [](auto& btn){ xbtn->eOnTap = [](auto& btn){
@ -85,13 +66,13 @@ void Core::Init() {
xbtn->SetText("(exit)"); xbtn->SetText("(exit)");
form->touchScreen->Add(xbtn); form->touchScreen->Add(xbtn);
/*auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0)); auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0));
tlbl->autoSizeV = true; tlbl->autoSizeV = true;
tlbl->SetPreset("normal.16"); tlbl->SetPreset("normal.16");
tlbl->textConfig->justification = Vector2::zero; tlbl->textConfig.justification = Vector2::zero;
tlbl->textConfig->borderColor = Color::black; tlbl->textConfig.borderColor = Color::black;
tlbl->SetText("3DS:~# sudo make me a sandwich_"); tlbl->SetText("3DS:~# sudo make me a sandwich_");
form->topScreen->Add(tlbl);*/ form->topScreen->Add(tlbl);
auto tb = std::make_shared<sl::ui::TextBox>(VRect(0, 64, 320, 24).Expand(-16, 0)); auto tb = std::make_shared<sl::ui::TextBox>(VRect(0, 64, 320, 24).Expand(-16, 0));
tb->text = "Single-line TextBox widget example. Tap me!"; tb->text = "Single-line TextBox widget example. Tap me!";
@ -107,9 +88,6 @@ void Core::Init() {
// open a backdrop with the default asset // open a backdrop with the default asset
sl::dialog::Backdrop::New()->Open(); sl::dialog::Backdrop::New()->Open();
// make a test thread
std::make_shared<ThreadTest>()->Enqueue();
// //
}; };
container->Add(button); container->Add(button);
@ -122,10 +100,9 @@ void Core::Init() {
auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240)); auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240));
pipf->SetPreset("normal.16"); pipf->SetPreset("normal.16");
pipf->textConfig->borderColor = Color::black; pipf->textConfig.borderColor = Color::black;
pipf->textConfig->justification = Vector2::half; pipf->textConfig.justification = Vector2::half;
//pipf->SetText("This label is on a parallax layer. Try moving the 3D slider.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); pipf->SetText("This label is on a parallax layer. Try moving the 3D slider.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
pipf->SetText(ThemeManager::ResolveAssetPath("app:/decorations/osk.background"));
parallax->Add(pipf); parallax->Add(pipf);
clearColor = Color(0.0f, 0.5f, 0.5f); clearColor = Color(0.0f, 0.5f, 0.5f);
@ -135,7 +112,7 @@ void Core::Init() {
cc.Json()["panini"] = "yes please!"; cc.Json()["panini"] = "yes please!";
cc.Save(); cc.Save();
//*/ //
} }
void Core::End() { void Core::End() {

View File

@ -1,21 +0,0 @@
#include "ThreadTest.h"
#include "starlight/Application.h"
#include "starlight/ConfigManager.h"
using starlight::Application;
void ThreadTest::Body() {
auto& cc = Application::GetConfig("test");
int count = 0;
cc.Json()["pork"] = 0;
cc.Save();
cc.autoSave = true;
while(true) {
cc.Json()["pork"] = ++count;
//cc.Save();
Yield();
}
}

View File

@ -1,7 +0,0 @@
#pragma once
#include "starlight/threading/Thread.h"
class ThreadTest : public sl::threading::Thread {
void Body() override;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

View File

@ -55,10 +55,6 @@
"textColor" : "midGray", "textColor" : "midGray",
"borderColor" : "darkGray", "borderColor" : "darkGray",
"justification" : [0.5, 0.5] "justification" : [0.5, 0.5]
},
"keyHighlight" : {
"_inherit" : "/controls/button/text",
"textColor" : [0.75, 0.825, 1]
} }
} }
}, },