mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
sm64 collision factory
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include "factories/Vec3sFactory.h"
|
||||
|
||||
#include "factories/sm64/AnimationFactory.h"
|
||||
#include "factories/sm64/CollisionFactory.h"
|
||||
#include "factories/sm64/DialogFactory.h"
|
||||
#include "factories/sm64/DictionaryFactory.h"
|
||||
#include "factories/sm64/TextFactory.h"
|
||||
@@ -86,6 +87,7 @@ void Companion::Init(const ExportType type) {
|
||||
this->RegisterFactory("SM64:TEXT", std::make_shared<SM64::TextFactory>());
|
||||
this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>());
|
||||
this->RegisterFactory("SM64:ANIM", std::make_shared<SM64::AnimationFactory>());
|
||||
this->RegisterFactory("SM64:COLLISION", std::make_shared<SM64::CollisionFactory>());
|
||||
this->RegisterFactory("SM64:GEO_LAYOUT", std::make_shared<SM64::GeoLayoutFactory>());
|
||||
|
||||
// MK64 specific
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
#include "CollisionFactory.h"
|
||||
#include "Companion.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#define FORMAT_HEX(x) std::hex << x << std::dec
|
||||
|
||||
std::unordered_map<int16_t, SpecialPresetTypes> specialPresetMap = {
|
||||
{ 0x00, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x01, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x02, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x03, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x04, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x05, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x06, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x07, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x08, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x09, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x0A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x0B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x0C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x0D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x0E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x0F, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x10, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x11, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x12, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x13, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x14, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x15, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x16, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x17, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x18, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x19, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x1A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x1B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x1C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x1D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x1E, SpecialPresetTypes::SPTYPE_UNKNOWN },
|
||||
{ 0x1F, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x20, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x21, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x22, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x23, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x24, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x25, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x26, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x27, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x28, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x65, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x66, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x67, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x68, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x69, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6A, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6B, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6C, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6D, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x6F, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x70, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x71, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x72, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x73, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x74, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x75, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x76, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x77, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x78, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x79, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x7A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x7B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x7C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x7D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
{ 0x89, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x7E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x7F, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x80, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x81, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x82, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
|
||||
{ 0x8A, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
|
||||
{ 0x8B, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
|
||||
{ 0x8C, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
|
||||
{ 0x8D, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
|
||||
{ 0x88, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0x83, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0x84, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0x85, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0x86, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0x87, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
|
||||
{ 0xFF, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
|
||||
};
|
||||
|
||||
ExportResult SM64::CollisionCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
|
||||
auto symbol = GetSafeNode(node, "symbol", entryName);
|
||||
auto offset = GetSafeNode<uint32_t>(node, "offset");
|
||||
const auto collision = std::static_pointer_cast<Collision>(data).get();
|
||||
uint32_t count = 0;
|
||||
|
||||
write << "Collision " << symbol << "[] = {\n";
|
||||
|
||||
write << fourSpaceTab;
|
||||
|
||||
write << "COL_INIT(),\n";
|
||||
++count;
|
||||
|
||||
// Vertices
|
||||
if (collision->mVertices.size() > 0) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_VERTEX_INIT(" << FORMAT_HEX(collision->mVertices.size()) << "),\n";
|
||||
++count;
|
||||
}
|
||||
for (auto &vertex : collision->mVertices) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_VERTEX(";
|
||||
write << vertex.x << ", ";
|
||||
write << vertex.y << ", ";
|
||||
write << vertex.z << "),\n";
|
||||
count += 3;
|
||||
}
|
||||
|
||||
// Surfaces
|
||||
for (auto &surface : collision->mSurfaces) {
|
||||
// size check is probably not necessary here
|
||||
if (surface.tris.size() > 0) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_TRI_INIT(";
|
||||
write << surface.surfaceType << ", ";
|
||||
write << surface.tris.size() << "),\n";
|
||||
count += 2;
|
||||
}
|
||||
bool hasForce = false;
|
||||
switch (surface.surfaceType) {
|
||||
case SurfaceType::SURFACE_0004:
|
||||
case SurfaceType::SURFACE_FLOWING_WATER:
|
||||
case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_HORIZONTAL_WIND:
|
||||
case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
|
||||
hasForce = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (auto &tri : surface.tris) {
|
||||
write << fourSpaceTab;
|
||||
if (hasForce) {
|
||||
write << "COL_TRI_SPECIAL(";
|
||||
} else {
|
||||
write << "COL_TRI(";
|
||||
}
|
||||
|
||||
write << tri.x << ", ";
|
||||
write << tri.y << ", ";
|
||||
if (hasForce) {
|
||||
write << tri.z << ", ";
|
||||
write << tri.force << "),\n";
|
||||
count += 4;
|
||||
} else {
|
||||
write << tri.z << "),\n";
|
||||
count += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collision->mSurfaces.size()) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_TRI_STOP()";
|
||||
++count;
|
||||
}
|
||||
|
||||
// Special Objects
|
||||
if (collision->mSpecialObjects.size() > 0) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_SPECIAL_INIT(" << collision->mSpecialObjects.size() << "),\n";
|
||||
count += 2;
|
||||
}
|
||||
for (auto &specialObject : collision->mSpecialObjects) {
|
||||
write << fourSpaceTab;
|
||||
if (specialPresetMap.find((int16_t)specialObject.presetId) == specialPresetMap.end()) {
|
||||
throw std::runtime_error("Special Preset Id has no associated Type");
|
||||
}
|
||||
SpecialPresetTypes type = specialPresetMap.at((int16_t)specialObject.presetId);
|
||||
switch (type) {
|
||||
case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
|
||||
case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
|
||||
write << "SPECIAL_OBJECT_WITH_YAW(";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
|
||||
write << "SPECIAL_OBJECT_WITH_YAW_AND_PARAM(";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
write << "SPECIAL_OBJECT(";
|
||||
break;
|
||||
}
|
||||
write << specialObject.presetId << ", ";
|
||||
write << specialObject.x << ", ";
|
||||
write << specialObject.y << ", ";
|
||||
write << specialObject.z;
|
||||
count += 4;
|
||||
|
||||
for (int16_t extraParam : specialObject.extraParams) {
|
||||
write << ", ";
|
||||
write << extraParam;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (type != SpecialPresetTypes::SPTYPE_UNKNOWN) {
|
||||
write << ")";
|
||||
}
|
||||
write << ",\n";
|
||||
}
|
||||
|
||||
// Environment Region Boxes
|
||||
if (collision->mEnvRegionBoxes.size() > 0) {
|
||||
write << fourSpaceTab;
|
||||
write << "COL_WATER_BOX_INIT(" << collision->mEnvRegionBoxes.size() << "),\n";
|
||||
count += 2;
|
||||
}
|
||||
for (auto &envRegionBox : collision->mEnvRegionBoxes) {
|
||||
write << fourSpaceTab;
|
||||
write << envRegionBox.id << ", ";
|
||||
write << envRegionBox.x1 << ", ";
|
||||
write << envRegionBox.z1 << ", ";
|
||||
write << envRegionBox.x2 << ", ";
|
||||
write << envRegionBox.z2 << ", ";
|
||||
write << envRegionBox.height << "),\n";
|
||||
count += 6;
|
||||
}
|
||||
|
||||
if (Companion::Instance->IsDebug()) {
|
||||
write << "// size: 0x" << std::hex << std::uppercase << "" << "\n";
|
||||
}
|
||||
|
||||
return offset + count * sizeof(int16_t);
|
||||
}
|
||||
|
||||
ExportResult SM64::CollisionHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
|
||||
const auto symbol = GetSafeNode(node, "symbol", entryName);
|
||||
|
||||
if(Companion::Instance->IsOTRMode()){
|
||||
write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
write << "extern " << "Collision " << symbol << "[];\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ExportResult SM64::CollisionBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
|
||||
const auto collision = std::static_pointer_cast<Collision>(data).get();
|
||||
|
||||
auto writer = LUS::BinaryWriter();
|
||||
writer.SetEndianness(LUS::Endianness::Big);
|
||||
|
||||
writer.Write((int16_t)COL_INIT());
|
||||
|
||||
// Vertices
|
||||
if (collision->mVertices.size() > 0) {
|
||||
writer.Write((int16_t)COL_VERTEX_INIT(collision->mVertices.size()));
|
||||
}
|
||||
for (auto &vertex : collision->mVertices) {
|
||||
writer.Write(vertex.x);
|
||||
writer.Write(vertex.y);
|
||||
writer.Write(vertex.z);
|
||||
}
|
||||
|
||||
// Surfaces
|
||||
for (auto &surface : collision->mSurfaces) {
|
||||
// size check is probably not necessary here
|
||||
if (surface.tris.size() > 0) {
|
||||
writer.Write((int16_t)surface.surfaceType);
|
||||
writer.Write((int16_t)surface.tris.size());
|
||||
}
|
||||
bool hasForce = false;
|
||||
switch (surface.surfaceType) {
|
||||
case SurfaceType::SURFACE_0004:
|
||||
case SurfaceType::SURFACE_FLOWING_WATER:
|
||||
case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_HORIZONTAL_WIND:
|
||||
case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
|
||||
hasForce = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (auto &tri : surface.tris) {
|
||||
writer.Write(tri.x);
|
||||
writer.Write(tri.y);
|
||||
writer.Write(tri.z);
|
||||
if (hasForce) {
|
||||
writer.Write(tri.force);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collision->mSurfaces.size()) {
|
||||
writer.Write((int16_t)COL_TRI_STOP());
|
||||
}
|
||||
|
||||
// Special Objects
|
||||
if (collision->mSpecialObjects.size() > 0) {
|
||||
writer.Write((int16_t)TERRAIN_LOAD_OBJECTS);
|
||||
writer.Write((int16_t)collision->mSpecialObjects.size());
|
||||
}
|
||||
for (auto &specialObject : collision->mSpecialObjects) {
|
||||
writer.Write((int16_t)specialObject.presetId);
|
||||
writer.Write(specialObject.x);
|
||||
writer.Write(specialObject.y);
|
||||
writer.Write(specialObject.z);
|
||||
for (int16_t extraParam : specialObject.extraParams) {
|
||||
writer.Write(extraParam);
|
||||
}
|
||||
}
|
||||
|
||||
// Environment Region Boxes
|
||||
if (collision->mEnvRegionBoxes.size() > 0) {
|
||||
writer.Write((int16_t)TERRAIN_LOAD_ENVIRONMENT);
|
||||
writer.Write((int16_t)collision->mEnvRegionBoxes.size());
|
||||
}
|
||||
for (auto &envRegionBox : collision->mEnvRegionBoxes) {
|
||||
writer.Write(envRegionBox.id);
|
||||
writer.Write(envRegionBox.x1);
|
||||
writer.Write(envRegionBox.z1);
|
||||
writer.Write(envRegionBox.x2);
|
||||
writer.Write(envRegionBox.z2);
|
||||
writer.Write(envRegionBox.height);
|
||||
}
|
||||
|
||||
std::vector<char> buffer = writer.ToVector();
|
||||
writer.Close();
|
||||
|
||||
LUS::BinaryWriter output = LUS::BinaryWriter();
|
||||
WriteHeader(output, LUS::ResourceType::Blob, 0);
|
||||
|
||||
output.Write(static_cast<uint32_t>(buffer.size()));
|
||||
output.Write(buffer.data(), buffer.size());
|
||||
output.Finish(write);
|
||||
output.Close();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<IParsedData>> SM64::CollisionFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
|
||||
std::vector<CollisionVertex> vertices;
|
||||
std::vector<CollisionSurface> surfaces;
|
||||
std::vector<SpecialObject> specialObjects;
|
||||
std::vector<EnvRegionBox> envRegionBoxes;
|
||||
bool processing = true;
|
||||
auto [_, segment] = Decompressor::AutoDecode(node, buffer);
|
||||
auto cmd = segment.data;
|
||||
LUS::BinaryReader reader(segment.data, segment.size);
|
||||
reader.SetEndianness(LUS::Endianness::Big);
|
||||
|
||||
while (processing) {
|
||||
int16_t terrainLoadType = reader.ReadInt16();
|
||||
|
||||
if (TERRAIN_LOAD_IS_SURFACE_TYPE_LOW(terrainLoadType)) {
|
||||
SurfaceType surfaceType = static_cast<SurfaceType>(terrainLoadType);
|
||||
bool hasForce = false;
|
||||
switch (surfaceType) {
|
||||
case SurfaceType::SURFACE_0004:
|
||||
case SurfaceType::SURFACE_FLOWING_WATER:
|
||||
case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_HORIZONTAL_WIND:
|
||||
case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
|
||||
hasForce = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int16_t numSurfaces = reader.ReadInt16();
|
||||
std::vector<CollisionTri> tris;
|
||||
for (int16_t i = 0; i < numSurfaces; ++i) {
|
||||
int16_t x = reader.ReadInt16();
|
||||
int16_t y = reader.ReadInt16();
|
||||
int16_t z = reader.ReadInt16();
|
||||
int16_t force = hasForce ? reader.ReadInt16() : -1;
|
||||
tris.emplace_back(x, y, z, force);
|
||||
}
|
||||
surfaces.emplace_back(surfaceType, tris);
|
||||
} else if (terrainLoadType == TERRAIN_LOAD_VERTICES) {
|
||||
int16_t numVertices = reader.ReadInt16();
|
||||
for (int16_t i = 0; i < numVertices; ++i) {
|
||||
int16_t x = reader.ReadInt16();
|
||||
int16_t y = reader.ReadInt16();
|
||||
int16_t z = reader.ReadInt16();
|
||||
vertices.emplace_back(x, y, z);
|
||||
}
|
||||
} else if (terrainLoadType == TERRAIN_LOAD_OBJECTS) {
|
||||
int16_t numSpecialObjects = reader.ReadInt16();
|
||||
for (int16_t i = 0; i < numSpecialObjects; ++i) {
|
||||
int16_t presetId = reader.ReadInt16();
|
||||
int16_t x = reader.ReadInt16();
|
||||
int16_t y = reader.ReadInt16();
|
||||
int16_t z = reader.ReadInt16();
|
||||
if (specialPresetMap.find(presetId) == specialPresetMap.end()) {
|
||||
throw std::runtime_error("Special Preset Id has no associated Type");
|
||||
}
|
||||
SpecialPresets specialPresetId = static_cast<SpecialPresets>(presetId);
|
||||
SpecialPresetTypes type = specialPresetMap.at(presetId);
|
||||
std::vector<int16_t> extraParams;
|
||||
switch (type) {
|
||||
case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
case SpecialPresetTypes::SPTYPE_UNKNOWN:
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
|
||||
extraParams.emplace_back(reader.ReadInt16());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
specialObjects.emplace_back(specialPresetId, x, y, z, extraParams);
|
||||
}
|
||||
} else if (terrainLoadType == TERRAIN_LOAD_ENVIRONMENT) {
|
||||
int16_t numRegions = reader.ReadInt16();
|
||||
for (int16_t i = 0; i < numRegions; ++i) {
|
||||
int16_t id = reader.ReadInt16();
|
||||
int16_t x1 = reader.ReadInt16();
|
||||
int16_t z1 = reader.ReadInt16();
|
||||
int16_t x2 = reader.ReadInt16();
|
||||
int16_t z2 = reader.ReadInt16();
|
||||
int16_t height = reader.ReadInt16();
|
||||
envRegionBoxes.emplace_back(id, x1, z1, x2, z2, height);
|
||||
}
|
||||
} else if (terrainLoadType == TERRAIN_LOAD_CONTINUE) {
|
||||
// need to figure out a way to handle when this should appear in exporters. seems to always be after vertices
|
||||
} else if (terrainLoadType == TERRAIN_LOAD_END) {
|
||||
processing = false;
|
||||
} else if (TERRAIN_LOAD_IS_SURFACE_TYPE_HIGH(terrainLoadType)) {
|
||||
SurfaceType surfaceType = static_cast<SurfaceType>(terrainLoadType);
|
||||
bool hasForce = false;
|
||||
switch (surfaceType) {
|
||||
case SurfaceType::SURFACE_0004:
|
||||
case SurfaceType::SURFACE_FLOWING_WATER:
|
||||
case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_MOVING_QUICKSAND:
|
||||
case SurfaceType::SURFACE_HORIZONTAL_WIND:
|
||||
case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
|
||||
hasForce = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int16_t numSurfaces = reader.ReadInt16();
|
||||
std::vector<CollisionTri> tris;
|
||||
for (int16_t i = 0; i < numSurfaces; ++i) {
|
||||
int16_t x = reader.ReadInt16();
|
||||
int16_t y = reader.ReadInt16();
|
||||
int16_t z = reader.ReadInt16();
|
||||
int16_t force = hasForce ? reader.ReadInt16() : -1;
|
||||
tris.emplace_back(x, y, z, force);
|
||||
}
|
||||
surfaces.emplace_back(surfaceType, tris);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Collision>(vertices, surfaces, specialObjects, envRegionBoxes);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "../BaseFactory.h"
|
||||
#include "collision/SpecialPresetNames.h"
|
||||
#include "collision/SurfaceTerrains.h"
|
||||
|
||||
namespace SM64 {
|
||||
|
||||
struct CollisionVertex {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
CollisionVertex(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {};
|
||||
};
|
||||
|
||||
struct CollisionTri {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
int16_t force;
|
||||
CollisionTri(int16_t x, int16_t y, int16_t z, int16_t force) : x(x), y(y), z(z), force(force) {};
|
||||
};
|
||||
|
||||
struct CollisionSurface {
|
||||
SurfaceType surfaceType;
|
||||
std::vector<CollisionTri> tris;
|
||||
CollisionSurface(SurfaceType surfaceType, std::vector<CollisionTri> tris) : surfaceType(surfaceType), tris(std::move(tris)) {};
|
||||
};
|
||||
|
||||
struct SpecialObject {
|
||||
SpecialPresets presetId;
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
std::vector<int16_t> extraParams; // e.g. y-rot
|
||||
SpecialObject(SpecialPresets presetId, int16_t x, int16_t y, int16_t z, std::vector<int16_t> extraParams) : presetId(presetId), x(x), y(y), z(z), extraParams(std::move(extraParams)) {};
|
||||
};
|
||||
|
||||
struct EnvRegionBox {
|
||||
int16_t id;
|
||||
int16_t x1;
|
||||
int16_t z1;
|
||||
int16_t x2;
|
||||
int16_t z2;
|
||||
int16_t height;
|
||||
EnvRegionBox(int16_t id, int16_t x1, int16_t z1, int16_t x2, int16_t z2, int16_t height) : id(id), x1(x1), z1(z1), x2(x2), z2(z2), height(height) {};
|
||||
}; // e.g. water-box
|
||||
|
||||
class Collision : public IParsedData {
|
||||
public:
|
||||
std::vector<CollisionVertex> mVertices;
|
||||
std::vector<CollisionSurface> mSurfaces;
|
||||
std::vector<SpecialObject> mSpecialObjects;
|
||||
std::vector<EnvRegionBox> mEnvRegionBoxes;
|
||||
|
||||
explicit Collision(std::vector<CollisionVertex> vertices, std::vector<CollisionSurface> surfaces, std::vector<SpecialObject> specialObjects, std::vector<EnvRegionBox> envRegionBoxes) : mVertices(std::move(vertices)), mSurfaces(std::move(surfaces)), mSpecialObjects(std::move(specialObjects)), mEnvRegionBoxes(std::move(envRegionBoxes)) {}
|
||||
};
|
||||
|
||||
class CollisionCodeExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class CollisionHeaderExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class CollisionBinaryExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class CollisionFactory : public BaseFactory {
|
||||
public:
|
||||
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
|
||||
std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
|
||||
return {
|
||||
REGISTER(Header, CollisionHeaderExporter)
|
||||
REGISTER(Binary, CollisionBinaryExporter)
|
||||
REGISTER(Code, CollisionCodeExporter)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/fmt/ostr.h>
|
||||
|
||||
enum class SpecialPresetTypes {
|
||||
SPTYPE_NO_YROT_OR_PARAMS,
|
||||
SPTYPE_YROT_NO_PARAMS,
|
||||
SPTYPE_PARAMS_AND_YROT,
|
||||
SPTYPE_UNKNOWN,
|
||||
SPTYPE_DEF_PARAM_AND_YROT,
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const SpecialPresetTypes& type) {
|
||||
std::string output;
|
||||
switch (type) {
|
||||
case SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS:
|
||||
output = "SPTYPE_NO_YROT_OR_PARAMS";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
|
||||
output = "SPTYPE_YROT_NO_PARAMS";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
|
||||
output = "SPTYPE_PARAMS_AND_YROT";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_UNKNOWN:
|
||||
output = "SPTYPE_UNKNOWN";
|
||||
break;
|
||||
case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
|
||||
output = "SPTYPE_DEF_PARAM_AND_YROT";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown Special Preset Type");
|
||||
}
|
||||
return out << output;
|
||||
}
|
||||
|
||||
enum class SpecialPresets {
|
||||
special_null_start,
|
||||
special_yellow_coin,
|
||||
special_yellow_coin_2,
|
||||
special_unknown_3,
|
||||
special_boo,
|
||||
special_unknown_5,
|
||||
special_lll_moving_octagonal_mesh_platform,
|
||||
special_snow_ball,
|
||||
special_lll_drawbridge_spawner,
|
||||
special_empty_9,
|
||||
special_lll_rotating_block_with_fire_bars,
|
||||
special_lll_floating_wood_bridge,
|
||||
special_tumbling_platform,
|
||||
special_lll_rotating_hexagonal_ring,
|
||||
special_lll_sinking_rectangular_platform,
|
||||
special_lll_sinking_square_platforms,
|
||||
special_lll_tilting_square_platform,
|
||||
special_lll_bowser_puzzle,
|
||||
special_mr_i,
|
||||
special_small_bully,
|
||||
special_big_bully,
|
||||
special_empty_21,
|
||||
special_empty_22,
|
||||
special_empty_23,
|
||||
special_empty_24,
|
||||
special_empty_25,
|
||||
special_moving_blue_coin,
|
||||
special_jrb_chest,
|
||||
special_water_ring,
|
||||
special_mine,
|
||||
special_empty_30,
|
||||
special_empty_31,
|
||||
special_butterfly,
|
||||
special_bowser,
|
||||
special_wf_rotating_wooden_platform,
|
||||
special_small_bomp,
|
||||
special_wf_sliding_platform,
|
||||
special_tower_platform_group,
|
||||
special_rotating_counter_clockwise,
|
||||
special_wf_tumbling_bridge,
|
||||
special_large_bomp,
|
||||
|
||||
special_level_geo_03 = 0x65,
|
||||
special_level_geo_04,
|
||||
special_level_geo_05,
|
||||
special_level_geo_06,
|
||||
special_level_geo_07,
|
||||
special_level_geo_08,
|
||||
special_level_geo_09,
|
||||
special_level_geo_0A,
|
||||
special_level_geo_0B,
|
||||
special_level_geo_0C,
|
||||
special_level_geo_0D,
|
||||
special_level_geo_0E,
|
||||
special_level_geo_0F,
|
||||
special_level_geo_10,
|
||||
special_level_geo_11,
|
||||
special_level_geo_12,
|
||||
special_level_geo_13,
|
||||
special_level_geo_14,
|
||||
special_level_geo_15,
|
||||
special_level_geo_16,
|
||||
special_bubble_tree,
|
||||
special_spiky_tree,
|
||||
special_snow_tree,
|
||||
special_unknown_tree,
|
||||
special_palm_tree,
|
||||
special_wooden_door,
|
||||
special_haunted_door = special_wooden_door,
|
||||
special_unknown_door,
|
||||
special_metal_door,
|
||||
special_hmc_door,
|
||||
special_unknown2_door,
|
||||
special_wooden_door_warp,
|
||||
special_unknown1_door_warp,
|
||||
special_metal_door_warp,
|
||||
special_unknown2_door_warp,
|
||||
special_unknown3_door_warp,
|
||||
special_castle_door_warp,
|
||||
special_castle_door,
|
||||
special_0stars_door,
|
||||
special_1star_door,
|
||||
special_3star_door,
|
||||
special_key_door,
|
||||
|
||||
special_null_end = 0xFF
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const SpecialPresets& preset) {
|
||||
std::string output;
|
||||
switch (preset) {
|
||||
case SpecialPresets::special_null_start:
|
||||
output = "special_null_start";
|
||||
break;
|
||||
case SpecialPresets::special_yellow_coin:
|
||||
output = "special_yellow_coin";
|
||||
break;
|
||||
case SpecialPresets::special_yellow_coin_2:
|
||||
output = "special_yellow_coin_2";
|
||||
break;
|
||||
case SpecialPresets::special_unknown_3:
|
||||
output = "special_unknown_3";
|
||||
break;
|
||||
case SpecialPresets::special_boo:
|
||||
output = "special_boo";
|
||||
break;
|
||||
case SpecialPresets::special_unknown_5:
|
||||
output = "special_unknown_5";
|
||||
break;
|
||||
case SpecialPresets::special_lll_moving_octagonal_mesh_platform:
|
||||
output = "special_lll_moving_octagonal_mesh_platform";
|
||||
break;
|
||||
case SpecialPresets::special_snow_ball:
|
||||
output = "special_snow_ball";
|
||||
break;
|
||||
case SpecialPresets::special_lll_drawbridge_spawner:
|
||||
output = "special_lll_drawbridge_spawner";
|
||||
break;
|
||||
case SpecialPresets::special_empty_9:
|
||||
output = "special_empty_9";
|
||||
break;
|
||||
case SpecialPresets::special_lll_rotating_block_with_fire_bars:
|
||||
output = "special_lll_rotating_block_with_fire_bars";
|
||||
break;
|
||||
case SpecialPresets::special_lll_floating_wood_bridge:
|
||||
output = "special_lll_floating_wood_bridge";
|
||||
break;
|
||||
case SpecialPresets::special_tumbling_platform:
|
||||
output = "special_tumbling_platform";
|
||||
break;
|
||||
case SpecialPresets::special_lll_rotating_hexagonal_ring:
|
||||
output = "special_lll_rotating_hexagonal_ring";
|
||||
break;
|
||||
case SpecialPresets::special_lll_sinking_rectangular_platform:
|
||||
output = "special_lll_sinking_rectangular_platform";
|
||||
break;
|
||||
case SpecialPresets::special_lll_sinking_square_platforms:
|
||||
output = "special_lll_sinking_square_platforms";
|
||||
break;
|
||||
case SpecialPresets::special_lll_tilting_square_platform:
|
||||
output = "special_lll_tilting_square_platform";
|
||||
break;
|
||||
case SpecialPresets::special_lll_bowser_puzzle:
|
||||
output = "special_lll_bowser_puzzle";
|
||||
break;
|
||||
case SpecialPresets::special_mr_i:
|
||||
output = "special_mr_i";
|
||||
break;
|
||||
case SpecialPresets::special_small_bully:
|
||||
output = "special_small_bully";
|
||||
break;
|
||||
case SpecialPresets::special_big_bully:
|
||||
output = "special_big_bully";
|
||||
break;
|
||||
case SpecialPresets::special_empty_21:
|
||||
output = "special_empty_21";
|
||||
break;
|
||||
case SpecialPresets::special_empty_22:
|
||||
output = "special_empty_22";
|
||||
break;
|
||||
case SpecialPresets::special_empty_23:
|
||||
output = "special_empty_23";
|
||||
break;
|
||||
case SpecialPresets::special_empty_24:
|
||||
output = "special_empty_24";
|
||||
break;
|
||||
case SpecialPresets::special_empty_25:
|
||||
output = "special_empty_25";
|
||||
break;
|
||||
case SpecialPresets::special_moving_blue_coin:
|
||||
output = "special_moving_blue_coin";
|
||||
break;
|
||||
case SpecialPresets::special_jrb_chest:
|
||||
output = "special_jrb_chest";
|
||||
break;
|
||||
case SpecialPresets::special_water_ring:
|
||||
output = "special_water_ring";
|
||||
break;
|
||||
case SpecialPresets::special_mine:
|
||||
output = "special_mine";
|
||||
break;
|
||||
case SpecialPresets::special_empty_30:
|
||||
output = "special_empty_30";
|
||||
break;
|
||||
case SpecialPresets::special_empty_31:
|
||||
output = "special_empty_31";
|
||||
break;
|
||||
case SpecialPresets::special_butterfly:
|
||||
output = "special_butterfly";
|
||||
break;
|
||||
case SpecialPresets::special_bowser:
|
||||
output = "special_bowser";
|
||||
break;
|
||||
case SpecialPresets::special_wf_rotating_wooden_platform:
|
||||
output = "special_wf_rotating_wooden_platform";
|
||||
break;
|
||||
case SpecialPresets::special_small_bomp:
|
||||
output = "special_small_bomp";
|
||||
break;
|
||||
case SpecialPresets::special_wf_sliding_platform:
|
||||
output = "special_wf_sliding_platform";
|
||||
break;
|
||||
case SpecialPresets::special_tower_platform_group:
|
||||
output = "special_tower_platform_group";
|
||||
break;
|
||||
case SpecialPresets::special_rotating_counter_clockwise:
|
||||
output = "special_rotating_counter_clockwise";
|
||||
break;
|
||||
case SpecialPresets::special_wf_tumbling_bridge:
|
||||
output = "special_wf_tumbling_bridge";
|
||||
break;
|
||||
case SpecialPresets::special_large_bomp:
|
||||
output = "special_large_bomp";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_03:
|
||||
output = "special_level_geo_03";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_04:
|
||||
output = "special_level_geo_04";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_05:
|
||||
output = "special_level_geo_05";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_06:
|
||||
output = "special_level_geo_06";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_07:
|
||||
output = "special_level_geo_07";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_08:
|
||||
output = "special_level_geo_08";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_09:
|
||||
output = "special_level_geo_09";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0A:
|
||||
output = "special_level_geo_0A";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0B:
|
||||
output = "special_level_geo_0B";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0C:
|
||||
output = "special_level_geo_0C";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0D:
|
||||
output = "special_level_geo_0D";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0E:
|
||||
output = "special_level_geo_0E";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_0F:
|
||||
output = "special_level_geo_0F";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_10:
|
||||
output = "special_level_geo_10";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_11:
|
||||
output = "special_level_geo_11";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_12:
|
||||
output = "special_level_geo_12";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_13:
|
||||
output = "special_level_geo_13";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_14:
|
||||
output = "special_level_geo_14";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_15:
|
||||
output = "special_level_geo_15";
|
||||
break;
|
||||
case SpecialPresets::special_level_geo_16:
|
||||
output = "special_level_geo_16";
|
||||
break;
|
||||
case SpecialPresets::special_bubble_tree:
|
||||
output = "special_bubble_tree";
|
||||
break;
|
||||
case SpecialPresets::special_spiky_tree:
|
||||
output = "special_spiky_tree";
|
||||
break;
|
||||
case SpecialPresets::special_snow_tree:
|
||||
output = "special_snow_tree";
|
||||
break;
|
||||
case SpecialPresets::special_unknown_tree:
|
||||
output = "special_unknown_tree";
|
||||
break;
|
||||
case SpecialPresets::special_palm_tree:
|
||||
output = "special_palm_tree";
|
||||
break;
|
||||
case SpecialPresets::special_wooden_door:
|
||||
output = "special_wooden_door";
|
||||
break;
|
||||
case SpecialPresets::special_unknown_door:
|
||||
output = "special_unknown_door";
|
||||
break;
|
||||
case SpecialPresets::special_metal_door:
|
||||
output = "special_metal_door";
|
||||
break;
|
||||
case SpecialPresets::special_hmc_door:
|
||||
output = "special_hmc_door";
|
||||
break;
|
||||
case SpecialPresets::special_unknown2_door:
|
||||
output = "special_unknown2_door";
|
||||
break;
|
||||
case SpecialPresets::special_wooden_door_warp:
|
||||
output = "special_wooden_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_unknown1_door_warp:
|
||||
output = "special_unknown1_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_metal_door_warp:
|
||||
output = "special_metal_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_unknown2_door_warp:
|
||||
output = "special_unknown2_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_unknown3_door_warp:
|
||||
output = "special_unknown3_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_castle_door_warp:
|
||||
output = "special_castle_door_warp";
|
||||
break;
|
||||
case SpecialPresets::special_castle_door:
|
||||
output = "special_castle_door";
|
||||
break;
|
||||
case SpecialPresets::special_0stars_door:
|
||||
output = "special_0stars_door";
|
||||
break;
|
||||
case SpecialPresets::special_1star_door:
|
||||
output = "special_1star_door";
|
||||
break;
|
||||
case SpecialPresets::special_3star_door:
|
||||
output = "special_3star_door";
|
||||
break;
|
||||
case SpecialPresets::special_key_door:
|
||||
output = "special_key_door";
|
||||
break;
|
||||
case SpecialPresets::special_null_end:
|
||||
output = "special_null_end";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown Special Preset");
|
||||
}
|
||||
|
||||
return out << output;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user