public CustomTerrainRenderer(World world) { map = world.Map; terrainInfo = map.Rules.TerrainInfo as CustomTerrain; if (terrainInfo == null) { throw new InvalidDataException("CustomTerrainRenderer can only be used with the CustomTerrain parser"); } tileCache = new CustomTileCache(terrainInfo); }
public CustomTileCache(CustomTerrain 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 = (CustomTerrainTemplateInfo)t.Value; for (var ii = 0; ii < templateInfo.Images.Length; ii++) { var i = templateInfo.Images[ii]; ISpriteFrame[] allFrames; if (onMissingImage != null) { try { allFrames = frameCache[i]; } catch (FileNotFoundException) { onMissingImage(t.Key, i); continue; } } else { allFrames = frameCache[i]; } var frameCount = 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) ? (CustomTerrainTileInfo)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); Util.FastCopyIntoChannel(s, f.Data, f.Type); return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into 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().Length, templateInfo.Images.Length)); } // 1x1px transparent tile var missingDataLength = 1; var missingFrameType = SpriteFrameType.Indexed8; var missingSheetType = SheetType.Indexed; missingTile = sheetBuilders[missingSheetType].Add(new byte[missingDataLength], missingFrameType, new Size(1, 1)); foreach (var sb in sheetBuilders.Values) { sb.Current.ReleaseBuffer(); } }