meshio.cpp
来自「RBF平台」· C++ 代码 · 共 1,634 行 · 第 1/3 页
CPP
1,634 行
// MeshIO.cpp: implementation of the CMeshIO class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "../rbfmodelor.h"
#include "MeshIO.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#ifdef WIN32
# ifndef strncasecmp
# define strncasecmp strnicmp
# endif
#endif
#define GET_LINE() if (!fgets(buf, 1024, f)) return false
#define COND_READ(cond, where, len) if ((cond) && !fread((void *)&(where), (len), 1, f)) return false
#define LINE_IS(text) !strncasecmp(buf, text, strlen(text))
#define BIGNUM 1.0e10
static void tess(const vector<point> &verts, const vector<int> &thisface, vector<TriMesh::Face> &tris);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMeshIO::CMeshIO()
{
}
CMeshIO::~CMeshIO()
{
}
// Actually read a mesh. Tries to figure out type of file from first
// few bytes. Filename can be "-" for stdin
bool CMeshIO::read_helper(const char *filename, TriMesh *mesh)
{
if (!filename || *filename == '\0')
return false;
FILE *f = NULL;
bool ok = false;
int c;
if (strcmp(filename, "-") == 0) {
f = stdin;
filename = "standard input";
} else {
f = fopen(filename, "rb");
if (!f) {
perror("fopen");
goto out;
}
}
//dprintf("Reading %s... ", filename);
c = fgetc(f);
if (c == EOF) {
fprintf(stderr, "Can't read header\n");
goto out;
}
if (c == 'p') {
// See if it's a ply file
char buf[4];
if (!fgets(buf, 4, f)) {
fprintf(stderr, "Can't read header\n");
goto out;
}
if (strncmp(buf, "ly", 2) == 0)
ok = read_ply(f, mesh);
} else if (c == 0x4d) {
int c2 = fgetc(f);
ungetc(c2, f);
ungetc(c, f);
if (c2 == 0x4d)
ok = read_3ds(f, mesh);
} else if (c == '#') {
char buf[1024];
fscanf(f, "%1024s", buf);
if (LINE_IS("material") || LINE_IS("vertex") ||
LINE_IS("shape_")) {
// Assume a ray file
pushback(buf, f);
ungetc(c, f);
ok = read_ray(f, mesh);
} else {
// Assume an obj file
ok = read_obj(f, mesh);
}
} else if (c == 'v' || c == 'u' || c == 'f' || c == 'g' || c == 's' || c == 'o') {
// Assume an obj file
ungetc(c, f);
ok = read_obj(f, mesh);
} else if (c == 'O') {
// Assume an OFF file
char buf[3];
if (!fgets(buf, 3, f)) {
fprintf(stderr, "Can't read header\n");
goto out;
}
if (strncmp(buf, "FF", 2) == 0)
ok = read_off(f, mesh);
} else if (isdigit(c)) {
// Assume an old-style sm file
ungetc(c, f);
ok = read_sm(f, mesh);
} else {
fprintf(stderr, "Unknown file type\n");
}
out:
if (f)
fclose(f);
if (!ok || (mesh->vertices.empty() && mesh->faces.empty())) {
fprintf(stderr, "\nError reading file [%s]\n", filename);
return false;
}
//dprintf("Done.\n");
check_ind_range(mesh);
return true;
}
// Read a ply file
bool CMeshIO::read_ply(FILE *f, TriMesh *mesh)
{
char buf[1024];
bool binary, need_swap;
int range_width = -1, range_height = -1;
int result, nverts = 0, nfaces = 0, nstrips = 0, ngrid = 0;
int vert_len = 0, vert_pos = -1, vert_norm = -1;
int vert_color = -1, vert_conf = -1;
int face_len = 0, face_count = -1, face_idx = -1;
// Read file format
GET_LINE();
while (buf[0] && isspace(buf[0]))
GET_LINE();
if (LINE_IS("format binary_big_endian 1.0")) {
binary = true;
need_swap = we_are_little_endian();
} else if (LINE_IS("format binary_little_endian 1.0")) {
binary = true;
need_swap = !we_are_little_endian();
} else if (LINE_IS("format ascii 1.0")) {
binary = false;
} else {
fprintf(stderr, "Unknown ply format or version\n");
return false;
}
// Skip comments and unknown obj_info lines
GET_LINE();
while (LINE_IS("obj_info") || LINE_IS("comment")) {
if (LINE_IS("obj_info num_cols"))
sscanf(buf, "obj_info num_cols %d", &range_width);
if (LINE_IS("obj_info num_rows"))
sscanf(buf, "obj_info num_rows %d", &range_height);
GET_LINE();
}
// Find number of vertices
result = sscanf(buf, "element vertex %d\n", &nverts);
if (result != 1) {
fprintf(stderr, "Expected \"element vertex\"\n");
return false;
}
// Parse vertex properties
GET_LINE();
while (LINE_IS("property")) {
if (LINE_IS("property float x") ||
LINE_IS("property float32 x"))
vert_pos = vert_len;
if (LINE_IS("property float nx") ||
LINE_IS("property float32 nx"))
vert_norm = vert_len;
if (LINE_IS("property uchar diffuse_red") ||
LINE_IS("property uint8 diffuse_red") ||
LINE_IS("property uchar red") ||
LINE_IS("property uint8 red"))
vert_color = vert_len;
if (LINE_IS("property float confidence") ||
LINE_IS("property float32 confidence"))
vert_conf = vert_len;
if (!ply_property(buf, vert_len, binary))
return false;
GET_LINE();
}
// Look for faces, tristrips, or range grid
if (LINE_IS("element face")) {
if (sscanf(buf, "element face %d\n", &nfaces) != 1)
return false;
GET_LINE();
while (LINE_IS("property")) {
if (LINE_IS("property list uchar int vertex_indices") ||
LINE_IS("property list uint8 int32 vertex_indices") ||
LINE_IS("property list char int vertex_indices") ||
LINE_IS("property list int8 int32 vertex_indices")||
LINE_IS("property list uchar int vertex_index")||
LINE_IS("property list uint8 int32 vertex_index")||
LINE_IS("property list char int vertex_index") ||
LINE_IS("property list int8 int32 vertex_index")) {
face_count = face_len;
face_idx = face_len + 1;
face_len += 1;
} else if
(LINE_IS("property list uint int vertex_indices") ||
LINE_IS("property list uint32 int32 vertex_indices") ||
LINE_IS("property list int int vertex_indices") ||
LINE_IS("property list int32 int32 vertex_indices")||
LINE_IS("property list uint int vertex_index") ||
LINE_IS("property list uint32 int32 vertex_index") ||
LINE_IS("property list int int vertex_index") ||
LINE_IS("property list int32 int32 vertex_index")) {
face_count = face_len;
face_idx = face_len + (binary ? 4 : 1);
face_len += (binary ? 4 : 1);
} else if (!ply_property(buf, face_len, binary))
return false;
GET_LINE();
}
} else if (LINE_IS("element tristrips")) {
nstrips = 1;
GET_LINE();
if (!LINE_IS("property list int int vertex_indices") &&
!LINE_IS("property list int32 int32 vertex_indices"))
return false;
GET_LINE();
} else if (LINE_IS("element range_grid")) {
if (sscanf(buf, "element range_grid %d\n", &ngrid) != 1)
return false;
if (ngrid != range_width*range_height) {
fprintf(stderr, "Range grid size does not equal num_rows*num_cols\n");
return false;
}
GET_LINE();
if (!LINE_IS("property list uchar int vertex_indices") &&
!LINE_IS("property list uint8 int32 vertex_indices") &&
!LINE_IS("property list char int vertex_indices") &&
!LINE_IS("property list int8 int32 vertex_indices"))
return false;
GET_LINE();
}
while (LINE_IS("property")) {
if (!ply_property(buf, face_len, binary))
return false;
GET_LINE();
}
// Skip to the end of the header
while (!LINE_IS("end_header"))
GET_LINE();
if (binary && buf[10] == '\r') {
fprintf(stderr, "Warning! Possibly corrupt file\n");
fprintf(stderr, " If things don't work, make sure this file was transferred in BINARY, not ASCII mode\n");
}
// Actually read everything in
if (binary) {
if (!read_verts_bin(f, mesh, need_swap, nverts, vert_len,
vert_pos, vert_norm, vert_color, vert_conf))
return false;
} else {
if (!read_verts_asc(f, mesh, nverts, vert_len,
vert_pos, vert_norm, vert_color, vert_conf))
return false;
}
if (ngrid) {
if (binary) {
if (!read_grid_bin(f, mesh, need_swap,
range_width, range_height))
return false;
} else {
if (!read_grid_asc(f, mesh,
range_width, range_height))
return false;
}
} else if (nstrips) {
if (binary) {
if (!read_strips_bin(f, mesh, need_swap))
return false;
} else {
if (!read_strips_asc(f, mesh))
return false;
}
mesh->convert_strips(TriMesh::TSTRIP_LENGTH);
} else if (nfaces) {
if (binary) {
if (!read_faces_bin(f, mesh, need_swap, nfaces,
face_len, face_count, face_idx))
return false;
} else {
if (!read_faces_asc(f, mesh, nfaces,
face_len, face_count, face_idx))
return false;
}
}
return true;
}
#define CHUNK_3DS_MAIN 0x4d4d
#define CHUNK_3DS_MODEL 0x3d3d
#define CHUNK_3DS_OBJ 0x4000
#define CHUNK_3DS_MESH 0x4100
#define CHUNK_3DS_VERT 0x4110
#define CHUNK_3DS_FACE 0x4120
// Read a 3DS file.
bool CMeshIO::read_3ds(FILE *f, TriMesh *mesh)
{
bool need_swap = !we_are_little_endian();
int mstart = 0;
while (!feof(f)) {
short chunkid;
int chunklen;
if (!fread(&chunkid, 2, 1, f) ||
!fread(&chunklen, 4, 1, f))
return false;
if (need_swap) {
swap_short(chunkid);
swap_int(chunklen);
}
//TriMesh::dprintf("Found chunk %x of length %d\n", chunkid, chunklen);
switch (chunkid) {
case CHUNK_3DS_MAIN:
case CHUNK_3DS_MODEL:
// Just recurse into this chunk
break;
case CHUNK_3DS_OBJ:
// Skip name, then recurse
while (!feof(f) && fgetc(f))
;
break;
case CHUNK_3DS_MESH:
mstart = mesh->vertices.size();
break;
case CHUNK_3DS_VERT: {
unsigned short nverts;
if (!fread(&nverts, 2, 1, f))
return false;
if (need_swap)
swap_ushort(nverts);
read_verts_bin(f, mesh, need_swap,
nverts, 12, 0, -1, -1, -1);
break;
}
case CHUNK_3DS_FACE: {
unsigned short nfaces;
if (!fread(&nfaces, 2, 1, f))
return false;
if (need_swap)
swap_ushort(nfaces);
TriMesh::dprintf("\n Reading %d faces... ", nfaces);
int old_nfaces = mesh->faces.size();
int new_nfaces = old_nfaces + nfaces;
mesh->faces.resize(new_nfaces);
for (int i = old_nfaces; i < new_nfaces; i++) {
unsigned short buf[4];
COND_READ(true, buf[0], 8);
if (need_swap) {
swap_ushort(buf[0]);
swap_ushort(buf[1]);
swap_ushort(buf[2]);
}
mesh->faces[i][0] = mstart + buf[0];
mesh->faces[i][1] = mstart + buf[1];
mesh->faces[i][2] = mstart + buf[2];
}
break;
}
default: {
// Skip over this chunk
fseek(f, chunklen-6, SEEK_CUR);
}
}
}
return true;
}
// Read a ray file
bool CMeshIO::read_ray(FILE *f, TriMesh *mesh)
{
while (!feof(f)) {
char buf[1024];
buf[0] = '\0';
if (fscanf(f, " %1024s", buf) == 0)
return true;
if (LINE_IS("#vertex")) {
float x, y, z;
if (fscanf(f, "%f %f %f", &x, &y, &z) != 3) {
return false;
}
mesh->vertices.push_back(point(x,y,z));
} else if (LINE_IS("#shape_triangle")) {
int f1, f2, f3, m;
if (fscanf(f, "%d %d %d %d", &m, &f1, &f2, &f3) != 4) {
return false;
}
mesh->faces.push_back(TriMesh::Face(f1,f2,f3));
}
}
return true;
}
// Read an obj file
bool CMeshIO::read_obj(FILE *f, TriMesh *mesh)
{
vector<int> thisface;
while (1) {
skip_comments(f);
if (feof(f))
return true;
char buf[1024];
GET_LINE();
if (LINE_IS("v ") || LINE_IS("v\t")) {
float x, y, z;
if (sscanf(buf+1, "%f %f %f", &x, &y, &z) != 3) {
return false;
}
mesh->vertices.push_back(point(x,y,z));
} else if (LINE_IS("f ") || LINE_IS("f\t") ||
LINE_IS("t ") || LINE_IS("t\t")) {
thisface.clear();
char *c = buf;
while (1) {
while (*c && *c != '\n' && !isspace(*c))
c++;
while (*c && isspace(*c))
c++;
int thisf;
if (sscanf(c, " %d", &thisf) != 1)
break;
if (thisf < 0)
thisf += mesh->vertices.size();
else
thisf--;
thisface.push_back(thisf);
}
tess(mesh->vertices, thisface, mesh->faces);
}
}
return true;
}
// Read an off file
bool CMeshIO::read_off(FILE *f, TriMesh *mesh)
{
skip_comments(f);
char buf[1024];
GET_LINE();
int nverts, nfaces, unused;
if (sscanf(buf, "%d %d %d", &nverts, &nfaces, &unused) < 2)
return false;
if (!read_verts_asc(f, mesh, nverts, 3, 0, -1, -1, -1))
return false;
if (!read_faces_asc(f, mesh, nfaces, 1, 0, 1, true))
return false;
return true;
}
// Read an sm file
bool CMeshIO::read_sm(FILE *f, TriMesh *mesh)
{
int nverts, nfaces;
if (fscanf(f, "%d", &nverts) != 1)
return false;
if (!read_verts_asc(f, mesh, nverts, 3, 0, -1, -1, -1))
return false;
skip_comments(f);
if (fscanf(f, "%d", &nfaces) != 1)
return true;
if (!read_faces_asc(f, mesh, nfaces, 0, -1, 0))
return false;
return true;
}
// Read a bunch of vertices from a binary file
bool CMeshIO::read_verts_bin(FILE *f, TriMesh *mesh, bool &need_swap,
int nverts, int vert_len, int vert_pos, int vert_norm,
int vert_color, int vert_conf)
{
if (nverts <= 0 || vert_len < 12 || vert_pos < 0)
return false;
int old_nverts = mesh->vertices.size();
int new_nverts = old_nverts + nverts;
mesh->vertices.resize(new_nverts);
int last = vert_pos + 12;
int norm_skip = vert_norm - last;
bool have_norm = (norm_skip >= 0);
if (have_norm) {
mesh->normals.resize(new_nverts);
last = vert_norm + 12;
}
int color_skip = vert_color - last;
bool have_colors = (color_skip >= 0);
if (have_colors) {
mesh->colors.resize(new_nverts);
last = vert_color + 3;
}
int conf_skip = vert_conf - last;
bool have_conf = (conf_skip >= 0);
if (have_conf) {
mesh->confidences.resize(new_nverts);
last = vert_conf + 4;
}
int skip = vert_len - last + vert_pos;
int i = old_nverts;
char buf[1024];
COND_READ(vert_pos > 0, buf[0], vert_pos);
COND_READ(true, mesh->vertices[i][0], 12);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?