public bool IsMarked(FaceInfo faceInfo) { return((faceInfo.StripId >= 0) || (IsExperiment() && faceInfo.ExperimentId == ExperimentId)); }
/// <summary> /// Builds a strip forward as far as we can go, then builds backwards, and joins the two lists. /// </summary> public void Build(List <EdgeInfo> edgeInfos, List <FaceInfo> faceInfos) { // used in building the strips forward and backward var scratchIndices = new List <ushort>(); // build forward... start with the initial face var forwardFaces = new List <FaceInfo>(); var backwardFaces = new List <FaceInfo>(); forwardFaces.Add(StartInfo.StartFace); MarkTriangle(StartInfo.StartFace); int v0 = (StartInfo.ToV1 ? StartInfo.StartEdge.V0 : StartInfo.StartEdge.V1); int v1 = (StartInfo.ToV1 ? StartInfo.StartEdge.V1 : StartInfo.StartEdge.V0); // easiest way to get v2 is to use this function which requires the // other indices to already be in the list. scratchIndices.Add(( ushort )v0); scratchIndices.Add(( ushort )v1); int v2 = Stripifier.GetNextIndex(scratchIndices, StartInfo.StartFace); scratchIndices.Add(( ushort )v2); // // build the forward list // int nv0 = v1; int nv1 = v2; var nextFace = Stripifier.FindOtherFace(edgeInfos, nv0, nv1, StartInfo.StartFace); while (nextFace != null && !IsMarked(nextFace)) { //check to see if this next face is going to cause us to die soon int testnv0 = nv1; int testnv1 = Stripifier.GetNextIndex(scratchIndices, nextFace); var nextNextFace = Stripifier.FindOtherFace(edgeInfos, testnv0, testnv1, nextFace); if ((nextNextFace == null) || (IsMarked(nextNextFace))) { //uh, oh, we're following a dead end, try swapping var testNextFace = Stripifier.FindOtherFace(edgeInfos, nv0, testnv1, nextFace); if (((testNextFace != null) && !IsMarked(testNextFace))) { //we only swap if it buys us something //add a "fake" degenerate face var tempFace = new FaceInfo(nv0, nv1, nv0, true); forwardFaces.Add(tempFace); MarkTriangle(tempFace); scratchIndices.Add(( ushort )nv0); testnv0 = nv0; ++DegenerateCount; } } // add this to the strip forwardFaces.Add(nextFace); MarkTriangle(nextFace); // add the index //nv0 = nv1; //nv1 = Stripifier.GetNextIndex(scratchIndices, nextFace); scratchIndices.Add(( ushort )testnv1); // and get the next face nv0 = testnv0; nv1 = testnv1; nextFace = Stripifier.FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // tempAllFaces is going to be forwardFaces + backwardFaces // it's used for Unique() var tempAllFaces = new List <FaceInfo>(); for (var i = 0; i < forwardFaces.Count; i++) { tempAllFaces.Add(forwardFaces[i]); } // // reset the indices for building the strip backwards and do so // scratchIndices.Clear(); scratchIndices.Add(( ushort )v2); scratchIndices.Add(( ushort )v1); scratchIndices.Add(( ushort )v0); nv0 = v1; nv1 = v0; nextFace = Stripifier.FindOtherFace(edgeInfos, nv0, nv1, StartInfo.StartFace); while (nextFace != null && !IsMarked(nextFace)) { //this tests to see if a face is "unique", meaning that its vertices aren't already in the list // so, strips which "wrap-around" are not allowed if (!Unique(tempAllFaces, nextFace)) { break; } //check to see if this next face is going to cause us to die soon int testnv0 = nv1; int testnv1 = Stripifier.GetNextIndex(scratchIndices, nextFace); var nextNextFace = Stripifier.FindOtherFace(edgeInfos, testnv0, testnv1, nextFace); if ((nextNextFace == null) || (IsMarked(nextNextFace))) { //uh, oh, we're following a dead end, try swapping var testNextFace = Stripifier.FindOtherFace(edgeInfos, nv0, testnv1, nextFace); if (((testNextFace != null) && !IsMarked(testNextFace))) { //we only swap if it buys us something //add a "fake" degenerate face var tempFace = new FaceInfo(nv0, nv1, nv0, true); backwardFaces.Add(tempFace); MarkTriangle(tempFace); scratchIndices.Add(( ushort )nv0); testnv0 = nv0; ++DegenerateCount; } } // add this to the strip backwardFaces.Add(nextFace); //this is just so Unique() will work tempAllFaces.Add(nextFace); MarkTriangle(nextFace); // add the index //nv0 = nv1; //nv1 = Stripifier.GetNextIndex(scratchIndices, nextFace); scratchIndices.Add(( ushort )testnv1); // and get the next face nv0 = testnv0; nv1 = testnv1; nextFace = Stripifier.FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // Combine the forward and backwards stripification lists and put into our own face vector Combine(forwardFaces, backwardFaces); }
/// <summary> /// Generates strips from the given input indices. /// </summary> /// <param name="indices">Input index list, the indices you would use to render.</param> /// <param name="primitiveGroups">Array of optimized/stripified PrimitiveGroups</param> /// <param name="validateEnabled">Whether to validate the output or not.</param> /// <returns>A boolean indicating whether the operation completed successfully.</returns> public bool GenerateStrips(ushort[] indices, out PrimitiveGroup[] primitiveGroups, bool validateEnabled = false) { var numGroups = 0; //put data in format that the stripifier likes var tempIndices = new List <ushort>(indices.Length); ushort maxIndex = 0; ushort minIndex = 0xFFFF; for (var i = 0; i < indices.Length; i++) { tempIndices.Add(indices[i]); if (indices[i] > maxIndex) { maxIndex = indices[i]; } if (indices[i] < minIndex) { minIndex = indices[i]; } } var tempStrips = new List <StripInfo>(); var tempFaces = new List <FaceInfo>(); var stripifier = new Stripifier(); //do actual stripification stripifier.Stripify(tempIndices, CacheSize, MinStripSize, maxIndex, tempStrips, tempFaces); //stitch strips together var stripIndices = new List <int>(); uint numSeparateStrips = 0; if (ListsOnly) { //if we're outputting only lists, we're done numGroups = 1; primitiveGroups = new PrimitiveGroup[numGroups]; var primGroupArray = primitiveGroups; //count the total number of indices uint numIndices = 0; for (var i = 0; i < tempStrips.Count; i++) { numIndices += ( uint )(tempStrips[i].Faces.Count * 3); } //add in the list numIndices += ( uint )(tempFaces.Count * 3); primGroupArray[0] = new PrimitiveGroup(PrimitiveType.TriangleList, new ushort[numIndices]); //do strips uint indexCtr = 0; for (var i = 0; i < tempStrips.Count; i++) { for (var j = 0; j < tempStrips[i].Faces.Count; j++) { //degenerates are of no use with lists if (!Stripifier.IsDegenerate(tempStrips[i].Faces[j])) { primGroupArray[0].Indices[indexCtr++] = ( ushort )tempStrips[i].Faces[j].V0; primGroupArray[0].Indices[indexCtr++] = ( ushort )tempStrips[i].Faces[j].V1; primGroupArray[0].Indices[indexCtr++] = ( ushort )tempStrips[i].Faces[j].V2; } else { //we've removed a tri, reduce the number of indices var resizedIndices = primGroupArray[0].Indices; Array.Resize(ref resizedIndices, primGroupArray[0].Indices.Length - 3); primGroupArray[0].Indices = resizedIndices; } } } //do lists for (var i = 0; i < tempFaces.Count; i++) { primGroupArray[0].Indices[indexCtr++] = ( ushort )tempFaces[i].V0; primGroupArray[0].Indices[indexCtr++] = ( ushort )tempFaces[i].V1; primGroupArray[0].Indices[indexCtr++] = ( ushort )tempFaces[i].V2; } } else { stripifier.CreateStrips(tempStrips, stripIndices, StitchStrips, ref numSeparateStrips, UseRestart, ( uint )RestartValue); //if we're stitching strips together, we better get back only one strip from CreateStrips() Debug.Assert(StitchStrips && numSeparateStrips == 1 || !StitchStrips); //convert to output format numGroups = ( ushort )numSeparateStrips; //for the strips if (tempFaces.Count != 0) { numGroups++; //we've got a list as well, increment } primitiveGroups = new PrimitiveGroup[numGroups]; var primGroupArray = primitiveGroups; //first, the strips var startingLoc = 0; for (var stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++) { var stripLength = 0; if (!StitchStrips) { //if we've got multiple strips, we need to figure out the correct length int i; for (i = startingLoc; i < stripIndices.Count; i++) { if (stripIndices[i] == -1) { break; } } stripLength = i - startingLoc; } else { stripLength = stripIndices.Count; } primGroupArray[stripCtr] = new PrimitiveGroup(PrimitiveType.TriangleStrip, new ushort[stripLength]); var indexCtr = 0; for (int i = startingLoc; i < stripLength + startingLoc; i++) { primGroupArray[stripCtr].Indices[indexCtr++] = ( ushort )stripIndices[i]; } //we add 1 to account for the -1 separating strips //this doesn't break the stitched case since we'll exit the loop startingLoc += stripLength + 1; } //next, the list if (tempFaces.Count != 0) { int faceGroupLoc = numGroups - 1; //the face group is the last one primGroupArray[faceGroupLoc] = new PrimitiveGroup(PrimitiveType.TriangleList, new ushort[tempFaces.Count * 3]); var indexCtr = 0; for (var i = 0; i < tempFaces.Count; i++) { primGroupArray[faceGroupLoc].Indices[indexCtr++] = ( ushort )tempFaces[i].V0; primGroupArray[faceGroupLoc].Indices[indexCtr++] = ( ushort )tempFaces[i].V1; primGroupArray[faceGroupLoc].Indices[indexCtr++] = ( ushort )tempFaces[i].V2; } } } //validate generated data against input if (validateEnabled) { var numbins = 100; var inBins = new List <FaceInfo> [numbins]; for (var i = 0; i < inBins.Length; ++i) { inBins[i] = new List <FaceInfo>(); } //hash input indices on first index for (var i = 0; i < indices.Length; i += 3) { var faceInfo = new FaceInfo(indices[i], indices[i + 1], indices[i + 2]); inBins[indices[i] % numbins].Add(faceInfo); } for (var i = 0; i < numGroups; ++i) { switch (primitiveGroups[i].Type) { case PrimitiveType.TriangleList: { for (var j = 0; j < primitiveGroups[i].Indices.Length; j += 3) { ushort v0 = primitiveGroups[i].Indices[j]; ushort v1 = primitiveGroups[i].Indices[j + 1]; ushort v2 = primitiveGroups[i].Indices[j + 2]; //ignore degenerates if (Stripifier.IsDegenerate(v0, v1, v2)) { continue; } if (!TestTriangle(v0, v1, v2, inBins, numbins)) { Cleanup(tempStrips, tempFaces); return(false); } } break; } case PrimitiveType.TriangleStrip: { var flip = false; for (var j = 2; j < primitiveGroups[i].Indices.Length; ++j) { ushort v0 = primitiveGroups[i].Indices[j - 2]; ushort v1 = primitiveGroups[i].Indices[j - 1]; ushort v2 = primitiveGroups[i].Indices[j]; if (flip) { //swap v1 and v2 ushort swap = v1; v1 = v2; v2 = swap; } //ignore degenerates if (Stripifier.IsDegenerate(v0, v1, v2)) { flip = !flip; continue; } if (!TestTriangle(v0, v1, v2, inBins, numbins)) { Cleanup(tempStrips, tempFaces); return(false); } flip = !flip; } break; } case PrimitiveType.TriangleFan: default: break; } } } //clean up everything Cleanup(tempStrips, tempFaces); return(true); }