Ejemplo n.º 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="textures"></param>
        void PackTextureAtlas(IEnumerable <VTTexture> textures, Allocator2D allocator)
        {
            foreach (var tex in textures)
            {
                var size = Math.Max(tex.Width / 128, tex.Height / 128);

                var addr = allocator.Alloc(size, tex.Name);

                tex.TexelOffsetX = addr.X * VTConfig.PageSize;
                tex.TexelOffsetY = addr.Y * VTConfig.PageSize;
                tex.TilesDirty   = true;

                Log.Message("...add: {0} : {1}x{2} : tile[{3},{4}]", tex.Name, tex.Width, tex.Height, addr.X, addr.Y);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="textures"></param>
        void RepackTextureAtlas(VTTextureTable vtexTable, Allocator2D allocator, DateTime targetWriteTime)
        {
            //
            //	remove deleted and changes textures from allocator :
            //
            var blockInfo = allocator.GetAllocatedBlockInfo();

            foreach (var block in blockInfo)
            {
                if (!vtexTable.Contains(block.Tag))
                {
                    Log.Message("...removed: {0}", block.Tag);
                    allocator.Free(block.Address);
                }
                else
                {
                    if (vtexTable[block.Tag].IsModified(targetWriteTime))
                    {
                        Log.Message("...changed: {0}", block.Tag);
                        allocator.Free(block.Address);
                    }
                }
            }


            //
            //	add missing textures (note, changed are already removed).
            //
            var blockDictionary = allocator.GetAllocatedBlockInfo().ToDictionary(bi => bi.Tag);
            var newTextureList  = new List <VTTexture>();

            foreach (var tex in vtexTable.SourceTextures)
            {
                Allocator2D.BlockInfo bi;

                if (blockDictionary.TryGetValue(tex.Name, out bi))
                {
                    tex.TexelOffsetX = bi.Address.X * VTConfig.PageSize;
                    tex.TexelOffsetY = bi.Address.Y * VTConfig.PageSize;
                }
                else
                {
                    newTextureList.Add(tex);
                }
            }

            PackTextureAtlas(newTextureList, allocator);
        }
Ejemplo n.º 3
0
        public static Allocator2D LoadState(BinaryReader reader)
        {
            //	read header:
            var fourcc  = reader.ReadFourCC();
            var version = reader.ReadFourCC();

            var size = reader.ReadInt32();

            var allocator = new Allocator2D(size);


            //	read nodes if depth-first order :
            var S = new Stack <Block>();

            S.Push(allocator.rootBlock);

            while (S.Any())
            {
                var block = S.Pop();

                var fcc = reader.ReadFourCC();

                block.Address.X = reader.ReadInt32();
                block.Address.Y = reader.ReadInt32();
                block.Size      = reader.ReadInt32();

                var state = (BlockState)reader.ReadInt32();

                if (state == BlockState.Allocated)
                {
                    block.Tag = reader.ReadString();
                }

                if (state == BlockState.Split)
                {
                    block.Split();
                    S.Push(block.BottomRight);
                    S.Push(block.BottomLeft);
                    S.Push(block.TopRight);
                    S.Push(block.TopLeft);
                }
            }

            return(allocator);
        }
Ejemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="allocator"></param>
        /// <returns></returns>
        public static void SaveState(BinaryWriter writer, Allocator2D allocator)
        {
            //	write header:
            writer.WriteFourCC("MLC2");
            writer.WriteFourCC("1.00");

            writer.Write(allocator.Size);

            //	write nodes if depth-first order :
            var S = new Stack <Block>();

            S.Push(allocator.rootBlock);

            while (S.Any())
            {
                var block = S.Pop();

                writer.WriteFourCC("BLCK");

                writer.Write(block.Address.X);
                writer.Write(block.Address.Y);
                writer.Write(block.Size);
                writer.Write((int)block.State);

                if (block.State == BlockState.Allocated)
                {
                    writer.Write(block.Tag);
                }

                if (block.State == BlockState.Split)
                {
                    S.Push(block.BottomRight);
                    S.Push(block.BottomLeft);
                    S.Push(block.TopRight);
                    S.Push(block.TopLeft);
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="dir"></param>
        public static void RunTest(int size, int interations, string dir)
        {
            Log.Message("Allocator2D test: {0} {1} {2}", size, interations, dir);

            var dirInfo = Directory.CreateDirectory(dir);

            foreach (FileInfo file in dirInfo.GetFiles())
            {
                file.Delete();
            }

            var alloc = new Allocator2D(size);
            var image = new Image(size, size, Color.Black);
            var rand  = new Random();

            var list = new List <Int2>();

            for (int i = 0; i < interations; i++)
            {
                Log.Message("{0,3:D3}/{1,3:D3}", i, interations);

                try {
                    bool allocNotFree = rand.NextFloat(0, 1) < 0.5f;
                    bool reloadState  = rand.NextFloat(0, 1) < 0.1f;

                    if (allocNotFree)
                    {
                        for (int j = 0; j < rand.Next(1, 16); j++)
                        {
                            //var sz = MathUtil.RoundUpNextPowerOf2( rand.Next(1,64) );
                            var sz = rand.Next(1, 64);

                            var tag = string.Format("Block#{0,4:D4}##{1,4:D4}", i, sz);

                            var a = alloc.Alloc(sz, tag);

                            list.Add(a);

                            DrawRectangle(image, a.X, a.Y, sz, sz, rand.NextColor(), false);
                        }
                    }
                    else
                    {
                        for (int j = 0; j < rand.Next(1, 16); j++)
                        {
                            if (!list.Any())
                            {
                                break;
                            }

                            var id = rand.Next(list.Count);
                            var fa = list[id];
                            list.RemoveAt(id);

                            var sz = alloc.Free(fa);

                            DrawRectangle(image, fa.X, fa.Y, sz, sz, Color.Black, true);
                        }
                    }

                    var imagePath = Path.Combine(dir, string.Format("allocTest{0,4:D4}.tga", i));
                    var stackPath = Path.Combine(dir, string.Format("allocTest{0,4:D4}.stk", i));

                    Image.SaveTga(image, imagePath);

                    if (reloadState)
                    {
                        Log.Message("---- STATE RELOAD ----------------------------------");

                        using (var stream = File.OpenWrite(stackPath)) {
                            Allocator2D.SaveState(stream, alloc);
                        }

                        using (var stream = File.OpenRead(stackPath)) {
                            alloc = Allocator2D.LoadState(stream);
                        }
                    }
                } catch (Exception e) {
                    Log.Error("Exception: {0}", e.Message);
                    continue;
                }
            }

            Log.Message("Done!");
        }
Ejemplo n.º 6
0
        public static void SaveState(Stream targetStream, Allocator2D allocator)
        {
            var writer = new BinaryWriter(targetStream, Encoding.Default, true);

            SaveState(writer, allocator);
        }
Ejemplo n.º 7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="buildContext"></param>
        public override void Process(AssetSource assetFile, BuildContext context)
        {
            Log.Message("-------- Virtual Texture --------");

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var xmlFiles = Directory.EnumerateFiles(Path.Combine(Builder.FullInputDirectory, "vt"), "*.xml").ToList();

            Log.Message("{0} megatexture segments", xmlFiles.Count);


            //
            //	Process tiles :
            //
            using (var tileStorage = context.GetVTStorage()) {
                var pageTable = CreateVTTextureTable(xmlFiles, context, tileStorage);


                //
                //	Get allocator and pack/repack textures :
                //
                Allocator2D allocator = null;

                if (tileStorage.FileExists(targetAllocator) && tileStorage.FileExists(targetMegatexture))
                {
                    Log.Message("Loading VT allocator...");

                    using (var allocStream = tileStorage.OpenRead(targetAllocator)) {
                        allocator = Allocator2D.LoadState(allocStream);
                        var targetTime = tileStorage.GetLastWriteTimeUtc(targetMegatexture);

                        Log.Message("Repacking textures to atlas...");
                        RepackTextureAtlas(pageTable, allocator, targetTime);
                    }
                }
                else
                {
                    allocator = new Allocator2D(VTConfig.VirtualPageCount);

                    Log.Message("Packing ALL textures to atlas...");
                    PackTextureAtlas(pageTable.SourceTextures, allocator);
                }

                Log.Message("Saving VT allocator...");

                using (var allocStream = tileStorage.OpenWrite(targetAllocator)) {
                    Allocator2D.SaveState(allocStream, allocator);
                }

                //
                //	Generate top-level pages :
                //
                Log.Message("Generating pages...");
                GenerateMostDetailedPages(pageTable.SourceTextures, context, pageTable, tileStorage);


                //
                //	Generate mip-maps :
                //
                Log.Message("Generating mipmaps...");
                for (int mip = 0; mip < VTConfig.MipCount - 1; mip++)
                {
                    Log.Message("Generating mip level {0}/{1}...", mip, VTConfig.MipCount);
                    GenerateMipLevels(context, pageTable, mip, tileStorage);
                }


                //
                //	Write asset :
                //
                using (var stream = tileStorage.OpenWrite(targetMegatexture)) {
                    using (var assetStream = AssetStream.OpenWrite(stream, "", new[] { "" })) {
                        using (var sw = new BinaryWriter(assetStream)) {
                            sw.Write(pageTable.SourceTextures.Count);

                            foreach (var tex in pageTable.SourceTextures)
                            {
                                VTTexture.Write(tex, sw);
                            }
                        }
                    }
                }
            }

            stopwatch.Stop();
            Log.Message("{0}", stopwatch.Elapsed.ToString());

            Log.Message("----------------");
        }