// Copyright Epic Games, Inc. All Rights Reserved. #include "dna/Writer.h" #include "dna/Reader.h" #include "dna/DataLayerBitmask.h" #include "dna/TypeDefs.h" #include "dna/types/Vector3.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4365 4987) #endif #include #ifdef _MSC_VER #pragma warning(pop) #endif namespace dna { namespace { using Vector3Vector = Vector; using TextureCoordinateVector = Vector; using VertexLayoutVector = Vector; } // namespace HeaderWriter::~HeaderWriter() = default; DescriptorWriter::~DescriptorWriter() = default; DefinitionWriter::~DefinitionWriter() = default; BehaviorWriter::~BehaviorWriter() = default; GeometryWriter::~GeometryWriter() = default; MachineLearnedBehaviorWriter::~MachineLearnedBehaviorWriter() = default; RBFBehaviorWriter::~RBFBehaviorWriter() = default; TwistSwingBehaviorWriter::~TwistSwingBehaviorWriter() = default; JointBehaviorMetadataWriter::~JointBehaviorMetadataWriter() = default; Writer::~Writer() = default; template static TVector collect_n(std::size_t count, TGetter getter, MemoryResource* memRes) { TVector retval{memRes}; retval.reserve(count); for (std::size_t i = 0ul; i < count; ++i) { retval.push_back(getter(i)); } return retval; } static void copyHeader(const HeaderReader* source, HeaderWriter* destination, MemoryResource* /*unused*/) { destination->setFileFormatGeneration(source->getFileFormatGeneration()); destination->setFileFormatVersion(source->getFileFormatVersion()); } static void copyDescriptor(const DescriptorReader* source, DescriptorWriter* destination, MemoryResource* /*unused*/) { destination->setName(source->getName()); destination->setArchetype(source->getArchetype()); destination->setGender(source->getGender()); destination->setAge(source->getAge()); destination->clearMetaData(); for (std::uint32_t i = {}; i < source->getMetaDataCount(); ++i) { const auto key = source->getMetaDataKey(i); const auto value = source->getMetaDataValue(key); destination->setMetaData(key, value); } destination->setTranslationUnit(source->getTranslationUnit()); destination->setRotationUnit(source->getRotationUnit()); destination->setCoordinateSystem(source->getCoordinateSystem()); destination->setLODCount(source->getLODCount()); destination->setDBMaxLOD(source->getDBMaxLOD()); destination->setDBComplexity(source->getDBComplexity()); destination->setDBName(source->getDBName()); } static std::pair findIndices(const Matrix& source, ConstArrayView indices) { // In the common scenario each LOD has it's unique set of indices for (std::size_t i = 0ul; i < source.size(); ++i) { ConstArrayView candidate{source[i].data(), source[i].size()}; if (indices == candidate) { // Unless the indices are the same between multiple LODs, in which case use the // already registered index return {true, static_cast(i)}; } } return {false, static_cast(0)}; } using IndicesGetter = std::function(std::uint16_t)>; using IndicesSetter = std::function; using LODMappingSetter = std::function; static void copyLODIndices(IndicesGetter getIndices, IndicesSetter setIndices, LODMappingSetter setLODMapping, std::uint16_t lodCount, MemoryResource* memRes) { Matrix allIndices{memRes}; std::uint16_t index = {}; for (std::uint16_t lod = {}; lod < lodCount; ++lod) { auto indices = getIndices(lod); // Check if these same indices were perhaps already used for previous LODs auto found = findIndices(allIndices, indices); if (!found.first) { setIndices(index, indices.data(), static_cast(indices.size())); setLODMapping(lod, index); allIndices.emplace_back(indices.begin(), indices.end()); ++index; } else { // Already used so do not replicate the same data twice setLODMapping(lod, found.second); } } } static void copyDefinition(const DefinitionReader* source, DefinitionWriter* destination, MemoryResource* memRes) { destination->clearGUIControlNames(); destination->clearRawControlNames(); destination->clearJointNames(); destination->clearBlendShapeChannelNames(); destination->clearAnimatedMapNames(); destination->clearMeshNames(); destination->clearJointIndices(); destination->clearLODJointMappings(); destination->clearBlendShapeChannelIndices(); destination->clearLODBlendShapeChannelMappings(); destination->clearAnimatedMapIndices(); destination->clearLODAnimatedMapMappings(); destination->clearMeshIndices(); destination->clearLODMeshMappings(); destination->clearMeshBlendShapeChannelMappings(); const auto lodCount = source->getLODCount(); for (std::uint16_t i = source->getGUIControlCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setGUIControlName(idx, source->getGUIControlName(idx).data()); } for (std::uint16_t i = source->getRawControlCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setRawControlName(idx, source->getRawControlName(idx).data()); } for (std::uint16_t i = source->getJointCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setJointName(idx, source->getJointName(idx).data()); } for (std::uint16_t i = source->getBlendShapeChannelCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setBlendShapeChannelName(idx, source->getBlendShapeChannelName(idx).data()); } for (std::uint16_t i = source->getAnimatedMapCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setAnimatedMapName(idx, source->getAnimatedMapName(idx)); } for (std::uint16_t i = source->getMeshCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setMeshName(idx, source->getMeshName(idx).data()); } using namespace std::placeholders; copyLODIndices( std::bind(&DefinitionReader::getJointIndicesForLOD, source, _1), std::bind(&DefinitionWriter::setJointIndices, destination, _1, _2, _3), std::bind(&DefinitionWriter::setLODJointMapping, destination, _1, _2), lodCount, memRes); copyLODIndices( std::bind(&DefinitionReader::getBlendShapeChannelIndicesForLOD, source, _1), std::bind(&DefinitionWriter::setBlendShapeChannelIndices, destination, _1, _2, _3), std::bind(&DefinitionWriter::setLODBlendShapeChannelMapping, destination, _1, _2), lodCount, memRes); copyLODIndices( std::bind(&DefinitionReader::getAnimatedMapIndicesForLOD, source, _1), std::bind(&DefinitionWriter::setAnimatedMapIndices, destination, _1, _2, _3), std::bind(&DefinitionWriter::setLODAnimatedMapMapping, destination, _1, _2), lodCount, memRes); copyLODIndices( std::bind(&DefinitionReader::getMeshIndicesForLOD, source, _1), std::bind(&DefinitionWriter::setMeshIndices, destination, _1, _2, _3), std::bind(&DefinitionWriter::setLODMeshMapping, destination, _1, _2), lodCount, memRes); Vector jointHierarchy{memRes}; jointHierarchy.reserve(source->getJointCount()); for (std::uint16_t i = {}; i < source->getJointCount(); ++i) { jointHierarchy.push_back(source->getJointParentIndex(i)); } destination->setJointHierarchy(jointHierarchy.data(), static_cast(jointHierarchy.size())); for (std::uint16_t i = {}; i < source->getMeshBlendShapeChannelMappingCount(); ++i) { auto mapping = source->getMeshBlendShapeChannelMapping(i); destination->setMeshBlendShapeChannelMapping(i, mapping.meshIndex, mapping.blendShapeChannelIndex); } auto jointCount = source->getJointCount(); auto translations = collect_n(jointCount, [source](std::size_t index) { return source->getNeutralJointTranslation(static_cast(index)); }, memRes); destination->setNeutralJointTranslations(translations.data(), static_cast(translations.size())); auto rotations = collect_n(jointCount, [source](std::size_t index) { return source->getNeutralJointRotation(static_cast(index)); }, memRes); destination->setNeutralJointRotations(rotations.data(), static_cast(rotations.size())); } static void copyBehavior(const BehaviorReader* source, BehaviorWriter* destination, MemoryResource* /*unused*/) { destination->clearJointGroups(); auto guiToRawInputIndices = source->getGUIToRawInputIndices(); destination->setGUIToRawInputIndices(guiToRawInputIndices.data(), static_cast(guiToRawInputIndices.size())); auto guiToRawOutputIndices = source->getGUIToRawOutputIndices(); destination->setGUIToRawOutputIndices(guiToRawOutputIndices.data(), static_cast(guiToRawOutputIndices.size())); auto guiToRawFromValues = source->getGUIToRawFromValues(); destination->setGUIToRawFromValues(guiToRawFromValues.data(), static_cast(guiToRawFromValues.size())); auto guiToRawToValues = source->getGUIToRawToValues(); destination->setGUIToRawToValues(guiToRawToValues.data(), static_cast(guiToRawToValues.size())); auto guiToRawSlopeValues = source->getGUIToRawSlopeValues(); destination->setGUIToRawSlopeValues(guiToRawSlopeValues.data(), static_cast(guiToRawSlopeValues.size())); auto guiToRawCutValues = source->getGUIToRawCutValues(); destination->setGUIToRawCutValues(guiToRawCutValues.data(), static_cast(guiToRawCutValues.size())); destination->setPSDCount(source->getPSDCount()); auto psdRowIndices = source->getPSDRowIndices(); destination->setPSDRowIndices(psdRowIndices.data(), static_cast(psdRowIndices.size())); auto psdColumnIndices = source->getPSDColumnIndices(); destination->setPSDColumnIndices(psdColumnIndices.data(), static_cast(psdColumnIndices.size())); auto psdValues = source->getPSDValues(); destination->setPSDValues(psdValues.data(), static_cast(psdValues.size())); destination->setJointRowCount(source->getJointRowCount()); destination->setJointColumnCount(source->getJointColumnCount()); for (std::uint16_t jointGroupIndexPlusOne = source->getJointGroupCount(); jointGroupIndexPlusOne > 0u; --jointGroupIndexPlusOne) { const auto jointGroupIndex = static_cast(jointGroupIndexPlusOne - 1u); auto jointGroupLODs = source->getJointGroupLODs(jointGroupIndex); destination->setJointGroupLODs(jointGroupIndex, jointGroupLODs.data(), static_cast(jointGroupLODs.size())); auto jointGroupInputIndices = source->getJointGroupInputIndices(jointGroupIndex); destination->setJointGroupInputIndices(jointGroupIndex, jointGroupInputIndices.data(), static_cast(jointGroupInputIndices.size())); auto jointGroupOutputIndices = source->getJointGroupOutputIndices(jointGroupIndex); destination->setJointGroupOutputIndices(jointGroupIndex, jointGroupOutputIndices.data(), static_cast(jointGroupOutputIndices.size())); auto jointGroupValues = source->getJointGroupValues(jointGroupIndex); destination->setJointGroupValues(jointGroupIndex, jointGroupValues.data(), static_cast(jointGroupValues.size())); auto jointGroupJointIndices = source->getJointGroupJointIndices(jointGroupIndex); destination->setJointGroupJointIndices(jointGroupIndex, jointGroupJointIndices.data(), static_cast(jointGroupJointIndices.size())); } auto blendShapeLODs = source->getBlendShapeChannelLODs(); destination->setBlendShapeChannelLODs(blendShapeLODs.data(), static_cast(blendShapeLODs.size())); auto blendShapeInputIndices = source->getBlendShapeChannelInputIndices(); destination->setBlendShapeChannelInputIndices(blendShapeInputIndices.data(), static_cast(blendShapeInputIndices.size())); auto blendShapeOutputIndices = source->getBlendShapeChannelOutputIndices(); destination->setBlendShapeChannelOutputIndices(blendShapeOutputIndices.data(), static_cast(blendShapeOutputIndices.size())); auto animatedMapLODs = source->getAnimatedMapLODs(); destination->setAnimatedMapLODs(animatedMapLODs.data(), static_cast(animatedMapLODs.size())); auto animatedMapInputIndices = source->getAnimatedMapInputIndices(); destination->setAnimatedMapInputIndices(animatedMapInputIndices.data(), static_cast(animatedMapInputIndices.size())); auto animatedMapOutputIndices = source->getAnimatedMapOutputIndices(); destination->setAnimatedMapOutputIndices(animatedMapOutputIndices.data(), static_cast(animatedMapOutputIndices.size())); auto animatedMapFromValues = source->getAnimatedMapFromValues(); destination->setAnimatedMapFromValues(animatedMapFromValues.data(), static_cast(animatedMapFromValues.size())); auto animatedMapToValues = source->getAnimatedMapToValues(); destination->setAnimatedMapToValues(animatedMapToValues.data(), static_cast(animatedMapToValues.size())); auto animatedMapSlopeValues = source->getAnimatedMapSlopeValues(); destination->setAnimatedMapSlopeValues(animatedMapSlopeValues.data(), static_cast(animatedMapSlopeValues.size())); auto animatedMapCutValues = source->getAnimatedMapCutValues(); destination->setAnimatedMapCutValues(animatedMapCutValues.data(), static_cast(animatedMapCutValues.size())); } static bool hasGeometry(const GeometryReader* source) { // Heuristic for determining whether source DNA actually has any geometry data, or mesh count is non-zero only // because of mesh names stored in definition layer std::uint32_t totalVertexCount = {}; std::uint32_t totalVertexNormalCount = {}; std::uint32_t totalTextureCoordCount = {}; std::uint32_t totalVertexLayoutCount = {}; std::uint32_t totalSkinWeightCount = {}; for (std::uint16_t meshIndex = {}; meshIndex < source->getMeshCount(); ++meshIndex) { totalVertexCount += source->getVertexPositionCount(meshIndex); totalVertexNormalCount += source->getVertexNormalCount(meshIndex); totalTextureCoordCount += source->getVertexTextureCoordinateCount(meshIndex); totalVertexLayoutCount += source->getVertexLayoutCount(meshIndex); totalSkinWeightCount += source->getSkinWeightsCount(meshIndex); } return ((totalVertexCount != 0u) || (totalVertexNormalCount != 0u) || (totalTextureCoordCount != 0u) || (totalVertexLayoutCount != 0u) || (totalSkinWeightCount != 0u)); } static void copyGeometry(const GeometryReader* source, GeometryWriter* destination, MemoryResource* memRes) { destination->clearMeshes(); if (!hasGeometry(source)) { // Source DNA was loaded without geometry layer return; } for (std::uint16_t meshIndexPlusOne = source->getMeshCount(); meshIndexPlusOne > 0u; --meshIndexPlusOne) { const auto meshIndex = static_cast(meshIndexPlusOne - 1u); auto vertexCount = source->getVertexPositionCount(meshIndex); auto positions = collect_n(vertexCount, [source, meshIndex](std::size_t index) { return source->getVertexPosition(meshIndex, static_cast(index)); }, memRes); destination->setVertexPositions(meshIndex, positions.data(), static_cast(positions.size())); auto textureCoordinateCount = source->getVertexTextureCoordinateCount(meshIndex); auto textureCoordinates = collect_n(textureCoordinateCount, [source, meshIndex](std::size_t index) { return source->getVertexTextureCoordinate(meshIndex, static_cast(index)); }, memRes); destination->setVertexTextureCoordinates(meshIndex, textureCoordinates.data(), static_cast(textureCoordinates.size())); auto normalCount = source->getVertexNormalCount(meshIndex); auto normals = collect_n(normalCount, [source, meshIndex](std::size_t index) { return source->getVertexNormal(meshIndex, static_cast(index)); }, memRes); destination->setVertexNormals(meshIndex, normals.data(), static_cast(normals.size())); auto layoutCount = source->getVertexLayoutCount(meshIndex); auto layouts = collect_n(layoutCount, [source, meshIndex](std::size_t index) { return source->getVertexLayout(meshIndex, static_cast(index)); }, memRes); destination->setVertexLayouts(meshIndex, layouts.data(), static_cast(layouts.size())); for (std::uint32_t faceIndexPlusOne = source->getFaceCount(meshIndex); faceIndexPlusOne > 0u; --faceIndexPlusOne) { const auto faceIndex = faceIndexPlusOne - 1u; auto faceVertices = source->getFaceVertexLayoutIndices(meshIndex, faceIndex); destination->setFaceVertexLayoutIndices(meshIndex, faceIndex, faceVertices.data(), static_cast(faceVertices.size())); } destination->setMaximumInfluencePerVertex(meshIndex, source->getMaximumInfluencePerVertex(meshIndex)); const auto skinWeightsCount = source->getSkinWeightsCount(meshIndex); for (std::uint32_t skinWeightsIndexPlusOne = skinWeightsCount; skinWeightsIndexPlusOne > 0u; --skinWeightsIndexPlusOne) { const auto skinWeightsIndex = skinWeightsIndexPlusOne - 1u; auto skinWeights = source->getSkinWeightsValues(meshIndex, skinWeightsIndex); destination->setSkinWeightsValues(meshIndex, skinWeightsIndex, skinWeights.data(), static_cast(skinWeights.size())); auto skinWeightsJoints = source->getSkinWeightsJointIndices(meshIndex, skinWeightsIndex); destination->setSkinWeightsJointIndices(meshIndex, skinWeightsIndex, skinWeightsJoints.data(), static_cast(skinWeightsJoints.size())); } } } static bool hasBlendShapeTargets(const GeometryReader* source) { // Heuristic for determining whether source DNA actually has any blend shape target data, or mesh count is non-zero only // because of mesh names stored in definition layer std::uint32_t totalBlendShapeTargetCount = {}; for (std::uint16_t meshIndex = {}; meshIndex < source->getMeshCount(); ++meshIndex) { totalBlendShapeTargetCount += source->getBlendShapeTargetCount(meshIndex); } return (totalBlendShapeTargetCount != 0u); } static void copyBlendShapeTargets(const GeometryReader* source, GeometryWriter* destination, MemoryResource* memRes) { if (!hasBlendShapeTargets(source)) { // Source DNA was loaded without blend shape targets return; } for (std::uint16_t meshIndexPlusOne = source->getMeshCount(); meshIndexPlusOne > 0u; --meshIndexPlusOne) { const auto meshIndex = static_cast(meshIndexPlusOne - 1u); for (std::uint16_t blendShapeTargetIndexPlusOne = source->getBlendShapeTargetCount(meshIndex); blendShapeTargetIndexPlusOne > 0u; --blendShapeTargetIndexPlusOne) { const auto blendShapeTargetIndex = static_cast(blendShapeTargetIndexPlusOne - 1u); auto channelIndex = source->getBlendShapeChannelIndex(meshIndex, blendShapeTargetIndex); destination->setBlendShapeChannelIndex(meshIndex, blendShapeTargetIndex, channelIndex); auto deltaCount = source->getBlendShapeTargetDeltaCount(meshIndex, blendShapeTargetIndex); auto deltas = collect_n(deltaCount, [source, meshIndex, blendShapeTargetIndex](std::size_t index) { return source->getBlendShapeTargetDelta(meshIndex, blendShapeTargetIndex, static_cast(index)); }, memRes); destination->setBlendShapeTargetDeltas(meshIndex, blendShapeTargetIndex, deltas.data(), static_cast(deltas.size())); auto deltasVertices = source->getBlendShapeTargetVertexIndices(meshIndex, blendShapeTargetIndex); destination->setBlendShapeTargetVertexIndices(meshIndex, blendShapeTargetIndex, deltasVertices.data(), static_cast(deltasVertices.size())); } } } static bool hasMachineLearnedBehavior(const MachineLearnedBehaviorReader* source) { // Heuristic for determining whether source DNA actually has any machine learned behavior data return (source->getMLControlCount() != 0u) || (source->getNeuralNetworkCount() != 0u); } static void copyMachineLearnedBehavior(const MachineLearnedBehaviorReader* source, MachineLearnedBehaviorWriter* destination, MemoryResource* memRes) { destination->clearMLControlNames(); destination->clearMeshRegionNames(); destination->clearNeuralNetworks(); destination->clearNeuralNetworkIndices(); destination->clearNeuralNetworkIndicesPerMeshRegion(); if (!hasMachineLearnedBehavior(source)) { // Source DNA was loaded without machine learned behavior layer return; } for (std::uint16_t i = source->getMLControlCount(); i > 0u; --i) { const auto idx = static_cast(i - 1u); destination->setMLControlName(idx, source->getMLControlName(idx).data()); } using namespace std::placeholders; copyLODIndices( std::bind(&MachineLearnedBehaviorReader::getNeuralNetworkIndicesForLOD, source, _1), std::bind(&MachineLearnedBehaviorWriter::setNeuralNetworkIndices, destination, _1, _2, _3), std::bind(&MachineLearnedBehaviorWriter::setLODNeuralNetworkMapping, destination, _1, _2), source->getLODCount(), memRes); for (std::uint16_t meshIndexPlusOne = source->getMeshCount(); meshIndexPlusOne > 0u; --meshIndexPlusOne) { const auto meshIndex = static_cast(meshIndexPlusOne - 1u); for (std::uint16_t regionIndexPlusOne = source->getMeshRegionCount(meshIndex); regionIndexPlusOne > 0u; --regionIndexPlusOne) { const auto regionIndex = static_cast(regionIndexPlusOne - 1u); destination->setMeshRegionName(meshIndex, regionIndex, source->getMeshRegionName(meshIndex, regionIndex)); const auto netIndices = source->getNeuralNetworkIndicesForMeshRegion(meshIndex, regionIndex); destination->setNeuralNetworkIndicesForMeshRegion(meshIndex, regionIndex, netIndices.data(), static_cast(netIndices.size())); } } for (std::uint16_t netIndexPlusOne = source->getNeuralNetworkCount(); netIndexPlusOne > 0u; --netIndexPlusOne) { const auto netIndex = static_cast(netIndexPlusOne - 1u); const auto inputIndices = source->getNeuralNetworkInputIndices(netIndex); destination->setNeuralNetworkInputIndices(netIndex, inputIndices.data(), static_cast(inputIndices.size())); const auto outputIndices = source->getNeuralNetworkOutputIndices(netIndex); destination->setNeuralNetworkOutputIndices(netIndex, outputIndices.data(), static_cast(outputIndices.size())); const auto layerCount = source->getNeuralNetworkLayerCount(netIndex); for (std::uint16_t layerIndexPlusOne = layerCount; layerIndexPlusOne > 0u; --layerIndexPlusOne) { const auto layerIndex = static_cast(layerIndexPlusOne - 1u); const auto activationFunction = source->getNeuralNetworkLayerActivationFunction(netIndex, layerIndex); destination->setNeuralNetworkLayerActivationFunction(netIndex, layerIndex, activationFunction); const auto activationFunctionParams = source->getNeuralNetworkLayerActivationFunctionParameters(netIndex, layerIndex); destination->setNeuralNetworkLayerActivationFunctionParameters(netIndex, layerIndex, activationFunctionParams.data(), static_cast(activationFunctionParams. size())); const auto biases = source->getNeuralNetworkLayerBiases(netIndex, layerIndex); destination->setNeuralNetworkLayerBiases(netIndex, layerIndex, biases.data(), static_cast(biases.size())); const auto weights = source->getNeuralNetworkLayerWeights(netIndex, layerIndex); destination->setNeuralNetworkLayerWeights(netIndex, layerIndex, weights.data(), static_cast(weights.size())); } } } static bool hasRBFBehavior(const RBFBehaviorReader* source) { // Heuristic for determining whether source DNA actually has any RBF behavior data return (source->getRBFPoseCount() != 0u) || (source->getRBFSolverCount() != 0u); } static void copyRBFBehavior(const RBFBehaviorReader* source, RBFBehaviorWriter* destination, MemoryResource* memRes) { destination->clearRBFPoses(); destination->clearRBFSolverIndices(); destination->clearRBFSolvers(); if (!hasRBFBehavior(source)) { // Source DNA was loaded without RBF behavior layer return; } using namespace std::placeholders; copyLODIndices( std::bind(&RBFBehaviorReader::getRBFSolverIndicesForLOD, source, _1), std::bind(&RBFBehaviorWriter::setRBFSolverIndices, destination, _1, _2, _3), std::bind(&RBFBehaviorWriter::setLODRBFSolverMapping, destination, _1, _2), source->getLODCount(), memRes); for (std::uint16_t pciPlusOne = source->getRBFPoseControlCount(); pciPlusOne > 0u; --pciPlusOne) { const auto pci = static_cast(pciPlusOne - 1u); destination->setRBFPoseControlName(pci, source->getRBFPoseControlName(pci).data()); } for (std::uint16_t posePlusOne = source->getRBFPoseCount(); posePlusOne > 0u; --posePlusOne) { const auto pi = static_cast(posePlusOne - 1u); destination->setRBFPoseName(pi, source->getRBFPoseName(pi).data()); destination->setRBFPoseScale(pi, source->getRBFPoseScale(pi)); const auto inputControlIndices = source->getRBFPoseInputControlIndices(pi); destination->setRBFPoseInputControlIndices(pi, inputControlIndices.data(), static_cast(inputControlIndices.size())); const auto outputControlIndices = source->getRBFPoseOutputControlIndices(pi); destination->setRBFPoseOutputControlIndices(pi, outputControlIndices.data(), static_cast(outputControlIndices.size())); const auto outputControlWeights = source->getRBFPoseOutputControlWeights(pi); destination->setRBFPoseOutputControlWeights(pi, outputControlWeights.data(), static_cast(outputControlWeights.size())); } for (std::uint16_t solverPlusOne = source->getRBFSolverCount(); solverPlusOne > 0u; --solverPlusOne) { const auto si = static_cast(solverPlusOne - 1u); destination->setRBFSolverName(si, source->getRBFSolverName(si).data()); const auto rawControlIndices = source->getRBFSolverRawControlIndices(si); destination->setRBFSolverRawControlIndices(si, rawControlIndices.data(), static_cast(rawControlIndices.size())); const auto poseIndices = source->getRBFSolverPoseIndices(si); destination->setRBFSolverPoseIndices(si, poseIndices.data(), static_cast(poseIndices.size())); const auto rawControlValues = source->getRBFSolverRawControlValues(si); destination->setRBFSolverRawControlValues(si, rawControlValues.data(), static_cast(rawControlValues.size())); destination->setRBFSolverType(si, source->getRBFSolverType(si)); destination->setRBFSolverRadius(si, source->getRBFSolverRadius(si)); destination->setRBFSolverAutomaticRadius(si, source->getRBFSolverAutomaticRadius(si)); destination->setRBFSolverWeightThreshold(si, source->getRBFSolverWeightThreshold(si)); destination->setRBFSolverDistanceMethod(si, source->getRBFSolverDistanceMethod(si)); destination->setRBFSolverNormalizeMethod(si, source->getRBFSolverNormalizeMethod(si)); destination->setRBFSolverFunctionType(si, source->getRBFSolverFunctionType(si)); destination->setRBFSolverTwistAxis(si, source->getRBFSolverTwistAxis(si)); } } static void copyJointBehaviorMetaData(const JointBehaviorMetadataReader* source, JointBehaviorMetadataWriter* destination, MemoryResource* /*unused*/) { destination->clearJointRepresentations(); for (std::uint16_t jointPlusOne = source->getJointCount(); jointPlusOne > 0u; --jointPlusOne) { const auto ji = static_cast(jointPlusOne - 1u); destination->setJointTranslationRepresentation(ji, source->getJointTranslationRepresentation(ji)); destination->setJointRotationRepresentation(ji, source->getJointRotationRepresentation(ji)); destination->setJointScaleRepresentation(ji, source->getJointScaleRepresentation(ji)); } } static bool hasTwistSwingBehavior(const TwistSwingBehaviorReader* source) { // Heuristic for determining whether source DNA actually has any TwistSwing behavior data return (source->getTwistCount() != 0u) || (source->getSwingCount() != 0u); } static void copyTwistSwingBehavior(const TwistSwingBehaviorReader* source, TwistSwingBehaviorWriter* destination, MemoryResource* /*unused*/) { destination->clearTwists(); destination->clearSwings(); if (!hasTwistSwingBehavior(source)) { // Source DNA was loaded without twist and swig behavior layer return; } for (std::uint16_t twistIndexPlusOne = source->getTwistCount(); twistIndexPlusOne > 0u; --twistIndexPlusOne) { const auto ti = static_cast(twistIndexPlusOne - 1u); destination->setTwistSetupTwistAxis(ti, source->getTwistSetupTwistAxis(ti)); const auto twistInputControlIndices = source->getTwistInputControlIndices(ti); destination->setTwistInputControlIndices(ti, twistInputControlIndices.data(), static_cast(twistInputControlIndices.size())); const auto twistOutputJointIndices = source->getTwistOutputJointIndices(ti); destination->setTwistOutputJointIndices(ti, twistOutputJointIndices.data(), static_cast(twistOutputJointIndices.size())); const auto twistBlendWeights = source->getTwistBlendWeights(ti); destination->setTwistBlendWeights(ti, twistBlendWeights.data(), static_cast(twistBlendWeights.size())); } for (std::uint16_t swingIndexPlusOne = source->getSwingCount(); swingIndexPlusOne > 0u; --swingIndexPlusOne) { const auto si = static_cast(swingIndexPlusOne - 1u); destination->setSwingSetupTwistAxis(si, source->getSwingSetupTwistAxis(si)); const auto swingInputControlIndices = source->getSwingInputControlIndices(si); destination->setSwingInputControlIndices(si, swingInputControlIndices.data(), static_cast(swingInputControlIndices.size())); const auto swingOutputJointIndices = source->getSwingOutputJointIndices(si); destination->setSwingOutputJointIndices(si, swingOutputJointIndices.data(), static_cast(swingOutputJointIndices.size())); const auto swingBlendWeights = source->getSwingBlendWeights(si); destination->setSwingBlendWeights(si, swingBlendWeights.data(), static_cast(swingBlendWeights.size())); } } void Writer::setFrom(const Reader* source, DataLayer layer, UnknownLayerPolicy /*unused*/, MemoryResource* memRes) { // Unknown layers are inaccessible when copying through the public API if (source == nullptr) { return; } const auto bitmask = computeDataLayerBitmask(layer); copyHeader(source, this, memRes); copyDescriptor(source, this, memRes); if (contains(bitmask, DataLayerBitmask::Definition)) { copyDefinition(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::Behavior)) { copyBehavior(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::GeometryRest)) { copyGeometry(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::GeometryBlendShapesOnly)) { copyBlendShapeTargets(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::MachineLearnedBehavior)) { copyMachineLearnedBehavior(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::RBFBehavior)) { copyRBFBehavior(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::JointBehaviorMetadata)) { copyJointBehaviorMetaData(source, this, memRes); } if (contains(bitmask, DataLayerBitmask::TwistSwingBehavior)) { copyTwistSwingBehavior(source, this, memRes); } } } // namespace dna