Skip to content

Commit

Permalink
#5576: Add NODE_TM parsing code, applying the transform to the normal…
Browse files Browse the repository at this point in the history
…s like the game
  • Loading branch information
codereader committed Apr 5, 2021
1 parent 4ecedd1 commit 70c4af2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 6 deletions.
50 changes: 46 additions & 4 deletions radiantcore/model/import/AseModel.cpp
Expand Up @@ -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());

Expand Down Expand Up @@ -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)
});

Expand Down Expand Up @@ -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<double>(tokeniser.nextToken());
matrix.xy() = string::convert<double>(tokeniser.nextToken());
matrix.xz() = string::convert<double>(tokeniser.nextToken());
}
else if (token == "*tm_row1")
{
matrix.yx() = string::convert<double>(tokeniser.nextToken());
matrix.yy() = string::convert<double>(tokeniser.nextToken());
matrix.yz() = string::convert<double>(tokeniser.nextToken());
}
else if (token == "*tm_row2")
{
matrix.zx() = string::convert<double>(tokeniser.nextToken());
matrix.zy() = string::convert<double>(tokeniser.nextToken());
matrix.zz() = string::convert<double>(tokeniser.nextToken());
}
// The fourth row *TM_ROW3 is ignored, translations are not applicable to normals
}
}

void AseModel::parseGeomObject(parser::StringTokeniser& tokeniser)
{
Mesh mesh;
Expand Down Expand Up @@ -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
Expand All @@ -460,7 +502,7 @@ void AseModel::parseGeomObject(parser::StringTokeniser& tokeniser)
}
}

finishSurface(mesh, materialIndex);
finishSurface(mesh, materialIndex, nodeMatrix);
}

void AseModel::parseFromTokens(parser::StringTokeniser& tokeniser)
Expand Down
4 changes: 3 additions & 1 deletion radiantcore/model/import/AseModel.h
@@ -1,6 +1,7 @@
#pragma once

#include <istream>
#include "math/Matrix4.h"
#include "../StaticModelSurface.h"
#include "parser/Tokeniser.h"

Expand Down Expand Up @@ -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);
};

}
2 changes: 1 addition & 1 deletion test/Models.cpp
Expand Up @@ -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;
}

Expand Down

0 comments on commit 70c4af2

Please sign in to comment.