Compare commits

..

5 Commits

Author SHA1 Message Date
1057099fcf [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m17s
2025-06-22 01:01:46 -05:00
17577b6e8b [nostalgia/gfx/studio/tilesheet] Disable paste when nothing is selected 2025-06-22 01:01:44 -05:00
db442e2775 [nostalgia/gfx] Address a couple of implicit conversions
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-21 14:21:23 -05:00
23cd50d29e [studio] Fix Studio to clear editor pointers when opening a new project 2025-06-21 14:21:12 -05:00
28088d1ed1 [nostalgia/studio] Set version to d2025.06.0
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-21 08:55:52 -05:00
168 changed files with 1018 additions and 1896 deletions

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba
pkg-gba: build-pack build-gba-player
pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac
@@ -26,44 +26,25 @@ generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio
run-studio: build-studio
run-studio: build
${PROJECT_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug
debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba
configure-gba:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}

View File

@@ -89,7 +89,7 @@ struct GLObject: public Base {
return id;
}
constexpr operator GLuint const&() const noexcept {
constexpr operator const GLuint&() const noexcept {
return id;
}
@@ -135,7 +135,7 @@ struct FrameBuffer {
return fbo.id;
}
constexpr operator GLuint const&() const noexcept {
constexpr operator const GLuint&() const noexcept {
return fbo.id;
}
@@ -158,14 +158,14 @@ struct FrameBuffer {
class FrameBufferBind {
private:
static FrameBuffer const *s_activeFb;
FrameBuffer const *m_restoreFb = nullptr;
static const FrameBuffer *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr;
public:
explicit FrameBufferBind(FrameBuffer const &fb) noexcept;
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
~FrameBufferBind() noexcept;
};
void bind(FrameBuffer const &fb) noexcept;
void bind(const FrameBuffer &fb) noexcept;
struct ShaderVarSet {
GLsizei len{};
@@ -176,7 +176,7 @@ struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] {
GLsizei len{};
for (auto const &v : shaderParams) {
for (auto const&v : shaderParams) {
len += v.len;
}
return len;
@@ -187,23 +187,23 @@ struct ProgramSource {
ox::String const geomShader{};
};
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept;
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const &vert,
ox::CStringView const &frag,
ox::CStringView const &geo = "") noexcept;
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo = "") noexcept;
void setupShaderParams(
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept;
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept;
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
GLVertexArray generateVertexArrayObject() noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept;
GLBuffer generateBuffer() noexcept;
glutils::GLBuffer generateBuffer() noexcept;
[[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept;
@@ -215,20 +215,20 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
*/
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
struct BufferSet {
GLVertexArray vao;
GLBuffer vbo;
GLBuffer ebo;
GLTexture tex;
glutils::GLVertexArray vao;
glutils::GLBuffer vbo;
glutils::GLBuffer ebo;
glutils::GLTexture tex;
ox::Vector<float> vertices;
ox::Vector<GLuint> elements;
};
void sendVbo(BufferSet const &bs) noexcept;
void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(BufferSet const &bs) noexcept;
void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept;

View File

@@ -46,9 +46,9 @@ template struct GLObject<deleteVertexArray>;
template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>;
FrameBuffer const *FrameBufferBind::s_activeFb = nullptr;
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr;
FrameBufferBind::FrameBufferBind(FrameBuffer const &fb) noexcept: m_restoreFb(s_activeFb) {
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) {
s_activeFb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
@@ -64,15 +64,15 @@ FrameBufferBind::~FrameBufferBind() noexcept {
}
}
void bind(FrameBuffer const &fb) noexcept {
void bind(const FrameBuffer &fb) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
}
static ox::Result<GLShader> buildShader(
GLuint const shaderType,
GLchar const *src,
GLuint shaderType,
const GLchar *src,
ox::StringViewCR shaderName) noexcept {
GLShader shader(glCreateShader(shaderType));
glShaderSource(shader, 1, &src, nullptr);
@@ -88,7 +88,7 @@ static ox::Result<GLShader> buildShader(
return shader;
}
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
OX_REQUIRE_M(program, buildShaderProgram(
src.vertShader,
src.fragShader,
@@ -98,11 +98,11 @@ ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
}
void setupShaderParams(
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept {
// setup vars
for (size_t lenWritten = 0; auto const &v : vars) {
for (size_t lenWritten = 0; auto const&v : vars) {
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
glEnableVertexAttribArray(attr);
glVertexAttribPointer(
@@ -113,19 +113,19 @@ void setupShaderParams(
}
}
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept {
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
// get row len
GLsizei vertexRowLen{};
for (auto const &v : vars) {
for (auto const&v : vars) {
vertexRowLen += v.len;
}
setupShaderParams(shader, vars, vertexRowLen);
}
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const &vert,
ox::CStringView const &frag,
ox::CStringView const &geo) noexcept {
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo) noexcept {
GLProgram prgm(glCreateProgram());
OX_REQUIRE(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
glAttachShader(prgm, vs);
@@ -162,30 +162,16 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
// color texture
glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glGenerateMipmap(GL_TEXTURE_2D);
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
glGenRenderbuffers(1, &fb.depth.id);
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
fb.depth);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
// verify FBO
oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete");
// restore primary FB
@@ -203,16 +189,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture
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
@@ -224,7 +201,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) noexcept {
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
if (!fb) {
fb = generateFrameBuffer(width, height);
return;
@@ -232,18 +209,18 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) n
resizeFrameBuffer(fb, width, height);
}
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept {
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
resizeInitFrameBuffer(fb, sz.width, sz.height);
}
void sendVbo(BufferSet const &bs) noexcept {
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
void sendVbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
}
void sendEbo(BufferSet const &bs) noexcept {
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
void sendEbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);
}

217
deps/ox/ox-docs.md vendored
View File

@@ -28,7 +28,10 @@ All components have a platform indicator next to them:
Ox provides ```ox::Error``` to report errors.
```ox::Error``` is a struct that has overloaded operators to behave like an
integer error code, plus some extra fields to enhance debuggability.
```ox::Error```s will also include the file and line of the error.
If instantiated through the ```OxError(x)``` macro, it will also include the
file and line of the error.
The ```OxError(x)``` macro should only be used for the initial instantiation of
an ```ox::Error```.
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
```ox::Result``` simply wraps the type T value in a struct that also includes
@@ -46,7 +49,7 @@ ox::Result<int> foo(int i) noexcept {
if (i < 10) {
return i + 1; // implicitly calls ox::Result<T>::Result(T)
}
return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
return OxError(1); // implicitly calls ox::Result<T>::Result(ox::Error)
}
int caller1() {
@@ -178,216 +181,6 @@ variant for creating a non-const value.
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
### Ox String Types
Ox has six different major string types.
These types are divided into two categories: store types and view types.
String stores maintain a copy of the string data, whereas view types only
maintain a reference to the data.
Views should be used where you otherwise might use a const reference to a
string store type.
Having all of these different string types may sound like an interoperability
nightmare, but taking string view types extensively where applicable makes the
imagined interoperability issues virtually non-existent.
#### String Store Types
##### String / BasicString
```ox::String```, or really ```ox::BasicString```, is Ox's version of
```std::string```.
Like ```std::string```, ```String``` allocates to store the string data.
Also like ```std::string```, ```String``` allows for small string
optimization for strings under 8 bytes.
Unlike ```std::string```, the template that ```String``` is based on,
```BasicString```, takes a parameter that allows adjusting to different size
small string buffers.
```ox::String``` is an alias to ```ox::BasicString<8>```.
```cpp
// s can hold up to 100 bytes, plus one for a null terminator before allocating
ox::BasicString<100> s;
```
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
constructor.
This prevents accidental instantiations of ```String```.
Consider the following:
```cpp
void fStd(std::string const&);
void fOx(ox::String const&);
int main() {
// implicit and silent instantiation of std::string, which includes an
// allocation
fStd("123456789");
// Will fail to compile:
fOx("123456789");
// But explicit String instantiation will work:
fOx(ox::String{"123456789"});
}
```
##### IString
```IString```, or "inline string", is like ```BasicString```, but it will cut
off strings that exceed that limit.
```cpp
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
s = "12345"; // valid
s = "123456"; // will compile and run, but will get cut off at '5'
```
This is useful for certain string categories that have fixed lengths, like UUID
strings or for numbers.
Ox makes use of ```IString``` in the following ways:
```cpp
using UUIDStr = ox::IString<36>;
// and
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {
case 1:
out = 3;
break;
case 2:
out = 5;
break;
case 4:
out = 10;
break;
case 8:
out = 21;
break;
}
return out + ox::is_signed_v<Integer>;
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;
}
```
##### StringParam
```StringParam``` is a weird type.
Because ```String::String(const char*)``` is explicit, it becomes a pain for
functions to take ```String```s.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::String p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // invalid - will not compile
Type t2{s}; // invalid - will not compile
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
```StringParam``` has implicit conversion constructors, and will appropriately
move from r-value ```String```s or create a ```String``` if not passed
ownership of an existing ```String```.
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
strings.
```StringParam``` can access the string as a view through the ```view()```
function, and the ```String``` inside can be accessed by moving from the
```StringParam```.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::StringParam p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // valid
Type t2{s}; // valid
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
#### String View Types
##### StringView
```ox::StringView``` is Ox's version of ```std::string_view```.
```StringView``` contains a pointer to a string, along with its size.
This should be the normal type taken when a function needs a string that will
exist until it returns.
##### CStringView
```CStringView``` is like ```StringView```, but it comes with the promise that
the string ends with a null terminator.
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
function that ```StringView``` has.
```CStringView``` should be used when wrapping a C API that only takes C
strings.
##### StringLiteral
```StringLiteral``` is a string view type, but it kind of straddles the line
between view and store types.
Creating a ```StringLiteral``` is a promise that you are passing a string
literal into the constructor.
This means you can treat it like a store, that can be safely used as a copy of
the data.
Functions that take ```StringLiteral```s are allowed to assume that the data
will have no lifetime concerns and hold onto it without any need to make a
copy.
It has a consteval constructor to enforce the promise that it is a compile time
string.
```cpp
void f(ox::StringLiteral const&);
int main() {
f("123456789"); // valid
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
}
```
#### Other Variants
There are a few convenience aliases as well.
* StringCR = String const&
* StringViewCR = StringView const&
* CStringViewCR = CStringView const&
* CString = const char*
String views do not generally need const references, but it does make debugging
easier, as we can skip the constructor call if a string view already exists.
These kind of aliases probably should not exist for most types, but strings are
fundamental and ease of use is desirable.
### Logging and Output
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,19 +17,19 @@ namespace ox {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 1) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept {
return i;
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 2) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept {
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 4) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
return ((i >> 24) & 0x000000ff) |
((i >> 8) & 0x0000ff00) |
((i << 8) & 0x00ff0000) |
@@ -38,7 +38,7 @@ constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 4) {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 8) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept {
return ((i >> 56) & 0x00000000000000ff) |
((i >> 40) & 0x000000000000ff00) |
((i >> 24) & 0x0000000000ff0000) |

View File

@@ -32,8 +32,4 @@ concept Integral_c = ox::is_integral_v<T>;
template<typename T, size_t max>
concept IntegerRange_c = ox::is_integer_v<T> && ox::MaxValue<T> >= max;
template<typename Union>
concept Union_c = is_union_v<Union>;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,34 +18,34 @@ namespace ox {
template<Integer_c Integer>
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) 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) {
OX_RETURN_ERROR(writer.put('-'));
val = ~val + 1;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
constexpr auto start = '0';
if (digit >= 10) [[unlikely]] {
digit -= 10;
OX_RETURN_ERROR(writer.put('1'));
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
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) {
OX_RETURN_ERROR(writer.put('-'));
++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;
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
++it;
}
}
} else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
} else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
return {};
return {};
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -28,4 +28,3 @@ add_test("[ox/std] FromHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "FromHex")
add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

@@ -183,7 +183,7 @@ OX_CLANG_NOWARN_END
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.size() == 4, "String assign broken");
oxAssert(s.len() == 4, "String assign broken");
return ox::Error(0);
}
},
@@ -337,6 +337,7 @@ OX_CLANG_NOWARN_END
oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii;
@@ -536,33 +537,6 @@ OX_CLANG_NOWARN_END
return ox::Error(0);
}
},
{
"intToStr",
[] {
oxExpect(ox::intToStr(static_cast<int8_t>(127)), "127");
oxExpect(ox::intToStr(static_cast<int8_t>(-128)), "-128");
oxExpect(ox::intToStr(static_cast<uint8_t>(255)), "255");
oxExpect(ox::intToStr(static_cast<uint16_t>(65535)), "65535");
oxExpect(ox::intToStr(static_cast<int16_t>(32767)), "32767");
oxExpect(ox::intToStr(static_cast<int16_t>(-32768)), "-32768");
oxExpect(ox::intToStr(static_cast<uint32_t>(4294967295)), "4294967295");
oxExpect(ox::intToStr(static_cast<int32_t>(2147483647)), "2147483647");
oxExpect(ox::intToStr(static_cast<int32_t>(-2147483648)), "-2147483648");
oxExpect(ox::intToStr(static_cast<uint64_t>(18446744073709551615u)), "18446744073709551615");
oxExpect(ox::intToStr(static_cast<int64_t>(9223372036854775807)), "9223372036854775807");
oxExpect(ox::intToStr(static_cast<int64_t>(-9223372036854775807)), "-9223372036854775807");
oxExpect(ox::intToStr(0), "0");
oxExpect(ox::intToStr(5), "5");
oxExpect(ox::intToStr(5000), "5000");
oxExpect(ox::intToStr(50000), "50000");
oxExpect(ox::intToStr(500000), "500000");
oxExpect(ox::intToStr(-5), "-5");
oxExpect(ox::intToStr(-5000), "-5000");
oxExpect(ox::intToStr(-50000), "-50000");
oxExpect(ox::intToStr(-500000), "-500000");
return ox::Error{};
}
},
};
int main(int argc, const char **argv) {

View File

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

View File

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

View File

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

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {};
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept {
constexpr void allocate(T **items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap);
@@ -49,31 +49,45 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom(
T **items,
VectorAllocator *src,
std::size_t const count,
std::size_t const cap) noexcept {
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
new (&m_data[i]) T(std::move(*srcItem));
}
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data());
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
std::construct_at<T>(dstItem, std::move(*srcItem));
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) {
if (items) {
Allocator{}.deallocate(items, cap);
}
Allocator{}.deallocate(items, cap);
} else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap);
@@ -87,10 +101,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> {
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept {
constexpr void allocate(T **items, std::size_t cap) noexcept {
*items = Allocator{}.allocate(cap);
}
@@ -98,15 +112,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom(
T**,
VectorAllocator*,
std::size_t const,
std::size_t const) noexcept {
const std::size_t,
const std::size_t) noexcept {
}
[[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept {
constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
}
constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
constexpr void deallocate(T *items, std::size_t cap) noexcept {
if (items) {
Allocator{}.deallocate(items, cap);
}
@@ -247,8 +261,6 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void resize(std::size_t size) noexcept(useNoexcept);
constexpr void reserveResize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]]
constexpr T *data() noexcept {
return m_items;
@@ -273,9 +285,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T const &item) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void push_back(T item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept);
@@ -409,7 +419,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
this->moveItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
@@ -519,12 +529,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
m_size = size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(std::size_t const size) noexcept(useNoexcept) {
reserve(size);
resize(size);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) {
@@ -611,16 +615,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}

View File

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

View File

@@ -37,10 +37,8 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept;
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept;
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
}

View File

@@ -26,7 +26,7 @@ extern void (*__preinit_array_end[]) (void);
extern void (*__init_array_start[]) (void);
extern void (*__init_array_end[]) (void);
int main(int argc, char const **argv);
int main(int argc, const char **argv);
extern "C" {
@@ -50,7 +50,7 @@ void __libc_init_array() {
}
int c_start() {
char const *args[2] = {"", "rom.oxfs"};
const char *args[2] = {"", "rom.oxfs"};
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
mgba::initConsole();
#pragma GCC diagnostic push

View File

@@ -12,13 +12,13 @@ namespace teagba {
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept {
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
return g_spriteBuffer[i];
}
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept {
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
const auto ie = REG_IE; // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~Int_vblank); // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
g_spriteBuffer[upd.idx] = upd;
REG_IE = ie; // enable vblank interrupt handler
}
@@ -29,10 +29,4 @@ void applySpriteUpdates() noexcept {
}
}
void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = x;
o.y = y;
}
}

View File

@@ -27,9 +27,9 @@ All components have a platform indicator next to them:
* opengl - OpenGL implementation (P-)
* studio - studio plugin for core (P-)
* keel - keel plugin for core (PG)
* sound - sound system for Nostalgia (PG)
* studio - studio plugin for sound (P-)
* keel - keel plugin for sound (PG)
* scene - defines & processes map data (PG)
* studio - studio plugin for scene (P-)
* keel - keel plugin for scene (PG)
* player - plays the games (PG)
* studio - makes the games (P-)
* tools - command line tools (P-)
@@ -48,7 +48,7 @@ All components have a platform indicator next to them:
Not really that external... (PG)
* GlUtils - OpenGL helpers (P-)
* teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL
2.0), and custom GBA hardware interop code (-G)
2.0), and custom GBA hardware interop code (-G)
Most GBA code is built on PC because it is small and helps to work on both
projects with the same CMake build dir, but GBA code is never linked with any
@@ -89,8 +89,7 @@ The GBA has two major resources for learning about its hardware:
On the surface, it seems like C++ changes the way we do things from C for no
reason, but there are reasons for many of these duplications of functionality.
The C++ language designers aren't stupid.
Question them, but don't ignore them.
The C++ language designers aren't stupid. Question them, but don't ignore them.
#### Casting
@@ -164,11 +163,10 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling
Instead of throwing exceptions, generally try to use
[ox::Error](deps/ox/ox-docs.md#error-handling) for error reporting.
Exceptions may be used where errors-as-values will not work, but catch them and
convert them to ```ox::Error``` as soon as possible.
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
but exceptions may be used where they make sense.
Exceptions should generally just use ```ox::Exception```, which is basically an
Exceptions should generally just use ```OxException```, which is bascially an
exception form of ```ox::Error```.
### File I/O

View File

@@ -1,9 +1,3 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0
* Add ability to remember recent projects in config

View File

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

View File

@@ -12,37 +12,8 @@ constexpr auto TileWidth = 8;
constexpr auto TileHeight = 8;
constexpr auto PixelsPerTile = TileWidth * TileHeight;
constexpr ox::StringLiteral FileExt_ng{"ng"};
constexpr ox::StringLiteral FileExt_nts{"nts"};
constexpr ox::StringLiteral FileExt_npal{"npal"};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_TileSheet{
FileExt_nts,
FileExt_ng,
};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_Palette{
FileExt_npal,
};
[[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_TileSheet.begin(),
FileExts_TileSheet.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
[[nodiscard]]
constexpr bool isPalette(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_Palette.begin(),
FileExts_Palette.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
constexpr ox::StringLiteral FileExt_ng("ng");
constexpr ox::StringLiteral FileExt_nts("nts");
constexpr ox::StringLiteral FileExt_npal("npal");
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,15 +23,22 @@ struct BgCbbData {
unsigned bpp = 4;
};
class Context final {
class Context {
public:
turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData;
ox::Array<OffsetPair, 4> bgOffsets;
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context const &other) noexcept = delete;
Context(Context &other) noexcept = delete;
Context(Context const&other) noexcept = delete;
Context(Context const&&other) noexcept = delete;
virtual ~Context() noexcept = default;
[[nodiscard]]
ox::MemFS const&rom() const noexcept {
return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
}
};
@@ -69,12 +76,12 @@ ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&) no
ox::Error loadBgPalette(
Context&,
size_t const palBank,
CompactPalette const &palette,
CompactPalette const&palette,
size_t const page) noexcept {
if (palette.pages.empty()) {
return {};
}
auto const paletteMem = ox::Span{MEM_BG_PALETTE} + palBank * 16;
auto const paletteMem = MEM_BG_PALETTE + palBank * 16;
for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i);
}
@@ -83,13 +90,14 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette(
Context&,
CompactPalette const &palette,
CompactPalette const&palette,
size_t const page) noexcept {
if (palette.pages.empty()) {
return {};
}
auto const paletteMem = MEM_SPRITE_PALETTE;
for (auto i = 0u; i < colorCnt(palette, page); ++i) {
MEM_SPRITE_PALETTE[i] = color(palette, page, i);
paletteMem[i] = color(palette, page, i);
}
return {};
}
@@ -110,15 +118,15 @@ void clearCbbs(Context &ctx) noexcept {
static ox::Error loadTileSheetSet(
Context &ctx,
ox::Span<uint16_t> tileMapTargetMem,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
size_t tileWriteIdx = 0;
size_t const bppMod = set.bpp == 4;
for (auto const &entry : set.entries) {
for (auto const&entry : set.entries) {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet));
if (set.bpp != ts->bpp && ts->bpp == 8) {
return ox::Error(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB");
}
for (auto const &s : entry.sections) {
for (auto const&s : entry.sections) {
auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) >> bppMod;
for (size_t i = 0; i < cnt; ++i) {
auto const begin = static_cast<size_t>(s.begin) * (PixelsPerTile >> bppMod);
@@ -137,7 +145,7 @@ static ox::Error loadTileSheetSet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const &ts,
CompactTileSheet const&ts,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
@@ -165,10 +173,10 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept {
auto const cnt = ts.pixels.size() >> (ts.bpp == 4);
for (size_t i{}; i < cnt; ++i) {
CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept {
auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
for (size_t i = 0; i < cnt; ++i) {
auto const srcIdx = i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
@@ -190,7 +198,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set));
// update bpp of all bgs with the updated cbb
@@ -214,13 +222,12 @@ static void setSpritesBpp(unsigned const bpp) noexcept {
ox::Error loadSpriteTileSheet(
Context &ctx,
CompactTileSheet const &ts,
CompactTileSheet const&ts,
bool const loadDefaultPalette) noexcept {
for (size_t i{}; i < ts.pixels.size(); i += 2) {
MEM_SPRITE_TILES[i >> 1] =
static_cast<uint16_t>(
ts.pixels[i] |
(static_cast<uint16_t>(ts.pixels[i + 1]) << 8));
for (size_t i = 0; i < ts.pixels.size(); i += 2) {
uint16_t v = ts.pixels[i];
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
MEM_SPRITE_TILES[i] = v;
}
if (loadDefaultPalette && ts.defaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@@ -231,19 +238,15 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set));
OX_RETURN_ERROR(loadTileSheetSet(ctx, {MEM_SPRITE_TILES, 32 * ox::units::KB}, set));
setSpritesBpp(bpp);
return {};
}
void setBgTile(
Context &ctx,
uint_t const bgIdx,
int const column,
int const row,
BgTile const &tile) noexcept {
Context &ctx, uint_t const bgIdx, int const column, int const row, BgTile const&tile) noexcept {
auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column);
// see Tonc 9.3
MEM_BG_MAP[bgIdx][tileIdx] =
@@ -272,7 +275,7 @@ bool bgStatus(Context&, unsigned const bg) noexcept {
void setBgStatus(Context&, unsigned const bg, bool const status) noexcept {
constexpr auto Bg0Status = 8;
auto const 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);
}
@@ -283,7 +286,7 @@ void setBgBpp(Context&, unsigned const bgIdx, unsigned const bpp) noexcept {
void setBgCbb(Context &ctx, unsigned const bgIdx, unsigned const cbbIdx) noexcept {
auto &bgCtl = regBgCtl(bgIdx);
auto const &cbbData = ctx.cbbData[cbbIdx];
const auto &cbbData = ctx.cbbData[cbbIdx];
teagba::bgSetBpp(bgCtl, cbbData.bpp);
teagba::bgSetCbb(bgCtl, cbbIdx);
}
@@ -293,18 +296,6 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
}
void setBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
ctx.bgOffsets[bg] = {.x = x, .y = y};
teagba::setBgOffset(bg, x, y);
}
void scrollBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = ctx.bgOffsets[bg];
o.x += x;
o.y += y;
teagba::setBgOffset(bg, o.x, o.y);
}
void hideSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({
@@ -321,7 +312,7 @@ void showSprite(Context&, unsigned const idx) noexcept {
});
}
void setSprite(Context&, uint_t const idx, Sprite const &s) noexcept {
void setSprite(Context&, uint_t const idx, Sprite const&s) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
uint16_t const eightBpp = s.bpp == 8;
teagba::addSpriteUpdate({
@@ -342,7 +333,7 @@ void setSprite(Context&, uint_t const idx, Sprite const &s) noexcept {
});
}
uint_t spriteCount(Context const &) noexcept {
uint_t spriteCount(Context const&) noexcept {
return SpriteCount;
}
@@ -350,13 +341,13 @@ uint_t spriteCount(Context const &) noexcept {
namespace ox {
void panic(char const *file, int line, char const *panicMsg, ox::Error const &err) noexcept {
void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM.data());
auto const heapSz = MEM_EWRAM.size() / 2;
auto const heapEnd = reinterpret_cast<char*>(MEM_EWRAM.data() + heapSz);
const auto heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN);
const auto heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2;
const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz);
ox::heapmgr::initHeap(heapBegin, heapEnd);
OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();

View File

@@ -87,7 +87,9 @@ class Context {
blocksPerSprite{params.glBlocksPerSprite} {
}
Context(Context const&) = delete;
Context(Context&&) = delete;
Context &operator=(Context const&) = delete;
Context &operator=(Context&&) = delete;
~Context() noexcept {
turbine::gl::removeDrawer(turbineCtx, &drawer);
}
@@ -111,7 +113,7 @@ namespace renderer {
static constexpr auto Scale = 1;
static constexpr auto PriorityScale = 0.01f;
static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
static constexpr ox::CStringView bgvshadTmpl = R"glsl(
{}
in vec2 vTexCoord;
in vec3 vPosition;
@@ -133,9 +135,9 @@ static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
fPalOffset = vPalOffset;
})glsl"};
})glsl";
static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
static constexpr ox::CStringView bgfshadTmpl = R"glsl(
{}
out vec4 outColor;
in float fPalOffset;
@@ -149,9 +151,9 @@ static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
if (outColor.a == 0) {
discard;
}
})glsl"};
})glsl";
static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
static constexpr ox::CStringView spritevshadTmpl = R"glsl(
{}
in float vEnabled;
in vec3 vPosition;
@@ -168,9 +170,9 @@ static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
vPosition.z - 0.004,
1.0) * vEnabled;
fTexCoord = vTexCoord * vec2(1, vTileHeight);
})glsl"};
})glsl";
static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
static constexpr ox::CStringView spritefshadTmpl = R"glsl(
{}
out vec4 outColor;
in vec2 fTexCoord;
@@ -183,7 +185,7 @@ static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
if (outColor.a == 0) {
discard;
}
})glsl"};
})glsl";
[[nodiscard]]
static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept {
@@ -285,7 +287,7 @@ static void initSpriteBufferObjects(Context const &ctx, glutils::BufferSet &bs)
static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
for (auto x = 0u; x < TileColumns; ++x) {
for (auto y = 0u; y < TileRows; ++y) {
auto const i = bgVertexRow(x, y);
const auto i = bgVertexRow(x, y);
auto const vbo = ox::Span{bs.vertices}
+ i * static_cast<std::size_t>(BgVertexVboLength);
auto const ebo = ox::Span{bs.elements}
@@ -385,7 +387,7 @@ static void initBackgroundBufferset(
static glutils::GLTexture createTexture(
GLsizei const w,
GLsizei const h,
void const *pixels) noexcept {
void const*pixels) noexcept {
GLuint texId = 0;
glGenTextures(1, &texId);
glutils::GLTexture tex(texId);
@@ -423,22 +425,22 @@ static void drawBackground(CBB &cbb) noexcept {
static void drawBackgrounds(
Context &ctx,
ox::Size const &renderSz) noexcept {
ox::Size const&renderSz) noexcept {
// load background shader and its uniforms
glUseProgram(ctx.bgShader);
auto const uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz");
auto const uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale"));
auto const uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight"));
auto const uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx"));
auto const [wi, hi] = renderSz;
auto const wf = static_cast<float>(wi);
auto const hf = static_cast<float>(hi);
const auto uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz");
const auto uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale"));
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight"));
const auto uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx"));
const auto [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf);
auto bgIdx = 0.f;
for (auto const &bg : ctx.backgrounds) {
for (const auto &bg : ctx.backgrounds) {
if (bg.enabled) {
auto &cbb = ctx.cbbs[bg.cbbIdx];
auto const tileRows = cbb.tex.height / (TileHeight * Scale);
const auto tileRows = cbb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
glUniform2f(
uniformSrcImgSz,
@@ -451,14 +453,14 @@ static void drawBackgrounds(
}
}
static void drawSprites(Context &ctx, ox::Size const &renderSz) noexcept {
static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
glUseProgram(ctx.spriteShader);
auto &sb = ctx.spriteBlocks;
auto const uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
auto const uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight");
auto const [wi, hi] = renderSz;
auto const wf = static_cast<float>(wi);
auto const hf = static_cast<float>(hi);
const auto uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
const auto uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight");
const auto [wi, hi] = renderSz;
const auto wf = static_cast<float>(wi);
const auto hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf);
// update vbo
glBindVertexArray(sb.vao);
@@ -467,7 +469,7 @@ static void drawSprites(Context &ctx, ox::Size const &renderSz) noexcept {
glutils::sendVbo(sb);
}
// set vTileHeight uniform
auto const tileRows = sb.tex.height / (TileHeight * Scale);
const auto tileRows = sb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
// draw
glBindTexture(GL_TEXTURE_2D, sb.tex);
@@ -479,7 +481,7 @@ static void loadPalette(
ox::Array<GLfloat, 1024> &palette,
size_t const palOffset,
GLuint const shaderPgrm,
CompactPalette const &pal,
CompactPalette const&pal,
size_t const page = 0) noexcept {
static constexpr std::size_t ColorCnt = 256;
for (auto i = palOffset; auto const c : pal.pages[page]) {
@@ -491,14 +493,14 @@ static void loadPalette(
// make first color transparent
palette[palOffset + 3] = 0;
glUseProgram(shaderPgrm);
auto const uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
glUniform4fv(uniformPalette, ColorCnt, palette.data());
}
static void setSprite(
Context &ctx,
uint_t const idx,
Sprite const &s) noexcept {
Sprite const&s) noexcept {
// Tonc Table 8.4
struct Sz { uint_t x{}, y{}; };
static constexpr ox::Array<Sz, 12> dimensions{
@@ -524,12 +526,12 @@ static void setSprite(
auto const uY = static_cast<int>(s.y + 8) % 255 - 8;
oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow");
oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow");
auto const spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength;
auto const spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength;
const auto spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength;
const auto spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength;
auto const vboBase = spriteVboSz * idx;
auto const eboBase = spriteEboSz * idx;
auto i = 0u;
auto const set = [&](int xIt, int yIt, bool enabled) {
const auto set = [&](int xIt, int yIt, bool enabled) {
auto const fX = static_cast<float>(uX + xIt * 8) / 8;
auto const fY = static_cast<float>(uY + yIt * 8) / 8;
auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i;
@@ -572,12 +574,12 @@ static void setSprite(
}
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params) noexcept {
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params) noexcept {
auto ctx = ox::make_unique<Context>(tctx, params);
auto const bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
auto const bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
auto const spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
auto const spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion);
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion);
OX_RETURN_ERROR(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx->bgShader));
OX_RETURN_ERROR(
glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx->spriteShader));
@@ -601,12 +603,12 @@ struct TileSheetData {
}
};
static ox::Result<TileSheetData> normalizeTileSheet
(CompactTileSheet const &ts) noexcept {
static ox::Result<TileSheetData> normalizeTileSheet(
CompactTileSheet const&ts) noexcept {
const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
auto const tiles = ts.pixels.size() / bytesPerTile;
const auto tiles = ts.pixels.size() / bytesPerTile;
constexpr int width = 8;
int const height = 8 * static_cast<int>(tiles);
const int height = 8 * static_cast<int>(tiles);
ox::Vector<uint32_t> pixels;
if (bytesPerTile == 64) { // 8 BPP
pixels.resize(ts.pixels.size());
@@ -630,7 +632,7 @@ static ox::Result<TileSheetData> normalizeTileSheet
ox::Error loadBgPalette(
Context &ctx,
size_t const palBank,
CompactPalette const &palette,
CompactPalette const&palette,
size_t const page) noexcept {
renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page);
return {};
@@ -638,7 +640,7 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette(
Context &ctx,
CompactPalette const &palette,
CompactPalette const&palette,
size_t const page) noexcept {
ox::Array<GLfloat, 1024> pal;
renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page);
@@ -647,14 +649,14 @@ ox::Error loadSpritePalette(
static ox::Result<TileSheetData> buildSetTsd(
Context const &ctx,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx);
TileSheetData setTsd;
setTsd.width = TileWidth;
for (auto const &entry : set.entries) {
for (auto const&entry : set.entries) {
OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet));
for (auto const &s : entry.sections) {
for (auto const&s : entry.sections) {
auto const size = s.tiles * PixelsPerTile;
for (auto i = 0; i < size; ++i) {
auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile);
@@ -667,7 +669,7 @@ static ox::Result<TileSheetData> buildSetTsd(
}
static void copyPixels(
CompactTileSheet const &ts,
CompactTileSheet const&ts,
ox::Span<uint32_t> const dst,
size_t const srcPxIdx,
size_t const pxlCnt) noexcept {
@@ -702,7 +704,7 @@ void clearCbbs(Context &ctx) noexcept {
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const &ts,
CompactTileSheet const&ts,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
@@ -726,8 +728,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
uint_t const cbb,
CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept {
CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept {
auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
auto const tiles = ts.pixels.size() / bytesPerTile;
OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles));
@@ -740,7 +742,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {};
@@ -748,7 +750,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
CompactTileSheet const &ts,
CompactTileSheet const&ts,
bool const loadDefaultPalette) noexcept {
OX_REQUIRE(tsd, normalizeTileSheet(ts));
oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
@@ -761,7 +763,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
TileSheetSet const &set) noexcept {
TileSheetSet const&set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {};
@@ -772,18 +774,18 @@ void setBgTile(
uint_t const bgIdx,
int const column,
int const row,
BgTile const &tile) noexcept {
BgTile const&tile) noexcept {
oxTracef(
"nostalgia.gfx.setBgTile",
"bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}",
bgIdx, column, row, tile.tileIdx, tile.palBank);
auto const z = static_cast<uint_t>(bgIdx);
auto const y = static_cast<uint_t>(row);
auto const x = static_cast<uint_t>(column);
auto const i = renderer::bgVertexRow(x, y);
const auto z = static_cast<uint_t>(bgIdx);
const auto y = static_cast<uint_t>(row);
const auto x = static_cast<uint_t>(column);
const auto i = renderer::bgVertexRow(x, y);
auto &cbb = ctx.cbbs[z];
auto const vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
auto const ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
auto &bg = ctx.backgrounds[bgIdx];
renderer::setTileBufferObject(
static_cast<uint_t>(i * renderer::BgVertexVboRows),
@@ -839,12 +841,6 @@ void setBgPriority(Context &ctx, uint_t const bgIdx, uint_t const priority) noex
bg.priority = static_cast<float>(priority & 0b11);
}
void setBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void scrollBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void hideSprite(Context &ctx, uint_t const idx) noexcept {
auto &s = ctx.spriteStates[idx];
s.enabled = false;
@@ -857,7 +853,7 @@ void showSprite(Context &ctx, uint_t const idx) noexcept {
renderer::setSprite(ctx, idx, s);
}
void setSprite(Context &ctx, uint_t const idx, Sprite const &sprite) noexcept {
void setSprite(Context &ctx, uint_t const idx, Sprite const&sprite) noexcept {
auto &s = ctx.spriteStates[idx];
s = sprite;
renderer::setSprite(ctx, idx, s);
@@ -873,7 +869,7 @@ ox::Size drawSize(int const scale) noexcept {
return {240 * scale, 160 * scale};
}
void draw(Context &ctx, ox::Size const &renderSz) noexcept {
void draw(Context &ctx, ox::Size const&renderSz) noexcept {
glViewport(0, 0, renderSz.width, renderSz.height);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);

View File

@@ -10,11 +10,11 @@ namespace nostalgia::gfx {
constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32;
int tileColumns(Context const&) noexcept {
int tileColumns(Context&) noexcept {
return GbaTileColumns;
}
int tileRows(Context const&) noexcept {
int tileRows(Context&) noexcept {
return GbaTileRows;
}
@@ -51,7 +51,7 @@ ox::Error loadSpritePalette(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
ox::FileAddress const &tsAddr,
ox::FileAddress const&tsAddr,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
@@ -74,7 +74,7 @@ ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const &paletteBank) noexcept {
ox::Optional<unsigned> const&paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}
@@ -82,8 +82,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
ox::FileAddress const &tilesheetAddr,
ox::Optional<unsigned> const &paletteBank) noexcept {
ox::FileAddress const&tilesheetAddr,
ox::Optional<unsigned> const&paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
}
@@ -98,7 +98,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::FileAddress const &tilesheetAddr,
ox::FileAddress const&tilesheetAddr,
bool const loadDefaultPalette) noexcept {
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
@@ -249,7 +249,7 @@ void setBgTile(
}
ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts");
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0);

View File

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

View File

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

View File

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

View File

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

View File

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)),
m_sctx(sctx),
m_tctx(sctx.tctx),
m_pal(m_sctx.project->loadObj<Palette>(itemPath()).unwrapThrow()) {
m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) {
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,7 +49,7 @@ TileSheetEditorModel::TileSheetEditorModel(
m_sctx{sctx},
m_tctx{m_sctx.tctx},
m_path{std::move(path)},
m_img{m_sctx.project->loadObj<TileSheet>(m_path).unwrapThrow()},
m_img{*readObj<TileSheet>(keelCtx(m_tctx), m_path).unwrapThrow()},
// ignore failure to load palette
m_pal{readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).value},
m_undoStack{undoStack} {
@@ -66,7 +66,7 @@ void TileSheetEditorModel::cut() {
}
TileSheetClipboard blankCb;
auto cb = ox::make_unique<TileSheetClipboard>();
auto const &s = activeSubSheet();
auto const&s = activeSubSheet();
if (iterateSelectionRows(*m_selection, [&](int const x, int const y) {
auto pt = ox::Point{x, y};
auto const idx = gfx::idx(s, pt);
@@ -97,7 +97,7 @@ void TileSheetEditorModel::copy() {
auto cb = ox::make_unique<TileSheetClipboard>();
if (iterateSelectionRows(*m_selection, [&](int const x, int const y) {
auto pt = ox::Point{x, y};
auto const &s = activeSubSheet();
auto const&s = activeSubSheet();
auto const idx = gfx::idx(s, pt);
if (idx >= s.pixels.size()) {
return ox::Error{1, "invalid idx"};
@@ -122,7 +122,7 @@ void TileSheetEditorModel::paste() {
oxErrf("Could not read clipboard: {}", toStr(err));
return;
}
auto const &s = activeSubSheet();
auto const&s = activeSubSheet();
auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
if (auto cmd = ox::make_unique_catch<CutPasteCommand>(
@@ -235,7 +235,7 @@ void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const &idx)
}
void TileSheetEditorModel::fill(ox::Point const &pt, uint8_t const palIdx) noexcept {
auto const &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
auto const&activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
// build idx list
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
return;
@@ -303,7 +303,7 @@ void TileSheetEditorModel::completeSelection() noexcept {
m_selTracker.finishSelection();
m_selection.emplace(m_selTracker.selection());
auto&pt = m_selection->b;
auto const &s = activeSubSheet();
auto const&s = activeSubSheet();
pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
}
@@ -356,7 +356,7 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
}
bool TileSheetEditorModel::pixelSelected(std::size_t const idx) const noexcept {
auto const &s = activeSubSheet();
auto const&s = activeSubSheet();
auto const pt = idxToPt(static_cast<int>(idx), s.columns);
return m_selection && m_selection->contains(pt);
}
@@ -398,7 +398,7 @@ ox::Error TileSheetEditorModel::moveSubSheet(TileSheet::SubSheetIdx src, TileShe
}
void TileSheetEditorModel::getFillPixels(
TileSheet::SubSheet const &activeSubSheet,
TileSheet::SubSheet const&activeSubSheet,
ox::Span<bool> const pixels,
ox::Point const &pt,
uint8_t const oldColor) noexcept {
@@ -448,7 +448,7 @@ ox::Error TileSheetEditorModel::pushCommand(ox::UPtr<studio::UndoCommand> &&cmd)
return {};
}
ox::Error TileSheetEditorModel::handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const &id) noexcept {
ox::Error TileSheetEditorModel::handleFileRename(ox::StringViewCR, ox::StringViewCR newPath, ox::UUID const&id) noexcept {
if ((beginsWith(m_img.defaultPalette, "uuid://") &&
substr(m_img.defaultPalette, 7) == id.toString()) ||
m_img.defaultPalette == newPath) {

View File

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

View File

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

View File

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

View File

@@ -66,20 +66,19 @@ class TileSheetGrid {
ox::Error buildShader() noexcept;
void draw(bool update, ox::Vec2 const &scroll) noexcept;
void draw(bool update, ox::Vec2 const&scroll) noexcept;
void initBufferSet(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;
void initBufferSet(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept;
void update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;
void update(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept;
private:
static void setBufferObject(
ox::Point pt1, ox::Point pt2, Color32 c, ox::Span<float> vbo, ox::Vec2 const &pixSize) noexcept;
static void setBufferObject(ox::Point pt1, ox::Point pt2, Color32 c, ox::Span<float> vbo, ox::Vec2 const&pixSize) noexcept;
void setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept;
void setBufferObjects(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept;
[[nodiscard]]
ox::Vec2 pixelSize(ox::Vec2 const &paneSize) const noexcept;
ox::Vec2 pixelSize(ox::Vec2 const&paneSize) const noexcept;
};

View File

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

View File

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

View File

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

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