@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
168 lines (131 loc) • 4.88 kB
JavaScript
//
import { assert } from "../../../../assert.js";
import { tm_face_kill } from "../tm_face_kill.js";
import { tm_kill_only_edge } from "../tm_kill_only_edge.js";
import { tm_vert_splice } from "../tm_vert_splice.js";
/**
*
* @param {TopoMesh} mesh
* @param {TopoTriangle} face
*/
function cleanupDanglingEdges(face, mesh) {
// find dangling edges
const edges = face.edges;
const edge_count = edges.length;
for (let i = 0; i < edge_count; i++) {
const edge = edges[i];
if (edge.faces.length === 0) {
// dangling edge, remove
edge.unlink();
tm_kill_only_edge(mesh, edge);
//TODO consider to clean up dangling vertices as well
}
}
}
/**
*
* @param {TopoMesh} mesh
* @param {TopoTriangle} victim_face
* @param {TopoVertex} vertex_victim
* @param {TopoVertex} vertex_successor
*/
function collapseFaceToEdge(mesh, victim_face, vertex_victim, vertex_successor) {
/**
* @type {TopoEdge}
*/
let victim_edge;
/**
* @type {TopoEdge}
*/
let successor_edge;
const collapsing_face_edges = victim_face.edges;
const collapsing_face_edge_0 = collapsing_face_edges[0];
const collapsing_face_edge_1 = collapsing_face_edges[1];
// classify corner edges
if (collapsing_face_edge_0.v0 === vertex_victim) {
victim_edge = collapsing_face_edge_0;
successor_edge = collapsing_face_edge_1;
} else if (collapsing_face_edge_0.v1 === vertex_victim) {
victim_edge = collapsing_face_edge_0;
successor_edge = collapsing_face_edge_1;
} else if (collapsing_face_edge_1.v0 === vertex_victim) {
victim_edge = collapsing_face_edge_1;
successor_edge = collapsing_face_edge_0;
} else {
victim_edge = collapsing_face_edge_1;
successor_edge = collapsing_face_edge_0;
}
victim_edge.unlink();
tm_kill_only_edge(mesh, victim_edge);
// debugValidateMesh(mesh);
// migrate faces
const victims_faces = victim_edge.faces;
const victims_face_count = victims_faces.length;
for (let i = 0; i < victims_face_count; i++) {
const face = victims_faces[i];
if (!face.containsEdge(successor_edge)) {
successor_edge.addFace(face);
face.addEdge(successor_edge);
}
}
// debugValidateMesh(mesh);
}
/**
* Removed edge from the mesh by replacing one of the edge vertices (victim) with the other vertex of the edge (replacement)
* Patches the rest of the topology
* Useful for mesh simplification
* @param {TopoMesh} mesh
* @param {TopoEdge} edge
* @param {TopoVertex} victim
* @param {TopoVertex} replacement
*/
export function partialEdgeCollapse(mesh, edge, victim, replacement) {
// debugValidateMesh(mesh);
// identify triangles attached to the edge
const edge_faces = edge.faces;
const edge_face_count = edge_faces.length;
// unlink the edge
edge.unlink();
// remove the edge
tm_kill_only_edge(mesh, edge);
// debugValidateMesh(mesh);
for (let i = 0; i < edge_face_count; i++) {
const edge_face = edge_faces[i];
// get the other two edges
const remaining_edges = edge_face.edges;
// remove the face
tm_face_kill(mesh, edge_face);
// topology_find_broken_links(mesh);
// debugValidateMesh(mesh);
if (remaining_edges.length === 2) {
// const remaining_edge_0 = remaining_edges[0];
// const remaining_edge_1 = remaining_edges[1];
// merge the two remaining edges of the face that's being removed
// remaining_edge_0.merge(remaining_edge_1);
collapseFaceToEdge(mesh, edge_face, victim, replacement);
// debugValidateMesh(mesh);
// topology_find_broken_links(mesh);
// remove absorbed edge
// mesh.removeEdge(remaining_edge_1);
// topology_find_broken_links(mesh);
}
// debugValidateMesh(mesh);
//
cleanupDanglingEdges(edge_face, mesh);
}
}
/**
* Removed edge from the mesh by replacing one of the edge vertices (victim) with the other vertex of the edge (replacement)
* Patches the rest of the topology
* Useful for mesh simplification
* @param {TopoMesh} mesh
* @param {TopoEdge} edge
* @param {TopoVertex} victim
* @param {TopoVertex} replacement
*/
export function collapseEdge(mesh, edge, victim, replacement) {
assert.notEqual(victim, replacement, 'victim === replacement');
partialEdgeCollapse(mesh, edge, victim, replacement);
// replace the victim vertex with the replacer
tm_vert_splice(mesh,replacement,victim);
}