📄 edittrimesh.cpp
字号:
t.normal.normalize();
}
//---------------------------------------------------------------------------
// EditTriMesh::computeTriNormals
//
// Compute all the triangle normals
void EditTriMesh::computeTriNormals() {
for (int i = 0 ; i < triCount() ; ++i) {
computeOneTriNormal(tri(i));
}
}
//---------------------------------------------------------------------------
// EditTriMesh::computeTriNormals
//
// Compute vertex level surface normals. This automatically computes the
// triangle level surface normals
void EditTriMesh::computeVertexNormals() {
int i;
// First, make sure triangle level surface normals are up-to-date
computeTriNormals();
// Zero out vertex normals
for (i = 0 ; i < vertexCount() ; ++i) {
vertex(i).normal.zero();
}
// Sum in the triangle normals into the vertex normals
// that are used by the triangle
for (i = 0 ; i < triCount() ; ++i) {
const Tri *t = &tri(i);
for (int j = 0 ; j < 3 ; ++j) {
vertex(t->v[j].index).normal += t->normal;
}
}
// Now "average" the vertex surface normals, by normalizing them
for (i = 0 ; i < vertexCount() ; ++i) {
vertex(i).normal.normalize();
}
}
//---------------------------------------------------------------------------
// EditTriMesh::computeBounds
//
// Compute the bounding box of the mesh
AABB3 EditTriMesh::computeBounds() const {
// Generate the bounding box of the vertices
AABB3 box;
box.empty();
for (int i = 0 ; i < vertexCount() ; ++i) {
box.add(vertex(i).p);
}
// Return it
return box;
}
/////////////////////////////////////////////////////////////////////////////
//
// EditTriMesh members - Optimization
//
/////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
// EditTriMesh::optimizeVertexOrder
//
// Re-order the vertex list, in the order that they are used by the faces.
// This can improve cache performace and vertex caching by increasing the
// locality of reference.
//
// If removeUnusedVertices is true, then any unused vertices are discarded.
// Otherwise, they are retained at the end of the vertex list. Normally
// you will want to discard them, which is why we default the paramater to
// true.
void EditTriMesh::optimizeVertexOrder(bool removeUnusedVertices) {
int i;
// Mark all vertices with a very high mark, which assumes
// that they will not be used
for (i = 0 ; i < vertexCount() ; ++i) {
vertex(i).mark = vertexCount();
}
// Scan the face list, and figure out where the vertices
// will end up in the new, ordered list. At the same time,
// we remap the indices in the triangles according to this
// new ordering.
int usedVertexCount = 0;
for (i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
// Process each of the three vertices on this triangle
for (int j = 0 ; j < 3 ; ++j) {
// Get shortcut to the vertex used
Vertex *v = &vertex(t->v[j].index);
// Has it been used already?
if (v->mark == vertexCount()) {
// We're the first triangle to use
// this one. Assign the vertex to
// the next slot in the new vertex
// list
v->mark = usedVertexCount;
++usedVertexCount;
}
// Remap the vertex index
t->v[j].index = v->mark;
}
}
// Re-sort the vertex list. This puts the used vertices
// in order where they go, and moves all the unused vertices
// to the end (in no particular order, since qsort is not
// a stable sort)
qsort(vList, vertexCount(), sizeof(Vertex), vertexCompareByMark);
// Did they want to discard the unused guys?
if (removeUnusedVertices) {
// Yep - chop off the unused vertices by slamming
// the vertex count. We don't call the function to
// set the vertex count here, since it will scan
// the triangle list for any triangle that use those
// vertices. But we already know that all of the
// vertices we are deleting are unused
vCount = usedVertexCount;
}
}
//---------------------------------------------------------------------------
// EditTriMesh::sortTrisByMaterial
//
// Sort triangles by material. This is VERY important for effecient
// rendering
void EditTriMesh::sortTrisByMaterial() {
// Put the current index into the "mark" field so we can
// have a stable sort
for (int i = 0 ; i < triCount() ; ++i) {
tri(i).mark = i;
}
// Use qsort
qsort(tList, triCount(), sizeof(Tri), triCompareByMaterial);
}
//---------------------------------------------------------------------------
// EditTriMesh::weldVertices
//
// Weld coincident vertices. For the moment, this disregards UVs and welds
// all vertices that are within geometric tolerance
void EditTriMesh::weldVertices(const OptimizationParameters &opt) {
// !FIXME!
}
//---------------------------------------------------------------------------
// EditTriMesh::copyUvsIntoVertices
//
// Ensure that the vertex UVs are correct, possibly duplicating
// vertices if necessary
void EditTriMesh::copyUvsIntoVertices() {
// Mark all vertices indicating thet their UV's are invalid
markAllVertices(0);
// Scan the faces, and shove in the UV's into the vertices
for (int triIndex = 0 ; triIndex < triCount() ; ++triIndex) {
Tri *triPtr = &tri(triIndex);
for (int i = 0 ; i < 3 ; ++i) {
// Locate vertex
int vIndex = triPtr->v[i].index;
Vertex *vPtr = &vertex(vIndex);
// Have we filled in the UVs for this vertex yet?
if (vPtr->mark == 0) {
// Nope. Shove them in
vPtr->u = triPtr->v[i].u;
vPtr->v = triPtr->v[i].v;
// Mark UV's as valid, and keep going
vPtr->mark = 1;
continue;
}
// UV's have already been filled in by another face.
// Did that face have the same UV's as me?
if (
(vPtr->u == triPtr->v[i].u) &&
(vPtr->v == triPtr->v[i].v)
) {
// Yep - no need to change anything
continue;
}
// OK, we can't use this vertex - somebody else already has
// it "claimed" with different UV's. First, we'll search
// for another vertex with the same position. Yikes -
// this requires a linear search through the vertex list.
// Luckily, this should not happen the majority of the time.
bool foundOne = false;
for (int newIndex = 0 ; newIndex < vertexCount() ; ++newIndex) {
Vertex *newPtr = &vertex(newIndex);
// Is the position and normal correct?
if (
(newPtr->p != vPtr->p) ||
(newPtr->normal != vPtr->normal)
) {
continue;
}
// OK, this vertex is geometrically correct.
// Has anybody filled in the UV's yet?
if (newPtr->mark == 0) {
// We can claim this one.
newPtr->mark = 1;
newPtr->u = triPtr->v[i].u;
newPtr->v = triPtr->v[i].v;
// Remap vertex index
triPtr->v[i].index = newIndex;
// No need to keep looking
foundOne = true;
break;
}
// Already claimed by somebody else, so we can't change
// them. but are they correct, already anyway?
if (
(newPtr->u == triPtr->v[i].u) &&
(newPtr->v == triPtr->v[i].v)
) {
// Yep - no need to change anything. Just remap the
// vertex index
triPtr->v[i].index = newIndex;
// No need to keep looking
foundOne = true;
break;
}
// No good - keep looking
}
// Did we find a vertex?
if (!foundOne) {
// Nope, we'll have to create a new one
Vertex newVertex = *vPtr;
newVertex.mark = 1;
newVertex.u = triPtr->v[i].u;
newVertex.v = triPtr->v[i].v;
triPtr->v[i].index = addVertex(newVertex);
}
}
}
}
// Do all of the optimizations and prepare the model
// for fast rendering under *most* rendering systems,
// with proper lighting.
void EditTriMesh::optimizeForRendering() {
computeVertexNormals();
}
/////////////////////////////////////////////////////////////////////////////
//
// EditTriMesh members - Import/Export S3D format
//
// For more on the S3D file format, and free tools for using the
// S3D format with popular rendering packages, visit
// gamemath.com
//
/////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
// EditTriMesh::importS3d
//
// Load up an S3D file. Returns true on success. If failure, returns
// false and puts an error message into returnErrMsg
bool EditTriMesh::importS3d(const char *filename, char *returnErrMsg) {
int i;
// Try to open up the file
FILE *f = fopen(filename, "rt");
if (f == NULL) {
strcpy(returnErrMsg, "Can't open file");
failed:
empty();
if (f != NULL) {
fclose(f);
}
return false;
}
// Read and check version
if (!skipLine(f)) {
corrupt:
strcpy(returnErrMsg, "File is corrupt");
goto failed;
}
int version;
if (fscanf(f, "%d\n", &version) != 1) {
goto corrupt;
}
if (version != 103) {
sprintf(returnErrMsg, "File is version %d - only version 103 supported", version);
goto failed;
}
// Read header
if (!skipLine(f)) {
goto corrupt;
}
int numTextures, numTris, numVerts, numParts, numFrames, numLights, numCameras;
if (fscanf(f, "%d , %d , %d , %d , %d , %d , %d\n", &numTextures, &numTris, &numVerts, &numParts, &numFrames, &numLights, &numCameras) != 7) {
goto corrupt;
}
// Allocate lists
setMaterialCount(numTextures);
setTriCount(numTris);
setVertexCount(numVerts);
setPartCount(numParts);
// Read part list. the only number we care about
// is the triangle count, which we'll temporarily
// stach into the mark field
if (!skipLine(f)) {
goto corrupt;
}
int firstVert = 0, firstTri = 0;
for (i = 0 ; i < numParts ; ++i) {
Part *p = &part(i);
int partFirstVert, partNumVerts, partFirstTri, partNumTris;
if (fscanf(f, "%d , %d , %d , %d , \"%[^\"]\"\n", &partFirstVert, &partNumVerts, &partFirstTri, &partNumTris, p->name) != 5) {
sprintf(returnErrMsg, "Corrupt at part %d", i);
goto failed;
}
if (firstVert != partFirstVert || firstTri != partFirstTri) {
sprintf(returnErrMsg, "Part vertex/tri mismatch detected at part %d", i);
goto failed;
}
p->mark = partNumTris;
firstVert += partNumVerts;
firstTri += partNumTris;
}
if (firstVert != numVerts || firstTri != numTris) {
strcpy(returnErrMsg, "Part vertex/tri mismatch detected at end of part list");
goto failed;
}
// Read textures.
if (!skipLine(f)) {
goto corrupt;
}
for (i = 0 ; i < numTextures ; ++i) {
Material *m = &material(i);
// Fetch line of text
if (fgets(m->diffuseTextureName, sizeof(m->diffuseTextureName), f) != m->diffuseTextureName) {
sprintf(returnErrMsg, "Corrupt reading texture %d", i);
goto failed;
}
// Styrip off newline, which fgets leaves.
// Wouldn't it have been nice if the stdio
// functions would just have a function to read a line
// WITHOUT the newline character. What a pain...
char *nl = strchr(m->diffuseTextureName, '\n');
if (nl != NULL) {
*nl = '\0';
}
}
// Read triangles a part at a time
if (!skipLine(f)) {
goto corrupt;
}
int whiteTextureIndex = -1;
int destTriIndex = 0;
for (int partIndex = 0 ; partIndex < numParts ; ++partIndex) {
// Read all triangles in this part
for (int i = 0 ; i < part(partIndex).mark ; ++i) {
// get shortcut to destination triangle
Tri *t = &tri(destTriIndex);
// Slam part number
t->part = partIndex;
// Parse values from file
if (fscanf(f, "%d , %d , %f , %f , %d , %f , %f , %d , %f , %f\n",
&t->material,
&t->v[0].index, &t->v[0].u, &t->v[0].v,
&t->v[1].index, &t->v[1].u, &t->v[1].v,
&t->v[2].index, &t->v[2].u, &t->v[2].v
) != 10) {
sprintf(returnErrMsg, "Corrupt reading triangle %d (%d of part %d)", destTriIndex, i, partIndex);
goto failed;
}
// Check for untextured triangle
if (t->material < 0) {
if (whiteTextureIndex < 0) {
Material whiteMaterial;
strcpy(whiteMaterial.diffuseTextureName, "White");
whiteTextureIndex = addMaterial(whiteMaterial);
}
t->material = whiteTextureIndex;
}
// Scale UV's to 0...1 range
t->v[0].u /= 256.0f;
t->v[0].v /= 256.0f;
t->v[1].u /= 256.0f;
t->v[1].v /= 256.0f;
t->v[2].u /= 256.0f;
t->v[2].v /= 256.0f;
// Next triangle, please
++destTriIndex;
}
}
assert(destTriIndex == triCount());
// Read vertices
if (!skipLine(f)) {
goto corrupt;
}
for (i = 0 ; i < numVerts ; ++i) {
Vertex *v = &vertex(i);
if (fscanf(f, "%f , %f , %f\n", &v->p.x, &v->p.y, &v->p.z) != 3) {
sprintf(returnErrMsg, "Corrupt reading vertex %d", i);
goto failed;
}
}
// OK, we don't need anything from the rest of the file. Close file.
fclose(f);
f = NULL;
// Check for structural errors in the mesh
if (!validityCheck(returnErrMsg)) {
goto failed;
}
// OK!
return true;
}
void EditTriMesh::exportS3d(const char *filename) {
}
/////////////////////////////////////////////////////////////////////////////
//
// EditTriMesh members - Debugging
//
/////////////////////////////////////////////////////////////////////////////
void EditTriMesh::validityCheck() {
char errMsg[256];
if (!validityCheck(errMsg)) {
ABORT("EditTriMesh failed validity check:\n%s", errMsg);
}
}
bool EditTriMesh::validityCheck(char *returnErrMsg) {
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -