Beispiel #1
0
        static void FillParcel(IntermediateMap map, Parcel parcel, List <Parcel> loadedParcels, int offsetX, int offsetY, int offsetZ, bool hasDonePalette, ParcelJsonConfiguration configuration)
        {
            //If no sourcefile, skip, well, sourcefile! and just plop in plots
            if (!emptySourceFileNames.Contains(parcel.sourceFile))
            {
                ParcelVoxReader parcelReader = new ParcelVoxReader();
                VoxReader       r            = new VoxReader(parcel.sourceFile, parcelReader);
                r.Read();

                parcelReader.insertReadParcel(map, offsetX, offsetY, offsetZ);

                //Do the palette
                if (!hasDonePalette)
                {
                    hasDonePalette = loadPalette(map, parcelReader.palette);
                }
            }

            foreach (Plot plot in parcel.parcelPlots)
            {
                Parcel insertParcel = findMatchingParcel(plot, parcel.parcelPlots, loadedParcels, configuration);

                FillParcel(map, insertParcel, loadedParcels, offsetX + plot.offsetX, offsetY + plot.offsetY, offsetZ + plot.offsetZ, hasDonePalette, configuration);
            }
        }
Beispiel #2
0
 void traverseCompositeTree(IModelTreeComponent component, IntermediateMap map, int offsetX, int offsetY, int offsetZ)
 {
     if (component is ModelLeaf)
     {
         ModelLeaf model = (ModelLeaf)component;
         for (int x = 0; x < model.sizeX; x++)
         {
             for (int y = 0; y < model.sizeY; y++)
             {
                 for (int z = 0; z < model.sizeZ; z++)
                 {
                     int colourIndex = model.data[x, y, z]; //Implicit conversion
                     map.setBlockAt(offsetX + x, offsetY + y, offsetZ + z, new Block(colourIndex));
                 }
             }
         }
     }
     else if (component is ModelTree)
     {
         ModelTree tree = (ModelTree)component;
         foreach (IModelTreeComponent child in tree.components)
         {
             traverseCompositeTree(child, map, offsetX + tree.offsetX, offsetY + tree.offsetY, offsetZ + tree.offsetZ);
         }
     }
 }
Beispiel #3
0
        public static IntermediateMap CreateMap(ParcelJsonConfiguration configuration)
        {
            IntermediateMap emptyMap = new IntermediateMap(configuration.primaryParcel.sizeX, configuration.primaryParcel.sizeY, configuration.primaryParcel.sizeZ, Block.AIR, new Palette(0));

            List <Parcel> loadedParcels = createDivisionParcels(configuration.plotDivisions);

            loadedParcels.AddRange(configuration.insertParcels);

            FillParcel(emptyMap, configuration.primaryParcel, loadedParcels, 0, 0, 0, false, configuration);
            return(emptyMap);
        }
Beispiel #4
0
 static bool loadPalette(IntermediateMap map, byte[,] paletteData)
 {
     try
     {
         Palette palette = new Palette(paletteData);
         map.palette = palette;
         return(true);
     } catch (Exception ignored)
     {
         Console.WriteLine("Exception loading map palette");
     }
     return(false);
 }
        static void PrintMapProgram(IntermediateMap map, ProgramConfiguration programConfig)
        {
            if (programConfig.mirrorMap)
            {
                map.mirrorOnY();
                Console.WriteLine("Mirrored map");
            }

            string outname = programConfig.outputName;

            if (outname == null || outname == "")
            {
                var random = new Random();
                int index  = random.Next(int.MaxValue);
                outname = "DodoTool" + index;
            }
            Console.WriteLine("Writting map to file. Might take a couple of seconds...");
            IMToVXL.IMToVoxel(map, outname + ".vox", programConfig.modelSizeX, programConfig.modelSizeY, programConfig.modelSizeZ);
            Console.WriteLine("There we are. There should now be a nice " + outname + ".vox with your map :)");
            Console.WriteLine("Press enter to close");
            Console.ReadLine();
        }
        static void ParcelProgram(ProgramConfiguration programConfig)
        {
            Console.WriteLine("Running parcel program");
            ParcelJsonConfiguration configuration;

            try
            {
                string configFileContent = File.ReadAllText(programConfig.parcelConfiguration + ".json");
                configuration = JsonConvert.DeserializeObject <ParcelJsonConfiguration>(configFileContent);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error parsing the parcel config json. Maybe some of this text will help you find the issue: ");
                Console.WriteLine(e.Message);
                return;
            }
            Console.WriteLine("Read parcel config");
            IntermediateMap map = CreateParcelMap.CreateMap(configuration);

            Console.WriteLine("Generated parcel map");

            PrintMapProgram(map, programConfig);
        }
        static void ConverterProgram(ProgramConfiguration programConfig)
        {
            byte[] AoSMapData;
            Console.WriteLine("Running Ace of Spades to MagicaVoxel map conversion tool");
            try
            {
                AoSMapData = File.ReadAllBytes(programConfig.aosFile + ".vxl");
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to read AoS map file");
                return;
            }

            Console.WriteLine("Alright, here I go parsing the Ace of Spades map. This might take a few seconds...");
            IntermediateMap map        = AceOfSpadesToIM.ToIntermediateMap(AoSMapData, programConfig.keepOcean);
            int             colorCount = map.palette.palette.Count;

            Console.WriteLine("Parsing went well. Map height detected to be " + map.sizeZ + " with " + colorCount + " unique colors");
            Console.WriteLine("Condensing colors. This might take a second...");
            map.PaletteShrink(Math.Min(programConfig.colourCount, colorCount)); //Use shrink even if at acceptable number of colors to shuffle indexes away from reserved spots
            Console.WriteLine("Shrunk colors.");
            PrintMapProgram(map, programConfig);
        }
        public static void IMToVoxel(IntermediateMap map, string outfileName, int modelSizeX, int modelSizeY, int modelSizeZ)
        {
            FileStream stream = new FileStream(outfileName, FileMode.Create, FileAccess.Write,
                                               FileShare.Write);
            BinaryWriter writer = new BinaryWriter(stream);

            //Standard opening
            writer.Write("VOX ".ToCharArray());
            writer.Write(150); //Version
            writer.Write("MAIN".ToCharArray());
            writer.Write(0);   //No chunk data in main

            //List of chunks
            List <RiffChunk> chunks = new List <RiffChunk>();

            Palette palette = map.palette;

            //Setup for staging nodes
            ResetNodeID();
            IDForGroup = new List <int>();
            int masterGRPID = GetNextNodeID(); //Pass to master Translate
            List <RiffChunk> modelStagings = new List <RiffChunk>();
            int modelID = 0;

            //Seperate the world into regions that become a model each
            int mapheight = map.sizeZ;

            for (int x = 0; x < map.sizeX; x += modelSizeX)
            {
                Console.Write("|");
                for (int y = 0; y < map.sizeY; y += modelSizeY)
                {
                    for (int z = 0; z < mapheight + modelSizeZ; z += modelSizeZ) //Map may not be that high, but getListOfVoxels will just return nothing for out of bounds values.
                    {
                        //The function will limit sizes to actual map boundaries
                        List <Voxel> voxels = map.getListOfVoxels(x, x + modelSizeX, y, y + modelSizeY, z, z + modelSizeZ);
                        //Find out if chunk even has any voxels
                        if (voxels.Count == 0)
                        {
                            //Don't create the object if there are no voxels
                            continue;
                        }

                        //I've not checked that this is just xyz, assuming it is
                        RiffChunk size = new RiffChunk("SIZE");
                        size.addData(new IntChunkData(modelSizeX));
                        size.addData(new IntChunkData(modelSizeY));
                        size.addData(new IntChunkData(modelSizeZ));
                        chunks.Add(size);

                        //Get a region of voxels and make them a model
                        RiffChunk xyzi = new RiffChunk("XYZI");
                        xyzi.addData(new IntChunkData(voxels.Count));
                        foreach (Voxel voxel in voxels)
                        {
                            try
                            {
                                xyzi.addData(new VoxelChunkData(Convert.ToByte(voxel.x - x), Convert.ToByte(voxel.y - y), Convert.ToByte(voxel.z - z), Convert.ToByte(voxel.colorIndex)));
                            } catch (Exception e)
                            {
                                Console.WriteLine("Byte overflow with voxel " + voxel.x + ", " + voxel.y + ", " + voxel.z + ". With object xyz being " + x + ", " + y + "," + z);
                                Console.WriteLine("Color index of " + voxel.colorIndex);
                                throw e;
                            }
                        }
                        chunks.Add(xyzi);

                        //Create shape and translate node for the model
                        modelStagings.AddRange(CreateStagingChunksForModel(x, y, z, modelID, modelSizeX, modelSizeY, modelSizeZ)); //Create translate and shape noded for model
                        //ModelID isn't written to file, it's just the order the models appear
                        modelID++;
                    }
                }
            }

            //Master group node
            RiffChunk masterGRP = new RiffChunk("nGRP");

            masterGRP.addData(new IntChunkData(masterGRPID));
            masterGRP.addData(new DictChunkData());       //empty dict
            masterGRP.addData(new IntChunkData(modelID)); //Number of models
            foreach (int nodeID in IDForGroup)
            {
                masterGRP.addData(new IntChunkData(nodeID));
            }

            //Master translate node
            RiffChunk masterTRN = new RiffChunk("nTRN");

            masterTRN.addData(new IntChunkData(0));  //Assuming top node has to be number 0
            masterTRN.addData(new DictChunkData());  //Empty dict
            masterTRN.addData(new IntChunkData(masterGRPID));
            masterTRN.addData(new IntChunkData(-1)); //Reserved
            masterTRN.addData(new IntChunkData(-1)); //Layer ID
            masterTRN.addData(new IntChunkData(1));  //Number of frames is always 1
            masterTRN.addData(new DictChunkData());  //Empty dict. No translation of master

            //Put in all the staging chunks
            chunks.Add(masterTRN);
            chunks.Add(masterGRP);
            chunks.AddRange(modelStagings);


            //Add in all the layer chunks. This may be unneeded
            chunks.AddRange(CreateLayrChunks());

            //RGBA palette chunk
            chunks.Add(palette.getPaletteChunk());

            //Material chunks. May be unneeded
            for (int i = 1; i <= 256; i++)
            {
                chunks.Add(CreateMatlChunk(i));
            }

            //Whatever the robj chunks are...
            chunks.AddRange(CreateROBJChunks());

            //Write in the main chunk child size field
            int mainChunkChildDataSize = 0;

            foreach (RiffChunk chunk in chunks)
            {
                mainChunkChildDataSize += chunk.getChunkSize();
            }
            writer.Write(mainChunkChildDataSize);

            Console.Write("|");
            //Write all those chunks
            foreach (RiffChunk chunk in chunks)
            {
                chunk.writeChunk(writer);
            }
            Console.Write("|");

            //Done
            writer.Close();
            stream.Close();
            Console.WriteLine("");
        }
        //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);
        }
Beispiel #10
0
 public void insertReadParcel(IntermediateMap map, int offsetX, int offsetY, int offsetZ)
 {
     assembleTree();
     traverseCompositeTree(masterNode, map, offsetX, offsetY, offsetZ);
 }