From 70c4af294e6d5459664b6005bcce8894c7b18c94 Mon Sep 17 00:00:00 2001 From: codereader Date: Mon, 5 Apr 2021 08:50:20 +0200 Subject: [PATCH] #5576: Add NODE_TM parsing code, applying the transform to the normals like the game --- radiantcore/model/import/AseModel.cpp | 50 ++++++++++++++++++++++++--- radiantcore/model/import/AseModel.h | 4 ++- test/Models.cpp | 2 +- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/radiantcore/model/import/AseModel.cpp b/radiantcore/model/import/AseModel.cpp index ca4f89f053..5337e66033 100644 --- a/radiantcore/model/import/AseModel.cpp +++ b/radiantcore/model/import/AseModel.cpp @@ -67,7 +67,7 @@ AseModel::Material::Material() : uvAngle(0) {} -void AseModel::finishSurface(Mesh& mesh, std::size_t materialIndex) +void AseModel::finishSurface(Mesh& mesh, std::size_t materialIndex, const Matrix4& nodeMatrix) { assert(mesh.vertices.size() == mesh.normals.size()); @@ -115,7 +115,7 @@ void AseModel::finishSurface(Mesh& mesh, std::size_t materialIndex) auto& meshVertex = surface.vertices.emplace_back(ArbitraryMeshVertex { vertex, - normal, + nodeMatrix.transformDirection(normal).getNormalised(), TexCoord2f(u * materialCos + v * materialSin, u * -materialSin + v * materialCos) }); @@ -416,6 +416,47 @@ void AseModel::parseMesh(Mesh& mesh, parser::StringTokeniser& tokeniser) } } +void AseModel::parseNodeMatrix(Matrix4& matrix, parser::StringTokeniser& tokeniser) +{ + int blockLevel = 0; + + // We parse the rows in the ASE file into the columns of the matrix + // to be able to just use Matrix4::transformDirection() to transform the normal + while (tokeniser.hasMoreTokens()) + { + auto token = tokeniser.nextToken(); + string::to_lower(token); + + if (token == "}") + { + if (--blockLevel == 0) break; + } + else if (token == "{") + { + ++blockLevel; + } + else if (token == "*tm_row0") + { + matrix.xx() = string::convert(tokeniser.nextToken()); + matrix.xy() = string::convert(tokeniser.nextToken()); + matrix.xz() = string::convert(tokeniser.nextToken()); + } + else if (token == "*tm_row1") + { + matrix.yx() = string::convert(tokeniser.nextToken()); + matrix.yy() = string::convert(tokeniser.nextToken()); + matrix.yz() = string::convert(tokeniser.nextToken()); + } + else if (token == "*tm_row2") + { + matrix.zx() = string::convert(tokeniser.nextToken()); + matrix.zy() = string::convert(tokeniser.nextToken()); + matrix.zz() = string::convert(tokeniser.nextToken()); + } + // The fourth row *TM_ROW3 is ignored, translations are not applicable to normals + } +} + void AseModel::parseGeomObject(parser::StringTokeniser& tokeniser) { Mesh mesh; @@ -444,7 +485,8 @@ void AseModel::parseGeomObject(parser::StringTokeniser& tokeniser) else if (token == "*node_tm") { // The NODE_TM block is parsed by the engine and applied to the - // normals of the mesh, needs to be implemented. + // normals of the mesh. + parseNodeMatrix(nodeMatrix, tokeniser); } /* mesh material reference. this usually comes at the end of * geomobjects after the mesh blocks. we must assume that the @@ -460,7 +502,7 @@ void AseModel::parseGeomObject(parser::StringTokeniser& tokeniser) } } - finishSurface(mesh, materialIndex); + finishSurface(mesh, materialIndex, nodeMatrix); } void AseModel::parseFromTokens(parser::StringTokeniser& tokeniser) diff --git a/radiantcore/model/import/AseModel.h b/radiantcore/model/import/AseModel.h index 7501e90e39..a4eca20528 100644 --- a/radiantcore/model/import/AseModel.h +++ b/radiantcore/model/import/AseModel.h @@ -1,6 +1,7 @@ #pragma once #include +#include "math/Matrix4.h" #include "../StaticModelSurface.h" #include "parser/Tokeniser.h" @@ -67,8 +68,9 @@ class AseModel void parseMaterialList(parser::StringTokeniser& tokeniser); void parseGeomObject(parser::StringTokeniser& tokeniser); void parseMesh(Mesh& mesh, parser::StringTokeniser& tokeniser); + void parseNodeMatrix(Matrix4& matrix, parser::StringTokeniser& tokeniser); - void finishSurface(Mesh& mesh, std::size_t materialIndex); + void finishSurface(Mesh& mesh, std::size_t materialIndex, const Matrix4& nodeMatrix); }; } diff --git a/test/Models.cpp b/test/Models.cpp index d5ca7a7906..463864864c 100644 --- a/test/Models.cpp +++ b/test/Models.cpp @@ -245,7 +245,7 @@ void expectVertexWithNormal(const model::IModelSurface& surface, const Vertex3f& { EXPECT_TRUE(surfaceHasVertexWith(surface, [&](const ArbitraryMeshVertex& v)->bool { - return v.vertex.isEqual(vertex, 1e-5) && v.normal.isEqual(normal, 1e-5); + return v.vertex.isEqual(vertex, 1e-3) && v.normal.isEqual(normal, 1e-3); })) << "Could not find a vertex with xyz = " << vertex << " and normal " << normal; }