Skip to content

Commit

Permalink
[librii] g3d: Support multi-MDL0 .brres files
Browse files Browse the repository at this point in the history
And match kuribo.brres to validate
  • Loading branch information
riidefi committed Jul 12, 2023
1 parent bd74a88 commit fcb8d31
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 22 deletions.
8 changes: 8 additions & 0 deletions source/librii/g3d/data/BoneData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct BinaryBoneData {
glm::mat4x3 modelMtx;
glm::mat4x3 inverseModelMtx;

// Not a real field: computed later on
bool forceDisplayMatrix = false;
bool omitFromNodeMix = false;

Result<void> read(oishii::BinaryReader& reader);
void write(NameTable& names, oishii::Writer& writer, u32 mdl_start) const;

Expand Down Expand Up @@ -88,6 +92,10 @@ struct BoneData {
};
std::vector<DisplayCommand> mDisplayCommands;

// Not a real field: computed later on
bool forceDisplayMatrix = false;
bool omitFromNodeMix = false;

std::string getName() const { return mName; }
bool isDisplayMatrix() const { return displayMatrix; }
bool hasChildren() const { return !mChildren.empty(); }
Expand Down
5 changes: 0 additions & 5 deletions source/librii/g3d/io/ArchiveIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ Result<void> BinaryArchive::read(oishii::BinaryReader& reader,

// TODO
if (node.name == "3DModels(NW4R)") {
if (cdic.nodes.size() > 1) {
return std::unexpected(
"This file has multiple MDL0 files within it. "
"Only single-MDL0 BRRES files are currently supported.");
}
for (auto& sub : cdic.nodes) {
EXPECT(sub.stream_pos);
reader.seekSet(sub.stream_pos);
Expand Down
96 changes: 85 additions & 11 deletions source/librii/g3d/io/ModelIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,16 @@ Result<void> BinaryModel::read(oishii::BinaryReader& unsafeReader,
return {};
};

TRY(readDict(secOfs.ofsBones, [&](const librii::g3d::BetterNode& dnode) {
auto& bone = bones.emplace_back();
return bone.read(unsafeReader);
}));
TRY(readDict(secOfs.ofsBones,
[&](const librii::g3d::BetterNode& dnode) -> Result<void> {
auto& bone = bones.emplace_back();
TRY(bone.read(unsafeReader));
// TODO: We shouldn't need this hack
if (bone.matrixId < info.numViewMtx) {
bone.forceDisplayMatrix = true;
}
return {};
}));

// Read Vertex data
TRY(readDict(
Expand Down Expand Up @@ -290,6 +296,22 @@ Result<void> BinaryModel::read(oishii::BinaryReader& unsafeReader,
return {};
}));

for (auto& bone : bones) {
bone.omitFromNodeMix = true;
}
for (auto& bc : bytecodes) {
if (bc.name != "NodeMix") {
continue;
}
for (auto& cmd : bc.commands) {
if (auto* x = std::get_if<ByteCodeLists::EnvelopeMatrix>(&cmd)) {
EXPECT(x->nodeId < bones.size());
bones[x->nodeId].omitFromNodeMix = false;
}
}
break;
}

if (!isValid) {
transaction.callback(kpi::IOMessageClass::Warning, transaction_path,
"Note: BRRES file was saved with BrawlBox. Certain "
Expand Down Expand Up @@ -743,6 +765,9 @@ librii::g3d::BoneData fromBinaryBone(const librii::g3d::BinaryBoneData& bin,
bone.mParent = bin.parent_id;
// Skip sibling and child links -- we recompute it all

bone.forceDisplayMatrix = bin.forceDisplayMatrix;
bone.omitFromNodeMix = bin.omitFromNodeMix;

auto modelMtx = calcSrtMtx(bin, bones, scalingRule);
auto modelMtx34 = glm::mat4x3(modelMtx);

Expand Down Expand Up @@ -817,6 +842,10 @@ toBinaryBone(const librii::g3d::BoneData& bone,
bin.modelMtx = modelMtx34;
bin.inverseModelMtx =
librii::g3d::MTXInverse(modelMtx34).value_or(glm::mat4x3(0.0f));

bin.forceDisplayMatrix = bone.forceDisplayMatrix;
bin.omitFromNodeMix = bone.omitFromNodeMix;

return bin;
}

Expand Down Expand Up @@ -947,6 +976,46 @@ class ByteCodeHelper {
kpi::IOContext& ctx;
};

inline std::set<s16> gcomputeShapeMtxRef(auto&& meshes) {
std::set<s16> shapeRefMtx;
for (auto&& mesh : meshes) {
// TODO: Do we need to check currentMatrixEmbedded flag?
if (mesh.mCurrentMatrix != -1) {
shapeRefMtx.insert(mesh.mCurrentMatrix);
continue;
}
// TODO: Presumably mCurrentMatrix (envelope mode) precludes blended weight
// mode?
for (auto& mp : mesh.mMatrixPrimitives) {
for (auto& w : mp.mDrawMatrixIndices) {
if (w == -1) {
continue;
}
shapeRefMtx.insert(w);
}
}
}
return shapeRefMtx;
}
inline std::set<s16> gcomputeDisplayMatricesSubset(
const auto& meshes, const auto& bones,
auto getMatrixId = [](auto& x) { return x.matrixId; }) {
std::set<s16> displayMatrices = gcomputeShapeMtxRef(meshes);
const size_t len = displayMatrices.size();
for (int i = 0; i < bones.size(); ++i) {
const auto& bone = bones[i];
if (!displayMatrices.contains(getMatrixId(bone, i))) {
// Assume non-view matrices are appended to end
// HACK: Permit leaves to match map_model.brres
if (!bone.forceDisplayMatrix) {
continue;
}
displayMatrices.insert(getMatrixId(bone, i));
}
}
return displayMatrices;
}

Result<void> processModel(const BinaryModel& binary_model,
kpi::LightIOTransaction& transaction,
std::string_view transaction_path, Model& mdl) {
Expand Down Expand Up @@ -981,14 +1050,14 @@ Result<void> processModel(const BinaryModel& binary_model,
}
mdl.info.sourceLocation = info.sourceLocation;
{
auto displayMatrices = librii::gx::computeDisplayMatricesSubset(
auto displayMatrices = gcomputeDisplayMatricesSubset(
binary_model.meshes, binary_model.bones,
[](auto& x, int i) { return x.matrixId; });
ctx.request(info.numViewMtx == displayMatrices.size(),
"Model header specifies {} display matrices, but the mesh "
"data only references {} display matrices.",
info.numViewMtx, displayMatrices.size());
auto ref = librii::gx::computeShapeMtxRef(binary_model.meshes);
auto ref = gcomputeShapeMtxRef(binary_model.meshes);
numDisplayMatrices = ref.size();
}
{
Expand Down Expand Up @@ -1044,13 +1113,14 @@ Result<void> processModel(const BinaryModel& binary_model,

mdl.bones.resize(0);
for (size_t i = 0; i < binary_model.bones.size(); ++i) {
auto& bone = binary_model.bones[i];
// CTools seemingly doesn't do this???
if (binary_model.bones[i].id != i) {
if (bone.id != i) {
ctx.error("Bone IDs are desynced. Is this a CTools minimap???");
}
mdl.bones.emplace_back() =
fromBinaryBone(binary_model.bones[i], binary_model.bones, ctx,
binary_model.info.scalingRule);
auto new_bone = fromBinaryBone(bone, binary_model.bones, ctx,
binary_model.info.scalingRule);
mdl.bones.push_back(new_bone);
}

mdl.positions = binary_model.positions;
Expand Down Expand Up @@ -1178,6 +1248,10 @@ BuildRenderLists(const Model& mdl,
if (needs_nodemix) {
// Bones come first
for (size_t i = 0; i < mdl.bones.size(); ++i) {
// Official models seem to omit unecessary NODEMIXES
if (mdl.bones[i].omitFromNodeMix) {
continue;
}
auto& drw = drawMatrices[boneToMatrix[i]];
TRY(write_drw(drw, boneToMatrix[i]));
}
Expand Down Expand Up @@ -1268,7 +1342,7 @@ Result<librii::g3d::BinaryModel> toBinaryModel(const Model& mdl) {
}
auto getMatrixId = [&](auto& x, int i) { return boneToMatrix[i]; };
std::set<s16> displayMatrices =
gx::computeDisplayMatricesSubset(mdl.meshes, mdl.bones, getMatrixId);
gcomputeDisplayMatricesSubset(mdl.meshes, mdl.bones, getMatrixId);
rsl::debug("boneToMatrix: {}, displayMatrices: {}, drawMatrices: {}",
boneToMatrix.size(), displayMatrices.size(), drawMatrices.size());

Expand Down
18 changes: 12 additions & 6 deletions source/librii/g3d/io/PolygonIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,15 +440,21 @@ struct BinaryPolygon {

if (currentMatrix == -1) {
librii::gpu::DLBuilder builder(writer);
bool anyNeedsTextureMtx = false;
for (u32 i = 0; i < 8; ++i) {
if (needsTextureMtx(i)) {
for (size_t i = 0; i < mp.mDrawMatrixIndices.size(); ++i) {
if (mp.mDrawMatrixIndices[i] == -1) {
continue;
}
builder.loadTexMtxIndx(mp.mDrawMatrixIndices[i], 30 + i * 3,
librii::gx::TexGenType::Matrix3x4);
anyNeedsTextureMtx = true;
break;
}
}
// Only one copy needed!
if (anyNeedsTextureMtx) {
for (size_t i = 0; i < mp.mDrawMatrixIndices.size(); ++i) {
if (mp.mDrawMatrixIndices[i] == -1) {
continue;
}
builder.loadTexMtxIndx(mp.mDrawMatrixIndices[i], 30 + i * 3,
librii::gx::TexGenType::Matrix3x4);
}
}
if (needsPositionMtx()) {
Expand Down
Binary file added tests/samples/MashBalloonGC.brres
Binary file not shown.
Binary file added tests/samples/kuribo.brres
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
# mariotreeGC.brres
'6fe8bbb50310b18ec2b3b9b2de4990f5': '6fe8bbb50310b18ec2b3b9b2de4990f5',

# Multi models
# kuribo.brres
'81deff134e06ff650704ff10056086a4': '81deff134e06ff650704ff10056086a4',
# MashBalloonGC.brres
'1708f97c5a7a90a236433f08f31673f6': '1708f97c5a7a90a236433f08f31673f6',

# ind_srt_0.brres
'2689c848e52167ecafee0334ce02dc4e': 'ae5364c457683c4a24d8e94121ec2e5f',

Expand Down

0 comments on commit fcb8d31

Please sign in to comment.