public void AddPalette(string name, ImmutablePalette p, bool allowModifiers) { if (palettes.ContainsKey(name)) { throw new InvalidOperationException($"Palette {name} has already been defined"); } // PERF: the first row in the palette textures is reserved as a placeholder for non-indexed sprites // that do not have a color-shift applied. This provides a quick shortcut to avoid querying the // color-shift texture for every pixel only to find that most are not shifted. var index = palettes.Count + 1; indices.Add(name, index); palettes.Add(name, p); if (index >= Height) { Height = Exts.NextPowerOf2(index + 1); Array.Resize(ref buffer, Height * Palette.Size * 4); Array.Resize(ref colorShiftBuffer, Height * 4); } if (allowModifiers) { mutablePalettes.Add(name, new MutablePalette(p)); } else { CopyPaletteToBuffer(index, p); } }
public static Bitmap ActorsBitmap(World world) { var map = world.Map; var b = map.Bounds; var size = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); var bitmap = new Bitmap(size, size); var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { var colors = (int *)bitmapData.Scan0; var stride = bitmapData.Stride / 4; foreach (var t in world.ActorsWithTrait <IRadarSignature>()) { if (!t.Actor.IsInWorld || world.FogObscures(t.Actor)) { continue; } foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) { var uv = cell.First.ToMPos(map); if (b.Contains(uv.U, uv.V)) { colors[(uv.V - b.Top) * stride + uv.U - b.Left] = cell.Second.ToArgb(); } } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
public static Bitmap ActorsBitmap(World world) { var map = world.Map; var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); var bitmap = new Bitmap(size, size); var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { int *c = (int *)bitmapData.Scan0; foreach (var t in world.ActorsWithTrait <IRadarSignature>()) { if (world.FogObscures(t.Actor)) { continue; } var color = t.Trait.RadarSignatureColor(t.Actor); foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) { if (world.Map.IsInMap(cell)) { *(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb(); } } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
public void Open(CpsD2Loader video) { this.image = video; stopped = true; paused = true; //onComplete = () => { }; TypeDictionary metadata; ImmutablePalette cpspalette; using (var stream = Game.ModData.DefaultFileSystem.Open(image.SpriteFilename)) { video.TryParseSpritePlusPalette(stream, out imageSprite, out metadata, out cpspalette); if (cpspalette != null) { LoadPalette(cpspalette, image.SpriteFilename); } } var imwidth = imageSprite[0].FrameSize.Width; var imheight = imageSprite[0].FrameSize.Height; var size = Math.Max(imwidth, imheight); var textureSize = Exts.NextPowerOf2(size); var scale = Math.Min((float)RenderBounds.Width / imwidth, (float)RenderBounds.Height / imheight * AspectRatio); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * imwidth) / 2, RenderBounds.Y + (RenderBounds.Height - scale * imheight * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(imwidth * scale), (int)Math.Ceiling(imheight * AspectRatio * scale)); }
public static Bitmap CustomTerrainBitmap(World world) { var map = world.Map; var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); var bitmap = new Bitmap(size, size); var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { int *c = (int *)bitmapData.Scan0; for (var x = 0; x < map.Bounds.Width; x++) { for (var y = 0; y < map.Bounds.Height; y++) { var mapX = x + map.Bounds.Left; var mapY = y + map.Bounds.Top; var custom = map.CustomTerrain[mapX, mapY]; if (custom == null) { continue; } *(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb(); } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
public void Open(IVideo video) { this.video = video; stopped = true; paused = true; Game.Sound.StopVideo(); onComplete = () => { }; invLength = video.Framerate * 1f / video.Frames; var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); var videoSheet = new Sheet(SheetType.BGRA, new Size(textureSize, textureSize)); videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear; videoSheet.GetTexture().SetData(video.FrameData); videoSprite = new Sprite(videoSheet, new Rectangle( 0, 0, video.Width, video.Height), TextureChannel.RGBA); var scale = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale)); }
public static Bitmap CustomTerrainBitmap(World world) { var map = world.Map; var b = map.Bounds; var size = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); var bitmap = new Bitmap(size, size); var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { var colors = (int *)bitmapData.Scan0; var stride = bitmapData.Stride / 4; for (var y = 0; y < b.Height; y++) { for (var x = 0; x < b.Width; x++) { var mapX = x + b.Left; var mapY = y + b.Top; var custom = map.CustomTerrain[new MPos(mapX, mapY)]; if (custom == byte.MaxValue) { continue; } colors[y * stride + x] = world.TileSet[custom].Color.ToArgb(); } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
private void LoadFrame() { var textData = ""; if (CurrentFrame == 0) { frame = new uint[Height / stride, Width]; palette = new uint[256]; TextData = ""; } else { frame = frames[CurrentFrame - 1].ApplyFrame(frame, ref palette, ref textData); } TextData += textData; // TODO for better performance, we should get rid of this copying as soon we can use non-power-of-2 textures FrameData = new uint[Exts.NextPowerOf2(Height), Exts.NextPowerOf2(Width)]; for (var y = 0; y < Height / stride; y++) { for (var i = 0; i < stride; i++) { Buffer.BlockCopy(frame, y * Width * 4, FrameData, (y * stride + i) * FrameData.GetLength(1) * 4, Width * 4); } } }
public void AddPalette(string name, ImmutablePalette p, bool allowModifiers) { if (palettes.ContainsKey(name)) { throw new InvalidOperationException("Palette {0} has already been defined".F(name)); } int index = palettes.Count; indices.Add(name, index); palettes.Add(name, p); if (palettes.Count > Height) { Height = Exts.NextPowerOf2(palettes.Count); Array.Resize(ref buffer, Height * Palette.Size * 4); } if (allowModifiers) { modifiablePalettes.Add(name, new MutablePalette(p)); } else { CopyPaletteToBuffer(index, p); } }
public void Open(VqaReader video) { this.video = video; stopped = true; paused = true; Game.Sound.StopVideo(); onComplete = () => { }; invLength = video.Framerate * 1f / video.Frames; var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); var videoSheet = new Sheet(SheetType.BGRA, new Size(textureSize, textureSize)); videoSheet.AssignOrGetOrSetDataGLTexture().ScaleFilter = TextureScaleFilter.Linear; videoSheet.AssignOrGetOrSetDataGLTexture().SetData(video.FrameData); videoSprite = new Sprite(videoSheet, new Rectangle( 0, 0, video.Width, video.Height), TextureChannel.RGBA); var scale = Math.Min((float)RenderBounds.Width / video.Width, (float)RenderBounds.Height / video.Height * AspectRatio); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale)); if (!DrawOverlay) { return; } var scaledHeight = (int)videoSize.Y; overlay = new uint[Exts.NextPowerOf2(scaledHeight), 1]; var black = 255U << 24; for (var y = 0; y < scaledHeight; y += 2) { overlay[y, 0] = black; } var overlaySheet = new Sheet(SheetType.BGRA, new Size(1, Exts.NextPowerOf2(scaledHeight))); overlaySheet.AssignOrGetOrSetDataGLTexture().SetData(overlay); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.RGBA); }
public void Load(string filename) { if (filename == cachedVideo) { return; } stopped = true; paused = true; Sound.StopVideo(); onComplete = () => { }; cachedVideo = filename; video = new VqaReader(GlobalFileSystem.Open(filename)); invLength = video.Framerate * 1f / video.Frames; var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); var videoSheet = new Sheet(new Size(textureSize, textureSize), false); videoSheet.Texture.ScaleFilter = TextureScaleFilter.Linear; videoSheet.Texture.SetData(video.FrameData); videoSprite = new Sprite(videoSheet, new Rectangle(0, 0, video.Width, video.Height), TextureChannel.Alpha); var scale = Math.Min(RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * AspectRatio * video.Height) / 2); // Round size to integer pixels. Round up to be consistent with the scale calcuation. videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * scale * AspectRatio)); if (!DrawOverlay) { return; } var scaledHeight = (int)videoSize.Y; overlay = new uint[Exts.NextPowerOf2(scaledHeight), 1]; var black = (uint)255 << 24; for (var y = 0; y < scaledHeight; y += 2) { overlay[y, 0] = black; } var overlaySheet = new Sheet(new Size(1, Exts.NextPowerOf2(scaledHeight)), false); overlaySheet.Texture.SetData(overlay); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha); }
public void Load(string filename) { if (filename == cachedVideo) { return; } stopped = true; paused = true; Sound.StopVideo(); onComplete = () => { }; cachedVideo = filename; video = new VqaReader(GlobalFileSystem.Open(filename)); invLength = video.Framerate * 1f / video.Frames; var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); var videoSheet = new Sheet(new Size(textureSize, textureSize), false); videoSheet.Texture.SetData(video.FrameData); videoSprite = new Sprite(videoSheet, new Rectangle(0, 0, video.Width, video.Height), TextureChannel.Alpha); var scale = Math.Min(RenderBounds.Width / video.Width, RenderBounds.Height / video.Height); videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height) / 2); videoSize = new float2(video.Width * scale, video.Height * scale); if (!DrawOverlay) { return; } overlay = new uint[2 * textureSize, 2 * textureSize]; var black = (uint)255 << 24; for (var y = 0; y < video.Height; y++) { for (var x = 0; x < video.Width; x++) { overlay[2 * y, x] = black; } } var overlaySheet = new Sheet(new Size(2 * textureSize, 2 * textureSize), false); overlaySheet.Texture.SetData(overlay); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, video.Width, 2 * video.Height), TextureChannel.Alpha); }
public void SetSize(int w, int h) { var size = Math.Max(w, h); var textureSize = Exts.NextPowerOf2(size); var scale = Math.Min((float)RenderBounds.Width / w, (float)RenderBounds.Height / h * AspectRatio); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * w) / 2, RenderBounds.Y + (RenderBounds.Height - scale * h * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(w * scale), (int)Math.Ceiling(h * AspectRatio * scale)); }
public static Bitmap ShroudBitmap(World world) { var map = world.Map; var b = map.Bounds; var size = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); var bitmap = new Bitmap(size, size); if (world.RenderPlayer == null) { return(bitmap); } var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var shroud = Color.Black.ToArgb(); var fog = Color.FromArgb(128, Color.Black).ToArgb(); var offset = new CVec(b.Left, b.Top); unsafe { var colors = (int *)bitmapData.Scan0; var stride = bitmapData.Stride / 4; var shroudObscured = world.ShroudObscuresTest(map.Cells); var fogObscured = world.FogObscuresTest(map.Cells); foreach (var cell in map.Cells) { var uv = Map.CellToMap(map.TileShape, cell) - offset; if (shroudObscured(cell)) { colors[uv.Y * stride + uv.X] = shroud; } else if (fogObscured(cell)) { colors[uv.Y * stride + uv.X] = fog; } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
static Sheet SpriteFrameToSheet(ISpriteFrame frame, PaletteReference p) { var size = Exts.NextPowerOf2(Math.Max(frame.FrameSize.Width, frame.FrameSize.Height)); SheetBuilder sheetBuilder = new SheetBuilder(SheetType.BGRA, size); byte[] data; if (frame.Type == SpriteFrameType.Indexed) { data = IndexedSpriteFrameToData(frame, p); } else { data = frame.Data; } var sprite = sheetBuilder.Add(data, frame.FrameSize); return(sprite.Sheet); }
public void SetData(Bitmap bitmap) { if (!IsPowerOf2(bitmap.Width) || !IsPowerOf2(bitmap.Height)) { //throw new InvalidOperationException( "non-power-of-2-texture" ); bitmap = new Bitmap(bitmap, new Size(Exts.NextPowerOf2(bitmap.Width), Exts.NextPowerOf2(bitmap.Height))); } var bits = bitmap.LockBits( new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); PrepareTexture(); Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides ErrorHandler.CheckGlError(); bitmap.UnlockBits(bits); }
public static Bitmap ShroudBitmap(World world) { var map = world.Map; var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); var bitmap = new Bitmap(size, size); if (world.LocalShroud.Disabled) { return(bitmap); } var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var shroud = Color.Black.ToArgb(); var fog = Color.FromArgb(128, Color.Black).ToArgb(); unsafe { int *c = (int *)bitmapData.Scan0; for (var x = 0; x < map.Bounds.Width; x++) { for (var y = 0; y < map.Bounds.Height; y++) { var mapX = x + map.Bounds.Left; var mapY = y + map.Bounds.Top; if (!world.LocalShroud.IsExplored(mapX, mapY)) { *(c + (y * bitmapData.Stride >> 2) + x) = shroud; } else if (!world.LocalShroud.IsVisible(mapX, mapY)) { *(c + (y * bitmapData.Stride >> 2) + x) = fog; } } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
void LoadFrame() { if (currentFrame >= frameCount) { return; } stream.Seek(frameOffsets[currentFrame], SeekOrigin.Begin); var dataLength = frameOffsets[currentFrame + 1] - frameOffsets[currentFrame]; var rawData = StreamExts.ReadBytes(stream, (int)dataLength); var intermediateData = new byte[width * height]; // Format80 decompression LCWCompression.DecodeInto(rawData, intermediateData); // and Format40 decompression currentFrameData = new byte[width * height]; if (previousFrameData == null) { Array.Clear(currentFrameData, 0, currentFrameData.Length); } else { Array.Copy(previousFrameData, currentFrameData, currentFrameData.Length); } XORDeltaCompression.DecodeInto(intermediateData, currentFrameData, 0); var c = 0; var frameSize = Exts.NextPowerOf2(Math.Max(width, height)); coloredFrameData = new uint[frameSize, frameSize]; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { coloredFrameData[y, x] = palette[currentFrameData[c++]]; } } }
public void Open(WsaReader video) { this.video = video; stopped = true; paused = true; onComplete = () => { }; var size = Math.Max(video.Width, video.Height); var textureSize = Exts.NextPowerOf2(size); var scale = Math.Min((float)RenderBounds.Width / video.Width, (float)RenderBounds.Height / video.Height * AspectRatio); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2); // Round size to integer pixels. Round up to be consistent with the scale calculation. videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale)); }
public static Bitmap ShroudBitmap(World world) { var map = world.Map; var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); var bitmap = new Bitmap(size, size); if (world.RenderPlayer == null) { return(bitmap); } var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var shroud = Color.Black.ToArgb(); var fog = Color.FromArgb(128, Color.Black).ToArgb(); unsafe { int *c = (int *)bitmapData.Scan0; for (var x = 0; x < map.Bounds.Width; x++) { for (var y = 0; y < map.Bounds.Height; y++) { var p = new CPos(x + map.Bounds.Left, y + map.Bounds.Top); if (world.ShroudObscures(p)) { *(c + (y * bitmapData.Stride >> 2) + x) = shroud; } else if (world.FogObscures(p)) { *(c + (y * bitmapData.Stride >> 2) + x) = fog; } } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
public static Bitmap TerrainBitmap(Map map, bool actualSize) { var tileset = Rules.TileSets[map.Tileset]; var width = map.Bounds.Width; var height = map.Bounds.Height; if (!actualSize) { width = height = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); } var terrain = new Bitmap(width, height); var bitmapData = terrain.LockBits(terrain.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { int *c = (int *)bitmapData.Scan0; for (var x = 0; x < map.Bounds.Width; x++) { for (var y = 0; y < map.Bounds.Height; y++) { var mapX = x + map.Bounds.Left; var mapY = y + map.Bounds.Top; var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]); if (!tileset.Terrain.ContainsKey(type)) { throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type)); } *(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb(); } } } terrain.UnlockBits(bitmapData); return(terrain); }
public static Bitmap TerrainBitmap(TileSet tileset, Map map, bool actualSize = false) { var b = map.Bounds; var width = b.Width; var height = b.Height; if (!actualSize) { width = height = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); } var terrain = new Bitmap(width, height); var bitmapData = terrain.LockBits(terrain.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var mapTiles = map.MapTiles.Value; unsafe { var colors = (int *)bitmapData.Scan0; var stride = bitmapData.Stride / 4; for (var y = 0; y < b.Height; y++) { for (var x = 0; x < b.Width; x++) { var mapX = x + b.Left; var mapY = y + b.Top; var type = tileset.GetTileInfo(mapTiles[new MPos(mapX, mapY)]); var color = type != null ? type.LeftColor : Color.Black; colors[y * stride + x] = color.ToArgb(); } } } terrain.UnlockBits(bitmapData); return(terrain); }
private void LoadFrame() { if (this.CurrentFrame == 0) { this.currentFrame = new uint[this.Height / this.stride, this.Width]; this.palette = new uint[256]; this.TextData = ""; } else { var nextFrame = this.frames[this.CurrentFrame - 1]; this.currentFrame = nextFrame.ApplyFrame(this.currentFrame, ref this.palette); if (nextFrame.Text != null) { this.TextData += nextFrame.Text; } } // TODO for better performance, we should get rid of this copying as soon we can use non-power-of-2 textures this.FrameData = new uint[Exts.NextPowerOf2(this.Height), Exts.NextPowerOf2(this.Width)]; for (var y = 0; y < this.Height / this.stride; y++) { for (var i = 0; i < this.stride; i++) { Buffer.BlockCopy( this.currentFrame, y * this.Width * 4, this.FrameData, (y * this.stride + i) * this.FrameData.GetLength(1) * 4, this.Width * 4 ); } } }
public static Bitmap ActorsBitmap(World world) { var map = world.Map; var b = map.Bounds; var size = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); var bitmap = new Bitmap(size, size); var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); unsafe { var c = (int *)bitmapData.Scan0; foreach (var t in world.ActorsWithTrait <IRadarSignature>()) { if (world.FogObscures(t.Actor)) { continue; } var color = t.Trait.RadarSignatureColor(t.Actor); foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) { var uv = Map.CellToMap(map.TileShape, cell); if (b.Contains(uv.X, uv.Y)) { *(c + ((uv.Y - b.Top) * bitmapData.Stride >> 2) + uv.X - b.Left) = color.ToArgb(); } } } } bitmap.UnlockBits(bitmapData); return(bitmap); }
public static Bitmap TerrainBitmap(TileSet tileset, Map map, bool actualSize = false) { var isRectangularIsometric = map.Grid.Type == MapGridType.RectangularIsometric; var b = map.Bounds; // Fudge the heightmap offset by adding as much extra as we need / can. // This tries to correct for our incorrect assumption that MPos == PPos var heightOffset = Math.Min(map.Grid.MaximumTerrainHeight, map.MapSize.Y - b.Bottom); var width = b.Width; var height = b.Height + heightOffset; var bitmapWidth = width; if (isRectangularIsometric) { bitmapWidth = 2 * bitmapWidth - 1; } if (!actualSize) { bitmapWidth = height = Exts.NextPowerOf2(Math.Max(bitmapWidth, height)); } var terrain = new Bitmap(bitmapWidth, height); var bitmapData = terrain.LockBits(terrain.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var mapTiles = map.MapTiles.Value; unsafe { var colors = (int *)bitmapData.Scan0; var stride = bitmapData.Stride / 4; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var uv = new MPos(x + b.Left, y + b.Top); var type = tileset.GetTileInfo(mapTiles[uv]); var leftColor = type != null ? type.LeftColor : Color.Black; if (isRectangularIsometric) { // Odd rows are shifted right by 1px var dx = uv.V & 1; var rightColor = type != null ? type.RightColor : Color.Black; if (x + dx > 0) { colors[y * stride + 2 * x + dx - 1] = leftColor.ToArgb(); } if (2 * x + dx < stride) { colors[y * stride + 2 * x + dx] = rightColor.ToArgb(); } } else { colors[y * stride + x] = leftColor.ToArgb(); } } } } terrain.UnlockBits(bitmapData); return(terrain); }
public VqaReader(Stream stream) { this.stream = stream; // Decode FORM chunk if (stream.ReadASCII(4) != "FORM") { throw new InvalidDataException("Invalid vqa (invalid FORM section)"); } /*var length = */ stream.ReadUInt32(); if (stream.ReadASCII(8) != "WVQAVQHD") { throw new InvalidDataException("Invalid vqa (not WVQAVQHD)"); } /*var length2 = */ stream.ReadUInt32(); /*var version = */ stream.ReadUInt16(); videoFlags = stream.ReadUInt16(); Frames = stream.ReadUInt16(); Width = stream.ReadUInt16(); Height = stream.ReadUInt16(); blockWidth = stream.ReadUInt8(); blockHeight = stream.ReadUInt8(); Framerate = stream.ReadUInt8(); chunkBufferParts = stream.ReadUInt8(); blocks = new int2(Width / blockWidth, Height / blockHeight); numColors = stream.ReadUInt16(); /*var maxBlocks = */ stream.ReadUInt16(); /*var unknown1 = */ stream.ReadUInt16(); /*var unknown2 = */ stream.ReadUInt32(); // Audio sampleRate = stream.ReadUInt16(); audioChannels = stream.ReadByte(); sampleBits = stream.ReadByte(); /*var unknown3 =*/ stream.ReadUInt32(); /*var unknown4 =*/ stream.ReadUInt16(); /*maxCbfzSize =*/ stream.ReadUInt32(); // Unreliable /*var unknown5 =*/ stream.ReadUInt32(); var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height)); if (IsHqVqa) { cbfBuffer = new byte[maxCbfzSize]; cbf = new byte[maxCbfzSize * 3]; origData = new byte[maxCbfzSize]; } else { cbfBuffer = new byte[Width * Height]; cbf = new byte[Width * Height]; cbp = new byte[Width * Height]; origData = new byte[2 * blocks.X * blocks.Y]; } palette = new uint[numColors]; frameData = new uint[frameSize, frameSize]; var type = stream.ReadASCII(4); while (type != "FINF") { // Sub type is a file tag if (type[3] == 'F') { var jmp = int2.Swap(stream.ReadUInt32()); stream.Seek(jmp, SeekOrigin.Current); type = stream.ReadASCII(4); } else { throw new NotSupportedException("Vqa uses unknown Subtype: {0}".F(type)); } } /*var length = */ stream.ReadUInt16(); /*var unknown4 = */ stream.ReadUInt16(); // Frame offsets offsets = new uint[Frames]; for (var i = 0; i < Frames; i++) { offsets[i] = stream.ReadUInt32(); if (offsets[i] > 0x40000000) { offsets[i] -= 0x40000000; } offsets[i] <<= 1; } CollectAudioData(); Reset(); }
public WsaVideo(Stream stream, bool useFramePadding) { this.stream = stream; FrameCount = stream.ReadUInt16(); /*var x = */ stream.ReadUInt16(); /*var y = */ stream.ReadUInt16(); Width = stream.ReadUInt16(); Height = stream.ReadUInt16(); var delta = stream.ReadUInt16() + 37; var flags = stream.ReadUInt16(); frameOffsets = new uint[FrameCount + 2]; for (var i = 0; i < frameOffsets.Length; i++) { frameOffsets[i] = stream.ReadUInt32(); } if (flags == 1) { paletteBytes = new byte[1024]; for (var i = 0; i < paletteBytes.Length;) { var r = (byte)(stream.ReadByte() << 2); var g = (byte)(stream.ReadByte() << 2); var b = (byte)(stream.ReadByte() << 2); // Replicate high bits into the (currently zero) low bits. r |= (byte)(r >> 6); g |= (byte)(g >> 6); b |= (byte)(b >> 6); paletteBytes[i++] = b; paletteBytes[i++] = g; paletteBytes[i++] = r; paletteBytes[i++] = 255; } for (var i = 0; i < frameOffsets.Length; i++) { frameOffsets[i] += 768; } } if (useFramePadding) { var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height)); CurrentFrameData = new byte[frameSize * frameSize * 4]; totalFrameWidth = (ushort)frameSize; } else { CurrentFrameData = new byte[Width * Height * 4]; totalFrameWidth = Width; } Reset(); }
public override void Draw() { if (video == null) { return; } if (!stopped && !paused) { var nextFrame = 0; if (video.HasAudio && !Game.Sound.DummyEngine) { nextFrame = (int)float2.Lerp(0, video.Frames, Game.Sound.VideoSeekPosition * invLength); } else { nextFrame = video.CurrentFrame + 1; } // Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame if (nextFrame > video.Frames || nextFrame < video.CurrentFrame) { Stop(); return; } var skippedFrames = 0; while (nextFrame > video.CurrentFrame) { video.AdvanceFrame(); videoSprite.Sheet.GetTexture().SetData(video.FrameData); skippedFrames++; } if (skippedFrames > 1) { Log.Write("perf", "VqaPlayer : {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrame); } } WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize); if (DrawOverlay) { // Create the scan line grid to render over the video // To avoid aliasing, this must be an integer number of screen pixels. // A few complications to be aware of: // - The video may have a different aspect ratio to the widget RenderBounds // - The RenderBounds coordinates may be a non-integer scale of the screen pixel size // - The screen pixel size may change while the video is playing back // (user moves a window between displays with different DPI on macOS) var scale = Game.Renderer.WindowScale; if (overlaySheet == null || overlayScale != scale) { overlaySheet?.Dispose(); // Calculate the scan line height by converting the video scale (copied from Open()) to screen // pixels, halving it (scan lines cover half the pixel height), and rounding to the nearest integer. var videoScale = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); var halfRowHeight = (int)(videoScale * scale / 2 + 0.5f); // The overlay can be minimally stored in a 1px column which is stretched to cover the full screen var overlayHeight = (int)(RenderBounds.Height * scale / halfRowHeight); var overlaySheetSize = new Size(1, Exts.NextPowerOf2(overlayHeight)); var overlay = new byte[4 * Exts.NextPowerOf2(overlayHeight)]; overlaySheet = new Sheet(SheetType.BGRA, overlaySheetSize); // Every second pixel is the scan line - set alpha to 128 to make the lines less harsh for (var i = 3; i < 4 * overlayHeight; i += 8) { overlay[i] = 128; } overlaySheet.GetTexture().SetData(overlay, overlaySheetSize.Width, overlaySheetSize.Height); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, overlayHeight), TextureChannel.RGBA); // Overlay origin must be rounded to the nearest screen pixel to prevent aliasing overlayOrigin = new float2((int)(RenderBounds.X * scale + 0.5f), (int)(RenderBounds.Y * scale + 0.5f)) / scale; overlaySize = new float2(RenderBounds.Width, overlayHeight * halfRowHeight / scale); overlayScale = scale; } WidgetUtils.DrawSprite(overlaySprite, overlayOrigin, overlaySize); } }
public VqaReader(Stream stream) { this.stream = stream; // Decode FORM chunk if (stream.ReadASCII(4) != "FORM") { throw new InvalidDataException("Invalid vqa (invalid FORM section)"); } /*var length = */ stream.ReadUInt32(); if (stream.ReadASCII(8) != "WVQAVQHD") { throw new InvalidDataException("Invalid vqa (not WVQAVQHD)"); } /* var length = */ stream.ReadUInt32(); /*var version = */ stream.ReadUInt16(); /*var flags = */ stream.ReadUInt16(); Frames = stream.ReadUInt16(); Width = stream.ReadUInt16(); Height = stream.ReadUInt16(); blockWidth = stream.ReadUInt8(); blockHeight = stream.ReadUInt8(); Framerate = stream.ReadUInt8(); cbParts = stream.ReadUInt8(); blocks = new int2(Width / blockWidth, Height / blockHeight); numColors = stream.ReadUInt16(); /*var maxBlocks = */ stream.ReadUInt16(); /*var unknown1 = */ stream.ReadUInt16(); /*var unknown2 = */ stream.ReadUInt32(); // Audio /*var freq = */ stream.ReadUInt16(); /*var channels = */ stream.ReadByte(); /*var bits = */ stream.ReadByte(); /*var unknown3 = */ stream.ReadBytes(14); var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height)); cbf = new byte[Width * Height]; cbp = new byte[Width * Height]; palette = new uint[numColors]; origData = new byte[2 * blocks.X * blocks.Y]; frameData = new uint[frameSize, frameSize]; var type = stream.ReadASCII(4); if (type != "FINF") { stream.Seek(27, SeekOrigin.Current); type = stream.ReadASCII(4); } /*var length = */ stream.ReadUInt16(); /*var unknown4 = */ stream.ReadUInt16(); // Frame offsets offsets = new UInt32[Frames]; for (int i = 0; i < Frames; i++) { offsets[i] = stream.ReadUInt32(); if (offsets[i] > 0x40000000) { offsets[i] -= 0x40000000; } offsets[i] <<= 1; } CollectAudioData(); Reset(); }