Compare commits

..

107 Commits

Author SHA1 Message Date
e1282b6bae [studio] Fix build
All checks were successful
Build / build (push) Successful in 3m23s
2025-01-22 00:58:43 -06:00
5fe7c14ccb [nostalgia/sample_project] Rename TileSheet files using new file ext
Some checks failed
Build / build (push) Failing after 52s
2025-01-21 23:40:19 -06:00
42165ba2d6 [nostalgia/gfx] Change default file extension for TileSheets to nts 2025-01-21 23:35:55 -06:00
1af4da43ad [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 3m22s
2025-01-21 22:56:59 -06:00
4fa879a09e [nostalgia/sample_project] Update NS_Logo.ng to final TileSheetV5 format
Some checks failed
Build / build (push) Has been cancelled
2025-01-21 22:54:27 -06:00
fd8f1a29c6 [nostalgia] Add release notes document
All checks were successful
Build / build (push) Successful in 3m24s
2025-01-21 22:45:55 -06:00
9fda2763ba [nostalgia/gfx] Make TileSheetV5::defaultPalette a string instead of FileAddress 2025-01-21 22:44:55 -06:00
cda23ac4af [ox/std] Change ox::String::operator[](size_t) const return a reference 2025-01-21 22:43:57 -06:00
c36b244dd3 [nostalgia/gfx] Cleanup, add PaletteV5, restore mistakenly removed function 2025-01-21 22:17:13 -06:00
335d278f5e [ox/oc] Fix integer read for signed/unsigned 2025-01-21 22:15:36 -06:00
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
189 changed files with 3434 additions and 1114 deletions

2
.gitignore vendored
View File

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

View File

@ -1,26 +1,31 @@
BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk
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
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
endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba
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
run: build
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: run-studio
run-studio: build
${NOSTALGIA_STUDIO}
${PROJECT_STUDIO}
.PHONY: gba-run
gba-run: pkg-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
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba
configure-gba:

View File

@ -1,8 +1,8 @@
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} -nostdinc++")
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-unwind-tables")
#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-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")

View File

@ -1,2 +1,11 @@
add_library(glad OBJECT src/glad.c)
target_include_directories(glad PUBLIC include)
add_library(glad src/glad.c)
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
add_library(
imgui OBJECT
imgui
imgui.cpp
imgui_demo.cpp
imgui_draw.cpp
@ -19,4 +19,12 @@ add_library(
target_include_directories(
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);
} 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 {
switch (addr.type()) {
case FileAddressType::Inode:

View File

@ -57,9 +57,9 @@ class FileSystem {
virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0;
virtual Error remove(StringViewCR path, bool recursive) noexcept = 0;
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
Error remove(StringViewCR path, bool recursive = false) noexcept {
return removePath(path, recursive);
}
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 removePath(StringViewCR path, bool recursive) 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;
@ -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 removePath(StringViewCR path, bool recursive) noexcept override;
Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(StringViewCR dir) const noexcept override;
@ -216,8 +220,6 @@ class FileSystemTemplate: public MemFS {
template<typename F>
Error ls(StringViewCR path, F cb) const;
Error remove(StringViewCR path, bool recursive) noexcept override;
/**
* 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);
}
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>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode);
@ -384,25 +405,6 @@ Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) cons
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>
Error FileSystemTemplate<FileStore, Directory>::resize() noexcept {
return m_fs.resize();

View File

@ -75,14 +75,6 @@ Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
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 {
// unsupported
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");
}
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 {
const auto p = (m_path / stripSlash(path));
try {

View File

@ -45,8 +45,6 @@ class PassThroughFS: public FileSystem {
template<typename F>
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;
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 removePath(StringViewCR path, bool recursive) 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;

View File

@ -14,7 +14,7 @@
{ \
const auto loggerErr = (loggerName).initConn(appName); \
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 { \
ox::trace::setLogger(&(loggerName)); \
} \

View File

@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
return out;
}
template<typename T>
template<typename T, typename Str = const char*>
[[nodiscard]]
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");
return name;
}
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*>
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();

View File

@ -144,7 +144,11 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
if (jv.empty()) {
*val = 0;
} else if (rightType) {
*val = static_cast<T>(jv.asUInt());
if constexpr(ox::is_signed_v<T>) {
*val = static_cast<T>(jv.asInt64());
} else {
*val = static_cast<T>(jv.asUInt64());
}
} else {
err = ox::Error(1, "Type mismatch");
}
@ -172,7 +176,8 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
err = ox::Error(1, "Type mismatch");
}
}
} catch (Json::LogicError const&) {
} catch (Json::LogicError const&e) {
oxDebugf("JSON error: {}", e.what());
err = ox::Error(1, "error reading JSON data");
}
++m_fieldIt;

View File

@ -9,13 +9,25 @@
#pragma once
#include "def.hpp"
#include "error.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
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) {
if (*begin == value) {
return begin;

View File

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

View File

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

View File

@ -22,9 +22,15 @@
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()) {
panic(file, line, panicMsg, err);
} 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(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
void assertFailFuncRuntime(
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 (!std::is_constant_evaluated()) {
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 (!std::is_constant_evaluated()) {
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 (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)

View File

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

View File

@ -31,7 +31,6 @@ concept Reader_c = requires(T v) {
class Reader_v {
public:
virtual constexpr ~Reader_v() noexcept = default;
[[nodiscard]]
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> tellg() noexcept = 0;

View File

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

View File

@ -62,6 +62,9 @@ class SmallMap {
[[nodiscard]]
constexpr Vector<K> keys() const noexcept;
[[nodiscard]]
constexpr Vector<T> values() const noexcept;
[[nodiscard]]
constexpr K const&key(size_t i) const noexcept;
@ -82,14 +85,22 @@ class SmallMap {
return m_pairs;
}
[[nodiscard]]
constexpr ox::Span<Pair> pairs() noexcept {
return m_pairs;
}
constexpr void clear();
private:
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>
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>
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
bool isNew{};
auto p = &access(m_pairs, k, isNew);
auto p = access(m_pairs, k, isNew);
if (isNew) {
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>
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) {
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>
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) {
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>
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>
@ -186,6 +199,16 @@ constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
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>
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
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 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 {
for (auto const&p : pairs) {
if (p.key == k) {
isNew = false;
return p;
return &p;
}
}
isNew = true;
return pairs.emplace_back();
return nullptr;
}
template<typename K, typename T, size_t SmallSz>
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) {
for (auto &p : pairs) {
if (p.key == k) {
isNew = false;
return p;
return &p;
}
}
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>

View File

@ -14,7 +14,7 @@
#include "iterator.hpp"
#include "vector.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace ox {
@ -133,7 +133,7 @@ class Span {
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");
return m_items[i];
}
@ -168,8 +168,20 @@ class Span {
};
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

@ -171,7 +171,7 @@ class BasicString {
constexpr bool operator>=(BasicString const&other) const noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char const&operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
@ -392,7 +392,7 @@ template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox::strlen(str);
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
BasicString<SmallStringSize_v> cpy;
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], str, strLen);
@ -425,7 +425,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen);
cpy.m_buff[cpy.m_buff.size() - 1] = 0;
return cpy;
}
@ -436,7 +437,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen);
cpy.m_buff[cpy.m_buff.size() - 1] = 0;
return cpy;
}
@ -488,7 +490,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator>=(BasicString const&othe
}
template<std::size_t SmallStringSize_v>
constexpr char BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
constexpr char const&BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}

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] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
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] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
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);
}
},
{
"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",
[] {
@ -246,7 +290,18 @@ OX_CLANG_NOWARN_END
oxExpect(map.size(), 1u);
oxExpect(map["aoeu"], "");
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);
}
},
{

View File

@ -269,8 +269,8 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
if (err.file != nullptr) {
trc << "Error: (" << err.file << ":" << err.line << "):";
if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} else {
trc << "Error:";
}
@ -282,8 +282,8 @@ inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
trc << "Error:" << err;
if (err.file != nullptr) {
trc << "(" << err.file << ":" << err.line << ")";
if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";
}
}
}

View File

@ -19,12 +19,15 @@
namespace std {
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();
}
template<typename T>
inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
}
#endif
@ -156,6 +159,9 @@ static_assert(is_class<int>::value == false);
template<typename 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>
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 shrink_to_fit() noexcept(useNoexcept);
private:
constexpr void reserveInsert(
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>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
reserve(list.size());
for (auto &item : list) {
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>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
std::size_t cap,

View File

@ -4,17 +4,20 @@
#include <ox/std/heapmgr.hpp>
#include <teagba/bios.hpp>
#include <teagba/registers.hpp>
namespace mgba {
void initConsole();
}
#define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000)
#define MEM_EWRAM_END reinterpret_cast<char*>(0x0203FFFF)
#define MEM_HEAP_BEGIN reinterpret_cast<char*>(0x02000000)
#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
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
#define HEAP_END reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE)
#define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2)
#define HEAP_END reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE)
extern void (*__preinit_array_start[]) (void);
extern void (*__preinit_array_end[]) (void);
@ -25,6 +28,14 @@ int main(int argc, const char **argv);
extern "C" {
void abort() {
REG_IE = 0;
teagba::intrwait(0, 0);
while (true);
}
void *__gxx_personality_v0{};
void __libc_init_array() {
auto preInits = __preinit_array_end - __preinit_array_start;
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
The GBA build has exceptions disabled.
Instead of throwing exceptions, all engine code should return
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting.
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.
Instead of throwing exceptions, generally try to use
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
but exceptions may be used where they make sense.
Exceptions should generally just use ```OxException```, which is bascially an
exception form of ```ox::Error```.

13
release-notes.md Normal file
View File

@ -0,0 +1,13 @@
# d2025.02
* Rename core namespace to gfx.
* Add PaletteV5 to accommodate namespace change.
* Add TileSheetV5. TileSheetV5 retains the bpp field for the sake of
CompactTileSheet, but always store it pixel as 8 bpp for itself.
* Replace file picker combo boxes with support for dragging files from the
project explorer.
* Add ability to create directories.
* Add ability to add files to specific directories.
* Add ability to delete files from the project explorer.
* Ctrl-<num key> keyboard shortcuts for jumping between tabs.
* Fix Palette Editor to ignore keyboard input when popups are open.

Binary file not shown.

View File

@ -0,0 +1,352 @@
K1;5667c759-7ba1-470a-8860-72f0720dc58c;O1;net.drinkingtea.nostalgia.gfx.TileSheet;5;{
"bpp" : 4,
"defaultPalette" : "uuid://14fc3dd8-42ff-4bf9-81f1-a010cc5ac251",
"idIt" : 7,
"subsheet" :
{
"columns" : -1,
"name" : "Root",
"rows" : -1,
"subsheets" :
[
{
"columns" : 1,
"id" : 5,
"name" : "Blank",
"pixels" :
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"rows" : 1
},
{
"columns" : 2,
"id" : 6,
"name" : "Dirt",
"pixels" :
[
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1
],
"rows" : 2
}
]
}
}

Binary file not shown.

View File

@ -0,0 +1,591 @@
K1;f551fb8b-0e9f-45fc-8106-b98b7fd18ff5;O1;net.drinkingtea.nostalgia.gfx.TileSheet;5;{
"bpp" : 4,
"defaultPalette" : "uuid://c79f21e2-f74f-4ad9-90ed-32b0ef7da6ed",
"idIt" : 2,
"subsheet" :
{
"columns" : 3,
"id" : 1,
"name" : "Root",
"pixels" :
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
3,
3,
3,
3,
0,
0,
0,
3,
3,
3,
2,
3,
3,
0,
0,
3,
3,
2,
3,
3,
3,
0,
0,
0,
3,
3,
3,
3,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
0,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"rows" : 3
}
}

Binary file not shown.

View File

@ -1,6 +1,6 @@
# module dir list
add_subdirectory(core)
add_subdirectory(gfx)
add_subdirectory(scene)
# 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/types.hpp>
namespace nostalgia::core {
namespace nostalgia::gfx {
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.
*/
using Color32 = uint32_t;
@ -154,7 +154,7 @@ static_assert(color16(16, 32, 8) == 9200);
[[nodiscard]]
constexpr Color16 applySelectionColor(Color16 const color) noexcept {
namespace core = nostalgia::core;
namespace core = nostalgia::gfx;
auto const r = core::red16(color) / 2;
auto const g = (core::green16(color) + 20) / 2;
auto const b = (core::blue16(color) + 31) / 2;

View File

@ -6,13 +6,14 @@
#include <ox/std/stringliteral.hpp>
namespace nostalgia::core {
namespace nostalgia::gfx {
constexpr auto TileWidth = 8;
constexpr auto TileHeight = 8;
constexpr auto PixelsPerTile = TileWidth * TileHeight;
constexpr ox::StringLiteral FileExt_ng("ng");
constexpr ox::StringLiteral FileExt_nts("nts");
constexpr ox::StringLiteral FileExt_npal("npal");
}

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 "tilesheet.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
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;
bool enabled = false;
int x = 0;
@ -46,7 +46,7 @@ OX_MODEL_BEGIN(Sprite)
OX_MODEL_END()
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;
unsigned tileIdx = 0;
unsigned palBank = 0;
@ -62,7 +62,7 @@ OX_MODEL_BEGIN(BgTile)
OX_MODEL_END()
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;
int32_t begin = 0;
int32_t tiles = 0;
@ -78,7 +78,7 @@ OX_MODEL_BEGIN(TileSheetSetEntrySection)
OX_MODEL_END()
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;
ox::FileAddress tilesheet;
ox::Vector<TileSheetSetEntrySection> sections;
@ -90,7 +90,7 @@ OX_MODEL_BEGIN(TileSheetSetEntry)
OX_MODEL_END()
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 Preloadable = true;
int32_t bpp = 0;
@ -102,8 +102,6 @@ OX_MODEL_BEGIN(TileSheetSet)
OX_MODEL_FIELD(entries)
OX_MODEL_END()
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
[[nodiscard]]
int tileColumns(Context&) noexcept;
@ -144,6 +142,10 @@ ox::Error loadBgTileSheet(
unsigned cbb,
TileSheetSet const&set) noexcept;
void clearCbb(Context &ctx, unsigned cbb) noexcept;
void clearCbbs(Context &ctx) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
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";
[[nodiscard]]
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>
namespace nostalgia::core {
namespace nostalgia::gfx {
struct InitParams {
bool glInstallDrawer = true;

View File

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

View File

@ -11,7 +11,7 @@
#include "color.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
struct PaletteColorV1 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.PaletteColor";
@ -33,7 +33,31 @@ OX_MODEL_BEGIN(PaletteColorV1)
OX_MODEL_FIELD(a)
OX_MODEL_END()
using PaletteColor = PaletteColorV1;
struct PaletteColorV2 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.PaletteColor";
static constexpr auto TypeVersion = 2;
uint8_t r{}, g{}, b{}, a{};
constexpr PaletteColorV2() noexcept = default;
constexpr PaletteColorV2(Color16 const c) noexcept:
r{red16(c)},
g{green16(c)},
b{blue16(c)},
a{alpha16(c)} {}
constexpr PaletteColorV2(uint8_t const r, uint8_t const g, uint8_t const b, uint8_t const a) noexcept:
r{r}, g{g}, b{b}, a{a} {}
constexpr operator Color16() const noexcept { return color16(r, g, b, a); }
};
OX_MODEL_BEGIN(PaletteColorV2)
OX_MODEL_FIELD(r)
OX_MODEL_FIELD(g)
OX_MODEL_FIELD(b)
OX_MODEL_FIELD(a)
OX_MODEL_END()
using PaletteColor = PaletteColorV2;
struct PalettePageV1 {
@ -58,7 +82,31 @@ OX_MODEL_BEGIN(PalettePageV1)
OX_MODEL_FIELD(colors)
OX_MODEL_END()
using PalettePage = PalettePageV1;
struct PalettePageV2 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.Palette.PalettePage";
static constexpr auto TypeVersion = 2;
ox::String name;
ox::Vector<PaletteColorV2> colors;
constexpr PalettePageV2() noexcept = default;
constexpr PalettePageV2(ox::StringParam pName, ox::Vector<PaletteColorV2> pColors) noexcept:
name(std::move(pName)), colors(std::move(pColors)) {}
constexpr PalettePageV2(ox::StringParam pName, ox::Vector<Color16> const&pColors) noexcept:
name(std::move(pName)) {
colors.reserve(pColors.size());
for (auto const c : pColors) {
colors.emplace_back(c);
}
}
};
OX_MODEL_BEGIN(PalettePageV2)
OX_MODEL_FIELD(name)
OX_MODEL_FIELD(colors)
OX_MODEL_END()
using PalettePage = PalettePageV2;
struct NostalgiaPalette {
@ -166,11 +214,41 @@ constexpr ox::Error repair(PaletteV4 &p) noexcept {
}
using Palette = PaletteV4;
struct PaletteV5 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.Palette";
static constexpr auto TypeVersion = 5;
static constexpr auto Preloadable = true;
ox::Vector<ox::String> colorNames;
ox::Vector<PalettePageV2> pages;
};
OX_MODEL_BEGIN(PaletteV5)
OX_MODEL_FIELD(colorNames)
OX_MODEL_FIELD(pages)
OX_MODEL_END()
[[nodiscard]]
constexpr bool valid(PaletteV5 const&p) noexcept {
auto const colors = p.colorNames.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV2 const&page) {
return page.colors.size() == colors;
});
}
constexpr ox::Error repair(PaletteV5 &p) noexcept {
auto const colors = p.colorNames.size();
for (auto &page : p.pages) {
page.colors.resize(colors);
}
return {};
}
using Palette = PaletteV5;
struct CompactPaletteV1 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactPalette";
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.CompactPalette";
static constexpr auto TypeVersion = 1;
static constexpr auto Preloadable = true;
ox::Vector<ox::Vector<Color16>> pages{};
@ -207,7 +285,7 @@ using CompactPalette = CompactPaletteV1;
[[nodiscard]]
constexpr Color16 color(Palette const&pal, size_t page, size_t idx) noexcept {
constexpr Color16 color(Palette const&pal, size_t const page, size_t const idx) noexcept {
if (page < pal.pages.size() && idx < pal.pages[page].colors.size()) [[likely]] {
return pal.pages[page].colors[idx];
}
@ -215,7 +293,7 @@ constexpr Color16 color(Palette const&pal, size_t page, size_t idx) noexcept {
}
[[nodiscard]]
constexpr Color16 color(CompactPalette const&pal, size_t page, size_t idx) noexcept {
constexpr Color16 color(CompactPalette const&pal, size_t const page, size_t const idx) noexcept {
if (page < pal.pages.size() && idx < pal.pages[page].size()) [[likely]] {
return pal.pages[page][idx];
}
@ -223,37 +301,37 @@ constexpr Color16 color(CompactPalette const&pal, size_t page, size_t idx) noexc
}
[[nodiscard]]
constexpr Color16 color(Palette const&pal, size_t idx) noexcept {
constexpr Color16 color(Palette const&pal, size_t const idx) noexcept {
return color(pal, 0, idx);
}
[[nodiscard]]
constexpr Color16 color(CompactPalette const&pal, size_t idx) noexcept {
constexpr Color16 color(CompactPalette const&pal, size_t const idx) noexcept {
return color(pal, 0, idx);
}
[[nodiscard]]
constexpr auto &colors(Palette &pal, size_t page = 0) noexcept {
constexpr auto &colors(Palette &pal, size_t const page = 0) noexcept {
return pal.pages[page].colors;
}
[[nodiscard]]
constexpr auto &colors(CompactPalette &pal, size_t page = 0) noexcept {
constexpr auto &colors(CompactPalette &pal, size_t const page = 0) noexcept {
return pal.pages[page];
}
[[nodiscard]]
constexpr auto &colors(Palette const&pal, size_t page = 0) noexcept {
constexpr auto &colors(Palette const&pal, size_t const page = 0) noexcept {
return pal.pages[page];
}
[[nodiscard]]
constexpr auto &colors(CompactPalette const&pal, size_t page = 0) noexcept {
constexpr auto &colors(CompactPalette const&pal, size_t const page = 0) noexcept {
return pal.pages[page];
}
[[nodiscard]]
constexpr size_t colorCnt(Palette const&pal, size_t page = 0) noexcept {
constexpr size_t colorCnt(Palette const&pal, size_t const page = 0) noexcept {
if (page < pal.pages.size()) [[likely]] {
return pal.pages[page].colors.size();
}
@ -261,7 +339,7 @@ constexpr size_t colorCnt(Palette const&pal, size_t page = 0) noexcept {
}
[[nodiscard]]
constexpr size_t colorCnt(CompactPalette const&pal, size_t page = 0) noexcept {
constexpr size_t colorCnt(CompactPalette const&pal, size_t const page = 0) noexcept {
if (page < pal.pages.size()) [[likely]] {
return pal.pages[page].size();
}

View File

@ -8,7 +8,7 @@
#include "consts.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
[[nodiscard]]
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>
namespace nostalgia::core {
namespace nostalgia::gfx {
const studio::Module *studioModule() noexcept;

View File

@ -5,18 +5,33 @@
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/array.hpp>
#include <ox/std/point.hpp>
#include <ox/std/size.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp>
#include <ox/model/def.hpp>
#include <nostalgia/core/ptidxconv.hpp>
#include <nostalgia/gfx/ptidxconv.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
struct TileSheetV1 {
@ -212,6 +227,10 @@ struct TileSheetV4 {
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);
@ -269,7 +288,109 @@ 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;
/**
* bpp is unused for TileSheet, but it does get used in CompactTileSheet.
* All pixel in TileSheet are 8 bpp, regardless of what the bpp field says.
*/
int8_t bpp = 4;
SubSheetId idIt = 0;
ox::String 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]]
std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
@ -281,75 +402,37 @@ size_t getTileCnt(TileSheet const&ts) noexcept;
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]]
size_t getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]]
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, std::size_t idx) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept;
[[nodiscard]]
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]]
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, ox::Point const&pt) noexcept;
constexpr void walkPixels(TileSheet::SubSheet const&ss, int8_t pBpp, auto callback) noexcept {
if (pBpp == 4) {
const auto pixelCnt = ox::min<std::size_t>(
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, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept;
/**
* 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
*/
[[nodiscard]]
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept;
/**
*
* @param ss
* @param pBpp
* @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
* preceding or parent sheet if the current corresponding sheet does
* not exist.
* @param ts
* @param idx SubSheetIdx to validate and correct
* @return a valid version of idx
*/
@ -385,13 +468,7 @@ ox::Error rmSubSheet(
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept;
[[nodiscard]]
uint8_t getPixel4Bpp(
TileSheet const&ts,
ox::Point const&pt,
TileSheet::SubSheetIdx const&subsheetIdx) noexcept;
[[nodiscard]]
uint8_t getPixel8Bpp(
uint8_t getPixel(
TileSheet const&ts,
ox::Point const&pt,
TileSheet::SubSheetIdx const&subsheetIdx) noexcept;
@ -400,6 +477,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<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 const&ts, SubSheetId pId) noexcept;
@ -409,7 +488,7 @@ ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept;
struct CompactTileSheetV1 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet";
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.CompactTileSheet";
static constexpr auto TypeVersion = 1;
static constexpr auto Preloadable = true;
int8_t bpp = 0;
@ -499,6 +578,22 @@ OX_MODEL_BEGIN(TileSheetV4)
OX_MODEL_FIELD(subsheet)
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_FIELD(bpp)
OX_MODEL_FIELD(defaultPalette)

View File

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

View File

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

View File

@ -11,15 +11,15 @@
#include <keel/keel.hpp>
#include <nostalgia/core/context.hpp>
#include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/tilesheet.hpp>
#include <nostalgia/gfx/context.hpp>
#include <nostalgia/gfx/gfx.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
#include "context.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
namespace nostalgia::core {
namespace nostalgia::gfx {
static constexpr auto SpriteCount = 128;
@ -63,6 +63,19 @@ ox::Error loadSpritePalette(
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(
Context &ctx,
ox::Span<uint16_t> tileMapTargetMem,
@ -99,10 +112,10 @@ ox::Error loadBgTileSheet(
size_t const tileCnt) noexcept {
size_t const bppMod = ts.bpp == 4;
size_t const bytesPerTile = PixelsPerTile >> bppMod;
auto const pixCnt = tileCnt * bytesPerTile;
auto const cnt = (tileCnt * bytesPerTile) / 2;
auto const srcPxIdx = srcTileIdx * bytesPerTile;
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 p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);

View File

@ -4,8 +4,8 @@
#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;
}

View File

@ -4,6 +4,7 @@
#include <ox/std/def.hpp>
#include <ox/std/realstd.hpp>
#include <keel/media.hpp>
#include <turbine/turbine.hpp>
@ -11,7 +12,7 @@
#include <teagba/addresses.hpp>
#include <teagba/bios.hpp>
#include <nostalgia/core/core.hpp>
#include <nostalgia/gfx/core.hpp>
#include "gfx.hpp"
@ -21,7 +22,7 @@
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 {
// 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 Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
if (err.src.file_name() != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
}
// disable all interrupt handling and IntrWait on no interrupts
REG_IE = 0;
teagba::intrwait(0, 0);
abort();
}
}

View File

@ -3,9 +3,9 @@
*/
#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 GbaTileRows = 32;

View File

@ -4,15 +4,14 @@
#include <ox/model/model.hpp>
#include <keel/asset.hpp>
#include <keel/module.hpp>
#include <nostalgia/core/palette.hpp>
#include <nostalgia/core/tilesheet.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
#include "typeconv.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
static class: public keel::Module {
private:
@ -20,16 +19,18 @@ static class: public keel::Module {
PaletteV1ToPaletteV2Converter m_paletteV1ToPaletteV2Converter;
PaletteV2ToPaletteV3Converter m_paletteV2ToPaletteV3Converter;
PaletteV3ToPaletteV4Converter m_paletteV3ToPaletteV4Converter;
PaletteV4ToPaletteV5Converter m_paletteV4ToPaletteV5Converter;
PaletteToCompactPaletteConverter m_paletteToCompactPaletteConverter;
TileSheetV1ToTileSheetV2Converter m_tileSheetV1ToTileSheetV2Converter;
TileSheetV2ToTileSheetV3Converter m_tileSheetV2ToTileSheetV3Converter;
TileSheetV3ToTileSheetV4Converter m_tileSheetV3ToTileSheetV4Converter;
TileSheetV4ToTileSheetV5Converter m_tileSheetV4ToTileSheetV5Converter;
TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter;
public:
[[nodiscard]]
ox::String id() const noexcept override {
return ox::String("net.drinkingtea.nostalgia.core");
return ox::String{"net.drinkingtea.nostalgia.gfx"};
}
[[nodiscard]]
@ -39,11 +40,13 @@ static class: public keel::Module {
keel::generateTypeDesc<TileSheetV2>,
keel::generateTypeDesc<TileSheetV3>,
keel::generateTypeDesc<TileSheetV4>,
keel::generateTypeDesc<TileSheetV5>,
keel::generateTypeDesc<CompactTileSheetV1>,
keel::generateTypeDesc<PaletteV1>,
keel::generateTypeDesc<PaletteV2>,
keel::generateTypeDesc<PaletteV3>,
keel::generateTypeDesc<PaletteV4>,
keel::generateTypeDesc<PaletteV5>,
keel::generateTypeDesc<CompactPaletteV1>,
};
}
@ -55,10 +58,12 @@ static class: public keel::Module {
&m_paletteV1ToPaletteV2Converter,
&m_paletteV2ToPaletteV3Converter,
&m_paletteV3ToPaletteV4Converter,
&m_paletteV4ToPaletteV5Converter,
&m_paletteToCompactPaletteConverter,
&m_tileSheetV1ToTileSheetV2Converter,
&m_tileSheetV2ToTileSheetV3Converter,
&m_tileSheetV3ToTileSheetV4Converter,
&m_tileSheetV4ToTileSheetV5Converter,
&m_tileSheetToCompactTileSheetConverter,
};
}
@ -67,23 +72,25 @@ static class: public keel::Module {
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
return {
// 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> ||
typeId == ox::ModelTypeId_v<TileSheetV2> ||
typeId == ox::ModelTypeId_v<TileSheetV3> ||
typeId == ox::ModelTypeId_v<TileSheetV4>) {
typeId == ox::ModelTypeId_v<TileSheetV4> ||
typeId == ox::ModelTypeId_v<TileSheetV5>) {
OX_RETURN_ERROR(keel::convertBuffToBuff<CompactTileSheet>(
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
return true;
}
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> ||
typeId == ox::ModelTypeId_v<PaletteV1> ||
typeId == ox::ModelTypeId_v<PaletteV2> ||
typeId == ox::ModelTypeId_v<PaletteV3> ||
typeId == ox::ModelTypeId_v<PaletteV4>) {
typeId == ox::ModelTypeId_v<PaletteV4> ||
typeId == ox::ModelTypeId_v<PaletteV5>) {
OX_RETURN_ERROR(keel::convertBuffToBuff<CompactPalette>(
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
return true;
@ -92,6 +99,7 @@ static class: public keel::Module {
},
};
}
} const mod;
keel::Module const*keelModule() noexcept {

View File

@ -4,7 +4,7 @@
#include "typeconv.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
ox::Error NostalgiaPaletteToPaletteV1Converter::convert(
keel::Context&,
@ -52,6 +52,26 @@ ox::Error PaletteV3ToPaletteV4Converter::convert(
return {};
}
ox::Error PaletteV4ToPaletteV5Converter::convert(
keel::Context&,
PaletteV4 &src,
PaletteV5 &dst) const noexcept {
dst.colorNames = std::move(src.colorNames);
dst.pages.reserve(src.pages.size());
for (auto &s : src.pages) {
ox::Vector<PaletteColorV2> colors;
colors.reserve(s.colors.size());
for (auto const&c : s.colors) {
colors.emplace_back(c.r, c.g, c.b, c.a);
}
dst.pages.emplace_back(PalettePageV2{
std::move(s.name),
std::move(colors),
});
}
return {};
}
ox::Error PaletteToCompactPaletteConverter::convert(
keel::Context&,
Palette &src,
@ -133,12 +153,50 @@ ox::Error TileSheetV3ToTileSheetV4Converter::convert(
return {};
}
void TileSheetV4ToTileSheetV5Converter::convertSubsheet(
int const bpp,
TileSheetV4::SubSheet &src,
TileSheetV5::SubSheet &dst) noexcept {
dst.id = src.id;
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);
}
dst.subsheets.resize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) {
convertSubsheet(bpp, src.subsheets[i], dst.subsheets[i]);
}
}
ox::Error TileSheetV4ToTileSheetV5Converter::convert(
keel::Context&,
TileSheetV4 &src,
TileSheetV5 &dst) const noexcept {
dst.bpp = src.bpp;
dst.idIt = src.idIt;
OX_RETURN_ERROR(src.defaultPalette.getPath().moveTo(dst.defaultPalette));
convertSubsheet(dst.bpp, src.subsheet, dst.subsheet);
return {};
}
ox::Error TileSheetToCompactTileSheetConverter::convert(
keel::Context&,
TileSheet &src,
CompactTileSheet &dst) const noexcept {
dst.bpp = src.bpp;
dst.defaultPalette = std::move(src.defaultPalette);
dst.defaultPalette = ox::FileAddress{src.defaultPalette};
dst.pixels = pixels(src);
return {};
}

View File

@ -8,11 +8,11 @@
#include <keel/typeconv.hpp>
#include <nostalgia/core/context.hpp>
#include <nostalgia/core/palette.hpp>
#include <nostalgia/core/tilesheet.hpp>
#include <nostalgia/gfx/context.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::core {
namespace nostalgia::gfx {
// Type converters
@ -21,15 +21,19 @@ class NostalgiaPaletteToPaletteV1Converter: public keel::Converter<NostalgiaPale
};
class PaletteV1ToPaletteV2Converter: public keel::Converter<PaletteV1, PaletteV2> {
ox::Error convert(keel::Context&, PaletteV1 &src, PaletteV2 &dst) const noexcept final;
ox::Error convert(keel::Context&, PaletteV1 &src, PaletteV2 &dst) const noexcept final;
};
class PaletteV2ToPaletteV3Converter: public keel::Converter<PaletteV2, PaletteV3> {
ox::Error convert(keel::Context&, PaletteV2 &src, PaletteV3 &dst) const noexcept final;
ox::Error convert(keel::Context&, PaletteV2 &src, PaletteV3 &dst) const noexcept final;
};
class PaletteV3ToPaletteV4Converter: public keel::Converter<PaletteV3, PaletteV4> {
ox::Error convert(keel::Context&, PaletteV3 &src, PaletteV4 &dst) const noexcept final;
ox::Error convert(keel::Context&, PaletteV3 &src, PaletteV4 &dst) const noexcept final;
};
class PaletteV4ToPaletteV5Converter: public keel::Converter<PaletteV4, PaletteV5> {
ox::Error convert(keel::Context&, PaletteV4 &src, PaletteV5 &dst) const noexcept final;
};
class PaletteToCompactPaletteConverter: public keel::Converter<Palette, CompactPalette> {
@ -56,6 +60,14 @@ class TileSheetV3ToTileSheetV4Converter: public keel::Converter<TileSheetV3, Til
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) noexcept;
ox::Error convert(keel::Context&, TileSheetV4 &src, TileSheetV5 &dst) const noexcept override;
};
class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> {
ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
};

View File

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

View File

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

View File

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

View File

@ -10,9 +10,9 @@
#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 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;
void shutdownGfx(Context &ctx) noexcept;
}

View File

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

View File

@ -1,6 +1,7 @@
target_sources(
NostalgiaCore-Studio PRIVATE
commands/addcolorcommand.cpp
commands/addpagecommand.cpp
commands/applycolorallpagescommand.cpp
commands/duplicatepagecommand.cpp
commands/movecolorcommand.cpp
@ -9,5 +10,9 @@ target_sources(
commands/renamepagecommand.cpp
commands/updatecolorcommand.cpp
commands/updatecolorinfocommand.cpp
)
target_sources(
NostalgiaCore-Studio-ImGui PRIVATE
paletteeditor-imgui.cpp
)

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

@ -0,0 +1,28 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "commands.hpp"
#include "addpagecommand.hpp"
namespace nostalgia::gfx {
AddPageCommand::AddPageCommand(Palette &pal) noexcept:
m_pal(pal) {}
int AddPageCommand::commandId() const noexcept {
return static_cast<int>(PaletteEditorCommandId::AddPage);
}
ox::Error AddPageCommand::redo() noexcept {
m_pal.pages.emplace_back(ox::sfmt("Page {}", m_pal.pages.size() + 1), ox::Vector<PaletteColor>{});
return {};
}
ox::Error AddPageCommand::undo() noexcept {
m_pal.pages.pop_back();
return {};
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <studio/studio.hpp>
#include <nostalgia/gfx/palette.hpp>
namespace nostalgia::gfx {
class AddPageCommand: public studio::UndoCommand {
private:
Palette &m_pal;
public:
explicit AddPageCommand(Palette &pal) noexcept;
~AddPageCommand() noexcept override = default;
[[nodiscard]]
int commandId() const noexcept final;
ox::Error redo() noexcept final;
ox::Error undo() noexcept final;
};
}

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

@ -4,11 +4,12 @@
#pragma once
namespace nostalgia::core {
namespace nostalgia::gfx {
enum class PaletteEditorCommandId {
ApplyColorAllPages,
RenamePage,
AddPage,
DuplicatePage,
RemovePage,
AddColor,

View File

@ -6,7 +6,7 @@
#include "duplicatepagecommand.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
DuplicatePageCommand::DuplicatePageCommand(Palette &pal, size_t srcIdx, size_t dstIdx) noexcept:
m_pal(pal),
@ -23,7 +23,7 @@ int DuplicatePageCommand::commandId() const noexcept {
}
ox::Error DuplicatePageCommand::redo() noexcept {
m_pal.pages.emplace(m_dstIdx, "", std::move(m_page));
m_pal.pages.emplace(m_dstIdx, ox::sfmt("Page {}", m_pal.pages.size() + 1), std::move(m_page));
return {};
}

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

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

View File

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

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

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

View File

@ -6,9 +6,9 @@
#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 {
private:

View File

@ -7,6 +7,7 @@
#include <keel/media.hpp>
#include "commands/addcolorcommand.hpp"
#include "commands/addpagecommand.hpp"
#include "commands/applycolorallpagescommand.hpp"
#include "commands/duplicatepagecommand.hpp"
#include "commands/movecolorcommand.hpp"
@ -18,7 +19,7 @@
#include "paletteeditor-imgui.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
namespace ig = studio::ig;
@ -106,7 +107,7 @@ void PaletteEditorImGui::colorInput(ox::CStringView label, int &v, bool &inputFo
void PaletteEditorImGui::drawColorsEditor() noexcept {
constexpr auto tableFlags = ImGuiTableFlags_RowBg;
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;
static constexpr auto toolbarHeight = 40;
{
@ -122,6 +123,7 @@ void PaletteEditorImGui::drawColorsEditor() noexcept {
if (ImGui::Button("Remove", sz)) {
std::ignore = pushCommand<RemoveColorCommand>(m_pal, 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::BeginDisabled(m_selectedColorRow <= 0);
@ -196,7 +198,11 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
constexpr auto toolbarHeight = 40;
auto const btnSz = ImVec2{paneSz.x / 4 - 5.5f, 24};
if (ImGui::Button("Add", btnSz)) {
std::ignore = pushCommand<DuplicatePageCommand>(m_pal, 0u, m_pal.pages.size());
if (m_pal.pages.empty()) {
std::ignore = pushCommand<AddPageCommand>(m_pal);
} else {
std::ignore = pushCommand<DuplicatePageCommand>(m_pal, 0u, m_pal.pages.size());
}
m_page = m_pal.pages.size() - 1;
}
ImGui::SameLine();
@ -252,7 +258,7 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
std::ignore = pushCommand<ApplyColorAllPagesCommand>(
m_pal, m_page, m_selectedColorRow);
}
if (!inputFocused && !m_pageRenameDlg.isOpen()) {
if (ig::mainWinHasFocus() && !inputFocused) {
if (!ImGui::IsKeyDown(ImGuiKey_ModAlt)) {
numShortcuts(m_selectedColorRow, largestPage(m_pal));
} else {

View File

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

View File

@ -9,20 +9,23 @@
#include "paletteeditor/paletteeditor-imgui.hpp"
#include "tilesheeteditor/tilesheeteditor-imgui.hpp"
namespace nostalgia::core {
namespace nostalgia::gfx {
static class: public studio::Module {
ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept final {
return {
studio::editorMaker<TileSheetEditorImGui>(ctx, FileExt_ng),
studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}),
studio::editorMaker<PaletteEditorImGui>(ctx, FileExt_npal),
};
}
ox::Vector<ox::UPtr<studio::ItemMaker>> itemMakers(studio::StudioContext&) const noexcept final {
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<core::Palette>>("Palette", "Palettes", FileExt_npal));
out.emplace_back(ox::make<studio::ItemMakerT<TileSheet>>("Tile Sheet", "TileSheets", FileExt_nts));
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;
}
} const mod;

View File

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

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