Compare commits

..

97 Commits

Author SHA1 Message Date
f987b02c65 [nostalgia/gfx] Move to TileSheetV5
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-21 02:21:01 -06:00
3c056276c1 [turbine,nostalgia] Cleanup 2025-01-20 23:19:07 -06:00
87e2fdefcf [ox/std] Make UAnyPtr uncopyable 2025-01-20 20:42:00 -06:00
672b92b363 [nostalgia/gfx/studio] Remove accidental version tag in default Palette
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-20 03:13:01 -06:00
762a6517b2 [nostalgia] Rename core to gfx 2025-01-20 03:11:35 -06:00
d141154a45 Merge commit '38777cfac8868b3628332090260710d5ac26aba0'
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-20 02:15:45 -06:00
6170647c0c [nostalgia,studio] Proper fix for input filtering 2025-01-20 02:10:48 -06:00
48e45c7dd6 [studio] Cleanup 2025-01-20 01:34:00 -06:00
5d3d9229b7 [nostalgia/core/studio/paletteeditor] Ignore keyboard input when popup is open 2025-01-20 01:33:23 -06:00
d54e93d836 [studio] Cleanup 2025-01-20 00:16:16 -06:00
830f8fe3e4 [studio,nostalgia/core/studio] Give default Palette created studio a default page
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-19 20:53:27 -06:00
7b638538aa Merge commit '8e0b6ffbabb10f8a6e9ad7e9f07e0ba1d039a02e' 2025-01-19 20:18:56 -06:00
2016f6e605 [studio] Fix DeleteConfirmation 'No' option to not delete file
All checks were successful
Build / build (push) Successful in 3m22s
2025-01-19 20:17:35 -06:00
240effd305 Merge commit '7e20f7200963cd0b22f84cc46e10db12b6c13806' 2025-01-19 19:04:24 -06:00
6bc629e02c [nostalgia/core/studio/tilesheeteditor] Replace Palette combobox with a readonly text input
All checks were successful
Build / build (push) Successful in 3m21s
2025-01-19 19:02:44 -06:00
f6f2acd67b [nostalgia/core/studio/tilesheeteditor] Add back file type check for palette drop 2025-01-19 18:21:50 -06:00
0146d38405 [nostalgia/core/studio/tilesheeteditor] Manually merge in changes that were lost in conflict
All checks were successful
Build / build (push) Successful in 3m19s
2025-01-19 18:18:52 -06:00
75d8e7bb89 [nostalgia/core/studio/paletteeditor] Fix crash that occurs when removing last color 2025-01-19 17:56:21 -06:00
6b53eaf6b1 [ox/std] Fix string append issues
All checks were successful
Build / build (push) Successful in 3m22s
2025-01-19 16:51:05 -06:00
16c32273ac [nostalgia/core/studio/tilesheeteditor] Fix palette drop target to only take palettes 2025-01-19 16:49:31 -06:00
1567a6e29d [applib] Fix build 2025-01-19 14:32:08 -06:00
89d543bcbc Merge commit '7b7d59cf63d77cf7ab6daf6ed7122eef97954555' 2025-01-19 13:39:31 -06:00
d68e64931b [nostalgia/core/studio/tilesheeteditor] Add support for dragging palette to palette selector
All checks were successful
Build / build (push) Successful in 3m22s
2025-01-19 11:41:48 -06:00
1cbc576286 [studio] Complete drag/drop support for files 2025-01-19 11:41:08 -06:00
500b93562c [studio] Make new dir window OK on Enter key
All checks were successful
Build / build (push) Successful in 3m17s
2025-01-19 09:33:17 -06:00
800ca85176 [ox/std] Fix possible error that occurs with appending on boundary of small string size
All checks were successful
Build / build (push) Successful in 3m20s
2025-01-19 09:26:06 -06:00
cc466a9f1d [studio] Add support for adding and deleting directories 2025-01-19 09:06:16 -06:00
9d1155843e [nostalgia] Rename player from 'nostalgia' to 'Nostalgia'
All checks were successful
Build / build (push) Successful in 3m24s
2025-01-19 01:48:53 -06:00
a2139c09b2 [studio] Cleanup unused member 2025-01-19 01:44:26 -06:00
a3e5f27ab8 [ox/std] Fix Mac build 2025-01-19 01:43:38 -06:00
643f95ec80 [studio] Add confirmation dialog for file deletion, move deletion to Project
All checks were successful
Build / build (push) Successful in 3m16s
2025-01-19 01:15:33 -06:00
6924147686 [studio] Add ability to add file through dir context menu
All checks were successful
Build / build (push) Successful in 3m15s
Also, fix dir context menu to work when dir is closed, and fix it not to
override last file in the directory.
2025-01-18 23:45:04 -06:00
6e2b4fa7b4 [nostalgia] Cleanup player run in Makefile 2025-01-18 23:33:55 -06:00
4e5c749918 [studio] Add support for deleting files
All checks were successful
Build / build (push) Successful in 3m16s
2025-01-18 22:32:12 -06:00
66229de77f [ox/fs] FileSystem fixes with removing files 2025-01-18 22:31:19 -06:00
7eb37c5318 [nostalgia/core/studio/paletteeditor] Fix adding page if there is no existing page
All checks were successful
Build / build (push) Successful in 3m17s
2025-01-18 21:29:36 -06:00
7a21b20711 [nostalgia/core] Replace ContextDeleter with safeDelete(Context*)
All checks were successful
Build / build (push) Successful in 3m15s
2025-01-18 20:57:15 -06:00
894be237f2 [ox/std] Drop ox:: qualifier from safeDelete function for pointee 2025-01-18 20:56:24 -06:00
92e9d9cbfc [keel,studio] Add support for New Item templates
Some checks failed
Build / build (push) Failing after 1m3s
2025-01-18 20:16:29 -06:00
b29b9a9b3a [ox/std] Add UAnyPtr 2025-01-18 20:11:42 -06:00
721f844214 [nostalgia/core/studio/tilesheeteditor] Fix subsheet and palette scrolling 2025-01-18 20:08:09 -06:00
a3d6a58cc8 [nostalgia/core/studio] Fix library cpp file ownership
All checks were successful
Build / build (push) Successful in 3m10s
2025-01-17 21:50:42 -06:00
e598e7fe27 [nostalgia,keel] Add ability to types Obj to Obj
All checks were successful
Build / build (push) Successful in 3m10s
2025-01-15 23:44:18 -06:00
ba9e720f9f [ox/model] Fix ModelTypeName_v to use requireModelTypeName 2025-01-15 23:34:58 -06:00
8e816a261f [nostalgia/core/studio] Cleanup, fix possible TileSheet fill tool failure
All checks were successful
Build / build (push) Successful in 3m11s
2025-01-14 23:06:12 -06:00
5b9929ab3d [keel] Add detail to preload logging 2025-01-14 21:20:13 -06:00
ceb54b3f1b [nostalgia/core/opengl] Cleanup 2025-01-14 21:18:22 -06:00
8764444758 [nostalgia/core] Add clearCbb functions
All checks were successful
Build / build (push) Successful in 3m12s
2025-01-14 21:13:42 -06:00
ce9a0b1fdb [nostalgia/core/opengl] Cleanup memcpys 2025-01-14 21:13:10 -06:00
f7a468ea1e [ox/std] Add spancpy 2025-01-14 21:10:18 -06:00
861d177a27 [studio] Cleanup
All checks were successful
Build / build (push) Successful in 3m12s
2025-01-13 22:58:39 -06:00
3936756b36 [nostalgia/developer-handbook] Update error handling to reflect the enablement of exceptions for GBA build 2025-01-13 22:53:12 -06:00
3e78ec3fe5 [studio] Cleanup 2025-01-13 22:40:08 -06:00
3c3d53b40c [studio] Ensure Editor tabs do first draw immediately, fix shift key being missed with tab shortcuts
All checks were successful
Build / build (push) Successful in 3m14s
2025-01-13 22:29:48 -06:00
151d7c5736 [nostalgia/core/gba] Fix partial tilesheet loading overrun
All checks were successful
Build / build (push) Successful in 3m11s
2025-01-13 22:03:36 -06:00
4e4d8d2c3f [nostalgia/core/gba] Make panic use standard abort call 2025-01-13 21:37:29 -06:00
03d1fd2857 [ox/std] Add and integrate standard abort call 2025-01-13 20:39:21 -06:00
6701decc91 [gbabuildcore] Enable exceptions 2025-01-13 20:18:28 -06:00
6cff526647 [teagba] Add symbols needed for enabling exceptions 2025-01-13 20:17:10 -06:00
dd50bd0249 [studio] Remap toggle explorer keyboard shortcut, add Ctrl+1-0 mappings for jumping between tabs
All checks were successful
Build / build (push) Successful in 3m17s
2025-01-13 01:14:57 -06:00
55a1660242 [nostalgia/core] Fix TileSheet validation/repair to ensure pixels gets cleared if there are subsheets
All checks were successful
Build / build (push) Successful in 3m10s
2025-01-12 16:06:24 -06:00
ed365dfef5 [studio] Fix new project menu to return an appropriately sized string for name 2025-01-12 15:04:31 -06:00
23a09e4a13 [nostalgia/core/studio] Fix SubSheet editor to return an appropriately sized string 2025-01-12 14:55:50 -06:00
b69e7ebb98 [nostalgia/core/studio/tilesheeteditor] Fix select all not to go beyond end
All checks were successful
Build / build (push) Successful in 3m10s
2025-01-11 16:21:10 -06:00
418d6e3f22 [nostalgia/core/studio] Fix crash that occurs when a non-leaf node subsheet is selected
All checks were successful
Build / build (push) Successful in 3m11s
2025-01-11 16:06:48 -06:00
c44d8678cb [nostalgia/core/studio] Fix tile insert to correct input when inserting past the last tile
All checks were successful
Build / build (push) Successful in 3m11s
2025-01-11 15:38:11 -06:00
eb4cd7106d [nostalgia/core/studio] Fix tile insert to work on last tile
All checks were successful
Build / build (push) Successful in 3m9s
2025-01-11 15:23:57 -06:00
d259770f32 Merge commit '4ea4a61d542777a270c4e2c283e0e986fc9eec9c'
All checks were successful
Build / build (push) Successful in 3m9s
2025-01-11 12:32:00 -06:00
80bad608f7 [keel] Fix reloadAsset 2025-01-11 03:39:38 -06:00
2bce9a2baf [ox/std] Add non-const SmallMap::pairs 2025-01-11 03:37:27 -06:00
791b7746f3 [nostalgia] Update liccor file
All checks were successful
Build / build (push) Successful in 3m18s
2025-01-08 23:13:14 -06:00
842e3587fd [nostalgia] Update .gitignore for new location of scripts dir 2025-01-08 23:13:02 -06:00
318e79004b [ox] Update liccor file 2025-01-08 23:12:28 -06:00
9f338a7429 [ox] Run liccor
All checks were successful
Build / build (push) Successful in 3m18s
2025-01-08 23:03:05 -06:00
645e48af7b [nostalgia,olympic] Run liccor 2025-01-08 23:02:08 -06:00
ef92c8df13 [nostalgia] Make pkg-gba.py force lower case for pack tool
All checks were successful
Build / build (push) Successful in 3m9s
2025-01-08 22:01:27 -06:00
849d50be8e [nostalgia/core] Make getTileIdx return an Optional 2025-01-08 21:34:01 -06:00
845092f114 [turbine] Make common turbine.cpp file private to its target 2025-01-08 21:33:23 -06:00
75819a1797 [ox/std] Add SmallMap::values() 2025-01-08 21:31:46 -06:00
d66da85753 [ox/std] SmallMap fixes, add findIdx function 2025-01-07 20:59:04 -06:00
98ddb08abd [nostalgia] Cleanup
All checks were successful
Build / build (push) Successful in 3m18s
2025-01-05 20:55:49 -06:00
8d1701b0bb [turbine/glfw] Ensure window opens with a standard mandatory refresh period
All checks were successful
Build / build (push) Successful in 3m19s
2025-01-04 23:49:04 -06:00
1048e522fd [imgui] Make ImGui not an object lib 2025-01-04 23:42:43 -06:00
ee59da4aa3 [glad] Make glad not an object lib 2025-01-04 23:42:43 -06:00
1ba64cb5d8 Merge commit '07610a5af2aaaac9cfcdcf8359b33f7df40d46cd'
All checks were successful
Build / build (push) Successful in 3m15s
2025-01-04 01:29:09 -06:00
462bebf6dd [nostalgia/core] Cleanup unused function declaration 2025-01-04 01:26:02 -06:00
e3f84c4e75 [studio] Make first tab not draw before selected tab when window opens 2025-01-04 01:12:48 -06:00
6837a0556d [keel] Make AssetManager take StringViewCR for assetId
All checks were successful
Build / build (push) Successful in 3m16s
2025-01-04 01:11:05 -06:00
ede2c8ca37 [keel] Make AssetTypeManager(Loader) move loader
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-04 01:05:04 -06:00
f50367f7d5 [ox/std] Add hash.hpp to install
All checks were successful
Build / build (push) Successful in 3m31s
2025-01-03 00:26:10 -06:00
e758e03d2b [nostalgia,olympic] Update for ox::Error changes
All checks were successful
Build / build (push) Successful in 3m20s
2025-01-01 23:43:32 -06:00
835e3270ce [ox] Make Error use std::source_location 2025-01-01 23:42:46 -06:00
480dd5ece4 [ox/std] Cleanup
All checks were successful
Build / build (push) Successful in 3m25s
2025-01-01 22:57:20 -06:00
dba6bb5800 [ox/std] Make Vector(initializer_list) use list size as capacity
All checks were successful
Build / build (push) Successful in 3m55s
2025-01-01 22:37:28 -06:00
40a456e54a [ox/std] Add Vector::shrink_to_fit 2025-01-01 22:32:57 -06:00
bf5be00c12 Merge commit 'dc96270ca5e882e41f6b657be14a20e8bd2ad501'
All checks were successful
Build / build (push) Successful in 3m14s
2024-12-21 20:13:20 -06:00
dc7c2559d6 [studio] Make selection tracker not go below 0 2024-12-21 20:06:48 -06:00
180 changed files with 2215 additions and 1034 deletions

2
.gitignore vendored
View File

@ -6,7 +6,7 @@
.mypy_cache .mypy_cache
.stfolder .stfolder
.stignore .stignore
scripts/__pycache__ util/scripts/__pycache__
pyenv pyenv
CMakeLists.txt.user CMakeLists.txt.user
ROM.oxfs ROM.oxfs

View File

@ -1,26 +1,31 @@
BC_VAR_PROJECT_NAME=nostalgia BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) ifeq ($(BC_VAR_OS),darwin)
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio PROJECT_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else else
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio PROJECT_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=mgba-qt MGBA=mgba-qt
endif endif
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
${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: run .PHONY: run
run: build run: build-player
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project ${PROJECT_PLAYER} sample_project
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build
${NOSTALGIA_STUDIO} ${PROJECT_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME}.gba ${MGBA} ${BC_VAR_PROJECT_NAME}.gba
@ -29,7 +34,7 @@ debug: build
${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project ${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
configure-gba: configure-gba:

View File

@ -1,8 +1,8 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")

View File

@ -1,2 +1,11 @@
add_library(glad OBJECT src/glad.c) add_library(glad src/glad.c)
target_include_directories(glad PUBLIC include)
target_include_directories(glad PUBLIC include)
install(
TARGETS
glad
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@ -6,7 +6,7 @@ endif()
# DrinkingTea: end # DrinkingTea: end
add_library( add_library(
imgui OBJECT imgui
imgui.cpp imgui.cpp
imgui_demo.cpp imgui_demo.cpp
imgui_draw.cpp imgui_draw.cpp
@ -19,4 +19,12 @@ add_library(
target_include_directories( target_include_directories(
imgui SYSTEM PUBLIC imgui SYSTEM PUBLIC
. .
) )
install(
TARGETS
imgui
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@ -215,7 +215,7 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
} }
return ox::Error(0); return ox::Error(0);
} catch (const ox::Exception &ex) { } catch (const ox::Exception &ex) {
return ox::Error(ex.file, ex.line, ex.errCode, ex.msg); return ox::Error(ex.errCode, ex.msg, ex.src);
} }
} }

View File

@ -63,18 +63,6 @@ Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size
} }
} }
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return remove(addr.getInode().value, recursive);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return remove(StringView(addr.getPath().value), recursive);
default:
return ox::Error(1);
}
}
Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:

View File

@ -57,9 +57,9 @@ class FileSystem {
virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0; virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0;
virtual Error remove(StringViewCR path, bool recursive) noexcept = 0; Error remove(StringViewCR path, bool recursive = false) noexcept {
return removePath(path, recursive);
Error remove(const FileAddress &addr, bool recursive = false) noexcept; }
virtual Error resize(uint64_t size, void *buffer) noexcept = 0; virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
@ -142,6 +142,8 @@ class FileSystem {
virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0; virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
virtual Error removePath(StringViewCR path, bool recursive) noexcept = 0;
virtual Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0; virtual Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
virtual Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0; virtual Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
@ -209,6 +211,8 @@ class FileSystemTemplate: public MemFS {
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override; Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Result<const char*> directAccessInode(uint64_t) const noexcept override; Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(StringViewCR dir) const noexcept override; Result<Vector<String>> ls(StringViewCR dir) const noexcept override;
@ -216,8 +220,6 @@ class FileSystemTemplate: public MemFS {
template<typename F> template<typename F>
Error ls(StringViewCR path, F cb) const; Error ls(StringViewCR path, F cb) const;
Error remove(StringViewCR path, bool recursive) noexcept override;
/** /**
* Resizes FileSystem to minimum possible size. * Resizes FileSystem to minimum possible size.
*/ */
@ -356,6 +358,25 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inod
return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size); return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size);
} }
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bool recursive) noexcept {
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
OX_REQUIRE(inode, rootDir.find(path));
OX_REQUIRE(st, statInode(inode));
if (st.fileType == FileType::NormalFile || recursive) {
if (auto err = rootDir.remove(path)) {
// removal failed, try putting the index back
oxLogError(rootDir.write(path, inode));
return err;
}
} else {
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return ox::Error(1);
}
return ox::Error(0);
}
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept { Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode); auto data = m_fs.read(inode);
@ -384,25 +405,6 @@ Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) cons
return dir.ls(cb); return dir.ls(cb);
} }
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::remove(StringViewCR path, bool recursive) noexcept {
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
OX_REQUIRE(inode, rootDir.find(path));
OX_REQUIRE(st, statInode(inode));
if (st.fileType == FileType::NormalFile || recursive) {
if (auto err = rootDir.remove(path)) {
// removal failed, try putting the index back
oxLogError(rootDir.write(path, inode));
return err;
}
} else {
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return ox::Error(1);
}
return ox::Error(0);
}
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::resize() noexcept { Error FileSystemTemplate<FileStore, Directory>::resize() noexcept {
return m_fs.resize(); return m_fs.resize();

View File

@ -75,14 +75,6 @@ Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
return out; return out;
} }
Error PassThroughFS::remove(StringViewCR path, bool recursive) noexcept {
if (recursive) {
return ox::Error(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
} else {
return ox::Error(std::filesystem::remove(m_path / stripSlash(path)) != 0);
}
}
Error PassThroughFS::resize(uint64_t, void*) noexcept { Error PassThroughFS::resize(uint64_t, void*) noexcept {
// unsupported // unsupported
return ox::Error(1, "resize is not supported by PassThroughFS"); return ox::Error(1, "resize is not supported by PassThroughFS");
@ -167,6 +159,14 @@ Error PassThroughFS::readFileInodeRange(uint64_t, std::size_t, std::size_t, void
return ox::Error(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS"); return ox::Error(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
} }
Error PassThroughFS::removePath(StringViewCR path, bool const recursive) noexcept {
if (recursive) {
return ox::Error{std::filesystem::remove_all(m_path / stripSlash(path)) == 0};
} else {
return ox::Error{!std::filesystem::remove(m_path / stripSlash(path))};
}
}
Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType) noexcept { Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType) noexcept {
const auto p = (m_path / stripSlash(path)); const auto p = (m_path / stripSlash(path));
try { try {

View File

@ -45,8 +45,6 @@ class PassThroughFS: public FileSystem {
template<typename F> template<typename F>
Error ls(StringViewCR dir, F cb) const noexcept; Error ls(StringViewCR dir, F cb) const noexcept;
Error remove(StringViewCR path, bool recursive) noexcept override;
Error resize(uint64_t size, void *buffer) noexcept override; Error resize(uint64_t size, void *buffer) noexcept override;
Result<FileStat> statInode(uint64_t inode) const noexcept override; Result<FileStat> statInode(uint64_t inode) const noexcept override;
@ -75,6 +73,8 @@ class PassThroughFS: public FileSystem {
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override; Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept override; Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override; Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;

View File

@ -14,7 +14,7 @@
{ \ { \
const auto loggerErr = (loggerName).initConn(appName); \ const auto loggerErr = (loggerName).initConn(appName); \
if (loggerErr) { \ if (loggerErr) { \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \ oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.src.file_name(), loggerErr.src.line()); \
} else { \ } else { \
ox::trace::setLogger(&(loggerName)); \ ox::trace::setLogger(&(loggerName)); \
} \ } \

View File

@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
return out; return out;
} }
template<typename T> template<typename T, typename Str = const char*>
[[nodiscard]] [[nodiscard]]
consteval auto requireModelTypeName() noexcept { consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T>(); constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName"); static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
return name; return name;
} }
template<typename T, typename Str = const char*> template<typename T, typename Str = const char*>
constexpr auto ModelTypeName_v = getModelTypeName<T, Str>(); constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
template<typename T, typename Str = const char*> template<typename T, typename Str = const char*>
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>(); constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();

View File

@ -58,11 +58,7 @@ class TypeStore {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
OX_REQUIRE_M(dt, loadDescriptor(typeId)); OX_REQUIRE_M(dt, loadDescriptor(typeId));
for (auto &f : dt->fieldList) { for (auto &f : dt->fieldList) {
if (typeId == f.typeId) { OX_RETURN_ERROR(this->getLoad(f.typeId).moveTo(f.type));
f.type = dt.get();
} else {
OX_RETURN_ERROR(this->getLoad(f.typeId).moveTo(f.type));
}
} }
auto &out = m_cache[typeId]; auto &out = m_cache[typeId];
out = std::move(dt); out = std::move(dt);

View File

@ -9,13 +9,25 @@
#pragma once #pragma once
#include "def.hpp" #include "def.hpp"
#include "error.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage) OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
template<typename It, typename T> template<typename It, typename T>
constexpr It find(It begin, It end, const T &value) { constexpr ox::Result<size_t> findIdx(It begin, It end, T const&value) {
auto it = begin;
for (; it != end; ++it) {
if (*it == value) {
return it.offset();
}
}
return ox::Error{1, "item not found"};
}
template<typename It, typename T>
constexpr It find(It begin, It end, T const&value) {
for (; begin != end; ++begin) { for (; begin != end; ++begin) {
if (*begin == value) { if (*begin == value) {
return begin; return begin;

View File

@ -15,18 +15,22 @@
namespace ox { namespace ox {
class AnyPtr { namespace detail {
template<bool unique>
class AnyPtrT {
private: private:
struct WrapBase { struct WrapBase {
virtual constexpr ~WrapBase() = default; virtual constexpr ~WrapBase() = default;
virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0; virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
virtual constexpr operator bool() const noexcept = 0; virtual constexpr operator bool() const noexcept = 0;
virtual void free() noexcept = 0;
}; };
template<typename T> template<typename T>
struct Wrap: public WrapBase { struct Wrap final: WrapBase {
T *data{}; T *data{};
constexpr Wrap(T *pData) noexcept: data(pData) { explicit constexpr Wrap(T *pData) noexcept: data(pData) {
} }
constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override { constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override {
oxAssert(s.size() >= sizeof(Wrap), "too small buffer"); oxAssert(s.size() >= sizeof(Wrap), "too small buffer");
@ -39,39 +43,60 @@ class AnyPtr {
constexpr operator bool() const noexcept override { constexpr operator bool() const noexcept override {
return data != nullptr; return data != nullptr;
} }
constexpr void free() noexcept override {
safeDelete(data);
data = {};
}
}; };
WrapBase *m_wrapPtr{}; WrapBase *m_wrapPtr{};
ox::Array<char, sizeof(Wrap<void*>)> m_wrapData; ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
public: public:
constexpr AnyPtr() noexcept = default; constexpr AnyPtrT() noexcept = default;
template<typename T> template<typename T>
constexpr AnyPtr(T *ptr) noexcept { constexpr AnyPtrT(T *ptr) noexcept {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
m_wrapPtr = new Wrap(ptr); m_wrapPtr = new Wrap<T>(ptr);
} else { } else {
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr); m_wrapPtr = new(m_wrapData.data()) Wrap<T>(ptr);
} }
} }
constexpr AnyPtr(AnyPtr const&other) noexcept { constexpr AnyPtrT(AnyPtrT const&other) noexcept requires(!unique) {
if (other) { if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData); m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
} }
} }
constexpr ~AnyPtr() noexcept { constexpr AnyPtrT(AnyPtrT &&other) noexcept {
if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
other.m_wrapPtr = {};
}
}
constexpr ~AnyPtrT() noexcept {
if constexpr(unique) {
free();
}
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_wrapPtr);
} }
} }
template<typename T> template<typename T>
constexpr AnyPtr &operator=(T *ptr) noexcept { constexpr AnyPtrT &operator=(T *ptr) noexcept {
if (std::is_constant_evaluated()) { if constexpr(unique) {
free();
} else if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_wrapPtr);
}
if (std::is_constant_evaluated()) {
m_wrapPtr = new Wrap(ptr); m_wrapPtr = new Wrap(ptr);
} else { } else {
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr); m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
@ -79,10 +104,12 @@ class AnyPtr {
return *this; return *this;
} }
constexpr AnyPtr &operator=(AnyPtr const&ptr) noexcept { constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept requires(!unique) {
if (this != &ptr) { if (this != &ptr) {
if (ptr) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_wrapPtr);
}
if (ptr) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData); m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
} else { } else {
m_wrapPtr = nullptr; m_wrapPtr = nullptr;
@ -91,10 +118,40 @@ class AnyPtr {
return *this; return *this;
} }
constexpr AnyPtrT &operator=(AnyPtrT &&ptr) noexcept {
if (this != &ptr) {
if constexpr(unique) {
free();
} else if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
if (ptr) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
if (std::is_constant_evaluated()) {
ox::safeDelete(ptr.m_wrapPtr);
ptr.m_wrapPtr = nullptr;
}
} else {
m_wrapPtr = nullptr;
}
}
return *this;
}
constexpr operator bool() const noexcept { constexpr operator bool() const noexcept {
return m_wrapPtr && *m_wrapPtr; return m_wrapPtr && *m_wrapPtr;
} }
constexpr void free() noexcept {
if (m_wrapPtr) {
m_wrapPtr->free();
}
if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
m_wrapPtr = nullptr;
}
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T *get() const noexcept { constexpr T *get() const noexcept {
@ -104,6 +161,12 @@ class AnyPtr {
return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data; return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
#endif #endif
} }
}; };
}
using AnyPtr = detail::AnyPtrT<false>;
using UAnyPtr = detail::AnyPtrT<true>;
} }

View File

@ -7,6 +7,7 @@
*/ */
#include "fmt.hpp" #include "fmt.hpp"
#include "realstd.hpp"
#include "stacktrace.hpp" #include "stacktrace.hpp"
#include "trace.hpp" #include "trace.hpp"
@ -14,14 +15,14 @@
namespace ox { namespace ox {
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err) noexcept { void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err)); oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) { if (err.src.file_name() != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line); oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
} }
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
printStackTrace(2); printStackTrace(2);
@ -32,16 +33,19 @@ void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err)
#endif #endif
} }
void panic(const char *file, int line, const char *panicMsg, const Error &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);
} }
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept { void assertFailFuncRuntime(
StringViewCR file,
int const line,
StringViewCR assertTxt,
StringViewCR msg) noexcept {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); auto const st = genStackTrace(2);
output += genStackTrace(2); oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); abort();
std::abort();
#else #else
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
@ -49,20 +53,25 @@ void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt,
#endif #endif
} }
void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept { void assertFailFuncRuntime(
StringViewCR file,
int const line,
[[maybe_unused]] Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) { if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg); msg += sfmt("\tError Message:\t{}\n", err.msg);
} }
msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err)); msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) { if (err.src.file_name() != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line); msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
} }
msg += genStackTrace(2); msg += genStackTrace(2);
oxErr(msg); oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line); oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort(); abort();
#else #else
constexprPanic(file, line, assertMsg); constexprPanic(file, line, assertMsg);
#endif #endif

View File

@ -22,9 +22,15 @@
namespace ox { namespace ox {
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept; [[noreturn]]
void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept { [[noreturn]]
constexpr void constexprPanic(
StringViewCR file,
int const line,
StringViewCR panicMsg,
Error const&err = {}) noexcept {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
panic(file, line, panicMsg, err); panic(file, line, panicMsg, err);
} else { } else {
@ -32,10 +38,24 @@ constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg
} }
} }
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept; void assertFailFuncRuntime(
void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept; StringViewCR file,
int line,
StringViewCR assertTxt,
StringViewCR msg) noexcept;
void assertFailFuncRuntime(
StringViewCR file,
int line,
Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept;
constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept { constexpr void assertFunc(
StringViewCR file,
int const line,
bool const pass,
[[maybe_unused]]StringViewCR assertTxt,
[[maybe_unused]]StringViewCR msg) noexcept {
if (!pass) { if (!pass) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, assertTxt, msg); assertFailFuncRuntime(file, line, assertTxt, msg);
@ -45,7 +65,12 @@ constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused
} }
} }
constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept { constexpr void assertFunc(
StringViewCR file,
int const line,
Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept {
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, err, {}, assertMsg); assertFailFuncRuntime(file, line, err, {}, assertMsg);
@ -55,7 +80,11 @@ constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringV
} }
} }
constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept { constexpr void expect(
StringViewCR file,
int const line,
auto const&actual,
auto const&expected) noexcept {
if (actual != expected) { if (actual != expected) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)

View File

@ -36,28 +36,16 @@ using ErrorCode = uint16_t;
struct [[nodiscard]] Error { struct [[nodiscard]] Error {
std::source_location src;
ox::CString msg = nullptr; ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0; ErrorCode errCode = 0;
constexpr Error() noexcept = default; constexpr Error() noexcept = default;
explicit constexpr Error(
ox::CString file,
uint32_t const line,
ErrorCode const errCode,
ox::CString msg = nullptr) noexcept:
msg{msg},
file{file},
line{static_cast<uint16_t>(line)},
errCode{errCode} {}
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
file{src.file_name()}, src{src},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} errCode{errCode}
{} {}
@ -65,9 +53,8 @@ struct [[nodiscard]] Error {
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg}, msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} errCode{errCode}
{} {}
@ -89,42 +76,31 @@ constexpr auto toStr(Error const&err) noexcept {
} }
struct Exception: public std::exception { struct Exception: public std::exception {
std::source_location src;
ox::CString msg = nullptr; ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0; ErrorCode errCode = 0;
explicit inline Exception(ox::CString file, uint32_t line, ErrorCode errCode, char const*msg = "") noexcept { explicit Exception(
this->file = file;
this->line = static_cast<uint16_t>(line);
this->msg = msg;
this->errCode = errCode;
}
explicit inline Exception(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
file{src.file_name()}, src{src},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {} errCode{errCode} {}
explicit inline Exception( explicit Exception(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg}, msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {} errCode{errCode} {}
explicit inline Exception(Error const&err) noexcept: explicit Exception(Error const&err) noexcept:
src{err.src},
msg{err.msg ? err.msg : ""}, msg{err.msg ? err.msg : ""},
file{err.file},
line{err.line},
errCode{err.errCode} {} errCode{err.errCode} {}
constexpr Error toError() const noexcept { constexpr Error toError() const noexcept {
return Error(file, line, errCode, msg); return Error(errCode, msg, src);
} }
[[nodiscard]] [[nodiscard]]
@ -133,6 +109,7 @@ struct Exception: public std::exception {
} }
}; };
[[noreturn]]
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept; void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
template<typename T> template<typename T>

View File

@ -11,7 +11,6 @@
#include "algorithm.hpp" #include "algorithm.hpp"
#include "hash.hpp" #include "hash.hpp"
#include "ignore.hpp" #include "ignore.hpp"
#include "optional.hpp"
#include "stringview.hpp" #include "stringview.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "vector.hpp" #include "vector.hpp"
@ -27,12 +26,11 @@ class HashMap {
private: private:
struct Pair { struct Pair {
UPtr<Pair> next;
K key = {}; K key = {};
T value{}; T value{};
}; };
Vector<K> m_keys; Vector<K> m_keys;
Vector<UPtr<Pair>> m_pairs; Vector<Pair*> m_pairs;
public: public:
explicit constexpr HashMap(std::size_t size = 127); explicit constexpr HashMap(std::size_t size = 127);
@ -75,10 +73,10 @@ class HashMap {
constexpr void expand(); constexpr void expand();
template<typename KK> template<typename KK>
constexpr UPtr<Pair> const &access(Vector<UPtr<Pair>> const &pairs, KK const &key) const; constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
template<typename KK> template<typename KK>
constexpr UPtr<Pair> &access(Vector<UPtr<Pair>> &pairs, KK const &key); constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key);
}; };
@ -87,13 +85,14 @@ constexpr HashMap<K, T>::HashMap(std::size_t size): m_pairs(size) {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap const &other) { constexpr HashMap<K, T>::HashMap(HashMap<K, T> const&other) {
operator=(other); m_pairs = other.m_pairs;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap &&other) noexcept { constexpr HashMap<K, T>::HashMap(HashMap<K, T> &&other) noexcept {
operator=(std::move(other)); m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs);
} }
template<typename K, typename T> template<typename K, typename T>
@ -102,7 +101,7 @@ constexpr HashMap<K, T>::~HashMap() {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr bool HashMap<K, T>::operator==(HashMap const &other) const { constexpr bool HashMap<K, T>::operator==(HashMap const&other) const {
if (m_keys != other.m_keys) { if (m_keys != other.m_keys) {
return false; return false;
} }
@ -116,25 +115,19 @@ constexpr bool HashMap<K, T>::operator==(HashMap const &other) const {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap const &other) { constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> const&other) {
if (this != &other) { if (this != &other) {
clear(); clear();
m_keys = other.m_keys; m_keys = other.m_keys;
m_pairs.resize(other.m_pairs.size()); m_pairs = other.m_pairs;
for (auto const&k : m_keys) {
auto const &src = access(other.m_pairs, k);
auto &dst = access(m_pairs, k);
dst = ox::make_unique<Pair>();
dst->key = src->key;
dst->value = src->value;
}
} }
return *this; return *this;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap &&other) noexcept { constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcept {
if (this != &other) { if (this != &other) {
clear();
m_keys = std::move(other.m_keys); m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs); m_pairs = std::move(other.m_pairs);
} }
@ -142,52 +135,60 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap &&other) noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const &key) { constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const&k) {
auto p = &access(m_pairs, key); auto p = &access(m_pairs, k);
if (*p == nullptr) { if (*p == nullptr) {
if (static_cast<double>(m_pairs.size()) * 0.7 < if (static_cast<double>(m_pairs.size()) * 0.7 <
static_cast<double>(m_keys.size())) { static_cast<double>(m_keys.size())) {
expand(); expand();
p = &access(m_pairs, key); p = &access(m_pairs, k);
} }
*p = ox::make_unique<Pair>(); *p = new Pair;
(*p)->key = key; (*p)->key = k;
m_keys.emplace_back(key); m_keys.emplace_back(k);
} }
return (*p)->value; return (*p)->value;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(MaybeView_t<K> const &key) noexcept { constexpr Result<T*> HashMap<K, T>::at(MaybeView_t<K> const&k) noexcept {
auto &p = access(m_pairs, key); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return ox::Error{1, "value not found for given key"}; return {nullptr, ox::Error(1, "value not found for given key")};
} }
return &p->value; return &p->value;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(MaybeView_t<K> const &key) const noexcept { constexpr Result<const T*> HashMap<K, T>::at(MaybeView_t<K> const&k) const noexcept {
auto &p = access(m_pairs, key); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return ox::Error{1, "value not found for given key"}; return {nullptr, ox::Error(1, "value not found for given key")};
} }
return &p->value; return &p->value;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr void HashMap<K, T>::erase(MaybeView_t<K> const &key) { constexpr void HashMap<K, T>::erase(MaybeView_t<K> const&k) {
if (!contains(key)) { if (!contains(k)) {
return; return;
} }
auto &c = access(m_pairs, key); auto h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
c = std::move(c->next); while (true) {
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), key)); const auto &p = m_pairs[h];
if (p == nullptr || p->key == k) {
std::ignore = m_pairs.erase(h);
break;
} else {
h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
}
}
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k));
} }
template<typename K, typename T> template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(MaybeView_t<K> const &key) const noexcept { constexpr bool HashMap<K, T>::contains(MaybeView_t<K> const&k) const noexcept {
return access(m_pairs, key).get() != nullptr; return access(m_pairs, k) != nullptr;
} }
template<typename K, typename T> template<typename K, typename T>
@ -203,26 +204,27 @@ constexpr Vector<K> const&HashMap<K, T>::keys() const noexcept {
template<typename K, typename T> template<typename K, typename T>
constexpr Vector<T> HashMap<K, T>::values() const noexcept { constexpr Vector<T> HashMap<K, T>::values() const noexcept {
Vector<T> out; Vector<T> out;
out.reserve(m_keys.size()); out.reserve(m_pairs.size());
for (auto const &p : m_pairs) { for (auto const&p : m_pairs) {
if (out) { out.emplace_back(p->value);
out.emplace_back(p->value);
}
} }
return out; return out;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr void HashMap<K, T>::clear() { constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear(); m_pairs.clear();
m_pairs.resize(127); m_pairs.resize(127);
} }
template<typename K, typename T> template<typename K, typename T>
constexpr void HashMap<K, T>::expand() { constexpr void HashMap<K, T>::expand() {
Vector<UPtr<Pair>> r{m_pairs.size() * 2}; Vector<Pair*> r(m_pairs.size() * 2);
for (std::size_t i = 0; i < m_keys.size(); ++i) { for (std::size_t i = 0; i < m_keys.size(); ++i) {
auto const &k = m_keys[i]; auto const&k = m_keys[i];
access(r, k) = std::move(access(m_pairs, k)); access(r, k) = std::move(access(m_pairs, k));
} }
m_pairs = std::move(r); m_pairs = std::move(r);
@ -230,39 +232,29 @@ constexpr void HashMap<K, T>::expand() {
template<typename K, typename T> template<typename K, typename T>
template<typename KK> template<typename KK>
constexpr UPtr<typename HashMap<K, T>::Pair> const &HashMap<K, T>::access( constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*> const&pairs, KK const&k) const {
Vector<UPtr<Pair>> const& pairs, auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
KK const &key) const {
auto const h = static_cast<std::size_t>(ox::hash<KK>{}(key) % pairs.size());
auto const &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == key) {
return p;
}
auto c = &p->next;
while (true) { while (true) {
if (*c == nullptr || (*c)->key == key) { auto const&p = *pairs.at(h).unwrap();
return *c; if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
} }
c = &(*c)->next;
} }
} }
template<typename K, typename T> template<typename K, typename T>
template<typename KK> template<typename KK>
constexpr UPtr<typename HashMap<K, T>::Pair> &HashMap<K, T>::access( constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, KK const&k) {
Vector<UPtr<Pair>> &pairs, auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
KK const &key) {
auto const h = static_cast<std::size_t>(ox::hash<KK>{}(key) % pairs.size());
auto &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == key) {
return p;
}
auto c = &p->next;
while (true) { while (true) {
if (*c == nullptr || (*c)->key == key) { auto &p = *pairs.at(h).unwrap();
return *c; if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
} }
c = &(*c)->next;
} }
} }

View File

@ -260,12 +260,12 @@ constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexce
template<typename T> template<typename T>
constexpr bool operator==(const UniquePtr<T> &p1, std::nullptr_t) noexcept { constexpr bool operator==(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
return p1.get() == nullptr; return p1.get();
} }
template<typename T> template<typename T>
constexpr bool operator==(std::nullptr_t, const UniquePtr<T> &p2) noexcept { constexpr bool operator==(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
return p2.get() == nullptr; return p2.get();
} }

View File

@ -31,7 +31,6 @@ concept Reader_c = requires(T v) {
class Reader_v { class Reader_v {
public: public:
virtual constexpr ~Reader_v() noexcept = default; virtual constexpr ~Reader_v() noexcept = default;
[[nodiscard]]
virtual constexpr ox::Result<char> peek() const noexcept = 0; virtual constexpr ox::Result<char> peek() const noexcept = 0;
virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0; virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0; virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;

View File

@ -12,4 +12,13 @@
#include <cassert> #include <cassert>
#else #else
#define assert(e) while (!(e)); #define assert(e) while (!(e));
#endif
#if __has_include(<cstdlib>)
#include <cstdlib>
#else
extern "C" {
[[noreturn]]
void abort();
}
#endif #endif

View File

@ -62,6 +62,9 @@ class SmallMap {
[[nodiscard]] [[nodiscard]]
constexpr Vector<K> keys() const noexcept; constexpr Vector<K> keys() const noexcept;
[[nodiscard]]
constexpr Vector<T> values() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr K const&key(size_t i) const noexcept; constexpr K const&key(size_t i) const noexcept;
@ -82,14 +85,22 @@ class SmallMap {
return m_pairs; return m_pairs;
} }
[[nodiscard]]
constexpr ox::Span<Pair> pairs() noexcept {
return m_pairs;
}
constexpr void clear(); constexpr void clear();
private: private:
template<typename KK> template<typename KK>
constexpr Pair const&access(PairVector const&pairs, KK const&key, bool &isNew) const; constexpr Pair const*access(PairVector const&pairs, KK const&key, bool &isNew) const;
template<typename KK> template<typename KK>
constexpr Pair &access(PairVector &pairs, KK const&key, bool &isNew); constexpr Pair *access(PairVector &pairs, KK const&key, bool &isNew);
template<typename KK>
constexpr Pair *accessNoCreate(PairVector &pairs, KK const&key);
}; };
@ -129,7 +140,7 @@ constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) { constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
bool isNew{}; bool isNew{};
auto p = &access(m_pairs, k, isNew); auto p = access(m_pairs, k, isNew);
if (isNew) { if (isNew) {
p->key = k; p->key = k;
} }
@ -138,7 +149,7 @@ constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept { constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
auto p = access(m_pairs, k); auto const p = accessNoCreate(m_pairs, k);
if (!p) { if (!p) {
return {nullptr, ox::Error(1, "value not found for given key")}; return {nullptr, ox::Error(1, "value not found for given key")};
} }
@ -147,7 +158,8 @@ constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcep
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept { constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
auto p = access(m_pairs, k); bool isNew{};
auto p = access(m_pairs, k, isNew);
if (!p) { if (!p) {
return {nullptr, ox::Error(1, "value not found for given key")}; return {nullptr, ox::Error(1, "value not found for given key")};
} }
@ -168,7 +180,8 @@ constexpr void SmallMap<K, T, SmallSz>::erase(MaybeView_t<K> const&k) {
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept { constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
return access(m_pairs, k) != nullptr; bool isNew{};
return access(m_pairs, k, isNew) != nullptr;
} }
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
@ -186,6 +199,16 @@ constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
return keys; return keys;
} }
template<typename K, typename T, size_t SmallSz>
constexpr Vector<T> SmallMap<K, T, SmallSz>::values() const noexcept {
ox::Vector<T> keys;
keys.reserve(m_pairs.size());
for (auto const&p : m_pairs) {
keys.emplace_back(p.key);
}
return keys;
}
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept { constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
return m_pairs[i].key; return m_pairs[i].key;
@ -218,30 +241,42 @@ constexpr void SmallMap<K, T, SmallSz>::clear() {
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
template<typename KK> template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::access( constexpr typename SmallMap<K, T, SmallSz>::Pair const*SmallMap<K, T, SmallSz>::access(
PairVector const&pairs, KK const&k, bool &isNew) const { PairVector const&pairs, KK const&k, bool &isNew) const {
for (auto const&p : pairs) { for (auto const&p : pairs) {
if (p.key == k) { if (p.key == k) {
isNew = false; isNew = false;
return p; return &p;
} }
} }
isNew = true; isNew = true;
return pairs.emplace_back(); return nullptr;
} }
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
template<typename KK> template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::access( constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::access(
PairVector &pairs, KK const&k, bool &isNew) { PairVector &pairs, KK const&k, bool &isNew) {
for (auto &p : pairs) { for (auto &p : pairs) {
if (p.key == k) { if (p.key == k) {
isNew = false; isNew = false;
return p; return &p;
} }
} }
isNew = true; isNew = true;
return pairs.emplace_back(); return &pairs.emplace_back();
}
template<typename K, typename T, size_t SmallSz>
template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::accessNoCreate(
PairVector &pairs, KK const&k) {
for (auto &p : pairs) {
if (p.key == k) {
return &p;
}
}
return nullptr;
} }
template<typename T, typename K, typename V, size_t SmallSz> template<typename T, typename K, typename V, size_t SmallSz>

View File

@ -14,7 +14,7 @@
#include "iterator.hpp" #include "iterator.hpp"
#include "vector.hpp" #include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage) OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace ox { namespace ox {
@ -133,7 +133,7 @@ class Span {
return m_items[i]; return m_items[i];
} }
constexpr const T &operator[](std::size_t i) const noexcept { constexpr T const&operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return m_items[i]; return m_items[i];
} }
@ -168,8 +168,20 @@ class Span {
}; };
template<typename T> template<typename T>
using SpanView = Span<const T>; using SpanView = Span<T const>;
template<typename T>
constexpr void spancpy(ox::Span<T> const dst, ox::SpanView<T> const src) noexcept {
auto const sz = ox::min(dst.size(), src.size());
if (std::is_constant_evaluated() || std::is_trivially_copyable_v<T>) {
for (size_t i{}; i < sz; ++i) {
dst.data()[i] = src.data()[i];
}
} else {
memcpy(dst.data(), src.data(), sz * sizeof(T));
}
}
} }
OX_CLANG_NOWARN_END OX_ALLOW_UNSAFE_BUFFERS_END

View File

@ -17,6 +17,8 @@ add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap") add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2") add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector") add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
add_test("[ox/std] Vector::shrink_to_fit" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector::shrink_to_fit")
add_test("[ox/std] findIdx" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "findIdx")
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap") add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc) add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int") add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int")

View File

@ -237,6 +237,50 @@ OX_CLANG_NOWARN_END
return ox::Error(0); return ox::Error(0);
} }
}, },
{
"Vector::shrink_to_fit",
[] {
{
ox::Vector<ox::IString<8>> v;
v.reserve(50);
v.emplace_back("asdf");
v.emplace_back("aoeu");
auto const origData = v.data();
v.shrink_to_fit();
oxExpect(v[0], "asdf");
oxExpect(v[1], "aoeu");
oxExpect(v.capacity(), 2u);
oxAssert(origData != v.data(), "shrink_to_fit did not create a new allocation");
}
{
ox::Vector<ox::IString<8>> v;
v.reserve(2);
v.emplace_back("asdf");
v.emplace_back("aoeu");
auto const origData = v.data();
v.shrink_to_fit();
oxExpect(v[0], "asdf");
oxExpect(v[1], "aoeu");
oxExpect(v.capacity(), 2u);
oxAssert(origData == v.data(), "shrink_to_fit inappropriately created a new allocation");
}
return ox::Error{};
}
},
{
"findIdx",
[] {
ox::Vector<ox::IString<8>> const v {"zero", "one", "two", "three", "four"};
oxExpect(ox::findIdx(v.begin(), v.end(), "zero").or_value(5), 0u);
oxExpect(ox::findIdx(v.begin(), v.end(), "one").or_value(5), 1u);
oxExpect(ox::findIdx(v.begin(), v.end(), "two").or_value(5), 2u);
oxExpect(ox::findIdx(v.begin(), v.end(), "three").or_value(5), 3u);
oxExpect(ox::findIdx(v.begin(), v.end(), "four").or_value(5), 4u);
oxExpect(ox::findIdx(v.begin(), v.end(), "five").or_value(5), 5u);
oxExpect(ox::findIdx(v.begin(), v.end(), "six").or_value(6), 6u);
return ox::Error{};
}
},
{ {
"SmallMap", "SmallMap",
[] { [] {
@ -246,7 +290,18 @@ OX_CLANG_NOWARN_END
oxExpect(map.size(), 1u); oxExpect(map.size(), 1u);
oxExpect(map["aoeu"], ""); oxExpect(map["aoeu"], "");
oxExpect(map.size(), 2u); oxExpect(map.size(), 2u);
return ox::Error(0); ox::SmallMap<ox::String, ox::String> cmap;
cmap["asdf"] = "aoeu";
auto constexpr constTest = [](ox::SmallMap<ox::String, ox::String> const&map) {
OX_REQUIRE(asdf, map.at("asdf"));
oxExpect(*asdf, "aoeu");
oxExpect(map.size(), 1u);
auto const aoeu = map.at("aoeu");
oxExpect(aoeu.ok(), false);
oxExpect(map.size(), 1u);
return ox::Error{};
};
return constTest(cmap);
} }
}, },
{ {
@ -273,16 +328,6 @@ OX_CLANG_NOWARN_END
si["aoeu"] = 100; si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42"); oxAssert(si["asdf"] == 42, "asdf != 42");
oxAssert(si["aoeu"] == 100, "aoeu != 100"); oxAssert(si["aoeu"] == 100, "aoeu != 100");
si.erase("asdf");
oxAssert(!si.contains("asdf"), "wrongly contains asdf");
oxAssert(si.contains("aoeu"), "does not contains aoeu");
oxAssert(!si.at("asdf").ok(), "asdf != 0");
oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii; ox::HashMap<int, int> ii;
ii[4] = 42; ii[4] = 42;
ii[5] = 100; ii[5] = 100;

View File

@ -269,8 +269,8 @@ 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.file != nullptr) { if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.file << ":" << err.line << "):"; trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} else { } else {
trc << "Error:"; trc << "Error:";
} }
@ -282,8 +282,8 @@ 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.file != nullptr) { if (err.src.file_name() != nullptr) {
trc << "(" << err.file << ":" << err.line << ")"; trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";
} }
} }
} }

View File

@ -19,12 +19,15 @@
namespace std { namespace std {
template<typename T> template<typename T>
constexpr bool is_union_v = __is_union(T); inline constexpr bool is_union_v = __is_union(T);
constexpr bool is_constant_evaluated() noexcept { inline constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated(); return __builtin_is_constant_evaluated();
} }
template<typename T>
inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
} }
#endif #endif
@ -156,6 +159,9 @@ static_assert(is_class<int>::value == false);
template<typename T> template<typename T>
constexpr bool is_class_v = is_class<T>(); constexpr bool is_class_v = is_class<T>();
template<typename T>
inline constexpr bool is_trivially_copyable_v = std::is_trivially_copyable_v<T>;
template<typename T> template<typename T>
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value; constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;

View File

@ -313,6 +313,8 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void reserve(std::size_t cap) noexcept(useNoexcept); constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
constexpr void shrink_to_fit() noexcept(useNoexcept);
private: private:
constexpr void reserveInsert( constexpr void reserveInsert(
std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept); std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept);
@ -341,6 +343,7 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexce
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
reserve(list.size());
for (auto &item : list) { for (auto &item : list) {
emplace_back(std::move(item)); emplace_back(std::move(item));
} }
@ -675,6 +678,24 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) n
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept) {
if (m_size == m_cap) {
return;
}
const auto oldItems = m_items;
const auto oldCap = m_cap;
m_cap = m_size;
this->allocate(&m_items, m_size);
if (oldItems) { // move over old items
for (std::size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T();
}
this->deallocate(oldItems, oldCap);
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert( constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
std::size_t cap, std::size_t cap,

View File

@ -4,17 +4,20 @@
#include <ox/std/heapmgr.hpp> #include <ox/std/heapmgr.hpp>
#include <teagba/bios.hpp>
#include <teagba/registers.hpp>
namespace mgba { namespace mgba {
void initConsole(); void initConsole();
} }
#define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000) #define MEM_HEAP_BEGIN reinterpret_cast<char*>(0x02000000)
#define MEM_EWRAM_END reinterpret_cast<char*>(0x0203FFFF) #define MEM_HEAP_END reinterpret_cast<char*>(0x0203FFFF)
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_EWRAM_BEGIN) #define HEAP_BEGIN reinterpret_cast<char*>(MEM_HEAP_BEGIN)
// set size to half of EWRAM // set size to half of EWRAM
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2) #define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2)
#define HEAP_END reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE) #define HEAP_END reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE)
extern void (*__preinit_array_start[]) (void); extern void (*__preinit_array_start[]) (void);
extern void (*__preinit_array_end[]) (void); extern void (*__preinit_array_end[]) (void);
@ -25,6 +28,14 @@ int main(int argc, const char **argv);
extern "C" { extern "C" {
void abort() {
REG_IE = 0;
teagba::intrwait(0, 0);
while (true);
}
void *__gxx_personality_v0{};
void __libc_init_array() { void __libc_init_array() {
auto preInits = __preinit_array_end - __preinit_array_start; auto preInits = __preinit_array_end - __preinit_array_start;
for (decltype(preInits) i = 0; i < preInits; i++) { for (decltype(preInits) i = 0; i < preInits; i++) {

View File

@ -162,11 +162,9 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling ### Error Handling
The GBA build has exceptions disabled. Instead of throwing exceptions, generally try to use
Instead of throwing exceptions, all engine code should return [ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting. but exceptions may be used where they make sense.
For the sake of consistency, try to stick to ```ox::Error``` in non-engine code
as well, but non-engine code is free to use exceptions when they make sense.
Exceptions should generally just use ```OxException```, which is bascially an Exceptions should generally just use ```OxException```, which is bascially an
exception form of ```ox::Error```. exception form of ```ox::Error```.

View File

@ -1,6 +1,6 @@
# module dir list # module dir list
add_subdirectory(core) add_subdirectory(gfx)
add_subdirectory(scene) add_subdirectory(scene)
# module libraries # module libraries

View File

@ -1,33 +0,0 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/model/desctypes.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/size.hpp>
#include <turbine/context.hpp>
#include "initparams.hpp"
namespace nostalgia::core {
class Context;
struct ContextDeleter {
void operator()(Context *p) noexcept;
};
using ContextUPtr = ox::UPtr<Context, ContextDeleter>;
ox::Result<ContextUPtr> init(turbine::Context &tctx, InitParams const&params = {}) noexcept;
keel::Context &keelCtx(Context &ctx) noexcept;
turbine::Context &turbineCtx(Context &ctx) noexcept;
}

View File

@ -7,12 +7,12 @@
#include <ox/std/math.hpp> #include <ox/std/math.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
using Color16 = uint16_t; using Color16 = uint16_t;
/** /**
* Nostalgia Core logically uses 16 bit colors, but must translate that to 32 * Nostalgia logically uses 16 bit colors, but must translate that to 32
* bit colors in some implementations. * bit colors in some implementations.
*/ */
using Color32 = uint32_t; using Color32 = uint32_t;
@ -154,7 +154,7 @@ static_assert(color16(16, 32, 8) == 9200);
[[nodiscard]] [[nodiscard]]
constexpr Color16 applySelectionColor(Color16 const color) noexcept { constexpr Color16 applySelectionColor(Color16 const color) noexcept {
namespace core = nostalgia::core; namespace core = nostalgia::gfx;
auto const r = core::red16(color) / 2; auto const r = core::red16(color) / 2;
auto const g = (core::green16(color) + 20) / 2; auto const g = (core::green16(color) + 20) / 2;
auto const b = (core::blue16(color) + 31) / 2; auto const b = (core::blue16(color) + 31) / 2;

View File

@ -6,7 +6,7 @@
#include <ox/std/stringliteral.hpp> #include <ox/std/stringliteral.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
constexpr auto TileWidth = 8; constexpr auto TileWidth = 8;
constexpr auto TileHeight = 8; constexpr auto TileHeight = 8;

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/memory.hpp>
#include <turbine/context.hpp>
#include "initparams.hpp"
namespace nostalgia::gfx {
class Context;
void safeDelete(Context *ctx) noexcept;
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params = {}) noexcept;
keel::Context &keelCtx(Context &ctx) noexcept;
turbine::Context &turbineCtx(Context &ctx) noexcept;
}

View File

@ -13,10 +13,10 @@
#include "palette.hpp" #include "palette.hpp"
#include "tilesheet.hpp" #include "tilesheet.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
struct Sprite { struct Sprite {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Sprite"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.Sprite";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool enabled = false; bool enabled = false;
int x = 0; int x = 0;
@ -46,7 +46,7 @@ OX_MODEL_BEGIN(Sprite)
OX_MODEL_END() OX_MODEL_END()
struct BgTile { struct BgTile {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.BgTile"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.BgTile";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
unsigned tileIdx = 0; unsigned tileIdx = 0;
unsigned palBank = 0; unsigned palBank = 0;
@ -62,7 +62,7 @@ OX_MODEL_BEGIN(BgTile)
OX_MODEL_END() OX_MODEL_END()
struct TileSheetSetEntrySection { struct TileSheetSetEntrySection {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntrySection"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheetSetEntrySection";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
int32_t begin = 0; int32_t begin = 0;
int32_t tiles = 0; int32_t tiles = 0;
@ -78,7 +78,7 @@ OX_MODEL_BEGIN(TileSheetSetEntrySection)
OX_MODEL_END() OX_MODEL_END()
struct TileSheetSetEntry { struct TileSheetSetEntry {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntry"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheetSetEntry";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
ox::FileAddress tilesheet; ox::FileAddress tilesheet;
ox::Vector<TileSheetSetEntrySection> sections; ox::Vector<TileSheetSetEntrySection> sections;
@ -90,7 +90,7 @@ OX_MODEL_BEGIN(TileSheetSetEntry)
OX_MODEL_END() OX_MODEL_END()
struct TileSheetSet { struct TileSheetSet {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSet"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheetSet";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
static constexpr auto Preloadable = true; static constexpr auto Preloadable = true;
int32_t bpp = 0; int32_t bpp = 0;
@ -102,8 +102,6 @@ OX_MODEL_BEGIN(TileSheetSet)
OX_MODEL_FIELD(entries) OX_MODEL_FIELD(entries)
OX_MODEL_END() OX_MODEL_END()
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
[[nodiscard]] [[nodiscard]]
int tileColumns(Context&) noexcept; int tileColumns(Context&) noexcept;
@ -144,6 +142,10 @@ ox::Error loadBgTileSheet(
unsigned cbb, unsigned cbb,
TileSheetSet const&set) noexcept; TileSheetSet const&set) noexcept;
void clearCbb(Context &ctx, unsigned cbb) noexcept;
void clearCbbs(Context &ctx) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
@ -240,15 +242,15 @@ void puts(Context &ctx, int column, int row, ox::StringViewCR str) noexcept;
} }
namespace nostalgia::core::gl { namespace nostalgia::gfx::gl {
constexpr ox::CStringView GlslVersion = "#version 330"; constexpr ox::CStringView GlslVersion = "#version 330";
[[nodiscard]] [[nodiscard]]
ox::Size drawSize(int scale = 5) noexcept; ox::Size drawSize(int scale = 5) noexcept;
void draw(core::Context &ctx, ox::Size const&renderSz) noexcept; void draw(gfx::Context &ctx, ox::Size const&renderSz) noexcept;
void draw(core::Context&, int scale = 5) noexcept; void draw(gfx::Context&, int scale = 5) noexcept;
} }

View File

@ -6,7 +6,7 @@
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
struct InitParams { struct InitParams {
bool glInstallDrawer = true; bool glInstallDrawer = true;

View File

@ -6,7 +6,7 @@
#include <keel/module.hpp> #include <keel/module.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
const keel::Module *keelModule() noexcept; const keel::Module *keelModule() noexcept;

View File

@ -11,7 +11,7 @@
#include "color.hpp" #include "color.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
struct PaletteColorV1 { struct PaletteColorV1 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.PaletteColor"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.PaletteColor";

View File

@ -8,7 +8,7 @@
#include "consts.hpp" #include "consts.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
[[nodiscard]] [[nodiscard]]
constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept { constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept {

View File

@ -0,0 +1,11 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <studio/studio.hpp>
namespace nostalgia::core {
}

View File

@ -6,7 +6,7 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
const studio::Module *studioModule() noexcept; const studio::Module *studioModule() noexcept;

View File

@ -5,18 +5,33 @@
#pragma once #pragma once
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/std/array.hpp>
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <ox/std/size.hpp> #include <ox/std/size.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/model/def.hpp> #include <ox/model/def.hpp>
#include <nostalgia/core/ptidxconv.hpp> #include <nostalgia/gfx/ptidxconv.hpp>
#include "palette.hpp" #include "palette.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
struct SubSheetTemplate {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.SubSheetTemplate";
static constexpr auto TypeVersion = 1;
ox::String name;
int32_t width{};
int32_t height{};
ox::Vector<SubSheetTemplate> subsheets;
};
OX_MODEL_BEGIN(SubSheetTemplate)
OX_MODEL_FIELD(name)
OX_MODEL_FIELD(width)
OX_MODEL_FIELD(height)
OX_MODEL_FIELD(subsheets)
OX_MODEL_END()
// Predecessor to TileSheet, kept for backward compatibility // Predecessor to TileSheet, kept for backward compatibility
struct TileSheetV1 { struct TileSheetV1 {
@ -212,6 +227,10 @@ struct TileSheetV4 {
pixels(std::move(pPixels)) { pixels(std::move(pPixels)) {
} }
/**
*
* @return the dimensional size of the SubSheet (e.g. width * height)
*/
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept { constexpr std::size_t size() const noexcept {
return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows); return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
@ -269,7 +288,105 @@ constexpr ox::Error repair(TileSheetV4 &ts) noexcept {
} }
using TileSheet = TileSheetV4; struct TileSheetV5 {
using SubSheetIdx = ox::Vector<std::size_t, 4>;
struct SubSheet {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet.SubSheet";
static constexpr auto TypeVersion = 5;
SubSheetId id = 0;
ox::String name;
int columns = 0;
int rows = 0;
ox::Vector<SubSheet> subsheets;
ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default;
SubSheet(
SubSheetId const pId,
ox::StringParam pName,
int const pColumns,
int const pRows) noexcept:
id(pId),
name(std::move(pName)),
columns(pColumns),
rows(pRows),
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile)) {
}
SubSheet(
SubSheetId const pId,
ox::StringParam pName,
int const pColumns,
int const pRows,
ox::Vector<uint8_t> pPixels) noexcept:
id(pId),
name(std::move(pName)),
columns(pColumns),
rows(pRows),
pixels(std::move(pPixels)) {
}
/**
*
* @return the dimensional size of the SubSheet (e.g. width * height)
*/
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
}
};
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet";
static constexpr auto TypeVersion = 5;
int8_t bpp = 4;
SubSheetId idIt = 0;
ox::FileAddress defaultPalette;
SubSheet subsheet{0, "Root", 1, 1};
};
[[nodiscard]]
constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept {
if (ss.subsheets.empty()) {
return static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) == ss.pixels.size();
} else {
return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[](TileSheetV5::SubSheet const&s) {
return valid(s);
});
}
}
[[nodiscard]]
constexpr bool valid(TileSheetV5 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet);
}
constexpr void repair(TileSheetV5::SubSheet &ss, int const bpp) noexcept {
if (ss.subsheets.empty()) {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile);
ss.pixels.resize(bytes);
} else {
ss.pixels.clear();
ss.columns = -1;
ss.rows = -1;
}
for (auto &s : ss.subsheets) {
repair(s, bpp);
}
}
constexpr ox::Error repair(TileSheetV5 &ts) noexcept {
if (ts.bpp != 4 && ts.bpp != 8) {
return ox::Error{1, "Unable to repair TileSheet"};
}
repair(ts.subsheet, ts.bpp);
return {};
}
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;
@ -281,7 +398,7 @@ size_t getTileCnt(TileSheet const&ts) noexcept;
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept; TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
size_t getTileIdx(TileSheet const&ts, SubSheetId id) noexcept; ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept; uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
@ -290,7 +407,7 @@ uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept; uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, std::size_t idx) noexcept; uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
@ -299,44 +416,24 @@ uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, ox::Point const&pt) noexcept; uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
constexpr void walkPixels(TileSheet::SubSheet const&ss, int8_t pBpp, auto callback) noexcept { constexpr void walkPixels(TileSheet::SubSheet const&ss, int8_t, auto callback) noexcept {
if (pBpp == 4) { for (std::size_t i = 0; i < ss.pixels.size(); ++i) {
const auto pixelCnt = ox::min<std::size_t>( callback(i, ss.pixels[i]);
static_cast<std::size_t>(ss.columns * ss.rows * PixelsPerTile) / 2,
ss.pixels.size());
//oxAssert(pixels.size() == pixelCnt, "Pixel count does not match rows and columns");
for (std::size_t i = 0; i < pixelCnt; ++i) {
const auto colorIdx1 = static_cast<uint8_t>(ss.pixels[i] & 0xF);
const auto colorIdx2 = static_cast<uint8_t>(ss.pixels[i] >> 4);
callback(i * 2 + 0, colorIdx1);
callback(i * 2 + 1, colorIdx2);
}
} else {
const auto pixelCnt = ox::min<std::size_t>(
static_cast<std::size_t>(ss.columns * ss.rows * PixelsPerTile),
ss.pixels.size());
for (std::size_t i = 0; i < pixelCnt; ++i) {
const auto p = ss.pixels[i];
callback(i, p);
}
} }
} }
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept; void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept;
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, 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, int8_t pBpp, std::size_t cnt) noexcept;
/** /**
* Gets a count of the pixels in this sheet, and not that of its children. * Gets a count of the pixels in this sheet, and not that of its children.
* @param pBpp bits per pixel, need for knowing how to count the pixels
* @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, int8_t pBpp) noexcept; unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept;
/** /**
* *
@ -344,7 +441,7 @@ unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
* @param pBpp * @param pBpp
* @param sz size of Subsheet in tiles (not pixels) * @param sz size of Subsheet in tiles (not pixels)
*/ */
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, 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
@ -400,6 +497,8 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
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<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 const&ts, SubSheetId pId) noexcept;
@ -499,6 +598,22 @@ OX_MODEL_BEGIN(TileSheetV4)
OX_MODEL_FIELD(subsheet) OX_MODEL_FIELD(subsheet)
OX_MODEL_END() OX_MODEL_END()
OX_MODEL_BEGIN(TileSheetV5::SubSheet)
OX_MODEL_FIELD(id)
OX_MODEL_FIELD(name)
OX_MODEL_FIELD(rows)
OX_MODEL_FIELD(columns)
OX_MODEL_FIELD(subsheets)
OX_MODEL_FIELD(pixels)
OX_MODEL_END()
OX_MODEL_BEGIN(TileSheetV5)
OX_MODEL_FIELD(bpp)
OX_MODEL_FIELD(idIt)
OX_MODEL_FIELD(defaultPalette)
OX_MODEL_FIELD(subsheet)
OX_MODEL_END()
OX_MODEL_BEGIN(CompactTileSheetV1) OX_MODEL_BEGIN(CompactTileSheetV1)
OX_MODEL_FIELD(bpp) OX_MODEL_FIELD(bpp)
OX_MODEL_FIELD(defaultPalette) OX_MODEL_FIELD(defaultPalette)

View File

@ -4,14 +4,14 @@
#include <turbine/turbine.hpp> #include <turbine/turbine.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include "context.hpp" #include "context.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
void ContextDeleter::operator()(Context *p) noexcept { void safeDelete(Context *ctx) noexcept {
ox::safeDelete(p); delete ctx;
} }
Context::Context(turbine::Context &tctx) noexcept: turbineCtx(tctx) { Context::Context(turbine::Context &tctx) noexcept: turbineCtx(tctx) {
@ -19,10 +19,10 @@ Context::Context(turbine::Context &tctx) noexcept: turbineCtx(tctx) {
ox::Error initGfx(Context &ctx, InitParams const&) noexcept; ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
ox::Result<ContextUPtr> 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); auto ctx = ox::make_unique<Context>(tctx);
OX_RETURN_ERROR(initGfx(*ctx, params)); OX_RETURN_ERROR(initGfx(*ctx, params));
return ContextUPtr(std::move(ctx)); return ox::UPtr<Context>(std::move(ctx));
} }
keel::Context &keelCtx(Context &ctx) noexcept { keel::Context &keelCtx(Context &ctx) noexcept {
@ -33,4 +33,4 @@ turbine::Context &turbineCtx(Context &ctx) noexcept {
return ctx.turbineCtx; return ctx.turbineCtx;
} }
} }

View File

@ -4,9 +4,9 @@
#pragma once #pragma once
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
struct BgCbbData { struct BgCbbData {
unsigned bpp = 4; unsigned bpp = 4;

View File

@ -11,15 +11,15 @@
#include <keel/keel.hpp> #include <keel/keel.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
#include "context.hpp" #include "context.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace nostalgia::core { namespace nostalgia::gfx {
static constexpr auto SpriteCount = 128; static constexpr auto SpriteCount = 128;
@ -63,6 +63,19 @@ ox::Error loadSpritePalette(
return {}; return {};
} }
void clearCbb(Context&, unsigned const cbb) noexcept {
for (auto &v : MEM_BG_TILES[cbb]) {
v = 0;
}
}
void clearCbbs(Context &ctx) noexcept {
clearCbb(ctx, 0);
clearCbb(ctx, 1);
clearCbb(ctx, 2);
clearCbb(ctx, 3);
}
static ox::Error loadTileSheetSet( static ox::Error loadTileSheetSet(
Context &ctx, Context &ctx,
ox::Span<uint16_t> tileMapTargetMem, ox::Span<uint16_t> tileMapTargetMem,
@ -99,10 +112,10 @@ ox::Error loadBgTileSheet(
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
size_t const bppMod = ts.bpp == 4; size_t const bppMod = ts.bpp == 4;
size_t const bytesPerTile = PixelsPerTile >> bppMod; size_t const bytesPerTile = PixelsPerTile >> bppMod;
auto const pixCnt = tileCnt * bytesPerTile; auto const cnt = (tileCnt * bytesPerTile) / 2;
auto const srcPxIdx = srcTileIdx * bytesPerTile; auto const srcPxIdx = srcTileIdx * bytesPerTile;
auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2; auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
for (size_t i = 0; i < pixCnt; ++i) { for (size_t i = 0; i < cnt; ++i) {
auto const srcIdx = srcPxIdx + i * 2; auto const srcIdx = srcPxIdx + 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]);

View File

@ -4,8 +4,8 @@
#pragma once #pragma once
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
ox::Error initGfx(Context &ctx, InitParams const&) noexcept; ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
} }

View File

@ -4,6 +4,7 @@
#include <ox/std/def.hpp> #include <ox/std/def.hpp>
#include <ox/std/realstd.hpp>
#include <keel/media.hpp> #include <keel/media.hpp>
#include <turbine/turbine.hpp> #include <turbine/turbine.hpp>
@ -11,7 +12,7 @@
#include <teagba/addresses.hpp> #include <teagba/addresses.hpp>
#include <teagba/bios.hpp> #include <teagba/bios.hpp>
#include <nostalgia/core/core.hpp> #include <nostalgia/gfx/core.hpp>
#include "gfx.hpp" #include "gfx.hpp"
@ -21,7 +22,7 @@
namespace ox { namespace ox {
using namespace nostalgia::core; using namespace nostalgia::gfx;
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept { void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
// reset heap to make sure we have enough memory to allocate context data // reset heap to make sure we have enough memory to allocate context data
@ -48,12 +49,10 @@ OX_ALLOW_UNSAFE_BUFFERS_END
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err)); oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) { if (err.src.file_name() != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line); oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
} }
// disable all interrupt handling and IntrWait on no interrupts abort();
REG_IE = 0;
teagba::intrwait(0, 0);
} }
} }

View File

@ -3,9 +3,9 @@
*/ */
#include <keel/media.hpp> #include <keel/media.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
constexpr auto GbaTileColumns = 32; constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32; constexpr auto GbaTileRows = 32;

View File

@ -4,15 +4,14 @@
#include <ox/model/model.hpp> #include <ox/model/model.hpp>
#include <keel/asset.hpp>
#include <keel/module.hpp> #include <keel/module.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
#include "typeconv.hpp" #include "typeconv.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
static class: public keel::Module { static class: public keel::Module {
private: private:
@ -24,12 +23,13 @@ static class: public keel::Module {
TileSheetV1ToTileSheetV2Converter m_tileSheetV1ToTileSheetV2Converter; TileSheetV1ToTileSheetV2Converter m_tileSheetV1ToTileSheetV2Converter;
TileSheetV2ToTileSheetV3Converter m_tileSheetV2ToTileSheetV3Converter; TileSheetV2ToTileSheetV3Converter m_tileSheetV2ToTileSheetV3Converter;
TileSheetV3ToTileSheetV4Converter m_tileSheetV3ToTileSheetV4Converter; TileSheetV3ToTileSheetV4Converter m_tileSheetV3ToTileSheetV4Converter;
TileSheetV4ToTileSheetV5Converter m_tileSheetV4ToTileSheetV5Converter;
TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter; TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter;
public: public:
[[nodiscard]] [[nodiscard]]
ox::String id() const noexcept override { ox::String id() const noexcept override {
return ox::String("net.drinkingtea.nostalgia.core"); return ox::String{"net.drinkingtea.nostalgia.gfx"};
} }
[[nodiscard]] [[nodiscard]]
@ -39,6 +39,7 @@ static class: public keel::Module {
keel::generateTypeDesc<TileSheetV2>, keel::generateTypeDesc<TileSheetV2>,
keel::generateTypeDesc<TileSheetV3>, keel::generateTypeDesc<TileSheetV3>,
keel::generateTypeDesc<TileSheetV4>, keel::generateTypeDesc<TileSheetV4>,
keel::generateTypeDesc<TileSheetV5>,
keel::generateTypeDesc<CompactTileSheetV1>, keel::generateTypeDesc<CompactTileSheetV1>,
keel::generateTypeDesc<PaletteV1>, keel::generateTypeDesc<PaletteV1>,
keel::generateTypeDesc<PaletteV2>, keel::generateTypeDesc<PaletteV2>,
@ -59,6 +60,7 @@ static class: public keel::Module {
&m_tileSheetV1ToTileSheetV2Converter, &m_tileSheetV1ToTileSheetV2Converter,
&m_tileSheetV2ToTileSheetV3Converter, &m_tileSheetV2ToTileSheetV3Converter,
&m_tileSheetV3ToTileSheetV4Converter, &m_tileSheetV3ToTileSheetV4Converter,
&m_tileSheetV4ToTileSheetV5Converter,
&m_tileSheetToCompactTileSheetConverter, &m_tileSheetToCompactTileSheetConverter,
}; };
} }
@ -67,7 +69,7 @@ static class: public keel::Module {
ox::Vector<keel::PackTransform> packTransforms() const noexcept final { ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
return { return {
// convert tilesheets to CompactTileSheets // convert tilesheets to CompactTileSheets
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> { [](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
if (typeId == ox::ModelTypeId_v<TileSheetV1> || if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
typeId == ox::ModelTypeId_v<TileSheetV2> || typeId == ox::ModelTypeId_v<TileSheetV2> ||
typeId == ox::ModelTypeId_v<TileSheetV3> || typeId == ox::ModelTypeId_v<TileSheetV3> ||
@ -78,7 +80,7 @@ static class: public keel::Module {
} }
return false; return false;
}, },
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> { [](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> || if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
typeId == ox::ModelTypeId_v<PaletteV1> || typeId == ox::ModelTypeId_v<PaletteV1> ||
typeId == ox::ModelTypeId_v<PaletteV2> || typeId == ox::ModelTypeId_v<PaletteV2> ||
@ -92,6 +94,7 @@ static class: public keel::Module {
}, },
}; };
} }
} const mod; } const mod;
keel::Module const*keelModule() noexcept { keel::Module const*keelModule() noexcept {

View File

@ -4,7 +4,7 @@
#include "typeconv.hpp" #include "typeconv.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
ox::Error NostalgiaPaletteToPaletteV1Converter::convert( ox::Error NostalgiaPaletteToPaletteV1Converter::convert(
keel::Context&, keel::Context&,
@ -133,6 +133,46 @@ ox::Error TileSheetV3ToTileSheetV4Converter::convert(
return {}; return {};
} }
void TileSheetV4ToTileSheetV5Converter::convertSubsheet(
int const bpp,
TileSheetV4::SubSheet &src,
TileSheetV5::SubSheet &dst,
SubSheetId &idIt) noexcept {
dst.id = idIt;
dst.name = std::move(src.name);
dst.columns = src.columns;
dst.rows = src.rows;
if (bpp == 4) {
dst.pixels.reserve(2 * src.pixels.size());
dst.pixels.resize(0);
for (auto const p : src.pixels) {
dst.pixels.emplace_back(static_cast<uint8_t>(p & 0xf));
dst.pixels.emplace_back(static_cast<uint8_t>(p >> 4));
}
oxAssert(dst.pixels.size() == src.pixels.size() *2, "mismatch");
} else {
dst.pixels = std::move(src.pixels);
}
++idIt;
dst.subsheets.resize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) {
convertSubsheet(bpp, src.subsheets[i], dst.subsheets[i], idIt);
}
}
ox::Error TileSheetV4ToTileSheetV5Converter::convert(
keel::Context&,
TileSheetV4 &src,
TileSheetV5 &dst) const noexcept {
dst.bpp = src.bpp;
dst.idIt = src.idIt;
dst.defaultPalette = std::move(src.defaultPalette);
convertSubsheet(dst.bpp, src.subsheet, dst.subsheet, dst.idIt);
return {};
}
ox::Error TileSheetToCompactTileSheetConverter::convert( ox::Error TileSheetToCompactTileSheetConverter::convert(
keel::Context&, keel::Context&,
TileSheet &src, TileSheet &src,

View File

@ -8,11 +8,11 @@
#include <keel/typeconv.hpp> #include <keel/typeconv.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
// Type converters // Type converters
@ -56,6 +56,15 @@ class TileSheetV3ToTileSheetV4Converter: public keel::Converter<TileSheetV3, Til
ox::Error convert(keel::Context&, TileSheetV3 &src, TileSheetV4 &dst) const noexcept final; ox::Error convert(keel::Context&, TileSheetV3 &src, TileSheetV4 &dst) const noexcept final;
}; };
class TileSheetV4ToTileSheetV5Converter final: public keel::Converter<TileSheetV4, TileSheetV5> {
static void convertSubsheet(
int bpp,
TileSheetV4::SubSheet &src,
TileSheetV5::SubSheet &dst,
SubSheetId &idIt) noexcept;
ox::Error convert(keel::Context&, TileSheetV4 &src, TileSheetV5 &dst) const noexcept override;
};
class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> { class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> {
ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final; ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
}; };

View File

@ -5,10 +5,10 @@
#include "context.hpp" #include "context.hpp"
#include "gfx.hpp" #include "gfx.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
void ContextDeleter::operator()(Context *p) noexcept { void safeDelete(Context *ctx) noexcept {
ox::safeDelete(p); delete ctx;
} }
Context::Context(turbine::Context &tctx, InitParams const&params) noexcept: Context::Context(turbine::Context &tctx, InitParams const&params) noexcept:
@ -23,10 +23,10 @@ Context::~Context() noexcept {
shutdownGfx(*this); shutdownGfx(*this);
} }
ox::Result<ContextUPtr> 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);
OX_RETURN_ERROR(initGfx(*ctx, params)); OX_RETURN_ERROR(initGfx(*ctx, params));
return ContextUPtr(ctx.release()); return ox::UPtr<Context>(ctx.release());
} }
keel::Context &keelCtx(Context &ctx) noexcept { keel::Context &keelCtx(Context &ctx) noexcept {

View File

@ -8,12 +8,12 @@
#include <glutils/glutils.hpp> #include <glutils/glutils.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
#include "gfx.hpp" #include "gfx.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
class Context { class Context {

View File

@ -10,15 +10,15 @@
#include <glutils/glutils.hpp> #include <glutils/glutils.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
#include "context.hpp" #include "context.hpp"
#include "gfx.hpp" #include "gfx.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
namespace renderer { namespace renderer {
@ -28,7 +28,7 @@ static constexpr auto PriorityScale = 0.01f;
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {} Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
void Drawer::draw(turbine::Context &tctx) noexcept { void Drawer::draw(turbine::Context &tctx) noexcept {
core::gl::draw(m_ctx, turbine::getScreenSize(tctx)); gfx::gl::draw(m_ctx, turbine::getScreenSize(tctx));
} }
static constexpr ox::CStringView bgvshadTmpl = R"glsl( static constexpr ox::CStringView bgvshadTmpl = R"glsl(
@ -111,15 +111,15 @@ static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
} }
static void setSpriteBufferObject( static void setSpriteBufferObject(
uint_t vi, uint_t const vi,
float enabled, float const enabled,
float x, float x,
float y, float y,
uint_t textureRow, uint_t const textureRow,
uint_t flipX, uint_t const flipX,
uint_t priority, uint_t const priority,
float *vbo, ox::Span<float> const vbo,
GLuint *ebo) noexcept { ox::Span<GLuint> const ebo) noexcept {
// don't worry, this memcpy gets optimized to something much more ideal // don't worry, this memcpy gets optimized to something much more ideal
constexpr float xmod = 0.1f; constexpr float xmod = 0.1f;
constexpr float ymod = 0.1f; constexpr float ymod = 0.1f;
@ -138,25 +138,25 @@ static void setSpriteBufferObject(
enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
enabled, x, y + ymod, prif, L, textureRowf + 0, // top left enabled, x, y + ymod, prif, L, textureRowf + 0, // top left
}; };
memcpy(vbo, vertices.data(), sizeof(vertices)); ox::spancpy<float>(vbo, vertices);
ox::Array<GLuint, SpriteVertexEboLength> const elms { ox::Array<GLuint, SpriteVertexEboLength> const elms {
vi + 0, vi + 1, vi + 2, vi + 0, vi + 1, vi + 2,
vi + 2, vi + 3, vi + 0, vi + 2, vi + 3, vi + 0,
}; };
memcpy(ebo, elms.data(), sizeof(elms)); ox::spancpy<GLuint>(ebo, elms);
} }
static void setTileBufferObject( static void setTileBufferObject(
uint_t vi, uint_t const vi,
float x, float x,
float y, float y,
float textureTileIdx, float const textureTileIdx,
float priority, float const priority,
float palOffset, float const palOffset,
bool flipX, bool const flipX,
bool flipY, bool const flipY,
float *vbo, ox::Span<float> const vbo,
GLuint *ebo) noexcept { ox::Span<GLuint> const ebo) noexcept {
// don't worry, this memcpy gets optimized to something much more ideal // don't worry, this memcpy gets optimized to something much more ideal
constexpr float ymod = 0.1f; constexpr float ymod = 0.1f;
constexpr float xmod = 0.1f; constexpr float xmod = 0.1f;
@ -170,24 +170,35 @@ static void setTileBufferObject(
float const T = flipY ? 1 : 0; float const T = flipY ? 1 : 0;
float const B = flipY ? 0 : 1; float const B = flipY ? 0 : 1;
ox::Array<float, BgVertexVboLength> const vertices { ox::Array<float, BgVertexVboLength> const vertices {
x, y, prif, L, B, textureTileIdx, palOffset, // bottom left x, y, prif, L, B, textureTileIdx, palOffset, // bottom left
x + xmod, y, prif, R, B, textureTileIdx, palOffset, // bottom right x + xmod, y, prif, R, B, textureTileIdx, palOffset, // bottom right
x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right
x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left
}; };
memcpy(vbo, vertices.data(), sizeof(vertices)); ox::spancpy<float>(vbo, vertices);
ox::Array<GLuint, BgVertexEboLength> const elms { ox::Array<GLuint, BgVertexEboLength> const elms {
vi + 0, vi + 1, vi + 2, vi + 0, vi + 1, vi + 2,
vi + 2, vi + 3, vi + 0, vi + 2, vi + 3, vi + 0,
}; };
memcpy(ebo, elms.data(), sizeof(elms)); ox::spancpy<GLuint>(ebo, elms);
} }
static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept { static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept {
for (auto i = 0u; i < ctx.spriteCount; ++i) { for (auto i = 0u; i < ctx.spriteCount; ++i) {
auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)]; auto const vbo = ox::Span{bs.vertices}
auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)]; + i * static_cast<std::size_t>(SpriteVertexVboLength);
setSpriteBufferObject(i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite, 0, 0, 0, 0, false, 0, vbo, ebo); auto const ebo = ox::Span{bs.elements}
+ i * static_cast<std::size_t>(SpriteVertexEboLength);
setSpriteBufferObject(
i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite,
0,
0,
0,
0,
false,
0,
vbo,
ebo);
} }
} }
@ -195,8 +206,10 @@ 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); const auto i = bgVertexRow(x, y);
auto vbo = &bs.vertices[i * static_cast<std::size_t>(BgVertexVboLength)]; auto const vbo = ox::Span{bs.vertices}
auto ebo = &bs.elements[i * static_cast<std::size_t>(BgVertexEboLength)]; + i * static_cast<std::size_t>(BgVertexVboLength);
auto const ebo = ox::Span{bs.elements}
+ i * static_cast<std::size_t>(BgVertexEboLength);
setTileBufferObject( setTileBufferObject(
static_cast<uint_t>(i * BgVertexVboRows), static_cast<uint_t>(i * BgVertexVboRows),
static_cast<float>(x), static_cast<float>(x),
@ -421,8 +434,8 @@ static void setSprite(
auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i; auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow"); oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow"); oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
auto const vbo = &ctx.spriteBlocks.vertices[vboIdx]; auto const vbo = ox::Span{ctx.spriteBlocks.vertices} + vboIdx;
auto const ebo = &ctx.spriteBlocks.elements[eboIdx]; auto const ebo = ox::Span{ctx.spriteBlocks.elements} + eboIdx;
renderer::setSpriteBufferObject( renderer::setSpriteBufferObject(
static_cast<uint_t>(vboIdx), static_cast<uint_t>(vboIdx),
enabled, enabled,
@ -556,7 +569,7 @@ static void copyPixels(
CompactTileSheet const&ts, CompactTileSheet const&ts,
ox::Span<uint32_t> dst, ox::Span<uint32_t> dst,
size_t const srcPxIdx, size_t const srcPxIdx,
size_t pxlCnt) noexcept { size_t const pxlCnt) noexcept {
size_t idx{}; size_t idx{};
if (ts.bpp == 4) { if (ts.bpp == 4) {
for (size_t i = 0; i < pxlCnt; i += 2) { for (size_t i = 0; i < pxlCnt; i += 2) {
@ -573,6 +586,18 @@ static void copyPixels(
} }
} }
void clearCbb(Context &ctx, unsigned const cbb) noexcept {
for (auto &v : ctx.cbbs[cbb].pixels) {
v = 0;
}
}
void clearCbbs(Context &ctx) noexcept {
for (unsigned i = 0 ; i < ctx.cbbs.size(); ++i) {
clearCbb(ctx, i);
}
}
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
@ -625,7 +650,7 @@ ox::Error loadSpriteTileSheet(
CompactTileSheet const&ts, CompactTileSheet const&ts,
bool loadDefaultPalette) noexcept { bool loadDefaultPalette) noexcept {
OX_REQUIRE(tsd, normalizeTileSheet(ts)); OX_REQUIRE(tsd, normalizeTileSheet(ts));
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height); oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data()); ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
if (loadDefaultPalette) { if (loadDefaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette)); OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@ -648,7 +673,7 @@ void setBgTile(
int row, int row,
BgTile const&tile) noexcept { BgTile const&tile) noexcept {
oxTracef( oxTracef(
"nostalgia.core.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); const auto z = static_cast<uint_t>(bgIdx);
@ -656,8 +681,8 @@ void setBgTile(
const auto x = static_cast<uint_t>(column); const auto x = static_cast<uint_t>(column);
const auto i = renderer::bgVertexRow(x, y); const auto i = renderer::bgVertexRow(x, y);
auto &cbb = ctx.cbbs[z]; auto &cbb = ctx.cbbs[z];
const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength]; const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength]; const auto 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),
@ -743,7 +768,7 @@ ox::Size drawSize(int scale) noexcept {
return {240 * scale, 160 * scale}; return {240 * scale, 160 * scale};
} }
void draw(core::Context &ctx, ox::Size const&renderSz) noexcept { void draw(gfx::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);
@ -758,7 +783,7 @@ void draw(core::Context &ctx, ox::Size const&renderSz) noexcept {
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
void draw(core::Context &ctx, int scale) noexcept { void draw(gfx::Context &ctx, int scale) noexcept {
draw(ctx, drawSize(scale)); draw(ctx, drawSize(scale));
} }

View File

@ -10,9 +10,9 @@
#include <glutils/glutils.hpp> #include <glutils/glutils.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/gfx/context.hpp>
namespace nostalgia::core::renderer { namespace nostalgia::gfx::renderer {
constexpr uint64_t TileRows = 128; constexpr uint64_t TileRows = 128;
constexpr uint64_t TileColumns = 128; constexpr uint64_t TileColumns = 128;
@ -59,7 +59,7 @@ class Drawer: public turbine::gl::Drawer {
} }
namespace nostalgia::core { namespace nostalgia::gfx {
ox::Error initGfx(Context &ctx, InitParams const&) noexcept; ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
void shutdownGfx(Context &ctx) noexcept; void shutdownGfx(Context &ctx) noexcept;
} }

View File

@ -3,7 +3,6 @@ add_library(NostalgiaCore-Studio)
add_library( add_library(
NostalgiaCore-Studio-ImGui NostalgiaCore-Studio-ImGui
studiomodule.cpp studiomodule.cpp
tilesheeteditor/tilesheeteditor-imgui.cpp
) )
target_link_libraries( target_link_libraries(
@ -15,7 +14,6 @@ target_link_libraries(
target_link_libraries( target_link_libraries(
NostalgiaCore-Studio-ImGui PUBLIC NostalgiaCore-Studio-ImGui PUBLIC
NostalgiaCore-Studio NostalgiaCore-Studio
Studio
) )
install( install(

View File

@ -10,5 +10,9 @@ target_sources(
commands/renamepagecommand.cpp commands/renamepagecommand.cpp
commands/updatecolorcommand.cpp commands/updatecolorcommand.cpp
commands/updatecolorinfocommand.cpp commands/updatecolorinfocommand.cpp
)
target_sources(
NostalgiaCore-Studio-ImGui PRIVATE
paletteeditor-imgui.cpp paletteeditor-imgui.cpp
) )

View File

@ -5,7 +5,7 @@
#include "commands.hpp" #include "commands.hpp"
#include "addcolorcommand.hpp" #include "addcolorcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
AddColorCommand::AddColorCommand(Palette &pal, Color16 const color, size_t const idx) noexcept: AddColorCommand::AddColorCommand(Palette &pal, Color16 const color, size_t const idx) noexcept:
m_pal(pal), m_pal(pal),

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class AddColorCommand: public studio::UndoCommand { class AddColorCommand: public studio::UndoCommand {
private: private:

View File

@ -6,7 +6,7 @@
#include "addpagecommand.hpp" #include "addpagecommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
AddPageCommand::AddPageCommand(Palette &pal) noexcept: AddPageCommand::AddPageCommand(Palette &pal) noexcept:
m_pal(pal) {} m_pal(pal) {}

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class AddPageCommand: public studio::UndoCommand { class AddPageCommand: public studio::UndoCommand {
private: private:

View File

@ -5,7 +5,7 @@
#include "commands.hpp" #include "commands.hpp"
#include "applycolorallpagescommand.hpp" #include "applycolorallpagescommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
ApplyColorAllPagesCommand::ApplyColorAllPagesCommand(Palette &pal, size_t const page, size_t const idx): ApplyColorAllPagesCommand::ApplyColorAllPagesCommand(Palette &pal, size_t const page, size_t const idx):
m_pal(pal), m_pal(pal),

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class ApplyColorAllPagesCommand: public studio::UndoCommand { class ApplyColorAllPagesCommand: public studio::UndoCommand {
private: private:

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
namespace nostalgia::core { namespace nostalgia::gfx {
enum class PaletteEditorCommandId { enum class PaletteEditorCommandId {
ApplyColorAllPages, ApplyColorAllPages,

View File

@ -6,7 +6,7 @@
#include "duplicatepagecommand.hpp" #include "duplicatepagecommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
DuplicatePageCommand::DuplicatePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept: DuplicatePageCommand::DuplicatePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept:
m_pal(pal), m_pal(pal),

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class DuplicatePageCommand: public studio::UndoCommand { class DuplicatePageCommand: public studio::UndoCommand {
private: private:

View File

@ -6,7 +6,7 @@
#include "movecolorcommand.hpp" #include "movecolorcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
MoveColorCommand::MoveColorCommand( MoveColorCommand::MoveColorCommand(
Palette &pal, size_t page, size_t srcIdx, size_t dstIdx) noexcept: Palette &pal, size_t page, size_t srcIdx, size_t dstIdx) noexcept:

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class MoveColorCommand: public studio::UndoCommand { class MoveColorCommand: public studio::UndoCommand {
private: private:

View File

@ -5,7 +5,7 @@
#include "commands.hpp" #include "commands.hpp"
#include "removecolorcommand.hpp" #include "removecolorcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
RemoveColorCommand::RemoveColorCommand(Palette &pal, size_t const idx) noexcept: RemoveColorCommand::RemoveColorCommand(Palette &pal, size_t const idx) noexcept:
m_pal(pal), m_pal(pal),

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class RemoveColorCommand: public studio::UndoCommand { class RemoveColorCommand: public studio::UndoCommand {
private: private:

View File

@ -6,7 +6,7 @@
#include "removepagecommand.hpp" #include "removepagecommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
RemovePageCommand::RemovePageCommand(Palette &pal, size_t idx) noexcept: RemovePageCommand::RemovePageCommand(Palette &pal, size_t idx) noexcept:
m_pal(pal), m_pal(pal),

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class RemovePageCommand: public studio::UndoCommand { class RemovePageCommand: public studio::UndoCommand {
private: private:

View File

@ -4,7 +4,7 @@
#include "renamepagecommand.hpp" #include "renamepagecommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
RenamePageCommand::RenamePageCommand(Palette &pal, size_t const page, ox::StringParam name) noexcept: RenamePageCommand::RenamePageCommand(Palette &pal, size_t const page, ox::StringParam name) noexcept:
m_pal(pal), m_pal(pal),

View File

@ -6,11 +6,11 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include "commands.hpp" #include "commands.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
class RenamePageCommand: public studio::UndoCommand { class RenamePageCommand: public studio::UndoCommand {
private: private:

View File

@ -5,7 +5,7 @@
#include "commands.hpp" #include "commands.hpp"
#include "updatecolorcommand.hpp" #include "updatecolorcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
UpdateColorCommand::UpdateColorCommand( UpdateColorCommand::UpdateColorCommand(
Palette &pal, Palette &pal,

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class UpdateColorCommand: public studio::UndoCommand { class UpdateColorCommand: public studio::UndoCommand {
private: private:

View File

@ -5,7 +5,7 @@
#include "commands.hpp" #include "commands.hpp"
#include "updatecolorinfocommand.hpp" #include "updatecolorinfocommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
UpdateColorInfoCommand::UpdateColorInfoCommand( UpdateColorInfoCommand::UpdateColorInfoCommand(
Palette &pal, Palette &pal,

View File

@ -6,9 +6,9 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class UpdateColorInfoCommand: public studio::UndoCommand { class UpdateColorInfoCommand: public studio::UndoCommand {
private: private:

View File

@ -19,7 +19,7 @@
#include "paletteeditor-imgui.hpp" #include "paletteeditor-imgui.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
namespace ig = studio::ig; namespace ig = studio::ig;
@ -107,7 +107,7 @@ void PaletteEditorImGui::colorInput(ox::CStringView label, int &v, bool &inputFo
void PaletteEditorImGui::drawColorsEditor() noexcept { void PaletteEditorImGui::drawColorsEditor() noexcept {
constexpr auto tableFlags = ImGuiTableFlags_RowBg; constexpr auto tableFlags = ImGuiTableFlags_RowBg;
auto const colorsSz = ImGui::GetContentRegionAvail(); auto const colorsSz = ImGui::GetContentRegionAvail();
auto const colorEditor = m_selectedColorRow < colorCnt(m_pal, m_page); auto colorEditor = m_selectedColorRow < colorCnt(m_pal, m_page);
auto const colorEditorWidth = 220; auto const colorEditorWidth = 220;
static constexpr auto toolbarHeight = 40; static constexpr auto toolbarHeight = 40;
{ {
@ -123,6 +123,7 @@ void PaletteEditorImGui::drawColorsEditor() noexcept {
if (ImGui::Button("Remove", sz)) { if (ImGui::Button("Remove", sz)) {
std::ignore = pushCommand<RemoveColorCommand>(m_pal, m_selectedColorRow); std::ignore = pushCommand<RemoveColorCommand>(m_pal, m_selectedColorRow);
m_selectedColorRow = ox::min(colorCnt(m_pal, m_page) - 1, m_selectedColorRow); m_selectedColorRow = ox::min(colorCnt(m_pal, m_page) - 1, m_selectedColorRow);
colorEditor = m_selectedColorRow < colorCnt(m_pal, m_page);
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginDisabled(m_selectedColorRow <= 0); ImGui::BeginDisabled(m_selectedColorRow <= 0);
@ -257,7 +258,7 @@ 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 (!inputFocused && !m_pageRenameDlg.isOpen()) { if (ig::mainWinHasFocus()) {
if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) { if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) {
numShortcuts(m_selectedColorRow, largestPage(m_pal)); numShortcuts(m_selectedColorRow, largestPage(m_pal));
} else { } else {

View File

@ -6,10 +6,10 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/core/palette.hpp> #include <nostalgia/gfx/palette.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
class PaletteEditorImGui: public studio::Editor { class PaletteEditorImGui: public studio::Editor {

View File

@ -9,7 +9,7 @@
#include "paletteeditor/paletteeditor-imgui.hpp" #include "paletteeditor/paletteeditor-imgui.hpp"
#include "tilesheeteditor/tilesheeteditor-imgui.hpp" #include "tilesheeteditor/tilesheeteditor-imgui.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
static class: public studio::Module { static class: public studio::Module {
ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept final { ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept final {
@ -21,8 +21,11 @@ static class: public studio::Module {
ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(studio::StudioContext&) const noexcept final { ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(studio::StudioContext&) const noexcept final {
ox::Vector<ox::UniquePtr<studio::ItemMaker>> out; ox::Vector<ox::UniquePtr<studio::ItemMaker>> out;
out.emplace_back(ox::make<studio::ItemMakerT<core::TileSheet>>("Tile Sheet", "TileSheets", FileExt_ng)); out.emplace_back(ox::make<studio::ItemMakerT<TileSheet>>("Tile Sheet", "TileSheets", FileExt_ng));
out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", FileExt_npal)); out.emplace_back(ox::make<studio::ItemMakerT<Palette>>("Palette", "Palettes", FileExt_npal, Palette{
.colorNames = {},
.pages = {{"Page 1", ox::Vector<PaletteColor>{}}},
}, ox::ClawFormat::Organic));
return out; return out;
} }
} const mod; } const mod;

View File

@ -6,6 +6,11 @@ target_sources(
tilesheetpixels.cpp tilesheetpixels.cpp
) )
target_sources(
NostalgiaCore-Studio-ImGui PRIVATE
tilesheeteditor-imgui.cpp
)
target_link_libraries( target_link_libraries(
NostalgiaCore-Studio-ImGui PUBLIC NostalgiaCore-Studio-ImGui PUBLIC
lodepng lodepng

View File

@ -4,7 +4,7 @@
#include "addsubsheetcommand.hpp" #include "addsubsheetcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
AddSubSheetCommand::AddSubSheetCommand( AddSubSheetCommand::AddSubSheetCommand(
TileSheet &img, TileSheet &img,
@ -28,12 +28,12 @@ ox::Error AddSubSheetCommand::redo() noexcept {
auto &parent = getSubSheet(m_img, m_parentIdx); auto &parent = getSubSheet(m_img, m_parentIdx);
if (m_addedSheets.size() < 2) { if (m_addedSheets.size() < 2) {
auto i = parent.subsheets.size(); auto i = parent.subsheets.size();
parent.subsheets.emplace_back(m_img.idIt++, ox::sfmt("Subsheet {}", i), 1, 1, m_img.bpp); parent.subsheets.emplace_back(m_img.idIt++, ox::sfmt("Subsheet {}", i), 1, 1);
} else { } else {
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels)); parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
parent.rows = 0; parent.rows = 0;
parent.columns = 0; parent.columns = 0;
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1, m_img.bpp); parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1);
} }
return {}; return {};
} }

View File

@ -6,7 +6,7 @@
#include "commands.hpp" #include "commands.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
class AddSubSheetCommand: public TileSheetCommand { class AddSubSheetCommand: public TileSheetCommand {
private: private:

View File

@ -5,9 +5,9 @@
#pragma once #pragma once
#include <studio/undostack.hpp> #include <studio/undostack.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::core { namespace nostalgia::gfx {
// Command IDs to use with QUndoCommand::id() // Command IDs to use with QUndoCommand::id()
enum class CommandId { enum class CommandId {

View File

@ -4,7 +4,7 @@
#include "cutpastecommand.hpp" #include "cutpastecommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
TileSheetClipboard::Pixel::Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept { TileSheetClipboard::Pixel::Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept {
colorIdx = pColorIdx; colorIdx = pColorIdx;
@ -37,8 +37,8 @@ CutPasteCommand::CutPasteCommand(
for (auto const&p : cb.pixels()) { for (auto const&p : cb.pixels()) {
auto const dstPt = p.pt + dstStart; auto const dstPt = p.pt + dstStart;
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) { if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
auto const idx = core::idx(ss, dstPt); auto const idx = gfx::idx(ss, dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, m_img.bpp, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, idx));
} }
} }
} }
@ -46,7 +46,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 (const auto &c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.newPalIdx)); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx);
} }
return {}; return {};
} }
@ -54,7 +54,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 (const auto &c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx)); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
} }
return {}; return {};
} }

View File

@ -8,19 +8,19 @@
#include "commands.hpp" #include "commands.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
OX_MODEL_FWD_DECL(class TileSheetClipboard); OX_MODEL_FWD_DECL(class TileSheetClipboard);
class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> { class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
public: public:
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetClipboard";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
OX_MODEL_FRIEND(TileSheetClipboard); OX_MODEL_FRIEND(TileSheetClipboard);
struct Pixel { struct Pixel {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard.Pixel"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetClipboard.Pixel";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
uint16_t colorIdx = 0; uint16_t colorIdx = 0;
ox::Point pt; ox::Point pt;

View File

@ -6,9 +6,9 @@
#include "deletetilescommand.hpp" #include "deletetilescommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
core::DeleteTilesCommand::DeleteTilesCommand( gfx::DeleteTilesCommand::DeleteTilesCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx idx, TileSheet::SubSheetIdx idx,
std::size_t tileIdx, std::size_t tileIdx,
@ -28,7 +28,7 @@ core::DeleteTilesCommand::DeleteTilesCommand(
} }
} }
ox::Error core::DeleteTilesCommand::redo() noexcept { ox::Error gfx::DeleteTilesCommand::redo() noexcept {
auto &s = getSubSheet(m_img, m_idx); auto &s = getSubSheet(m_img, m_idx);
auto &p = s.pixels; auto &p = s.pixels;
auto srcPos = m_deletePos + m_deleteSz; auto srcPos = m_deletePos + m_deleteSz;

View File

@ -6,7 +6,7 @@
#include "commands.hpp" #include "commands.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
class DeleteTilesCommand: public TileSheetCommand { class DeleteTilesCommand: public TileSheetCommand {
private: private:

View File

@ -4,7 +4,7 @@
#include "drawcommand.hpp" #include "drawcommand.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
DrawCommand::DrawCommand( DrawCommand::DrawCommand(
TileSheet &img, TileSheet &img,
@ -15,7 +15,7 @@ DrawCommand::DrawCommand(
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, m_img.bpp, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
} }
DrawCommand::DrawCommand( DrawCommand::DrawCommand(
@ -28,20 +28,20 @@ DrawCommand::DrawCommand(
m_palIdx(palIdx) { m_palIdx(palIdx) {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const idx : idxList) { for (auto const idx : idxList) {
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, m_img.bpp, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
} }
} }
bool DrawCommand::append(std::size_t idx) noexcept { bool DrawCommand::append(std::size_t idx) noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
if (m_changes.back().value->idx != idx && getPixel(subsheet, m_img.bpp, 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 = ox::find_if(m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) { auto existing = ox::find_if(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()) {
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, m_img.bpp, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
setPixel(subsheet, m_img.bpp, idx, static_cast<uint8_t>(m_palIdx)); subsheet.pixels[idx] = static_cast<uint8_t>(m_palIdx);
return true; return true;
} }
} }
@ -59,7 +59,7 @@ bool DrawCommand::append(ox::Vector<std::size_t> const&idxList) 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) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx)); subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx);
} }
return {}; return {};
} }
@ -67,7 +67,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) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx)); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
} }
return {}; return {};
} }

View File

@ -6,7 +6,7 @@
#include "commands.hpp" #include "commands.hpp"
namespace nostalgia::core { namespace nostalgia::gfx {
class DrawCommand: public TileSheetCommand { class DrawCommand: public TileSheetCommand {
private: private:

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