// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "dna/DataLayer.h" #include "dna/LODMapping.h" #include "dna/SurjectiveMapping.h" #include "dna/TypeDefs.h" #include "dna/utils/Extd.h" #include #include #include #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4365 4987) #endif #include #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(pop) #endif namespace dna { template struct Dispatcher; template struct Dispatcher { template void operator()(Archive& archive, TSerializable& object, TVersion /*unused*/, bool transparent) { // Dispatching occurs only after DNA version has already been read, identified and confirmed // to be supported (the unknown enum won't be passed here ever). Likewise, if a newer // version is encountered than the latest version listed here, it will be dispatched to the // latest available serializer. auto versionedObject = terse::versioned(object, terse::Version{}); if (transparent) { archive(terse::transparent(versionedObject)); } else { archive(versionedObject); } } }; template struct Dispatcher : Dispatcher { using Super = Dispatcher; template void operator()(Archive& archive, TSerializable& object, TVersion version, bool transparent) { if (version == Expected) { auto versionedObject = terse::versioned(object, terse::Version{}); if (transparent) { archive(terse::transparent(versionedObject)); } else { archive(versionedObject); } } else { Super::operator()(archive, object, version, transparent); } } }; static constexpr std::uint32_t sid4(const char* name) { return ((static_cast(name[0]) << 24u) + (static_cast(name[1]) << 16u) + (static_cast(name[2]) << 8u) + (static_cast(name[3]) << 0u)); } static constexpr std::uint32_t rev(std::uint16_t generation, std::uint16_t version) { return (static_cast(generation) << 16u) + static_cast(version); } static constexpr std::uint16_t high16(std::uint32_t packed) { return static_cast(packed >> 16u); } static constexpr std::uint16_t low16(std::uint32_t packed) { return static_cast(packed & 0x0000FFFFu); } enum FileVersion : std::uint64_t { unknown = 0u, v21 = rev(2, 1), v22 = rev(2, 2), v23 = rev(2, 3), v24 = rev(2, 4), v25 = rev(2, 5), latest = v25 }; using Dispatch = Dispatcher; template using IfHigher = typename std::enable_if<(A::value() > B), void>::type; template using IfLower = typename std::enable_if < (A::value() < B), void > ::type; enum class UpgradeFormatPolicy { Disallowed, Allowed }; struct SerializationContext { FileVersion version; void* data; }; struct Version { std::uint16_t generation; std::uint16_t version; Version(FileVersion fileVersion) : generation{high16(static_cast(fileVersion))}, version{low16(static_cast(fileVersion))} { } operator FileVersion() const { return static_cast(rev(generation, version)); } template void serialize(Archive& archive) { archive.label("generation"); archive(generation); archive.label("version"); archive(version); } bool matches(FileVersion fileVersion) const { const Version expected{fileVersion}; return (generation == expected.generation) && (version == expected.version); } bool supported() const { return (generation == Version{FileVersion::latest}.generation); } }; template struct ExpectedValue { T expected; T got; explicit ExpectedValue(const T& value) : expected{value}, got{} { } template void load(Archive& archive) { archive.label("value"); archive(got); } template void save(Archive& archive) { archive.label("value"); archive(expected); got = expected; } bool matches() const { return (expected == got); } }; template struct Signature { using SignatureValueType = std::array; ExpectedValue value; explicit Signature(SignatureValueType bytes) : value{bytes} { } template void serialize(Archive& archive) { archive.label("data"); archive(value); } bool matches() const { return value.matches(); } }; struct SectionLookupTable { terse::ArchiveOffset descriptor; terse::ArchiveOffset definition; terse::ArchiveOffset behavior; terse::ArchiveOffset controls; terse::ArchiveOffset joints; terse::ArchiveOffset blendShapeChannels; terse::ArchiveOffset animatedMaps; terse::ArchiveOffset geometry; template void serialize(Archive& archive) { archive.label("descriptor"); archive(descriptor); archive.label("definition"); archive(definition); archive.label("behavior"); archive(behavior); archive.label("controls"); archive(controls); archive.label("joints"); archive(joints); archive.label("blendShapeChannels"); archive(blendShapeChannels); archive.label("animatedMaps"); archive(animatedMaps); archive.label("geometry"); archive(geometry); } }; struct Index { std::uint32_t id; std::uint32_t version; terse::ArchiveOffset offset; terse::ArchiveSize size; template std::array label() { std::array output; std::memcpy(output.data(), &id, sizeof(id)); std::reverse(output.begin(), extd::advanced(output.begin(), sizeof(id))); const std::uint32_t major = version >> 16u; const std::uint32_t minor = version & 0x0000FFFFu; std::snprintf(output.data() + sizeof(id), output.size() - sizeof(id), "%u.%u", major, minor); return output; } template void serialize(Archive& archive) { archive.label("id"); archive(id); archive.label("version"); archive(version); archive.label("offset"); archive(offset); archive.label("size"); archive(size); } }; struct IndexTable { Vector entries; explicit IndexTable(MemoryResource* memRes) : entries{memRes} { } Index* get(std::uint32_t id, std::uint32_t version) { for (auto& index : entries) { if ((index.id == id) && (index.version == version)) { return &index; } } return nullptr; } const Index* get(std::uint32_t id, std::uint32_t version) const { return const_cast(this)->get(id, version); } Index* create(std::uint32_t id, std::uint32_t version) { assert(get(id, version) == nullptr); entries.push_back({id, version, {}, {}}); return &entries.back(); } void destroy(std::uint32_t id, std::uint32_t version) { entries.erase(std::remove_if(entries.begin(), entries.end(), [id, version](const Index& index) { return (index.id == id) && (index.version == version); }), entries.end()); } template void serialize(Archive& archive) { archive.label("entries"); archive(entries); } }; struct UnknownLayer { std::uint32_t id; std::uint32_t version; Blob data; UnknownLayer(std::uint32_t id_, std::uint32_t version_, MemoryResource* memRes) : id{id_}, version{version_}, data{memRes} { } std::uint32_t layerId() { return id; } std::uint32_t layerVersion() { return version; } bool layerSupported(FileVersion /*unused*/) { return true; } template void serialize(Archive& archive) { // Serialization of the layer type itself is transparent // and should not generate an additional, new structure level in JSON auto context = static_cast(archive.getUserData()); auto index = static_cast(context->data); const auto layerName = index->label(); archive.label(layerName.data()); archive(terse::proxy(index->offset)); terse::Anchor base; archive(base); data.setSize(index->size.value); archive(data); archive(terse::proxy(index->size, base)); } }; template struct Layer : TData { template explicit Layer(Args&& ... args) : TData{std::forward(args)...} { } std::uint32_t layerId() { return Id; } std::uint32_t layerVersion() { return Version; } bool layerSupported(FileVersion inVersion) { return (inVersion >= AvailableFromFileVersion); } template void serialize(Archive& archive) { // Serialization of the layer type itself is transparent // and should not generate an additional, new structure level in JSON auto context = static_cast(archive.getUserData()); auto index = static_cast(context->data); const auto layerName = index->label(); archive.label(layerName.data()); archive(terse::proxy(index->offset)); terse::Anchor base; archive(base); Dispatch()(archive, static_cast(*this), context->version, false); archive(terse::proxy(index->size, base)); } }; template struct LayerContainer; template<> struct LayerContainer<> { UnknownLayerPolicy unknownPolicy; UpgradeFormatPolicy upgradePolicy; Vector unknownLayers; LayerContainer(UnknownLayerPolicy unknownPolicy_, UpgradeFormatPolicy upgradePolicy_, MemoryResource* memRes) : unknownPolicy{unknownPolicy_}, upgradePolicy{upgradePolicy_}, unknownLayers{memRes} { } template void serialize(TArchive& archive) { auto context = static_cast(archive.getUserData()); auto index = static_cast(context->data); for (auto& layer : unknownLayers) { if ((index->id == layer.layerId()) && (index->version == layer.layerVersion())) { archive(terse::transparent(layer)); return; } } // This code path should be executed only by input archives, when loading unknown layers. // After initially adding all unknown layers, there is no way for new unknown layers to be // encountered, so the above loop will take care of all during saving. if (unknownPolicy == UnknownLayerPolicy::Preserve) { auto memRes = unknownLayers.get_allocator().getMemoryResource(); unknownLayers.push_back(UnknownLayer{index->id, index->version, memRes}); archive(terse::transparent(unknownLayers.back())); } else { // Mark index for deletion context->data = nullptr; } } void updateIndexTable(IndexTable& /*unused*/, FileVersion /*unused*/) { // Unknown layers are already in the index (that's the only way they could have been encountered) } }; template struct LayerContainer : LayerContainer { using Super = LayerContainer; TLayer* layer; LayerContainer(UnknownLayerPolicy unknownPolicy_, UpgradeFormatPolicy upgradePolicy_, MemoryResource* memRes, TLayer* layer_, TRest* ... rest) : Super{unknownPolicy_, upgradePolicy_, memRes, std::forward(rest)...}, layer{layer_} { } template void serialize(TArchive& archive) { auto context = static_cast(archive.getUserData()); auto index = static_cast(context->data); if ((index->id == layer->layerId()) && (index->version == layer->layerVersion())) { archive(terse::transparent(*layer)); } else { archive(terse::transparent(static_cast(*this))); } } void updateIndexTable(IndexTable& indexTable, FileVersion fileVersion) { const bool exists = (indexTable.get(layer->layerId(), layer->layerVersion()) != nullptr); if (layer->layerSupported(fileVersion)) { // Do not merge ifs, as the below else branch depends solely on the condition of the // layer not being supported in the file version if (!exists && (this->upgradePolicy == UpgradeFormatPolicy::Allowed)) { indexTable.create(layer->layerId(), layer->layerVersion()); } } else { if (exists && (this->unknownPolicy == UnknownLayerPolicy::Ignore)) { indexTable.destroy(layer->layerId(), layer->layerVersion()); } } Super::updateIndexTable(indexTable, fileVersion); } }; template struct RawSurjectiveMapping : public SurjectiveMapping { using SurjectiveMapping::SurjectiveMapping; template void serialize(Archive& archive) { archive.label("from"); archive(this->from); archive.label("to"); archive(this->to); } }; struct RawCoordinateSystem { std::uint16_t xAxis; std::uint16_t yAxis; std::uint16_t zAxis; template void serialize(Archive& archive) { archive.label("xAxis"); archive(xAxis); archive.label("yAxis"); archive(yAxis); archive.label("zAxis"); archive(zAxis); } }; struct RawLODMapping : public LODMapping { using LODMapping::LODMapping; template void serialize(Archive& archive) { archive.label("lods"); archive(lods); archive.label("indices"); archive(indices); } }; struct RawDescriptor { using StringPair = std::tuple, String >; String name; std::uint16_t archetype; std::uint16_t gender; std::uint16_t age; Vector metadata; std::uint16_t translationUnit; std::uint16_t rotationUnit; RawCoordinateSystem coordinateSystem; std::uint16_t lodCount; std::uint16_t maxLOD; String complexity; String dbName; explicit RawDescriptor(MemoryResource* memRes) : name{memRes}, archetype{}, gender{}, age{}, metadata{memRes}, translationUnit{}, rotationUnit{}, coordinateSystem{}, lodCount{}, maxLOD{}, complexity{memRes}, dbName{memRes} { } template void serialize(Archive& archive) { archive.label("name"); archive(name); archive.label("archetype"); archive(archetype); archive.label("gender"); archive(gender); archive.label("age"); archive(age); archive.label("metadata"); archive(metadata); archive.label("translationUnit"); archive(translationUnit); archive.label("rotationUnit"); archive(rotationUnit); archive.label("coordinateSystem"); archive(coordinateSystem); archive.label("lodCount"); archive(lodCount); archive.label("maxLOD"); archive(maxLOD); archive.label("complexity"); archive(complexity); archive.label("dbName"); archive(dbName); } }; struct RawVector3Vector { AlignedDynArray xs; AlignedDynArray ys; AlignedDynArray zs; explicit RawVector3Vector(MemoryResource* memRes) : xs{memRes}, ys{memRes}, zs{memRes} { } RawVector3Vector(std::size_t size_, float initial, MemoryResource* memRes) : xs{size_, initial, memRes}, ys{size_, initial, memRes}, zs{size_, initial, memRes} { } RawVector3Vector(ConstArrayView xs_, ConstArrayView ys_, ConstArrayView zs_, MemoryResource* memRes) : xs{xs_.begin(), xs_.end(), memRes}, ys{ys_.begin(), ys_.end(), memRes}, zs{zs_.begin(), zs_.end(), memRes} { } template void serialize(Archive& archive) { archive.label("xs"); archive(xs); archive.label("ys"); archive(ys); archive.label("zs"); archive(zs); } std::size_t size() const { assert(xs.size() == ys.size() && ys.size() == zs.size()); return xs.size(); } void reserve(std::size_t count) { xs.resize_uninitialized(count); ys.resize_uninitialized(count); zs.resize_uninitialized(count); } void resize(std::size_t count) { xs.resize(count); ys.resize(count); zs.resize(count); } void resize(std::size_t count, float value) { xs.resize(count, value); ys.resize(count, value); zs.resize(count, value); } void clear() { xs.clear(); ys.clear(); zs.clear(); } template void assign(Iterator start, Iterator end) { reserve(static_cast(std::distance(start, end))); std::size_t i{}; for (auto it = start; it != end; ++it, ++i) { xs[i] = it->x; ys[i] = it->y; zs[i] = it->z; } } }; struct RawDefinition { RawLODMapping lodJointMapping; RawLODMapping lodBlendShapeMapping; RawLODMapping lodAnimatedMapMapping; RawLODMapping lodMeshMapping; Vector > guiControlNames; Vector > rawControlNames; Vector > jointNames; Vector > blendShapeChannelNames; Vector > animatedMapNames; Vector > meshNames; RawSurjectiveMapping meshBlendShapeChannelMapping; DynArray jointHierarchy; RawVector3Vector neutralJointTranslations; RawVector3Vector neutralJointRotations; explicit RawDefinition(MemoryResource* memRes) : lodJointMapping{memRes}, lodBlendShapeMapping{memRes}, lodAnimatedMapMapping{memRes}, lodMeshMapping{memRes}, guiControlNames{memRes}, rawControlNames{memRes}, jointNames{memRes}, blendShapeChannelNames{memRes}, animatedMapNames{memRes}, meshNames{memRes}, meshBlendShapeChannelMapping{memRes}, jointHierarchy{memRes}, neutralJointTranslations{memRes}, neutralJointRotations{memRes} { } template void serialize(Archive& archive) { archive.label("lodJointMapping"); archive(lodJointMapping); archive.label("lodBlendShapeMapping"); archive(lodBlendShapeMapping); archive.label("lodAnimatedMapMapping"); archive(lodAnimatedMapMapping); archive.label("lodMeshMapping"); archive(lodMeshMapping); archive.label("guiControlNames"); archive(guiControlNames); archive.label("rawControlNames"); archive(rawControlNames); archive.label("jointNames"); archive(jointNames); archive.label("blendShapeChannelNames"); archive(blendShapeChannelNames); archive.label("animatedMapNames"); archive(animatedMapNames); archive.label("meshNames"); archive(meshNames); archive.label("meshBlendShapeChannelMapping"); archive(meshBlendShapeChannelMapping); archive.label("jointHierarchy"); archive(jointHierarchy); archive.label("neutralJointTranslations"); archive(neutralJointTranslations); archive.label("neutralJointRotations"); archive(neutralJointRotations); } }; struct RawConditionalTable { DynArray inputIndices; DynArray outputIndices; DynArray fromValues; DynArray toValues; DynArray slopeValues; DynArray cutValues; explicit RawConditionalTable(MemoryResource* memRes) : inputIndices{memRes}, outputIndices{memRes}, fromValues{memRes}, toValues{memRes}, slopeValues{memRes}, cutValues{memRes} { } template void serialize(Archive& archive) { archive.label("inputIndices"); archive(inputIndices); archive.label("outputIndices"); archive(outputIndices); archive.label("fromValues"); archive(fromValues); archive.label("toValues"); archive(toValues); archive.label("slopeValues"); archive(slopeValues); archive.label("cutValues"); archive(cutValues); } }; struct RawPSDMatrix { DynArray rows; DynArray columns; DynArray values; explicit RawPSDMatrix(MemoryResource* memRes) : rows{memRes}, columns{memRes}, values{memRes} { } template void serialize(Archive& archive) { archive.label("rows"); archive(rows); archive.label("columns"); archive(columns); archive.label("values"); archive(values); } }; struct RawControls { std::uint16_t psdCount; RawConditionalTable conditionals; RawPSDMatrix psds; explicit RawControls(MemoryResource* memRes) : psdCount{}, conditionals{memRes}, psds{memRes} { } template void serialize(Archive& archive) { archive.label("psdCount"); archive(psdCount); archive.label("conditionals"); archive(conditionals); archive.label("psds"); archive(psds); } }; struct RawJointGroup { // Row count of each LOD // 12, 9, 3, // | | + LOD-2 contains first 3 rows // | + LOD-1 contains first 9 rows // + LOD-0 contains first 12 rows DynArray lods; // Sub-matrix col -> input vector DynArray inputIndices; // Sub-matrix row -> output vector DynArray outputIndices; // Non-zero values of all sub-matrices AlignedDynArray values; DynArray jointIndices; explicit RawJointGroup(MemoryResource* memRes) : lods{memRes}, inputIndices{memRes}, outputIndices{memRes}, values{memRes}, jointIndices{memRes} { } template void serialize(Archive& archive) { archive.label("lods"); archive(lods); archive.label("inputIndices"); archive(inputIndices); archive.label("outputIndices"); archive(outputIndices); archive.label("values"); archive(values); archive.label("jointIndices"); archive(jointIndices); } }; struct RawJoints { std::uint16_t rowCount; std::uint16_t colCount; Vector jointGroups; explicit RawJoints(MemoryResource* memRes) : rowCount{}, colCount{}, jointGroups{memRes} { } template void serialize(Archive& archive) { archive.label("rowCount"); archive(rowCount); archive.label("colCount"); archive(colCount); archive.label("jointGroups"); archive(jointGroups); } }; struct RawBlendShapeChannels { DynArray lods; DynArray inputIndices; DynArray outputIndices; explicit RawBlendShapeChannels(MemoryResource* memRes) : lods{memRes}, inputIndices{memRes}, outputIndices{memRes} { } template void serialize(Archive& archive) { archive.label("lods"); archive(lods); archive.label("inputIndices"); archive(inputIndices); archive.label("outputIndices"); archive(outputIndices); } }; struct RawAnimatedMaps { DynArray lods; RawConditionalTable conditionals; explicit RawAnimatedMaps(MemoryResource* memRes) : lods{memRes}, conditionals{memRes} { } template void serialize(Archive& archive) { archive.label("lods"); archive(lods); archive.label("conditionals"); archive(conditionals); } }; struct RawBehavior { RawControls controls; RawJoints joints; RawBlendShapeChannels blendShapeChannels; RawAnimatedMaps animatedMaps; explicit RawBehavior(MemoryResource* memRes) : controls{memRes}, joints{memRes}, blendShapeChannels{memRes}, animatedMaps{memRes} { } template void serialize(Archive& archive, terse::Version /*unused*/) { auto context = static_cast(archive.getUserData()); auto sections = static_cast(context->data); archive(terse::proxy(sections->controls)); archive.label("controls"); archive(controls); archive(terse::proxy(sections->joints)); archive.label("joints"); archive(joints); archive(terse::proxy(sections->blendShapeChannels)); archive.label("blendShapeChannels"); archive(blendShapeChannels); archive(terse::proxy(sections->animatedMaps)); archive.label("animatedMaps"); archive(animatedMaps); } template void serialize(Archive& archive, AnyVersion) { archive.label("controls"); archive(controls); archive.label("joints"); archive(joints); archive.label("blendShapeChannels"); archive(blendShapeChannels); archive.label("animatedMaps"); archive(animatedMaps); } }; struct RawTextureCoordinateVector { DynArray us; DynArray vs; explicit RawTextureCoordinateVector(MemoryResource* memRes) : us{memRes}, vs{memRes} { } template void serialize(Archive& archive) { archive.label("us"); archive(us); archive.label("vs"); archive(vs); } std::size_t size() const { assert(us.size() == vs.size()); return us.size(); } void clear() { us.clear(); vs.clear(); } }; struct RawVertexLayoutVector { DynArray positions; DynArray textureCoordinates; DynArray normals; explicit RawVertexLayoutVector(MemoryResource* memRes) : positions{memRes}, textureCoordinates{memRes}, normals{memRes} { } template void serialize(Archive& archive) { archive.label("positions"); archive(positions); archive.label("textureCoordinates"); archive(textureCoordinates); archive.label("normals"); archive(normals); } std::size_t size() const { assert(positions.size() == textureCoordinates.size() && textureCoordinates.size() == normals.size()); return positions.size(); } void clear() { positions.clear(); textureCoordinates.clear(); normals.clear(); } }; struct RawFace { DynArray layoutIndices; explicit RawFace(MemoryResource* memRes) : layoutIndices{memRes} { } template void serialize(Archive& archive) { archive.label("layoutIndices"); archive(layoutIndices); } }; struct RawVertexSkinWeights { AlignedDynArray weights; DynArray jointIndices; explicit RawVertexSkinWeights(MemoryResource* memRes) : weights{memRes}, jointIndices{memRes} { } template void serialize(Archive& archive) { archive.label("weights"); archive(weights); archive.label("jointIndices"); archive(jointIndices); } }; struct RawBlendShapeTarget { RawVector3Vector deltas; DynArray vertexIndices; std::uint16_t blendShapeChannelIndex; explicit RawBlendShapeTarget(MemoryResource* memRes) : deltas{memRes}, vertexIndices{memRes}, blendShapeChannelIndex{} { } template void serialize(Archive& archive) { archive.label("deltas"); archive(deltas); archive.label("vertexIndices"); archive(vertexIndices); archive.label("blendShapeChannelIndex"); archive(blendShapeChannelIndex); } }; struct RawMesh { terse::ArchiveOffset offset; terse::ArchiveSize size; terse::Anchor baseMarker; RawVector3Vector positions; RawTextureCoordinateVector textureCoordinates; RawVector3Vector normals; RawVertexLayoutVector layouts; Vector faces; std::uint16_t maximumInfluencePerVertex; Vector skinWeights; Vector blendShapeTargets; terse::ArchiveOffset::Proxy offsetMarker; terse::ArchiveSize::Proxy sizeMarker; explicit RawMesh(MemoryResource* memRes) : offset{}, size{}, baseMarker{}, positions{memRes}, textureCoordinates{memRes}, normals{memRes}, layouts{memRes}, faces{memRes}, maximumInfluencePerVertex{}, skinWeights{memRes}, blendShapeTargets{memRes}, offsetMarker{offset}, sizeMarker{size, baseMarker} { } template void serialize(Archive& archive) { auto context = static_cast(archive.getUserData()); Dispatch()(archive, *this, context->version, true); } template void serialize(Archive& archive, terse::Version /*unused*/) { // Old format uses a hacky absolute file offset pointing to the next Mesh start archive.label("offset"); archive(offset); archive.label("positions"); archive(positions); archive.label("textureCoordinates"); archive(textureCoordinates); archive.label("normals"); archive(normals); archive.label("layouts"); archive(layouts); archive.label("faces"); archive(faces); archive.label("maximumInfluencePerVertex"); archive(maximumInfluencePerVertex); archive.label("skinWeights"); archive(skinWeights); archive.label("blendShapeTargets"); archive(blendShapeTargets); archive(offsetMarker); } template void serialize(Archive& archive, AnyVersion) { // The new format uses a size, denoting the size of the current mesh, thus allowing // the same skip mechanism, but in a position independent way archive.label("size"); archive(size); archive(baseMarker); archive.label("positions"); archive(positions); archive.label("textureCoordinates"); archive(textureCoordinates); archive.label("normals"); archive(normals); archive.label("layouts"); archive(layouts); archive.label("faces"); archive(faces); archive.label("maximumInfluencePerVertex"); archive(maximumInfluencePerVertex); archive.label("skinWeights"); archive(skinWeights); archive.label("blendShapeTargets"); archive(blendShapeTargets); // Offset is not written into file archive(sizeMarker); } }; struct RawGeometry { Vector meshes; explicit RawGeometry(MemoryResource* memRes) : meshes{memRes} { } template void serialize(Archive& archive) { archive.label("meshes"); archive(meshes); } }; struct RawActivationFunction { std::uint16_t functionId; DynArray parameters; explicit RawActivationFunction(MemoryResource* memRes) : functionId{}, parameters{memRes} { } template void serialize(Archive& archive) { archive.label("functionId"); archive(functionId); archive.label("parameters"); archive(parameters); } }; struct RawNeuralNetworkLayer { DynArray biases; DynArray weights; // 2D Matrix RawActivationFunction activationFunction; explicit RawNeuralNetworkLayer(MemoryResource* memRes) : biases{memRes}, weights{memRes}, activationFunction{memRes} { } template void serialize(Archive& archive) { archive.label("biases"); archive(biases); archive.label("weights"); archive(weights); archive.label("activationFunction"); archive(activationFunction); } }; struct RawNeuralNetwork { terse::ArchiveSize size; terse::Anchor baseMarker; DynArray outputIndices; DynArray inputIndices; Vector layers; terse::ArchiveSize::Proxy sizeMarker; explicit RawNeuralNetwork(MemoryResource* memRes) : size{}, baseMarker{}, outputIndices{memRes}, inputIndices{memRes}, layers{memRes}, sizeMarker{size, baseMarker} { } template void serialize(Archive& archive) { archive.label("size"); archive(size); archive(baseMarker); archive.label("outputIndices"); archive(outputIndices); archive.label("inputIndices"); archive(inputIndices); archive.label("layers"); archive(layers); archive(sizeMarker); } }; struct RawMeshRegionMembership { Matrix > regionNames; // [meshIndex][regionIndex] Vector > indices; // [meshIndex][regionIndex][neuralNetworkIndices...] explicit RawMeshRegionMembership(MemoryResource* memRes) : regionNames{memRes}, indices{memRes} { } template void serialize(Archive& archive) { archive.label("regionNames"); archive(regionNames); archive.label("indices"); archive(indices); } }; struct RawMachineLearnedBehavior { Vector > mlControlNames; RawLODMapping lodNeuralNetworkMapping; RawMeshRegionMembership neuralNetworkToMeshRegion; Vector neuralNetworks; explicit RawMachineLearnedBehavior(MemoryResource* memRes) : mlControlNames{memRes}, lodNeuralNetworkMapping{memRes}, neuralNetworkToMeshRegion{memRes}, neuralNetworks{memRes} { } template void serialize(Archive& archive) { archive.label("mlControlNames"); archive(mlControlNames); archive.label("lodNeuralNetworkMapping"); archive(lodNeuralNetworkMapping); archive.label("neuralNetworkToMeshRegion"); archive(neuralNetworkToMeshRegion); archive.label("neuralNetworks"); archive(neuralNetworks); } }; struct RawRBFPose { String name; float scale; explicit RawRBFPose(MemoryResource* memRes) : name{memRes}, scale{1.0f} { } template void serialize(Archive& archive) { archive.label("name"); archive(name); archive.label("scale"); archive(scale); } }; struct RawRBFPoseExt { DynArray inputControlIndices; DynArray outputControlIndices; DynArray outputControlWeights; explicit RawRBFPoseExt(MemoryResource* memRes) : inputControlIndices{memRes}, outputControlIndices{memRes}, outputControlWeights{memRes} { } template void serialize(Archive& archive) { archive.label("inputControlIndices"); archive(inputControlIndices); archive.label("outputControlIndices"); archive(outputControlIndices); archive.label("outputControlWeights"); archive(outputControlWeights); } }; struct RawRBFSolver { terse::ArchiveSize size; terse::Anchor baseMarker; String name; DynArray rawControlIndices; DynArray poseIndices; DynArray rawControlValues; float radius; float weightThreshold; std::uint16_t solverType; std::uint16_t automaticRadius; std::uint16_t distanceMethod; std::uint16_t normalizeMethod; std::uint16_t functionType; std::uint16_t twistAxis; terse::ArchiveSize::Proxy sizeMarker; explicit RawRBFSolver(MemoryResource* memRes) : size{}, baseMarker{}, name{memRes}, rawControlIndices{memRes}, poseIndices{memRes}, rawControlValues{memRes}, radius{}, weightThreshold{}, solverType{}, automaticRadius{}, distanceMethod{}, normalizeMethod{}, functionType{}, twistAxis{}, sizeMarker{size, baseMarker} { } template void serialize(Archive& archive) { archive.label("size"); archive(size); archive(baseMarker); archive.label("name"); archive(name); archive.label("rawControlIndices"); archive(rawControlIndices); archive.label("poseIndices"); archive(poseIndices); archive.label("rawControlValues"); archive(rawControlValues); archive.label("radius"); archive(radius); archive.label("weightThreshold"); archive(weightThreshold); archive.label("solverType"); archive(solverType); archive.label("automaticRadius"); archive(automaticRadius); archive.label("distanceMethod"); archive(distanceMethod); archive.label("normalizeMethod"); archive(normalizeMethod); archive.label("functionType"); archive(functionType); archive.label("twistAxis"); archive(twistAxis); archive(sizeMarker); } }; struct RawRBFBehavior { RawLODMapping lodSolverMapping; Vector solvers; Vector poses; explicit RawRBFBehavior(MemoryResource* memRes) : lodSolverMapping{memRes}, solvers{memRes}, poses{memRes} { } template void serialize(Archive& archive) { archive.label("lodSolverMapping"); archive(lodSolverMapping); archive.label("solvers"); archive(solvers); archive.label("poses"); archive(poses); } }; struct RawRBFBehaviorExt { Vector > poseControlNames; Vector poses; explicit RawRBFBehaviorExt(MemoryResource* memRes) : poseControlNames{memRes}, poses{memRes} { } template void serialize(Archive& archive) { archive.label("poseControlNames"); archive(poseControlNames); archive.label("poses"); archive(poses); } }; struct RawJointRepresentation { std::uint16_t translation; std::uint16_t rotation; std::uint16_t scale; template void serialize(Archive& archive) { archive.label("translation"); archive(translation); archive.label("rotation"); archive(rotation); archive.label("scale"); archive(scale); } }; struct RawJointBehaviorMetadata { Vector jointRepresentations; explicit RawJointBehaviorMetadata(MemoryResource* memRes) : jointRepresentations{memRes} { } template void serialize(Archive& archive) { archive.label("jointRepresentations"); archive(jointRepresentations); } }; struct RawTwist { DynArray twistBlendWeights; DynArray twistOutputJointIndices; DynArray twistInputControlIndices; std::uint16_t twistAxis; explicit RawTwist(MemoryResource* memRes) : twistBlendWeights{memRes}, twistOutputJointIndices{memRes}, twistInputControlIndices{memRes}, twistAxis{} { } template void serialize(Archive& archive) { archive.label("twistBlendWeights"); archive(twistBlendWeights); archive.label("twistOutputJointIndices"); archive(twistOutputJointIndices); archive.label("twistInputControlIndices"); archive(twistInputControlIndices); archive.label("twistAxis"); archive(twistAxis); } }; struct RawSwing { DynArray swingBlendWeights; DynArray swingOutputJointIndices; DynArray swingInputControlIndices; std::uint16_t twistAxis; explicit RawSwing(MemoryResource* memRes) : swingBlendWeights{memRes}, swingOutputJointIndices{memRes}, swingInputControlIndices{memRes}, twistAxis{} { } template void serialize(Archive& archive) { archive.label("swingBlendWeights"); archive(swingBlendWeights); archive.label("swingOutputJointIndices"); archive(swingOutputJointIndices); archive.label("swingInputControlIndices"); archive(swingInputControlIndices); archive.label("twistAxis"); archive(twistAxis); } }; struct RawTwistSwingBehavior { Vector twists; Vector swings; explicit RawTwistSwingBehavior(MemoryResource* memRes) : twists{memRes}, swings{memRes} { } template void serialize(Archive& archive) { archive.label("twists"); archive(twists); archive.label("swings"); archive(swings); } }; struct DNA { MemoryResource* memRes; Signature<3> signature{{'D', 'N', 'A'}}; Version version{FileVersion::latest}; IndexTable indexTable; Layer descriptor; Layer definition; Layer behavior; Layer geometry; Layer machineLearnedBehavior; Layer rbfBehavior; Layer rbfBehaviorExt; Layer jointBehaviorMetadata; Layer twistSwingBehavior; using Layers = LayerContainer; Layers layers; DNA(UnknownLayerPolicy unknownPolicy, UpgradeFormatPolicy upgradePolicy, MemoryResource* memRes_) : memRes{memRes_}, indexTable{memRes_}, descriptor{memRes}, definition{memRes}, behavior{memRes}, geometry{memRes}, machineLearnedBehavior{memRes}, rbfBehavior{memRes}, rbfBehaviorExt{memRes}, jointBehaviorMetadata{memRes}, twistSwingBehavior{memRes}, layers{unknownPolicy, upgradePolicy, memRes, &descriptor, &definition, &behavior, &geometry, &machineLearnedBehavior, &rbfBehavior, &rbfBehaviorExt, &jointBehaviorMetadata, &twistSwingBehavior} { } explicit DNA(MemoryResource* memRes_) : DNA{UnknownLayerPolicy::Preserve, UpgradeFormatPolicy::Allowed, memRes_} { } template void serialize(Archive& archive) { archive.label("signature"); archive(signature); archive.label("version"); archive(version); if (!signature.matches()) { return; } SerializationContext context{version, nullptr}; auto oldUserData = archive.getUserData(); archive.setUserData(&context); Dispatch()(archive, *this, version, true); archive.setUserData(oldUserData); } template void serialize(Archive& archive, terse::Version v21) { auto context = static_cast(archive.getUserData()); SectionLookupTable sections; context->data = §ions; archive.label("sections"); archive(sections); archive.label("descriptor"); archive(terse::proxy(sections.descriptor)); archive(terse::versioned(static_cast(descriptor), v21)); archive.label("definition"); archive(terse::proxy(sections.definition)); archive(terse::versioned(static_cast(definition), v21)); archive.label("behavior"); archive(terse::proxy(sections.behavior)); archive(terse::versioned(static_cast(behavior), v21)); archive.label("geometry"); archive(terse::proxy(sections.geometry)); archive(terse::versioned(static_cast(geometry), v21)); Signature<3> eof{{'A', 'N', 'D'}}; archive(eof); assert(eof.matches()); context->data = nullptr; } template IfHigher load(Archive& archive, AnyVersion) { auto context = static_cast(archive.getUserData()); archive.label("index"); archive(indexTable); std::size_t indexCount = indexTable.entries.size(); for (std::size_t i = {}; i < indexCount;) { auto& index = indexTable.entries[i]; context->data = &index; archive(terse::transparent(layers)); // Check if index was marked for deletion, and if so, get rid of it if (context->data == nullptr) { indexTable.destroy(index.id, index.version); --indexCount; } else { ++i; } } context->data = nullptr; postLoadActions(); } template IfHigher save(Archive& archive, AnyVersion) { auto context = static_cast(archive.getUserData()); // Add layers to index that were not already there layers.updateIndexTable(indexTable, context->version); archive.label("index"); archive(indexTable); for (auto& index : indexTable.entries) { context->data = &index; archive(terse::transparent(layers)); } } void postLoadActions() { if (rbfBehaviorExt.poses.empty() && !rbfBehavior.poses.empty()) { rbfBehaviorExt.poses.resize(rbfBehavior.poses.size(), RawRBFPoseExt{memRes}); rbfBehaviorExt.poseControlNames.resize(rbfBehavior.poses.size()); const auto controlOffset = (definition.rawControlNames.size() + behavior.controls.psdCount + machineLearnedBehavior.mlControlNames.size()); for (std::size_t pi = {}; pi < rbfBehaviorExt.poses.size(); ++pi) { rbfBehaviorExt.poseControlNames[pi] = rbfBehavior.poses[pi].name; rbfBehaviorExt.poses[pi].outputControlIndices.resize(1ul); rbfBehaviorExt.poses[pi].outputControlWeights.resize(1ul); rbfBehaviorExt.poses[pi].outputControlIndices[0] = static_cast(controlOffset + pi); rbfBehaviorExt.poses[pi].outputControlWeights[0] = 1.0f; } } } void unloadDefinition() { static_cast(definition) = RawDefinition{memRes}; } void unloadBehavior() { static_cast(behavior) = RawBehavior{memRes}; } void unloadGeometry() { static_cast(geometry) = RawGeometry{memRes}; } void unloadMachineLearnedBehavior() { static_cast(machineLearnedBehavior) = RawMachineLearnedBehavior{memRes}; } void unloadRBFBehavior() { static_cast(rbfBehavior) = RawRBFBehavior{memRes}; static_cast(rbfBehaviorExt) = RawRBFBehaviorExt{memRes}; } void unloadJointBehaviorMetadata() { static_cast(jointBehaviorMetadata) = RawJointBehaviorMetadata{memRes}; } void unloadTwistSwingBehavior() { static_cast(twistSwingBehavior) = RawTwistSwingBehavior{memRes}; } }; } // namespace dna