public static Bitmap ToRGBA(VGABitmap vga) { var bmp = new Bitmap(vga.Width, vga.Height); for (int y = 0; y < vga.Height; ++y) { for (int x = 0; x < vga.Width; ++x) { int k = vga.Data[x + y * vga.Width]; if (k != 0) { bmp.SetPixel(x, y, Color.FromArgb(Convert6BitTo8Bit(vga.Palette[k * 3]), Convert6BitTo8Bit(vga.Palette[k * 3 + 1]), Convert6BitTo8Bit(vga.Palette[k * 3 + 2]))); } } } return(bmp); }
public List <VGABitmap> DecodeFrames(BOBFile bob) { List <VGABitmap> frames = new List <VGABitmap>(bob.Frames.Count); foreach (var frame in bob.Frames) { //System.IO.File.WriteAllBytes("dp.com", frame.DrawProgram); var cpu = new DrawProgramCPU { Text = frame.DrawProgram, Data = frame.PixelData }; byte[] screenbuffer = new byte[frame.Width * frame.Height]; //byte[] dest = new byte[5000]; int page = -1; // this number was determined by experimentation // the draw-program appears to align lines of pixels along these boundaries // might have something to do with how EGA works, or simply a kink of the game int rowBytes = 86; cpu.Write += (s, e) => { //dest[e.Address] = (byte)e.Value; int pageAddr = e.Address; int x = (pageAddr % rowBytes) * 4; int y = pageAddr / rowBytes; switch (page) { case 0: break; case 1: x -= 3; break; case 2: x -= 6; break; case 3: x -= 9; break; default: return; } if (x + y * frame.Width < screenbuffer.Length) { screenbuffer[x + y * frame.Width] = (byte)e.Value; } }; // the draw-program calls this at the beginning of every EGA page: cpu.EgaSequencerReset += (s, e) => { ++page; }; cpu.Call(0); // call the draw-program var vgabmp = new VGABitmap(frame.Width, frame.Height, bob.Palette); vgabmp.Data = screenbuffer; frames.Add(vgabmp); } return(frames); }