Compare commits

...

118 Commits

Author SHA1 Message Date
d056323679 [nostalgia,olympic] Remove src as include directory 2023-12-12 20:31:05 -06:00
b10d9b6118 [developer-handbook] Cleanup ordering of Claw section 2023-12-12 20:24:31 -06:00
bd44fcf6ad [nfde] Update minimum CMake version 2023-12-12 20:24:20 -06:00
a1de7fbd8a [olympic,nostalgia] Make Applib an interface library that publicly exports applib.cpp 2023-12-12 20:23:54 -06:00
debeb83119 [glutils] Move glutils to deps 2023-12-11 22:57:59 -06:00
e2545a956b [olympic] Move keel, turbine, and studio to olympic 2023-12-11 22:48:22 -06:00
a60765b338 Use project name in Makefile throughout and pass to pkg-gba 2023-12-11 22:26:20 -06:00
dc233286b4 [nostalgia] Update logo 2023-12-11 22:21:45 -06:00
5b929b8796 [nostalgia] Move Olympic app parameters to NostalgiaProfile library 2023-12-11 22:21:01 -06:00
aea1aabcd7 [nostalgia] Restructure module register guards to behave more like include guards 2023-12-11 22:19:10 -06:00
3b8a9af97b [keel] Remove NostalgiaKeelModules as a dependency of keel 2023-12-11 22:16:16 -06:00
d54853a8b5 [studio/applib] Cleanup 2023-12-10 22:18:48 -06:00
d06412a6fe [nostalgia/tools] Remove old pack.cpp file 2023-12-10 22:16:23 -06:00
937e88ce7a [keel] Add missing file 2023-12-10 22:14:06 -06:00
9a5bdebbd7 [nostalgia] Rename nost-pack to nostalgia-pack 2023-12-10 22:12:02 -06:00
a2361c3fd9 [keel,nostalgia] AppLib-ize nost-pack 2023-12-10 22:10:37 -06:00
d6f0fe0cc8 [studio/applib] Remove separate logger instantiation 2023-12-10 21:35:01 -06:00
e3b2c66d70 [olympic/applib] Change applib run arguments 2023-12-10 21:33:45 -06:00
6dec1bf5ed [olympic/applib] Cleanup unused header 2023-12-10 21:10:35 -06:00
af1f674bc0 [olympic/applib] Move run function to olympic namespace 2023-12-10 21:07:17 -06:00
6a1e2f7566 [olympic/applib] Make applib module loading optional 2023-12-10 20:59:15 -06:00
393259a010 [nostalgia,olympic,studio] Add Olympic applib system, convert Studio to use it 2023-12-10 20:39:08 -06:00
b6b59e77f5 [nostalgia/core/studio] Cleanup TileSheetEditor commands 2023-12-10 17:27:18 -06:00
4a94672fdc [nostalgia/core/studio] Fix some use after move bugs 2023-12-10 17:17:03 -06:00
d22c968561 [nostalgia/core/studio] String hygiene change 2023-12-10 17:13:42 -06:00
79c85c2a33 [turbine] Cleanup 2023-12-10 17:03:58 -06:00
3ac3b7b5e6 [nostalgia,studio] Cleanup 2023-12-10 17:03:51 -06:00
8c9ebbedae [nostalgia,studio] Replace some String returns with StringView 2023-12-10 15:09:51 -06:00
dbd98fe18b [nostalgia/core/studio] Really pedantic formatting change 2023-12-10 02:00:54 -06:00
7418a7126a [nostalgia/core/studio] Restructure core studio for maintainability 2023-12-10 01:50:52 -06:00
d5a1e11ec5 [nostalgia/scene/studio] Fix vertical resizing to crop from bottom of view 2023-12-10 00:16:02 -06:00
f4a93d8419 [glutils] Change frame buffers to just use linear filtering 2023-12-10 00:10:51 -06:00
e923c73c91 [nostalgia/scene/studio] Simplify check for framebuffer resizing 2023-12-09 23:53:34 -06:00
4a9f035014 Disable some annoying clang-tidy warnings 2023-12-09 23:39:03 -06:00
b5ee68c90b [nostalgia/scene/studio] Fix SceneEditorView to work after switching tabs 2023-12-09 23:24:14 -06:00
e906237d76 [nostalgia/core/opengl] Remove debug line 2023-12-09 23:23:39 -06:00
6bcf29b8f2 [nostalgia/core] Cleanup 2023-12-09 23:20:48 -06:00
406388c042 [README] Add libgtk-3-dev to Debian dependency list 2023-12-09 23:20:12 -06:00
371044d63d [nostalgia] Fix scaling of SceneEditorView not to be completely broken 2023-12-09 23:18:04 -06:00
62c671e823 [nostalgia/core] Cleanup on TileSheet 2023-12-09 17:46:16 -06:00
0ac494998f [glutils] Add wrapper function around resizeInitFrameBuffer 2023-12-09 17:13:58 -06:00
500c012713 [nostalgia/core/studio] Cleanup TileSheetEditor constructor 2023-12-09 17:12:04 -06:00
1c4fb80702 Remove debug build from GitLab CI 2023-12-09 15:18:51 -06:00
a4fac4c1d3 [ox/fs] Some cleanup for FileAddress 2023-12-09 15:06:06 -06:00
115941a787 [nostalgia/core/studio] Fix palette selection reversion on undo of palette change 2023-12-09 12:57:16 -06:00
65a179e314 [nostalgia/player] Make error output actually check for error 2023-12-09 11:22:10 -06:00
eed240eacc [ox/mc] Fix test struct model, fix zeroing out of empty vectors in unions 2023-12-09 11:21:27 -06:00
cc7c7ac9d7 [ox/std] Fix more functions to work with UPter custom deleters 2023-12-09 01:33:33 -06:00
9a80196fa6 [nostalgia/core] Make Context definition private 2023-12-09 01:27:31 -06:00
8804819e17 [ox/model] Remove another const_cast 2023-12-09 00:50:14 -06:00
ade6af8698 [ox] Add optional typename to satisfy clangd 2023-12-09 00:49:37 -06:00
cd0958c691 [ox] Cleanup some const_casts 2023-12-09 00:49:03 -06:00
40a3c28fbf [turbine] Remove dead code 2023-12-09 00:32:39 -06:00
def994f406 [turbine/glfw] Enable GLFW_OPENGL_FORWARD_COMPAT on all platforms 2023-12-09 00:18:10 -06:00
e808859e29 [nostalgia/player] Give player a mechanism for reporting failure in release builds 2023-12-09 00:14:30 -06:00
9e9f30fb18 [nostalgia/core] Fix some GL rendering issues 2023-12-09 00:05:14 -06:00
facde6bdce [keel,nostalgia,studio,turbine] Cleanup structure of Turbine 2023-12-09 00:03:31 -06:00
1298051a1a [ox/std] Give UPter alias the other template parameter of UniquePtr 2023-12-08 22:33:36 -06:00
f169c96e78 [ox/claw] Remove ReadClaw from build 2023-12-07 00:15:08 -06:00
1547e8e550 Add OX_NODEBUG to GitLab CI 2023-12-07 00:08:37 -06:00
795b1add64 [nostalgia,studio] Fix includes 2023-12-06 23:59:03 -06:00
db91ea6a63 [glutils,nostalgia] Ptr to ref changes 2023-12-06 23:56:49 -06:00
7e19f45c69 [ox/std] Add SpanView::data() 2023-12-05 22:51:18 -06:00
57ba1caf90 [nostalgia] Cleanup headers 2023-12-05 22:50:03 -06:00
a5bdad448f [nostalgia/core] Cleanup headers, TileSheet versioning 2023-12-05 22:37:22 -06:00
54fcbb1a33 [studio] Adjust size of NewMenu, sort items, rename Quit to Cancel 2023-12-04 21:45:59 -06:00
195fd7a113 [nostalgia,studio] Cleanup, simplify string handling 2023-12-04 21:45:23 -06:00
0d606643f5 [ox/mc,ox/oc] Fix write for ox::Array, cleanup 2023-12-04 21:43:22 -06:00
402f54b3e3 [sample_project] Add ox FileAddress type descriptors 2023-12-04 00:45:59 -06:00
ed5fc079ee [studio/modlib] Fix project data directory in Project 2023-12-04 00:45:31 -06:00
140005799f [glutils,nostalgia/core] Move GlslVersion from GlUtils to Nostalgia Core 2023-12-04 00:40:25 -06:00
7d9a1676e8 [ox/claw] Test cleanup 2023-12-04 00:26:08 -06:00
b61f81abf0 [ox] Make tests more consistent 2023-12-04 00:22:00 -06:00
775efbddc8 [keel] Formatting fixes 2023-12-03 23:49:02 -06:00
1505d7ea37 [keel,nostalgia/tools,studio] Convert some pointers to references 2023-12-03 22:48:30 -06:00
26a2d340d6 [keel,studio] Cleanup string handling 2023-12-03 22:26:25 -06:00
ce514d586c [keel] Cleanup string handling 2023-12-03 22:15:22 -06:00
5cbf789374 [ox/std] Add lastIndexOf(StringView, char) 2023-12-03 22:14:42 -06:00
3f83a254d2 [keel] Fix UUID to path lookups to fail properly 2023-12-03 22:02:00 -06:00
348193ae9e [nostalgia,studio] Cleanup string handling 2023-12-03 22:01:38 -06:00
6b7c002a10 [nostalgia] Style updates 2023-12-03 21:14:20 -06:00
34081a0414 [turbine/gba] Make wake up time static 2023-12-03 20:38:23 -06:00
d23b69ce17 [nostalgia,studio] Cleanup 2023-12-03 19:59:27 -06:00
5717d67462 [nostalgia/core] Cleanup 2023-12-03 19:10:27 -06:00
7666bcc2db [keel,nostalgia] Cleanup pack, move toward further library-ization 2023-12-03 19:09:23 -06:00
8f5173e52a [ox/std] Add CStringView::CStringView(StringLiteral) 2023-12-03 19:06:37 -06:00
9ab3543b32 [ox/std] Rename Result::get to Result::copyTo 2023-12-03 19:03:42 -06:00
d16bbef282 [ox/std] Remove ox_strcpy 2023-12-03 19:03:08 -06:00
a8db357360 [ox/fs] Cleanup unnecessary constructors in FileAddress 2023-12-03 19:02:36 -06:00
566b724d36 [nostalgia] Update to new FileAddress constructor 2023-12-03 10:18:33 -06:00
b13eb0ef70 [ox/fs] Make FileAddress constructor take a StringLiteral 2023-12-03 10:17:24 -06:00
9855a0bcf0 [ox/std] Cleanup 2023-12-02 04:02:42 -06:00
611e2fa7cb [ox/std] Cleanup 2023-12-02 01:13:03 -06:00
95d9aee0cf [ox/std] Cleanup stdlib/non-stdlib specific build path in logging 2023-12-02 00:26:18 -06:00
3de03bf1fd [ox] Make String::String(String const&) explicit 2023-12-01 23:39:40 -06:00
742427584a [keel,nostalgia/core] Remove implicit String::String(String const&) calls 2023-12-01 23:38:59 -06:00
91fd0d0786 Disable GLFW tests, example programs, and docs in build 2023-12-01 23:00:17 -06:00
53262c53c4 [keel] Fix formatting 2023-12-01 22:54:27 -06:00
b212385b17 [studio] Cleanup ItemMaker constructors 2023-12-01 22:54:00 -06:00
453e08497d [keel,nostalgia] Make core calls take Context references instead of pointers 2023-12-01 22:53:21 -06:00
72c130d8a9 [ox/std] Fix Result move constructor, add & and && variants of unwrap 2023-12-01 22:50:25 -06:00
9904399724 [keel,studio,turbine] Finish removing implicit String(const char*) calls 2023-12-01 22:44:24 -06:00
1a1c8ae6cc [ox] Make ox::String::String(const char*) explicit 2023-12-01 22:36:24 -06:00
e9822bf124 [nostalgia,studio] Remove implicit ox::String::String(const char*) calls 2023-12-01 22:35:02 -06:00
644abd7f22 Get rid of separate test stage in gitlab-ci 2023-12-01 01:03:53 -06:00
1e8d8c8b9e [buildcore] Use python3 variable instead of python3 directly 2023-12-01 01:00:58 -06:00
eccb8c4fb3 Make gitlab-ci build release and test with release, debug, and asan 2023-12-01 00:53:51 -06:00
6b3974eb93 [buildcore] Make mypy run with python3 -m 2023-12-01 00:51:23 -06:00
f6058f4e07 Add gitlab-ci file 2023-12-01 00:50:45 -06:00
ecb09930db [turbine/glfw] Partially revert debug change 2023-12-01 00:06:58 -06:00
fc5e63a4d7 [ox/std] Make substr support CStringView, and always return a StringView 2023-11-30 23:15:51 -06:00
232a166833 [keel,nostalgia,studio] Make keel use references in place of a lot of pointers 2023-11-30 23:15:16 -06:00
95ba8eb138 [glutils] Do some cleanup with ox::CStringView 2023-11-30 22:06:03 -06:00
a37df08c19 [keel] Make Context::appName a BasicString<32> to generally avoid allocations while ensuring that Context owns a copy 2023-11-30 21:46:17 -06:00
0fc7e7005c [keel,nostalgia/tools/pack,studio] Cleanup 2023-11-30 21:45:03 -06:00
68a0dd9660 [ox/std] Give Vector MaybeSV in places where it makes sense 2023-11-30 21:28:11 -06:00
d635a954fa [ox/std] Add missing file, add more string types 2023-11-30 21:24:05 -06:00
d0f19fd51d [teagba] Make some globals static 2023-11-30 01:29:53 -06:00
245 changed files with 4044 additions and 3433 deletions

View File

@ -4,10 +4,9 @@ Checks: '-*,
cppcoreguidelines-interfaces-global-init, cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions, cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init, cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing, cppcoreguidelines-slicing,
google-default-arguments, google-default-arguments,
google-explicit-constructor,
google-runtime-operator, google-runtime-operator,
hicpp-exception-baseclass, hicpp-exception-baseclass,
hicpp-multiway-paths-covered, hicpp-multiway-paths-covered,
@ -53,6 +52,7 @@ readability-uniqueptr-delete-release,
readability-use-anyofallof, readability-use-anyofallof,
cert-*, cert-*,
misc-*, misc-*,
-misc-include-cleaner
-misc-use-anonymous-namespace, -misc-use-anonymous-namespace,
readability-duplicate-include, readability-duplicate-include,
-misc-non-private-member-variables-in-classes, -misc-non-private-member-variables-in-classes,

24
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,24 @@
# This file is a template, and might need editing before it works on your project.
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/C++.gitlab-ci.yml
# use the official gcc image, based on debian
# can use versions as well, like gcc:5.2
# see https://hub.docker.com/_/gcc/
image: gcc
build:
stage: build
variables:
OX_NODEBUG: 1
before_script:
- apt update && apt -y install make cmake ninja-build pkg-config xorg-dev libgtk-3-dev python3 python3-mypy
script:
- make purge configure-release test install
- make purge configure-asan test install

View File

@ -65,7 +65,11 @@ if(NOT BUILDCORE_TARGET STREQUAL "gba")
/usr/local/include /usr/local/include
) )
add_subdirectory(deps/glad) add_subdirectory(deps/glad)
set(GLFW_BUILD_EXAMPLES OFF)
set(GLFW_BUILD_TESTS OFF)
set(GLFW_BUILD_DOCS OFF)
add_subdirectory(deps/glfw) add_subdirectory(deps/glfw)
add_subdirectory(deps/glutils)
add_subdirectory(deps/imgui) add_subdirectory(deps/imgui)
add_subdirectory(deps/lodepng) add_subdirectory(deps/lodepng)
add_subdirectory(deps/nfde) add_subdirectory(deps/nfde)

View File

@ -3,29 +3,29 @@ BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) ifeq ($(BC_VAR_OS),darwin)
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/nostalgia-studio.app/Contents/MacOS/nostalgia-studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME}-studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME}-studio
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else else
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/nostalgia-studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME}-studio
MGBA=mgba-qt MGBA=mgba-qt
endif endif
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: run .PHONY: run
run: build run: build
./build/${BC_VAR_CURRENT_BUILD}/bin/nostalgia sample_project ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build
${NOSTALGIA_STUDIO} ${NOSTALGIA_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} nostalgia.gba ${MGBA} ${BC_VAR_PROJECT_NAME}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/nostalgia sample_project ${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}

View File

@ -14,6 +14,7 @@ For Debian (and probably other Linux distros, but the package names will
probably differ), install the following additional packages: probably differ), install the following additional packages:
* pkg-config * pkg-config
* xorg-dev * xorg-dev
* libgtk-3-dev
## Build ## Build

View File

@ -89,7 +89,7 @@ purge:
${BC_CMD_RM_RF} compile_commands.json ${BC_CMD_RM_RF} compile_commands.json
.PHONY: test .PHONY: test
test: build test: build
${BC_CMD_ENVRUN} mypy ${BC_VAR_SCRIPTS} ${BC_CMD_ENVRUN} ${BC_CMD_PY3} -m mypy ${BC_VAR_SCRIPTS}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose .PHONY: test-verbose
test-verbose: build test-verbose: build

10
deps/glutils/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,10 @@
project(GlUtils CXX)
add_subdirectory(src)
install(
DIRECTORY
include/glutils
DESTINATION
include
)

View File

@ -9,14 +9,14 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <ox/std/bounds.hpp> #include <ox/std/bounds.hpp>
#include <ox/std/cstringview.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/size.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
namespace glutils { namespace glutils {
constexpr ox::StringView GlslVersion = "#version 330";
struct Empty { struct Empty {
virtual ~Empty() noexcept = default; virtual ~Empty() noexcept = default;
}; };
@ -151,9 +151,7 @@ class FrameBufferBind {
void bind(const FrameBuffer &fb) noexcept; void bind(const FrameBuffer &fb) noexcept;
ox::Result<GLProgram> buildShaderProgram(const GLchar *vert, const GLchar *frag, const GLchar *geo = nullptr) noexcept; ox::Result<GLProgram> buildShaderProgram(ox::CStringView const&vert, ox::CStringView const&frag, ox::CStringView const&geo = "") noexcept;
ox::Result<GLProgram> buildShaderProgram(const ox::String &vert, const ox::String &frag, const ox::String &geo = "") noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept; glutils::GLVertexArray generateVertexArrayObject() noexcept;
@ -165,7 +163,9 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept;
/** /**
* Resizes a FrameBuffer, and creates if it does not already exist. * Resizes a FrameBuffer, and creates if it does not already exist.
*/ */
void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept; void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
struct BufferSet { struct BufferSet {
glutils::GLVertexArray vao; glutils::GLVertexArray vao;
@ -176,9 +176,9 @@ struct BufferSet {
ox::Vector<GLuint> elements; ox::Vector<GLuint> elements;
}; };
void sendVbo(const BufferSet &bs) noexcept; void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(const BufferSet &bs) noexcept; void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept; void clearScreen() noexcept;

View File

@ -3,19 +3,17 @@ add_library(
glutils.cpp glutils.cpp
) )
target_include_directories(
GlUtils PUBLIC
../include
)
target_link_libraries( target_link_libraries(
GlUtils PUBLIC GlUtils PUBLIC
OxStd OxStd
glad glad
) )
install(
FILES
glutils.hpp
DESTINATION
include/glutils
)
install( install(
TARGETS TARGETS
GlUtils GlUtils

View File

@ -6,7 +6,7 @@
#include <ox/std/bstring.hpp> #include <ox/std/bstring.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include "glutils.hpp" #include "glutils/glutils.hpp"
namespace glutils { namespace glutils {
@ -88,27 +88,23 @@ static ox::Result<GLShader> buildShader(
return shader; return shader;
} }
ox::Result<GLProgram> buildShaderProgram(const GLchar *vert, const GLchar *frag, const GLchar *geo) noexcept { ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo) noexcept {
GLProgram prgm(glCreateProgram()); GLProgram prgm(glCreateProgram());
oxRequire(vs, buildShader(GL_VERTEX_SHADER, vert, "vshad")); oxRequire(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
glAttachShader(prgm, vs); glAttachShader(prgm, vs);
if (geo && ox_strlen(geo) != 0) { if (geo.c_str() && geo.bytes() != 0) {
oxRequire(gs, buildShader(GL_GEOMETRY_SHADER, geo, "gshad")); oxRequire(gs, buildShader(GL_GEOMETRY_SHADER, geo.c_str(), "gshad"));
glAttachShader(prgm, gs); glAttachShader(prgm, gs);
} }
oxRequire(fs, buildShader(GL_FRAGMENT_SHADER, frag, "fshad")); oxRequire(fs, buildShader(GL_FRAGMENT_SHADER, frag.c_str(), "fshad"));
glAttachShader(prgm, fs); glAttachShader(prgm, fs);
glLinkProgram(prgm); glLinkProgram(prgm);
return prgm; return prgm;
} }
ox::Result<GLProgram> buildShaderProgram(
const ox::String &vert,
const ox::String &frag,
const ox::String &geo) noexcept {
return buildShaderProgram(vert.c_str(), frag.c_str(), geo.c_str());
}
GLVertexArray generateVertexArrayObject() noexcept { GLVertexArray generateVertexArrayObject() noexcept {
GLVertexArray vao; GLVertexArray vao;
glGenVertexArrays(1, &vao.id); glGenVertexArrays(1, &vao.id);
@ -133,8 +129,9 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
glGenTextures(1, &fb.color.id); glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
// depth texture // depth texture
glGenRenderbuffers(1, &fb.depth.id); glGenRenderbuffers(1, &fb.depth.id);
@ -150,21 +147,23 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
return fb; return fb;
} }
void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept { void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
if (!*fb) { if (!fb) {
*fb = generateFrameBuffer(width, height); fb = generateFrameBuffer(width, height);
return; return;
} }
width = ox::max(1, width); width = ox::max(1, width);
height = ox::max(1, height); height = ox::max(1, height);
fb->width = width; fb.width = width;
fb->height = height; fb.height = height;
glBindFramebuffer(GL_FRAMEBUFFER, *fb); glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture // color texture
glBindTexture(GL_TEXTURE_2D, fb->color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// depth texture // depth texture
glBindRenderbuffer(GL_RENDERBUFFER, fb->depth); glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// restore primary FB // restore primary FB
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -172,13 +171,17 @@ void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
void sendVbo(const BufferSet &bs) noexcept { void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
resizeInitFrameBuffer(fb, sz.width, sz.height);
}
void sendVbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size()); const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo); glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
} }
void sendEbo(const BufferSet &bs) noexcept { void sendEbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size()); const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.5)
project(nativefiledialog-extended) project(nativefiledialog-extended)
if(NOT MSVC) if(NOT MSVC)

View File

@ -13,7 +13,7 @@ namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept { ClArgs::ClArgs(int argc, const char **args) noexcept {
for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) { for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) {
String arg = args[i]; auto arg = String(args[i]);
if (arg[0] == '-') { if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) { while (arg[0] == '-' && arg.len()) {
arg = arg.substr(1); arg = arg.substr(1);
@ -21,7 +21,7 @@ ClArgs::ClArgs(int argc, const char **args) noexcept {
m_bools[arg] = true; m_bools[arg] = true;
// parse additional arguments // parse additional arguments
if (i < static_cast<unsigned>(argc) && args[i + 1]) { if (i < static_cast<unsigned>(argc) && args[i + 1]) {
String val = args[i + 1]; auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') { if (val.len() && val[i] != '-') {
if (val == "false") { if (val == "false") {
m_bools[arg] = false; m_bools[arg] = false;
@ -37,32 +37,32 @@ ClArgs::ClArgs(int argc, const char **args) noexcept {
} }
} }
bool ClArgs::getBool(ox::CRString arg, bool defaultValue) const noexcept { bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
String ClArgs::getString(ox::CRString arg, const char *defaultValue) const noexcept { String ClArgs::getString(ox::CRStringView arg, const char *defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg); auto [value, err] = m_strings.at(arg);
return !err ? *value : defaultValue; return !err ? ox::String(std::move(*value)) : ox::String(defaultValue);
} }
int ClArgs::getInt(ox::CRString arg, int defaultValue) const noexcept { int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
Result<bool> ClArgs::getBool(ox::CRString arg) const noexcept { Result<bool> ClArgs::getBool(ox::CRStringView arg) const noexcept {
oxRequire(out, m_bools.at(arg)); oxRequire(out, m_bools.at(arg));
return *out; return *out;
} }
Result<String> ClArgs::getString(ox::CRString argName) const noexcept { Result<String> ClArgs::getString(ox::CRStringView argName) const noexcept {
oxRequire(out, m_strings.at(argName)); oxRequire(out, m_strings.at(argName));
return *out; return *out;
} }
Result<int> ClArgs::getInt(ox::CRString arg) const noexcept { Result<int> ClArgs::getInt(ox::CRStringView arg) const noexcept {
oxRequire(out, m_ints.at(arg)); oxRequire(out, m_ints.at(arg));
return *out; return *out;
} }

View File

@ -23,21 +23,21 @@ class ClArgs {
ClArgs(int argc, const char **args) noexcept; ClArgs(int argc, const char **args) noexcept;
[[nodiscard]] [[nodiscard]]
bool getBool(ox::CRString arg, bool defaultValue) const noexcept; bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
[[nodiscard]] [[nodiscard]]
String getString(ox::CRString argName, const char *defaultValue) const noexcept; String getString(ox::CRStringView argName, const char *defaultValue) const noexcept;
[[nodiscard]] [[nodiscard]]
int getInt(ox::CRString arg, int defaultValue) const noexcept; int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
[[nodiscard]] [[nodiscard]]
Result<bool> getBool(ox::CRString arg) const noexcept; Result<bool> getBool(ox::CRStringView arg) const noexcept;
[[nodiscard]] [[nodiscard]]
Result<String> getString(ox::CRString argName) const noexcept; Result<String> getString(ox::CRStringView argName) const noexcept;
Result<int> getInt(ox::CRString arg) const noexcept; Result<int> getInt(ox::CRStringView arg) const noexcept;
}; };

View File

@ -16,16 +16,16 @@ target_link_libraries(
$<$<BOOL:${OX_USE_STDLIB}>:OxOrganicClaw> $<$<BOOL:${OX_USE_STDLIB}>:OxOrganicClaw>
) )
if(OX_USE_STDLIB) #if(OX_USE_STDLIB)
add_executable( # add_executable(
readclaw # readclaw
readclaw.cpp # readclaw.cpp
) # )
target_link_libraries( # target_link_libraries(
readclaw PUBLIC # readclaw PUBLIC
OxClaw # OxClaw
) # )
endif() #endif()
install(TARGETS OxClaw install(TARGETS OxClaw
LIBRARY DESTINATION lib LIBRARY DESTINATION lib

View File

@ -8,11 +8,7 @@
#undef NDEBUG #undef NDEBUG
#include <cassert>
#include <iostream>
#include <map> #include <map>
#include <memory>
#include <string>
#include <ox/claw/format.hpp> #include <ox/claw/format.hpp>
#include <ox/claw/read.hpp> #include <ox/claw/read.hpp>
#include <ox/claw/write.hpp> #include <ox/claw/write.hpp>
@ -107,12 +103,12 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
return OxError(0); return OxError(0);
} }
static std::map<std::string_view, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"ClawHeaderReader", "ClawHeaderReader",
[] { [] {
ox::String hdr = "O1;com.drinkingtea.ox.claw.test.Header;2;"; constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1); auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
@ -124,7 +120,7 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
{ {
"ClawHeaderReader2", "ClawHeaderReader2",
[] { [] {
ox::String hdr = "M2;com.drinkingtea.ox.claw.test.Header2;3;"; constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1); auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
@ -192,14 +188,14 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1; if (argc < 2) {
if (argc > 0) { oxError("Must specify test to run");
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
retval = static_cast<int>(tests[testName]());
} else {
retval = 1;
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
} }
return retval; return -1;
} }

View File

@ -21,7 +21,7 @@ struct TestStruct: public ox::SignalHandler {
} }
}; };
std::map<std::string, std::function<ox::Error()>> tests = { std::map<ox::StringView, std::function<ox::Error()>> tests = {
{ {
"test1", "test1",
[] { [] {
@ -39,12 +39,14 @@ std::map<std::string, std::function<ox::Error()>> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 1) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test returned Error");
return 0;
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
} }
return -1; return -1;
} }

View File

@ -36,13 +36,6 @@ FileAddress::FileAddress(ox::CRStringView path) noexcept {
m_type = FileAddressType::Path; m_type = FileAddressType::Path;
} }
FileAddress::FileAddress(char *path) noexcept {
auto pathSize = ox_strlen(path) + 1;
m_data.path = new char[pathSize];
memcpy(m_data.path, path, pathSize);
m_type = FileAddressType::Path;
}
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept { FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
if (this == &other) { if (this == &other) {
return *this; return *this;

View File

@ -25,7 +25,7 @@ enum class FileAddressType: int8_t {
class FileAddress { class FileAddress {
template<typename T> template<typename T>
friend constexpr Error model(T*, CommonPtrWith<FileAddress> auto*) noexcept; friend constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept;
public: public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress"; static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
@ -59,13 +59,7 @@ class FileAddress {
explicit FileAddress(CRStringView path) noexcept; explicit FileAddress(CRStringView path) noexcept;
template<std::size_t SmallStrSz> constexpr FileAddress(ox::StringLiteral path) noexcept;
explicit FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
}
explicit FileAddress(char *path) noexcept;
explicit constexpr FileAddress(const char *path) noexcept;
constexpr ~FileAddress() noexcept; constexpr ~FileAddress() noexcept;
@ -86,7 +80,6 @@ class FileAddress {
} }
} }
[[nodiscard]]
constexpr Result<uint64_t> getInode() const noexcept { constexpr Result<uint64_t> getInode() const noexcept {
switch (m_type) { switch (m_type) {
case FileAddressType::Inode: case FileAddressType::Inode:
@ -124,8 +117,8 @@ class FileAddress {
}; };
constexpr FileAddress::FileAddress(const char *path) noexcept { constexpr FileAddress::FileAddress(ox::StringLiteral path) noexcept {
m_data.constPath = path; m_data.constPath = path.c_str();
m_type = FileAddressType::ConstPath; m_type = FileAddressType::ConstPath;
} }
@ -133,45 +126,6 @@ constexpr FileAddress::~FileAddress() noexcept {
cleanup(); cleanup();
} }
template<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName;
}
template<>
constexpr const char *getModelTypeName<FileAddress>() noexcept {
return FileAddress::TypeName;
}
template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<FileAddress::Data>());
oxReturnError(io->fieldCString("path", &obj->path));
oxReturnError(io->fieldCString("constPath", &obj->path));
oxReturnError(io->field("inode", &obj->inode));
return OxError(0);
}
template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
oxReturnError(io->template setTypeInfo<FileAddress>());
if constexpr(T::opType() == OpType::Reflect) {
int8_t type = 0;
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, 0)));
} else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(T::opType() == OpType::Write) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return OxError(0);
}
constexpr void FileAddress::cleanup() noexcept { constexpr void FileAddress::cleanup() noexcept {
if (m_type == FileAddressType::Path) { if (m_type == FileAddressType::Path) {
safeDeleteArray(m_data.path); safeDeleteArray(m_data.path);
@ -184,4 +138,43 @@ constexpr void FileAddress::clear() noexcept {
m_type = FileAddressType::None; m_type = FileAddressType::None;
} }
template<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName;
}
template<>
constexpr const char *getModelTypeName<FileAddress>() noexcept {
return FileAddress::TypeName;
}
template<typename T>
constexpr Error model(T *h, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
oxReturnError(h->template setTypeInfo<FileAddress::Data>());
oxReturnError(h->fieldCString("path", &obj->path));
oxReturnError(h->fieldCString("constPath", &obj->path));
oxReturnError(h->field("inode", &obj->inode));
return {};
}
template<typename T>
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
oxReturnError(h->template setTypeInfo<FileAddress>());
if constexpr(T::opType() == OpType::Reflect) {
int8_t type = 0;
oxReturnError(h->field("type", &type));
oxReturnError(h->field("data", UnionView(&fa->m_data, 0)));
} else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(h->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(T::opType() == OpType::Write) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(h->field("type", &type));
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return {};
}
} }

View File

@ -24,7 +24,7 @@ PassThroughFS::PassThroughFS(CRStringView dirPath) {
PassThroughFS::~PassThroughFS() noexcept = default; PassThroughFS::~PassThroughFS() noexcept = default;
String PassThroughFS::basePath() const noexcept { String PassThroughFS::basePath() const noexcept {
return m_path.string().c_str(); return ox::String(m_path.string().c_str());
} }
Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept { Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {

View File

@ -26,11 +26,11 @@ struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
} }
}; };
const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tests = { const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests = {
{ {
{ {
"PtrArith::setSize", "PtrArith::setSize",
[](std::string_view) { [](ox::StringView) {
using BuffPtr_t = uint32_t; using BuffPtr_t = uint32_t;
ox::Vector<char> buff(5 * ox::units::MB); ox::Vector<char> buff(5 * ox::units::MB);
auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size()); auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
@ -57,8 +57,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next1", "PathIterator::next1",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
@ -69,8 +69,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next2", "PathIterator::next2",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/"; auto const path = ox::String("/usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
@ -80,8 +80,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next3", "PathIterator::next3",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/"; auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
@ -90,8 +90,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next4", "PathIterator::next4",
[](std::string_view) { [](ox::StringView) {
ox::String path = "usr/share/charset.gbag"; auto const path = ox::String("usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
@ -102,8 +102,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next5", "PathIterator::next5",
[](std::string_view) { [](ox::StringView) {
ox::String path = "usr/share/"; auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
@ -113,8 +113,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::dirPath", "PathIterator::dirPath",
[] (std::string_view) { [] (ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.dirPath(buff, path.len()) == 0 && ox_strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path"); oxAssert(it.dirPath(buff, path.len()) == 0 && ox_strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
@ -123,8 +123,8 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::fileName", "PathIterator::fileName",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.fileName(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name"); oxAssert(it.fileName(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name");
@ -133,7 +133,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::hasNext", "PathIterator::hasNext",
[](std::string_view) { [](ox::StringView) {
const auto path = "/file1"; const auto path = "/file1";
ox::PathIterator it(path, ox_strlen(path)); ox::PathIterator it(path, ox_strlen(path));
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext"); oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
@ -143,7 +143,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"Ptr::subPtr", "Ptr::subPtr",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500); ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid."); oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");
@ -155,7 +155,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"NodeBuffer::insert", "NodeBuffer::insert",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(list->malloc(50).value.valid(), "NodeBuffer::insert: malloc 1 failed"); oxAssert(list->malloc(50).value.valid(), "NodeBuffer::insert: malloc 1 failed");
@ -168,7 +168,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"FileStore::readWrite", "FileStore::readWrite",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
constexpr auto str1 = "Hello, World!"; constexpr auto str1 = "Hello, World!";
constexpr auto str1Len = ox_strlen(str1) + 1; constexpr auto str1Len = ox_strlen(str1) + 1;
@ -189,7 +189,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"Directory", "Directory",
[](std::string_view) { [](ox::StringView) {
ox::Vector<uint8_t> fsBuff(5000); ox::Vector<uint8_t> fsBuff(5000);
oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed"); oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size()); ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
@ -216,7 +216,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"FileSystem", "FileSystem",
[](std::string_view) { [](ox::StringView) {
ox::Vector<uint8_t> fsBuff(5000); ox::Vector<uint8_t> fsBuff(5000);
oxTrace("ox.fs.test.FileSystem") << "format"; oxTrace("ox.fs.test.FileSystem") << "format";
oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed"); oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
@ -237,16 +237,15 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1; if (argc < 3) {
if (argc > 1) { oxError("Must specify test to run and test argument");
std::string_view testName = args[1];
std::string_view testArg;
if (args[2]) {
testArg = args[2];
} }
if (tests.find(testName) != tests.end()) { ox::StringView const testName = args[1];
retval = static_cast<int>(tests.at(testName)(testArg)); ox::StringView const testArg = args[2] ? args[2] : nullptr;
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(testArg), "Test returned Error");
return 0;
} }
} return -1;
return retval;
} }

View File

@ -67,7 +67,7 @@ static ox::Error run(int argc, const char **argv) noexcept {
return OxError(1); return OxError(1);
} }
const auto fsPath = argv[1]; const auto fsPath = argv[1];
ox::String subCmd = argv[2]; ox::String subCmd(argv[2]);
oxRequire(fs, loadFs(fsPath)); oxRequire(fs, loadFs(fsPath));
if (subCmd == "ls") { if (subCmd == "ls") {
return runLs(fs.get(), argc - 2, argv + 2); return runLs(fs.get(), argc - 2, argv + 2);

View File

@ -276,8 +276,8 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
val->resize(len); val->resize(len);
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());
} }
}
val->resize(0); val->resize(0);
}
++m_field; ++m_field;
return {}; return {};
} else if constexpr(isArray_v<T>) { } else if constexpr(isArray_v<T>) {

View File

@ -45,7 +45,7 @@ struct TestStruct {
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1; int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::String String = ""; ox::String String;
ox::BString<32> BString = ""; ox::BString<32> BString = "";
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5}; ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5};
@ -105,7 +105,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
return OxError(0); return OxError(0);
} }
std::map<ox::String, ox::Error(*)()> tests = { std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"MetalClawWriter", "MetalClawWriter",
@ -460,11 +460,14 @@ std::map<ox::String, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 0) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test failed...");
}
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0; return 0;
} }
return -1;
}

View File

@ -43,39 +43,30 @@ class MetalClawWriter {
constexpr ~MetalClawWriter() noexcept = default; constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept; constexpr Error field(const char*, const int8_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept; constexpr Error field(const char*, const int16_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept; constexpr Error field(const char*, const int32_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept; constexpr Error field(const char*, const int64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept; constexpr Error field(const char*, const uint8_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept; constexpr Error field(const char*, const uint16_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept; constexpr Error field(const char*, const uint32_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept; constexpr Error field(const char*, const uint64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<bool> auto *val) noexcept; constexpr Error field(const char*, const bool *val) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char*, T *val, std::size_t len) noexcept; constexpr Error field(const char*, const T *val, std::size_t len) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept; constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept; constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<std::size_t L>
constexpr Error field(const char*, const BString<L> *val) noexcept; constexpr Error field(const char*, const BString<L> *val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept; constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(const char *name, const char **val) noexcept; constexpr Error fieldCString(const char *name, const char **val) noexcept;
@ -84,20 +75,8 @@ class MetalClawWriter {
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept; constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char**>(val), buffLen);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return fieldCString(name, const_cast<const char**>(val));
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char*>(val), buffLen);
}
template<typename T> template<typename T>
constexpr Error field(const char*, T *val) noexcept; constexpr Error field(const char*, const T *val) noexcept;
template<typename U, bool force = false> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> val) noexcept; constexpr Error field(const char*, UnionView<U, force> val) noexcept;
@ -159,47 +138,47 @@ constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, int unionIdx)
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int8_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint8_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<bool> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
} }
@ -230,18 +209,6 @@ constexpr Error MetalClawWriter<Writer>::field(const char *name, const BString<L
return fieldCString(name, val->data(), val->cap()); return fieldCString(name, val->data(), val->cap());
} }
template<Writer_c Writer>
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept { constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false; bool fieldSet = false;
@ -287,7 +254,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *v
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) { if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size()); return field(nullptr, val->data(), val->size());
} else { } else {
@ -323,7 +290,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force>
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val, std::size_t len) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length // write the length
@ -361,7 +328,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
oxReturnError(handler.setTypeInfo("Map", 0, {}, len * 2)); oxReturnError(handler.setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call // this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error { constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = ox_strlen(key); const auto keyLen = key.len();
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1); memcpy(wkey.get(), key.c_str(), keyLen + 1);
oxReturnError(handler.fieldCString("", wkey.get(), keyLen)); oxReturnError(handler.fieldCString("", wkey.get(), keyLen));
@ -381,12 +348,6 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
return OxError(0); return OxError(0);
} }
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo( constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo(
@ -421,7 +382,7 @@ Result<Buffer> writeMC(Writer_c auto &writer, const auto &val) noexcept {
return {}; return {};
} }
Result<Buffer> writeMC(const auto &val, std::size_t buffReserveSz = 2 * units::KB) noexcept { Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz); Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0); BufferWriter bw(&buff, 0);
oxReturnError(writeMC(bw, val)); oxReturnError(writeMC(bw, val));
@ -429,7 +390,7 @@ Result<Buffer> writeMC(const auto &val, std::size_t buffReserveSz = 2 * units::K
return buff; return buff;
} }
Error writeMC(char *buff, std::size_t buffLen, const auto &val, std::size_t *sizeOut = nullptr) noexcept { Error writeMC(char *buff, std::size_t buffLen, auto const&val, std::size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw(buff, buffLen); CharBuffWriter bw(buff, buffLen);
oxReturnError(writeMC(bw, val)); oxReturnError(writeMC(bw, val));
if (sizeOut) { if (sizeOut) {

View File

@ -209,7 +209,7 @@ constexpr Error TypeDescWriter::field(CRStringView name, UnionView<T, force> val
if (m_type) { if (m_type) {
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, t->typeName); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -238,7 +238,7 @@ template<typename ...Args>
constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept { constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept {
constexpr auto s = ""; constexpr auto s = "";
const auto t = type(s); const auto t = type(s);
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, t->typeName); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return {}; return {};
} }

View File

@ -144,8 +144,6 @@ class ModelValue {
constexpr ModelValue(const ModelValue &other) noexcept; constexpr ModelValue(const ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &&other) noexcept; constexpr ModelValue(ModelValue &&other) noexcept;
template<typename T> template<typename T>
@ -350,7 +348,7 @@ class ModelObject {
constexpr ModelObject(const ModelObject &other) noexcept { constexpr ModelObject(const ModelObject &other) noexcept {
for (const auto &f : other.m_fieldsOrder) { for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value}); auto &field = m_fieldsOrder.emplace_back(new Field{ox::String(f->name), f->value});
m_fields[field->name] = &field->value; m_fields[field->name] = &field->value;
} }
m_type = other.m_type; m_type = other.m_type;
@ -427,7 +425,7 @@ class ModelObject {
return *this; return *this;
} }
for (const auto &f : other.m_fieldsOrder) { for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value}); auto &field = m_fieldsOrder.emplace_back(new Field{ox::String(f->name), f->value});
m_fields[field->name] = &field->value; m_fields[field->name] = &field->value;
} }
m_type = other.m_type; m_type = other.m_type;
@ -450,7 +448,7 @@ class ModelObject {
f = val; f = val;
} }
constexpr Result<const ModelValue*> get(const String &k) const noexcept { constexpr Result<const ModelValue*> get(StringView const&k) const noexcept {
if (m_fields.contains(k)) { if (m_fields.contains(k)) {
return *m_fields.at(k).value; return *m_fields.at(k).value;
} }
@ -464,7 +462,7 @@ class ModelObject {
return {}; return {};
} }
constexpr auto &operator[](const String &k) noexcept { constexpr auto &operator[](StringView const&k) noexcept {
auto [v, err] = m_fields.at(k); auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] { if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str()); oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
@ -528,7 +526,7 @@ class ModelUnion {
public: public:
constexpr ModelUnion(const ModelUnion &other) noexcept { constexpr ModelUnion(const ModelUnion &other) noexcept {
for (auto i = 0; const auto &f : other.m_fieldsOrder) { for (auto i = 0; const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{i, f->name, f->value}); auto &field = m_fieldsOrder.emplace_back(new Field{i, ox::String(f->name), f->value});
m_fields[field->name] = field.get(); m_fields[field->name] = field.get();
++i; ++i;
} }
@ -553,7 +551,7 @@ class ModelUnion {
return UniquePtr<ModelUnion>(new ModelUnion(other)); return UniquePtr<ModelUnion>(new ModelUnion(other));
} }
constexpr auto &operator[](const String &k) noexcept { constexpr auto &operator[](StringView const&k) noexcept {
const auto [v, err] = m_fields.at(k); const auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] { if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str()); oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
@ -588,7 +586,7 @@ class ModelUnion {
} }
[[nodiscard]] [[nodiscard]]
constexpr Result<const ModelValue*> get(const String &k) const noexcept { constexpr Result<const ModelValue*> get(StringView const&k) const noexcept {
oxRequire(t, m_fields.at(k)); oxRequire(t, m_fields.at(k));
return &(*t)->value; return &(*t)->value;
} }
@ -814,9 +812,6 @@ constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
} }
} }
constexpr ModelValue::ModelValue(ModelValue &other) noexcept: ModelValue(const_cast<const ModelValue&>(other)) {
}
constexpr ModelValue::ModelValue(ModelValue &&other) noexcept { constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
m_type = other.m_type; m_type = other.m_type;
switch (m_type) { switch (m_type) {

View File

@ -32,7 +32,7 @@ constexpr auto getModelTypeVersion(TestType2*) noexcept {
return 2; return 2;
} }
std::map<ox::String, ox::Error(*)()> tests = { std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"ModelValue", "ModelValue",
@ -47,6 +47,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
return ox::Error{}; return ox::Error{};
} }
}, },
{ {
"getModelTypeName", "getModelTypeName",
[] { [] {
@ -55,6 +56,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
return ox::Error{}; return ox::Error{};
} }
}, },
{ {
"getModelTypeVersion", "getModelTypeVersion",
[] { [] {
@ -67,11 +69,14 @@ std::map<ox::String, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 0) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test failed...");
}
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0; return 0;
} }
return -1;
}

View File

@ -53,7 +53,7 @@ struct TestStruct {
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1; int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::String String = ""; ox::String String{""};
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
ox::HashMap<ox::String, int> Map; ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
@ -124,7 +124,7 @@ constexpr TestStruct &TestStruct::operator=(TestStruct &&other) noexcept {
return *this; return *this;
} }
const std::map<std::string_view, ox::Error(*)()> tests = { const std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"OrganicClawWriter", "OrganicClawWriter",
@ -354,13 +354,11 @@ int main(int argc, const char **args) {
if (argc < 2) { if (argc < 2) {
oxError("Must specify test to run"); oxError("Must specify test to run");
} }
const auto testName = args[1]; auto const testName = args[1];
ox::Error(*test)(); auto const func = tests.find(testName);
try { if (func != tests.end()) {
test = tests.at(testName); oxAssert(func->second(), "Test returned Error");
} catch (const std::out_of_range&) { return 0;
oxErrorf("Test {} not found", testName);
return 1;
} }
return static_cast<int>(test()); return -1;
} }

View File

@ -26,18 +26,10 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val, in
return OxError(0); return OxError(0);
} }
Error OrganicClawWriter::fieldCString(const char *key, char **val, int len) noexcept {
return fieldCString(key, const_cast<const char**>(val), len);
}
Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) noexcept { Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {}); return fieldCString(key, const_cast<const char**>(val), {});
} }
Error OrganicClawWriter::fieldCString(const char *key, char **val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {});
}
Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept { Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept {
const auto uuidStr = uuid->toString(); const auto uuidStr = uuid->toString();
if (targetValid() && uuidStr.len()) { if (targetValid() && uuidStr.len()) {

View File

@ -36,7 +36,7 @@ class OrganicClawWriter {
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept; explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
Error field(const char *key, CommonPtrWith<int8_t> auto *val) noexcept { Error field(const char *key, const int8_t *val) noexcept {
if (*val) { if (*val) {
value(key) = *val; value(key) = *val;
} }
@ -44,7 +44,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<int16_t> auto *val) noexcept { Error field(const char *key, const int16_t *val) noexcept {
if (*val) { if (*val) {
value(key) = *val; value(key) = *val;
} }
@ -52,7 +52,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<int32_t> auto *val) noexcept { Error field(const char *key, const int32_t *val) noexcept {
if (*val) { if (*val) {
value(key) = *val; value(key) = *val;
} }
@ -60,7 +60,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<int64_t> auto *val) noexcept { Error field(const char *key, const int64_t *val) noexcept {
if (*val) { if (*val) {
value(key) = *val; value(key) = *val;
} }
@ -69,7 +69,7 @@ class OrganicClawWriter {
} }
Error field(const char *key, CommonPtrWith<uint8_t> auto *val) noexcept { Error field(const char *key, const uint8_t *val) noexcept {
if (*val) { if (*val) {
value(key) = *val; value(key) = *val;
} }
@ -77,7 +77,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<uint16_t> auto *val) noexcept { Error field(const char *key, const uint16_t *val) noexcept {
if (targetValid() && *val) { if (targetValid() && *val) {
value(key) = *val; value(key) = *val;
} }
@ -85,7 +85,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<uint32_t> auto *val) noexcept { Error field(const char *key, const uint32_t *val) noexcept {
if (targetValid() && *val) { if (targetValid() && *val) {
value(key) = *val; value(key) = *val;
} }
@ -93,7 +93,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<uint64_t> auto *val) noexcept { Error field(const char *key, const uint64_t *val) noexcept {
if (targetValid() && *val) { if (targetValid() && *val) {
value(key) = *val; value(key) = *val;
} }
@ -101,7 +101,7 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
Error field(const char *key, CommonPtrWith<bool> auto *val) noexcept { Error field(const char *key, const bool *val) noexcept {
if (targetValid() && *val) { if (targetValid() && *val) {
value(key) = *val; value(key) = *val;
} }
@ -109,9 +109,6 @@ class OrganicClawWriter {
return {}; return {};
} }
template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept;
template<typename U, bool force = true> template<typename U, bool force = true>
Error field(const char*, UnionView<U, force> val) noexcept; Error field(const char*, UnionView<U, force> val) noexcept;
@ -134,11 +131,6 @@ class OrganicClawWriter {
return {}; return {};
} }
template<typename T>
Error field(const char *key, HashMap<String, T> *val) noexcept {
return field(key, const_cast<const HashMap<String, T>*>(val));
}
template<std::size_t L> template<std::size_t L>
Error field(const char *key, const BString<L> *val) noexcept { Error field(const char *key, const BString<L> *val) noexcept {
if (targetValid() && val->len()) { if (targetValid() && val->len()) {
@ -148,15 +140,6 @@ class OrganicClawWriter {
return {}; return {};
} }
template<std::size_t L>
Error field(const char *key, BString<L> *val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return {};
}
template<std::size_t L> template<std::size_t L>
Error field(const char *key, const BasicString<L> *val) noexcept { Error field(const char *key, const BasicString<L> *val) noexcept {
if (targetValid() && val->len()) { if (targetValid() && val->len()) {
@ -166,23 +149,17 @@ class OrganicClawWriter {
return OxError(0); return OxError(0);
} }
template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept {
return field(key, const_cast<const BasicString<L>*>(val));
}
Error fieldCString(const char*, const char *const*val, int len) noexcept; Error fieldCString(const char*, const char *const*val, int len) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
Error fieldCString(const char *name, const char *const*val) noexcept; Error fieldCString(const char *name, const char *const*val) noexcept;
Error fieldCString(const char *name, char **val) noexcept;
Error field(const char *key, const UUID *uuid) noexcept; Error field(const char *key, const UUID *uuid) noexcept;
template<typename T> template<typename T>
Error field(const char*, T *val) noexcept; Error field(const char*, const T *val, std::size_t len) noexcept;
template<typename T>
Error field(const char*, const T *val) noexcept;
template<typename T> template<typename T>
constexpr ox::Error setTypeInfo( constexpr ox::Error setTypeInfo(
@ -200,6 +177,7 @@ class OrganicClawWriter {
return {}; return {};
} }
[[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return OpType::Write; return OpType::Write;
} }
@ -216,7 +194,7 @@ class OrganicClawWriter {
}; };
template<typename T> template<typename T>
Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcept { Error OrganicClawWriter::field(const char *key, const T *val, std::size_t len) noexcept {
if (targetValid() && len) { if (targetValid() && len) {
OrganicClawWriter w((Json::Value(Json::arrayValue))); OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface handler{&w}; ModelHandlerInterface handler{&w};
@ -230,7 +208,7 @@ Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcep
} }
template<typename T> template<typename T>
Error OrganicClawWriter::field(const char *key, T *val) noexcept { Error OrganicClawWriter::field(const char *key, const T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) { if constexpr(isVector_v<T> || isArray_v<T>) {
return field(key, val->data(), val->size()); return field(key, val->data(), val->size());
} else if (val && targetValid()) { } else if (val && targetValid()) {

217
deps/ox/src/ox/std/basestringview.hpp vendored Normal file
View File

@ -0,0 +1,217 @@
/*
* Copyright 2015 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "bit.hpp"
#include "cstrops.hpp"
#include "iterator.hpp"
namespace ox::detail {
class BaseStringView {
public:
template<typename RefType = char&, typename PtrType = char*, bool reverse = false>
struct iterator: public Iterator<std::bidirectional_iterator_tag, char> {
private:
PtrType m_t = nullptr;
std::size_t m_offset = 0;
std::size_t m_max = 0;
public:
constexpr iterator() noexcept = default;
constexpr iterator(PtrType t, std::size_t offset, std::size_t max) noexcept {
m_t = t;
m_offset = offset;
m_max = max;
}
[[nodiscard]]
constexpr auto offset() const noexcept {
return m_offset;
}
constexpr iterator operator+(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
} else {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
}
}
constexpr auto operator-(const iterator &other) const noexcept {
if constexpr(reverse) {
return m_offset + other.m_offset;
} else {
return m_offset - other.m_offset;
}
}
constexpr iterator operator-(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
} else {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
}
}
constexpr iterator &operator+=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = max<std::size_t>(m_offset - s, 0);
} else {
m_offset = min(m_offset + s, m_max);
}
return *this;
}
constexpr iterator &operator-=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = min(m_offset + s, m_max);
} else {
m_offset = max<std::size_t>(m_offset - s, 0);
}
return *this;
}
constexpr iterator &operator++() noexcept {
return operator+=(1);
}
constexpr iterator &operator--() noexcept {
return operator-=(1);
}
constexpr RefType operator*() const noexcept {
return m_t[m_offset];
}
constexpr RefType operator[](std::size_t s) const noexcept {
return m_t[s];
}
constexpr bool operator<(const iterator &other) const noexcept {
return m_offset < other.m_offset;
}
constexpr bool operator>(const iterator &other) const noexcept {
return m_offset > other.m_offset;
}
constexpr bool operator<=(const iterator &other) const noexcept {
return m_offset <= other.m_offset;
}
constexpr bool operator>=(const iterator &other) const noexcept {
return m_offset >= other.m_offset;
}
constexpr bool operator==(const iterator &other) const noexcept {
return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max;
}
constexpr bool operator!=(const iterator &other) const noexcept {
return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max;
}
};
private:
const char *m_str = nullptr;
std::size_t m_len = 0;
protected:
constexpr BaseStringView() noexcept = default;
constexpr BaseStringView(BaseStringView const&sv) noexcept = default;
constexpr explicit BaseStringView(std::nullptr_t) noexcept {}
constexpr explicit BaseStringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {}
constexpr explicit BaseStringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {}
public:
[[nodiscard]]
constexpr iterator<const char&, const char*> begin() const noexcept {
return {m_str, 0, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> end() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cbegin() const noexcept {
return {m_str, 0, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cend() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]]
constexpr auto bytes() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto len() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto *data() const noexcept {
return &m_str[0];
}
[[nodiscard]]
constexpr auto &front() const noexcept {
return m_str[0];
}
[[nodiscard]]
constexpr auto &back() const noexcept {
return m_str[m_len - 1];
}
[[nodiscard]]
constexpr auto operator[](std::size_t i) const noexcept {
return m_str[i];
}
protected:
constexpr void set(const char *str, std::size_t len) noexcept {
m_str = str;
m_len = len;
}
};
}

53
deps/ox/src/ox/std/cstringview.hpp vendored Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright 2015 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "basestringview.hpp"
#include "bstring.hpp"
#include "string.hpp"
#include "stringliteral.hpp"
namespace ox {
class CStringView: public detail::BaseStringView {
public:
constexpr CStringView() noexcept = default;
constexpr CStringView(CStringView const&sv) noexcept = default;
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(std::nullptr_t) noexcept {}
constexpr CStringView(const char *str) noexcept: BaseStringView(str) {}
constexpr CStringView(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
}
return *this;
}
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return data();
}
};
}

145
deps/ox/src/ox/std/cstrops.hpp vendored Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright 2015 - 2023 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "types.hpp"
#include "typetraits.hpp"
template<typename T1, typename T2>
constexpr T1 ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (i < maxLen && src[i]) {
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
dest[i] = 0;
return dest;
}
[[nodiscard]]
constexpr auto ox_strnlen(const char *str1, std::size_t maxLen) noexcept {
std::size_t len = 0;
for (; len < maxLen && str1[len]; len++);
return len;
}
template<typename T>
[[nodiscard]]
constexpr auto ox_strlen(T const&str1) noexcept {
std::size_t len = 0;
for (; str1[len]; len++);
return len;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept {
auto retval = 0;
auto i = 0u;
while (str1[i] || str2[i]) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strncmp(T1 const&str1, T2 const&str2, const std::size_t maxLen) noexcept {
auto retval = 0;
std::size_t i = 0;
while (i < maxLen && (str1[i] || str2[i])) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
[[nodiscard]]
constexpr const char *ox_strchr(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i <= maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i < maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
int retval = -1;
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
if (str[i] == character) {
retval = static_cast<int>(i);
}
}
return retval;
}
template<typename Integer, typename T>
constexpr T ox_itoa(Integer v, T str) noexcept {
if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
str[static_cast<std::size_t>(it)] = '-';
it++;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) {
start = 'a';
digit -= 10;
}
str[static_cast<std::size_t>(it)] = static_cast<typename ox::remove_reference<decltype(str[0])>::type>(start + digit);
it++;
}
}
str[static_cast<std::size_t>(it)] = 0;
} else {
// 0 is a special case
str[0] = '0';
str[1] = 0;
}
return str;
}

View File

@ -17,16 +17,9 @@
#define oxOut(...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", __VA_ARGS__) #define oxOut(...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", __VA_ARGS__)
#define oxErr(...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", __VA_ARGS__) #define oxErr(...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", __VA_ARGS__)
#ifdef OX_USE_STDLIB #define oxTracef(ch, fmt, ...) ox::trace::TraceStream(__FILE__, __LINE__, ch, ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
// Non-GCC compilers don't like ##__VA_ARGS__, so use initializer list, which relies on std lib #define oxOutf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#define oxTracef(ch, fmt, ...) ox::trace::TraceStream(__FILE__, __LINE__, ch, ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), {__VA_ARGS__}) #define oxErrf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
#define oxOutf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), {__VA_ARGS__})
#define oxErrf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), {__VA_ARGS__})
#else
#define oxTracef(ch, fmt, ...) ox::trace::TraceStream(__FILE__, __LINE__, ch, ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), ##__VA_ARGS__)
#define oxOutf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stdout", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), ##__VA_ARGS__)
#define oxErrf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "stderr", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), ##__VA_ARGS__)
#endif
#define oxInfo(...) oxTrace("info", __VA_ARGS__) #define oxInfo(...) oxTrace("info", __VA_ARGS__)
#define oxInfof(...) oxTracef("info", __VA_ARGS__) #define oxInfof(...) oxTracef("info", __VA_ARGS__)
@ -35,12 +28,7 @@
#ifndef OX_NODEBUG #ifndef OX_NODEBUG
#define oxDebug(...) ox::trace::OutStream(__FILE__, __LINE__, "debug", __VA_ARGS__) #define oxDebug(...) ox::trace::OutStream(__FILE__, __LINE__, "debug", __VA_ARGS__)
#ifdef OX_USE_STDLIB #define oxDebugf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "debug", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), __VA_ARGS__)
// Non-GCC compilers don't like ##__VA_ARGS__, so use initializer list, which relies on std lib
#define oxDebugf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "debug", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), {__VA_ARGS__})
#else
#define oxDebugf(fmt, ...) ox::trace::OutStream(__FILE__, __LINE__, "debug", ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), ##__VA_ARGS__)
#endif
#else #else
#define oxDebug(...) static_assert(false, "Debug prints were checked in."); #define oxDebug(...) static_assert(false, "Debug prints were checked in.");
#define oxDebugf(...) static_assert(false, "Debug prints were checked in."); #define oxDebugf(...) static_assert(false, "Debug prints were checked in.");

View File

@ -138,16 +138,16 @@ struct [[nodiscard]] Result {
} }
template<typename U> template<typename U>
constexpr Result(const Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) { constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
} }
constexpr Result(const Error &error) noexcept: value(), error(error) { constexpr Result(const Error &error) noexcept: value(), error(error) {
} }
constexpr Result(const type &value, const Error &error = OxError(0)) noexcept: value(const_cast<type&>(value)), error(error) { constexpr Result(const type &value, const Error &error = OxError(0)) noexcept: value(value), error(error) {
} }
constexpr Result(type &&value, const Error &error = OxError(0)) noexcept: value(ox::forward<type>(value)), error(error) { constexpr Result(type &&value, const Error &error = OxError(0)) noexcept: value(std::move(value)), error(error) {
} }
constexpr ~Result() noexcept = default; constexpr ~Result() noexcept = default;
@ -165,12 +165,12 @@ struct [[nodiscard]] Result {
return error == 0; return error == 0;
} }
constexpr Error get(type *val) const noexcept { constexpr Error copyTo(type *val) const noexcept {
*val = value; *val = value;
return error; return error;
} }
constexpr Error get(type *val) noexcept { constexpr Error copyTo(type *val) noexcept {
*val = value; *val = value;
return error; return error;
} }
@ -182,23 +182,44 @@ struct [[nodiscard]] Result {
return error; return error;
} }
constexpr auto &unwrap() noexcept { constexpr T &unwrap() & noexcept {
if (error) { if (error) {
oxPanic(error, "Failed unwrap"); oxPanic(error, "Failed unwrap");
} }
return value; return value;
} }
constexpr auto &unwrapThrow() { constexpr T &&unwrap() && noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return std::move(value);
}
constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap");
}
return value;
}
constexpr T &unwrapThrow() & {
if (error) { if (error) {
throw ox::Exception(error); throw ox::Exception(error);
} }
return value; return value;
} }
constexpr const auto &unwrap() const noexcept { constexpr T &&unwrapThrow() && {
if (error) [[unlikely]] { if (error) {
oxPanic(error, "Failed unwrap"); throw ox::Exception(error);
}
return std::move(value);
}
constexpr T const&unwrapThrow() const & {
if (error) {
throw ox::Exception(error);
} }
return value; return value;
} }

View File

@ -186,7 +186,7 @@ constexpr Fmt<segementCnt> fmtSegments(StringView fmt) noexcept {
template<typename StringType = String, typename ...Args> template<typename StringType = String, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr StringType sfmt(StringView fmt, Args... args) noexcept { constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept {
assert(ox::detail::argCount(fmt) == sizeof...(args)); assert(ox::detail::argCount(fmt) == sizeof...(args));
StringType out; StringType out;
const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt); const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);

View File

@ -18,25 +18,11 @@ namespace ox {
template<typename K, typename T> template<typename K, typename T>
class HashMap { class HashMap {
public:
using key_t = K; using key_t = K;
using value_t = T; using value_t = T;
private: private:
// Maybe StringView. If K (or KK for MaybeSV) is a string type,
// MaybeSV::type/MaybeSV_t is a StringView.
// This avoids creating unnecessary Strings when taking a StringView or C
// string in lookups.
template<typename KK, bool isStr = isOxString_v<KK>>
struct MaybeSV {
using type = KK;
};
template<typename KK>
struct MaybeSV<KK, true> {
using type = ox::StringView;
};
template<typename KK>
using MaybeSV_t = MaybeSV<KK>::type;
struct Pair { struct Pair {
K key = {}; K key = {};
T value{}; T value{};
@ -85,15 +71,9 @@ class HashMap {
constexpr static uint64_t hash(StringView const&) noexcept; constexpr static uint64_t hash(StringView const&) noexcept;
/**
* K is assumed to be a null terminated string.
*/
template<typename KK> template<typename KK>
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const; constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
/**
* K is assumed to be a null terminated string.
*/
template<typename KK> template<typename KK>
constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key); constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key);
@ -124,7 +104,7 @@ constexpr bool HashMap<K, T>::operator==(HashMap const&other) const {
if (m_keys != other.m_keys) { if (m_keys != other.m_keys) {
return false; return false;
} }
for (int i = 0; i < m_keys.size(); i++) { for (int i = 0; i < m_keys.size(); ++i) {
auto &k = m_keys[i]; auto &k = m_keys[i];
if (at(k) != other.at(k)) { if (at(k) != other.at(k)) {
return false; return false;
@ -194,7 +174,7 @@ constexpr void HashMap<K, T>::erase(MaybeSV_t<K> const&k) {
auto h = hash(k) % m_pairs.size(); auto h = hash(k) % m_pairs.size();
while (true) { while (true) {
const auto &p = m_pairs[h]; const auto &p = m_pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) { if (p == nullptr || p->key == k) {
oxIgnoreError(m_pairs.erase(h)); oxIgnoreError(m_pairs.erase(h));
break; break;
} else { } else {
@ -232,7 +212,7 @@ template<typename K, typename T>
constexpr void HashMap<K, T>::expand() { constexpr void HashMap<K, T>::expand() {
Vector<Pair*> r; Vector<Pair*> r;
for (std::size_t i = 0; i < m_keys.size(); ++i) { for (std::size_t i = 0; i < m_keys.size(); ++i) {
auto k = m_keys[i]; K k{m_keys[i]};
access(r, k) = std::move(access(m_pairs, k)); access(r, k) = std::move(access(m_pairs, k));
} }
m_pairs = std::move(r); m_pairs = std::move(r);
@ -264,7 +244,7 @@ constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*
auto h = static_cast<std::size_t>(hash(k) % pairs.size()); auto h = static_cast<std::size_t>(hash(k) % pairs.size());
while (true) { while (true) {
const auto &p = pairs[h]; const auto &p = pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) { if (p == nullptr || p->key == k) {
return p; return p;
} else { } else {
h = (h + 1) % pairs.size(); h = (h + 1) % pairs.size();
@ -278,14 +258,7 @@ constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pa
auto h = static_cast<std::size_t>(hash(k) % pairs.size()); auto h = static_cast<std::size_t>(hash(k) % pairs.size());
while (true) { while (true) {
auto &p = pairs[h]; auto &p = pairs[h];
bool matches = [&] { if (p == nullptr || p->key == k) {
if constexpr (is_integral_v<KK>) {
return p == nullptr || k == p->key;
} else {
return p == nullptr || ox_strcmp(p->key, k) == 0;
}
}();
if (matches) {
return p; return p;
} else { } else {
h = (h + 1) % pairs.size(); h = (h + 1) % pairs.size();

View File

@ -180,7 +180,7 @@ template<typename T, typename Deleter = DefaultDelete>
class UniquePtr { class UniquePtr {
private: private:
T *m_t; T *m_t = nullptr;
public: public:
explicit constexpr UniquePtr(T *t = nullptr) noexcept: m_t(t) { explicit constexpr UniquePtr(T *t = nullptr) noexcept: m_t(t) {
@ -190,8 +190,8 @@ class UniquePtr {
constexpr UniquePtr(const UniquePtr&) = delete; constexpr UniquePtr(const UniquePtr&) = delete;
template<typename U> template<typename U, typename UDeleter>
constexpr UniquePtr(UniquePtr<U> &&other) noexcept { constexpr UniquePtr(UniquePtr<U, UDeleter> &&other) noexcept {
m_t = other.release(); m_t = other.release();
} }
@ -210,25 +210,25 @@ class UniquePtr {
return m_t; return m_t;
} }
template<typename U> template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U> &&other = UniquePtr()) { constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
auto t = m_t; auto t = m_t;
m_t = other.release(); m_t = other.release();
Deleter()(t); Deleter()(t);
} }
constexpr UniquePtr &operator=(const UniquePtr<T> &other) = delete; constexpr UniquePtr &operator=(UniquePtr const&other) = delete;
template<typename U> template<typename U, typename UDeleter>
constexpr UniquePtr &operator=(const UniquePtr<U> &other) = delete; constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> const&other) = delete;
constexpr UniquePtr &operator=(UniquePtr<T> &&other) noexcept { constexpr UniquePtr &operator=(UniquePtr<T> &&other) noexcept {
reset(std::move(other)); reset(std::move(other));
return *this; return *this;
} }
template<typename U> template<typename U, typename UDeleter>
constexpr UniquePtr &operator=(UniquePtr<U> &&other) noexcept { constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> &&other) noexcept {
reset(std::move(other)); reset(std::move(other));
return *this; return *this;
} }
@ -247,8 +247,8 @@ class UniquePtr {
}; };
template<typename T> template<typename T, typename Deleter = DefaultDelete>
using UPtr = UniquePtr<T>; using UPtr = UniquePtr<T, Deleter>;
template<typename T> template<typename T>
constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept { constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {

View File

@ -25,7 +25,7 @@ class SpanView {
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = std::size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false> template<typename RefType = T const&, typename PtrType = T const*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>; using iterator = SpanIterator<T, RefType, PtrType, reverse>;
template<std::size_t sz> template<std::size_t sz>
@ -103,6 +103,11 @@ class SpanView {
return m_items[i]; return m_items[i];
} }
[[nodiscard]]
constexpr T const*data() const noexcept {
return m_items;
}
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept { constexpr std::size_t size() const noexcept {
return m_size; return m_size;

View File

@ -15,6 +15,8 @@
#include "bstring.hpp" #include "bstring.hpp"
#include "byteswap.hpp" #include "byteswap.hpp"
#include "concepts.hpp" #include "concepts.hpp"
#include "cstringview.hpp"
#include "cstrops.hpp"
#include "def.hpp" #include "def.hpp"
#include "defer.hpp" #include "defer.hpp"
#include "defines.hpp" #include "defines.hpp"
@ -37,6 +39,7 @@
#include "stacktrace.hpp" #include "stacktrace.hpp"
#include "stddef.hpp" #include "stddef.hpp"
#include "string.hpp" #include "string.hpp"
#include "stringliteral.hpp"
#include "stringview.hpp" #include "stringview.hpp"
#include "strongint.hpp" #include "strongint.hpp"
#include "strops.hpp" #include "strops.hpp"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,7 +8,7 @@
#pragma once #pragma once
#if defined(OX_USE_STDLIB) #if __has_include(<string>)
#include <string> #include <string>
#endif #endif
@ -32,15 +32,15 @@ class BasicString {
constexpr explicit BasicString(std::size_t cap) noexcept; constexpr explicit BasicString(std::size_t cap) noexcept;
constexpr BasicString(const char *str) noexcept; constexpr explicit BasicString(const char *str) noexcept;
constexpr BasicString(const char8_t *str) noexcept; constexpr explicit BasicString(const char8_t *str) noexcept;
constexpr BasicString(const char *str, std::size_t size) noexcept; constexpr BasicString(const char *str, std::size_t size) noexcept;
constexpr explicit BasicString(CRStringView str) noexcept; constexpr explicit BasicString(CRStringView str) noexcept;
constexpr BasicString(const BasicString&) noexcept; constexpr explicit BasicString(BasicString const&) noexcept;
constexpr BasicString(BasicString&&) noexcept; constexpr BasicString(BasicString&&) noexcept;
@ -130,7 +130,7 @@ class BasicString {
constexpr BasicString &operator+=(StringView src) noexcept; constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(const BasicString &src) noexcept; constexpr BasicString &operator+=(BasicString const&src) noexcept;
constexpr BasicString operator+(const char *str) const noexcept; constexpr BasicString operator+(const char *str) const noexcept;
@ -142,23 +142,23 @@ class BasicString {
constexpr BasicString operator+(CRStringView src) const noexcept; constexpr BasicString operator+(CRStringView src) const noexcept;
constexpr BasicString operator+(const BasicString &src) const noexcept; constexpr BasicString operator+(BasicString const&src) const noexcept;
constexpr bool operator==(const char *other) const noexcept; constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const OxString_c auto &other) const noexcept; constexpr bool operator==(OxString_c auto const&other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept; constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const OxString_c auto &other) const noexcept; constexpr bool operator!=(OxString_c auto const&other) const noexcept;
constexpr bool operator<(const BasicString &other) const noexcept; constexpr bool operator<(BasicString const&other) const noexcept;
constexpr bool operator>(const BasicString &other) const noexcept; constexpr bool operator>(BasicString const&other) const noexcept;
constexpr bool operator<=(const BasicString &other) const noexcept; constexpr bool operator<=(BasicString const&other) const noexcept;
constexpr bool operator>=(const BasicString &other) const noexcept; constexpr bool operator>=(BasicString const&other) const noexcept;
constexpr char operator[](std::size_t i) const noexcept; constexpr char operator[](std::size_t i) const noexcept;
@ -200,7 +200,7 @@ class BasicString {
return c_str(); return c_str();
} }
#ifdef OX_USE_STDLIB #if __has_include(<string>)
[[nodiscard]] [[nodiscard]]
inline std::string toStdString() const { inline std::string toStdString() const {
return c_str(); return c_str();
@ -225,19 +225,14 @@ class BasicString {
constexpr std::size_t bytes() const noexcept; constexpr std::size_t bytes() const noexcept;
private: private:
template<std::size_t OtherSize>
constexpr void set(const BasicString<OtherSize> &src) noexcept;
constexpr void set(CRStringView str) noexcept; constexpr void set(CRStringView str) noexcept;
constexpr void set(const char *str) noexcept;
constexpr void set(const char8_t *str) noexcept; constexpr void set(const char8_t *str) noexcept;
}; };
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString() noexcept { constexpr BasicString<SmallStringSize_v>::BasicString() noexcept {
if (m_buff.size()) { if (!m_buff.empty()) {
m_buff[0] = 0; m_buff[0] = 0;
} else { } else {
m_buff.push_back(0); m_buff.push_back(0);
@ -247,14 +242,14 @@ constexpr BasicString<SmallStringSize_v>::BasicString() noexcept {
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) { constexpr BasicString<SmallStringSize_v>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) {
// GCC complains if you don't do this pretty unnecessary size check // GCC complains if you don't do this pretty unnecessary size check
if (m_buff.size()) { if (!m_buff.empty()) {
m_buff[0] = 0; m_buff[0] = 0;
} }
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept { constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept {
if (m_buff.size()) { if (!m_buff.empty()) {
m_buff[0] = 0; m_buff[0] = 0;
} else { } else {
m_buff.push_back(0); m_buff.push_back(0);
@ -264,7 +259,7 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char8_t *str) noexcept { constexpr BasicString<SmallStringSize_v>::BasicString(const char8_t *str) noexcept {
if (m_buff.size()) { if (!m_buff.empty()) {
m_buff[0] = 0; m_buff[0] = 0;
} else { } else {
m_buff.push_back(0); m_buff.push_back(0);
@ -388,7 +383,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const BasicString &src) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
oxIgnoreError(append(src.c_str(), src.len())); oxIgnoreError(append(src.c_str(), src.len()));
return *this; return *this;
} }
@ -436,7 +431,7 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const BasicString &src) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.len(); const std::size_t strLen = src.len();
const auto currentLen = len(); const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen); BasicString<SmallStringSize_v> cpy(currentLen + strLen);
@ -459,7 +454,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(const OxString_c auto &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return ox::StringView(*this) == ox::StringView(other); return ox::StringView(*this) == ox::StringView(other);
} }
@ -469,27 +464,27 @@ constexpr bool BasicString<SmallStringSize_v>::operator!=(const char *other) con
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator!=(const OxString_c auto &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator!=(OxString_c auto const&other) const noexcept {
return !operator==(other); return !operator==(other);
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator<(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 0; return ox_strcmp(c_str(), other.c_str()) < 0;
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator>(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > 0; return ox_strcmp(c_str(), other.c_str()) > 0;
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<=(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator<=(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 1; return ox_strcmp(c_str(), other.c_str()) < 1;
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>=(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator>=(BasicString const&other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > -1; return ox_strcmp(c_str(), other.c_str()) > -1;
} }
@ -543,31 +538,14 @@ constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
return length; return length;
} }
template<std::size_t SmallStringSize_v>
template<std::size_t OtherSize>
constexpr void BasicString<SmallStringSize_v>::set(const BasicString<OtherSize> &src) noexcept {
std::size_t strBytes = src.bytes();
m_buff.resize(strBytes);
copy_n(src.begin(), strBytes, m_buff.data());
*m_buff.back().value = 0;
}
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(CRStringView str) noexcept { constexpr void BasicString<SmallStringSize_v>::set(CRStringView str) noexcept {
std::size_t strBytes = str.bytes(); std::size_t const strBytes = str.bytes();
m_buff.resize(strBytes + 1); m_buff.resize(strBytes + 1);
copy_n(str.data(), strBytes, m_buff.data()); copy_n(str.data(), strBytes, m_buff.data());
*m_buff.back().value = 0; *m_buff.back().value = 0;
} }
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
m_buff.resize(strBytes);
copy_n(str, strBytes, m_buff.data());
*m_buff.back().value = 0;
}
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept { constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1; std::size_t strBytes = ox_strlen(str) + 1;
@ -581,6 +559,13 @@ extern template class BasicString<8>;
using String = BasicString<8>; using String = BasicString<8>;
using CRString = String const&; using CRString = String const&;
[[nodiscard]]
constexpr ox::String toString(ox::CRStringView sv) noexcept {
return ox::String(sv);
}
template<typename PlatSpec, std::size_t SmallStringSize_v> template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]] [[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept { constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {

View File

@ -41,6 +41,10 @@ class StringLiteral: public detail::BaseStringView {
return *this; return *this;
} }
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return data();
}
}; };

View File

@ -12,12 +12,9 @@
#include <string_view> #include <string_view>
#endif #endif
#include "bit.hpp" #include "basestringview.hpp"
#include "concepts.hpp" #include "cstrops.hpp"
#include "iterator.hpp" #include "writer.hpp"
#include "stringliteral.hpp"
#include "strops.hpp"
#include "vector.hpp"
namespace ox { namespace ox {
@ -89,70 +86,6 @@ constexpr auto operator<=>(CRStringView s1, CRStringView s2) noexcept {
} }
} }
[[nodiscard]]
constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len());
return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0;
}
[[nodiscard]]
constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept {
const auto endingLen = ending.len();
return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0;
}
constexpr std::size_t find(CRStringView str, char search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
if (str[i] == search) {
break;
}
}
return i;
}
constexpr std::size_t find(CRStringView str, CRStringView search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
if (beginsWith(substr(str, i), search)) {
break;
}
}
return i;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, char del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, char del) {
return substr(current, find(current, del) + 1);
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, CRStringView del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, CRStringView del) {
return substr(current, find(current, del) + del.len());
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
constexpr auto write(Writer_c auto &writer, ox::CRStringView sv) noexcept { constexpr auto write(Writer_c auto &writer, ox::CRStringView sv) noexcept {
return writer.write(sv.data(), sv.bytes()); return writer.write(sv.data(), sv.bytes());
} }
@ -163,6 +96,22 @@ constexpr auto toStdStringView(CRStringView sv) noexcept {
} }
#endif #endif
// Maybe StringView. If T is a string type, MaybeType::type/MaybeSV_t is a
// StringView. This avoids creating unnecessary Strings when taking a
// StringView or C string as a function argument.
template<typename T, bool isStr = isOxString_v<T>>
struct MaybeSV {
using type = T;
};
template<typename T>
struct MaybeSV<T, true> {
using type = ox::StringView;
};
template<typename T>
using MaybeSV_t = typename MaybeSV<T>::type;
} }
constexpr ox::Result<int> ox_atoi(ox::CRStringView str) noexcept { constexpr ox::Result<int> ox_atoi(ox::CRStringView str) noexcept {

View File

@ -8,130 +8,19 @@
#pragma once #pragma once
#include "concepts.hpp" #include "cstrops.hpp"
#include "error.hpp" #include "error.hpp"
#include "math.hpp" #include "math.hpp"
#include "stringview.hpp"
#include "types.hpp" #include "types.hpp"
#include "typetraits.hpp" #include "vector.hpp"
#include "writer.hpp" #include "writer.hpp"
template<typename T1, typename T2>
constexpr T1 ox_strcpy(T1 dest, T2 src) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (src[i]) {
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
dest[i] = 0;
return dest;
}
template<typename T1, typename T2>
constexpr T1 ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (i < maxLen && src[i]) {
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
dest[i] = 0;
return dest;
}
[[nodiscard]]
constexpr auto ox_strnlen(const char *str1, std::size_t maxLen) noexcept {
std::size_t len = 0;
for (; len < maxLen && str1[len]; len++);
return len;
}
template<typename T>
[[nodiscard]]
constexpr auto ox_strlen(T str1) noexcept {
std::size_t len = 0;
for (; str1[len]; len++);
return len;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept {
auto retval = 0;
auto i = 0u;
while (str1[i] || str2[i]) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
template<typename T1, typename T2>
[[nodiscard]]
constexpr int ox_strncmp(T1 str1, T2 str2, const std::size_t maxLen) noexcept {
auto retval = 0;
std::size_t i = 0;
while (i < maxLen && (str1[i] || str2[i])) {
if (str1[i] < str2[i]) {
retval = -1;
break;
} else if (str1[i] > str2[i]) {
retval = 1;
break;
}
i++;
}
return retval;
}
[[nodiscard]]
constexpr const char *ox_strchr(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i <= maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
for (std::size_t i = 0; i < maxLen; i++) {
if (str[i] == character) {
return &str[i];
} else if (str[i] == 0) {
return nullptr;
}
}
return nullptr;
}
[[nodiscard]]
constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
int retval = -1;
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
if (str[i] == character) {
retval = static_cast<int>(i);
}
}
return retval;
}
namespace ox { namespace ox {
template<OxString_c Str> template<OxString_c Str>
[[nodiscard]] [[nodiscard]]
constexpr Str substr(Str const&str, std::size_t pos) noexcept { constexpr ox::StringView substr(Str const&str, std::size_t pos) noexcept {
if (str.len() >= pos) { if (str.len() >= pos) {
return Str(str.data() + pos, str.len() - pos); return Str(str.data() + pos, str.len() - pos);
} }
@ -140,7 +29,7 @@ constexpr Str substr(Str const&str, std::size_t pos) noexcept {
template<OxString_c Str> template<OxString_c Str>
[[nodiscard]] [[nodiscard]]
constexpr Str substr(Str const&str, std::size_t start, std::size_t end) noexcept { constexpr ox::StringView substr(Str const&str, std::size_t start, std::size_t end) noexcept {
if (str.len() >= start && end >= start) { if (str.len() >= start && end >= start) {
return Str(str.data() + start, end - start); return Str(str.data() + start, end - start);
} }
@ -179,38 +68,79 @@ constexpr ox::Error itoa(Integer v, ox::Writer_c auto &writer) noexcept {
return {}; return {};
} }
[[nodiscard]]
constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len());
return base.len() >= beginning.len() && ox_strncmp(base.data(), beginning, beginningLen) == 0;
} }
template<typename Integer, typename T> [[nodiscard]]
constexpr T ox_itoa(Integer v, T str) noexcept { constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept {
if (v) { const auto endingLen = ending.len();
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000; return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
str[static_cast<std::size_t>(it)] = '-';
it++;
} }
while (mod) {
auto digit = val / mod; constexpr std::size_t find(CRStringView str, char search) noexcept {
val %= mod; std::size_t i = 0;
mod /= base; for (; i < str.len(); ++i) {
if (it || digit) { if (str[i] == search) {
ox::ResizedInt_t<Integer, 64> start = '0'; break;
if (digit >= 10) {
start = 'a';
digit -= 10;
}
str[static_cast<std::size_t>(it)] = static_cast<typename ox::remove_reference<decltype(str[0])>::type>(start + digit);
it++;
} }
} }
str[static_cast<std::size_t>(it)] = 0; return i;
} else {
// 0 is a special case
str[0] = '0';
str[1] = 0;
} }
return str;
constexpr std::size_t find(CRStringView str, CRStringView search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
if (beginsWith(substr(str, i), search)) {
break;
}
}
return i;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, char del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, char del) {
return substr(current, find(current, del) + 1);
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(CRStringView str, CRStringView del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](CRStringView current, CRStringView del) {
return substr(current, find(current, del) + del.len());
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
}
return out;
}
[[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::CRStringView str, int character) noexcept {
ox::Result<std::size_t> retval = OxError(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) {
retval = static_cast<std::size_t>(i);
}
}
return retval;
}
} }

View File

@ -12,7 +12,7 @@
#include <ox/std/uuid.hpp> #include <ox/std/uuid.hpp>
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
static std::map<ox::String, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
"malloc", "malloc",
[] { [] {
@ -117,6 +117,7 @@ static std::map<ox::String, ox::Error(*)()> tests = {
[] { [] {
ox::Vector<int> v; ox::Vector<int> v;
oxAssert(v.size() == 0, "Initial Vector size not 0"); oxAssert(v.size() == 0, "Initial Vector size not 0");
oxAssert(v.empty(), "Vector::empty() is broken");
auto insertTest = [&v](int val, [[maybe_unused]] std::size_t size) { auto insertTest = [&v](int val, [[maybe_unused]] std::size_t size) {
v.push_back(val); v.push_back(val);
oxReturnError(OxError(v.size() != size, "Vector size incorrect")); oxReturnError(OxError(v.size() != size, "Vector size incorrect"));
@ -172,7 +173,7 @@ static std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(w.write("aoeu", 4), "write failed"); oxAssert(w.write("aoeu", 4), "write failed");
oxExpect(b.size(), 8u); oxExpect(b.size(), 8u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu"); oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu");
ox::StringView qwerty = "qwerty"; ox::StringView constexpr qwerty = "qwerty";
oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed"); oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed");
oxExpect(b.size(), 14u); oxExpect(b.size(), 14u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty"); oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty");
@ -313,12 +314,14 @@ static std::map<ox::String, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 1) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test returned Error");
return 0;
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
} }
return -1; return -1;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -39,10 +39,10 @@ enum class MsgId: char {
struct TraceMsgRcv { struct TraceMsgRcv {
static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg"; static constexpr auto TypeName = "net.drinkingtea.ox.trace.TraceMsg";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
BasicString<50> file = ""; BasicString<50> file{""};
int line = 0; int line = 0;
uint64_t time = 0; uint64_t time = 0;
BasicString<50> ch = ""; BasicString<50> ch{""};
BasicString<100> msg; BasicString<100> msg;
}; };
@ -141,39 +141,22 @@ class OutStream {
m_msg.msg = msg; m_msg.msg = msg;
} }
#ifdef OX_USE_STDLIB
template<std::size_t fmtSegmentCnt, typename ...Args> template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr OutStream(const char *file, int line, const char *ch, detail::Fmt<fmtSegmentCnt> fmtSegments, std::array<detail::FmtArg, fmtSegmentCnt - 1> elements) noexcept { constexpr OutStream(const char *file, int line, const char *ch, detail::Fmt<fmtSegmentCnt> fmtSegments, Args const&...elements) noexcept {
//static_assert(sizeof...(args) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format."); static_assert(sizeof...(elements) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
m_msg.file = file; m_msg.file = file;
m_msg.line = line; m_msg.line = line;
m_msg.ch = ch; m_msg.ch = ch;
const auto &firstSegment = fmtSegments.segments[0]; const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(m_msg.msg.append(firstSegment.str, firstSegment.length)); oxIgnoreError(m_msg.msg.append(firstSegment.str, firstSegment.length));
//const detail::FmtArg elements[sizeof...(args)] = {args...}; //const detail::FmtArg elements[sizeof...(args)] = {args...};
for (size_t i = 0; i < fmtSegments.size - 1; ++i) { for (size_t i = 0; auto const&e : std::initializer_list<detail::FmtArg>{elements...}) {
m_msg.msg += elements[i].out; m_msg.msg += e.out;
const auto &s = fmtSegments.segments[i + 1]; const auto &s = fmtSegments.segments[i + 1];
oxIgnoreError(m_msg.msg.append(s.str, s.length)); oxIgnoreError(m_msg.msg.append(s.str, s.length));
++i;
} }
} }
#else
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr OutStream(const char *file, int line, const char *ch, detail::Fmt<fmtSegmentCnt> fmtSegments, Args... args) noexcept {
//static_assert(sizeof...(args) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(m_msg.msg.append(firstSegment.str, firstSegment.length));
const detail::FmtArg elements[sizeof...(args)] = {args...};
for (auto i = 0u; i < fmtSegments.size - 1; ++i) {
m_msg.msg += elements[i].out;
const auto &s = fmtSegments.segments[i + 1];
oxIgnoreError(m_msg.msg.append(s.str, s.length));
}
}
#endif
inline ~OutStream() noexcept { inline ~OutStream() noexcept {
oxTraceHook(m_msg.file, m_msg.line, m_msg.ch, m_msg.msg.c_str()); oxTraceHook(m_msg.file, m_msg.line, m_msg.ch, m_msg.msg.c_str());
@ -257,15 +240,10 @@ class NullStream {
constexpr NullStream(const char*, int, const char*, const char* = "") noexcept { constexpr NullStream(const char*, int, const char*, const char* = "") noexcept {
} }
#ifdef OX_USE_STDLIB
template<std::size_t fmtSegmentCnt, typename ...Args> template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr NullStream(const char*, int, const char*, detail::Fmt<fmtSegmentCnt>, std::array<detail::FmtArg, fmtSegmentCnt - 1>) noexcept { constexpr NullStream(const char*, int, const char*, detail::Fmt<fmtSegmentCnt>, Args const&...elements) noexcept {
static_assert(sizeof...(elements) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
} }
#else
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr NullStream(const char*, int, const char*, detail::Fmt<fmtSegmentCnt>, Args...) noexcept {
}
#endif
template<typename T> template<typename T>
constexpr const NullStream &operator<<(const T&) const noexcept { constexpr const NullStream &operator<<(const T&) const noexcept {

View File

@ -273,6 +273,7 @@ template<std::size_t SmallStringSize>
class BasicString; class BasicString;
template<std::size_t sz> template<std::size_t sz>
class BString; class BString;
class CStringView;
class StringLiteral; class StringLiteral;
class StringView; class StringView;
@ -292,6 +293,10 @@ constexpr auto isOxString(const BString<sz>*) noexcept {
return true; return true;
} }
constexpr auto isOxString(const CStringView*) noexcept {
return true;
}
constexpr auto isOxString(const StringLiteral*) noexcept { constexpr auto isOxString(const StringLiteral*) noexcept {
return true; return true;
} }

View File

@ -16,7 +16,7 @@
#include "iterator.hpp" #include "iterator.hpp"
#include "math.hpp" #include "math.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "new.hpp" #include "stringview.hpp"
#include "types.hpp" #include "types.hpp"
#include "utility.hpp" #include "utility.hpp"
@ -254,12 +254,12 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
} }
[[nodiscard]] [[nodiscard]]
constexpr bool contains(const T&) const noexcept(useNoexcept); constexpr bool contains(MaybeSV_t<T> const&) const noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert( constexpr iterator<T&, T*, false> insert(
std::size_t pos, std::size_t cnt, const T &val) noexcept(useNoexcept); std::size_t pos, std::size_t cnt, MaybeSV_t<T> const&val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, const T &val) noexcept(useNoexcept); constexpr iterator<T&, T*, false> insert(std::size_t pos, MaybeSV_t<T> const&val) noexcept(useNoexcept);
template<typename... Args> template<typename... Args>
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept); constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept);
@ -267,7 +267,9 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(const T &item) noexcept(useNoexcept); constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void push_back(MaybeSV_t<T> const&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept); constexpr void pop_back() noexcept(useNoexcept);
@ -484,7 +486,7 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(const T &v) const noexcept(useNoexcept) { constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeSV_t<T> const&v) const noexcept(useNoexcept) {
for (std::size_t i = 0; i < m_size; i++) { for (std::size_t i = 0; i < m_size; i++) {
if (m_items[i] == v) { if (m_items[i] == v) {
return true; return true;
@ -496,7 +498,7 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(const T &v) const
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert( Vector<T, SmallVectorSize, Allocator>::insert(
std::size_t pos, std::size_t cnt, const T &val) noexcept(useNoexcept) { std::size_t pos, std::size_t cnt, MaybeSV_t<T> const&val) noexcept(useNoexcept) {
if (m_size + cnt > m_cap) { if (m_size + cnt > m_cap) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt); reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
if (pos < m_size) { if (pos < m_size) {
@ -524,7 +526,7 @@ Vector<T, SmallVectorSize, Allocator>::insert(
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, const T &val) noexcept(useNoexcept) { Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, MaybeSV_t<T> const&val) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos); reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) { if (pos < m_size) {
@ -581,7 +583,16 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(const T &item) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], std::move(item));
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(MaybeSV_t<T> const&item) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
} }

View File

@ -36,9 +36,6 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
}; };
extern volatile uint16_t g_spriteUpdates;
extern ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept; void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
void applySpriteUpdates() noexcept; void applySpriteUpdates() noexcept;

View File

@ -10,8 +10,8 @@
namespace teagba { namespace teagba {
volatile uint16_t g_spriteUpdates = 0; static volatile uint16_t g_spriteUpdates = 0;
ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer; static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept { void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
// block until g_spriteUpdates is less than buffer len // block until g_spriteUpdates is less than buffer len

View File

@ -485,17 +485,14 @@ implements a superset of JSON.
OrganicClaw requires support for 64 bit integers, whereas normal JSON OrganicClaw requires support for 64 bit integers, whereas normal JSON
technically does not. technically does not.
These formats do not currently support floats.
There is also a wrapper format called Claw that provides a header at the There is also a wrapper format called Claw that provides a header at the
beginning of the file and can dynamically switch between the two depending on beginning of the file and can dynamically switch between the two depending on
what the header says is present. what the header says is present.
The Claw header also includes information about the type and type version of The Claw header also includes information about the type and type version of
the data. the data.
Except when the data is exported for loading on the GBA, Claw is always used as
a wrapper around the bare formats.
These formats do not currently support ```float```s.
Claw header: ```M1;net.drinkingtea.nostalgia.core.NostalgiaPalette;1;``` Claw header: ```M1;net.drinkingtea.nostalgia.core.NostalgiaPalette;1;```
That reads: That reads:
@ -504,6 +501,9 @@ That reads:
* Type ID is net.drinkingtea.nostalgia.core.NostalgiaPalette * Type ID is net.drinkingtea.nostalgia.core.NostalgiaPalette
* Type version is 1 * Type version is 1
Except when the data is exported for loading on the GBA, Claw is always used as
a wrapper around the bare formats.
#### Metal Claw Example #### Metal Claw Example
##### Read ##### Read

View File

@ -14,7 +14,6 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
"typeId" : "B.uint64;0" "typeId" : "B.uint64;0"
} }
], ],
"preloadable" : true,
"primitiveType" : 6, "primitiveType" : 6,
"typeName" : "net.drinkingtea.ox.FileAddress.Data", "typeName" : "net.drinkingtea.ox.FileAddress.Data",
"typeVersion" : 1 "typeVersion" : 1

View File

@ -10,7 +10,6 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
"typeId" : "net.drinkingtea.ox.FileAddress.Data" "typeId" : "net.drinkingtea.ox.FileAddress.Data"
} }
], ],
"preloadable" : true,
"primitiveType" : 5, "primitiveType" : 5,
"typeName" : "net.drinkingtea.ox.FileAddress", "typeName" : "net.drinkingtea.ox.FileAddress",
"typeVersion" : 1 "typeVersion" : 1

Binary file not shown.

View File

@ -21,12 +21,13 @@ host_env = f'{os}-{arch}'
with open(".current_build","r") as f: with open(".current_build","r") as f:
current_build = f.readlines()[0] current_build = f.readlines()[0]
project_dir = sys.argv[1]
project_name = sys.argv[2]
bin = f'./build/{host_env}-{current_build}/bin/' bin = f'./build/{host_env}-{current_build}/bin/'
nostalgia_bin = 'build/gba-release/bin/nostalgia.bin' project_bin = f'build/gba-release/bin/{project_name}.bin'
nostalgia_project = sys.argv[1] project_gba = f'{project_name}.gba'
nostalgia_gba = 'nostalgia.gba'
shutil.copyfile(nostalgia_bin, nostalgia_gba) shutil.copyfile(project_bin, project_gba)
subprocess.run([ subprocess.run([
f'{bin}/nost-pack', '-src', nostalgia_project, '-rom-bin', nostalgia_gba]) f'{bin}/{project_name}-pack', '-src', project_dir, '-rom-bin', project_gba])
subprocess.run(['gbafix', nostalgia_gba]) subprocess.run(['gbafix', project_gba])

View File

@ -1,9 +1,2 @@
include_directories(".")
if(TURBINE_BUILD_TYPE STREQUAL "Native")
add_subdirectory(glutils)
add_subdirectory(studio)
endif()
add_subdirectory(keel)
add_subdirectory(nostalgia) add_subdirectory(nostalgia)
add_subdirectory(turbine) add_subdirectory(olympic)

View File

@ -1,47 +0,0 @@
add_library(
Keel
asset.cpp
keel.cpp
media.cpp
module.cpp
pack.cpp
typeconv.cpp
typestore.cpp
)
target_link_libraries(
Keel PUBLIC
OxClaw
OxEvent
OxFS
OxModel
OxPreloader
)
install(
FILES
asset.hpp
assetmanager.hpp
context.hpp
keel.hpp
media.hpp
module.hpp
pack.hpp
typeconv.hpp
typestore.hpp
DESTINATION
include/keel
)
install(
TARGETS
Keel
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(TURBINE_BUILD_TYPE STREQUAL "Native")
add_subdirectory(test)
endif()

View File

@ -3,7 +3,6 @@
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(scene) add_subdirectory(scene)
# module libraries # module libraries
# Keel # Keel
@ -43,3 +42,11 @@ if(TURBINE_BUILD_TYPE STREQUAL "Native")
include/nostalgia/modules include/nostalgia/modules
) )
endif() endif()
add_library(NostalgiaProfile INTERFACE)
target_compile_definitions(
NostalgiaProfile INTERFACE
OLYMPIC_PROJECT_NAME="Nostalgia"
OLYMPIC_PROJECT_NAMESPACE=nostalgia
OLYMPIC_PROJECT_DATADIR=".nostalgia"
)

View File

@ -5,9 +5,6 @@
#pragma once #pragma once
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/point.hpp>
#include "context.hpp"
namespace nostalgia::core { namespace nostalgia::core {

View File

@ -15,19 +15,15 @@
namespace nostalgia::core { namespace nostalgia::core {
// User Input Output class Context;
class Context {
public:
Context() noexcept = default;
Context(Context &other) noexcept = delete;
Context(const Context &other) noexcept = delete;
Context(const Context &&other) noexcept = delete;
virtual ~Context() noexcept = default;
struct ContextDeleter {
void operator()(Context *p) noexcept;
}; };
ox::Result<ox::UniquePtr<Context>> init(turbine::Context *tctx, const InitParams& = {}) noexcept; using ContextUPtr = ox::UPtr<Context, ContextDeleter>;
ox::Result<ContextUPtr> init(turbine::Context &tctx, InitParams const&params = {}) noexcept;
} }

View File

@ -36,48 +36,56 @@ oxModelBegin(Sprite)
oxModelEnd() oxModelEnd()
[[nodiscard]] [[nodiscard]]
uint8_t bgStatus(Context *ctx) noexcept; uint8_t bgStatus(Context &ctx) noexcept;
void setBgStatus(Context *ctx, uint32_t status) noexcept; void setBgStatus(Context &ctx, uint32_t status) noexcept;
bool bgStatus(Context *ctx, unsigned bg) noexcept; bool bgStatus(Context &ctx, unsigned bg) noexcept;
void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept; void setBgStatus(Context &ctx, unsigned bg, bool status) noexcept;
void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept; void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept;
/** /**
* @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section]) * @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section])
*/ */
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context *ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr = nullptr) noexcept; ox::FileAddress const&paletteAddr = nullptr) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context *ctx, Context &ctx,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept; ox::FileAddress const&paletteAddr) noexcept;
ox::Error initConsole(Context *ctx) noexcept; ox::Error initConsole(Context &ctx) noexcept;
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept; void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept;
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept; void setTile(Context &ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept; void clearTileLayer(Context &ctx, unsigned bgIdx) noexcept;
void hideSprite(Context *ctx, unsigned) noexcept; void hideSprite(Context &ctx, unsigned) noexcept;
void setSprite(Context *ctx, unsigned idx, int x, int y, unsigned tileIdx, void setSprite(Context &ctx, unsigned idx, int x, int y, unsigned tileIdx,
unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept; unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept;
void setSprite(Context *ctx, Sprite const&s) noexcept; void setSprite(Context &ctx, Sprite const&s) noexcept;
} }
namespace nostalgia::core::gl { namespace nostalgia::core::gl {
void drawMainView(core::Context&, ox::Size const&) noexcept;
}
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(core::Context&, int scale = 5) noexcept;
}

View File

@ -8,12 +8,11 @@
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <ox/std/size.hpp> #include <ox/std/size.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/vector.hpp>
#include <ox/model/def.hpp> #include <ox/model/def.hpp>
#include "color.hpp" #include "color.hpp"
#include "context.hpp"
#include "ptidxconv.hpp"
namespace nostalgia::core { namespace nostalgia::core {

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <ox/std/size.hpp> #include <ox/std/size.hpp>
@ -11,10 +12,8 @@
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/model/def.hpp> #include <ox/model/def.hpp>
#include <nostalgia/core/ptidxconv.hpp>
#include "color.hpp"
#include "context.hpp"
#include "ptidxconv.hpp"
#include "palette.hpp" #include "palette.hpp"
namespace nostalgia::core { namespace nostalgia::core {
@ -96,7 +95,7 @@ struct TileSheet {
SubSheet &operator=(SubSheet &&other) noexcept; SubSheet &operator=(SubSheet &&other) noexcept;
[[nodiscard]] [[nodiscard]]
std::size_t idx(const ox::Point &pt) const noexcept; std::size_t idx(ox::Point const&pt) const noexcept;
/** /**
* Reads all pixels of this sheet or its children into the given pixel list * Reads all pixels of this sheet or its children into the given pixel list
@ -160,7 +159,7 @@ struct TileSheet {
void setPixel(int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept; void setPixel(int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept;
void setPixel(int8_t pBpp, const ox::Point &pt, uint8_t palIdx) noexcept; void setPixel(int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(int8_t pBpp, std::size_t cnt) noexcept; ox::Error setPixelCount(int8_t pBpp, std::size_t cnt) noexcept;
@ -175,19 +174,16 @@ struct TileSheet {
/** /**
* Gets the offset in tiles of the desired subsheet. * Gets the offset in tiles of the desired subsheet.
*/ */
[[nodiscard]]
ox::Result<unsigned> getTileOffset( ox::Result<unsigned> getTileOffset(
ox::SpanView<ox::StringView> const&pNamePath, ox::SpanView<ox::StringView> const&pNamePath,
int8_t pBpp, int8_t pBpp,
std::size_t pIt = 0, std::size_t pIt = 0,
unsigned pCurrentTotal = 0) const noexcept; unsigned pCurrentTotal = 0) const noexcept;
[[nodiscard]]
ox::Result<SubSheetId> getIdFor( ox::Result<SubSheetId> getIdFor(
ox::SpanView<ox::StringView> const&pNamePath, ox::SpanView<ox::StringView> const&pNamePath,
std::size_t pIt = 0) const noexcept; std::size_t pIt = 0) const noexcept;
[[nodiscard]]
ox::Result<ox::StringView> getNameFor(SubSheetId pId) const noexcept; ox::Result<ox::StringView> getNameFor(SubSheetId pId) const noexcept;
}; };
@ -200,7 +196,7 @@ struct TileSheet {
SubSheet subsheet{0, "Root", 1, 1, bpp}; SubSheet subsheet{0, "Root", 1, 1, bpp};
constexpr TileSheet() noexcept = default; constexpr TileSheet() noexcept = default;
TileSheet(const TileSheet &other) noexcept = default; TileSheet(TileSheet const&other) noexcept = default;
inline TileSheet(TileSheet &&other) noexcept: inline TileSheet(TileSheet &&other) noexcept:
bpp(other.bpp), bpp(other.bpp),
idIt(other.idIt), idIt(other.idIt),
@ -208,13 +204,13 @@ struct TileSheet {
subsheet(std::move(other.subsheet)) { subsheet(std::move(other.subsheet)) {
} }
TileSheet &operator=(const TileSheet &other) noexcept; TileSheet &operator=(TileSheet const&other) noexcept;
TileSheet &operator=(TileSheet &&other) noexcept; TileSheet &operator=(TileSheet &&other) noexcept;
[[nodiscard]] [[nodiscard]]
SubSheetIdx validateSubSheetIdx( SubSheetIdx validateSubSheetIdx(
const SubSheetIdx &pIdx, SubSheetIdx const&pIdx,
std::size_t pIdxIt, std::size_t pIdxIt,
const SubSheet *pSubsheet) noexcept; const SubSheet *pSubsheet) noexcept;
@ -229,43 +225,43 @@ struct TileSheet {
SubSheetIdx validateSubSheetIdx(const SubSheetIdx &idx) noexcept; SubSheetIdx validateSubSheetIdx(const SubSheetIdx &idx) noexcept;
[[nodiscard]] [[nodiscard]]
static const SubSheet &getSubSheet( static SubSheet const&getSubSheet(
const SubSheetIdx &idx, SubSheetIdx const&idx,
std::size_t idxIt, std::size_t idxIt,
const SubSheet *pSubsheet) noexcept; const SubSheet *pSubsheet) noexcept;
[[nodiscard]] [[nodiscard]]
static SubSheet &getSubSheet( static SubSheet &getSubSheet(
const SubSheetIdx &idx, SubSheetIdx const&idx,
std::size_t idxIt, std::size_t idxIt,
SubSheet *pSubsheet) noexcept; SubSheet *pSubsheet) noexcept;
[[nodiscard]] [[nodiscard]]
const SubSheet &getSubSheet(const SubSheetIdx &idx) const noexcept; const SubSheet &getSubSheet(SubSheetIdx const&idx) const noexcept;
[[nodiscard]] [[nodiscard]]
SubSheet &getSubSheet(const SubSheetIdx &idx) noexcept; SubSheet &getSubSheet(SubSheetIdx const&idx) noexcept;
ox::Error addSubSheet(const SubSheetIdx &idx) noexcept; ox::Error addSubSheet(SubSheetIdx const&idx) noexcept;
[[nodiscard]] [[nodiscard]]
static ox::Error rmSubSheet( static ox::Error rmSubSheet(
const SubSheetIdx &idx, SubSheetIdx const&idx,
std::size_t idxIt, std::size_t idxIt,
SubSheet *pSubsheet) noexcept; SubSheet *pSubsheet) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Error rmSubSheet(const SubSheetIdx &idx) noexcept; ox::Error rmSubSheet(SubSheetIdx const&idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel4Bpp( uint8_t getPixel4Bpp(
const ox::Point &pt, ox::Point const&pt,
const SubSheetIdx &subsheetIdx) const noexcept; SubSheetIdx const&subsheetIdx) const noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel8Bpp( uint8_t getPixel8Bpp(
const ox::Point &pt, ox::Point const&pt,
const SubSheetIdx &subsheetIdx) const noexcept; SubSheetIdx const&subsheetIdx) const noexcept;
ox::Result<SubSheetId> getIdFor(ox::CRStringView path) const noexcept; ox::Result<SubSheetId> getIdFor(ox::CRStringView path) const noexcept;
@ -278,6 +274,8 @@ struct TileSheet {
}; };
using TileSheetV3 = TileSheet;
struct CompactTileSheet { struct CompactTileSheet {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
@ -309,7 +307,7 @@ oxModelBegin(TileSheetV2)
oxModelField(subsheet) oxModelField(subsheet)
oxModelEnd() oxModelEnd()
oxModelBegin(TileSheet::SubSheet) oxModelBegin(TileSheetV3::SubSheet)
oxModelField(name); oxModelField(name);
oxModelField(rows); oxModelField(rows);
oxModelField(columns); oxModelField(columns);
@ -317,7 +315,7 @@ oxModelBegin(TileSheet::SubSheet)
oxModelField(pixels) oxModelField(pixels)
oxModelEnd() oxModelEnd()
oxModelBegin(TileSheet) oxModelBegin(TileSheetV3)
oxModelField(bpp) oxModelField(bpp)
oxModelField(idIt) oxModelField(idIt)
oxModelField(defaultPalette) oxModelField(defaultPalette)

View File

@ -12,6 +12,7 @@ target_link_libraries(
NostalgiaCore-GBA PUBLIC NostalgiaCore-GBA PUBLIC
TeaGBA TeaGBA
Keel Keel
Turbine
) )
if(TURBINE_BUILD_TYPE STREQUAL "GBA") if(TURBINE_BUILD_TYPE STREQUAL "GBA")

View File

@ -8,15 +8,19 @@
namespace nostalgia::core { namespace nostalgia::core {
GbaContext::GbaContext(turbine::Context *tctx) noexcept: turbineCtx(tctx) { void ContextDeleter::operator()(Context *p) noexcept {
ox::safeDelete(p);
} }
ox::Error initGfx(Context *ctx, InitParams const&) noexcept; Context::Context(turbine::Context &tctx) noexcept: turbineCtx(tctx) {
}
ox::Result<ox::UniquePtr<Context>> init(turbine::Context *tctx, InitParams const&params) noexcept { ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
auto ctx = ox::make_unique<GbaContext>(tctx);
oxReturnError(initGfx(ctx.get(), params)); ox::Result<ContextUPtr> init(turbine::Context &tctx, InitParams const&params) noexcept {
return ox::UPtr<Context>(ctx.release()); auto ctx = ox::make_unique<Context>(tctx);
oxReturnError(initGfx(*ctx, params));
return ContextUPtr(std::move(ctx));
} }
} }

View File

@ -8,15 +8,20 @@
namespace nostalgia::core { namespace nostalgia::core {
struct GbaContext: public core::Context { class Context {
turbine::Context const*turbineCtx = nullptr; public:
turbine::Context &turbineCtx;
explicit GbaContext(turbine::Context *tctx) noexcept; explicit Context(turbine::Context &tctx) noexcept;
Context(Context &other) noexcept = delete;
Context(Context const&other) noexcept = delete;
Context(Context const&&other) noexcept = delete;
virtual ~Context() noexcept = default;
[[nodiscard]] [[nodiscard]]
auto const&rom() const noexcept { ox::MemFS const&rom() const noexcept {
return *turbine::rom(*turbineCtx); return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
} }
}; };

View File

@ -71,44 +71,45 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap); return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
} }
ox::Error initGfx(Context*, InitParams const&) noexcept { ox::Error initGfx(Context&, InitParams const&) noexcept {
for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) { for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) {
teagba::bgSetSbb(bgCtl, 28); teagba::bgSetSbb(bgCtl, 28);
} }
return {}; return {};
} }
void shutdownGfx(Context*) noexcept { uint8_t bgStatus(Context&) noexcept {
}
uint8_t bgStatus(Context*) noexcept {
return (REG_DISPCTL >> 8u) & 0b1111u; return (REG_DISPCTL >> 8u) & 0b1111u;
} }
void setBgStatus(Context*, uint32_t status) noexcept { void setBgStatus(Context&, uint32_t status) noexcept {
constexpr auto BgStatus = 8; constexpr auto BgStatus = 8;
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus; REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus;
} }
bool bgStatus(Context*, unsigned bg) noexcept { bool bgStatus(Context&, unsigned bg) noexcept {
return (REG_DISPCTL >> (8 + bg)) & 1; return (REG_DISPCTL >> (8 + bg)) & 1;
} }
void setBgStatus(Context*, unsigned bg, bool status) noexcept { void setBgStatus(Context&, unsigned bg, bool status) noexcept {
constexpr auto Bg0Status = 8; constexpr auto Bg0Status = 8;
const auto mask = static_cast<uint32_t>(status) << (Bg0Status + bg); const auto mask = static_cast<uint32_t>(status) << (Bg0Status + bg);
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask); REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
} }
void setBgCbb(Context*, unsigned bgIdx, unsigned cbb) noexcept { static void setBgCbb(Context*, unsigned bgIdx, unsigned cbb) noexcept {
auto &bgCtl = regBgCtl(bgIdx); auto &bgCtl = regBgCtl(bgIdx);
const auto &cbbData = g_cbbData[cbb]; const auto &cbbData = g_cbbData[cbb];
teagba::bgSetBpp(&bgCtl, cbbData.bpp); teagba::bgSetBpp(&bgCtl, cbbData.bpp);
teagba::bgSetCbb(&bgCtl, cbb); teagba::bgSetCbb(&bgCtl, cbb);
} }
void setBgCbb(Context&, unsigned bgIdx, unsigned cbb) noexcept {
setBgCbb(nullptr, bgIdx, cbb);
}
static ox::Error loadBgTileSheet( static ox::Error loadBgTileSheet(
const ox::MemFS &rom, ox::MemFS const&rom,
unsigned cbb, unsigned cbb,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept { ox::FileAddress const&paletteAddr) noexcept {
@ -136,22 +137,20 @@ static ox::Error loadBgTileSheet(
} }
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context *ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept { ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = static_cast<GbaContext&>(*ctx); auto &rom = ctx.rom();
auto &rom = static_cast<const ox::MemFS&>(gctx.rom());
return loadBgTileSheet(rom, cbb, tilesheetAddr, paletteAddr); return loadBgTileSheet(rom, cbb, tilesheetAddr, paletteAddr);
} }
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context *ctx, Context &ctx,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept { ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = static_cast<GbaContext&>(*ctx); auto &rom = ctx.rom();
auto &rom = static_cast<const ox::MemFS&>(gctx.rom()); oxRequire(tsStat, ctx.rom().stat(tilesheetAddr));
oxRequire(tsStat, gctx.rom().stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr)); oxRequire(ts, rom.directAccess(tilesheetAddr));
GbaTileMapTarget target; GbaTileMapTarget target;
target.pal.palette = MEM_SPRITE_PALETTE; target.pal.palette = MEM_SPRITE_PALETTE;
@ -159,27 +158,25 @@ ox::Error loadSpriteTileSheet(
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target)); oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
// load external palette if available // load external palette if available
if (paletteAddr) { if (paletteAddr) {
oxRequire(palStat, gctx.rom().stat(paletteAddr)); oxRequire(palStat, ctx.rom().stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr)); oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal)); oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
} }
return {}; return {};
} }
ox::Error loadBgPalette(Context *ctx, unsigned, ox::FileAddress const&paletteAddr) noexcept { ox::Error loadBgPalette(Context &ctx, unsigned, ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = static_cast<GbaContext&>(*ctx); auto &rom = ctx.rom();
auto &rom = static_cast<const ox::MemFS&>(gctx.rom());
GbaPaletteTarget target; GbaPaletteTarget target;
target.palette = MEM_BG_PALETTE; target.palette = MEM_BG_PALETTE;
oxRequire(palStat, gctx.rom().stat(paletteAddr)); oxRequire(palStat, ctx.rom().stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr)); oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target)); oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
return {}; return {};
} }
ox::Error loadSpritePalette(Context *ctx, unsigned cbb, ox::FileAddress const&paletteAddr) noexcept { ox::Error loadSpritePalette(Context &ctx, unsigned cbb, ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = static_cast<GbaContext&>(*ctx); auto &rom = ctx.rom();
auto &rom = static_cast<const ox::MemFS&>(gctx.rom());
GbaPaletteTarget target; GbaPaletteTarget target;
target.palette = &MEM_SPRITE_PALETTE[cbb]; target.palette = &MEM_SPRITE_PALETTE[cbb];
oxRequire(palStat, rom.stat(paletteAddr)); oxRequire(palStat, rom.stat(paletteAddr));
@ -188,25 +185,16 @@ ox::Error loadSpritePalette(Context *ctx, unsigned cbb, ox::FileAddress const&pa
return {}; return {};
} }
// Do NOT rely on Context in the GBA version of this function. ox::Error initConsole(Context &ctx) noexcept {
ox::Error initConsole(Context *ctx) noexcept { constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng"); constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001); setBgStatus(ctx, 0b0001);
if (!ctx) {
oxRequire(rom, keel::loadRom());
const ox::FileSystem32 romFs(ox::FileStore32(rom, 32 * ox::units::MB));
oxReturnError(loadBgTileSheet(romFs, 0, TilesheetAddr, PaletteAddr));
setBgCbb(nullptr, 0, 0);
return {};
} else {
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr)); oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr));
setBgCbb(ctx, 0, 0); setBgCbb(ctx, 0, 0);
return {}; return {};
} }
}
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept { void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
const auto col = static_cast<unsigned>(column); const auto col = static_cast<unsigned>(column);
for (auto i = 0u; i < str.bytes(); i++) { for (auto i = 0u; i < str.bytes(); i++) {
const auto c = charMap[static_cast<std::size_t>(str[i])]; const auto c = charMap[static_cast<std::size_t>(str[i])];
@ -214,18 +202,18 @@ void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept {
} }
} }
void setTile(Context*, unsigned bgIdx, int column, int row, uint8_t tile) noexcept { void setTile(Context&, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column); const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
MEM_BG_MAP[bgIdx][tileIdx] = tile; MEM_BG_MAP[bgIdx][tileIdx] = tile;
} }
// Do NOT use Context in the GBA version of this function. // Do NOT use Context in the GBA version of this function.
void clearTileLayer(Context*, unsigned bgIdx) noexcept { void clearTileLayer(Context&, unsigned bgIdx) noexcept {
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns); memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
} }
[[maybe_unused]] [[maybe_unused]]
void hideSprite(Context*, unsigned idx) noexcept { void hideSprite(Context&, unsigned idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::GbaSpriteAttrUpdate oa; teagba::GbaSpriteAttrUpdate oa;
oa.attr0 = 2 << 8; oa.attr0 = 2 << 8;
@ -233,7 +221,7 @@ void hideSprite(Context*, unsigned idx) noexcept {
teagba::addSpriteUpdate(oa); teagba::addSpriteUpdate(oa);
} }
void setSprite(Context*, void setSprite(Context&,
unsigned idx, unsigned idx,
int x, int x,
int y, int y,

View File

@ -7,5 +7,5 @@
#include <nostalgia/core/context.hpp> #include <nostalgia/core/context.hpp>
namespace nostalgia::core { namespace nostalgia::core {
ox::Error initGfx(Context *ctx, InitParams const&) noexcept; ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
} }

View File

@ -3,33 +3,44 @@
*/ */
#include <nostalgia/core/core.hpp> #include <ox/std/def.hpp>
#include <keel/media.hpp>
#include <turbine/turbine.hpp>
#include <teagba/addresses.hpp> #include <teagba/addresses.hpp>
#include <teagba/bios.hpp> #include <teagba/bios.hpp>
#include <teagba/gfx.hpp>
#include <nostalgia/core/core.hpp>
#include "gfx.hpp" #include "gfx.hpp"
#define HEAP_BEGIN (reinterpret_cast<char*>(MEM_EWRAM_BEGIN))
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
#define HEAP_END (reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE))
namespace ox { namespace ox {
using namespace nostalgia::core; using namespace nostalgia::core;
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept { void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
oxIgnoreError(initGfx(nullptr, {})); // reset heap to make sure we have enough memory to allocate context data
oxIgnoreError(initConsole(nullptr)); ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
// enable only BG 0 auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
REG_DISPCTL = teagba::DispCtl_Bg0; auto ctx = init(*tctx).unwrap();
clearTileLayer(nullptr, 0); oxIgnoreError(initGfx(*ctx, {}));
oxIgnoreError(initConsole(*ctx));
setBgStatus(*ctx, 0, true);
clearTileLayer(*ctx, 0);
ox::BString<23> serr = "Error code: "; ox::BString<23> serr = "Error code: ";
serr += static_cast<int64_t>(err); serr += static_cast<int64_t>(err);
puts(nullptr, 32 + 1, 1, "SADNESS..."); puts(*ctx, 32 + 1, 1, "SADNESS...");
puts(nullptr, 32 + 1, 4, "UNEXPECTED STATE:"); puts(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
puts(nullptr, 32 + 2, 6, panicMsg); puts(*ctx, 32 + 2, 6, panicMsg);
if (err) { if (err) {
puts(nullptr, 32 + 2, 8, serr); puts(*ctx, 32 + 2, 8, serr);
} }
puts(nullptr, 32 + 1, 15, "PLEASE RESTART THE SYSTEM"); puts(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
// print to terminal if in mGBA // print to terminal if in mGBA
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) { if (err.msg) {

View File

@ -43,7 +43,7 @@ ox::Array<char, 128> charMap = {
0, // space 0, // space
38, // ! 38, // !
0, // " 0, // "
0, // # 49, // #
0, // $ 0, // $
0, // % 0, // %
0, // & 0, // &
@ -132,12 +132,12 @@ ox::Array<char, 128> charMap = {
25, // y 25, // y
26, // z 26, // z
46, // { 46, // {
0, // | 51, // |
48, // } 48, // }
0, // ~ 50, // ~
}; };
void setSprite(Context *c, const Sprite &s) noexcept { void setSprite(Context &c, Sprite const&s) noexcept {
setSprite(c, s.idx, s.x, s.y, s.tileIdx, s.spriteShape, s.spriteSize, s.flipX); setSprite(c, s.idx, s.x, s.y, s.tileIdx, s.spriteShape, s.spriteSize, s.flipX);
} }

View File

@ -17,14 +17,14 @@ namespace nostalgia::core {
class KeelModule: public keel::Module { class KeelModule: public keel::Module {
private: private:
NostalgiaPaletteToPaletteConverter m_nostalgiaPaletteToPaletteConverter; NostalgiaPaletteToPaletteConverter m_nostalgiaPaletteToPaletteConverter;
TileSheetV1ToTileSheetConverter m_tileSheetV1ToTileSheetV2Converter; TileSheetV1ToTileSheetV2Converter m_tileSheetV1ToTileSheetV2Converter;
TileSheetV2ToTileSheetV3Converter m_tileSheetV2ToTileSheetConverter;
TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter; TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter;
TileSheetV2ToTileSheetConverter m_tileSheetV2ToTileSheetConverter;
public: public:
[[nodiscard]] [[nodiscard]]
ox::String id() const noexcept override { ox::String id() const noexcept override {
return "net.drinkingtea.nostalgia.core"; return ox::String("net.drinkingtea.nostalgia.core");
} }
[[nodiscard]] [[nodiscard]]
@ -52,15 +52,15 @@ class KeelModule: public keel::Module {
ox::Vector<keel::PackTransform> packTransforms() const noexcept final { ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
return { return {
// convert tilesheets to CompactTileSheets // convert tilesheets to CompactTileSheets
[](keel::Context *ctx, ox::Buffer *buff) -> ox::Error { [](keel::Context &ctx, ox::Buffer &buff) -> ox::Error {
oxRequire(hdr, keel::readAssetHeader(*buff)); oxRequire(hdr, keel::readAssetHeader(buff));
const auto typeId = ox::buildTypeId( const auto typeId = ox::buildTypeId(
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams); hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
if (typeId == ox::buildTypeId<TileSheetV1>() || if (typeId == ox::buildTypeId<TileSheetV1>() ||
typeId == ox::buildTypeId<TileSheetV2>() || typeId == ox::buildTypeId<TileSheetV2>() ||
typeId == ox::buildTypeId<TileSheet>()) { typeId == ox::buildTypeId<TileSheet>()) {
oxReturnError(keel::convertBuffToBuff<core::CompactTileSheet>( oxReturnError(keel::convertBuffToBuff<core::CompactTileSheet>(
ctx, *buff, ox::ClawFormat::Metal).moveTo(buff)); ctx, buff, ox::ClawFormat::Metal).moveTo(&buff));
} }
return {}; return {};
}, },

View File

@ -7,60 +7,59 @@
namespace nostalgia::core { namespace nostalgia::core {
ox::Error NostalgiaPaletteToPaletteConverter::convert( ox::Error NostalgiaPaletteToPaletteConverter::convert(
keel::Context*, keel::Context&,
NostalgiaPalette *src, NostalgiaPalette &src,
Palette *dst) const noexcept { Palette &dst) const noexcept {
dst->colors = std::move(src->colors); dst.colors = std::move(src.colors);
return {}; return {};
} }
ox::Error TileSheetV1ToTileSheetConverter::convert( ox::Error TileSheetV1ToTileSheetV2Converter::convert(
keel::Context*, keel::Context&,
TileSheetV1 *src, TileSheetV1 &src,
TileSheet *dst) const noexcept { TileSheetV2 &dst) const noexcept {
dst->bpp = src->bpp; dst.bpp = src.bpp;
dst->defaultPalette = std::move(src->defaultPalette); dst.defaultPalette = std::move(src.defaultPalette);
dst->subsheet.name = "Root"; dst.subsheet.name = "Root";
dst->subsheet.rows = src->rows; dst.subsheet.rows = src.rows;
dst->subsheet.columns = src->columns; dst.subsheet.columns = src.columns;
dst->subsheet.pixels = std::move(src->pixels); dst.subsheet.pixels = std::move(src.pixels);
return {};
}
void TileSheetV2ToTileSheetV3Converter::convertSubsheet(
TileSheetV2::SubSheet &src,
TileSheetV3::SubSheet &dst,
SubSheetId &idIt) noexcept {
dst.id = idIt;
dst.name = std::move(src.name);
dst.columns = src.columns;
dst.rows = src.rows;
dst.pixels = std::move(src.pixels);
++idIt;
dst.subsheets.resize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) {
convertSubsheet(src.subsheets[i], dst.subsheets[i], idIt);
}
}
ox::Error TileSheetV2ToTileSheetV3Converter::convert(
keel::Context&,
TileSheetV2 &src,
TileSheetV3 &dst) const noexcept {
dst.bpp = src.bpp;
dst.defaultPalette = std::move(src.defaultPalette);
convertSubsheet(src.subsheet, dst.subsheet, dst.idIt);
return {}; return {};
} }
ox::Error TileSheetToCompactTileSheetConverter::convert( ox::Error TileSheetToCompactTileSheetConverter::convert(
keel::Context*, keel::Context&,
TileSheet *src, TileSheet &src,
CompactTileSheet *dst) const noexcept { CompactTileSheet &dst) const noexcept {
dst->bpp = src->bpp; dst.bpp = src.bpp;
dst->defaultPalette = std::move(src->defaultPalette); dst.defaultPalette = std::move(src.defaultPalette);
dst->pixels = src->pixels(); dst.pixels = src.pixels();
return {};
}
void TileSheetV2ToTileSheetConverter::convertSubsheet(
TileSheetV2::SubSheet *src,
TileSheet::SubSheet *dst,
SubSheetId *idIt) noexcept {
dst->id = *idIt;
dst->name = std::move(src->name);
dst->columns = src->columns;
dst->rows = src->rows;
dst->pixels = std::move(src->pixels);
++*idIt;
dst->subsheets.resize(src->subsheets.size());
for (auto i = 0u; i < src->subsheets.size(); ++i) {
convertSubsheet(&src->subsheets[i], &dst->subsheets[i], idIt);
}
}
ox::Error TileSheetV2ToTileSheetConverter::convert(
keel::Context*,
TileSheetV2 *src,
TileSheet *dst) const noexcept {
dst->bpp = src->bpp;
dst->defaultPalette = std::move(src->defaultPalette);
convertSubsheet(&src->subsheet, &dst->subsheet, &dst->idIt);
return {}; return {};
} }

View File

@ -17,25 +17,23 @@ namespace nostalgia::core {
// Type converters // Type converters
class NostalgiaPaletteToPaletteConverter: public keel::Converter<NostalgiaPalette, Palette> { class NostalgiaPaletteToPaletteConverter: public keel::Converter<NostalgiaPalette, Palette> {
ox::Error convert(keel::Context*, NostalgiaPalette *src, Palette *dst) const noexcept final; ox::Error convert(keel::Context&, NostalgiaPalette &src, Palette &dst) const noexcept final;
}; };
class TileSheetV1ToTileSheetConverter: public keel::Converter<TileSheetV1, TileSheet> { class TileSheetV1ToTileSheetV2Converter: public keel::Converter<TileSheetV1, TileSheetV2> {
ox::Error convert(keel::Context*, TileSheetV1 *src, TileSheet *dst) const noexcept final; ox::Error convert(keel::Context&, TileSheetV1 &src, TileSheetV2 &dst) const noexcept final;
};
class TileSheetV2ToTileSheetV3Converter: public keel::Converter<TileSheetV2, TileSheetV3> {
static void convertSubsheet(
TileSheetV2::SubSheet &src,
TileSheetV3::SubSheet &dst,
SubSheetId &idIt) noexcept;
ox::Error convert(keel::Context&, TileSheetV2 &src, TileSheetV3 &dst) const noexcept final;
}; };
class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> { class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> {
ox::Error convert(keel::Context*, TileSheet *src, CompactTileSheet *dst) const noexcept final; ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
};
class TileSheetV2ToTileSheetConverter: public keel::Converter<TileSheetV2, TileSheet> {
static void convertSubsheet(
TileSheetV2::SubSheet *src,
TileSheet::SubSheet *dst,
SubSheetId *idIt) noexcept;
ox::Error convert(keel::Context*, TileSheetV2 *src, TileSheet *dst) const noexcept final;
}; };
} }

View File

@ -7,19 +7,23 @@
namespace nostalgia::core { namespace nostalgia::core {
GlContext::GlContext(turbine::Context &tctx) noexcept: void ContextDeleter::operator()(Context *p) noexcept {
ox::safeDelete(p);
}
Context::Context(turbine::Context &tctx) noexcept:
turbineCtx(tctx), turbineCtx(tctx),
drawer(*this) { drawer(*this) {
} }
GlContext::~GlContext() noexcept { Context::~Context() noexcept {
shutdownGfx(*this); shutdownGfx(*this);
} }
ox::Result<ox::UniquePtr<Context>> init(turbine::Context *tctx, InitParams const&params) noexcept { ox::Result<ContextUPtr> init(turbine::Context &tctx, InitParams const&params) noexcept {
auto ctx = ox::make_unique<GlContext>(*tctx); auto ctx = ox::make_unique<Context>(tctx);
oxReturnError(initGfx(ctx.get(), params)); oxReturnError(initGfx(*ctx, params));
return ox::UPtr<Context>(ctx.release()); return ContextUPtr(ctx.release());
} }
} }

View File

@ -15,7 +15,9 @@
namespace nostalgia::core { namespace nostalgia::core {
struct GlContext: public core::Context { class Context {
public:
turbine::Context &turbineCtx; turbine::Context &turbineCtx;
glutils::GLProgram bgShader; glutils::GLProgram bgShader;
glutils::GLProgram spriteShader; glutils::GLProgram spriteShader;
@ -23,10 +25,9 @@ struct GlContext: public core::Context {
renderer::SpriteBlockset spriteBlocks; renderer::SpriteBlockset spriteBlocks;
ox::Array<Sprite, 128> spriteStates; ox::Array<Sprite, 128> spriteStates;
ox::Array<renderer::Background, 4> backgrounds; ox::Array<renderer::Background, 4> backgrounds;
ox::Optional<ox::Size> renderSize;
renderer::Drawer drawer; renderer::Drawer drawer;
explicit GlContext(turbine::Context &tctx) noexcept; explicit Context(turbine::Context &tctx) noexcept;
~GlContext() noexcept override; ~Context() noexcept;
}; };
} }

View File

@ -15,32 +15,25 @@
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/core/tilesheet.hpp>
#include "context.hpp" #include "context.hpp"
#include "gfx.hpp"
namespace nostalgia::core { namespace nostalgia::core {
[[nodiscard]] constexpr auto Scale = 1;
inline GlContext &glctx(Context &ctx) noexcept {
if constexpr(ox::defines::Debug) {
return dynamic_cast<GlContext&>(ctx);
} else {
return static_cast<GlContext&>(ctx);
}
}
constexpr auto Scale = 5;
namespace renderer { namespace renderer {
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {} Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
void Drawer::draw(turbine::Context &tctx) noexcept { void Drawer::draw(turbine::Context &tctx) noexcept {
core::gl::drawMainView(m_ctx, turbine::getScreenSize(tctx)); core::gl::draw(m_ctx, turbine::getScreenSize(tctx));
} }
constexpr ox::StringView bgvshadTmpl = R"( constexpr ox::StringView bgvshadTmpl = R"glsl(
{} {}
in vec2 vTexCoord; in vec2 vTexCoord;
in vec2 vPosition; in vec2 vPosition;
in float vTileIdx;
out vec2 fTexCoord; out vec2 fTexCoord;
uniform float vXScale; uniform float vXScale;
uniform float vTileHeight; uniform float vTileHeight;
@ -49,10 +42,12 @@ constexpr ox::StringView bgvshadTmpl = R"(
gl_Position = vec4( gl_Position = vec4(
vPosition.x * vXScale - xScaleInvert, vPosition.y, vPosition.x * vXScale - xScaleInvert, vPosition.y,
0.0, 1.0); 0.0, 1.0);
fTexCoord = vTexCoord; fTexCoord = vec2(
})"; vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
})glsl";
constexpr ox::StringView bgfshadTmpl = R"( constexpr ox::StringView bgfshadTmpl = R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in vec2 fTexCoord; in vec2 fTexCoord;
@ -68,21 +63,11 @@ constexpr ox::StringView bgfshadTmpl = R"(
void main() { void main() {
pixelSz = vec2(1, 1) / (fSrcImgSz); pixelSz = vec2(1, 1) / (fSrcImgSz);
vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz; vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz;
vec4 c0 = getColor(pixelCoord + pixelSz * vec2(0, 0));
vec4 c1 = getColor(pixelCoord + pixelSz * vec2(0.75, 0));
vec4 c2 = getColor(pixelCoord + pixelSz * vec2(0, 0.75));
vec4 c3 = getColor(pixelCoord + pixelSz * vec2(0.75, 0.75));
float u = fTexCoord.x - fTexCoord.x / pixelSz.x;
float v = fTexCoord.y - fTexCoord.y / pixelSz.y;
vec4 b0 = (1.0 - u) * c0 + u * c1;
vec4 b1 = (1.0 - u) * c2 + u * c3;
outColor = (1.0 - v) * b0 + u * b1;
outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)]; outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)];
//outColor = fPalette[int(texture(image, pixelCoord).rgb.r * 256)];
//outColor = vec4(0.0, 0.7, 1.0, 1.0); //outColor = vec4(0.0, 0.7, 1.0, 1.0);
})"; })glsl";
constexpr ox::StringView spritevshadTmpl = R"( constexpr ox::StringView spritevshadTmpl = R"glsl(
{} {}
in float vEnabled; in float vEnabled;
in vec2 vTexCoord; in vec2 vTexCoord;
@ -96,7 +81,7 @@ constexpr ox::StringView spritevshadTmpl = R"(
vPosition.x * vXScale - xScaleInvert, vPosition.y, vPosition.x * vXScale - xScaleInvert, vPosition.y,
0.0, 1.0); 0.0, 1.0);
fTexCoord = vTexCoord * vec2(1, vTileHeight) * vec2(vEnabled, vEnabled); fTexCoord = vTexCoord * vec2(1, vTileHeight) * vec2(vEnabled, vEnabled);
})"; })glsl";
constexpr ox::StringView spritefshadTmpl = bgfshadTmpl; constexpr ox::StringView spritefshadTmpl = bgfshadTmpl;
@ -142,8 +127,7 @@ static void setTileBufferObject(
uint_t vi, uint_t vi,
float x, float x,
float y, float y,
float textureYOffset, float textureTileIdx,
float tileHeight,
float *vbo, float *vbo,
GLuint *ebo) noexcept { GLuint *ebo) noexcept {
// don't worry, this memcpy gets optimized to something much more ideal // don't worry, this memcpy gets optimized to something much more ideal
@ -153,14 +137,14 @@ static void setTileBufferObject(
y *= -ymod; y *= -ymod;
x -= 1.0f; x -= 1.0f;
y += 1.0f - ymod; y += 1.0f - ymod;
const ox::Array<float, BgVertexVboLength> vertices { ox::Array<float, BgVertexVboLength> const vertices {
x, y, 0, tileHeight + textureYOffset, // bottom left x, y, 0, 1, textureTileIdx, // bottom left
x + xmod, y, 1, tileHeight + textureYOffset, // bottom right x + xmod, y, 1, 1, textureTileIdx, // bottom right
x + xmod, y + ymod, 1, 0 + textureYOffset, // top right x + xmod, y + ymod, 1, 0, textureTileIdx, // top right
x, y + ymod, 0, 0 + textureYOffset, // top left x, y + ymod, 0, 0, textureTileIdx, // top left
}; };
memcpy(vbo, vertices.data(), sizeof(vertices)); memcpy(vbo, vertices.data(), sizeof(vertices));
const ox::Array<GLuint, BgVertexEboLength> elms { ox::Array<GLuint, BgVertexEboLength> const elms {
vi + 0, vi + 1, vi + 2, vi + 0, vi + 1, vi + 2,
vi + 2, vi + 3, vi + 0, vi + 2, vi + 3, vi + 0,
}; };
@ -186,7 +170,6 @@ static void initBackgroundBufferObjects(glutils::BufferSet &bg) noexcept {
static_cast<float>(x), static_cast<float>(x),
static_cast<float>(y), static_cast<float>(y),
0, 0,
0,
vbo, vbo,
ebo); ebo);
} }
@ -236,11 +219,16 @@ static void initBackgroundBufferset(
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord")); auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
glEnableVertexAttribArray(texCoordAttr); glEnableVertexAttribArray(texCoordAttr);
glVertexAttribPointer( glVertexAttribPointer(
texCoordAttr, 2, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(bg.vertices[0]), texCoordAttr, 2, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float),
reinterpret_cast<void*>(2 * sizeof(bg.vertices[0]))); reinterpret_cast<void*>(2 * sizeof(float)));
auto const heightMultAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTileIdx"));
glEnableVertexAttribArray(heightMultAttr);
glVertexAttribPointer(
heightMultAttr, 1, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float)));
} }
static glutils::GLTexture loadTexture( static glutils::GLTexture createTexture(
GLsizei w, GLsizei w,
GLsizei h, GLsizei h,
const void *pixels) noexcept { const void *pixels) noexcept {
@ -252,8 +240,8 @@ static glutils::GLTexture loadTexture(
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex.id); glBindTexture(GL_TEXTURE_2D, tex.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return tex; return tex;
@ -270,20 +258,20 @@ static void drawBackground(CBB &cbb) noexcept {
} }
static void drawBackgrounds( static void drawBackgrounds(
GlContext &gctx, Context &ctx,
ox::Size const&renderSz) noexcept { ox::Size const&renderSz) noexcept {
// load background shader and its uniforms // load background shader and its uniforms
glUseProgram(gctx.bgShader); glUseProgram(ctx.bgShader);
const auto uniformSrcImgSz = glGetUniformLocation(gctx.bgShader, "fSrcImgSz"); const auto uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz");
const auto uniformXScale = static_cast<GLint>(glGetUniformLocation(gctx.bgShader, "vXScale")); const auto uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale"));
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(gctx.bgShader, "vTileHeight")); const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight"));
const auto [wi, hi] = renderSz; const auto [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi); const auto wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi); const auto hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf); glUniform1f(uniformXScale, hf / wf);
for (const auto &bg : gctx.backgrounds) { for (const auto &bg : ctx.backgrounds) {
if (bg.enabled) { if (bg.enabled) {
auto &cbb = gctx.cbbs[bg.cbbIdx]; auto &cbb = ctx.cbbs[bg.cbbIdx];
const auto tileRows = cbb.tex.height / (TileHeight * Scale); const auto tileRows = cbb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows)); glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
glUniform2f( glUniform2f(
@ -295,11 +283,11 @@ static void drawBackgrounds(
} }
} }
static void drawSprites(GlContext &gctx, ox::Size const&renderSz) noexcept { static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
glUseProgram(gctx.spriteShader); glUseProgram(ctx.spriteShader);
auto &sb = gctx.spriteBlocks; auto &sb = ctx.spriteBlocks;
const auto uniformXScale = glGetUniformLocation(gctx.bgShader, "vXScale"); const auto uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
const auto uniformTileHeight = glGetUniformLocation(gctx.spriteShader, "vTileHeight"); const auto uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight");
const auto [wi, hi] = renderSz; const auto [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi); const auto wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi); const auto hf = static_cast<float>(hi);
@ -338,61 +326,59 @@ static void loadPalette(
glUniform4fv(uniformPalette, ColorCnt, palette.data()); glUniform4fv(uniformPalette, ColorCnt, palette.data());
} }
static void loadBgPalette(GlContext &gctx, Palette const&pal) noexcept { static void loadBgPalette(Context &ctx, Palette const&pal) noexcept {
loadPalette(gctx.bgShader, pal); loadPalette(ctx.bgShader, pal);
} }
static void loadSpritePalette(GlContext &gctx, Palette const&pal) noexcept { static void loadSpritePalette(Context &ctx, Palette const&pal) noexcept {
loadPalette(gctx.spriteShader, pal, true); loadPalette(ctx.spriteShader, pal, true);
} }
static void loadBgTexture( static void loadBgTexture(
GlContext &gctx, Context &ctx,
uint_t cbbIdx, uint_t cbbIdx,
const void *pixels, const void *pixels,
int w, int w,
int h) noexcept { int h) noexcept {
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h); oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h);
gctx.cbbs[cbbIdx].tex = loadTexture(w, h, pixels); ctx.cbbs[cbbIdx].tex = createTexture(w, h, pixels);
} }
static void loadSpriteTexture( static void loadSpriteTexture(
GlContext &gctx, Context &ctx,
const void *pixels, const void *pixels,
int w, int w,
int h) noexcept { int h) noexcept {
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", w, h); oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", w, h);
gctx.spriteBlocks.tex = loadTexture(w, h, pixels); ctx.spriteBlocks.tex = createTexture(w, h, pixels);
} }
} }
ox::Error initGfx( ox::Error initGfx(
Context *ctx, Context &ctx,
InitParams const&initParams) noexcept { InitParams const&initParams) noexcept {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, glutils::GlslVersion); const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, glutils::GlslVersion); const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, glutils::GlslVersion); const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, glutils::GlslVersion); const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion);
auto &gctx = glctx(*ctx); oxReturnError(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(&ctx.bgShader));
oxReturnError(glutils::buildShaderProgram(bgVshad.c_str(), bgFshad.c_str()).moveTo(&gctx.bgShader));
oxReturnError( oxReturnError(
glutils::buildShaderProgram(spriteVshad.c_str(), spriteFshad.c_str()).moveTo(&gctx.spriteShader)); glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(&ctx.spriteShader));
for (auto &bg : gctx.cbbs) { for (auto &bg : ctx.cbbs) {
initBackgroundBufferset(gctx.bgShader, bg); initBackgroundBufferset(ctx.bgShader, bg);
} }
initSpritesBufferset(gctx.spriteShader, gctx.spriteBlocks); initSpritesBufferset(ctx.spriteShader, ctx.spriteBlocks);
if (initParams.glInstallDrawer) { if (initParams.glInstallDrawer) {
turbine::gl::addDrawer(gctx.turbineCtx, &gctx.drawer); turbine::gl::addDrawer(ctx.turbineCtx, &ctx.drawer);
} }
return {}; return {};
} }
void shutdownGfx(Context &ctx) noexcept { void shutdownGfx(Context &ctx) noexcept {
auto &gctx = glctx(ctx); turbine::gl::removeDrawer(ctx.turbineCtx, &ctx.drawer);
turbine::gl::removeDrawer(gctx.turbineCtx, &gctx.drawer);
} }
struct TileSheetData { struct TileSheetData {
@ -406,8 +392,8 @@ struct TileSheetData {
}; };
static ox::Result<TileSheetData> loadTileSheet( static ox::Result<TileSheetData> loadTileSheet(
Context &ctx, CompactTileSheet const&tilesheet) noexcept { Context &ctx,
auto &gctx = glctx(ctx); CompactTileSheet const&tilesheet) noexcept {
const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2; const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
const auto tiles = tilesheet.pixels.size() / bytesPerTile; const auto tiles = tilesheet.pixels.size() / bytesPerTile;
constexpr int width = 8; constexpr int width = 8;
@ -425,54 +411,52 @@ static ox::Result<TileSheetData> loadTileSheet(
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4; pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
} }
} }
renderer::loadSpriteTexture(gctx, pixels.data(), width, height); renderer::loadSpriteTexture(ctx, pixels.data(), width, height);
return TileSheetData{std::move(pixels), width, height}; return TileSheetData{std::move(pixels), width, height};
} }
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context *ctx, Context &ctx,
uint_t cbb, uint_t cbb,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept { ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = glctx(*ctx); auto &kctx = keelCtx(ctx.turbineCtx);
auto &kctx = gctx.turbineCtx.keelCtx; oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
oxRequire(tilesheet, readObj<CompactTileSheet>(&kctx, tilesheetAddr)); oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
oxRequire(palette, readObj<Palette>(&kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette)); oxRequire(tsd, loadTileSheet(ctx, *tilesheet).to([](TileSheetData const&t) -> TileSheetData {
oxRequire(tsd, loadTileSheet(*ctx, *tilesheet).to([](TileSheetData const&t) -> TileSheetData {
return { return {
.pixels = resizeTileSheetData(t.pixels, t.size(), Scale), .pixels = resizeTileSheetData(t.pixels, t.size(), Scale),
.width = t.width * Scale, .width = t.width * Scale,
.height = t.height * Scale, .height = t.height * Scale,
}; };
})); }));
renderer::loadBgTexture(gctx, cbb, tsd.pixels.data(), tsd.width, tsd.height); renderer::loadBgTexture(ctx, cbb, tsd.pixels.data(), tsd.width, tsd.height);
renderer::loadBgPalette(gctx, *palette); renderer::loadBgPalette(ctx, *palette);
return {}; return {};
} }
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context *ctx, Context &ctx,
ox::FileAddress const&tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept { ox::FileAddress const&paletteAddr) noexcept {
auto &gctx = glctx(*ctx); auto &kctx = keelCtx(ctx.turbineCtx);
auto &kctx = gctx.turbineCtx.keelCtx; oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
oxRequire(tilesheet, readObj<CompactTileSheet>(&kctx, tilesheetAddr)); oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
oxRequire(palette, readObj<Palette>(&kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette)); oxRequire(tsd, loadTileSheet(ctx, *tilesheet));
oxRequire(tsd, loadTileSheet(*ctx, *tilesheet)); renderer::loadSpriteTexture(ctx, tsd.pixels.data(), tsd.width, tsd.height);
renderer::loadSpriteTexture(gctx, tsd.pixels.data(), tsd.width, tsd.height); renderer::loadSpritePalette(ctx, *palette);
renderer::loadSpritePalette(gctx, *palette);
return {}; return {};
} }
ox::Error initConsole(Context *ctx) noexcept { ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng"); constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal"); constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001); setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0); setBgCbb(ctx, 0, 0);
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr); return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
} }
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept { void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
const auto col = static_cast<uint_t>(column); const auto col = static_cast<uint_t>(column);
for (auto i = 0u; i < str.bytes(); ++i) { for (auto i = 0u; i < str.bytes(); ++i) {
setTile( setTile(
@ -484,57 +468,50 @@ void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept {
} }
} }
void setBgCbb(Context *ctx, uint_t bgIdx, uint_t cbbIdx) noexcept { void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept {
auto &gctx = glctx(*ctx); auto &bg = ctx.backgrounds[bgIdx];
auto &bg = gctx.backgrounds[bgIdx];
bg.cbbIdx = cbbIdx; bg.cbbIdx = cbbIdx;
} }
uint8_t bgStatus(Context *ctx) noexcept { uint8_t bgStatus(Context &ctx) noexcept {
const auto &gctx = glctx(*ctx);
uint8_t out = 0; uint8_t out = 0;
for (uint_t i = 0; i < gctx.cbbs.size(); ++i) { for (uint_t i = 0; i < ctx.cbbs.size(); ++i) {
out |= static_cast<uint8_t>(static_cast<uint_t>(gctx.backgrounds[i].enabled) << i); out |= static_cast<uint8_t>(static_cast<uint_t>(ctx.backgrounds[i].enabled) << i);
} }
return out; return out;
} }
void setBgStatus(Context *ctx, uint32_t status) noexcept { void setBgStatus(Context &ctx, uint32_t status) noexcept {
auto &gctx = glctx(*ctx); for (uint_t i = 0; i < ctx.cbbs.size(); ++i) {
for (uint_t i = 0; i < gctx.cbbs.size(); ++i) { ctx.backgrounds[i].enabled = (status >> i) & 1;
gctx.backgrounds[i].enabled = (status >> i) & 1;
} }
} }
bool bgStatus(Context *ctx, uint_t bg) noexcept { bool bgStatus(Context &ctx, uint_t bg) noexcept {
const auto &gctx = glctx(*ctx); return ctx.backgrounds[bg].enabled;
return gctx.backgrounds[bg].enabled;
} }
void setBgStatus(Context *ctx, uint_t bg, bool status) noexcept { void setBgStatus(Context &ctx, uint_t bg, bool status) noexcept {
auto &gctx = glctx(*ctx); ctx.backgrounds[bg].enabled = status;
gctx.backgrounds[bg].enabled = status;
} }
void clearTileLayer(Context *ctx, uint_t bgIdx) noexcept { void clearTileLayer(Context &ctx, uint_t bgIdx) noexcept {
auto &gctx = glctx(*ctx); auto &bg = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
auto &bg = gctx.cbbs[static_cast<std::size_t>(bgIdx)];
initBackgroundBufferObjects(bg); initBackgroundBufferObjects(bg);
bg.updated = true; bg.updated = true;
} }
void hideSprite(Context *ctx, uint_t idx) noexcept { void hideSprite(Context &ctx, uint_t idx) noexcept {
auto &gctx = glctx(*ctx); auto vbo = &ctx.spriteBlocks.vertices[idx * renderer::SpriteVertexVboLength];
auto vbo = &gctx.spriteBlocks.vertices[idx * renderer::SpriteVertexVboLength]; auto ebo = &ctx.spriteBlocks.elements[idx * renderer::SpriteVertexEboLength];
auto ebo = &gctx.spriteBlocks.elements[idx * renderer::SpriteVertexEboLength]; renderer::setSpriteBufferObject(
renderer::setSpriteBufferObject(idx * renderer::SpriteVertexVboRows, 0, idx * renderer::SpriteVertexVboRows, 0, 0, 0, 0, false, vbo, ebo);
0, 0, 0, false, vbo, ebo); ctx.spriteBlocks.updated = true;
gctx.spriteBlocks.updated = true;
} }
void setSprite( void setSprite(
Context *ctx, Context &ctx,
uint_t idx, uint_t idx,
int x, int x,
int y, int y,
@ -565,14 +542,13 @@ void setSprite(
const auto dim = dimensions[(spriteShape << 2) | spriteSize]; const auto dim = dimensions[(spriteShape << 2) | spriteSize];
const auto uX = static_cast<int>(x) % 255; const auto uX = static_cast<int>(x) % 255;
const auto uY = static_cast<int>(y + 8) % 255 - 8; const auto uY = static_cast<int>(y + 8) % 255 - 8;
auto &gctx = glctx(*ctx);
auto i = 0u; auto i = 0u;
const auto set = [&](int xIt, int yIt) { const auto set = [&](int xIt, int yIt) {
const auto fX = static_cast<float>(uX + xIt * 8) / 8; const auto fX = static_cast<float>(uX + xIt * 8) / 8;
const auto fY = static_cast<float>(uY + yIt * 8) / 8; const auto fY = static_cast<float>(uY + yIt * 8) / 8;
const auto cidx = idx + i; const auto cidx = idx + i;
auto vbo = &gctx.spriteBlocks.vertices[cidx * renderer::SpriteVertexVboLength]; auto vbo = &ctx.spriteBlocks.vertices[cidx * renderer::SpriteVertexVboLength];
auto ebo = &gctx.spriteBlocks.elements[cidx * renderer::SpriteVertexEboLength]; auto ebo = &ctx.spriteBlocks.elements[cidx * renderer::SpriteVertexEboLength];
renderer::setSpriteBufferObject( renderer::setSpriteBufferObject(
cidx * renderer::SpriteVertexVboRows, cidx * renderer::SpriteVertexVboRows,
1, 1,
@ -597,11 +573,11 @@ void setSprite(
} }
} }
} }
gctx.spriteBlocks.updated = true; ctx.spriteBlocks.updated = true;
} }
void setTile( void setTile(
Context *ctx, Context &ctx,
uint_t bgIdx, uint_t bgIdx,
int column, int column,
int row, int row,
@ -610,22 +586,18 @@ void setTile(
"nostalgia.core.gfx.setTile", "nostalgia.core.gfx.setTile",
"bgIdx: {}, column: {}, row: {}, tile: {}", "bgIdx: {}, column: {}, row: {}, tile: {}",
bgIdx, column, row, tile); bgIdx, column, row, tile);
auto &gctx = glctx(*ctx);
const auto z = static_cast<uint_t>(bgIdx); const auto z = static_cast<uint_t>(bgIdx);
const auto y = static_cast<uint_t>(row); const auto y = static_cast<uint_t>(row);
const auto x = static_cast<uint_t>(column); const auto x = static_cast<uint_t>(column);
const auto i = renderer::bgVertexRow(x, y); const auto i = renderer::bgVertexRow(x, y);
auto &bg = gctx.cbbs[z]; auto &bg = ctx.cbbs[z];
const auto vbo = &bg.vertices[i * renderer::BgVertexVboLength]; const auto vbo = &bg.vertices[i * renderer::BgVertexVboLength];
const auto ebo = &bg.elements[i * renderer::BgVertexEboLength]; const auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
const auto tileHeight = static_cast<float>(TileHeight * Scale) / static_cast<float>(bg.tex.height);
const auto tileOffset = tileHeight * static_cast<float>(tile);
renderer::setTileBufferObject( renderer::setTileBufferObject(
static_cast<uint_t>(i * renderer::BgVertexVboRows), static_cast<uint_t>(i * renderer::BgVertexVboRows),
static_cast<float>(x), static_cast<float>(x),
static_cast<float>(y), static_cast<float>(y),
tileOffset, static_cast<float>(tile),
tileHeight,
vbo, vbo,
ebo); ebo);
bg.updated = true; bg.updated = true;
@ -633,16 +605,23 @@ void setTile(
namespace gl { namespace gl {
void drawMainView(core::Context &ctx, ox::Size const&renderSz) noexcept { ox::Size drawSize(int scale) noexcept {
return {240 * scale, 160 * scale};
}
void draw(core::Context &ctx, ox::Size const&renderSz) noexcept {
glViewport(0, 0, renderSz.width, renderSz.height); glViewport(0, 0, renderSz.width, renderSz.height);
glutils::clearScreen(); glutils::clearScreen();
auto &gctx = glctx(ctx); renderer::drawBackgrounds(ctx, renderSz);
renderer::drawBackgrounds(gctx, renderSz); if (ctx.spriteBlocks.tex) {
if (gctx.spriteBlocks.tex) { renderer::drawSprites(ctx, renderSz);
renderer::drawSprites(gctx, renderSz);
} }
} }
void draw(core::Context &ctx, int scale) noexcept {
draw(ctx, drawSize(scale));
}
} }
} }

View File

@ -19,7 +19,7 @@ constexpr uint64_t TileColumns = 128;
constexpr uint64_t TileCount = TileRows * TileColumns; constexpr uint64_t TileCount = TileRows * TileColumns;
constexpr uint64_t SpriteCount = 128; constexpr uint64_t SpriteCount = 128;
constexpr uint64_t BgVertexVboRows = 4; constexpr uint64_t BgVertexVboRows = 4;
constexpr uint64_t BgVertexVboRowLength = 4; constexpr uint64_t BgVertexVboRowLength = 5;
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength; constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
constexpr uint64_t BgVertexEboLength = 6; constexpr uint64_t BgVertexEboLength = 6;
constexpr uint64_t SpriteVertexVboRows = 256; constexpr uint64_t SpriteVertexVboRows = 256;
@ -63,6 +63,6 @@ class Drawer: public turbine::gl::Drawer {
} }
namespace nostalgia::core { namespace nostalgia::core {
ox::Error initGfx(Context *ctx, InitParams const&) noexcept; ox::Error initGfx(Context &ctx, InitParams const&) noexcept;
void shutdownGfx(Context &ctx) noexcept; void shutdownGfx(Context &ctx) noexcept;
} }

View File

@ -1,17 +1,9 @@
add_library( add_library(NostalgiaCore-Studio)
NostalgiaCore-Studio
paletteeditor.cpp
tilesheeteditorview.cpp
tilesheeteditormodel.cpp
tilesheetpixelgrid.cpp
tilesheetpixels.cpp
)
add_library( add_library(
NostalgiaCore-Studio-ImGui NostalgiaCore-Studio-ImGui
studiomodule.cpp studiomodule.cpp
paletteeditor-imgui.cpp tilesheeteditor/tilesheeteditor-imgui.cpp
tilesheeteditor-imgui.cpp
) )
target_link_libraries( target_link_libraries(
@ -24,7 +16,6 @@ target_link_libraries(
NostalgiaCore-Studio-ImGui PUBLIC NostalgiaCore-Studio-ImGui PUBLIC
NostalgiaCore-Studio NostalgiaCore-Studio
Studio Studio
lodepng
) )
install( install(
@ -34,3 +25,6 @@ install(
LIBRARY DESTINATION LIBRARY DESTINATION
${NOSTALGIA_DIST_MODULE} ${NOSTALGIA_DIST_MODULE}
) )
add_subdirectory(paletteeditor)
add_subdirectory(tilesheeteditor)

View File

@ -0,0 +1,5 @@
target_sources(
NostalgiaCore-Studio PRIVATE
paletteeditor.cpp
paletteeditor-imgui.cpp
)

View File

@ -15,22 +15,22 @@
namespace nostalgia::core { namespace nostalgia::core {
PaletteEditorImGui::PaletteEditorImGui(turbine::Context *ctx, ox::String path): PaletteEditorImGui::PaletteEditorImGui(turbine::Context &ctx, ox::CRStringView path):
m_ctx(ctx), m_ctx(ctx),
m_itemPath(std::move(path)), m_itemPath(path),
m_itemName(m_itemPath.substr(std::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset() + 1)), m_itemName(m_itemPath.substr(std::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset() + 1)),
m_pal(*keel::readObj<Palette>(&m_ctx->keelCtx, ox::FileAddress(m_itemPath.c_str())).unwrapThrow()) { m_pal(*keel::readObj<Palette>(keelCtx(m_ctx), ox::FileAddress(m_itemPath.c_str())).unwrapThrow()) {
} }
const ox::String &PaletteEditorImGui::itemName() const noexcept { ox::CStringView PaletteEditorImGui::itemName() const noexcept {
return m_itemPath; return m_itemPath;
} }
const ox::String &PaletteEditorImGui::itemDisplayName() const noexcept { ox::CStringView PaletteEditorImGui::itemDisplayName() const noexcept {
return m_itemName; return m_itemName;
} }
void PaletteEditorImGui::draw(turbine::Context*) noexcept { void PaletteEditorImGui::draw(turbine::Context&) noexcept {
static constexpr auto flags = ImGuiTableFlags_RowBg; static constexpr auto flags = ImGuiTableFlags_RowBg;
const auto paneSize = ImGui::GetContentRegionAvail(); const auto paneSize = ImGui::GetContentRegionAvail();
ImGui::BeginChild("Colors", ImVec2(paneSize.x - 208, paneSize.y), true); ImGui::BeginChild("Colors", ImVec2(paneSize.x - 208, paneSize.y), true);
@ -42,14 +42,14 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
if (ImGui::Button("Add", sz)) { if (ImGui::Button("Add", sz)) {
const auto colorSz = static_cast<int>(m_pal.colors.size()); const auto colorSz = static_cast<int>(m_pal.colors.size());
constexpr Color16 c = 0; constexpr Color16 c = 0;
undoStack()->push(ox::make<AddColorCommand>(&m_pal, c, colorSz)); undoStack()->push(ox::make_unique<AddColorCommand>(&m_pal, c, colorSz));
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size()); ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size());
{ {
if (ImGui::Button("Remove", sz)) { if (ImGui::Button("Remove", sz)) {
undoStack()->push( undoStack()->push(
ox::make<RemoveColorCommand>( ox::make_unique<RemoveColorCommand>(
&m_pal, &m_pal,
m_pal.colors[static_cast<std::size_t>(m_selectedRow)], m_pal.colors[static_cast<std::size_t>(m_selectedRow)],
static_cast<int>(m_selectedRow))); static_cast<int>(m_selectedRow)));
@ -59,7 +59,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
ImGui::BeginDisabled(m_selectedRow <= 0); ImGui::BeginDisabled(m_selectedRow <= 0);
{ {
if (ImGui::Button("Move Up", sz)) { if (ImGui::Button("Move Up", sz)) {
undoStack()->push(ox::make<MoveColorCommand>(&m_pal, m_selectedRow, -1)); undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_selectedRow, -1));
--m_selectedRow; --m_selectedRow;
} }
} }
@ -68,7 +68,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size() - 1); ImGui::BeginDisabled(m_selectedRow >= m_pal.colors.size() - 1);
{ {
if (ImGui::Button("Move Down", sz)) { if (ImGui::Button("Move Down", sz)) {
undoStack()->push(ox::make<MoveColorCommand>(&m_pal, m_selectedRow, 1)); undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_selectedRow, 1));
++m_selectedRow; ++m_selectedRow;
} }
} }
@ -125,13 +125,13 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
int r = red16(c); int r = red16(c);
int g = green16(c); int g = green16(c);
int b = blue16(c); int b = blue16(c);
int a = alpha16(c); int const a = alpha16(c);
ImGui::InputInt("Red", &r, 1, 5); ImGui::InputInt("Red", &r, 1, 5);
ImGui::InputInt("Green", &g, 1, 5); ImGui::InputInt("Green", &g, 1, 5);
ImGui::InputInt("Blue", &b, 1, 5); ImGui::InputInt("Blue", &b, 1, 5);
const auto newColor = color16(r, g, b, a); const auto newColor = color16(r, g, b, a);
if (c != newColor) { if (c != newColor) {
undoStack()->push(ox::make<UpdateColorCommand>(&m_pal, static_cast<int>(m_selectedRow), c, newColor)); undoStack()->push(ox::make_unique<UpdateColorCommand>(&m_pal, static_cast<int>(m_selectedRow), c, newColor));
} }
} }
ImGui::EndChild(); ImGui::EndChild();
@ -139,7 +139,7 @@ void PaletteEditorImGui::draw(turbine::Context*) noexcept {
} }
ox::Error PaletteEditorImGui::saveItem() noexcept { ox::Error PaletteEditorImGui::saveItem() noexcept {
const auto sctx = applicationData<studio::StudioContext>(*m_ctx); const auto sctx = applicationData<studio::StudioContext>(m_ctx);
return sctx->project->writeObj(m_itemPath, m_pal); return sctx->project->writeObj(m_itemPath, m_pal);
} }

View File

@ -14,25 +14,23 @@ namespace nostalgia::core {
class PaletteEditorImGui: public studio::Editor { class PaletteEditorImGui: public studio::Editor {
private: private:
turbine::Context *m_ctx = nullptr; turbine::Context &m_ctx;
ox::String m_itemPath; ox::String m_itemPath;
ox::String m_itemName; ox::String m_itemName;
Palette m_pal; Palette m_pal;
std::size_t m_selectedRow = 0; std::size_t m_selectedRow = 0;
PaletteEditorImGui() noexcept = default;
public: public:
PaletteEditorImGui(turbine::Context *ctx, ox::String path); PaletteEditorImGui(turbine::Context &ctx, ox::CRStringView path);
/** /**
* Returns the name of item being edited. * Returns the name of item being edited.
*/ */
const ox::String &itemName() const noexcept final; ox::CStringView itemName() const noexcept final;
const ox::String &itemDisplayName() const noexcept final; ox::CStringView itemDisplayName() const noexcept final;
void draw(turbine::Context*) noexcept final; void draw(turbine::Context&) noexcept final;
protected: protected:
ox::Error saveItem() noexcept final; ox::Error saveItem() noexcept final;

View File

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

View File

@ -0,0 +1,14 @@
target_sources(
NostalgiaCore-Studio PRIVATE
tilesheeteditorview.cpp
tilesheeteditormodel.cpp
tilesheetpixelgrid.cpp
tilesheetpixels.cpp
)
target_link_libraries(
NostalgiaCore-Studio-ImGui PUBLIC
lodepng
)
add_subdirectory(commands)

View File

@ -0,0 +1,11 @@
target_sources(
NostalgiaCore-Studio PRIVATE
addsubsheetcommand.cpp
cutpastecommand.cpp
deletetilescommand.cpp
drawcommand.cpp
inserttilescommand.cpp
palettechangecommand.cpp
rmsubsheetcommand.cpp
updatesubsheetcommand.cpp
)

View File

@ -0,0 +1,63 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "addsubsheetcommand.hpp"
namespace nostalgia::core {
AddSubSheetCommand::AddSubSheetCommand(
TileSheet &img,
TileSheet::SubSheetIdx parentIdx) noexcept:
m_img(img), m_parentIdx(std::move(parentIdx)) {
auto &parent = m_img.getSubSheet(m_parentIdx);
if (!parent.subsheets.empty()) {
auto idx = m_parentIdx;
idx.emplace_back(parent.subsheets.size());
m_addedSheets.push_back(idx);
} else {
auto idx = m_parentIdx;
idx.emplace_back(0u);
m_addedSheets.push_back(idx);
*idx.back().value = 1;
m_addedSheets.push_back(idx);
}
}
void AddSubSheetCommand::redo() noexcept {
auto &parent = m_img.getSubSheet(m_parentIdx);
if (m_addedSheets.size() < 2) {
auto i = parent.subsheets.size();
parent.subsheets.emplace_back(m_img.idIt++, ox::sfmt("Subsheet {}", i), 1, 1, m_img.bpp);
} else {
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
parent.rows = 0;
parent.columns = 0;
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1, m_img.bpp);
}
}
void AddSubSheetCommand::undo() noexcept {
auto &parent = m_img.getSubSheet(m_parentIdx);
if (parent.subsheets.size() == 2) {
auto s = parent.subsheets[0];
parent.rows = s.rows;
parent.columns = s.columns;
parent.pixels = std::move(s.pixels);
parent.subsheets.clear();
} else {
for (auto idx = m_addedSheets.rbegin(); idx != m_addedSheets.rend(); ++idx) {
oxLogError(m_img.rmSubSheet(*idx));
}
}
}
int AddSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::AddSubSheet);
}
TileSheet::SubSheetIdx const&AddSubSheetCommand::subsheetIdx() const noexcept {
return m_parentIdx;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include "commands.hpp"
namespace nostalgia::core {
class AddSubSheetCommand: public TileSheetCommand {
private:
TileSheet &m_img;
TileSheet::SubSheetIdx m_parentIdx;
ox::Vector<TileSheet::SubSheetIdx, 2> m_addedSheets;
public:
AddSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx parentIdx) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <studio/undostack.hpp>
#include <nostalgia/core/tilesheet.hpp>
namespace nostalgia::core {
// Command IDs to use with QUndoCommand::id()
enum class CommandId {
Draw = 1,
AddSubSheet = 2,
RmSubSheet = 3,
DeleteTile = 4,
InsertTile = 4,
UpdateSubSheet = 5,
Cut = 6,
Paste = 7,
PaletteChange = 8,
};
constexpr bool operator==(CommandId c, int i) noexcept {
return static_cast<int>(c) == i;
}
constexpr bool operator==(int i, CommandId c) noexcept {
return static_cast<int>(c) == i;
}
class TileSheetCommand: public studio::UndoCommand {
public:
[[nodiscard]]
virtual TileSheet::SubSheetIdx const&subsheetIdx() const noexcept = 0;
};
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "cutpastecommand.hpp"
namespace nostalgia::core {
TileSheetClipboard::Pixel::Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept {
colorIdx = pColorIdx;
pt = pPt;
}
void TileSheetClipboard::addPixel(const ox::Point &pt, uint16_t colorIdx) noexcept {
m_pixels.emplace_back(colorIdx, pt);
}
const ox::Vector<TileSheetClipboard::Pixel> &TileSheetClipboard::pixels() const noexcept {
return m_pixels;
}
CutPasteCommand::CutPasteCommand(
CommandId commandId,
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
const ox::Point &dstStart,
const ox::Point &dstEnd,
const TileSheetClipboard &cb) noexcept:
m_commandId(commandId),
m_img(img),
m_subSheetIdx(std::move(subSheetIdx)) {
const auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto &p : cb.pixels()) {
const auto dstPt = p.pt + dstStart;
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
const auto idx = subsheet.idx(dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, subsheet.getPixel(m_img.bpp, idx));
}
}
}
void CutPasteCommand::redo() noexcept {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto &c : m_changes) {
subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(c.newPalIdx));
}
}
void CutPasteCommand::undo() noexcept {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto &c : m_changes) {
subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
}
}
int CutPasteCommand::commandId() const noexcept {
return static_cast<int>(m_commandId);
}
TileSheet::SubSheetIdx const&CutPasteCommand::subsheetIdx() const noexcept {
return m_subSheetIdx;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <turbine/clipboard.hpp>
#include "commands.hpp"
namespace nostalgia::core {
class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
public:
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
static constexpr auto TypeVersion = 1;
oxModelFriend(TileSheetClipboard);
struct Pixel {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard.Pixel";
static constexpr auto TypeVersion = 1;
uint16_t colorIdx = 0;
ox::Point pt;
Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept;
};
protected:
ox::Vector<Pixel> m_pixels;
public:
void addPixel(ox::Point const&pt, uint16_t colorIdx) noexcept;
[[nodiscard]]
ox::Vector<Pixel> const&pixels() const noexcept;
};
oxModelBegin(TileSheetClipboard::Pixel)
oxModelField(colorIdx)
oxModelField(pt)
oxModelEnd()
oxModelBegin(TileSheetClipboard)
oxModelFieldRename(pixels, m_pixels)
oxModelEnd()
class CutPasteCommand: public TileSheetCommand {
private:
struct Change {
uint32_t idx = 0;
uint16_t newPalIdx = 0;
uint16_t oldPalIdx = 0;
constexpr Change(uint32_t pIdx, uint16_t pNewPalIdx, uint16_t pOldPalIdx) noexcept {
idx = pIdx;
newPalIdx = pNewPalIdx;
oldPalIdx = pOldPalIdx;
}
};
CommandId m_commandId;
TileSheet &m_img;
TileSheet::SubSheetIdx m_subSheetIdx;
ox::Vector<Change> m_changes;
public:
CutPasteCommand(
CommandId commandId,
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
ox::Point const&dstStart,
ox::Point const&dstEnd,
TileSheetClipboard const&cb) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "deletetilescommand.hpp"
namespace nostalgia::core {
core::DeleteTilesCommand::DeleteTilesCommand(
TileSheet &img,
TileSheet::SubSheetIdx idx,
std::size_t tileIdx,
std::size_t tileCnt) noexcept:
m_img(img),
m_idx(std::move(idx)) {
const unsigned bytesPerTile = m_img.bpp == 4 ? PixelsPerTile / 2 : PixelsPerTile;
m_deletePos = tileIdx * bytesPerTile;
m_deleteSz = tileCnt * bytesPerTile;
m_deletedPixels.resize(m_deleteSz);
// copy pixels to be erased
{
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
auto dst = m_deletedPixels.data();
auto src = p.data() + m_deletePos;
const auto sz = m_deleteSz * sizeof(decltype(p[0]));
ox_memcpy(dst, src, sz);
}
}
void core::DeleteTilesCommand::redo() noexcept {
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
auto srcPos = m_deletePos + m_deleteSz;
const auto src = p.data() + srcPos;
const auto dst1 = p.data() + m_deletePos;
const auto dst2 = p.data() + (p.size() - m_deleteSz);
ox_memmove(dst1, src, p.size() - srcPos);
ox_memset(dst2, 0, m_deleteSz * sizeof(decltype(p[0])));
}
void DeleteTilesCommand::undo() noexcept {
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
const auto src = p.data() + m_deletePos;
const auto dst1 = p.data() + m_deletePos + m_deleteSz;
const auto dst2 = src;
const auto sz = p.size() - m_deletePos - m_deleteSz;
ox_memmove(dst1, src, sz);
ox_memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
}
int DeleteTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::DeleteTile);
}
TileSheet::SubSheetIdx const&DeleteTilesCommand::subsheetIdx() const noexcept {
return m_idx;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include "commands.hpp"
namespace nostalgia::core {
class DeleteTilesCommand: public TileSheetCommand {
private:
TileSheet &m_img;
TileSheet::SubSheetIdx m_idx;
std::size_t m_deletePos = 0;
std::size_t m_deleteSz = 0;
ox::Vector<uint8_t> m_deletedPixels = {};
public:
DeleteTilesCommand(
TileSheet &img,
TileSheet::SubSheetIdx idx,
std::size_t tileIdx,
std::size_t tileCnt) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "drawcommand.hpp"
namespace nostalgia::core {
DrawCommand::DrawCommand(
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
std::size_t idx,
int palIdx) noexcept:
m_img(img),
m_subSheetIdx(std::move(subSheetIdx)),
m_palIdx(palIdx) {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
}
DrawCommand::DrawCommand(
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
const ox::Vector<std::size_t> &idxList,
int palIdx) noexcept:
m_img(img),
m_subSheetIdx(std::move(subSheetIdx)),
m_palIdx(palIdx) {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto idx : idxList) {
m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
}
}
bool DrawCommand::append(std::size_t idx) noexcept {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
if (m_changes.back().value->idx != idx && subsheet.getPixel(m_img.bpp, idx) != m_palIdx) {
// duplicate entries are bad
auto existing = ox::find_if(m_changes.cbegin(), m_changes.cend(), [idx](const auto &c) {
return c.idx == idx;
});
if (existing == m_changes.cend()) {
m_changes.emplace_back(static_cast<uint32_t>(idx), subsheet.getPixel(m_img.bpp, idx));
subsheet.setPixel(m_img.bpp, idx, static_cast<uint8_t>(m_palIdx));
return true;
}
}
return false;
}
bool DrawCommand::append(const ox::Vector<std::size_t> &idxList) noexcept {
auto out = false;
for (auto idx : idxList) {
out = append(idx) || out;
}
return out;
}
void DrawCommand::redo() noexcept {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto &c : m_changes) {
subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx));
}
}
void DrawCommand::undo() noexcept {
auto &subsheet = m_img.getSubSheet(m_subSheetIdx);
for (const auto &c : m_changes) {
subsheet.setPixel(m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
}
}
int DrawCommand::commandId() const noexcept {
return static_cast<int>(CommandId::Draw);
}
TileSheet::SubSheetIdx const&DrawCommand::subsheetIdx() const noexcept {
return m_subSheetIdx;
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include "commands.hpp"
namespace nostalgia::core {
class DrawCommand: public TileSheetCommand {
private:
struct Change {
uint32_t idx = 0;
uint16_t oldPalIdx = 0;
constexpr Change(uint32_t pIdx, uint16_t pOldPalIdx) noexcept {
idx = pIdx;
oldPalIdx = pOldPalIdx;
}
};
TileSheet &m_img;
TileSheet::SubSheetIdx m_subSheetIdx;
ox::Vector<Change, 8> m_changes;
int m_palIdx = 0;
public:
DrawCommand(
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
std::size_t idx,
int palIdx) noexcept;
DrawCommand(
TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx,
const ox::Vector<std::size_t> &idxList,
int palIdx) noexcept;
bool append(std::size_t idx) noexcept;
bool append(const ox::Vector<std::size_t> &idxList) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "inserttilescommand.hpp"
namespace nostalgia::core {
core::InsertTilesCommand::InsertTilesCommand(
TileSheet &img,
TileSheet::SubSheetIdx idx,
std::size_t tileIdx,
std::size_t tileCnt) noexcept:
m_img(img),
m_idx(std::move(idx)) {
const unsigned bytesPerTile = m_img.bpp == 4 ? PixelsPerTile / 2 : PixelsPerTile;
m_insertPos = tileIdx * bytesPerTile;
m_insertCnt = tileCnt * bytesPerTile;
m_deletedPixels.resize(m_insertCnt);
// copy pixels to be erased
{
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
auto dst = m_deletedPixels.data();
auto src = p.data() + p.size() - m_insertCnt;
const auto sz = m_insertCnt * sizeof(decltype(p[0]));
ox_memcpy(dst, src, sz);
}
}
void InsertTilesCommand::redo() noexcept {
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
auto dstPos = m_insertPos + m_insertCnt;
const auto dst = p.data() + dstPos;
const auto src = p.data() + m_insertPos;
ox_memmove(dst, src, p.size() - dstPos);
ox_memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
}
void InsertTilesCommand::undo() noexcept {
auto &s = m_img.getSubSheet(m_idx);
auto &p = s.pixels;
const auto srcIdx = m_insertPos + m_insertCnt;
const auto src = p.data() + srcIdx;
const auto dst1 = p.data() + m_insertPos;
const auto dst2 = p.data() + p.size() - m_insertCnt;
const auto sz = p.size() - srcIdx;
ox_memmove(dst1, src, sz);
ox_memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
}
int InsertTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::InsertTile);
}
TileSheet::SubSheetIdx const&InsertTilesCommand::subsheetIdx() const noexcept {
return m_idx;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include "commands.hpp"
namespace nostalgia::core {
class InsertTilesCommand: public TileSheetCommand {
private:
TileSheet &m_img;
TileSheet::SubSheetIdx m_idx;
std::size_t m_insertPos = 0;
std::size_t m_insertCnt = 0;
ox::Vector<uint8_t> m_deletedPixels = {};
public:
InsertTilesCommand(
TileSheet &img,
TileSheet::SubSheetIdx idx,
std::size_t tileIdx,
std::size_t tileCnt) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "palettechangecommand.hpp"
namespace nostalgia::core {
core::PaletteChangeCommand::PaletteChangeCommand(
TileSheet::SubSheetIdx idx,
TileSheet &img,
ox::CRStringView newPalette) noexcept:
m_img(img),
m_idx(std::move(idx)),
m_oldPalette(m_img.defaultPalette),
m_newPalette(ox::FileAddress(ox::sfmt<ox::BString<43>>("uuid://{}", newPalette))) {
}
void PaletteChangeCommand::redo() noexcept {
m_img.defaultPalette = m_newPalette;
}
void PaletteChangeCommand::undo() noexcept {
m_img.defaultPalette = m_oldPalette;
}
int PaletteChangeCommand::commandId() const noexcept {
return static_cast<int>(CommandId::PaletteChange);
}
TileSheet::SubSheetIdx const&PaletteChangeCommand::subsheetIdx() const noexcept {
return m_idx;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include "commands.hpp"
namespace nostalgia::core {
class PaletteChangeCommand: public TileSheetCommand {
private:
TileSheet &m_img;
TileSheet::SubSheetIdx m_idx;
ox::FileAddress m_oldPalette;
ox::FileAddress m_newPalette;
public:
PaletteChangeCommand(
TileSheet::SubSheetIdx idx,
TileSheet &img,
ox::CRStringView newPalette) noexcept;
void redo() noexcept final;
void undo() noexcept final;
[[nodiscard]]
int commandId() const noexcept final;
[[nodiscard]]
TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
};
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "rmsubsheetcommand.hpp"
namespace nostalgia::core {
core::RmSubSheetCommand::RmSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx idx) noexcept:
m_img(img),
m_idx(std::move(idx)),
m_parentIdx(m_idx) {
m_parentIdx.pop_back();
auto &parent = m_img.getSubSheet(m_parentIdx);
m_sheet = parent.subsheets[*m_idx.back().value];
}
void RmSubSheetCommand::redo() noexcept {
auto &parent = m_img.getSubSheet(m_parentIdx);
oxLogError(parent.subsheets.erase(*m_idx.back().value).error);
}
void RmSubSheetCommand::undo() noexcept {
auto &parent = m_img.getSubSheet(m_parentIdx);
auto i = *m_idx.back().value;
parent.subsheets.insert(i, m_sheet);
}
int RmSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::RmSubSheet);
}
TileSheet::SubSheetIdx const&RmSubSheetCommand::subsheetIdx() const noexcept {
return m_idx;
}
}

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