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 + -
显示快捷键?