Пример #1
0
        ///========================================================================
        /// Method : ReindexImages
        ///
        /// <summary>
        ///     Reindex images of the given type - remove duplicates and renumber
        ///   to the top of the image array.
        /// </summary>
        /// <param name="xiImageType"></param>
        ///========================================================================
        public void ReindexImages(eTexMetaDataEntries xiImageType)
        {
            Level lLevel = mMainForm.CurrentLevel;

            if (lLevel == null)
            {
                MessageBox.Show("Must have a level open for this action");
                return;
            }

            Chunk[] lChunkArray;
            if (xiImageType == eTexMetaDataEntries.Bumpmap)
            {
                lChunkArray = lLevel.SHET.BumpImages.mChildren;
            }
            else if (xiImageType == eTexMetaDataEntries.Steering)
            {
                lChunkArray = lLevel.SHET.SteeringImages.mChildren;
            }
            else if (xiImageType == eTexMetaDataEntries.CameraPos)
            {
                lChunkArray = lLevel.SHET.CameraPositions.mChildren;
            }
            else
            {
                throw new Exception("Internal error: Cannot reindex images of type " + xiImageType.ToString());
            }

            // count how many times each image is currently in use
            int[] lUseCount     = new int[lChunkArray.Length];
            int   lTexMetaIndex = (int)xiImageType;

            foreach (FlatChunk flat in lLevel.SHET.Flats)
            {
                if (flat.TexMetaData != null)
                {
                    foreach (byte[][] row in flat.TexMetaData)
                    {
                        foreach (byte[] entry in row)
                        {
                            lUseCount[entry[lTexMetaIndex]]++;
                        }
                    }
                }
            }

            //get a mapping from each equivalence class of chunks to the lowest index in that class
            SortedDictionary <IReindexableChunk, int> lImagesToCanonicalId = new SortedDictionary <IReindexableChunk, int>(new ReindexableChunkComparer());

            for (int i = lChunkArray.Length - 1; i >= 0; i--)
            {
                if (lUseCount[i] == 0)
                {
                    // Ignore any unused images - otherwise we might try to remap used images
                    // to unused ones, which would cause errors when we remove all the unused
                    // images later on.
                    continue;
                }

                lImagesToCanonicalId[(IReindexableChunk)lChunkArray[i]] = i;
            }

            int[] lOldToNewIndexMap = new int[lUseCount.Length];

            //determine where each image should map to:
            int lNextUnusedId = 0;

            for (int lOldIdx = 0; lOldIdx < lOldToNewIndexMap.Length; lOldIdx++)
            {
                if (lUseCount[lOldIdx] > 0)
                {
                    //we need to map this to somewhere.
                    //can it be coalesced with other, identical bumps?
                    int lCanonicalId = (int)lImagesToCanonicalId[(IReindexableChunk)lChunkArray[lOldIdx]];
                    if (lCanonicalId < lOldIdx)
                    {
                        lOldToNewIndexMap[lOldIdx] = lOldToNewIndexMap[lCanonicalId];
                    }
                    else if (lCanonicalId == lOldIdx)
                    {
                        lOldToNewIndexMap[lOldIdx] = lNextUnusedId;
                        lNextUnusedId++;
                    }
                    else
                    {
                        throw new Exception("Internal error: lCanonicalId can't be greater than lOldIdx");
                    }
                }
                else
                {
                    lOldToNewIndexMap[lOldIdx] = -1;
                }
            }

            //take a copy of each canonical image, so we don't lose any information
            Dictionary <int, byte[]> lCanonicalImages = new Dictionary <int, byte[]>();

            foreach (KeyValuePair <IReindexableChunk, int> lEntry in lImagesToCanonicalId)
            {
                lCanonicalImages.Add(lEntry.Value, (byte[])lEntry.Key.Data.Clone());
            }

            //fill in all the bump images with their new values:
            int lHighestUsed = -1;

            for (int lOldIdx = 0; lOldIdx < lOldToNewIndexMap.Length; lOldIdx++)
            {
                int lNew = lOldToNewIndexMap[lOldIdx];
                if (lNew != -1)
                {
                    if (lCanonicalImages.ContainsKey(lOldIdx))
                    {
                        lHighestUsed = lNew;
                        ((IReindexableChunk)lChunkArray[lNew]).Data = lCanonicalImages[lOldIdx];
                    }
                }
            }
            for (int i = lHighestUsed + 1; i < lChunkArray.Length; i++)
            {
                ((IReindexableChunk)lChunkArray[i]).Clear();
            }

            //now update all the bumps in the Flats
            foreach (FlatChunk flat in lLevel.SHET.Flats)
            {
                if (flat.TexMetaData != null)
                {
                    foreach (byte[][] row in flat.TexMetaData)
                    {
                        foreach (byte[] entry in row)
                        {
                            int lOldIdx = entry[lTexMetaIndex];
                            int lNewIdx = lOldToNewIndexMap[lOldIdx];
                            if (lNewIdx < 0)
                            {
                                throw new Exception("Internal error: this image should be unused");
                            }
                            entry[lTexMetaIndex] = (byte)lNewIdx;
                        }
                    }
                }
            }

            MessageBox.Show(string.Format(
                                "Successfully reindexed. There are {0} {2} tiles in use, and {1} free",
                                lCanonicalImages.Count,
                                lChunkArray.Length - lCanonicalImages.Count,
                                xiImageType.ToString().ToLower()));
        }
Пример #2
0
        ///========================================================================
        /// Method : CompactImages
        ///
        /// <summary>
        ///     Compact images fo the given type - remove any unused images from the
        ///   end of the array.
        /// </summary>
        /// <param name="xiImageType"></param>
        /// <remarks>
        ///   Note that no attempt is made to deduplicate - it is assumed that
        ///   duplicates will be removed via ReindexImages if required.
        /// </remarks>
        ///========================================================================
        public void CompactImages(eTexMetaDataEntries xiImageType)
        {
            Level lLevel = mMainForm.CurrentLevel;

            if (lLevel == null)
            {
                MessageBox.Show("Must have a level open for this action");
                return;
            }

            //=======================================================================
            // Work out which array of images to work with
            //=======================================================================
            Chunk[] lChunkArray;
            if (xiImageType == eTexMetaDataEntries.Bumpmap)
            {
                lChunkArray = lLevel.SHET.BumpImages.mChildren;
            }
            else if (xiImageType == eTexMetaDataEntries.Steering)
            {
                lChunkArray = lLevel.SHET.SteeringImages.mChildren;
            }
            else if (xiImageType == eTexMetaDataEntries.CameraPos)
            {
                lChunkArray = lLevel.SHET.CameraPositions.mChildren;
            }
            else
            {
                throw new Exception("Internal error: Cannot reindex images of type " + xiImageType.ToString());
            }

            //=======================================================================
            // Find the highest numbered image that's in use - we'll remove all
            // higher-numbered images
            //=======================================================================
            int lMaxUsedIndex = -1;
            int lTexMetaIndex = (int)xiImageType;

            foreach (FlatChunk lFlat in lLevel.SHET.Flats)
            {
                if (lFlat.TexMetaData != null)
                {
                    foreach (byte[][] lRow in lFlat.TexMetaData)
                    {
                        foreach (byte[] lEntry in lRow)
                        {
                            if (lMaxUsedIndex < lEntry[lTexMetaIndex])
                            {
                                lMaxUsedIndex = lEntry[lTexMetaIndex];
                            }
                        }
                    }
                }
            }

            if (lMaxUsedIndex == -1)
            {
                MessageBox.Show(string.Format("No compaction required - there are no {0} tiles!",
                                              xiImageType.ToString().ToLower()));
                return;
            }

            //=======================================================================
            // Create a new image array and adjust zero padding
            //=======================================================================
            Chunk[] lNewChunkArray = new Chunk[lMaxUsedIndex + 1];
            Array.Copy(lChunkArray, lNewChunkArray, lMaxUsedIndex + 1);

            lLevel.SHET.TrailingZeroByteCount += (lChunkArray.Length - (lMaxUsedIndex + 1)) * ((IReindexableChunk)lChunkArray[0]).Data.Length;

            if (xiImageType == eTexMetaDataEntries.Bumpmap)
            {
                lLevel.SHET.BumpImages.mChildren = lNewChunkArray;
            }
            else if (xiImageType == eTexMetaDataEntries.Steering)
            {
                lLevel.SHET.SteeringImages.mChildren = lNewChunkArray;
            }
            else if (xiImageType == eTexMetaDataEntries.CameraPos)
            {
                lLevel.SHET.CameraPositions.mChildren = lNewChunkArray;
            }

            MessageBox.Show(string.Format("Successfully compacted. There are {0} {1} tiles remaining",
                                          lMaxUsedIndex + 1,
                                          xiImageType.ToString().ToLower()));
        }