Compare commits
1 Commits
2761f23d31
...
release-d2
Author | SHA1 | Date | |
---|---|---|---|
889fe04255 |
17
deps/glutils/include/glutils/glutils.hpp
vendored
17
deps/glutils/include/glutils/glutils.hpp
vendored
@ -13,7 +13,6 @@
|
|||||||
#include <ox/std/error.hpp>
|
#include <ox/std/error.hpp>
|
||||||
#include <ox/std/size.hpp>
|
#include <ox/std/size.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
#include <ox/std/vec.hpp>
|
|
||||||
#include <ox/std/vector.hpp>
|
#include <ox/std/vector.hpp>
|
||||||
|
|
||||||
namespace glutils {
|
namespace glutils {
|
||||||
@ -138,22 +137,6 @@ struct FrameBuffer {
|
|||||||
constexpr operator const GLuint&() const noexcept {
|
constexpr operator const GLuint&() const noexcept {
|
||||||
return fbo.id;
|
return fbo.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr ox::Vec2 sizef() const noexcept {
|
|
||||||
return {
|
|
||||||
static_cast<float>(width),
|
|
||||||
static_cast<float>(height),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr ox::Size size() const noexcept {
|
|
||||||
return {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FrameBufferBind {
|
class FrameBufferBind {
|
||||||
|
2
deps/glutils/src/glutils.cpp
vendored
2
deps/glutils/src/glutils.cpp
vendored
@ -102,7 +102,7 @@ void setupShaderParams(
|
|||||||
ox::Vector<ShaderVarSet> const&vars,
|
ox::Vector<ShaderVarSet> const&vars,
|
||||||
GLsizei vertexRowLen) noexcept {
|
GLsizei vertexRowLen) noexcept {
|
||||||
// setup vars
|
// setup vars
|
||||||
for (size_t lenWritten = 0; auto const&v : vars) {
|
for (auto lenWritten = 0LU; auto const&v : vars) {
|
||||||
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
|
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
|
||||||
glEnableVertexAttribArray(attr);
|
glEnableVertexAttribArray(attr);
|
||||||
glVertexAttribPointer(
|
glVertexAttribPointer(
|
||||||
|
2
deps/ox/src/ox/claw/format.hpp
vendored
2
deps/ox/src/ox/claw/format.hpp
vendored
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
enum class ClawFormat {
|
enum class ClawFormat: int {
|
||||||
None,
|
None,
|
||||||
Metal,
|
Metal,
|
||||||
Organic,
|
Organic,
|
||||||
|
15
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
15
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
@ -99,21 +99,6 @@ class FileSystem {
|
|||||||
|
|
||||||
Result<FileStat> stat(const FileAddress &addr) const noexcept;
|
Result<FileStat> stat(const FileAddress &addr) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
inline bool exists(uint64_t inode) const noexcept {
|
|
||||||
return statInode(inode).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
inline bool exists(ox::StringView path) const noexcept {
|
|
||||||
return statPath(path).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
inline bool exists(FileAddress const&addr) const noexcept {
|
|
||||||
return stat(addr).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
|
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
|
||||||
|
|
||||||
|
7
deps/ox/src/ox/model/desctypes.hpp
vendored
7
deps/ox/src/ox/model/desctypes.hpp
vendored
@ -34,16 +34,15 @@ constexpr auto buildTypeId() noexcept {
|
|||||||
return ox::sfmt("{};{}", name, version);
|
return ox::sfmt("{};{}", name, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto buildTypeId(
|
static constexpr auto buildTypeId(CRStringView name, int version,
|
||||||
CRStringView name, int version,
|
const TypeParamPack &typeParams = {}) noexcept {
|
||||||
const TypeParamPack &typeParams = {}) noexcept {
|
|
||||||
String tp;
|
String tp;
|
||||||
if (!typeParams.empty()) {
|
if (!typeParams.empty()) {
|
||||||
tp = "#";
|
tp = "#";
|
||||||
for (const auto &p : typeParams) {
|
for (const auto &p : typeParams) {
|
||||||
tp += p + ",";
|
tp += p + ",";
|
||||||
}
|
}
|
||||||
tp.resize(tp.len());
|
tp.resize(tp.len() - 1);
|
||||||
tp += "#";
|
tp += "#";
|
||||||
}
|
}
|
||||||
return ox::sfmt("{}{};{}", name, tp, version);
|
return ox::sfmt("{}{};{}", name, tp, version);
|
||||||
|
19
deps/ox/src/ox/preloader/preloader.hpp
vendored
19
deps/ox/src/ox/preloader/preloader.hpp
vendored
@ -94,7 +94,7 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename U, bool force>
|
template<typename U, bool force>
|
||||||
constexpr ox::Error field(CRStringView, ox::UnionView<U, force> val) noexcept;
|
constexpr ox::Error field(CRStringView, const ox::UnionView<U, force> val) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr ox::Error field(CRStringView, const T *val) noexcept;
|
constexpr ox::Error field(CRStringView, const T *val) noexcept;
|
||||||
@ -135,9 +135,6 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
|
|||||||
constexpr ox::Error fieldArray(CRStringView name, ox::ModelValueArray const*val) noexcept;
|
constexpr ox::Error fieldArray(CRStringView name, ox::ModelValueArray const*val) noexcept;
|
||||||
|
|
||||||
constexpr bool unionCheckAndIt() noexcept;
|
constexpr bool unionCheckAndIt() noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr size_t calcPadding(size_t align) const noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename PlatSpec>
|
template<typename PlatSpec>
|
||||||
@ -268,7 +265,7 @@ template<typename PlatSpec>
|
|||||||
constexpr ox::Result<std::size_t> Preloader<PlatSpec>::startAlloc(size_t sz, size_t align) noexcept {
|
constexpr ox::Result<std::size_t> Preloader<PlatSpec>::startAlloc(size_t sz, size_t align) noexcept {
|
||||||
m_allocStack.emplace_back(static_cast<typename PlatSpec::PtrType>(m_writer.tellp()));
|
m_allocStack.emplace_back(static_cast<typename PlatSpec::PtrType>(m_writer.tellp()));
|
||||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||||
auto const padding = calcPadding(align);
|
const auto padding = m_writer.tellp() % align;
|
||||||
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
||||||
a += padding;
|
a += padding;
|
||||||
oxReturnError(m_writer.seekp(a));
|
oxReturnError(m_writer.seekp(a));
|
||||||
@ -281,7 +278,7 @@ constexpr ox::Result<std::size_t> Preloader<PlatSpec>::startAlloc(
|
|||||||
std::size_t sz, size_t align, std::size_t restore) noexcept {
|
std::size_t sz, size_t align, std::size_t restore) noexcept {
|
||||||
m_allocStack.emplace_back(restore, ox::ios_base::beg);
|
m_allocStack.emplace_back(restore, ox::ios_base::beg);
|
||||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||||
auto const padding = calcPadding(align);
|
const auto padding = m_writer.tellp() % align;
|
||||||
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
oxRequireM(a, ox::allocate(m_writer, sz + padding));
|
||||||
a += padding;
|
a += padding;
|
||||||
oxReturnError(m_writer.seekp(a));
|
oxReturnError(m_writer.seekp(a));
|
||||||
@ -361,7 +358,7 @@ constexpr ox::Error Preloader<PlatSpec>::fieldVector(
|
|||||||
const auto sz = sizeOf<PlatSpec>(&(*val)[0]) * val->size();
|
const auto sz = sizeOf<PlatSpec>(&(*val)[0]) * val->size();
|
||||||
const auto align = alignOf<PlatSpec>((*val)[0]);
|
const auto align = alignOf<PlatSpec>((*val)[0]);
|
||||||
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
oxReturnError(m_writer.seekp(0, ox::ios_base::end));
|
||||||
auto const padding = calcPadding(align);
|
const auto padding = m_writer.tellp() % align;
|
||||||
oxRequireM(p, ox::allocate(m_writer, sz + padding));
|
oxRequireM(p, ox::allocate(m_writer, sz + padding));
|
||||||
p += padding;
|
p += padding;
|
||||||
oxReturnError(m_writer.seekp(p));
|
oxReturnError(m_writer.seekp(p));
|
||||||
@ -384,6 +381,8 @@ constexpr ox::Error Preloader<PlatSpec>::fieldVector(
|
|||||||
|
|
||||||
template<typename PlatSpec>
|
template<typename PlatSpec>
|
||||||
constexpr ox::Error Preloader<PlatSpec>::fieldArray(CRStringView, ox::ModelValueArray const*val) noexcept {
|
constexpr ox::Error Preloader<PlatSpec>::fieldArray(CRStringView, ox::ModelValueArray const*val) noexcept {
|
||||||
|
oxDebugf("array size: {}", val->size());
|
||||||
|
oxDebugf("array sizeOf: {}", sizeOf<PlatSpec>(val));
|
||||||
oxReturnError(pad(&(*val)[0]));
|
oxReturnError(pad(&(*val)[0]));
|
||||||
for (auto const&v : *val) {
|
for (auto const&v : *val) {
|
||||||
oxReturnError(this->interface()->field({}, &v));
|
oxReturnError(this->interface()->field({}, &v));
|
||||||
@ -397,12 +396,6 @@ constexpr bool Preloader<PlatSpec>::unionCheckAndIt() noexcept {
|
|||||||
return u.checkAndIterate();
|
return u.checkAndIterate();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename PlatSpec>
|
|
||||||
constexpr size_t Preloader<PlatSpec>::calcPadding(size_t align) const noexcept {
|
|
||||||
auto const excess = m_writer.tellp() % align;
|
|
||||||
return (align * (excess != 0)) - excess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename PlatSpec, typename T>
|
template<typename PlatSpec, typename T>
|
||||||
constexpr ox::Error preload(Preloader<PlatSpec> *pl, ox::CommonPtrWith<T> auto *obj) noexcept {
|
constexpr ox::Error preload(Preloader<PlatSpec> *pl, ox::CommonPtrWith<T> auto *obj) noexcept {
|
||||||
oxReturnError(model(pl->interface(), obj));
|
oxReturnError(model(pl->interface(), obj));
|
||||||
|
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -96,7 +96,6 @@ install(
|
|||||||
buildinfo.hpp
|
buildinfo.hpp
|
||||||
byteswap.hpp
|
byteswap.hpp
|
||||||
concepts.hpp
|
concepts.hpp
|
||||||
conv.hpp
|
|
||||||
def.hpp
|
def.hpp
|
||||||
defer.hpp
|
defer.hpp
|
||||||
defines.hpp
|
defines.hpp
|
||||||
|
2
deps/ox/src/ox/std/bit.hpp
vendored
2
deps/ox/src/ox/std/bit.hpp
vendored
@ -32,7 +32,7 @@ constexpr To bit_cast(const From &src) noexcept requires(sizeof(To) == sizeof(Fr
|
|||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
constexpr To cbit_cast(From src) noexcept requires(sizeof(To) == sizeof(From)) {
|
constexpr typename enable_if<sizeof(To) == sizeof(From), To>::type cbit_cast(From src) noexcept {
|
||||||
To dst = {};
|
To dst = {};
|
||||||
ox::memcpy(&dst, &src, sizeof(src));
|
ox::memcpy(&dst, &src, sizeof(src));
|
||||||
return dst;
|
return dst;
|
||||||
|
3
deps/ox/src/ox/std/concepts.hpp
vendored
3
deps/ox/src/ox/std/concepts.hpp
vendored
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "bit.hpp"
|
|
||||||
#include "typetraits.hpp"
|
#include "typetraits.hpp"
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
@ -30,6 +29,4 @@ concept OxString_c = isOxString_v<T>;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
concept Integral_c = ox::is_integral_v<T>;
|
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;
|
|
||||||
}
|
}
|
||||||
|
45
deps/ox/src/ox/std/conv.hpp
vendored
45
deps/ox/src/ox/std/conv.hpp
vendored
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2015 - 2024 gary@drinkingtea.net
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "point.hpp"
|
|
||||||
#include "size.hpp"
|
|
||||||
#include "vec.hpp"
|
|
||||||
|
|
||||||
namespace ox {
|
|
||||||
|
|
||||||
constexpr Vec2::operator Point() const noexcept {
|
|
||||||
return {
|
|
||||||
static_cast<int32_t>(x),
|
|
||||||
static_cast<int32_t>(y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2::operator Size() const noexcept {
|
|
||||||
return {
|
|
||||||
static_cast<int32_t>(x),
|
|
||||||
static_cast<int32_t>(y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Point::operator Vec2() const noexcept {
|
|
||||||
return {
|
|
||||||
static_cast<float>(x),
|
|
||||||
static_cast<float>(y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Size::operator Vec2() const noexcept {
|
|
||||||
return {
|
|
||||||
static_cast<float>(width),
|
|
||||||
static_cast<float>(height),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
4
deps/ox/src/ox/std/iterator.hpp
vendored
4
deps/ox/src/ox/std/iterator.hpp
vendored
@ -128,10 +128,6 @@ struct SpanIterator {
|
|||||||
return operator-=(1);
|
return operator-=(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr PtrType operator->() const noexcept {
|
|
||||||
return &m_t[m_offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr RefType operator*() const noexcept {
|
constexpr RefType operator*() const noexcept {
|
||||||
return m_t[m_offset];
|
return m_t[m_offset];
|
||||||
}
|
}
|
||||||
|
1
deps/ox/src/ox/std/new.hpp
vendored
1
deps/ox/src/ox/std/new.hpp
vendored
@ -102,7 +102,6 @@ class MallocaPtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr ~MallocaPtr() noexcept {
|
constexpr ~MallocaPtr() noexcept {
|
||||||
m_val->~T();
|
|
||||||
if (m_onHeap && m_val) {
|
if (m_onHeap && m_val) {
|
||||||
delete[] reinterpret_cast<uint8_t*>(m_val);
|
delete[] reinterpret_cast<uint8_t*>(m_val);
|
||||||
}
|
}
|
||||||
|
5
deps/ox/src/ox/std/point.hpp
vendored
5
deps/ox/src/ox/std/point.hpp
vendored
@ -17,8 +17,8 @@ class Point {
|
|||||||
public:
|
public:
|
||||||
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
|
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
int32_t x = 0;
|
int x = 0;
|
||||||
int32_t y = 0;
|
int y = 0;
|
||||||
|
|
||||||
constexpr Point() noexcept = default;
|
constexpr Point() noexcept = default;
|
||||||
|
|
||||||
@ -64,7 +64,6 @@ class Point {
|
|||||||
|
|
||||||
constexpr bool operator!=(const Point&) const noexcept;
|
constexpr bool operator!=(const Point&) const noexcept;
|
||||||
|
|
||||||
explicit constexpr operator class Vec2() const noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Point::Point(int x, int y) noexcept {
|
constexpr Point::Point(int x, int y) noexcept {
|
||||||
|
55
deps/ox/src/ox/std/reader.cpp
vendored
55
deps/ox/src/ox/std/reader.cpp
vendored
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
#include <istream>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
#include "reader.hpp"
|
#include "reader.hpp"
|
||||||
@ -16,56 +16,41 @@
|
|||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
|
constexpr int sdMap(ox::ios_base::seekdir in) noexcept {
|
||||||
switch (in) {
|
switch (in) {
|
||||||
case ox::ios_base::beg:
|
case ox::ios_base::beg:
|
||||||
return std::ios_base::beg;
|
return SEEK_SET;
|
||||||
case ox::ios_base::end:
|
case ox::ios_base::end:
|
||||||
return std::ios_base::end;
|
return SEEK_END;
|
||||||
case ox::ios_base::cur:
|
case ox::ios_base::cur:
|
||||||
return std::ios_base::cur;
|
return SEEK_CUR;
|
||||||
}
|
}
|
||||||
return std::ios_base::beg;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<char> StreamReader::peek() const noexcept {
|
ox::Result<char> FileReader::peek() const noexcept {
|
||||||
try {
|
auto const c = fgetc(m_file);
|
||||||
char c{};
|
auto const ok = c != EOF;
|
||||||
m_strm.get(c);
|
if (ok && ungetc(c, m_file)) [[unlikely]] {
|
||||||
auto const ok = c != EOF;
|
return OxError(1, "Unable to unget character");
|
||||||
if (ok && m_strm.unget()) [[unlikely]] {
|
|
||||||
return OxError(1, "Unable to unget character");
|
|
||||||
}
|
|
||||||
return {static_cast<char>(c), OxError(!ok, "File peek failed")};
|
|
||||||
} catch (std::exception const&) {
|
|
||||||
return OxError(1, "peek failed");
|
|
||||||
}
|
}
|
||||||
|
return {static_cast<char>(c), OxError(!ok, "File peek failed")};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<std::size_t> StreamReader::read(char *v, std::size_t cnt) noexcept {
|
ox::Result<std::size_t> FileReader::read(char *v, std::size_t cnt) noexcept {
|
||||||
return static_cast<size_t>(m_strm.read(v, static_cast<std::streamsize>(cnt)).gcount());
|
return fread(v, 1, cnt, m_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error StreamReader::seekg(std::size_t p) noexcept {
|
ox::Error FileReader::seekg(std::size_t p) noexcept {
|
||||||
try {
|
return OxError(fseek(m_file, static_cast<int64_t>(p), SEEK_CUR) != 0);
|
||||||
m_strm.seekg(static_cast<long long int>(p), std::ios_base::cur);
|
|
||||||
} catch (std::exception const&) {
|
|
||||||
return OxError(1, "seekg failed");
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error StreamReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
|
ox::Error FileReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
|
||||||
try {
|
return OxError(fseek(m_file, p, sdMap(sd)) != 0);
|
||||||
m_strm.seekg(p, sdMap(sd));
|
|
||||||
} catch (std::exception const&) {
|
|
||||||
return OxError(1, "seekg failed");
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<std::size_t> StreamReader::tellg() noexcept {
|
ox::Result<std::size_t> FileReader::tellg() noexcept {
|
||||||
const auto sz = m_strm.tellg();
|
const auto sz = ftell(m_file);
|
||||||
return {static_cast<std::size_t>(sz), OxError(sz == -1)};
|
return {static_cast<std::size_t>(sz), OxError(sz == -1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
deps/ox/src/ox/std/reader.hpp
vendored
8
deps/ox/src/ox/std/reader.hpp
vendored
@ -9,7 +9,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
#include <istream>
|
#include <cstdio>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "concepts.hpp"
|
#include "concepts.hpp"
|
||||||
@ -65,11 +65,11 @@ class ReaderT: public Reader_v {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
class StreamReader: public Reader_v {
|
class FileReader: public Reader_v {
|
||||||
private:
|
private:
|
||||||
std::istream &m_strm;
|
FILE *m_file = nullptr;
|
||||||
public:
|
public:
|
||||||
constexpr explicit StreamReader(std::istream &stream) noexcept: m_strm(stream) {}
|
constexpr explicit FileReader(FILE *file) noexcept: m_file(file) {}
|
||||||
ox::Result<char> peek() const noexcept override;
|
ox::Result<char> peek() const noexcept override;
|
||||||
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
|
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
|
||||||
ox::Error seekg(std::size_t p) noexcept override;
|
ox::Error seekg(std::size_t p) noexcept override;
|
||||||
|
5
deps/ox/src/ox/std/size.hpp
vendored
5
deps/ox/src/ox/std/size.hpp
vendored
@ -17,8 +17,8 @@ class Size {
|
|||||||
public:
|
public:
|
||||||
static constexpr auto TypeName = "net.drinkingtea.ox.Size";
|
static constexpr auto TypeName = "net.drinkingtea.ox.Size";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
int32_t width = 0;
|
int width = 0;
|
||||||
int32_t height = 0;
|
int height = 0;
|
||||||
|
|
||||||
constexpr Size() noexcept = default;
|
constexpr Size() noexcept = default;
|
||||||
|
|
||||||
@ -64,7 +64,6 @@ class Size {
|
|||||||
|
|
||||||
constexpr bool operator!=(const Size&) const noexcept;
|
constexpr bool operator!=(const Size&) const noexcept;
|
||||||
|
|
||||||
explicit constexpr operator class Vec2() const noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Size::Size(int width, int height) noexcept {
|
constexpr Size::Size(int width, int height) noexcept {
|
||||||
|
28
deps/ox/src/ox/std/smallmap.hpp
vendored
28
deps/ox/src/ox/std/smallmap.hpp
vendored
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "def.hpp"
|
#include "algorithm.hpp"
|
||||||
#include "hash.hpp"
|
#include "hash.hpp"
|
||||||
#include "ignore.hpp"
|
#include "ignore.hpp"
|
||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
@ -28,7 +28,7 @@ class SmallMap {
|
|||||||
T value{};
|
T value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
using PairVector = Vector<Pair, SmallSz>;
|
using PairVector = Vector<Pair, SmallSz>;
|
||||||
PairVector m_pairs;
|
PairVector m_pairs;
|
||||||
|
|
||||||
@ -39,6 +39,8 @@ class SmallMap {
|
|||||||
|
|
||||||
constexpr SmallMap(SmallMap &&other) noexcept;
|
constexpr SmallMap(SmallMap &&other) noexcept;
|
||||||
|
|
||||||
|
constexpr ~SmallMap();
|
||||||
|
|
||||||
constexpr bool operator==(SmallMap const&other) const;
|
constexpr bool operator==(SmallMap const&other) const;
|
||||||
|
|
||||||
constexpr SmallMap &operator=(SmallMap const&other);
|
constexpr SmallMap &operator=(SmallMap const&other);
|
||||||
@ -77,11 +79,6 @@ class SmallMap {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr Pair &get(size_t i) noexcept;
|
constexpr Pair &get(size_t i) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr ox::SpanView<Pair> pairs() const noexcept {
|
|
||||||
return m_pairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void clear();
|
constexpr void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -103,6 +100,11 @@ constexpr SmallMap<K, T, SmallSz>::SmallMap(SmallMap<K, T, SmallSz> &&other) noe
|
|||||||
m_pairs = std::move(other.m_pairs);
|
m_pairs = std::move(other.m_pairs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::~SmallMap() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename K, typename T, size_t SmallSz>
|
template<typename K, typename T, size_t SmallSz>
|
||||||
constexpr bool SmallMap<K, T, SmallSz>::operator==(SmallMap const&other) const {
|
constexpr bool SmallMap<K, T, SmallSz>::operator==(SmallMap const&other) const {
|
||||||
return m_pairs == other.m_pairs;
|
return m_pairs == other.m_pairs;
|
||||||
@ -202,12 +204,12 @@ constexpr T &SmallMap<K, T, SmallSz>::value(size_t i) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename T, size_t SmallSz>
|
template<typename K, typename T, size_t SmallSz>
|
||||||
constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::get(size_t i) const noexcept {
|
constexpr SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::get(size_t i) const noexcept {
|
||||||
return m_pairs[i];
|
return m_pairs[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename T, size_t SmallSz>
|
template<typename K, typename T, size_t SmallSz>
|
||||||
constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::get(size_t i) noexcept {
|
constexpr SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::get(size_t i) noexcept {
|
||||||
return m_pairs[i];
|
return m_pairs[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,12 +246,4 @@ constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::acces
|
|||||||
return pairs.emplace_back();
|
return pairs.emplace_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename K, typename V, size_t SmallSz>
|
|
||||||
constexpr Error model(T *io, ox::CommonPtrWith<SmallMap<K, V, SmallSz>> auto *obj) noexcept {
|
|
||||||
using Map = SmallMap<K, V, SmallSz>;
|
|
||||||
oxReturnError(io->template setTypeInfo<Map>());
|
|
||||||
oxReturnError(io->field("pairs", &obj->m_pairs));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
2
deps/ox/src/ox/std/stacktrace.cpp
vendored
2
deps/ox/src/ox/std/stacktrace.cpp
vendored
@ -26,7 +26,7 @@
|
|||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
|
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
|
||||||
[[nodiscard]] [[maybe_unused]]
|
[[nodiscard]]
|
||||||
static auto symbolicate([[maybe_unused]]void **frames,
|
static auto symbolicate([[maybe_unused]]void **frames,
|
||||||
[[maybe_unused]]std::size_t frameCnt,
|
[[maybe_unused]]std::size_t frameCnt,
|
||||||
[[maybe_unused]]const char *linePrefix) {
|
[[maybe_unused]]const char *linePrefix) {
|
||||||
|
1
deps/ox/src/ox/std/std.hpp
vendored
1
deps/ox/src/ox/std/std.hpp
vendored
@ -16,7 +16,6 @@
|
|||||||
#include "istring.hpp"
|
#include "istring.hpp"
|
||||||
#include "byteswap.hpp"
|
#include "byteswap.hpp"
|
||||||
#include "concepts.hpp"
|
#include "concepts.hpp"
|
||||||
#include "conv.hpp"
|
|
||||||
#include "cstringview.hpp"
|
#include "cstringview.hpp"
|
||||||
#include "cstrops.hpp"
|
#include "cstrops.hpp"
|
||||||
#include "def.hpp"
|
#include "def.hpp"
|
||||||
|
1
deps/ox/src/ox/std/string.hpp
vendored
1
deps/ox/src/ox/std/string.hpp
vendored
@ -194,7 +194,6 @@ class BasicString {
|
|||||||
|
|
||||||
constexpr void resize(size_t sz) noexcept {
|
constexpr void resize(size_t sz) noexcept {
|
||||||
m_buff.resize(sz);
|
m_buff.resize(sz);
|
||||||
m_buff[sz - 1] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
|
14
deps/ox/src/ox/std/test/tests.cpp
vendored
14
deps/ox/src/ox/std/test/tests.cpp
vendored
@ -18,12 +18,12 @@
|
|||||||
#include <ox/std/std.hpp>
|
#include <ox/std/std.hpp>
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static uint64_t steadyNowMs() {
|
static uint64_t nowMs() {
|
||||||
#if __has_include(<chrono>)
|
#if __has_include(<chrono>)
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
return static_cast<uint64_t>(
|
return static_cast<uint64_t>(
|
||||||
duration_cast<milliseconds>(
|
duration_cast<milliseconds>(
|
||||||
steady_clock::now().time_since_epoch()).count());
|
system_clock::now().time_since_epoch()).count());
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
@ -41,13 +41,13 @@ uint64_t timeMapStrToUuid(int elemCnt, int lookups, uint64_t seed = 4321) noexce
|
|||||||
auto const keys = map.keys();
|
auto const keys = map.keys();
|
||||||
ox::Random rand;
|
ox::Random rand;
|
||||||
// start
|
// start
|
||||||
auto const startTime = steadyNowMs();
|
auto const startTime = nowMs();
|
||||||
for (int i = 0; i < lookups; ++i) {
|
for (int i = 0; i < lookups; ++i) {
|
||||||
auto const&k = keys[rand.gen() % keys.size()];
|
auto const&k = keys[rand.gen() % keys.size()];
|
||||||
map[k];
|
map[k];
|
||||||
oxExpect(map[k], ox::UUID::fromString(k).unwrap());
|
oxExpect(map[k], ox::UUID::fromString(k).unwrap());
|
||||||
}
|
}
|
||||||
return steadyNowMs() - startTime;
|
return nowMs() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Map = ox::SmallMap<ox::UUID, ox::String>>
|
template<typename Map = ox::SmallMap<ox::UUID, ox::String>>
|
||||||
@ -62,16 +62,16 @@ uint64_t timeMapUuidToStr(int elemCnt, int lookups, uint64_t seed = 4321) noexce
|
|||||||
auto const keys = map.keys();
|
auto const keys = map.keys();
|
||||||
ox::Random rand;
|
ox::Random rand;
|
||||||
// start
|
// start
|
||||||
auto const startTime = steadyNowMs();
|
auto const startTime = nowMs();
|
||||||
for (int i = 0; i < lookups; ++i) {
|
for (int i = 0; i < lookups; ++i) {
|
||||||
auto const&k = keys[rand.gen() % keys.size()];
|
auto const&k = keys[rand.gen() % keys.size()];
|
||||||
oxExpect(map[k], k.toString());
|
oxExpect(map[k], k.toString());
|
||||||
}
|
}
|
||||||
return steadyNowMs() - startTime;
|
return nowMs() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error compareMaps(int lookupCnt = 1'000'000) {
|
static ox::Error compareMaps(int lookupCnt = 1'000'000) {
|
||||||
auto const seed = steadyNowMs();
|
auto const seed = nowMs();
|
||||||
uint64_t hashTime{};
|
uint64_t hashTime{};
|
||||||
uint64_t smallTime{};
|
uint64_t smallTime{};
|
||||||
int elemCnt = 1;
|
int elemCnt = 1;
|
||||||
|
2
deps/ox/src/ox/std/typetraits.hpp
vendored
2
deps/ox/src/ox/std/typetraits.hpp
vendored
@ -185,8 +185,6 @@ struct enable_if<true, T> {
|
|||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool B, typename T>
|
|
||||||
using enable_if_t = typename enable_if<B, T>::type;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_pointer {
|
struct is_pointer {
|
||||||
|
71
deps/ox/src/ox/std/vec.hpp
vendored
71
deps/ox/src/ox/std/vec.hpp
vendored
@ -23,16 +23,17 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
class Vec2 {
|
template<typename T>
|
||||||
|
struct Vec {
|
||||||
public:
|
public:
|
||||||
using value_type = float;
|
using value_type = T;
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
|
static constexpr auto TypeName = "net.drinkingtea.ox.Point";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
|
|
||||||
float x = 0;
|
T x = 0;
|
||||||
float y = 0;
|
T y = 0;
|
||||||
|
|
||||||
template<typename RefType = value_type&, typename PtrType = value_type*, bool reverse = false>
|
template<typename RefType = value_type&, typename PtrType = value_type*, bool reverse = false>
|
||||||
struct iterator: public ox::Iterator<std::bidirectional_iterator_tag, value_type> {
|
struct iterator: public ox::Iterator<std::bidirectional_iterator_tag, value_type> {
|
||||||
@ -140,14 +141,14 @@ class Vec2 {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr Vec2() noexcept = default;
|
constexpr Vec() noexcept = default;
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
constexpr Vec2(float pX, float pY) noexcept: x(pX), y(pY) {
|
constexpr Vec(T pX, T pY) noexcept: x(pX), y(pY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __has_include(<imgui.h>)
|
#if __has_include(<imgui.h>)
|
||||||
explicit constexpr Vec2(const ImVec2 &v) noexcept: Vec2(v.x, v.y) {
|
explicit constexpr Vec(const ImVec2 &v) noexcept: Vec(v.x, v.y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit inline operator ImVec2() const noexcept {
|
explicit inline operator ImVec2() const noexcept {
|
||||||
@ -227,7 +228,7 @@ class Vec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto operator==(const Vec2 &v) const noexcept {
|
constexpr auto operator==(const Vec &v) const noexcept {
|
||||||
for (auto i = 0u; i < v.size(); ++i) {
|
for (auto i = 0u; i < v.size(); ++i) {
|
||||||
if ((*this)[i] != v[i]) {
|
if ((*this)[i] != v[i]) {
|
||||||
return false;
|
return false;
|
||||||
@ -236,71 +237,29 @@ class Vec2 {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto operator!=(const Vec2 &v) const noexcept {
|
constexpr auto operator!=(const Vec &v) const noexcept {
|
||||||
return !operator==(v);
|
return !operator==(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit constexpr operator class Point() const noexcept;
|
|
||||||
|
|
||||||
explicit constexpr operator class Size() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr std::size_t size() const noexcept {
|
constexpr std::size_t size() const noexcept {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Vec2 operator+(float i) const noexcept {
|
|
||||||
return {x + i, y + i};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator+=(float i) noexcept {
|
|
||||||
x += i;
|
|
||||||
y += i;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator-(float i) const noexcept {
|
|
||||||
return {x - i, y - i};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator-=(float i) noexcept {
|
|
||||||
x -= i;
|
|
||||||
y -= i;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator*(float i) const noexcept {
|
|
||||||
return {x * i, y * i};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator*=(float i) noexcept {
|
|
||||||
x *= i;
|
|
||||||
y *= i;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator/(float i) const noexcept {
|
|
||||||
return {x / i, y / i};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Vec2 operator/=(float i) noexcept {
|
|
||||||
x /= i;
|
|
||||||
y /= i;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr float *start() noexcept {
|
constexpr T *start() noexcept {
|
||||||
return&x;
|
return &x;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr const float *start() const noexcept {
|
constexpr const T *start() const noexcept {
|
||||||
return &x;
|
return &x;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Vec2 = Vec<float>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error model(T *io, ox::CommonPtrWith<Vec2> auto *obj) noexcept {
|
constexpr Error model(T *io, ox::CommonPtrWith<Vec2> auto *obj) noexcept {
|
||||||
oxReturnError(io->template setTypeInfo<Vec2>());
|
oxReturnError(io->template setTypeInfo<Vec2>());
|
||||||
|
48
deps/ox/src/ox/std/vector.hpp
vendored
48
deps/ox/src/ox/std/vector.hpp
vendored
@ -271,7 +271,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
|
|||||||
constexpr bool contains(MaybeView_t<T> const&) const noexcept;
|
constexpr bool contains(MaybeView_t<T> const&) const noexcept;
|
||||||
|
|
||||||
constexpr iterator<T&, T*, false> insert(
|
constexpr iterator<T&, T*, false> insert(
|
||||||
std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept);
|
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept);
|
||||||
|
|
||||||
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept);
|
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept);
|
||||||
|
|
||||||
@ -531,23 +531,29 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
|
|||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
||||||
Vector<T, SmallVectorSize, Allocator>::insert(
|
Vector<T, SmallVectorSize, Allocator>::insert(
|
||||||
std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept) {
|
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept) {
|
||||||
if (m_size + cnt > m_cap) {
|
if (m_size + cnt > m_cap) {
|
||||||
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
|
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
|
||||||
}
|
if (pos < m_size) {
|
||||||
if (pos < m_size) {
|
m_items[pos] = std::move(val);
|
||||||
for (auto i = m_size + cnt - 1; i > pos; --i) {
|
} else {
|
||||||
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
|
for (auto i = 0u; i < cnt; ++i) {
|
||||||
}
|
std::construct_at(&m_items[pos + i], m_items[pos]);
|
||||||
for (auto i = pos; i < pos + cnt; ++i) {
|
}
|
||||||
m_items[i] = val;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto i = 0u; i < cnt; ++i) {
|
if (pos < m_size) {
|
||||||
std::construct_at(&m_items[pos + i], m_items[pos]);
|
for (auto i = m_size + cnt - 1; i > pos; --i) {
|
||||||
|
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
|
||||||
|
}
|
||||||
|
m_items[pos] = std::move(val);
|
||||||
|
} else {
|
||||||
|
for (auto i = 0u; i < cnt; ++i) {
|
||||||
|
std::construct_at(&m_items[pos + i], m_items[pos]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_size += cnt;
|
++m_size;
|
||||||
return begin() + pos;
|
return begin() + pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,14 +562,20 @@ constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&,
|
|||||||
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(useNoexcept) {
|
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(useNoexcept) {
|
||||||
if (m_size == m_cap) {
|
if (m_size == m_cap) {
|
||||||
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
|
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
|
||||||
}
|
if (pos < m_size) {
|
||||||
if (pos < m_size) {
|
m_items[pos] = std::move(val);
|
||||||
for (auto i = m_size; i > pos; --i) {
|
} else {
|
||||||
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
|
std::construct_at(&m_items[pos], m_items[pos]);
|
||||||
}
|
}
|
||||||
m_items[pos] = std::move(val);
|
|
||||||
} else {
|
} else {
|
||||||
std::construct_at(&m_items[pos], std::move(val));
|
if (pos < m_size) {
|
||||||
|
for (auto i = m_size; i > pos; --i) {
|
||||||
|
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
|
||||||
|
}
|
||||||
|
m_items[pos] = std::move(val);
|
||||||
|
} else {
|
||||||
|
std::construct_at(&m_items[pos], m_items[pos]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
++m_size;
|
++m_size;
|
||||||
return begin() + pos;
|
return begin() + pos;
|
||||||
|
@ -162,10 +162,18 @@ classes in question.
|
|||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
The GBA build has exceptions disabled.
|
Exceptions are clean and nice in userland code running in environments with
|
||||||
Instead of throwing exceptions, all engine code must return ```ox::Error```s.
|
expansive system resources, but they are a bit of a pain in small bare metal
|
||||||
For the sake of consistency, try to stick to ```ox::Error``` in non-engine code
|
environments.
|
||||||
as well, but non-engine code is free to use exceptions when they make sense.
|
The GBA build has them disabled.
|
||||||
|
Exceptions cause also the compiler to generate a great deal of extra code that
|
||||||
|
inflates the size of the binary.
|
||||||
|
The binary size bloat is often cited as one of the main reasons why many
|
||||||
|
embedded developers prefer C to C++.
|
||||||
|
|
||||||
|
Instead of throwing exceptions, all engine code must return Ox error codes.
|
||||||
|
For the sake of consistency, try to stick to Ox error codes in non-engine code
|
||||||
|
as well.
|
||||||
Nostalgia and Ox both use ```ox::Error``` to report errors. ```ox::Error``` is
|
Nostalgia and Ox both use ```ox::Error``` to report errors. ```ox::Error``` is
|
||||||
a struct that has overloaded operators to behave like an integer error code,
|
a struct that has overloaded operators to behave like an integer error code,
|
||||||
plus some extra fields to enhance debuggability.
|
plus some extra fields to enhance debuggability.
|
||||||
@ -211,30 +219,6 @@ int caller2() {
|
|||||||
std::cout << val << '\n';
|
std::cout << val << '\n';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error caller3(int &i) {
|
|
||||||
return foo(i).moveTo(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error caller4(int &i) {
|
|
||||||
return foo(i).copyTo(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int caller5(int i) {
|
|
||||||
return foo(i).unwrap(); // unwrap will kill the program if there is an error
|
|
||||||
}
|
|
||||||
|
|
||||||
int caller6(int i) {
|
|
||||||
return foo(i).unwrapThrow(); // unwrap will throw if there is an error
|
|
||||||
}
|
|
||||||
|
|
||||||
int caller7(int i) {
|
|
||||||
return foo(i).or_value(0); // will return 0 if foo returned an error
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<uint64_t> caller8(int i) {
|
|
||||||
return foo(i).to<uint64_t>(); // will convert the result of foo to uint64_t
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Lastly, there are a few macros available to help in passing ```ox::Error```s
|
Lastly, there are a few macros available to help in passing ```ox::Error```s
|
||||||
@ -291,7 +275,6 @@ ox::Error engineCode() noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Ox also has the ```oxRequire``` macro, which will initialize a value if there is no error, and return if there is.
|
Ox also has the ```oxRequire``` macro, which will initialize a value if there is no error, and return if there is.
|
||||||
It aims to somewhat emulate the ```?``` operator in Rust and Swift.
|
It aims to somewhat emulate the ```?``` operator in Rust and Swift.
|
||||||
|
|
||||||
@ -326,9 +309,6 @@ ox::Result<int> f2() noexcept {
|
|||||||
* ```oxRequireT``` - oxRequire Throw
|
* ```oxRequireT``` - oxRequire Throw
|
||||||
* ```oxRequireMT``` - oxRequire Mutable Throw
|
* ```oxRequireMT``` - oxRequire Mutable Throw
|
||||||
|
|
||||||
The throw variants of ```oxRequire``` are generally legacy code.
|
|
||||||
```ox::Result::unwrapThrow``` is generally preferred now.
|
|
||||||
|
|
||||||
### Logging and Output
|
### Logging and Output
|
||||||
|
|
||||||
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.
|
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.
|
||||||
@ -546,13 +526,19 @@ a wrapper around the bare formats.
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/mc/read.hpp>
|
#include <ox/mc/read.hpp>
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette1(const Buffer &buff) noexcept {
|
||||||
return ox::readMC<NostalgiaPalette>(buff);
|
return ox::readMC<NostalgiaPalette>(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette2(const Buffer &buff) noexcept {
|
||||||
|
return ox::readMC<NostalgiaPalette>(buff.data(), buff.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Result<NostalgiaPalette> loadPalette3(const Buffer &buff) noexcept {
|
||||||
NostalgiaPalette pal;
|
NostalgiaPalette pal;
|
||||||
oxReturnError(ox::readMC(buff, pal));
|
std::size_t sz = 0;
|
||||||
|
oxReturnError(ox::readMC(buff.data(), buff.size(), &pal, &sz));
|
||||||
|
buffer.resize(sz);
|
||||||
return pal;
|
return pal;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -562,7 +548,7 @@ ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/mc/write.hpp>
|
#include <ox/mc/write.hpp>
|
||||||
|
|
||||||
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette const&pal) noexcept {
|
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette *pal) noexcept {
|
||||||
ox::Buffer buffer(ox::units::MB);
|
ox::Buffer buffer(ox::units::MB);
|
||||||
std::size_t sz = 0;
|
std::size_t sz = 0;
|
||||||
oxReturnError(ox::writeMC(buffer.data(), buffer.size(), pal, &sz));
|
oxReturnError(ox::writeMC(buffer.data(), buffer.size(), pal, &sz));
|
||||||
@ -570,7 +556,7 @@ ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette const&pal) noexcept
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept {
|
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette *pal) noexcept {
|
||||||
return ox::writeMC(pal);
|
return ox::writeMC(pal);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -582,13 +568,17 @@ ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/oc/read.hpp>
|
#include <ox/oc/read.hpp>
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette1(const Buffer &buff) noexcept {
|
||||||
return ox::readOC<NostalgiaPalette>(buff);
|
return ox::readOC<NostalgiaPalette>(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette2(const Buffer &buff) noexcept {
|
||||||
|
return ox::readOC<NostalgiaPalette>(buff.data(), buff.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Result<NostalgiaPalette> loadPalette3(const Buffer &buff) noexcept {
|
||||||
NostalgiaPalette pal;
|
NostalgiaPalette pal;
|
||||||
oxReturnError(ox::readOC(buff, &pal));
|
oxReturnError(ox::readOC(buff.data(), buff.size(), &pal));
|
||||||
return pal;
|
return pal;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -598,13 +588,13 @@ ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/oc/write.hpp>
|
#include <ox/oc/write.hpp>
|
||||||
|
|
||||||
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette const&pal) noexcept {
|
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette *pal) noexcept {
|
||||||
ox::Buffer buffer(ox::units::MB);
|
ox::Buffer buffer(ox::units::MB);
|
||||||
oxReturnError(ox::writeOC(buffer.data(), buffer.size(), pal));
|
oxReturnError(ox::writeOC(buffer.data(), buffer.size(), pal));
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept {
|
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette *pal) noexcept {
|
||||||
return ox::writeOC(pal);
|
return ox::writeOC(pal);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -616,13 +606,17 @@ ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/claw/read.hpp>
|
#include <ox/claw/read.hpp>
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette1(const Buffer &buff) noexcept {
|
||||||
return ox::readClaw<NostalgiaPalette>(buff);
|
return ox::readClaw<NostalgiaPalette>(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
ox::Result<NostalgiaPalette> loadPalette2(const Buffer &buff) noexcept {
|
||||||
|
return ox::readClaw<NostalgiaPalette>(buff.data(), buff.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Result<NostalgiaPalette> loadPalette3(const Buffer &buff) noexcept {
|
||||||
NostalgiaPalette pal;
|
NostalgiaPalette pal;
|
||||||
oxReturnError(ox::readClaw(buff, pal));
|
oxReturnError(ox::readClaw(buff.data(), buff.size(), &pal));
|
||||||
return pal;
|
return pal;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -632,8 +626,8 @@ ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
|
|||||||
```cpp
|
```cpp
|
||||||
#include <ox/claw/write.hpp>
|
#include <ox/claw/write.hpp>
|
||||||
|
|
||||||
ox::Result<ox::Buffer> writeSpritePalette(NostalgiaPalette const&pal) noexcept {
|
ox::Result<ox::Buffer> writeSpritePalette(NostalgiaPalette *pal) noexcept {
|
||||||
return ox::writeClaw(pal);
|
return ox::writeClaw(&pal);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ox/std/math.hpp>
|
|
||||||
#include <ox/std/types.hpp>
|
#include <ox/std/types.hpp>
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
@ -136,7 +135,7 @@ constexpr Color16 color16(int r, int g, int b, int a = 0) noexcept {
|
|||||||
return static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(r), 31))
|
return static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(r), 31))
|
||||||
| static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(g), 31) << 5)
|
| static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(g), 31) << 5)
|
||||||
| static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(b), 31) << 10)
|
| static_cast<Color16>(ox::min<uint8_t>(static_cast<uint8_t>(b), 31) << 10)
|
||||||
| static_cast<Color16>(a << 15);
|
| static_cast<Color16>(a << 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -152,13 +151,4 @@ static_assert(color16(16, 31, 0) == 1008);
|
|||||||
static_assert(color16(16, 31, 8) == 9200);
|
static_assert(color16(16, 31, 8) == 9200);
|
||||||
static_assert(color16(16, 32, 8) == 9200);
|
static_assert(color16(16, 32, 8) == 9200);
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr Color16 applySelectionColor(Color16 const color) noexcept {
|
|
||||||
namespace core = nostalgia::core;
|
|
||||||
auto const r = core::red16(color) / 2;
|
|
||||||
auto const g = (core::green16(color) + 20) / 2;
|
|
||||||
auto const b = (core::blue16(color) + 31) / 2;
|
|
||||||
return core::color16(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -103,12 +103,6 @@ oxModelEnd()
|
|||||||
|
|
||||||
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
|
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
int tileColumns(Context&) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
int tileRows(Context&) noexcept;
|
|
||||||
|
|
||||||
ox::Error loadBgPalette(
|
ox::Error loadBgPalette(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
size_t palBank,
|
size_t palBank,
|
||||||
|
@ -222,14 +222,6 @@ ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) n
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
|
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param ss
|
|
||||||
* @param pBpp
|
|
||||||
* @param sz size of Subsheet in tiles (not pixels)
|
|
||||||
*/
|
|
||||||
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz) noexcept;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the
|
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the
|
||||||
* preceding or parent sheet if the current corresponding sheet does
|
* preceding or parent sheet if the current corresponding sheet does
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
constexpr auto GbaTileColumns = 32;
|
||||||
|
constexpr auto GbaTileRows = 32;
|
||||||
constexpr auto SpriteCount = 128;
|
constexpr auto SpriteCount = 128;
|
||||||
|
|
||||||
struct GbaTileMapTarget {
|
struct GbaTileMapTarget {
|
||||||
@ -282,8 +284,8 @@ ox::Error loadSpriteTileSheet(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept {
|
void setBgTile(Context&, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept {
|
||||||
auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column);
|
auto const tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
|
||||||
// see Tonc 9.3
|
// see Tonc 9.3
|
||||||
MEM_BG_MAP[bgIdx][tileIdx] =
|
MEM_BG_MAP[bgIdx][tileIdx] =
|
||||||
static_cast<uint16_t>(tile.tileIdx & 0b1'1111'1111) |
|
static_cast<uint16_t>(tile.tileIdx & 0b1'1111'1111) |
|
||||||
@ -292,8 +294,8 @@ void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&til
|
|||||||
static_cast<uint16_t>(tile.palBank << 0xc);
|
static_cast<uint16_t>(tile.palBank << 0xc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearBg(Context &ctx, uint_t bgIdx) noexcept {
|
void clearBg(Context&, uint_t bgIdx) noexcept {
|
||||||
memset(MEM_BG_MAP[bgIdx].data(), 0, static_cast<size_t>(tileRows(ctx) * tileColumns(ctx)));
|
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bgStatus(Context&) noexcept {
|
uint8_t bgStatus(Context&) noexcept {
|
||||||
|
@ -6,17 +6,6 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
constexpr auto GbaTileColumns = 32;
|
|
||||||
constexpr auto GbaTileRows = 32;
|
|
||||||
|
|
||||||
int tileColumns(Context&) noexcept {
|
|
||||||
return GbaTileColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tileRows(Context&) noexcept {
|
|
||||||
return GbaTileRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map ASCII values to the nostalgia charset
|
// map ASCII values to the nostalgia charset
|
||||||
constexpr ox::Array<char, 128> charMap = {
|
constexpr ox::Array<char, 128> charMap = {
|
||||||
0,
|
0,
|
||||||
|
@ -385,8 +385,7 @@ static void setSprite(
|
|||||||
uint_t const idx,
|
uint_t const idx,
|
||||||
Sprite const&s) noexcept {
|
Sprite const&s) noexcept {
|
||||||
// Tonc Table 8.4
|
// Tonc Table 8.4
|
||||||
struct Sz { uint_t x{}, y{}; };
|
static constexpr ox::Array<ox::Vec<uint_t>, 12> dimensions{
|
||||||
static constexpr ox::Array<Sz, 12> dimensions{
|
|
||||||
// col 0
|
// col 0
|
||||||
{1, 1}, // 0, 0
|
{1, 1}, // 0, 0
|
||||||
{2, 2}, // 0, 1
|
{2, 2}, // 0, 1
|
||||||
|
@ -79,13 +79,13 @@ void PaletteEditorImGui::drawColorsEditor() noexcept {
|
|||||||
if (ImGui::Button("Add", sz)) {
|
if (ImGui::Button("Add", sz)) {
|
||||||
auto const colorSz = static_cast<int>(colors(m_pal, m_page));
|
auto const colorSz = static_cast<int>(colors(m_pal, m_page));
|
||||||
constexpr Color16 c = 0;
|
constexpr Color16 c = 0;
|
||||||
std::ignore = undoStack()->push(ox::make_unique<AddColorCommand>(&m_pal, c, m_page, colorSz));
|
undoStack()->push(ox::make_unique<AddColorCommand>(&m_pal, c, m_page, colorSz));
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page));
|
ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page));
|
||||||
{
|
{
|
||||||
if (ImGui::Button("Remove", sz)) {
|
if (ImGui::Button("Remove", sz)) {
|
||||||
std::ignore = undoStack()->push(
|
undoStack()->push(
|
||||||
ox::make_unique<RemoveColorCommand>(
|
ox::make_unique<RemoveColorCommand>(
|
||||||
&m_pal,
|
&m_pal,
|
||||||
color(m_pal, m_page, static_cast<std::size_t>(m_selectedColorRow)),
|
color(m_pal, m_page, static_cast<std::size_t>(m_selectedColorRow)),
|
||||||
@ -97,7 +97,7 @@ void PaletteEditorImGui::drawColorsEditor() noexcept {
|
|||||||
ImGui::BeginDisabled(m_selectedColorRow <= 0);
|
ImGui::BeginDisabled(m_selectedColorRow <= 0);
|
||||||
{
|
{
|
||||||
if (ImGui::Button("Move Up", sz)) {
|
if (ImGui::Button("Move Up", sz)) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, -1));
|
undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, -1));
|
||||||
--m_selectedColorRow;
|
--m_selectedColorRow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ void PaletteEditorImGui::drawColorsEditor() noexcept {
|
|||||||
ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page) - 1);
|
ImGui::BeginDisabled(m_selectedColorRow >= colors(m_pal, m_page) - 1);
|
||||||
{
|
{
|
||||||
if (ImGui::Button("Move Down", sz)) {
|
if (ImGui::Button("Move Down", sz)) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, 1));
|
undoStack()->push(ox::make_unique<MoveColorCommand>(&m_pal, m_page, m_selectedColorRow, 1));
|
||||||
++m_selectedColorRow;
|
++m_selectedColorRow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,17 +155,17 @@ void PaletteEditorImGui::drawPagesEditor() noexcept {
|
|||||||
constexpr auto toolbarHeight = 40;
|
constexpr auto toolbarHeight = 40;
|
||||||
auto const btnSz = ImVec2(paneSz.x / 3 - 5.5f, 24);
|
auto const btnSz = ImVec2(paneSz.x / 3 - 5.5f, 24);
|
||||||
if (ImGui::Button("Add", btnSz)) {
|
if (ImGui::Button("Add", btnSz)) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<AddPageCommand>(m_pal));
|
undoStack()->push(ox::make_unique<AddPageCommand>(m_pal));
|
||||||
m_page = m_pal.pages.size() - 1;
|
m_page = m_pal.pages.size() - 1;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Remove", btnSz)) {
|
if (ImGui::Button("Remove", btnSz)) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<RemovePageCommand>(m_pal, m_page));
|
undoStack()->push(ox::make_unique<RemovePageCommand>(m_pal, m_page));
|
||||||
m_page = std::min(m_page, m_pal.pages.size() - 1);
|
m_page = std::min(m_page, m_pal.pages.size() - 1);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Duplicate", btnSz)) {
|
if (ImGui::Button("Duplicate", btnSz)) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<DuplicatePageCommand>(m_pal, m_page, m_pal.pages.size()));
|
undoStack()->push(ox::make_unique<DuplicatePageCommand>(m_pal, m_page, m_pal.pages.size()));
|
||||||
}
|
}
|
||||||
ImGui::BeginTable("PageSelect", 2, tableFlags, ImVec2(paneSz.x, paneSz.y - (toolbarHeight + 5)));
|
ImGui::BeginTable("PageSelect", 2, tableFlags, ImVec2(paneSz.x, paneSz.y - (toolbarHeight + 5)));
|
||||||
{
|
{
|
||||||
@ -198,7 +198,7 @@ void PaletteEditorImGui::drawColorEditor() noexcept {
|
|||||||
ImGui::InputInt("Blue", &b, 1, 5);
|
ImGui::InputInt("Blue", &b, 1, 5);
|
||||||
auto const newColor = color16(r, g, b, a);
|
auto const newColor = color16(r, g, b, a);
|
||||||
if (c != newColor) {
|
if (c != newColor) {
|
||||||
std::ignore = undoStack()->push(ox::make_unique<UpdateColorCommand>(
|
undoStack()->push(ox::make_unique<UpdateColorCommand>(
|
||||||
&m_pal, m_page, static_cast<int>(m_selectedColorRow), c, newColor));
|
&m_pal, m_page, static_cast<int>(m_selectedColorRow), c, newColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,12 @@ int AddPageCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::AddPage);
|
return static_cast<int>(PaletteEditorCommandId::AddPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddPageCommand::redo() noexcept {
|
void AddPageCommand::redo() noexcept {
|
||||||
m_pal.pages.emplace_back();
|
m_pal.pages.emplace_back();
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddPageCommand::undo() noexcept {
|
void AddPageCommand::undo() noexcept {
|
||||||
return m_pal.pages.erase(static_cast<std::size_t>(m_pal.pages.size() - 1)).error;
|
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_pal.pages.size() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,14 +37,13 @@ int DuplicatePageCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::DuplicatePage);
|
return static_cast<int>(PaletteEditorCommandId::DuplicatePage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error DuplicatePageCommand::redo() noexcept {
|
void DuplicatePageCommand::redo() noexcept {
|
||||||
m_pal.pages.emplace(m_dstIdx, std::move(m_page));
|
m_pal.pages.emplace(m_dstIdx, std::move(m_page));
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error DuplicatePageCommand::undo() noexcept {
|
void DuplicatePageCommand::undo() noexcept {
|
||||||
m_page = std::move(m_pal.pages[m_dstIdx]);
|
m_page = std::move(m_pal.pages[m_dstIdx]);
|
||||||
return m_pal.pages.erase(static_cast<std::size_t>(m_dstIdx)).error;
|
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_dstIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DuplicatePageCommand::insertIdx() const noexcept {
|
size_t DuplicatePageCommand::insertIdx() const noexcept {
|
||||||
@ -62,14 +60,13 @@ int RemovePageCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::RemovePage);
|
return static_cast<int>(PaletteEditorCommandId::RemovePage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RemovePageCommand::redo() noexcept {
|
void RemovePageCommand::redo() noexcept {
|
||||||
m_page = std::move(m_pal.pages[m_idx]);
|
m_page = std::move(m_pal.pages[m_idx]);
|
||||||
return m_pal.pages.erase(static_cast<std::size_t>(m_idx)).error;
|
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RemovePageCommand::undo() noexcept {
|
void RemovePageCommand::undo() noexcept {
|
||||||
m_pal.pages.insert(m_idx, std::move(m_page));
|
m_pal.pages.insert(m_idx, std::move(m_page));
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,13 +81,12 @@ int AddColorCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::AddColor);
|
return static_cast<int>(PaletteEditorCommandId::AddColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddColorCommand::redo() noexcept {
|
void AddColorCommand::redo() noexcept {
|
||||||
m_pal->pages[m_page].insert(static_cast<std::size_t>(m_idx), m_color);
|
m_pal->pages[m_page].insert(static_cast<std::size_t>(m_idx), m_color);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddColorCommand::undo() noexcept {
|
void AddColorCommand::undo() noexcept {
|
||||||
return m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx)).error;
|
std::ignore = m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,13 +101,12 @@ int RemoveColorCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::RemoveColor);
|
return static_cast<int>(PaletteEditorCommandId::RemoveColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RemoveColorCommand::redo() noexcept {
|
void RemoveColorCommand::redo() noexcept {
|
||||||
return m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx)).error;
|
std::ignore = m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RemoveColorCommand::undo() noexcept {
|
void RemoveColorCommand::undo() noexcept {
|
||||||
m_pal->pages[m_page].insert(static_cast<std::size_t>(m_idx), m_color);
|
m_pal->pages[m_page].insert(static_cast<std::size_t>(m_idx), m_color);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -129,11 +124,11 @@ UpdateColorCommand::UpdateColorCommand(
|
|||||||
//setObsolete(m_oldColor == m_newColor);
|
//setObsolete(m_oldColor == m_newColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateColorCommand::mergeWith(UndoCommand const&cmd) noexcept {
|
bool UpdateColorCommand::mergeWith(const UndoCommand *cmd) noexcept {
|
||||||
if (cmd.commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColor)) {
|
if (cmd->commandId() != static_cast<int>(PaletteEditorCommandId::UpdateColor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto ucCmd = static_cast<UpdateColorCommand const*>(&cmd);
|
auto ucCmd = static_cast<const UpdateColorCommand*>(cmd);
|
||||||
if (m_idx != ucCmd->m_idx) {
|
if (m_idx != ucCmd->m_idx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -146,14 +141,12 @@ int UpdateColorCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::UpdateColor);
|
return static_cast<int>(PaletteEditorCommandId::UpdateColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UpdateColorCommand::redo() noexcept {
|
void UpdateColorCommand::redo() noexcept {
|
||||||
m_pal->pages[m_page][static_cast<std::size_t>(m_idx)] = m_newColor;
|
m_pal->pages[m_page][static_cast<std::size_t>(m_idx)] = m_newColor;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UpdateColorCommand::undo() noexcept {
|
void UpdateColorCommand::undo() noexcept {
|
||||||
m_pal->pages[m_page][static_cast<std::size_t>(m_idx)] = m_oldColor;
|
m_pal->pages[m_page][static_cast<std::size_t>(m_idx)] = m_oldColor;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -168,14 +161,12 @@ int MoveColorCommand::commandId() const noexcept {
|
|||||||
return static_cast<int>(PaletteEditorCommandId::MoveColor);
|
return static_cast<int>(PaletteEditorCommandId::MoveColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error MoveColorCommand::redo() noexcept {
|
void MoveColorCommand::redo() noexcept {
|
||||||
moveColor(static_cast<int>(m_idx), m_offset);
|
moveColor(static_cast<int>(m_idx), m_offset);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error MoveColorCommand::undo() noexcept {
|
void MoveColorCommand::undo() noexcept {
|
||||||
moveColor(static_cast<int>(m_idx) + m_offset, -m_offset);
|
moveColor(static_cast<int>(m_idx) + m_offset, -m_offset);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveColorCommand::moveColor(int idx, int offset) noexcept {
|
void MoveColorCommand::moveColor(int idx, int offset) noexcept {
|
||||||
|
@ -35,9 +35,9 @@ class AddPageCommand: public studio::UndoCommand {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,9 +55,9 @@ class DuplicatePageCommand: public studio::UndoCommand {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
size_t insertIdx() const noexcept;
|
size_t insertIdx() const noexcept;
|
||||||
@ -78,9 +78,9 @@ class RemovePageCommand: public studio::UndoCommand {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,9 +99,9 @@ class AddColorCommand: public studio::UndoCommand {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept override;
|
int commandId() const noexcept override;
|
||||||
|
|
||||||
ox::Error redo() noexcept override;
|
void redo() noexcept override;
|
||||||
|
|
||||||
ox::Error undo() noexcept override;
|
void undo() noexcept override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,9 +120,9 @@ class RemoveColorCommand: public studio::UndoCommand {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept override;
|
int commandId() const noexcept override;
|
||||||
|
|
||||||
ox::Error redo() noexcept override;
|
void redo() noexcept override;
|
||||||
|
|
||||||
ox::Error undo() noexcept override;
|
void undo() noexcept override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,14 +140,14 @@ class UpdateColorCommand: public studio::UndoCommand {
|
|||||||
~UpdateColorCommand() noexcept override = default;
|
~UpdateColorCommand() noexcept override = default;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool mergeWith(const UndoCommand &cmd) noexcept final;
|
bool mergeWith(const UndoCommand *cmd) noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,9 +167,9 @@ class MoveColorCommand: public studio::UndoCommand {
|
|||||||
int commandId() const noexcept override;
|
int commandId() const noexcept override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ox::Error redo() noexcept override;
|
void redo() noexcept override;
|
||||||
|
|
||||||
ox::Error undo() noexcept override;
|
void undo() noexcept override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void moveColor(int idx, int offset) noexcept;
|
void moveColor(int idx, int offset) noexcept;
|
||||||
|
@ -24,7 +24,7 @@ AddSubSheetCommand::AddSubSheetCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddSubSheetCommand::redo() noexcept {
|
void AddSubSheetCommand::redo() noexcept {
|
||||||
auto &parent = getSubSheet(m_img, m_parentIdx);
|
auto &parent = getSubSheet(m_img, m_parentIdx);
|
||||||
if (m_addedSheets.size() < 2) {
|
if (m_addedSheets.size() < 2) {
|
||||||
auto i = parent.subsheets.size();
|
auto i = parent.subsheets.size();
|
||||||
@ -35,10 +35,9 @@ ox::Error AddSubSheetCommand::redo() noexcept {
|
|||||||
parent.columns = 0;
|
parent.columns = 0;
|
||||||
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1, m_img.bpp);
|
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1, m_img.bpp);
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error AddSubSheetCommand::undo() noexcept {
|
void AddSubSheetCommand::undo() noexcept {
|
||||||
auto &parent = getSubSheet(m_img, m_parentIdx);
|
auto &parent = getSubSheet(m_img, m_parentIdx);
|
||||||
if (parent.subsheets.size() == 2) {
|
if (parent.subsheets.size() == 2) {
|
||||||
auto s = parent.subsheets[0];
|
auto s = parent.subsheets[0];
|
||||||
@ -48,10 +47,9 @@ ox::Error AddSubSheetCommand::undo() noexcept {
|
|||||||
parent.subsheets.clear();
|
parent.subsheets.clear();
|
||||||
} else {
|
} else {
|
||||||
for (auto idx = m_addedSheets.rbegin(); idx != m_addedSheets.rend(); ++idx) {
|
for (auto idx = m_addedSheets.rbegin(); idx != m_addedSheets.rend(); ++idx) {
|
||||||
oxReturnError(rmSubSheet(m_img, *idx));
|
oxLogError(rmSubSheet(m_img, *idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddSubSheetCommand::commandId() const noexcept {
|
int AddSubSheetCommand::commandId() const noexcept {
|
||||||
|
@ -17,9 +17,9 @@ class AddSubSheetCommand: public TileSheetCommand {
|
|||||||
public:
|
public:
|
||||||
AddSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx parentIdx) noexcept;
|
AddSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx parentIdx) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -41,20 +41,18 @@ CutPasteCommand::CutPasteCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error CutPasteCommand::redo() noexcept {
|
void CutPasteCommand::redo() noexcept {
|
||||||
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
||||||
for (const auto &c : m_changes) {
|
for (const auto &c : m_changes) {
|
||||||
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.newPalIdx));
|
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.newPalIdx));
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error CutPasteCommand::undo() noexcept {
|
void CutPasteCommand::undo() noexcept {
|
||||||
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
||||||
for (const auto &c : m_changes) {
|
for (const auto &c : m_changes) {
|
||||||
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
|
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CutPasteCommand::commandId() const noexcept {
|
int CutPasteCommand::commandId() const noexcept {
|
||||||
|
@ -69,9 +69,9 @@ class CutPasteCommand: public TileSheetCommand {
|
|||||||
ox::Point const&dstEnd,
|
ox::Point const&dstEnd,
|
||||||
TileSheetClipboard const&cb) noexcept;
|
TileSheetClipboard const&cb) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -28,7 +28,7 @@ core::DeleteTilesCommand::DeleteTilesCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error core::DeleteTilesCommand::redo() noexcept {
|
void core::DeleteTilesCommand::redo() noexcept {
|
||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
auto srcPos = m_deletePos + m_deleteSz;
|
auto srcPos = m_deletePos + m_deleteSz;
|
||||||
@ -37,10 +37,9 @@ ox::Error core::DeleteTilesCommand::redo() noexcept {
|
|||||||
const auto dst2 = p.data() + (p.size() - m_deleteSz);
|
const auto dst2 = p.data() + (p.size() - m_deleteSz);
|
||||||
ox::memmove(dst1, src, p.size() - srcPos);
|
ox::memmove(dst1, src, p.size() - srcPos);
|
||||||
ox::memset(dst2, 0, m_deleteSz * sizeof(decltype(p[0])));
|
ox::memset(dst2, 0, m_deleteSz * sizeof(decltype(p[0])));
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error DeleteTilesCommand::undo() noexcept {
|
void DeleteTilesCommand::undo() noexcept {
|
||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
const auto src = p.data() + m_deletePos;
|
const auto src = p.data() + m_deletePos;
|
||||||
@ -49,7 +48,6 @@ ox::Error DeleteTilesCommand::undo() noexcept {
|
|||||||
const auto sz = p.size() - m_deletePos - m_deleteSz;
|
const auto sz = p.size() - m_deletePos - m_deleteSz;
|
||||||
ox::memmove(dst1, src, sz);
|
ox::memmove(dst1, src, sz);
|
||||||
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int DeleteTilesCommand::commandId() const noexcept {
|
int DeleteTilesCommand::commandId() const noexcept {
|
||||||
|
@ -23,9 +23,9 @@ class DeleteTilesCommand: public TileSheetCommand {
|
|||||||
std::size_t tileIdx,
|
std::size_t tileIdx,
|
||||||
std::size_t tileCnt) noexcept;
|
std::size_t tileCnt) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -56,20 +56,18 @@ bool DrawCommand::append(const ox::Vector<std::size_t> &idxList) noexcept {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error DrawCommand::redo() noexcept {
|
void DrawCommand::redo() noexcept {
|
||||||
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
||||||
for (const auto &c : m_changes) {
|
for (const auto &c : m_changes) {
|
||||||
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx));
|
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx));
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error DrawCommand::undo() noexcept {
|
void DrawCommand::undo() noexcept {
|
||||||
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
|
||||||
for (const auto &c : m_changes) {
|
for (const auto &c : m_changes) {
|
||||||
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
|
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int DrawCommand::commandId() const noexcept {
|
int DrawCommand::commandId() const noexcept {
|
||||||
|
@ -40,9 +40,9 @@ class DrawCommand: public TileSheetCommand {
|
|||||||
|
|
||||||
bool append(const ox::Vector<std::size_t> &idxList) noexcept;
|
bool append(const ox::Vector<std::size_t> &idxList) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -28,7 +28,7 @@ core::InsertTilesCommand::InsertTilesCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error InsertTilesCommand::redo() noexcept {
|
void InsertTilesCommand::redo() noexcept {
|
||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
auto dstPos = m_insertPos + m_insertCnt;
|
auto dstPos = m_insertPos + m_insertCnt;
|
||||||
@ -36,10 +36,9 @@ ox::Error InsertTilesCommand::redo() noexcept {
|
|||||||
const auto src = p.data() + m_insertPos;
|
const auto src = p.data() + m_insertPos;
|
||||||
ox::memmove(dst, src, p.size() - dstPos);
|
ox::memmove(dst, src, p.size() - dstPos);
|
||||||
ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
|
ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error InsertTilesCommand::undo() noexcept {
|
void InsertTilesCommand::undo() noexcept {
|
||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
const auto srcIdx = m_insertPos + m_insertCnt;
|
const auto srcIdx = m_insertPos + m_insertCnt;
|
||||||
@ -49,7 +48,6 @@ ox::Error InsertTilesCommand::undo() noexcept {
|
|||||||
const auto sz = p.size() - srcIdx;
|
const auto sz = p.size() - srcIdx;
|
||||||
ox::memmove(dst1, src, sz);
|
ox::memmove(dst1, src, sz);
|
||||||
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int InsertTilesCommand::commandId() const noexcept {
|
int InsertTilesCommand::commandId() const noexcept {
|
||||||
|
@ -23,9 +23,9 @@ class InsertTilesCommand: public TileSheetCommand {
|
|||||||
std::size_t tileIdx,
|
std::size_t tileIdx,
|
||||||
std::size_t tileCnt) noexcept;
|
std::size_t tileCnt) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -16,14 +16,12 @@ core::PaletteChangeCommand::PaletteChangeCommand(
|
|||||||
m_newPalette(ox::FileAddress(ox::sfmt<ox::IString<43>>("uuid://{}", newPalette))) {
|
m_newPalette(ox::FileAddress(ox::sfmt<ox::IString<43>>("uuid://{}", newPalette))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error PaletteChangeCommand::redo() noexcept {
|
void PaletteChangeCommand::redo() noexcept {
|
||||||
m_img.defaultPalette = m_newPalette;
|
m_img.defaultPalette = m_newPalette;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error PaletteChangeCommand::undo() noexcept {
|
void PaletteChangeCommand::undo() noexcept {
|
||||||
m_img.defaultPalette = m_oldPalette;
|
m_img.defaultPalette = m_oldPalette;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PaletteChangeCommand::commandId() const noexcept {
|
int PaletteChangeCommand::commandId() const noexcept {
|
||||||
|
@ -21,9 +21,9 @@ class PaletteChangeCommand: public TileSheetCommand {
|
|||||||
TileSheet &img,
|
TileSheet &img,
|
||||||
ox::CRStringView newPalette) noexcept;
|
ox::CRStringView newPalette) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -11,20 +11,19 @@ core::RmSubSheetCommand::RmSubSheetCommand(TileSheet &img, TileSheet::SubSheetId
|
|||||||
m_idx(std::move(idx)),
|
m_idx(std::move(idx)),
|
||||||
m_parentIdx(m_idx) {
|
m_parentIdx(m_idx) {
|
||||||
m_parentIdx.pop_back();
|
m_parentIdx.pop_back();
|
||||||
|
auto &parent = getSubSheet(m_img, m_parentIdx);
|
||||||
|
m_sheet = parent.subsheets[*m_idx.back().value];
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RmSubSheetCommand::redo() noexcept {
|
void RmSubSheetCommand::redo() noexcept {
|
||||||
auto &parent = getSubSheet(m_img, m_parentIdx);
|
auto &parent = getSubSheet(m_img, m_parentIdx);
|
||||||
m_sheet = std::move(parent.subsheets[*m_idx.back().value]);
|
oxLogError(parent.subsheets.erase(*m_idx.back().value).error);
|
||||||
oxReturnError(parent.subsheets.erase(*m_idx.back().value).error);
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error RmSubSheetCommand::undo() noexcept {
|
void RmSubSheetCommand::undo() noexcept {
|
||||||
auto &parent = getSubSheet(m_img, m_parentIdx);
|
auto &parent = getSubSheet(m_img, m_parentIdx);
|
||||||
auto const i = *m_idx.back().value;
|
auto i = *m_idx.back().value;
|
||||||
parent.subsheets.insert(i, std::move(m_sheet));
|
parent.subsheets.insert(i, m_sheet);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RmSubSheetCommand::commandId() const noexcept {
|
int RmSubSheetCommand::commandId() const noexcept {
|
||||||
|
@ -18,9 +18,9 @@ class RmSubSheetCommand: public TileSheetCommand {
|
|||||||
public:
|
public:
|
||||||
RmSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx idx) noexcept;
|
RmSubSheetCommand(TileSheet &img, TileSheet::SubSheetIdx idx) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -20,17 +20,17 @@ core::UpdateSubSheetCommand::UpdateSubSheetCommand(
|
|||||||
m_newRows(rows) {
|
m_newRows(rows) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UpdateSubSheetCommand::redo() noexcept {
|
void UpdateSubSheetCommand::redo() noexcept {
|
||||||
auto &sheet = getSubSheet(m_img, m_idx);
|
auto &sheet = getSubSheet(m_img, m_idx);
|
||||||
sheet.name = m_newName;
|
sheet.name = m_newName;
|
||||||
oxLogError(resizeSubsheet(sheet, m_img.bpp, {m_newCols, m_newRows}));
|
sheet.columns = m_newCols;
|
||||||
return {};
|
sheet.rows = m_newRows;
|
||||||
|
oxLogError(setPixelCount(sheet, m_img.bpp, static_cast<std::size_t>(PixelsPerTile * m_newCols * m_newRows)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UpdateSubSheetCommand::undo() noexcept {
|
void UpdateSubSheetCommand::undo() noexcept {
|
||||||
auto &sheet = getSubSheet(m_img, m_idx);
|
auto &sheet = getSubSheet(m_img, m_idx);
|
||||||
sheet = m_sheet;
|
sheet = m_sheet;
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int UpdateSubSheetCommand::commandId() const noexcept {
|
int UpdateSubSheetCommand::commandId() const noexcept {
|
||||||
|
@ -25,9 +25,9 @@ class UpdateSubSheetCommand: public TileSheetCommand {
|
|||||||
int cols,
|
int cols,
|
||||||
int rows) noexcept;
|
int rows) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
void redo() noexcept final;
|
||||||
|
|
||||||
ox::Error undo() noexcept final;
|
void undo() noexcept final;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept final;
|
int commandId() const noexcept final;
|
||||||
|
@ -105,10 +105,6 @@ void TileSheetEditorImGui::paste() {
|
|||||||
m_model.paste();
|
m_model.paste();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileSheetEditorImGui::acceptsClipboardPayload() const noexcept {
|
|
||||||
return m_model.acceptsClipboardPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
||||||
if (!down) {
|
if (!down) {
|
||||||
return;
|
return;
|
||||||
@ -122,18 +118,18 @@ void TileSheetEditorImGui::keyStateChanged(turbine::Key key, bool down) {
|
|||||||
if (!popupOpen) {
|
if (!popupOpen) {
|
||||||
auto const colorCnt = pal.pages[m_model.palettePage()].size();
|
auto const colorCnt = pal.pages[m_model.palettePage()].size();
|
||||||
if (key == turbine::Key::Alpha_D) {
|
if (key == turbine::Key::Alpha_D) {
|
||||||
m_tool = TileSheetTool::Draw;
|
m_tool = Tool::Draw;
|
||||||
setCopyEnabled(false);
|
setCopyEnabled(false);
|
||||||
setCutEnabled(false);
|
setCutEnabled(false);
|
||||||
setPasteEnabled(false);
|
setPasteEnabled(false);
|
||||||
m_model.clearSelection();
|
m_model.clearSelection();
|
||||||
} else if (key == turbine::Key::Alpha_S) {
|
} else if (key == turbine::Key::Alpha_S) {
|
||||||
m_tool = TileSheetTool::Select;
|
m_tool = Tool::Select;
|
||||||
setCopyEnabled(true);
|
setCopyEnabled(true);
|
||||||
setCutEnabled(true);
|
setCutEnabled(true);
|
||||||
setPasteEnabled(true);
|
setPasteEnabled(true);
|
||||||
} else if (key == turbine::Key::Alpha_F) {
|
} else if (key == turbine::Key::Alpha_F) {
|
||||||
m_tool = TileSheetTool::Fill;
|
m_tool = Tool::Fill;
|
||||||
setCopyEnabled(false);
|
setCopyEnabled(false);
|
||||||
setCutEnabled(false);
|
setCutEnabled(false);
|
||||||
setPasteEnabled(false);
|
setPasteEnabled(false);
|
||||||
@ -177,17 +173,17 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
|
ImGui::BeginChild("ToolBox", ImVec2(m_palViewWidth - 24, 30), true);
|
||||||
{
|
{
|
||||||
auto const btnSz = ImVec2(45, 14);
|
auto const btnSz = ImVec2(45, 14);
|
||||||
if (ImGui::Selectable("Select", m_tool == TileSheetTool::Select, 0, btnSz)) {
|
if (ImGui::Selectable("Select", m_tool == Tool::Select, 0, btnSz)) {
|
||||||
m_tool = TileSheetTool::Select;
|
m_tool = Tool::Select;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Selectable("Draw", m_tool == TileSheetTool::Draw, 0, btnSz)) {
|
if (ImGui::Selectable("Draw", m_tool == Tool::Draw, 0, btnSz)) {
|
||||||
m_tool = TileSheetTool::Draw;
|
m_tool = Tool::Draw;
|
||||||
m_model.clearSelection();
|
m_model.clearSelection();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Selectable("Fill", m_tool == TileSheetTool::Fill, 0, btnSz)) {
|
if (ImGui::Selectable("Fill", m_tool == Tool::Fill, 0, btnSz)) {
|
||||||
m_tool = TileSheetTool::Fill;
|
m_tool = Tool::Fill;
|
||||||
m_model.clearSelection();
|
m_model.clearSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,16 +370,16 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
|
|||||||
if (io.MouseDown[0] && m_prevMouseDownPos != mousePos) {
|
if (io.MouseDown[0] && m_prevMouseDownPos != mousePos) {
|
||||||
m_prevMouseDownPos = mousePos;
|
m_prevMouseDownPos = mousePos;
|
||||||
switch (m_tool) {
|
switch (m_tool) {
|
||||||
case TileSheetTool::Draw:
|
case Tool::Draw:
|
||||||
m_view.clickDraw(fbSize, clickPos(winPos, mousePos));
|
m_view.clickDraw(fbSize, clickPos(winPos, mousePos));
|
||||||
break;
|
break;
|
||||||
case TileSheetTool::Fill:
|
case Tool::Fill:
|
||||||
m_view.clickFill(fbSize, clickPos(winPos, mousePos));
|
m_view.clickFill(fbSize, clickPos(winPos, mousePos));
|
||||||
break;
|
break;
|
||||||
case TileSheetTool::Select:
|
case Tool::Select:
|
||||||
m_view.clickSelect(fbSize, clickPos(winPos, mousePos));
|
m_view.clickSelect(fbSize, clickPos(winPos, mousePos));
|
||||||
break;
|
break;
|
||||||
case TileSheetTool::None:
|
case Tool::None:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,7 +396,7 @@ void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const&fbSize) noexcept {
|
|||||||
}
|
}
|
||||||
if (io.MouseReleased[0]) {
|
if (io.MouseReleased[0]) {
|
||||||
m_prevMouseDownPos = {-1, -1};
|
m_prevMouseDownPos = {-1, -1};
|
||||||
m_view.releaseMouseButton(m_tool);
|
m_view.releaseMouseButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,13 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
enum class Tool {
|
||||||
|
None,
|
||||||
|
Draw,
|
||||||
|
Fill,
|
||||||
|
Select,
|
||||||
|
};
|
||||||
|
|
||||||
class TileSheetEditorImGui: public studio::Editor {
|
class TileSheetEditorImGui: public studio::Editor {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -64,7 +71,7 @@ class TileSheetEditorImGui: public studio::Editor {
|
|||||||
TileSheetEditorModel &m_model;
|
TileSheetEditorModel &m_model;
|
||||||
float m_palViewWidth = 300;
|
float m_palViewWidth = 300;
|
||||||
ox::Vec2 m_prevMouseDownPos;
|
ox::Vec2 m_prevMouseDownPos;
|
||||||
TileSheetTool m_tool = TileSheetTool::Draw;
|
Tool m_tool = Tool::Draw;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRStringView path);
|
TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRStringView path);
|
||||||
@ -79,9 +86,6 @@ class TileSheetEditorImGui: public studio::Editor {
|
|||||||
|
|
||||||
void paste() override;
|
void paste() override;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
bool acceptsClipboardPayload() const noexcept override;
|
|
||||||
|
|
||||||
void keyStateChanged(turbine::Key key, bool down) override;
|
void keyStateChanged(turbine::Key key, bool down) override;
|
||||||
|
|
||||||
void draw(studio::StudioContext&) noexcept override;
|
void draw(studio::StudioContext&) noexcept override;
|
||||||
|
@ -55,63 +55,55 @@ TileSheetEditorModel::TileSheetEditorModel(studio::StudioContext &sctx, ox::Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::cut() {
|
void TileSheetEditorModel::cut() {
|
||||||
if (!m_selection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TileSheetClipboard blankCb;
|
TileSheetClipboard blankCb;
|
||||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||||
auto const&s = activeSubSheet();
|
const auto &s = activeSubSheet();
|
||||||
iterateSelectionRows(*m_selection, [&](int x, int y) {
|
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||||
auto pt = ox::Point{x, y};
|
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||||
auto const idx = core::idx(s, pt);
|
auto pt = ox::Point(x, y);
|
||||||
auto const c = getPixel(s, m_img.bpp, idx);
|
const auto idx = core::idx(s, pt);
|
||||||
pt -= m_selection->a;
|
const auto c = getPixel(s, m_img.bpp, idx);
|
||||||
cb->addPixel(pt, c);
|
pt.x -= m_selectionBounds.x;
|
||||||
blankCb.addPixel(pt, 0);
|
pt.y -= m_selectionBounds.y;
|
||||||
});
|
cb->addPixel(pt, c);
|
||||||
auto const pt1 = m_selection->a;
|
blankCb.addPixel(pt, 0);
|
||||||
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
|
}
|
||||||
|
}
|
||||||
|
const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
|
||||||
|
const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
|
||||||
turbine::setClipboardObject(m_tctx, std::move(cb));
|
turbine::setClipboardObject(m_tctx, std::move(cb));
|
||||||
pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
|
pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::copy() {
|
void TileSheetEditorModel::copy() {
|
||||||
if (!m_selection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||||
iterateSelectionRows(*m_selection, [&](int x, int y) {
|
for (int y = m_selectionBounds.y; y <= m_selectionBounds.y2(); ++y) {
|
||||||
auto pt = ox::Point{x, y};
|
for (int x = m_selectionBounds.x; x <= m_selectionBounds.x2(); ++x) {
|
||||||
const auto&s = activeSubSheet();
|
auto pt = ox::Point(x, y);
|
||||||
const auto idx = core::idx(s, pt);
|
const auto &s = activeSubSheet();
|
||||||
const auto c = getPixel(s, m_img.bpp, idx);
|
const auto idx = core::idx(s, pt);
|
||||||
pt -= m_selection->a;
|
const auto c = getPixel(s, m_img.bpp, idx);
|
||||||
cb->addPixel(pt, c);
|
pt.x -= m_selectionBounds.x;
|
||||||
});
|
pt.y -= m_selectionBounds.y;
|
||||||
|
cb->addPixel(pt, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
turbine::setClipboardObject(m_tctx, std::move(cb));
|
turbine::setClipboardObject(m_tctx, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::paste() {
|
void TileSheetEditorModel::paste() {
|
||||||
if (!m_selection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto [cb, err] = turbine::getClipboardObject<TileSheetClipboard>(m_tctx);
|
auto [cb, err] = turbine::getClipboardObject<TileSheetClipboard>(m_tctx);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxLogError(err);
|
oxLogError(err);
|
||||||
oxErrf("Could not read clipboard: {}", toStr(err));
|
oxErrf("Could not read clipboard: {}", toStr(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto const&s = activeSubSheet();
|
const auto &s = activeSubSheet();
|
||||||
auto const pt1 = m_selection->a;
|
const auto pt1 = m_selectionOrigin == ox::Point(-1, -1) ? ox::Point(0, 0) : m_selectionOrigin;
|
||||||
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
|
const auto pt2 = ox::Point(s.columns * TileWidth, s.rows * TileHeight);
|
||||||
pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
|
|
||||||
auto const cb = getClipboardObject<TileSheetClipboard>(m_tctx);
|
|
||||||
return cb.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::StringView TileSheetEditorModel::palPath() const noexcept {
|
ox::StringView TileSheetEditorModel::palPath() const noexcept {
|
||||||
auto [path, err] = m_img.defaultPalette.getPath();
|
auto [path, err] = m_img.defaultPalette.getPath();
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -214,26 +206,30 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int palIdx) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::select(ox::Point const&pt) noexcept {
|
void TileSheetEditorModel::select(ox::Point const&pt) noexcept {
|
||||||
if (m_selTracker.updateCursorPoint(pt)) {
|
if (!m_selectionOngoing) {
|
||||||
m_selection.emplace(m_selTracker.selection());
|
m_selectionOrigin = pt;
|
||||||
|
m_selectionOngoing = true;
|
||||||
|
m_selectionBounds = {pt, pt};
|
||||||
|
m_updated = true;
|
||||||
|
} else if (m_selectionBounds.pt2() != pt) {
|
||||||
|
m_selectionBounds = {m_selectionOrigin, pt};
|
||||||
m_updated = true;
|
m_updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::completeSelection() noexcept {
|
void TileSheetEditorModel::completeSelection() noexcept {
|
||||||
if (m_selTracker.selectionOngoing()) {
|
m_selectionOngoing = false;
|
||||||
m_selTracker.finishSelection();
|
auto &s = activeSubSheet();
|
||||||
m_selection.emplace(m_selTracker.selection());
|
auto pt = m_selectionBounds.pt2();
|
||||||
auto&pt = m_selection->b;
|
pt.x = ox::min(s.columns * TileWidth, pt.x);
|
||||||
auto&s = activeSubSheet();
|
pt.y = ox::min(s.rows * TileHeight, pt.y);
|
||||||
pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
|
m_selectionBounds.setPt2(pt);
|
||||||
pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::clearSelection() noexcept {
|
void TileSheetEditorModel::clearSelection() noexcept {
|
||||||
m_updated = true;
|
m_updated = true;
|
||||||
m_selection.reset();
|
m_selectionOrigin = {-1, -1};
|
||||||
|
m_selectionBounds = {{-1, -1}, {-1, -1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileSheetEditorModel::updated() const noexcept {
|
bool TileSheetEditorModel::updated() const noexcept {
|
||||||
@ -270,9 +266,9 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
|
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
|
||||||
auto const&s = activeSubSheet();
|
const auto &s = activeSubSheet();
|
||||||
auto const pt = idxToPt(static_cast<int>(idx), s.columns);
|
const auto pt = idxToPt(static_cast<int>(idx), s.columns);
|
||||||
return m_selection && m_selection->contains(pt);
|
return m_selectionBounds.contains(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
|
void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int oldColor) const noexcept {
|
||||||
@ -309,7 +305,7 @@ void TileSheetEditorModel::getFillPixels(bool *pixels, ox::Point const&pt, int o
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept {
|
void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept {
|
||||||
std::ignore = m_undoStack.push(ox::UPtr<studio::UndoCommand>(cmd));
|
m_undoStack.push(ox::UPtr<studio::UndoCommand>(cmd));
|
||||||
m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd);
|
m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd);
|
||||||
m_updated = true;
|
m_updated = true;
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,10 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
size_t m_palettePage{};
|
size_t m_palettePage{};
|
||||||
studio::UndoStack &m_undoStack;
|
studio::UndoStack &m_undoStack;
|
||||||
class DrawCommand *m_ongoingDrawCommand = nullptr;
|
class DrawCommand *m_ongoingDrawCommand = nullptr;
|
||||||
studio::SelectionTracker m_selTracker;
|
|
||||||
ox::Optional<studio::Selection> m_selection;
|
|
||||||
bool m_updated = false;
|
bool m_updated = false;
|
||||||
|
bool m_selectionOngoing = false;
|
||||||
|
ox::Point m_selectionOrigin = {-1, -1};
|
||||||
|
ox::Bounds m_selectionBounds = {{-1, -1}, {-1, -1}};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
|
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
|
||||||
@ -48,9 +49,6 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
|
|
||||||
void paste();
|
void paste();
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
bool acceptsClipboardPayload() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr TileSheet const&img() const noexcept;
|
constexpr TileSheet const&img() const noexcept;
|
||||||
|
|
||||||
|
@ -84,18 +84,9 @@ void TileSheetEditorView::clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clic
|
|||||||
m_model.fill(pt, static_cast<int>(m_palIdx));
|
m_model.fill(pt, static_cast<int>(m_palIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorView::releaseMouseButton(TileSheetTool tool) noexcept {
|
void TileSheetEditorView::releaseMouseButton() noexcept {
|
||||||
switch (tool) {
|
m_model.endDrawCommand();
|
||||||
case TileSheetTool::Draw:
|
m_model.completeSelection();
|
||||||
m_model.endDrawCommand();
|
|
||||||
break;
|
|
||||||
case TileSheetTool::Select:
|
|
||||||
m_model.completeSelection();
|
|
||||||
break;
|
|
||||||
case TileSheetTool::Fill:
|
|
||||||
case TileSheetTool::None:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept {
|
void TileSheetEditorView::resizeView(ox::Vec2 const&sz) noexcept {
|
||||||
|
@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
enum class TileSheetTool {
|
enum class TileSheetTool: int {
|
||||||
None,
|
|
||||||
Select,
|
Select,
|
||||||
Draw,
|
Draw,
|
||||||
Fill,
|
Fill,
|
||||||
@ -34,8 +33,6 @@ constexpr auto toString(TileSheetTool t) noexcept {
|
|||||||
return "Draw";
|
return "Draw";
|
||||||
case TileSheetTool::Fill:
|
case TileSheetTool::Fill:
|
||||||
return "Fill";
|
return "Fill";
|
||||||
case TileSheetTool::None:
|
|
||||||
return "None";
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -69,7 +66,7 @@ class TileSheetEditorView: public ox::SignalHandler {
|
|||||||
|
|
||||||
void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept;
|
void clickFill(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept;
|
||||||
|
|
||||||
void releaseMouseButton(TileSheetTool tool) noexcept;
|
void releaseMouseButton() noexcept;
|
||||||
|
|
||||||
void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept;
|
void scrollV(ox::Vec2 const&paneSz, float wheel, bool zoomMod) noexcept;
|
||||||
|
|
||||||
|
@ -139,7 +139,10 @@ void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_model.pixelSelected(i)) {
|
if (m_model.pixelSelected(i)) {
|
||||||
color = applySelectionColor(color);
|
auto const r = red16(color) / 2;
|
||||||
|
auto const g = (green16(color) + 20) / 2;
|
||||||
|
auto const b = (blue16(color) + 31) / 2;
|
||||||
|
color = color16(r, g, b);
|
||||||
}
|
}
|
||||||
setPixelBufferObject(paneSize, static_cast<unsigned>(i * VertexVboRows), fx, fy, color, vbo, ebo);
|
setPixelBufferObject(paneSize, static_cast<unsigned>(i * VertexVboRows), fx, fy, color, vbo, ebo);
|
||||||
});
|
});
|
||||||
|
@ -15,11 +15,11 @@ std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static TileSheet::SubSheet const *getSubsheet(TileSheet::SubSheet const&ss, SubSheetId const id) noexcept {
|
static TileSheet::SubSheet const*getSubsheet(TileSheet::SubSheet const&ss, SubSheetId const id) noexcept {
|
||||||
if (ss.id == id) {
|
if (ss.id == id) {
|
||||||
return &ss;
|
return &ss;
|
||||||
}
|
}
|
||||||
for (auto const&child: ss.subsheets) {
|
for (auto const&child : ss.subsheets) {
|
||||||
if (auto out = getSubsheet(child, id)) {
|
if (auto out = getSubsheet(child, id)) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ static size_t getTileCnt(TileSheet::SubSheet const&ss, int const bpp) noexcept {
|
|||||||
return ss.pixels.size() / bytesPerTile;
|
return ss.pixels.size() / bytesPerTile;
|
||||||
} else {
|
} else {
|
||||||
size_t out{};
|
size_t out{};
|
||||||
for (auto const&child: ss.subsheets) {
|
for (auto const&child : ss.subsheets) {
|
||||||
out += getTileCnt(child, bpp);
|
out += getTileCnt(child, bpp);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@ -45,7 +45,7 @@ size_t getTileCnt(TileSheet const&ts) noexcept {
|
|||||||
return getTileCnt(ts.subsheet, ts.bpp);
|
return getTileCnt(ts.subsheet, ts.bpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheet::SubSheet const *getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept {
|
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept {
|
||||||
return getSubsheet(ts.subsheet, id);
|
return getSubsheet(ts.subsheet, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ static ox::Optional<size_t> getPixelIdx(
|
|||||||
SubSheetId const id,
|
SubSheetId const id,
|
||||||
size_t idx,
|
size_t idx,
|
||||||
int8_t const bpp) noexcept {
|
int8_t const bpp) noexcept {
|
||||||
for (auto const&child: ss.subsheets) {
|
for (auto const&child : ss.subsheets) {
|
||||||
if (child.id == id) {
|
if (child.id == id) {
|
||||||
return ox::Optional<size_t>(ox::in_place, idx);
|
return ox::Optional<size_t>(ox::in_place, idx);
|
||||||
}
|
}
|
||||||
@ -106,8 +106,8 @@ uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, ox::Point const&pt)
|
|||||||
return getPixel(ss, pBpp, idx);
|
return getPixel(ss, pBpp, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setPixel(ox::Vector<uint8_t> &pixels, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept {
|
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept {
|
||||||
auto &pixel = pixels[static_cast<std::size_t>(idx / 2)];
|
auto &pixel = ss.pixels[static_cast<std::size_t>(idx / 2)];
|
||||||
if (pBpp == 4) {
|
if (pBpp == 4) {
|
||||||
if (idx & 1) {
|
if (idx & 1) {
|
||||||
pixel = static_cast<uint8_t>((pixel & 0b0000'1111) | (palIdx << 4));
|
pixel = static_cast<uint8_t>((pixel & 0b0000'1111) | (palIdx << 4));
|
||||||
@ -119,59 +119,29 @@ static void setPixel(ox::Vector<uint8_t> &pixels, int8_t pBpp, uint64_t idx, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept {
|
|
||||||
setPixel(ss.pixels, pBpp, idx, palIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setPixel(ox::Vector<uint8_t> &pixels, int columns, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept {
|
|
||||||
const auto idx = ptToIdx(pt, columns);
|
|
||||||
setPixel(pixels, pBpp, idx, palIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept {
|
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept {
|
||||||
const auto idx = ptToIdx(pt, ss.columns);
|
const auto idx = ptToIdx(pt, ss.columns);
|
||||||
setPixel(ss, pBpp, idx, palIdx);
|
setPixel(ss, pBpp, idx, palIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error setPixelCount(ox::Vector<uint8_t> &pixels, int8_t pBpp, std::size_t cnt) noexcept {
|
ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) noexcept {
|
||||||
switch (pBpp) {
|
switch (pBpp) {
|
||||||
case 4:
|
case 4:
|
||||||
pixels.resize(cnt / 2);
|
ss.pixels.resize(cnt / 2);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
case 8:
|
case 8:
|
||||||
pixels.resize(cnt);
|
ss.pixels.resize(cnt);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
default:
|
default:
|
||||||
return OxError(1, "Invalid pBpp used for TileSheet::SubSheet::setPixelCount");
|
return OxError(1, "Invalid pBpp used for TileSheet::SubSheet::setPixelCount");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) noexcept {
|
|
||||||
return setPixelCount(ss.pixels, pBpp, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept {
|
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept {
|
||||||
const auto pixelsSize = static_cast<unsigned>(ss.pixels.size());
|
const auto pixelsSize = static_cast<unsigned>(ss.pixels.size());
|
||||||
return pBpp == 4 ? pixelsSize * 2 : pixelsSize;
|
return pBpp == 4 ? pixelsSize * 2 : pixelsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz) noexcept {
|
|
||||||
ox::Vector<uint8_t> out;
|
|
||||||
oxReturnError(setPixelCount(out, pBpp, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile));
|
|
||||||
auto const w = sz.width * TileWidth;
|
|
||||||
auto const h = sz.height * TileHeight;
|
|
||||||
for (auto x = 0; x < w; ++x) {
|
|
||||||
for (auto y = 0; y < h; ++y) {
|
|
||||||
auto const palIdx = getPixel(ss, pBpp, {x, y});
|
|
||||||
setPixel(out, sz.width, pBpp, {x, y}, palIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss.columns = sz.width;
|
|
||||||
ss.rows = sz.height;
|
|
||||||
ss.pixels = std::move(out);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept {
|
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept {
|
||||||
if (ss.id == pId) {
|
if (ss.id == pId) {
|
||||||
return ox::StringView(ss.name);
|
return ox::StringView(ss.name);
|
||||||
|
@ -50,6 +50,7 @@ void SceneEditorImGui::onActivated() noexcept {
|
|||||||
ox::Error SceneEditorImGui::saveItem() noexcept {
|
ox::Error SceneEditorImGui::saveItem() noexcept {
|
||||||
const auto sctx = applicationData<studio::StudioContext>(m_ctx);
|
const auto sctx = applicationData<studio::StudioContext>(m_ctx);
|
||||||
oxReturnError(sctx->project->writeObj(itemPath(), m_editor.scene()));
|
oxReturnError(sctx->project->writeObj(itemPath(), m_editor.scene()));
|
||||||
|
oxReturnError(keelCtx(m_ctx).assetManager.setAsset(itemPath(), m_editor.scene()));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ target_link_libraries(
|
|||||||
|
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
NostalgiaStudio PUBLIC
|
NostalgiaStudio PUBLIC
|
||||||
OLYMPIC_APP_VERSION="dev build"
|
OLYMPIC_APP_VERSION="d2024.05.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
#include <functional>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ox/event/signal.hpp>
|
#include <ox/event/signal.hpp>
|
||||||
#include <ox/fs/fs.hpp>
|
#include <ox/fs/fs.hpp>
|
||||||
#include <ox/model/typenamecatcher.hpp>
|
#include <ox/model/typenamecatcher.hpp>
|
||||||
@ -182,11 +178,9 @@ constexpr AssetRef<T>::AssetRef(AssetRef &&h) noexcept: m_ctr(h.m_ctr) {
|
|||||||
h.m_ctr = nullptr;
|
h.m_ctr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Context;
|
|
||||||
|
|
||||||
class AssetManager {
|
class AssetManager {
|
||||||
private:
|
private:
|
||||||
class AssetTypeManagerBase: public ox::SignalHandler {
|
class AssetTypeManagerBase {
|
||||||
public:
|
public:
|
||||||
virtual ~AssetTypeManagerBase() = default;
|
virtual ~AssetTypeManagerBase() = default;
|
||||||
|
|
||||||
@ -195,45 +189,36 @@ class AssetManager {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class AssetTypeManager: public AssetTypeManagerBase {
|
class AssetTypeManager: public AssetTypeManagerBase {
|
||||||
public:
|
|
||||||
using Loader = std::function<ox::Result<T>(ox::StringView assetId)>;
|
|
||||||
private:
|
private:
|
||||||
Loader m_loader{};
|
|
||||||
ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
|
ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AssetTypeManager(Loader loader) noexcept: m_loader(loader) {}
|
ox::Result<AssetRef<T>> getAsset(ox::StringView const&assetId) const noexcept {
|
||||||
|
auto out = m_cache.at(assetId);
|
||||||
ox::Result<AssetRef<T>> getAsset(ox::StringView const assetId) const noexcept {
|
oxReturnError(out);
|
||||||
oxRequire(out, m_cache.at(assetId));
|
return AssetRef<T>(out.value->get());
|
||||||
if (!out || !*out) {
|
|
||||||
return OxError(1, "asset is null");
|
|
||||||
}
|
|
||||||
return AssetRef<T>(out->get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<AssetRef<T>> loadAsset(ox::StringView const assetId) noexcept {
|
ox::Result<AssetRef<T>> setAsset(ox::StringView const&assetId, T const&obj) noexcept {
|
||||||
auto &p = m_cache[assetId];
|
auto &p = m_cache[assetId];
|
||||||
oxRequireM(obj, m_loader(assetId));
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = ox::make_unique<AssetContainer<T>>(std::move(obj));
|
p = ox::make_unique<AssetContainer<T>>(obj);
|
||||||
} else {
|
} else {
|
||||||
p->set(std::move(obj));
|
p->set(obj);
|
||||||
p->updated.emit();
|
p->updated.emit();
|
||||||
}
|
}
|
||||||
return AssetRef<T>(p.get());
|
return AssetRef<T>(p.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(ox::StringView const assetId) noexcept {
|
ox::Result<AssetRef<T>> setAsset(ox::StringView const&assetId, T &&obj) noexcept {
|
||||||
auto &p = m_cache[assetId];
|
auto &p = m_cache[assetId];
|
||||||
oxRequireM(obj, m_loader(assetId));
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = ox::make_unique<AssetContainer<T>>(std::move(obj));
|
p = ox::make_unique<AssetContainer<T>>(obj);
|
||||||
} else {
|
} else {
|
||||||
p->set(std::move(obj));
|
p->set(std::move(obj));
|
||||||
p->updated.emit();
|
p->updated.emit();
|
||||||
}
|
}
|
||||||
return {};
|
return AssetRef<T>(p.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc() noexcept final {
|
void gc() noexcept final {
|
||||||
@ -247,51 +232,29 @@ class AssetManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ox::HashMap<ox::String, ox::UPtr<AssetTypeManagerBase>> m_assetTypeManagers;
|
ox::HashMap<ox::String, ox::UPtr<AssetTypeManagerBase>> m_assetTypeManagers;
|
||||||
struct FileTracker {
|
|
||||||
ox::Signal<ox::Error(ox::StringView assetId)> updated;
|
|
||||||
};
|
|
||||||
ox::HashMap<ox::String, FileTracker> m_fileTrackers;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<AssetTypeManager<T>*> getTypeManager() noexcept {
|
AssetTypeManager<T> *getTypeManager() noexcept {
|
||||||
constexpr auto &typeId = ox::ModelTypeId_v<T>;
|
constexpr auto typeName = ox::requireModelTypeName<T>();
|
||||||
static_assert(typeId != "", "Types must have TypeName to use AssetManager");
|
static_assert(ox::StringView(typeName) != "", "Types must have TypeName to use AssetManager");
|
||||||
auto &am = m_assetTypeManagers[typeId];
|
auto &am = m_assetTypeManagers[typeName];
|
||||||
auto const out = dynamic_cast<AssetTypeManager<T>*>(am.get());
|
if (!am) {
|
||||||
if (!out) {
|
am = ox::make_unique<AssetTypeManager<T>>();
|
||||||
return OxError(1, "no AssetTypeManager for type");
|
|
||||||
}
|
}
|
||||||
return out;
|
return dynamic_cast<AssetTypeManager<T>*>(am.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void initTypeManager(auto const&makeLoader, Context &ctx) noexcept {
|
ox::Result<AssetRef<T>> getAsset(ox::CRStringView assetId) noexcept {
|
||||||
constexpr auto &typeId = ox::ModelTypeId_v<T>;
|
auto m = getTypeManager<T>();
|
||||||
static_assert(typeId != "", "Types must have TypeName to use AssetManager");
|
|
||||||
auto &am = m_assetTypeManagers[typeId];
|
|
||||||
if (!am) {
|
|
||||||
am = ox::make_unique<AssetTypeManager<T>>(makeLoader(ctx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ox::Result<AssetRef<T>> getAsset(ox::StringView assetId) noexcept {
|
|
||||||
oxRequire(m, getTypeManager<T>());
|
|
||||||
return m->getAsset(assetId);
|
return m->getAsset(assetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(ox::StringView assetId) noexcept {
|
|
||||||
m_fileTrackers[assetId].updated.emit(assetId);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<AssetRef<T>> loadAsset(ox::StringView assetId) noexcept {
|
ox::Result<AssetRef<T>> setAsset(ox::CRStringView assetId, T const&obj) noexcept {
|
||||||
oxRequire(m, getTypeManager<T>());
|
auto m = getTypeManager<T>();
|
||||||
oxRequire(out, m->loadAsset(assetId));
|
return m->setAsset(assetId, obj);
|
||||||
m_fileTrackers[assetId].updated.connect(m, &AssetTypeManager<T>::reloadAsset);
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc() noexcept {
|
void gc() noexcept {
|
||||||
|
@ -32,43 +32,14 @@ oxModelEnd()
|
|||||||
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&file) noexcept;
|
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&file) noexcept;
|
||||||
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::CRStringView file) noexcept;
|
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::CRStringView file) noexcept;
|
||||||
|
|
||||||
|
|
||||||
void createUuidMapping(Context &ctx, ox::StringView filePath, ox::UUID const&uuid) noexcept;
|
|
||||||
|
|
||||||
ox::Error buildUuidMap(Context &ctx) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::CRStringView path) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringView path) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> getPath(Context &ctx, ox::CStringView fileId) noexcept;
|
|
||||||
|
|
||||||
constexpr ox::Result<ox::UUID> uuidUrlToUuid(ox::StringView uuidUrl) noexcept {
|
|
||||||
return ox::UUID::fromString(substr(uuidUrl, 7));
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidUrlToPath(Context &ctx, ox::StringView uuid) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept;
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
|
|
||||||
|
|
||||||
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept;
|
|
||||||
|
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr auto makeLoader(Context &ctx) {
|
ox::Result<keel::AssetRef<T>> readObjFile(
|
||||||
return [&ctx](ox::StringView assetId) -> ox::Result<T> {
|
keel::Context &ctx,
|
||||||
ox::StringView path;
|
ox::StringView assetId,
|
||||||
oxRequire(p, ctx.uuidToPath.at(assetId));
|
bool forceLoad) noexcept {
|
||||||
path = *p;
|
constexpr auto readConvert = [](Context &ctx, const ox::Buffer &buff) -> ox::Result<T> {
|
||||||
oxRequire(buff, ctx.rom->read(path));
|
|
||||||
auto [obj, err] = readAsset<T>(buff);
|
auto [obj, err] = readAsset<T>(buff);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
||||||
@ -78,34 +49,25 @@ constexpr auto makeLoader(Context &ctx) {
|
|||||||
}
|
}
|
||||||
return std::move(obj);
|
return std::move(obj);
|
||||||
};
|
};
|
||||||
};
|
ox::StringView path;
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ox::Result<keel::AssetRef<T>> readObjFile(
|
|
||||||
keel::Context &ctx,
|
|
||||||
ox::StringView assetId,
|
|
||||||
bool forceLoad) noexcept {
|
|
||||||
ox::UUIDStr uuidStr;
|
|
||||||
if (beginsWith(assetId, "uuid://")) {
|
if (beginsWith(assetId, "uuid://")) {
|
||||||
assetId = substr(assetId, 7);
|
assetId = substr(assetId, 7);
|
||||||
oxRequire(p, keel::uuidToPath(ctx, assetId));
|
oxRequire(p, ctx.uuidToPath.at(assetId));
|
||||||
|
path = *p;
|
||||||
} else {
|
} else {
|
||||||
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
|
path = assetId;
|
||||||
if (!uuidErr) {
|
|
||||||
uuidStr = uuid.toString();
|
|
||||||
assetId = uuidStr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (forceLoad) {
|
if (forceLoad) {
|
||||||
ctx.assetManager.initTypeManager<T>(detail::makeLoader<T>, ctx);
|
oxRequire(buff, ctx.rom->read(path));
|
||||||
oxRequire(cached, ctx.assetManager.loadAsset<T>(assetId));
|
oxRequire(obj, readConvert(ctx, buff));
|
||||||
|
oxRequire(cached, ctx.assetManager.setAsset(assetId, obj));
|
||||||
return cached;
|
return cached;
|
||||||
} else {
|
} else {
|
||||||
auto [cached, err] = ctx.assetManager.getAsset<T>(assetId);
|
auto [cached, err] = ctx.assetManager.getAsset<T>(assetId);
|
||||||
if (err) {
|
if (err) {
|
||||||
ctx.assetManager.initTypeManager<T>(detail::makeLoader<T>, ctx);
|
oxRequire(buff, ctx.rom->read(path));
|
||||||
oxReturnError(ctx.assetManager.loadAsset<T>(assetId).moveTo(cached));
|
oxRequire(obj, readConvert(ctx, buff));
|
||||||
|
oxReturnError(ctx.assetManager.setAsset(assetId, obj).moveTo(cached));
|
||||||
}
|
}
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
@ -127,7 +89,34 @@ ox::Result<keel::AssetRef<T>> readObjNoCache(
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ox::Error reloadAsset(keel::Context &ctx, ox::StringView assetId) noexcept;
|
void createUuidMapping(Context &ctx, ox::StringView filePath, ox::UUID const&uuid) noexcept;
|
||||||
|
|
||||||
|
ox::Error buildUuidMap(Context &ctx) noexcept;
|
||||||
|
|
||||||
|
ox::Result<ox::String> uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept;
|
||||||
|
|
||||||
|
ox::Result<ox::String> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
|
||||||
|
|
||||||
|
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<AssetRef<T>> setAsset(keel::Context &ctx, ox::StringView assetId, T const&asset) noexcept {
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
|
if (assetId.len() == 0) {
|
||||||
|
return OxError(1, "Invalid asset ID");
|
||||||
|
}
|
||||||
|
ox::UUIDStr idStr;
|
||||||
|
if (assetId[0] == '/') {
|
||||||
|
auto const [id, err] = ctx.pathToUuid.at(assetId);
|
||||||
|
oxReturnError(err);
|
||||||
|
idStr = id->toString();
|
||||||
|
assetId = idStr;
|
||||||
|
}
|
||||||
|
return ctx.assetManager.setAsset(assetId, asset);
|
||||||
|
#else
|
||||||
|
return OxError(1, "Not supported on this platform");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<keel::AssetRef<T>> readObj(
|
ox::Result<keel::AssetRef<T>> readObj(
|
||||||
|
@ -86,21 +86,19 @@ ox::Error preloadObj(
|
|||||||
ox::TypeStore &ts,
|
ox::TypeStore &ts,
|
||||||
ox::FileSystem &romFs,
|
ox::FileSystem &romFs,
|
||||||
ox::Preloader<PlatSpec> &pl,
|
ox::Preloader<PlatSpec> &pl,
|
||||||
ox::StringView const path) noexcept {
|
ox::CRStringView path) noexcept {
|
||||||
// load file
|
// load file
|
||||||
oxRequireM(buff, romFs.read(path));
|
oxRequireM(buff, romFs.read(path));
|
||||||
oxRequireM(obj, keel::readAsset(ts, buff));
|
oxRequireM(obj, keel::readAsset(ts, buff));
|
||||||
if (obj.type()->preloadable) {
|
if (obj.type()->preloadable) {
|
||||||
|
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
|
||||||
// preload
|
// preload
|
||||||
auto const size = ox::sizeOf<GbaPlatSpec>(&obj);
|
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj)));
|
||||||
auto const alignment = ox::alignOf<GbaPlatSpec>(obj);
|
|
||||||
oxRequire(a, pl.startAlloc(size, alignment));
|
|
||||||
auto const err = ox::preload<GbaPlatSpec, ox::ModelObject>(&pl, &obj);
|
auto const err = ox::preload<GbaPlatSpec, ox::ModelObject>(&pl, &obj);
|
||||||
oxReturnError(pl.endAlloc());
|
oxReturnError(pl.endAlloc());
|
||||||
oxReturnError(err);
|
oxReturnError(err);
|
||||||
keel::PreloadPtr const p{.preloadAddr = a};
|
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};
|
||||||
oxReturnError(ox::writeMC(p).moveTo(buff));
|
oxReturnError(ox::writeMC(p).moveTo(buff));
|
||||||
oxOutf("preloaded {} as a {} @ {} to {}\n", path, obj.type()->typeName, a, a + size);
|
|
||||||
} else {
|
} else {
|
||||||
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
||||||
oxReturnError(ox::writeMC(obj).moveTo(buff));
|
oxReturnError(ox::writeMC(obj).moveTo(buff));
|
||||||
|
@ -83,72 +83,19 @@ ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::CRStringView path) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
|
ox::Result<ox::String> uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept {
|
||||||
oxRequire(path, fileAddr.getPath());
|
|
||||||
return getUuid(ctx, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringView path) noexcept {
|
|
||||||
if (beginsWith(path, "uuid://")) {
|
|
||||||
auto const uuid = substr(path, 7);
|
|
||||||
return ox::UUID::fromString(uuid);
|
|
||||||
} else {
|
|
||||||
return pathToUuid(ctx, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
|
|
||||||
oxRequire(path, fileAddr.getPath());
|
|
||||||
if (beginsWith(path, "uuid://")) {
|
|
||||||
auto const uuid = substr(path, 7);
|
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
oxRequire(out, ctx.uuidToPath.at(uuid));
|
||||||
return ox::CStringView{*out};
|
return *out;
|
||||||
#else
|
|
||||||
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
return ox::CStringView{path};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> getPath(Context &ctx, ox::CStringView fileId) noexcept {
|
|
||||||
if (beginsWith(fileId, "uuid://")) {
|
|
||||||
auto const uuid = substr(fileId, 7);
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
||||||
return ox::CStringView{*out};
|
|
||||||
#else
|
|
||||||
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
return ox::CStringView{fileId};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidUrlToPath(Context &ctx, ox::StringView uuid) noexcept {
|
|
||||||
uuid = substr(uuid, 7);
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
||||||
return ox::CStringView(*out);
|
|
||||||
#else
|
#else
|
||||||
return OxError(1, "UUID to path conversion not supported on this platform");
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept {
|
ox::Result<ox::String> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
oxRequire(out, ctx.uuidToPath.at(uuid.toString()));
|
||||||
return ox::CStringView(*out);
|
return *out;
|
||||||
#else
|
|
||||||
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
oxRequireM(out, ctx.uuidToPath.at(uuid.toString()));
|
|
||||||
return ox::CStringView(*out);
|
|
||||||
#else
|
#else
|
||||||
return OxError(1, "UUID to path conversion not supported on this platform");
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
||||||
#endif
|
#endif
|
||||||
@ -166,21 +113,6 @@ ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(keel::Context &ctx, ox::StringView assetId) noexcept {
|
|
||||||
ox::UUIDStr uuidStr;
|
|
||||||
if (beginsWith(assetId, "uuid://")) {
|
|
||||||
assetId = substr(assetId, 7);
|
|
||||||
oxRequire(p, keel::uuidToPath(ctx, assetId));
|
|
||||||
} else {
|
|
||||||
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
|
|
||||||
if (!uuidErr) {
|
|
||||||
uuidStr = uuid.toString();
|
|
||||||
assetId = uuidStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ctx.assetManager.reloadAsset(assetId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -234,10 +166,6 @@ ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const
|
|||||||
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(keel::Context&, ox::StringView) noexcept {
|
|
||||||
return OxError(1, "reloadAsset is unsupported on this platform");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include <keel/keel.hpp>
|
#include <keel/keel.hpp>
|
||||||
|
|
||||||
static ox::Error writeFileBuff(ox::StringView path, ox::BufferView const buff) noexcept {
|
static ox::Error writeFileBuff(ox::StringView path, ox::Buffer const&buff) noexcept {
|
||||||
try {
|
try {
|
||||||
std::ofstream f(std::string(toStdStringView(path)), std::ios::binary);
|
std::ofstream f(std::string(toStdStringView(path)), std::ios::binary);
|
||||||
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
||||||
@ -39,10 +39,10 @@ static ox::Result<ox::Buffer> readFileBuff(ox::StringView path) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error generateTypes(ox::TypeStore &ts) noexcept {
|
static ox::Error generateTypes(ox::TypeStore *ts) noexcept {
|
||||||
for (auto const mod : keel::modules()) {
|
for (auto const mod : keel::modules()) {
|
||||||
for (auto gen : mod->types()) {
|
for (auto gen : mod->types()) {
|
||||||
oxReturnError(gen(ts));
|
oxReturnError(gen(*ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
@ -54,7 +54,7 @@ static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::Strin
|
|||||||
ox::FileSystem32 dst(dstBuff);
|
ox::FileSystem32 dst(dstBuff);
|
||||||
oxRequire(ctx, keel::init(ox::make_unique<ox::PassThroughFS>(argSrc), "keel-pack"));
|
oxRequire(ctx, keel::init(ox::make_unique<ox::PassThroughFS>(argSrc), "keel-pack"));
|
||||||
keel::TypeStore ts(*ctx->rom, ox::sfmt("{}/type_descriptors", projectDataDir));
|
keel::TypeStore ts(*ctx->rom, ox::sfmt("{}/type_descriptors", projectDataDir));
|
||||||
oxReturnError(generateTypes(ts));
|
oxReturnError(generateTypes(&ts));
|
||||||
oxReturnError(keel::pack(*ctx, ts, dst));
|
oxReturnError(keel::pack(*ctx, ts, dst));
|
||||||
oxRequireM(pl, keel::GbaPreloader::make());
|
oxRequireM(pl, keel::GbaPreloader::make());
|
||||||
oxReturnError(preload(ts, dst, *pl));
|
oxReturnError(preload(ts, dst, *pl));
|
||||||
@ -62,13 +62,14 @@ static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::Strin
|
|||||||
// resize buffer
|
// resize buffer
|
||||||
oxRequire(dstSize, dst.size());
|
oxRequire(dstSize, dst.size());
|
||||||
dstBuff.resize(dstSize);
|
dstBuff.resize(dstSize);
|
||||||
// concatenate ROM segments
|
|
||||||
oxRequireM(romBuff, readFileBuff(argRomBin));
|
oxRequireM(romBuff, readFileBuff(argRomBin));
|
||||||
oxOutf("Input exe size: {} bytes\n", romBuff.size());
|
oxReturnError(appendBinary(romBuff, dstBuff, *pl));
|
||||||
|
|
||||||
oxOutf("Dest FS size: {} bytes\n", dstSize);
|
oxOutf("Dest FS size: {} bytes\n", dstSize);
|
||||||
oxOutf("Preload buff size: {} bytes\n", pl->buff().size());
|
oxOutf("Preload buff size: {} bytes\n", pl->buff().size());
|
||||||
oxReturnError(appendBinary(romBuff, dstBuff, *pl));
|
oxOutf("ROM buff size: {} bytes\n", romBuff.size());
|
||||||
oxOutf("Final ROM buff size: {} bytes\n", romBuff.size());
|
|
||||||
oxReturnError(writeFileBuff(argRomBin, romBuff));
|
oxReturnError(writeFileBuff(argRomBin, romBuff));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,11 @@ static ox::Error pathToInode(
|
|||||||
}
|
}
|
||||||
if (beginsWith(path, "uuid://")) {
|
if (beginsWith(path, "uuid://")) {
|
||||||
auto const uuid = ox::substr(path, 7);
|
auto const uuid = ox::substr(path, 7);
|
||||||
oxReturnError(keel::uuidToPath(ctx, uuid).to<ox::String>().moveTo(path));
|
oxReturnError(keel::uuidToPath(ctx, uuid).moveTo(path));
|
||||||
}
|
}
|
||||||
oxRequire(s, dest.stat(path));
|
oxRequire(s, dest.stat(path));
|
||||||
oxReturnError(o.at("type").unwrap()->set(static_cast<int8_t>(ox::FileAddressType::Inode)));
|
oxReturnError(o.at("type").unwrap()->set(static_cast<int8_t>(ox::FileAddressType::Inode)));
|
||||||
oxOutf("\tpath to inode: {} => {}\n", path, s.inode);
|
oxOutf("path to inode: {} => {}\n", path, s.inode);
|
||||||
return data.set(2, s.inode);
|
return data.set(2, s.inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,6 @@ static ox::Error doTransformations(
|
|||||||
oxReturnError(keel::performPackTransforms(ctx, buff));
|
oxReturnError(keel::performPackTransforms(ctx, buff));
|
||||||
// transform FileAddresses
|
// transform FileAddresses
|
||||||
oxRequireM(obj, keel::readAsset(ts, buff));
|
oxRequireM(obj, keel::readAsset(ts, buff));
|
||||||
oxOutf("transforming {}\n", filePath);
|
|
||||||
oxReturnError(transformFileAddressesObj(ctx, dest, obj));
|
oxReturnError(transformFileAddressesObj(ctx, dest, obj));
|
||||||
oxReturnError(ox::writeClaw(obj).moveTo(buff));
|
oxReturnError(ox::writeClaw(obj).moveTo(buff));
|
||||||
// write file to dest
|
// write file to dest
|
||||||
@ -144,15 +143,16 @@ static ox::Error copy(
|
|||||||
if (beginsWith(name, ".")) {
|
if (beginsWith(name, ".")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
oxOutf("reading {}\n", currentFile);
|
||||||
oxRequire(stat, src.stat(currentFile));
|
oxRequire(stat, src.stat(currentFile));
|
||||||
if (stat.fileType == ox::FileType::Directory) {
|
if (stat.fileType == ox::FileType::Directory) {
|
||||||
oxReturnError(dest.mkdir(currentFile, true));
|
oxReturnError(dest.mkdir(currentFile, true));
|
||||||
oxReturnError(copy(src, dest, currentFile + '/'));
|
oxReturnError(copy(src, dest, currentFile + '/'));
|
||||||
} else {
|
} else {
|
||||||
// load file
|
// load file
|
||||||
oxOutf("copying file: {}\n", currentFile);
|
|
||||||
oxRequireM(buff, src.read(currentFile));
|
oxRequireM(buff, src.read(currentFile));
|
||||||
// write file to dest
|
// write file to dest
|
||||||
|
oxOutf("writing {}\n", currentFile);
|
||||||
oxReturnError(dest.write(currentFile, buff));
|
oxReturnError(dest.write(currentFile, buff));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
@ -197,10 +196,10 @@ void StudioUI::drawMenu() noexcept {
|
|||||||
if (ImGui::BeginMenu("Edit")) {
|
if (ImGui::BeginMenu("Edit")) {
|
||||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (ImGui::MenuItem("Undo", "Ctrl+Z", false, undoStack && undoStack->canUndo())) {
|
if (ImGui::MenuItem("Undo", "Ctrl+Z", false, undoStack && undoStack->canUndo())) {
|
||||||
oxLogError(undoStack->undo());
|
undoStack->undo();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Redo", "Ctrl+Y", false, undoStack && undoStack->canRedo())) {
|
if (ImGui::MenuItem("Redo", "Ctrl+Y", false, undoStack && undoStack->canRedo())) {
|
||||||
oxLogError(undoStack->redo());
|
undoStack->redo();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem("Copy", "Ctrl+C", false, m_activeEditor && m_activeEditor->copyEnabled())) {
|
if (ImGui::MenuItem("Copy", "Ctrl+C", false, m_activeEditor && m_activeEditor->copyEnabled())) {
|
||||||
@ -209,7 +208,7 @@ void StudioUI::drawMenu() noexcept {
|
|||||||
if (ImGui::MenuItem("Cut", "Ctrl+X", false, m_activeEditor && m_activeEditor->cutEnabled())) {
|
if (ImGui::MenuItem("Cut", "Ctrl+X", false, m_activeEditor && m_activeEditor->cutEnabled())) {
|
||||||
m_activeEditor->cut();
|
m_activeEditor->cut();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Paste", "Ctrl+V", false, m_activeEditor && m_activeEditor->pasteEnabled())) {
|
if (ImGui::MenuItem("Paste", "Ctrl+V", false, m_activeEditor && m_activeEditor->pasteEnabled()) && m_activeEditor) {
|
||||||
m_activeEditor->paste();
|
m_activeEditor->paste();
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
@ -315,14 +314,14 @@ void StudioUI::toggleProjectExplorer() noexcept {
|
|||||||
void StudioUI::redo() noexcept {
|
void StudioUI::redo() noexcept {
|
||||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (undoStack && undoStack->canRedo()) {
|
if (undoStack && undoStack->canRedo()) {
|
||||||
oxLogError(m_activeEditor->undoStack()->redo());
|
m_activeEditor->undoStack()->redo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::undo() noexcept {
|
void StudioUI::undo() noexcept {
|
||||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (undoStack && undoStack->canUndo()) {
|
if (undoStack && undoStack->canUndo()) {
|
||||||
oxLogError(m_activeEditor->undoStack()->undo());
|
m_activeEditor->undoStack()->undo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +22,4 @@ struct StudioContext {
|
|||||||
ui(pUi), tctx(pTctx) {}
|
ui(pUi), tctx(pTctx) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
inline keel::Context &keelCtx(StudioContext &ctx) noexcept {
|
|
||||||
return keelCtx(ctx.tctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,6 @@ class BaseEditor: public Widget {
|
|||||||
|
|
||||||
virtual void paste();
|
virtual void paste();
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual bool acceptsClipboardPayload() const noexcept;
|
|
||||||
|
|
||||||
virtual void exportFile();
|
virtual void exportFile();
|
||||||
|
|
||||||
virtual void keyStateChanged(turbine::Key key, bool down);
|
virtual void keyStateChanged(turbine::Key key, bool down);
|
||||||
@ -134,14 +131,14 @@ class Editor: public studio::BaseEditor {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
UndoStack *undoStack() noexcept final;
|
UndoStack *undoStack() noexcept final;
|
||||||
|
|
||||||
ox::Error pushCommand(ox::UPtr<UndoCommand> &&cmd) noexcept;
|
void pushCommand(ox::UPtr<UndoCommand> &&cmd) noexcept;
|
||||||
|
|
||||||
template<typename UC, typename ...Args>
|
template<typename UC, typename ...Args>
|
||||||
ox::Error pushCommand(Args&&... args) noexcept {
|
void pushCommand(Args&&... args) noexcept {
|
||||||
try {
|
try {
|
||||||
return m_undoStack.push(ox::make_unique<UC>(ox::forward<Args>(args)...));
|
m_undoStack.push(ox::make_unique<UC>(ox::forward<Args>(args)...));
|
||||||
} catch (ox::Exception const&ex) {
|
} catch (ox::Exception const&ex) {
|
||||||
return ex.toError();
|
oxLogError(ex.toError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ ox::Result<T> getDragDropPayload(ox::CStringView name) noexcept {
|
|||||||
static_cast<size_t>(payload->DataSize)});
|
static_cast<size_t>(payload->DataSize)});
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error setDragDropPayload(ox::CStringView name, auto const&obj) noexcept {
|
ox::Error setDragDropPayload(ox::CStringView name, auto const &obj) noexcept {
|
||||||
oxRequire(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
oxRequire(buff, ox::writeClaw(obj, ox::ClawFormat::Metal));
|
||||||
ImGui::SetDragDropPayload(name.c_str(), buff.data(), buff.size());
|
ImGui::SetDragDropPayload(name.c_str(), buff.data(), buff.size());
|
||||||
return {};
|
return {};
|
||||||
@ -148,19 +148,6 @@ bool BeginPopup(turbine::Context &ctx, ox::CStringView popupName, bool &show, Im
|
|||||||
*/
|
*/
|
||||||
bool ComboBox(ox::CStringView lbl, ox::SpanView<ox::String> list, size_t &selectedIdx) noexcept;
|
bool ComboBox(ox::CStringView lbl, ox::SpanView<ox::String> list, size_t &selectedIdx) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param lbl
|
|
||||||
* @param callback
|
|
||||||
* @param selectedIdx
|
|
||||||
* @return true if new value selected, false otherwise
|
|
||||||
*/
|
|
||||||
bool ComboBox(
|
|
||||||
ox::CStringView lbl,
|
|
||||||
std::function<ox::CStringView(size_t)> const&f,
|
|
||||||
size_t strCnt,
|
|
||||||
size_t &selectedIdx) noexcept;
|
|
||||||
|
|
||||||
bool FileComboBox(
|
bool FileComboBox(
|
||||||
ox::CStringView lbl,
|
ox::CStringView lbl,
|
||||||
studio::StudioContext &sctx,
|
studio::StudioContext &sctx,
|
||||||
|
@ -31,7 +31,7 @@ enum class ProjectEvent {
|
|||||||
constexpr ox::Result<ox::StringView> fileExt(ox::CRStringView path) noexcept {
|
constexpr ox::Result<ox::StringView> fileExt(ox::CRStringView path) noexcept {
|
||||||
auto const extStart = ox::find(path.crbegin(), path.crend(), '.').offset();
|
auto const extStart = ox::find(path.crbegin(), path.crend(), '.').offset();
|
||||||
if (!extStart) {
|
if (!extStart) {
|
||||||
return OxError(1, "file path does not have valid extension");
|
return OxError(1, "Cannot open a file without valid extension.");
|
||||||
}
|
}
|
||||||
return substr(path, extStart + 1);
|
return substr(path, extStart + 1);
|
||||||
}
|
}
|
||||||
@ -47,7 +47,6 @@ constexpr ox::StringView parentDir(ox::StringView path) noexcept {
|
|||||||
|
|
||||||
class Project {
|
class Project {
|
||||||
private:
|
private:
|
||||||
ox::SmallMap<ox::String, ox::Optional<ox::ClawFormat>> m_typeFmt;
|
|
||||||
keel::Context &m_ctx;
|
keel::Context &m_ctx;
|
||||||
ox::String m_path;
|
ox::String m_path;
|
||||||
ox::String m_projectDataDir;
|
ox::String m_projectDataDir;
|
||||||
@ -76,15 +75,7 @@ class Project {
|
|||||||
ox::Error writeObj(
|
ox::Error writeObj(
|
||||||
ox::CRStringView path,
|
ox::CRStringView path,
|
||||||
T const&obj,
|
T const&obj,
|
||||||
ox::ClawFormat fmt) noexcept;
|
ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a MetalClaw object to the project at the given path.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
ox::Error writeObj(
|
|
||||||
ox::CRStringView path,
|
|
||||||
T const&obj) noexcept;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> loadObj(ox::CRStringView path) const noexcept;
|
ox::Result<T> loadObj(ox::CRStringView path) const noexcept;
|
||||||
@ -124,7 +115,7 @@ class Project {
|
|||||||
// file.
|
// file.
|
||||||
ox::Signal<ox::Error(ox::CRStringView)> fileRecognized;
|
ox::Signal<ox::Error(ox::CRStringView)> fileRecognized;
|
||||||
ox::Signal<ox::Error(ox::CRStringView)> fileDeleted;
|
ox::Signal<ox::Error(ox::CRStringView)> fileDeleted;
|
||||||
ox::Signal<ox::Error(ox::StringView, ox::UUID)> fileUpdated;
|
ox::Signal<ox::Error(ox::CRStringView)> fileUpdated;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,24 +130,15 @@ ox::Error Project::writeObj(ox::CRStringView path, T const&obj, ox::ClawFormat f
|
|||||||
oxReturnError(ox::buildTypeDef(&m_typeStore, &obj));
|
oxReturnError(ox::buildTypeDef(&m_typeStore, &obj));
|
||||||
}
|
}
|
||||||
oxRequire(desc, m_typeStore.get<T>());
|
oxRequire(desc, m_typeStore.get<T>());
|
||||||
auto const descPath = ox::sfmt("{}/{}", m_typeDescPath, buildTypeId(*desc));
|
auto const descExists = m_fs.stat(ox::sfmt("{}/{}", m_typeDescPath, buildTypeId(*desc))).error != 0;
|
||||||
auto const descExists = m_fs.exists(descPath);
|
|
||||||
if (!descExists) {
|
if (!descExists) {
|
||||||
oxReturnError(writeTypeStore());
|
oxReturnError(writeTypeStore());
|
||||||
}
|
}
|
||||||
oxReturnError(keel::reloadAsset(m_ctx, path));
|
oxReturnError(keel::setAsset(m_ctx, path, obj));
|
||||||
oxRequire(uuid, pathToUuid(m_ctx, path));
|
fileUpdated.emit(path);
|
||||||
fileUpdated.emit(path, uuid);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ox::Error Project::writeObj(ox::CRStringView path, T const&obj) noexcept {
|
|
||||||
oxRequire(ext, fileExt(path));
|
|
||||||
auto const fmt = m_typeFmt[ext].or_value(ox::ClawFormat::Metal);
|
|
||||||
return writeObj(path, obj, fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> Project::loadObj(ox::CRStringView path) const noexcept {
|
ox::Result<T> Project::loadObj(ox::CRStringView path) const noexcept {
|
||||||
oxRequire(buff, loadBuff(path));
|
oxRequire(buff, loadBuff(path));
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
#include <ox/std/math.hpp>
|
|
||||||
#include <ox/std/point.hpp>
|
|
||||||
#include <ox/std/size.hpp>
|
|
||||||
#include <ox/std/typetraits.hpp>
|
|
||||||
|
|
||||||
namespace studio {
|
|
||||||
|
|
||||||
struct Selection {
|
|
||||||
ox::Point a, b;
|
|
||||||
constexpr Selection() noexcept = default;
|
|
||||||
constexpr Selection(ox::Point const&pA, ox::Point const&pB) noexcept: a(pA), b(pB) {}
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr ox::Size size() const noexcept {
|
|
||||||
return {b.x - a.x, b.y - a.y};
|
|
||||||
}
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool contains(ox::Point const&pt) const noexcept {
|
|
||||||
return a.x <= pt.x && a.y <= pt.y
|
|
||||||
&& b.x >= pt.x && b.y >= pt.y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
|
|
||||||
constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
|
|
||||||
for (auto x = sel.a.x; x <= sel.b.x; ++x) {
|
|
||||||
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
|
|
||||||
if constexpr(retErr) {
|
|
||||||
oxReturnError(cb(x, y));
|
|
||||||
} else {
|
|
||||||
cb(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if constexpr(retErr) {
|
|
||||||
return ox::Error{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto iterateSelectionRows(studio::Selection const&sel, auto const&cb) {
|
|
||||||
constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
|
|
||||||
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
|
|
||||||
for (auto x = sel.a.x; x <= sel.b.x; ++x) {
|
|
||||||
if constexpr(retErr) {
|
|
||||||
oxReturnError(cb(x, y));
|
|
||||||
} else {
|
|
||||||
cb(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if constexpr(retErr) {
|
|
||||||
return ox::Error{};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SelectionTracker {
|
|
||||||
private:
|
|
||||||
bool m_selectionOngoing{};
|
|
||||||
ox::Point m_pointA;
|
|
||||||
ox::Point m_pointB;
|
|
||||||
public:
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool selectionOngoing() const noexcept {
|
|
||||||
return m_selectionOngoing;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void startSelection(ox::Point cursor) noexcept {
|
|
||||||
m_pointA = cursor;
|
|
||||||
m_pointB = cursor;
|
|
||||||
m_selectionOngoing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param cursor
|
|
||||||
* @param allowStart
|
|
||||||
* @return true if changed, false otherwise
|
|
||||||
*/
|
|
||||||
constexpr bool updateCursorPoint(ox::Point cursor, bool allowStart = true) noexcept {
|
|
||||||
auto changed = false;
|
|
||||||
if (!m_selectionOngoing && allowStart) {
|
|
||||||
m_pointA = cursor;
|
|
||||||
m_selectionOngoing = true;
|
|
||||||
}
|
|
||||||
if (m_selectionOngoing) {
|
|
||||||
m_pointB = cursor;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void updateCursorPoint(ox::Vec2 cursor, bool allowStart = true) noexcept {
|
|
||||||
updateCursorPoint(
|
|
||||||
ox::Point{
|
|
||||||
static_cast<int32_t>(cursor.x),
|
|
||||||
static_cast<int32_t>(cursor.y),
|
|
||||||
},
|
|
||||||
allowStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void updateCursorPoint(ImVec2 cursor, bool allowStart = true) noexcept {
|
|
||||||
updateCursorPoint(
|
|
||||||
ox::Point{
|
|
||||||
static_cast<int32_t>(cursor.x),
|
|
||||||
static_cast<int32_t>(cursor.y),
|
|
||||||
},
|
|
||||||
allowStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void finishSelection() noexcept {
|
|
||||||
m_selectionOngoing = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr Selection selection() const noexcept {
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
ox::min(m_pointA.x, m_pointB.x),
|
|
||||||
ox::min(m_pointA.y, m_pointB.y),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ox::max(m_pointA.x, m_pointB.x),
|
|
||||||
ox::max(m_pointA.y, m_pointB.y),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -12,7 +12,6 @@
|
|||||||
#include <studio/itemmaker.hpp>
|
#include <studio/itemmaker.hpp>
|
||||||
#include <studio/popup.hpp>
|
#include <studio/popup.hpp>
|
||||||
#include <studio/project.hpp>
|
#include <studio/project.hpp>
|
||||||
#include <studio/selectiontracker.hpp>
|
|
||||||
#include <studio/task.hpp>
|
#include <studio/task.hpp>
|
||||||
#include <studio/undocommand.hpp>
|
#include <studio/undocommand.hpp>
|
||||||
#include <studio/undostack.hpp>
|
#include <studio/undostack.hpp>
|
||||||
|
@ -4,26 +4,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <source_location>
|
|
||||||
|
|
||||||
#include <ox/std/error.hpp>
|
|
||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
class NoChangesException: public ox::Exception {
|
|
||||||
public:
|
|
||||||
inline NoChangesException(std::source_location sloc = std::source_location::current()):
|
|
||||||
ox::Exception(sloc.file_name(), sloc.line(), 1, "Command makes no changes.") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class UndoCommand {
|
class UndoCommand {
|
||||||
public:
|
public:
|
||||||
virtual ~UndoCommand() noexcept = default;
|
virtual ~UndoCommand() noexcept = default;
|
||||||
virtual ox::Error redo() noexcept = 0;
|
virtual void redo() noexcept = 0;
|
||||||
virtual ox::Error undo() noexcept = 0;
|
virtual void undo() noexcept = 0;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual int commandId() const noexcept = 0;
|
virtual int commandId() const noexcept = 0;
|
||||||
virtual bool mergeWith(UndoCommand const&cmd) noexcept;
|
virtual bool mergeWith(UndoCommand const*cmd) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ class UndoStack {
|
|||||||
std::size_t m_stackIdx = 0;
|
std::size_t m_stackIdx = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ox::Error push(ox::UPtr<UndoCommand> &&cmd) noexcept;
|
void push(ox::UPtr<UndoCommand> &&cmd) noexcept;
|
||||||
|
|
||||||
ox::Error redo() noexcept;
|
void redo() noexcept;
|
||||||
|
|
||||||
ox::Error undo() noexcept;
|
void undo() noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr bool canRedo() const noexcept {
|
constexpr bool canRedo() const noexcept {
|
||||||
|
@ -23,10 +23,6 @@ void BaseEditor::copy() {
|
|||||||
void BaseEditor::paste() {
|
void BaseEditor::paste() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseEditor::acceptsClipboardPayload() const noexcept {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseEditor::exportFile() {
|
void BaseEditor::exportFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +95,7 @@ void BaseEditor::setPasteEnabled(bool v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BaseEditor::pasteEnabled() const noexcept {
|
bool BaseEditor::pasteEnabled() const noexcept {
|
||||||
return m_pasteEnabled && acceptsClipboardPayload();
|
return m_pasteEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error BaseEditor::saveItem() noexcept {
|
ox::Error BaseEditor::saveItem() noexcept {
|
||||||
@ -131,8 +127,8 @@ ox::CStringView Editor::itemDisplayName() const noexcept {
|
|||||||
return m_itemName;
|
return m_itemName;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Editor::pushCommand(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
void Editor::pushCommand(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
||||||
return m_undoStack.push(std::move(cmd));
|
m_undoStack.push(std::move(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
UndoStack *Editor::undoStack() noexcept {
|
UndoStack *Editor::undoStack() noexcept {
|
||||||
|
@ -100,26 +100,6 @@ bool ComboBox(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ComboBox(
|
|
||||||
ox::CStringView lbl,
|
|
||||||
std::function<ox::CStringView(size_t)> const&f,
|
|
||||||
size_t strCnt,
|
|
||||||
size_t &selectedIdx) noexcept {
|
|
||||||
bool out{};
|
|
||||||
auto const first = selectedIdx < strCnt ? f(selectedIdx).c_str() : "";
|
|
||||||
if (ImGui::BeginCombo(lbl.c_str(), first, 0)) {
|
|
||||||
for (auto i = 0u; i < strCnt; ++i) {
|
|
||||||
const auto selected = (selectedIdx == i);
|
|
||||||
if (ImGui::Selectable(f(i).c_str(), selected) && selectedIdx != i) {
|
|
||||||
selectedIdx = i;
|
|
||||||
out = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileComboBox(
|
bool FileComboBox(
|
||||||
ox::CStringView lbl,
|
ox::CStringView lbl,
|
||||||
studio::StudioContext &sctx,
|
studio::StudioContext &sctx,
|
||||||
|
@ -56,13 +56,9 @@ ox::FileSystem &Project::romFs() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Project::mkdir(ox::CRStringView path) const noexcept {
|
ox::Error Project::mkdir(ox::CRStringView path) const noexcept {
|
||||||
auto const [stat, err] = m_fs.stat(path);
|
oxReturnError(m_fs.mkdir(path, true));
|
||||||
if (err) {
|
fileUpdated.emit(path);
|
||||||
oxReturnError(m_fs.mkdir(path, true));
|
return {};
|
||||||
fileUpdated.emit(path, {});
|
|
||||||
}
|
|
||||||
return stat.fileType == ox::FileType::Directory ?
|
|
||||||
ox::Error{} : OxError(1, "path exists as normal file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::FileStat> Project::stat(ox::CRStringView path) const noexcept {
|
ox::Result<ox::FileStat> Project::stat(ox::CRStringView path) const noexcept {
|
||||||
@ -119,9 +115,9 @@ ox::Error Project::writeBuff(ox::CRStringView path, ox::Buffer const&buff) noexc
|
|||||||
ox::Buffer outBuff;
|
ox::Buffer outBuff;
|
||||||
outBuff.reserve(buff.size() + HdrSz);
|
outBuff.reserve(buff.size() + HdrSz);
|
||||||
ox::BufferWriter writer(&outBuff);
|
ox::BufferWriter writer(&outBuff);
|
||||||
auto const [uuid, err] = pathToUuid(m_ctx, path);
|
auto const [uuid, err] = m_ctx.pathToUuid.at(path);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
oxReturnError(keel::writeUuidHeader(writer, uuid));
|
oxReturnError(keel::writeUuidHeader(writer, *uuid));
|
||||||
}
|
}
|
||||||
oxReturnError(writer.write(buff.data(), buff.size()));
|
oxReturnError(writer.write(buff.data(), buff.size()));
|
||||||
auto const newFile = m_fs.stat(path).error != 0;
|
auto const newFile = m_fs.stat(path).error != 0;
|
||||||
@ -130,7 +126,7 @@ ox::Error Project::writeBuff(ox::CRStringView path, ox::Buffer const&buff) noexc
|
|||||||
fileAdded.emit(path);
|
fileAdded.emit(path);
|
||||||
indexFile(path);
|
indexFile(path);
|
||||||
} else {
|
} else {
|
||||||
fileUpdated.emit(path, uuid);
|
fileUpdated.emit(path);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
bool UndoCommand::mergeWith(UndoCommand const&) noexcept {
|
bool UndoCommand::mergeWith(UndoCommand const*) noexcept {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,39 +6,35 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
ox::Error UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
void UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
||||||
for (auto const i = m_stackIdx; i < m_stack.size();) {
|
for (auto const i = m_stackIdx; i < m_stack.size();) {
|
||||||
std::ignore = m_stack.erase(i);
|
std::ignore = m_stack.erase(i);
|
||||||
}
|
}
|
||||||
oxReturnError(cmd->redo());
|
cmd->redo();
|
||||||
redoTriggered.emit(cmd.get());
|
redoTriggered.emit(cmd.get());
|
||||||
changeTriggered.emit(cmd.get());
|
changeTriggered.emit(cmd.get());
|
||||||
if (m_stack.empty() || !(*m_stack.back().value)->mergeWith(*cmd)) {
|
if (m_stack.empty() || !(*m_stack.back().value)->mergeWith(cmd.get())) {
|
||||||
m_stack.emplace_back(std::move(cmd));
|
m_stack.emplace_back(std::move(cmd));
|
||||||
++m_stackIdx;
|
++m_stackIdx;
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UndoStack::redo() noexcept {
|
void UndoStack::redo() noexcept {
|
||||||
if (m_stackIdx < m_stack.size()) {
|
if (m_stackIdx < m_stack.size()) {
|
||||||
auto &c = m_stack[m_stackIdx];
|
auto &c = m_stack[m_stackIdx++];
|
||||||
oxReturnError(c->redo());
|
c->redo();
|
||||||
++m_stackIdx;
|
|
||||||
redoTriggered.emit(c.get());
|
redoTriggered.emit(c.get());
|
||||||
changeTriggered.emit(c.get());
|
changeTriggered.emit(c.get());
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UndoStack::undo() noexcept {
|
void UndoStack::undo() noexcept {
|
||||||
if (m_stackIdx) {
|
if (m_stackIdx) {
|
||||||
auto &c = m_stack[--m_stackIdx];
|
auto &c = m_stack[--m_stackIdx];
|
||||||
oxReturnError(c->undo());
|
c->undo();
|
||||||
undoTriggered.emit(c.get());
|
undoTriggered.emit(c.get());
|
||||||
changeTriggered.emit(c.get());
|
changeTriggered.emit(c.get());
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,19 @@ class BaseClipboardObject {
|
|||||||
virtual ~BaseClipboardObject() noexcept = default;
|
virtual ~BaseClipboardObject() noexcept = default;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual ox::StringView typeId() const noexcept = 0;
|
virtual ox::String typeId() const noexcept = 0;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto typeMatch(ox::StringView name, int version) const noexcept {
|
||||||
|
return typeId() == ox::buildTypeId(name, version);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class ClipboardObject: public BaseClipboardObject {
|
class ClipboardObject: public BaseClipboardObject {
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::StringView typeId() const noexcept final {
|
ox::String typeId() const noexcept final {
|
||||||
return ox::ModelTypeId_v<T>;
|
return ox::buildTypeId(T::TypeName, T::TypeVersion);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,11 +39,11 @@ void setClipboardText(Context &ctx, ox::CRStringView text) noexcept;
|
|||||||
|
|
||||||
void setClipboardObject(Context &ctx, ox::UPtr<BaseClipboardObject> &&obj) noexcept;
|
void setClipboardObject(Context &ctx, ox::UPtr<BaseClipboardObject> &&obj) noexcept;
|
||||||
|
|
||||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeId) noexcept;
|
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeName, int typeVersion) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T*> getClipboardObject(Context &ctx) noexcept {
|
ox::Result<T*> getClipboardObject(Context &ctx) noexcept {
|
||||||
oxRequire(p, getClipboardData(ctx, ox::ModelTypeId_v<T>));
|
oxRequire(p, getClipboardData(ctx, T::TypeName, T::TypeVersion));
|
||||||
return dynamic_cast<T*>(p);
|
return dynamic_cast<T*>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ void setClipboardObject(Context &ctx, ox::UPtr<BaseClipboardObject> &&obj) noexc
|
|||||||
ctx.clipboard = std::move(obj);
|
ctx.clipboard = std::move(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeId) noexcept {
|
ox::Result<BaseClipboardObject*> getClipboardData(Context &ctx, ox::StringView typeName, int typeVersion) noexcept {
|
||||||
if (ctx.clipboard && ctx.clipboard->typeId() == typeId) {
|
if (ctx.clipboard && ctx.clipboard->typeMatch(typeName, typeVersion)) {
|
||||||
return ctx.clipboard.get();
|
return ctx.clipboard.get();
|
||||||
}
|
}
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
|
Reference in New Issue
Block a user