internal void SetDetails(uint index, PMFaceVertex v0, PMFaceVertex v1, PMFaceVertex v2) { Debug.Assert(v0 != v1 && v1 != v2 && v2 != v0); this.index = index; this.vertex[0] = v0; this.vertex[1] = v1; this.vertex[2] = v2; ComputeNormal(); // Add tri to vertices // Also tell vertices they are neighbours for (var i = 0; i < 3; i++) { this.vertex[i].commonVertex.faces.Add(this); for (var j = 0; j < 3; j++) { if (i != j) { this.vertex[i].commonVertex.AddIfNonNeighbor(this.vertex[j].commonVertex); } } } }
internal void ReplaceVertex(PMFaceVertex vold, PMFaceVertex vnew) { Debug.Assert(vold == this.vertex[0] || vold == this.vertex[1] || vold == this.vertex[2]); Debug.Assert(vnew != this.vertex[0] && vnew != this.vertex[1] && vnew != this.vertex[2]); if (vold == this.vertex[0]) { this.vertex[0] = vnew; } else if (vold == this.vertex[1]) { this.vertex[1] = vnew; } else { this.vertex[2] = vnew; } vold.commonVertex.faces.Remove(this); vnew.commonVertex.faces.Add(this); for (var i = 0; i < 3; i++) { vold.commonVertex.RemoveIfNonNeighbor(this.vertex[i].commonVertex); this.vertex[i].commonVertex.RemoveIfNonNeighbor(vold.commonVertex); } for (var i = 0; i < 3; i++) { Debug.Assert(this.vertex[i].commonVertex.faces.Contains(this)); for (var j = 0; j < 3; j++) { if (i != j) { this.vertex[i].commonVertex.AddIfNonNeighbor(this.vertex[j].commonVertex); } } } ComputeNormal(); }
/// <summary> /// Internal method, collapses vertex onto it's saved collapse target. /// </summary> /// <remarks> /// This updates the working triangle list to drop a triangle and recalculates /// the edge collapse costs around the collapse target. /// This also updates all the working vertex lists for the relevant buffer. /// </remarks> /// <pram name="src">the collapser</pram> private void Collapse(PMVertex src) { var dest = src.collapseTo; var recomputeSet = new List <PMVertex>(); // Abort if we're never supposed to collapse if (src.collapseCost == float.MaxValue) { return; } // Remove this vertex from the running for the next check src.collapseTo = null; src.collapseCost = float.MaxValue; this.worstCosts[(int)src.index] = float.MaxValue; // 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 (dest == null) { // src is a vertex all by itself return; } // Add dest and all the neighbours of source and dest to recompute list recomputeSet.Add(dest); foreach (var neighbor in src.neighbors) { if (!recomputeSet.Contains(neighbor)) { recomputeSet.Add(neighbor); } } foreach (var neighbor in dest.neighbors) { if (!recomputeSet.Contains(neighbor)) { recomputeSet.Add(neighbor); } } // delete triangles on edge src-dest // Notify others to replace src with dest // Queue of faces for removal / replacement // prevents us screwing up the iterators while we parse var faceRemovalList = new List <PMTriangle>(); var faceReplacementList = new List <PMTriangle>(); foreach (var face in src.faces) { if (face.HasCommonVertex(dest)) { // Tri is on src-dest therefore is gone faceRemovalList.Add(face); // Reduce index count by 3 (useful for quick allocation later) this.currNumIndexes -= 3; } else { // Only src involved, replace with dest faceReplacementList.Add(face); } } src.toBeRemoved = true; // Replace all the faces queued for replacement foreach (var face in faceReplacementList) { /* Locate the face vertex which corresponds with the common 'dest' vertex * To to this, find a removed face which has the FACE vertex corresponding with * src, and use it's FACE vertex version of dest. */ var srcFaceVert = face.GetFaceVertexFromCommon(src); PMFaceVertex destFaceVert = null; foreach (var removed in faceRemovalList) { //if (removed.HasFaceVertex(srcFaceVert)) //{ destFaceVert = removed.GetFaceVertexFromCommon(dest); //} } Debug.Assert(destFaceVert != null); face.ReplaceVertex(srcFaceVert, destFaceVert); } // Remove all the faces queued for removal foreach (var face in faceRemovalList) { face.NotifyRemoved(); } // Notify the vertex that it is gone src.NotifyRemoved(); // recompute costs foreach (var recomp in recomputeSet) { ComputeEdgeCostAtVertex(recomp.index); } }
private bool HasFaceVertex(PMFaceVertex v) { return(v == this.vertex[0] || v == this.vertex[1] || v == this.vertex[2]); }
bool HasFaceVertex(PMFaceVertex v) { return (v == vertex[0] || v == vertex[1] || v == vertex[2]); }
internal void SetDetails(uint index, PMFaceVertex v0, PMFaceVertex v1, PMFaceVertex v2) { Debug.Assert(v0 != v1 && v1 != v2 && v2 != v0); this.index = index; vertex[0] = v0; vertex[1] = v1; vertex[2] = v2; ComputeNormal(); // Add tri to vertices // Also tell vertices they are neighbours for (int i = 0; i < 3; i++) { vertex[i].commonVertex.faces.Add(this); for (int j = 0; j < 3; j++) if (i != j) vertex[i].commonVertex.AddIfNonNeighbor(vertex[j].commonVertex); } }
internal void ReplaceVertex(PMFaceVertex vold, PMFaceVertex vnew) { Debug.Assert(vold == vertex[0] || vold == vertex[1] || vold == vertex[2]); Debug.Assert(vnew != vertex[0] && vnew != vertex[1] && vnew != vertex[2]); if (vold == vertex[0]) { vertex[0] = vnew; } else if (vold == vertex[1]) { vertex[1] = vnew; } else { vertex[2] = vnew; } vold.commonVertex.faces.Remove(this); vnew.commonVertex.faces.Add(this); for (int i = 0; i < 3; i++) { vold.commonVertex.RemoveIfNonNeighbor(vertex[i].commonVertex); vertex[i].commonVertex.RemoveIfNonNeighbor(vold.commonVertex); } for (int i = 0; i < 3; i++) { Debug.Assert(vertex[i].commonVertex.faces.Contains(this)); for (int j = 0; j < 3; j++) if (i != j) vertex[i].commonVertex.AddIfNonNeighbor(vertex[j].commonVertex); } ComputeNormal(); }
private bool HasFaceVertex( PMFaceVertex v ) { return ( v == this.vertex[ 0 ] || v == this.vertex[ 1 ] || v == this.vertex[ 2 ] ); }
/// <summary> /// Internal method for building PMWorkingData from geometry data /// </summary> void AddWorkingData(VertexData vertexData, IndexData indexData) { // Insert blank working data, then fill PMWorkingData work = new PMWorkingData(); this.workingDataList.Add(work); // Build vertex list // Resize face list (this will always be this big) work.faceVertList = new PMFaceVertex[vertexData.vertexCount]; // Also resize common vert list to max, to avoid reallocations work.vertList = new PMVertex[vertexData.vertexCount]; // locate position element & the buffer to go with it VertexElement posElem = vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position); HardwareVertexBuffer vbuf = vertexData.vertexBufferBinding.GetBuffer(posElem.Source); // lock the buffer for reading IntPtr bufPtr = vbuf.Lock(BufferLocking.ReadOnly); uint numCommon = 0; unsafe { byte *pVertex = (byte *)bufPtr.ToPointer(); float * pFloat; Vector3 pos; // Map for identifying duplicate position vertices Dictionary <Vector3, uint> commonVertexMap = new Dictionary <Vector3, uint>(); for (uint i = 0; i < vertexData.vertexCount; ++i, pVertex += vbuf.VertexSize) { pFloat = (float *)(pVertex + posElem.Offset); pos.x = *pFloat++; pos.y = *pFloat++; pos.z = *pFloat++; work.faceVertList[(int)i] = new PMFaceVertex(); // Try to find this position in the existing map if (!commonVertexMap.ContainsKey(pos)) { // Doesn't exist, so create it PMVertex commonVert = new PMVertex(); commonVert.SetDetails(pos, numCommon); commonVert.removed = false; commonVert.toBeRemoved = false; commonVert.seam = false; // Add it to our working set work.vertList[(int)numCommon] = commonVert; // Enter it in the map commonVertexMap.Add(pos, numCommon); // Increment common index ++numCommon; work.faceVertList[(int)i].commonVertex = commonVert; work.faceVertList[(int)i].realIndex = i; } else { // Exists already, reference it PMVertex existingVert = work.vertList[(int)commonVertexMap[pos]]; work.faceVertList[(int)i].commonVertex = existingVert; work.faceVertList[(int)i].realIndex = i; // Also tag original as a seam since duplicates at this location work.faceVertList[(int)i].commonVertex.seam = true; } } } vbuf.Unlock(); numCommonVertices = numCommon; // Build tri list uint numTris = (uint)indexData.indexCount / 3; HardwareIndexBuffer ibuf = indexData.indexBuffer; bool use32bitindexes = (ibuf.Type == IndexType.Size32); IntPtr indexBufferPtr = ibuf.Lock(BufferLocking.ReadOnly); unsafe { ushort *pShort = null; uint * pInt = null; if (use32bitindexes) { pInt = (uint *)indexBufferPtr.ToPointer(); } else { pShort = (ushort *)indexBufferPtr.ToPointer(); } work.triList = new PMTriangle[(int)numTris]; // assumed tri list for (uint i = 0; i < numTris; ++i) { // use 32-bit index always since we're not storing uint vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v0 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v1 = work.faceVertList[(int)vindex]; vindex = use32bitindexes ? *pInt++ : *pShort++; PMFaceVertex v2 = work.faceVertList[(int)vindex]; work.triList[(int)i] = new PMTriangle(); work.triList[(int)i].SetDetails(i, v0, v1, v2); work.triList[(int)i].removed = false; } } ibuf.Unlock(); }
bool HasFaceVertex(PMFaceVertex v) { return(v == vertex[0] || v == vertex[1] || v == vertex[2]); }