Ejemplo n.º 1
0
        /// <summary>
        ///     Function to remap your indices to improve spatial locality in your vertex buffer.
        /// </summary>
        /// <remarks>
        ///     Note that, according to the remapping handed back to you, you must reorder your
        ///     vertex buffer.
        /// </remarks>
        /// <param name="primitiveGroups">Array of PrimitiveGroups you want remapped.</param>
        /// <param name="vertexCount">
        ///     Number of vertices in your vertex buffer, also can be thought of as the range of acceptable
        ///     values for indices in your primitive groups.
        /// </param>
        /// <param name="remappedPrimitiveGroups">Array of remapped PrimitiveGroups.</param>
        public void RemapIndices(PrimitiveGroup[] primitiveGroups, ushort vertexCount,
                                 out PrimitiveGroup[] remappedPrimitiveGroups)
        {
            remappedPrimitiveGroups = new PrimitiveGroup[primitiveGroups.Length];

            //caches oldIndex --> newIndex conversion
            var indexCache = new int[vertexCount];

            for (int i = 0; i < indexCache.Length; ++i)
            {
                indexCache[i] = -1;
            }

            //loop over primitive groups
            uint indexCtr = 0;

            for (int i = 0; i < primitiveGroups.Length; i++)
            {
                int numIndices = primitiveGroups[i].Indices.Length;

                //init remapped group
                remappedPrimitiveGroups[i] =
                    new PrimitiveGroup(primitiveGroups[i].Type, new ushort[numIndices]);

                for (int j = 0; j < numIndices; j++)
                {
                    int cachedIndex = indexCache[primitiveGroups[i].Indices[j]];
                    if (cachedIndex == -1)   //we haven't seen this index before
                    {
                        //point to "last" vertex in VB
                        remappedPrimitiveGroups[i].Indices[j] = ( ushort )indexCtr;

                        //add to index cache, increment
                        indexCache[primitiveGroups[i].Indices[j]] = ( ushort )indexCtr++;
                    }
                    else
                    {
                        //we've seen this index before
                        remappedPrimitiveGroups[i].Indices[j] = ( ushort )cachedIndex;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <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);
        }