Show MeshLODVector.cpp syntax highlighted
////////////////////////////////////////////////////////////////////////////////
// Scorched3D (c) 2000-2003
//
// This file is part of Scorched3D.
//
// Scorched3D is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Scorched3D is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Scorched3D; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
// MeshLODVector.cpp: implementation of the MeshLODVector class.
//
//////////////////////////////////////////////////////////////////////
#include <3dsparse/MeshLODTri.h>
#include <3dsparse/MeshLODVector.h>
#include <common/Defines.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
MeshLODVector::MeshLODVector(Vector &v, int _id)
: Vector(v), id(_id)
{
}
MeshLODVector::~MeshLODVector()
{
}
void MeshLODVector::addNeighbour(MeshLODVector *vector)
{
if (vector != this)
{
bool found = false;
std::list<MeshLODVector *>::iterator neighborItor;
for (neighborItor = neighbor.begin();
neighborItor != neighbor.end();
neighborItor++)
{
if (*neighborItor == vector)
{
found = true;
break;
}
}
if (!found) neighbor.push_back(vector);
}
}
void MeshLODVector::removeNeighbor(MeshLODVector *vector)
{
for (unsigned int i=0; i<neighbor.size(); i++)
{
MeshLODVector *vec = neighbor.front();
neighbor.pop_front();
if (vec == vector)
{
break;
}
neighbor.push_back(vec);
}
}
void MeshLODVector::removeIfNonNeighbor(MeshLODVector *n)
{
// removes n from neighbor list if n isn't a neighbor.
std::list<MeshLODTri *>::iterator faceItor;
for (faceItor = face.begin();
faceItor != face.end();
faceItor++)
{
MeshLODTri *tri = (*faceItor);
if(tri->hasVertex(n)) return;
}
removeNeighbor(n);
}
void MeshLODVector::removeFace(MeshLODTri *rface)
{
for (unsigned int i=0; i<face.size(); i++)
{
MeshLODTri *tri = face.front();
face.pop_front();
if (tri == rface)
{
break;
}
face.push_back(tri);
}
}
float MeshLODVector::computeEdgeCollapseCost(MeshLODVector *neigbour)
{
//(Vertex *u,Vertex *v)
// if we collapse edge uv by moving u to v then how
// much different will the model change, i.e. how much "error".
// Texture, vertex normal, and border vertex code was removed
// to keep this demo as simple as possible.
// The method of determining cost was designed in order
// to exploit small and coplanar regions for
// effective polygon reduction.
// Is is possible to add some checks here to see if "folds"
// would be generated. i.e. normal of a remaining face gets
// flipped. I never seemed to run into this problem and
// therefore never added code to detect this case.
float edgelength = (*neigbour - *this).Magnitude();
// find the "sides" triangles that are on the edge uv
std::list<MeshLODTri *> sides;
std::list<MeshLODTri *>::iterator faceItor;
for (faceItor = face.begin();
faceItor != face.end();
faceItor++)
{
if ((*faceItor)->hasVertex(neigbour))
{
sides.push_back(*faceItor);
}
}
// use the triangle facing most away from the sides
// to determine our curvature term
float curvature = 0;
for (faceItor = face.begin();
faceItor != face.end();
faceItor++)
{
float mincurv = 1; // curve for face i and closer side to it
std::list<MeshLODTri *>::iterator sideItor;
for (sideItor = sides.begin();
sideItor != sides.end();
sideItor++)
{
// use dot product of face normals. '^' defined in vector
float dotprod = (*faceItor)->normal.dotP((*sideItor)->normal);
mincurv = MIN(mincurv,(1-dotprod)/2.0f);
}
curvature = MAX(curvature,mincurv);
}
// the more coplanar the lower the curvature term
return edgelength * curvature;
}
void MeshLODVector::computeEdgeCostAtVertex()
{
// compute the edge collapse cost for all edges that start
// from vertex v. Since we are only interested in reducing
// the object by selecting the min cost edge at each step, we
// only cache the cost of the least cost edge at this vertex
// (in member variable collapse) as well as the value of the
// cost (in member variable objdist).
collapse = NULL;
if(neighbor.empty())
{
// v doesn't have neighbors so it costs nothing to collapse
objdist = -0.01f;
}
else
{
// search all neighboring edges for "least cost" edge
objdist = 1000000;
std::list<MeshLODVector *>::iterator neighborItor;
for (neighborItor = neighbor.begin();
neighborItor != neighbor.end();
neighborItor++)
{
float dist = computeEdgeCollapseCost(*neighborItor);
if(dist < objdist)
{
collapse = *neighborItor; // candidate for edge collapse
objdist = dist; // cost of the collapse
}
}
}
}
void MeshLODVector::collapseVertex()
{
// Vertex *u = this,Vertex *v = collapse
// Collapse the edge uv by moving vertex u onto v
// Actually remove tris on uv, then update tris that
// have u to have v, and then remove u.
if(!collapse)
{
// u is a vertex all by itself so just delete it
}
else
{
// make tmp a list of all the neighbors of u
std::list<MeshLODVector *> tmp(neighbor);
// delete triangles on edge uv:
std::list<MeshLODTri *> delList(face);
while (!delList.empty())
{
MeshLODTri *tri = delList.front();
if (tri->hasVertex(collapse))
{
delete tri;
}
delList.pop_front();
}
// update remaining triangles to have v instead of u
std::list<MeshLODTri *> tmpList(face);
while (!tmpList.empty())
{
MeshLODTri *tri = tmpList.front();
tmpList.pop_front();
tri->replaceVertex(this, collapse);
}
// Remove from neigbours lists
while(!neighbor.empty())
{
neighbor.back()->removeNeighbor(this);
neighbor.pop_back();
}
// recompute the edge collapse costs for neighboring vertices
std::list<MeshLODVector *>::iterator tmpItor = tmp.begin();
for (tmpItor = tmp.begin();
tmpItor != tmp.end();
tmpItor++)
{
(*tmpItor)->computeEdgeCostAtVertex();
}
}
}
See more files for this project here