コード例 #1
0
ファイル: DefaultTileCache.cs プロジェクト: lujiawen/OpenRA
        public DefaultTileCache(DefaultTerrain terrainInfo, Action <uint, string> onMissingImage = null)
        {
            sheetBuilders = new Cache <SheetType, SheetBuilder>(t => new SheetBuilder(t, terrainInfo.SheetSize));

            random = new MersenneTwister();

            var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);

            foreach (var t in terrainInfo.Templates)
            {
                var variants     = new List <Sprite[]>();
                var templateInfo = (DefaultTerrainTemplateInfo)t.Value;

                for (var ii = 0; ii < templateInfo.Images.Length; ii++)
                {
                    var i = templateInfo.Images[ii];

                    ISpriteFrame[] allFrames;
                    ISpriteFrame[] depthFrames = null;

                    if (onMissingImage != null)
                    {
                        try
                        {
                            allFrames = frameCache[i];
                        }
                        catch (FileNotFoundException)
                        {
                            onMissingImage(t.Key, i);
                            continue;
                        }
                    }
                    else
                    {
                        allFrames = frameCache[i];
                    }

                    if (terrainInfo.EnableDepth && templateInfo.DepthImages != null && templateInfo.DepthImages.Length == templateInfo.Images.Length)
                    {
                        var di = templateInfo.DepthImages[ii];
                        if (onMissingImage != null)
                        {
                            try
                            {
                                depthFrames = frameCache[di];
                            }
                            catch (FileNotFoundException)
                            {
                                onMissingImage(t.Key, di);
                                continue;
                            }
                        }
                        else
                        {
                            depthFrames = frameCache[di];
                        }
                    }

                    var frameCount = terrainInfo.EnableDepth && depthFrames == null ? allFrames.Length / 2 : allFrames.Length;
                    var indices    = templateInfo.Frames != null ? templateInfo.Frames : Exts.MakeArray(t.Value.TilesCount, j => j);

                    var start = indices.Min();
                    var end   = indices.Max();
                    if (start < 0 || end >= frameCount)
                    {
                        throw new YamlException($"Template `{t.Key}` uses frames [{start}..{end}] of {i}, but only [0..{frameCount - 1}] actually exist");
                    }

                    variants.Add(indices.Select(j =>
                    {
                        var f    = allFrames[j];
                        var tile = t.Value.Contains(j) ? (DefaultTerrainTileInfo)t.Value[j] : null;

                        // The internal z axis is inverted from expectation (negative is closer)
                        var zOffset = tile != null ? -tile.ZOffset : 0;
                        var zRamp   = tile != null ? tile.ZRamp : 1f;
                        var offset  = new float3(f.Offset, zOffset);
                        var type    = SheetBuilder.FrameTypeToSheetType(f.Type);

                        var s = sheetBuilders[type].Allocate(f.Size, zRamp, offset);
                        OpenRA.Graphics.Util.FastCopyIntoChannel(s, f.Data, f.Type);

                        if (terrainInfo.EnableDepth)
                        {
                            var depthFrame = depthFrames != null ? depthFrames[j] : allFrames[j + frameCount];
                            var depthType  = SheetBuilder.FrameTypeToSheetType(depthFrame.Type);
                            var ss         = sheetBuilders[depthType].Allocate(depthFrame.Size, zRamp, offset);
                            OpenRA.Graphics.Util.FastCopyIntoChannel(ss, depthFrame.Data, depthFrame.Type);
                            s = new SpriteWithSecondaryData(s, ss.Sheet, ss.Bounds, ss.Channel);
                        }

                        return(s);
                    }).ToArray());
                }

                var allSprites = variants.SelectMany(s => s);

                // Ignore the offsets baked into R8 sprites
                if (terrainInfo.IgnoreTileSpriteOffsets)
                {
                    allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode));
                }

                if (onMissingImage != null && !variants.Any())
                {
                    continue;
                }

                templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), templateInfo.Images.Length));
            }

            // 1x1px transparent tile
            var missingDataLength = 1;
            var missingFrameType  = SpriteFrameType.Indexed8;
            var missingSheetType  = SheetType.Indexed;

            // Avoid creating an indexed sheet if all tiles are BGRA
            var missing = sheetBuilders.FirstOrDefault();

            if (missing.Value != null && missing.Key == SheetType.BGRA)
            {
                missingDataLength = 4;
                missingFrameType  = SpriteFrameType.Bgra32;
                missingSheetType  = SheetType.BGRA;
            }

            missingTile = sheetBuilders[missingSheetType].Add(new byte[missingDataLength], missingFrameType, new Size(1, 1));
            foreach (var sb in sheetBuilders.Values)
            {
                sb.Current.ReleaseBuffer();
            }
        }
コード例 #2
0
        public DefaultTileCache(DefaultTerrain terrainInfo, Action <uint, string> onMissingImage = null)
        {
            var allocated = false;

            Func <Sheet> allocate = () =>
            {
                if (allocated)
                {
                    throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter.");
                }
                allocated = true;

                return(new Sheet(SheetType.Indexed, new Size(terrainInfo.SheetSize, terrainInfo.SheetSize)));
            };

            random = new MersenneTwister();

            var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);

            foreach (var t in terrainInfo.Templates)
            {
                var variants     = new List <Sprite[]>();
                var templateInfo = (DefaultTerrainTemplateInfo)t.Value;

                foreach (var i in templateInfo.Images)
                {
                    ISpriteFrame[] allFrames;
                    if (onMissingImage != null)
                    {
                        try
                        {
                            allFrames = frameCache[i];
                        }
                        catch (FileNotFoundException)
                        {
                            onMissingImage(t.Key, i);
                            continue;
                        }
                    }
                    else
                    {
                        allFrames = frameCache[i];
                    }

                    var frameCount = terrainInfo.EnableDepth ? allFrames.Length / 2 : allFrames.Length;
                    var indices    = templateInfo.Frames != null ? templateInfo.Frames : Exts.MakeArray(t.Value.TilesCount, j => j);

                    var start = indices.Min();
                    var end   = indices.Max();
                    if (start < 0 || end >= frameCount)
                    {
                        throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist"
                                                .F(t.Key, start, end, i, frameCount - 1));
                    }

                    variants.Add(indices.Select(j =>
                    {
                        var f    = allFrames[j];
                        var tile = t.Value.Contains(j) ? (DefaultTerrainTileInfo)t.Value[j] : null;

                        // The internal z axis is inverted from expectation (negative is closer)
                        var zOffset = tile != null ? -tile.ZOffset : 0;
                        var zRamp   = tile != null ? tile.ZRamp : 1f;
                        var offset  = new float3(f.Offset, zOffset);
                        var type    = SheetBuilder.FrameTypeToSheetType(f.Type);

                        // Defer SheetBuilder creation until we know what type of frames we are loading!
                        // TODO: Support mixed indexed and BGRA frames
                        if (sheetBuilder == null)
                        {
                            sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate);
                        }
                        else if (type != sheetBuilder.Type)
                        {
                            throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA.");
                        }

                        var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
                        OpenRA.Graphics.Util.FastCopyIntoChannel(s, f.Data, f.Type);

                        if (terrainInfo.EnableDepth)
                        {
                            var depthFrame = allFrames[j + frameCount];
                            var ss         = sheetBuilder.Allocate(f.Size, zRamp, offset);
                            OpenRA.Graphics.Util.FastCopyIntoChannel(ss, depthFrame.Data, depthFrame.Type);

                            // s and ss are guaranteed to use the same sheet
                            // because of the custom terrain sheet allocation
                            s = new SpriteWithSecondaryData(s, s.Sheet, ss.Bounds, ss.Channel);
                        }

                        return(s);
                    }).ToArray());
                }

                var allSprites = variants.SelectMany(s => s);

                // Ignore the offsets baked into R8 sprites
                if (terrainInfo.IgnoreTileSpriteOffsets)
                {
                    allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode));
                }

                if (onMissingImage != null && !variants.Any())
                {
                    continue;
                }

                templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), templateInfo.Images.Length));
            }

            // 1x1px transparent tile
            if (sheetBuilder.Type == SheetType.BGRA)
            {
                missingTile = sheetBuilder.Add(new byte[4], SpriteFrameType.Bgra32, new Size(1, 1));
            }
            else
            {
                missingTile = sheetBuilder.Add(new byte[1], SpriteFrameType.Indexed8, new Size(1, 1));
            }

            Sheet.ReleaseBuffer();
        }