Skip to content

Commit

Permalink
Added bone data to Mesh and MeshVertext structs
Browse files Browse the repository at this point in the history
  • Loading branch information
McCallisterRomer committed Oct 5, 2023
1 parent eee2d47 commit 0b5bda2
Show file tree
Hide file tree
Showing 24 changed files with 817 additions and 115 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
type: boolean

env:
VERSION: '1.0.0'
VERSION: '2.0.0'

jobs:
Build:
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.20)
project("nc-tools" VERSION "1.0.0" LANGUAGES CXX)
project("nc-tools" VERSION "2.0.0" LANGUAGES CXX)

if(${PROJECT_SOURCE_DIR} EQUAL ${PROJECT_BINARY_DIR})
message(FATAL_ERROR "Don't be a fool, out-of-source build with your tool.")
endif()

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

option(NC_TOOLS_BUILD_CONVERTER "Build nc-convert executable" ON)
Expand Down
20 changes: 10 additions & 10 deletions docs/AssetFormats.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,20 @@ CubeMap faces in pixel data array are ordered: front, back, up, down, right, lef
| extents | Vector3 | 12 |
| max extent | float | 4 |
| vertex count | u64 | 8 |
| vertext list | Vector3[] | vertex count * 12 |
| vertex list | Vector3[] | vertex count * 12 |

### Mesh Blob Format
> Magic Number: 'MESH'
| Name | Type | Size |
|--------------|--------------|-------------------|
| extents | Vector3 | 12 |
| max extent | float | 4 |
| vertex count | u64 | 8 |
| index count | u64 | 8 |
| vertext list | MeshVertex[] | vertex count * 56 |
| indices | int[] | index count * 4 |

| Name | Type | Size |
|--------------|---------------------|-------------------|
| extents | Vector3 | 12 |
| max extent | float | 4 |
| vertex count | u64 | 8 |
| index count | u64 | 8 |
| vertex list | MeshVertex[] | vertex count * 88 |
| indices | int[] | index count * 4 |
| bones data | optional<BonesData> | 56 |

### Shader Blob Format
> Magic Number: 'SHAD'
Expand Down
34 changes: 13 additions & 21 deletions include/ncasset/Assets.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <optional>
#include <string>
#include <vector>
#include <unordered_map>

namespace nc::asset
{
Expand All @@ -18,19 +17,24 @@ struct AudioClip
std::vector<double> rightChannel;
};

struct BodySpaceNode
struct VertexSpaceToBoneSpace
{
std::string boneName;
DirectX::XMMATRIX localSpace;
BodySpaceNode* parent;
std::vector<BodySpaceNode*> children;
DirectX::XMMATRIX transformationMatrix;
};

struct BoneSpaceToParentSpace
{
std::string boneName;
DirectX::XMMATRIX transformationMatrix;
uint32_t numChildren;
uint32_t indexOfFirstChild;
};

struct BonesData
{
std::unordered_map<std::string, uint32_t> boneNamesToIds;
std::vector<DirectX::XMMATRIX> boneTransforms;
BodySpaceNode* bodySpaceOffsetTree;
std::vector<VertexSpaceToBoneSpace> vertexSpaceToBoneSpace;
std::vector<BoneSpaceToParentSpace> boneSpaceToParentSpace;
};

struct HullCollider
Expand Down Expand Up @@ -69,20 +73,8 @@ struct Mesh

struct PerVertexBones
{
std::array<float, 4> boneWeights;
std::array<float, 4> boneWeights {-1, -1, -1, -1};
std::array<uint32_t, 4> boneIds;

void Add(uint32_t id, float weight)
{
for (auto i = 0u; i < boneIds.size(); i++)
{
if (boneWeights[i] == 0.0)
{
boneIds[i] = id;
boneWeights[i] = weight;
}
}
}
};

struct Shader
Expand Down
51 changes: 51 additions & 0 deletions source/ncasset/BonesReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "BonesReader.h"

namespace nc::asset
{
auto ReadMatrix(RawNcaBuffer& bytes) -> DirectX::XMMATRIX
{
float buf[16];
bytes.Read(buf, 16 * sizeof(float));
return DirectX::XMMATRIX{buf};
}

auto ReadVertexToBoneMatrices(RawNcaBuffer& bytes, size_t matrixCount) -> std::vector<nc::asset::VertexSpaceToBoneSpace>
{
auto vertexSpaceToBoneSpaceMatrices = std::vector<nc::asset::VertexSpaceToBoneSpace>{};
vertexSpaceToBoneSpaceMatrices.reserve(matrixCount);
for (auto i = 0u; i < matrixCount; i++)
{
auto boneNameSize = size_t{};
bytes.Read(&boneNameSize);
auto vertexSpaceToBoneSpace = nc::asset::VertexSpaceToBoneSpace{};
vertexSpaceToBoneSpace.boneName.resize(boneNameSize);
bytes.Read(vertexSpaceToBoneSpace.boneName.data(), boneNameSize);
vertexSpaceToBoneSpace.transformationMatrix = ReadMatrix(bytes);
vertexSpaceToBoneSpaceMatrices.push_back(std::move(vertexSpaceToBoneSpace));
}
return vertexSpaceToBoneSpaceMatrices;
}

auto ReadBoneToParentMatrices(RawNcaBuffer& bytes, size_t matrixCount) -> std::vector<nc::asset::BoneSpaceToParentSpace>
{
auto boneSpaceToParentSpaceMatrices = std::vector<nc::asset::BoneSpaceToParentSpace>{};
boneSpaceToParentSpaceMatrices.reserve(matrixCount);
for (auto i = 0u; i < matrixCount; i++)
{
auto numChildren = uint32_t{};
auto indexOfFirstChild = uint32_t{};
auto boneNameSize = size_t{};
bytes.Read(&boneNameSize);
auto boneSpaceToParentSpace = nc::asset::BoneSpaceToParentSpace{};
boneSpaceToParentSpace.boneName.resize(boneNameSize);
bytes.Read(boneSpaceToParentSpace.boneName.data(), boneNameSize);
boneSpaceToParentSpace.transformationMatrix = ReadMatrix(bytes);
bytes.Read(&numChildren);
boneSpaceToParentSpace.numChildren = numChildren;
bytes.Read(&indexOfFirstChild);
boneSpaceToParentSpace.indexOfFirstChild = indexOfFirstChild;
boneSpaceToParentSpaceMatrices.push_back(std::move(boneSpaceToParentSpace));
}
return boneSpaceToParentSpaceMatrices;
}
} // namespace nc::asset
31 changes: 31 additions & 0 deletions source/ncasset/BonesReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include "ncasset/Assets.h"
#include "RawNcaBuffer.h"

namespace nc::asset
{
/** @brief Read a VertexSpaceToBoneSpace vector from a RawNcaBuffer byte stream.
* A VertexSpaceToBoneSpace object represents the transformation matrix required to transform the vertex/vertices affected by the named bone into the bone's space.
*
* @param bytes The byte stream to read from.
* @param matrixCount The count of items in the VertexSpaceToBoneSpace vector.
* @returns A VertexSpaceToBoneSpace vector
*/
auto ReadVertexToBoneMatrices(RawNcaBuffer& bytes, size_t matrixCount) -> std::vector<nc::asset::VertexSpaceToBoneSpace>;

/** @brief Read a BoneSpaceToParentSpace vector from a RawNcaBuffer byte stream.
* A BoneSpaceToParentSpace object represents the transformation matrix required to transform the named bone's space into it's parent bone's space.
*
* @param bytes The byte stream to read from.
* @param matrixCount The count of items in the BoneSpaceToParentSpace vector.
* @returns A vector of BoneSpaceToParentSpace objects.
*/
auto ReadBoneToParentMatrices(RawNcaBuffer& bytes, size_t matrixCount) -> std::vector<nc::asset::BoneSpaceToParentSpace>;

/** @brief Read a DirectX::XMMATRIX from a RawNcaBuffer byte stream.
*
* @param bytes The byte stream to read from.
*/
auto ReadMatrix(RawNcaBuffer& bytes) -> DirectX::XMMATRIX;
} // namespace nc::asset
1 change: 1 addition & 0 deletions source/ncasset/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ target_include_directories(NcAsset

target_sources(NcAsset
PRIVATE
${PROJECT_SOURCE_DIR}/source/ncasset/BonesReader.cpp
${PROJECT_SOURCE_DIR}/source/ncasset/Deserialize.cpp
${PROJECT_SOURCE_DIR}/source/ncasset/Import.cpp
${PROJECT_SOURCE_DIR}/source/ncasset/NcaHeader.cpp
Expand Down
13 changes: 13 additions & 0 deletions source/ncasset/Deserialize.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Deserialize.h"
#include "BonesReader.h"
#include "RawNcaBuffer.h"
#include "ncasset/Assets.h"

Expand Down Expand Up @@ -133,6 +134,7 @@ auto DeserializeMesh(std::istream& stream) -> DeserializedResult<Mesh>
auto asset = Mesh{};
auto vertexCount = size_t{};
auto indexCount = size_t{};
auto hasBones = false;
bytes.Read(&asset.extents);
bytes.Read(&asset.maxExtent);
bytes.Read(&vertexCount);
Expand All @@ -141,6 +143,17 @@ auto DeserializeMesh(std::istream& stream) -> DeserializedResult<Mesh>
bytes.Read(asset.vertices.data(), vertexCount * sizeof(MeshVertex));
asset.indices.resize(indexCount);
bytes.Read(asset.indices.data(), indexCount * sizeof(uint32_t));
bytes.Read(&hasBones);
if (hasBones)
{
auto vertexToBoneSpaceMatrixCount = size_t{};
bytes.Read(&vertexToBoneSpaceMatrixCount);
auto boneSpaceToParentSpaceMatrixCount = size_t{};
bytes.Read(&boneSpaceToParentSpaceMatrixCount);
asset.bonesData = BonesData{};
asset.bonesData.value().vertexSpaceToBoneSpace = ReadVertexToBoneMatrices(bytes, vertexToBoneSpaceMatrixCount);
asset.bonesData.value().boneSpaceToParentSpace = ReadBoneToParentMatrices(bytes, boneSpaceToParentSpaceMatrixCount);
}

if (bytes.RemainingByteCount() != 0)
{
Expand Down
36 changes: 36 additions & 0 deletions source/ncconvert/builder/BonesWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "BonesWriter.h"
#include "builder/DataWriter.h"

#include <cstring>

namespace nc::convert
{
void Write(std::ostream& stream, const std::vector<nc::asset::VertexSpaceToBoneSpace>& vertexSpaceToBoneSpaceMatrices)
{
for (const auto& toBoneSpace : vertexSpaceToBoneSpaceMatrices)
{
Write(stream, toBoneSpace.boneName.size());
Write(stream, toBoneSpace.boneName.data(), toBoneSpace.boneName.size());
Write(stream, toBoneSpace.transformationMatrix);
}
}

void Write(std::ostream& stream, const std::vector<nc::asset::BoneSpaceToParentSpace>& boneSpaceToParentSpaceMatrices)
{
for (const auto& toParentSpace : boneSpaceToParentSpaceMatrices)
{
Write(stream, toParentSpace.boneName.size());
Write(stream, toParentSpace.boneName.data(), toParentSpace.boneName.size());
Write(stream, toParentSpace.transformationMatrix);
Write(stream, toParentSpace.numChildren);
Write(stream, toParentSpace.indexOfFirstChild);
}
}

void Write(std::ostream& stream, const DirectX::XMMATRIX& matrix)
{
DirectX::XMFLOAT4X4 view;
XMStoreFloat4x4(&view, matrix);
Write(stream, view.m, sizeof(float)*16);
}
} // namespace nc::convert
30 changes: 30 additions & 0 deletions source/ncconvert/builder/BonesWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "ncasset/Assets.h"

#include <ostream>

namespace nc::convert
{
/** @brief Write a VertexSpaceToBoneSpace vector to a binary stream.
*
* @param stream The byte stream to write to.
* @param vertexSpaceToBoneSpaceMatrices A vector of VertexSpaceToBoneSpace objects.
* A VertexSpaceToBoneSpace object represents the transformation matrix required to transform the vertex/vertices affected by the named bone into the bone's space.
*/
void Write(std::ostream& stream, const std::vector<nc::asset::VertexSpaceToBoneSpace>& vertexSpaceToBoneSpaceMatrices);

/** @brief Write a BoneSpaceToParentSpace vector to a binary stream.
*
* @param stream The byte stream to write to.
* @param boneSpaceToParentSpace A vector of BoneSpaceToParentSpace objects.
* A BoneSpaceToParentSpace object represents the transformation matrix required to transform the named bone's space into it's parent bone's space.
*/
void Write(std::ostream& stream, const std::vector<nc::asset::BoneSpaceToParentSpace>& boneSpaceToParentSpace);

/** @brief Write a DirectX::XMMATRIX to a binary stream.
*
* @param bytes The byte stream to write to.
*/
void Write(std::ostream& stream, const DirectX::XMMATRIX& matrix);
} // namespace nc::convert
1 change: 1 addition & 0 deletions source/ncconvert/builder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
target_sources(nc-convert
PRIVATE
${PROJECT_SOURCE_DIR}/source/ncconvert/builder/BonesWriter.cpp
${PROJECT_SOURCE_DIR}/source/ncconvert/builder/Builder.cpp
${PROJECT_SOURCE_DIR}/source/ncconvert/builder/BuildInstructions.cpp
${PROJECT_SOURCE_DIR}/source/ncconvert/builder/BuildOrchestrator.cpp
Expand Down
43 changes: 43 additions & 0 deletions source/ncconvert/builder/DataWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <ostream>

namespace nc::convert
{
/** @brief Write the asset header into the given stream.
*
* @param stream The byte stream to write to.
* @param magicNumber The string_view used to reperesent the asset type. See NcaHeader.h
* @param assetId The unique ID for the asset.
* @param size The size of the asset.
*/
inline void WriteHeader(std::ostream& stream, std::string_view magicNumber, size_t assetId, size_t size)
{
constexpr char defaultAlgo[5] = "NONE"; // not yet supported
stream.write(magicNumber.data(), 4);
stream.write(defaultAlgo, 4);
stream.write(reinterpret_cast<const char*>(&assetId), sizeof(size_t));
stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
}

/** @brief Write the data into the stream.
*
* @param stream The byte stream to read to.
* @param data The data to write.
*/
template<class T>
void Write(std::ostream& stream, const T& data)
{
stream.write(reinterpret_cast<const char*>(&data), sizeof(T));
}

/** @brief Write the data into the stream. Used for vectors/arrays.
*
* @param stream The byte stream to read to.
* @param data The data to write.
* @param size The size of the data to write.
*/
template<class T>
void Write(std::ostream& stream, const T* data, size_t size)
{
stream.write(reinterpret_cast<const char*>(data), size);
}
} // namespace nc::convert
Loading

0 comments on commit 0b5bda2

Please sign in to comment.