📄 edittrimesh.cpp
字号:
assert(false);
return;
}
// Scan triangle list and fixup vertex indices
for (int i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
// Do we need to delete it?
if (t->material == materialIndex) {
t->mark = 1;
} else {
t->mark = 0;
if (t->material > materialIndex) {
--t->material;
}
}
}
// Delete it
--mCount;
memmove(&mList[materialIndex], &mList[materialIndex+1], (mCount - materialIndex) * sizeof(*mList));
// Delete the triangles that used it
deleteMarkedTris(1);
}
//---------------------------------------------------------------------------
// EditTriMesh::deletePart
//
// Deletes one part from the part list. Part indices in the triangles are
// fixed up and any triangles from that part are deleted
void EditTriMesh::deletePart(int partIndex) {
// Check index. Warn in debug build, don't crash release
if ((partIndex < 0) || (partIndex >= partCount())) {
assert(false);
return;
}
// Scan triangle list and fixup vertex indices
for (int i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
// Do we need to delete it?
if (t->part == partIndex) {
t->mark = 1;
} else {
t->mark = 0;
if (t->part > partIndex) {
--t->part;
}
}
}
// Delete it
--pCount;
memmove(&pList[partIndex], &pList[partIndex+1], (pCount - partIndex) * sizeof(*pList));
// Delete the triangles that used it
deleteMarkedTris(1);
}
//---------------------------------------------------------------------------
// EditTriMesh::deleteUnusedMaterials
//
// Scan list of materials and delete any that are not used by any triangles
//
// This method may seem a little more complicated, but it operates
// in linear time with respect to the number of triangles.
// Other methods will run in quadratic time or worse.
void EditTriMesh::deleteUnusedMaterials() {
int i;
// Assume all materials will be unused
markAllMaterials(0);
// Scan triangle list and mark referenced materials
for (i = 0 ; i < triCount() ; ++i) {
material(tri(i).material).mark = 1;
}
// OK, figure out how many materials there will be,
// and where they will go int he new material list,
// after the unused ones are removed
int newMaterialCount = 0;
for (i = 0 ; i < materialCount() ; ++i) {
Material *m = &material(i);
// Was it used?
if (m->mark == 0) {
// No - mark it to be whacked
m->mark = -1;
} else {
// Yes - it will occupy the next slot in the
// new material list
m->mark = newMaterialCount;
++newMaterialCount;
}
}
// Check if nothing got deleted, then don't bother with the
// rest of this
if (newMaterialCount == materialCount()) {
return;
}
// Fixup indices in the face list
for (i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
t->material = material(t->material).mark;
}
// Remove the empty spaces from the material list
int destMaterialIndex = 0;
for (i = 0 ; i < materialCount() ; ++i) {
const Material *m = &material(i);
// This one staying?
if (m->mark != -1) {
assert(m->mark == destMaterialIndex);
if (i != destMaterialIndex) {
material(destMaterialIndex) = *m;
}
++destMaterialIndex;
}
}
assert(destMaterialIndex == newMaterialCount);
// Set the new count. We don't call the function to
// do this, since it will scan for triangles that use the
// whacked entries. We already took care of that.
mCount = newMaterialCount;
}
//---------------------------------------------------------------------------
// EditTriMesh::deleteEmptyParts
//
// Scan list of parts and delete any that do not contain any triangles
//
// This method may seem a little more complicated, but it operates
// in linear time with respect to the number of triangles.
// Other methods will run in quadratic time or worse.
void EditTriMesh::deleteEmptyParts() {
int i;
// Assume all parts will be empty
markAllParts(0);
// Scan triangle list and mark referenced parts
for (i = 0 ; i < triCount() ; ++i) {
part(tri(i).part).mark = 1;
}
// OK, figure out how many parts there will be,
// and where they will go int he new part list,
// after the unused ones are removed
int newPartCount = 0;
for (i = 0 ; i < partCount() ; ++i) {
Part *p = &part(i);
// Was it used?
if (p->mark == 0) {
// No - mark it to be whacked
p->mark = -1;
} else {
// Yes - it will occupy the next slot in the
// new part list
p->mark = newPartCount;
++newPartCount;
}
}
// Check if nothing got deleted, then don't bother with the
// rest of this
if (newPartCount == partCount()) {
return;
}
// Fixup indices in the face list
for (i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
t->part = part(t->part).mark;
}
// Remove the empty spaces from the part list
int destPartIndex = 0;
for (i = 0 ; i < partCount() ; ++i) {
const Part *p = &part(i);
// This one staying?
if (p->mark != -1) {
assert(p->mark == destPartIndex);
if (i != destPartIndex) {
part(destPartIndex) = *p;
}
++destPartIndex;
}
}
assert(destPartIndex == newPartCount);
// Set the new count. We don't call the function to
// do this, since it will scan for triangles that use the
// whacked entries. We already took care of that.
pCount = newPartCount;
}
//---------------------------------------------------------------------------
// EditTriMesh::deleteMarkedTris
//
// Scan triangle list, deleting triangles with the given mark
void EditTriMesh::deleteMarkedTris(int mark) {
// Scan triangle list, and move triangles forward to
// suck up the "holes" left by deleted triangles
int destTriIndex = 0;
for (int i = 0 ; i < triCount() ; ++i) {
const Tri *t = &tri(i);
// Is it staying?
if (t->mark != mark) {
if (destTriIndex != i) {
tri(destTriIndex) = *t;
}
++destTriIndex;
}
}
// Set new triangle count
setTriCount(destTriIndex);
}
//---------------------------------------------------------------------------
// EditTriMesh::deleteDegenerateTris
//
// Scan triangle list and remove "degenerate" triangles. See
// isDegenerate() for the defininition of "degenerate" in this case.
void EditTriMesh::deleteDegenerateTris() {
// Scan triangle list, marking the bad ones
for (int i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
// Is it bogus?
if (t->isDegenerate()) {
// Mark it to be whacked
t->mark = 1;
} else {
// Keep it
t->mark = 0;
}
}
// Delete the bad triangles that we found
deleteMarkedTris(1);
}
//---------------------------------------------------------------------------
// EditTriMesh::detachAllFaces
//
// Detach all the faces from one another. This creates a new vertex list,
// with each vertex only used by one triangle. Simultaneously, unused
// vertices are removed.
void EditTriMesh::detachAllFaces() {
// Check if we don't have any faces, then bail now.
// This saves us a crash with a spurrious "out of memory"
if (triCount() < 1) {
return;
}
// Figure out how many triangles we'll have
int newVertexCount = triCount() * 3;
// Allocate a new vertex list
Vertex *newVertexList = (Vertex *)::malloc(newVertexCount * sizeof(Vertex));
// Check for out of memory. You may need more
// robust error handling...
if (newVertexList == NULL) {
ABORT("Out of memory");
}
// Scan the triangle list and fill it in
for (int i = 0 ; i < triCount() ; ++i) {
Tri *t = &tri(i);
// Process the three vertices on this face
for (int j = 0 ; j < 3 ; ++j) {
// Get source and destination vertex indices
int sIndex = t->v[j].index;
int dIndex = i*3 + j;
Vertex *dPtr = &newVertexList[dIndex];
// Copy the vertex
*dPtr = vertex(sIndex);
// Go ahead and fill in UV and normal now. It can't hurt
dPtr->u = t->v[j].u;
dPtr->v = t->v[j].v;
dPtr->normal = t->normal;
// Set new vertex index
t->v[j].index = dIndex;
}
}
// Free the old vertex list
::free(vList);
// Install the new one
vList = newVertexList;
vCount = newVertexCount;
vAlloc = newVertexCount;
}
//---------------------------------------------------------------------------
// EditTriMesh::transformVertices
//
// Transform all the vertices. We could transform the surface normals,
// but they may not even be valid, anyway. If you need them, compute them.
void EditTriMesh::transformVertices(const Matrix4x3 &m) {
for (int i = 0 ; i < vertexCount() ; ++i) {
vertex(i).p *= m;
}
}
//---------------------------------------------------------------------------
// EditTriMesh::extractParts
//
// Extract each part into a seperate mesh. Each resulting mesh will
// have exactly one part
void EditTriMesh::extractParts(EditTriMesh *meshes) {
// !SPEED! This function will run in O(partCount * triCount).
// We could optimize it somewhat by having the triangles sorted by
// part. However, any real optimization would be considerably
// more complicated. Let's just keep it simple.
// Scan through each part
for (int partIndex = 0 ; partIndex < partCount() ; ++partIndex) {
// Get shortcut to destination mesh
EditTriMesh *dMesh = &meshes[partIndex];
// Mark all vertices and materials, assuming they will
// not be used by this part
markAllVertices(-1);
markAllMaterials(-1);
// Setup the destination part mesh with a single part
dMesh->empty();
dMesh->setPartCount(1);
dMesh->part(0) = part(partIndex);
// Convert face list, simultaneously building material and
// vertex list
for (int faceIndex = 0 ; faceIndex < triCount() ; ++faceIndex) {
// Fetch shortcut, make sure it belongs to this
// part
Tri *tPtr = &tri(faceIndex);
if (tPtr->part != partIndex) {
continue;
}
// Make a copy
Tri t = *tPtr;
// Remap material index
Material *m = &material(t.material);
if (m->mark < 0) {
m->mark = dMesh->addMaterial(*m);
}
t.material = m->mark;
// Remap vertices
for (int j = 0 ; j < 3 ; ++j) {
Vertex *v = &vertex(t.v[j].index);
if (v->mark < 0) {
v->mark = dMesh->addVertex(*v);
}
t.v[j].index = v->mark;
}
// Add the face
t.part = 0;
dMesh->addTri(t);
}
}
}
void EditTriMesh::extractOnePartOneMaterial(int partIndex, int materialIndex, EditTriMesh *result) {
// Mark all vertices, assuming they will not be used
markAllVertices(-1);
// Setup the destination mesh with a single part and material
result->empty();
result->setPartCount(1);
result->part(0) = part(partIndex);
result->setMaterialCount(1);
result->material(0) = material(materialIndex);
// Convert face list, simultaneously building vertex list
for (int faceIndex = 0 ; faceIndex < triCount() ; ++faceIndex) {
// Fetch shortcut, make sure it belongs to this
// part and uses this material
Tri *tPtr = &tri(faceIndex);
if (tPtr->part != partIndex) {
continue;
}
if (tPtr->material != materialIndex) {
continue;
}
// Make a copy
Tri t = *tPtr;
// Remap vertices
for (int j = 0 ; j < 3 ; ++j) {
Vertex *v = &vertex(t.v[j].index);
if (v->mark < 0) {
v->mark = result->addVertex(*v);
}
t.v[j].index = v->mark;
}
// Add the face
t.part = 0;
t.material = 0;
result->addTri(t);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// EditTriMesh members - Computations
//
/////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------
// EditTriMesh::computeOneTriNormal
//
// Compute a single triangle normal.
void EditTriMesh::computeOneTriNormal(int triIndex) {
computeOneTriNormal(tri(triIndex));
}
void EditTriMesh::computeOneTriNormal(Tri &t) {
// Fetch shortcuts to vertices
const Vector3 &v1 = vertex(t.v[0].index).p;
const Vector3 &v2 = vertex(t.v[1].index).p;
const Vector3 &v3 = vertex(t.v[2].index).p;
// Compute clockwise edge vectors. We use the edge vector
// indexing that agrees with Section 12.6.
Vector3 e1 = v3 - v2;
Vector3 e2 = v1 - v3;
// Cross product to compute surface normal
t.normal = crossProduct(e1, e2);
// Normalize it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -