public Theater(TileSet tileset) { 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(new Size(tileset.SheetSize, tileset.SheetSize), true); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); templates = new Dictionary<ushort, Sprite[]>(); var frameCache = new FrameCache(Game.modData.SpriteLoaders, tileset.Extensions); foreach (var t in tileset.Templates) { var allFrames = frameCache[t.Value.Image]; var frames = t.Value.Frames != null ? t.Value.Frames.Select(f => allFrames[f]).ToArray() : allFrames; templates.Add(t.Value.Id, frames.Select(f => sheetBuilder.Add(f)).ToArray()); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public CursorProvider(ModData modData) { var fileSystem = modData.DefaultFileSystem; var sequenceYaml = MiniYaml.Merge(modData.Manifest.Cursors.Select( s => MiniYaml.FromStream(fileSystem.Open(s), s))); var shadowIndex = new int[] { }; var nodesDict = new MiniYaml(null, sequenceYaml).ToDictionary(); if (nodesDict.ContainsKey("ShadowIndex")) { Array.Resize(ref shadowIndex, shadowIndex.Length + 1); Exts.TryParseIntegerInvariant(nodesDict["ShadowIndex"].Value, out shadowIndex[shadowIndex.Length - 1]); } var palettes = new Dictionary<string, ImmutablePalette>(); foreach (var p in nodesDict["Palettes"].Nodes) palettes.Add(p.Key, new ImmutablePalette(fileSystem.Open(p.Value.Value), shadowIndex)); Palettes = palettes.AsReadOnly(); var frameCache = new FrameCache(fileSystem, modData.SpriteLoaders); var cursors = new Dictionary<string, CursorSequence>(); foreach (var s in nodesDict["Cursors"].Nodes) foreach (var sequence in s.Value.Nodes) cursors.Add(sequence.Key, new CursorSequence(frameCache, sequence.Key, s.Key, s.Value.Value, sequence.Value)); Cursors = cursors.AsReadOnly(); }
public Theater(TileSet tileset) { this.tileset = tileset; var allocated = false; var type = tileset.EnableDepth ? SheetType.DualIndexed : SheetType.Indexed; Func<Sheet> allocate = () => { if (allocated) throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); allocated = true; return new Sheet(type, new Size(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(type, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List<Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); variants.Add(indices.Select(j => { var f = allFrames[j]; var s = sheetBuilder.Allocate(f.Size, f.Offset); Util.FastCopyIntoChannel(s, 0, f.Data); if (tileset.EnableDepth) Util.FastCopyIntoChannel(s, 1, allFrames[j + frameCount].Data); return s; }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, float2.Zero, s.Channel, s.BlendMode)); templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public TileSetRenderer(TileSet tileset, Size tileSize) { this.TileSet = tileset; this.TileSize = Math.Min(tileSize.Width, tileSize.Height); templates = new Dictionary<ushort, byte[][]>(); var frameCache = new FrameCache(Game.modData.SpriteLoaders, tileset.Extensions); foreach (var t in tileset.Templates) { var allFrames = frameCache[t.Value.Image]; var frames = t.Value.Frames != null ? t.Value.Frames.Select(f => allFrames[f]).ToArray() : allFrames; templates.Add(t.Value.Id, frames.Select(f => ExtractSquareTile(f)).ToArray()); } }
public Theater(TileSet tileset) { this.tileset = tileset; 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(new Size(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List<Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frames = t.Value.Frames != null ? t.Value.Frames.Select(f => allFrames[f]).ToArray() : allFrames; variants.Add(frames.Select(f => sheetBuilder.Add(f)).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, float2.Zero, s.Channel, s.BlendMode)); templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public CursorSequence(FrameCache cache, string name, string cursorSrc, string palette, MiniYaml info) { var d = info.ToDictionary(); Start = Exts.ParseIntegerInvariant(d["Start"].Value); Palette = palette; Name = name; if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*")) Length = Frames.Length - Start; else if (d.ContainsKey("Length")) Length = Exts.ParseIntegerInvariant(d["Length"].Value); else if (d.ContainsKey("End")) Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start; else Length = 1; Frames = cache[cursorSrc] .Skip(Start) .Take(Length) .ToArray(); if (d.ContainsKey("X")) { int x; Exts.TryParseIntegerInvariant(d["X"].Value, out x); Hotspot = Hotspot.WithX(x); } if (d.ContainsKey("Y")) { int y; Exts.TryParseIntegerInvariant(d["Y"].Value, out y); Hotspot = Hotspot.WithY(y); } }
void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. var modData = Game.ModData = utility.ModData; var imageField = typeof(TerrainTemplateInfo).GetField("Image"); var pickAnyField = typeof(TerrainTemplateInfo).GetField("PickAny"); var tileInfoField = typeof(TerrainTemplateInfo).GetField("tileInfo", BindingFlags.NonPublic | BindingFlags.Instance); var terrainTypeField = typeof(TerrainTileInfo).GetField("TerrainType"); var terrainLeftColorField = typeof(TerrainTileInfo).GetField("LeftColor"); var terrainRightColorField = typeof(TerrainTileInfo).GetField("RightColor"); var empty = new Size(0, 0); var single = new int2(1, 1); var exts = new[] { "" }.Concat(args[1].Split(',')); foreach (var t in modData.Manifest.TileSets) { var ts = new TileSet(modData.DefaultFileSystem, t); var frameCache = new FrameCache(modData.DefaultFileSystem, modData.SpriteLoaders); Console.WriteLine("Tileset: " + ts.Name); foreach (var template in ts.Templates.Values) { // Find the sprite associated with this template foreach (var ext in exts) { Stream s; if (modData.DefaultFileSystem.TryOpen(template.Images[0] + ext, out s)) s.Dispose(); else continue; // Rewrite the template image (normally readonly) using reflection imageField.SetValue(template, template.Images[0] + ext); // Fetch the private tileInfo array so that we can write new entries var tileInfo = (TerrainTileInfo[])tileInfoField.GetValue(template); // Open the file and search for any implicit frames var allFrames = frameCache[template.Images[0]]; var frames = template.Frames != null ? template.Frames.Select(f => allFrames[f]).ToArray() : allFrames; // Resize array for new entries if (frames.Length > template.TilesCount) { var ti = new TerrainTileInfo[frames.Length]; Array.Copy(tileInfo, ti, template.TilesCount); tileInfoField.SetValue(template, ti); tileInfo = ti; } for (var i = 0; i < template.TilesCount; i++) { if (template[i] == null && frames[i] != null && frames[i].Size != empty) { tileInfo[i] = new TerrainTileInfo(); var ti = ts.GetTerrainIndex("Clear"); terrainTypeField.SetValue(tileInfo[i], ti); terrainLeftColorField.SetValue(tileInfo[i], ts[ti].Color); terrainRightColorField.SetValue(tileInfo[i], ts[ti].Color); Console.WriteLine("Fixing entry for {0}:{1}", template.Images[0], i); } } if (template.TilesCount > 1 && template.Size == single) pickAnyField.SetValue(template, true); } } ts.Save(t); } }
public Theater(TileSet tileset) { this.tileset = tileset; 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(tileset.SheetSize, tileset.SheetSize))); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); variants.Add(indices.Select(j => { var f = allFrames[j]; var tile = t.Value.Contains(j) ? 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 s = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(s, f.Data); if (tileset.EnableDepth) { var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data); // s and ss are guaranteed to use the same sheet // because of the custom terrain sheet allocation s = new SpriteWithSecondaryData(s, ss.Bounds, ss.Channel); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public Theater(TileSet tileset) { this.tileset = tileset; var allocated = false; var type = tileset.EnableDepth ? SheetType.DualIndexed : SheetType.Indexed; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); } allocated = true; return(new Sheet(type, new Size(tileset.SheetSize, tileset.SheetSize))); }; sheetBuilder = new SheetBuilder(type, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); variants.Add(indices.Select(j => { var f = allFrames[j]; var s = sheetBuilder.Allocate(f.Size, f.Offset); Util.FastCopyIntoChannel(s, 0, f.Data); if (tileset.EnableDepth) { Util.FastCopyIntoChannel(s, 1, allFrames[j + frameCount].Data); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, float2.Zero, s.Channel, s.BlendMode)); } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public Theater(TileSet tileset) { this.tileset = tileset; 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(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List<Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); variants.Add(indices.Select(j => { var f = allFrames[j]; var tile = t.Value.Contains(j) ? 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 s = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(s, f.Data); if (tileset.EnableDepth) { var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data); // s and ss are guaranteed to use the same sheet // because of the custom terrain sheet allocation s = new SpriteWithSecondaryData(s, ss.Bounds, ss.Channel); } return s; }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public Theater(TileSet tileset) { this.tileset = tileset; var allocated = false; //Func<Sheet2D> allocate = () => //{ // if (allocated) // throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); // allocated = true; // SheetBuilder2D shb= Game.worldRenderer.World.Map.Rules.Sequences.SpriteCache.SheetBuilder2D; // return new Sheet2D(SheetType.Indexed, shb., shb.TextureArrayIndex); //}; //SheetBuilder2D shb = Game.OrderManager.World.Map.Rules.Sequences.SpriteCache.SheetBuilder2D; //sheetBuilder2d = Game.OrderManager.World.Map.Rules.Sequences.SpriteCache.SheetBuilder2D; sheetBuilder2d = Game.SheetBuilder2D; if (!string.IsNullOrEmpty(tileset.MegaTexture)) { sbMegaTexture = sheetBuilder2d; LoadsbMegaTexture(tileset.MegaTexture); } random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); //дл¤ каждого templates есть сво¤ коллекци¤ Sprites , это заполн¤етс¤ в цикле по tileset.Templates ниже foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { var allFrames = frameCache[i]; var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount); variants.Add(indices.Select(j => { var f = allFrames[j]; var tile = t.Value.Contains(j) ? 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 s = sheetBuilder2d.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(s, f.Data); if (tileset.EnableDepth) { var ss = sheetBuilder2d.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data); // 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 (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet2D, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } if (t.Value.Variants == "Calc") { templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), 1, variants.First().Count())); } else { templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } } // 1x1px transparent tile missingTile = sheetBuilder2d.Add(new byte[1], new Size(1, 1)); //Sheet2D.ReleaseBuffer(); }
public Theater(TileSet tileset, Action <uint, string> onMissingImage = null) { this.tileset = tileset; 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(tileset.SheetSize, tileset.SheetSize))); }; random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { ISpriteFrame[] allFrames; if (onMissingImage != null) { try { allFrames = frameCache[i]; } catch (FileNotFoundException) { onMissingImage(t.Key, i); continue; } } else { allFrames = frameCache[i]; } var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.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) ? 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); Util.FastCopyIntoChannel(s, f.Data); if (tileset.EnableDepth) { var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data); // 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 (tileset.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(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1)); Sheet.ReleaseBuffer(); }