//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); }