rodecomp/Source/Resource/ModelMesh.cpp
2026-10-24 00:35:19 +00:00

91 lines
2.8 KiB
C++

#include "Resource/ModelMesh.h"
#include <cmath>
#include <map>
namespace {
void Normalize(float* vector) {
const float squared = (vector[0] * vector[0] + vector[1] * vector[1]) + vector[2] * vector[2];
const float length = std::sqrt(squared);
const float inverse = 1.0f / length;
vector[0] = inverse * vector[0];
vector[1] = inverse * vector[1];
vector[2] = inverse * vector[2];
}
}
// OFFSET: 0x00755880
// FUNCTION: fn_07988
ModelFace::ModelFace() = default;
// OFFSET: 0x00551FD0
// FUNCTION: fn_02011
void ModelMesh::CalculateNormals() {
if (this->faceNormals.empty()) {
this->faceNormals.resize(this->faces.size());
}
for (unsigned index = 0; index < this->faces.size(); ++index) {
const ModelFace& face = this->faces[index];
const auto& first = this->vertices[face.vertices[0]];
const auto& second = this->vertices[face.vertices[1]];
const auto& third = this->vertices[face.vertices[2]];
const float x1 = first[0] - third[0];
const float y1 = first[1] - third[1];
const float z1 = first[2] - third[2];
const float x2 = second[0] - third[0];
const float y2 = second[1] - third[1];
const float z2 = second[2] - third[2];
auto& normal = this->faceNormals[index];
normal[0] = y2 * z1 - z2 * y1;
normal[1] = z2 * x1 - x2 * z1;
normal[2] = x2 * y1 - y2 * x1;
Normalize(normal.data());
}
std::map<unsigned, std::vector<unsigned>> adjacent;
for (unsigned face = 0; face < this->faces.size(); ++face) {
for (unsigned corner = 0; corner < 3; ++corner) {
// Repeated vertex indices deliberately add the same adjacent face again.
adjacent[this->faces[face].vertices[corner]].push_back(face);
}
}
if (this->vertexNormals.empty()) {
this->vertexNormals.resize(this->faces.size() * 3);
}
for (unsigned index = 0; index < this->faces.size(); ++index) {
const ModelFace& face = this->faces[index];
for (unsigned corner = 0; corner < 3; ++corner) {
auto& normal = this->vertexNormals[index * 3 + corner];
for (unsigned neighbor : adjacent[face.vertices[corner]]) {
const ModelFace& other = this->faces[neighbor];
for (std::uint32_t group : face.smoothing) {
bool matches = false;
for (std::uint32_t candidate : other.smoothing) {
if (candidate == group) {
matches = true;
break;
}
}
if (matches) {
normal[0] = normal[0] + this->faceNormals[neighbor][0];
normal[1] = this->faceNormals[neighbor][1] + normal[1];
normal[2] = this->faceNormals[neighbor][2] + normal[2];
}
}
}
}
}
for (unsigned index = 0; index < this->faces.size() * 3; ++index) {
Normalize(this->vertexNormals[index].data());
}
}