Compare commits
No commits in common. "master" and "v0.5.0" have entirely different histories.
1
.gitignore
vendored
@ -32,7 +32,6 @@
|
||||
*.app
|
||||
*.elf
|
||||
*.3dsx
|
||||
*.cia
|
||||
# ...and icons
|
||||
*.smdh
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
//
|
||||
};
|
||||
}
|
@ -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)); }
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -50,7 +48,6 @@ 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 bool Valid() const { return x == x && y == y; }
|
||||
inline explicit operator bool() const { return x == x && y == y; }
|
||||
|
||||
static const Vector2 invalid;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#include "starlight/_global.h"
|
||||
|
||||
namespace starlight {
|
||||
namespace gfx {
|
||||
enum class BlendMode {
|
||||
Blend,
|
||||
Mask,
|
||||
Replace,
|
||||
|
||||
Normal = Blend
|
||||
};
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ namespace starlight {
|
||||
namespace gfx {
|
||||
class Font {
|
||||
public:
|
||||
static constexpr const int defaultSize = 16;
|
||||
|
||||
Font() { }
|
||||
virtual ~Font() { }
|
||||
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
//
|
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
@ -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
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "starlight/threading/Thread.h"
|
||||
|
||||
class ThreadTest : public sl::threading::Thread {
|
||||
void Body() override;
|
||||
};
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 237 B |
Before Width: | Height: | Size: 250 B |
Before Width: | Height: | Size: 234 B |
@ -55,10 +55,6 @@
|
||||
"textColor" : "midGray",
|
||||
"borderColor" : "darkGray",
|
||||
"justification" : [0.5, 0.5]
|
||||
},
|
||||
"keyHighlight" : {
|
||||
"_inherit" : "/controls/button/text",
|
||||
"textColor" : [0.75, 0.825, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
|