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
*.elf
*.3dsx
*.cia
# ...and icons
*.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)
## 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/`.
(Themes on SD go in `sdmc:/.starlight/themes/`)
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`.
## License
* MIT (see [license.md](license.md))

View File

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

View File

@ -17,9 +17,6 @@ using starlight::ThemeManager;
using starlight::InputManager;
using starlight::gfx::RenderCore;
using starlight::threading::Thread;
using starlight::threading::ThreadState;
using starlight::ui::TouchScreenCanvas;
using starlight::ui::TopScreenCanvas;
@ -33,7 +30,6 @@ using starlight::Application;
////////////////////
Application* Application::_currentApp = nullptr;
unsigned long long Application::ftime = 0;
bool Application::Quit() {
if (_currentApp == nullptr) return false;
@ -86,9 +82,6 @@ void Application::_init() {
void Application::_end() {
End();
for (auto& thread : threads) thread->Exit();
threads.clear();
//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
@ -104,9 +97,6 @@ void Application::_end() {
}
void Application::_mainLoop() {
RenderCore::SyncFrame(); // sync to vblank here for more accurate timing
frameTimer.FrameStart();
if (!forms.empty()) {
if (_sFormState) {
_sFormState = false;
@ -134,8 +124,6 @@ void Application::_mainLoop() {
}
// update step
ftime = osGetTime();
InputManager::Update();
Update();
{ // update loop for forms, guarded from snap-outs
@ -163,16 +151,4 @@ void Application::_mainLoop() {
topScreen->Draw();
PostDraw();
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 <memory>
#include <list>
#include "starlight/datatypes/Vector2.h"
#include "starlight/datatypes/VRect.h"
#include "starlight/datatypes/Color.h"
#include "starlight/util/FrameTimer.h"
#include "starlight/threading/Thread.h"
#include "starlight/ui/TouchScreenCanvas.h"
#include "starlight/ui/TopScreenCanvas.h"
@ -27,14 +22,12 @@ namespace starlight {
////////////////////
private:
static Application* _currentApp;
static unsigned long long ftime;
public:
static bool Quit();
static Config& GetConfig(const std::string& path);
static std::string AppName();
static inline Application* Current() { return _currentApp; }
static inline unsigned long long GetTime() { return ftime; }
//////////////////////
// INSTANCE MEMBERS //
@ -46,9 +39,6 @@ namespace starlight {
void _mainLoop();
void _end();
std::list<std::shared_ptr<threading::Thread>> threads;
util::FrameTimer frameTimer;
public:
const std::string appId;
@ -67,14 +57,13 @@ namespace starlight {
void Run();
void EnqueueThread(std::shared_ptr<threading::Thread> thread);
inline void SignalFormState() { _sFormState = true; }
virtual void Init() { }
virtual void Update() { }
virtual void PostUpdate() { }
virtual void Draw() { }
virtual void PostDraw() { }
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
};
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 {
// forward declare this for OpenKeyboard
namespace dialog {
@ -97,11 +94,11 @@ namespace starlight {
static Vector2 CStick();
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 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 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 TouchDelta();

View File

@ -19,17 +19,12 @@
#include "starlight/gfx/DrawableNinePatch.h"
#include "starlight/gfx/DrawableTest.h"
#include "starlight/gfx/FontBMF.h"
#include "starlight/gfx/FontNull.h"
#include "starlight/gfx/RenderCore.h"
#include "starlight/gfx/BitmapFont.h"
#include "starlight/util/JsonConversions.h"
#include "starlight/util/Profiler.h"
using starlight::util::Profiler;
#include <sstream>
using std::string;
using std::shared_ptr;
using std::make_shared;
@ -80,48 +75,40 @@ namespace {
}
CTexture* LoadPNG(const std::string& path, bool isPremult = false) {
//Profiler::TaskStart();
unsigned char* imgbuf;
unsigned width, height;
lodepng::State state;
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);
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) {
u32* src = reinterpret_cast<u32*>(imgbuf); u32* dst = reinterpret_cast<u32*>(gpubuf);
// just convert endianness
for(unsigned iy = 0; iy < height; iy++) {
for (unsigned ix = 0; ix < width; ix++) {
u32 clr = *src;
*dst = __builtin_bswap32(clr);
int r = *src++;
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
}
} else {
u8* src = static_cast<u8*>(imgbuf); u8* dst = static_cast<u8*>(gpubuf);
// convert and premultiply
for(unsigned iy = 0; iy < height; iy++) {
for (unsigned ix = 0; ix < width; ix++) {
u8 r = *src++;
u8 g = *src++;
u8 b = *src++;
u8 a = *src++;
int r = *src++;
int g = *src++;
int b = *src++;
int a = *src++;
float aa = (1.0f / 255.0f) * a;
@ -133,14 +120,11 @@ namespace {
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,
// 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);
tx->size = Vector2(width, height); // and for now just fix the size after the fact
//Profiler::TaskFinish("copied into linear");
std::free(imgbuf);
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) {
auto const& itr = drawables.find(name);
if (itr == drawables.end()) {
@ -225,14 +195,14 @@ ThemeRef<Font> ThemeManager::GetFont(const std::string& name) {
void ThemeManager::Fulfill(ThemeRefContainer<Drawable>& ref) {
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>();
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") {
return make_shared<DrawableImage>(LoadPNG(path));
}
@ -243,7 +213,7 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
fs >> j;
}
auto st = j.dump();
//printf("file contents: %s\n", st.c_str());
printf("file contents: %s\n", st.c_str());
string type = j["assetType"];
/**/ if (type == "ninepatch") {
@ -255,8 +225,9 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
// else if (type == "") { }
else if (type == "link") {
string npath = ResolveAssetPath(j["path"]);
ref.redir = const_cast<ThemeRefContainer<Drawable>*>(GetAsset(npath).cptr); // link containers directly
return nulldrw; // doesn't really matter what's inside, it'll never get used
//return LoadAsset(npath);
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;
}
@ -265,10 +236,6 @@ shared_ptr<Drawable> ThemeManager::LoadAsset(string& path, ThemeRefContainer<Dra
void ThemeManager::Fulfill(ThemeRefContainer<Font>& ref) {
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>();
{ // using:
json j;
@ -291,100 +258,54 @@ void ThemeManager::LoadProc() {
}
string ThemeManager::ResolveAssetPath(const string& id) {
string pfx = "";
//struct stat buf;
//string path(id.length() + 64, ' '); // preallocate buffer space
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:/"
static const string pfxLocal = "app:/";
if (id.compare(0, pfxLocal.length(), pfxLocal) == 0) {
// app-local asset
// check if present in theme/app/[appname]/, else check in romfs
for (auto thm : themeData) {
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;
p = bp.Combine(sid+".json");
if (p.IsFile()) return p;
p = bp.Combine(sid+".png");
p = bp.Combine(id+".png");
if (p.IsFile()) return p;
}
// TBD - directly in romfs, or in an assets folder?
Path bp = Path("romfs:/");
Path p = bp.Combine(sid);
Path bp = Path("romfs:");
Path p = bp.Combine(id+".json");
if (p.IsFile()) return p;
p = bp.Combine(sid+".json");
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");
p = bp.Combine(id+".png");
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(id);
if (p.IsFile()) return p;
p = thm.basePath.Combine(id+".json");
Path p = thm.basePath.Combine(id+".json");
if (p.IsFile()) return p;
p = thm.basePath.Combine(id+".png");
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();
}
string ThemeManager::ResolveFontPath(const string& id) { // there we go, nice and simple
string pfx = "";
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");
for (auto thm : themeData) {
Path p = thm.basePath.Combine("fonts").Combine(id+".json");
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
const string fallback = "mono.12";
if (id != fallback) return ResolveFontPath(fallback);
return string(); // fallback not found; no themes on sdmc or romfs, probably
return string();
}
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::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:
ThemeManager() = delete; // "static" class
static void Init();
static void End();
static void GC();
static gfx::ThemeRef<gfx::Drawable> GetAsset(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() = 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(VRect rect, const std::string& text, Vector2 justification = Vector2::invalid);

View File

@ -1,13 +1,9 @@
#include "Color.h"
#include <limits>
#include "starlight/_incLib/json.hpp"
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::white = Color(1.0f, 1.0f, 1.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 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
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)); }
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 white;
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 <cmath>
#include <algorithm>
#include <fastmath.h>
#include <limits>
@ -12,11 +11,6 @@ using starlight::Vector2;
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::ClampLength(float max) const {
float len = Length();
return *this * (std::min(len, max) / len);
}
Vector2 Vector2::Reciprocal() const { return Vector2(y, x); }
Vector2 Vector2::IntSnap() const { return Vector2(roundf(x), roundf(y)); }

View File

@ -19,8 +19,6 @@ namespace starlight {
Vector2 Normalized() const;
inline float Area() const { return x * y; }
Vector2 ClampLength(float max = 1) const;
Vector2 Reciprocal() 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 bool Valid() const { return x == x && y == y; }
inline explicit operator bool() const { return x == x && y == y; }
static const Vector2 invalid;

View File

@ -37,10 +37,6 @@ namespace {
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;
}
@ -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
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;
touchScreen->Add(cover);
// build keyboard
// wip
//setContainer = touchScreen->AddNew<ui::UIContainer>(VRect::touchScreen); // kept as a test case
setContainer = touchScreen->AddNew<ui::UICanvas>(VRect::touchScreen); // but this is much more efficient
setContainer = std::make_shared<ui::UIContainer>(VRect::touchScreen);
touchScreen->Add(setContainer);
auto actSym = [this](Button& key){
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);
} else {
// 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;
key->SetText(string(1, c));
key->eOnTap = actSym;
setContainer->Add(key);
// 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;
key->SetText(string(1, C));
key->eOnTap = actSym;
setContainer->Add(key);
// and after
bpen.x += key->rect.size.x;
@ -95,30 +94,26 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
// backspace
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->style.glyph = ThemeManager::GetAsset("glyphs/backspace.small");
key->SetText("< <");
key->eOnTap = [this](auto& btn){ this->handler->Backspace(); this->OnKey(); };
touchScreen->Add(key);
// enter
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->style.glyph = ThemeManager::GetAsset("glyphs/enter.large");
key->SetText("Enter");
key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); };
touchScreen->Add(key);
// shift
bpen = bpstart + bs * Vector2(linestart[0] + .25, 4);
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 = std::make_shared<ScrollField>(VRect(VRect::touchScreen.TopEdge(66)));
touchScreen->Add(previewSc);
previewSc = touchScreen->AddNew<ScrollField>(VRect(VRect::touchScreen.TopEdge(66)));
preview = previewSc->AddNew<DrawLayerProxy>(VRect::touchScreen.TopEdge(66).Expand(-2, 0), [this](auto& layer){ this->DrawPreview(layer); }, true);
preview = std::make_shared<DrawLayerProxy>(VRect::touchScreen.TopEdge(66).Expand(-2, 0), [this](auto& layer){ this->DrawPreview(layer); }, true);
preview->eOnTap = [this](auto& layer){ this->OnPreviewTap(layer); };
previewSc->Add(preview);
RefreshPreview();
}
@ -129,57 +124,46 @@ void OSK::Update(bool focused) {
return;
}
if (focused) {
if (InputManager::Pressed(Keys::B | Keys::Start)) handler->Done();
if (InputManager::Pressed(Keys::B)) handler->Done();
if (handler->showPreview) {
auto& tc = PreviewTC();
bool refresh = false;
if (ShiftScroll(Keys::DPadLeft)) {
if (InputManager::Pressed(Keys::DPadLeft)) {
auto c = handler->GetCursor();
if (c > 0) handler->SetCursor(c - 1);
refresh = true;
RefreshPreview();
}
if (ShiftScroll(Keys::DPadRight)) {
if (InputManager::Pressed(Keys::DPadRight)) {
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());
pt.y -= tc.Measure("|").y * 0.5f;
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());
pt.y += tc.Measure("|").y * 1.5f;
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
refresh = true;
RefreshPreview();
}
if (refresh) RefreshPreview();
}
float& s = setContainer->scrollOffset.y;
float ts = 0;
if (InputManager::Held(Keys::L) || InputManager::Held(Keys::R)) {
ts = 1000;
shiftLock = false;
} else if (shiftLock) ts = 1000;
}
if (s != ts) {
s = ts;
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() {
shiftLock = false;
RefreshPreview();
}

View File

@ -6,7 +6,6 @@
#include <memory>
#include "starlight/ui/Form.h"
#include "starlight/ui/Button.h"
#include "starlight/ui/ScrollField.h"
#include "starlight/ui/DrawLayerProxy.h"
@ -20,10 +19,7 @@ namespace starlight {
std::shared_ptr<ui::ScrollField> previewSc;
std::shared_ptr<ui::DrawLayerProxy> preview;
std::shared_ptr<ui::Button> shiftKey;
//Vector2 cursorPos;
bool shiftLock = false;
public:
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)); }
// 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()) {
target->Bind(color ? color.get() : Color(1,1,1,1));
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()) {
target->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : this->rect;

View File

@ -23,8 +23,8 @@ namespace starlight {
DrawContextCanvas(Vector2 size);
~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 VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, 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) override;
Vector2 Size() override;
@ -32,4 +32,4 @@ namespace starlight {
void Clear() override;
};
}
}
}

View File

@ -7,8 +7,6 @@
#include "starlight/datatypes/OptRef.h"
#include "starlight/gfx/Enums.h"
namespace starlight {
namespace gfx {
class Drawable {
@ -19,14 +17,16 @@ namespace starlight {
// pattern after:
// 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);
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;
void Draw(const Vector2& position, OptRef<Vector2> hotspot, OptRef<VRect> sampleRect, OptRef<Color> color, float rotation, float scale, BlendMode mode = BlendMode::Normal) {
Draw(position, hotspot, sampleRect, color, rotation, Vector2(scale, scale), mode);
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) {
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;
};
}
}

View File

@ -15,18 +15,18 @@ using starlight::gfx::DrawableImage;
using starlight::gfx::RenderCore;
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()) {
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);
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);
}
}
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()) {
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);
RenderCore::DrawQuad(rect, sr / texture->txSize);
}

View File

@ -15,10 +15,11 @@ namespace starlight {
DrawableImage(CTexture* texture) : texture(texture) { }
~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 VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, 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) override;
Vector2 Size() override;
};
}
}

View File

@ -15,9 +15,9 @@ using starlight::gfx::DrawableNinePatch;
using starlight::gfx::RenderCore;
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()) {
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();
const VRect& sr = (sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size)).IntSnap();

View File

@ -16,7 +16,7 @@ namespace starlight {
~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 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;
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()) {
//static u32 col = Color(0, 0.5f, 1);
//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()) {
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());
}
}

View File

@ -10,10 +10,11 @@ namespace starlight {
DrawableTest() { }
~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 VRect& rect, OptRef<VRect> sampleRect = nullptr, OptRef<Color> color = nullptr, 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) override;
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 {
class Font {
public:
static constexpr const int defaultSize = 16;
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::Color;
using starlight::util::WorkerThread;
using starlight::gfx::BlendMode;
using starlight::gfx::CTexture;
using starlight::gfx::CRenderTarget;
using starlight::gfx::RenderCore;
@ -25,33 +24,41 @@ namespace { // internals
typedef struct {
float x, y, z, u, v;
} vbo_xyzuv;
vbo_xyzuv* vboArray = nullptr;
size_t vboIndex = 0;
size_t vboSize = 0;
void addVertXYZUV(float x, float y, float z, float u, float 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 setXYZUV(vbo_xyzuv& vbo, float x, float y, float z, float u, float v) {
vbo.x = x;
vbo.y = y;
vbo.z = z;
vbo.u = u;
vbo.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;
shaderProgram_s shader;
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 >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
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 {
@ -70,8 +77,8 @@ namespace { // internals
C3D_TexDelete(texture);
delete texture;
}
void Bind(Color color = Color::white, BlendMode mode = BlendMode::Normal) override {
RenderCore::BindTexture(texture, color, mode);
void Bind(Color color = Color::white) override {
RenderCore::BindTexture(texture, color);
}
};
}
@ -87,21 +94,9 @@ void RenderCore::Open() {
gfxSet3D(true);
C3D_Init(0x80000*8);
// allocate and initialize VBO
vboSize = 0x80000;
void* vboAddr = linearAlloc(vboSize);
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);
bufferSize = 0x80000;
bufferStart = linearAlloc(bufferSize);
bufferInd = 0;
// set up screen targets
targetTopLeft = std::make_unique<CRenderTarget>(240, 400, true);
@ -124,7 +119,7 @@ void RenderCore::Open() {
// 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_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL); // hmm.
C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); // hmm.
C3D_CullFace(GPU_CULL_NONE);
}
@ -134,75 +129,45 @@ void RenderCore::Close() {
targetTopRight.reset(nullptr);
targetBottom.reset(nullptr);
linearFree(reinterpret_cast<void*>(vboArray));
linearFree(bufferStart);
C3D_Fini();
gfxExit();
}
void RenderCore::SyncFrame() {
C3D_FrameSync();
}
void RenderCore::BeginFrame() {
C3D_FrameBegin(0/*C3D_FRAME_SYNCDRAW*/);
vboIndex = 0;
ResetBuffer();
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
}
void RenderCore::EndFrame() {
C3D_FrameEnd(0);
}
namespace {
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) {
void RenderCore::BindTexture(C3D_Tex* tex, const Color& color) {
C3D_TexBind(0, tex); // 0 should be correct
C3D_TexEnv* env = C3D_GetTexEnv(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());
}
void RenderCore::BindColor(const Color& color, BlendMode mode) {
void RenderCore::BindColor(const Color& color) {
C3D_TexEnv* env = C3D_GetTexEnv(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());
}
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
@ -214,23 +179,41 @@ void RenderCore::DrawQuad(const VRect& rect, const VRect& src, bool noSnap) {
// 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 srl = src.pos.x, srr = srl + src.size.x, srt = src.pos.y, srb = srt + src.size.y;
addVertXYZUV(rl, rt, 0, srl, srt);
addVertXYZUV(rr, rt, 0, srr, srt);
addVertXYZUV(rl, rb, 0, srl, srb);
addVertXYZUV(rr, rb, 0, srr, srb);
setXYZUV(verts[0], rl, rt, 0, srl, srt);
setXYZUV(verts[1], rr, rt, 0, srr, srt);
setXYZUV(verts[2], rl, rb, 0, srl, 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) {
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());
addVertXYZUV(rect.TopRight().RotateAround(anchor, angle), src.TopRight());
addVertXYZUV(rect.BottomLeft().RotateAround(anchor, angle), src.BottomLeft());
addVertXYZUV(rect.BottomRight().RotateAround(anchor, angle), src.BottomRight());
setXYZUV(verts[0], rect.TopLeft().RotateAround(anchor, angle), src.TopLeft());
setXYZUV(verts[1], rect.TopRight().RotateAround(anchor, angle), src.TopRight());
setXYZUV(verts[2], rect.BottomLeft().RotateAround(anchor, angle), src.BottomLeft());
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
@ -251,7 +234,7 @@ CTexture* RenderCore::LoadTexture(void* src, int width, int height) {
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;
}
@ -265,22 +248,9 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) {
auto w = forceExact ? width : NextPow2(width),
h = forceExact ? height : NextPow2(height);
txSize = Vector2(w, h);
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...
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
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);
//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() {
@ -288,33 +258,17 @@ CRenderTarget::~CRenderTarget() {
}
void CRenderTarget::Clear(Color color) {
//unsigned int c = color;
//c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
//C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0);
clearColor = color;
unsigned int c = color;
c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
}
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_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) {
//C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0); // don't clear again until marked to
RenderCore::BindTexture(&tex, color, mode);
void CRenderTarget::Bind(Color color) {
C3D_RenderTargetSetClear(tgt, 0, 0, 0); // don't clear again until marked to
RenderCore::BindTexture(&(tgt->renderBuf.colorBuf), color);
}

View File

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

View File

@ -16,30 +16,21 @@ namespace starlight {
protected:
const std::string name;
std::shared_ptr<T> ptr = nullptr;
ThemeRefContainer* redir = nullptr;
unsigned int lastAccess = 0; // how many gc sweeps since last use
volatile int refCount = 0;
void Unload(bool full = false) {
void Unload() {
ptr.reset();
if (full) redir = nullptr;
}
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) : 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:
~ThemeRefContainer() { }
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 {
@ -53,32 +44,15 @@ namespace starlight {
template <class T>
class ThemeRef {
friend class starlight::ThemeManager;
protected:
ThemeRefContainer<T>* cptr;
private:
const ThemeRefContainer<T>* cptr;
public:
ThemeRef() : cptr(nullptr) { }
ThemeRef(ThemeRefContainer<T>* c) : cptr(c) { if (cptr) cptr->refCount++; }
ThemeRef(ThemeRef<T>& o) : cptr(o.cptr) { if (cptr) cptr->refCount++; }
ThemeRef(ThemeRef<T>&& o) : cptr(o.cptr) { if (cptr) cptr->refCount++; }
~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); }
ThemeRef(ThemeRefContainer<T>* c) : cptr(c) { }
~ThemeRef() { }
inline const ThemeRefContainer<T>& operator ->() const { return *cptr; }
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; }
};
}

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::ThemeManager;
using starlight::TextConfig;
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) {
label = text;
MarkForRedraw();
@ -35,18 +28,18 @@ void Button::Draw() {
static auto idle = ThemeManager::GetAsset("controls/button.idle");
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();
if (InputManager::GetDragHandle() == this) {
(style.press ? style.press : press)->Draw(rect);
press->Draw(rect);
} 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);
if (style.glyph) style.glyph->Draw(rect.Center(), Vector2::half, nullptr, tc.textColor);
}
void Button::OnTouchOn() {

View File

@ -4,30 +4,15 @@
#include <string>
#include <functional>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h"
#include "starlight/ui/UIElement.h"
namespace starlight {
namespace ui {
class Button : public UIElement {
public:
struct Style {
gfx::ThemeRef<gfx::Drawable>
idle = nullptr,
press = nullptr,
glyph = nullptr;
Optional<TextConfig> textConfig = &Button::defCfg;
};
private:
static std::function<TextConfig&()> defCfg;
//
public:
Style style;
std::string label = "";
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"
using starlight::GFXManager;
using starlight::TextConfig;
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) {
this->rect = rect;
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
}
void Label::AutoSize() {
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);
}
@ -33,13 +28,12 @@ void Label::SetText(const std::string& text) {
}
void Label::SetFont(const std::string& fontName) {
textConfig->font = ThemeManager::GetFont(fontName);
textConfig->Measure(""); // force load
textConfig.font = ThemeManager::GetFont(fontName);
AutoSize();
}
void Label::SetPreset(const std::string& name) {
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig.ROGet());
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig);
AutoSize();
}
@ -54,8 +48,7 @@ void Label::PreDraw() {
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.ROGet().Print(buffer->rect, text);
textConfig.Print(buffer->rect, text);
GFXManager::PopContext();
}
}
@ -65,6 +58,6 @@ void Label::Draw() {
if (buffer) {
buffer->Draw(VRect(rect.pos, buffer->rect.size));
} else {
textConfig.ROGet().Print(rect, text);
textConfig.Print(rect, text);
}
}

View File

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

View File

@ -35,7 +35,6 @@ void UICanvas::PreDraw() {
drawContext->Clear();
GFXManager::PushContext(drawContext.get());
GFXManager::PushOffsetAdd(-scrollOffset);
GFXManager::PrepareForDrawing(); // force clear to take so you don't get garbage if nothing renders
VRect vr = ViewportRect();
@ -52,3 +51,4 @@ void UICanvas::PreDraw() {
void UICanvas::Draw() {
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) {
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()));
if (front) children.push_front(std::move(elem));
else children.push_back(std::move(elem));
MarkForRedraw();
}
//void UIContainer::Add(UIElement* elem) {
@ -71,7 +71,6 @@ void UIContainer::RemoveAll() {
it->parent = std::weak_ptr<UIContainer>(); // clear parent
}
children.clear();
MarkForRedraw();
}
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 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 Remove(std::shared_ptr<UIElement> elem);
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 {
- make font-not-found not outright crash the app (hopefully)
- 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"
roadmap to first release, in no particular order {
- ding!
} 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)
garbage collection for not-recently-used theme assets {
- keep track of last-use in ThemeRefContainer
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
}
add customization for Button (alternate idle/press images, optional glyph drawable)
^ use that to spice up the OSK
actual cursor image for OSK instead of just using a | glypyh
input prompt dialog
make the panel background not just the button image
"shortcut" overloads for InputManager::OpenKeyboard
language config and atlas support
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
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 {

View File

@ -1,4 +1,4 @@
The MIT License (MIT)
### MIT License
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
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
}
mode=send
if [ "$1" = "sc" ]; then
mode=send-cia
elif [ "$1" = "c" ]; then
if [ "$1" = "c" ]; then
mode=run
fi
cd libstarlight

View File

@ -44,8 +44,6 @@ APP_TITLE := Starlight Testbed
APP_DESCRIPTION := Test application for libstarlight
APP_AUTHOR := zetaPRIME
3DSIP := 10.0.0.6
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
@ -58,7 +56,7 @@ CFLAGS := -g -Wall -O2 -mword-relocations \
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
# 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
#CXXFLAGS := $(CFLAGS) -std=gnu++14
@ -89,7 +87,6 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
export ROMFS_ROOT := $(CURDIR)/$(ROMFS)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
@ -165,19 +162,14 @@ cci: $(TARGET)-strip.elf
@echo "built ... sf2d_sample.3ds"
#---------------------------------------------------------------------------------
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"
#---------------------------------------------------------------------------------
send: $(BUILD)
#@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)
@3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx || 3dslink $(TARGET).3dsx
#---------------------------------------------------------------------------------
run: $(BUILD)
@citra-qt $(TARGET).3dsx
@citra $(TARGET).3dsx
#---------------------------------------------------------------------------------
copy_cia: $(TARGET).cia
@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/util/Path.h"
#include "starlight/util/Profiler.h"
#include "starlight/ui/ParallaxLayer.h"
#include "starlight/ui/ScrollField.h"
#include "starlight/ui/Button.h"
#include "starlight/ui/TextBox.h"
#include "starlight/ui/Label.h"
#include "starlight/ui/Image.h"
#include "starlight/ui/DebugConsole.h"
#include "starlight/dialog/Backdrop.h"
#include "starlight/dialog/MessageBox.h"
#include "starlight/dialog/OSK.h"
#include "ThreadTest.h"
using starlight::Vector2;
using starlight::VRect;
using starlight::Color;
@ -37,24 +32,19 @@ using starlight::GFXManager;
using starlight::gfx::RenderCore;
using starlight::util::Path;
using starlight::util::Profiler;
using starlight::Application;
void Core::Init() {
/*clearColor = Color(0,0,0.5);
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;*/
//consoleInit(GFX_TOP, consoleGetDefault());
auto container = std::make_shared<sl::ui::ScrollField>(VRect(0,0,320-0,240-0));
touchScreen->Add(container);
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->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);
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
auto form = std::make_shared<sl::ui::Form>(true);
auto tbtn = form->touchScreen->AddNew<sl::ui::Button>(VRect(4, 28, 80, 24));
tbtn->SetText("print something");
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;
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
label->textConfig.justification = Vector2::half;
label->autoSizeV = true;
label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops.");
form->touchScreen->Add(label);*/
auto console = form->topScreen->AddNew<sl::ui::DebugConsole>(VRect::topScreen);
console->Start();
form->touchScreen->Add(label);
auto xbtn = std::make_shared<sl::ui::Button>(VRect(320-96,28,32,24));
xbtn->eOnTap = [](auto& btn){
@ -85,13 +66,13 @@ void Core::Init() {
xbtn->SetText("(exit)");
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->SetPreset("normal.16");
tlbl->textConfig->justification = Vector2::zero;
tlbl->textConfig->borderColor = Color::black;
tlbl->textConfig.justification = Vector2::zero;
tlbl->textConfig.borderColor = Color::black;
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));
tb->text = "Single-line TextBox widget example. Tap me!";
@ -107,9 +88,6 @@ void Core::Init() {
// open a backdrop with the default asset
sl::dialog::Backdrop::New()->Open();
// make a test thread
std::make_shared<ThreadTest>()->Enqueue();
//
};
container->Add(button);
@ -122,10 +100,9 @@ void Core::Init() {
auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240));
pipf->SetPreset("normal.16");
pipf->textConfig->borderColor = Color::black;
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(ThemeManager::ResolveAssetPath("app:/decorations/osk.background"));
pipf->textConfig.borderColor = Color::black;
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.");
parallax->Add(pipf);
clearColor = Color(0.0f, 0.5f, 0.5f);
@ -135,7 +112,7 @@ void Core::Init() {
cc.Json()["panini"] = "yes please!";
cc.Save();
//*/
//
}
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",
"borderColor" : "darkGray",
"justification" : [0.5, 0.5]
},
"keyHighlight" : {
"_inherit" : "/controls/button/text",
"textColor" : [0.75, 0.825, 1]
}
}
},