Compare commits

..

101 Commits

Author SHA1 Message Date
671b8edaad [ox/std] Make StringLiteral constructors consteval
All checks were successful
Build / build (push) Successful in 1m29s
2025-06-27 23:05:42 -05:00
952637a1ea Merge commit 'cbf4414fcaf00c00a2abf73b5c04a055180ad980'
All checks were successful
Build / build (push) Successful in 1m37s
2025-06-25 21:33:16 -05:00
7569698e95 [nostalgia,studio] Add FileExts_TileSheet const, and corresponding FilePickerPopup constructor 2025-06-25 21:30:49 -05:00
21713ba945 [ox/std] Fix StringLiteral::operator= to work with DevkitARM 2025-06-25 21:29:41 -05:00
73273b6fa7 [nostalgia/gfx] Add isTileSheet function for checking paths against both file extensions 2025-06-25 21:03:45 -05:00
9f040392c7 [olympic,nostalgia] Cleanup style
All checks were successful
Build / build (push) Successful in 1m18s
2025-06-24 01:59:22 -05:00
f4f7e5d053 Merge commit '9b5f7886cadc5c3dc826d00fa5b2e71696151dfd' 2025-06-23 20:49:01 -05:00
f847289bd4 [glutils] Cleanup
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-23 01:39:47 -05:00
94b0020d15 [nostalgia,olympic] Cleanup
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-23 01:30:33 -05:00
c54c0bad38 [teagba] Cleanup
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-23 01:03:33 -05:00
b9ffae0269 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m18s
2025-06-23 00:47:46 -05:00
003f3e01c6 [nostalgia] Update release notes 2025-06-22 01:01:09 -05:00
9028e74af0 [nostalgia/gfx/studio/tilesheet] Disable paste when nothing is selected 2025-06-22 01:00:56 -05:00
f5ccab5f2c [studio] Cleanup 2025-06-21 19:19:39 -05:00
c27726a4a9 Merge commit '6bbcae10cc7b21b73171ec0ff196f4baf6304404' 2025-06-21 14:29:47 -05:00
37cfa927d1 [nostalgia/gfx] Address a couple of implicit conversions
All checks were successful
Build / build (push) Successful in 1m19s
2025-06-21 14:16:17 -05:00
0efed70b57 [studio] Fix Studio to clear editor pointers when opening a new project
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-21 14:12:45 -05:00
baf5fa3199 [nostalgia] Move d2025.05.2 release notes to d2025.06.0
All checks were successful
Build / build (push) Successful in 1m19s
2025-06-21 08:54:57 -05:00
bd24a775b2 Merge commit '7371df429534f264c179684412f6197f7968ebfa' 2025-06-21 08:48:13 -05:00
857587c18b [studio] Cleanup
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-21 08:31:27 -05:00
eb3d53c955 [studio] Cleanup
All checks were successful
Build / build (push) Successful in 1m15s
2025-06-21 08:22:13 -05:00
14d58f3f5b [studio] Fix Navigation shortcuts for non-Mac systems
All checks were successful
Build / build (push) Successful in 1m18s
2025-06-21 08:13:14 -05:00
5f2397903a [studio,nostalgia/gfx/studio/tilesheet] Fix copy/cut/paste enablement when there is no selection
All checks were successful
Build / build (push) Successful in 2m2s
2025-06-21 00:20:06 -05:00
58e0ecb469 [studio] Make FilePickerPopup accept on double click of a file
All checks were successful
Build / build (push) Successful in 1m22s
2025-06-20 23:58:29 -05:00
8838bf420e [studio] Fix to properly copy file that has the same name as deleted file
All checks were successful
Build / build (push) Successful in 1m24s
2025-06-20 23:36:20 -05:00
bddc544d7c [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m33s
2025-06-20 22:48:39 -05:00
a9437191bf [studio,turbine] Add support for mouse back/forward buttons
All checks were successful
Build / build (push) Successful in 1m30s
2025-06-20 22:44:09 -05:00
9d8da7ccda [ox/std] Make strToInt return error for empty string
Some checks failed
Build / build (push) Has been cancelled
2025-06-20 22:43:33 -05:00
394b568e72 [studio] Add Back/Forward navigation
All checks were successful
Build / build (push) Successful in 1m14s
2025-06-20 20:58:42 -05:00
78e9f70db6 [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-19 23:58:42 -05:00
12e5623fe6 [ox/logconn] Add exception handling for logger thread
All checks were successful
Build / build (push) Successful in 1m18s
2025-06-19 23:56:26 -05:00
cfdfb0a8c9 [studio] Fix file deletion to close file even if not active 2025-06-19 23:55:47 -05:00
56e665301f [studio] Cleanup
All checks were successful
Build / build (push) Successful in 1m29s
2025-06-19 21:37:57 -05:00
7415ce4bd9 [nostalgia/gfx/studio] Cleanup
All checks were successful
Build / build (push) Successful in 2m53s
2025-06-17 20:45:24 -05:00
05f42150a1 [olympic] Add new loc command to Makefile
All checks were successful
Build / build (push) Successful in 1m19s
2025-06-09 21:29:27 -05:00
8ea2bc6934 [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-09 00:22:17 -05:00
c780924122 [studio] Add [DEBUG] tag to About in debug builds
All checks were successful
Build / build (push) Successful in 1m18s
2025-06-08 21:33:17 -05:00
8c538560ca [nostalgia/gfx/studio/palette] Make RGB key shortcuts work when color channel inputs are focused
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-08 17:00:52 -05:00
c3e75bdb55 [nostalgia/gfx/studio/tilesheet] Cleanup
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-08 16:26:55 -05:00
4419dff299 Merge commit '7688c05bac8c20bc267cae62ec78d55e5d0c493b' 2025-05-31 02:14:15 -05:00
e78c405046 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m19s
2025-05-31 01:53:59 -05:00
6b7c5d896e [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-31 01:48:07 -05:00
a33a73d73a [nostalgia/gfx/studio/palette] Add preview to color editor
All checks were successful
Build / build (push) Successful in 1m16s
2025-05-31 01:34:00 -05:00
536999c070 Merge commit '47eee1d56d591e3631d16e95a78ea3629ee312ee' 2025-05-30 23:38:53 -05:00
e1cfcc8b5f [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m13s
2025-05-30 23:37:58 -05:00
514cb97835 [nostalgia/gfx/studio/tilesheet] Fix draw command to work on same pixel after switching subsheets 2025-05-30 23:32:51 -05:00
4b5218c4f1 [nostalgia/gfx] Cleanup 2025-05-30 23:32:27 -05:00
2ca77173d3 [keel] Add isUuidUrl function 2025-05-30 23:29:42 -05:00
cce5f52f96 [nostalgia/gfx/studio/tilesheet] Fix manual redo of draw actions, fix drawing to pixel 0, 0 as first action
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-29 22:12:10 -05:00
b55993294a [studio/modlib] Fix headerizeConfigFile to handle slashes in file name
All checks were successful
Build / build (push) Successful in 1m12s
2025-05-25 01:20:20 -05:00
d8f847d707 [studio/applib] Move popup types into their own directory
All checks were successful
Build / build (push) Successful in 1m20s
2025-05-24 15:01:17 -05:00
a5535ef59a Merge commit '08236fc790e711afe886b6ef545511d35e4e5c6c' 2025-05-24 01:44:07 -05:00
8419b137e5 [turbine,studio] Fix some popup window resize weirdness, cleanup some function names
All checks were successful
Build / build (push) Successful in 1m17s
2025-05-24 01:32:14 -05:00
ed1160ec74 [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-24 00:50:22 -05:00
1e21778059 [nostalgia/gfx/studio/tilesheet] Ensure config file has a Claw header 2025-05-24 00:48:54 -05:00
78379f58c8 [studio] Add ability to remember recent projects in config 2025-05-24 00:48:10 -05:00
4322f720ba [keel] Fix ox::Result<DstType> convert(Context &ctx, ox::BufferView const&src) 2025-05-24 00:47:39 -05:00
26f1a6051f [ox/std] Make Vector::remove take a MaybeView_t
All checks were successful
Build / build (push) Successful in 1m17s
2025-05-24 00:46:39 -05:00
c4c1d4777b [keel] Cleanup ox::Error(0) instance 2025-05-23 20:25:08 -05:00
fab012d3e7 [ox] Cleanup all ox::Error(0) instances 2025-05-23 20:24:58 -05:00
a90380f377 Merge commit 'e90dd887477452922f783535edb3d4c55e9a0d2c' 2025-05-23 03:23:17 -05:00
312097a799 [ox/std] Fix implementation of std cmp functions
All checks were successful
Build / build (push) Successful in 1m12s
2025-05-23 03:22:27 -05:00
a40198ab8d [nostalgia] Update release-d2025.05.2 release notes
All checks were successful
Build / build (push) Successful in 1m23s
2025-05-22 20:45:34 -05:00
52d8c0bdc8 [nostalgia/gfx] Replace static_cast compare with std::cmp_equal 2025-05-22 20:43:27 -05:00
c19d7f4ea3 [nostalgia] Add .vs and cmake-build-* to .gitignore 2025-05-22 20:42:09 -05:00
159b7e7ee7 [buildcore] Make pybb cmake_build specify --config debug/release 2025-05-22 20:41:30 -05:00
c93eec4f05 [teagba] Make cstart.cpp only compile if GCC 2025-05-22 20:40:33 -05:00
e7e7a22390 [nostalgia/sample_project] Make sample_project exempt from autocrlf 2025-05-22 20:39:56 -05:00
26d5048e67 [ox/fs] Fix new build error in MSVC (VS 17.14) 2025-05-22 20:05:09 -05:00
3b8f97cc41 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-21 22:15:56 -05:00
f1e68e0a04 [nostalgia/gfx/studio/tilesheet] Fix overrun errors when switching subsheets, clear selection on switch 2025-05-21 22:15:07 -05:00
d6e4ab7a24 [keel] Cleanup
All checks were successful
Build / build (push) Successful in 1m24s
2025-05-18 14:08:39 -05:00
2000b2deee [nostalgia/gfx/studio] Cleanup 2025-05-17 23:35:10 -05:00
7d92400f6d [nostalgia/gfx/studio] Add type specific navigateTo functions 2025-05-17 23:26:23 -05:00
cb304ecf28 [applib] Cleanup
All checks were successful
Build / build (push) Successful in 1m12s
2025-05-17 17:46:38 -05:00
ea17377700 [ox/std] Make StringViewCR honest
All checks were successful
Build / build (push) Successful in 1m17s
2025-05-17 17:34:22 -05:00
c424bde06d [nostalgia] Style cleanup
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-17 17:31:47 -05:00
ee7d5c6d51 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-17 17:22:13 -05:00
99247cee32 [nostalgia/gfx/test] Cleanup
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-17 17:18:51 -05:00
7b8ddc189a [nostalgia/gfx] Consolidate implementations into single files, remove unnecessary function exports
All checks were successful
Build / build (push) Successful in 1m17s
2025-05-17 17:13:13 -05:00
a6814030ee [studio/applib] Cleanup
All checks were successful
Build / build (push) Successful in 1m13s
2025-05-17 16:15:32 -05:00
9937a01042 [turbine] Cleanup 2025-05-17 16:12:16 -05:00
abcf2adc56 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-17 03:02:59 -05:00
05f9023550 [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-17 02:51:56 -05:00
5ba0bcf963 [turbine] Consolidate some files that didn't have sensible distinctions
Some checks failed
Build / build (push) Has been cancelled
2025-05-17 02:51:23 -05:00
3ccadba2f5 [nostalgia/gfx/studio/tilesheet] Fix dragging cursor on image
All checks were successful
Build / build (push) Successful in 1m20s
2025-05-16 21:22:33 -05:00
00e52b6491 [nostalgia] Make pkg-dmg more versatile
All checks were successful
Build / build (push) Successful in 1m14s
2025-05-15 22:26:35 -05:00
ae40487990 [nostalgia/gfx] Add navigateTo handler to TileSheetEditor
All checks were successful
Build / build (push) Successful in 1m20s
2025-05-15 20:39:50 -05:00
84b612c693 [studio/modlib] Give navigateTo a default argument 2025-05-15 20:39:01 -05:00
3c2a6b047e [studio/applib] Make navigateTo handle UUID paths 2025-05-15 20:38:27 -05:00
626da322d9 [ox/std] Add StringParam(IString const&) constructor 2025-05-15 20:37:44 -05:00
0de428a2e5 [studio/applib] Cleanup
All checks were successful
Build / build (push) Successful in 1m19s
2025-05-14 22:11:43 -05:00
8a52df4f76 [nostalgia/gfx] More cleanup
All checks were successful
Build / build (push) Successful in 1m16s
2025-05-14 01:43:59 -05:00
efec6eb3c8 [nostalgia/gfx/studio/palette] Add RGB key shortcuts for focusing color channels
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-14 01:13:40 -05:00
56eeb24900 [nostalgia/gfx/opengl] More cleanup
All checks were successful
Build / build (push) Successful in 1m56s
2025-05-13 22:06:08 -05:00
ae81f6b3de [ox/std] Make Span::operator[] const
All checks were successful
Build / build (push) Successful in 1m17s
2025-05-13 22:02:23 -05:00
c1108301c0 [nostalgia/gfx] Cleanup 2025-05-13 22:01:59 -05:00
83fbe6ac74 [keel,turbine,studio] Fix some install mistakes
All checks were successful
Build / build (push) Successful in 2m17s
2025-05-13 21:39:37 -05:00
80b452833f [nostalgia/gfx] Cleanup
All checks were successful
Build / build (push) Successful in 2m28s
2025-05-13 21:24:04 -05:00
0fa394333b [nostalgia] Add release note about Mac menubar using Cmd
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-10 01:01:11 -05:00
cae7535034 [nostalgia] Fix typos in release notes
All checks were successful
Build / build (push) Successful in 1m15s
2025-05-10 00:57:45 -05:00
192 changed files with 2474 additions and 1991 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
sample_project text eol=lf

2
.gitignore vendored
View File

@@ -6,12 +6,14 @@
.mypy_cache .mypy_cache
.stfolder .stfolder
.stignore .stignore
.vs
util/scripts/__pycache__ util/scripts/__pycache__
pyenv pyenv
CMakeLists.txt.user CMakeLists.txt.user
ROM.oxfs ROM.oxfs
Session.vim Session.vim
build build
cmake-build-*
compile_commands.json compile_commands.json
dist dist
graph_info.json graph_info.json

View File

@@ -19,7 +19,7 @@ pkg-gba: build
.PHONY: pkg-mac .PHONY: pkg-mac
pkg-mac: install pkg-mac: install
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-dmg.py ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-dmg.py NostalgiaStudio
.PHONY: generate-studio-rsrc .PHONY: generate-studio-rsrc
generate-studio-rsrc: generate-studio-rsrc:
@@ -52,3 +52,25 @@ configure-gba:
.PHONY: configure-gba-debug .PHONY: configure-gba-debug
configure-gba-debug: configure-gba-debug:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BC_VAR_BUILD_PATH} ${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BC_VAR_BUILD_PATH}
.PHONY: loc
loc:
${BC_PY3} util/scripts/loc.py \
--search-dirs \
src \
deps/ox/src \
deps/buildcore \
deps/gbabuildcore \
deps/glutils \
deps/teagba \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake \
--exclude-paths \
deps/teagba/src/gba_crt0.s \
src/olympic/studio/applib/src/font.cpp \
src/olympic/studio/applib/src/font.hpp \
src/nostalgia/studio/icondata.cpp

View File

@@ -89,7 +89,7 @@ struct GLObject: public Base {
return id; return id;
} }
constexpr operator const GLuint&() const noexcept { constexpr operator GLuint const&() const noexcept {
return id; return id;
} }
@@ -135,7 +135,7 @@ struct FrameBuffer {
return fbo.id; return fbo.id;
} }
constexpr operator const GLuint&() const noexcept { constexpr operator GLuint const&() const noexcept {
return fbo.id; return fbo.id;
} }
@@ -158,14 +158,14 @@ struct FrameBuffer {
class FrameBufferBind { class FrameBufferBind {
private: private:
static const FrameBuffer *s_activeFb; static FrameBuffer const *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr; FrameBuffer const *m_restoreFb = nullptr;
public: public:
explicit FrameBufferBind(const FrameBuffer &fb) noexcept; explicit FrameBufferBind(FrameBuffer const &fb) noexcept;
~FrameBufferBind() noexcept; ~FrameBufferBind() noexcept;
}; };
void bind(const FrameBuffer &fb) noexcept; void bind(FrameBuffer const &fb) noexcept;
struct ShaderVarSet { struct ShaderVarSet {
GLsizei len{}; GLsizei len{};
@@ -201,9 +201,9 @@ void setupShaderParams(
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept; void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept; GLVertexArray generateVertexArrayObject() noexcept;
glutils::GLBuffer generateBuffer() noexcept; GLBuffer generateBuffer() noexcept;
[[nodiscard]] [[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept; FrameBuffer generateFrameBuffer(int width, int height) noexcept;
@@ -218,10 +218,10 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept; void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept;
struct BufferSet { struct BufferSet {
glutils::GLVertexArray vao; GLVertexArray vao;
glutils::GLBuffer vbo; GLBuffer vbo;
glutils::GLBuffer ebo; GLBuffer ebo;
glutils::GLTexture tex; GLTexture tex;
ox::Vector<float> vertices; ox::Vector<float> vertices;
ox::Vector<GLuint> elements; ox::Vector<GLuint> elements;
}; };

View File

@@ -46,9 +46,9 @@ template struct GLObject<deleteVertexArray>;
template struct GLObject<deleteProgram>; template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>; template struct GLObject<deleteShader>;
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr; FrameBuffer const *FrameBufferBind::s_activeFb = nullptr;
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) { FrameBufferBind::FrameBufferBind(FrameBuffer const &fb) noexcept: m_restoreFb(s_activeFb) {
s_activeFb = &fb; s_activeFb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb); glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height); glViewport(0, 0, fb.width, fb.height);
@@ -64,15 +64,15 @@ FrameBufferBind::~FrameBufferBind() noexcept {
} }
} }
void bind(const FrameBuffer &fb) noexcept { void bind(FrameBuffer const &fb) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb); glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height); glViewport(0, 0, fb.width, fb.height);
} }
static ox::Result<GLShader> buildShader( static ox::Result<GLShader> buildShader(
GLuint shaderType, GLuint const shaderType,
const GLchar *src, GLchar const *src,
ox::StringViewCR shaderName) noexcept { ox::StringViewCR shaderName) noexcept {
GLShader shader(glCreateShader(shaderType)); GLShader shader(glCreateShader(shaderType));
glShaderSource(shader, 1, &src, nullptr); glShaderSource(shader, 1, &src, nullptr);
@@ -162,16 +162,30 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
// color texture // color texture
glGenTextures(1, &fb.color.id); glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
nullptr);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0); glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
// depth texture // depth texture
glGenRenderbuffers(1, &fb.depth.id); glGenRenderbuffers(1, &fb.depth.id);
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth); glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth); glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
fb.depth);
// verify FBO // verify FBO
oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete"); oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete");
// restore primary FB // restore primary FB
@@ -189,7 +203,16 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb); glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture // color texture
glBindTexture(GL_TEXTURE_2D, fb.color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// depth texture // depth texture
@@ -201,7 +224,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept { void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) noexcept {
if (!fb) { if (!fb) {
fb = generateFrameBuffer(width, height); fb = generateFrameBuffer(width, height);
return; return;
@@ -214,13 +237,13 @@ void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
} }
void sendVbo(BufferSet const &bs) noexcept { void sendVbo(BufferSet const &bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size()); auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo); glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
} }
void sendEbo(BufferSet const &bs) noexcept { void sendEbo(BufferSet const &bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size()); auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);
} }

View File

@@ -39,7 +39,7 @@ struct TypeInfoCatcher {
} }
constexpr Error field(...) noexcept { constexpr Error field(...) noexcept {
return ox::Error(0); return {};
} }
static constexpr auto opType() { static constexpr auto opType() {

View File

@@ -218,7 +218,7 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) { for (auto &f : m_slots) {
f->call(args...); f->call(args...);
} }
return ox::Error(0); return {};
} catch (const ox::Exception &ex) { } catch (const ox::Exception &ex) {
return ox::Error(ex.errCode, ex.msg, ex.src); return ox::Error(ex.errCode, ex.msg, ex.src);
} }
@@ -410,7 +410,7 @@ Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) { for (auto &f : m_slots) {
OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...)); OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...));
} }
return ox::Error(0); return {};
} }
} }

View File

@@ -230,7 +230,7 @@ template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(uint64_t id) { Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate()); OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
++item->links; ++item->links;
return ox::Error(0); return {};
} }
template<typename size_t> template<typename size_t>
@@ -240,7 +240,7 @@ Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
if (item->links == 0) { if (item->links == 0) {
OX_RETURN_ERROR(remove(item)); OX_RETURN_ERROR(remove(item));
} }
return ox::Error(0); return {};
} }
template<typename size_t> template<typename size_t>
@@ -298,7 +298,7 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
dest->id.get(), dest.offset(), destData.size()); dest->id.get(), dest.offset(), destData.size());
fsData->rootNode = dest.offset(); fsData->rootNode = dest.offset();
oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get()); oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
return ox::Error(0); return {};
} }
} else { } else {
oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header."); oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header.");
@@ -427,7 +427,7 @@ Error FileStoreTemplate<size_t>::resize() {
oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize); oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
OX_RETURN_ERROR(m_buffer->setSize(newSize)); OX_RETURN_ERROR(m_buffer->setSize(newSize));
oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size()); oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
return ox::Error(0); return {};
} }
template<typename size_t> template<typename size_t>
@@ -479,7 +479,7 @@ Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
for (auto i = m_buffer->iterator(); i.valid(); i.next()) { for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end())); OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
} }
return ox::Error(0); return {};
} }
template<typename size_t> template<typename size_t>
@@ -503,7 +503,7 @@ Error FileStoreTemplate<size_t>::compact() {
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error { return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error {
if (isFirstItem) { if (isFirstItem) {
isFirstItem = false; isFirstItem = false;
return ox::Error(0); return {};
} }
if (!item.valid()) { if (!item.valid()) {
return ox::Error(1); return ox::Error(1);
@@ -524,7 +524,7 @@ Error FileStoreTemplate<size_t>::compact() {
parent->right = item; parent->right = item;
} }
} }
return ox::Error(0); return {};
}); });
} }
@@ -552,7 +552,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
item->left = root->left; item->left = root->left;
item->right = root->right; item->right = root->right;
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
return ox::Error(0); return {};
} else { } else {
return placeItem(root, item); return placeItem(root, item);
} }
@@ -573,7 +573,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = right->right; item->right = right->right;
} }
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return ox::Error(0); return {};
} else { } else {
return placeItem(right, item, depth + 1); return placeItem(right, item, depth + 1);
} }
@@ -586,7 +586,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = left->right; item->right = left->right;
} }
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return ox::Error(0); return {};
} else { } else {
return placeItem(left, item, depth + 1); return placeItem(left, item, depth + 1);
} }
@@ -624,7 +624,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
} else { } else {
fsData->rootNode = 0; fsData->rootNode = 0;
} }
return ox::Error(0); return {};
} else { } else {
return unplaceItem(root, item); return unplaceItem(root, item);
} }
@@ -661,7 +661,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
if (item->left) { if (item->left) {
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left))); OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left)));
} }
return ox::Error(0); return {};
} }
template<typename size_t> template<typename size_t>
@@ -669,7 +669,7 @@ Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
if (item.valid()) { if (item.valid()) {
OX_RETURN_ERROR(unplaceItem(item)); OX_RETURN_ERROR(unplaceItem(item));
OX_RETURN_ERROR(m_buffer->free(item)); OX_RETURN_ERROR(m_buffer->free(item));
return ox::Error(0); return {};
} }
return ox::Error(1); return ox::Error(1);
} }

View File

@@ -329,7 +329,7 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
return ox::Error(1); return ox::Error(1);
} }
return ox::Error(0); return {};
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@@ -346,7 +346,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(StringViewCR src, StringVie
OX_REQUIRE_M(inode, rootDir.find(src)); OX_REQUIRE_M(inode, rootDir.find(src));
OX_RETURN_ERROR(rootDir.write(dest, inode)); OX_RETURN_ERROR(rootDir.write(dest, inode));
OX_RETURN_ERROR(rootDir.remove(src)); OX_RETURN_ERROR(rootDir.remove(src));
return ox::Error(0); return {};
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@@ -407,7 +407,7 @@ Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bo
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting."); oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return ox::Error(1); return ox::Error(1);
} }
return ox::Error(0); return {};
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@@ -424,7 +424,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR
Vector<String> out; Vector<String> out;
OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) { OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
out.emplace_back(name); out.emplace_back(name);
return ox::Error(0); return ox::Error{};
})); }));
return out; return out;
} }

View File

@@ -60,7 +60,7 @@ Error PassThroughFS::move(StringViewCR src, StringViewCR dest) noexcept {
if (ec.value()) { if (ec.value()) {
return ox::Error(1); return ox::Error(1);
} }
return ox::Error(0); return {};
} }
Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept { Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
@@ -148,7 +148,7 @@ Error PassThroughFS::readFilePath(StringViewCR path, void *buffer, std::size_t b
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what()); oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return ox::Error(2); return ox::Error(2);
} }
return ox::Error(0); return {};
} }
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept { Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
@@ -197,7 +197,7 @@ Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what()); oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return ox::Error(1); return ox::Error(1);
} }
return ox::Error(0); return {};
} }
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept { Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept {

View File

@@ -99,7 +99,7 @@ Error PassThroughFS::ls(StringViewCR dir, F cb) const noexcept {
for (auto &p : di) { for (auto &p : di) {
OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0)); OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0));
} }
return ox::Error(0); return {};
} }
} }

View File

@@ -36,7 +36,7 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
if (idx >= 0 && size < outSize) { if (idx >= 0 && size < outSize) {
ox::memcpy(out, m_path, size); ox::memcpy(out, m_path, size);
out[size] = 0; out[size] = 0;
return ox::Error(0); return {};
} else { } else {
return ox::Error(1); return ox::Error(1);
} }
@@ -85,7 +85,7 @@ Error PathIterator::next(StringView &fileName) {
std::size_t size = 0; std::size_t size = 0;
auto retval = ox::Error(1); auto retval = ox::Error(1);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) { if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = ox::Error(0); retval = {};
if (m_path[m_iterator] == '/') { if (m_path[m_iterator] == '/') {
m_iterator++; m_iterator++;
} }
@@ -118,7 +118,7 @@ Result<std::size_t> PathIterator::nextSize() const {
auto retval = ox::Error(1); auto retval = ox::Error(1);
auto it = m_iterator; auto it = m_iterator;
if (it < m_maxSize && ox::strlen(&m_path[it])) { if (it < m_maxSize && ox::strlen(&m_path[it])) {
retval = ox::Error(0); retval = {};
if (m_path[it] == '/') { if (m_path[it] == '/') {
it++; it++;
} }

View File

@@ -354,7 +354,7 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
} }
} }
m_header.bytesUsed -= item.size(); m_header.bytesUsed -= item.size();
return ox::Error(0); return {};
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
@@ -370,7 +370,7 @@ Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
m_header.size = static_cast<size_t>(size); m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end; auto data = reinterpret_cast<uint8_t*>(this) + end;
ox::memset(data, 0, size - end); ox::memset(data, 0, size - end);
return ox::Error(0); return {};
} }
} }
@@ -422,7 +422,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
src = ptr(dest->next); src = ptr(dest->next);
dest = uninitializedPtr(dest.offset() + dest->fullSize()); dest = uninitializedPtr(dest.offset() + dest->fullSize());
} }
return ox::Error(0); return {};
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>

View File

@@ -48,7 +48,7 @@ static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept
for (const auto &file : files) { for (const auto &file : files) {
oxOutf("{}\n", file); oxOutf("{}\n", file);
} }
return ox::Error(0); return {};
} }
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept { static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
@@ -60,7 +60,7 @@ static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcep
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout); std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0); return {};
} }
static ox::Error run(int argc, const char **argv) noexcept { static ox::Error run(int argc, const char **argv) noexcept {

View File

@@ -91,6 +91,7 @@ ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept {
} }
void LoggerConn::msgSend() noexcept { void LoggerConn::msgSend() noexcept {
try {
while (true) { while (true) {
std::unique_lock lk(m_waitMut); std::unique_lock lk(m_waitMut);
m_waitCond.wait(lk); m_waitCond.wait(lk);
@@ -109,6 +110,10 @@ void LoggerConn::msgSend() noexcept {
std::ignore = send(tmp.data(), read); std::ignore = send(tmp.data(), read);
} }
} }
} catch (std::exception const &e) {
oxErrf("Exception in logger thread: {}\n", e.what());
oxAssert(false, "logger thread exception");
}
} }
} }

View File

@@ -197,7 +197,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
OX_RETURN_ERROR(result); OX_RETURN_ERROR(result);
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
// array handler // array handler
@@ -256,7 +256,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<Stri
} }
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -330,7 +330,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
} }
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -370,7 +370,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
data[size] = 0; data[size] = 0;
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -388,7 +388,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
data[size] = 0; data[size] = 0;
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -416,7 +416,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
} }
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -464,7 +464,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
} }
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -487,7 +487,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexc
} }
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>

View File

@@ -122,7 +122,7 @@ class MetalClawWriter {
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
}; };
@@ -184,7 +184,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noe
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
} }
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -201,7 +201,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -229,7 +229,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *c
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -255,7 +255,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *v
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -319,7 +319,7 @@ OX_ALLOW_UNSAFE_BUFFERS_END
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -356,7 +356,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return ox::Error(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>

View File

@@ -13,7 +13,7 @@
// oxModelFwdDecl is necessary because Apple-Clang is broken... // oxModelFwdDecl is necessary because Apple-Clang is broken...
#define OX_MODEL_FWD_DECL(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept #define OX_MODEL_FWD_DECL(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
#define OX_MODEL_BEGIN(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { OX_RETURN_ERROR(io->template setTypeInfo<modelName>()); #define OX_MODEL_BEGIN(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { OX_RETURN_ERROR(io->template setTypeInfo<modelName>());
#define OX_MODEL_END() return ox::Error(0); } #define OX_MODEL_END() return {}; }
#define OX_MODEL_FIELD(fieldName) OX_RETURN_ERROR(io->field(#fieldName, &o->fieldName)); #define OX_MODEL_FIELD(fieldName) OX_RETURN_ERROR(io->field(#fieldName, &o->fieldName));
#define OX_MODEL_FIELD_RENAME(objFieldName, serFieldName) OX_RETURN_ERROR(io->field(#serFieldName, &o->objFieldName)); #define OX_MODEL_FIELD_RENAME(objFieldName, serFieldName) OX_RETURN_ERROR(io->field(#serFieldName, &o->objFieldName));
#define OX_MODEL_FRIEND(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept #define OX_MODEL_FRIEND(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept

View File

@@ -244,7 +244,7 @@ constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto
// defaultValue is unused now, but placeholder for backwards compatibility // defaultValue is unused now, but placeholder for backwards compatibility
int defaultValue = 0; int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue)); oxReturnError(io->field("defaultValue", &defaultValue));
return ox::Error(0); return {};
} }
#endif #endif

View File

@@ -205,7 +205,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t,
const auto t = type(p); const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t)); m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
return ox::Error(0); return {};
} }
return ox::Error(1); return ox::Error(1);
} }
@@ -220,7 +220,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t)
auto const lvls = detail::indirectionLevels_v<T> + 1; auto const lvls = detail::indirectionLevels_v<T> + 1;
SubscriptStack subscriptStack{lvls}; SubscriptStack subscriptStack{lvls};
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t)); m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
return ox::Error(0); return {};
} }
return ox::Error(1); return ox::Error(1);
} }
@@ -231,7 +231,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName)); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return ox::Error(0); return {};
} }
return ox::Error(1); return ox::Error(1);
} }

View File

@@ -31,25 +31,25 @@ class FieldCounter {
template<typename U> template<typename U>
constexpr ox::Error field(StringViewCR, U) noexcept { constexpr ox::Error field(StringViewCR, U) noexcept {
++fields; ++fields;
return ox::Error(0); return {};
} }
template<typename U> template<typename U>
constexpr ox::Error field(StringViewCR, U, std::size_t) noexcept { constexpr ox::Error field(StringViewCR, U, std::size_t) noexcept {
++fields; ++fields;
return ox::Error(0); return {};
} }
template<typename U, typename Handler> template<typename U, typename Handler>
constexpr Error field(StringViewCR, Handler) { constexpr Error field(StringViewCR, Handler) {
++fields; ++fields;
return ox::Error(0); return {};
} }
template<typename ...Args> template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept { constexpr Error fieldCString(Args&&...) noexcept {
++fields; ++fields;
return ox::Error(0); return {};
} }
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {

View File

@@ -56,19 +56,19 @@ class MemberList {
template<typename T> template<typename T>
constexpr Error field(const char*, T *v) noexcept { constexpr Error field(const char*, T *v) noexcept {
vars[m_i++] = static_cast<void*>(v); vars[m_i++] = static_cast<void*>(v);
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
constexpr Error field(const char*, T *v, int) noexcept { constexpr Error field(const char*, T *v, int) noexcept {
vars[m_i++] = static_cast<void*>(v); vars[m_i++] = static_cast<void*>(v);
return ox::Error(0); return {};
} }
template<typename U, bool force = false> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept { constexpr Error field(const char*, UnionView<U, force> u) noexcept {
vars[m_i++] = static_cast<void*>(u.get()); vars[m_i++] = static_cast<void*>(u.get());
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
@@ -107,7 +107,7 @@ class Copier {
auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]); auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]);
dst = src; dst = src;
++m_i; ++m_i;
return ox::Error(0); return {};
} }
} }
@@ -119,7 +119,7 @@ class Copier {
dst = src; dst = src;
} }
++m_i; ++m_i;
return ox::Error(0); return {};
} }
template<typename U, bool force = false> template<typename U, bool force = false>
@@ -128,7 +128,7 @@ class Copier {
auto &src = *u.get(); auto &src = *u.get();
dst = src; dst = src;
++m_i; ++m_i;
return ox::Error(0); return {};
} }
template<typename T = void> template<typename T = void>
@@ -168,7 +168,7 @@ class Mover {
dst = std::move(src); dst = std::move(src);
src = FT{}; src = FT{};
++m_i; ++m_i;
return ox::Error(0); return {};
} }
} }
@@ -181,7 +181,7 @@ class Mover {
src = FT{}; src = FT{};
} }
++m_i; ++m_i;
return ox::Error(0); return {};
} }
template<typename U, bool force = false> template<typename U, bool force = false>
@@ -190,7 +190,7 @@ class Mover {
auto &src = *u.get(); auto &src = *u.get();
dst = std::move(src); dst = std::move(src);
++m_i; ++m_i;
return ox::Error(0); return {};
} }
template<typename T = void> template<typename T = void>
@@ -228,7 +228,7 @@ class Equals {
const auto &dst = std::bit_cast<FT>(*m_other->vars[m_i]); const auto &dst = std::bit_cast<FT>(*m_other->vars[m_i]);
++m_i; ++m_i;
if (dst == src) { if (dst == src) {
return ox::Error(0); return {};
} else { } else {
this->value = false; this->value = false;
return ox::Error(1); return ox::Error(1);
@@ -246,7 +246,7 @@ class Equals {
} }
} }
++m_i; ++m_i;
return ox::Error(0); return {};
} }
template<typename U, bool force = false> template<typename U, bool force = false>
@@ -255,7 +255,7 @@ class Equals {
const auto &src = *u.get(); const auto &src = *u.get();
++m_i; ++m_i;
if (dst == src) { if (dst == src) {
return ox::Error(0); return {};
} else { } else {
this->value = false; this->value = false;
return ox::Error(1); return ox::Error(1);

View File

@@ -18,6 +18,6 @@ static_assert([]() -> ox::Error {
} }
//oxReturnError(v.set<int32_t>(5)); //oxReturnError(v.set<int32_t>(5));
return {}; return {};
}() == ox::Error(0)); }() == ox::Error{});
} }

View File

@@ -972,7 +972,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value)); OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
} }
return ox::Error(0); return {};
} }
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept { constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
@@ -981,7 +981,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value)); OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
} }
return ox::Error(0); return {};
} }
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept { constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
@@ -1129,7 +1129,7 @@ constexpr Error ModelValue::setType(
OX_RETURN_ERROR(m_data.uni->setType(type)); OX_RETURN_ERROR(m_data.uni->setType(type));
} }
oxAssert(m_type != Type::Undefined, "No type set"); oxAssert(m_type != Type::Undefined, "No type set");
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
@@ -1184,7 +1184,7 @@ constexpr Error ModelValue::set(const T &v) noexcept {
safeDelete(&value); safeDelete(&value);
} }
value = v; value = v;
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
@@ -1199,7 +1199,7 @@ constexpr Error ModelValue::set(T &&v) noexcept {
safeDelete(&value); safeDelete(&value);
} }
value = std::move(v); value = std::move(v);
return ox::Error(0); return {};
} }
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept { constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {

View File

@@ -38,17 +38,17 @@ struct TypeNameCatcher {
template<typename T> template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept { constexpr Error field(const char*, T*, std::size_t) noexcept {
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
constexpr Error field(const char*, T) noexcept { constexpr Error field(const char*, T) noexcept {
return ox::Error(0); return {};
} }
template<typename ...Args> template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept { constexpr Error fieldCString(Args&&...) noexcept {
return ox::Error(0); return {};
} }
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
@@ -77,17 +77,17 @@ struct TypeInfoCatcher {
template<typename T> template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept { constexpr Error field(const char*, T*, std::size_t) noexcept {
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
constexpr Error field(const char*, T) noexcept { constexpr Error field(const char*, T) noexcept {
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
constexpr Error fieldCString(const char*, T) noexcept { constexpr Error fieldCString(const char*, T) noexcept {
return ox::Error(0); return {};
} }
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {

View File

@@ -127,7 +127,7 @@ static constexpr Error parseField(const DescriptorField &field, Reader *rdr, Dat
} }
} }
walker->popNamePath(); walker->popNamePath();
return ox::Error(0); return {};
} }
template<typename Reader, typename FH> template<typename Reader, typename FH>
@@ -141,7 +141,7 @@ constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
for (const auto &field : fields) { for (const auto &field : fields) {
OX_RETURN_ERROR(parseField(field, rdr, walker)); OX_RETURN_ERROR(parseField(field, rdr, walker));
} }
return ox::Error(0); return {};
} }
template<typename Reader, typename Handler> template<typename Reader, typename Handler>

View File

@@ -37,7 +37,7 @@ OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept:
} }
Error OrganicClawReader::field(const char *key, bool *val) noexcept { Error OrganicClawReader::field(const char *key, bool *val) noexcept {
auto err = ox::Error(0); ox::Error err{};
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -53,7 +53,7 @@ Error OrganicClawReader::field(const char *key, bool *val) noexcept {
} }
Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept { Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept {
auto err = ox::Error(0); ox::Error err{};
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
if (targetValid()) { if (targetValid()) {
@@ -81,7 +81,7 @@ Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t bu
} }
Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept { Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
auto err = ox::Error(0); ox::Error err{};
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
auto &data = *val; auto &data = *val;
@@ -106,7 +106,7 @@ Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
} }
Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept { Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept {
auto err = ox::Error(0); ox::Error err{};
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
if (targetValid()) { if (targetValid()) {

View File

@@ -137,7 +137,7 @@ class OrganicClawReader {
template<typename T> template<typename T>
Error OrganicClawReader::field(const char *key, T *val) noexcept { Error OrganicClawReader::field(const char *key, T *val) noexcept {
auto err = ox::Error(0); ox::Error err{};
try { try {
if constexpr (is_integer_v<T>) { if constexpr (is_integer_v<T>) {
if (targetValid()) { if (targetValid()) {
@@ -190,7 +190,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
template<typename U, bool force> template<typename U, bool force>
Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept { Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept {
auto err = ox::Error(0); ox::Error err{};
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty() || jv.isObject()) { if (jv.empty() || jv.isObject()) {
@@ -207,7 +207,7 @@ Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcep
template<std::size_t L> template<std::size_t L>
Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept { Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
auto err = ox::Error(0); ox::Error err{};
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -224,7 +224,7 @@ Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
template<std::size_t L> template<std::size_t L>
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept { Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
auto err = ox::Error(0); ox::Error err{};
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -257,7 +257,7 @@ OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field("", &val[i])); OX_RETURN_ERROR(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
} }
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
@@ -274,7 +274,7 @@ Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcep
const auto k = keys[i].c_str(); const auto k = keys[i].c_str();
OX_RETURN_ERROR(handler.field(k, &val->operator[](k))); OX_RETURN_ERROR(handler.field(k, &val->operator[](k)));
} }
return ox::Error(0); return {};
} }
Error readOC(BufferView buff, auto &val) noexcept { Error readOC(BufferView buff, auto &val) noexcept {

View File

@@ -23,7 +23,7 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val, in
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) noexcept { Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) noexcept {

View File

@@ -46,7 +46,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const int16_t *val) noexcept { Error field(const char *key, const int16_t *val) noexcept {
@@ -54,7 +54,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const int32_t *val) noexcept { Error field(const char *key, const int32_t *val) noexcept {
@@ -62,7 +62,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const int64_t *val) noexcept { Error field(const char *key, const int64_t *val) noexcept {
@@ -70,7 +70,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
@@ -79,7 +79,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const uint16_t *val) noexcept { Error field(const char *key, const uint16_t *val) noexcept {
@@ -87,7 +87,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const uint32_t *val) noexcept { Error field(const char *key, const uint32_t *val) noexcept {
@@ -95,7 +95,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(const char *key, const uint64_t *val) noexcept { Error field(const char *key, const uint64_t *val) noexcept {
@@ -103,7 +103,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error field(char const*key, bool const*val) noexcept { Error field(char const*key, bool const*val) noexcept {
@@ -151,7 +151,7 @@ class OrganicClawWriter {
value(key) = val->c_str(); value(key) = val->c_str();
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Error fieldCString(const char*, const char *const*val, int len) noexcept; Error fieldCString(const char*, const char *const*val, int len) noexcept;
@@ -211,7 +211,7 @@ OX_ALLOW_UNSAFE_BUFFERS_END
value(key) = w.m_json; value(key) = w.m_json;
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
template<typename T> template<typename T>
@@ -237,7 +237,7 @@ Error OrganicClawWriter::field(const char *key, const T *val) noexcept {
} }
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
template<typename U, bool force> template<typename U, bool force>
@@ -251,7 +251,7 @@ Error OrganicClawWriter::field(const char *key, UnionView<U, force> val) noexcep
} }
} }
++m_fieldIt; ++m_fieldIt;
return ox::Error(0); return {};
} }
Result<ox::Buffer> writeOC(const auto &val) noexcept { Result<ox::Buffer> writeOC(const auto &val) noexcept {

View File

@@ -146,12 +146,7 @@ class Span {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size); return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
} }
constexpr T &operator[](std::size_t i) noexcept { constexpr T &operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow");
return m_items[i];
}
constexpr T const&operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow");
return m_items[i]; return m_items[i];
} }

View File

@@ -182,7 +182,7 @@ class BasicString {
// make sure last element is a null terminator // make sure last element is a null terminator
m_buff[currentLen + strLen] = 0; m_buff[currentLen + strLen] = 0;
// this can't fail, but it returns an Error to match BString::append // this can't fail, but it returns an Error to match BString::append
return ox::Error(0); return {};
} }
constexpr Error append(ox::StringView sv) noexcept { constexpr Error append(ox::StringView sv) noexcept {

View File

@@ -16,35 +16,28 @@ namespace ox {
* StringLiteral is used for functions that want to ensure that they are taking * StringLiteral is used for functions that want to ensure that they are taking
* string literals, and not strings outside of the data section of the program * string literals, and not strings outside of the data section of the program
* that might get deleted. * that might get deleted.
* This type cannot force you to use it correctly, so don't give it something
* that is not a literal.
* If you do this:
* StringLiteral(str.c_str())
* the resulting segfault is on you.
*/ */
class StringLiteral: public detail::BaseStringView { class StringLiteral: public detail::BaseStringView {
public: public:
constexpr StringLiteral() noexcept = default; consteval StringLiteral() noexcept = default;
constexpr StringLiteral(StringLiteral const &sv) noexcept = default; constexpr StringLiteral(StringLiteral const &sv) noexcept = default;
constexpr explicit StringLiteral(std::nullptr_t) noexcept {} consteval explicit StringLiteral(std::nullptr_t) noexcept {}
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {} consteval explicit StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr explicit StringLiteral(char const *str) noexcept: StringLiteral(str, ox::strlen(str)) {} consteval explicit StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
constexpr StringLiteral &operator=(StringLiteral const &other) noexcept { constexpr StringLiteral &operator=(StringLiteral const &other) noexcept {
if (&other != this) {
set(other.data(), other.len()); set(other.data(), other.len());
}
return *this; return *this;
} }
[[nodiscard]] [[nodiscard]]
constexpr const char *c_str() const noexcept { constexpr char const *c_str() const noexcept {
return data(); return data();
} }

View File

@@ -20,6 +20,8 @@ class StringParam {
constexpr StringParam(StringParam &&o) noexcept: m_value{std::move(o.m_value)} {} constexpr StringParam(StringParam &&o) noexcept: m_value{std::move(o.m_value)} {}
constexpr StringParam(char const*value) noexcept: m_value{value} {} constexpr StringParam(char const*value) noexcept: m_value{value} {}
constexpr StringParam(detail::BaseStringView const&value) noexcept: m_value{value} {} constexpr StringParam(detail::BaseStringView const&value) noexcept: m_value{value} {}
template<size_t sz>
constexpr StringParam(ox::IString<sz> const&value) noexcept: m_value{value} {}
constexpr StringParam(ox::String const&value) noexcept: m_value{value} {} constexpr StringParam(ox::String const&value) noexcept: m_value{value} {}
constexpr StringParam(ox::String &&value) noexcept: m_value{std::move(value)} {} constexpr StringParam(ox::String &&value) noexcept: m_value{std::move(value)} {}
constexpr operator ox::String() && noexcept { return std::move(m_value); } constexpr operator ox::String() && noexcept { return std::move(m_value); }

View File

@@ -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 { constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
if (s2.len() != s1.len()) { 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()); return writer.write(sv.data(), sv.bytes());
} }
@@ -100,17 +100,20 @@ constexpr auto toStdStringView(StringViewCR sv) noexcept {
#endif #endif
constexpr ox::Result<int> strToInt(ox::StringViewCR str) noexcept { constexpr ox::Result<int> strToInt(StringViewCR str) noexcept {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
int total = 0; int total = 0;
int multiplier = 1; int multiplier = 1;
if (str.len() == 0) [[unlikely]] {
return Error{1, "Empty string passed to strToInt"};
}
for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) { for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) {
auto s = static_cast<std::size_t>(i); auto s = static_cast<std::size_t>(i);
if (str[s] >= '0' && str[s] <= '9') { if (str[s] >= '0' && str[s] <= '9') {
total += (str[s] - '0') * multiplier; total += (str[s] - '0') * multiplier;
multiplier *= 10; multiplier *= 10;
} else { } else {
return ox::Error(1); return ox::Error{1};
} }
} }
return total; return total;

View File

@@ -32,9 +32,9 @@ constexpr bool cmp_equal(T const t, U const u) noexcept {
if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) { if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
return t == u; return t == u;
} else if constexpr(ox::is_signed_v<T>) { } else if constexpr(ox::is_signed_v<T>) {
return ox::Signed<T>{t} == u; return t >= 0 && static_cast<ox::Unsigned<T>>(t) == u;
} else { } else {
return t == ox::Signed<U>{u}; return u >= 0 && t == static_cast<ox::Unsigned<U>>(u);
} }
} }
@@ -43,9 +43,9 @@ constexpr bool cmp_less(T const t, U const u) noexcept {
if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) { if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
return t < u; return t < u;
} else if constexpr(ox::is_signed_v<T>) { } else if constexpr(ox::is_signed_v<T>) {
return ox::Signed<T>{t} < u; return t < 0 || static_cast<ox::Unsigned<T>>(t) < u;
} else { } else {
return t < ox::Signed<U>{u}; return u >= 0 && t < static_cast<ox::Unsigned<U>>(u);
} }
} }
@@ -69,6 +69,13 @@ constexpr bool cmp_greater_equal(T const t, U const u) noexcept {
return !std::cmp_less(t, u); return !std::cmp_less(t, u);
} }
static_assert(cmp_less(-1, 5u));
static_assert(!cmp_less(5u, -1));
static_assert(cmp_equal(5u, 5));
static_assert(cmp_equal(5, 5u));
static_assert(!cmp_equal(-5, 5u));
static_assert(!cmp_equal(4u, 5u));
} }
#endif #endif

View File

@@ -311,7 +311,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
*/ */
constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept); constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept);
constexpr Error remove(T const &val); constexpr Error remove(MaybeView_t<T> const &val);
constexpr void reserve(std::size_t cap) noexcept(useNoexcept); constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
@@ -658,11 +658,11 @@ constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size
--m_size; --m_size;
m_items[pos] = std::move(m_items[m_size]); m_items[pos] = std::move(m_items[m_size]);
m_items[m_size].~T(); m_items[m_size].~T();
return ox::Error(0); return {};
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(T const &val) { constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T> const &val) {
for (size_t i{}; auto const &v : *this) { for (size_t i{}; auto const &v : *this) {
if (v == val) { if (v == val) {
return erase(i).error; return erase(i).error;

View File

@@ -37,7 +37,7 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept; GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept;
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept; void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept;
void applySpriteUpdates() noexcept; void applySpriteUpdates() noexcept;

View File

@@ -2,6 +2,8 @@
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#ifdef __GNUC__
#include <ox/std/heapmgr.hpp> #include <ox/std/heapmgr.hpp>
#include <teagba/bios.hpp> #include <teagba/bios.hpp>
@@ -24,7 +26,7 @@ extern void (*__preinit_array_end[]) (void);
extern void (*__init_array_start[]) (void); extern void (*__init_array_start[]) (void);
extern void (*__init_array_end[]) (void); extern void (*__init_array_end[]) (void);
int main(int argc, const char **argv); int main(int argc, char const **argv);
extern "C" { extern "C" {
@@ -48,7 +50,7 @@ void __libc_init_array() {
} }
int c_start() { int c_start() {
const char *args[2] = {"", "rom.oxfs"}; char const *args[2] = {"", "rom.oxfs"};
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END); ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
mgba::initConsole(); mgba::initConsole();
#pragma GCC diagnostic push #pragma GCC diagnostic push
@@ -58,3 +60,5 @@ int c_start() {
} }
} }
#endif

View File

@@ -16,7 +16,7 @@ GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
return g_spriteBuffer[i]; return g_spriteBuffer[i];
} }
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept { void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept {
const auto ie = REG_IE; // disable vblank interrupt handler const auto ie = REG_IE; // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
g_spriteBuffer[upd.idx] = upd; g_spriteBuffer[upd.idx] = upd;

View File

@@ -1,3 +1,20 @@
# d2025.06.0
* Add ability to remember recent projects in config
* Add navigation support (back and forward)
* Fix file deletion to close file even if not active
* Fix file copy to work when creating a copy with the name of a previously
deleted file
* Fix crash that could occur after switching projects
* Make file picker popup accept on double click of a file
* TileSheetEditor: Fix copy/cut/paste enablement when there is no selection
* TileSheetEditor: Fix manual redo of draw actions, fix drawing to pixel 0, 0
as first action
* TileSheetEditor: Fix draw command to work on same pixel after switching
subsheets
* PaletteEditor: Add RGB key shortcuts for focusing color channels
* PaletteEditor: Add color preview to color editor
# d2025.05.1 # d2025.05.1
* TileSheetEditor: Fix overrun errors when switching subsheets, clear selection * TileSheetEditor: Fix overrun errors when switching subsheets, clear selection
@@ -10,16 +27,17 @@
* Change application font to Roboto Medium * Change application font to Roboto Medium
* Closing application will now confirm with user if any files have unsaved * Closing application will now confirm with user if any files have unsaved
changes. changes.
* UUID duplicates will now be reported when opening a project * UUID duplicates will now be reported when opening a project.
* Deleting a directory now closes files in that directory * Deleting a directory now closes files in that directory.
* Delete key now initiates deletion of selected directory * Delete key now initiates deletion of selected directory.
* Remove ability to re-order tabs. There were bugs associated with that. * Remove ability to re-order tabs. There were bugs associated with that.
* TileSheetEditor: Fix selection clearing in to work when clicking outside * Mac: Menu bar shortcuts now say Cmd instead of Ctrl.
image. * TileSheetEditor: Fix selection clearing to work when clicking outside image.
* TileSheetEditor: Fix Delete Tile functionality, which was completely broken * TileSheetEditor: Fix Delete Tile functionality, which was completely broken
* PaletteEditor: Fix color number key range in. Previously, pressing A caused * TileSheetEditor: Fix Insert Tile functionality, which was completely broken
the editor to jump to the last color. * PaletteEditor: Fix color number key range. Previously, pressing A caused the
* PaletteEditor: page rename will now take effect upon pressing enter if the editor to jump to the last color.
* PaletteEditor: Page rename will now take effect upon pressing enter if the
text input has focus text input has focus
# d2025.02.1 # d2025.02.1

View File

@@ -19,10 +19,10 @@ using Color32 = uint32_t;
[[nodiscard]] [[nodiscard]]
constexpr Color32 toColor32(Color16 nc) noexcept { constexpr Color32 toColor32(Color16 nc) noexcept {
const auto r = static_cast<Color32>(((nc & 0b0000000000011111) >> 0) * 8); auto const r = static_cast<Color32>(((nc & 0b0000000000011111) >> 0) * 8);
const auto g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8); auto const g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8);
const auto b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8); auto const b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8);
const auto a = static_cast<Color32>(255); auto const a = static_cast<Color32>(255);
return r | (g << 8) | (b << 16) | (a << 24); return r | (g << 8) | (b << 16) | (a << 24);
} }

View File

@@ -12,8 +12,18 @@ constexpr auto TileWidth = 8;
constexpr auto TileHeight = 8; constexpr auto TileHeight = 8;
constexpr auto PixelsPerTile = TileWidth * TileHeight; constexpr auto PixelsPerTile = TileWidth * TileHeight;
constexpr ox::StringLiteral FileExt_ng("ng"); constexpr ox::StringLiteral FileExt_ng{"ng"};
constexpr ox::StringLiteral FileExt_nts("nts"); constexpr ox::StringLiteral FileExt_nts{"nts"};
constexpr ox::StringLiteral FileExt_npal("npal"); constexpr ox::StringLiteral FileExt_npal{"npal"};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_TileSheet{
FileExt_nts,
FileExt_ng,
};
[[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return endsWith(path, FileExt_nts) || endsWith(path, FileExt_ng);
}
} }

View File

@@ -8,16 +8,12 @@
#include <turbine/context.hpp> #include <turbine/context.hpp>
#include "initparams.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
class Context; class Context;
void safeDelete(Context *ctx) noexcept; void safeDelete(Context *ctx) noexcept;
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params = {}) noexcept;
keel::Context &keelCtx(Context &ctx) noexcept; keel::Context &keelCtx(Context &ctx) noexcept;
turbine::Context &turbineCtx(Context &ctx) noexcept; turbine::Context &turbineCtx(Context &ctx) noexcept;

View File

@@ -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"

View File

@@ -9,8 +9,11 @@
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/model/def.hpp> #include <ox/model/def.hpp>
#include "color.hpp"
#include "context.hpp" #include "context.hpp"
#include "keelmodule.hpp"
#include "palette.hpp" #include "palette.hpp"
#include "ptidxconv.hpp"
#include "tilesheet.hpp" #include "tilesheet.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
@@ -102,11 +105,19 @@ OX_MODEL_BEGIN(TileSheetSet)
OX_MODEL_FIELD(entries) OX_MODEL_FIELD(entries)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] struct InitParams {
int tileColumns(Context&) noexcept; bool glInstallDrawer = true;
uint_t glSpriteCount = 128;
uint_t glBlocksPerSprite = 64;
};
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params = {}) noexcept;
[[nodiscard]] [[nodiscard]]
int tileRows(Context&) noexcept; int tileColumns(Context const&) noexcept;
[[nodiscard]]
int tileRows(Context const&) noexcept;
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
@@ -223,7 +234,7 @@ bool bgStatus(Context &ctx, unsigned bg) noexcept;
void setBgStatus(Context &ctx, unsigned bg, bool status) noexcept; void setBgStatus(Context &ctx, unsigned bg, bool status) noexcept;
void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept; void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbbIdx) noexcept;
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept; void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
@@ -231,10 +242,10 @@ void hideSprite(Context &ctx, unsigned) noexcept;
void showSprite(Context &ctx, unsigned) noexcept; void showSprite(Context &ctx, unsigned) noexcept;
void setSprite(Context &c, uint_t idx, Sprite const&s) noexcept; void setSprite(Context &ctx, uint_t idx, Sprite const &sprite) noexcept;
[[nodiscard]] [[nodiscard]]
uint_t spriteCount(Context &ctx) noexcept; uint_t spriteCount(Context const &ctx) noexcept;
ox::Error initConsole(Context &ctx) noexcept; ox::Error initConsole(Context &ctx) noexcept;

View File

@@ -1,17 +0,0 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/types.hpp>
namespace nostalgia::gfx {
struct InitParams {
bool glInstallDrawer = true;
uint_t glSpriteCount = 128;
uint_t glBlocksPerSprite = 64;
};
}

View File

@@ -8,6 +8,6 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
const keel::Module *keelModule() noexcept; keel::Module const *keelModule() noexcept;
} }

View File

@@ -12,15 +12,15 @@ namespace nostalgia::gfx {
[[nodiscard]] [[nodiscard]]
constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept { constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept {
const auto tileWidth = TileWidth * scale; auto const tileWidth = TileWidth * scale;
const auto tileHeight = TileHeight * scale; auto const tileHeight = TileHeight * scale;
const auto pixelsPerTile = tileWidth * tileHeight; auto const pixelsPerTile = tileWidth * tileHeight;
const auto colLength = static_cast<std::size_t>(pixelsPerTile); auto const colLength = static_cast<std::size_t>(pixelsPerTile);
const auto rowLength = static_cast<std::size_t>(static_cast<std::size_t>(c / tileWidth) * colLength); auto const rowLength = static_cast<std::size_t>(static_cast<std::size_t>(c / tileWidth) * colLength);
const auto colStart = static_cast<std::size_t>(colLength * static_cast<std::size_t>(x / tileWidth)); auto const colStart = static_cast<std::size_t>(colLength * static_cast<std::size_t>(x / tileWidth));
const auto rowStart = static_cast<std::size_t>(rowLength * static_cast<std::size_t>(y / tileHeight)); auto const rowStart = static_cast<std::size_t>(rowLength * static_cast<std::size_t>(y / tileHeight));
const auto colOffset = static_cast<std::size_t>(x % tileWidth); auto const colOffset = static_cast<std::size_t>(x % tileWidth);
const auto rowOffset = static_cast<std::size_t>((y % tileHeight) * tileHeight); auto const rowOffset = static_cast<std::size_t>((y % tileHeight) * tileHeight);
return static_cast<std::size_t>(colStart + colOffset + rowStart + rowOffset); return static_cast<std::size_t>(colStart + colOffset + rowStart + rowOffset);
} }
@@ -31,19 +31,19 @@ constexpr std::size_t ptToIdx(const ox::Point &pt, int c, int scale = 1) noexcep
[[nodiscard]] [[nodiscard]]
constexpr ox::Point idxToPt(int i, int c, int scale = 1) noexcept { constexpr ox::Point idxToPt(int i, int c, int scale = 1) noexcept {
const auto tileWidth = TileWidth * scale; auto const tileWidth = TileWidth * scale;
const auto tileHeight = TileHeight * scale; auto const tileHeight = TileHeight * scale;
const auto pixelsPerTile = tileWidth * tileHeight; auto const pixelsPerTile = tileWidth * tileHeight;
// prevent divide by zeros // prevent divide by zeros
if (!c) { if (!c) {
++c; ++c;
} }
const auto t = i / pixelsPerTile; // tile number auto const t = i / pixelsPerTile; // tile number
const auto iti = i % pixelsPerTile; // in tile index auto const iti = i % pixelsPerTile; // in tile index
const auto tc = t % c; // tile column auto const tc = t % c; // tile column
const auto tr = t / c; // tile row auto const tr = t / c; // tile row
const auto itx = iti % tileWidth; // in tile x auto const itx = iti % tileWidth; // in tile x
const auto ity = iti / tileHeight; // in tile y auto const ity = iti / tileHeight; // in tile y
return { return {
itx + tc * tileWidth, itx + tc * tileWidth,
ity + tr * tileHeight, ity + tr * tileHeight,

View File

@@ -6,6 +6,28 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
namespace nostalgia::core { #include "tilesheet.hpp"
namespace nostalgia::gfx {
inline void navigateToTileSheet(
studio::Context &ctx, ox::StringParam path, SubSheetId const subsheetId) noexcept {
studio::navigateTo(ctx, std::move(path), ox::intToStr(subsheetId));
}
inline void navigateToPalette(studio::Context &ctx, ox::StringParam path) noexcept {
studio::navigateTo(ctx, std::move(path));
}
inline void navigateToPalette(
studio::Context &ctx,
ox::StringParam path,
size_t const colorIdx,
size_t const palPage) noexcept {
studio::navigateTo(
ctx,
std::move(path),
ox::sfmt("{};{}", colorIdx, palPage));
}
} }

View File

@@ -8,6 +8,6 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
const studio::Module *studioModule() noexcept; studio::Module const *studioModule() noexcept;
} }

View File

@@ -336,7 +336,7 @@ struct TileSheetV5 {
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept { constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept {
if (ss.subsheets.empty()) { if (ss.subsheets.empty()) {
return static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) == ss.pixels.size(); return std::cmp_equal(ss.columns * ss.rows * PixelsPerTile, ss.pixels.size());
} else { } else {
return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[](TileSheetV5::SubSheet const&s) { [](TileSheetV5::SubSheet const&s) {
@@ -426,6 +426,8 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubSheetIdx idx) noexcept; TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubSheetIdx idx) noexcept;
ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId pId) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet &getSubSheet( TileSheet::SubSheet &getSubSheet(
ox::SpanView<uint32_t> const&idx, ox::SpanView<uint32_t> const&idx,

View File

@@ -4,11 +4,6 @@ add_library(
tilesheet.cpp tilesheet.cpp
) )
add_subdirectory(gba)
if(NOT BUILDCORE_TARGET STREQUAL "gba")
add_subdirectory(opengl)
endif()
target_include_directories( target_include_directories(
NostalgiaGfx PUBLIC NostalgiaGfx PUBLIC
../include ../include
@@ -31,3 +26,38 @@ install(
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE 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()

View File

@@ -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()

View File

@@ -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&params) noexcept {
auto ctx = ox::make_unique<Context>(tctx);
OX_RETURN_ERROR(initGfx(*ctx, params));
return ox::UPtr<Context>(std::move(ctx));
}
keel::Context &keelCtx(Context &ctx) noexcept {
return turbine::keelCtx(ctx.turbineCtx);
}
turbine::Context &turbineCtx(Context &ctx) noexcept {
return ctx.turbineCtx;
}
}

View File

@@ -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));
}
};
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -15,15 +15,48 @@
#include <nostalgia/gfx/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/gfx/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
#include "context.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace nostalgia::gfx { 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; static constexpr auto SpriteCount = 128;
ox::Error initGfx(Context&, InitParams const&) noexcept { static ox::Error initGfx() noexcept {
for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) { for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) {
teagba::bgSetSbb(*bgCtl, 28); teagba::bgSetSbb(*bgCtl, 28);
} }
@@ -34,11 +67,17 @@ ox::Error initGfx(Context&, InitParams const&) noexcept {
return {}; 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( ox::Error loadBgPalette(
Context&, Context&,
size_t palBank, size_t const palBank,
CompactPalette const &palette, CompactPalette const &palette,
size_t page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
@@ -52,7 +91,7 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context&, Context&,
CompactPalette const &palette, CompactPalette const &palette,
size_t page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
@@ -133,7 +172,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
CompactTileSheet const &ts, CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const &paletteBank) noexcept {
auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4)); auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
@@ -184,7 +223,7 @@ static void setSpritesBpp(unsigned const bpp) noexcept {
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const &ts, CompactTileSheet const &ts,
bool loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
for (size_t i = 0; i < ts.pixels.size(); i += 2) { for (size_t i = 0; i < ts.pixels.size(); i += 2) {
uint16_t v = ts.pixels[i]; uint16_t v = ts.pixels[i];
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8); v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
@@ -206,7 +245,12 @@ ox::Error loadSpriteTileSheet(
return {}; return {};
} }
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept { void setBgTile(
Context &ctx,
uint_t const bgIdx,
int const column,
int const row,
BgTile const &tile) noexcept {
auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column); auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column);
// see Tonc 9.3 // see Tonc 9.3
MEM_BG_MAP[bgIdx][tileIdx] = MEM_BG_MAP[bgIdx][tileIdx] =
@@ -216,7 +260,7 @@ void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&til
static_cast<uint16_t>(tile.palBank << 0xc); static_cast<uint16_t>(tile.palBank << 0xc);
} }
void clearBg(Context &ctx, uint_t bgIdx) noexcept { void clearBg(Context &ctx, uint_t const bgIdx) noexcept {
memset(MEM_BG_MAP[bgIdx].data(), 0, static_cast<size_t>(tileRows(ctx) * tileColumns(ctx))); memset(MEM_BG_MAP[bgIdx].data(), 0, static_cast<size_t>(tileRows(ctx) * tileColumns(ctx)));
} }
@@ -224,39 +268,39 @@ uint8_t bgStatus(Context&) noexcept {
return (REG_DISPCTL >> 8u) & 0b1111u; return (REG_DISPCTL >> 8u) & 0b1111u;
} }
void setBgStatus(Context&, uint32_t status) noexcept { void setBgStatus(Context&, uint32_t const status) noexcept {
constexpr auto BgStatus = 8; constexpr auto BgStatus = 8;
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus; REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus;
} }
bool bgStatus(Context&, unsigned bg) noexcept { bool bgStatus(Context&, unsigned const bg) noexcept {
return (REG_DISPCTL >> (8 + bg)) & 1; return (REG_DISPCTL >> (8 + bg)) & 1;
} }
void setBgStatus(Context&, unsigned bg, bool status) noexcept { void setBgStatus(Context&, unsigned const bg, bool const status) noexcept {
constexpr auto Bg0Status = 8; constexpr auto Bg0Status = 8;
const auto mask = static_cast<uint32_t>(status) << (Bg0Status + bg); auto const mask = static_cast<uint32_t>(status) << (Bg0Status + bg);
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask); REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
} }
void setBgBpp(Context&, unsigned bgIdx, unsigned bpp) noexcept { void setBgBpp(Context&, unsigned const bgIdx, unsigned const bpp) noexcept {
auto &bgCtl = regBgCtl(bgIdx); auto &bgCtl = regBgCtl(bgIdx);
teagba::bgSetBpp(bgCtl, bpp); teagba::bgSetBpp(bgCtl, bpp);
} }
void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept { void setBgCbb(Context &ctx, unsigned const bgIdx, unsigned const cbbIdx) noexcept {
auto &bgCtl = regBgCtl(bgIdx); auto &bgCtl = regBgCtl(bgIdx);
const auto &cbbData = ctx.cbbData[cbb]; auto const &cbbData = ctx.cbbData[cbbIdx];
teagba::bgSetBpp(bgCtl, cbbData.bpp); teagba::bgSetBpp(bgCtl, cbbData.bpp);
teagba::bgSetCbb(bgCtl, cbb); teagba::bgSetCbb(bgCtl, cbbIdx);
} }
void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept { void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept {
auto &bgCtl = regBgCtl(bgIdx); auto &bgCtl = regBgCtl(bgIdx);
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11); bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
} }
void hideSprite(Context&, unsigned idx) noexcept { void hideSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
.attr0 = uint16_t{0b11 << 8}, .attr0 = uint16_t{0b11 << 8},
@@ -264,7 +308,7 @@ void hideSprite(Context&, unsigned idx) noexcept {
}); });
} }
void showSprite(Context&, unsigned idx) noexcept { void showSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
.attr0 = 0, .attr0 = 0,
@@ -272,7 +316,7 @@ void showSprite(Context&, unsigned idx) noexcept {
}); });
} }
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept { void setSprite(Context&, uint_t const idx, Sprite const &s) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
uint16_t const eightBpp = s.bpp == 8; uint16_t const eightBpp = s.bpp == 8;
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
@@ -293,10 +337,49 @@ void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
}); });
} }
uint_t spriteCount(Context&) noexcept { uint_t spriteCount(Context const &) noexcept {
return SpriteCount; return SpriteCount;
} }
} }
namespace ox {
void panic(char const *file, int line, char const *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
auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN);
auto const heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2;
auto const 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 OX_ALLOW_UNSAFE_BUFFERS_END

View File

@@ -4,7 +4,6 @@
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <ox/std/fmt.hpp> #include <ox/std/fmt.hpp>
#include <ox/std/vec.hpp>
#include <keel/media.hpp> #include <keel/media.hpp>
@@ -15,22 +14,105 @@
#include <nostalgia/gfx/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
#include "context.hpp"
#include "gfx.hpp"
namespace nostalgia::gfx { 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 &params) 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 { namespace renderer {
static constexpr auto Scale = 1; static constexpr auto Scale = 1;
static constexpr auto PriorityScale = 0.01f; static constexpr auto PriorityScale = 0.01f;
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
void Drawer::draw(turbine::Context &tctx) noexcept {
gfx::gl::draw(m_ctx, turbine::getScreenSize(tctx));
}
static constexpr ox::CStringView bgvshadTmpl = R"glsl( static constexpr ox::CStringView bgvshadTmpl = R"glsl(
{} {}
in vec2 vTexCoord; in vec2 vTexCoord;
@@ -106,7 +188,7 @@ static constexpr ox::CStringView spritefshadTmpl = R"glsl(
})glsl"; })glsl";
[[nodiscard]] [[nodiscard]]
static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept { static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept {
return y * TileRows + x; return y * TileRows + x;
} }
@@ -183,7 +265,7 @@ static void setTileBufferObject(
ox::spancpy<GLuint>(ebo, elms); ox::spancpy<GLuint>(ebo, elms);
} }
static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept { static void initSpriteBufferObjects(Context const &ctx, glutils::BufferSet &bs) noexcept {
for (auto i = 0u; i < ctx.spriteCount; ++i) { for (auto i = 0u; i < ctx.spriteCount; ++i) {
auto const vbo = ox::Span{bs.vertices} auto const vbo = ox::Span{bs.vertices}
+ i * static_cast<std::size_t>(SpriteVertexVboLength); + i * static_cast<std::size_t>(SpriteVertexVboLength);
@@ -205,7 +287,7 @@ static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexce
static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept { static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
for (auto x = 0u; x < TileColumns; ++x) { for (auto x = 0u; x < TileColumns; ++x) {
for (auto y = 0u; y < TileRows; ++y) { for (auto y = 0u; y < TileRows; ++y) {
const auto i = bgVertexRow(x, y); auto const i = bgVertexRow(x, y);
auto const vbo = ox::Span{bs.vertices} auto const vbo = ox::Span{bs.vertices}
+ i * static_cast<std::size_t>(BgVertexVboLength); + i * static_cast<std::size_t>(BgVertexVboLength);
auto const ebo = ox::Span{bs.elements} auto const ebo = ox::Span{bs.elements}
@@ -241,7 +323,13 @@ static void initSpritesBufferset(Context &ctx) noexcept {
// in float vEnabled; // in float vEnabled;
auto const enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled")); auto const enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled"));
glEnableVertexAttribArray(enabledAttr); 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; // in vec3 vPosition;
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition")); auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
glEnableVertexAttribArray(posAttr); glEnableVertexAttribArray(posAttr);
@@ -250,13 +338,14 @@ static void initSpritesBufferset(Context &ctx) noexcept {
// in vec2 vTexCoord; // in vec2 vTexCoord;
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord")); auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
glEnableVertexAttribArray(texCoordAttr); glEnableVertexAttribArray(texCoordAttr);
glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float), glVertexAttribPointer(
texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
std::bit_cast<void*>(uintptr_t{4 * sizeof(float)})); std::bit_cast<void*>(uintptr_t{4 * sizeof(float)}));
glBindVertexArray(0); glBindVertexArray(0);
} }
static void initBackgroundBufferset( static void initBackgroundBufferset(
GLuint shader, GLuint const shader,
glutils::BufferSet &bs) noexcept { glutils::BufferSet &bs) noexcept {
// vao // vao
bs.vao = glutils::generateVertexArrayObject(); bs.vao = glutils::generateVertexArrayObject();
@@ -270,7 +359,13 @@ static void initBackgroundBufferset(
// vbo layout // vbo layout
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition")); auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
glEnableVertexAttribArray(posAttr); 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")); auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
glEnableVertexAttribArray(texCoordAttr); glEnableVertexAttribArray(texCoordAttr);
glVertexAttribPointer( glVertexAttribPointer(
@@ -290,8 +385,8 @@ static void initBackgroundBufferset(
} }
static glutils::GLTexture createTexture( static glutils::GLTexture createTexture(
GLsizei w, GLsizei const w,
GLsizei h, GLsizei const h,
void const *pixels) noexcept { void const *pixels) noexcept {
GLuint texId = 0; GLuint texId = 0;
glGenTextures(1, &texId); glGenTextures(1, &texId);
@@ -300,7 +395,16 @@ static glutils::GLTexture createTexture(
tex.height = h; tex.height = h;
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex.id); 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_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -324,19 +428,19 @@ static void drawBackgrounds(
ox::Size const &renderSz) noexcept { ox::Size const &renderSz) noexcept {
// load background shader and its uniforms // load background shader and its uniforms
glUseProgram(ctx.bgShader); glUseProgram(ctx.bgShader);
const auto uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz"); auto const uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz");
const auto uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale")); auto const uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale"));
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight")); auto const uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight"));
const auto uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx")); auto const uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx"));
const auto [wi, hi] = renderSz; auto const [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi); auto const wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi); auto const hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf); glUniform1f(uniformXScale, hf / wf);
auto bgIdx = 0.f; auto bgIdx = 0.f;
for (const auto &bg : ctx.backgrounds) { for (auto const &bg : ctx.backgrounds) {
if (bg.enabled) { if (bg.enabled) {
auto &cbb = ctx.cbbs[bg.cbbIdx]; auto &cbb = ctx.cbbs[bg.cbbIdx];
const auto tileRows = cbb.tex.height / (TileHeight * Scale); auto const tileRows = cbb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows)); glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
glUniform2f( glUniform2f(
uniformSrcImgSz, uniformSrcImgSz,
@@ -352,11 +456,11 @@ static void drawBackgrounds(
static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept { static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
glUseProgram(ctx.spriteShader); glUseProgram(ctx.spriteShader);
auto &sb = ctx.spriteBlocks; auto &sb = ctx.spriteBlocks;
const auto uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale"); auto const uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
const auto uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight"); auto const uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight");
const auto [wi, hi] = renderSz; auto const [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi); auto const wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi); auto const hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf); glUniform1f(uniformXScale, hf / wf);
// update vbo // update vbo
glBindVertexArray(sb.vao); glBindVertexArray(sb.vao);
@@ -365,7 +469,7 @@ static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
glutils::sendVbo(sb); glutils::sendVbo(sb);
} }
// set vTileHeight uniform // set vTileHeight uniform
const auto tileRows = sb.tex.height / (TileHeight * Scale); auto const tileRows = sb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows)); glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
// draw // draw
glBindTexture(GL_TEXTURE_2D, sb.tex); glBindTexture(GL_TEXTURE_2D, sb.tex);
@@ -375,10 +479,10 @@ static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
static void loadPalette( static void loadPalette(
ox::Array<GLfloat, 1024> &palette, ox::Array<GLfloat, 1024> &palette,
size_t palOffset, size_t const palOffset,
GLuint shaderPgrm, GLuint const shaderPgrm,
CompactPalette const&pal, CompactPalette const&pal,
size_t page = 0) noexcept { size_t const page = 0) noexcept {
static constexpr std::size_t ColorCnt = 256; static constexpr std::size_t ColorCnt = 256;
for (auto i = palOffset; auto const c : pal.pages[page]) { for (auto i = palOffset; auto const c : pal.pages[page]) {
palette[i++] = redf(c); palette[i++] = redf(c);
@@ -389,7 +493,7 @@ static void loadPalette(
// make first color transparent // make first color transparent
palette[palOffset + 3] = 0; palette[palOffset + 3] = 0;
glUseProgram(shaderPgrm); glUseProgram(shaderPgrm);
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette")); auto const uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
glUniform4fv(uniformPalette, ColorCnt, palette.data()); glUniform4fv(uniformPalette, ColorCnt, palette.data());
} }
@@ -422,12 +526,12 @@ static void setSprite(
auto const uY = static_cast<int>(s.y + 8) % 255 - 8; auto const uY = static_cast<int>(s.y + 8) % 255 - 8;
oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow"); oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow");
oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow"); oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow");
const auto spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength; auto const spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength;
const auto spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength; auto const spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength;
auto const vboBase = spriteVboSz * idx; auto const vboBase = spriteVboSz * idx;
auto const eboBase = spriteEboSz * idx; auto const eboBase = spriteEboSz * idx;
auto i = 0u; auto i = 0u;
const auto set = [&](int xIt, int yIt, bool enabled) { auto const set = [&](int xIt, int yIt, bool enabled) {
auto const fX = static_cast<float>(uX + xIt * 8) / 8; auto const fX = static_cast<float>(uX + xIt * 8) / 8;
auto const fY = static_cast<float>(uY + yIt * 8) / 8; auto const fY = static_cast<float>(uY + yIt * 8) / 8;
auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i; auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i;
@@ -470,28 +574,23 @@ static void setSprite(
} }
ox::Error initGfx( ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params) noexcept {
Context &ctx, auto ctx = ox::make_unique<Context>(tctx, params);
InitParams const&initParams) noexcept { auto const bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion); auto const bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion); auto const spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion); auto const spriteFshad = ox::sfmt(renderer::spritefshadTmpl, 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( OX_RETURN_ERROR(
glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx.spriteShader)); glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx->spriteShader));
for (auto &cbb : ctx.cbbs) { for (auto &cbb : ctx->cbbs) {
initBackgroundBufferset(ctx.bgShader, cbb); initBackgroundBufferset(ctx->bgShader, cbb);
} }
renderer::initSpritesBufferset(ctx); renderer::initSpritesBufferset(*ctx);
if (initParams.glInstallDrawer) { if (params.glInstallDrawer) {
turbine::gl::addDrawer(ctx.turbineCtx, &ctx.drawer); turbine::gl::addDrawer(ctx->turbineCtx, &ctx->drawer);
} }
return {}; return ctx;
}
void shutdownGfx(Context &ctx) noexcept {
turbine::gl::removeDrawer(ctx.turbineCtx, &ctx.drawer);
} }
struct TileSheetData { struct TileSheetData {
@@ -504,12 +603,12 @@ struct TileSheetData {
} }
}; };
static ox::Result<TileSheetData> normalizeTileSheet( static ox::Result<TileSheetData> normalizeTileSheet
CompactTileSheet const&ts) noexcept { (CompactTileSheet const&ts) noexcept {
const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2; const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
const auto tiles = ts.pixels.size() / bytesPerTile; auto const tiles = ts.pixels.size() / bytesPerTile;
constexpr int width = 8; constexpr int width = 8;
const int height = 8 * static_cast<int>(tiles); int const height = 8 * static_cast<int>(tiles);
ox::Vector<uint32_t> pixels; ox::Vector<uint32_t> pixels;
if (bytesPerTile == 64) { // 8 BPP if (bytesPerTile == 64) { // 8 BPP
pixels.resize(ts.pixels.size()); pixels.resize(ts.pixels.size());
@@ -523,14 +622,18 @@ static ox::Result<TileSheetData> normalizeTileSheet(
pixels[i * 2 + 1] = ts.pixels[i] >> 4; pixels[i * 2 + 1] = ts.pixels[i] >> 4;
} }
} }
return TileSheetData{std::move(pixels), width, height}; return TileSheetData{
.pixels = std::move(pixels),
.width = width,
.height = height
};
} }
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t const palBank,
CompactPalette const&palette, CompactPalette const&palette,
size_t page) noexcept { size_t const page) noexcept {
renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page); renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page);
return {}; return {};
} }
@@ -538,14 +641,14 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
CompactPalette const&palette, CompactPalette const&palette,
size_t page) noexcept { size_t const page) noexcept {
ox::Array<GLfloat, 1024> pal; ox::Array<GLfloat, 1024> pal;
renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page); renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page);
return {}; return {};
} }
static ox::Result<TileSheetData> buildSetTsd( static ox::Result<TileSheetData> buildSetTsd(
Context &ctx, Context const &ctx,
TileSheetSet const&set) noexcept { TileSheetSet const&set) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx); auto &kctx = keelCtx(ctx.turbineCtx);
TileSheetData setTsd; TileSheetData setTsd;
@@ -567,7 +670,7 @@ static ox::Result<TileSheetData> buildSetTsd(
static void copyPixels( static void copyPixels(
CompactTileSheet const&ts, CompactTileSheet const&ts,
ox::Span<uint32_t> dst, ox::Span<uint32_t> const dst,
size_t const srcPxIdx, size_t const srcPxIdx,
size_t const pxlCnt) noexcept { size_t const pxlCnt) noexcept {
size_t idx{}; size_t idx{};
@@ -624,7 +727,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
uint_t cbb, uint_t const cbb,
CompactTileSheet const&ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4))); auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
@@ -638,7 +741,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
TileSheetSet const&set) noexcept { TileSheetSet const&set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set)); OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data()); ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
@@ -648,7 +751,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const&ts, CompactTileSheet const&ts,
bool loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
OX_REQUIRE(tsd, normalizeTileSheet(ts)); OX_REQUIRE(tsd, normalizeTileSheet(ts));
oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height); oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data()); ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
@@ -668,21 +771,21 @@ ox::Error loadSpriteTileSheet(
void setBgTile( void setBgTile(
Context &ctx, Context &ctx,
uint_t bgIdx, uint_t const bgIdx,
int column, int const column,
int row, int const row,
BgTile const&tile) noexcept { BgTile const&tile) noexcept {
oxTracef( oxTracef(
"nostalgia.gfx.setBgTile", "nostalgia.gfx.setBgTile",
"bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}", "bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}",
bgIdx, column, row, tile.tileIdx, tile.palBank); bgIdx, column, row, tile.tileIdx, tile.palBank);
const auto z = static_cast<uint_t>(bgIdx); auto const z = static_cast<uint_t>(bgIdx);
const auto y = static_cast<uint_t>(row); auto const y = static_cast<uint_t>(row);
const auto x = static_cast<uint_t>(column); auto const x = static_cast<uint_t>(column);
const auto i = renderer::bgVertexRow(x, y); auto const i = renderer::bgVertexRow(x, y);
auto &cbb = ctx.cbbs[z]; auto &cbb = ctx.cbbs[z];
const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength; auto const vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength; auto const ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
auto &bg = ctx.backgrounds[bgIdx]; auto &bg = ctx.backgrounds[bgIdx];
renderer::setTileBufferObject( renderer::setTileBufferObject(
static_cast<uint_t>(i * renderer::BgVertexVboRows), static_cast<uint_t>(i * renderer::BgVertexVboRows),
@@ -698,7 +801,7 @@ void setBgTile(
cbb.updated = true; cbb.updated = true;
} }
void clearBg(Context &ctx, uint_t bgIdx) noexcept { void clearBg(Context &ctx, uint_t const bgIdx) noexcept {
auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)]; auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
initBackgroundBufferObjects(cbb); initBackgroundBufferObjects(cbb);
cbb.updated = true; cbb.updated = true;
@@ -714,61 +817,59 @@ uint8_t bgStatus(Context &ctx) noexcept {
return out; return out;
} }
void setBgStatus(Context &ctx, uint32_t status) noexcept { void setBgStatus(Context &ctx, uint32_t const status) noexcept {
for (uint_t i = 0; i < ctx.cbbs.size(); ++i) { for (uint_t i = 0; i < ctx.cbbs.size(); ++i) {
ctx.backgrounds[i].enabled = (status >> i) & 1; ctx.backgrounds[i].enabled = (status >> i) & 1;
} }
} }
bool bgStatus(Context &ctx, uint_t bg) noexcept { bool bgStatus(Context &ctx, uint_t const bg) noexcept {
return ctx.backgrounds[bg].enabled; return ctx.backgrounds[bg].enabled;
} }
void setBgStatus(Context&ctx, uint_t bg, bool status) noexcept { void setBgStatus(Context&ctx, uint_t const bg, bool const status) noexcept {
ctx.backgrounds[bg].enabled = status; ctx.backgrounds[bg].enabled = status;
} }
void setBgBpp(Context&, unsigned, unsigned) noexcept {} void setBgCbb(Context &ctx, uint_t const bgIdx, uint_t const cbbIdx) noexcept {
void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept {
auto &bg = ctx.backgrounds[bgIdx]; auto &bg = ctx.backgrounds[bgIdx];
bg.cbbIdx = cbbIdx; bg.cbbIdx = cbbIdx;
} }
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept { void setBgPriority(Context &ctx, uint_t const bgIdx, uint_t const priority) noexcept {
auto &bg = ctx.backgrounds[bgIdx]; auto &bg = ctx.backgrounds[bgIdx];
bg.priority = static_cast<float>(priority & 0b11); bg.priority = static_cast<float>(priority & 0b11);
} }
void hideSprite(Context &ctx, uint_t idx) noexcept { void hideSprite(Context &ctx, uint_t const idx) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s.enabled = false; s.enabled = false;
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
} }
void showSprite(Context &ctx, uint_t idx) noexcept { void showSprite(Context &ctx, uint_t const idx) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s.enabled = true; s.enabled = true;
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
} }
void setSprite(Context &ctx, uint_t idx, Sprite const&sprite) noexcept { void setSprite(Context &ctx, uint_t const idx, Sprite const&sprite) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s = sprite; s = sprite;
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
} }
uint_t spriteCount(Context &ctx) noexcept { uint_t spriteCount(Context const &ctx) noexcept {
return ctx.spriteCount; return ctx.spriteCount;
} }
namespace gl { namespace gl {
ox::Size drawSize(int scale) noexcept { ox::Size drawSize(int const scale) noexcept {
return {240 * scale, 160 * scale}; return {240 * scale, 160 * scale};
} }
void draw(gfx::Context &ctx, ox::Size const&renderSz) noexcept { void draw(Context &ctx, ox::Size const&renderSz) noexcept {
glViewport(0, 0, renderSz.width, renderSz.height); glViewport(0, 0, renderSz.width, renderSz.height);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND); glEnable(GL_BLEND);
@@ -783,7 +884,7 @@ void draw(gfx::Context &ctx, ox::Size const&renderSz) noexcept {
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
void draw(gfx::Context &ctx, int scale) noexcept { void draw(Context &ctx, int const scale) noexcept {
draw(ctx, drawSize(scale)); draw(ctx, drawSize(scale));
} }

View File

@@ -10,17 +10,17 @@ namespace nostalgia::gfx {
constexpr auto GbaTileColumns = 32; constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32; constexpr auto GbaTileRows = 32;
int tileColumns(Context&) noexcept { int tileColumns(Context const&) noexcept {
return GbaTileColumns; return GbaTileColumns;
} }
int tileRows(Context&) noexcept { int tileRows(Context const&) noexcept {
return GbaTileRows; return GbaTileRows;
} }
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t const palBank,
ox::StringViewCR palettePath) noexcept { ox::StringViewCR palettePath) noexcept {
OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath)); OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), palettePath));
return loadBgPalette(ctx, palBank, *pal, 0); return loadBgPalette(ctx, palBank, *pal, 0);
@@ -28,7 +28,7 @@ ox::Error loadBgPalette(
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t const palBank,
ox::FileAddress const &paletteAddr) noexcept { ox::FileAddress const &paletteAddr) noexcept {
OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr)); OX_REQUIRE(pal, keel::readObj<CompactPalette>(keelCtx(ctx), paletteAddr));
return loadBgPalette(ctx, palBank, *pal, 0); return loadBgPalette(ctx, palBank, *pal, 0);
@@ -50,11 +50,11 @@ ox::Error loadSpritePalette(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
ox::FileAddress const &tsAddr, ox::FileAddress const &tsAddr,
size_t dstTileIdx, size_t const dstTileIdx,
size_t srcTileIdx, size_t const srcTileIdx,
size_t tileCnt) noexcept { size_t const tileCnt) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsAddr)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsAddr));
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt); return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
} }
@@ -63,16 +63,16 @@ ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::StringViewCR tsPath, ox::StringViewCR tsPath,
size_t dstTileIdx, size_t const dstTileIdx,
size_t srcTileIdx, size_t const srcTileIdx,
size_t tileCnt) noexcept { size_t const tileCnt) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsPath)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tsPath));
return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt); return loadBgTileSheet(ctx, cbb, *ts, dstTileIdx, srcTileIdx, tileCnt);
} }
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
ox::StringViewCR tilesheetPath, ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const &paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
@@ -81,7 +81,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const &tilesheetAddr,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const &paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
@@ -91,7 +91,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::StringViewCR tilesheetPath, ox::StringViewCR tilesheetPath,
bool loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath)); OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette); return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
} }
@@ -99,7 +99,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const &tilesheetAddr,
bool loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr)); OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette); return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
} }
@@ -235,7 +235,13 @@ constexpr ox::Array<char, 128> charMap = {
50, // ~ 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, { setBgTile(ctx, bgIdx, column, row, {
.tileIdx = tile, .tileIdx = tile,
.palBank = palBank, .palBank = palBank,

View File

@@ -8,7 +8,6 @@
#include <keel/typeconv.hpp> #include <keel/typeconv.hpp>
#include <nostalgia/gfx/context.hpp>
#include <nostalgia/gfx/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>

View File

@@ -1,9 +0,0 @@
target_sources(
NostalgiaGfx PRIVATE
context.cpp
gfx.cpp
)
target_link_libraries(
NostalgiaGfx PUBLIC
GlUtils
)

View File

@@ -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&params) 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&params) noexcept {
auto ctx = ox::make_unique<Context>(tctx, params);
OX_RETURN_ERROR(initGfx(*ctx, params));
return ox::UPtr<Context>(ctx.release());
}
keel::Context &keelCtx(Context &ctx) noexcept {
return turbine::keelCtx(ctx.turbineCtx);
}
turbine::Context &turbineCtx(Context &ctx) noexcept {
return ctx.turbineCtx;
}
}

View File

@@ -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&params) noexcept;
Context(Context const&) = delete;
Context(Context&&) = delete;
Context &operator=(Context const&) = delete;
Context &operator=(Context&&) = delete;
~Context() noexcept;
};
}

View File

@@ -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;
}

View File

@@ -8,7 +8,7 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
RemovePageCommand::RemovePageCommand(Palette &pal, size_t idx) noexcept: RemovePageCommand::RemovePageCommand(Palette &pal, size_t const idx) noexcept:
m_pal(pal), m_pal(pal),
m_idx(idx) {} m_idx(idx) {}

View File

@@ -9,13 +9,13 @@ namespace nostalgia::gfx {
UpdateColorCommand::UpdateColorCommand( UpdateColorCommand::UpdateColorCommand(
Palette &pal, Palette &pal,
size_t page, size_t const page,
size_t idx, size_t const idx,
Color16 newColor): Color16 const newColor):
m_pal(pal), m_pal{pal},
m_page(page), m_page{page},
m_idx(idx), m_idx{idx},
m_altColor(newColor) { m_altColor{newColor} {
if (color(m_pal, m_page, m_idx) == newColor) { if (color(m_pal, m_page, m_idx) == newColor) {
throw studio::NoChangesException(); throw studio::NoChangesException();
} }

View File

@@ -118,12 +118,12 @@ void PaletteEditorImGui::navigateTo(ox::StringViewCR arg) noexcept {
} }
} }
void PaletteEditorImGui::drawColumnLeftAlign(ox::CStringView txt) noexcept { void PaletteEditorImGui::drawColumnLeftAlign(ox::CStringViewCR txt) noexcept {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s", txt.c_str()); ImGui::Text("%s", txt.c_str());
} }
void PaletteEditorImGui::drawColumn(ox::CStringView txt) noexcept { void PaletteEditorImGui::drawColumn(ox::CStringViewCR txt) noexcept {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetCursorPosX( ImGui::SetCursorPosX(
ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(txt.data()).x); ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(txt.data()).x);
@@ -143,7 +143,15 @@ void PaletteEditorImGui::numShortcuts(size_t &val, size_t const sizeRange) noexc
} }
} }
void PaletteEditorImGui::colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept { void PaletteEditorImGui::colorInput(
ox::CStringViewCR label,
int &v,
bool &inputFocused,
FocusCmd const colorChannel) noexcept {
if (colorChannel == m_focusCmd) [[unlikely]] {
ImGui::SetKeyboardFocusHere();
m_focusCmd = FocusCmd::None;
}
ImGui::InputInt(label.c_str(), &v, 1, 5); ImGui::InputInt(label.c_str(), &v, 1, 5);
inputFocused = inputFocused || ImGui::IsItemFocused(); inputFocused = inputFocused || ImGui::IsItemFocused();
v = ox::max(v, 0); v = ox::max(v, 0);
@@ -294,21 +302,44 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
int const a = alpha16(c); int const a = alpha16(c);
auto const newName = ig::InputText<50>( auto const newName = ig::InputText<50>(
"Name", m_pal.colorNames[m_selectedColorRow]); "Name", m_pal.colorNames[m_selectedColorRow]);
bool inputFocused = ImGui::IsItemFocused(); auto const nameInputFocused = ImGui::IsItemFocused();
ImGui::Separator(); ImGui::Separator();
colorInput("Red", r, inputFocused); bool colorInFocused{};
colorInput("Green", g, inputFocused); colorInput("Red", r, colorInFocused, FocusCmd::Red);
colorInput("Blue", b, inputFocused); colorInput("Green", g, colorInFocused, FocusCmd::Green);
colorInput("Blue", b, colorInFocused, FocusCmd::Blue);
// color preview
{
ImGui::PushStyleColor(
ImGuiCol_ChildBg,
color32(color16(r, g, b)) | 0xff'00'00'00);
ImGui::BeginChild("ColorPreview", {0, 25});
ImGui::EndChild();
ImGui::PopStyleColor();
}
if (ig::PushButton("Apply to all pages", {-1, ig::BtnSz.y})) { if (ig::PushButton("Apply to all pages", {-1, ig::BtnSz.y})) {
std::ignore = pushCommand<ApplyColorAllPagesCommand>( std::ignore = pushCommand<ApplyColorAllPagesCommand>(
m_pal, m_page, m_selectedColorRow); m_pal, m_page, m_selectedColorRow);
} }
if (ig::mainWinHasFocus() && !inputFocused && !ImGui::IsKeyDown(ImGuiKey_ModCtrl)) { if (ig::mainWinHasFocus() && !ImGui::IsKeyDown(ImGuiKey_ModCtrl)) {
if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) { if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) {
if (!nameInputFocused && !colorInFocused) {
numShortcuts(m_selectedColorRow, largestPage(m_pal)); numShortcuts(m_selectedColorRow, largestPage(m_pal));
}
} else { } else {
numShortcuts(m_page, m_pal.pages.size()); numShortcuts(m_page, m_pal.pages.size());
} }
if (!nameInputFocused) {
if (ImGui::IsKeyDown(ImGuiKey_R)) {
m_focusCmd = FocusCmd::Red;
}
if (ImGui::IsKeyDown(ImGuiKey_G)) {
m_focusCmd = FocusCmd::Green;
}
if (ImGui::IsKeyDown(ImGuiKey_B)) {
m_focusCmd = FocusCmd::Blue;
}
}
} }
auto const newColor = color16(r, g, b, a); auto const newColor = color16(r, g, b, a);
if (c != newColor) { if (c != newColor) {
@@ -320,7 +351,7 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
} }
} }
ox::Error PaletteEditorImGui::renamePage(ox::StringView name) noexcept { ox::Error PaletteEditorImGui::renamePage(ox::StringViewCR name) noexcept {
return pushCommand<RenamePageCommand>(m_pal, m_page, name); return pushCommand<RenamePageCommand>(m_pal, m_page, name);
} }

View File

@@ -36,6 +36,13 @@ class PaletteEditorImGui: public studio::Editor {
Palette m_pal; Palette m_pal;
size_t m_selectedColorRow = 0; size_t m_selectedColorRow = 0;
size_t m_page = 0; size_t m_page = 0;
enum class FocusCmd {
None,
Red,
Green,
Blue,
};
FocusCmd m_focusCmd;
public: public:
PaletteEditorImGui(studio::Context &sctx, ox::StringParam path); PaletteEditorImGui(studio::Context &sctx, ox::StringParam path);
@@ -48,9 +55,9 @@ class PaletteEditorImGui: public studio::Editor {
void navigateTo(ox::StringViewCR arg) noexcept override; void navigateTo(ox::StringViewCR arg) noexcept override;
private: private:
static void drawColumnLeftAlign(ox::CStringView txt) noexcept; static void drawColumnLeftAlign(ox::CStringViewCR txt) noexcept;
static void drawColumn(ox::CStringView txt) noexcept; static void drawColumn(ox::CStringViewCR txt) noexcept;
static void drawColumn(ox::Integer_c auto i) noexcept { static void drawColumn(ox::Integer_c auto i) noexcept {
drawColumn(ox::intToStr(i)); drawColumn(ox::intToStr(i));
@@ -58,7 +65,7 @@ class PaletteEditorImGui: public studio::Editor {
static void numShortcuts(size_t &val, size_t sizeRange) noexcept; static void numShortcuts(size_t &val, size_t sizeRange) noexcept;
static void colorInput(ox::CStringView label, int &v, bool &inputFocused) noexcept; void colorInput(ox::CStringViewCR label, int &v, bool &inputFocused, FocusCmd colorChannel) noexcept;
void drawColorsEditor() noexcept; void drawColorsEditor() noexcept;
@@ -66,7 +73,7 @@ class PaletteEditorImGui: public studio::Editor {
void drawColorEditor() noexcept; void drawColorEditor() noexcept;
ox::Error renamePage(ox::StringView name) noexcept; ox::Error renamePage(ox::StringViewCR name) noexcept;
ox::Error handleCommand(studio::UndoCommand const*) noexcept; ox::Error handleCommand(studio::UndoCommand const*) noexcept;
}; };

View File

@@ -30,7 +30,7 @@ static class: public studio::Module {
} }
} const mod; } const mod;
const studio::Module *studioModule() noexcept { studio::Module const *studioModule() noexcept {
return &mod; return &mod;
} }

View File

@@ -13,7 +13,7 @@ AddSubSheetCommand::AddSubSheetCommand(
auto &parent = getSubSheet(m_img, m_parentIdx); auto &parent = getSubSheet(m_img, m_parentIdx);
if (!parent.subsheets.empty()) { if (!parent.subsheets.empty()) {
auto idx = m_parentIdx; auto idx = m_parentIdx;
idx.emplace_back(parent.subsheets.size()); idx.emplace_back(static_cast<uint32_t>(parent.subsheets.size()));
m_addedSheets.push_back(idx); m_addedSheets.push_back(idx);
} else { } else {
auto idx = m_parentIdx; auto idx = m_parentIdx;

View File

@@ -48,7 +48,7 @@ CutPasteCommand::CutPasteCommand(
ox::Error CutPasteCommand::redo() noexcept { ox::Error CutPasteCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (const auto &c : m_changes) { for (auto const &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx);
} }
return {}; return {};
@@ -56,7 +56,7 @@ ox::Error CutPasteCommand::redo() noexcept {
ox::Error CutPasteCommand::undo() noexcept { ox::Error CutPasteCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (const auto &c : m_changes) { for (auto const &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
} }
return {}; return {};

View File

@@ -13,20 +13,19 @@ DeleteTilesCommand::DeleteTilesCommand(
TileSheet::SubSheetIdx idx, TileSheet::SubSheetIdx idx,
std::size_t const tileIdx, std::size_t const tileIdx,
std::size_t const tileCnt) noexcept: std::size_t const tileCnt) noexcept:
m_img(img), m_img{img},
m_idx(std::move(idx)) { m_idx{std::move(idx)},
constexpr unsigned bytesPerTile = PixelsPerTile; m_deletePos{tileIdx * PixelsPerTile},
m_deletePos = tileIdx * bytesPerTile; m_deleteSz{tileCnt * PixelsPerTile},
m_deleteSz = tileCnt * bytesPerTile; m_deletedPixels{[this] {
m_deletedPixels.resize(m_deleteSz); ox::Vector<uint8_t> deletedPixels(m_deleteSz);
// copy pixels to be erased // copy pixels to be erased
{ auto const &s = getSubSheet(m_img, m_idx);
auto &s = getSubSheet(m_img, m_idx); auto const dst = deletedPixels.begin();
auto dst = m_deletedPixels.begin(); auto const src = s.pixels.begin() + m_deletePos;
auto src = s.pixels.begin() + m_deletePos;
ox::copy_n(src, m_deleteSz, dst); ox::copy_n(src, m_deleteSz, dst);
} return deletedPixels;
} }()} {}
ox::Error DeleteTilesCommand::redo() noexcept { ox::Error DeleteTilesCommand::redo() noexcept {
auto &s = getSubSheet(m_img, m_idx); auto &s = getSubSheet(m_img, m_idx);

View File

@@ -11,10 +11,10 @@ namespace nostalgia::gfx {
class DeleteTilesCommand: public TileSheetCommand { class DeleteTilesCommand: public TileSheetCommand {
private: private:
TileSheet &m_img; TileSheet &m_img;
TileSheet::SubSheetIdx m_idx; TileSheet::SubSheetIdx const m_idx;
std::size_t m_deletePos = 0; std::size_t const m_deletePos = 0;
std::size_t m_deleteSz = 0; std::size_t const m_deleteSz = 0;
ox::Vector<uint8_t> m_deletedPixels = {}; ox::Vector<uint8_t> const m_deletedPixels;
public: public:
DeleteTilesCommand( DeleteTilesCommand(

View File

@@ -62,11 +62,11 @@ constexpr void iterateLine(ox::Point const &a, ox::Point const &b, auto const &f
DrawCommand::DrawCommand( DrawCommand::DrawCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
std::size_t idx, std::size_t const idx,
int const palIdx) noexcept: int const palIdx) noexcept:
m_img(img), m_img{img},
m_subSheetIdx(std::move(subSheetIdx)), m_subSheetIdx{std::move(subSheetIdx)},
m_palIdx(palIdx) { m_palIdx{palIdx} {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
} }

View File

@@ -12,19 +12,19 @@ InsertTilesCommand::InsertTilesCommand(
std::size_t const tileIdx, std::size_t const tileIdx,
std::size_t const tileCnt) noexcept: std::size_t const tileCnt) noexcept:
m_img{img}, m_img{img},
m_idx{std::move(idx)} { m_idx{std::move(idx)},
m_insertPos = tileIdx * PixelsPerTile; m_insertPos{tileIdx * PixelsPerTile},
m_insertCnt = tileCnt * PixelsPerTile; m_insertCnt{tileCnt * PixelsPerTile},
m_deletedPixels.resize(m_insertCnt); m_insertedPixels{[this] {
ox::Vector<uint8_t> insertedPixels(m_insertCnt);
// copy pixels to be erased // copy pixels to be erased
{
auto &s = getSubSheet(m_img, m_idx); auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels; auto &p = s.pixels;
auto const dst = m_deletedPixels.begin(); auto const dst = insertedPixels.begin();
auto const src = p.begin() + p.size() - m_insertCnt; auto const src = p.begin() + p.size() - m_insertCnt;
ox::copy_n(src, m_insertCnt, dst); ox::copy_n(src, m_insertCnt, dst);
} return insertedPixels;
} }()} {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
@@ -52,7 +52,7 @@ ox::Error InsertTilesCommand::undo() noexcept {
auto const src = &p[srcIdx]; auto const src = &p[srcIdx];
ox::memmove(dst1, src, sz); ox::memmove(dst1, src, sz);
} }
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size()); ox::memcpy(dst2, m_insertedPixels.data(), m_insertedPixels.size());
return {}; return {};
} }

View File

@@ -11,10 +11,10 @@ namespace nostalgia::gfx {
class InsertTilesCommand: public TileSheetCommand { class InsertTilesCommand: public TileSheetCommand {
private: private:
TileSheet &m_img; TileSheet &m_img;
TileSheet::SubSheetIdx m_idx; TileSheet::SubSheetIdx const m_idx;
std::size_t m_insertPos = 0; std::size_t const m_insertPos{};
std::size_t m_insertCnt = 0; std::size_t const m_insertCnt{};
ox::Vector<uint8_t> m_deletedPixels = {}; ox::Vector<uint8_t> const m_insertedPixels;
public: public:
InsertTilesCommand( InsertTilesCommand(

View File

@@ -15,7 +15,6 @@ UpdateSubSheetCommand::UpdateSubSheetCommand(
m_img{img}, m_img{img},
m_idx{std::move(idx)}, m_idx{std::move(idx)},
m_sheet{getSubSheet(m_img, m_idx)} { m_sheet{getSubSheet(m_img, m_idx)} {
m_sheet = getSubSheet(m_img, m_idx);
m_sheet.name = std::move(name); m_sheet.name = std::move(name);
OX_THROW_ERROR(resizeSubsheet(m_sheet, {cols, rows})); OX_THROW_ERROR(resizeSubsheet(m_sheet, {cols, rows}));
} }

View File

@@ -11,7 +11,7 @@ namespace nostalgia::gfx {
class UpdateSubSheetCommand: public TileSheetCommand { class UpdateSubSheetCommand: public TileSheetCommand {
private: private:
TileSheet &m_img; TileSheet &m_img;
TileSheet::SubSheetIdx m_idx; TileSheet::SubSheetIdx const m_idx;
TileSheet::SubSheet m_sheet; TileSheet::SubSheet m_sheet;
public: public:

View File

@@ -9,6 +9,8 @@
#include <keel/media.hpp> #include <keel/media.hpp>
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/gfx/studio.hpp>
#include "tilesheeteditor-imgui.hpp" #include "tilesheeteditor-imgui.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
@@ -67,10 +69,10 @@ static ox::Vector<uint32_t> normalizePixelArrangement(
} }
static ox::Error toPngFile( static ox::Error toPngFile(
ox::CStringView const&path, ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels, ox::Vector<uint32_t> &&pixels,
Palette const &pal, Palette const &pal,
size_t page, size_t const page,
unsigned const width, unsigned const width,
unsigned const height) noexcept { unsigned const height) noexcept {
for (auto &c : pixels) { for (auto &c : pixels) {
@@ -88,7 +90,7 @@ static ox::Error toPngFile(
} }
TileSheetEditorImGui::TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path): TileSheetEditorImGui::TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path):
Editor(sctx, std::move(path)), Editor{sctx, std::move(path)},
m_sctx{sctx}, m_sctx{sctx},
m_tctx{m_sctx.tctx}, m_tctx{m_sctx.tctx},
m_palPicker{"Palette Chooser", keelCtx(sctx), FileExt_npal}, m_palPicker{"Palette Chooser", keelCtx(sctx), FileExt_npal},
@@ -98,8 +100,11 @@ TileSheetEditorImGui::TileSheetEditorImGui(studio::Context &sctx, ox::StringPara
m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet); m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet);
m_exportMenu.inputSubmitted.connect(this, &TileSheetEditorImGui::exportSubsheetToPng); m_exportMenu.inputSubmitted.connect(this, &TileSheetEditorImGui::exportSubsheetToPng);
// load config // load config
auto const&config = studio::readConfig<TileSheetEditorConfig>( auto &kctx = keelCtx(m_sctx);
keelCtx(m_sctx), itemPath()); auto const ip = itemPath();
oxLogError(studio::headerizeConfigFile<TileSheetEditorConfig>(kctx, ip));
auto const &config =
studio::readConfig<TileSheetEditorConfig>(kctx, ip);
if (config.ok()) { if (config.ok()) {
m_model.setActiveSubsheet(validateSubSheetIdx(m_model.img(), config.value.activeSubsheet)); m_model.setActiveSubsheet(validateSubSheetIdx(m_model.img(), config.value.activeSubsheet));
} }
@@ -189,6 +194,9 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key const key, bool const do
} }
void TileSheetEditorImGui::draw(studio::Context&) noexcept { void TileSheetEditorImGui::draw(studio::Context&) noexcept {
setCopyEnabled(m_model.hasSelection());
setCutEnabled(m_model.hasSelection());
setPasteEnabled(m_model.hasSelection());
if (ig::mainWinHasFocus() && m_tool == TileSheetTool::Select) { if (ig::mainWinHasFocus() && m_tool == TileSheetTool::Select) {
if (ImGui::IsKeyDown(ImGuiKey_ModCtrl) && !m_palPathFocused) { if (ImGui::IsKeyDown(ImGuiKey_ModCtrl) && !m_palPathFocused) {
if (ImGui::IsKeyPressed(ImGuiKey_A)) { if (ImGui::IsKeyPressed(ImGuiKey_A)) {
@@ -273,7 +281,7 @@ void TileSheetEditorImGui::draw(studio::Context&) noexcept {
auto insertOnIdx = m_model.activeSubSheetIdx(); auto insertOnIdx = m_model.activeSubSheetIdx();
auto const &parent = m_model.activeSubSheet(); auto const &parent = m_model.activeSubSheet();
m_model.addSubsheet(insertOnIdx); m_model.addSubsheet(insertOnIdx);
insertOnIdx.emplace_back(parent.subsheets.size() - 1); insertOnIdx.emplace_back(static_cast<uint32_t>(parent.subsheets.size() - 1));
setActiveSubsheet(insertOnIdx); setActiveSubsheet(insertOnIdx);
} }
ImGui::SameLine(); ImGui::SameLine();
@@ -388,6 +396,17 @@ ox::Error TileSheetEditorImGui::saveItem() noexcept {
return m_model.saveFile(); return m_model.saveFile();
} }
void TileSheetEditorImGui::navigateTo(ox::StringViewCR arg) noexcept {
auto const subSheetId = strToInt(arg);
if (subSheetId.error) {
return;
}
if (auto const [val, err] = getSubSheetIdx(m_model.img(), subSheetId.value);
!err) {
setActiveSubsheet(val);
}
}
void TileSheetEditorImGui::showSubsheetEditor() noexcept { void TileSheetEditorImGui::showSubsheetEditor() noexcept {
auto const &sheet = m_model.activeSubSheet(); auto const &sheet = m_model.activeSubSheet();
if (!sheet.subsheets.empty()) { if (!sheet.subsheets.empty()) {
@@ -451,7 +470,10 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
if (wheelh != 0) { if (wheelh != 0) {
m_view.scrollH(fbSize, wheelh); m_view.scrollH(fbSize, wheelh);
} }
if (ImGui::IsMouseDown(0) && m_prevMouseDownPos != mousePos) { using ImGui::IsMouseClicked;
using ImGui::IsMouseDragging;
if ((IsMouseDragging(ImGuiMouseButton_Left) || IsMouseClicked(ImGuiMouseButton_Left))
&& m_prevMouseDownPos != mousePos) {
m_prevMouseDownPos = mousePos; m_prevMouseDownPos = mousePos;
switch (m_tool) { switch (m_tool) {
case TileSheetTool::Draw: case TileSheetTool::Draw:
@@ -556,10 +578,10 @@ void TileSheetEditorImGui::drawPaletteMenu() noexcept {
m_view.setPalIdx(i); m_view.setPalIdx(i);
} }
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
studio::navigateTo( navigateToPalette(
m_sctx, m_sctx,
m_model.palPath(), m_model.palPath(),
ox::sfmt("{};{}", i, m_model.palettePage())); i, m_model.palettePage());
} }
// Column: color RGB // Column: color RGB
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@@ -580,7 +602,7 @@ void TileSheetEditorImGui::drawPaletteMenu() noexcept {
} }
ox::Error TileSheetEditorImGui::updateActiveSubsheet( ox::Error TileSheetEditorImGui::updateActiveSubsheet(
ox::StringView const&name, int const cols, int const rows) noexcept { ox::StringViewCR name, int const cols, int const rows) noexcept {
return m_model.updateSubsheet(m_model.activeSubSheetIdx(), name, cols, rows); return m_model.updateSubsheet(m_model.activeSubSheetIdx(), name, cols, rows);
} }

View File

@@ -87,6 +87,8 @@ class TileSheetEditorImGui: public studio::Editor {
protected: protected:
ox::Error saveItem() noexcept override; ox::Error saveItem() noexcept override;
void navigateTo(ox::StringViewCR arg) noexcept override;
private: private:
void showSubsheetEditor() noexcept; void showSubsheetEditor() noexcept;
@@ -96,7 +98,7 @@ class TileSheetEditorImGui: public studio::Editor {
void drawPaletteMenu() noexcept; void drawPaletteMenu() noexcept;
ox::Error updateActiveSubsheet(ox::StringView const&name, int cols, int rows) noexcept; ox::Error updateActiveSubsheet(ox::StringViewCR name, int cols, int rows) noexcept;
void setActiveSubsheet(TileSheet::SubSheetIdx path) noexcept; void setActiveSubsheet(TileSheet::SubSheetIdx path) noexcept;

View File

@@ -84,9 +84,9 @@ void TileSheetEditorModel::cut() {
auto const pt1 = m_selection->a; auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight}; auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
turbine::setClipboardObject(m_tctx, std::move(cb)); turbine::setClipboardObject(m_tctx, std::move(cb));
if (auto const cmd = ox::makeCatch<CutPasteCommand>( if (auto cmd = ox::make_unique_catch<CutPasteCommand>(
CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb); cmd.ok()) { CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb); cmd.ok()) {
std::ignore = pushCommand(cmd.value); std::ignore = pushCommand(std::move(cmd.value));
} }
} }
@@ -125,9 +125,9 @@ void TileSheetEditorModel::paste() {
auto const &s = activeSubSheet(); auto const &s = activeSubSheet();
auto const pt1 = m_selection->a; auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight}; auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
if (auto const cmd = ox::makeCatch<CutPasteCommand>( if (auto cmd = ox::make_unique_catch<CutPasteCommand>(
CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb); cmd.ok()) { CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb); cmd.value) {
std::ignore = pushCommand(cmd.value); std::ignore = pushCommand(std::move(cmd.value));
} }
} }
@@ -142,7 +142,7 @@ ox::String const &TileSheetEditorModel::palPath() const & noexcept {
ox::Error TileSheetEditorModel::setPalette(ox::StringViewCR path) noexcept { ox::Error TileSheetEditorModel::setPalette(ox::StringViewCR path) noexcept {
OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path)); OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path));
std::ignore = pushCommand(ox::make<PaletteChangeCommand>( std::ignore = pushCommand(ox::make_unique<PaletteChangeCommand>(
activeSubSheetIdx(), m_img, uuid->toString())); activeSubSheetIdx(), m_img, uuid->toString()));
return {}; return {};
} }
@@ -169,7 +169,7 @@ void TileSheetEditorModel::drawCommand(ox::Point const &pt, std::size_t const pa
if (m_ongoingDrawCommand) { if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idx); m_updated = m_updated || m_ongoingDrawCommand->append(idx);
} else if (activeSubSheet.pixels[idx] != palIdx) { } else if (activeSubSheet.pixels[idx] != palIdx) {
std::ignore = pushCommand(ox::make<DrawCommand>( std::ignore = pushCommand(ox::make_unique<DrawCommand>(
m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx))); m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
} }
} }
@@ -188,7 +188,7 @@ void TileSheetEditorModel::drawLineCommand(ox::Point const &pt, std::size_t cons
m_ongoingDrawCommand->lineUpdate(m_lineStartPt, pt); m_ongoingDrawCommand->lineUpdate(m_lineStartPt, pt);
m_updated = true; m_updated = true;
} else { } else {
std::ignore = pushCommand(ox::make<DrawCommand>( std::ignore = pushCommand(ox::make_unique<DrawCommand>(
m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx))); m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
m_lineStartPt = pt; m_lineStartPt = pt;
} }
@@ -198,31 +198,32 @@ void TileSheetEditorModel::endDrawCommand() noexcept {
if (m_ongoingDrawCommand) { if (m_ongoingDrawCommand) {
m_ongoingDrawCommand->finish(); m_ongoingDrawCommand->finish();
m_ongoingDrawCommand = nullptr; m_ongoingDrawCommand = nullptr;
m_lastDrawUpdatePt = {-1, -1};
} }
} }
void TileSheetEditorModel::addSubsheet(TileSheet::SubSheetIdx const &parentIdx) noexcept { void TileSheetEditorModel::addSubsheet(TileSheet::SubSheetIdx const &parentIdx) noexcept {
std::ignore = pushCommand(ox::make<AddSubSheetCommand>(m_img, parentIdx)); std::ignore = pushCommand(ox::make_unique<AddSubSheetCommand>(m_img, parentIdx));
} }
void TileSheetEditorModel::rmSubsheet(TileSheet::SubSheetIdx const &idx) noexcept { void TileSheetEditorModel::rmSubsheet(TileSheet::SubSheetIdx const &idx) noexcept {
std::ignore = pushCommand(ox::make<RmSubSheetCommand>(m_img, idx)); std::ignore = pushCommand(ox::make_unique<RmSubSheetCommand>(m_img, idx));
} }
void TileSheetEditorModel::insertTiles( void TileSheetEditorModel::insertTiles(
TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept { TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
std::ignore = pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt)); std::ignore = pushCommand(ox::make_unique<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
void TileSheetEditorModel::deleteTiles( void TileSheetEditorModel::deleteTiles(
TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept { TileSheet::SubSheetIdx const &idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
std::ignore = pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt)); std::ignore = pushCommand(ox::make_unique<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
ox::Error TileSheetEditorModel::updateSubsheet( ox::Error TileSheetEditorModel::updateSubsheet(
TileSheet::SubSheetIdx const &idx, ox::StringViewCR name, int const cols, int const rows) noexcept { TileSheet::SubSheetIdx const &idx, ox::StringViewCR name, int const cols, int const rows) noexcept {
OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows)); OX_REQUIRE_M(cmd, ox::make_unique_catch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows));
std::ignore = pushCommand(cmd); std::ignore = pushCommand(std::move(cmd));
return {}; return {};
} }
@@ -230,9 +231,10 @@ void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const&idx) n
m_activeSubsSheetIdx = idx; m_activeSubsSheetIdx = idx;
this->activeSubsheetChanged.emit(m_activeSubsSheetIdx); this->activeSubsheetChanged.emit(m_activeSubsSheetIdx);
clearSelection(); clearSelection();
m_lastDrawUpdatePt = {-1, -1};
} }
void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept { void TileSheetEditorModel::fill(ox::Point const &pt, uint8_t const palIdx) noexcept {
auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx); auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
// build idx list // build idx list
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
@@ -253,29 +255,29 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept {
if (m_ongoingDrawCommand) { if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idxList); m_updated = m_updated || m_ongoingDrawCommand->append(idxList);
} else if (getPixel(activeSubSheet, pt) != palIdx) { } else if (getPixel(activeSubSheet, pt) != palIdx) {
std::ignore = pushCommand(ox::make<DrawCommand>(m_img, m_activeSubsSheetIdx, idxList, palIdx)); std::ignore = pushCommand(ox::make_unique<DrawCommand>(m_img, m_activeSubsSheetIdx, idxList, palIdx));
} }
} }
ox::Error TileSheetEditorModel::rotateLeft() noexcept { ox::Error TileSheetEditorModel::rotateLeft() noexcept {
auto &ss = activeSubSheet(); auto const &ss = activeSubSheet();
ox::Point pt1, pt2{ss.columns * TileWidth - 1, ss.rows * TileHeight - 1}; ox::Point pt1, pt2{ss.columns * TileWidth - 1, ss.rows * TileHeight - 1};
if (m_selection) { if (m_selection) {
pt1 = m_selection->a; pt1 = m_selection->a;
pt2 = m_selection->b; pt2 = m_selection->b;
} }
return pushCommand(ox::make<RotateCommand>( return pushCommand(ox::make_unique<RotateCommand>(
m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Left)); m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Left));
} }
ox::Error TileSheetEditorModel::rotateRight() noexcept { ox::Error TileSheetEditorModel::rotateRight() noexcept {
auto &ss = activeSubSheet(); auto const &ss = activeSubSheet();
ox::Point pt1, pt2{ss.columns * TileWidth - 1, ss.rows * TileHeight - 1}; ox::Point pt1, pt2{ss.columns * TileWidth - 1, ss.rows * TileHeight - 1};
if (m_selection) { if (m_selection) {
pt1 = m_selection->a; pt1 = m_selection->a;
pt2 = m_selection->b; pt2 = m_selection->b;
} }
return pushCommand(ox::make<RotateCommand>( return pushCommand(ox::make_unique<RotateCommand>(
m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Right)); m_img, m_activeSubsSheetIdx, pt1, pt2, RotateCommand::Direction::Right));
} }
@@ -313,6 +315,10 @@ void TileSheetEditorModel::clearSelection() noexcept {
m_selection.reset(); m_selection.reset();
} }
bool TileSheetEditorModel::hasSelection() const noexcept {
return m_selection.has_value();
}
bool TileSheetEditorModel::updated() const noexcept { bool TileSheetEditorModel::updated() const noexcept {
return m_updated; return m_updated;
} }
@@ -363,7 +369,7 @@ ox::Error TileSheetEditorModel::flipX() noexcept {
a = m_selection->a; a = m_selection->a;
b = m_selection->b; b = m_selection->b;
} }
return pushCommand(ox::make<FlipXCommand>(m_img, m_activeSubsSheetIdx, a, b)); return pushCommand(ox::make_unique<FlipXCommand>(m_img, m_activeSubsSheetIdx, a, b));
} }
ox::Error TileSheetEditorModel::flipY() noexcept { ox::Error TileSheetEditorModel::flipY() noexcept {
@@ -374,7 +380,7 @@ ox::Error TileSheetEditorModel::flipY() noexcept {
a = m_selection->a; a = m_selection->a;
b = m_selection->b; b = m_selection->b;
} }
return pushCommand(ox::make<FlipYCommand>(m_img, m_activeSubsSheetIdx, a, b)); return pushCommand(ox::make_unique<FlipYCommand>(m_img, m_activeSubsSheetIdx, a, b));
} }
bool TileSheetEditorModel::rotateEligible() const noexcept { bool TileSheetEditorModel::rotateEligible() const noexcept {
@@ -388,14 +394,14 @@ bool TileSheetEditorModel::rotateEligible() const noexcept {
} }
ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept { ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept {
return pushCommand(ox::make<MoveSubSheetCommand>(m_img, std::move(src), std::move(dst))); return pushCommand(ox::make_unique<MoveSubSheetCommand>(m_img, std::move(src), std::move(dst)));
} }
void TileSheetEditorModel::getFillPixels( void TileSheetEditorModel::getFillPixels(
TileSheet::SubSheet const &activeSubSheet, TileSheet::SubSheet const &activeSubSheet,
ox::Span<bool> pixels, ox::Span<bool> const pixels,
ox::Point const &pt, ox::Point const &pt,
int const oldColor) const noexcept { uint8_t const oldColor) noexcept {
auto const idx = ptToIdx(pt, activeSubSheet.columns); auto const idx = ptToIdx(pt, activeSubSheet.columns);
auto const relIdx = idx % PixelsPerTile; auto const relIdx = idx % PixelsPerTile;
if (pixels[relIdx] || activeSubSheet.pixels[idx] != oldColor) { if (pixels[relIdx] || activeSubSheet.pixels[idx] != oldColor) {
@@ -435,9 +441,9 @@ void TileSheetEditorModel::setPalPath() noexcept {
} }
} }
ox::Error TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept { ox::Error TileSheetEditorModel::pushCommand(ox::UPtr<studio::UndoCommand> &&cmd) noexcept {
std::ignore = m_undoStack.push(ox::UPtr{cmd}); m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd.get());
m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd); std::ignore = m_undoStack.push(std::move(cmd));
m_updated = true; m_updated = true;
return {}; return {};
} }

View File

@@ -14,7 +14,7 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
class TileSheetEditorModel: public ox::SignalHandler { class TileSheetEditorModel final: public ox::SignalHandler {
public: public:
ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged; ox::Signal<ox::Error(const TileSheet::SubSheetIdx&)> activeSubsheetChanged;
@@ -35,7 +35,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
studio::SelectionTracker m_selTracker; studio::SelectionTracker m_selTracker;
ox::Optional<studio::Selection> m_selection; ox::Optional<studio::Selection> m_selection;
ox::Point m_lineStartPt; ox::Point m_lineStartPt;
ox::Point m_lastDrawUpdatePt; ox::Point m_lastDrawUpdatePt{-1, -1};
bool m_updated = false; bool m_updated = false;
public: public:
@@ -104,7 +104,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
return m_activeSubsSheetIdx; return m_activeSubsSheetIdx;
} }
void fill(ox::Point const&pt, int palIdx) noexcept; void fill(ox::Point const &pt, uint8_t palIdx) noexcept;
ox::Error rotateLeft() noexcept; ox::Error rotateLeft() noexcept;
@@ -118,6 +118,9 @@ class TileSheetEditorModel: public ox::SignalHandler {
void clearSelection() noexcept; void clearSelection() noexcept;
[[nodiscard]]
bool hasSelection() const noexcept;
[[nodiscard]] [[nodiscard]]
bool updated() const noexcept; bool updated() const noexcept;
@@ -144,15 +147,15 @@ class TileSheetEditorModel: public ox::SignalHandler {
ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept; ox::Error moveSubSheet(TileSheet::SubSheetIdx src, TileSheet::SubSheetIdx dst) noexcept;
private: private:
void getFillPixels( static void getFillPixels(
TileSheet::SubSheet const &activeSubSheet, TileSheet::SubSheet const &activeSubSheet,
ox::Span<bool> pixels, ox::Span<bool> pixels,
ox::Point const &pt, ox::Point const &pt,
int oldColor) const noexcept; uint8_t oldColor) noexcept;
void setPalPath() noexcept; void setPalPath() noexcept;
ox::Error pushCommand(studio::UndoCommand *cmd) noexcept; ox::Error pushCommand(ox::UPtr<studio::UndoCommand> &&cmd) noexcept;
ox::Error handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const &id) noexcept; ox::Error handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const &id) noexcept;

View File

@@ -89,10 +89,10 @@ void TileSheetEditorView::clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&cl
void TileSheetEditorView::clickFill(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept { void TileSheetEditorView::clickFill(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
m_model.fill(pt, static_cast<int>(m_palIdx)); m_model.fill(pt, static_cast<uint8_t>(m_palIdx));
} }
void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept { void TileSheetEditorView::releaseMouseButton(TileSheetTool const tool) noexcept {
switch (tool) { switch (tool) {
case TileSheetTool::Draw: case TileSheetTool::Draw:
case TileSheetTool::Fill: case TileSheetTool::Fill:
@@ -135,7 +135,7 @@ void TileSheetEditorView::initView() noexcept {
ox::Point TileSheetEditorView::clickPoint(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) const noexcept { ox::Point TileSheetEditorView::clickPoint(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) const noexcept {
auto [x, y] = clickPos; auto [x, y] = clickPos;
const auto pixDrawSz = m_pixelsDrawer.pixelSize(paneSize); auto const pixDrawSz = m_pixelsDrawer.pixelSize(paneSize);
x /= paneSize.x; x /= paneSize.x;
y /= paneSize.y; y /= paneSize.y;
x += -m_scrollOffset.x / 2; x += -m_scrollOffset.x / 2;

View File

@@ -73,7 +73,8 @@ class TileSheetGrid {
void update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept; void update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;
private: private:
static void setBufferObject(ox::Point pt1, ox::Point pt2, Color32 c, ox::Span<float> vbo, ox::Vec2 const&pixSize) noexcept; static void setBufferObject(
ox::Point pt1, ox::Point pt2, Color32 c, ox::Span<float> vbo, ox::Vec2 const &pixSize) noexcept;
void setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept; void setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;

View File

@@ -2,6 +2,8 @@
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#include "nostalgia/gfx/tilesheet.hpp"
#include <ox/std/size.hpp> #include <ox/std/size.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
@@ -84,12 +86,12 @@ static void setPixel(
int const columns, int const columns,
ox::Point const &pt, ox::Point const &pt,
uint8_t const palIdx) noexcept { uint8_t const palIdx) noexcept {
const auto idx = ptToIdx(pt, columns); auto const idx = ptToIdx(pt, columns);
pixels[idx] = palIdx; pixels[idx] = palIdx;
} }
void setPixel(TileSheet::SubSheet &ss, ox::Point const &pt, uint8_t const palIdx) noexcept { void setPixel(TileSheet::SubSheet &ss, ox::Point const &pt, uint8_t const palIdx) noexcept {
const auto idx = ptToIdx(pt, ss.columns); auto const idx = ptToIdx(pt, ss.columns);
ss.pixels[idx] = palIdx; ss.pixels[idx] = palIdx;
} }
@@ -152,8 +154,8 @@ ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId c
if (ss.id == pId) { if (ss.id == pId) {
return ox::StringView(ss.name); return ox::StringView(ss.name);
} }
for (const auto &sub : ss.subsheets) { for (auto const &sub : ss.subsheets) {
const auto [name, err] = getNameFor(sub, pId); auto const [name, err] = getNameFor(sub, pId);
if (!err) { if (!err) {
return name; return name;
} }
@@ -187,6 +189,28 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe
return validateSubSheetIdx(std::move(idx), 0, ts.subsheet); return validateSubSheetIdx(std::move(idx), 0, ts.subsheet);
} }
static ox::Error getSubSheetIdx(TileSheet::SubSheet const &ss, SubSheetId const pId, TileSheet::SubSheetIdx &idx) noexcept {
if (ss.id == pId) {
return {};
}
for (uint32_t i{}; auto const &sub : ss.subsheets) {
idx.emplace_back(i);
auto const err = getSubSheetIdx(sub, pId, idx);
if (!err) {
return {};
}
idx.pop_back();
++i;
}
return ox::Error{1, "SubSheet not found"};
}
ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId const pId) noexcept {
ox::Result<TileSheet::SubSheetIdx> out;
OX_RETURN_ERROR(getSubSheetIdx(ts.subsheet, pId, out.value));
return out;
}
#if defined(__GNUC__) && __GNUC__ >= 13 #if defined(__GNUC__) && __GNUC__ >= 13
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference" #pragma GCC diagnostic ignored "-Wdangling-reference"
@@ -198,7 +222,7 @@ static TileSheet::SubSheet const&getSubSheet(
if (idxIt == idx.size()) { if (idxIt == idx.size()) {
return pSubsheet; return pSubsheet;
} }
const auto currentIdx = idx[idxIt]; auto const currentIdx = idx[idxIt];
if (pSubsheet.subsheets.size() < currentIdx) { if (pSubsheet.subsheets.size() < currentIdx) {
return pSubsheet; return pSubsheet;
} }
@@ -413,13 +437,13 @@ ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> dst; ox::Vector<uint32_t> dst;
auto dstWidth = srcSize.width * scale; auto dstWidth = srcSize.width * scale;
auto dstHeight = srcSize.height * scale; auto dstHeight = srcSize.height * scale;
const auto pixelCnt = dstWidth * dstHeight; auto const pixelCnt = dstWidth * dstHeight;
dst.resize(static_cast<std::size_t>(pixelCnt)); dst.resize(static_cast<std::size_t>(pixelCnt));
for (auto i = 0; i < pixelCnt; ++i) { for (auto i = 0; i < pixelCnt; ++i) {
const auto dstPt = idxToPt(i, 1, scale); auto const dstPt = idxToPt(i, 1, scale);
const auto srcPt = dstPt / ox::Point{scale, scale}; auto const srcPt = dstPt / ox::Point{scale, scale};
const auto srcIdx = ptToIdx(srcPt, 1); auto const srcIdx = ptToIdx(srcPt, 1);
const auto srcPixel = srcPixels[srcIdx]; auto const srcPixel = srcPixels[srcIdx];
dst[static_cast<std::size_t>(i)] = srcPixel; dst[static_cast<std::size_t>(i)] = srcPixel;
} }
return dst; return dst;

View File

@@ -6,16 +6,16 @@
#include <map> #include <map>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/mc/mc.hpp> #include <ox/mc/write.hpp>
#include <nostalgia/gfx/core.hpp> #include <nostalgia/gfx/gfx.hpp>
using namespace nostalgia; using namespace nostalgia;
static std::map<ox::StringView, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
"readWriteTileSheet", "readWriteTileSheet",
[]() -> ox::Error { [] -> ox::Error {
gfx::TileSheet in; gfx::TileSheet const in;
OX_REQUIRE(buff, ox::writeMC(in)); OX_REQUIRE(buff, ox::writeMC(in));
OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff)); OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff));
oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken"); oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken");
@@ -24,12 +24,12 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
}, },
}; };
int main(int argc, const char **argv) { int main(int argc, char const **argv) {
int retval = -1; int retval = -1;
if (argc > 0) { if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)}; auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto const testName = ox::StringView(args[1]); auto const testName = ox::StringView(args[1]);
if (tests.find(testName) != tests.end()) { if (tests.contains(testName)) {
retval = static_cast<int>(tests[testName]()); retval = static_cast<int>(tests[testName]());
} else { } else {
retval = 1; retval = 1;

View File

@@ -8,6 +8,6 @@
namespace nostalgia::sound { namespace nostalgia::sound {
const keel::Module *keelModule() noexcept; keel::Module const *keelModule() noexcept;
} }

View File

@@ -8,6 +8,6 @@
namespace nostalgia::sound { namespace nostalgia::sound {
const studio::Module *studioModule() noexcept; studio::Module const *studioModule() noexcept;
} }

View File

@@ -10,10 +10,8 @@
namespace nostalgia::sound { namespace nostalgia::sound {
static class: public keel::Module { static struct: keel::Module {
private:
public:
[[nodiscard]] [[nodiscard]]
ox::String id() const noexcept override { ox::String id() const noexcept override {
return ox::String{"net.drinkingtea.nostalgia.sound"}; return ox::String{"net.drinkingtea.nostalgia.sound"};

View File

@@ -8,7 +8,8 @@
namespace nostalgia::sound { namespace nostalgia::sound {
static class: public studio::Module { static struct: studio::Module {
ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final { ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final {
return { return {
}; };
@@ -18,6 +19,7 @@ static class: public studio::Module {
ox::Vector<ox::UPtr<studio::ItemMaker>> out; ox::Vector<ox::UPtr<studio::ItemMaker>> out;
return out; return out;
} }
} const mod; } const mod;
const studio::Module *studioModule() noexcept { const studio::Module *studioModule() noexcept {

View File

@@ -11,7 +11,7 @@
static std::map<ox::StringView, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **argv) { int main(int argc, char const **argv) {
int retval = -1; int retval = -1;
if (argc > 0) { if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)}; auto const args = ox::Span{argv, static_cast<size_t>(argc)};

View File

@@ -5,7 +5,7 @@
#include <keel/media.hpp> #include <keel/media.hpp>
#include <turbine/turbine.hpp> #include <turbine/turbine.hpp>
#include <nostalgia/gfx/core.hpp> #include <nostalgia/gfx/gfx.hpp>
using namespace nostalgia; using namespace nostalgia;
@@ -52,7 +52,7 @@ static int testUpdateHandler(turbine::Context &tctx) noexcept {
} }
[[maybe_unused]] [[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 (down) {
if (key == turbine::Key::Alpha_Q) { if (key == turbine::Key::Alpha_Q) {
turbine::requestShutdown(tctx); turbine::requestShutdown(tctx);

View File

@@ -15,7 +15,7 @@ target_link_libraries(
target_compile_definitions( target_compile_definitions(
NostalgiaStudio PUBLIC NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="d2025.05.1" OLYMPIC_APP_VERSION="dev build"
) )
install( install(

View File

@@ -18,7 +18,7 @@
<string>APPL</string> <string>APPL</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>d2025.05.1</string> <string>dev build</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0.0</string> <string>12.0.0</string>

View File

@@ -38,7 +38,7 @@
#endif #endif
namespace olympic { namespace olympic {
ox::String appVersion = ox::String(OLYMPIC_APP_VERSION); ox::String appVersion{OLYMPIC_APP_VERSION};
} }
ox::Error run( ox::Error run(
@@ -55,9 +55,9 @@ void registerStudioModules() noexcept;
#if defined(_WIN32) && OLYMPIC_GUI_APP #if defined(_WIN32) && OLYMPIC_GUI_APP
int WinMain() { int WinMain() {
auto const argc = __argc; auto const argc = __argc;
auto const argv = const_cast<const char**>(__argv); auto const argv = const_cast<char const**>(__argv);
#else #else
int main(int argc, char const**argv) { int main(int const argc, char const **argv) {
#endif #endif
OX_INIT_DEBUG_LOGGER(loggerConn, OLYMPIC_PROJECT_NAME " " OLYMPIC_APP_NAME) OX_INIT_DEBUG_LOGGER(loggerConn, OLYMPIC_PROJECT_NAME " " OLYMPIC_APP_NAME)
#if OLYMPIC_LOAD_KEEL_MODULES #if OLYMPIC_LOAD_KEEL_MODULES

View File

@@ -26,7 +26,7 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
template<typename T> template<typename T>
ox::Result<T> readAsset(ox::BufferView buff) noexcept { ox::Result<T> readAsset(ox::BufferView buff) noexcept {
std::size_t offset = 0; std::size_t offset = 0;
const auto err = readUuidHeader(buff).error; auto const err = readUuidHeader(buff).error;
if (!err) { if (!err) {
offset = K1HdrSz; // the size of K1 headers offset = K1HdrSz; // the size of K1 headers
} }

View File

@@ -154,7 +154,7 @@ class AssetRef: public ox::SignalHandler {
private: private:
constexpr ox::Error emitUpdated() const noexcept { constexpr ox::Error emitUpdated() const noexcept {
updated.emit(); updated.emit();
return ox::Error(0); return {};
} }
}; };

View File

@@ -60,6 +60,11 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noex
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept; ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
[[nodiscard]]
constexpr bool isUuidUrl(ox::StringViewCR path) noexcept {
return ox::beginsWith(path, "uuid://");
}
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
namespace detail { namespace detail {

Some files were not shown because too many files have changed in this diff Show More