mirror of
https://github.com/recastnavigation/recastnavigation.git
synced 2026-08-15 15:50:03 +00:00
190 lines
4.2 KiB
C++
190 lines
4.2 KiB
C++
//
|
|
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
//
|
|
// This software is provided 'as-is', without any express or implied
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
// arising from the use of this software.
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
// including commercial applications, and to alter it and redistribute it
|
|
// freely, subject to the following restrictions:
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software. If you use this software
|
|
// in a product, an acknowledgment in the product documentation would be
|
|
// appreciated but is not required.
|
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
// misrepresented as being the original software.
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
//
|
|
|
|
#include "MeshLoaderObj.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
namespace
|
|
{
|
|
char* readRow(char* buf, char* bufEnd, char* row, int len)
|
|
{
|
|
// skip leading whitespace
|
|
for (; buf < bufEnd; ++buf)
|
|
{
|
|
char c = *buf;
|
|
if (c != '\\' && c != '\r' && c != '\n' && c != '\t' && c != ' ')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
int n = 0;
|
|
for (; buf < bufEnd; ++buf)
|
|
{
|
|
char c = *buf;
|
|
|
|
if (c == '\n')
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (c == '\\' || c == '\r')
|
|
{
|
|
// skip
|
|
continue;
|
|
}
|
|
|
|
// Copy character
|
|
row[n++] = c;
|
|
if (n >= len - 1)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
row[n] = '\0';
|
|
return buf;
|
|
}
|
|
|
|
int readFace(char* row, int* data, int maxDataLen, int vertCount)
|
|
{
|
|
int numVertices = 0;
|
|
while (*row != '\0')
|
|
{
|
|
// Skip initial white space
|
|
while (*row != '\0' && (*row == ' ' || *row == '\t'))
|
|
{
|
|
row++;
|
|
}
|
|
|
|
char* s = row;
|
|
// Find vertex delimiter and terminate the string there for conversion.
|
|
while (*row != '\0' && *row != ' ' && *row != '\t')
|
|
{
|
|
if (*row == '/')
|
|
{
|
|
*row = '\0';
|
|
}
|
|
row++;
|
|
}
|
|
|
|
if (*s == '\0')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int vertexIndex = atoi(s);
|
|
data[numVertices++] = vertexIndex < 0 ? vertexIndex + vertCount : vertexIndex - 1;
|
|
if (numVertices >= maxDataLen)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return numVertices;
|
|
}
|
|
}
|
|
|
|
void parseObjModel(char* buf, size_t bufLen, std::vector<float>& verts, std::vector<int>& tris, std::vector<float>& normals)
|
|
{
|
|
char* src = buf;
|
|
char* srcEnd = buf + bufLen;
|
|
char row[512];
|
|
int face[32];
|
|
float x, y, z;
|
|
int numVertices;
|
|
|
|
while (src < srcEnd)
|
|
{
|
|
// Parse one row
|
|
row[0] = '\0';
|
|
src = readRow(src, srcEnd, row, sizeof(row) / sizeof(row[0]));
|
|
|
|
if (row[0] == '#')
|
|
{
|
|
// Comment
|
|
continue;
|
|
}
|
|
if (row[0] == 'v' && row[1] != 'n' && row[1] != 't')
|
|
{
|
|
// Vertex pos
|
|
sscanf(row + 1, "%f %f %f", &x, &y, &z);
|
|
verts.push_back(x);
|
|
verts.push_back(y);
|
|
verts.push_back(z);
|
|
}
|
|
if (row[0] == 'f')
|
|
{
|
|
// Face
|
|
const int vertCount = static_cast<int>(verts.size()) / 3;
|
|
numVertices = readFace(row + 1, face, sizeof(face) / sizeof(face[0]), vertCount);
|
|
for (int i = 2; i < numVertices; ++i)
|
|
{
|
|
const int a = face[0];
|
|
const int b = face[i - 1];
|
|
const int c = face[i];
|
|
if (a < 0 || a >= vertCount || b < 0 || b >= vertCount || c < 0 || c >= vertCount)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
tris.push_back(a);
|
|
tris.push_back(b);
|
|
tris.push_back(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate face normals.
|
|
normals.resize(tris.size());
|
|
for (int i = 0; i < static_cast<int>(tris.size()); i += 3)
|
|
{
|
|
const float* vertex0 = &verts[tris[i + 0] * 3];
|
|
const float* vertex1 = &verts[tris[i + 1] * 3];
|
|
const float* vertex2 = &verts[tris[i + 2] * 3];
|
|
|
|
// Construct two triangle edges
|
|
float edge0[3];
|
|
float edge1[3];
|
|
for (int j = 0; j < 3; ++j)
|
|
{
|
|
edge0[j] = vertex1[j] - vertex0[j];
|
|
edge1[j] = vertex2[j] - vertex0[j];
|
|
}
|
|
|
|
float* normal = &normals[i];
|
|
|
|
// Cross product
|
|
normal[0] = edge0[1] * edge1[2] - edge0[2] * edge1[1];
|
|
normal[1] = edge0[2] * edge1[0] - edge0[0] * edge1[2];
|
|
normal[2] = edge0[0] * edge1[1] - edge0[1] * edge1[0];
|
|
|
|
// Normalize
|
|
float normalLength = sqrtf(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
|
|
if (normalLength > 0)
|
|
{
|
|
normalLength = 1.0f / normalLength;
|
|
normal[0] *= normalLength;
|
|
normal[1] *= normalLength;
|
|
normal[2] *= normalLength;
|
|
}
|
|
}
|
|
}
|