Compare commits
13 Commits
77c86b9516
...
2bad4ee416
Author | SHA1 | Date | |
---|---|---|---|
2bad4ee416 | |||
46d1313797 | |||
fcf6f00797 | |||
ef6e3af735 | |||
80d0df2f46 | |||
9db10ec4a1 | |||
c460e0f9e0 | |||
3fa9d132ae | |||
907ead2948 | |||
8526b3fa51 | |||
6de0e882e9 | |||
d29118d783 | |||
8395128efa |
@ -13,10 +13,12 @@ include(deps/buildcore/base.cmake)
|
|||||||
|
|
||||||
set(NOSTALGIA_BUILD_PLAYER ON CACHE BOOL "Build Player")
|
set(NOSTALGIA_BUILD_PLAYER ON CACHE BOOL "Build Player")
|
||||||
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
||||||
|
set(OLYMPIC_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
||||||
set(OX_ENABLE_TRACEHOOK OFF CACHE BOOL "Generate OxTraceHook shared library for uprobes")
|
set(OX_ENABLE_TRACEHOOK OFF CACHE BOOL "Generate OxTraceHook shared library for uprobes")
|
||||||
|
|
||||||
if(BUILDCORE_TARGET STREQUAL "gba")
|
if(BUILDCORE_TARGET STREQUAL "gba")
|
||||||
set(NOSTALGIA_BUILD_STUDIO OFF)
|
set(NOSTALGIA_BUILD_STUDIO OFF)
|
||||||
|
set(OLYMPIC_BUILD_STUDIO OFF)
|
||||||
set(TURBINE_BUILD_TYPE "GBA")
|
set(TURBINE_BUILD_TYPE "GBA")
|
||||||
include(deps/gbabuildcore/base.cmake)
|
include(deps/gbabuildcore/base.cmake)
|
||||||
else()
|
else()
|
||||||
|
@ -161,16 +161,16 @@ template<typename T>
|
|||||||
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
|
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
|
||||||
oxReturnError(h->template setTypeInfo<FileAddress>());
|
oxReturnError(h->template setTypeInfo<FileAddress>());
|
||||||
if constexpr(T::opType() == OpType::Reflect) {
|
if constexpr(T::opType() == OpType::Reflect) {
|
||||||
int8_t type = 0;
|
int8_t type = -1;
|
||||||
oxReturnError(h->field("type", &type));
|
oxReturnError(h->field("type", &type));
|
||||||
oxReturnError(h->field("data", UnionView(&fa->m_data, 0)));
|
oxReturnError(h->field("data", UnionView(&fa->m_data, type)));
|
||||||
} else if constexpr(T::opType() == OpType::Read) {
|
} else if constexpr(T::opType() == OpType::Read) {
|
||||||
auto type = static_cast<int8_t>(fa->m_type);
|
auto type = static_cast<int8_t>(fa->m_type);
|
||||||
oxReturnError(h->field("type", &type));
|
oxReturnError(h->field("type", &type));
|
||||||
fa->m_type = static_cast<FileAddressType>(type);
|
fa->m_type = static_cast<FileAddressType>(type);
|
||||||
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||||
} else if constexpr(T::opType() == OpType::Write) {
|
} else if constexpr(T::opType() == OpType::Write) {
|
||||||
auto type = static_cast<int8_t>(fa->m_type);
|
auto const type = static_cast<int8_t>(fa->m_type);
|
||||||
oxReturnError(h->field("type", &type));
|
oxReturnError(h->field("type", &type));
|
||||||
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||||
}
|
}
|
||||||
|
7
deps/ox/src/ox/mc/intops.hpp
vendored
7
deps/ox/src/ox/mc/intops.hpp
vendored
@ -64,13 +64,14 @@ struct McInt {
|
|||||||
|
|
||||||
template<typename I>
|
template<typename I>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr McInt encodeInteger(I input) noexcept {
|
constexpr McInt encodeInteger(I pInput) noexcept {
|
||||||
|
auto const input = ox::ResizedInt_t<I, 64>{pInput};
|
||||||
McInt out;
|
McInt out;
|
||||||
const auto inputNegative = is_signed_v<I> && input < 0;
|
const auto inputNegative = is_signed_v<I> && input < 0;
|
||||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||||
// overflow concerns
|
// overflow concerns
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
ox_memcpy(&val, &input, sizeof(I));
|
ox_memcpy(&val, &input, sizeof(input));
|
||||||
if (val) {
|
if (val) {
|
||||||
// bits needed to represent number factoring in space possibly
|
// bits needed to represent number factoring in space possibly
|
||||||
// needed for signed bit
|
// needed for signed bit
|
||||||
@ -93,7 +94,7 @@ constexpr McInt encodeInteger(I input) noexcept {
|
|||||||
}
|
}
|
||||||
if (bytes == 9) {
|
if (bytes == 9) {
|
||||||
out.data[0] = bytesIndicator;
|
out.data[0] = bytesIndicator;
|
||||||
ox_memcpy(&out.data[1], &leVal, sizeof(I));
|
ox_memcpy(&out.data[1], &leVal, 8);
|
||||||
if (inputNegative) {
|
if (inputNegative) {
|
||||||
out.data[1] |= 0b1000'0000;
|
out.data[1] |= 0b1000'0000;
|
||||||
}
|
}
|
||||||
|
55
deps/ox/src/ox/mc/read.hpp
vendored
55
deps/ox/src/ox/mc/read.hpp
vendored
@ -15,6 +15,7 @@
|
|||||||
#include <ox/model/types.hpp>
|
#include <ox/model/types.hpp>
|
||||||
#include <ox/std/buffer.hpp>
|
#include <ox/std/buffer.hpp>
|
||||||
#include <ox/std/byteswap.hpp>
|
#include <ox/std/byteswap.hpp>
|
||||||
|
#include <ox/std/optional.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
#include <ox/std/trace.hpp>
|
#include <ox/std/trace.hpp>
|
||||||
#include <ox/std/vector.hpp>
|
#include <ox/std/vector.hpp>
|
||||||
@ -33,15 +34,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
|||||||
FieldBitmapReader<Reader> m_fieldPresence;
|
FieldBitmapReader<Reader> m_fieldPresence;
|
||||||
std::size_t m_fields = 0;
|
std::size_t m_fields = 0;
|
||||||
std::size_t m_field = 0;
|
std::size_t m_field = 0;
|
||||||
int m_unionIdx = -1;
|
ox::Optional<int> m_unionIdx;
|
||||||
Reader &m_reader;
|
Reader &m_reader;
|
||||||
MetalClawReaderTemplate<Reader> *m_parent = nullptr;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit constexpr MetalClawReaderTemplate(
|
explicit constexpr MetalClawReaderTemplate(
|
||||||
Reader &reader,
|
Reader &reader,
|
||||||
int unionIdx = -1,
|
ox::Optional<int> const&unionIdx = {}) noexcept;
|
||||||
MetalClawReaderTemplate<Reader> *parent = nullptr) noexcept;
|
|
||||||
|
|
||||||
constexpr ~MetalClawReaderTemplate() noexcept;
|
constexpr ~MetalClawReaderTemplate() noexcept;
|
||||||
|
|
||||||
@ -108,7 +107,7 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
|||||||
* Returns a MetalClawReader to parse a child object.
|
* Returns a MetalClawReader to parse a child object.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr MetalClawReaderTemplate<Reader> child(const char *name, int unionIdx = -1) noexcept;
|
constexpr MetalClawReaderTemplate<Reader> child(const char *name, ox::Optional<int> unionIdx = {}) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the next field to be read is present.
|
* Indicates whether or not the next field to be read is present.
|
||||||
@ -136,12 +135,10 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
|||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
|
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
|
||||||
Reader &reader,
|
Reader &reader,
|
||||||
int unionIdx,
|
ox::Optional<int> const&unionIdx) noexcept:
|
||||||
MetalClawReaderTemplate *parent) noexcept:
|
|
||||||
m_fieldPresence(reader),
|
m_fieldPresence(reader),
|
||||||
m_unionIdx(unionIdx),
|
m_unionIdx(unionIdx),
|
||||||
m_reader(reader),
|
m_reader(reader) {
|
||||||
m_parent(parent) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
@ -194,7 +191,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *va
|
|||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
|
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
|
||||||
*val = result.value;
|
*val = result.value;
|
||||||
oxReturnError(result);
|
oxReturnError(result);
|
||||||
@ -206,7 +203,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
|
|||||||
// array handler
|
// array handler
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -232,7 +229,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *v
|
|||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
oxRequire(g, m_reader.tellg());
|
oxRequire(g, m_reader.tellg());
|
||||||
@ -264,19 +261,19 @@ template<Reader_c Reader>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
|
||||||
if constexpr(isVector_v<T>) {
|
if constexpr(isVector_v<T>) {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
// set size of val if the field is present, don't worry about it if not
|
// set size of val if the field is present, don't worry about it if not
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
oxRequire(len, arrayLength(name, false));
|
oxRequire(len, arrayLength(name, false));
|
||||||
val->resize(len);
|
oxReturnError(ox::resizeVector(*val, len));
|
||||||
return field(name, val->data(), val->size());
|
return field(name, val->data(), val->size());
|
||||||
}
|
}
|
||||||
val->resize(0);
|
oxReturnError(ox::resizeVector(*val, 0));
|
||||||
}
|
}
|
||||||
++m_field;
|
++m_field;
|
||||||
return {};
|
return {};
|
||||||
} else if constexpr(isArray_v<T>) {
|
} else if constexpr(isArray_v<T>) {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
// set size of val if the field is present, don't worry about it if not
|
// set size of val if the field is present, don't worry about it if not
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
oxRequire(len, arrayLength(name, false));
|
oxRequire(len, arrayLength(name, false));
|
||||||
@ -289,7 +286,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
|||||||
++m_field;
|
++m_field;
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val) {
|
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
auto reader = child("");
|
auto reader = child("");
|
||||||
oxReturnError(model(reader.interface(), val));
|
oxReturnError(model(reader.interface(), val));
|
||||||
@ -303,20 +300,20 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
|||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<typename U, bool force>
|
template<typename U, bool force>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
|
||||||
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val.get()) {
|
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
auto reader = child("", val.idx());
|
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
|
||||||
oxReturnError(model(reader.interface(), val.get()));
|
oxReturnError(model(reader.interface(), val.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++m_field;
|
++m_field;
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<std::size_t SmallStringSize>
|
template<std::size_t SmallStringSize>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -382,7 +379,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
|||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -410,7 +407,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
|||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
|
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -427,7 +424,7 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const
|
|||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
|
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -442,7 +439,7 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(con
|
|||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<typename I>
|
template<typename I>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
|
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
|
||||||
@ -459,7 +456,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
|
|||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<typename T, typename CB>
|
template<typename T, typename CB>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
|
||||||
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
// read the length
|
// read the length
|
||||||
std::size_t bytesRead = 0;
|
std::size_t bytesRead = 0;
|
||||||
@ -491,8 +488,10 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(const char*, int unionIdx) noexcept {
|
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
|
||||||
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx, this);
|
const char*,
|
||||||
|
ox::Optional<int> unionIdx) noexcept {
|
||||||
|
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
|
3
deps/ox/src/ox/mc/test/tests.cpp
vendored
3
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -267,6 +267,9 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
};
|
};
|
||||||
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
|
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
|
||||||
|
oxAssert(check(int8_t(-1)), "Decode of -1 failed.");
|
||||||
|
oxAssert(check(int16_t(-1)), "Decode of -1 failed.");
|
||||||
|
oxAssert(check(int32_t(-1)), "Decode of -1 failed.");
|
||||||
oxAssert(check(int64_t(-1)), "Decode of -1 failed.");
|
oxAssert(check(int64_t(-1)), "Decode of -1 failed.");
|
||||||
oxAssert(check(int64_t(-2)), "Decode of -2 failed.");
|
oxAssert(check(int64_t(-2)), "Decode of -2 failed.");
|
||||||
oxAssert(check(int64_t(-127)), "Decode of -127 failed.");
|
oxAssert(check(int64_t(-127)), "Decode of -127 failed.");
|
||||||
|
44
deps/ox/src/ox/mc/write.hpp
vendored
44
deps/ox/src/ox/mc/write.hpp
vendored
@ -16,6 +16,7 @@
|
|||||||
#include <ox/std/buffer.hpp>
|
#include <ox/std/buffer.hpp>
|
||||||
#include <ox/std/byteswap.hpp>
|
#include <ox/std/byteswap.hpp>
|
||||||
#include <ox/std/hashmap.hpp>
|
#include <ox/std/hashmap.hpp>
|
||||||
|
#include <ox/std/optional.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
#include <ox/std/types.hpp>
|
#include <ox/std/types.hpp>
|
||||||
#include <ox/std/units.hpp>
|
#include <ox/std/units.hpp>
|
||||||
@ -34,12 +35,12 @@ class MetalClawWriter {
|
|||||||
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
|
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
|
||||||
FieldBitmap m_fieldPresence;
|
FieldBitmap m_fieldPresence;
|
||||||
int m_field = 0;
|
int m_field = 0;
|
||||||
int m_unionIdx = -1;
|
ox::Optional<int> m_unionIdx;
|
||||||
std::size_t m_writerBeginP{};
|
std::size_t m_writerBeginP{};
|
||||||
Writer &m_writer;
|
Writer &m_writer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr explicit MetalClawWriter(Writer &writer, int unionIdx = -1) noexcept;
|
constexpr explicit MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx = {}) noexcept;
|
||||||
|
|
||||||
constexpr ~MetalClawWriter() noexcept = default;
|
constexpr ~MetalClawWriter() noexcept = default;
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ class MetalClawWriter {
|
|||||||
private:
|
private:
|
||||||
constexpr Error appendInteger(Integer_c auto val) noexcept {
|
constexpr Error appendInteger(Integer_c auto val) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
auto mi = mc::encodeInteger(val);
|
auto mi = mc::encodeInteger(val);
|
||||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
|
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
|
||||||
fieldSet = true;
|
fieldSet = true;
|
||||||
@ -130,7 +131,7 @@ extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
|
|||||||
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
|
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
|
||||||
|
|
||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, int unionIdx) noexcept:
|
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx) noexcept:
|
||||||
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
|
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
|
||||||
m_unionIdx(unionIdx),
|
m_unionIdx(unionIdx),
|
||||||
m_writerBeginP(writer.tellp()),
|
m_writerBeginP(writer.tellp()),
|
||||||
@ -179,7 +180,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val)
|
|||||||
|
|
||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
|
constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
|
||||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
|
||||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
|
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
|
||||||
}
|
}
|
||||||
++m_field;
|
++m_field;
|
||||||
@ -190,7 +191,7 @@ template<Writer_c Writer>
|
|||||||
template<std::size_t SmallStringSize>
|
template<std::size_t SmallStringSize>
|
||||||
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
|
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
// write the length
|
// write the length
|
||||||
const auto strLen = mc::encodeInteger(val->len());
|
const auto strLen = mc::encodeInteger(val->len());
|
||||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
|
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
|
||||||
@ -212,7 +213,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char *name, const BString<L
|
|||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
|
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
|
||||||
const auto strLen = *val ? ox_strlen(*val) : 0;
|
const auto strLen = *val ? ox_strlen(*val) : 0;
|
||||||
// write the length
|
// write the length
|
||||||
const auto strLenBuff = mc::encodeInteger(strLen);
|
const auto strLenBuff = mc::encodeInteger(strLen);
|
||||||
@ -239,7 +240,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const ch
|
|||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
|
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
// write the length
|
// write the length
|
||||||
const auto strLenBuff = mc::encodeInteger(strLen);
|
const auto strLenBuff = mc::encodeInteger(strLen);
|
||||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
|
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
|
||||||
@ -259,16 +260,17 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexce
|
|||||||
return field(nullptr, val->data(), val->size());
|
return field(nullptr, val->data(), val->size());
|
||||||
} else {
|
} else {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
|
auto const writeIdx = m_writer.tellp();
|
||||||
MetalClawWriter<Writer> writer(m_writer);
|
MetalClawWriter<Writer> writer(m_writer);
|
||||||
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
|
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
|
||||||
oxReturnError(model(&handler, val));
|
oxReturnError(model(&handler, val));
|
||||||
oxReturnError(writer.finalize());
|
oxReturnError(writer.finalize());
|
||||||
fieldSet = true;
|
fieldSet = writeIdx != m_writer.tellp();
|
||||||
}
|
}
|
||||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||||
++m_field;
|
++m_field;
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,35 +278,37 @@ template<Writer_c Writer>
|
|||||||
template<typename U, bool force>
|
template<typename U, bool force>
|
||||||
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
|
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
MetalClawWriter<Writer> writer(m_writer, val.idx());
|
auto const writeIdx = m_writer.tellp();
|
||||||
|
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
|
||||||
ModelHandlerInterface handler{&writer};
|
ModelHandlerInterface handler{&writer};
|
||||||
oxReturnError(model(&handler, val.get()));
|
oxReturnError(model(&handler, val.get()));
|
||||||
oxReturnError(writer.finalize());
|
oxReturnError(writer.finalize());
|
||||||
fieldSet = true;
|
fieldSet = writeIdx != m_writer.tellp();
|
||||||
}
|
}
|
||||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||||
++m_field;
|
++m_field;
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
|
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
// write the length
|
// write the length
|
||||||
const auto arrLen = mc::encodeInteger(len);
|
const auto arrLen = mc::encodeInteger(len);
|
||||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
|
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
|
||||||
|
auto const writeIdx = m_writer.tellp();
|
||||||
MetalClawWriter<Writer> writer(m_writer);
|
MetalClawWriter<Writer> writer(m_writer);
|
||||||
ModelHandlerInterface handler{&writer};
|
ModelHandlerInterface handler{&writer};
|
||||||
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
|
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
|
||||||
// write the array
|
// write the array
|
||||||
for (std::size_t i = 0; i < len; i++) {
|
for (std::size_t i = 0; i < len; ++i) {
|
||||||
oxReturnError(handler.field("", &val[i]));
|
oxReturnError(handler.field("", &val[i]));
|
||||||
}
|
}
|
||||||
oxReturnError(writer.finalize());
|
oxReturnError(writer.finalize());
|
||||||
fieldSet = true;
|
fieldSet = writeIdx != m_writer.tellp();
|
||||||
}
|
}
|
||||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||||
++m_field;
|
++m_field;
|
||||||
@ -317,7 +321,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
|
|||||||
const auto &keys = val->keys();
|
const auto &keys = val->keys();
|
||||||
const auto len = keys.size();
|
const auto len = keys.size();
|
||||||
bool fieldSet = false;
|
bool fieldSet = false;
|
||||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||||
// write the length
|
// write the length
|
||||||
const auto arrLen = mc::encodeInteger(len);
|
const auto arrLen = mc::encodeInteger(len);
|
||||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
|
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
|
||||||
@ -336,7 +340,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
|
|||||||
return handler.field("", value);
|
return handler.field("", value);
|
||||||
};
|
};
|
||||||
// write the array
|
// write the array
|
||||||
for (std::size_t i = 0; i < len; i++) {
|
for (std::size_t i = 0; i < len; ++i) {
|
||||||
auto const&key = keys[i];
|
auto const&key = keys[i];
|
||||||
oxReturnError(loopBody(handler, key, *val));
|
oxReturnError(loopBody(handler, key, *val));
|
||||||
}
|
}
|
||||||
|
12
deps/ox/src/ox/model/modelhandleradaptor.hpp
vendored
12
deps/ox/src/ox/model/modelhandleradaptor.hpp
vendored
@ -196,7 +196,6 @@ class ModelHandlerInterface {
|
|||||||
constexpr auto handler() noexcept {
|
constexpr auto handler() noexcept {
|
||||||
return m_handler;
|
return m_handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Handler, ox::OpType opType_v = Handler::opType()>
|
template<typename Handler, ox::OpType opType_v = Handler::opType()>
|
||||||
@ -215,7 +214,16 @@ class ModelHandlerBase {
|
|||||||
static constexpr ox::OpType opType() noexcept {
|
static constexpr ox::OpType opType() noexcept {
|
||||||
return opType_v;
|
return opType_v;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
constexpr ox::Error resizeVector(auto &vec, size_t sz) {
|
||||||
|
if constexpr(ox::is_same_v<decltype(vec.resize(0)), ox::Error>) {
|
||||||
|
return vec.resize(sz);
|
||||||
|
} else {
|
||||||
|
vec.resize(sz);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
16
deps/ox/src/ox/model/modelvalue.hpp
vendored
16
deps/ox/src/ox/model/modelvalue.hpp
vendored
@ -202,7 +202,8 @@ class ModelValue {
|
|||||||
class ModelValueVector {
|
class ModelValueVector {
|
||||||
private:
|
private:
|
||||||
Vector<ModelValue> m_vec;
|
Vector<ModelValue> m_vec;
|
||||||
ModelValue m_templateValue;
|
const DescriptorType *m_type = nullptr;
|
||||||
|
int m_typeSubscriptLevels = 0;
|
||||||
String m_typeName;
|
String m_typeName;
|
||||||
int m_typeVersion = 0;
|
int m_typeVersion = 0;
|
||||||
|
|
||||||
@ -227,14 +228,15 @@ class ModelValueVector {
|
|||||||
return m_vec.data();
|
return m_vec.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void resize(std::size_t sz) noexcept {
|
constexpr ox::Error resize(std::size_t sz) noexcept {
|
||||||
const auto oldSz = m_vec.size();
|
const auto oldSz = m_vec.size();
|
||||||
m_vec.resize(sz);
|
m_vec.resize(sz);
|
||||||
if (sz > oldSz) {
|
if (sz > oldSz) {
|
||||||
for (auto i = oldSz; i < sz; ++i) {
|
for (auto i = oldSz; i < sz; ++i) {
|
||||||
m_vec[i] = m_templateValue;
|
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -248,7 +250,9 @@ class ModelValueVector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
|
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
|
||||||
return m_templateValue.setType(type, subscriptLevels);
|
m_type = type;
|
||||||
|
m_typeSubscriptLevels = subscriptLevels;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -1089,14 +1093,12 @@ constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noex
|
|||||||
for (auto &v : other.m_vec) {
|
for (auto &v : other.m_vec) {
|
||||||
m_vec.emplace_back(v);
|
m_vec.emplace_back(v);
|
||||||
}
|
}
|
||||||
m_templateValue = other.m_templateValue;
|
|
||||||
m_typeName = other.m_typeName;
|
m_typeName = other.m_typeName;
|
||||||
m_typeVersion = other.m_typeVersion;
|
m_typeVersion = other.m_typeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
|
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
|
||||||
m_vec = std::move(other.m_vec);
|
m_vec = std::move(other.m_vec);
|
||||||
m_templateValue = std::move(other.m_templateValue);
|
|
||||||
m_typeName = std::move(other.m_typeName);
|
m_typeName = std::move(other.m_typeName);
|
||||||
m_typeVersion = other.m_typeVersion;
|
m_typeVersion = other.m_typeVersion;
|
||||||
}
|
}
|
||||||
@ -1108,7 +1110,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(const ModelValueVector &
|
|||||||
for (auto &v : other.m_vec) {
|
for (auto &v : other.m_vec) {
|
||||||
m_vec.emplace_back(v);
|
m_vec.emplace_back(v);
|
||||||
}
|
}
|
||||||
m_templateValue = other.m_templateValue;
|
|
||||||
m_typeName = other.m_typeName;
|
m_typeName = other.m_typeName;
|
||||||
m_typeVersion = other.m_typeVersion;
|
m_typeVersion = other.m_typeVersion;
|
||||||
return *this;
|
return *this;
|
||||||
@ -1119,7 +1120,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
m_vec = std::move(other.m_vec);
|
m_vec = std::move(other.m_vec);
|
||||||
m_templateValue = std::move(other.m_templateValue);
|
|
||||||
m_typeName = std::move(other.m_typeName);
|
m_typeName = std::move(other.m_typeName);
|
||||||
m_typeVersion = other.m_typeVersion;
|
m_typeVersion = other.m_typeVersion;
|
||||||
return *this;
|
return *this;
|
||||||
|
2
deps/ox/src/ox/oc/read.hpp
vendored
2
deps/ox/src/ox/oc/read.hpp
vendored
@ -147,7 +147,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
|
|||||||
if constexpr(isVector_v<T>) {
|
if constexpr(isVector_v<T>) {
|
||||||
const auto &srcVal = value(key);
|
const auto &srcVal = value(key);
|
||||||
const auto srcSize = srcVal.size();
|
const auto srcSize = srcVal.size();
|
||||||
val->resize(srcSize);
|
oxReturnError(ox::resizeVector(*val, srcSize));
|
||||||
err = field(key, val->data(), val->size());
|
err = field(key, val->data(), val->size());
|
||||||
} else if constexpr(isArray_v<T>) {
|
} else if constexpr(isArray_v<T>) {
|
||||||
const auto &srcVal = value(key);
|
const auto &srcVal = value(key);
|
||||||
|
12
deps/ox/src/ox/std/optional.hpp
vendored
12
deps/ox/src/ox/std/optional.hpp
vendored
@ -28,7 +28,7 @@ class Optional {
|
|||||||
constexpr Optional() noexcept = default;
|
constexpr Optional() noexcept = default;
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
explicit constexpr Optional(Args &&... args);
|
explicit constexpr Optional(ox::in_place_t, Args &&... args);
|
||||||
|
|
||||||
constexpr Optional(const Optional &other) {
|
constexpr Optional(const Optional &other) {
|
||||||
if (other.m_ptr) {
|
if (other.m_ptr) {
|
||||||
@ -65,19 +65,19 @@ class Optional {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr T &operator*() & noexcept {
|
constexpr T &operator*() & noexcept {
|
||||||
return m_ptr;
|
return *m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T &operator*() const & noexcept {
|
constexpr const T &operator*() const & noexcept {
|
||||||
return m_ptr;
|
return *m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T &&operator*() && noexcept {
|
constexpr T &&operator*() && noexcept {
|
||||||
return m_ptr;
|
return *m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T &&operator*() const && noexcept {
|
constexpr const T &&operator*() const && noexcept {
|
||||||
return m_ptr;
|
return *m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T *operator->() noexcept {
|
constexpr T *operator->() noexcept {
|
||||||
@ -163,7 +163,7 @@ class Optional {
|
|||||||
|
|
||||||
template<typename T, std::size_t buffSize>
|
template<typename T, std::size_t buffSize>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr Optional<T, buffSize>::Optional(Args &&... args) {
|
constexpr Optional<T, buffSize>::Optional(ox::in_place_t, Args &&... args) {
|
||||||
emplace(ox::forward<Args>(args)...);
|
emplace(ox::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
deps/ox/src/ox/std/utility.hpp
vendored
6
deps/ox/src/ox/std/utility.hpp
vendored
@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
|
struct in_place_t {
|
||||||
|
explicit constexpr in_place_t() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr ox::in_place_t in_place;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
constexpr T &&forward(remove_reference_t<T> &t) noexcept {
|
constexpr T &&forward(remove_reference_t<T> &t) noexcept {
|
||||||
return static_cast<T&&>(t);
|
return static_cast<T&&>(t);
|
||||||
|
6
deps/teagba/include/teagba/addresses.hpp
vendored
6
deps/teagba/include/teagba/addresses.hpp
vendored
@ -49,7 +49,7 @@ using BgCtl = uint16_t;
|
|||||||
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
|
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline auto ®BgCtl(uintptr_t bgIdx) noexcept {
|
inline volatile BgCtl ®BgCtl(uintptr_t bgIdx) noexcept {
|
||||||
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
|
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ inline auto ®BgCtl(uintptr_t bgIdx) noexcept {
|
|||||||
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
|
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline volatile auto ®BgHofs(auto bgIdx) noexcept {
|
inline volatile uint32_t ®BgHofs(auto bgIdx) noexcept {
|
||||||
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
|
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ inline volatile auto ®BgHofs(auto bgIdx) noexcept {
|
|||||||
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
|
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline volatile auto ®BgVofs(auto bgIdx) noexcept {
|
inline volatile uint32_t ®BgVofs(auto bgIdx) noexcept {
|
||||||
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
|
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
deps/teagba/include/teagba/gfx.hpp
vendored
3
deps/teagba/include/teagba/gfx.hpp
vendored
@ -33,9 +33,10 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
|
|||||||
uint16_t attr1 = 0;
|
uint16_t attr1 = 0;
|
||||||
uint16_t attr2 = 0;
|
uint16_t attr2 = 0;
|
||||||
uint16_t idx = 0;
|
uint16_t idx = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept;
|
||||||
|
|
||||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
|
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
|
||||||
|
|
||||||
void applySpriteUpdates() noexcept;
|
void applySpriteUpdates() noexcept;
|
||||||
|
35
deps/teagba/include/teagba/registers.hpp
vendored
35
deps/teagba/include/teagba/registers.hpp
vendored
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
namespace teagba {
|
namespace teagba {
|
||||||
|
|
||||||
inline auto bgSetSbb(volatile BgCtl *bgCtl, unsigned sbb) noexcept {
|
inline auto bgSetSbb(volatile BgCtl &bgCtl, unsigned sbb) noexcept {
|
||||||
*bgCtl = static_cast<BgCtl>(*bgCtl & ~0b11111'0000'0000u) | static_cast<BgCtl>(sbb << 8);
|
bgCtl = static_cast<BgCtl>(bgCtl & ~0b11111'0000'0000u) | static_cast<BgCtl>(sbb << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -17,14 +17,9 @@ constexpr unsigned bgPri(BgCtl bgCtl) noexcept {
|
|||||||
return bgCtl & 1;
|
return bgCtl & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
inline auto bgSetPri(volatile BgCtl &bgCtl, unsigned pri) noexcept {
|
||||||
inline auto bgPri(const volatile BgCtl *bgCtl) noexcept {
|
|
||||||
return bgPri(*bgCtl);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto bgSetPri(volatile BgCtl *bgCtl, unsigned pri) noexcept {
|
|
||||||
pri = pri & 0b1;
|
pri = pri & 0b1;
|
||||||
*bgCtl = static_cast<BgCtl>(*bgCtl & ~0b1u) | static_cast<BgCtl>(pri << 0);
|
bgCtl = static_cast<BgCtl>(bgCtl & ~0b1u) | static_cast<BgCtl>(pri << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -32,17 +27,12 @@ constexpr unsigned bgBpp(BgCtl bgCtl) noexcept {
|
|||||||
return ((bgCtl >> 7) & 1) ? 8 : 4;
|
return ((bgCtl >> 7) & 1) ? 8 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
inline auto bgSetBpp(volatile BgCtl &bgCtl, unsigned bpp) noexcept {
|
||||||
inline auto bgBpp(const volatile BgCtl *bgCtl) noexcept {
|
|
||||||
return bgBpp(*bgCtl);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto bgSetBpp(volatile BgCtl *bgCtl, unsigned bpp) noexcept {
|
|
||||||
constexpr auto Bpp8 = 1 << 7;
|
constexpr auto Bpp8 = 1 << 7;
|
||||||
if (bpp == 4) {
|
if (bpp == 4) {
|
||||||
*bgCtl = *bgCtl | ((*bgCtl | Bpp8) ^ Bpp8); // set to use 4 bits per pixel
|
bgCtl = bgCtl | ((bgCtl | Bpp8) ^ Bpp8); // set to use 4 bits per pixel
|
||||||
} else {
|
} else {
|
||||||
*bgCtl = *bgCtl | Bpp8; // set to use 8 bits per pixel
|
bgCtl = bgCtl | Bpp8; // set to use 8 bits per pixel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,19 +41,14 @@ constexpr auto bgCbb(BgCtl bgCtl) noexcept {
|
|||||||
return (bgCtl >> 2) & 0b11u;
|
return (bgCtl >> 2) & 0b11u;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
inline auto bgSetCbb(volatile BgCtl &bgCtl, unsigned cbb) noexcept {
|
||||||
inline auto bgCbb(const volatile BgCtl *bgCtl) noexcept {
|
|
||||||
return bgCbb(*bgCtl);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto bgSetCbb(volatile BgCtl *bgCtl, unsigned cbb) noexcept {
|
|
||||||
cbb = cbb & 0b11;
|
cbb = cbb & 0b11;
|
||||||
*bgCtl = static_cast<BgCtl>(*bgCtl & ~0b1100u) | static_cast<BgCtl>(cbb << 2);
|
bgCtl = static_cast<BgCtl>(bgCtl & ~0b1100u) | static_cast<BgCtl>(cbb << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void iterateBgCtl(auto cb) noexcept {
|
constexpr void iterateBgCtl(auto cb) noexcept {
|
||||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||||
cb(bgCtl);
|
cb(*bgCtl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
deps/teagba/src/gfx.cpp
vendored
21
deps/teagba/src/gfx.cpp
vendored
@ -10,32 +10,23 @@
|
|||||||
|
|
||||||
namespace teagba {
|
namespace teagba {
|
||||||
|
|
||||||
static volatile uint16_t g_spriteUpdates = 0;
|
|
||||||
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
||||||
|
|
||||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
|
||||||
// block until g_spriteUpdates is less than buffer len
|
return g_spriteBuffer[i];
|
||||||
if (g_spriteUpdates >= g_spriteBuffer.size()) [[unlikely]] {
|
|
||||||
teagba_vblankintrwait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
||||||
const auto ie = REG_IE; // disable vblank interrupt handler
|
const auto ie = REG_IE; // disable vblank interrupt handler
|
||||||
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
|
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
|
||||||
const auto updateCnt = g_spriteUpdates;
|
g_spriteBuffer[upd.idx] = upd;
|
||||||
g_spriteBuffer[updateCnt] = upd;
|
|
||||||
g_spriteUpdates = updateCnt + 1;
|
|
||||||
REG_IE = ie; // enable vblank interrupt handler
|
REG_IE = ie; // enable vblank interrupt handler
|
||||||
}
|
}
|
||||||
|
|
||||||
void applySpriteUpdates() noexcept {
|
void applySpriteUpdates() noexcept {
|
||||||
// copy g_spriteUpdates to allow it to use a register instead of reading
|
for (auto const&oa : g_spriteBuffer) {
|
||||||
// from memory every iteration of the loop, needed because g_spriteUpdates
|
|
||||||
// is volatile
|
|
||||||
const unsigned updates = g_spriteUpdates;
|
|
||||||
for (unsigned i = 0; i < updates; ++i) {
|
|
||||||
const auto &oa = g_spriteBuffer[i];
|
|
||||||
MEM_OAM[oa.idx] = std::bit_cast<uint64_t>(oa);
|
MEM_OAM[oa.idx] = std::bit_cast<uint64_t>(oa);
|
||||||
}
|
}
|
||||||
g_spriteUpdates = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ install(
|
|||||||
include/nostalgia/modules
|
include/nostalgia/modules
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(${OLYMPIC_BUILD_STUDIO})
|
||||||
# Studio
|
# Studio
|
||||||
if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
||||||
add_library(
|
add_library(
|
||||||
@ -42,6 +43,7 @@ if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
|||||||
include/nostalgia/modules
|
include/nostalgia/modules
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(NostalgiaProfile INTERFACE)
|
add_library(NostalgiaProfile INTERFACE)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
if(NOT TURBINE_BUILD_TYPE STREQUAL "GBA")
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(
|
install(
|
||||||
DIRECTORY
|
DIRECTORY
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
extern ox::Array<char, 128> charMap;
|
|
||||||
|
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Sprite";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
@ -23,6 +23,7 @@ struct Sprite {
|
|||||||
unsigned spriteShape = 0;
|
unsigned spriteShape = 0;
|
||||||
unsigned spriteSize = 0;
|
unsigned spriteSize = 0;
|
||||||
unsigned flipX = 0;
|
unsigned flipX = 0;
|
||||||
|
unsigned bpp = 0;
|
||||||
/**
|
/**
|
||||||
* Valid priorities: 0-3
|
* Valid priorities: 0-3
|
||||||
*/
|
*/
|
||||||
@ -38,14 +39,89 @@ oxModelBegin(Sprite)
|
|||||||
oxModelField(spriteShape)
|
oxModelField(spriteShape)
|
||||||
oxModelField(spriteSize)
|
oxModelField(spriteSize)
|
||||||
oxModelField(flipX)
|
oxModelField(flipX)
|
||||||
|
oxModelField(bpp)
|
||||||
oxModelField(priority)
|
oxModelField(priority)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSetEntrySection {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntrySection";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
int32_t begin = 0;
|
||||||
|
int32_t tiles = 0;
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto end() const noexcept {
|
||||||
|
return begin + tiles - 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSetEntrySection)
|
||||||
|
oxModelField(begin)
|
||||||
|
oxModelField(size)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSetEntry {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntry";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::FileAddress tilesheet;
|
||||||
|
ox::Vector<TileSheetSetEntrySection> sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSetEntry)
|
||||||
|
oxModelField(tilesheet)
|
||||||
|
oxModelField(sections)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSet {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSet";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
static constexpr auto Preloadable = true;
|
||||||
|
int bpp = 0;
|
||||||
|
ox::Vector<TileSheetSetEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSet)
|
||||||
|
oxModelField(bpp)
|
||||||
|
oxModelField(entries)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
ox::Error loadBgPalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadSpritePalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
ox::FileAddress const&tilesheetAddr,
|
||||||
|
bool loadDefaultPalette = false) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&tilesheetAddr,
|
||||||
|
bool loadDefaultPalette = false) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept;
|
||||||
|
|
||||||
|
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, uint8_t tile) noexcept;
|
||||||
|
|
||||||
|
void clearBg(Context &ctx, uint_t bgIdx) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
uint8_t bgStatus(Context &ctx) noexcept;
|
uint8_t bgStatus(Context &ctx) noexcept;
|
||||||
|
|
||||||
void setBgStatus(Context &ctx, uint32_t status) noexcept;
|
void setBgStatus(Context &ctx, uint32_t status) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
bool bgStatus(Context &ctx, unsigned bg) noexcept;
|
bool bgStatus(Context &ctx, unsigned bg) noexcept;
|
||||||
|
|
||||||
void setBgStatus(Context &ctx, unsigned bg, bool status) noexcept;
|
void setBgStatus(Context &ctx, unsigned bg, bool status) noexcept;
|
||||||
@ -54,34 +130,19 @@ void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept;
|
|||||||
|
|
||||||
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
|
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section])
|
|
||||||
*/
|
|
||||||
ox::Error loadBgTileSheet(
|
|
||||||
Context &ctx,
|
|
||||||
unsigned cbb,
|
|
||||||
ox::FileAddress const&tilesheetAddr,
|
|
||||||
ox::FileAddress const&paletteAddr = nullptr) noexcept;
|
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(
|
|
||||||
Context &ctx,
|
|
||||||
ox::FileAddress const&tilesheetAddr,
|
|
||||||
ox::FileAddress const&paletteAddr) noexcept;
|
|
||||||
|
|
||||||
ox::Error initConsole(Context &ctx) noexcept;
|
|
||||||
|
|
||||||
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept;
|
|
||||||
|
|
||||||
void setTile(Context &ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
|
|
||||||
|
|
||||||
void clearTileLayer(Context &ctx, unsigned bgIdx) noexcept;
|
|
||||||
|
|
||||||
void hideSprite(Context &ctx, unsigned) noexcept;
|
void hideSprite(Context &ctx, unsigned) noexcept;
|
||||||
|
|
||||||
void showSprite(Context &ctx, unsigned) noexcept;
|
void showSprite(Context &ctx, unsigned) noexcept;
|
||||||
|
|
||||||
void setSprite(Context &c, uint_t idx, Sprite const&s) noexcept;
|
void setSprite(Context &c, uint_t idx, Sprite const&s) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
uint_t spriteCount(Context &ctx) noexcept;
|
||||||
|
|
||||||
|
ox::Error initConsole(Context &ctx) noexcept;
|
||||||
|
|
||||||
|
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace nostalgia::core::gl {
|
namespace nostalgia::core::gl {
|
||||||
|
@ -8,10 +8,15 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
struct BgCbbData {
|
||||||
|
unsigned bpp = 4;
|
||||||
|
};
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
turbine::Context &turbineCtx;
|
turbine::Context &turbineCtx;
|
||||||
|
ox::Array<BgCbbData, 4> cbbData;
|
||||||
|
|
||||||
explicit Context(turbine::Context &tctx) noexcept;
|
explicit Context(turbine::Context &tctx) noexcept;
|
||||||
Context(Context &other) noexcept = delete;
|
Context(Context &other) noexcept = delete;
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include <teagba/gfx.hpp>
|
#include <teagba/gfx.hpp>
|
||||||
#include <teagba/registers.hpp>
|
#include <teagba/registers.hpp>
|
||||||
|
|
||||||
#include <keel/media.hpp>
|
|
||||||
#include <turbine/turbine.hpp>
|
#include <turbine/turbine.hpp>
|
||||||
|
|
||||||
#include <nostalgia/core/color.hpp>
|
#include <nostalgia/core/color.hpp>
|
||||||
@ -22,13 +21,9 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
struct BgCbbData {
|
|
||||||
unsigned bpp = 4;
|
|
||||||
};
|
|
||||||
static ox::Array<BgCbbData, 4> g_cbbData;
|
|
||||||
|
|
||||||
constexpr auto GbaTileColumns = 32;
|
constexpr auto GbaTileColumns = 32;
|
||||||
constexpr auto GbaTileRows = 32;
|
constexpr auto GbaTileRows = 32;
|
||||||
|
constexpr auto SpriteCount = 128;
|
||||||
|
|
||||||
struct GbaPaletteTarget {
|
struct GbaPaletteTarget {
|
||||||
static constexpr auto TypeName = Palette::TypeName;
|
static constexpr auto TypeName = Palette::TypeName;
|
||||||
@ -39,25 +34,105 @@ struct GbaPaletteTarget {
|
|||||||
struct GbaTileMapTarget {
|
struct GbaTileMapTarget {
|
||||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||||
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||||
BgCbbData *cbbData = nullptr;
|
unsigned &bpp;
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
GbaPaletteTarget pal;
|
|
||||||
volatile uint16_t *tileMap = nullptr;
|
volatile uint16_t *tileMap = nullptr;
|
||||||
|
// the following values are not actually in CompactTileSheet,
|
||||||
|
// and only exist to communicate with the loading process
|
||||||
|
size_t tileWriteIdx = 0;
|
||||||
|
unsigned targetBpp = 0;
|
||||||
|
TileSheetSetEntry const*setEntry = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
||||||
oxReturnError(io->template setTypeInfo<Palette>());
|
oxReturnError(io->template setTypeInfo<Palette>());
|
||||||
|
if (t->palette) {
|
||||||
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
|
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
|
||||||
t->palette[i] = *c;
|
t->palette[i] = *c;
|
||||||
return OxError(0);
|
return ox::Error{};
|
||||||
};
|
};
|
||||||
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
|
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
|
||||||
|
} else {
|
||||||
|
constexpr auto colorHandler = [](std::size_t, const Color16*) {
|
||||||
|
return ox::Error{};
|
||||||
|
};
|
||||||
|
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static bool loadPixel(TileSheetSetEntry const&setEntry, size_t §ionIdx, int tileIdx) noexcept {
|
||||||
|
if (setEntry.sections.size() <= sectionIdx) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto §ion = setEntry.sections[sectionIdx];
|
||||||
|
if (tileIdx < section.begin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tileIdx > section.end()) {
|
||||||
|
if (sectionIdx >= setEntry.sections.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++sectionIdx;
|
||||||
|
return tileIdx > section.begin && tileIdx <= section.end();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
||||||
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
||||||
oxReturnError(io->field("bpp", &t->cbbData->bpp));
|
oxReturnError(io->field("bpp", &t->bpp));
|
||||||
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||||
|
if (t->targetBpp == 0) {
|
||||||
|
t->targetBpp = t->bpp;
|
||||||
|
}
|
||||||
|
if (t->targetBpp != t->bpp && t->bpp == 8) {
|
||||||
|
return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB");
|
||||||
|
}
|
||||||
|
ox::Error out{};
|
||||||
|
if (t->setEntry) {
|
||||||
|
// The following code is atrocious, but it works.
|
||||||
|
// It might be possible to clean it up a little, but it probably
|
||||||
|
// cannot be seriously optimized without preloading TileSheets.
|
||||||
|
size_t sectionIdx = 0;
|
||||||
|
if (t->targetBpp == t->bpp) {
|
||||||
|
TileSheetSetEntrySection const*section = &t->setEntry->sections[0];
|
||||||
|
size_t writeIt = 0;
|
||||||
|
uint16_t intermediate = 0;
|
||||||
|
size_t const fourBpp = t->bpp == 4;
|
||||||
|
const auto handleTileMap = [t, &intermediate, §ion, §ionIdx, &writeIt, fourBpp]
|
||||||
|
(std::size_t i, uint8_t const*tile) {
|
||||||
|
auto const tileIdx = static_cast<int>((i * (2 * fourBpp)) / PixelsPerTile);
|
||||||
|
if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) {
|
||||||
|
return ox::Error{};
|
||||||
|
}
|
||||||
|
if (writeIt & 1) { // i is odd
|
||||||
|
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||||
|
t->tileMap[writeIt / 2] = intermediate;
|
||||||
|
++t->tileWriteIdx;
|
||||||
|
} else { // i is even
|
||||||
|
intermediate = *tile & 0x00ff;
|
||||||
|
}
|
||||||
|
++writeIt;
|
||||||
|
return ox::Error{};
|
||||||
|
};
|
||||||
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
|
} else if (t->targetBpp > t->bpp) { // 4 -> 8 bits
|
||||||
|
const auto handleTileMap = [t, §ionIdx](std::size_t writeIt, uint8_t const*tile) {
|
||||||
|
auto constexpr BytesPerTile4Bpp = 32;
|
||||||
|
auto const tileIdx = static_cast<int>(writeIt / BytesPerTile4Bpp);
|
||||||
|
if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) {
|
||||||
|
return ox::Error{};
|
||||||
|
}
|
||||||
|
uint16_t const px1 = *tile & 0xf;
|
||||||
|
uint16_t const px2 = *tile >> 4;
|
||||||
|
t->tileMap[t->tileWriteIdx] = static_cast<uint16_t>(px1 | (px2 << 8));
|
||||||
|
++t->tileWriteIdx;
|
||||||
|
return ox::Error{};
|
||||||
|
};
|
||||||
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
uint16_t intermediate = 0;
|
uint16_t intermediate = 0;
|
||||||
const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t*tile) {
|
const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t*tile) {
|
||||||
if (i & 1) { // i is odd
|
if (i & 1) { // i is odd
|
||||||
@ -66,18 +141,160 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
|
|||||||
} else { // i is even
|
} else { // i is even
|
||||||
intermediate = *tile & 0x00ff;
|
intermediate = *tile & 0x00ff;
|
||||||
}
|
}
|
||||||
return OxError(0);
|
return ox::Error{};
|
||||||
};
|
};
|
||||||
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error initGfx(Context&, InitParams const&) noexcept {
|
ox::Error initGfx(Context&, InitParams const&) noexcept {
|
||||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||||
teagba::bgSetSbb(bgCtl, 28);
|
teagba::bgSetSbb(*bgCtl, 28);
|
||||||
|
}
|
||||||
|
for (uint16_t i = 0; i < SpriteCount; ++i) {
|
||||||
|
auto &sa = teagba::spriteAttr(i);
|
||||||
|
sa.idx = i;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgPalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
GbaPaletteTarget const palTarget{.palette = MEM_BG_PALETTE};
|
||||||
|
oxRequire(palStat, rom.stat(paletteAddr));
|
||||||
|
oxRequire(pal, rom.directAccess(paletteAddr));
|
||||||
|
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &palTarget));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpritePalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
GbaPaletteTarget const palTarget{.palette = MEM_SPRITE_PALETTE};
|
||||||
|
oxRequire(palStat, rom.stat(paletteAddr));
|
||||||
|
oxRequire(pal, rom.directAccess(paletteAddr));
|
||||||
|
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &palTarget));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ox::Error loadTileSheetSet(
|
||||||
|
Context &ctx,
|
||||||
|
uint16_t *tileMapTargetMem,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
size_t tileWriteIdx = 0;
|
||||||
|
for (auto const&entry : set.entries) {
|
||||||
|
oxRequire(tsStat, rom.stat(entry.tilesheet));
|
||||||
|
oxRequire(ts, rom.directAccess(entry.tilesheet));
|
||||||
|
unsigned tilesheetBpp{};
|
||||||
|
GbaTileMapTarget target{
|
||||||
|
.bpp = tilesheetBpp,
|
||||||
|
.defaultPalette = {},
|
||||||
|
.tileMap = tileMapTargetMem + tileWriteIdx,
|
||||||
|
.targetBpp = static_cast<unsigned>(set.bpp),
|
||||||
|
.setEntry = &entry,
|
||||||
|
};
|
||||||
|
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
||||||
|
tileWriteIdx += target.tileWriteIdx;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
ox::FileAddress const&tilesheetAddr,
|
||||||
|
bool loadDefaultPalette) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||||
|
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||||
|
GbaTileMapTarget target{
|
||||||
|
.bpp = ctx.cbbData[cbb].bpp,
|
||||||
|
.defaultPalette = {},
|
||||||
|
.tileMap = MEM_BG_TILES[cbb].data(),
|
||||||
|
};
|
||||||
|
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
||||||
|
// update bpp of all bgs with the updated cbb
|
||||||
|
const auto bpp = ctx.cbbData[cbb].bpp;
|
||||||
|
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||||
|
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||||
|
teagba::bgSetBpp(bgCtl, bpp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (loadDefaultPalette && target.defaultPalette) {
|
||||||
|
oxReturnError(loadBgPalette(ctx, target.defaultPalette));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto const bpp = static_cast<unsigned>(set.bpp);
|
||||||
|
oxReturnError(loadTileSheetSet(ctx, MEM_BG_TILES[cbb].data(), set));
|
||||||
|
// update bpp of all bgs with the updated cbb
|
||||||
|
ctx.cbbData[cbb].bpp = bpp;
|
||||||
|
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||||
|
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||||
|
teagba::bgSetBpp(bgCtl, bpp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setSpritesBpp(unsigned const bpp) noexcept {
|
||||||
|
auto const eightBpp = static_cast<uint16_t >(bpp == 8);
|
||||||
|
for (auto i = 0u; i < SpriteCount; ++i) {
|
||||||
|
auto &sa = teagba::spriteAttr(i);
|
||||||
|
auto &a = sa.attr0;
|
||||||
|
a |= static_cast<uint16_t>((a & ~static_cast<uint16_t>(1u << 13)) | (eightBpp << 13));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&tilesheetAddr,
|
||||||
|
bool loadDefaultPalette) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||||
|
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||||
|
unsigned bpp{};
|
||||||
|
GbaTileMapTarget target{
|
||||||
|
.bpp = bpp,
|
||||||
|
.defaultPalette = {},
|
||||||
|
.tileMap = MEM_SPRITE_TILES,
|
||||||
|
};
|
||||||
|
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
||||||
|
if (loadDefaultPalette && target.defaultPalette) {
|
||||||
|
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
||||||
|
}
|
||||||
|
setSpritesBpp(bpp);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto const bpp = static_cast<unsigned>(set.bpp);
|
||||||
|
oxReturnError(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set));
|
||||||
|
setSpritesBpp(bpp);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBgTile(Context&, uint_t bgIdx, int column, int row, uint8_t tile) noexcept {
|
||||||
|
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
|
||||||
|
MEM_BG_MAP[bgIdx][tileIdx] = tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBg(Context&, uint_t bgIdx) noexcept {
|
||||||
|
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t bgStatus(Context&) noexcept {
|
uint8_t bgStatus(Context&) noexcept {
|
||||||
return (REG_DISPCTL >> 8u) & 0b1111u;
|
return (REG_DISPCTL >> 8u) & 0b1111u;
|
||||||
}
|
}
|
||||||
@ -97,11 +314,11 @@ void setBgStatus(Context&, unsigned bg, bool status) noexcept {
|
|||||||
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
|
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBgCbb(Context&, unsigned bgIdx, unsigned cbb) noexcept {
|
void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept {
|
||||||
auto &bgCtl = regBgCtl(bgIdx);
|
auto &bgCtl = regBgCtl(bgIdx);
|
||||||
const auto &cbbData = g_cbbData[cbb];
|
const auto &cbbData = ctx.cbbData[cbb];
|
||||||
teagba::bgSetBpp(&bgCtl, cbbData.bpp);
|
teagba::bgSetBpp(bgCtl, cbbData.bpp);
|
||||||
teagba::bgSetCbb(&bgCtl, cbb);
|
teagba::bgSetCbb(bgCtl, cbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept {
|
void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept {
|
||||||
@ -109,111 +326,6 @@ void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept {
|
|||||||
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
|
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error loadBgTileSheet(
|
|
||||||
ox::MemFS const&rom,
|
|
||||||
unsigned cbb,
|
|
||||||
ox::FileAddress const&tilesheetAddr,
|
|
||||||
ox::FileAddress const&paletteAddr) noexcept {
|
|
||||||
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
|
||||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
|
||||||
GbaTileMapTarget target;
|
|
||||||
target.pal.palette = MEM_BG_PALETTE;
|
|
||||||
target.cbbData = &g_cbbData[cbb];
|
|
||||||
target.tileMap = MEM_BG_TILES[cbb].data();
|
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
|
||||||
// load external palette if available
|
|
||||||
if (paletteAddr) {
|
|
||||||
oxRequire(palStat, rom.stat(paletteAddr));
|
|
||||||
oxRequire(pal, rom.directAccess(paletteAddr));
|
|
||||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
|
|
||||||
}
|
|
||||||
// update bpp of all bgs with the updated cbb
|
|
||||||
const auto bpp = g_cbbData[cbb].bpp;
|
|
||||||
teagba::iterateBgCtl([bpp, cbb](auto bgCtl) {
|
|
||||||
if (teagba::bgCbb(bgCtl) == cbb) {
|
|
||||||
teagba::bgSetBpp(bgCtl, bpp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
|
||||||
Context &ctx,
|
|
||||||
unsigned cbb,
|
|
||||||
ox::FileAddress const&tilesheetAddr,
|
|
||||||
ox::FileAddress const&paletteAddr) noexcept {
|
|
||||||
auto &rom = ctx.rom();
|
|
||||||
return loadBgTileSheet(rom, cbb, tilesheetAddr, paletteAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(
|
|
||||||
Context &ctx,
|
|
||||||
ox::FileAddress const&tilesheetAddr,
|
|
||||||
ox::FileAddress const&paletteAddr) noexcept {
|
|
||||||
auto &rom = ctx.rom();
|
|
||||||
oxRequire(tsStat, ctx.rom().stat(tilesheetAddr));
|
|
||||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
|
||||||
GbaTileMapTarget target;
|
|
||||||
target.pal.palette = MEM_SPRITE_PALETTE;
|
|
||||||
target.tileMap = MEM_SPRITE_TILES;
|
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
|
||||||
// load external palette if available
|
|
||||||
if (paletteAddr) {
|
|
||||||
oxRequire(palStat, ctx.rom().stat(paletteAddr));
|
|
||||||
oxRequire(pal, rom.directAccess(paletteAddr));
|
|
||||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error loadBgPalette(Context &ctx, unsigned, ox::FileAddress const&paletteAddr) noexcept {
|
|
||||||
auto &rom = ctx.rom();
|
|
||||||
GbaPaletteTarget target;
|
|
||||||
target.palette = MEM_BG_PALETTE;
|
|
||||||
oxRequire(palStat, ctx.rom().stat(paletteAddr));
|
|
||||||
oxRequire(pal, rom.directAccess(paletteAddr));
|
|
||||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error loadSpritePalette(Context &ctx, unsigned cbb, ox::FileAddress const&paletteAddr) noexcept {
|
|
||||||
auto &rom = ctx.rom();
|
|
||||||
GbaPaletteTarget target;
|
|
||||||
target.palette = &MEM_SPRITE_PALETTE[cbb];
|
|
||||||
oxRequire(palStat, rom.stat(paletteAddr));
|
|
||||||
oxRequire(pal, rom.directAccess(paletteAddr));
|
|
||||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error initConsole(Context &ctx) noexcept {
|
|
||||||
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
|
|
||||||
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
|
|
||||||
setBgStatus(ctx, 0b0001);
|
|
||||||
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr));
|
|
||||||
setBgCbb(ctx, 0, 0);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
|
|
||||||
const auto col = static_cast<unsigned>(column);
|
|
||||||
for (auto i = 0u; i < str.bytes(); i++) {
|
|
||||||
const auto c = charMap[static_cast<std::size_t>(str[i])];
|
|
||||||
setTile(ctx, 0, static_cast<int>(col + i), row, static_cast<uint8_t>(c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTile(Context&, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
|
|
||||||
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
|
|
||||||
MEM_BG_MAP[bgIdx][tileIdx] = tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do NOT use Context in the GBA version of this function.
|
|
||||||
void clearTileLayer(Context&, unsigned bgIdx) noexcept {
|
|
||||||
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
void hideSprite(Context&, unsigned idx) noexcept {
|
void hideSprite(Context&, unsigned idx) noexcept {
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
teagba::addSpriteUpdate({
|
teagba::addSpriteUpdate({
|
||||||
@ -222,7 +334,6 @@ void hideSprite(Context&, unsigned idx) noexcept {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
void showSprite(Context&, unsigned idx) noexcept {
|
void showSprite(Context&, unsigned idx) noexcept {
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
teagba::addSpriteUpdate({
|
teagba::addSpriteUpdate({
|
||||||
@ -233,20 +344,27 @@ void showSprite(Context&, unsigned idx) noexcept {
|
|||||||
|
|
||||||
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
|
uint16_t const eightBpp = s.bpp == 8;
|
||||||
teagba::addSpriteUpdate({
|
teagba::addSpriteUpdate({
|
||||||
.attr0 = static_cast<uint16_t>(
|
.attr0 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
||||||
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||||
|
| (static_cast<uint16_t>(eightBpp) << 13)
|
||||||
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
||||||
.attr1 = static_cast<uint16_t>(
|
.attr1 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
||||||
| (static_cast<uint16_t>(s.flipX) << 12)
|
| (static_cast<uint16_t>(s.flipX) << 12)
|
||||||
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
||||||
.attr2 = static_cast<uint16_t>(
|
.attr2 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.tileIdx & ox::onMask<uint16_t>(8)))
|
// double tileIdx if 8 bpp
|
||||||
|
(static_cast<uint16_t>((s.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
|
||||||
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
|
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
|
||||||
.idx = static_cast<uint16_t>(idx),
|
.idx = static_cast<uint16_t>(idx),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint_t spriteCount(Context&) noexcept {
|
||||||
|
return SpriteCount;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ void panic(const char *file, int line, const char *panicMsg, ox::Error const&err
|
|||||||
oxIgnoreError(initGfx(*ctx, {}));
|
oxIgnoreError(initGfx(*ctx, {}));
|
||||||
oxIgnoreError(initConsole(*ctx));
|
oxIgnoreError(initConsole(*ctx));
|
||||||
setBgStatus(*ctx, 0, true);
|
setBgStatus(*ctx, 0, true);
|
||||||
clearTileLayer(*ctx, 0);
|
clearBg(*ctx, 0);
|
||||||
ox::BString<23> serr = "Error code: ";
|
ox::BString<23> serr = "Error code: ";
|
||||||
serr += static_cast<int64_t>(err);
|
serr += static_cast<int64_t>(err);
|
||||||
puts(*ctx, 32 + 1, 1, "SADNESS...");
|
puts(*ctx, 32 + 1, 1, "SADNESS...");
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
// map ASCII values to the nostalgia charset
|
// map ASCII values to the nostalgia charset
|
||||||
ox::Array<char, 128> charMap = {
|
constexpr ox::Array<char, 128> charMap = {
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -137,4 +137,29 @@ ox::Array<char, 128> charMap = {
|
|||||||
50, // ~
|
50, // ~
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ox::Error initConsole(Context &ctx) noexcept {
|
||||||
|
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
|
||||||
|
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
|
||||||
|
setBgStatus(ctx, 0b0001);
|
||||||
|
setBgCbb(ctx, 0, 0);
|
||||||
|
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr));
|
||||||
|
return loadBgPalette(ctx, PaletteAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void puts(
|
||||||
|
Context &ctx,
|
||||||
|
int const column,
|
||||||
|
int const row,
|
||||||
|
ox::CRStringView str) noexcept {
|
||||||
|
auto const col = static_cast<uint_t>(column);
|
||||||
|
for (auto i = 0u; i < str.bytes(); ++i) {
|
||||||
|
setBgTile(
|
||||||
|
ctx,
|
||||||
|
0,
|
||||||
|
static_cast<int>(col + i),
|
||||||
|
row,
|
||||||
|
static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
namespace renderer {
|
||||||
|
|
||||||
constexpr auto Scale = 1;
|
constexpr auto Scale = 1;
|
||||||
constexpr auto PriorityScale = 0.01f;
|
constexpr auto PriorityScale = 0.01f;
|
||||||
|
|
||||||
namespace renderer {
|
|
||||||
|
|
||||||
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
|
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
|
||||||
|
|
||||||
void Drawer::draw(turbine::Context &tctx) noexcept {
|
void Drawer::draw(turbine::Context &tctx) noexcept {
|
||||||
@ -98,7 +98,7 @@ constexpr ox::CStringView spritefshadTmpl = R"glsl(
|
|||||||
if (outColor.a == 0) {
|
if (outColor.a == 0) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
})glsl";;
|
})glsl";
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
|
static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
|
||||||
@ -338,8 +338,7 @@ static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
|
|||||||
|
|
||||||
static void loadPalette(
|
static void loadPalette(
|
||||||
GLuint shaderPgrm,
|
GLuint shaderPgrm,
|
||||||
Palette const&pal,
|
Palette const&pal) noexcept {
|
||||||
bool firstIsTransparent) noexcept {
|
|
||||||
static constexpr std::size_t ColorCnt = 256;
|
static constexpr std::size_t ColorCnt = 256;
|
||||||
ox::Array<GLfloat, ColorCnt * 4> palette{};
|
ox::Array<GLfloat, ColorCnt * 4> palette{};
|
||||||
for (auto i = 0u; const auto c : pal.colors) {
|
for (auto i = 0u; const auto c : pal.colors) {
|
||||||
@ -348,41 +347,13 @@ static void loadPalette(
|
|||||||
palette[i++] = bluef(c);
|
palette[i++] = bluef(c);
|
||||||
palette[i++] = 255;
|
palette[i++] = 255;
|
||||||
}
|
}
|
||||||
if (firstIsTransparent) {
|
// make first color transparent
|
||||||
palette[3] = 0;
|
palette[3] = 0;
|
||||||
}
|
|
||||||
glUseProgram(shaderPgrm);
|
glUseProgram(shaderPgrm);
|
||||||
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
|
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
|
||||||
glUniform4fv(uniformPalette, ColorCnt, palette.data());
|
glUniform4fv(uniformPalette, ColorCnt, palette.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadBgPalette(Context &ctx, Palette const&pal) noexcept {
|
|
||||||
loadPalette(ctx.bgShader, pal, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadSpritePalette(Context &ctx, Palette const&pal) noexcept {
|
|
||||||
loadPalette(ctx.spriteShader, pal, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadBgTexture(
|
|
||||||
Context &ctx,
|
|
||||||
uint_t cbbIdx,
|
|
||||||
const void *pixels,
|
|
||||||
int w,
|
|
||||||
int h) noexcept {
|
|
||||||
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h);
|
|
||||||
ctx.cbbs[cbbIdx].tex = createTexture(w, h, pixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void loadSpriteTexture(
|
|
||||||
Context &ctx,
|
|
||||||
const void *pixels,
|
|
||||||
int w,
|
|
||||||
int h) noexcept {
|
|
||||||
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", w, h);
|
|
||||||
ctx.spriteBlocks.tex = createTexture(w, h, pixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setSprite(
|
static void setSprite(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
uint_t const idx,
|
uint_t const idx,
|
||||||
@ -493,8 +464,7 @@ struct TileSheetData {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static ox::Result<TileSheetData> loadTileSheet(
|
static ox::Result<TileSheetData> normalizeTileSheet(
|
||||||
Context &ctx,
|
|
||||||
CompactTileSheet const&tilesheet) noexcept {
|
CompactTileSheet const&tilesheet) noexcept {
|
||||||
const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
|
const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
|
||||||
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
|
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
|
||||||
@ -513,71 +483,131 @@ static ox::Result<TileSheetData> loadTileSheet(
|
|||||||
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
|
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderer::loadSpriteTexture(ctx, pixels.data(), width, height);
|
|
||||||
return TileSheetData{std::move(pixels), width, height};
|
return TileSheetData{std::move(pixels), width, height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgPalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept {
|
||||||
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
|
oxRequire(palette, readObj<Palette>(kctx, paletteAddr));
|
||||||
|
renderer::loadPalette(ctx.bgShader, *palette);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpritePalette(
|
||||||
|
Context &ctx,
|
||||||
|
ox::FileAddress const&paletteAddr) noexcept {
|
||||||
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
|
oxRequire(palette, readObj<Palette>(kctx, paletteAddr));
|
||||||
|
renderer::loadPalette(ctx.spriteShader, *palette);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ox::Result<TileSheetData> buildSetTsd(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
|
TileSheetData setTsd;
|
||||||
|
setTsd.width = TileWidth;
|
||||||
|
for (auto const&entry : set.entries) {
|
||||||
|
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
|
||||||
|
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||||
|
for (auto const&s : entry.sections) {
|
||||||
|
auto const size = s.tiles * PixelsPerTile;
|
||||||
|
for (auto i = 0; i < size; ++i) {
|
||||||
|
auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile);
|
||||||
|
setTsd.pixels.push_back(tsd.pixels[srcIdx]);
|
||||||
|
}
|
||||||
|
setTsd.height += TileHeight * s.tiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setTsd;
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
uint_t cbb,
|
uint_t cbb,
|
||||||
ox::FileAddress const&tilesheetAddr,
|
ox::FileAddress const&tilesheetAddr,
|
||||||
ox::FileAddress const&paletteAddr) noexcept {
|
bool loadDefaultPalette) noexcept {
|
||||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||||
oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||||
oxRequire(tsd, loadTileSheet(ctx, *tilesheet).to([](TileSheetData const&t) -> TileSheetData {
|
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height);
|
||||||
return {
|
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||||
.pixels = resizeTileSheetData(t.pixels, t.size(), Scale),
|
if (loadDefaultPalette) {
|
||||||
.width = t.width * Scale,
|
oxReturnError(loadBgPalette(ctx, tilesheet->defaultPalette));
|
||||||
.height = t.height * Scale,
|
}
|
||||||
};
|
return {};
|
||||||
}));
|
}
|
||||||
renderer::loadBgTexture(ctx, cbb, tsd.pixels.data(), tsd.width, tsd.height);
|
|
||||||
renderer::loadBgPalette(ctx, *palette);
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
oxRequire(setTsd, buildSetTsd(ctx, set));
|
||||||
|
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(
|
ox::Error loadSpriteTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::FileAddress const&tilesheetAddr,
|
ox::FileAddress const&tilesheetAddr,
|
||||||
ox::FileAddress const&paletteAddr) noexcept {
|
bool loadDefaultPalette) noexcept {
|
||||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||||
oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||||
oxRequire(tsd, loadTileSheet(ctx, *tilesheet));
|
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
|
||||||
renderer::loadSpriteTexture(ctx, tsd.pixels.data(), tsd.width, tsd.height);
|
ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||||
renderer::loadSpritePalette(ctx, *palette);
|
if (loadDefaultPalette) {
|
||||||
|
oxReturnError(loadSpritePalette(ctx, tilesheet->defaultPalette));
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error initConsole(Context &ctx) noexcept {
|
ox::Error loadSpriteTileSheet(
|
||||||
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
|
Context &ctx,
|
||||||
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
|
TileSheetSet const&set) noexcept {
|
||||||
setBgStatus(ctx, 0b0001);
|
oxRequire(setTsd, buildSetTsd(ctx, set));
|
||||||
setBgCbb(ctx, 0, 0);
|
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
|
||||||
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
|
void setBgTile(
|
||||||
const auto col = static_cast<uint_t>(column);
|
Context &ctx,
|
||||||
for (auto i = 0u; i < str.bytes(); ++i) {
|
uint_t bgIdx,
|
||||||
setTile(
|
int column,
|
||||||
ctx,
|
int row,
|
||||||
0,
|
uint8_t tile) noexcept {
|
||||||
static_cast<int>(col + i),
|
oxTracef(
|
||||||
row,
|
"nostalgia.core.gfx.setBgTile",
|
||||||
static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
|
"bgIdx: {}, column: {}, row: {}, tile: {}",
|
||||||
}
|
bgIdx, column, row, tile);
|
||||||
}
|
const auto z = static_cast<uint_t>(bgIdx);
|
||||||
|
const auto y = static_cast<uint_t>(row);
|
||||||
void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept {
|
const auto x = static_cast<uint_t>(column);
|
||||||
|
const auto i = renderer::bgVertexRow(x, y);
|
||||||
|
auto &cbb = ctx.cbbs[z];
|
||||||
|
const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength];
|
||||||
|
const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength];
|
||||||
auto &bg = ctx.backgrounds[bgIdx];
|
auto &bg = ctx.backgrounds[bgIdx];
|
||||||
bg.cbbIdx = cbbIdx;
|
renderer::setTileBufferObject(
|
||||||
|
static_cast<uint_t>(i * renderer::BgVertexVboRows),
|
||||||
|
static_cast<float>(x),
|
||||||
|
static_cast<float>(y),
|
||||||
|
static_cast<float>(tile),
|
||||||
|
bg.priority,
|
||||||
|
vbo,
|
||||||
|
ebo);
|
||||||
|
cbb.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept {
|
void clearBg(Context &ctx, uint_t bgIdx) noexcept {
|
||||||
auto &bg = ctx.backgrounds[bgIdx];
|
auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
|
||||||
bg.priority = static_cast<float>(priority & 0b11);
|
initBackgroundBufferObjects(cbb);
|
||||||
|
cbb.updated = true;
|
||||||
|
auto &bg = ctx.backgrounds[static_cast<std::size_t>(bgIdx)];
|
||||||
|
bg.priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bgStatus(Context &ctx) noexcept {
|
uint8_t bgStatus(Context &ctx) noexcept {
|
||||||
@ -602,13 +632,14 @@ void setBgStatus(Context &ctx, uint_t bg, bool status) noexcept {
|
|||||||
ctx.backgrounds[bg].enabled = status;
|
ctx.backgrounds[bg].enabled = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept {
|
||||||
|
auto &bg = ctx.backgrounds[bgIdx];
|
||||||
|
bg.cbbIdx = cbbIdx;
|
||||||
|
}
|
||||||
|
|
||||||
void clearTileLayer(Context &ctx, uint_t bgIdx) noexcept {
|
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept {
|
||||||
auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
|
auto &bg = ctx.backgrounds[bgIdx];
|
||||||
initBackgroundBufferObjects(cbb);
|
bg.priority = static_cast<float>(priority & 0b11);
|
||||||
cbb.updated = true;
|
|
||||||
auto &bg = ctx.backgrounds[static_cast<std::size_t>(bgIdx)];
|
|
||||||
bg.priority = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideSprite(Context &ctx, uint_t idx) noexcept {
|
void hideSprite(Context &ctx, uint_t idx) noexcept {
|
||||||
@ -629,33 +660,8 @@ void setSprite(Context &ctx, uint_t idx, Sprite const&sprite) noexcept {
|
|||||||
renderer::setSprite(ctx, idx, s);
|
renderer::setSprite(ctx, idx, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTile(
|
uint_t spriteCount(Context &ctx) noexcept {
|
||||||
Context &ctx,
|
return ctx.spriteCount;
|
||||||
uint_t bgIdx,
|
|
||||||
int column,
|
|
||||||
int row,
|
|
||||||
uint8_t tile) noexcept {
|
|
||||||
oxTracef(
|
|
||||||
"nostalgia.core.gfx.setTile",
|
|
||||||
"bgIdx: {}, column: {}, row: {}, tile: {}",
|
|
||||||
bgIdx, column, row, tile);
|
|
||||||
const auto z = static_cast<uint_t>(bgIdx);
|
|
||||||
const auto y = static_cast<uint_t>(row);
|
|
||||||
const auto x = static_cast<uint_t>(column);
|
|
||||||
const auto i = renderer::bgVertexRow(x, y);
|
|
||||||
auto &cbb = ctx.cbbs[z];
|
|
||||||
const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength];
|
|
||||||
const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength];
|
|
||||||
auto &bg = ctx.backgrounds[bgIdx];
|
|
||||||
renderer::setTileBufferObject(
|
|
||||||
static_cast<uint_t>(i * renderer::BgVertexVboRows),
|
|
||||||
static_cast<float>(x),
|
|
||||||
static_cast<float>(y),
|
|
||||||
static_cast<float>(tile),
|
|
||||||
bg.priority,
|
|
||||||
vbo,
|
|
||||||
ebo);
|
|
||||||
cbb.updated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
|
11
src/nostalgia/modules/core/test/CMakeLists.txt
Normal file
11
src/nostalgia/modules/core/test/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
add_executable(
|
||||||
|
NostalgiaCoreTest
|
||||||
|
tests.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
NostalgiaCoreTest
|
||||||
|
NostalgiaCore
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test("[NostalgiaCore] readWriteTileSheet" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/NostalgiaCoreTest readWriteTileSheet)
|
38
src/nostalgia/modules/core/test/tests.cpp
Normal file
38
src/nostalgia/modules/core/test/tests.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef NDEBUG
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <ox/std/error.hpp>
|
||||||
|
#include <ox/mc/mc.hpp>
|
||||||
|
#include <nostalgia/core/core.hpp>
|
||||||
|
|
||||||
|
using namespace nostalgia;
|
||||||
|
|
||||||
|
static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||||
|
{
|
||||||
|
"readWriteTileSheet",
|
||||||
|
[]() -> ox::Error {
|
||||||
|
core::TileSheet in;
|
||||||
|
oxRequire(buff, ox::writeMC(in));
|
||||||
|
oxRequire(out, ox::readMC<core::TileSheet>(buff));
|
||||||
|
oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char **args) {
|
||||||
|
int retval = -1;
|
||||||
|
if (argc > 0) {
|
||||||
|
auto const testName = ox::StringView(args[1]);
|
||||||
|
if (tests.find(testName) != tests.end()) {
|
||||||
|
retval = static_cast<int>(tests[testName]());
|
||||||
|
} else {
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
@ -17,8 +17,8 @@ ox::Error Scene::setupDisplay(core::Context &ctx) const noexcept {
|
|||||||
return OxError(1, "Scene has no palettes");
|
return OxError(1, "Scene has no palettes");
|
||||||
}
|
}
|
||||||
auto const&palette = m_sceneStatic.palettes[0];
|
auto const&palette = m_sceneStatic.palettes[0];
|
||||||
oxReturnError(core::loadBgTileSheet(
|
oxReturnError(core::loadBgTileSheet(ctx, 0, m_sceneStatic.tilesheet));
|
||||||
ctx, 0, m_sceneStatic.tilesheet, palette));
|
oxReturnError(core::loadBgPalette(ctx, palette));
|
||||||
// disable all backgrounds
|
// disable all backgrounds
|
||||||
core::setBgStatus(ctx, 0);
|
core::setBgStatus(ctx, 0);
|
||||||
for (auto layerNo = 0u; auto const&layer : m_sceneStatic.tileMapIdx) {
|
for (auto layerNo = 0u; auto const&layer : m_sceneStatic.tileMapIdx) {
|
||||||
@ -39,10 +39,10 @@ void Scene::setupLayer(
|
|||||||
const auto width = m_sceneStatic.rows[layerNo];
|
const auto width = m_sceneStatic.rows[layerNo];
|
||||||
for (auto const&tile : layer) {
|
for (auto const&tile : layer) {
|
||||||
const auto tile8 = static_cast<uint8_t>(tile);
|
const auto tile8 = static_cast<uint8_t>(tile);
|
||||||
core::setTile(ctx, layerNo, x, y, tile8);
|
core::setBgTile(ctx, layerNo, x, y, tile8);
|
||||||
core::setTile(ctx, layerNo, x + 1, y, tile8 + 1);
|
core::setBgTile(ctx, layerNo, x + 1, y, tile8 + 1);
|
||||||
core::setTile(ctx, layerNo, x, y + 1, tile8 + 2);
|
core::setBgTile(ctx, layerNo, x, y + 1, tile8 + 2);
|
||||||
core::setTile(ctx, layerNo, x + 1, y + 1, tile8 + 3);
|
core::setBgTile(ctx, layerNo, x + 1, y + 1, tile8 + 3);
|
||||||
x += 2;
|
x += 2;
|
||||||
if (x >= width * 2) {
|
if (x >= width * 2) {
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -14,25 +14,6 @@ static int spriteX{};
|
|||||||
static int spriteY{};
|
static int spriteY{};
|
||||||
static bool s_paused = false;
|
static bool s_paused = false;
|
||||||
|
|
||||||
static int sceneUpdateHandler(turbine::Context&) noexcept {
|
|
||||||
constexpr auto sleepTime = 16;
|
|
||||||
if (s_paused) {
|
|
||||||
return sleepTime;
|
|
||||||
}
|
|
||||||
// do stuff
|
|
||||||
return sleepTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sceneKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool down) noexcept {
|
|
||||||
if (down) {
|
|
||||||
if (key == turbine::Key::Alpha_Q) {
|
|
||||||
turbine::requestShutdown(tctx);
|
|
||||||
} else if (key == turbine::Key::Alpha_P) {
|
|
||||||
s_paused = !s_paused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static int testUpdateHandler(turbine::Context &tctx) noexcept {
|
static int testUpdateHandler(turbine::Context &tctx) noexcept {
|
||||||
auto &cctx = *turbine::applicationData<core::Context>(tctx);
|
auto &cctx = *turbine::applicationData<core::Context>(tctx);
|
||||||
@ -82,7 +63,6 @@ static void testKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static ox::Error runTest(turbine::Context &tctx) {
|
static ox::Error runTest(turbine::Context &tctx) {
|
||||||
constexpr ox::FileAddress TileSheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
|
constexpr ox::FileAddress TileSheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
|
||||||
@ -90,17 +70,78 @@ static ox::Error runTest(turbine::Context &tctx) {
|
|||||||
oxRequireM(cctx, core::init(tctx));
|
oxRequireM(cctx, core::init(tctx));
|
||||||
turbine::setApplicationData(tctx, cctx.get());
|
turbine::setApplicationData(tctx, cctx.get());
|
||||||
oxRequire(tsStat, turbine::rom(tctx)->stat(PaletteAddr));
|
oxRequire(tsStat, turbine::rom(tctx)->stat(PaletteAddr));
|
||||||
oxReturnError(core::loadSpriteTileSheet(*cctx, TileSheetAddr, PaletteAddr));
|
oxReturnError(core::loadSpriteTileSheet(*cctx, TileSheetAddr));
|
||||||
|
oxReturnError(core::loadSpritePalette(*cctx, PaletteAddr));
|
||||||
oxReturnError(core::initConsole(*cctx));
|
oxReturnError(core::initConsole(*cctx));
|
||||||
core::puts(*cctx, 10, 9, "DOPENESS!!!");
|
core::puts(*cctx, 10, 9, "DOPENESS!!!");
|
||||||
turbine::setUpdateHandler(tctx, testUpdateHandler);
|
turbine::setUpdateHandler(tctx, testUpdateHandler);
|
||||||
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
||||||
//core::setBgStatus(*cctx, 1, true);
|
|
||||||
//core::setBgStatus(*cctx, 2, true);
|
|
||||||
//core::setBgStatus(*cctx, 3, true);
|
|
||||||
return turbine::run(tctx);
|
return turbine::run(tctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
static ox::Error runTileSheetSetTest(turbine::Context &tctx) {
|
||||||
|
// this should make the screen display 'ABCDB'
|
||||||
|
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
|
||||||
|
oxRequireM(cctx, core::init(tctx));
|
||||||
|
turbine::setApplicationData(tctx, cctx.get());
|
||||||
|
oxRequire(tsStat, turbine::rom(tctx)->stat(PaletteAddr));
|
||||||
|
core::TileSheetSet const set{
|
||||||
|
.bpp = 4,
|
||||||
|
.entries = {
|
||||||
|
{ .tilesheet = ox::StringLiteral("/TileSheets/Chester.ng"), .sections{{.begin = 0, .tiles = 1}} },
|
||||||
|
{ .tilesheet = ox::StringLiteral("/TileSheets/AB.ng"), .sections{{.begin = 0, .tiles = 2}} },
|
||||||
|
{ .tilesheet = ox::StringLiteral("/TileSheets/CD.ng"), .sections{{.begin = 0, .tiles = 2}} },
|
||||||
|
{ .tilesheet = ox::StringLiteral("/TileSheets/AB.ng"), .sections{{.begin = 1, .tiles = 1}} },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
oxReturnError(core::loadBgTileSheet(*cctx, 0, set));
|
||||||
|
oxReturnError(core::loadSpriteTileSheet(*cctx, set));
|
||||||
|
oxReturnError(core::loadBgPalette(*cctx, PaletteAddr));
|
||||||
|
oxReturnError(core::loadSpritePalette(*cctx, PaletteAddr));
|
||||||
|
core::setBgStatus(*cctx, 0, true);
|
||||||
|
core::setBgTile(*cctx, 0, 10, 9, 1);
|
||||||
|
core::setBgTile(*cctx, 0, 11, 9, 2);
|
||||||
|
core::setBgTile(*cctx, 0, 13, 9, 4);
|
||||||
|
core::setSprite(*cctx, 16, {
|
||||||
|
.enabled = true,
|
||||||
|
.x = 12 * 8,
|
||||||
|
.y = 9 * 8,
|
||||||
|
.tileIdx = 3,
|
||||||
|
.bpp = static_cast<unsigned>(set.bpp),
|
||||||
|
});
|
||||||
|
core::setSprite(*cctx, 17, {
|
||||||
|
.enabled = true,
|
||||||
|
.x = 14 * 8,
|
||||||
|
.y = 9 * 8,
|
||||||
|
.tileIdx = 5,
|
||||||
|
.bpp = static_cast<unsigned>(set.bpp),
|
||||||
|
});
|
||||||
|
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
||||||
|
return turbine::run(tctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int sceneUpdateHandler(turbine::Context&) noexcept {
|
||||||
|
constexpr auto sleepTime = 16;
|
||||||
|
if (s_paused) {
|
||||||
|
return sleepTime;
|
||||||
|
}
|
||||||
|
// do stuff
|
||||||
|
return sleepTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sceneKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool down) noexcept {
|
||||||
|
if (down) {
|
||||||
|
if (key == turbine::Key::Alpha_Q) {
|
||||||
|
turbine::requestShutdown(tctx);
|
||||||
|
} else if (key == turbine::Key::Alpha_P) {
|
||||||
|
s_paused = !s_paused;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static ox::Error runScene(turbine::Context &tctx) {
|
static ox::Error runScene(turbine::Context &tctx) {
|
||||||
constexpr ox::FileAddress SceneAddr = ox::StringLiteral("/Scenes/Chester.nscn");
|
constexpr ox::FileAddress SceneAddr = ox::StringLiteral("/Scenes/Chester.nscn");
|
||||||
@ -115,5 +156,5 @@ static ox::Error runScene(turbine::Context &tctx) {
|
|||||||
|
|
||||||
ox::Error run(ox::UniquePtr<ox::FileSystem> &&fs) noexcept {
|
ox::Error run(ox::UniquePtr<ox::FileSystem> &&fs) noexcept {
|
||||||
oxRequireM(tctx, turbine::init(std::move(fs), "Nostalgia"));
|
oxRequireM(tctx, turbine::init(std::move(fs), "Nostalgia"));
|
||||||
return runTest(*tctx);
|
return runTileSheetSetTest(*tctx);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
add_subdirectory(applib)
|
add_subdirectory(applib)
|
||||||
add_subdirectory(keel)
|
add_subdirectory(keel)
|
||||||
add_subdirectory(turbine)
|
add_subdirectory(turbine)
|
||||||
if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
if(${OLYMPIC_BUILD_STUDIO})
|
||||||
add_subdirectory(studio)
|
add_subdirectory(studio)
|
||||||
endif()
|
endif()
|
||||||
|
@ -20,6 +20,8 @@ NewMenu::NewMenu() noexcept {
|
|||||||
void NewMenu::open() noexcept {
|
void NewMenu::open() noexcept {
|
||||||
m_stage = Stage::Opening;
|
m_stage = Stage::Opening;
|
||||||
m_selectedType = 0;
|
m_selectedType = 0;
|
||||||
|
m_itemName = "";
|
||||||
|
m_typeName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewMenu::close() noexcept {
|
void NewMenu::close() noexcept {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user