public SpriteFont(string name, byte[] data, int size, int ascender, float scale, SheetBuilder builder) { if (builder.Type != SheetType.BGRA) { throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); } deviceScale = scale; this.size = size; this.builder = builder; font = Game.Renderer.CreateFont(data); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); contrastGlyphs = new Cache <Tuple <char, Color, int>, Sprite>(CreateContrastGlyph); dilationElements = new Cache <int, float[]>(CreateCircularWeightMap); // PERF: Cache these delegates for Measure calls. Func <char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; lineWidth = line => line.Sum(characterWidth) / deviceScale; if (size <= 24) { PrecacheColor(Color.White, name); } TopOffset = size - ascender; }
public SpriteFontMSDF(string name, byte[] data, int size, float scale, SheetBuilder builder) { Mfont = new FontMSDF(); Mfont.LoadFontTexturesAsPng(name); if (builder.Type != SheetType.BGRA) { throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); } deviceScale = scale; this.size = size; this.builder = builder; Console.WriteLine("Font {0} : {1}", name, size); font = Game.Renderer.CreateFont(data); // FreeTypeFont библиотека создает IFont структуру, где есть байтовое представление символа. font.SetSize(size, deviceScale); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); // PERF: Cache these delegates for Measure calls. Func <char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; // это одна функция с аргументом character, а телом из glyphs[Pair.New(character, Color.White)].Advance lineWidth = line => line.Sum(characterWidth) / deviceScale; // тоже функция как и characterWidth //if (size <= 24) // пытается, подобрать size? чтобы в строку влезло 24 символа. PrecacheColor(Color.White, name); TopOffset = size - font.Height; }
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 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 SpriteFont(string name, byte[] data, int size, float scale, SheetBuilder builder) { if (builder.Type != SheetType.BGRA) { throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); } deviceScale = scale; this.size = size; this.builder = builder; face = new Face(Library, data, 0); face.SetPixelSizes((uint)(size * deviceScale), (uint)(size * deviceScale)); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); // PERF: Cache these delegates for Measure calls. Func <char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; lineWidth = line => line.Sum(characterWidth) / deviceScale; if (size <= 24) { PrecacheColor(Color.White, name); } }
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))); }; var r8Cache = new Cache <string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); templates = new Dictionary <ushort, Sprite[]>(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates) { templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); }
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)); }; var sourceCache = new Dictionary <string, ISpriteSource>(); templates = new Dictionary <ushort, Sprite[]>(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates) { templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public HardwareCursor(CursorProvider cursorProvider) { this.cursorProvider = cursorProvider; paletteReferences = new Cache <string, PaletteReference>(CreatePaletteReference); foreach (var p in cursorProvider.Palettes) { hardwarePalette.AddPalette(p.Key, p.Value, false); } hardwarePalette.Initialize(); sheetBuilder = new SheetBuilder(SheetType.Indexed); foreach (var kv in cursorProvider.Cursors) { var palette = cursorProvider.Palettes[kv.Value.Palette]; var hc = kv.Value.Frames .Select(f => CreateCursor(f, palette, kv.Key, kv.Value)) .ToArray(); hardwareCursors.Add(kv.Key, hc); var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray(); sprites.Add(kv.Key, s); } sheetBuilder.Current.ReleaseBuffer(); Update(); }
public SpriteCache(ISpriteLoader[] loaders, string[] exts, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; // Include extension-less version exts = exts.Append("").ToArray(); sprites = new Cache <string, Sprite[]>(filename => SpriteLoader.GetSprites(filename, exts, loaders, sheetBuilder)); }
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; // Include extension-less version this.exts = exts.Append("").ToArray(); sprites = new Cache <string, Sprite[]>(CacheSpriteFrames); }
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; // Include extension-less version this.exts = exts.Append("").ToArray(); sprites = new Cache<string, Sprite[]>(CacheSpriteFrames); }
public VoxelLoader() { voxels = new Cache<Pair<string,string>, Voxel>(LoadFile); vertices = new List<Vertex[]>(); totalVertexCount = 0; cachedVertexCount = 0; sheetBuilder = CreateSheetBuilder(); }
public void BeginFrame() { foreach (var kv in mappedBuffers) unmappedBuffers.Push(kv); mappedBuffers.Clear(); sheetBuilder = new SheetBuilder(SheetType.BGRA, AllocateSheet); doRender.Clear(); }
public VoxelLoader() { voxels = new Cache <Pair <string, string>, Voxel>(LoadFile); vertices = new List <Vertex[]>(); totalVertexCount = 0; cachedVertexCount = 0; sheetBuilder = CreateSheetBuilder(); }
public HardwareCursor(CursorProvider cursorProvider) { this.cursorProvider = cursorProvider; paletteReferences = new Cache <string, PaletteReference>(CreatePaletteReference); foreach (var p in cursorProvider.Palettes) { hardwarePalette.AddPalette(p.Key, p.Value, false); } hardwarePalette.Initialize(); sheetBuilder = new SheetBuilder(SheetType.Indexed); foreach (var kv in cursorProvider.Cursors) { var frames = kv.Value.Frames; var palette = cursorProvider.Palettes[kv.Value.Palette]; // Hardware cursors have a number of odd platform-specific bugs/limitations. // Reduce the number of edge cases by padding the individual frames such that: // - the hotspot is inside the frame bounds (enforced by SDL) // - all frames within a sequence have the same size (needed for macOS 10.15) // - the frame size is a multiple of 8 (needed for Windows) var sequenceBounds = Rectangle.FromLTRB(0, 0, 1, 1); var frameHotspots = new int2[frames.Length]; for (var i = 0; i < frames.Length; i++) { // Hotspot relative to the center of the frame frameHotspots[i] = kv.Value.Hotspot - frames[i].Offset.ToInt2() + new int2(frames[i].Size) / 2; // Bounds relative to the hotspot sequenceBounds = Rectangle.Union(sequenceBounds, new Rectangle(-frameHotspots[i], frames[i].Size)); } // Pad bottom-right edge to make the frame size a multiple of 8 var paddedSize = 8 * new int2((sequenceBounds.Width + 7) / 8, (sequenceBounds.Height + 7) / 8); var cursors = new IHardwareCursor[frames.Length]; var frameSprites = new Sprite[frames.Length]; for (var i = 0; i < frames.Length; i++) { // Software rendering is used when the cursor is locked frameSprites[i] = sheetBuilder.Add(frames[i].Data, frames[i].Size, 0, frames[i].Offset); // Calculate the padding to position the frame within sequenceBounds var paddingTL = -(sequenceBounds.Location + frameHotspots[i]); var paddingBR = paddedSize - new int2(frames[i].Size) - paddingTL; cursors[i] = CreateCursor(kv.Key, frames[i], palette, paddingTL, paddingBR, -sequenceBounds.Location); } hardwareCursors.Add(kv.Key, cursors); sprites.Add(kv.Key, frameSprites); } sheetBuilder.Current.ReleaseBuffer(); Update(); }
public VoxelLoader(IReadOnlyFileSystem fileSystem) { this.fileSystem = fileSystem; voxels = new Cache <Pair <string, string>, Voxel>(LoadFile); vertices = new List <Vertex[]>(); totalVertexCount = 0; cachedVertexCount = 0; sheetBuilder = CreateSheetBuilder(); }
public VoxelLoader(IReadOnlyFileSystem fileSystem) { this.fileSystem = fileSystem; voxels = new Cache<Pair<string, string>, Voxel>(LoadFile); vertices = new List<Vertex[]>(); totalVertexCount = 0; cachedVertexCount = 0; sheetBuilder = CreateSheetBuilder(); }
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 void BeginFrame() { foreach (var kv in mappedBuffers) { unmappedBuffers.Push(kv); } mappedBuffers.Clear(); sheetBuilder = new SheetBuilder(SheetType.BGRA, AllocateSheet); doRender.Clear(); }
public CursorManager(CursorProvider cursorProvider) { hardwareCursorsDisabled = Game.Settings.Graphics.DisableHardwareCursors; graphicSettings = Game.Settings.Graphics; sheetBuilder = new SheetBuilder(SheetType.BGRA); foreach (var kv in cursorProvider.Cursors) { var frames = kv.Value.Frames; var palette = !string.IsNullOrEmpty(kv.Value.Palette) ? cursorProvider.Palettes[kv.Value.Palette] : null; var c = new Cursor { Name = kv.Key, Bounds = Rectangle.FromLTRB(0, 0, 1, 1), Length = 0, Sprites = new Sprite[frames.Length], Cursors = new IHardwareCursor[frames.Length] }; // Hardware cursors have a number of odd platform-specific bugs/limitations. // Reduce the number of edge cases by padding the individual frames such that: // - the hotspot is inside the frame bounds (enforced by SDL) // - all frames within a sequence have the same size (needed for macOS 10.15) // - the frame size is a multiple of 8 (needed for Windows) foreach (var f in frames) { // Hotspot is specified relative to the center of the frame var hotspot = f.Offset.ToInt2() - kv.Value.Hotspot - new int2(f.Size) / 2; // SheetBuilder expects data in BGRA var data = FrameToBGRA(kv.Key, f, palette); c.Sprites[c.Length++] = sheetBuilder.Add(data, f.Size, 0, hotspot); // Bounds relative to the hotspot c.Bounds = Rectangle.Union(c.Bounds, new Rectangle(hotspot, f.Size)); } // Pad bottom-right edge to make the frame size a multiple of 8 c.PaddedSize = 8 * new int2((c.Bounds.Width + 7) / 8, (c.Bounds.Height + 7) / 8); cursors.Add(kv.Key, c); } CreateOrUpdateHardwareCursors(); foreach (var s in sheetBuilder.AllSheets) { s.ReleaseBuffer(); } Update(); }
public void InitializeFonts(Manifest m) { using (new Support.PerfTimer("SpriteFonts")) { if (fontSheetBuilder != null) { fontSheetBuilder.Dispose(); } fontSheetBuilder = new SheetBuilder(SheetType.BGRA); Fonts = m.Fonts.ToDictionary(x => x.Key, x => new SpriteFont(Platform.ResolvePath(x.Value.First), x.Value.Second, fontSheetBuilder)).AsReadOnly(); } }
/// <summary> /// Returns the first set of sprites with the given filename. /// If getUsedFrames is defined then the indices returned by the function call /// are guaranteed to be loaded. The value of other indices in the returned /// array are undefined and should never be accessed. /// </summary> public Sprite[] this[string filename, Func <int, IEnumerable <int> > getUsedFrames = null] { get { var allSprites = sprites.GetOrAdd(filename); var sprite = allSprites.FirstOrDefault(); if (!unloadedFrames.TryGetValue(filename, out var unloaded)) { unloaded = null; } // This is the first time that the file has been requested // Load all of the frames into the unused buffer and initialize // the loaded cache (initially empty) if (sprite == null) { unloaded = FrameLoader.GetFrames(fileSystem, filename, loaders, out var fileMetadata); unloadedFrames[filename] = unloaded; metadata[filename] = fileMetadata; sprite = new Sprite[unloaded.Length]; allSprites.Add(sprite); } // HACK: The sequence code relies on side-effects from getUsedFrames var indices = getUsedFrames != null?getUsedFrames(sprite.Length) : Enumerable.Range(0, sprite.Length); // Load any unused frames into the SheetBuilder if (unloaded != null) { foreach (var i in indices) { if (unloaded[i] != null) { sprite[i] = SheetBuilders[SheetBuilder.FrameTypeToSheetType(unloaded[i].Type)].Add(unloaded[i]); unloaded[i] = null; } } // All frames have been loaded if (unloaded.All(f => f == null)) { unloadedFrames.Remove(filename); } } return(sprite); } }
SheetBuilder CreateSheetBuilder() { var allocated = false; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException(""); } allocated = true; return(SheetBuilder.AllocateSheet()); }; return(new SheetBuilder(SheetType.DualIndexed, allocate)); }
public ModData( params string[] mods ) { Manifest = new Manifest( mods ); ObjectCreator = new ObjectCreator( Manifest ); LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen); LoadScreen.Init(); LoadScreen.Display(); FileSystem.LoadFromManifest( Manifest ); ChromeProvider.Initialize( Manifest.Chrome ); SheetBuilder = new SheetBuilder( TextureChannel.Red ); CursorSheetBuilder = new CursorSheetBuilder( this ); AvailableMaps = FindMaps( mods ); WidgetLoader = new WidgetLoader( this ); }
static SheetBuilder CreateSheetBuilder() { var allocated = false; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException(""); } allocated = true; return(SheetBuilder.AllocateSheet(SheetType.Indexed, Game.Settings.Graphics.SheetSize)); }; return(new SheetBuilder(SheetType.Indexed, allocate)); }
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 SpriteFont(string name, int size) { this.size = size; if (0 != FT.FT_New_Face(library, name, 0, out face)) throw new InvalidOperationException("FT_New_Face failed"); FT.FT_Set_Pixel_Sizes(face, 0, (uint)size); glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph); // setup a 1-channel SheetBuilder for our private use if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha); PrecacheColor(Color.White); PrecacheColor(Color.Red); }
public SpriteFont(string name, int size) { this.size = size; face = library.NewFace(name, 0); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char,Color>.EqualityComparer); // setup a 1-channel SheetBuilder for our private use if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha); PrecacheColor(Color.White); PrecacheColor(Color.Red); }
public SpriteFont(string name, int size) { this.size = size; face = library.NewFace(name, 0); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char,Color>.EqualityComparer); // setup a SheetBuilder for our private use // TODO: SheetBuilder state is leaked between mod switches if (builder == null) builder = new SheetBuilder(SheetType.BGRA); PrecacheColor(Color.White); PrecacheColor(Color.Red); }
public SpriteFont(Renderer r, string name, int size) { this.size = size; if (0 != FT.FT_New_Face(library, name, 0, out face)) throw new InvalidOperationException("FT_New_Face failed"); FT.FT_Set_Pixel_Sizes(face, 0, (uint)size); glyphs = new Cache<char, GlyphInfo>(CreateGlyph); // setup a 1-channel SheetBuilder for our private use if (builder == null) builder = new SheetBuilder(r, TextureChannel.Alpha); // precache glyphs for U+0020 - U+007f for (var n = (char)0x20; n < (char)0x7f; n++) if (glyphs[n] == null) throw new InvalidOperationException(); }
public ModData( params string[] mods ) { Manifest = new Manifest( mods ); ObjectCreator = new ObjectCreator( Manifest ); LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen); LoadScreen.Init(); LoadScreen.Display(); // all this manipulation of static crap here is nasty and breaks // horribly when you use ModData in unexpected ways. FileSystem.LoadFromManifest( Manifest ); ChromeProvider.Initialize( Manifest.Chrome ); SheetBuilder = new SheetBuilder( TextureChannel.Red ); CursorSheetBuilder = new CursorSheetBuilder( this ); AvailableMaps = FindMaps( mods ); WidgetLoader = new WidgetLoader( this ); }
public SpriteFont(string name, int size, SheetBuilder builder) { if (builder.Type != SheetType.BGRA) throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); this.size = size; this.builder = builder; face = new Face(Library, name); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache<Pair<char, Color>, GlyphInfo>(CreateGlyph, Pair<char, Color>.EqualityComparer); Func<char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; lineWidth = line => line.Sum(characterWidth); PrecacheColor(Color.White, name); PrecacheColor(Color.Red, name); }
public SpriteFont(string name, int size) { this.size = size; face = library.NewFace(name, 0); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); // setup a 1-channel SheetBuilder for our private use if (builder == null) { builder = new SheetBuilder(TextureChannel.Alpha); } PrecacheColor(Color.White); PrecacheColor(Color.Red); }
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 void EndFrame() { if (!isInFrame) { throw new InvalidOperationException("BeginFrame has not been called. There is no frame to end."); } isInFrame = false; sheetBuilderForFrame = null; if (doRender.Count == 0) { return; } Sheet currentSheet = null; IFrameBuffer fbo = null; foreach (var v in doRender) { // Change sheet if (v.First != currentSheet) { if (fbo != null) { DisableFrameBuffer(fbo); } currentSheet = v.First; fbo = EnableFrameBuffer(currentSheet); } v.Second(); } if (fbo != null) { DisableFrameBuffer(fbo); } doRender.Clear(); }
public SpriteFont(string name, int size) { this.size = size; face = library.NewFace(name, 0); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); // setup a SheetBuilder for our private use // TODO: SheetBuilder state is leaked between mod switches if (builder == null) { builder = new SheetBuilder(SheetType.BGRA); } PrecacheColor(Color.White); PrecacheColor(Color.Red); }
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)); }; var sourceCache = new Dictionary<string, ISpriteSource>(); templates = new Dictionary<ushort, Sprite[]>(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates) templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames)); // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); }
public SoftwareCursor(CursorProvider cursorProvider) { this.cursorProvider = cursorProvider; paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference); foreach (var p in cursorProvider.Palettes) palette.AddPalette(p.Key, p.Value, false); palette.Initialize(); sheetBuilder = new SheetBuilder(SheetType.Indexed); foreach (var kv in cursorProvider.Cursors) { var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray(); sprites.Add(kv.Key, s); } sheetBuilder.Current.ReleaseBuffer(); Game.Renderer.Device.SetHardwareCursor(null); }
public SpriteFont(string name, int size, SheetBuilder builder) { if (builder.Type != SheetType.BGRA) { throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); } this.size = size; this.builder = builder; face = new Face(Library, name); face.SetPixelSizes((uint)size, (uint)size); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); Func <char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance; lineWidth = line => line.Sum(characterWidth); PrecacheColor(Color.White, name); PrecacheColor(Color.Red, name); }
public SpriteFont(string name, int size) { this.size = size; if (0 != FT.FT_New_Face(library, name, 0, out face)) { throw new InvalidOperationException("FT_New_Face failed"); } FT.FT_Set_Pixel_Sizes(face, 0, (uint)size); glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph, Pair <char, Color> .EqualityComparer); // setup a 1-channel SheetBuilder for our private use if (builder == null) { builder = new SheetBuilder(TextureChannel.Alpha); } PrecacheColor(Color.White); PrecacheColor(Color.Red); }
public SoftwareCursor(CursorProvider cursorProvider) { this.cursorProvider = cursorProvider; paletteReferences = new Cache <string, PaletteReference>(CreatePaletteReference); foreach (var p in cursorProvider.Palettes) { palette.AddPalette(p.Key, p.Value, false); } palette.Initialize(); sheetBuilder = new SheetBuilder(SheetType.Indexed); foreach (var kv in cursorProvider.Cursors) { var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray(); sprites.Add(kv.Key, s); } sheetBuilder.Current.ReleaseBuffer(); Game.Renderer.Window.SetHardwareCursor(null); }
public VoxelRenderData GenerateRenderData(VxlLimb l) { Vertex[] v; try { v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray(); } catch (SheetOverflowException) { // Sheet overflow - allocate a new sheet and try once more Log.Write("debug", "Voxel sheet overflow! Generating new sheet"); sheetBuilder = CreateSheetBuilder(); v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray(); } vertices.Add(v); var start = totalVertexCount; var count = v.Length; totalVertexCount += count; return(new VoxelRenderData(start, count, sheetBuilder.Current)); }
public void EndFrame() { sheetBuilderForFrame = null; if (doRender.Count == 0) { return; } Sheet currentSheet = null; IFrameBuffer fbo = null; foreach (var v in doRender) { // Change sheet if (v.First != currentSheet) { if (fbo != null) { DisableFrameBuffer(fbo); } currentSheet = v.First; fbo = EnableFrameBuffer(currentSheet); } v.Second(); } if (fbo != null) { DisableFrameBuffer(fbo); } doRender.Clear(); }
public VoxelRenderData GenerateRenderData(VxlLimb l) { Vertex[] v; try { v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray(); } catch (SheetOverflowException) { // Sheet overflow - allocate a new sheet and try once more Log.Write("debug", "Voxel sheet overflow! Generating new sheet"); sheetBuilder = CreateSheetBuilder(); v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray(); } vertices.Add(v); var start = totalVertexCount; var count = v.Length; totalVertexCount += count; return new VoxelRenderData(start, count, sheetBuilder.Current); }
public Map PrepareMap(string uid) { LoadScreen.Display(); if (!AvailableMaps.ContainsKey(uid)) throw new InvalidDataException("Invalid map uid: {0}".F(uid)); var map = new Map(AvailableMaps[uid].Path); // unload the previous map mount if we have one if (previousMapMount != null) FileSystem.Unmount(previousMapMount); // Adds the map its container to the FileSystem // allowing the map to use custom assets // Container should have the lowest priority of all (ie int max) // Store a reference so we can unload it next time previousMapMount = FileSystem.OpenPackage(map.Path, int.MaxValue); FileSystem.Mount(previousMapMount); Rules.LoadRules(Manifest, map); if (map.Tileset != cachedTileset || previousMapHadSequences || map.Sequences.Count > 0) { SheetBuilder = new SheetBuilder( TextureChannel.Red ); SpriteSheetBuilder.Initialize( Rules.TileSets[map.Tileset] ); CursorSheetBuilder = new CursorSheetBuilder( this ); CursorProvider.Initialize(Manifest.Cursors); SequenceProvider.Initialize(Manifest.Sequences, map.Sequences); cachedTileset = map.Tileset; } previousMapHadSequences = map.Sequences.Count > 0; return map; }
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; sprites = new Cache<string, Sprite[]>(filename => SpriteLoader.GetSprites(fileSystem, filename, loaders, sheetBuilder)); }
public static void Initialize(Renderer r) { SharedInstance = new SheetBuilder(r, TextureChannel.Red); }
public SpriteCache(ISpriteLoader[] loaders, string[] exts, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; // Include extension-less version exts = exts.Append("").ToArray(); sprites = new Cache<string, Sprite[]>(filename => SpriteLoader.GetSprites(filename, exts, loaders, sheetBuilder)); }
public static Sprite[] GetSprites(string filename, string[] exts, ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { return GetFrames(filename, exts, loaders).Select(a => sheetBuilder.Add(a)).ToArray(); }
public static Sprite[] GetSprites(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { return GetFrames(fileSystem, filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray(); }
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; this.fileSystem = fileSystem; this.loaders = loaders; }
public ModBrowserLogic(Widget widget) { modChooserPanel = widget; loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == Game.ModData.Manifest.Mod.Id; modChooserPanel.Get<ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = modChooserPanel.Get("MOD_LIST"); modTemplate = modList.Get<ButtonWidget>("MOD_TEMPLATE"); modChooserPanel.Get<LabelWidget>("MOD_DESC").GetText = () => selectedDescription; modChooserPanel.Get<LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title; modChooserPanel.Get<LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; modChooserPanel.Get<LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version; var prevMod = modChooserPanel.Get<ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = modChooserPanel.Get<ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; modChooserPanel.Get<RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return ret; }; sheetBuilder = new SheetBuilder(SheetType.BGRA); allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden) .OrderBy(m => m.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"))) if (preview.Width == 296 && preview.Height == 196) previews.Add(mod.Id, sheetBuilder.Add(preview)); } catch (Exception) { } try { using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"))) if (logo.Width == 96 && logo.Height == 96) logos.Add(mod.Id, sheetBuilder.Add(logo)); } catch (Exception) { } } modInstallStatus = new Cache<ModMetadata, bool>(IsModInstalled); ModMetadata initialMod; ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]); RebuildModList(); }
public void InitializeLoaders() { // all this manipulation of static crap here is nasty and breaks // horribly when you use ModData in unexpected ways. ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeProvider.Initialize(Manifest.Chrome); SheetBuilder = new SheetBuilder(SheetType.Indexed); SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder); VoxelLoader = new VoxelLoader(); CursorProvider.Initialize(Manifest.Cursors); }
public static Sprite[] GetSprites(string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { return(GetFrames(filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray()); }
public SpriteCache(ISpriteLoader[] loaders, SheetBuilder sheetBuilder) { SheetBuilder = sheetBuilder; sprites = new Cache <string, Sprite[]>(filename => SpriteLoader.GetSprites(filename, loaders, sheetBuilder)); }
public SpriteLoader( string[] exts, SheetBuilder sheetBuilder ) { SheetBuilder = sheetBuilder; this.exts = exts; sprites = new Cache<string, Sprite[]>( LoadSprites ); }
public void LoadInitialAssets() { // all this manipulation of static crap here is nasty and breaks // horribly when you use ModData in unexpected ways. FileSystem.UnmountAll(); foreach (var dir in Manifest.Folders) FileSystem.Mount(dir); AvailableMaps = FindMaps(Manifest.Mods); ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeProvider.Initialize(Manifest.Chrome); SheetBuilder = new SheetBuilder(TextureChannel.Red); SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder); CursorProvider.Initialize(Manifest.Cursors); }
public ModBrowserLogic(Widget widget) { var panel = widget; var loadButton = panel.Get<ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == Game.modData.Manifest.Mod.Id; panel.Get<ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = panel.Get("MOD_LIST"); modTemplate = modList.Get<ButtonWidget>("MOD_TEMPLATE"); panel.Get<LabelWidget>("MOD_DESC").GetText = () => selectedDescription; panel.Get<LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title; panel.Get<LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; panel.Get<LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version; var prevMod = panel.Get<ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = panel.Get<ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; panel.Get<RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return ret; }; var sheetBuilder = new SheetBuilder(SheetType.BGRA); previews = new Dictionary<string, Sprite>(); logos = new Dictionary<string, Sprite>(); allMods = ModMetadata.AllMods.Values.Where(m => m.Id != "modchooser") .OrderBy(m => m.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { var preview = new Bitmap(new[] { "mods", mod.Id, "preview.png" }.Aggregate(Path.Combine)); if (preview.Width != 296 || preview.Height != 196) continue; previews.Add(mod.Id, sheetBuilder.Add(preview)); } catch (Exception) { } try { var logo = new Bitmap(new[] { "mods", mod.Id, "logo.png" }.Aggregate(Path.Combine)); if (logo.Width != 96 || logo.Height != 96) continue; logos.Add(mod.Id, sheetBuilder.Add(logo)); } catch (Exception) { } } ModMetadata initialMod = null; ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod ?? ModMetadata.AllMods["ra"]); RebuildModList(); }
public ModelRenderProxy RenderAsync( WorldRenderer wr, IEnumerable <ModelAnimation> models, WRot camera, float scale, float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { if (!isInFrame) { throw new InvalidOperationException("BeginFrame has not been called. You cannot render until a frame has been started."); } // Correct for inverted y-axis var scaleTransform = Util.ScaleMatrix(scale, scale, scale); // Correct for bogus light source definition var lightYaw = Util.MakeFloatMatrix(new WRot(WAngle.Zero, WAngle.Zero, -lightSource.Yaw).AsMatrix()); var lightPitch = Util.MakeFloatMatrix(new WRot(WAngle.Zero, -lightSource.Pitch, WAngle.Zero).AsMatrix()); var shadowTransform = Util.MatrixMultiply(lightPitch, lightYaw); var invShadowTransform = Util.MatrixInverse(shadowTransform); var cameraTransform = Util.MakeFloatMatrix(camera.AsMatrix()); var invCameraTransform = Util.MatrixInverse(cameraTransform); if (invCameraTransform == null) { throw new InvalidOperationException("Failed to invert the cameraTransform matrix during RenderAsync."); } // Sprite rectangle var tl = new float2(float.MaxValue, float.MaxValue); var br = new float2(float.MinValue, float.MinValue); // Shadow sprite rectangle var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(float.MinValue, float.MinValue); foreach (var m in models) { // Convert screen offset back to world coords var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var bounds = m.Model.Bounds(m.FrameFunc()); var worldBounds = Util.MatrixAABBMultiply(worldTransform, bounds); var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds); var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds); // Aggregate bounds rects tl = float2.Min(tl, new float2(screenBounds[0], screenBounds[1])); br = float2.Max(br, new float2(screenBounds[3], screenBounds[4])); stl = float2.Min(stl, new float2(shadowBounds[0], shadowBounds[1])); sbr = float2.Max(sbr, new float2(shadowBounds[3], shadowBounds[4])); } // Inflate rects to ensure rendering is within bounds tl -= SpritePadding; br += SpritePadding; stl -= SpritePadding; sbr += SpritePadding; // Corners of the shadow quad, in shadow-space var corners = new float[][] { new[] { stl.X, stl.Y, 0, 1 }, new[] { sbr.X, sbr.Y, 0, 1 }, new[] { sbr.X, stl.Y, 0, 1 }, new[] { stl.X, sbr.Y, 0, 1 } }; var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform); var shadowGroundNormal = Util.MatrixVectorMultiply(shadowTransform, groundNormal); var screenCorners = new float3[4]; for (var j = 0; j < 4; j++) { // Project to ground plane corners[j][2] = -(corners[j][1] * shadowGroundNormal[1] / shadowGroundNormal[2] + corners[j][0] * shadowGroundNormal[0] / shadowGroundNormal[2]); // Rotate to camera-space corners[j] = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]); screenCorners[j] = new float3(corners[j][0], corners[j][1], 0); } // Shadows are rendered at twice the resolution to reduce artifacts Size spriteSize, shadowSpriteSize; int2 spriteOffset, shadowSpriteOffset; CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset); CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset); if (sheetBuilderForFrame == null) { sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet); } var sprite = sheetBuilderForFrame.Allocate(spriteSize, 0, spriteOffset); var shadowSprite = sheetBuilderForFrame.Allocate(shadowSpriteSize, 0, shadowSpriteOffset); var sb = sprite.Bounds; var ssb = shadowSprite.Bounds; var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2); var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx); var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx); doRender.Add(Pair.New <Sheet, Action>(sprite.Sheet, () => { foreach (var m in models) { // Convert screen offset to world offset var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); var transform = Util.MatrixMultiply(cameraTransform, worldTransform); transform = Util.MatrixMultiply(correctionTransform, transform); var shadow = Util.MatrixMultiply(shadowTransform, worldTransform); shadow = Util.MatrixMultiply(shadowCorrectionTransform, shadow); var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(rotations), invShadowTransform); var frame = m.FrameFunc(); for (uint i = 0; i < m.Model.Sections; i++) { var rd = m.Model.RenderData(i); var t = m.Model.TransformationMatrix(i, frame); var it = Util.MatrixInverse(t); if (it == null) { throw new InvalidOperationException("Failed to invert the transformed matrix of frame {0} during RenderAsync.".F(i)); } // Transform light vector from shadow -> world -> limb coords var lightDirection = ExtractRotationVector(Util.MatrixMultiply(it, lightTransform)); Render(rd, wr.World.ModelCache, Util.MatrixMultiply(transform, t), lightDirection, lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex); // Disable shadow normals by forcing zero diffuse and identity ambient light if (m.ShowShadow) { Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection, ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex); } } } })); var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); return(new ModelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1])); }
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(); }