Files
UnrealEngine/Engine/Plugins/Animation/RigLogic/Source/RigLogicLib/Private/dna/DNA.h
2025-05-18 13:04:45 +08:00

1746 lines
50 KiB
C++

// 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 <terse/types/Anchor.h>
#include <terse/types/ArchiveOffset.h>
#include <terse/types/ArchiveSize.h>
#include <terse/types/Transparent.h>
#include <terse/types/Versioned.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4365 4987)
#endif
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <memory>
#include <tuple>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
namespace dna {
template<typename TVersion, TVersion... Args>
struct Dispatcher;
template<typename TVersion, TVersion Fallback>
struct Dispatcher<TVersion, Fallback> {
template<class Archive, typename TSerializable>
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<Fallback>{});
if (transparent) {
archive(terse::transparent(versionedObject));
} else {
archive(versionedObject);
}
}
};
template<typename TVersion, TVersion Expected, TVersion... Rest>
struct Dispatcher<TVersion, Expected, Rest...> : Dispatcher<TVersion, Rest...> {
using Super = Dispatcher<TVersion, Rest...>;
template<class Archive, typename TSerializable>
void operator()(Archive& archive, TSerializable& object, TVersion version, bool transparent) {
if (version == Expected) {
auto versionedObject = terse::versioned(object, terse::Version<Expected>{});
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<std::uint32_t>(name[0]) << 24u) +
(static_cast<std::uint32_t>(name[1]) << 16u) +
(static_cast<std::uint32_t>(name[2]) << 8u) +
(static_cast<std::uint32_t>(name[3]) << 0u));
}
static constexpr std::uint32_t rev(std::uint16_t generation, std::uint16_t version) {
return (static_cast<std::uint32_t>(generation) << 16u) + static_cast<std::uint32_t>(version);
}
static constexpr std::uint16_t high16(std::uint32_t packed) {
return static_cast<std::uint16_t>(packed >> 16u);
}
static constexpr std::uint16_t low16(std::uint32_t packed) {
return static_cast<std::uint16_t>(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<FileVersion, FileVersion::v21, FileVersion::v22, FileVersion::v23, FileVersion::v24>;
template<typename A, FileVersion B>
using IfHigher = typename std::enable_if<(A::value() > B), void>::type;
template<typename A, FileVersion B>
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<std::uint32_t>(fileVersion))},
version{low16(static_cast<std::uint32_t>(fileVersion))} {
}
operator FileVersion() const {
return static_cast<FileVersion>(rev(generation, version));
}
template<class Archive>
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<typename T>
struct ExpectedValue {
T expected;
T got;
explicit ExpectedValue(const T& value) : expected{value}, got{} {
}
template<class Archive>
void load(Archive& archive) {
archive.label("value");
archive(got);
}
template<class Archive>
void save(Archive& archive) {
archive.label("value");
archive(expected);
got = expected;
}
bool matches() const {
return (expected == got);
}
};
template<std::size_t Size>
struct Signature {
using SignatureValueType = std::array<char, Size>;
ExpectedValue<SignatureValueType> value;
explicit Signature(SignatureValueType bytes) : value{bytes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("data");
archive(value);
}
bool matches() const {
return value.matches();
}
};
struct SectionLookupTable {
terse::ArchiveOffset<std::uint32_t> descriptor;
terse::ArchiveOffset<std::uint32_t> definition;
terse::ArchiveOffset<std::uint32_t> behavior;
terse::ArchiveOffset<std::uint32_t> controls;
terse::ArchiveOffset<std::uint32_t> joints;
terse::ArchiveOffset<std::uint32_t> blendShapeChannels;
terse::ArchiveOffset<std::uint32_t> animatedMaps;
terse::ArchiveOffset<std::uint32_t> geometry;
template<class Archive>
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<std::uint32_t> offset;
terse::ArchiveSize<std::uint32_t, std::uint32_t> size;
template<std::size_t Length = 16ul>
std::array<char, Length> label() {
std::array<char, Length> 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<class Archive>
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<Index> 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<IndexTable*>(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<class Archive>
void serialize(Archive& archive) {
archive.label("entries");
archive(entries);
}
};
struct UnknownLayer {
std::uint32_t id;
std::uint32_t version;
Blob<char> 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<class Archive>
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<SerializationContext*>(archive.getUserData());
auto index = static_cast<Index*>(context->data);
const auto layerName = index->label();
archive.label(layerName.data());
archive(terse::proxy(index->offset));
terse::Anchor<std::uint32_t> base;
archive(base);
data.setSize(index->size.value);
archive(data);
archive(terse::proxy(index->size, base));
}
};
template<std::uint32_t Id, std::uint32_t Version, typename TData, FileVersion AvailableFromFileVersion>
struct Layer : TData {
template<typename ... Args>
explicit Layer(Args&& ... args) : TData{std::forward<Args>(args)...} {
}
std::uint32_t layerId() {
return Id;
}
std::uint32_t layerVersion() {
return Version;
}
bool layerSupported(FileVersion inVersion) {
return (inVersion >= AvailableFromFileVersion);
}
template<class Archive>
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<SerializationContext*>(archive.getUserData());
auto index = static_cast<Index*>(context->data);
const auto layerName = index->label();
archive.label(layerName.data());
archive(terse::proxy(index->offset));
terse::Anchor<std::uint32_t> base;
archive(base);
Dispatch()(archive, static_cast<TData&>(*this), context->version, false);
archive(terse::proxy(index->size, base));
}
};
template<typename ... TLayer>
struct LayerContainer;
template<>
struct LayerContainer<> {
UnknownLayerPolicy unknownPolicy;
UpgradeFormatPolicy upgradePolicy;
Vector<UnknownLayer> unknownLayers;
LayerContainer(UnknownLayerPolicy unknownPolicy_, UpgradeFormatPolicy upgradePolicy_, MemoryResource* memRes) :
unknownPolicy{unknownPolicy_}, upgradePolicy{upgradePolicy_}, unknownLayers{memRes} {
}
template<typename TArchive>
void serialize(TArchive& archive) {
auto context = static_cast<SerializationContext*>(archive.getUserData());
auto index = static_cast<Index*>(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<typename TLayer, typename ... TRest>
struct LayerContainer<TLayer, TRest...> : LayerContainer<TRest...> {
using Super = LayerContainer<TRest...>;
TLayer* layer;
LayerContainer(UnknownLayerPolicy unknownPolicy_,
UpgradeFormatPolicy upgradePolicy_,
MemoryResource* memRes,
TLayer* layer_,
TRest* ... rest) :
Super{unknownPolicy_, upgradePolicy_, memRes, std::forward<TRest*>(rest)...},
layer{layer_} {
}
template<typename TArchive>
void serialize(TArchive& archive) {
auto context = static_cast<SerializationContext*>(archive.getUserData());
auto index = static_cast<Index*>(context->data);
if ((index->id == layer->layerId()) && (index->version == layer->layerVersion())) {
archive(terse::transparent(*layer));
} else {
archive(terse::transparent(static_cast<Super&>(*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<typename TFrom, typename TTo = TFrom>
struct RawSurjectiveMapping : public SurjectiveMapping<TFrom, TTo> {
using SurjectiveMapping<TFrom, TTo>::SurjectiveMapping;
template<class Archive>
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<class Archive>
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<class Archive>
void serialize(Archive& archive) {
archive.label("lods");
archive(lods);
archive.label("indices");
archive(indices);
}
};
struct RawDescriptor {
using StringPair = std::tuple<String<char>, String<char> >;
String<char> name;
std::uint16_t archetype;
std::uint16_t gender;
std::uint16_t age;
Vector<StringPair> metadata;
std::uint16_t translationUnit;
std::uint16_t rotationUnit;
RawCoordinateSystem coordinateSystem;
std::uint16_t lodCount;
std::uint16_t maxLOD;
String<char> complexity;
String<char> dbName;
explicit RawDescriptor(MemoryResource* memRes) :
name{memRes},
archetype{},
gender{},
age{},
metadata{memRes},
translationUnit{},
rotationUnit{},
coordinateSystem{},
lodCount{},
maxLOD{},
complexity{memRes},
dbName{memRes} {
}
template<class Archive>
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<float> xs;
AlignedDynArray<float> ys;
AlignedDynArray<float> 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<float> xs_, ConstArrayView<float> ys_, ConstArrayView<float> zs_, MemoryResource* memRes) :
xs{xs_.begin(), xs_.end(), memRes},
ys{ys_.begin(), ys_.end(), memRes},
zs{zs_.begin(), zs_.end(), memRes} {
}
template<class Archive>
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<typename Iterator>
void assign(Iterator start, Iterator end) {
reserve(static_cast<std::size_t>(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<String<char> > guiControlNames;
Vector<String<char> > rawControlNames;
Vector<String<char> > jointNames;
Vector<String<char> > blendShapeChannelNames;
Vector<String<char> > animatedMapNames;
Vector<String<char> > meshNames;
RawSurjectiveMapping<std::uint16_t> meshBlendShapeChannelMapping;
DynArray<std::uint16_t> 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<class Archive>
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<std::uint16_t> inputIndices;
DynArray<std::uint16_t> outputIndices;
DynArray<float> fromValues;
DynArray<float> toValues;
DynArray<float> slopeValues;
DynArray<float> cutValues;
explicit RawConditionalTable(MemoryResource* memRes) :
inputIndices{memRes},
outputIndices{memRes},
fromValues{memRes},
toValues{memRes},
slopeValues{memRes},
cutValues{memRes} {
}
template<class Archive>
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<std::uint16_t> rows;
DynArray<std::uint16_t> columns;
DynArray<float> values;
explicit RawPSDMatrix(MemoryResource* memRes) :
rows{memRes},
columns{memRes},
values{memRes} {
}
template<class Archive>
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<class Archive>
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<std::uint16_t> lods;
// Sub-matrix col -> input vector
DynArray<std::uint16_t> inputIndices;
// Sub-matrix row -> output vector
DynArray<std::uint16_t> outputIndices;
// Non-zero values of all sub-matrices
AlignedDynArray<float> values;
DynArray<std::uint16_t> jointIndices;
explicit RawJointGroup(MemoryResource* memRes) :
lods{memRes},
inputIndices{memRes},
outputIndices{memRes},
values{memRes},
jointIndices{memRes} {
}
template<class Archive>
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<RawJointGroup> jointGroups;
explicit RawJoints(MemoryResource* memRes) :
rowCount{},
colCount{},
jointGroups{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("rowCount");
archive(rowCount);
archive.label("colCount");
archive(colCount);
archive.label("jointGroups");
archive(jointGroups);
}
};
struct RawBlendShapeChannels {
DynArray<std::uint16_t> lods;
DynArray<std::uint16_t> inputIndices;
DynArray<std::uint16_t> outputIndices;
explicit RawBlendShapeChannels(MemoryResource* memRes) :
lods{memRes},
inputIndices{memRes},
outputIndices{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("lods");
archive(lods);
archive.label("inputIndices");
archive(inputIndices);
archive.label("outputIndices");
archive(outputIndices);
}
};
struct RawAnimatedMaps {
DynArray<std::uint16_t> lods;
RawConditionalTable conditionals;
explicit RawAnimatedMaps(MemoryResource* memRes) :
lods{memRes},
conditionals{memRes} {
}
template<class Archive>
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<class Archive>
void serialize(Archive& archive, terse::Version<FileVersion::v21> /*unused*/) {
auto context = static_cast<SerializationContext*>(archive.getUserData());
auto sections = static_cast<SectionLookupTable*>(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<class Archive, typename AnyVersion>
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<float> us;
DynArray<float> vs;
explicit RawTextureCoordinateVector(MemoryResource* memRes) :
us{memRes},
vs{memRes} {
}
template<class Archive>
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<std::uint32_t> positions;
DynArray<std::uint32_t> textureCoordinates;
DynArray<std::uint32_t> normals;
explicit RawVertexLayoutVector(MemoryResource* memRes) :
positions{memRes},
textureCoordinates{memRes},
normals{memRes} {
}
template<class Archive>
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<std::uint32_t> layoutIndices;
explicit RawFace(MemoryResource* memRes) :
layoutIndices{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("layoutIndices");
archive(layoutIndices);
}
};
struct RawVertexSkinWeights {
AlignedDynArray<float> weights;
DynArray<std::uint16_t> jointIndices;
explicit RawVertexSkinWeights(MemoryResource* memRes) :
weights{memRes},
jointIndices{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("weights");
archive(weights);
archive.label("jointIndices");
archive(jointIndices);
}
};
struct RawBlendShapeTarget {
RawVector3Vector deltas;
DynArray<std::uint32_t> vertexIndices;
std::uint16_t blendShapeChannelIndex;
explicit RawBlendShapeTarget(MemoryResource* memRes) :
deltas{memRes},
vertexIndices{memRes},
blendShapeChannelIndex{} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("deltas");
archive(deltas);
archive.label("vertexIndices");
archive(vertexIndices);
archive.label("blendShapeChannelIndex");
archive(blendShapeChannelIndex);
}
};
struct RawMesh {
terse::ArchiveOffset<std::uint32_t> offset;
terse::ArchiveSize<std::uint32_t, std::uint32_t> size;
terse::Anchor<std::uint32_t> baseMarker;
RawVector3Vector positions;
RawTextureCoordinateVector textureCoordinates;
RawVector3Vector normals;
RawVertexLayoutVector layouts;
Vector<RawFace> faces;
std::uint16_t maximumInfluencePerVertex;
Vector<RawVertexSkinWeights> skinWeights;
Vector<RawBlendShapeTarget> blendShapeTargets;
terse::ArchiveOffset<std::uint32_t>::Proxy offsetMarker;
terse::ArchiveSize<std::uint32_t, std::uint32_t>::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<class Archive>
void serialize(Archive& archive) {
auto context = static_cast<SerializationContext*>(archive.getUserData());
Dispatch()(archive, *this, context->version, true);
}
template<class Archive>
void serialize(Archive& archive, terse::Version<FileVersion::v21> /*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<class Archive, typename AnyVersion>
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<RawMesh> meshes;
explicit RawGeometry(MemoryResource* memRes) : meshes{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("meshes");
archive(meshes);
}
};
struct RawActivationFunction {
std::uint16_t functionId;
DynArray<float> parameters;
explicit RawActivationFunction(MemoryResource* memRes) : functionId{}, parameters{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("functionId");
archive(functionId);
archive.label("parameters");
archive(parameters);
}
};
struct RawNeuralNetworkLayer {
DynArray<float> biases;
DynArray<float> weights; // 2D Matrix
RawActivationFunction activationFunction;
explicit RawNeuralNetworkLayer(MemoryResource* memRes) :
biases{memRes},
weights{memRes},
activationFunction{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("biases");
archive(biases);
archive.label("weights");
archive(weights);
archive.label("activationFunction");
archive(activationFunction);
}
};
struct RawNeuralNetwork {
terse::ArchiveSize<std::uint32_t, std::uint32_t> size;
terse::Anchor<std::uint32_t> baseMarker;
DynArray<std::uint16_t> outputIndices;
DynArray<std::uint16_t> inputIndices;
Vector<RawNeuralNetworkLayer> layers;
terse::ArchiveSize<std::uint32_t, std::uint32_t>::Proxy sizeMarker;
explicit RawNeuralNetwork(MemoryResource* memRes) :
size{},
baseMarker{},
outputIndices{memRes},
inputIndices{memRes},
layers{memRes},
sizeMarker{size, baseMarker} {
}
template<class Archive>
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<String<char> > regionNames; // [meshIndex][regionIndex]
Vector<Matrix<std::uint16_t> > indices; // [meshIndex][regionIndex][neuralNetworkIndices...]
explicit RawMeshRegionMembership(MemoryResource* memRes) :
regionNames{memRes},
indices{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("regionNames");
archive(regionNames);
archive.label("indices");
archive(indices);
}
};
struct RawMachineLearnedBehavior {
Vector<String<char> > mlControlNames;
RawLODMapping lodNeuralNetworkMapping;
RawMeshRegionMembership neuralNetworkToMeshRegion;
Vector<RawNeuralNetwork> neuralNetworks;
explicit RawMachineLearnedBehavior(MemoryResource* memRes) :
mlControlNames{memRes},
lodNeuralNetworkMapping{memRes},
neuralNetworkToMeshRegion{memRes},
neuralNetworks{memRes} {
}
template<class Archive>
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<char> name;
float scale;
explicit RawRBFPose(MemoryResource* memRes) :
name{memRes},
scale{1.0f} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("name");
archive(name);
archive.label("scale");
archive(scale);
}
};
struct RawRBFPoseExt {
DynArray<std::uint16_t> inputControlIndices;
DynArray<std::uint16_t> outputControlIndices;
DynArray<float> outputControlWeights;
explicit RawRBFPoseExt(MemoryResource* memRes) :
inputControlIndices{memRes},
outputControlIndices{memRes},
outputControlWeights{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("inputControlIndices");
archive(inputControlIndices);
archive.label("outputControlIndices");
archive(outputControlIndices);
archive.label("outputControlWeights");
archive(outputControlWeights);
}
};
struct RawRBFSolver {
terse::ArchiveSize<std::uint32_t, std::uint32_t> size;
terse::Anchor<std::uint32_t> baseMarker;
String<char> name;
DynArray<std::uint16_t> rawControlIndices;
DynArray<std::uint16_t> poseIndices;
DynArray<float> 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<std::uint32_t, std::uint32_t>::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<class Archive>
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<RawRBFSolver> solvers;
Vector<RawRBFPose> poses;
explicit RawRBFBehavior(MemoryResource* memRes) :
lodSolverMapping{memRes},
solvers{memRes},
poses{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("lodSolverMapping");
archive(lodSolverMapping);
archive.label("solvers");
archive(solvers);
archive.label("poses");
archive(poses);
}
};
struct RawRBFBehaviorExt {
Vector<String<char> > poseControlNames;
Vector<RawRBFPoseExt> poses;
explicit RawRBFBehaviorExt(MemoryResource* memRes) :
poseControlNames{memRes},
poses{memRes} {
}
template<class Archive>
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<class Archive>
void serialize(Archive& archive) {
archive.label("translation");
archive(translation);
archive.label("rotation");
archive(rotation);
archive.label("scale");
archive(scale);
}
};
struct RawJointBehaviorMetadata {
Vector<RawJointRepresentation> jointRepresentations;
explicit RawJointBehaviorMetadata(MemoryResource* memRes) :
jointRepresentations{memRes} {
}
template<class Archive>
void serialize(Archive& archive) {
archive.label("jointRepresentations");
archive(jointRepresentations);
}
};
struct RawTwist {
DynArray<float> twistBlendWeights;
DynArray<std::uint16_t> twistOutputJointIndices;
DynArray<std::uint16_t> twistInputControlIndices;
std::uint16_t twistAxis;
explicit RawTwist(MemoryResource* memRes) :
twistBlendWeights{memRes},
twistOutputJointIndices{memRes},
twistInputControlIndices{memRes},
twistAxis{} {
}
template<class Archive>
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<float> swingBlendWeights;
DynArray<std::uint16_t> swingOutputJointIndices;
DynArray<std::uint16_t> swingInputControlIndices;
std::uint16_t twistAxis;
explicit RawSwing(MemoryResource* memRes) :
swingBlendWeights{memRes},
swingOutputJointIndices{memRes},
swingInputControlIndices{memRes},
twistAxis{} {
}
template<class Archive>
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<RawTwist> twists;
Vector<RawSwing> swings;
explicit RawTwistSwingBehavior(MemoryResource* memRes) :
twists{memRes},
swings{memRes} {
}
template<class Archive>
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<sid4("desc"), rev(1, 1), RawDescriptor, FileVersion::v22> descriptor;
Layer<sid4("defn"), rev(1, 1), RawDefinition, FileVersion::v22> definition;
Layer<sid4("bhvr"), rev(1, 1), RawBehavior, FileVersion::v22> behavior;
Layer<sid4("geom"), rev(1, 1), RawGeometry, FileVersion::v22> geometry;
Layer<sid4("mlbh"), rev(1, 0), RawMachineLearnedBehavior, FileVersion::v23> machineLearnedBehavior;
Layer<sid4("rbfb"), rev(1, 0), RawRBFBehavior, FileVersion::v24> rbfBehavior;
Layer<sid4("rbfe"), rev(1, 0), RawRBFBehaviorExt, FileVersion::v25> rbfBehaviorExt;
Layer<sid4("jbmd"), rev(1, 0), RawJointBehaviorMetadata, FileVersion::v24> jointBehaviorMetadata;
Layer<sid4("twsw"), rev(1, 0), RawTwistSwingBehavior, FileVersion::v24> twistSwingBehavior;
using Layers =
LayerContainer<decltype(descriptor),
decltype(definition),
decltype(behavior),
decltype(geometry),
decltype(machineLearnedBehavior),
decltype(rbfBehavior),
decltype(rbfBehaviorExt),
decltype(jointBehaviorMetadata),
decltype(twistSwingBehavior)>;
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<class Archive>
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<class Archive>
void serialize(Archive& archive, terse::Version<FileVersion::v21> v21) {
auto context = static_cast<SerializationContext*>(archive.getUserData());
SectionLookupTable sections;
context->data = &sections;
archive.label("sections");
archive(sections);
archive.label("descriptor");
archive(terse::proxy(sections.descriptor));
archive(terse::versioned(static_cast<RawDescriptor&>(descriptor), v21));
archive.label("definition");
archive(terse::proxy(sections.definition));
archive(terse::versioned(static_cast<RawDefinition&>(definition), v21));
archive.label("behavior");
archive(terse::proxy(sections.behavior));
archive(terse::versioned(static_cast<RawBehavior&>(behavior), v21));
archive.label("geometry");
archive(terse::proxy(sections.geometry));
archive(terse::versioned(static_cast<RawGeometry&>(geometry), v21));
Signature<3> eof{{'A', 'N', 'D'}};
archive(eof);
assert(eof.matches());
context->data = nullptr;
}
template<class Archive, typename AnyVersion>
IfHigher<AnyVersion, FileVersion::v21> load(Archive& archive, AnyVersion) {
auto context = static_cast<SerializationContext*>(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<class Archive, typename AnyVersion>
IfHigher<AnyVersion, FileVersion::v21> save(Archive& archive, AnyVersion) {
auto context = static_cast<SerializationContext*>(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<std::uint16_t>(controlOffset + pi);
rbfBehaviorExt.poses[pi].outputControlWeights[0] = 1.0f;
}
}
}
void unloadDefinition() {
static_cast<RawDefinition&>(definition) = RawDefinition{memRes};
}
void unloadBehavior() {
static_cast<RawBehavior&>(behavior) = RawBehavior{memRes};
}
void unloadGeometry() {
static_cast<RawGeometry&>(geometry) = RawGeometry{memRes};
}
void unloadMachineLearnedBehavior() {
static_cast<RawMachineLearnedBehavior&>(machineLearnedBehavior) = RawMachineLearnedBehavior{memRes};
}
void unloadRBFBehavior() {
static_cast<RawRBFBehavior&>(rbfBehavior) = RawRBFBehavior{memRes};
static_cast<RawRBFBehaviorExt&>(rbfBehaviorExt) = RawRBFBehaviorExt{memRes};
}
void unloadJointBehaviorMetadata() {
static_cast<RawJointBehaviorMetadata&>(jointBehaviorMetadata) = RawJointBehaviorMetadata{memRes};
}
void unloadTwistSwingBehavior() {
static_cast<RawTwistSwingBehavior&>(twistSwingBehavior) = RawTwistSwingBehavior{memRes};
}
};
} // namespace dna