Merge commit 'a4a00c99d05441f5db491e06186039f817cb5c81'
Some checks failed
Build / build (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
This commit is contained in:
commit
5c9ab7ae08
@ -60,7 +60,7 @@ class StringView: public detail::BaseStringView {
|
||||
|
||||
};
|
||||
|
||||
using StringViewCR = const StringView&;
|
||||
using StringViewCR = StringView const&;
|
||||
|
||||
constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
|
||||
if (s2.len() != s1.len()) {
|
||||
@ -89,7 +89,7 @@ constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto write(Writer_c auto &writer, ox::StringViewCR sv) noexcept {
|
||||
constexpr auto write(Writer_c auto &writer, StringViewCR sv) noexcept {
|
||||
return writer.write(sv.data(), sv.bytes());
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ constexpr auto toStdStringView(StringViewCR sv) noexcept {
|
||||
#endif
|
||||
|
||||
|
||||
constexpr ox::Result<int> strToInt(ox::StringViewCR str) noexcept {
|
||||
constexpr ox::Result<int> strToInt(StringViewCR str) noexcept {
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
int total = 0;
|
||||
int multiplier = 1;
|
||||
|
@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "color.hpp"
|
||||
#include "context.hpp"
|
||||
#include "gfx.hpp"
|
||||
#include "initparams.hpp"
|
||||
#include "keelmodule.hpp"
|
||||
#include "palette.hpp"
|
||||
#include "ptidxconv.hpp"
|
||||
#include "tilesheet.hpp"
|
@ -9,8 +9,12 @@
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/model/def.hpp>
|
||||
|
||||
#include "color.hpp"
|
||||
#include "context.hpp"
|
||||
#include "initparams.hpp"
|
||||
#include "keelmodule.hpp"
|
||||
#include "palette.hpp"
|
||||
#include "ptidxconv.hpp"
|
||||
#include "tilesheet.hpp"
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
@ -8,6 +8,6 @@
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
const keel::Module *keelModule() noexcept;
|
||||
keel::Module const *keelModule() noexcept;
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,6 @@
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
const studio::Module *studioModule() noexcept;
|
||||
studio::Module const *studioModule() noexcept;
|
||||
|
||||
}
|
||||
|
@ -4,11 +4,6 @@ add_library(
|
||||
tilesheet.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(gba)
|
||||
if(NOT BUILDCORE_TARGET STREQUAL "gba")
|
||||
add_subdirectory(opengl)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
NostalgiaGfx PUBLIC
|
||||
../include
|
||||
@ -31,3 +26,38 @@ install(
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
# OpenGL
|
||||
|
||||
if(NOT BUILDCORE_TARGET STREQUAL "gba")
|
||||
target_sources(
|
||||
NostalgiaGfx PRIVATE
|
||||
gfx-opengl.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
NostalgiaGfx PUBLIC
|
||||
GlUtils
|
||||
)
|
||||
endif()
|
||||
|
||||
# GBA
|
||||
|
||||
add_library(
|
||||
NostalgiaGfx-GBA OBJECT
|
||||
gfx-gba.cpp
|
||||
)
|
||||
target_include_directories(
|
||||
NostalgiaGfx-GBA PUBLIC
|
||||
../include
|
||||
)
|
||||
target_link_libraries(
|
||||
NostalgiaGfx-GBA PUBLIC
|
||||
TeaGBA
|
||||
Keel
|
||||
Turbine
|
||||
)
|
||||
|
||||
if(BUILDCORE_TARGET STREQUAL "gba")
|
||||
set_source_files_properties(gfx-gba.cpp PROPERTIES COMPILE_FLAGS -marm)
|
||||
target_link_libraries(NostalgiaGfx PUBLIC NostalgiaGfx-GBA)
|
||||
endif()
|
||||
|
@ -1,21 +0,0 @@
|
||||
add_library(
|
||||
NostalgiaGfx-GBA OBJECT
|
||||
context.cpp
|
||||
gfx.cpp
|
||||
panic.cpp
|
||||
)
|
||||
target_include_directories(
|
||||
NostalgiaGfx-GBA PUBLIC
|
||||
../../include
|
||||
)
|
||||
target_link_libraries(
|
||||
NostalgiaGfx-GBA PUBLIC
|
||||
TeaGBA
|
||||
Keel
|
||||
Turbine
|
||||
)
|
||||
|
||||
if(BUILDCORE_TARGET STREQUAL "gba")
|
||||
set_source_files_properties(gfx.cpp PROPERTIES COMPILE_FLAGS -marm)
|
||||
target_link_libraries(NostalgiaGfx PUBLIC NostalgiaGfx-GBA)
|
||||
endif()
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include <nostalgia/gfx/gfx.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
void safeDelete(Context *ctx) noexcept {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
Context::Context(turbine::Context &tctx) noexcept: turbineCtx(tctx) {
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const¶ms) noexcept {
|
||||
auto ctx = ox::make_unique<Context>(tctx);
|
||||
OX_RETURN_ERROR(initGfx(*ctx, params));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
keel::Context &keelCtx(Context &ctx) noexcept {
|
||||
return turbine::keelCtx(ctx.turbineCtx);
|
||||
}
|
||||
|
||||
turbine::Context &turbineCtx(Context &ctx) noexcept {
|
||||
return ctx.turbineCtx;
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nostalgia/gfx/context.hpp>
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
struct BgCbbData {
|
||||
unsigned bpp = 4;
|
||||
};
|
||||
|
||||
class Context {
|
||||
|
||||
public:
|
||||
turbine::Context &turbineCtx;
|
||||
ox::Array<BgCbbData, 4> cbbData;
|
||||
|
||||
explicit Context(turbine::Context &tctx) noexcept;
|
||||
Context(Context &other) noexcept = delete;
|
||||
Context(Context const&other) noexcept = delete;
|
||||
Context(Context const&&other) noexcept = delete;
|
||||
virtual ~Context() noexcept = default;
|
||||
|
||||
[[nodiscard]]
|
||||
ox::MemFS const&rom() const noexcept {
|
||||
return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nostalgia/gfx/context.hpp>
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <ox/std/def.hpp>
|
||||
#include <ox/std/realstd.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/bios.hpp>
|
||||
|
||||
#include <nostalgia/gfx/core.hpp>
|
||||
|
||||
#include "gfx.hpp"
|
||||
|
||||
#define HEAP_BEGIN (reinterpret_cast<char*>(MEM_EWRAM_BEGIN))
|
||||
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
|
||||
#define HEAP_END (reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE))
|
||||
|
||||
namespace ox {
|
||||
|
||||
using namespace nostalgia::gfx;
|
||||
|
||||
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
|
||||
// reset heap to make sure we have enough memory to allocate context data
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
|
||||
auto ctx = init(*tctx).unwrap();
|
||||
std::ignore = initGfx(*ctx, {});
|
||||
std::ignore = initConsole(*ctx);
|
||||
setBgStatus(*ctx, 0, true);
|
||||
clearBg(*ctx, 0);
|
||||
auto const serr = ox::sfmt<ox::IString<23>>("Error code: {}", static_cast<int64_t>(err));
|
||||
consoleWrite(*ctx, 32 + 1, 1, "SADNESS...");
|
||||
consoleWrite(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
|
||||
consoleWrite(*ctx, 32 + 2, 6, panicMsg);
|
||||
if (err) {
|
||||
consoleWrite(*ctx, 32 + 2, 8, serr);
|
||||
}
|
||||
consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
|
||||
// print to terminal if in mGBA
|
||||
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
|
||||
if (err.msg) {
|
||||
oxErrf("\tError Message:\t{}\n", err.msg);
|
||||
}
|
||||
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
|
||||
if (err.src.file_name() != nullptr) {
|
||||
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
}
|
@ -15,15 +15,48 @@
|
||||
#include <nostalgia/gfx/gfx.hpp>
|
||||
#include <nostalgia/gfx/tilesheet.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
struct BgCbbData {
|
||||
unsigned bpp = 4;
|
||||
};
|
||||
|
||||
class Context {
|
||||
|
||||
public:
|
||||
turbine::Context &turbineCtx;
|
||||
ox::Array<BgCbbData, 4> cbbData;
|
||||
|
||||
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
|
||||
Context(Context &other) noexcept = delete;
|
||||
Context(Context const&other) noexcept = delete;
|
||||
Context(Context const&&other) noexcept = delete;
|
||||
virtual ~Context() noexcept = default;
|
||||
|
||||
[[nodiscard]]
|
||||
ox::MemFS const&rom() const noexcept {
|
||||
return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void safeDelete(Context *ctx) noexcept {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
keel::Context &keelCtx(Context &ctx) noexcept {
|
||||
return turbine::keelCtx(ctx.turbineCtx);
|
||||
}
|
||||
|
||||
turbine::Context &turbineCtx(Context &ctx) noexcept {
|
||||
return ctx.turbineCtx;
|
||||
}
|
||||
|
||||
static constexpr auto SpriteCount = 128;
|
||||
|
||||
ox::Error initGfx(Context&, InitParams const&) noexcept {
|
||||
static ox::Error initGfx() noexcept {
|
||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||
teagba::bgSetSbb(*bgCtl, 28);
|
||||
}
|
||||
@ -34,6 +67,12 @@ ox::Error initGfx(Context&, InitParams const&) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&) noexcept {
|
||||
auto ctx = ox::make_unique<Context>(tctx);
|
||||
OX_RETURN_ERROR(initGfx());
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ox::Error loadBgPalette(
|
||||
Context&,
|
||||
size_t const palBank,
|
||||
@ -300,4 +339,43 @@ uint_t spriteCount(Context const&) noexcept {
|
||||
|
||||
}
|
||||
|
||||
namespace ox {
|
||||
|
||||
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
|
||||
using namespace nostalgia::gfx;
|
||||
// reset heap to make sure we have enough memory to allocate context data
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
const auto heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN);
|
||||
const auto heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2;
|
||||
const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz);
|
||||
ox::heapmgr::initHeap(heapBegin, heapEnd);
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
|
||||
auto ctx = init(*tctx).unwrap();
|
||||
std::ignore = initGfx();
|
||||
std::ignore = initConsole(*ctx);
|
||||
setBgStatus(*ctx, 0, true);
|
||||
clearBg(*ctx, 0);
|
||||
auto const serr = ox::sfmt<ox::IString<23>>("Error code: {}", static_cast<int64_t>(err));
|
||||
consoleWrite(*ctx, 32 + 1, 1, "SADNESS...");
|
||||
consoleWrite(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
|
||||
consoleWrite(*ctx, 32 + 2, 6, panicMsg);
|
||||
if (err) {
|
||||
consoleWrite(*ctx, 32 + 2, 8, serr);
|
||||
}
|
||||
consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
|
||||
// print to terminal if in mGBA
|
||||
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
|
||||
if (err.msg) {
|
||||
oxErrf("\tError Message:\t{}\n", err.msg);
|
||||
}
|
||||
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
|
||||
if (err.src.file_name() != nullptr) {
|
||||
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <ox/std/array.hpp>
|
||||
#include <ox/std/fmt.hpp>
|
||||
#include <ox/std/vec.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
|
||||
@ -15,22 +14,105 @@
|
||||
#include <nostalgia/gfx/palette.hpp>
|
||||
#include <nostalgia/gfx/tilesheet.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
namespace renderer {
|
||||
|
||||
constexpr uint64_t TileRows = 128;
|
||||
constexpr uint64_t TileColumns = 128;
|
||||
constexpr uint64_t TileCount = TileRows * TileColumns;
|
||||
constexpr uint64_t BgVertexVboRows = 4;
|
||||
constexpr uint64_t BgVertexVboRowLength = 7;
|
||||
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
||||
constexpr uint64_t BgVertexEboLength = 6;
|
||||
constexpr uint64_t SpriteVertexVboRows = 4;
|
||||
constexpr uint64_t SpriteVertexVboRowLength = 6;
|
||||
constexpr uint64_t SpriteVertexVboLength = SpriteVertexVboRows * SpriteVertexVboRowLength;
|
||||
constexpr uint64_t SpriteVertexEboLength = 6;
|
||||
|
||||
struct CBB: glutils::BufferSet {
|
||||
bool updated = false;
|
||||
ox::Array<uint32_t, 32768> pixels;
|
||||
constexpr CBB() noexcept {
|
||||
vertices.resize(TileCount * BgVertexVboLength);
|
||||
elements.resize(TileCount * BgVertexEboLength);
|
||||
}
|
||||
};
|
||||
|
||||
struct SpriteBlockset: glutils::BufferSet {
|
||||
bool updated = false;
|
||||
constexpr SpriteBlockset(uint64_t spriteCount, uint64_t blocksPerSprite) noexcept {
|
||||
vertices.resize(spriteCount * SpriteVertexVboLength * blocksPerSprite);
|
||||
elements.resize(spriteCount * SpriteVertexEboLength * blocksPerSprite);
|
||||
}
|
||||
};
|
||||
|
||||
struct Background {
|
||||
float priority = 0;
|
||||
bool enabled = false;
|
||||
unsigned cbbIdx = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class Context {
|
||||
public:
|
||||
class Drawer final: public turbine::gl::Drawer {
|
||||
private:
|
||||
Context &m_ctx;
|
||||
public:
|
||||
explicit Drawer(Context &ctx) noexcept: m_ctx{ctx} {}
|
||||
void draw(turbine::Context &tctx) noexcept override {
|
||||
gl::draw(m_ctx, turbine::getScreenSize(tctx));
|
||||
}
|
||||
};
|
||||
|
||||
turbine::Context &turbineCtx;
|
||||
glutils::GLProgram bgShader;
|
||||
glutils::GLProgram spriteShader;
|
||||
ox::Array<renderer::CBB, 4> cbbs;
|
||||
renderer::SpriteBlockset spriteBlocks;
|
||||
ox::Array<Sprite, 128> spriteStates;
|
||||
ox::Array<GLfloat, 1024> bgPalette;
|
||||
ox::Array<renderer::Background, 4> backgrounds;
|
||||
Drawer drawer;
|
||||
uint_t spriteCount = 0;
|
||||
uint_t blocksPerSprite = 0;
|
||||
|
||||
explicit Context(turbine::Context &tctx, InitParams const ¶ms) noexcept:
|
||||
turbineCtx{tctx},
|
||||
spriteBlocks{params.glSpriteCount, params.glBlocksPerSprite},
|
||||
drawer{*this},
|
||||
spriteCount{params.glSpriteCount},
|
||||
blocksPerSprite{params.glBlocksPerSprite} {
|
||||
}
|
||||
Context(Context const&) = delete;
|
||||
Context(Context&&) = delete;
|
||||
Context &operator=(Context const&) = delete;
|
||||
Context &operator=(Context&&) = delete;
|
||||
~Context() noexcept {
|
||||
turbine::gl::removeDrawer(turbineCtx, &drawer);
|
||||
}
|
||||
};
|
||||
|
||||
void safeDelete(Context *ctx) noexcept {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
keel::Context &keelCtx(Context &ctx) noexcept {
|
||||
return turbine::keelCtx(ctx.turbineCtx);
|
||||
}
|
||||
|
||||
turbine::Context &turbineCtx(Context &ctx) noexcept {
|
||||
return ctx.turbineCtx;
|
||||
}
|
||||
|
||||
|
||||
namespace renderer {
|
||||
|
||||
static constexpr auto Scale = 1;
|
||||
static constexpr auto PriorityScale = 0.01f;
|
||||
|
||||
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
|
||||
|
||||
void Drawer::draw(turbine::Context &tctx) noexcept {
|
||||
gl::draw(m_ctx, turbine::getScreenSize(tctx));
|
||||
}
|
||||
|
||||
static constexpr ox::CStringView bgvshadTmpl = R"glsl(
|
||||
{}
|
||||
in vec2 vTexCoord;
|
||||
@ -241,7 +323,13 @@ static void initSpritesBufferset(Context &ctx) noexcept {
|
||||
// in float vEnabled;
|
||||
auto const enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled"));
|
||||
glEnableVertexAttribArray(enabledAttr);
|
||||
glVertexAttribPointer(enabledAttr, 1, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float), nullptr);
|
||||
glVertexAttribPointer(
|
||||
enabledAttr,
|
||||
1,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
SpriteVertexVboRowLength * sizeof(float),
|
||||
nullptr);
|
||||
// in vec3 vPosition;
|
||||
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
|
||||
glEnableVertexAttribArray(posAttr);
|
||||
@ -250,8 +338,9 @@ static void initSpritesBufferset(Context &ctx) noexcept {
|
||||
// in vec2 vTexCoord;
|
||||
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
|
||||
glEnableVertexAttribArray(texCoordAttr);
|
||||
glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||
std::bit_cast<void*>(uintptr_t{4 * sizeof(float)}));
|
||||
glVertexAttribPointer(
|
||||
texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||
std::bit_cast<void*>(uintptr_t{4 * sizeof(float)}));
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
@ -270,7 +359,13 @@ static void initBackgroundBufferset(
|
||||
// vbo layout
|
||||
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
|
||||
glEnableVertexAttribArray(posAttr);
|
||||
glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float), nullptr);
|
||||
glVertexAttribPointer(
|
||||
posAttr,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
BgVertexVboRowLength * sizeof(float),
|
||||
nullptr);
|
||||
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
|
||||
glEnableVertexAttribArray(texCoordAttr);
|
||||
glVertexAttribPointer(
|
||||
@ -300,7 +395,16 @@ static glutils::GLTexture createTexture(
|
||||
tex.height = h;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex.id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
tex.width,
|
||||
tex.height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixels);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
@ -470,28 +574,23 @@ static void setSprite(
|
||||
|
||||
}
|
||||
|
||||
ox::Error initGfx(
|
||||
Context &ctx,
|
||||
InitParams const&initParams) noexcept {
|
||||
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const¶ms) noexcept {
|
||||
auto ctx = ox::make_unique<Context>(tctx, params);
|
||||
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
|
||||
const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
|
||||
const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
|
||||
const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion);
|
||||
OX_RETURN_ERROR(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx.bgShader));
|
||||
OX_RETURN_ERROR(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx->bgShader));
|
||||
OX_RETURN_ERROR(
|
||||
glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx.spriteShader));
|
||||
for (auto &cbb : ctx.cbbs) {
|
||||
initBackgroundBufferset(ctx.bgShader, cbb);
|
||||
glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx->spriteShader));
|
||||
for (auto &cbb : ctx->cbbs) {
|
||||
initBackgroundBufferset(ctx->bgShader, cbb);
|
||||
}
|
||||
renderer::initSpritesBufferset(ctx);
|
||||
if (initParams.glInstallDrawer) {
|
||||
turbine::gl::addDrawer(ctx.turbineCtx, &ctx.drawer);
|
||||
renderer::initSpritesBufferset(*ctx);
|
||||
if (params.glInstallDrawer) {
|
||||
turbine::gl::addDrawer(ctx->turbineCtx, &ctx->drawer);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void shutdownGfx(Context &ctx) noexcept {
|
||||
turbine::gl::removeDrawer(ctx.turbineCtx, &ctx.drawer);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct TileSheetData {
|
@ -20,7 +20,7 @@ int tileRows(Context&) noexcept {
|
||||
|
||||
ox::Error loadBgPalette(
|
||||
Context &ctx,
|
||||
size_t palBank,
|
||||
size_t const palBank,
|
||||
ox::StringViewCR palettePath) noexcept {
|
||||
OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
|
||||
return loadBgPalette(ctx, palBank, *pal, 0);
|
||||
@ -28,8 +28,8 @@ ox::Error loadBgPalette(
|
||||
|
||||
ox::Error loadBgPalette(
|
||||
Context &ctx,
|
||||
size_t palBank,
|
||||
ox::FileAddress const&paletteAddr) noexcept {
|
||||
size_t const palBank,
|
||||
ox::FileAddress const &paletteAddr) noexcept {
|
||||
OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr));
|
||||
return loadBgPalette(ctx, palBank, *pal, 0);
|
||||
}
|
||||
@ -43,18 +43,18 @@ ox::Error loadSpritePalette(
|
||||
|
||||
ox::Error loadSpritePalette(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&paletteAddr) noexcept {
|
||||
ox::FileAddress const &paletteAddr) noexcept {
|
||||
OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr));
|
||||
return loadSpritePalette(ctx, *pal, 0);
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
unsigned const cbb,
|
||||
ox::FileAddress const&tsAddr,
|
||||
size_t dstTileIdx,
|
||||
size_t srcTileIdx,
|
||||
size_t tileCnt) noexcept {
|
||||
size_t const dstTileIdx,
|
||||
size_t const srcTileIdx,
|
||||
size_t const tileCnt) noexcept {
|
||||
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsAddr));
|
||||
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
|
||||
}
|
||||
@ -63,16 +63,16 @@ ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
ox::StringViewCR tsPath,
|
||||
size_t dstTileIdx,
|
||||
size_t srcTileIdx,
|
||||
size_t tileCnt) noexcept {
|
||||
size_t const dstTileIdx,
|
||||
size_t const srcTileIdx,
|
||||
size_t const tileCnt) noexcept {
|
||||
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsPath));
|
||||
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
unsigned const cbb,
|
||||
ox::StringViewCR tilesheetPath,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
|
||||
@ -81,7 +81,7 @@ ox::Error loadBgTileSheet(
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
unsigned const cbb,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
|
||||
@ -91,7 +91,7 @@ ox::Error loadBgTileSheet(
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::StringViewCR tilesheetPath,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
bool const loadDefaultPalette) noexcept {
|
||||
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
|
||||
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
|
||||
}
|
||||
@ -99,7 +99,7 @@ ox::Error loadSpriteTileSheet(
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
bool const loadDefaultPalette) noexcept {
|
||||
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
|
||||
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
|
||||
}
|
||||
@ -235,7 +235,13 @@ constexpr ox::Array<char, 128> charMap = {
|
||||
50, // ~
|
||||
};
|
||||
|
||||
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank) noexcept {
|
||||
void setBgTile(
|
||||
Context &ctx,
|
||||
uint_t const bgIdx,
|
||||
int const column,
|
||||
int const row,
|
||||
unsigned const tile,
|
||||
unsigned const palBank) noexcept {
|
||||
setBgTile(ctx, bgIdx, column, row, {
|
||||
.tileIdx = tile,
|
||||
.palBank = palBank,
|
||||
|
@ -1,9 +0,0 @@
|
||||
target_sources(
|
||||
NostalgiaGfx PRIVATE
|
||||
context.cpp
|
||||
gfx.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
NostalgiaGfx PUBLIC
|
||||
GlUtils
|
||||
)
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include "context.hpp"
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
void safeDelete(Context *ctx) noexcept {
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
Context::Context(turbine::Context &tctx, InitParams const¶ms) noexcept:
|
||||
turbineCtx(tctx),
|
||||
spriteBlocks(params.glSpriteCount, params.glBlocksPerSprite),
|
||||
drawer(*this),
|
||||
spriteCount(params.glSpriteCount),
|
||||
blocksPerSprite(params.glBlocksPerSprite) {
|
||||
}
|
||||
|
||||
Context::~Context() noexcept {
|
||||
shutdownGfx(*this);
|
||||
}
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const¶ms) noexcept {
|
||||
auto ctx = ox::make_unique<Context>(tctx, params);
|
||||
OX_RETURN_ERROR(initGfx(*ctx, params));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
keel::Context &keelCtx(Context &ctx) noexcept {
|
||||
return turbine::keelCtx(ctx.turbineCtx);
|
||||
}
|
||||
|
||||
turbine::Context &turbineCtx(Context &ctx) noexcept {
|
||||
return ctx.turbineCtx;
|
||||
}
|
||||
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
#include <glutils/glutils.hpp>
|
||||
|
||||
#include <nostalgia/gfx/gfx.hpp>
|
||||
#include <nostalgia/gfx/context.hpp>
|
||||
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
|
||||
class Context {
|
||||
|
||||
public:
|
||||
turbine::Context &turbineCtx;
|
||||
glutils::GLProgram bgShader;
|
||||
glutils::GLProgram spriteShader;
|
||||
ox::Array<renderer::CBB, 4> cbbs;
|
||||
renderer::SpriteBlockset spriteBlocks;
|
||||
ox::Array<Sprite, 128> spriteStates;
|
||||
ox::Array<GLfloat, 1024> bgPalette;
|
||||
ox::Array<renderer::Background, 4> backgrounds;
|
||||
renderer::Drawer drawer;
|
||||
uint_t spriteCount = 0;
|
||||
uint_t blocksPerSprite = 0;
|
||||
explicit Context(turbine::Context &tctx, InitParams const¶ms) noexcept;
|
||||
Context(Context const&) = delete;
|
||||
Context(Context&&) = delete;
|
||||
Context &operator=(Context const&) = delete;
|
||||
Context &operator=(Context&&) = delete;
|
||||
~Context() noexcept;
|
||||
};
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
#include <turbine/gfx.hpp>
|
||||
|
||||
#include <glutils/glutils.hpp>
|
||||
|
||||
#include <nostalgia/gfx/context.hpp>
|
||||
|
||||
namespace nostalgia::gfx::renderer {
|
||||
|
||||
constexpr uint64_t TileRows = 128;
|
||||
constexpr uint64_t TileColumns = 128;
|
||||
constexpr uint64_t TileCount = TileRows * TileColumns;
|
||||
constexpr uint64_t BgVertexVboRows = 4;
|
||||
constexpr uint64_t BgVertexVboRowLength = 7;
|
||||
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
||||
constexpr uint64_t BgVertexEboLength = 6;
|
||||
constexpr uint64_t SpriteVertexVboRows = 4;
|
||||
constexpr uint64_t SpriteVertexVboRowLength = 6;
|
||||
constexpr uint64_t SpriteVertexVboLength = SpriteVertexVboRows * SpriteVertexVboRowLength;
|
||||
constexpr uint64_t SpriteVertexEboLength = 6;
|
||||
|
||||
struct CBB: public glutils::BufferSet {
|
||||
bool updated = false;
|
||||
ox::Array<uint32_t, 32768> pixels;
|
||||
constexpr CBB() noexcept {
|
||||
vertices.resize(TileCount * BgVertexVboLength);
|
||||
elements.resize(TileCount * BgVertexEboLength);
|
||||
}
|
||||
};
|
||||
|
||||
struct SpriteBlockset: public glutils::BufferSet {
|
||||
bool updated = false;
|
||||
constexpr SpriteBlockset(uint64_t spriteCount, uint64_t blocksPerSprite) noexcept {
|
||||
vertices.resize(spriteCount * SpriteVertexVboLength * blocksPerSprite);
|
||||
elements.resize(spriteCount * SpriteVertexEboLength * blocksPerSprite);
|
||||
}
|
||||
};
|
||||
|
||||
struct Background {
|
||||
float priority = 0;
|
||||
bool enabled = false;
|
||||
unsigned cbbIdx = 0;
|
||||
};
|
||||
|
||||
class Drawer: public turbine::gl::Drawer {
|
||||
private:
|
||||
Context &m_ctx;
|
||||
public:
|
||||
explicit Drawer(Context &ctx) noexcept;
|
||||
void draw(turbine::Context&) noexcept final;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace nostalgia::gfx {
|
||||
ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
|
||||
void shutdownGfx(Context &ctx) noexcept;
|
||||
}
|
@ -6,16 +6,16 @@
|
||||
|
||||
#include <map>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <nostalgia/gfx/core.hpp>
|
||||
#include <ox/mc/write.hpp>
|
||||
#include <nostalgia/gfx/gfx.hpp>
|
||||
|
||||
using namespace nostalgia;
|
||||
|
||||
static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||
{
|
||||
"readWriteTileSheet",
|
||||
[]() -> ox::Error {
|
||||
gfx::TileSheet in;
|
||||
[] -> ox::Error {
|
||||
gfx::TileSheet const in;
|
||||
OX_REQUIRE(buff, ox::writeMC(in));
|
||||
OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff));
|
||||
oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken");
|
||||
@ -29,7 +29,7 @@ int main(int argc, const char **argv) {
|
||||
if (argc > 0) {
|
||||
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
|
||||
auto const testName = ox::StringView(args[1]);
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
if (tests.contains(testName)) {
|
||||
retval = static_cast<int>(tests[testName]());
|
||||
} else {
|
||||
retval = 1;
|
||||
|
@ -8,6 +8,6 @@
|
||||
|
||||
namespace nostalgia::sound {
|
||||
|
||||
const keel::Module *keelModule() noexcept;
|
||||
keel::Module const *keelModule() noexcept;
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,6 @@
|
||||
|
||||
namespace nostalgia::sound {
|
||||
|
||||
const studio::Module *studioModule() noexcept;
|
||||
studio::Module const *studioModule() noexcept;
|
||||
|
||||
}
|
||||
|
@ -10,32 +10,30 @@
|
||||
|
||||
namespace nostalgia::sound {
|
||||
|
||||
static class: public keel::Module {
|
||||
private:
|
||||
static struct: keel::Module {
|
||||
|
||||
public:
|
||||
[[nodiscard]]
|
||||
ox::String id() const noexcept override {
|
||||
return ox::String{"net.drinkingtea.nostalgia.sound"};
|
||||
}
|
||||
[[nodiscard]]
|
||||
ox::String id() const noexcept override {
|
||||
return ox::String{"net.drinkingtea.nostalgia.sound"};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::TypeDescGenerator> types() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::TypeDescGenerator> types() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::Converter> converters() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::Converter> converters() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
[[nodiscard]]
|
||||
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
||||
return {
|
||||
};
|
||||
}
|
||||
|
||||
} const mod;
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
namespace nostalgia::sound {
|
||||
|
||||
static class: public studio::Module {
|
||||
static struct: studio::Module {
|
||||
|
||||
ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final {
|
||||
return {
|
||||
};
|
||||
@ -18,6 +19,7 @@ static class: public studio::Module {
|
||||
ox::Vector<ox::UPtr<studio::ItemMaker>> out;
|
||||
return out;
|
||||
}
|
||||
|
||||
} const mod;
|
||||
|
||||
const studio::Module *studioModule() noexcept {
|
||||
|
4
deps/nostalgia/src/nostalgia/player/app.cpp
vendored
4
deps/nostalgia/src/nostalgia/player/app.cpp
vendored
@ -5,7 +5,7 @@
|
||||
#include <keel/media.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include <nostalgia/gfx/core.hpp>
|
||||
#include <nostalgia/gfx/gfx.hpp>
|
||||
|
||||
using namespace nostalgia;
|
||||
|
||||
@ -52,7 +52,7 @@ static int testUpdateHandler(turbine::Context &tctx) noexcept {
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static void testKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool down) noexcept {
|
||||
static void testKeyEventHandler(turbine::Context &tctx, turbine::Key const key, bool const down) noexcept {
|
||||
if (down) {
|
||||
if (key == turbine::Key::Alpha_Q) {
|
||||
turbine::requestShutdown(tctx);
|
||||
|
4
deps/nostalgia/src/olympic/applib/applib.cpp
vendored
4
deps/nostalgia/src/olympic/applib/applib.cpp
vendored
@ -38,7 +38,7 @@
|
||||
#endif
|
||||
|
||||
namespace olympic {
|
||||
ox::String appVersion = ox::String(OLYMPIC_APP_VERSION);
|
||||
ox::String appVersion{OLYMPIC_APP_VERSION};
|
||||
}
|
||||
|
||||
ox::Error run(
|
||||
@ -57,7 +57,7 @@ int WinMain() {
|
||||
auto const argc = __argc;
|
||||
auto const argv = const_cast<const char**>(__argv);
|
||||
#else
|
||||
int main(int argc, char const**argv) {
|
||||
int main(int const argc, char const **argv) {
|
||||
#endif
|
||||
OX_INIT_DEBUG_LOGGER(loggerConn, OLYMPIC_PROJECT_NAME " " OLYMPIC_APP_NAME)
|
||||
#if OLYMPIC_LOAD_KEEL_MODULES
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace studio {
|
||||
|
||||
studio::TaskState FileDialogManager::update(turbine::Context &ctx) noexcept {
|
||||
TaskState FileDialogManager::update(turbine::Context &ctx) noexcept {
|
||||
switch (m_state) {
|
||||
case UpdateProjectPathState::EnableSystemCursor: {
|
||||
// switch to system cursor in this update and open file dialog in the next
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include <ox/event/signal.hpp>
|
||||
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include "undostack.hpp"
|
||||
#include "widget.hpp"
|
||||
|
||||
|
@ -34,7 +34,7 @@ void setClipboardText(Context &ctx, ox::StringViewCR text) noexcept;
|
||||
|
||||
void setClipboardObject(Context &ctx, ox::UPtr<BaseClipboardObject> &&obj) noexcept;
|
||||
|
||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeId) noexcept;
|
||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringViewCR typeId) noexcept;
|
||||
|
||||
template<typename T>
|
||||
ox::Result<T*> getClipboardObject(Context &ctx) noexcept {
|
||||
|
@ -6,13 +6,9 @@
|
||||
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/model/desctypes.hpp>
|
||||
#include <ox/std/buffer.hpp>
|
||||
#include <ox/std/size.hpp>
|
||||
|
||||
#include <keel/context.hpp>
|
||||
|
||||
#include "input.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
class Context;
|
||||
@ -47,10 +43,5 @@ T *applicationData(Context &ctx) noexcept {
|
||||
return applicationDataRaw(ctx).get<T>();
|
||||
}
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace turbine {
|
||||
|
||||
class Context;
|
||||
|
||||
using UpdateHandler = int(*)(Context&);
|
||||
|
||||
// Sets event handler that sleeps for the time given in the return value. The
|
||||
// sleep time is a minimum of ~16 milliseconds.
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler) noexcept;
|
||||
|
||||
}
|
@ -21,11 +21,9 @@ class Drawer {
|
||||
virtual void draw(Context&) noexcept = 0;
|
||||
};
|
||||
void addDrawer(Context &ctx, Drawer *cd) noexcept;
|
||||
void removeDrawer(Context &ctx, Drawer *cd) noexcept;
|
||||
void removeDrawer(Context &ctx, Drawer const *cd) noexcept;
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context &ctx) noexcept;
|
||||
|
||||
ox::Error setWindowIcon(Context &ctx, ox::SpanView<ox::SpanView<uint8_t>> const &iconPngs) noexcept;
|
||||
|
||||
void setWindowTitle(Context &ctx, ox::StringViewCR title) noexcept;
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/defines.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
||||
enum Key {
|
||||
// GBA implementation currently relies on GamePad entry order
|
||||
GamePad_A = 0,
|
||||
GamePad_B,
|
||||
GamePad_Select,
|
||||
GamePad_Start,
|
||||
GamePad_Right,
|
||||
GamePad_Left,
|
||||
GamePad_Up,
|
||||
GamePad_Down,
|
||||
GamePad_R,
|
||||
GamePad_L,
|
||||
|
||||
Num_0,
|
||||
Num_1,
|
||||
Num_2,
|
||||
Num_3,
|
||||
Num_4,
|
||||
Num_5,
|
||||
Num_6,
|
||||
Num_7,
|
||||
Num_8,
|
||||
Num_9,
|
||||
|
||||
Alpha_A,
|
||||
Alpha_B,
|
||||
Alpha_C,
|
||||
Alpha_D,
|
||||
Alpha_E,
|
||||
Alpha_F,
|
||||
Alpha_G,
|
||||
Alpha_H,
|
||||
Alpha_I,
|
||||
Alpha_J,
|
||||
Alpha_K,
|
||||
Alpha_L,
|
||||
Alpha_M,
|
||||
Alpha_N,
|
||||
Alpha_O,
|
||||
Alpha_P,
|
||||
Alpha_Q,
|
||||
Alpha_R,
|
||||
Alpha_S,
|
||||
Alpha_T,
|
||||
Alpha_U,
|
||||
Alpha_V,
|
||||
Alpha_W,
|
||||
Alpha_X,
|
||||
Alpha_Y,
|
||||
Alpha_Z,
|
||||
|
||||
Mod_Alt,
|
||||
Mod_Ctrl,
|
||||
Mod_Super,
|
||||
Mod_Shift,
|
||||
|
||||
Escape,
|
||||
|
||||
End
|
||||
};
|
||||
|
||||
class Context;
|
||||
|
||||
[[nodiscard]]
|
||||
bool buttonDown(Context const&ctx, Key) noexcept;
|
||||
|
||||
using KeyEventHandler = void(*)(Context&, Key, bool);
|
||||
|
||||
}
|
@ -8,13 +8,85 @@
|
||||
#include <ox/fs/fs.hpp>
|
||||
|
||||
#include "clipboard.hpp"
|
||||
#include "event.hpp"
|
||||
#include "gfx.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
class Context;
|
||||
|
||||
using TimeMs = uint64_t;
|
||||
using UpdateHandler = int(*)(Context&);
|
||||
|
||||
enum Key {
|
||||
// GBA implementation currently relies on GamePad entry order
|
||||
GamePad_A = 0,
|
||||
GamePad_B,
|
||||
GamePad_Select,
|
||||
GamePad_Start,
|
||||
GamePad_Right,
|
||||
GamePad_Left,
|
||||
GamePad_Up,
|
||||
GamePad_Down,
|
||||
GamePad_R,
|
||||
GamePad_L,
|
||||
|
||||
Num_0,
|
||||
Num_1,
|
||||
Num_2,
|
||||
Num_3,
|
||||
Num_4,
|
||||
Num_5,
|
||||
Num_6,
|
||||
Num_7,
|
||||
Num_8,
|
||||
Num_9,
|
||||
|
||||
Alpha_A,
|
||||
Alpha_B,
|
||||
Alpha_C,
|
||||
Alpha_D,
|
||||
Alpha_E,
|
||||
Alpha_F,
|
||||
Alpha_G,
|
||||
Alpha_H,
|
||||
Alpha_I,
|
||||
Alpha_J,
|
||||
Alpha_K,
|
||||
Alpha_L,
|
||||
Alpha_M,
|
||||
Alpha_N,
|
||||
Alpha_O,
|
||||
Alpha_P,
|
||||
Alpha_Q,
|
||||
Alpha_R,
|
||||
Alpha_S,
|
||||
Alpha_T,
|
||||
Alpha_U,
|
||||
Alpha_V,
|
||||
Alpha_W,
|
||||
Alpha_X,
|
||||
Alpha_Y,
|
||||
Alpha_Z,
|
||||
|
||||
Mod_Alt,
|
||||
Mod_Ctrl,
|
||||
Mod_Super,
|
||||
Mod_Shift,
|
||||
|
||||
Escape,
|
||||
|
||||
End
|
||||
};
|
||||
|
||||
using KeyEventHandler = void(*)(Context&, Key, bool);
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool buttonDown(Context const&ctx, Key) noexcept;
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> &&fs, ox::StringViewCR appName) noexcept;
|
||||
|
||||
@ -33,4 +105,8 @@ using ShutdownHandler = bool (*)(Context&);
|
||||
|
||||
void setShutdownHandler(Context &ctx, ShutdownHandler handler) noexcept;
|
||||
|
||||
// Sets event handler that sleeps for the time given in the return value. The
|
||||
// sleep time is a minimum of ~16 milliseconds.
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler) noexcept;
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ target_sources(
|
||||
Turbine-GBA PRIVATE
|
||||
context.cpp
|
||||
clipboard.cpp
|
||||
event.cpp
|
||||
gfx.cpp
|
||||
irq.arm.cpp
|
||||
turbine.arm.cpp
|
||||
turbine.cpp
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <ox/std/string.hpp>
|
||||
|
||||
#include <turbine/context.hpp>
|
||||
#include <turbine/clipboard.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
||||
@ -15,4 +16,8 @@ ox::String getClipboardText(Context&) noexcept {
|
||||
void setClipboardText(Context&, ox::StringViewCR) noexcept {
|
||||
}
|
||||
|
||||
ox::Result<BaseClipboardObject*> getClipboardData(Context&, ox::StringViewCR) noexcept {
|
||||
return ox::Error{1, "not implemented"};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,8 @@
|
||||
|
||||
#include <keel/context.hpp>
|
||||
|
||||
#include <turbine/clipboard.hpp>
|
||||
#include <turbine/context.hpp>
|
||||
#include <turbine/event.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <turbine/event.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler h) noexcept {
|
||||
ctx.updateHandler = h;
|
||||
}
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept {
|
||||
ctx.keyEventHandler = h;
|
||||
}
|
||||
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept {
|
||||
return ctx.keyEventHandler;
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <ox/std/size.hpp>
|
||||
#include <ox/std/stringview.hpp>
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/gfx.hpp>
|
||||
#include <teagba/irq.hpp>
|
||||
|
||||
#include <turbine/context.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
||||
ox::Error initGfx(Context&) noexcept {
|
||||
REG_DISPCTL = teagba::DispCtl_Mode0
|
||||
| teagba::DispCtl_SpriteMap1D
|
||||
| teagba::DispCtl_Obj;
|
||||
// tell display to trigger vblank interrupts
|
||||
REG_DISPSTAT = REG_DISPSTAT | teagba::DispStat_irq_vblank;
|
||||
// enable vblank interrupt
|
||||
REG_IE = REG_IE | teagba::Int_vblank;
|
||||
return {};
|
||||
}
|
||||
|
||||
void setWindowTitle(Context&, ox::StringViewCR) noexcept {
|
||||
}
|
||||
|
||||
int getScreenWidth(Context const&) noexcept {
|
||||
return 240;
|
||||
}
|
||||
|
||||
int getScreenHeight(Context const&) noexcept {
|
||||
return 160;
|
||||
}
|
||||
|
||||
ox::Size getScreenSize(Context const&) noexcept {
|
||||
return {240, 160};
|
||||
}
|
||||
|
||||
ox::Bounds getWindowBounds(Context const&) noexcept {
|
||||
return {0, 0, 240, 160};
|
||||
}
|
||||
|
||||
ox::Error setWindowBounds(Context&, ox::Bounds const&) noexcept {
|
||||
return ox::Error(1, "setWindowBounds not supported on GBA");
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,10 @@
|
||||
*/
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/gfx.hpp>
|
||||
#include <teagba/irq.hpp>
|
||||
|
||||
|
||||
#include <keel/keel.hpp>
|
||||
#include <turbine/context.hpp>
|
||||
#include <turbine/gfx.hpp>
|
||||
@ -58,6 +60,40 @@ OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
return ox::Error(1);
|
||||
}
|
||||
|
||||
static ox::Error initGfx(Context&) noexcept {
|
||||
REG_DISPCTL = teagba::DispCtl_Mode0
|
||||
| teagba::DispCtl_SpriteMap1D
|
||||
| teagba::DispCtl_Obj;
|
||||
// tell display to trigger vblank interrupts
|
||||
REG_DISPSTAT = REG_DISPSTAT | teagba::DispStat_irq_vblank;
|
||||
// enable vblank interrupt
|
||||
REG_IE = REG_IE | teagba::Int_vblank;
|
||||
return {};
|
||||
}
|
||||
|
||||
void setWindowTitle(Context&, ox::StringViewCR) noexcept {
|
||||
}
|
||||
|
||||
int getScreenWidth(Context const&) noexcept {
|
||||
return 240;
|
||||
}
|
||||
|
||||
int getScreenHeight(Context const&) noexcept {
|
||||
return 160;
|
||||
}
|
||||
|
||||
ox::Size getScreenSize(Context const&) noexcept {
|
||||
return {240, 160};
|
||||
}
|
||||
|
||||
ox::Bounds getWindowBounds(Context const&) noexcept {
|
||||
return {0, 0, 240, 160};
|
||||
}
|
||||
|
||||
ox::Error setWindowBounds(Context&, ox::Bounds const&) noexcept {
|
||||
return ox::Error(1, "setWindowBounds not supported on GBA");
|
||||
}
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(
|
||||
ox::UPtr<ox::FileSystem> &&fs, ox::StringViewCR appName) noexcept {
|
||||
auto ctx = ox::make_unique<Context>();
|
||||
@ -68,7 +104,7 @@ ox::Result<ox::UPtr<Context>> init(
|
||||
OX_RETURN_ERROR(initGfx(*ctx));
|
||||
initTimer();
|
||||
initIrq();
|
||||
return ox::UPtr<Context>(std::move(ctx));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void shutdown(Context&) noexcept {
|
||||
@ -89,4 +125,16 @@ void requestShutdown(Context &ctx, bool) noexcept {
|
||||
void setShutdownHandler(Context&, ShutdownHandler) noexcept {
|
||||
}
|
||||
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler h) noexcept {
|
||||
ctx.updateHandler = h;
|
||||
}
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept {
|
||||
ctx.keyEventHandler = h;
|
||||
}
|
||||
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept {
|
||||
return ctx.keyEventHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ target_sources(
|
||||
Turbine PRIVATE
|
||||
context.cpp
|
||||
clipboard.cpp
|
||||
event.cpp
|
||||
gfx.cpp
|
||||
turbine.cpp
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,7 @@ void setClipboardObject(Context &ctx, ox::UPtr<BaseClipboardObject> &&obj) noexc
|
||||
ctx.clipboard = std::move(obj);
|
||||
}
|
||||
|
||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeId) noexcept {
|
||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringViewCR typeId) noexcept {
|
||||
if (ctx.clipboard && ctx.clipboard->typeId() == typeId) {
|
||||
return ctx.clipboard.get();
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <turbine/clipboard.hpp>
|
||||
#include <turbine/context.hpp>
|
||||
#include <turbine/gfx.hpp>
|
||||
#include <turbine/event.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
namespace turbine {
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <turbine/event.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler h) noexcept {
|
||||
ctx.updateHandler = h;
|
||||
}
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept {
|
||||
ctx.keyEventHandler = h;
|
||||
}
|
||||
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept {
|
||||
return ctx.keyEventHandler;
|
||||
}
|
||||
|
||||
}
|
324
deps/nostalgia/src/olympic/turbine/src/glfw/gfx.cpp
vendored
324
deps/nostalgia/src/olympic/turbine/src/glfw/gfx.cpp
vendored
@ -1,324 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <lodepng.h>
|
||||
#if TURBINE_USE_IMGUI
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#endif
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <ox/std/span.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace turbine {
|
||||
|
||||
namespace gl {
|
||||
|
||||
void addDrawer(Context &ctx, Drawer *cd) noexcept {
|
||||
ctx.drawers.emplace_back(cd);
|
||||
}
|
||||
|
||||
void removeDrawer(Context &ctx, Drawer *cd) noexcept {
|
||||
for (auto i = 0u; i < ctx.drawers.size(); ++i) {
|
||||
if (ctx.drawers[i] == cd) {
|
||||
std::ignore = ctx.drawers.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void handleGlfwError(int err, char const*desc) noexcept {
|
||||
oxErrf("GLFW error ({}): {}\n", err, desc);
|
||||
}
|
||||
|
||||
static auto setKeyDownStatus(Context &ctx, Key key, bool down) noexcept {
|
||||
ctx.keysDown &= ~(1llu << static_cast<int>(key));
|
||||
ctx.keysDown |= static_cast<uint64_t>(down) << static_cast<int>(key);
|
||||
}
|
||||
|
||||
static void handleKeyPress(Context &ctx, int key, bool down) noexcept {
|
||||
static constexpr auto keyMap = [] {
|
||||
ox::Array<Key, GLFW_KEY_LAST> map = {};
|
||||
for (auto i = 0u; i < 26; ++i) {
|
||||
map[GLFW_KEY_A + i] = static_cast<Key>(static_cast<unsigned>(Key::Alpha_A) + i);
|
||||
}
|
||||
for (auto i = 0u; i < 10; ++i) {
|
||||
map[GLFW_KEY_0 + i] = static_cast<Key>(static_cast<unsigned>(Key::Num_0) + i);
|
||||
}
|
||||
map[GLFW_KEY_LEFT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_RIGHT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_LEFT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_RIGHT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_LEFT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_RIGHT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_LEFT_SHIFT] = Key::Mod_Shift;
|
||||
map[GLFW_KEY_RIGHT_SHIFT] = Key::Mod_Shift;
|
||||
map[GLFW_KEY_ESCAPE] = Key::Escape;
|
||||
return map;
|
||||
}();
|
||||
auto const eventHandler = keyEventHandler(ctx);
|
||||
auto const keyIdx = static_cast<std::size_t>(key);
|
||||
if (keyIdx < keyMap.size()) {
|
||||
auto const k = keyMap[keyIdx];
|
||||
setKeyDownStatus(ctx, k, down);
|
||||
if (eventHandler) {
|
||||
eventHandler(ctx, k, down);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handleGlfwCursorPosEvent(GLFWwindow*, double, double) noexcept {
|
||||
}
|
||||
|
||||
static void handleGlfwMouseButtonEvent(GLFWwindow *window, int, int, int) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
}
|
||||
|
||||
static void handleGlfwKeyEvent(GLFWwindow *window, int key, int, int action, int) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
if (action == GLFW_PRESS) {
|
||||
handleKeyPress(ctx, key, true);
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
handleKeyPress(ctx, key, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void handleGlfwWindowCloseEvent(GLFWwindow *window) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
ctx.running = ctx.shutdownHandler ? !ctx.shutdownHandler(ctx) : false;
|
||||
glfwSetWindowShouldClose(window, !ctx.running);
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
#if TURBINE_USE_IMGUI
|
||||
static void themeImgui() noexcept {
|
||||
// Dark Ruda style by Raikiri from ImThemes
|
||||
auto &style = ImGui::GetStyle();
|
||||
style.Alpha = 1.0;
|
||||
style.DisabledAlpha = 0.6000000238418579;
|
||||
style.WindowPadding = ImVec2(8.0, 8.0);
|
||||
style.WindowRounding = 0.0;
|
||||
style.WindowBorderSize = 1.0;
|
||||
style.WindowMinSize = ImVec2(32.0, 32.0);
|
||||
style.WindowTitleAlign = ImVec2(0.0, 0.5);
|
||||
style.WindowMenuButtonPosition = ImGuiDir_Left;
|
||||
style.ChildRounding = 0.0;
|
||||
style.ChildBorderSize = 1.0;
|
||||
style.PopupRounding = 0.0;
|
||||
style.PopupBorderSize = 1.0;
|
||||
style.FramePadding = ImVec2(4.0, 3.0);
|
||||
// custom value
|
||||
style.FrameRounding = 3.0;
|
||||
style.FrameBorderSize = 0.0;
|
||||
style.ItemSpacing = ImVec2(8.0, 4.0);
|
||||
style.ItemInnerSpacing = ImVec2(4.0, 4.0);
|
||||
style.CellPadding = ImVec2(4.0, 2.0);
|
||||
style.IndentSpacing = 21.0;
|
||||
style.ColumnsMinSpacing = 6.0;
|
||||
style.ScrollbarSize = 14.0;
|
||||
style.ScrollbarRounding = 9.0;
|
||||
style.GrabMinSize = 10.0;
|
||||
style.GrabRounding = 4.0;
|
||||
style.TabRounding = 4.0;
|
||||
style.TabBorderSize = 0.0;
|
||||
style.TabMinWidthForCloseButton = 0.0;
|
||||
style.ColorButtonPosition = ImGuiDir_Right;
|
||||
style.ButtonTextAlign = ImVec2(0.5, 0.5);
|
||||
style.SelectableTextAlign = ImVec2(0.0, 0.0);
|
||||
// colors
|
||||
constexpr auto imVec4 = [](double r, double g, double b, double a) {
|
||||
return ImVec4(
|
||||
static_cast<float>(r),
|
||||
static_cast<float>(g),
|
||||
static_cast<float>(b),
|
||||
static_cast<float>(a));
|
||||
};
|
||||
auto colors = ox::Span(style.Colors);
|
||||
colors[ImGuiCol_Text] = imVec4(0.9490196108818054, 0.95686274766922, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_TextDisabled] = imVec4(0.3568627536296844, 0.4196078479290009, 0.4666666686534882, 1.0);
|
||||
colors[ImGuiCol_WindowBg] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_ChildBg] = imVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
colors[ImGuiCol_PopupBg] = imVec4(0.0784313753247261, 0.0784313753247261, 0.0784313753247261, 0.9399999976158142);
|
||||
colors[ImGuiCol_Border] = imVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
colors[ImGuiCol_BorderShadow] = imVec4(0.0, 0.0, 0.0, 0.0);
|
||||
colors[ImGuiCol_FrameBg] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_FrameBgHovered] = imVec4(0.1176470592617989, 0.2000000029802322, 0.2784313857555389, 1.0);
|
||||
colors[ImGuiCol_FrameBgActive] = imVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 1.0);
|
||||
colors[ImGuiCol_TitleBg] = imVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 0.6499999761581421);
|
||||
colors[ImGuiCol_TitleBgActive] = imVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
colors[ImGuiCol_TitleBgCollapsed] = imVec4(0.0, 0.0, 0.0, 0.5099999904632568);
|
||||
colors[ImGuiCol_MenuBarBg] = imVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
colors[ImGuiCol_ScrollbarBg] = imVec4(0.01960784383118153, 0.01960784383118153, 0.01960784383118153, 0.3899999856948853);
|
||||
colors[ImGuiCol_ScrollbarGrab] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_ScrollbarGrabHovered] = imVec4(0.1764705926179886, 0.2196078449487686, 0.2470588237047195, 1.0);
|
||||
colors[ImGuiCol_ScrollbarGrabActive] = imVec4(0.08627451211214066, 0.2078431397676468, 0.3098039329051971, 1.0);
|
||||
colors[ImGuiCol_CheckMark] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_SliderGrab] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_SliderGrabActive] = imVec4(0.3686274588108063, 0.6078431606292725, 1.0, 1.0);
|
||||
colors[ImGuiCol_Button] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_ButtonHovered] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_ButtonActive] = imVec4(0.05882352963089943, 0.529411792755127, 0.9764705896377563, 1.0);
|
||||
// custom value
|
||||
colors[ImGuiCol_Header] = imVec4(0.4000000029802322, 0.4470588237047195, 0.4862745225429535, 0.550000011920929);
|
||||
colors[ImGuiCol_HeaderHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
colors[ImGuiCol_HeaderActive] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_Separator] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_SeparatorHovered] = imVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 0.7799999713897705);
|
||||
colors[ImGuiCol_SeparatorActive] = imVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 1.0);
|
||||
colors[ImGuiCol_ResizeGrip] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.25);
|
||||
colors[ImGuiCol_ResizeGripHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.6700000166893005);
|
||||
colors[ImGuiCol_ResizeGripActive] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.949999988079071);
|
||||
colors[ImGuiCol_Tab] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_TabHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
colors[ImGuiCol_TabActive] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_TabUnfocused] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_PlotLines] = imVec4(0.6078431606292725, 0.6078431606292725, 0.6078431606292725, 1.0);
|
||||
colors[ImGuiCol_PlotLinesHovered] = imVec4(1.0, 0.4274509847164154, 0.3490196168422699, 1.0);
|
||||
colors[ImGuiCol_PlotHistogram] = imVec4(0.8980392217636108, 0.6980392336845398, 0.0, 1.0);
|
||||
colors[ImGuiCol_PlotHistogramHovered] = imVec4(1.0, 0.6000000238418579, 0.0, 1.0);
|
||||
colors[ImGuiCol_TableHeaderBg] = imVec4(0.1882352977991104, 0.1882352977991104, 0.2000000029802322, 1.0);
|
||||
colors[ImGuiCol_TableBorderStrong] = imVec4(0.3098039329051971, 0.3098039329051971, 0.3490196168422699, 1.0);
|
||||
colors[ImGuiCol_TableBorderLight] = imVec4(0.2274509817361832, 0.2274509817361832, 0.2470588237047195, 1.0);
|
||||
colors[ImGuiCol_TableRowBg] = imVec4(0.0, 0.0, 0.0, 0.0);
|
||||
colors[ImGuiCol_TableRowBgAlt] = imVec4(1.0, 1.0, 1.0, 0.05999999865889549);
|
||||
colors[ImGuiCol_TextSelectedBg] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.3499999940395355);
|
||||
colors[ImGuiCol_DragDropTarget] = imVec4(1.0, 1.0, 0.0, 0.8999999761581421);
|
||||
colors[ImGuiCol_NavHighlight] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_NavWindowingHighlight] = imVec4(1.0, 1.0, 1.0, 0.699999988079071);
|
||||
colors[ImGuiCol_NavWindowingDimBg] = imVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.2000000029802322);
|
||||
colors[ImGuiCol_ModalWindowDimBg] = imVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.3499999940395355);
|
||||
}
|
||||
#endif
|
||||
|
||||
ox::Error initGfx(Context &ctx) noexcept {
|
||||
glfwSetErrorCallback(handleGlfwError);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
constexpr auto Scale = 5;
|
||||
ctx.window = glfwCreateWindow(240 * Scale, 160 * Scale, ctx.keelCtx.appName.c_str(), nullptr, nullptr);
|
||||
//ctx.window = glfwCreateWindow(876, 743, ctx.keelCtx.appName.c_str(), nullptr, nullptr);
|
||||
if (ctx.window == nullptr) {
|
||||
return ox::Error(1, "Could not open GLFW window");
|
||||
}
|
||||
glfwSetCursorPosCallback(ctx.window, handleGlfwCursorPosEvent);
|
||||
glfwSetMouseButtonCallback(ctx.window, handleGlfwMouseButtonEvent);
|
||||
glfwSetKeyCallback(ctx.window, handleGlfwKeyEvent);
|
||||
glfwSetWindowCloseCallback(ctx.window, handleGlfwWindowCloseEvent);
|
||||
glfwSetWindowUserPointer(ctx.window, &ctx);
|
||||
glfwMakeContextCurrent(ctx.window);
|
||||
if (!gladLoadGLES2Loader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {
|
||||
return ox::Error(2, "Could not init Glad");
|
||||
}
|
||||
#if TURBINE_USE_IMGUI
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
auto &io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
//io.MouseDrawCursor = true;
|
||||
ImGui_ImplGlfw_InitForOpenGL(ctx.window, true);
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
io.IniFilename = nullptr;
|
||||
themeImgui();
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
struct IconData {
|
||||
std::vector<uint8_t> pixels;
|
||||
int w{}, h{};
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
[[maybe_unused]]
|
||||
static ox::Result<IconData> toGlfwImgPixels(ox::SpanView<uint8_t> const &iconPng) noexcept {
|
||||
ox::Result<IconData> out;
|
||||
unsigned w{}, h{};
|
||||
if (lodepng::decode(out.value.pixels, w, h, iconPng.data(), iconPng.size())) {
|
||||
return ox::Error{1, "unable to decode window icon PNG data"};
|
||||
}
|
||||
out.value.w = static_cast<int>(w);
|
||||
out.value.h = static_cast<int>(h);
|
||||
return out;
|
||||
}
|
||||
|
||||
ox::Error setWindowIcon(Context &ctx, ox::SpanView<ox::SpanView<uint8_t>> const &iconPngs) noexcept {
|
||||
if constexpr(ox::defines::OS != ox::OS::Darwin) {
|
||||
ox::Vector<IconData, 8> src;
|
||||
ox::Vector<GLFWimage, 8> imgs;
|
||||
for (auto const &iconPng : iconPngs) {
|
||||
OX_RETURN_ERROR(toGlfwImgPixels(iconPng).moveTo(src.emplace_back()));
|
||||
auto &icon = *src.back().unwrap();
|
||||
imgs.emplace_back(GLFWimage{
|
||||
.width = icon.w,
|
||||
.height = icon.h,
|
||||
.pixels = icon.pixels.data(),
|
||||
});
|
||||
}
|
||||
glfwSetWindowIcon(ctx.window, static_cast<int>(imgs.size()), imgs.data());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void setWindowTitle(Context &ctx, ox::StringViewCR title) noexcept {
|
||||
auto cstr = ox_malloca(title.bytes() + 1, char);
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
ox::strncpy(cstr.get(), title.data(), title.bytes());
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
glfwSetWindowTitle(ctx.window, cstr.get());
|
||||
}
|
||||
|
||||
void focusWindow(Context &ctx) noexcept {
|
||||
glfwFocusWindow(ctx.window);
|
||||
}
|
||||
|
||||
int getScreenWidth(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
int getScreenHeight(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return h;
|
||||
}
|
||||
|
||||
ox::Size getScreenSize(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
ox::Bounds getWindowBounds(Context const &ctx) noexcept {
|
||||
ox::Bounds bnds;
|
||||
glfwGetWindowPos(ctx.window, &bnds.x, &bnds.y);
|
||||
glfwGetWindowSize(ctx.window, &bnds.width, &bnds.height);
|
||||
return bnds;
|
||||
}
|
||||
|
||||
ox::Error setWindowBounds(Context &ctx, ox::Bounds const&bnds) noexcept {
|
||||
glfwSetWindowPos(ctx.window, bnds.x, bnds.y);
|
||||
glfwSetWindowSize(ctx.window, bnds.width, bnds.height);
|
||||
return {};
|
||||
}
|
||||
|
||||
void setRefreshWithin(Context &ctx, int ms) noexcept {
|
||||
ctx.refreshWithinMs = ox::min(ms, ctx.refreshWithinMs);
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,9 @@
|
||||
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <lodepng.h>
|
||||
#if TURBINE_USE_IMGUI
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
@ -17,6 +19,207 @@
|
||||
|
||||
namespace turbine {
|
||||
|
||||
namespace gl {
|
||||
|
||||
void addDrawer(Context &ctx, Drawer *cd) noexcept {
|
||||
ctx.drawers.emplace_back(cd);
|
||||
}
|
||||
|
||||
void removeDrawer(Context &ctx, Drawer const *cd) noexcept {
|
||||
for (auto i = 0u; i < ctx.drawers.size(); ++i) {
|
||||
if (ctx.drawers[i] == cd) {
|
||||
std::ignore = ctx.drawers.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if TURBINE_USE_IMGUI
|
||||
static void themeImgui() noexcept {
|
||||
// Dark Ruda style by Raikiri from ImThemes
|
||||
auto &style = ImGui::GetStyle();
|
||||
style.Alpha = 1.0;
|
||||
style.DisabledAlpha = 0.6000000238418579;
|
||||
style.WindowPadding = ImVec2(8.0, 8.0);
|
||||
style.WindowRounding = 0.0;
|
||||
style.WindowBorderSize = 1.0;
|
||||
style.WindowMinSize = ImVec2(32.0, 32.0);
|
||||
style.WindowTitleAlign = ImVec2(0.0, 0.5);
|
||||
style.WindowMenuButtonPosition = ImGuiDir_Left;
|
||||
style.ChildRounding = 0.0;
|
||||
style.ChildBorderSize = 1.0;
|
||||
style.PopupRounding = 0.0;
|
||||
style.PopupBorderSize = 1.0;
|
||||
style.FramePadding = ImVec2(4.0, 3.0);
|
||||
// custom value
|
||||
style.FrameRounding = 3.0;
|
||||
style.FrameBorderSize = 0.0;
|
||||
style.ItemSpacing = ImVec2(8.0, 4.0);
|
||||
style.ItemInnerSpacing = ImVec2(4.0, 4.0);
|
||||
style.CellPadding = ImVec2(4.0, 2.0);
|
||||
style.IndentSpacing = 21.0;
|
||||
style.ColumnsMinSpacing = 6.0;
|
||||
style.ScrollbarSize = 14.0;
|
||||
style.ScrollbarRounding = 9.0;
|
||||
style.GrabMinSize = 10.0;
|
||||
style.GrabRounding = 4.0;
|
||||
style.TabRounding = 4.0;
|
||||
style.TabBorderSize = 0.0;
|
||||
style.TabMinWidthForCloseButton = 0.0;
|
||||
style.ColorButtonPosition = ImGuiDir_Right;
|
||||
style.ButtonTextAlign = ImVec2(0.5, 0.5);
|
||||
style.SelectableTextAlign = ImVec2(0.0, 0.0);
|
||||
// colors
|
||||
constexpr auto imVec4 = [](double r, double g, double b, double a) {
|
||||
return ImVec4(
|
||||
static_cast<float>(r),
|
||||
static_cast<float>(g),
|
||||
static_cast<float>(b),
|
||||
static_cast<float>(a));
|
||||
};
|
||||
auto colors = ox::Span(style.Colors);
|
||||
colors[ImGuiCol_Text] = imVec4(0.9490196108818054, 0.95686274766922, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_TextDisabled] = imVec4(0.3568627536296844, 0.4196078479290009, 0.4666666686534882, 1.0);
|
||||
colors[ImGuiCol_WindowBg] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_ChildBg] = imVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
colors[ImGuiCol_PopupBg] = imVec4(0.0784313753247261, 0.0784313753247261, 0.0784313753247261, 0.9399999976158142);
|
||||
colors[ImGuiCol_Border] = imVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
colors[ImGuiCol_BorderShadow] = imVec4(0.0, 0.0, 0.0, 0.0);
|
||||
colors[ImGuiCol_FrameBg] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_FrameBgHovered] = imVec4(0.1176470592617989, 0.2000000029802322, 0.2784313857555389, 1.0);
|
||||
colors[ImGuiCol_FrameBgActive] = imVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 1.0);
|
||||
colors[ImGuiCol_TitleBg] = imVec4(0.08627451211214066, 0.1176470592617989, 0.1372549086809158, 0.6499999761581421);
|
||||
colors[ImGuiCol_TitleBgActive] = imVec4(0.0784313753247261, 0.09803921729326248, 0.1176470592617989, 1.0);
|
||||
colors[ImGuiCol_TitleBgCollapsed] = imVec4(0.0, 0.0, 0.0, 0.5099999904632568);
|
||||
colors[ImGuiCol_MenuBarBg] = imVec4(0.1490196138620377, 0.1764705926179886, 0.2196078449487686, 1.0);
|
||||
colors[ImGuiCol_ScrollbarBg] = imVec4(0.01960784383118153, 0.01960784383118153, 0.01960784383118153, 0.3899999856948853);
|
||||
colors[ImGuiCol_ScrollbarGrab] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_ScrollbarGrabHovered] = imVec4(0.1764705926179886, 0.2196078449487686, 0.2470588237047195, 1.0);
|
||||
colors[ImGuiCol_ScrollbarGrabActive] = imVec4(0.08627451211214066, 0.2078431397676468, 0.3098039329051971, 1.0);
|
||||
colors[ImGuiCol_CheckMark] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_SliderGrab] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_SliderGrabActive] = imVec4(0.3686274588108063, 0.6078431606292725, 1.0, 1.0);
|
||||
colors[ImGuiCol_Button] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_ButtonHovered] = imVec4(0.2784313857555389, 0.5568627715110779, 1.0, 1.0);
|
||||
colors[ImGuiCol_ButtonActive] = imVec4(0.05882352963089943, 0.529411792755127, 0.9764705896377563, 1.0);
|
||||
// custom value
|
||||
colors[ImGuiCol_Header] = imVec4(0.4000000029802322, 0.4470588237047195, 0.4862745225429535, 0.550000011920929);
|
||||
colors[ImGuiCol_HeaderHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
colors[ImGuiCol_HeaderActive] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_Separator] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_SeparatorHovered] = imVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 0.7799999713897705);
|
||||
colors[ImGuiCol_SeparatorActive] = imVec4(0.09803921729326248, 0.4000000059604645, 0.7490196228027344, 1.0);
|
||||
colors[ImGuiCol_ResizeGrip] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.25);
|
||||
colors[ImGuiCol_ResizeGripHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.6700000166893005);
|
||||
colors[ImGuiCol_ResizeGripActive] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.949999988079071);
|
||||
colors[ImGuiCol_Tab] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_TabHovered] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.800000011920929);
|
||||
colors[ImGuiCol_TabActive] = imVec4(0.2000000029802322, 0.2470588237047195, 0.2862745225429535, 1.0);
|
||||
colors[ImGuiCol_TabUnfocused] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = imVec4(0.1098039224743843, 0.1490196138620377, 0.168627455830574, 1.0);
|
||||
colors[ImGuiCol_PlotLines] = imVec4(0.6078431606292725, 0.6078431606292725, 0.6078431606292725, 1.0);
|
||||
colors[ImGuiCol_PlotLinesHovered] = imVec4(1.0, 0.4274509847164154, 0.3490196168422699, 1.0);
|
||||
colors[ImGuiCol_PlotHistogram] = imVec4(0.8980392217636108, 0.6980392336845398, 0.0, 1.0);
|
||||
colors[ImGuiCol_PlotHistogramHovered] = imVec4(1.0, 0.6000000238418579, 0.0, 1.0);
|
||||
colors[ImGuiCol_TableHeaderBg] = imVec4(0.1882352977991104, 0.1882352977991104, 0.2000000029802322, 1.0);
|
||||
colors[ImGuiCol_TableBorderStrong] = imVec4(0.3098039329051971, 0.3098039329051971, 0.3490196168422699, 1.0);
|
||||
colors[ImGuiCol_TableBorderLight] = imVec4(0.2274509817361832, 0.2274509817361832, 0.2470588237047195, 1.0);
|
||||
colors[ImGuiCol_TableRowBg] = imVec4(0.0, 0.0, 0.0, 0.0);
|
||||
colors[ImGuiCol_TableRowBgAlt] = imVec4(1.0, 1.0, 1.0, 0.05999999865889549);
|
||||
colors[ImGuiCol_TextSelectedBg] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 0.3499999940395355);
|
||||
colors[ImGuiCol_DragDropTarget] = imVec4(1.0, 1.0, 0.0, 0.8999999761581421);
|
||||
colors[ImGuiCol_NavHighlight] = imVec4(0.2588235437870026, 0.5882353186607361, 0.9764705896377563, 1.0);
|
||||
colors[ImGuiCol_NavWindowingHighlight] = imVec4(1.0, 1.0, 1.0, 0.699999988079071);
|
||||
colors[ImGuiCol_NavWindowingDimBg] = imVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.2000000029802322);
|
||||
colors[ImGuiCol_ModalWindowDimBg] = imVec4(0.800000011920929, 0.800000011920929, 0.800000011920929, 0.3499999940395355);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct IconData {
|
||||
std::vector<uint8_t> pixels;
|
||||
int w{}, h{};
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
[[maybe_unused]]
|
||||
static ox::Result<IconData> toGlfwImgPixels(ox::SpanView<uint8_t> const &iconPng) noexcept {
|
||||
ox::Result<IconData> out;
|
||||
unsigned w{}, h{};
|
||||
if (lodepng::decode(out.value.pixels, w, h, iconPng.data(), iconPng.size())) {
|
||||
return ox::Error{1, "unable to decode window icon PNG data"};
|
||||
}
|
||||
out.value.w = static_cast<int>(w);
|
||||
out.value.h = static_cast<int>(h);
|
||||
return out;
|
||||
}
|
||||
|
||||
ox::Error setWindowIcon(Context &ctx, ox::SpanView<ox::SpanView<uint8_t>> const &iconPngs) noexcept {
|
||||
if constexpr(ox::defines::OS != ox::OS::Darwin) {
|
||||
ox::Vector<IconData, 8> src;
|
||||
ox::Vector<GLFWimage, 8> imgs;
|
||||
for (auto const &iconPng : iconPngs) {
|
||||
OX_RETURN_ERROR(toGlfwImgPixels(iconPng).moveTo(src.emplace_back()));
|
||||
auto &icon = *src.back().unwrap();
|
||||
imgs.emplace_back(GLFWimage{
|
||||
.width = icon.w,
|
||||
.height = icon.h,
|
||||
.pixels = icon.pixels.data(),
|
||||
});
|
||||
}
|
||||
glfwSetWindowIcon(ctx.window, static_cast<int>(imgs.size()), imgs.data());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void setWindowTitle(Context &ctx, ox::StringViewCR title) noexcept {
|
||||
auto cstr = ox_malloca(title.bytes() + 1, char);
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
ox::strncpy(cstr.get(), title.data(), title.bytes());
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
glfwSetWindowTitle(ctx.window, cstr.get());
|
||||
}
|
||||
|
||||
void focusWindow(Context &ctx) noexcept {
|
||||
glfwFocusWindow(ctx.window);
|
||||
}
|
||||
|
||||
int getScreenWidth(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
int getScreenHeight(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return h;
|
||||
}
|
||||
|
||||
ox::Size getScreenSize(Context const &ctx) noexcept {
|
||||
int w = 0, h = 0;
|
||||
glfwGetFramebufferSize(ctx.window, &w, &h);
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
ox::Bounds getWindowBounds(Context const &ctx) noexcept {
|
||||
ox::Bounds bnds;
|
||||
glfwGetWindowPos(ctx.window, &bnds.x, &bnds.y);
|
||||
glfwGetWindowSize(ctx.window, &bnds.width, &bnds.height);
|
||||
return bnds;
|
||||
}
|
||||
|
||||
ox::Error setWindowBounds(Context &ctx, ox::Bounds const&bnds) noexcept {
|
||||
glfwSetWindowPos(ctx.window, bnds.x, bnds.y);
|
||||
glfwSetWindowSize(ctx.window, bnds.width, bnds.height);
|
||||
return {};
|
||||
}
|
||||
|
||||
void setRefreshWithin(Context &ctx, int ms) noexcept {
|
||||
ctx.refreshWithinMs = ox::min(ms, ctx.refreshWithinMs);
|
||||
}
|
||||
|
||||
static void draw(Context &ctx) noexcept {
|
||||
// draw start
|
||||
#if TURBINE_USE_IMGUI
|
||||
@ -35,11 +238,77 @@ static void draw(Context &ctx) noexcept {
|
||||
glfwSwapBuffers(ctx.window);
|
||||
}
|
||||
|
||||
static void draw(GLFWwindow *window, int, int) noexcept {
|
||||
static void handleGlfwResize(GLFWwindow *window, int, int) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
draw(ctx);
|
||||
}
|
||||
|
||||
static void handleGlfwError(int const err, char const *desc) noexcept {
|
||||
oxErrf("GLFW error ({}): {}\n", err, desc);
|
||||
}
|
||||
|
||||
static auto setKeyDownStatus(Context &ctx, Key const key, bool const down) noexcept {
|
||||
ctx.keysDown &= ~(1llu << static_cast<int>(key));
|
||||
ctx.keysDown |= static_cast<uint64_t>(down) << static_cast<int>(key);
|
||||
}
|
||||
|
||||
static void handleKeyPress(Context &ctx, int const key, bool const down) noexcept {
|
||||
static constexpr auto keyMap = [] {
|
||||
ox::Array<Key, GLFW_KEY_LAST> map = {};
|
||||
for (auto i = 0u; i < 26; ++i) {
|
||||
map[GLFW_KEY_A + i] = static_cast<Key>(static_cast<unsigned>(Key::Alpha_A) + i);
|
||||
}
|
||||
for (auto i = 0u; i < 10; ++i) {
|
||||
map[GLFW_KEY_0 + i] = static_cast<Key>(static_cast<unsigned>(Key::Num_0) + i);
|
||||
}
|
||||
map[GLFW_KEY_LEFT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_RIGHT_ALT] = Key::Mod_Alt;
|
||||
map[GLFW_KEY_LEFT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_RIGHT_CONTROL] = Key::Mod_Ctrl;
|
||||
map[GLFW_KEY_LEFT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_RIGHT_SUPER] = Key::Mod_Super;
|
||||
map[GLFW_KEY_LEFT_SHIFT] = Key::Mod_Shift;
|
||||
map[GLFW_KEY_RIGHT_SHIFT] = Key::Mod_Shift;
|
||||
map[GLFW_KEY_ESCAPE] = Key::Escape;
|
||||
return map;
|
||||
}();
|
||||
auto const eventHandler = keyEventHandler(ctx);
|
||||
auto const keyIdx = static_cast<std::size_t>(key);
|
||||
if (keyIdx < keyMap.size()) {
|
||||
auto const k = keyMap[keyIdx];
|
||||
setKeyDownStatus(ctx, k, down);
|
||||
if (eventHandler) {
|
||||
eventHandler(ctx, k, down);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handleGlfwCursorPosEvent(GLFWwindow*, double, double) noexcept {
|
||||
}
|
||||
|
||||
static void handleGlfwMouseButtonEvent(GLFWwindow *window, int, int, int) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
}
|
||||
|
||||
static void handleGlfwKeyEvent(GLFWwindow *window, int const key, int, int const action, int) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
if (action == GLFW_PRESS) {
|
||||
handleKeyPress(ctx, key, true);
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
handleKeyPress(ctx, key, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void handleGlfwWindowCloseEvent(GLFWwindow *window) noexcept {
|
||||
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
|
||||
ctx.mandatoryRefreshPeriodEnd = ticksMs(ctx) + config::MandatoryRefreshPeriod;
|
||||
ctx.running = ctx.shutdownHandler ? !ctx.shutdownHandler(ctx) : false;
|
||||
glfwSetWindowShouldClose(window, !ctx.running);
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
ox::Result<ox::UPtr<Context>> init(
|
||||
ox::UPtr<ox::FileSystem> &&fs, ox::StringViewCR appName) noexcept {
|
||||
auto ctx = ox::make_unique<Context>();
|
||||
@ -47,11 +316,44 @@ ox::Result<ox::UPtr<Context>> init(
|
||||
using namespace std::chrono;
|
||||
ctx->startTime = static_cast<TimeMs>(
|
||||
duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
|
||||
glfwInit();
|
||||
OX_RETURN_ERROR(initGfx(*ctx));
|
||||
glfwSetWindowSizeCallback(ctx->window, draw);
|
||||
ctx->mandatoryRefreshPeriodEnd = ticksMs(*ctx) + config::MandatoryRefreshPeriod;
|
||||
return ox::UPtr<Context>(ctx.release());
|
||||
// init GLFW context
|
||||
glfwInit();
|
||||
glfwSetErrorCallback(handleGlfwError);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
constexpr auto Scale = 5;
|
||||
ctx->window = glfwCreateWindow(240 * Scale, 160 * Scale, ctx->keelCtx.appName.c_str(), nullptr, nullptr);
|
||||
//ctx.window = glfwCreateWindow(876, 743, ctx.keelCtx.appName.c_str(), nullptr, nullptr);
|
||||
if (ctx->window == nullptr) {
|
||||
return ox::Error(1, "Could not open GLFW window");
|
||||
}
|
||||
glfwSetCursorPosCallback(ctx->window, handleGlfwCursorPosEvent);
|
||||
glfwSetMouseButtonCallback(ctx->window, handleGlfwMouseButtonEvent);
|
||||
glfwSetKeyCallback(ctx->window, handleGlfwKeyEvent);
|
||||
glfwSetWindowCloseCallback(ctx->window, handleGlfwWindowCloseEvent);
|
||||
glfwSetWindowSizeCallback(ctx->window, handleGlfwResize);
|
||||
glfwSetWindowUserPointer(ctx->window, ctx.get());
|
||||
glfwMakeContextCurrent(ctx->window);
|
||||
if (!gladLoadGLES2Loader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {
|
||||
return ox::Error(2, "Could not init Glad");
|
||||
}
|
||||
// init ImGui
|
||||
#if TURBINE_USE_IMGUI
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
auto &io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
//io.MouseDrawCursor = true;
|
||||
ImGui_ImplGlfw_InitForOpenGL(ctx->window, true);
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
io.IniFilename = nullptr;
|
||||
themeImgui();
|
||||
#endif
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void tickFps(Context &ctx, uint64_t const nowMs) noexcept {
|
||||
@ -132,4 +434,16 @@ void setShutdownHandler(Context &ctx, ShutdownHandler const handler) noexcept {
|
||||
ctx.shutdownHandler = handler;
|
||||
}
|
||||
|
||||
void setUpdateHandler(Context &ctx, UpdateHandler h) noexcept {
|
||||
ctx.updateHandler = h;
|
||||
}
|
||||
|
||||
void setKeyEventHandler(Context &ctx, KeyEventHandler h) noexcept {
|
||||
ctx.keyEventHandler = h;
|
||||
}
|
||||
|
||||
KeyEventHandler keyEventHandler(Context &ctx) noexcept {
|
||||
return ctx.keyEventHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user