Compare commits

..

44 Commits

Author SHA1 Message Date
a53d1f87ee [Makefile] Add targets for build-pack and build-gba-player, update pkg-gba target to use them
All checks were successful
Build / build (push) Successful in 1m20s
2025-10-01 00:30:41 -05:00
7b5c760974 [ox/std] Ignore broken GCC warning
All checks were successful
Build / build (push) Successful in 1m24s
2025-09-20 13:57:45 -05:00
53446cfa1d Merge commit '5384d8c83bd449618b0ab318877fd967cb1f034f'
All checks were successful
Build / build (push) Successful in 1m49s
2025-09-10 23:48:49 -05:00
5384d8c83b Squashed 'deps/nostalgia/' changes from 31b39982..671fa54f
671fa54f [ox/std] Make ox::Vector::push_back comply with std::vector::push_back
51743267 [nostalgia/gfx/studio] Cleanup includes
b31c01f7 [keel,studio] Cleanup
f41213f1 [ox/std] Fix channel format for oxLogError
28be7c46 [ox/fs] Fix write functions to take SpanViews
2f340b13 [ox/std] Fix Windows GCC build
312c8188 [nostalgia/gfx/studio] Remove unused variable
0d69d0c4 [ox/std] Remove oxDebug line
81a0b8c8 [ox/mc] Remove an oxDebug line
172b5aee [ox/oc] Remove an oxDebug line
2b5338a9 [nostalgia] Improve Makefile dependency handling
8a430faf [keel] Cleanup
e59382dd [keel] Address undefined behavior
3006e77e [ox/std] Add and integrate std::launder
59c112a6 [studio] Fix navigate back not to iterate on the first item twice

git-subtree-dir: deps/nostalgia
git-subtree-split: 671fa54f6f3f16f4772353bb0b12cfe09dd2fd92
2025-09-10 23:48:49 -05:00
6a0f57994c Merge commit '6b0a56d5d66032c4d150c76c2b6a537930a5c5fa'
All checks were successful
Build / build (push) Successful in 1m31s
2025-08-01 02:53:02 -05:00
6b0a56d5d6 Squashed 'deps/nostalgia/' changes from e38b85b4..31b39982
31b39982 [keel] Fix AssetRef to call incRef on initial creation of ref, not just copy
5476417b [nostalgia] Add release notes for d2025.07.0
e03be694 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
490c0368 [nostalgia/gfx] Add lists for file extensions
a24fc407 [ox/std] Fix MSVC build

git-subtree-dir: deps/nostalgia
git-subtree-split: 31b39982c5ead87da1727bc1f561b945e4d1e5fb
2025-08-01 02:53:02 -05:00
3aac345637 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-31 00:41:06 -05:00
b67b95767b Squashed 'deps/nostalgia/' changes from f7c3c02c..e38b85b4
e38b85b4 [studio] Eliminate redundant serialization and deserialization

git-subtree-dir: deps/nostalgia
git-subtree-split: e38b85b4f4134af04b9b71caddcd2268f425f5df
2025-07-31 00:41:06 -05:00
8aea7c2ecf [nostalgia/gfx] Add lists for file extensions
All checks were successful
Build / build (push) Successful in 1m31s
2025-07-31 00:39:55 -05:00
e9a7fb1ec8 [ox/std] Fix MSVC build
Some checks failed
Build / build (push) Has been cancelled
2025-07-31 00:38:26 -05:00
375388c0f1 Squashed 'deps/nostalgia/' changes from e27eee50..f7c3c02c
f7c3c02c Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
8f0f1fea [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets
2f36a3f6 [studio] Add File -> Reload Project menu item
07e5bf90 [keel] Make keel attempt to delete all existing assets when FS is changed
aacff3da [ox/std] Fix UPtr::reset to conform to unique_ptr::reset

git-subtree-dir: deps/nostalgia
git-subtree-split: f7c3c02c4cbe676ea116ea53f1f31b27f668cd98
2025-07-30 01:51:46 -05:00
084baa6005 Merge commit '375388c0f16a0de1b16575578ad49e8318a1c80f'
All checks were successful
Build / build (push) Successful in 1m31s
2025-07-30 01:51:46 -05:00
b1f912445d Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
All checks were successful
Build / build (push) Successful in 1m29s
2025-07-30 00:42:42 -05:00
1bfb7f99c2 Squashed 'deps/nostalgia/' changes from c7bc2a95..e27eee50
e27eee50 [teagba] Add set and scroll background offset functions
fd610454 [nostalgia/gfx] Fix compiler warning
e61d4647 [nostalgia/gfx] Fix BG tilesheet loading, add background offset functions
c275c5f5 [hull] Disable building hull for now
fbf49ba5 [ox/std] Add pre- and post-increment operators to Span
92f74b27 [ox/std] Add null check for deallocating in consteval context Vector
934f0c92 [ox/std] Add beginsWith and endsWith variants that that cingle chars
ee9a3e11 [ox/std] Cleanup
16886cdf [hull] Add start on command interpreter
08b9508d [ox/std] Give std::ignore a named type
69bd968f [nostalgia/player] Fix build
4e7dc666 [nostalgia,olympic] Rename string len() functions to size()
bea0cf5a [ox/std] Rename string len() functions to size()

git-subtree-dir: deps/nostalgia
git-subtree-split: e27eee50f05bb437710313430e0d9cef636a66b1
2025-07-30 00:40:03 -05:00
10db939d62 [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets 2025-07-30 00:37:59 -05:00
553797fdbd [studio] Add File -> Reload Project menu item 2025-07-30 00:37:23 -05:00
fb0cd99d8c [keel] Make keel attempt to delete all existing assets when FS is changed 2025-07-30 00:36:56 -05:00
a372814e3c [ox/std] Fix UPtr::reset to conform to unique_ptr::reset 2025-07-30 00:29:34 -05:00
ceea6c7b27 [nostalgia/player] Fix build
All checks were successful
Build / build (push) Successful in 1m40s
2025-07-25 22:54:43 -05:00
7f6e734026 [jasper/world/studio] Cleanup
Some checks failed
Build / build (push) Failing after 22s
2025-07-25 22:51:14 -05:00
2863874ae0 [jasper/project] Fill out more facets of player assets 2025-07-25 22:51:02 -05:00
d0277a43fc [jasper/world/studio] Rename string len() functions to size() 2025-07-25 22:49:35 -05:00
aa875e9be2 [nostalgia,olympic] Rename string len() functions to size() 2025-07-25 22:48:08 -05:00
b126a3a859 [ox/std] Rename string len() functions to size() 2025-07-25 22:47:56 -05:00
90613184e0 [jasper] Add make loc command 2025-07-25 22:45:14 -05:00
8a74e044dc Squashed 'deps/nostalgia/' changes from fae1e73e..c7bc2a95
c7bc2a95 [nostalgia/gfx] Style update
7372036a [nostalgia/gfx] Add function missing from header
7461d832 [nostalgia/gfx/studio,studio] Fix CLI tool output to only show usage if no args given
6052798f Merge commit 'dceeaaa9302b7e9ce85fa773fc187bc593f3c93c'
801d35c8 [keel] Make type converters work with functions that take const src arg

git-subtree-dir: deps/nostalgia
git-subtree-split: c7bc2a954fdf435127fb09896f32c5cb23c99f02
2025-07-25 00:32:02 -05:00
f1d4c20c88 Merge commit '8a74e044dc5fa44ba10dbbf7d2812c7070ff4f7c'
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-25 00:32:02 -05:00
6a7226ae68 [jasper/world/studio] Fix build
All checks were successful
Build / build (push) Successful in 1m33s
2025-07-24 02:02:46 -05:00
dceeaaa930 Squashed 'deps/nostalgia/' changes from 671b8eda..fae1e73e
fae1e73e [nostalgia/gfx] Make getSubSheet check root subsheet name
51f2905c [nostalgia/gfx/studio] Make TileSheetEditor use export-tilesheet functions for export, fix exporting Root subsheet
0c866d1b [studio,nostalgia/gfx] Add system for adding sub-commands in Modules, add export-tilesheet command
fdf39d1a [ox/std] Add Result::transformError
a523a75e [ox/std] Add missing include to StringParam
cdaa64ed [ox/clargs] Fix arg parsing for first '-'
37b5fcc0 [teagba] Put parentheses around all registers
f5f2c3be [studio/applib] Make Studio remove files unable to be opened from open file list in config
f6ef2b5a [turbine,nostalgia] Make memory regions cast to bounded ox::Arrays
bf958a4a [teagba] Make memory regions cast to bounded ox::Arrays
6a70e478 [nostalgia/gfx] Cleanup

git-subtree-dir: deps/nostalgia
git-subtree-split: fae1e73e54a420d4b93af67e03144d5442825a11
2025-07-24 01:58:27 -05:00
86860cf27b Merge commit 'dceeaaa9302b7e9ce85fa773fc187bc593f3c93c' 2025-07-24 01:58:27 -05:00
6f80f634b0 [jasper/world/keel] Make convertWorldDocToWorldStatic take a const src
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-23 00:42:41 -05:00
99ee44b838 [keel] Make type converters work with functions that take const src arg 2025-07-23 00:41:33 -05:00
be7dd92971 Merge commit 'b0726568df6aaa37390906ca44ff1eee11735f98'
All checks were successful
Build / build (push) Successful in 1m34s
2025-06-29 17:34:57 -05:00
b0726568df Squashed 'deps/nostalgia/' changes from f847289b..671b8eda
671b8eda [ox/std] Make StringLiteral constructors consteval
952637a1 Merge commit 'cbf4414fcaf00c00a2abf73b5c04a055180ad980'
7569698e [nostalgia,studio] Add FileExts_TileSheet const, and corresponding FilePickerPopup constructor
21713ba9 [ox/std] Fix StringLiteral::operator= to work with DevkitARM
73273b6f [nostalgia/gfx] Add isTileSheet function for checking paths against both file extensions
9f040392 [olympic,nostalgia] Cleanup style
f4f7e5d0 Merge commit '9b5f7886cadc5c3dc826d00fa5b2e71696151dfd'
c27726a4 Merge commit '6bbcae10cc7b21b73171ec0ff196f4baf6304404'
bd24a775 Merge commit '7371df429534f264c179684412f6197f7968ebfa'
4419dff2 Merge commit '7688c05bac8c20bc267cae62ec78d55e5d0c493b'
536999c0 Merge commit '47eee1d56d591e3631d16e95a78ea3629ee312ee'
a5535ef5 Merge commit '08236fc790e711afe886b6ef545511d35e4e5c6c'
a90380f3 Merge commit 'e90dd887477452922f783535edb3d4c55e9a0d2c'
2000b2de [nostalgia/gfx/studio] Cleanup
7d92400f [nostalgia/gfx/studio] Add type specific navigateTo functions

git-subtree-dir: deps/nostalgia
git-subtree-split: 671b8edaadefe1872fb8954ad13d221b24f676c0
2025-06-29 17:33:27 -05:00
d98d78890a [jasper/world] Fix WorldObjectSetEditor to handle .ng and .nts file extensions
All checks were successful
Build / build (push) Successful in 1m45s
2025-06-25 21:32:23 -05:00
43efcbf59f [nostalgia,studio] Add FileExts_TileSheet const, and corresponding FilePickerPopup constructor 2025-06-25 21:30:49 -05:00
07e223937b [ox/std] Fix StringLiteral::operator= to work with DevkitARM 2025-06-25 21:29:41 -05:00
f1ad8567f3 [nostalgia/gfx] Add isTileSheet function for checking paths against both file extensions 2025-06-25 21:03:45 -05:00
9b5f7886ca Squashed 'deps/nostalgia/' changes from 37cfa927..f847289b
f847289b [glutils] Cleanup
94b0020d [nostalgia,olympic] Cleanup
c54c0bad [teagba] Cleanup
b9ffae02 [nostalgia/gfx] Cleanup
003f3e01 [nostalgia] Update release notes
9028e74a [nostalgia/gfx/studio/tilesheet] Disable paste when nothing is selected
f5ccab5f [studio] Cleanup

git-subtree-dir: deps/nostalgia
git-subtree-split: f847289bd493e3318eb6fc1d09ea216e140899aa
2025-06-23 20:49:01 -05:00
2c8a8a4e9f Merge commit '9b5f7886cadc5c3dc826d00fa5b2e71696151dfd' 2025-06-23 20:49:01 -05:00
6bbcae10cc Squashed 'deps/nostalgia/' changes from 857587c1..37cfa927
37cfa927 [nostalgia/gfx] Address a couple of implicit conversions
0efed70b [studio] Fix Studio to clear editor pointers when opening a new project
baf5fa31 [nostalgia] Move d2025.05.2 release notes to d2025.06.0

git-subtree-dir: deps/nostalgia
git-subtree-split: 37cfa927d1d63390d91a6c4b98021023552dd980
2025-06-21 14:29:47 -05:00
d4201a7183 Merge commit '6bbcae10cc7b21b73171ec0ff196f4baf6304404' 2025-06-21 14:29:47 -05:00
7371df4295 Squashed 'deps/nostalgia/' changes from e78c4050..857587c1
857587c1 [studio] Cleanup
eb3d53c9 [studio] Cleanup
14d58f3f [studio] Fix Navigation shortcuts for non-Mac systems
5f239790 [studio,nostalgia/gfx/studio/tilesheet] Fix copy/cut/paste enablement when there is no selection
58e0ecb4 [studio] Make FilePickerPopup accept on double click of a file
8838bf42 [studio] Fix to properly copy file that has the same name as deleted file
bddc544d [nostalgia] Update release notes
a9437191 [studio,turbine] Add support for mouse back/forward buttons
9d8da7cc [ox/std] Make strToInt return error for empty string
394b568e [studio] Add Back/Forward navigation
78e9f70d [nostalgia] Update release notes
12e5623f [ox/logconn] Add exception handling for logger thread
cfdfb0a8 [studio] Fix file deletion to close file even if not active
56e66530 [studio] Cleanup
7415ce4b [nostalgia/gfx/studio] Cleanup
05f42150 [olympic] Add new loc command to Makefile
8ea2bc69 [nostalgia] Update release notes
c7809241 [studio] Add [DEBUG] tag to About in debug builds
8c538560 [nostalgia/gfx/studio/palette] Make RGB key shortcuts work when color channel inputs are focused
c3e75bdb [nostalgia/gfx/studio/tilesheet] Cleanup

git-subtree-dir: deps/nostalgia
git-subtree-split: 857587c18b4695eacd31457e3c30b4971b4e46e8
2025-06-21 08:48:13 -05:00
ba524fc733 Merge commit '7371df429534f264c179684412f6197f7968ebfa'
All checks were successful
Build / build (push) Successful in 1m32s
2025-06-21 08:48:13 -05:00
177 changed files with 2815 additions and 1839 deletions

View File

@@ -15,16 +15,26 @@ else
endif endif
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-gba.py project ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-gba.py project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac .PHONY: pkg-mac
pkg-mac: install pkg-mac: install
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-dmg.py JasperStudio ${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-dmg.py JasperStudio
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player .PHONY: build-player
build-player: build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run .PHONY: run
run: build-player run: build-player
${PROJECT_PLAYER} project ${PROJECT_PLAYER} project
@@ -65,3 +75,38 @@ git-push-nostalgia:
.PHONY: generate-studio-rsrc .PHONY: generate-studio-rsrc
generate-studio-rsrc: generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/file-to-cpp.py --rsrc src/jasper/tools/rsrc.json ${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/file-to-cpp.py --rsrc src/jasper/tools/rsrc.json
.PHONY: loc
loc:
${BC_PY3} deps/nostalgia/util/scripts/loc.py \
--search-dirs \
src \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake
.PHONY: loc-full
loc-full:
${BC_PY3} deps/nostalgia/util/scripts/loc.py \
--search-dirs \
src \
deps/nostalgia/src \
deps/nostalgia/deps/ox/src \
deps/nostalgia/deps/buildcore \
deps/nostalgia/deps/gbabuildcore \
deps/nostalgia/deps/glutils \
deps/nostalgia/deps/teagba \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake \
--exclude-paths \
deps/nostalgia/deps/teagba/src/gba_crt0.s \
deps/nostalgia/src/olympic/studio/applib/src/font.cpp \
deps/nostalgia/src/olympic/studio/applib/src/font.hpp \
deps/nostalgia/src/nostalgia/studio/icondata.cpp

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP} PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac .PHONY: pkg-mac
@@ -26,25 +26,44 @@ generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player .PHONY: build-player
build-player: build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run .PHONY: run
run: build-player run: build-player
${PROJECT_PLAYER} sample_project ${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build-studio
${PROJECT_STUDIO} ${PROJECT_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba ${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project ${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
configure-gba: configure-gba:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH} ${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}
@@ -52,3 +71,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{};
@@ -176,7 +176,7 @@ struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams; ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] { GLsizei const rowLen = [this] {
GLsizei len{}; GLsizei len{};
for (auto const&v : shaderParams) { for (auto const &v : shaderParams) {
len += v.len; len += v.len;
} }
return len; return len;
@@ -187,23 +187,23 @@ struct ProgramSource {
ox::String const geomShader{}; ox::String const geomShader{};
}; };
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept; ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept;
ox::Result<GLProgram> buildShaderProgram( ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert, ox::CStringView const &vert,
ox::CStringView const&frag, ox::CStringView const &frag,
ox::CStringView const&geo = "") noexcept; ox::CStringView const &geo = "") noexcept;
void setupShaderParams( void setupShaderParams(
GLProgram const&shader, GLProgram const &shader,
ox::Vector<ShaderVarSet> const&vars, ox::Vector<ShaderVarSet> const &vars,
GLsizei vertexRowLen) noexcept; GLsizei vertexRowLen) noexcept;
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;
@@ -215,20 +215,20 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
*/ */
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept; 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;
}; };
void sendVbo(BufferSet const&bs) noexcept; void sendVbo(BufferSet const &bs) noexcept;
void sendEbo(BufferSet const&bs) noexcept; void sendEbo(BufferSet const &bs) noexcept;
void clearScreen() noexcept; void clearScreen() noexcept;

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);
@@ -88,7 +88,7 @@ static ox::Result<GLShader> buildShader(
return shader; return shader;
} }
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept { ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
OX_REQUIRE_M(program, buildShaderProgram( OX_REQUIRE_M(program, buildShaderProgram(
src.vertShader, src.vertShader,
src.fragShader, src.fragShader,
@@ -98,11 +98,11 @@ ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
} }
void setupShaderParams( void setupShaderParams(
GLProgram const&shader, GLProgram const &shader,
ox::Vector<ShaderVarSet> const&vars, ox::Vector<ShaderVarSet> const &vars,
GLsizei vertexRowLen) noexcept { GLsizei vertexRowLen) noexcept {
// setup vars // setup vars
for (size_t lenWritten = 0; auto const&v : vars) { for (size_t lenWritten = 0; auto const &v : vars) {
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str())); auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
glEnableVertexAttribArray(attr); glEnableVertexAttribArray(attr);
glVertexAttribPointer( glVertexAttribPointer(
@@ -113,19 +113,19 @@ void setupShaderParams(
} }
} }
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept { void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept {
// get row len // get row len
GLsizei vertexRowLen{}; GLsizei vertexRowLen{};
for (auto const&v : vars) { for (auto const &v : vars) {
vertexRowLen += v.len; vertexRowLen += v.len;
} }
setupShaderParams(shader, vars, vertexRowLen); setupShaderParams(shader, vars, vertexRowLen);
} }
ox::Result<GLProgram> buildShaderProgram( ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert, ox::CStringView const &vert,
ox::CStringView const&frag, ox::CStringView const &frag,
ox::CStringView const&geo) noexcept { ox::CStringView const &geo) noexcept {
GLProgram prgm(glCreateProgram()); GLProgram prgm(glCreateProgram());
OX_REQUIRE(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad")); OX_REQUIRE(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
glAttachShader(prgm, vs); glAttachShader(prgm, vs);
@@ -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;
@@ -209,18 +232,18 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
resizeFrameBuffer(fb, width, height); resizeFrameBuffer(fb, width, height);
} }
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept { void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept {
resizeInitFrameBuffer(fb, sz.width, sz.height); resizeInitFrameBuffer(fb, sz.width, sz.height);
} }
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

@@ -15,16 +15,16 @@ ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept { ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
for (auto i = 0u; i < args.size(); ++i) { for (auto i = 0u; i < args.size(); ++i) {
auto arg = StringView(args[i]); auto arg = StringView{args[i]};
if (arg[0] == '-') { if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) { while (arg[0] == '-' && arg.size()) {
arg = substr(arg, 1); arg = substr(arg, 1);
} }
m_bools[arg] = true; m_bools[arg] = true;
// parse additional arguments // parse additional arguments
if (i < args.size() && args[i + 1]) { if (i < args.size() && args[i + 1]) {
auto val = String(args[i + 1]); auto const val = StringView{args[i + 1]};
if (val.len() && val[i] != '-') { if (val.size() && val[0] != '-') {
if (val == "false") { if (val == "false") {
m_bools[arg] = false; m_bools[arg] = false;
} }
@@ -40,17 +40,17 @@ ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
} }
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept { bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept { String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg); auto const [value, err] = m_strings.at(arg);
return !err ? ox::String(*value) : ox::String(defaultValue); return !err ? ox::String(*value) : ox::String(defaultValue);
} }
int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept { int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }

View File

@@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader", "ClawHeaderReader",
[] { [] {
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;"); constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1}); auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong"); oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
@@ -121,7 +121,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader2", "ClawHeaderReader2",
[] { [] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;"); constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1}); auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong"); oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
@@ -134,7 +134,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
[] { [] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf"); constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3"); constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1})); OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
oxExpect(actual, expected); oxExpect(actual, expected);
return ox::Error{}; return ox::Error{};
} }

View File

@@ -52,7 +52,7 @@ struct OX_PACKED DirectoryEntry {
if (d.valid()) { if (d.valid()) {
d->inode = inode; d->inode = inode;
auto const maxStrSz = bufferSize - 1 - sizeof(*this); auto const maxStrSz = bufferSize - 1 - sizeof(*this);
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len())); ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.size()));
return {}; return {};
} }
return ox::Error(1); return ox::Error(1);
@@ -219,7 +219,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory"); oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
return ox::Error(1, "Could not read existing version of Directory"); return ox::Error(1, "Could not read existing version of Directory");
} }
const auto pathSize = name.len() + 1; const auto pathSize = name.size() + 1;
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize); const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize); const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size); auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);

View File

@@ -87,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); return writeFilePath(path, buffer, size, FileType::NormalFile);
} }
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept { Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile); return write(path, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -95,7 +95,7 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile); return write(inode, buffer, size, FileType::NormalFile);
} }
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept { Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile); return write(inode, buff.data(), buff.size(), FileType::NormalFile);
} }

View File

@@ -206,7 +206,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
} }
std::string_view PassThroughFS::stripSlash(StringView path) noexcept { std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
for (auto i = 0u; i < path.len() && path[0] == '/'; i++) { for (auto i = 0u; i < path.size() && path[0] == '/'; i++) {
path = substr(path, 1); path = substr(path, 1);
} }
return {path.data(), path.bytes()}; return {path.data(), path.bytes()};

View File

@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
if (size && fileName[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + size - 1); fileName = ox::substr(m_path, start, start + size - 1);
} }
oxAssert(fileName[fileName.len()-1] != '/', "name ends in /"); oxAssert(fileName[fileName.size()-1] != '/', "name ends in /");
return {}; return {};
} }
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
} }
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
// truncate trailing / // truncate trailing /
while (fileName.len() && fileName[fileName.len() - 1] == '/') { while (fileName.size() && fileName[fileName.size() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
} }
m_iterator += size; m_iterator += size;
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /"); oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /");
} }
return retval; return retval;
} }

View File

@@ -59,7 +59,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next1", "PathIterator::next1",
[](ox::StringView) { [](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next3", "PathIterator::next3",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/"); auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return ox::Error(0); return ox::Error(0);
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next5", "PathIterator::next5",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("usr/share/"); auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -117,10 +117,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::dirPath", "PathIterator::dirPath",
[] (ox::StringView) { [] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.size());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path"); oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0); return ox::Error(0);
} }

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

@@ -157,7 +157,6 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch"); oxAssert(testIn.String == testOut.String, "String value mismatch");
oxDebugf("{}", testOut.IString.len());
oxExpect(testIn.IString, testOut.IString); oxExpect(testIn.IString, testOut.IString);
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");

View File

@@ -191,12 +191,12 @@ template<Writer_c Writer>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) { if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length // write the length
const auto strLen = mc::encodeInteger(val->len()); const auto strLen = mc::encodeInteger(val->size());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length)); OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length));
// write the string // write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len()))); OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->size())));
fieldSet = true; fieldSet = true;
} }
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));
@@ -207,7 +207,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
template<Writer_c Writer> template<Writer_c Writer>
template<std::size_t L> template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->len()); return fieldCString(name, val->data(), val->size());
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -339,7 +339,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
OX_RETURN_ERROR(handler.setTypeInfo("Map", 0, {}, len * 2)); OX_RETURN_ERROR(handler.setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call // this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error { constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = key.len(); const auto keyLen = key.size();
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1); memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen)); OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));

View File

@@ -43,7 +43,7 @@ static constexpr auto buildTypeId(
for (const auto &p : typeParams) { for (const auto &p : typeParams) {
tp += p + ","; tp += p + ",";
} }
tp.resize(tp.len() - 1); tp.resize(tp.size() - 1);
tp += "#"; tp += "#";
} }
return ox::sfmt("{}{};{}", name, tp, version); return ox::sfmt("{}{};{}", name, tp, version);

View File

@@ -144,7 +144,7 @@ template<typename T, typename Str = const char*>
[[nodiscard]] [[nodiscard]]
consteval auto requireModelTypeName() noexcept { consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>(); constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName"); static_assert(ox::StringView{name}.size(), "Type lacks required TypeName");
return name; return name;
} }
@@ -159,7 +159,7 @@ constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>; constexpr auto name = ModelTypeName_v<T, ox::StringView>;
constexpr auto version = ModelTypeVersion_v<T>; constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version); constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr); return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
}(); }();
} }

View File

@@ -181,7 +181,6 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
} }
} }
} catch (Json::LogicError const&e) { } catch (Json::LogicError const&e) {
oxDebugf("JSON error: {}", e.what());
err = ox::Error(1, "error reading JSON data"); err = ox::Error(1, "error reading JSON data");
} }
++m_fieldIt; ++m_fieldIt;
@@ -307,7 +306,7 @@ Result<T> readOC(BufferView buff) noexcept {
template<typename T> template<typename T>
Result<T> readOC(ox::StringView json) noexcept { Result<T> readOC(ox::StringView json) noexcept {
return readOC<T>(ox::BufferView{json.data(), json.len()}); return readOC<T>(ox::BufferView{json.data(), json.size()});
} }
} }

View File

@@ -32,7 +32,7 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) no
Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept { Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept {
const auto uuidStr = uuid->toString(); const auto uuidStr = uuid->toString();
if (targetValid() && uuidStr.len()) { if (targetValid() && uuidStr.size()) {
value(key) = uuidStr.c_str(); value(key) = uuidStr.c_str();
} }
++m_fieldIt; ++m_fieldIt;

View File

@@ -138,7 +138,7 @@ class OrganicClawWriter {
template<std::size_t L> template<std::size_t L>
Error field(char const*key, IString<L> const*val) noexcept { Error field(char const*key, IString<L> const*val) noexcept {
if (targetValid() && val->len()) { if (targetValid() && val->size()) {
value(key) = val->c_str(); value(key) = val->c_str();
} }
++m_fieldIt; ++m_fieldIt;
@@ -147,7 +147,7 @@ class OrganicClawWriter {
template<std::size_t L> template<std::size_t L>
Error field(char const*key, BasicString<L> const*val) noexcept { Error field(char const*key, BasicString<L> const*val) noexcept {
if (targetValid() && val->len()) { if (targetValid() && val->size()) {
value(key) = val->c_str(); value(key) = val->c_str();
} }
++m_fieldIt; ++m_fieldIt;

View File

@@ -33,6 +33,9 @@ void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const
#endif #endif
} }
#if __GNUC__ && !_WIN32
__attribute__((weak))
#endif
void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept { void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err); panic(StringView{file}, line, StringView{panicMsg}, err);
} }

View File

@@ -185,7 +185,7 @@ class BaseStringView {
} }
[[nodiscard]] [[nodiscard]]
constexpr auto len() const noexcept { constexpr auto size() const noexcept {
return m_len; return m_len;
} }

View File

@@ -21,13 +21,13 @@ class CStringView: public detail::BaseStringView {
constexpr CStringView(CStringView const&sv) noexcept = default; constexpr CStringView(CStringView const&sv) noexcept = default;
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz> template<std::size_t SmallStrSz>
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz> template<std::size_t SmallStrSz>
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr CStringView(std::nullptr_t) noexcept {} constexpr CStringView(std::nullptr_t) noexcept {}
@@ -37,7 +37,7 @@ class CStringView: public detail::BaseStringView {
constexpr auto &operator=(CStringView const&other) noexcept { constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) { if (&other != this) {
set(other.data(), other.len()); set(other.data(), other.size());
} }
return *this; return *this;
} }

View File

@@ -307,6 +307,13 @@ struct [[nodiscard]] Result {
return std::move(value); return std::move(value);
} }
constexpr Result transformError(ErrorCode const ec, CString const msg) && {
if (error) {
error = Error{ec, msg};
}
return *this;
}
}; };
namespace detail { namespace detail {

View File

@@ -16,7 +16,7 @@
namespace std { namespace std {
inline constexpr struct { inline constexpr struct ignore_t {
constexpr void operator=(auto&&) const noexcept {} constexpr void operator=(auto&&) const noexcept {}
} ignore; } ignore;

View File

@@ -72,7 +72,7 @@ class IString {
* Returns the number of characters in this string. * Returns the number of characters in this string.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr std::size_t len() const noexcept; constexpr std::size_t size() const noexcept;
/** /**
* Returns the number of bytes used for this string. * Returns the number of bytes used for this string.
@@ -121,7 +121,7 @@ constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
template<std::size_t size> template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(ox::StringViewCR str) noexcept { constexpr IString<size> &IString<size>::operator=(ox::StringViewCR str) noexcept {
std::size_t strLen = str.len(); std::size_t strLen = str.size();
if (cap() < strLen) { if (cap() < strLen) {
strLen = cap(); strLen = cap();
} }
@@ -171,7 +171,7 @@ constexpr char &IString<StrCap>::operator[](std::size_t i) noexcept {
template<std::size_t StrCap> template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept { constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept {
Error err{}; Error err{};
auto const currentLen = len(); auto const currentLen = size();
if (cap() < currentLen + strLen) { if (cap() < currentLen + strLen) {
strLen = cap() - currentLen; strLen = cap() - currentLen;
err = ox::Error(1, "Insufficient space for full string"); err = ox::Error(1, "Insufficient space for full string");
@@ -187,7 +187,7 @@ OX_CLANG_NOWARN_END
template<std::size_t StrCap> template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(ox::StringView str) noexcept { constexpr Error IString<StrCap>::append(ox::StringView str) noexcept {
return append(str.data(), str.len()); return append(str.data(), str.size());
} }
template<std::size_t StrCap> template<std::size_t StrCap>
@@ -207,7 +207,7 @@ constexpr const char *IString<StrCap>::c_str() const noexcept {
template<std::size_t StrCap> template<std::size_t StrCap>
constexpr std::size_t IString<StrCap>::len() const noexcept { constexpr std::size_t IString<StrCap>::size() const noexcept {
return m_size; return m_size;
} }

View File

@@ -213,8 +213,7 @@ class UniquePtr {
return m_t; return m_t;
} }
template<typename U, typename UDeleter> constexpr void reset(UniquePtr &&other = UniquePtr()) {
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
auto t = m_t; auto t = m_t;
m_t = other.release(); m_t = other.release();
Deleter()(t); Deleter()(t);

View File

@@ -30,11 +30,49 @@ constexpr void *operator new(std::size_t, void *addr) noexcept {
constexpr void *operator new[](std::size_t, void *addr) noexcept { constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr; return addr;
} }
namespace std {
template<typename T>
[[nodiscard]]
constexpr T* launder(T* __p) noexcept {
return __builtin_launder(__p);
}
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args...) noexcept(noex)) = delete;
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args......) noexcept(noex)) = delete;
void launder(void*) = delete;
void launder(void const*) = delete;
void launder(volatile void*) = delete;
void launder(volatile void const*) = delete;
}
#endif #endif
namespace ox { namespace ox {
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<T const*>(this);
}
};
template<typename T, typename U = T, typename ...Args> template<typename T, typename U = T, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr U *make(Args &&...args) noexcept { constexpr U *make(Args &&...args) noexcept {

View File

@@ -30,13 +30,15 @@ constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
ox::Result<char> StreamReader::peek() const noexcept { ox::Result<char> StreamReader::peek() const noexcept {
try { try {
if (m_strm.eof()) {
return Error{1, "EOF"};
}
char c{}; char c{};
m_strm.get(c); m_strm.get(c);
auto const ok = c != EOF; if (m_strm.unget()) [[unlikely]] {
if (ok && m_strm.unget()) [[unlikely]] { return ox::Error{1, "Unable to unget character"};
return ox::Error(1, "Unable to unget character");
} }
return {static_cast<char>(c), ox::Error(!ok, "File peek failed")}; return static_cast<char>(c);
} catch (std::exception const&) { } catch (std::exception const&) {
return ox::Error(1, "peek failed"); return ox::Error(1, "peek failed");
} }

View File

@@ -163,6 +163,24 @@ class Span {
return *this; return *this;
} }
constexpr Span operator++(int) noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
constexpr Span operator++() noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
[[nodiscard]] [[nodiscard]]
constexpr auto data() const noexcept { constexpr auto data() const noexcept {
return m_items; return m_items;

View File

@@ -139,7 +139,7 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept; constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept; constexpr BasicString &operator+=(StringViewCR src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept; constexpr BasicString &operator+=(BasicString const&src) noexcept;
@@ -176,7 +176,7 @@ class BasicString {
constexpr char &operator[](std::size_t i) noexcept; constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept { constexpr Error append(const char *str, std::size_t strLen) noexcept {
auto currentLen = len(); auto currentLen = size();
m_buff.resize(m_buff.size() + strLen); m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&m_buff[currentLen], str, strLen); ox::listcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator // make sure last element is a null terminator
@@ -185,8 +185,8 @@ class BasicString {
return {}; return {};
} }
constexpr Error append(ox::StringView sv) noexcept { constexpr Error append(StringViewCR sv) noexcept {
return append(sv.data(), sv.len()); return append(sv.data(), sv.size());
} }
[[nodiscard]] [[nodiscard]]
@@ -237,7 +237,7 @@ class BasicString {
* Returns the number of characters in this string. * Returns the number of characters in this string.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr std::size_t len() const noexcept; constexpr std::size_t size() const noexcept;
/** /**
* Returns the number of bytes used for this string. * Returns the number of bytes used for this string.
@@ -277,7 +277,7 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept: constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept:
BasicString(StringView{str.data(), str.len()}) { BasicString(StringView{str.data(), str.size()}) {
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
@@ -376,7 +376,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringViewCR s) noexcept {
std::size_t strLen = s.bytes(); std::size_t strLen = s.bytes();
std::ignore = append(s.data(), strLen); std::ignore = append(s.data(), strLen);
return *this; return *this;
@@ -384,14 +384,14 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
std::ignore = append(src.c_str(), src.len()); std::ignore = append(src.c_str(), src.size());
return *this; return *this;
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox::strlen(str); const std::size_t strLen = ox::strlen(str);
const auto currentLen = len(); const auto currentLen = size();
BasicString<SmallStringSize_v> cpy; BasicString<SmallStringSize_v> cpy;
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -420,8 +420,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept {
const std::size_t strLen = src.len(); const std::size_t strLen = src.size();
const auto currentLen = len(); const auto currentLen = size();
BasicString<SmallStringSize_v> cpy(currentLen + strLen); BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -432,8 +432,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.len(); const std::size_t strLen = src.size();
const auto currentLen = len(); const auto currentLen = size();
BasicString<SmallStringSize_v> cpy(currentLen + strLen); BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -456,7 +456,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return ox::StringView(*this) == ox::StringView(other); return StringView(*this) == StringView(other);
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
@@ -521,7 +521,7 @@ constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept { constexpr std::size_t BasicString<SmallStringSize_v>::size() const noexcept {
return m_buff.size() - 1; return m_buff.size() - 1;
} }
@@ -548,28 +548,28 @@ using StringCR = String const&;
[[nodiscard]] [[nodiscard]]
constexpr ox::String toString(ox::StringViewCR sv) noexcept { constexpr String toString(StringViewCR sv) noexcept {
return ox::String(sv); return ox::String(sv);
} }
template<typename PlatSpec, std::size_t SmallStringSize_v> template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]] [[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept { constexpr auto sizeOf(BasicString<SmallStringSize_v> const*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v}; VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v); return sizeOf<PlatSpec>(&v);
} }
template<typename PlatSpec, std::size_t SmallStringSize_v> template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]] [[nodiscard]]
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept { constexpr auto alignOf(BasicString<SmallStringSize_v> const&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v}; VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v); return alignOf<PlatSpec>(&v);
} }
template<size_t sz> template<size_t sz>
struct MaybeView<ox::BasicString<sz>> { struct MaybeView<BasicString<sz>> {
using type = ox::StringView; using type = StringView;
}; };
} }

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; constexpr 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.size());
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

@@ -8,6 +8,7 @@
#pragma once #pragma once
#include "cstringview.hpp"
#include "string.hpp" #include "string.hpp"
namespace ox { namespace ox {

View File

@@ -40,10 +40,10 @@ class StringView: public detail::BaseStringView {
constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {} constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
template<std::size_t SmallStrSz> template<std::size_t SmallStrSz>
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz> template<std::size_t SmallStrSz>
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {} constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr StringView(std::nullptr_t) noexcept {} constexpr StringView(std::nullptr_t) noexcept {}
@@ -53,7 +53,7 @@ class StringView: public detail::BaseStringView {
constexpr auto &operator=(StringView const&other) noexcept { constexpr auto &operator=(StringView const&other) noexcept {
if (&other != this) { if (&other != this) {
set(other.data(), other.len()); set(other.data(), other.size());
} }
return *this; return *this;
} }
@@ -63,14 +63,14 @@ class StringView: public detail::BaseStringView {
using StringViewCR = StringView const&; 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.size() != s1.size()) {
return false; return false;
} }
return ox::strncmp(s1.data(), s2.data(), s1.len()) == 0; return ox::strncmp(s1.data(), s2.data(), s1.size()) == 0;
} }
constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept { constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
const auto maxLen = ox::min(s1.len(), s2.len()); const auto maxLen = ox::min(s1.size(), s2.size());
const auto a = &s1.front(); const auto a = &s1.front();
const auto b = &s2.front(); const auto b = &s2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) { for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
@@ -80,9 +80,9 @@ constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
return 1; return 1;
} }
} }
if (s1.len() > s2.len()) { if (s1.size() > s2.size()) {
return 1; return 1;
} else if (s1.len() < s2.len()) { } else if (s1.size() < s2.size()) {
return -1; return -1;
} else { } else {
return 0; return 0;
@@ -104,13 +104,16 @@ 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;
for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) { if (str.size() == 0) [[unlikely]] {
return Error{1, "Empty string passed to strToInt"};
}
for (auto i = static_cast<int64_t>(str.size()) - 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

@@ -21,37 +21,47 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
[[nodiscard]] [[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept { constexpr StringView substr(StringViewCR str, std::size_t const pos) noexcept {
if (str.len() >= pos) { if (str.size() >= pos) {
return {&str[pos], str.len() - pos}; return {&str[pos], str.size() - pos};
} }
return {}; return {};
} }
[[nodiscard]] [[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept { constexpr StringView substr(StringViewCR str, std::size_t const start, std::size_t const end) noexcept {
if (str.len() >= start && end >= start) { if (str.size() >= start && end >= start) {
return {&str[start], end - start}; return {&str[start], end - start};
} }
return {}; return {};
} }
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, char const ending) noexcept {
return base.size() && base[base.size() - 1] == ending;
}
[[nodiscard]] [[nodiscard]]
constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept { constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len()); const auto beginningLen = ox::min(beginning.size(), base.size());
return base.len() >= beginning.len() && ox::strncmp(base.data(), beginning, beginningLen) == 0; return base.size() >= beginning.size() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
} }
[[nodiscard]] [[nodiscard]]
constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept { constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept {
const auto endingLen = ending.len(); const auto endingLen = ending.size();
return base.len() >= endingLen && ox::strcmp(base.data() + (base.len() - endingLen), ending) == 0; return base.size() >= endingLen && ox::strcmp(base.data() + (base.size() - endingLen), ending) == 0;
} }
[[nodiscard]] [[nodiscard]]
constexpr std::size_t find(StringViewCR str, char search) noexcept { constexpr std::size_t find(StringViewCR str, char const search) noexcept {
std::size_t i = 0; std::size_t i = 0;
for (; i < str.len(); ++i) { for (; i < str.size(); ++i) {
if (str[i] == search) { if (str[i] == search) {
break; break;
} }
@@ -62,7 +72,7 @@ constexpr std::size_t find(StringViewCR str, char search) noexcept {
[[nodiscard]] [[nodiscard]]
constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept { constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
std::size_t i = 0; std::size_t i = 0;
for (; i < str.len(); ++i) { for (; i < str.size(); ++i) {
if (beginsWith(substr(str, i), search)) { if (beginsWith(substr(str, i), search)) {
break; break;
} }
@@ -72,14 +82,14 @@ constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
template<std::size_t smallSz = 0> template<std::size_t smallSz = 0>
[[nodiscard]] [[nodiscard]]
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char del) noexcept { constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char const del) noexcept {
ox::Vector<ox::StringView, smallSz> out; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, char del) { constexpr auto nextSeg = [](StringViewCR current, char del) {
return substr(current, find(current, del) + 1); return substr(current, find(current, del) + 1);
}; };
for (auto current = str; current.len(); current = nextSeg(current, del)) { for (auto current = str; current.size(); current = nextSeg(current, del)) {
const auto next = find(current, del); const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) { if (const auto s = substr(current, 0, next); s.size()) {
out.emplace_back(s); out.emplace_back(s);
} }
current = substr(current, next); current = substr(current, next);
@@ -92,11 +102,11 @@ template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringViewCR del) noexcept { constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringViewCR del) noexcept {
ox::Vector<ox::StringView, smallSz> out; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, StringViewCR del) { constexpr auto nextSeg = [](StringViewCR current, StringViewCR del) {
return substr(current, find(current, del) + del.len()); return substr(current, find(current, del) + del.size());
}; };
for (auto current = str; current.len(); current = nextSeg(current, del)) { for (auto current = str; current.size(); current = nextSeg(current, del)) {
const auto next = find(current, del); const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) { if (const auto s = substr(current, 0, next); s.size()) {
out.emplace_back(s); out.emplace_back(s);
} }
current = substr(current, next); current = substr(current, next);
@@ -105,7 +115,7 @@ constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringView
} }
[[nodiscard]] [[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int character) noexcept { constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int const character) noexcept {
ox::Result<std::size_t> retval = ox::Error(1, "Character not found"); ox::Result<std::size_t> retval = ox::Error(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) { for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) { if (str[static_cast<std::size_t>(i)] == character) {

View File

@@ -183,7 +183,7 @@ OX_CLANG_NOWARN_END
s = "asdf"; s = "asdf";
oxAssert(s == "asdf", "String assign broken"); oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken"); oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.len() == 4, "String assign broken"); oxAssert(s.size() == 4, "String assign broken");
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -337,7 +337,6 @@ OX_CLANG_NOWARN_END
oxExpect(si["asdf"], 0); oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100"); oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si; auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0); oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100"); oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii; ox::HashMap<int, int> ii;

View File

@@ -166,7 +166,7 @@ class OutStream {
constexpr OutStream &operator<<(Integer_c auto v) noexcept; constexpr OutStream &operator<<(Integer_c auto v) noexcept;
constexpr OutStream &operator<<(char v) noexcept { constexpr OutStream &operator<<(char v) noexcept {
if (m_msg.msg.len()) { if (m_msg.msg.size()) {
m_msg.msg += m_delimiter; m_msg.msg += m_delimiter;
} }
m_msg.msg += v; m_msg.msg += v;
@@ -174,7 +174,7 @@ class OutStream {
} }
constexpr OutStream &operator<<(StringViewCR v) noexcept { constexpr OutStream &operator<<(StringViewCR v) noexcept {
if (m_msg.msg.len()) { if (m_msg.msg.size()) {
m_msg.msg += m_delimiter; m_msg.msg += m_delimiter;
} }
m_msg.msg += v; m_msg.msg += v;
@@ -209,7 +209,7 @@ class OutStream {
private: private:
constexpr OutStream &appendSignedInt(int64_t v) noexcept { constexpr OutStream &appendSignedInt(int64_t v) noexcept {
if (m_msg.msg.len()) { if (m_msg.msg.size()) {
m_msg.msg += m_delimiter; m_msg.msg += m_delimiter;
} }
m_msg.msg += static_cast<int64_t>(v); m_msg.msg += static_cast<int64_t>(v);
@@ -217,7 +217,7 @@ class OutStream {
} }
constexpr OutStream &appendUnsignedInt(uint64_t v) noexcept { constexpr OutStream &appendUnsignedInt(uint64_t v) noexcept {
if (m_msg.msg.len()) { if (m_msg.msg.size()) {
m_msg.msg += m_delimiter; m_msg.msg += m_delimiter;
} }
m_msg.msg += static_cast<int64_t>(v); m_msg.msg += static_cast<int64_t>(v);
@@ -227,7 +227,7 @@ class OutStream {
}; };
constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept { constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
if (m_msg.msg.len()) { if (m_msg.msg.size()) {
m_msg.msg += m_delimiter; m_msg.msg += m_delimiter;
} }
m_msg.msg += v; m_msg.msg += v;
@@ -268,7 +268,7 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept { inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) { if (err) {
TraceStream trc(file, line, "ox::error"); TraceStream trc(file, line, "ox.error");
if (err.src.file_name() != nullptr) { if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):"; trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} else { } else {
@@ -280,7 +280,7 @@ inline void logError(const char *file, int line, const char *fmt, const Error &e
inline void logError(const char *file, int line, const Error &err) noexcept { inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) { if (err) {
TraceStream trc(file, line, "ox::error"); TraceStream trc(file, line, "ox.error");
trc << "Error:" << err; trc << "Error:" << err;
if (err.src.file_name() != nullptr) { if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")"; trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";

View File

@@ -63,25 +63,6 @@ namespace ox {
using CString = char const*; using CString = char const*;
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<const T*>(this);
}
};
template<std::size_t sz> template<std::size_t sz>
struct SignedType { struct SignedType {
}; };

View File

@@ -58,7 +58,7 @@ constexpr ox::Result<uint8_t> fromHex(ox::StringViewCR v) noexcept {
if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) { if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) {
return ox::Error(1, "Invalid UUID"); return ox::Error(1, "Invalid UUID");
} }
if (v.len() != 2) { if (v.size() != 2) {
return ox::Error(2); return ox::Error(2);
} }
uint8_t out = 0; uint8_t out = 0;
@@ -133,18 +133,18 @@ class UUID {
} }
static constexpr ox::Result<ox::UUID> fromString(ox::StringViewCR s) noexcept { static constexpr ox::Result<ox::UUID> fromString(ox::StringViewCR s) noexcept {
if (s.len() < 36) { if (s.size() < 36) {
return ox::Error(1, "Insufficient data to contain a complete UUID"); return ox::Error(1, "Insufficient data to contain a complete UUID");
} }
UUID out; UUID out;
auto valueI = 0u; auto valueI = 0u;
for (size_t i = 0; i < s.len();) { for (size_t i = 0; i < s.size();) {
if (s[i] == '-') { if (s[i] == '-') {
++i; ++i;
continue; continue;
} }
const auto seg = substr(s, i, i + 2); const auto seg = substr(s, i, i + 2);
if (seg.len() != 2) { if (seg.size() != 2) {
return ox::Error(1, "Invalid UUID"); return ox::Error(1, "Invalid UUID");
} }
OX_REQUIRE(val, detail::fromHex(seg)); OX_REQUIRE(val, detail::fromHex(seg));
@@ -174,7 +174,7 @@ class UUID {
for (auto i = 0u; i < cnt; ++i) { for (auto i = 0u; i < cnt; ++i) {
const auto v = value[valueI]; const auto v = value[valueI];
const auto h = detail::toHex(v); const auto h = detail::toHex(v);
std::ignore = writer.write(h.c_str(), h.len()); std::ignore = writer.write(h.c_str(), h.size());
++valueI; ++valueI;
} }
}; };

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {}; ox::Array<AllocAlias<T>, Size> m_data = {};
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept { constexpr void allocate(T **items, std::size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) { if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
@@ -49,45 +49,38 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T **items, T **items,
VectorAllocator *src, VectorAllocator *src,
const std::size_t count, std::size_t const count,
const std::size_t cap) noexcept { std::size_t const cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) { if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) { for (auto i = 0u; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]); auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]); #if defined(__GNUC__) && __GNUC__ >= 12
std::construct_at<T>(dstItem, std::move(*srcItem)); #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
new (&m_data[i]) T(std::move(*srcItem));
#if defined(__GNUC__) && __GNUC__ >= 12
#pragma GCC diagnostic pop
#endif
} }
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data()); *items = reinterpret_cast<T*>(m_data.data());
} }
} }
} }
constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
} }
constexpr void deallocate(T *items, std::size_t cap) noexcept { constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
}
} else { } else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) { if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
@@ -101,10 +94,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> { struct VectorAllocator<T, Allocator, 0> {
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept { constexpr void allocate(T **items, std::size_t const cap) noexcept {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
} }
@@ -112,15 +105,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T**, T**,
VectorAllocator*, VectorAllocator*,
const std::size_t, std::size_t const,
const std::size_t) noexcept { std::size_t const) noexcept {
} }
[[maybe_unused]] [[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept { constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept {
} }
constexpr void deallocate(T *items, std::size_t cap) noexcept { constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
if (items) { if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
} }
@@ -285,7 +278,9 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T item) noexcept(useNoexcept); constexpr void push_back(T const &item) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept); constexpr void pop_back() noexcept(useNoexcept);
@@ -419,7 +414,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
m_items = other.m_items; m_items = other.m_items;
this->moveItemsFrom(&m_items, &other, m_size, m_cap); this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0; other.m_size = 0;
other.m_cap = 0; other.m_cap = 0;
other.m_items = nullptr; other.m_items = nullptr;
@@ -615,7 +610,16 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
} }

View File

@@ -5,103 +5,117 @@
#pragma once #pragma once
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <ox/std/types.hpp> #include <ox/std/units.hpp>
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Interrupt Handler // Interrupt Handler
using interrupt_handler = void (*)(); using InterruptHandler = void(*)();
#define REG_ISR *reinterpret_cast<interrupt_handler*>(0x0300'7FFC) #define REG_ISR (*reinterpret_cast<InterruptHandler*>(0x0300'7FFC))
#define REG_IE *reinterpret_cast<volatile uint16_t*>(0x0400'0200) #define REG_IE (*reinterpret_cast<volatile uint16_t*>(0x0400'0200))
#define REG_IF *reinterpret_cast<volatile uint16_t*>(0x0400'0202) #define REG_IF (*reinterpret_cast<volatile uint16_t*>(0x0400'0202))
#define REG_IME *reinterpret_cast<volatile uint16_t*>(0x0400'0208) #define REG_IME (*reinterpret_cast<volatile uint16_t*>(0x0400'0208))
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Display Registers // Display Registers
#define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x0400'0000) #define REG_DISPCTL (*reinterpret_cast<volatile uint32_t*>(0x0400'0000))
#define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x0400'0004) #define REG_DISPSTAT (*reinterpret_cast<volatile uint32_t*>(0x0400'0004))
#define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x0400'0006) #define REG_VCOUNT (*reinterpret_cast<volatile uint32_t*>(0x0400'0006))
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Timers // Timers
#define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x0400'0100) #define REG_TIMER0 (*reinterpret_cast<volatile uint16_t*>(0x0400'0100))
#define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0102) #define REG_TIMER0CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0102))
#define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x0400'0104) #define REG_TIMER1 (*reinterpret_cast<volatile uint16_t*>(0x0400'0104))
#define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0106) #define REG_TIMER1CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0106))
#define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x0400'0108) #define REG_TIMER2 (*reinterpret_cast<volatile uint16_t*>(0x0400'0108))
#define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010a) #define REG_TIMER2CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010a))
#define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400'010c) #define REG_TIMER3 (*reinterpret_cast<volatile uint16_t*>(0x0400'010c))
#define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010e) #define REG_TIMER3CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010e))
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// background registers // background registers
// background control registers // background control registers
using BgCtl = uint16_t; using BgCtl = uint16_t;
#define REG_BG0CTL *reinterpret_cast<volatile BgCtl*>(0x0400'0008) #define REG_BG0CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'0008))
#define REG_BG1CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000a) #define REG_BG1CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000a))
#define REG_BG2CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000c) #define REG_BG2CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000c))
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e) #define REG_BG3CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000e))
[[nodiscard]] [[nodiscard]]
inline volatile BgCtl &regBgCtl(uintptr_t bgIdx) noexcept { inline volatile BgCtl &regBgCtl(uintptr_t const bgIdx) noexcept {
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx); return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
} }
// background horizontal scrolling registers // background horizontal scrolling registers
#define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0010) #define REG_BG0HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0010))
#define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0014) #define REG_BG1HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0014))
#define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0018) #define REG_BG2HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0018))
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c) #define REG_BG3HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001c))
[[nodiscard]] [[nodiscard]]
inline volatile uint32_t &regBgHofs(auto bgIdx) noexcept { volatile int16_t &regBgHofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx); return *reinterpret_cast<volatile int16_t*>(0x0400'0010 + 4 * bgIdx);
} }
// background vertical scrolling registers // background vertical scrolling registers
#define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0012) #define REG_BG0VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0012))
#define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0016) #define REG_BG1VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0016))
#define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001a) #define REG_BG2VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001a))
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e) #define REG_BG3VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001e))
[[nodiscard]] [[nodiscard]]
inline volatile uint32_t &regBgVofs(auto bgIdx) noexcept { volatile int16_t &regBgVofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx); return *reinterpret_cast<volatile int16_t*>(0x0400'0012 + 4 * bgIdx);
}
// background scrolling registers
struct OffsetPair {
int16_t x{}, y{};
};
#define REG_BG0OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0010))
#define REG_BG1OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0014))
#define REG_BG2OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0018))
#define REG_BG3OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'001c))
[[nodiscard]]
volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile OffsetPair*>(0x0400'0010 + sizeof(OffsetPair) * bgIdx);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// User Input // User Input
#define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x0400'0130) #define REG_GAMEPAD (*reinterpret_cast<volatile uint16_t*>(0x0400'0130))
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Memory Addresses // Memory Addresses
#define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0200'0000) #define MEM_EWRAM (*reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000))
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203'FFFF)
#define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0300'0000) #define MEM_IWRAM (*reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000))
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x0300'7FFF)
#define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x0400'0050) #define REG_BLNDCTL (*reinterpret_cast<uint16_t*>(0x0400'0050))
#define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x0500'0000) using Palette = ox::Array<uint16_t, 128>;
#define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x0500'0200) #define MEM_BG_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0000))
#define MEM_SPRITE_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0200))
using BgMapTile = ox::Array<uint16_t, 8192>; using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x0600'0000) #define MEM_BG_TILES (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000))
#define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600'e000) #define MEM_BG_MAP (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000))
#define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x0601'0000) #define MEM_SPRITE_TILES (*reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'0000))
#define MEM_OAM reinterpret_cast<uint64_t*>(0x0700'0000) #define MEM_OAM (*reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000))
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000) #define MEM_ROM (*reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000))
#define MEM_SRAM reinterpret_cast<char*>(0x0e00'0000) #define MEM_SRAM (*reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000))
#define MEM_SRAM_SIZE 65535

View File

@@ -37,8 +37,12 @@ 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;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
} }

View File

@@ -26,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" {
@@ -50,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

View File

@@ -12,11 +12,11 @@ namespace teagba {
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer; static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept { GbaSpriteAttrUpdate &spriteAttr(size_t const 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;
@@ -29,4 +29,16 @@ void applySpriteUpdates() noexcept {
} }
} }
void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = x;
o.y = y;
}
void scrollBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = o.x + x;
o.y = o.y + y;
}
} }

View File

@@ -1,14 +1,26 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0 # d2025.06.0
* Add ability to remember recent projects in config * 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 RGB key shortcuts for focusing color channels
* PaletteEditor: Add color preview to color editor * PaletteEditor: Add color preview to color editor
# d2025.05.2
* TileSheetEditor: Fix manual redo of draw actions, fix drawing to pixel 0, 0 as first action (cce5f52f96511694afd98f0b9b6b1f19c06ecd20)
* TileSheetEditor: Fix draw command to work on same pixel after switching subsheets (514cb978351ee4b0a5335c22a506a6d9f608f0a7)
# d2025.05.1 # d2025.05.1
* TileSheetEditor: Fix overrun errors when switching subsheets, clear selection * TileSheetEditor: Fix overrun errors when switching subsheets, clear selection

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,37 @@ 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,
};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_Palette{
FileExt_npal,
};
[[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_TileSheet.begin(),
FileExts_TileSheet.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
[[nodiscard]]
constexpr bool isPalette(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_Palette.begin(),
FileExts_Palette.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
} }

View File

@@ -111,23 +111,23 @@ struct InitParams {
uint_t glBlocksPerSprite = 64; uint_t glBlocksPerSprite = 64;
}; };
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params = {}) noexcept; ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params = {}) noexcept;
[[nodiscard]] [[nodiscard]]
int tileColumns(Context&) noexcept; int tileColumns(Context const&) noexcept;
[[nodiscard]] [[nodiscard]]
int tileRows(Context&) noexcept; int tileRows(Context const&) noexcept;
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t palBank,
CompactPalette const&palette, CompactPalette const &palette,
size_t page = 0) noexcept; size_t page = 0) noexcept;
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
CompactPalette const&palette, CompactPalette const &palette,
size_t page = 0) noexcept; size_t page = 0) noexcept;
ox::Error loadBgPalette( ox::Error loadBgPalette(
@@ -138,7 +138,7 @@ ox::Error loadBgPalette(
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t palBank,
ox::FileAddress const&paletteAddr) noexcept; ox::FileAddress const &paletteAddr) noexcept;
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
@@ -146,12 +146,12 @@ ox::Error loadSpritePalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
ox::FileAddress const&paletteAddr) noexcept; ox::FileAddress const &paletteAddr) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
TileSheetSet const&set) noexcept; TileSheetSet const &set) noexcept;
void clearCbb(Context &ctx, unsigned cbb) noexcept; void clearCbb(Context &ctx, unsigned cbb) noexcept;
@@ -160,7 +160,7 @@ void clearCbbs(Context &ctx) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t dstTileIdx, size_t dstTileIdx,
size_t srcTileIdx, size_t srcTileIdx,
size_t tileCnt) noexcept; size_t tileCnt) noexcept;
@@ -176,7 +176,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const&tsAddr, ox::FileAddress const &tsAddr,
size_t dstTileIdx, size_t dstTileIdx,
size_t srcTileIdx, size_t srcTileIdx,
size_t tileCnt) noexcept; size_t tileCnt) noexcept;
@@ -184,24 +184,24 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
CompactTileSheet const&ts, CompactTileSheet const &ts,
ox::Optional<unsigned> const&paletteBank = {}) noexcept; ox::Optional<unsigned> const &paletteBank = {}) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::StringViewCR tilesheetPath, ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const&paletteBank) noexcept; ox::Optional<unsigned> const &paletteBank) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const &tilesheetAddr,
ox::Optional<unsigned> const&paletteBank = {}) noexcept; ox::Optional<unsigned> const &paletteBank = {}) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const&ts, CompactTileSheet const &ts,
bool loadDefaultPalette) noexcept; bool loadDefaultPalette) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
@@ -211,16 +211,16 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const &tilesheetAddr,
bool loadDefaultPalette = false) noexcept; bool loadDefaultPalette = false) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const&set) noexcept; TileSheetSet const &set) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank = 0) noexcept; void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank = 0) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept; void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const &tile) noexcept;
void clearBg(Context &ctx, uint_t bgIdx) noexcept; void clearBg(Context &ctx, uint_t bgIdx) noexcept;
@@ -238,11 +238,15 @@ 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;
void setBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void hideSprite(Context &ctx, unsigned) noexcept; void hideSprite(Context &ctx, unsigned) noexcept;
void showSprite(Context &ctx, unsigned) noexcept; void showSprite(Context &ctx, unsigned) noexcept;
void setSprite(Context &ctx, uint_t idx, Sprite const&sprite) noexcept; void setSprite(Context &ctx, uint_t idx, Sprite const &sprite) noexcept;
[[nodiscard]] [[nodiscard]]
uint_t spriteCount(Context const &ctx) noexcept; uint_t spriteCount(Context const &ctx) noexcept;
@@ -260,8 +264,8 @@ constexpr ox::CStringView GlslVersion = "#version 330";
[[nodiscard]] [[nodiscard]]
ox::Size drawSize(int scale = 5) noexcept; ox::Size drawSize(int scale = 5) noexcept;
void draw(gfx::Context &ctx, ox::Size const&renderSz) noexcept; void draw(Context &ctx, ox::Size const &renderSz) noexcept;
void draw(gfx::Context&, int scale = 5) noexcept; void draw(Context&, int scale = 5) noexcept;
} }

View File

@@ -168,9 +168,9 @@ OX_MODEL_BEGIN(PaletteV3)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] [[nodiscard]]
constexpr bool valid(PaletteV3 const&p) noexcept { constexpr bool valid(PaletteV3 const &p) noexcept {
auto const colors = p.colorInfo.size(); auto const colors = p.colorInfo.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const&page) { return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const &page) {
return page.size() == colors; return page.size() == colors;
}); });
} }
@@ -198,9 +198,9 @@ OX_MODEL_BEGIN(PaletteV4)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] [[nodiscard]]
constexpr bool valid(PaletteV4 const&p) noexcept { constexpr bool valid(PaletteV4 const &p) noexcept {
auto const colors = p.colorNames.size(); auto const colors = p.colorNames.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const&page) { return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const &page) {
return page.colors.size() == colors; return page.colors.size() == colors;
}); });
} }

View File

@@ -11,39 +11,39 @@
namespace nostalgia::gfx { 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 const x, int const y, int const c, int const 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);
} }
[[nodiscard]] [[nodiscard]]
constexpr std::size_t ptToIdx(const ox::Point &pt, int c, int scale = 1) noexcept { constexpr std::size_t ptToIdx(ox::Point const &pt, int const c, int const scale = 1) noexcept {
return ptToIdx(pt.x, pt.y, c * TileWidth, scale); return ptToIdx(pt.x, pt.y, c * TileWidth, scale);
} }
[[nodiscard]] [[nodiscard]]
constexpr ox::Point idxToPt(int i, int c, int scale = 1) noexcept { constexpr ox::Point idxToPt(int const i, int c, int const 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

@@ -30,7 +30,7 @@ struct TileSheetV1 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV1 const&ts) noexcept { constexpr bool valid(TileSheetV1 const &ts) noexcept {
auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1);
return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes; return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes;
} }
@@ -71,16 +71,16 @@ struct TileSheetV2 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV2::SubSheet const&ss, int bpp) noexcept { constexpr bool valid(TileSheetV2::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV2::SubSheet const&s) { [bpp, bytes](TileSheetV2::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV2 const&ts) noexcept { constexpr bool valid(TileSheetV2 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -141,16 +141,16 @@ struct TileSheetV3 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV3::SubSheet const&ss, int bpp) noexcept { constexpr bool valid(TileSheetV3::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV3::SubSheet const&s) { [bpp, bytes](TileSheetV3::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV3 const&ts) noexcept { constexpr bool valid(TileSheetV3 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -233,18 +233,18 @@ struct TileSheetV4 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept { constexpr bool valid(TileSheetV4::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return return
(ss.pixels.empty() || ss.subsheets.empty()) && (ss.pixels.empty() || ss.subsheets.empty()) &&
ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV4::SubSheet const&s) { [bpp, bytes](TileSheetV4::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV4 const&ts) noexcept { constexpr bool valid(TileSheetV4 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -334,19 +334,19 @@ 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 std::cmp_equal(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) {
return valid(s); return valid(s);
}); });
} }
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV5 const&ts) noexcept { constexpr bool valid(TileSheetV5 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet);
} }
@@ -376,24 +376,24 @@ constexpr ox::Error repair(TileSheetV5 &ts) noexcept {
using TileSheet = TileSheetV5; using TileSheet = TileSheetV5;
[[nodiscard]] [[nodiscard]]
std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; std::size_t idx(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept;
[[nodiscard]] [[nodiscard]]
size_t getTileCnt(TileSheet const&ts) noexcept; size_t getTileCnt(TileSheet const &ts) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept; TileSheet::SubSheet const*getSubsheet(TileSheet const &ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept; ox::Optional<size_t> getTileIdx(TileSheet const &ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept; uint8_t getPixel(TileSheet::SubSheet const &ss, std::size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; uint8_t getPixel(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept; void setPixel(TileSheet::SubSheet &ss, ox::Point const &pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept; ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept;
@@ -406,14 +406,14 @@ void flipY(TileSheet::SubSheet &ss, ox::Point const &a, ox::Point const &b) noex
* @return a count of the pixels in this sheet * @return a count of the pixels in this sheet
*/ */
[[nodiscard]] [[nodiscard]]
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept; unsigned pixelCnt(TileSheet::SubSheet const &ss) noexcept;
/** /**
* *
* @param ss * @param ss
* @param sz size of Subsheet in tiles (not pixels) * @param sz size of Subsheet in tiles (not pixels)
*/ */
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept; ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const &sz) noexcept;
/** /**
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the * validateSubSheetIdx takes a SubSheetIdx and moves the index to the
@@ -424,13 +424,21 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
* @return a valid version of idx * @return a valid version of idx
*/ */
[[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; ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId pId) noexcept;
ox::Result<TileSheet::SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet &ts) noexcept;
ox::Result<TileSheet::SubSheet const*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet const &ts) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet &getSubSheet( TileSheet::SubSheet &getSubSheet(
ox::SpanView<uint32_t> const&idx, ox::SpanView<uint32_t> const &idx,
std::size_t idxIt, std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept; TileSheet::SubSheet &pSubsheet) noexcept;
@@ -439,7 +447,7 @@ TileSheet::SubSheet &getSubSheet(
#pragma GCC diagnostic ignored "-Wdangling-reference" #pragma GCC diagnostic ignored "-Wdangling-reference"
#endif #endif
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, ox::SpanView<uint32_t> const &idx) noexcept; TileSheet::SubSheet const &getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept; TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept;
@@ -453,27 +461,29 @@ ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx, TileS
ox::Error rmSubSheet( ox::Error rmSubSheet(
TileSheet &ts, TileSheet &ts,
TileSheet::SubSheetIdx const&idx, TileSheet::SubSheetIdx const &idx,
std::size_t idxIt, std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept; TileSheet::SubSheet &pSubsheet) noexcept;
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept; ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel( uint8_t getPixel(
TileSheet const&ts, TileSheet const &ts,
ox::Point const&pt, ox::Point const &pt,
TileSheet::SubSheetIdx const&subsheetIdx) noexcept; TileSheet::SubSheetIdx const &subsheetIdx) noexcept;
ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexcept; ox::Result<SubSheetId> getIdFor(TileSheet const &ts, ox::StringViewCR path) noexcept;
ox::Result<unsigned> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept; ox::Result<unsigned> getTileOffset(TileSheet const &ts, ox::StringViewCR pNamePath) noexcept;
ox::Result<uint32_t> getTileOffset(TileSheet const&ts, SubSheetId pId) noexcept; ox::Result<uint32_t> getTileOffset(TileSheet const &ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const &ss, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet const &ts, SubSheetId pId) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept; ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept;
@@ -489,7 +499,7 @@ struct CompactTileSheetV1 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(CompactTileSheetV1 const&ts) noexcept { constexpr bool valid(CompactTileSheetV1 const &ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8; return ts.bpp == 4 || ts.bpp == 8;
} }
@@ -498,22 +508,22 @@ using CompactTileSheet = CompactTileSheetV1;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel4Bpp( uint8_t getPixel4Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel8Bpp( uint8_t getPixel8Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Pair<uint8_t> get2Pixels4Bpp( ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Pair<uint8_t> get2Pixels8Bpp( ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t idx) noexcept; size_t idx) noexcept;
OX_MODEL_BEGIN(TileSheetV1) OX_MODEL_BEGIN(TileSheetV1)
@@ -593,8 +603,8 @@ OX_MODEL_BEGIN(CompactTileSheetV1)
OX_MODEL_END() OX_MODEL_END()
ox::Vector<uint32_t> resizeTileSheetData( ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> const&srcPixels, ox::Vector<uint32_t> const &srcPixels,
ox::Size const&srcSize, ox::Size const &srcSize,
int scale = 2) noexcept; int scale = 2) noexcept;
} }

View File

@@ -31,15 +31,10 @@ class Context {
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {} explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context &other) noexcept = delete; Context(Context &other) noexcept = delete;
Context(Context const&other) noexcept = delete; Context(Context const &other) noexcept = delete;
Context(Context const&&other) noexcept = delete; Context(Context const &&other) noexcept = delete;
virtual ~Context() noexcept = default; 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 { void safeDelete(Context *ctx) noexcept {
@@ -76,12 +71,12 @@ ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&) no
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context&, Context&,
size_t const palBank, size_t const palBank,
CompactPalette const&palette, CompactPalette const &palette,
size_t const page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
auto const paletteMem = MEM_BG_PALETTE + palBank * 16; auto const paletteMem = ox::Span{MEM_BG_PALETTE} + palBank * 16;
for (auto i = 0u; i < colorCnt(palette, page); ++i) { for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i); paletteMem[i] = color(palette, page, i);
} }
@@ -90,14 +85,13 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context&, Context&,
CompactPalette const&palette, CompactPalette const &palette,
size_t const page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
auto const paletteMem = MEM_SPRITE_PALETTE;
for (auto i = 0u; i < colorCnt(palette, page); ++i) { for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i); MEM_SPRITE_PALETTE[i] = color(palette, page, i);
} }
return {}; return {};
} }
@@ -118,15 +112,15 @@ void clearCbbs(Context &ctx) noexcept {
static ox::Error loadTileSheetSet( static ox::Error loadTileSheetSet(
Context &ctx, Context &ctx,
ox::Span<uint16_t> tileMapTargetMem, ox::Span<uint16_t> tileMapTargetMem,
TileSheetSet const&set) noexcept { TileSheetSet const &set) noexcept {
size_t tileWriteIdx = 0; size_t tileWriteIdx = 0;
size_t const bppMod = set.bpp == 4; size_t const bppMod = set.bpp == 4;
for (auto const&entry : set.entries) { for (auto const &entry : set.entries) {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet));
if (set.bpp != ts->bpp && ts->bpp == 8) { if (set.bpp != ts->bpp && ts->bpp == 8) {
return ox::Error(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB"); return ox::Error(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB");
} }
for (auto const&s : entry.sections) { for (auto const &s : entry.sections) {
auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) >> bppMod; auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) >> bppMod;
for (size_t i = 0; i < cnt; ++i) { for (size_t i = 0; i < cnt; ++i) {
auto const begin = static_cast<size_t>(s.begin) * (PixelsPerTile >> bppMod); auto const begin = static_cast<size_t>(s.begin) * (PixelsPerTile >> bppMod);
@@ -145,7 +139,7 @@ static ox::Error loadTileSheetSet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -173,10 +167,10 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const 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() >> (ts.bpp == 4);
for (size_t i = 0; i < cnt; ++i) { for (size_t i{}; i < cnt; ++i) {
auto const srcIdx = i * 2; auto const srcIdx = i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]); auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]); auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
@@ -198,7 +192,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
TileSheetSet const&set) noexcept { TileSheetSet const &set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set)); OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set));
// update bpp of all bgs with the updated cbb // update bpp of all bgs with the updated cbb
@@ -222,12 +216,13 @@ static void setSpritesBpp(unsigned const bpp) noexcept {
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const&ts, CompactTileSheet const &ts,
bool const loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
for (size_t i = 0; i < ts.pixels.size(); i += 2) { for (size_t i{}; i < ts.pixels.size(); i += 2) {
uint16_t v = ts.pixels[i]; MEM_SPRITE_TILES[i >> 1] =
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8); static_cast<uint16_t>(
MEM_SPRITE_TILES[i] = v; ts.pixels[i] |
(static_cast<uint16_t>(ts.pixels[i + 1]) << 8));
} }
if (loadDefaultPalette && ts.defaultPalette) { if (loadDefaultPalette && ts.defaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette)); OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@@ -238,15 +233,19 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const&set) noexcept { TileSheetSet const &set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, {MEM_SPRITE_TILES, 32 * ox::units::KB}, set)); OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set));
setSpritesBpp(bpp); setSpritesBpp(bpp);
return {}; return {};
} }
void setBgTile( void setBgTile(
Context &ctx, uint_t const bgIdx, int const column, int const row, BgTile const&tile) noexcept { 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] =
@@ -275,7 +274,7 @@ bool bgStatus(Context&, unsigned const bg) noexcept {
void setBgStatus(Context&, unsigned const bg, bool const 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);
} }
@@ -286,7 +285,7 @@ void setBgBpp(Context&, unsigned const bgIdx, unsigned const bpp) noexcept {
void setBgCbb(Context &ctx, unsigned const bgIdx, unsigned const cbbIdx) 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[cbbIdx]; auto const &cbbData = ctx.cbbData[cbbIdx];
teagba::bgSetBpp(bgCtl, cbbData.bpp); teagba::bgSetBpp(bgCtl, cbbData.bpp);
teagba::bgSetCbb(bgCtl, cbbIdx); teagba::bgSetCbb(bgCtl, cbbIdx);
} }
@@ -296,6 +295,14 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11); bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
} }
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::setBgOffset(bg, x, y);
}
void scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y);
}
void hideSprite(Context&, unsigned const 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({
@@ -312,7 +319,7 @@ void showSprite(Context&, unsigned const idx) noexcept {
}); });
} }
void setSprite(Context&, uint_t const 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({
@@ -333,7 +340,7 @@ void setSprite(Context&, uint_t const idx, Sprite const&s) noexcept {
}); });
} }
uint_t spriteCount(Context const&) noexcept { uint_t spriteCount(Context const &) noexcept {
return SpriteCount; return SpriteCount;
} }
@@ -341,13 +348,13 @@ uint_t spriteCount(Context const&) noexcept {
namespace ox { namespace ox {
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept { void panic(char const *file, int line, char const *panicMsg, ox::Error const &err) noexcept {
using namespace nostalgia::gfx; using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data // reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
const auto heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN); auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM.data());
const auto heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2; auto const heapSz = MEM_EWRAM.size() / 2;
const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz); auto const heapEnd = reinterpret_cast<char*>(MEM_EWRAM.data() + heapSz);
ox::heapmgr::initHeap(heapBegin, heapEnd); ox::heapmgr::initHeap(heapBegin, heapEnd);
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap(); auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();

View File

@@ -287,7 +287,7 @@ static void initSpriteBufferObjects(Context const &ctx, glutils::BufferSet &bs)
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}
@@ -387,7 +387,7 @@ static void initBackgroundBufferset(
static glutils::GLTexture createTexture( static glutils::GLTexture createTexture(
GLsizei const w, GLsizei const w,
GLsizei const h, GLsizei const h,
void const*pixels) noexcept { void const *pixels) noexcept {
GLuint texId = 0; GLuint texId = 0;
glGenTextures(1, &texId); glGenTextures(1, &texId);
glutils::GLTexture tex(texId); glutils::GLTexture tex(texId);
@@ -425,22 +425,22 @@ static void drawBackground(CBB &cbb) noexcept {
static void drawBackgrounds( static void drawBackgrounds(
Context &ctx, Context &ctx,
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,
@@ -453,14 +453,14 @@ 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);
@@ -469,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);
@@ -481,7 +481,7 @@ static void loadPalette(
ox::Array<GLfloat, 1024> &palette, ox::Array<GLfloat, 1024> &palette,
size_t const palOffset, size_t const palOffset,
GLuint const shaderPgrm, GLuint const shaderPgrm,
CompactPalette const&pal, CompactPalette const &pal,
size_t const 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]) {
@@ -493,14 +493,14 @@ 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());
} }
static void setSprite( static void setSprite(
Context &ctx, Context &ctx,
uint_t const idx, uint_t const idx,
Sprite const&s) noexcept { Sprite const &s) noexcept {
// Tonc Table 8.4 // Tonc Table 8.4
struct Sz { uint_t x{}, y{}; }; struct Sz { uint_t x{}, y{}; };
static constexpr ox::Array<Sz, 12> dimensions{ static constexpr ox::Array<Sz, 12> dimensions{
@@ -526,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;
@@ -574,12 +574,12 @@ static void setSprite(
} }
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params) noexcept { ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params) noexcept {
auto ctx = ox::make_unique<Context>(tctx, params); auto ctx = ox::make_unique<Context>(tctx, params);
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion); auto const bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion); auto const bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion); auto const spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion); auto const 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));
@@ -603,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());
@@ -632,7 +632,7 @@ static ox::Result<TileSheetData> normalizeTileSheet(
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t const palBank, size_t const palBank,
CompactPalette const&palette, CompactPalette const &palette,
size_t const 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 {};
@@ -640,7 +640,7 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
CompactPalette const&palette, CompactPalette const &palette,
size_t const 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);
@@ -649,14 +649,14 @@ ox::Error loadSpritePalette(
static ox::Result<TileSheetData> buildSetTsd( static ox::Result<TileSheetData> buildSetTsd(
Context const &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;
setTsd.width = TileWidth; setTsd.width = TileWidth;
for (auto const&entry : set.entries) { for (auto const &entry : set.entries) {
OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet)); OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet)); OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet));
for (auto const&s : entry.sections) { for (auto const &s : entry.sections) {
auto const size = s.tiles * PixelsPerTile; auto const size = s.tiles * PixelsPerTile;
for (auto i = 0; i < size; ++i) { for (auto i = 0; i < size; ++i) {
auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile); auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile);
@@ -669,7 +669,7 @@ static ox::Result<TileSheetData> buildSetTsd(
} }
static void copyPixels( static void copyPixels(
CompactTileSheet const&ts, CompactTileSheet const &ts,
ox::Span<uint32_t> const 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 {
@@ -704,7 +704,7 @@ void clearCbbs(Context &ctx) noexcept {
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -728,8 +728,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
uint_t const 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)));
auto const tiles = ts.pixels.size() / bytesPerTile; auto const tiles = ts.pixels.size() / bytesPerTile;
OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles)); OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles));
@@ -742,7 +742,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const 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());
return {}; return {};
@@ -750,7 +750,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const&ts, CompactTileSheet const &ts,
bool const 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);
@@ -763,7 +763,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const&set) noexcept { TileSheetSet const &set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set)); OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data()); ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {}; return {};
@@ -774,18 +774,18 @@ void setBgTile(
uint_t const bgIdx, uint_t const bgIdx,
int const column, int const column,
int const 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),
@@ -853,7 +853,7 @@ void showSprite(Context &ctx, uint_t const idx) noexcept {
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
} }
void setSprite(Context &ctx, uint_t const 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);
@@ -869,7 +869,7 @@ ox::Size drawSize(int const scale) noexcept {
return {240 * scale, 160 * scale}; return {240 * scale, 160 * scale};
} }
void draw(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);

View File

@@ -10,11 +10,11 @@ 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;
} }
@@ -51,7 +51,7 @@ ox::Error loadSpritePalette(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
ox::FileAddress const&tsAddr, ox::FileAddress const &tsAddr,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -74,7 +74,7 @@ ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const 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));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank); return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
} }
@@ -82,8 +82,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const 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));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank); return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
} }
@@ -98,7 +98,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const &tilesheetAddr,
bool const 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);
@@ -249,7 +249,7 @@ void setBgTile(
} }
ox::Error initConsole(Context &ctx) noexcept { ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng"); constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal"); constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001); setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0); setBgCbb(ctx, 0, 0);

View File

@@ -89,7 +89,7 @@ static class: public keel::Module {
} const mod; } const mod;
keel::Module const*keelModule() noexcept { keel::Module const *keelModule() noexcept {
return &mod; return &mod;
} }

View File

@@ -61,7 +61,7 @@ ox::Error convertPaletteV4ToPaletteV5(
for (auto &s : src.pages) { for (auto &s : src.pages) {
ox::Vector<PaletteColorV2> colors; ox::Vector<PaletteColorV2> colors;
colors.reserve(s.colors.size()); colors.reserve(s.colors.size());
for (auto const&c : s.colors) { for (auto const &c : s.colors) {
colors.emplace_back(c.r, c.g, c.b, c.a); colors.emplace_back(c.r, c.g, c.b, c.a);
} }
dst.pages.emplace_back(PalettePageV2{ dst.pages.emplace_back(PalettePageV2{

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

@@ -26,3 +26,4 @@ install(
add_subdirectory(paletteeditor) add_subdirectory(paletteeditor)
add_subdirectory(tilesheeteditor) add_subdirectory(tilesheeteditor)
add_subdirectory(subcommands)

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

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)), Editor(sctx, std::move(path)),
m_sctx(sctx), m_sctx(sctx),
m_tctx(sctx.tctx), m_tctx(sctx.tctx),
m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) { m_pal(m_sctx.project->loadObj<Palette>(itemPath()).unwrapThrow()) {
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand); undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage); m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
} }
@@ -302,11 +302,12 @@ 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, FocusCmd::Red); bool colorInFocused{};
colorInput("Green", g, inputFocused, FocusCmd::Green); colorInput("Red", r, colorInFocused, FocusCmd::Red);
colorInput("Blue", b, inputFocused, FocusCmd::Blue); colorInput("Green", g, colorInFocused, FocusCmd::Green);
colorInput("Blue", b, colorInFocused, FocusCmd::Blue);
// color preview // color preview
{ {
ImGui::PushStyleColor( ImGui::PushStyleColor(
@@ -320,12 +321,15 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
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)) { if (ImGui::IsKeyDown(ImGuiKey_R)) {
m_focusCmd = FocusCmd::Red; m_focusCmd = FocusCmd::Red;
} }
@@ -336,6 +340,7 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
m_focusCmd = FocusCmd::Blue; 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) {
std::ignore = pushCommand<UpdateColorCommand>(m_pal, m_page, m_selectedColorRow, newColor); std::ignore = pushCommand<UpdateColorCommand>(m_pal, m_page, m_selectedColorRow, newColor);

View File

@@ -20,7 +20,7 @@ class PaletteEditorImGui: public studio::Editor {
bool m_show = false; bool m_show = false;
public: public:
ox::Signal<ox::Error(ox::StringView name)> inputSubmitted; ox::Signal<ox::Error(ox::StringView name)> inputSubmitted;
constexpr void show(ox::StringView const&name) noexcept { constexpr void show(ox::StringView const &name) noexcept {
m_show = true; m_show = true;
m_name = name; m_name = name;
} }

View File

@@ -8,10 +8,25 @@
#include "paletteeditor/paletteeditor-imgui.hpp" #include "paletteeditor/paletteeditor-imgui.hpp"
#include "tilesheeteditor/tilesheeteditor-imgui.hpp" #include "tilesheeteditor/tilesheeteditor-imgui.hpp"
#include "subcommands/export-tilesheet/export-tilesheet.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
static class: public studio::Module { static struct: studio::Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.nostalgia.gfx"};
}
ox::Vector<studio::Command> commands() const final {
return {
{
"export-tilesheet",
cmdExportTilesheet,
}
};
}
ox::Vector<studio::EditorMaker> editors(studio::Context &ctx) const noexcept final { ox::Vector<studio::EditorMaker> editors(studio::Context &ctx) const noexcept final {
return { return {
studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}), studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}),
@@ -28,9 +43,10 @@ static class: public studio::Module {
}, ox::ClawFormat::Organic)); }, ox::ClawFormat::Organic));
return out; return out;
} }
} const mod; } const mod;
const studio::Module *studioModule() noexcept { studio::Module const *studioModule() noexcept {
return &mod; return &mod;
} }

View File

@@ -0,0 +1,10 @@
target_sources(
NostalgiaGfx-Studio PRIVATE
export-tilesheet/export-tilesheet.cpp
)
target_link_libraries(
NostalgiaGfx-Studio PUBLIC
OxClArgs
)

View File

@@ -0,0 +1,161 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <lodepng.h>
#include <ox/clargs/clargs.hpp>
#include <ox/std/trace.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
#include "export-tilesheet.hpp"
#include "nostalgia/gfx/tilesheet.hpp"
#include "studio/context.hpp"
namespace nostalgia::gfx {
static ox::Vector<uint32_t> normalizePixelSizes(
ox::Vector<uint8_t> const &inPixels) noexcept {
ox::Vector<uint32_t> outPixels;
outPixels.reserve(inPixels.size());
outPixels.resize(inPixels.size());
for (size_t i{}; i < inPixels.size(); ++i) {
outPixels[i] = inPixels[i];
}
return outPixels;
}
static ox::Vector<uint32_t> normalizePixelArrangement(
ox::Vector<uint32_t> const &inPixels,
int const cols,
int const scale) {
auto const scalePt = ox::Point{scale, scale};
auto const width = cols * TileWidth;
auto const height = static_cast<int>(inPixels.size()) / width;
auto const dstWidth = width * scale;
ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
for (size_t dstIdx{}; dstIdx < outPixels.size(); ++dstIdx) {
auto const dstPt = ox::Point{
static_cast<int>(dstIdx) % dstWidth,
static_cast<int>(dstIdx) / dstWidth};
auto const srcPt = dstPt / scalePt;
auto const srcIdx = ptToIdx(srcPt, cols);
outPixels[dstIdx] = inPixels[srcIdx];
}
return outPixels;
}
static ox::Error toPngFile(
ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels,
Palette const &pal,
size_t const page,
unsigned const width,
unsigned const height) noexcept {
for (auto &c : pixels) {
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
}
constexpr auto fmt = LCT_RGBA;
return ox::Error(static_cast<ox::ErrorCode>(
lodepng_encode_file(
path.c_str(),
reinterpret_cast<uint8_t const*>(pixels.data()),
width,
height,
fmt,
8)));
}
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const width = s.columns * TileWidth;
auto const height = s.rows * TileHeight;
auto const err = toPngFile(
dstPath,
normalizePixelArrangement(
normalizePixelSizes(s.pixels),
s.columns,
scale),
pal,
palPage,
static_cast<unsigned>(width * scale),
static_cast<unsigned>(height * scale));
if (err) {
oxErrorf("TileSheet export failed: {}", toStr(err));
return ox::Error{7, "TileSheet export failed"};
}
return {};
}
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const [s, ssErr] = getSubSheet(
ox::split(subsheetPath, '.'), src);
if (ssErr) {
return ox::Error{6, "failed to find SubSheet"};
}
return exportSubsheetToPng(
*s,
pal,
palPage,
dstPath,
scale);
}
ox::Error cmdExportTilesheet(studio::Project &project, ox::SpanView<ox::CString> const args) noexcept {
// parse args
ox::ClArgs const clargs{args};
bool showUsage = true;
OX_DEFER [&showUsage] {
if (showUsage) {
oxErr("usage: export-tilesheet "
"-src-path <path> "
"-dst-path <path> "
"[-pal-path <path>] "
"[-subsheet-path <path>] "
"[-scale <int>]\n");
}
};
if (args.empty()) {
return {};
}
OX_REQUIRE(srcPath, clargs.getString("src-path").transformError(1, "no src path specified"));
OX_REQUIRE(dstPath, clargs.getString("dst-path").transformError(2, "no dst path specified"));
auto const palPath = clargs.getString("pal-path", "");
auto const subsheetPath = clargs.getString("subsheet-path").or_value(ox::String{"Root"});
auto const palPage = static_cast<size_t>(clargs.getInt("pal-page", 0));
auto const scale = clargs.getInt("scale", 1);
showUsage = false;
// load objects
auto &kctx = project.kctx();
OX_REQUIRE(ts, keel::readObj<TileSheet>(kctx, srcPath).transformError(4, "could not load TileSheet"));
OX_REQUIRE(pal, keel::readObj<Palette>(kctx, palPath.size() ? palPath : ts->defaultPalette)
.transformError(5, "could not load Palette"));
// export to the destination file
return exportSubsheetToPng(
*ts,
*pal,
subsheetPath,
palPage,
dstPath,
scale);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/stringview.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::gfx {
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error cmdExportTilesheet(studio::Project& project, ox::SpanView<ox::CString> args) noexcept;
}

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;
@@ -60,7 +60,7 @@ int AddSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::AddSubSheet); return static_cast<int>(CommandId::AddSubSheet);
} }
TileSheet::SubSheetIdx const&AddSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &AddSubSheetCommand::subsheetIdx() const noexcept {
return m_parentIdx; return m_parentIdx;
} }

View File

@@ -25,7 +25,7 @@ class AddSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -37,7 +37,7 @@ constexpr bool operator==(int i, CommandId c) noexcept {
class TileSheetCommand: public studio::UndoCommand { class TileSheetCommand: public studio::UndoCommand {
public: public:
[[nodiscard]] [[nodiscard]]
virtual TileSheet::SubSheetIdx const&subsheetIdx() const noexcept = 0; virtual TileSheet::SubSheetIdx const &subsheetIdx() const noexcept = 0;
}; };
} }

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

@@ -30,10 +30,10 @@ class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
ox::Vector<Pixel> m_pixels; ox::Vector<Pixel> m_pixels;
public: public:
void addPixel(ox::Point const&pt, uint16_t colorIdx) noexcept; void addPixel(ox::Point const &pt, uint16_t colorIdx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<Pixel> const&pixels() const noexcept; ox::Vector<Pixel> const &pixels() const noexcept;
}; };
OX_MODEL_BEGIN(TileSheetClipboard::Pixel) OX_MODEL_BEGIN(TileSheetClipboard::Pixel)
@@ -67,9 +67,9 @@ class CutPasteCommand: public TileSheetCommand {
CommandId commandId, CommandId commandId,
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::Point const&dstStart, ox::Point const &dstStart,
ox::Point dstEnd, ox::Point dstEnd,
TileSheetClipboard const&cb); TileSheetClipboard const &cb);
ox::Error redo() noexcept final; ox::Error redo() noexcept final;
@@ -79,7 +79,7 @@ class CutPasteCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

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);
@@ -67,7 +66,7 @@ int DeleteTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::DeleteTile); return static_cast<int>(CommandId::DeleteTile);
} }
TileSheet::SubSheetIdx const&DeleteTilesCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &DeleteTilesCommand::subsheetIdx() const noexcept {
return m_idx; return 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(
@@ -31,7 +31,7 @@ class DeleteTilesCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

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));
} }
@@ -74,7 +74,7 @@ DrawCommand::DrawCommand(
DrawCommand::DrawCommand( DrawCommand::DrawCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::SpanView<std::size_t> const&idxList, ox::SpanView<std::size_t> const &idxList,
int const palIdx) noexcept: int const palIdx) noexcept:
m_img(img), m_img(img),
m_subSheetIdx(std::move(subSheetIdx)), m_subSheetIdx(std::move(subSheetIdx)),
@@ -90,7 +90,7 @@ bool DrawCommand::append(std::size_t const idx) noexcept {
if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) { if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) {
// duplicate entries are bad // duplicate entries are bad
auto existing = find_if( auto existing = find_if(
m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) { m_changes.cbegin(), m_changes.cend(), [idx](auto const &c) {
return c.idx == idx; return c.idx == idx;
}); });
if (existing == m_changes.cend()) { if (existing == m_changes.cend()) {
@@ -102,7 +102,7 @@ bool DrawCommand::append(std::size_t const idx) noexcept {
return false; return false;
} }
bool DrawCommand::append(ox::SpanView<std::size_t> const&idxList) noexcept { bool DrawCommand::append(ox::SpanView<std::size_t> const &idxList) noexcept {
auto out = false; auto out = false;
for (auto idx : idxList) { for (auto idx : idxList) {
out = append(idx) || out; out = append(idx) || out;
@@ -134,7 +134,7 @@ void DrawCommand::lineUpdate(ox::Point a, ox::Point b) noexcept {
ox::Error DrawCommand::redo() noexcept { ox::Error DrawCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const&c : m_changes) { for (auto const &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx);
} }
return {}; return {};
@@ -142,7 +142,7 @@ ox::Error DrawCommand::redo() noexcept {
ox::Error DrawCommand::undo() noexcept { ox::Error DrawCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const&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 {};
@@ -152,7 +152,7 @@ int DrawCommand::commandId() const noexcept {
return static_cast<int>(CommandId::Draw); return static_cast<int>(CommandId::Draw);
} }
TileSheet::SubSheetIdx const&DrawCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &DrawCommand::subsheetIdx() const noexcept {
return m_subSheetIdx; return m_subSheetIdx;
} }

View File

@@ -33,12 +33,12 @@ class DrawCommand: public TileSheetCommand {
DrawCommand( DrawCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::SpanView<std::size_t> const&idxList, ox::SpanView<std::size_t> const &idxList,
int palIdx) noexcept; int palIdx) noexcept;
bool append(std::size_t idx) noexcept; bool append(std::size_t idx) noexcept;
bool append(ox::SpanView<std::size_t> const&idxList) noexcept; bool append(ox::SpanView<std::size_t> const &idxList) noexcept;
void lineUpdate(ox::Point a, ox::Point b) noexcept; void lineUpdate(ox::Point a, ox::Point b) noexcept;
@@ -50,7 +50,7 @@ class DrawCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
void finish() noexcept; void finish() noexcept;

View File

@@ -30,7 +30,7 @@ class FlipXCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };
@@ -56,7 +56,7 @@ class FlipYCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

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 {};
} }
@@ -62,7 +62,7 @@ int InsertTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::InsertTile); return static_cast<int>(CommandId::InsertTile);
} }
TileSheet::SubSheetIdx const&InsertTilesCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &InsertTilesCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

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(
@@ -31,7 +31,7 @@ class InsertTilesCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -33,7 +33,7 @@ int MoveSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::MoveSubSheet); return static_cast<int>(CommandId::MoveSubSheet);
} }
TileSheet::SubSheetIdx const&MoveSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &MoveSubSheetCommand::subsheetIdx() const noexcept {
return *m_active; return *m_active;
} }

View File

@@ -26,7 +26,7 @@ class MoveSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -30,7 +30,7 @@ int PaletteChangeCommand::commandId() const noexcept {
return static_cast<int>(CommandId::PaletteChange); return static_cast<int>(CommandId::PaletteChange);
} }
TileSheet::SubSheetIdx const&PaletteChangeCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &PaletteChangeCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

View File

@@ -29,7 +29,7 @@ class PaletteChangeCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -31,7 +31,7 @@ int RmSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::RmSubSheet); return static_cast<int>(CommandId::RmSubSheet);
} }
TileSheet::SubSheetIdx const&RmSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &RmSubSheetCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

View File

@@ -26,7 +26,7 @@ class RmSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -119,7 +119,7 @@ int RotateCommand::commandId() const noexcept {
return static_cast<int>(CommandId::Rotate); return static_cast<int>(CommandId::Rotate);
} }
TileSheet::SubSheetIdx const&RotateCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &RotateCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

View File

@@ -40,7 +40,7 @@ class RotateCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

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}));
} }
@@ -34,7 +33,7 @@ int UpdateSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::UpdateSubSheet); return static_cast<int>(CommandId::UpdateSubSheet);
} }
TileSheet::SubSheetIdx const&UpdateSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &UpdateSubSheetCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

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:
@@ -30,7 +30,7 @@ class UpdateSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
}; };

View File

@@ -3,7 +3,6 @@
*/ */
#include <imgui.h> #include <imgui.h>
#include <lodepng.h>
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <keel/media.hpp> #include <keel/media.hpp>
@@ -11,6 +10,7 @@
#include <nostalgia/gfx/studio.hpp> #include <nostalgia/gfx/studio.hpp>
#include "../subcommands/export-tilesheet/export-tilesheet.hpp"
#include "tilesheeteditor-imgui.hpp" #include "tilesheeteditor-imgui.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
@@ -37,58 +37,6 @@ OX_MODEL_BEGIN(TileSheetEditorConfig)
OX_MODEL_FIELD_RENAME(activeSubsheet, active_subsheet) OX_MODEL_FIELD_RENAME(activeSubsheet, active_subsheet)
OX_MODEL_END() OX_MODEL_END()
static ox::Vector<uint32_t> normalizePixelSizes(
ox::Vector<uint8_t> const &inPixels) noexcept {
ox::Vector<uint32_t> outPixels;
outPixels.reserve(inPixels.size());
outPixels.resize(inPixels.size());
for (std::size_t i = 0; i < inPixels.size(); ++i) {
outPixels[i] = inPixels[i];
}
return outPixels;
}
static ox::Vector<uint32_t> normalizePixelArrangement(
ox::Vector<uint32_t> const &inPixels,
int const cols,
int const scale) {
auto const scalePt = ox::Point{scale, scale};
auto const width = cols * TileWidth;
auto const height = static_cast<int>(inPixels.size()) / width;
auto const dstWidth = width * scale;
ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
for (std::size_t dstIdx = 0; dstIdx < outPixels.size(); ++dstIdx) {
auto const dstPt = ox::Point{
static_cast<int>(dstIdx) % dstWidth,
static_cast<int>(dstIdx) / dstWidth};
auto const srcPt = dstPt / scalePt;
auto const srcIdx = ptToIdx(srcPt, cols);
outPixels[dstIdx] = inPixels[srcIdx];
}
return outPixels;
}
static ox::Error toPngFile(
ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels,
Palette const &pal,
size_t const page,
unsigned const width,
unsigned const height) noexcept {
for (auto &c : pixels) {
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
}
constexpr auto fmt = LCT_RGBA;
return ox::Error(static_cast<ox::ErrorCode>(
lodepng_encode_file(
path.c_str(),
reinterpret_cast<uint8_t const*>(pixels.data()),
width,
height,
fmt,
8)));
}
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},
@@ -194,6 +142,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)) {
@@ -278,7 +229,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();
@@ -418,21 +369,7 @@ ox::Error TileSheetEditorImGui::exportSubsheetToPng(int const scale) const noexc
// subsheet to png // subsheet to png
auto const &s = m_model.activeSubSheet(); auto const &s = m_model.activeSubSheet();
auto const &pal = m_model.pal(); auto const &pal = m_model.pal();
auto const width = s.columns * TileWidth; return gfx::exportSubsheetToPng(s, pal, m_model.palettePage(), path, scale);
auto const height = s.rows * TileHeight;
auto pixels = normalizePixelSizes(s.pixels);
pixels = normalizePixelArrangement(pixels, s.columns, scale);
auto const err = toPngFile(
path,
std::move(pixels),
pal,
m_model.palettePage(),
static_cast<unsigned>(width * scale),
static_cast<unsigned>(height * scale));
if (err) {
oxErrorf("TileSheet export failed: {}", toStr(err));
}
return err;
} }
void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const &fbSize) noexcept { void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const &fbSize) noexcept {

View File

@@ -57,7 +57,6 @@ class TileSheetEditorImGui: public studio::Editor {
ox::Vec2 m_prevMouseDownPos; ox::Vec2 m_prevMouseDownPos;
TileSheetTool m_tool = TileSheetTool::Draw; TileSheetTool m_tool = TileSheetTool::Draw;
bool m_palPathFocused{}; bool m_palPathFocused{};
ox::Vector<ox::UPtr<studio::UndoCommand>, 1> m_deferredCmds;
public: public:
TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path); TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path);

View File

@@ -49,7 +49,7 @@ TileSheetEditorModel::TileSheetEditorModel(
m_sctx{sctx}, m_sctx{sctx},
m_tctx{m_sctx.tctx}, m_tctx{m_sctx.tctx},
m_path{std::move(path)}, m_path{std::move(path)},
m_img{*readObj<TileSheet>(keelCtx(m_tctx), m_path).unwrapThrow()}, m_img{m_sctx.project->loadObj<TileSheet>(m_path).unwrapThrow()},
// ignore failure to load palette // ignore failure to load palette
m_pal{readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).value}, m_pal{readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).value},
m_undoStack{undoStack} { m_undoStack{undoStack} {
@@ -66,7 +66,7 @@ void TileSheetEditorModel::cut() {
} }
TileSheetClipboard blankCb; TileSheetClipboard blankCb;
auto cb = ox::make_unique<TileSheetClipboard>(); auto cb = ox::make_unique<TileSheetClipboard>();
auto const&s = activeSubSheet(); auto const &s = activeSubSheet();
if (iterateSelectionRows(*m_selection, [&](int const x, int const y) { if (iterateSelectionRows(*m_selection, [&](int const x, int const y) {
auto pt = ox::Point{x, y}; auto pt = ox::Point{x, y};
auto const idx = gfx::idx(s, pt); auto const idx = gfx::idx(s, pt);
@@ -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));
} }
} }
@@ -97,7 +97,7 @@ void TileSheetEditorModel::copy() {
auto cb = ox::make_unique<TileSheetClipboard>(); auto cb = ox::make_unique<TileSheetClipboard>();
if (iterateSelectionRows(*m_selection, [&](int const x, int const y) { if (iterateSelectionRows(*m_selection, [&](int const x, int const y) {
auto pt = ox::Point{x, y}; auto pt = ox::Point{x, y};
auto const&s = activeSubSheet(); auto const &s = activeSubSheet();
auto const idx = gfx::idx(s, pt); auto const idx = gfx::idx(s, pt);
if (idx >= s.pixels.size()) { if (idx >= s.pixels.size()) {
return ox::Error{1, "invalid idx"}; return ox::Error{1, "invalid idx"};
@@ -122,12 +122,12 @@ void TileSheetEditorModel::paste() {
oxErrf("Could not read clipboard: {}", toStr(err)); oxErrf("Could not read clipboard: {}", toStr(err));
return; return;
} }
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.value) { 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;
} }
@@ -203,27 +203,27 @@ void TileSheetEditorModel::endDrawCommand() noexcept {
} }
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 {};
} }
@@ -235,7 +235,7 @@ void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const &idx)
} }
void TileSheetEditorModel::fill(ox::Point const &pt, uint8_t 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) {
return; return;
@@ -255,29 +255,29 @@ void TileSheetEditorModel::fill(ox::Point const &pt, uint8_t const palIdx) noexc
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));
} }
@@ -303,7 +303,7 @@ void TileSheetEditorModel::completeSelection() noexcept {
m_selTracker.finishSelection(); m_selTracker.finishSelection();
m_selection.emplace(m_selTracker.selection()); m_selection.emplace(m_selTracker.selection());
auto&pt = m_selection->b; auto&pt = m_selection->b;
auto const&s = activeSubSheet(); auto const &s = activeSubSheet();
pt.x = ox::min(s.columns * TileWidth - 1, pt.x); pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
pt.y = ox::min(s.rows * TileHeight - 1, pt.y); pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
} }
@@ -315,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;
} }
@@ -352,7 +356,7 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
} }
bool TileSheetEditorModel::pixelSelected(std::size_t const idx) const noexcept { bool TileSheetEditorModel::pixelSelected(std::size_t const idx) const noexcept {
auto const&s = activeSubSheet(); auto const &s = activeSubSheet();
auto const pt = idxToPt(static_cast<int>(idx), s.columns); auto const pt = idxToPt(static_cast<int>(idx), s.columns);
return m_selection && m_selection->contains(pt); return m_selection && m_selection->contains(pt);
} }
@@ -365,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 {
@@ -376,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 {
@@ -390,11 +394,11 @@ 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> const pixels, ox::Span<bool> const pixels,
ox::Point const &pt, ox::Point const &pt,
uint8_t const oldColor) noexcept { uint8_t const oldColor) noexcept {
@@ -437,14 +441,14 @@ 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 {};
} }
ox::Error TileSheetEditorModel::handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const&id) noexcept { ox::Error TileSheetEditorModel::handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const &id) noexcept {
if ((beginsWith(m_img.defaultPalette, "uuid://") && if ((beginsWith(m_img.defaultPalette, "uuid://") &&
substr(m_img.defaultPalette, 7) == id.toString()) || substr(m_img.defaultPalette, 7) == id.toString()) ||
m_img.defaultPalette == newPath) { m_img.defaultPalette == newPath) {

View File

@@ -118,6 +118,9 @@ class TileSheetEditorModel final: public ox::SignalHandler {
void clearSelection() noexcept; void clearSelection() noexcept;
[[nodiscard]]
bool hasSelection() const noexcept;
[[nodiscard]] [[nodiscard]]
bool updated() const noexcept; bool updated() const noexcept;
@@ -152,7 +155,7 @@ class TileSheetEditorModel final: public ox::SignalHandler {
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

@@ -29,8 +29,8 @@ void TileSheetEditorView::draw() noexcept {
m_pixelGridDrawer.draw(updated(), m_scrollOffset); m_pixelGridDrawer.draw(updated(), m_scrollOffset);
} }
void TileSheetEditorView::scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept { void TileSheetEditorView::scrollV(ox::Vec2 const &paneSz, float wheel, bool zoomMod) noexcept {
auto const&s = m_model.activeSubSheet(); auto const &s = m_model.activeSubSheet();
auto const pixelSize = m_pixelsDrawer.pixelSize(paneSz); auto const pixelSize = m_pixelsDrawer.pixelSize(paneSz);
ImVec2 const sheetSize(pixelSize.x * static_cast<float>(s.columns) * TileWidth, ImVec2 const sheetSize(pixelSize.x * static_cast<float>(s.columns) * TileWidth,
pixelSize.y * static_cast<float>(s.rows) * TileHeight); pixelSize.y * static_cast<float>(s.rows) * TileHeight);
@@ -47,8 +47,8 @@ void TileSheetEditorView::scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomM
m_scrollOffset.y = ox::clamp(m_scrollOffset.y, 0.f, sheetSize.y / 2); m_scrollOffset.y = ox::clamp(m_scrollOffset.y, 0.f, sheetSize.y / 2);
} }
void TileSheetEditorView::scrollH(ox::Vec2 const&paneSz, float wheelh) noexcept { void TileSheetEditorView::scrollH(ox::Vec2 const &paneSz, float wheelh) noexcept {
auto const&s = m_model.activeSubSheet(); auto const &s = m_model.activeSubSheet();
auto const pixelSize = m_pixelsDrawer.pixelSize(paneSz); auto const pixelSize = m_pixelsDrawer.pixelSize(paneSz);
ImVec2 const sheetSize(pixelSize.x * static_cast<float>(s.columns) * TileWidth, ImVec2 const sheetSize(pixelSize.x * static_cast<float>(s.columns) * TileWidth,
pixelSize.y * static_cast<float>(s.rows) * TileHeight); pixelSize.y * static_cast<float>(s.rows) * TileHeight);
@@ -56,43 +56,43 @@ void TileSheetEditorView::scrollH(ox::Vec2 const&paneSz, float wheelh) noexcept
m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f); m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f);
} }
void TileSheetEditorView::insertTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::insertTile(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto pt = clickPoint(paneSize, clickPos); auto pt = clickPoint(paneSize, clickPos);
auto const&s = m_model.activeSubSheet(); auto const &s = m_model.activeSubSheet();
pt.x = ox::min(pt.x, s.columns * TileWidth - 1); pt.x = ox::min(pt.x, s.columns * TileWidth - 1);
pt.y = ox::min(pt.y, s.rows * TileHeight - 1); pt.y = ox::min(pt.y, s.rows * TileHeight - 1);
auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile; auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile;
m_model.insertTiles(m_model.activeSubSheetIdx(), tileIdx, 1); m_model.insertTiles(m_model.activeSubSheetIdx(), tileIdx, 1);
} }
void TileSheetEditorView::deleteTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::deleteTile(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
auto const&s = m_model.activeSubSheet(); auto const &s = m_model.activeSubSheet();
auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile; auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile;
m_model.deleteTiles(m_model.activeSubSheetIdx(), tileIdx, 1); m_model.deleteTiles(m_model.activeSubSheetIdx(), tileIdx, 1);
} }
void TileSheetEditorView::clickDraw(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::clickDraw(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
m_model.drawCommand(pt, m_palIdx); m_model.drawCommand(pt, m_palIdx);
} }
void TileSheetEditorView::clickLine(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::clickLine(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
m_model.drawLineCommand(pt, m_palIdx); m_model.drawLineCommand(pt, m_palIdx);
} }
void TileSheetEditorView::clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept { void TileSheetEditorView::clickSelect(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept {
auto const pt = clickPoint(paneSize, clickPos); auto const pt = clickPoint(paneSize, clickPos);
m_model.select(pt); m_model.select(pt);
} }
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<uint8_t>(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:
@@ -107,7 +107,7 @@ void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept {
} }
} }
void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept { void TileSheetEditorView::resizeView(ox::Vec2 const &sz) noexcept {
m_viewSize = sz; m_viewSize = sz;
initView(); initView();
} }
@@ -133,9 +133,9 @@ void TileSheetEditorView::initView() noexcept {
m_pixelGridDrawer.initBufferSet(m_viewSize, m_model.activeSubSheet()); m_pixelGridDrawer.initBufferSet(m_viewSize, m_model.activeSubSheet());
} }
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

@@ -62,28 +62,28 @@ class TileSheetEditorView: public ox::SignalHandler {
void draw() noexcept; void draw() noexcept;
void insertTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void insertTile(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void deleteTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void deleteTile(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void clickDraw(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void clickDraw(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void clickLine(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void clickLine(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void clickSelect(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void clickSelect(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept; void clickFill(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) noexcept;
void releaseMouseButton(TileSheetTool tool) noexcept; void releaseMouseButton(TileSheetTool tool) noexcept;
void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept; void scrollV(ox::Vec2 const &paneSz, float wheel, bool zoomMod) noexcept;
void scrollH(ox::Vec2 const&paneSz, float wheel) noexcept; void scrollH(ox::Vec2 const &paneSz, float wheel) noexcept;
void resizeView(ox::Vec2 const&sz) noexcept; void resizeView(ox::Vec2 const &sz) noexcept;
[[nodiscard]] [[nodiscard]]
constexpr TileSheet const&img() const noexcept; constexpr TileSheet const &img() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr TileSheet &img() noexcept; constexpr TileSheet &img() noexcept;
@@ -117,13 +117,13 @@ class TileSheetEditorView: public ox::SignalHandler {
private: private:
void initView() noexcept; void initView() noexcept;
ox::Point clickPoint(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) const noexcept; ox::Point clickPoint(ox::Vec2 const &paneSize, ox::Vec2 const &clickPos) const noexcept;
ox::Error setActiveSubsheet(TileSheet::SubSheetIdx const&idx) noexcept; ox::Error setActiveSubsheet(TileSheet::SubSheetIdx const &idx) noexcept;
}; };
constexpr TileSheet const&TileSheetEditorView::img() const noexcept { constexpr TileSheet const &TileSheetEditorView::img() const noexcept {
return m_model.img(); return m_model.img();
} }

View File

@@ -23,7 +23,7 @@ ox::Error TileSheetGrid::buildShader() noexcept {
pixelLineVshad, pixelLineFshad, pixelLineGshad).moveTo(m_shader); pixelLineVshad, pixelLineFshad, pixelLineGshad).moveTo(m_shader);
} }
void TileSheetGrid::draw(bool const update, ox::Vec2 const&scroll) noexcept { void TileSheetGrid::draw(bool const update, ox::Vec2 const &scroll) noexcept {
// the lines just show up bigger on Windows for some reason // the lines just show up bigger on Windows for some reason
if constexpr(ox::defines::OS == ox::OS::Windows) { if constexpr(ox::defines::OS == ox::OS::Windows) {
glLineWidth(3 * m_pixelSizeMod * 0.25f); glLineWidth(3 * m_pixelSizeMod * 0.25f);
@@ -42,7 +42,7 @@ void TileSheetGrid::draw(bool const update, ox::Vec2 const&scroll) noexcept {
glUseProgram(0); glUseProgram(0);
} }
void TileSheetGrid::initBufferSet(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept { void TileSheetGrid::initBufferSet(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept {
// vao // vao
m_bufferSet.vao = glutils::generateVertexArrayObject(); m_bufferSet.vao = glutils::generateVertexArrayObject();
glBindVertexArray(m_bufferSet.vao); glBindVertexArray(m_bufferSet.vao);
@@ -65,7 +65,7 @@ void TileSheetGrid::initBufferSet(ox::Vec2 const&paneSize, TileSheet::SubSheet c
std::bit_cast<void*>(uintptr_t{4 * sizeof(float)})); std::bit_cast<void*>(uintptr_t{4 * sizeof(float)}));
} }
void TileSheetGrid::update(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept { void TileSheetGrid::update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept {
glBindVertexArray(m_bufferSet.vao); glBindVertexArray(m_bufferSet.vao);
setBufferObjects(paneSize, subsheet); setBufferObjects(paneSize, subsheet);
glutils::sendVbo(m_bufferSet); glutils::sendVbo(m_bufferSet);
@@ -77,7 +77,7 @@ void TileSheetGrid::setBufferObject(
ox::Point const pt2, ox::Point const pt2,
Color32 const c, Color32 const c,
ox::Span<float> const vbo, ox::Span<float> const vbo,
ox::Vec2 const&pixSize) noexcept { ox::Vec2 const &pixSize) noexcept {
auto const x1 = static_cast<float>(pt1.x) * pixSize.x - 1.f; auto const x1 = static_cast<float>(pt1.x) * pixSize.x - 1.f;
auto const y1 = 1.f - static_cast<float>(pt1.y) * pixSize.y; auto const y1 = 1.f - static_cast<float>(pt1.y) * pixSize.y;
auto const x2 = static_cast<float>(pt2.x) * pixSize.x - 1.f; auto const x2 = static_cast<float>(pt2.x) * pixSize.x - 1.f;
@@ -87,7 +87,7 @@ void TileSheetGrid::setBufferObject(
ox::spancpy(vbo, ox::SpanView<float>{vertices}); ox::spancpy(vbo, ox::SpanView<float>{vertices});
} }
void TileSheetGrid::setBufferObjects(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept { void TileSheetGrid::setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept {
if (subsheet.columns < 1 || subsheet.rows < 1) { if (subsheet.columns < 1 || subsheet.rows < 1) {
m_bufferSet.elements.clear(); m_bufferSet.elements.clear();
m_bufferSet.vertices.clear(); m_bufferSet.vertices.clear();
@@ -129,7 +129,7 @@ void TileSheetGrid::setBufferObjects(ox::Vec2 const&paneSize, TileSheet::SubShee
} }
} }
ox::Vec2 TileSheetGrid::pixelSize(ox::Vec2 const&paneSize) const noexcept { ox::Vec2 TileSheetGrid::pixelSize(ox::Vec2 const &paneSize) const noexcept {
auto const [sw, sh] = paneSize; auto const [sw, sh] = paneSize;
constexpr float ymod = 0.35f / 10.0f; constexpr float ymod = 0.35f / 10.0f;
auto const xmod = ymod * sh / sw; auto const xmod = ymod * sh / sw;

View File

@@ -66,19 +66,20 @@ class TileSheetGrid {
ox::Error buildShader() noexcept; ox::Error buildShader() noexcept;
void draw(bool update, ox::Vec2 const&scroll) noexcept; void draw(bool update, ox::Vec2 const &scroll) noexcept;
void initBufferSet(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept; void initBufferSet(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;
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;
[[nodiscard]] [[nodiscard]]
ox::Vec2 pixelSize(ox::Vec2 const&paneSize) const noexcept; ox::Vec2 pixelSize(ox::Vec2 const &paneSize) const noexcept;
}; };

View File

@@ -49,7 +49,7 @@ ox::Error TileSheetPixels::buildShader() noexcept {
return glutils::buildShaderProgram(s_programSrc).moveTo(m_shader); return glutils::buildShaderProgram(s_programSrc).moveTo(m_shader);
} }
void TileSheetPixels::draw(bool const update, ox::Vec2 const&scroll) noexcept { void TileSheetPixels::draw(bool const update, ox::Vec2 const &scroll) noexcept {
glUseProgram(m_shader); glUseProgram(m_shader);
glBindVertexArray(m_bufferSet.vao); glBindVertexArray(m_bufferSet.vao);
if (update) { if (update) {
@@ -62,7 +62,7 @@ void TileSheetPixels::draw(bool const update, ox::Vec2 const&scroll) noexcept {
glUseProgram(0); glUseProgram(0);
} }
void TileSheetPixels::initBufferSet(ox::Vec2 const&paneSize) noexcept { void TileSheetPixels::initBufferSet(ox::Vec2 const &paneSize) noexcept {
m_bufferSet.vao = glutils::generateVertexArrayObject(); m_bufferSet.vao = glutils::generateVertexArrayObject();
m_bufferSet.vbo = glutils::generateBuffer(); m_bufferSet.vbo = glutils::generateBuffer();
m_bufferSet.ebo = glutils::generateBuffer(); m_bufferSet.ebo = glutils::generateBuffer();
@@ -70,14 +70,14 @@ void TileSheetPixels::initBufferSet(ox::Vec2 const&paneSize) noexcept {
glutils::setupShaderParams(m_shader, s_programSrc.shaderParams); glutils::setupShaderParams(m_shader, s_programSrc.shaderParams);
} }
void TileSheetPixels::update(ox::Vec2 const&paneSize) noexcept { void TileSheetPixels::update(ox::Vec2 const &paneSize) noexcept {
glBindVertexArray(m_bufferSet.vao); glBindVertexArray(m_bufferSet.vao);
setBufferObjects(paneSize); setBufferObjects(paneSize);
glutils::sendVbo(m_bufferSet); glutils::sendVbo(m_bufferSet);
glutils::sendEbo(m_bufferSet); glutils::sendEbo(m_bufferSet);
} }
ox::Vec2 TileSheetPixels::pixelSize(ox::Vec2 const&paneSize) const noexcept { ox::Vec2 TileSheetPixels::pixelSize(ox::Vec2 const &paneSize) const noexcept {
auto const [sw, sh] = paneSize; auto const [sw, sh] = paneSize;
constexpr float ymod = 0.35f / 10.0f; constexpr float ymod = 0.35f / 10.0f;
auto const xmod = ymod * sh / sw; auto const xmod = ymod * sh / sw;
@@ -85,7 +85,7 @@ ox::Vec2 TileSheetPixels::pixelSize(ox::Vec2 const&paneSize) const noexcept {
} }
void TileSheetPixels::setPixelBufferObject( void TileSheetPixels::setPixelBufferObject(
ox::Vec2 const&paneSize, ox::Vec2 const &paneSize,
unsigned const vertexRow, unsigned const vertexRow,
float x, float y, float x, float y,
Color16 const color, Color16 const color,
@@ -112,15 +112,15 @@ void TileSheetPixels::setPixelBufferObject(
ox::spancpy(ebo, ox::SpanView<GLuint>{elms}); ox::spancpy(ebo, ox::SpanView<GLuint>{elms});
} }
void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept { void TileSheetPixels::setBufferObjects(ox::Vec2 const &paneSize) noexcept {
// set buffer lengths // set buffer lengths
auto const&subSheet = m_model.activeSubSheet(); auto const &subSheet = m_model.activeSubSheet();
if (subSheet.columns < 1 || subSheet.rows < 1) { if (subSheet.columns < 1 || subSheet.rows < 1) {
m_bufferSet.vertices.clear(); m_bufferSet.vertices.clear();
m_bufferSet.elements.clear(); m_bufferSet.elements.clear();
return; return;
} }
auto const&pal = m_model.pal(); auto const &pal = m_model.pal();
auto const width = subSheet.columns * TileWidth; auto const width = subSheet.columns * TileWidth;
auto const height = subSheet.rows * TileHeight; auto const height = subSheet.rows * TileHeight;
auto const pixels = static_cast<size_t>(width) * static_cast<size_t>(height); auto const pixels = static_cast<size_t>(width) * static_cast<size_t>(height);

View File

@@ -22,7 +22,7 @@ class TileSheetPixels {
float m_pixelSizeMod = 1; float m_pixelSizeMod = 1;
glutils::GLProgram m_shader; glutils::GLProgram m_shader;
glutils::BufferSet m_bufferSet; glutils::BufferSet m_bufferSet;
class TileSheetEditorModel const&m_model; class TileSheetEditorModel const &m_model;
public: public:
explicit TileSheetPixels(class TileSheetEditorModel &model) noexcept; explicit TileSheetPixels(class TileSheetEditorModel &model) noexcept;
@@ -31,18 +31,18 @@ class TileSheetPixels {
ox::Error buildShader() noexcept; ox::Error buildShader() noexcept;
void draw(bool update, ox::Vec2 const&scroll) noexcept; void draw(bool update, ox::Vec2 const &scroll) noexcept;
void initBufferSet(ox::Vec2 const&paneSize) noexcept; void initBufferSet(ox::Vec2 const &paneSize) noexcept;
void update(ox::Vec2 const&paneSize) noexcept; void update(ox::Vec2 const &paneSize) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vec2 pixelSize(ox::Vec2 const&paneSize) const noexcept; ox::Vec2 pixelSize(ox::Vec2 const &paneSize) const noexcept;
private: private:
void setPixelBufferObject( void setPixelBufferObject(
ox::Vec2 const&paneSize, ox::Vec2 const &paneSize,
unsigned vertexRow, unsigned vertexRow,
float x, float x,
float y, float y,
@@ -50,7 +50,7 @@ class TileSheetPixels {
ox::Span<float> vbo, ox::Span<float> vbo,
ox::Span<GLuint> ebo) const noexcept; ox::Span<GLuint> ebo) const noexcept;
void setBufferObjects(ox::Vec2 const&paneSize) noexcept; void setBufferObjects(ox::Vec2 const &paneSize) noexcept;
}; };

View File

@@ -12,16 +12,16 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept { std::size_t idx(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept {
return ptToIdx(pt, ss.columns); return ptToIdx(pt, ss.columns);
} }
[[nodiscard]] [[nodiscard]]
static TileSheet::SubSheet const *getSubsheet(TileSheet::SubSheet const&ss, SubSheetId const id) noexcept { static TileSheet::SubSheet const *getSubsheet(TileSheet::SubSheet const &ss, SubSheetId const id) noexcept {
if (ss.id == id) { if (ss.id == id) {
return &ss; return &ss;
} }
for (auto const&child: ss.subsheets) { for (auto const &child: ss.subsheets) {
if (auto out = getSubsheet(child, id)) { if (auto out = getSubsheet(child, id)) {
return out; return out;
} }
@@ -30,31 +30,31 @@ static TileSheet::SubSheet const *getSubsheet(TileSheet::SubSheet const&ss, SubS
} }
[[nodiscard]] [[nodiscard]]
static size_t getTileCnt(TileSheet::SubSheet const&ss) noexcept { static size_t getTileCnt(TileSheet::SubSheet const &ss) noexcept {
if (ss.subsheets.empty()) { if (ss.subsheets.empty()) {
return ss.pixels.size() / PixelsPerTile; return ss.pixels.size() / PixelsPerTile;
} else { } else {
size_t out{}; size_t out{};
for (auto const&child: ss.subsheets) { for (auto const &child: ss.subsheets) {
out += getTileCnt(child); out += getTileCnt(child);
} }
return out; return out;
} }
} }
size_t getTileCnt(TileSheet const&ts) noexcept { size_t getTileCnt(TileSheet const &ts) noexcept {
return getTileCnt(ts.subsheet); return getTileCnt(ts.subsheet);
} }
TileSheet::SubSheet const *getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept { TileSheet::SubSheet const *getSubsheet(TileSheet const &ts, SubSheetId const id) noexcept {
return getSubsheet(ts.subsheet, id); return getSubsheet(ts.subsheet, id);
} }
static ox::Optional<size_t> getPixelIdx( static ox::Optional<size_t> getPixelIdx(
TileSheet::SubSheet const&ss, TileSheet::SubSheet const &ss,
SubSheetId const id, SubSheetId const id,
size_t &idx) noexcept { size_t &idx) noexcept {
for (auto const&child: ss.subsheets) { for (auto const &child: ss.subsheets) {
if (child.id == id) { if (child.id == id) {
return ox::Optional<size_t>(ox::in_place, idx); return ox::Optional<size_t>(ox::in_place, idx);
} }
@@ -66,17 +66,17 @@ static ox::Optional<size_t> getPixelIdx(
return ox::Optional<size_t>{}; return ox::Optional<size_t>{};
} }
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept { ox::Optional<size_t> getTileIdx(TileSheet const &ts, SubSheetId const id) noexcept {
size_t idx{}; size_t idx{};
auto const out = getPixelIdx(ts.subsheet, id, idx); auto const out = getPixelIdx(ts.subsheet, id, idx);
return out ? ox::Optional<size_t>{ox::in_place, *out / PixelsPerTile} : out; return out ? ox::Optional<size_t>{ox::in_place, *out / PixelsPerTile} : out;
} }
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t const idx) noexcept { uint8_t getPixel(TileSheet::SubSheet const &ss, std::size_t const idx) noexcept {
return ss.pixels[idx]; return ss.pixels[idx];
} }
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept { uint8_t getPixel(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept {
auto const idx = ptToIdx(pt, ss.columns); auto const idx = ptToIdx(pt, ss.columns);
return getPixel(ss, idx); return getPixel(ss, idx);
} }
@@ -84,14 +84,14 @@ uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept {
static void setPixel( static void setPixel(
ox::Vector<uint8_t> &pixels, ox::Vector<uint8_t> &pixels,
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;
} }
@@ -129,11 +129,11 @@ void flipY(TileSheet::SubSheet &ss, ox::Point const &a, ox::Point const &b) noex
} }
} }
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept { unsigned pixelCnt(TileSheet::SubSheet const &ss) noexcept {
return static_cast<unsigned>(ss.pixels.size()); return static_cast<unsigned>(ss.pixels.size());
} }
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept { ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const &sz) noexcept {
ox::Vector<uint8_t> out; ox::Vector<uint8_t> out;
OX_RETURN_ERROR(setPixelCount(out, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile)); OX_RETURN_ERROR(setPixelCount(out, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile));
auto const w = ox::min<int32_t>(ss.columns, sz.width) * TileWidth; auto const w = ox::min<int32_t>(ss.columns, sz.width) * TileWidth;
@@ -150,12 +150,12 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept {
return {}; return {};
} }
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId const pId) noexcept { ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const &ss, SubSheetId const pId) noexcept {
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;
} }
@@ -167,7 +167,7 @@ ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId c
TileSheet::SubSheetIdx validateSubSheetIdx( TileSheet::SubSheetIdx validateSubSheetIdx(
TileSheet::SubSheetIdx &&pIdx, TileSheet::SubSheetIdx &&pIdx,
std::size_t const pIdxIt, std::size_t const pIdxIt,
TileSheet::SubSheet const&pSubsheet) noexcept { TileSheet::SubSheet const &pSubsheet) noexcept {
if (pIdxIt >= pIdx.size()) { if (pIdxIt >= pIdx.size()) {
return std::move(pIdx); return std::move(pIdx);
} }
@@ -185,7 +185,7 @@ TileSheet::SubSheetIdx validateSubSheetIdx(
return validateSubSheetIdx(std::move(pIdx), pIdxIt + 1, pSubsheet.subsheets[currentIdx]); return validateSubSheetIdx(std::move(pIdx), pIdxIt + 1, pSubsheet.subsheets[currentIdx]);
} }
TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubSheetIdx idx) noexcept { TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const &ts, TileSheet::SubSheetIdx idx) noexcept {
return validateSubSheetIdx(std::move(idx), 0, ts.subsheet); return validateSubSheetIdx(std::move(idx), 0, ts.subsheet);
} }
@@ -211,18 +211,59 @@ ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetI
return out; return out;
} }
template<typename SubSheet>
static ox::Result<SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
std::size_t const idxIt,
SubSheet &pSubSheet) noexcept {
if (idxIt == idx.size()) {
return &pSubSheet;
}
auto const &currentIdx = idx[idxIt];
auto const next = ox::find_if(
pSubSheet.subsheets.begin(),
pSubSheet.subsheets.end(),
[&currentIdx](TileSheet::SubSheet const &ss) {
return ss.name == currentIdx;
});
if (next == pSubSheet.subsheets.end()) {
return ox::Error{1, "SubSheet not found"};
}
return getSubSheet(idx, idxIt + 1, *next);
}
ox::Result<TileSheet::SubSheet const*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet const &ts) noexcept {
if (!idx.empty() && idx[0] == ts.subsheet.name) {
return getSubSheet<TileSheet::SubSheet const>(idx, 1, ts.subsheet);
}
return ox::Error{1, "SubSheet not found"};
}
ox::Result<TileSheet::SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet &ts) noexcept {
if (!idx.empty() && idx[0] == ts.subsheet.name) {
return getSubSheet<TileSheet::SubSheet>(idx, 1, ts.subsheet);
}
return ox::Error{1, "SubSheet not found"};
}
#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"
#endif #endif
static TileSheet::SubSheet const&getSubSheet( static TileSheet::SubSheet const &getSubSheet(
ox::SpanView<uint32_t> const &idx, ox::SpanView<uint32_t> const &idx,
std::size_t const idxIt, std::size_t const idxIt,
TileSheet::SubSheet const &pSubsheet) noexcept { TileSheet::SubSheet const &pSubsheet) noexcept {
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;
} }
@@ -246,7 +287,7 @@ TileSheet::SubSheet &getSubSheet(
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference" #pragma GCC diagnostic ignored "-Wdangling-reference"
#endif #endif
TileSheet::SubSheet const&getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept { TileSheet::SubSheet const &getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept {
return gfx::getSubSheet(idx, 0, ts.subsheet); return gfx::getSubSheet(idx, 0, ts.subsheet);
} }
@@ -257,7 +298,7 @@ TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &id
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept { ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept {
auto &parent = getSubSheet(ts, idx); auto &parent = getSubSheet(ts, idx);
if (parent.subsheets.size() < 2) { if (parent.subsheets.size() < 2) {
parent.subsheets.emplace_back(++ts.idIt, ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1); parent.subsheets.emplace_back(++ts.idIt, ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1);
@@ -268,7 +309,7 @@ ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept
return {}; return {};
} }
ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const&idx, TileSheet::SubSheet ss) noexcept { ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx, TileSheet::SubSheet ss) noexcept {
if (idx.empty()) { if (idx.empty()) {
return ox::Error{1, "invalid insert idx"}; return ox::Error{1, "invalid insert idx"};
} }
@@ -283,7 +324,7 @@ ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const&idx, TileSh
ox::Error rmSubSheet( ox::Error rmSubSheet(
TileSheet &ts, TileSheet &ts,
TileSheet::SubSheetIdx const&idx, TileSheet::SubSheetIdx const &idx,
std::size_t const idxIt, std::size_t const idxIt,
TileSheet::SubSheet &pSubsheet) noexcept { TileSheet::SubSheet &pSubsheet) noexcept {
if (idxIt == idx.size() - 1) { if (idxIt == idx.size() - 1) {
@@ -292,21 +333,21 @@ ox::Error rmSubSheet(
return rmSubSheet(ts, idx, idxIt + 1, pSubsheet.subsheets[idx[idxIt]]); return rmSubSheet(ts, idx, idxIt + 1, pSubsheet.subsheets[idx[idxIt]]);
} }
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept { ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept {
return rmSubSheet(ts, idx, 0, ts.subsheet); return rmSubSheet(ts, idx, 0, ts.subsheet);
} }
uint8_t getPixel( uint8_t getPixel(
TileSheet const&ts, TileSheet const &ts,
ox::Point const&pt, ox::Point const &pt,
TileSheet::SubSheetIdx const&subsheetIdx) noexcept { TileSheet::SubSheetIdx const &subsheetIdx) noexcept {
auto &s = getSubSheet(ts, subsheetIdx); auto &s = getSubSheet(ts, subsheetIdx);
auto const idx = ptToIdx(pt, s.columns); auto const idx = ptToIdx(pt, s.columns);
return getPixel(s, idx); return getPixel(s, idx);
} }
uint8_t getPixel4Bpp( uint8_t getPixel4Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const idx) noexcept { size_t const idx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp"); oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
if (idx & 1) { if (idx & 1) {
@@ -317,14 +358,14 @@ uint8_t getPixel4Bpp(
} }
uint8_t getPixel8Bpp( uint8_t getPixel8Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const idx) noexcept { size_t const idx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp"); oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
return ts.pixels[idx]; return ts.pixels[idx];
} }
ox::Pair<uint8_t> get2Pixels4Bpp( ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const idx) noexcept { size_t const idx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp"); oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
auto const out = ts.pixels[idx / 2]; auto const out = ts.pixels[idx / 2];
@@ -335,7 +376,7 @@ ox::Pair<uint8_t> get2Pixels4Bpp(
} }
ox::Pair<uint8_t> get2Pixels8Bpp( ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts, CompactTileSheet const &ts,
size_t const idx) noexcept { size_t const idx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp"); oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
return { return {
@@ -345,8 +386,8 @@ ox::Pair<uint8_t> get2Pixels8Bpp(
} }
static ox::Result<SubSheetId> getIdFor( static ox::Result<SubSheetId> getIdFor(
TileSheet::SubSheet const&ss, TileSheet::SubSheet const &ss,
ox::SpanView<ox::StringView> const&pNamePath, ox::SpanView<ox::StringView> const &pNamePath,
std::size_t const pIt = 0) noexcept { std::size_t const pIt = 0) noexcept {
for (auto &sub : ss.subsheets) { for (auto &sub : ss.subsheets) {
if (sub.name == pNamePath[pIt]) { if (sub.name == pNamePath[pIt]) {
@@ -359,7 +400,7 @@ static ox::Result<SubSheetId> getIdFor(
return ox::Error(1, "SubSheet not found"); return ox::Error(1, "SubSheet not found");
} }
ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexcept { ox::Result<SubSheetId> getIdFor(TileSheet const &ts, ox::StringViewCR path) noexcept {
return getIdFor(ts.subsheet, ox::split<8>(path, '.')); return getIdFor(ts.subsheet, ox::split<8>(path, '.'));
} }
@@ -367,8 +408,8 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
* Gets the offset in tiles of the desired subsheet. * Gets the offset in tiles of the desired subsheet.
*/ */
static ox::Result<uint32_t> getTileOffset( static ox::Result<uint32_t> getTileOffset(
TileSheet::SubSheet const&ss, TileSheet::SubSheet const &ss,
ox::SpanView<ox::StringView> const&pNamePath, ox::SpanView<ox::StringView> const &pNamePath,
std::size_t const pIt = 0, std::size_t const pIt = 0,
uint32_t pCurrentTotal = 0) noexcept { uint32_t pCurrentTotal = 0) noexcept {
// pIt == pNamePath.size() - 1 && // pIt == pNamePath.size() - 1 &&
@@ -391,7 +432,7 @@ static ox::Result<uint32_t> getTileOffset(
return ox::Error(1, "SubSheet not found"); return ox::Error(1, "SubSheet not found");
} }
ox::Result<uint32_t> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept { ox::Result<uint32_t> getTileOffset(TileSheet const &ts, ox::StringViewCR pNamePath) noexcept {
return gfx::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.')); return gfx::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.'));
} }
@@ -399,7 +440,7 @@ ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId const pId) noexc
return gfx::getNameFor(ts.subsheet, pId); return gfx::getNameFor(ts.subsheet, pId);
} }
ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId const pId) noexcept { ox::Result<ox::StringView> getNameFor(TileSheet const &ts, SubSheetId const pId) noexcept {
return gfx::getNameFor(ts.subsheet, pId); return gfx::getNameFor(ts.subsheet, pId);
} }
@@ -431,19 +472,19 @@ ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept {
ox::Vector<uint32_t> resizeTileSheetData( ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> const&srcPixels, ox::Vector<uint32_t> const &srcPixels,
ox::Size const&srcSize, ox::Size const &srcSize,
int const scale) noexcept { int const scale) noexcept {
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

@@ -24,7 +24,7 @@ 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

@@ -10,6 +10,10 @@ namespace nostalgia::sound {
static struct: studio::Module { static struct: studio::Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.nostalgia.sound"};
}
ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final { ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final {
return { return {
}; };
@@ -22,7 +26,7 @@ static struct: studio::Module {
} const mod; } const mod;
const studio::Module *studioModule() noexcept { studio::Module const *studioModule() noexcept {
return &mod; return &mod;
} }

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