예제 #1
0
        internal static void LoadPreTexture(IResourceCache cache, LoadStepData data)
        {
            var metadata = LoadRsiMetadata(cache, data.Path);

            var stateCount = metadata.States.Length;
            var toAtlas    = new StateReg[stateCount];

            var frameSize = metadata.Size;
            var rsi       = new RSI(frameSize, data.Path, metadata.States.Length);

            var callbackOffsets = new Dictionary <RSI.StateId, Vector2i[][]>(stateCount);

            // Check for duplicate states
            for (var i = 0; i < metadata.States.Length; i++)
            {
                var stateId = metadata.States[i].StateId;

                for (int j = i + 1; j < metadata.States.Length; j++)
                {
                    if (stateId == metadata.States[j].StateId)
                    {
                        throw new RSILoadException($"RSI '{data.Path}' has a duplicate stateId '{stateId}'.");
                    }
                }
            }

            // Do every state.
            for (var index = 0; index < metadata.States.Length; index++)
            {
                ref var reg = ref toAtlas[index];

                var stateObject = metadata.States[index];
                // Load image from disk.
                var texPath = data.Path / (stateObject.StateId + ".png");
                using (var stream = cache.ContentFileRead(texPath))
                {
                    reg.Src = Image.Load <Rgba32>(stream);
                }

                if (reg.Src.Width % frameSize.X != 0 || reg.Src.Height % frameSize.Y != 0)
                {
                    var regDims  = $"{reg.Src.Width}x{reg.Src.Height}";
                    var iconDims = $"{frameSize.X}x{frameSize.Y}";
                    throw new RSILoadException($"State '{stateObject.StateId}' image size ({regDims}) is not a multiple of the icon size ({iconDims}).");
                }

                // Load all frames into a list so we can operate on it more sanely.
                reg.TotalFrameCount = stateObject.Delays.Sum(delayList => delayList.Length);

                var(foldedDelays, foldedIndices) = FoldDelays(stateObject.Delays);

                var textures       = new Texture[foldedIndices.Length][];
                var callbackOffset = new Vector2i[foldedIndices.Length][];

                for (var i = 0; i < textures.Length; i++)
                {
                    textures[i]       = new Texture[foldedIndices[0].Length];
                    callbackOffset[i] = new Vector2i[foldedIndices[0].Length];
                }

                reg.Output  = textures;
                reg.Indices = foldedIndices;
                reg.Offsets = callbackOffset;

                var state = new RSI.State(frameSize, rsi, stateObject.StateId, stateObject.DirType, foldedDelays,
                                          textures);
                rsi.AddState(state);

                callbackOffsets[stateObject.StateId] = callbackOffset;
            }
예제 #2
0
        public override void Load(IResourceCache cache, ResourcePath path)
        {
            var    manifestPath = path / "meta.json";
            string manifestContents;

            using (var manifestFile = cache.ContentFileRead(manifestPath))
                using (var reader = new StreamReader(manifestFile))
                {
                    manifestContents = reader.ReadToEnd();
                }

#if DEBUG
            if (RSISchema != null)
            {
                var errors = RSISchema.Validate(manifestContents);
                if (errors.Count != 0)
                {
                    Logger.Error($"Unable to load RSI from '{path}', {errors.Count} errors:");

                    foreach (var error in errors)
                    {
                        Logger.Error("{0}", error.ToString());
                    }

                    throw new RSILoadException($"{errors.Count} errors while loading RSI. See console.");
                }
            }
#endif

            // Ok schema validated just fine.
            var manifestJson = JObject.Parse(manifestContents);

            var toAtlas = new List <(Image <Rgba32> src, Texture[][] output, int[][] indices, int totalFrameCount)>();

            var metaData  = ParseMetaData(manifestJson);
            var frameSize = metaData.Size;
            var rsi       = new RSI(frameSize);

            // Do every state.
            foreach (var stateObject in metaData.States)
            {
                // Load image from disk.
                var texPath   = path / (stateObject.StateId + ".png");
                var image     = Image.Load(cache.ContentFileRead(texPath));
                var sheetSize = new Vector2i(image.Width, image.Height);

                if (sheetSize.X % frameSize.X != 0 || sheetSize.Y % frameSize.Y != 0)
                {
                    throw new RSILoadException("State image size is not a multiple of the icon size.");
                }

                // Load all frames into a list so we can operate on it more sanely.
                var frameCount = stateObject.Delays.Sum(delayList => delayList.Length);

                var(foldedDelays, foldedIndices) = FoldDelays(stateObject.Delays);

                var textures = new Texture[foldedIndices.Length][];

                for (var i = 0; i < textures.Length; i++)
                {
                    textures[i] = new Texture[foldedIndices[0].Length];
                }

                var state = new RSI.State(frameSize, stateObject.StateId, stateObject.DirType, foldedDelays, textures);
                rsi.AddState(state);

                toAtlas.Add((image, textures, foldedIndices, frameCount));
            }

            // Poorly hacked in texture atlas support here.
            {
                var totalFrameCount = toAtlas.Sum(p => p.totalFrameCount);

                // Generate atlas.
                var dimensionX = (int)MathF.Ceiling(MathF.Sqrt(totalFrameCount));
                var dimensionY = (int)MathF.Ceiling((float)totalFrameCount / dimensionX);

                using var sheet = new Image <Rgba32>(dimensionX * frameSize.X, dimensionY * frameSize.Y);

                var sheetIndex = 0;
                foreach (var(src, _, _, frameCount) in toAtlas)
                {
                    // Blit all the frames over.
                    for (var i = 0; i < frameCount; i++)
                    {
                        var srcWidth  = (src.Width / frameSize.X);
                        var srcColumn = i % srcWidth;
                        var srcRow    = i / srcWidth;
                        var srcPos    = (srcColumn * frameSize.X, srcRow *frameSize.Y);

                        var sheetColumn = (sheetIndex + i) % dimensionX;
                        var sheetRow    = (sheetIndex + i) / dimensionX;
                        var sheetPos    = (sheetColumn * frameSize.X, sheetRow *frameSize.Y);

                        var srcBox = UIBox2i.FromDimensions(srcPos, frameSize);

                        src.Blit(srcBox, sheet, sheetPos);
                    }

                    sheetIndex += frameCount;
                }

                // Load atlas.
                var texture = Texture.LoadFromImage(sheet, path.ToString());

                var sheetOffset = 0;
                foreach (var(src, output, indices, frameCount) in toAtlas)
                {
                    for (var i = 0; i < indices.Length; i++)
                    {
                        var dirIndices = indices[i];
                        var dirOutput  = output[i];

                        for (var j = 0; j < dirIndices.Length; j++)
                        {
                            var index = sheetOffset + dirIndices[j];

                            var sheetColumn = index % dimensionX;
                            var sheetRow    = index / dimensionX;
                            var sheetPos    = (sheetColumn * frameSize.X, sheetRow *frameSize.Y);

                            dirOutput[j] = new AtlasTexture(texture, UIBox2.FromDimensions(sheetPos, frameSize));
                        }
                    }

                    sheetOffset += frameCount;
                }
            }

            foreach (var(image, _, _, _) in toAtlas)
            {
                image.Dispose();
            }

            RSI = rsi;
        }