Beispiel #1
0
        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;
        }
Beispiel #2
0
        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;
        }
Beispiel #3
0
        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();
        }
Beispiel #4
0
        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();
        }
Beispiel #5
0
        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);
            }
        }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        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();
        }
Beispiel #8
0
        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();
        }
Beispiel #9
0
 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));
 }
Beispiel #10
0
        public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
        {
            SheetBuilder = sheetBuilder;

            // Include extension-less version
            this.exts = exts.Append("").ToArray();
            sprites   = new Cache <string, Sprite[]>(CacheSpriteFrames);
        }
Beispiel #11
0
		public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
		{
			SheetBuilder = sheetBuilder;

			// Include extension-less version
			this.exts = exts.Append("").ToArray();
			sprites = new Cache<string, Sprite[]>(CacheSpriteFrames);
		}
Beispiel #12
0
        public VoxelLoader()
        {
            voxels = new Cache<Pair<string,string>, Voxel>(LoadFile);
            vertices = new List<Vertex[]>();
            totalVertexCount = 0;
            cachedVertexCount = 0;

            sheetBuilder = CreateSheetBuilder();
        }
Beispiel #13
0
        public void BeginFrame()
        {
            foreach (var kv in mappedBuffers)
                unmappedBuffers.Push(kv);
            mappedBuffers.Clear();

            sheetBuilder = new SheetBuilder(SheetType.BGRA, AllocateSheet);
            doRender.Clear();
        }
Beispiel #14
0
        public VoxelLoader()
        {
            voxels            = new Cache <Pair <string, string>, Voxel>(LoadFile);
            vertices          = new List <Vertex[]>();
            totalVertexCount  = 0;
            cachedVertexCount = 0;

            sheetBuilder = CreateSheetBuilder();
        }
Beispiel #15
0
        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();
        }
Beispiel #16
0
        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();
        }
Beispiel #17
0
        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();
        }
Beispiel #18
0
		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();
		}
Beispiel #19
0
        public void BeginFrame()
        {
            foreach (var kv in mappedBuffers)
            {
                unmappedBuffers.Push(kv);
            }
            mappedBuffers.Clear();

            sheetBuilder = new SheetBuilder(SheetType.BGRA, AllocateSheet);
            doRender.Clear();
        }
Beispiel #20
0
        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();
        }
Beispiel #21
0
 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();
     }
 }
Beispiel #22
0
        /// <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);
            }
        }
Beispiel #23
0
        SheetBuilder CreateSheetBuilder()
        {
            var          allocated = false;
            Func <Sheet> allocate  = () =>
            {
                if (allocated)
                {
                    throw new SheetOverflowException("");
                }
                allocated = true;
                return(SheetBuilder.AllocateSheet());
            };

            return(new SheetBuilder(SheetType.DualIndexed, allocate));
        }
Beispiel #24
0
        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 );
        }
Beispiel #25
0
        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));
        }
Beispiel #26
0
        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();
        }
Beispiel #27
0
        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);
        }
Beispiel #28
0
        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);
        }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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();
        }
Beispiel #31
0
        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 );
        }
Beispiel #32
0
        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);
        }
Beispiel #33
0
        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);
        }
Beispiel #34
0
        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();
        }
Beispiel #36
0
        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);
        }
Beispiel #37
0
        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));
        }
Beispiel #38
0
        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);
        }
Beispiel #39
0
        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);
        }
Beispiel #40
0
        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);
        }
Beispiel #41
0
        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);
        }
Beispiel #42
0
        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));
        }
Beispiel #43
0
        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();
        }
Beispiel #44
0
        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);
        }
Beispiel #45
0
        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;
        }
Beispiel #46
0
        public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
        {
            SheetBuilder = sheetBuilder;

            sprites = new Cache<string, Sprite[]>(filename => SpriteLoader.GetSprites(fileSystem, filename, loaders, sheetBuilder));
        }
Beispiel #47
0
 public static void Initialize(Renderer r)
 {
     SharedInstance = new SheetBuilder(r, TextureChannel.Red);
 }
Beispiel #48
0
 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));
 }
Beispiel #49
0
 public static Sprite[] GetSprites(string filename, string[] exts, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     return GetFrames(filename, exts, loaders).Select(a => sheetBuilder.Add(a)).ToArray();
 }
Beispiel #50
0
 public static Sprite[] GetSprites(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     return GetFrames(fileSystem, filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray();
 }
Beispiel #51
0
 public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     SheetBuilder = sheetBuilder;
     this.fileSystem = fileSystem;
     this.loaders = loaders;
 }
Beispiel #52
0
		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();
		}
Beispiel #53
0
 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);
 }
Beispiel #54
0
 public static Sprite[] GetSprites(string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     return(GetFrames(filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray());
 }
Beispiel #55
0
        public SpriteCache(ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
        {
            SheetBuilder = sheetBuilder;

            sprites = new Cache <string, Sprite[]>(filename => SpriteLoader.GetSprites(filename, loaders, sheetBuilder));
        }
Beispiel #56
0
 public SpriteLoader( string[] exts, SheetBuilder sheetBuilder )
 {
     SheetBuilder = sheetBuilder;
     this.exts = exts;
     sprites = new Cache<string, Sprite[]>( LoadSprites );
 }
Beispiel #57
0
        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);
        }
Beispiel #58
0
        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]));
        }
Beispiel #60
0
        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();
        }