Exemplo n.º 1
0
        public void Apply(ref VoxelModel model, IProgressListener progress)
        {
            var m = model;

            progress?.Report("Analyzing structure");
            var ext = new ExteriorAnalyzer()
            {
                Model = m
            }.Analyze(new ProgressMapper(progress, 0.0, 1.0 / 3.0, null));

            progress?.Report("Creating shell");
            var extexpanded = new DilationFilter()
            {
                Distance = Distance,
                DistanceType = DistanceType
            }.Apply(ext, new ProgressMapper(progress, 1.0 / 3.0, 1.0 / 3.0, null));

            progress?.Report("Removing invisible voxels");

            int d1 = m.Width;
            int d2 = m.Height;
            int d3 = m.Depth;
            int d = IsExteriorSolid ? 0 : Distance;
            for (int x = d; x < d1 - d; ++x)
            {
                for (int y = d; y < d2 - d; ++y)
                {
                    for (int z = d; z < d3 - d; ++z)
                    {
                        if (!extexpanded[x, y, z])
                        {
                            m[x, y, z] = VoxelModel.EmptyVoxel;
                        }
                    }
                }
                progress?.Report((double)(x - d) / (d1 - d * 2) * (1.0 / 3.0) + 2.0 / 3.0);
            }
        }
Exemplo n.º 2
0
 public void GenerateTextureAndUV(VoxelModel model, MeshSlices slices, out Bitmap bitmap)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 3
0
        public VoxelModel LoadVoxelModel(byte[] bytes, IProgressListener progress)
        {
            int w = Width, h = Height, d = Depth;
            var model = new VoxelModel(w, h, d);
            var r = new Random();

            int pos = 0;

            progress?.Report("Reading voxels");

            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    int z = 0;
                    uint color = 0;

                    // fill with brownish color
                    for (; z < d; ++z)
                    {
                        uint col = 0x284067;
                        col ^= 0x070707 & (uint) r.Next();
                        model[x, y, z] = col;
                    }

                    z = 0;
                    while (true)
                    {
                        int number_4byte_chunks = bytes[pos];
                        int top_color_start = bytes[pos + 1];
                        int top_color_end = bytes[pos + 2];
                        int bottom_color_start;
                        int bottom_color_end;
                        int len_top;
                        int len_bottom;

                        for (; z < top_color_start; ++z)
                        {
                            model[x, y, z] = VoxelModel.EmptyVoxel;
                        }

                        int colorpos = pos + 4;
                        for (; z <= top_color_end; z++)
                        {
                            color = BitConverter.ToUInt32(bytes, colorpos);
                            colorpos += 4;
                            model[x, y, z] = color;
                        }

                        if (top_color_end == d - 2)
                        {
                            model[x, y, d - 1] = model[x, y, d - 2];
                        }

                        len_bottom = top_color_end - top_color_start + 1;

                        if (number_4byte_chunks == 0)
                        {
                            pos += 4 * (len_bottom + 1);
                            break;
                        }

                        len_top = (number_4byte_chunks - 1) - len_bottom;

                        pos += (int) bytes[pos] * 4;

                        bottom_color_end = bytes[pos + 3];
                        bottom_color_start = bottom_color_end - len_top;

                        for (z = bottom_color_start; z < bottom_color_end; z++)
                        {
                            color = BitConverter.ToUInt32(bytes, colorpos);
                            colorpos += 4;
                            model[x, y, z] = color;
                        }
                        if (bottom_color_end == d - 1)
                        {
                            model[x, y, d - 1] = model[x, y, d - 2];
                        }
                    } // while (true)
                } // for x

                progress?.Report((double)(y + 1) / h);
            } // for y

            return model;
        }
Exemplo n.º 4
0
        public VoxelModel LoadVoxelModel(byte[] bytes, IProgressListener progress)
        {
            uint magic = BitConverter.ToUInt32(bytes, 0);
            // int version = BitConverter.ToInt32(bytes, 4);
            if (magic != FourCCs.Vox)
            {
                throw new System.IO.IOException("Invalid magic number (wrong file format?).");
            }
            // FIXME: should we check the version number?

            var mainChunk = Chunk.LoadChunk(new ArraySegment<byte>(bytes, 8, bytes.Length - 8));
            if (mainChunk.ChunkID != FourCCs.Main)
            {
                throw new System.IO.IOException("File is corrupted. Bad root chunk ID (should be MAIN).");
            }

            Chunk sizeChunk = null;
            Chunk voxelChunk = null;
            Chunk paletteChunk = null;
            foreach (var chunk in mainChunk.Children)
            {
                if (chunk.ChunkID == FourCCs.Size)
                {
                    sizeChunk = chunk;
                }
                else if (chunk.ChunkID == FourCCs.Xyzi)
                {
                    voxelChunk = chunk;
                }
                else if (chunk.ChunkID == FourCCs.Rgba)
                {
                    paletteChunk = chunk;
                }
            }

            if (sizeChunk == null)
            {
                throw new System.IO.IOException("File is corrupted. SIZE chunk was not found.");
            }
            if (voxelChunk == null)
            {
                throw new System.IO.IOException("File is corrupted. XYZI chunk was not found.");
            }
            if (paletteChunk == null)
            {
                throw new System.IO.IOException("VOX file without a palette (RGBA chunk) is currently not supported.");
            }

            // Parse size
            if (sizeChunk.Contents.Count < 12)
            {
                throw new System.IO.IOException("File is corrupted. SIZE chunk is too short.");
            }
            int dimX = BitConverter.ToInt32(sizeChunk.Contents.Array, sizeChunk.Contents.Offset);
            int dimY = BitConverter.ToInt32(sizeChunk.Contents.Array, sizeChunk.Contents.Offset + 4);
            int dimZ = BitConverter.ToInt32(sizeChunk.Contents.Array, sizeChunk.Contents.Offset + 8);
            if (dimX <= 0 || dimY <= 0 || dimZ <= 0)
            {
                throw new System.IO.IOException("File is corrupted. Bad dimensions.");
            }

            // Read palette
            var palette = new uint[256];
            {
                var paldata = paletteChunk.Contents;
                if (paldata.Count < 256 * 4)
                {
                    throw new System.IO.IOException("File is corrupted. RGBA chunk is too short.");
                }
                for (int i = 0; i < 255; ++i)
                {
                    uint r = paldata.Array[paldata.Offset + i * 4];
                    uint g = paldata.Array[paldata.Offset + i * 4 + 1];
                    uint b = paldata.Array[paldata.Offset + i * 4 + 2];
                    palette[i + 1] = b | (g << 8) | (r << 16);
                }
            }

            // Read geometry
            var model = new VoxelModel(dimX, dimY, dimZ);
            int numVoxels = BitConverter.ToInt32(voxelChunk.Contents.Array, voxelChunk.Contents.Offset);
            if (voxelChunk.Contents.Count / 4 < numVoxels + 1)
            {
                throw new System.IO.IOException("File is corrupted. XYZI chunk is too short.");
            }
            progress?.Report("Reading voxels");
            {
                var data = voxelChunk.Contents;
                int end = data.Offset + 4 + numVoxels * 4;
                for (int i = data.Offset + 4; i < end; i += 4)
                {
                    int x = data.Array[i];
                    int y = data.Array[i + 1];
                    int z = data.Array[i + 2];
                    int color = data.Array[i + 3];
                    if (x < 0 || x >= dimX || y < 0 || y >= dimY || z < 0 || z >= dimZ)
                    {
                        throw new System.IO.IOException("File is corrupted. Voxel location is out of bounds.");
                    }
                    model[x, y, z] = palette[color];
                    if (((i & 8191) == 0))
                    {
                        progress?.Report((double)(i - data.Offset) / (double)(numVoxels * 4));
                    }
                }
            }
            return model;
        }
Exemplo n.º 5
0
        public VoxelModel LoadVoxelModel(System.IO.Stream stream, out Vector3 pivot, IProgressListener progress)
        {
            var reader = new System.IO.BinaryReader(stream);

            {
                var buf = new byte[4];
                if (stream.Read(buf, 0, 4) < 4)
                {
                    throw new System.IO.IOException("Magic not read");
                }
                if (buf[0] != 'K' ||
                   buf[1] != 'v' ||
                   buf[2] != 'x' ||
                   buf[3] != 'l')
                {
                    throw new System.IO.IOException("Invalid magic");
                }
            }

            int xsiz = reader.ReadInt32();
            int ysiz = reader.ReadInt32();
            int zsiz = reader.ReadInt32();
            float xpivot = reader.ReadSingle();
            float ypivot = reader.ReadSingle();
            float zpivot = reader.ReadSingle();
            int numblocks = reader.ReadInt32();
            var blocks = new Kv6Block[numblocks];

            progress?.Report("Reading voxels");

            for (int i = 0; i < blocks.Length; ++i)
            {
                blocks[i].color = reader.ReadUInt32();
                blocks[i].zpos = (int) reader.ReadUInt16();
                reader.ReadUInt16(); // skip visFaces & lighting
                if (((i & 8191) == 0))
                {
                    progress?.Report((double)i / blocks.Length * 0.5);
                }
            }

            var xyoffset = new int[xsiz * ysiz];

            // skip xoffset
            for (int i = 0; i < xsiz; ++i)
            {
                reader.ReadInt32();
            }
            for (int i = 0; i < xyoffset.Length; ++i)
            {
                xyoffset[i] = (int) reader.ReadUInt16();
            }

            progress?.Report("Placing voxels");

            int pos = 0;
            var model = new VoxelModel(xsiz, ysiz, zsiz);
            for (int x = 0; x < xsiz; ++x) {
                for (int y = 0; y < ysiz; ++y) {
                    int sb = xyoffset[x * ysiz + y];
                    for (int i = 0; i < sb; ++i) {
                        var b = blocks[pos];
                        model[x, y, b.zpos] = b.color;
                        pos += 1;
                    }
                }

                progress?.Report((double)pos / blocks.Length * 0.5 + 0.5);
            }

            pivot = new Vector3(xpivot, ypivot, zpivot);

            return model;
        }
Exemplo n.º 6
0
        public void GenerateTextureAndUV(VoxelModel model, MeshSlices slices, out Bitmap bitmap, IProgressListener progress)
        {
            // Collect colors
            var colors = new List<int>(); // Marshal.Copy doesn't support uint[] lol

            int totalSlices = 0;
            foreach (var slicelist in slices)
            {
                totalSlices += slicelist.Length;
            }

            int sliceIndex = 0;

            progress?.Report("Collecting colors");

            foreach (var slicelist in slices)
            {
                foreach (var slice in slicelist)
                {
                    ++sliceIndex;
                    progress?.Report((double)sliceIndex / totalSlices);

                    var verts = slice.Positions;
                    Axis3 paxis1, paxis2;
                    GetPerpendicularAxises(slice.Axis, out paxis1, out paxis2);

                    var pt = new IntVector3();
                    pt[slice.Axis] = slice.Layer;

                    foreach (var face in slice.MeshSliceFaces)
                    {
                        var scoord = FindSliceCoordForFace(slice, face, slice.Axis, paxis1, paxis2);
                        pt[paxis1] = scoord.X;
                        pt[paxis2] = scoord.Y;

                        colors.Add((int) (model[pt] | 0xff000000));
                    }
                }
            }

            // Determine the dimensions of the texture
            int texwidth = (int)Math.Ceiling(Math.Sqrt(colors.Count));
            int texheight = (colors.Count + texwidth - 1) / texwidth;

            // And then create the texture
            bitmap = new Bitmap(texwidth * 2, texheight * 2,
                                System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            var bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                                          System.Drawing.Imaging.ImageLockMode.WriteOnly,
                                          System.Drawing.Imaging.PixelFormat.Format32bppRgb);

            System.Runtime.InteropServices.Marshal.Copy(Scale2x(colors.ToArray(), texwidth, texheight), 0,
                                                        bmpdata.Scan0, colors.Count * 4);

            bitmap.UnlockBits(bmpdata);

            // Assign UVs
            int faceu = 0, facev = 0;

            sliceIndex = 0;
            progress?.Report("Assigning UV coordinates");

            foreach (var slicelist in slices)
            {
                foreach (var slice in slicelist)
                {
                    ++sliceIndex;
                    progress?.Report((double)sliceIndex / totalSlices);

                    var verts = slice.Positions;
                    var uvs = slice.UVs = new Vector2[slice.Positions.Length];
                    Axis3 paxis1, paxis2;
                    GetPerpendicularAxises(slice.Axis, out paxis1, out paxis2);

                    foreach (var face in slice.MeshSliceFaces)
                    {
                        var scoord = FindSliceCoordForFace(slice, face, slice.Axis, paxis1, paxis2);

                        var uv = new Vector2((float) (faceu << 1) + 0.5f, (float) (facev << 1) + 0.5f);
                        for (int i = face.StartIndex; i < face.EndIndex; ++i)
                        {
                            var vt = verts[i];
                            float u = uv.X + (float)(vt[paxis1] - scoord.X);
                            float v = uv.Y + (float)(vt[paxis2] - scoord.Y);
                            uvs[i] = new Vector2(u, v);
                        }

                        faceu += 1;
                        if (faceu == texwidth)
                        {
                            faceu = 0;
                            facev += 1;
                        }
                    }
                }
            }
        }
Exemplo n.º 7
0
 static void Traverse(int x, int y, int z, VoxelModel m, bool[,,] ext, Queue<IntVector3> queue, uint adjcolor)
 {
     if (m.IsVoxelSolid(x, y, z) || ext[x, y, z])
     {
         return;
     }
     m[x, y, z] = adjcolor;
     queue.Enqueue(new IntVector3(x, y, z));
 }
Exemplo n.º 8
0
        public void Apply(ref VoxelModel model, IProgressListener progress)
        {
            var m = model;

            progress?.Report("Analyzing structure");
            var ext = new ExteriorAnalyzer()
            {
                Model = m
            }.Analyze(new ProgressMapper(progress, 0, 1.0 / 3.0, null));

            // Find the initial points (solid voxels adjacent to interior empty voxels)
            progress?.Report("Planting seeds");
            var queue = new Queue<IntVector3>();
            int width = m.Width, height = m.Height, depth = m.Depth;
            int numVoxelsToProcess = 0;
            for (int x = 0; x < width; ++x)
            {
                for (int y = 0; y < height; ++y)
                {
                    for (int z = 0; z < depth; ++z)
                    {
                        if (!ext[x, y, z] && !model.IsVoxelSolid(x, y, z))
                        {
                            ++numVoxelsToProcess;
                        }
                        if (!model.IsVoxelSolid(x, y, z))
                        {
                            continue;
                        }
                        queue.Enqueue(new IntVector3(x, y, z));
                    }
                }
                progress?.Report((double)(x + 1) / width * (1.0 / 3.0) + (1.0 / 3.0));
            }
            numVoxelsToProcess += queue.Count;

            progress?.Report("Filling inside");
            int numProcessed = 0;
            while (queue.Count > 0)
            {
                ++numProcessed;
                if ((numProcessed & 2047) == 0)
                {
                    progress?.Report((double)numProcessed / numVoxelsToProcess * (1.0 / 3.0) + (2.0 / 3.0));
                }

                var p = queue.Dequeue();
                uint color = m[p];
                if (p.X > 0)
                {
                    Traverse(p.X - 1, p.Y, p.Z, m, ext, queue, color);
                }
                if (p.Y > 0)
                {
                    Traverse(p.X, p.Y - 1, p.Z, m, ext, queue, color);
                }
                if (p.Z > 0)
                {
                    Traverse(p.X, p.Y, p.Z - 1, m, ext, queue, color);
                }
                if (p.X < width - 1)
                {
                    Traverse(p.X + 1, p.Y, p.Z, m, ext, queue, color);
                }
                if (p.Y < height - 1)
                {
                    Traverse(p.X, p.Y + 1, p.Z, m, ext, queue, color);
                }
                if (p.Z < depth - 1)
                {
                    Traverse(p.X, p.Y, p.Z + 1, m, ext, queue, color);
                }
            }
        }
Exemplo n.º 9
0
        public MeshSlices GenerateSlices(VoxelModel model, IProgressListener progress)
        {
            var slices = new MeshSlices();
            var dims = model.Dimensions;

            int totalsteps = 2 * (model.Width + model.Height + model.Depth);
            int step = 0;

            progress?.Report("Generating slices");

            for (int iaxis = 0; iaxis < 3; ++iaxis)
            {
                for (int iface = 0; iface < 2; ++iface)
                {

                    var axis = (Axis3) iaxis;
                    var paxis1 = (Axis3) ((iaxis + 1) % 3);
                    var paxis2 = (Axis3) ((iaxis + 2) % 3);
                    bool face = iface != 0;

                    int dim0 = dims[axis];
                    int dim1 = dims[paxis1];
                    int dim2 = dims[paxis2];

                    var slicelist = new MeshSlice[dim0];
                    slices[axis, face] = slicelist;

                    for (int layer = 0; layer < dim0; ++layer)
                    {
                        ++step;
                        progress?.Report((double)step / totalsteps);

                        var faces = new List<int>();
                        var ret = new List<IntVector3>();

                        var pt1 = new IntVector3();
                        pt1[axis] = layer;
                        for (int x = 0; x < dim1; ++x)
                        {
                            pt1[paxis1] = x;
                            for (int y = 0; y < dim2; ++y)
                            {
                                pt1[paxis2] = y;

                                bool solid1 = model.IsVoxelSolid(pt1);

                                var pt2 = pt1;
                                bool solid2 = false;
                                if (face)
                                {
                                    pt2[axis] += 1;
                                    if (pt2[axis] < dim0)
                                    {
                                        solid2 = model.IsVoxelSolid(pt2);
                                    }
                                }
                                else
                                {
                                    pt2[axis] -= 1;
                                    if (pt2[axis] >= 0)
                                    {
                                        solid2 = model.IsVoxelSolid(pt2);
                                    }
                                }

                                if (!solid1 || solid2)
                                {
                                    continue;
                                }

                                // Create quad
                                var qpt1 = pt1;
                                if (face)
                                {
                                    qpt1[axis] += 1;
                                    qpt1[paxis2] += 1;
                                }
                                var qpt2 = qpt1;
                                qpt2[paxis1] += 1;
                                var qpt3 = qpt1;
                                var qpt4 = qpt2;
                                if (face)
                                {
                                    qpt3[paxis2] -= 1;
                                    qpt4[paxis2] -= 1;
                                }
                                else
                                {
                                    qpt3[paxis2] += 1;
                                    qpt4[paxis2] += 1;
                                }

                                // Emit polygons
                                faces.Add(ret.Count);
                                ret.Add(qpt3);
                                ret.Add(qpt4);
                                ret.Add(qpt2);
                                ret.Add(qpt1);
                            } // for y
                        } // for x

                        slicelist[layer] = new MeshSlice()
                        {
                            Positions = ret.ToArray(),
                            Faces = faces.ToArray(),

                            Face = face,
                            Axis = axis,
                            Layer = layer
                        };

                    } // for slice
                } // iface
            } // iaxis
            return slices;
        }