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_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")
|
||||
|
||||
if(BUILDCORE_TARGET STREQUAL "gba")
|
||||
set(NOSTALGIA_BUILD_STUDIO OFF)
|
||||
set(OLYMPIC_BUILD_STUDIO OFF)
|
||||
set(TURBINE_BUILD_TYPE "GBA")
|
||||
include(deps/gbabuildcore/base.cmake)
|
||||
else()
|
||||
|
@ -161,16 +161,16 @@ template<typename T>
|
||||
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
|
||||
oxReturnError(h->template setTypeInfo<FileAddress>());
|
||||
if constexpr(T::opType() == OpType::Reflect) {
|
||||
int8_t type = 0;
|
||||
int8_t type = -1;
|
||||
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) {
|
||||
auto type = static_cast<int8_t>(fa->m_type);
|
||||
oxReturnError(h->field("type", &type));
|
||||
fa->m_type = static_cast<FileAddressType>(type);
|
||||
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||
} else if constexpr(T::opType() == OpType::Write) {
|
||||
auto type = static_cast<int8_t>(fa->m_type);
|
||||
auto const type = static_cast<int8_t>(fa->m_type);
|
||||
oxReturnError(h->field("type", &type));
|
||||
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||
}
|
||||
|
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>
|
||||
[[nodiscard]]
|
||||
constexpr McInt encodeInteger(I input) noexcept {
|
||||
constexpr McInt encodeInteger(I pInput) noexcept {
|
||||
auto const input = ox::ResizedInt_t<I, 64>{pInput};
|
||||
McInt out;
|
||||
const auto inputNegative = is_signed_v<I> && input < 0;
|
||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||
// overflow concerns
|
||||
uint64_t val = 0;
|
||||
ox_memcpy(&val, &input, sizeof(I));
|
||||
ox_memcpy(&val, &input, sizeof(input));
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
@ -93,7 +94,7 @@ constexpr McInt encodeInteger(I input) noexcept {
|
||||
}
|
||||
if (bytes == 9) {
|
||||
out.data[0] = bytesIndicator;
|
||||
ox_memcpy(&out.data[1], &leVal, sizeof(I));
|
||||
ox_memcpy(&out.data[1], &leVal, 8);
|
||||
if (inputNegative) {
|
||||
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/std/buffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/optional.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
@ -33,15 +34,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
FieldBitmapReader<Reader> m_fieldPresence;
|
||||
std::size_t m_fields = 0;
|
||||
std::size_t m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
ox::Optional<int> m_unionIdx;
|
||||
Reader &m_reader;
|
||||
MetalClawReaderTemplate<Reader> *m_parent = nullptr;
|
||||
|
||||
public:
|
||||
explicit constexpr MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
int unionIdx = -1,
|
||||
MetalClawReaderTemplate<Reader> *parent = nullptr) noexcept;
|
||||
ox::Optional<int> const&unionIdx = {}) noexcept;
|
||||
|
||||
constexpr ~MetalClawReaderTemplate() noexcept;
|
||||
|
||||
@ -108,7 +107,7 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[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.
|
||||
@ -136,12 +135,10 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
int unionIdx,
|
||||
MetalClawReaderTemplate *parent) noexcept:
|
||||
ox::Optional<int> const&unionIdx) noexcept:
|
||||
m_fieldPresence(reader),
|
||||
m_unionIdx(unionIdx),
|
||||
m_reader(reader),
|
||||
m_parent(parent) {
|
||||
m_reader(reader) {
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
@ -194,7 +191,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *va
|
||||
|
||||
template<Reader_c Reader>
|
||||
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));
|
||||
*val = result.value;
|
||||
oxReturnError(result);
|
||||
@ -206,7 +203,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
|
||||
// array handler
|
||||
template<Reader_c Reader>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -232,7 +229,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *v
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
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))) {
|
||||
// read the length
|
||||
oxRequire(g, m_reader.tellg());
|
||||
@ -264,19 +261,19 @@ template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
|
||||
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
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
oxRequire(len, arrayLength(name, false));
|
||||
val->resize(len);
|
||||
oxReturnError(ox::resizeVector(*val, len));
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
val->resize(0);
|
||||
oxReturnError(ox::resizeVector(*val, 0));
|
||||
}
|
||||
++m_field;
|
||||
return {};
|
||||
} 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
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
oxRequire(len, arrayLength(name, false));
|
||||
@ -289,7 +286,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
||||
++m_field;
|
||||
return {};
|
||||
} 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))) {
|
||||
auto reader = child("");
|
||||
oxReturnError(model(reader.interface(), val));
|
||||
@ -303,20 +300,20 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
||||
template<Reader_c Reader>
|
||||
template<typename U, bool force>
|
||||
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))) {
|
||||
auto reader = child("", val.idx());
|
||||
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
|
||||
oxReturnError(model(reader.interface(), val.get()));
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<std::size_t SmallStringSize>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -382,7 +379,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
||||
|
||||
template<Reader_c Reader>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -410,7 +407,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
||||
|
||||
template<Reader_c Reader>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -427,7 +424,7 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const
|
||||
|
||||
template<Reader_c Reader>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -442,7 +439,7 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(con
|
||||
template<Reader_c Reader>
|
||||
template<typename I>
|
||||
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))) {
|
||||
std::size_t bytesRead = 0;
|
||||
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<typename T, typename CB>
|
||||
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))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
@ -491,8 +488,10 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(const char*, int unionIdx) noexcept {
|
||||
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx, this);
|
||||
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
|
||||
const char*,
|
||||
ox::Optional<int> unionIdx) noexcept {
|
||||
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
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(-2)), "Decode of -2 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/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/optional.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/units.hpp>
|
||||
@ -34,12 +35,12 @@ class MetalClawWriter {
|
||||
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
|
||||
FieldBitmap m_fieldPresence;
|
||||
int m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
ox::Optional<int> m_unionIdx;
|
||||
std::size_t m_writerBeginP{};
|
||||
Writer &m_writer;
|
||||
|
||||
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;
|
||||
|
||||
@ -114,7 +115,7 @@ class MetalClawWriter {
|
||||
private:
|
||||
constexpr Error appendInteger(Integer_c auto val) noexcept {
|
||||
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);
|
||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
|
||||
fieldSet = true;
|
||||
@ -130,7 +131,7 @@ extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
|
||||
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
|
||||
|
||||
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_unionIdx(unionIdx),
|
||||
m_writerBeginP(writer.tellp()),
|
||||
@ -179,7 +180,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val)
|
||||
|
||||
template<Writer_c Writer>
|
||||
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));
|
||||
}
|
||||
++m_field;
|
||||
@ -190,7 +191,7 @@ template<Writer_c Writer>
|
||||
template<std::size_t SmallStringSize>
|
||||
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto strLen = mc::encodeInteger(val->len());
|
||||
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>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
|
||||
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;
|
||||
// write the length
|
||||
const auto strLenBuff = mc::encodeInteger(strLen);
|
||||
@ -239,7 +240,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const ch
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
|
||||
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
|
||||
const auto strLenBuff = mc::encodeInteger(strLen);
|
||||
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());
|
||||
} else {
|
||||
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);
|
||||
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
|
||||
oxReturnError(model(&handler, val));
|
||||
oxReturnError(writer.finalize());
|
||||
fieldSet = true;
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,35 +278,37 @@ template<Writer_c Writer>
|
||||
template<typename U, bool force>
|
||||
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
MetalClawWriter<Writer> writer(m_writer, val.idx());
|
||||
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
auto const writeIdx = m_writer.tellp();
|
||||
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
|
||||
ModelHandlerInterface handler{&writer};
|
||||
oxReturnError(model(&handler, val.get()));
|
||||
oxReturnError(writer.finalize());
|
||||
fieldSet = true;
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
|
||||
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
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
|
||||
auto const writeIdx = m_writer.tellp();
|
||||
MetalClawWriter<Writer> writer(m_writer);
|
||||
ModelHandlerInterface handler{&writer};
|
||||
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
// 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(writer.finalize());
|
||||
fieldSet = true;
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
@ -317,7 +321,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
|
||||
const auto &keys = val->keys();
|
||||
const auto len = keys.size();
|
||||
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
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
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);
|
||||
};
|
||||
// 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];
|
||||
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 {
|
||||
return m_handler;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename Handler, ox::OpType opType_v = Handler::opType()>
|
||||
@ -215,7 +214,16 @@ class ModelHandlerBase {
|
||||
static constexpr ox::OpType opType() noexcept {
|
||||
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 {
|
||||
private:
|
||||
Vector<ModelValue> m_vec;
|
||||
ModelValue m_templateValue;
|
||||
const DescriptorType *m_type = nullptr;
|
||||
int m_typeSubscriptLevels = 0;
|
||||
String m_typeName;
|
||||
int m_typeVersion = 0;
|
||||
|
||||
@ -227,14 +228,15 @@ class ModelValueVector {
|
||||
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();
|
||||
m_vec.resize(sz);
|
||||
if (sz > oldSz) {
|
||||
for (auto i = oldSz; i < sz; ++i) {
|
||||
m_vec[i] = m_templateValue;
|
||||
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@ -248,7 +250,9 @@ class ModelValueVector {
|
||||
}
|
||||
|
||||
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
|
||||
return m_templateValue.setType(type, subscriptLevels);
|
||||
m_type = type;
|
||||
m_typeSubscriptLevels = subscriptLevels;
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@ -1089,14 +1093,12 @@ constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noex
|
||||
for (auto &v : other.m_vec) {
|
||||
m_vec.emplace_back(v);
|
||||
}
|
||||
m_templateValue = other.m_templateValue;
|
||||
m_typeName = other.m_typeName;
|
||||
m_typeVersion = other.m_typeVersion;
|
||||
}
|
||||
|
||||
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
|
||||
m_vec = std::move(other.m_vec);
|
||||
m_templateValue = std::move(other.m_templateValue);
|
||||
m_typeName = std::move(other.m_typeName);
|
||||
m_typeVersion = other.m_typeVersion;
|
||||
}
|
||||
@ -1108,7 +1110,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(const ModelValueVector &
|
||||
for (auto &v : other.m_vec) {
|
||||
m_vec.emplace_back(v);
|
||||
}
|
||||
m_templateValue = other.m_templateValue;
|
||||
m_typeName = other.m_typeName;
|
||||
m_typeVersion = other.m_typeVersion;
|
||||
return *this;
|
||||
@ -1119,7 +1120,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other
|
||||
return *this;
|
||||
}
|
||||
m_vec = std::move(other.m_vec);
|
||||
m_templateValue = std::move(other.m_templateValue);
|
||||
m_typeName = std::move(other.m_typeName);
|
||||
m_typeVersion = other.m_typeVersion;
|
||||
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>) {
|
||||
const auto &srcVal = value(key);
|
||||
const auto srcSize = srcVal.size();
|
||||
val->resize(srcSize);
|
||||
oxReturnError(ox::resizeVector(*val, srcSize));
|
||||
err = field(key, val->data(), val->size());
|
||||
} else if constexpr(isArray_v<T>) {
|
||||
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;
|
||||
|
||||
template<typename ...Args>
|
||||
explicit constexpr Optional(Args &&... args);
|
||||
explicit constexpr Optional(ox::in_place_t, Args &&... args);
|
||||
|
||||
constexpr Optional(const Optional &other) {
|
||||
if (other.m_ptr) {
|
||||
@ -65,19 +65,19 @@ class Optional {
|
||||
}
|
||||
|
||||
constexpr T &operator*() & noexcept {
|
||||
return m_ptr;
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
constexpr const T &operator*() const & noexcept {
|
||||
return m_ptr;
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
constexpr T &&operator*() && noexcept {
|
||||
return m_ptr;
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
constexpr const T &&operator*() const && noexcept {
|
||||
return m_ptr;
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
constexpr T *operator->() noexcept {
|
||||
@ -163,7 +163,7 @@ class Optional {
|
||||
|
||||
template<typename T, std::size_t buffSize>
|
||||
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)...);
|
||||
}
|
||||
|
||||
|
6
deps/ox/src/ox/std/utility.hpp
vendored
6
deps/ox/src/ox/std/utility.hpp
vendored
@ -12,6 +12,12 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
struct in_place_t {
|
||||
explicit constexpr in_place_t() = default;
|
||||
};
|
||||
|
||||
inline constexpr ox::in_place_t in_place;
|
||||
|
||||
template<class T>
|
||||
constexpr T &&forward(remove_reference_t<T> &t) noexcept {
|
||||
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)
|
||||
|
||||
[[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);
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ inline auto ®BgCtl(uintptr_t bgIdx) noexcept {
|
||||
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
|
||||
|
||||
[[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);
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ inline volatile auto ®BgHofs(auto bgIdx) noexcept {
|
||||
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
|
||||
|
||||
[[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);
|
||||
}
|
||||
|
||||
|
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 attr2 = 0;
|
||||
uint16_t idx = 0;
|
||||
|
||||
};
|
||||
|
||||
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept;
|
||||
|
||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) 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 {
|
||||
|
||||
inline auto bgSetSbb(volatile BgCtl *bgCtl, unsigned sbb) noexcept {
|
||||
*bgCtl = static_cast<BgCtl>(*bgCtl & ~0b11111'0000'0000u) | static_cast<BgCtl>(sbb << 8);
|
||||
inline auto bgSetSbb(volatile BgCtl &bgCtl, unsigned sbb) noexcept {
|
||||
bgCtl = static_cast<BgCtl>(bgCtl & ~0b11111'0000'0000u) | static_cast<BgCtl>(sbb << 8);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
@ -17,14 +17,9 @@ constexpr unsigned bgPri(BgCtl bgCtl) noexcept {
|
||||
return bgCtl & 1;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgPri(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgPri(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetPri(volatile BgCtl *bgCtl, unsigned pri) noexcept {
|
||||
inline auto bgSetPri(volatile BgCtl &bgCtl, unsigned pri) noexcept {
|
||||
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]]
|
||||
@ -32,17 +27,12 @@ constexpr unsigned bgBpp(BgCtl bgCtl) noexcept {
|
||||
return ((bgCtl >> 7) & 1) ? 8 : 4;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgBpp(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgBpp(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetBpp(volatile BgCtl *bgCtl, unsigned bpp) noexcept {
|
||||
inline auto bgSetBpp(volatile BgCtl &bgCtl, unsigned bpp) noexcept {
|
||||
constexpr auto Bpp8 = 1 << 7;
|
||||
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 {
|
||||
*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;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline auto bgCbb(const volatile BgCtl *bgCtl) noexcept {
|
||||
return bgCbb(*bgCtl);
|
||||
}
|
||||
|
||||
inline auto bgSetCbb(volatile BgCtl *bgCtl, unsigned cbb) noexcept {
|
||||
inline auto bgSetCbb(volatile BgCtl &bgCtl, unsigned cbb) noexcept {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
static volatile uint16_t g_spriteUpdates = 0;
|
||||
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
|
||||
|
||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
||||
// block until g_spriteUpdates is less than buffer len
|
||||
if (g_spriteUpdates >= g_spriteBuffer.size()) [[unlikely]] {
|
||||
teagba_vblankintrwait();
|
||||
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
|
||||
return g_spriteBuffer[i];
|
||||
}
|
||||
|
||||
void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
|
||||
const auto ie = REG_IE; // 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[updateCnt] = upd;
|
||||
g_spriteUpdates = updateCnt + 1;
|
||||
g_spriteBuffer[upd.idx] = upd;
|
||||
REG_IE = ie; // enable vblank interrupt handler
|
||||
}
|
||||
|
||||
void applySpriteUpdates() noexcept {
|
||||
// copy g_spriteUpdates to allow it to use a register instead of reading
|
||||
// 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];
|
||||
for (auto const&oa : g_spriteBuffer) {
|
||||
MEM_OAM[oa.idx] = std::bit_cast<uint64_t>(oa);
|
||||
}
|
||||
g_spriteUpdates = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ install(
|
||||
include/nostalgia/modules
|
||||
)
|
||||
|
||||
if(${OLYMPIC_BUILD_STUDIO})
|
||||
# Studio
|
||||
if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
||||
add_library(
|
||||
@ -42,6 +43,7 @@ if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
||||
include/nostalgia/modules
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(NostalgiaProfile INTERFACE)
|
||||
target_compile_definitions(
|
||||
|
@ -1,4 +1,7 @@
|
||||
add_subdirectory(src)
|
||||
if(NOT TURBINE_BUILD_TYPE STREQUAL "GBA")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
|
@ -13,9 +13,9 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
extern ox::Array<char, 128> charMap;
|
||||
|
||||
struct Sprite {
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Sprite";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
bool enabled = false;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
@ -23,6 +23,7 @@ struct Sprite {
|
||||
unsigned spriteShape = 0;
|
||||
unsigned spriteSize = 0;
|
||||
unsigned flipX = 0;
|
||||
unsigned bpp = 0;
|
||||
/**
|
||||
* Valid priorities: 0-3
|
||||
*/
|
||||
@ -38,14 +39,89 @@ oxModelBegin(Sprite)
|
||||
oxModelField(spriteShape)
|
||||
oxModelField(spriteSize)
|
||||
oxModelField(flipX)
|
||||
oxModelField(bpp)
|
||||
oxModelField(priority)
|
||||
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]]
|
||||
uint8_t bgStatus(Context &ctx) noexcept;
|
||||
|
||||
void setBgStatus(Context &ctx, uint32_t status) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool bgStatus(Context &ctx, unsigned bg) 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;
|
||||
|
||||
/**
|
||||
* @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 showSprite(Context &ctx, unsigned) 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 {
|
||||
|
@ -8,10 +8,15 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
struct BgCbbData {
|
||||
unsigned bpp = 4;
|
||||
};
|
||||
|
||||
class Context {
|
||||
|
||||
public:
|
||||
turbine::Context &turbineCtx;
|
||||
ox::Array<BgCbbData, 4> cbbData;
|
||||
|
||||
explicit Context(turbine::Context &tctx) noexcept;
|
||||
Context(Context &other) noexcept = delete;
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <teagba/gfx.hpp>
|
||||
#include <teagba/registers.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include <nostalgia/core/color.hpp>
|
||||
@ -22,13 +21,9 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
struct BgCbbData {
|
||||
unsigned bpp = 4;
|
||||
};
|
||||
static ox::Array<BgCbbData, 4> g_cbbData;
|
||||
|
||||
constexpr auto GbaTileColumns = 32;
|
||||
constexpr auto GbaTileRows = 32;
|
||||
constexpr auto SpriteCount = 128;
|
||||
|
||||
struct GbaPaletteTarget {
|
||||
static constexpr auto TypeName = Palette::TypeName;
|
||||
@ -39,25 +34,105 @@ struct GbaPaletteTarget {
|
||||
struct GbaTileMapTarget {
|
||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||
BgCbbData *cbbData = nullptr;
|
||||
unsigned &bpp;
|
||||
ox::FileAddress defaultPalette;
|
||||
GbaPaletteTarget pal;
|
||||
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 {
|
||||
oxReturnError(io->template setTypeInfo<Palette>());
|
||||
if (t->palette) {
|
||||
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
|
||||
t->palette[i] = *c;
|
||||
return OxError(0);
|
||||
return ox::Error{};
|
||||
};
|
||||
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 {
|
||||
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
||||
oxReturnError(io->field("bpp", &t->cbbData->bpp));
|
||||
oxReturnError(io->field("bpp", &t->bpp));
|
||||
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;
|
||||
const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t*tile) {
|
||||
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
|
||||
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 {
|
||||
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 {};
|
||||
}
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
void setBgCbb(Context&, unsigned bgIdx, unsigned cbb) noexcept {
|
||||
void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept {
|
||||
auto &bgCtl = regBgCtl(bgIdx);
|
||||
const auto &cbbData = g_cbbData[cbb];
|
||||
teagba::bgSetBpp(&bgCtl, cbbData.bpp);
|
||||
teagba::bgSetCbb(&bgCtl, cbb);
|
||||
const auto &cbbData = ctx.cbbData[cbb];
|
||||
teagba::bgSetBpp(bgCtl, cbbData.bpp);
|
||||
teagba::bgSetCbb(bgCtl, cbb);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||
teagba::addSpriteUpdate({
|
||||
@ -222,7 +334,6 @@ void hideSprite(Context&, unsigned idx) noexcept {
|
||||
});
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
void showSprite(Context&, unsigned idx) noexcept {
|
||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||
teagba::addSpriteUpdate({
|
||||
@ -233,20 +344,27 @@ void showSprite(Context&, unsigned idx) noexcept {
|
||||
|
||||
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||
uint16_t const eightBpp = s.bpp == 8;
|
||||
teagba::addSpriteUpdate({
|
||||
.attr0 = static_cast<uint16_t>(
|
||||
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
||||
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||
| (static_cast<uint16_t>(eightBpp) << 13)
|
||||
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
||||
.attr1 = static_cast<uint16_t>(
|
||||
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
||||
| (static_cast<uint16_t>(s.flipX) << 12)
|
||||
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
||||
.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)),
|
||||
.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(initConsole(*ctx));
|
||||
setBgStatus(*ctx, 0, true);
|
||||
clearTileLayer(*ctx, 0);
|
||||
clearBg(*ctx, 0);
|
||||
ox::BString<23> serr = "Error code: ";
|
||||
serr += static_cast<int64_t>(err);
|
||||
puts(*ctx, 32 + 1, 1, "SADNESS...");
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace nostalgia::core {
|
||||
|
||||
// map ASCII values to the nostalgia charset
|
||||
ox::Array<char, 128> charMap = {
|
||||
constexpr ox::Array<char, 128> charMap = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@ -137,4 +137,29 @@ ox::Array<char, 128> charMap = {
|
||||
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 renderer {
|
||||
|
||||
constexpr auto Scale = 1;
|
||||
constexpr auto PriorityScale = 0.01f;
|
||||
|
||||
namespace renderer {
|
||||
|
||||
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
|
||||
|
||||
void Drawer::draw(turbine::Context &tctx) noexcept {
|
||||
@ -98,7 +98,7 @@ constexpr ox::CStringView spritefshadTmpl = R"glsl(
|
||||
if (outColor.a == 0) {
|
||||
discard;
|
||||
}
|
||||
})glsl";;
|
||||
})glsl";
|
||||
|
||||
[[nodiscard]]
|
||||
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(
|
||||
GLuint shaderPgrm,
|
||||
Palette const&pal,
|
||||
bool firstIsTransparent) noexcept {
|
||||
Palette const&pal) noexcept {
|
||||
static constexpr std::size_t ColorCnt = 256;
|
||||
ox::Array<GLfloat, ColorCnt * 4> palette{};
|
||||
for (auto i = 0u; const auto c : pal.colors) {
|
||||
@ -348,41 +347,13 @@ static void loadPalette(
|
||||
palette[i++] = bluef(c);
|
||||
palette[i++] = 255;
|
||||
}
|
||||
if (firstIsTransparent) {
|
||||
// make first color transparent
|
||||
palette[3] = 0;
|
||||
}
|
||||
glUseProgram(shaderPgrm);
|
||||
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
|
||||
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(
|
||||
Context &ctx,
|
||||
uint_t const idx,
|
||||
@ -493,8 +464,7 @@ struct TileSheetData {
|
||||
}
|
||||
};
|
||||
|
||||
static ox::Result<TileSheetData> loadTileSheet(
|
||||
Context &ctx,
|
||||
static ox::Result<TileSheetData> normalizeTileSheet(
|
||||
CompactTileSheet const&tilesheet) noexcept {
|
||||
const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
|
||||
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
|
||||
@ -513,71 +483,131 @@ static ox::Result<TileSheetData> loadTileSheet(
|
||||
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
|
||||
}
|
||||
}
|
||||
renderer::loadSpriteTexture(ctx, pixels.data(), 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(
|
||||
Context &ctx,
|
||||
uint_t cbb,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::FileAddress const&paletteAddr) noexcept {
|
||||
bool loadDefaultPalette) noexcept {
|
||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
||||
oxRequire(tsd, loadTileSheet(ctx, *tilesheet).to([](TileSheetData const&t) -> TileSheetData {
|
||||
return {
|
||||
.pixels = resizeTileSheetData(t.pixels, t.size(), Scale),
|
||||
.width = t.width * Scale,
|
||||
.height = t.height * Scale,
|
||||
};
|
||||
}));
|
||||
renderer::loadBgTexture(ctx, cbb, tsd.pixels.data(), tsd.width, tsd.height);
|
||||
renderer::loadBgPalette(ctx, *palette);
|
||||
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height);
|
||||
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||
if (loadDefaultPalette) {
|
||||
oxReturnError(loadBgPalette(ctx, tilesheet->defaultPalette));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::FileAddress const&paletteAddr) noexcept {
|
||||
bool loadDefaultPalette) noexcept {
|
||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
oxRequire(palette, readObj<Palette>(kctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
||||
oxRequire(tsd, loadTileSheet(ctx, *tilesheet));
|
||||
renderer::loadSpriteTexture(ctx, tsd.pixels.data(), tsd.width, tsd.height);
|
||||
renderer::loadSpritePalette(ctx, *palette);
|
||||
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
|
||||
ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||
if (loadDefaultPalette) {
|
||||
oxReturnError(loadSpritePalette(ctx, tilesheet->defaultPalette));
|
||||
}
|
||||
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);
|
||||
setBgCbb(ctx, 0, 0);
|
||||
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
TileSheetSet const&set) noexcept {
|
||||
oxRequire(setTsd, buildSetTsd(ctx, set));
|
||||
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
|
||||
return {};
|
||||
}
|
||||
|
||||
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
|
||||
const auto col = static_cast<uint_t>(column);
|
||||
for (auto i = 0u; i < str.bytes(); ++i) {
|
||||
setTile(
|
||||
ctx,
|
||||
0,
|
||||
static_cast<int>(col + i),
|
||||
row,
|
||||
static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
|
||||
}
|
||||
}
|
||||
|
||||
void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept {
|
||||
void setBgTile(
|
||||
Context &ctx,
|
||||
uint_t bgIdx,
|
||||
int column,
|
||||
int row,
|
||||
uint8_t tile) noexcept {
|
||||
oxTracef(
|
||||
"nostalgia.core.gfx.setBgTile",
|
||||
"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];
|
||||
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 {
|
||||
auto &bg = ctx.backgrounds[bgIdx];
|
||||
bg.priority = static_cast<float>(priority & 0b11);
|
||||
void clearBg(Context &ctx, uint_t bgIdx) noexcept {
|
||||
auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
|
||||
initBackgroundBufferObjects(cbb);
|
||||
cbb.updated = true;
|
||||
auto &bg = ctx.backgrounds[static_cast<std::size_t>(bgIdx)];
|
||||
bg.priority = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
auto &cbb = ctx.cbbs[static_cast<std::size_t>(bgIdx)];
|
||||
initBackgroundBufferObjects(cbb);
|
||||
cbb.updated = true;
|
||||
auto &bg = ctx.backgrounds[static_cast<std::size_t>(bgIdx)];
|
||||
bg.priority = 0;
|
||||
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept {
|
||||
auto &bg = ctx.backgrounds[bgIdx];
|
||||
bg.priority = static_cast<float>(priority & 0b11);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void setTile(
|
||||
Context &ctx,
|
||||
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;
|
||||
uint_t spriteCount(Context &ctx) noexcept {
|
||||
return ctx.spriteCount;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
auto const&palette = m_sceneStatic.palettes[0];
|
||||
oxReturnError(core::loadBgTileSheet(
|
||||
ctx, 0, m_sceneStatic.tilesheet, palette));
|
||||
oxReturnError(core::loadBgTileSheet(ctx, 0, m_sceneStatic.tilesheet));
|
||||
oxReturnError(core::loadBgPalette(ctx, palette));
|
||||
// disable all backgrounds
|
||||
core::setBgStatus(ctx, 0);
|
||||
for (auto layerNo = 0u; auto const&layer : m_sceneStatic.tileMapIdx) {
|
||||
@ -39,10 +39,10 @@ void Scene::setupLayer(
|
||||
const auto width = m_sceneStatic.rows[layerNo];
|
||||
for (auto const&tile : layer) {
|
||||
const auto tile8 = static_cast<uint8_t>(tile);
|
||||
core::setTile(ctx, layerNo, x, y, tile8);
|
||||
core::setTile(ctx, layerNo, x + 1, y, tile8 + 1);
|
||||
core::setTile(ctx, layerNo, x, y + 1, tile8 + 2);
|
||||
core::setTile(ctx, layerNo, x + 1, y + 1, tile8 + 3);
|
||||
core::setBgTile(ctx, layerNo, x, y, tile8);
|
||||
core::setBgTile(ctx, layerNo, x + 1, y, tile8 + 1);
|
||||
core::setBgTile(ctx, layerNo, x, y + 1, tile8 + 2);
|
||||
core::setBgTile(ctx, layerNo, x + 1, y + 1, tile8 + 3);
|
||||
x += 2;
|
||||
if (x >= width * 2) {
|
||||
x = 0;
|
||||
|
@ -14,25 +14,6 @@ static int spriteX{};
|
||||
static int spriteY{};
|
||||
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]]
|
||||
static int testUpdateHandler(turbine::Context &tctx) noexcept {
|
||||
auto &cctx = *turbine::applicationData<core::Context>(tctx);
|
||||
@ -82,7 +63,6 @@ static void testKeyEventHandler(turbine::Context &tctx, turbine::Key key, bool d
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[[maybe_unused]]
|
||||
static ox::Error runTest(turbine::Context &tctx) {
|
||||
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));
|
||||
turbine::setApplicationData(tctx, cctx.get());
|
||||
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));
|
||||
core::puts(*cctx, 10, 9, "DOPENESS!!!");
|
||||
turbine::setUpdateHandler(tctx, testUpdateHandler);
|
||||
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
||||
//core::setBgStatus(*cctx, 1, true);
|
||||
//core::setBgStatus(*cctx, 2, true);
|
||||
//core::setBgStatus(*cctx, 3, true);
|
||||
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]]
|
||||
static ox::Error runScene(turbine::Context &tctx) {
|
||||
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 {
|
||||
oxRequireM(tctx, turbine::init(std::move(fs), "Nostalgia"));
|
||||
return runTest(*tctx);
|
||||
return runTileSheetSetTest(*tctx);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
add_subdirectory(applib)
|
||||
add_subdirectory(keel)
|
||||
add_subdirectory(turbine)
|
||||
if(TURBINE_BUILD_TYPE STREQUAL "Native")
|
||||
if(${OLYMPIC_BUILD_STUDIO})
|
||||
add_subdirectory(studio)
|
||||
endif()
|
||||
|
@ -20,6 +20,8 @@ NewMenu::NewMenu() noexcept {
|
||||
void NewMenu::open() noexcept {
|
||||
m_stage = Stage::Opening;
|
||||
m_selectedType = 0;
|
||||
m_itemName = "";
|
||||
m_typeName = "";
|
||||
}
|
||||
|
||||
void NewMenu::close() noexcept {
|
||||
|
Loading…
x
Reference in New Issue
Block a user