Example #1
0
        //Reduce number of color indexes to count. Return list of new indexes
        public List <int> PaletteShrink(int count)
        {
            List <int> resultList   = new List <int>();
            int        paletteCount = palette.Count;

            for (int i = 0; i < paletteCount; i++)
            {
                //At the start, all indexes should just be replaced by themselves
                resultList.Add(i);
            }
            int[,] distances = new int[paletteCount, paletteCount];
            //Find all distances, except to index 0
            for (int i = 1; i < paletteCount; i++)
            {
                for (int j = 1; j < paletteCount; j++)
                {
                    if (i == j)
                    {
                        distances[i, j] = int.MaxValue;
                    }
                    else
                    {
                        distances[i, j] = palette[i].Difference(palette[j]);
                    }
                }
            }
            while (paletteCount > count + 1) //+1 for solid index
            {
                //Find indexes with smallest distance
                (int, int)combining = SmallestDistance(distances, resultList);
                //Combine the two indexes
                int      one           = combining.Item1;
                int      two           = combining.Item2;
                RGBColor newColor      = RGBColor.Combine(palette[one], indexCount[one], palette[two], indexCount[two]);
                int      newIndexCount = indexCount[one] + indexCount[two];
                //Write new color and count to smallest index. Refer higher index to smaller in result list
                int smallest = Math.Min(one, two);
                int highest  = Math.Max(one, two);
                palette[smallest]    = newColor;
                indexCount[smallest] = newIndexCount;
                resultList[highest]  = smallest;
                //Recalculate distance matrix
                distances = CalculateDistanceForIndex(smallest, distances);
                //Lower paletteCount
                paletteCount--;
                if (paletteCount % 3 == 0)
                {
                    Console.Write("|");
                }
            }
            //Now there is at most count palette colors. We now have to condense the indexes so they go from 0 to count

            //Get all indexes to point directly at a valid endpoint
            List <RGBColor> newPalette = new List <RGBColor>();

            for (int i = 0; i < palette.Count; i++)
            {
                if (resultList[i] != i) //Index is not valid endpoint
                {
                    while (resultList[i] != resultList[resultList[i]])
                    {
                        resultList[i] = resultList[resultList[i]];
                    }
                }
            }
            //Now all indexes in the resultlist point directly to a valid colorindex
            for (int i = 0; i < palette.Count; i++)
            {
                if (resultList[i] == i) //Index is valid endpoint
                {
                    newPalette.Add(palette[i]);
                    resultList[i] = newPalette.Count - 1;
                }
                else   //Index is pointing to valid endpoint and should follow it to final index
                {
                    resultList[i] = resultList[resultList[i]];
                }
            }

            //Shift results by palette offset
            List <int> shiftedResults = new List <int>();

            for (int i = 0; i < paletteOffset; i++)
            {
                shiftedResults.Add(paletteOffset);
            }
            for (int i = 0; i < resultList.Count; i++)
            {
                shiftedResults.Add(resultList[i] + 17);
            }

            //Write in the new condensed palette and return the resultlist for the map to update block indexes
            palette = newPalette;
            return(shiftedResults); //Shift by palette offset
        }
        //private const int IMSizeZ = 256;
        //Size Z varies by map, but should be 256 at most. Figure out map height by lowest block and then add that in.
        public static IntermediateMap ToIntermediateMap(byte[] AoSMapData, bool keepOcean)
        {
            //Go through each column
            int             columnStart  = 0;
            int             groundHeight = GroundHeight(AoSMapData);
            List <RGBColor> oceanColors  = new List <RGBColor>();
            int             finalHeight  = 256 - groundHeight;

            if (!keepOcean)
            {
                finalHeight--;
            }
            IntermediateMap mapResult;

            mapResult = new IntermediateMap(aosSizeX, aosSizeY, finalHeight, Block.AOSSOLID, new Palette(Palette.SECTORS_EDGE_RESERVED_INDEXES));
            Palette palette  = mapResult.palette;
            Block   airBlock = new Block(Block.AIR, palette);

            for (int x = 0; x < aosSizeX; x++)
            {
                for (int y = 0; y < aosSizeY; y++)
                {
                    int spanStart = columnStart;
                    int z         = finalHeight - 1;
                    while (true)
                    {
                        //Read span metadata
                        int number_4_byte_chunks = (int)AoSMapData[spanStart];
                        int top_color_start      = (int)AoSMapData[spanStart + 1];
                        int top_color_end        = (int)AoSMapData[spanStart + 2]; //Inclusive
                        int surfaceBlockCount    = top_color_end - top_color_start + 1;
                        int i;                                                     //Offset into data bytes

                        //Value where z = 0 is the bottom of the map
                        int top_color_switched = finalHeight - top_color_start - 1;

                        //Air run. Start at the latest z and go down to top_color_start
                        for (/*Use z*/; z > top_color_switched; z--)
                        {
                            mapResult.setBlockAt(x, y, z, airBlock);
                        }

                        //Surface/top run
                        for (i = 0; i < surfaceBlockCount; i++)
                        {
                            int      blue  = AoSMapData[spanStart + 4 + i * 4];
                            int      green = AoSMapData[spanStart + 5 + i * 4];
                            int      red   = AoSMapData[spanStart + 6 + i * 4];
                            RGBColor color = new RGBColor(red, green, blue);
                            if (z < 0)
                            {
                                oceanColors.Add(color);
                                break;
                            }
                            mapResult.setBlockAt(x, y, z, new Block(palette, color));
                            if (z == 0 && keepOcean) //Ocean height
                            {
                                oceanColors.Add(color);
                                break;
                            }
                            z--;
                        }

                        if (number_4_byte_chunks == 0) //Last span of column
                        {
                            //Update if this column was the highest.
                            //Rest of the column is already solid, leave it
                            //Next column is past first 4 span bytes and then past the number of surface blocks * the four bytes one of those takes
                            columnStart = spanStart + 4 + 4 * surfaceBlockCount;
                            break;
                        }

                        //Don't run over the solid area. It is already there.

                        //Do the ceiling at the bottom of the span
                        int ceilingBlockCount   = (number_4_byte_chunks - 1) - surfaceBlockCount;
                        int ceiling_color_end   = AoSMapData[spanStart + number_4_byte_chunks * 4 + 3]; //Read next span air start;
                        int ceiling_color_start = ceiling_color_end - ceilingBlockCount;
                        z = finalHeight - ceiling_color_start - 1;                                      //Jump down to top of bottom blocks
                        //Continue from previous set of data bytes
                        for (int j = i; j < i + ceilingBlockCount; j++)
                        {
                            int blue  = AoSMapData[spanStart + 4 + j * 4];
                            int green = AoSMapData[spanStart + 5 + j * 4];
                            int red   = AoSMapData[spanStart + 6 + j * 4];
                            mapResult.setBlockAt(x, y, z, new Block(palette, new RGBColor(red, green, blue)));
                            z--;
                        }

                        //Set spanstart to next span. Z is already at the end of the previous ceiling
                        spanStart += 4 * number_4_byte_chunks;
                    }
                }
                Console.Write("|");
            }

            RGBColor finalOcean = RGBColor.Combine(oceanColors);

            mapResult.oceanColor = finalOcean;

            Console.WriteLine("");
            return(mapResult);
        }
 public Block(Palette palette, RGBColor color)
 {
     this.ID    = UNASSIGNED;
     ColorIndex = palette.getExactColorIndex(color);
 }