Compare commits

..

16 Commits

Author SHA1 Message Date
gary 5b338043aa save work
Build / build (push) Failing after 11m15s
2026-05-20 19:31:54 -05:00
gary ef1c108b58 [ox/std] Address GCC finding a new way to be retarded
Build / build (push) Successful in 1m12s
2026-05-19 23:19:50 -05:00
gary 6a054cd970 [nostalgia] Enable Wayland support for GLFW
Build / build (push) Successful in 1m39s
2026-05-19 22:47:02 -05:00
gary 9070e6e109 [ox/std] Fix compiler warning
Build / build (push) Successful in 1m18s
2026-05-17 20:33:58 -05:00
gary 6cc6e9e7ed [studio] Rename caseInsensitiveEquals to caseInsensitiveStrCmp
Build / build (push) Successful in 1m9s
2026-05-17 15:56:14 -05:00
gary de859bef77 [ox/std] Rename caseInsensitiveEquals to caseInsensitiveStrCmp 2026-05-17 15:55:35 -05:00
gary d1a3538e9a [ox/oc] Fix writeOC Writer_c variant to add null terminator
Build / build (push) Successful in 1m10s
2026-05-17 15:49:00 -05:00
gary d10a71f06d [studio] Add missing include
Build / build (push) Failing after 1m6s
2026-05-17 15:36:57 -05:00
gary 9593e7eef9 [ox] Add writeOC Writer_c variant 2026-05-17 15:31:56 -05:00
gary 2f9b9c0842 [studio] Fix change-format to only write data portion once
Build / build (push) Successful in 1m15s
2026-05-17 15:22:11 -05:00
gary dce09b564c [ox/std] Fix Result::originate to return value
Build / build (push) Successful in 1m12s
2026-05-17 15:19:13 -05:00
gary 9f485d9496 [studio] Cleanup
Build / build (push) Successful in 1m9s
2026-05-17 15:07:10 -05:00
gary 2c50ce48ed [ox/std] Add Result::reoriginate functions 2026-05-17 15:02:07 -05:00
gary 72e16cb285 [studio] Change output of Claw OC files to make them recognizable as test files 2026-05-17 14:53:42 -05:00
gary d1e410ac55 [ox/std] Add caseInsensitiveEquals 2026-05-17 14:30:43 -05:00
gary be32d575f5 [ox/claw] Add writeClaw Writer_c variant 2026-05-17 14:29:43 -05:00
15 changed files with 125 additions and 23 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.19) cmake_minimum_required(VERSION 3.25)
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19 set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
if(BUILDCORE_TARGET STREQUAL "gba") if(BUILDCORE_TARGET STREQUAL "gba")
@@ -52,7 +52,7 @@ if(NOT BUILDCORE_TARGET STREQUAL "gba")
set(GLFW_BUILD_TESTS OFF) set(GLFW_BUILD_TESTS OFF)
set(GLFW_BUILD_DOCS OFF) set(GLFW_BUILD_DOCS OFF)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(GLFW_BUILD_WAYLAND OFF) set(GLFW_BUILD_WAYLAND ON)
endif() endif()
add_subdirectory(deps/glfw) add_subdirectory(deps/glfw)
add_subdirectory(deps/glutils) add_subdirectory(deps/glutils)
+20
View File
@@ -120,4 +120,24 @@ Result<Buffer> writeClaw(
return out; return out;
} }
Error writeClaw(
auto const &obj,
Writer_c auto &writer,
ClawFormat const fmt = ClawFormat::Metal) noexcept {
OX_RETURN_ERROR(detail::writeClawHeader(writer, &obj, fmt));
#ifdef OX_USE_STDLIB
if (fmt == ClawFormat::Metal) {
OX_RETURN_ERROR(writeMC(writer, obj));
} else if (fmt == ClawFormat::Organic) {
OX_RETURN_ERROR(writeOC(writer, obj));
}
#else
if (fmt != ClawFormat::Metal) {
return ox::Error(1, "OC is not supported in this build");
}
OX_RETURN_ERROR(writeMC(writer, obj));
#endif
return {};
}
} }
+13 -2
View File
@@ -28,6 +28,7 @@ namespace ox {
class OrganicClawWriter { class OrganicClawWriter {
friend Error writeOC(Writer_c auto &writer, auto const &val) noexcept;
friend Result<Buffer> writeOC(const auto &val) noexcept; friend Result<Buffer> writeOC(const auto &val) noexcept;
friend Result<String> writeOCString(const auto &val) noexcept; friend Result<String> writeOCString(const auto &val) noexcept;
@@ -254,9 +255,19 @@ Error OrganicClawWriter::field(CString key, UnionView<U, force> val) noexcept {
return {}; return {};
} }
Error writeOC(Writer_c auto &writer, auto const &val) noexcept {
OrganicClawWriter ocWriter;
ModelHandlerInterface handler(ocWriter);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, ocWriter.m_json);
OX_RETURN_ERROR(writer.write(str.data(), str.size()));
return writer.put('\0');
}
Result<Buffer> writeOC(auto const &val) noexcept { Result<Buffer> writeOC(auto const &val) noexcept {
OrganicClawWriter writer; OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer); ModelHandlerInterface handler(writer);
OX_RETURN_ERROR(model(&handler, &val)); OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder; Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json); auto const str = Json::writeString(jsonBuilder, writer.m_json);
@@ -270,7 +281,7 @@ Result<Buffer> writeOC(auto const &val) noexcept {
Result<String> writeOCString(auto const &val) noexcept { Result<String> writeOCString(auto const &val) noexcept {
OrganicClawWriter writer; OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer); ModelHandlerInterface handler(writer);
OX_RETURN_ERROR(model(&handler, &val)); OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder; Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json); auto const str = Json::writeString(jsonBuilder, writer.m_json);
+15
View File
@@ -345,6 +345,21 @@ struct [[nodiscard]] Result {
return *this; return *this;
} }
constexpr Result reoriginate(
ErrorCode const pErrCode,
CString const pMsg = nullptr,
std::source_location const &pSrc = std::source_location::current()) const && noexcept {
if (error) {
return {std::move(value), Error{pErrCode, pMsg, pSrc}};
}
return {std::move(value)};
}
constexpr Result reoriginate(
std::source_location const &pSrc = std::source_location::current()) const && noexcept {
return {std::move(value), Error{error.errCode, error.msg, pSrc}};
}
}; };
namespace detail { namespace detail {
+21
View File
@@ -36,6 +36,27 @@ constexpr StringView substr(StringViewCR str, std::size_t const start, std::size
return {}; return {};
} }
[[nodiscard]]
constexpr char toUpper(char const c) noexcept {
return c & static_cast<char>(0b1101'1111);
}
[[nodiscard]]
constexpr int caseInsensitiveStrCmp(StringViewCR a, StringViewCR b) noexcept {
auto const sz = ox::min(a.size(), b.size());
for (size_t i{}; i < sz; ++i) {
auto const ac = toUpper(a[i]);
auto const bc = toUpper(b[i]);
if (ac < bc) {
return -1;
}
if (ac > bc) {
return 1;
}
}
return 0;
}
[[nodiscard]] [[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept { constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning; return base.size() && base[0] == beginning;
+7
View File
@@ -54,6 +54,10 @@ struct VectorAllocator {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
if (cap <= m_data.size() && count <= m_data.size()) { if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) { for (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i])); auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
@@ -65,6 +69,9 @@ struct VectorAllocator {
*items = reinterpret_cast<T*>(m_data.data()); *items = reinterpret_cast<T*>(m_data.data());
} }
} }
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} }
} }
@@ -155,19 +155,20 @@ void TileSheetEditorImGui::draw(studio::Context&) noexcept {
} }
} }
} }
auto const scale = turbine::scale(m_tctx);
auto const paneSize = ImGui::GetContentRegionAvail(); auto const paneSize = ImGui::GetContentRegionAvail();
auto const tileSheetParentSize = ImVec2{paneSize.x - s_palViewWidth, paneSize.y}; auto const tileSheetParentSize = ImVec2{paneSize.x - s_palViewWidth * scale, paneSize.y};
auto const fbSize = ox::Vec2{tileSheetParentSize.x - 16, tileSheetParentSize.y - 16}; auto const fbSize = ox::Vec2{tileSheetParentSize.x - 16 * scale, tileSheetParentSize.y - 16 * scale};
ImGui::BeginChild("TileSheetView", tileSheetParentSize, true); ImGui::BeginChild("TileSheetView", tileSheetParentSize, true);
{ {
drawTileSheet(fbSize); drawTileSheet(fbSize);
} }
ImGui::EndChild(); ImGui::EndChild();
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginChild("Controls", {s_palViewWidth - 8, paneSize.y}, true); ImGui::BeginChild("Controls", {(s_palViewWidth - 8) * scale, paneSize.y}, true);
{ {
auto const controlsSize = ImGui::GetContentRegionAvail(); auto const controlsSize = ImGui::GetContentRegionAvail();
ImGui::BeginChild("ToolBox", {0, 32}, true); ImGui::BeginChild("ToolBox", {0, 32 * scale}, true);
{ {
auto const btnSz = ImVec2{45, 14}; auto const btnSz = ImVec2{45, 14};
if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) { if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
@@ -193,7 +194,7 @@ void TileSheetEditorImGui::draw(studio::Context&) noexcept {
//ig::ComboBox("##Operations", ox::Array<ox::CStringView, 1>{"Operations"}, i); //ig::ComboBox("##Operations", ox::Array<ox::CStringView, 1>{"Operations"}, i);
} }
ImGui::EndChild(); ImGui::EndChild();
ImGui::BeginChild("OperationsBox", {0, 35}, ImGuiWindowFlags_NoTitleBar); ImGui::BeginChild("OperationsBox", {0, 35 * scale}, ImGuiWindowFlags_NoTitleBar);
{ {
if (ImGui::BeginCombo("##Operations", "Operations", 0)) { if (ImGui::BeginCombo("##Operations", "Operations", 0)) {
if (ImGui::Selectable("Flip X", false)) { if (ImGui::Selectable("Flip X", false)) {
@@ -216,12 +217,12 @@ void TileSheetEditorImGui::draw(studio::Context&) noexcept {
ImGui::EndChild(); ImGui::EndChild();
auto const ySize = controlsSize.y - (38 + ig::BtnSz.y + 21); auto const ySize = controlsSize.y - (38 + ig::BtnSz.y + 21);
// draw palette/color picker // draw palette/color picker
ImGui::BeginChild("Palette", {s_palViewWidth - 24, ySize / 2.f}, true); ImGui::BeginChild("Palette", {(s_palViewWidth - 24) * scale, ySize / 2.f}, true);
{ {
drawPaletteMenu(); drawPaletteMenu();
} }
ImGui::EndChild(); ImGui::EndChild();
ImGui::BeginChild("SubSheets", {s_palViewWidth - 24, ySize / 2.f}, true); ImGui::BeginChild("SubSheets", {(s_palViewWidth - 24) * scale, ySize / 2.f}, true);
{ {
static constexpr auto btnHeight = ig::BtnSz.y; static constexpr auto btnHeight = ig::BtnSz.y;
auto constexpr btnSize = ImVec2{btnHeight, btnHeight}; auto constexpr btnSize = ImVec2{btnHeight, btnHeight};
+2 -1
View File
@@ -17,6 +17,7 @@
#include "subcommands/change-format/change-format.hpp" #include "subcommands/change-format/change-format.hpp"
#include "configfile.hpp" #include "configfile.hpp"
#include "font.hpp"
#include "studioui.hpp" #include "studioui.hpp"
namespace studio { namespace studio {
@@ -129,7 +130,7 @@ static ox::Error run(
if (m->id() == moduleId) { if (m->id() == moduleId) {
for (auto const &c : m->commands()) { for (auto const &c : m->commands()) {
if (c.name == subCmd) { if (c.name == subCmd) {
auto kctx = keel::init( auto const kctx = keel::init(
ox::make_unique<ox::PassThroughFS>(projectDir), ox::make_unique<ox::PassThroughFS>(projectDir),
c.name); c.name);
if (kctx.error) { if (kctx.error) {
+6 -2
View File
@@ -132,7 +132,11 @@ StudioUI::StudioUI(turbine::Context &tctx, ox::StringParam projectDataDir) noexc
// that it will still be treated as const. // that it will still be treated as const.
// ImGui documentation recognizes that this is a bad design, // ImGui documentation recognizes that this is a bad design,
// and hopefully it will change at some point. // and hopefully it will change at some point.
io.Fonts->AddFontFromMemoryTTF(const_cast<uint8_t*>(font.data()), static_cast<int>(font.size()), 13, &fontCfg); io.Fonts->AddFontFromMemoryTTF(
const_cast<uint8_t*>(font.data()),
static_cast<int>(font.size()),
13 * turbine::scale(m_tctx),
&fontCfg);
} }
auto &kctx = keelCtx(m_tctx); auto &kctx = keelCtx(m_tctx);
kctx.converters.emplace_back(keel::Converter::make<convertStudioConfigV1ToStudioConfigV2>()); kctx.converters.emplace_back(keel::Converter::make<convertStudioConfigV1ToStudioConfigV2>());
@@ -215,7 +219,7 @@ void StudioUI::draw() noexcept {
ImGuiFocusedFlags_RootAndChildWindows | ImGuiFocusedFlags_NoPopupHierarchy); ImGuiFocusedFlags_RootAndChildWindows | ImGuiFocusedFlags_NoPopupHierarchy);
if (m_showProjectExplorer) { if (m_showProjectExplorer) {
auto const v = ImGui::GetContentRegionAvail(); auto const v = ImGui::GetContentRegionAvail();
m_projectExplorer.draw(m_sctx, {300, v.y}); m_projectExplorer.draw(m_sctx, {300 * turbine::scale(m_tctx), v.y});
ImGui::SameLine(); ImGui::SameLine();
} }
drawTabBar(); drawTabBar();
@@ -16,11 +16,16 @@ static ox::Error convertFile(
ox::TypeStore &ts, ox::TypeStore &ts,
ox::StringViewCR path, ox::StringViewCR path,
ox::ClawFormat const fmt) noexcept { ox::ClawFormat const fmt) noexcept {
ox::Buffer buff; OX_REQUIRE_M(buff, fs.read(path).reoriginate(1, "unable to read file"));
ox::ModelObject obj; OX_REQUIRE(uuid, keel::readUuidHeader(buff));
OX_RETURN_ERROR(fs.read(path).moveTo(buff).reoriginate(1, "unable to read file")); OX_REQUIRE(obj, keel::readAsset(ts, buff).reoriginate(1, "unable to parse file"));
OX_RETURN_ERROR(keel::readAsset(ts, buff).moveTo(obj).reoriginate(1, "unable to parse file")); buff.clear();
OX_RETURN_ERROR(ox::writeClaw(obj, fmt).moveTo(buff)); ox::BufferWriter writer{&buff};
OX_RETURN_ERROR(keel::writeUuidHeader(writer, uuid));
OX_RETURN_ERROR(ox::writeClaw(obj, writer, fmt));
if (fmt == ox::ClawFormat::Organic) {
*buff.back().value = '\n';
}
OX_RETURN_ERROR(fs.write(path, buff).reoriginate(1, "unable to write file")); OX_RETURN_ERROR(fs.write(path, buff).reoriginate(1, "unable to write file"));
return {}; return {};
} }
@@ -31,12 +36,12 @@ static void printUsage() noexcept {
[[nodiscard]] [[nodiscard]]
static constexpr ox::Result<ox::ClawFormat> getFmt(ox::StringViewCR fmtStr) noexcept { static constexpr ox::Result<ox::ClawFormat> getFmt(ox::StringViewCR fmtStr) noexcept {
if (fmtStr == "mc") { if (caseInsensitiveStrCmp(fmtStr, "mc") == 0) {
return ox::ClawFormat::Metal; return ox::ClawFormat::Metal;
} else if (fmtStr == "oc") { } else if (caseInsensitiveStrCmp(fmtStr, "oc") == 0) {
return ox::ClawFormat::Organic; return ox::ClawFormat::Organic;
} }
return ox::Error(1, "invalid format"); return ox::Error{1, "invalid format"};
} }
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> const args) noexcept { ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> const args) noexcept {
@@ -4,6 +4,8 @@
#pragma once #pragma once
#include <studio/project.hpp>
namespace studio { namespace studio {
ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> args) noexcept; ox::Error cmdChangeFormat(Project &project, ox::SpanView<ox::CString> args) noexcept;
@@ -165,7 +165,7 @@ template<typename T>
ox::Error Project::writeObj(ox::StringViewCR path, T const &obj, ox::ClawFormat fmt) noexcept { ox::Error Project::writeObj(ox::StringViewCR path, T const &obj, ox::ClawFormat fmt) noexcept {
OX_REQUIRE_M(buff, ox::writeClaw(obj, fmt)); OX_REQUIRE_M(buff, ox::writeClaw(obj, fmt));
if (fmt == ox::ClawFormat::Organic) { if (fmt == ox::ClawFormat::Organic) {
buff.pop_back(); *buff.back().value = '\n';
} }
// write to FS // write to FS
OX_RETURN_ERROR(mkdir(parentDir(path))); OX_RETURN_ERROR(mkdir(parentDir(path)));
@@ -112,4 +112,7 @@ void setShutdownHandler(Context &ctx, ShutdownHandler handler) noexcept;
// sleep time is a minimum of ~16 milliseconds. // sleep time is a minimum of ~16 milliseconds.
void setUpdateHandler(Context &ctx, UpdateHandler) noexcept; void setUpdateHandler(Context &ctx, UpdateHandler) noexcept;
[[nodiscard]]
float scale(Context const &ctx) noexcept;
} }
+1
View File
@@ -32,6 +32,7 @@ class Context {
uint64_t draws = 0; uint64_t draws = 0;
bool running{}; bool running{};
ShutdownHandler shutdownHandler{}; ShutdownHandler shutdownHandler{};
float scale{};
Context() noexcept = default; Context() noexcept = default;
+11
View File
@@ -339,6 +339,7 @@ ox::Result<ox::UPtr<Context>> init(
setMandatoryRefreshPeriod(*ctx, ticksMs(*ctx) + config::MandatoryRefreshPeriod); setMandatoryRefreshPeriod(*ctx, ticksMs(*ctx) + config::MandatoryRefreshPeriod);
// init GLFW context // init GLFW context
glfwInit(); glfwInit();
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
glfwSetErrorCallback(handleGlfwError); glfwSetErrorCallback(handleGlfwError);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
@@ -372,7 +373,13 @@ ox::Result<ox::UPtr<Context>> init(
ImGui_ImplGlfw_InitForOpenGL(ctx->window, true); ImGui_ImplGlfw_InitForOpenGL(ctx->window, true);
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
io.IniFilename = nullptr; io.IniFilename = nullptr;
float xscale{}, yscale{};
glfwGetWindowContentScale(ctx->window, &xscale, &yscale);
ctx->scale = ox::max(xscale, yscale);
io.DisplayFramebufferScale = ImVec2(ctx->scale, ctx->scale);
themeImgui(); themeImgui();
auto &style = ImGui::GetStyle();
style.ScaleAllSizes(ctx->scale);
#endif #endif
return ctx; return ctx;
} }
@@ -471,4 +478,8 @@ KeyEventHandler keyEventHandler(Context const &ctx) noexcept {
return ctx.keyEventHandler; return ctx.keyEventHandler;
} }
float scale(Context const &ctx) noexcept {
return ctx.scale;
}
} }