public SmackerVideoTrack(uint width, uint height, uint frameCount, Rational frameRate, uint flags, uint signature) { _surface = new Surface((int)width, (int)(height * (flags != 0 ? 2 : 1)), PixelFormat.Indexed8, false); _frameCount = frameCount; _frameRate = frameRate; _flags = flags; _signature = signature; _curFrame = -1; _dirtyPalette = false; _palette = new byte[3 * 256]; }
public PsxVideoTrack(Stream firstSector, CDSpeed speed, uint frameCount, PixelFormat screenFormat) { var br = new BinaryReader(firstSector); _nextFrameStartTime = new Timestamp(0, (int)speed); _frameCount = frameCount; firstSector.Seek(40, SeekOrigin.Begin); _width = br.ReadUInt16(); _height = br.ReadUInt16(); _surface = new Surface(_width, _height, screenFormat, false); _macroBlocksW = (ushort)((_width + 15) / 16); _macroBlocksH = (ushort)((_height + 15) / 16); _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16]; _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; _endOfTrack = false; _curFrame = -1; _acHuffman = new Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols); _dcHuffmanChroma = new Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols); _dcHuffmanLuma = new Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols); }
public void Draw2byte(Surface s, int c, int x, int y, byte color) { throw new NotImplementedException(); // FIXME: This gets passed a const destination Surface. Intuitively this // should never get written to. But sadly it does... For now we simply // cast the const qualifier away. // var dstNav = new PixelNavigator(s); // dstNav.Offset(x, y); // var width = _vm._2byteWidth; // var height = Math.Min(_vm._2byteHeight, s.h - y); // var src = _vm.Get2byteCharPtr(c); // byte bits = 0; // // if (height <= 0 || width <= 0) // { // return; // } // // for (int ty = 0; ty < height; ty++) // { // for (int tx = 0; tx < width; tx++) // { // if ((tx & 7) == 0) // bits = *src++; // if (x + tx < 0 || x + tx >= s.w || y + ty < 0) // continue; // if (bits & ScummHelper.RevBitMask(tx % 8)) // { // dst[tx] = color; // } // } // dst += s.Pitch; // } }
public VirtScreen(int top, int width, int height, PixelFormat format, int numBuffers, bool trick = false) { if (numBuffers <= 0) throw new ArgumentOutOfRangeException("numBuffers", "The number of buffers should be positive."); var numStrips = Math.Max(width / 8, 80); tdirty = new int[numStrips + 1]; bdirty = new int[numStrips + 1]; TopLine = top; _surfaces = new Surface[numBuffers]; _roSurfaces = new ReadOnlyCollection<Surface>(_surfaces); for (int i = 0; i < numBuffers; i++) { _surfaces[i] = new Surface(width, height, format, trick); } SetDirtyRange(0, height); HasTwoBuffers = Surfaces.Count == 2; }
protected virtual void DrawBits1(Surface surface, int x, int y, BinaryReader src, int drawTop, int width, int height) { var dst = new PixelNavigator(surface); dst.GoTo(x, y); byte bits = 0; byte col = Color; //int pitch = surface.Pitch - width * surface.BytesPerPixel; var dst2 = new PixelNavigator(dst); dst2.OffsetY(1); for (y = 0; y < height && y + drawTop < surface.Height; y++) { for (x = 0; x < width; x++) { if ((x % 8) == 0) bits = src.ReadByte(); if ((bits & ScummHelper.RevBitMask(x % 8)) != 0 && y + drawTop >= 0) { if (_shadowMode) { dst.OffsetX(1); dst.Write(_shadowColor); dst2.Write(_shadowColor); dst2.OffsetX(1); dst2.Write(_shadowColor); } dst.Write(col); } dst.OffsetX(1); dst2.OffsetX(1); } dst.OffsetX(surface.Width - width); dst2.OffsetX(surface.Width - width); } }
public override void DrawChar(int chr, Surface s, int x, int y) { //const byte *charPtr = (Vm.UseCjkMode && chr > 127) ? Vm.Get2byteCharPtr(chr) : _fontPtr + chr * 8; var charPtr = new BinaryReader(new MemoryStream(_fontPtr)); charPtr.BaseStream.Seek(_charOffset + chr * 8, SeekOrigin.Begin); var width = GetDrawWidthIntern(chr); var height = GetDrawHeightIntern(chr); SetDrawCharIntern(chr); DrawBits1(s, x, y, charPtr, y, width, height); }
Surface GrabScreen565() { Surface screen = _system.GraphicsManager.Capture(); var bpp = Surface.GetBytesPerPixel(screen.PixelFormat); Debug.Assert(bpp == 1 || bpp == 2); Debug.Assert(screen.Pixels != null); PixelFormat screenFormat = _system.GraphicsManager.PixelFormat; var screenBpp = Surface.GetBytesPerPixel(screenFormat); var surf = new Surface(screen.Width, screen.Height, PixelFormat.Rgb16, false); Color[] palette = null; if (screenBpp == 1) { palette = _system.GraphicsManager.GetPalette(); } for (uint y = 0; y < screen.Height; ++y) { for (uint x = 0; x < screen.Width; ++x) { Color c = new Color(); if (screenBpp == 1) { var pixel = screen.Pixels[x + y * screen.Width]; c = palette[pixel]; } else if (screenBpp == 2) { ushort col = screen.Pixels.ToUInt16((int)(x * 2 + y * 2 * screen.Width)); byte r, g, b; ColorHelper.ColorToRGB(col, out r, out g, out b); c = Color.FromRgb(r, g, b); } var colDst = ColorHelper.RGBToColor((byte)c.R, (byte)c.G, (byte)c.B); surf.Pixels.WriteUInt16((int)(x * 2 + y * 2 * screen.Width), colDst); } } return surf; }
protected override void DrawBitsN(Surface s, PixelNavigator dst, IList<byte> src, int srcPos, byte bpp, int drawTop, int width, int height) { // if (_sjisCurChar) // { // assert(Vm._cjkFont); // Vm._cjkFont.drawChar(Vm._textSurface, _sjisCurChar, _left * Vm._textSurfaceMultiplier, (_top - Vm._screenTop) * Vm._textSurfaceMultiplier, Vm._townsCharsetColorMap[1], _shadowColor); // return; // } bool scale2x = (Vm.TextSurfaceMultiplier == 2); dst = new PixelNavigator(Vm.TextSurface); dst.GoTo(Left * Vm.TextSurfaceMultiplier, (Top - Vm.ScreenTop) * Vm.TextSurfaceMultiplier); int y, x; int color; byte numbits, bits; int pitch = Vm.TextSurface.Pitch - width; Debug.Assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8); bits = src[srcPos++]; numbits = 8; var cmap = Vm.CharsetColorMap; var dst2 = new PixelNavigator(dst); if (Vm.Game.Platform == Platform.FMTowns) cmap = Vm.TownsCharsetColorMap; if (scale2x) { dst2.OffsetY(1); pitch <<= 1; } for (y = 0; y < height && y + drawTop < Vm.TextSurface.Height; y++) { for (x = 0; x < width; x++) { color = (bits >> (8 - bpp)) & 0xFF; if (color != 0 && y + drawTop >= 0) { dst.Write(cmap[color]); if (scale2x) { dst.Write(1, dst.Read()); dst2.Write(dst.Read()); dst2.Write(1, dst.Read()); } } dst.OffsetX(1); if (scale2x) { dst.OffsetX(1); dst2.OffsetX(2); } bits <<= bpp; numbits -= bpp; if (numbits == 0) { bits = src[srcPos++]; numbits = 8; } } dst.OffsetX(pitch / dst.BytesByPixel); dst2.OffsetX(pitch / dst2.BytesByPixel); } }
public override void DrawChar(int chr, Surface s, int x, int y) { if (!PrepareDraw(chr)) return; var pn = new PixelNavigator(s); pn.GoTo(x, y); DrawBitsN(s, pn, _fontPtr, _charPos, _fontPtr[_fontPos], y, _width, _height); }
public abstract void DrawChar(int chr, Surface s, int x, int y);
protected override void DrawBits1(Surface dest, int x, int y, BinaryReader src, int drawTop, int width, int height) { if (_sjisCurChar != 0) { // Debug.Assert(Vm._cjkFont); // Vm._cjkFont.drawChar(dest, _sjisCurChar, x, y, _color, _shadowColor); return; } bool scale2x = ((dest == Vm.TextSurface) && (Vm.TextSurfaceMultiplier == 2) /*&& !(_sjisCurChar >= 256 && Vm.UseCJKMode)*/); byte bits = 0; var col = Color; var bpp = Surface.GetBytesPerPixel(dest.PixelFormat); int pitch = dest.Pitch - width * bpp; var dst = new PixelNavigator(dest); dst.GoTo(x, y); var dst2 = new PixelNavigator(dst); dst2.OffsetY(1); var dst3 = new PixelNavigator(dst2); var dst4 = new PixelNavigator(dst2); if (scale2x) { dst3.OffsetY(1); dst4.OffsetY(1); pitch <<= 1; } for (y = 0; y < height && y + drawTop < dest.Height; y++) { for (x = 0; x < width; x++) { if ((x % 8) == 0) bits = src.ReadByte(); if (((bits & ScummHelper.RevBitMask(x % 8)) != 0) && y + drawTop >= 0) { if (bpp == 2) { if (_enableShadow) { dst.WriteUInt16(2, Vm._16BitPalette[_shadowColor]); dst.WriteUInt16(2 + dest.Pitch, Vm._16BitPalette[_shadowColor]); } dst.WriteUInt16(Vm._16BitPalette[Color]); } else { if (_enableShadow) { if (scale2x) { dst.Write(2, _shadowColor); dst.Write(3, _shadowColor); dst2.Write(2, _shadowColor); dst2.Write(3, _shadowColor); dst3.Write(0, _shadowColor); dst3.Write(1, _shadowColor); dst4.Write(0, _shadowColor); dst4.Write(0, _shadowColor); } else { dst2.Write(_shadowColor); dst.Write(1, _shadowColor); } } dst.Write(col); if (scale2x) { dst.Write(1, col); dst2.Write(0, col); dst2.Write(1, col); } } } dst.OffsetX(1); dst2.OffsetX(1); if (scale2x) { dst.OffsetX(1); dst2.OffsetX(1); dst3.OffsetX(1); dst4.OffsetX(1); } } dst.OffsetX(pitch / dst.BytesByPixel); dst2.OffsetX(pitch / dst2.BytesByPixel); dst3.OffsetX(pitch / dst3.BytesByPixel); dst4.OffsetX(pitch / dst4.BytesByPixel); } }
public static void Fill(Surface surface, Rect r, int color) { r = new Rect(r.Left, r.Top, r.Right, r.Bottom); r.Clip(surface.Width, surface.Height); if (!r.IsValid) return; int width = r.Width; int lineLen = width; int height = r.Height; bool useMemset = true; var bpp = Surface.GetBytesPerPixel(surface.PixelFormat); if (bpp == 2) { lineLen *= 2; if ((ushort)color != ((color & 0xff) | (color & 0xff) << 8)) useMemset = false; } else if (bpp == 4) { useMemset = false; } else if (bpp != 1) { throw new InvalidOperationException("Surface::fillRect: bytesPerPixel must be 1, 2, or 4"); } if (useMemset) { var pn = new PixelNavigator(surface); pn.GoTo(r.Left, r.Top); for (int i = 0; i < height; i++) { pn.Set((byte)color, lineLen); pn.OffsetY(1); } } else { if (bpp == 2) { var pn = new PixelNavigator(surface); pn.GoTo(r.Left, r.Top); for (int i = 0; i < height; i++) { pn.Set((ushort)color, lineLen); pn.OffsetX(surface.Width); } } else { var pn = new PixelNavigator(surface); pn.GoTo(r.Left, r.Top); for (int i = 0; i < height; i++) { pn.Set((uint)color, lineLen); pn.OffsetX(surface.Width / 2); } } } }
public PixelNavigator(Surface surface) : this(surface.Pixels, surface.Width, surface.BytesPerPixel) { }
static void ScaleThumbnail(Surface input, Surface output) { // TODO: //while (input.Width / output.Width >= 4 || input.Height / output.Height >= 4) //{ // createThumbnail_4 < 565 > ((const uint8*)input.getPixels(), input.pitch, (uint8*)input.getPixels(), input.pitch, input.w, input.h); // input.w /= 4; // input.h /= 4; //} //while (input.w / output.w >= 2 || input.h / output.h >= 2) //{ // createThumbnail_2 < 565 > ((const uint8*)input.getPixels(), input.pitch, (uint8*)input.getPixels(), input.pitch, input.w, input.h); // input.w /= 2; // input.h /= 2; //} //if ((input.w == output.w && input.h < output.h) || (input.w < output.w && input.h == output.h)) //{ // // In this case we simply center the input surface in the output // uint8* dst = (uint8*)output.getBasePtr((output.w - input.w) / 2, (output.h - input.h) / 2); // const uint8* src = (const uint8*)input.getPixels(); // for (int y = 0; y < input.h; ++y) // { // memcpy(dst, src, input.w * input.format.bytesPerPixel); // src += input.pitch; // dst += output.pitch; // } //} //else //{ // // Assure the aspect of the scaled image still matches the original. // int targetWidth = output.w, targetHeight = output.h; // const float inputAspect = (float)input.w / input.h; // const float outputAspect = (float)output.w / output.h; // if (inputAspect > outputAspect) // { // targetHeight = int(targetWidth / inputAspect); // } // else if (inputAspect < outputAspect) // { // targetWidth = int(targetHeight * inputAspect); // } // // Make sure we are still in the bounds of the output // assert(targetWidth <= output.w); // assert(targetHeight <= output.h); // // Center the image on the output surface // byte* dst = (byte*)output.getBasePtr((output.w - targetWidth) / 2, (output.h - targetHeight) / 2); // const uint dstLineIncrease = output.pitch - targetWidth * output.format.bytesPerPixel; // const float scaleFactorX = (float)targetWidth / input.w; // const float scaleFactorY = (float)targetHeight / input.h; // for (int y = 0; y < targetHeight; ++y) // { // const float yFrac = (y / scaleFactorY); // const int y1 = (int)yFrac; // const int y2 = (y1 + 1 < input.h) ? (y1 + 1) : (input.h - 1); // for (int x = 0; x < targetWidth; ++x) // { // const float xFrac = (x / scaleFactorX); // const int x1 = (int)xFrac; // const int x2 = (x1 + 1 < input.w) ? (x1 + 1) : (input.w - 1); // // Look up colors at the points // uint8 p1R, p1G, p1B; // Graphics::colorToRGB < Graphics::ColorMasks < 565 > > (READ_UINT16(input.getBasePtr(x1, y1)), p1R, p1G, p1B); // uint8 p2R, p2G, p2B; // Graphics::colorToRGB < Graphics::ColorMasks < 565 > > (READ_UINT16(input.getBasePtr(x2, y1)), p2R, p2G, p2B); // uint8 p3R, p3G, p3B; // Graphics::colorToRGB < Graphics::ColorMasks < 565 > > (READ_UINT16(input.getBasePtr(x1, y2)), p3R, p3G, p3B); // uint8 p4R, p4G, p4B; // Graphics::colorToRGB < Graphics::ColorMasks < 565 > > (READ_UINT16(input.getBasePtr(x2, y2)), p4R, p4G, p4B); // const float xDiff = xFrac - x1; // const float yDiff = yFrac - y1; // uint8 pR = (uint8)((1 - yDiff) * ((1 - xDiff) * p1R + xDiff * p2R) + yDiff * ((1 - xDiff) * p3R + xDiff * p4R)); // uint8 pG = (uint8)((1 - yDiff) * ((1 - xDiff) * p1G + xDiff * p2G) + yDiff * ((1 - xDiff) * p3G + xDiff * p4G)); // uint8 pB = (uint8)((1 - yDiff) * ((1 - xDiff) * p1B + xDiff * p2B) + yDiff * ((1 - xDiff) * p3B + xDiff * p4B)); // WRITE_UINT16(dst, Graphics::RGBToColor < Graphics::ColorMasks < 565 > > (pR, pG, pB)); // dst += 2; //} //// Move to the next line //dst = (byte*)dst + dstLineIncrease; }
static Surface CreateThumbnail(Surface input) { int height; if ((input.Width == 320 && input.Height == 200) || (input.Width == 640 && input.Height == 400)) { height = (int)ThumbnailSize.ThumbnailHeight1; } else { height = (int)ThumbnailSize.ThumbnailHeight2; } var output = new Surface((int)ThumbnailSize.ThumbnailWidth, height, PixelFormat.Rgb16, false); ScaleThumbnail(input, output); return output; }
protected ScummEngine(GameSettings settings, IGraphicsManager gfxManager, IInputManager inputManager, IMixer mixer) { Settings = settings; var game = (GameInfo)settings.Game; _resManager = ResourceManager.Load(game); _game = game; InvalidBox = _game.Version < 5 ? (byte)255 : (byte)0; _gameMD5 = ToMd5Bytes(game.MD5); _gfxManager = gfxManager; _inputManager = inputManager; _inputState = inputManager.GetState(); _strings = new byte[_resManager.NumArray][]; _inventory = new ushort[_resManager.NumInventory]; _invData = new ObjectData[_resManager.NumInventory]; CurrentScript = 0xFF; Mixer = mixer; ScreenWidth = Game.Width; ScreenHeight = Game.Height; AudioCDManager = new DefaultAudioCDManager(this, mixer); Sound = new Sound(this, mixer); SetupMusic(); _variables = new int[_resManager.NumVariables]; _bitVars = new BitArray(_resManager.NumBitVariables); _slots = new ScriptSlot[NumScriptSlot]; for (int i = 0; i < NumScriptSlot; i++) { _slots[i] = new ScriptSlot(); } for (int i = 0; i < 200; i++) { _objs[i] = new ObjectData(); } for (int i = 0; i < 6; i++) { _string[i] = new TextSlot(); if (game.Version != 3) { _string[i].Default.Position = new Point(2, 5); } } _colorCycle = new ColorCycle[16]; for (int i = 0; i < _colorCycle.Length; i++) { _colorCycle[i] = new ColorCycle(); } _nest = new NestedScript[MaxScriptNesting + 1]; for (int i = 0; i < _nest.Length; i++) { _nest[i] = new NestedScript(); } _scaleSlots = new ScaleSlot[20]; for (int i = 0; i < _scaleSlots.Length; i++) { _scaleSlots[i] = new ScaleSlot(); } Gdi = Gdi.Create(this, game); switch (game.Version) { case 0: _costumeLoader = new CostumeLoader0(this); _costumeRenderer = new CostumeRenderer0(this); break; case 7: case 8: _costumeLoader = new AkosCostumeLoader(this); _costumeRenderer = new AkosRenderer(this); break; default: _costumeLoader = new ClassicCostumeLoader(this); _costumeRenderer = new ClassicCostumeRenderer(this); break; } CreateCharset(); ResetCursors(); // Create the text surface var pixelFormat = _game.Features.HasFlag(GameFeatures.Is16BitColor) ? PixelFormat.Rgb16 : PixelFormat.Indexed8; _textSurface = new Surface(ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, PixelFormat.Indexed8, false); ClearTextSurface(); if (Game.Platform == Platform.FMTowns) { _townsScreen = new TownsScreen(_gfxManager, ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, PixelFormat.Rgb16); _townsScreen.SetupLayer(0, ScreenWidth, ScreenHeight, 32767); _townsScreen.SetupLayer(1, ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, 16, _textPalette); } if (Game.Version == 0) { InitScreens(8, 144); } else if ((Game.GameId == GameId.Maniac) && (_game.Version <= 1) && _game.Platform != Platform.NES) { InitScreens(16, 152); } else if (Game.Version >= 7) { InitScreens(0, ScreenHeight); } else { InitScreens(16, 144); } // Allocate gfx compositing buffer (not needed for V7/V8 games). if (Game.Version < 7) { _composite = new Surface(ScreenWidth, ScreenHeight, pixelFormat, false); } InitActors(); OwnerRoom = Game.Version >= 7 ? 0x0FF : 0x0F; if (Game.Version < 7) { Camera.LeftTrigger = 10; Camera.RightTrigger = 30; } InitPalettes(); InitializeVerbs(); // WORKAROUND for bug in boot script of Loom (CD) // The boot script sets the characters of string 21, // before creating the string.resource. if (_game.GameId == GameId.Loom) { _strings[21] = new byte[13]; } }
public override void DrawChar(int chr, Surface s, int x, int y) { }
private void DrawFramePSX(Surface frame) { // The PSX videos have half resolution var scaledFrame = new Surface(frame.Width, frame.Height * 2, frame.PixelFormat, false); for (int y = 0; y < scaledFrame.Height; y++) { Array.Copy(frame.Pixels, (y / 2) * frame.Pitch, scaledFrame.Pixels, y * frame.Pitch, scaledFrame.Width * scaledFrame.BytesPerPixel); } { ushort x = (ushort)((_vm.Settings.Game.Width - scaledFrame.Width) / 2); ushort y = (ushort)((_vm.Settings.Game.Height - scaledFrame.Height) / 2); _vm.GraphicsManager.CopyRectToScreen(scaledFrame.Pixels, scaledFrame.Pitch, 0, 0, x, y, scaledFrame.Width, scaledFrame.Height); } }
protected virtual void DrawBitsN(Surface s, PixelNavigator dst, System.Collections.Generic.IList<byte> src, int srcPos, byte bpp, int drawTop, int width, int height) { if (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8) throw new ArgumentException("Invalid bpp", "bpp"); byte bits = src[srcPos++]; byte numbits = 8; var cmap = Vm.CharsetColorMap; for (int y = 0; y < height && y + drawTop < s.Height; y++) { for (int x = 0; x < width; x++) { int color = (bits >> (8 - bpp)) & 0xFF; if (color != 0 && (y + drawTop >= 0)) { dst.Write(cmap[color]); } dst.OffsetX(1); bits <<= bpp; numbits -= bpp; if (numbits == 0) { bits = src[srcPos++]; numbits = 8; } } dst.Offset(-width, 1); } }
public static void Convert420(Surface dst, LuminanceScale scale, byte[] ySrc, byte[] uSrc, byte[] vSrc, int yWidth, int yHeight, int yPitch, int uvPitch) { // Sanity checks Debug.Assert(dst != null && dst.Pixels != null); Debug.Assert(dst.BytesPerPixel == 2 || dst.BytesPerPixel == 4); Debug.Assert(ySrc != null && uSrc != null && vSrc != null); Debug.Assert((yWidth & 1) == 0); Debug.Assert((yHeight & 1) == 0); var lookup = GetLookup(dst.PixelFormat, scale); // Use a templated function to avoid an if check on every pixel if (dst.BytesPerPixel == 2) ConvertYUV420ToRGB(dst.Pixels, dst.Pitch, lookup, _colorTab.Value, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch, sizeof(ushort)); else ConvertYUV420ToRGB(dst.Pixels, dst.Pitch, lookup, _colorTab.Value, ySrc, uSrc, vSrc, yWidth, yHeight, yPitch, uvPitch, sizeof(uint)); }
protected void RedefineBuiltinCursorFromChar(int index, int chr) { // Cursor image in both Loom versions are based on images from charset. // This function is *only* supported for Loom! if (_game.GameId != Scumm.IO.GameId.Loom) throw new NotSupportedException("RedefineBuiltinCursorFromChar is *only* supported for Loom!"); if (index < 0 || index >= 4) throw new ArgumentException("index"); // const int oldID = _charset->getCurID(); var ptr = _cursorImages[index]; if (_game.Version == 3) { _charset.SetCurID(0); } else if (_game.Version >= 4) { _charset.SetCurID(1); } var s = new Surface(_charset.GetCharWidth(chr), _charset.GetFontHeight(), PixelFormat.Indexed8, false); var p = new PixelNavigator(s); Gdi.Fill(new PixelNavigator(s), 123, s.Width, s.Height); _charset.DrawChar(chr, s, 0, 0); Array.Clear(ptr, 0, ptr.Length); for (int h = 0; h < s.Height; h++) { for (int w = 0; w < s.Width; w++) { p.GoTo(w, h); if (p.Read() != 123) { ptr[h] |= (ushort)(1 << (15 - w)); } } } // _charset->setCurID(oldID); }
void SaveThumbnail(BinaryWriter output, Surface thumb) { var bpp = Surface.GetBytesPerPixel(thumb.PixelFormat); if (bpp != 2 && bpp != 4) { // TODO: warning("trying to save thumbnail with bpp %u", bpp); return; } ThumbnailHeader header = new ThumbnailHeader(); header.Type = ScummHelper.MakeTag('T', 'H', 'M', 'B'); header.Size = (uint)(ThumbnailHeaderSize + thumb.Width * thumb.Height * bpp); header.Version = THMB_VERSION; header.Width = (ushort)thumb.Width; header.Height = (ushort)thumb.Height; output.WriteUInt32BigEndian(header.Type); output.WriteUInt32BigEndian(header.Size); output.WriteByte(header.Version); output.WriteUInt16BigEndian(header.Width); output.WriteUInt16BigEndian(header.Height); // Serialize the PixelFormat output.WriteByte(bpp); output.WriteByte(3); output.WriteByte(2); output.WriteByte(3); output.WriteByte(8); output.WriteByte(11); output.WriteByte(5); output.WriteByte(0); output.WriteByte(0); // Serialize the pixel data for (uint y = 0; y < thumb.Height; ++y) { switch (bpp) { case 2: { var pixels = new UShortAccess(thumb.Pixels, (int)(y * thumb.Width * 2)); for (uint x = 0; x < thumb.Width; ++x) { output.WriteUInt16BigEndian(pixels[0]); pixels.Offset += 2; } } break; case 4: { var pixels = new UIntAccess(thumb.Pixels, (int)(y * thumb.Width * 4)); for (var x = 0; x < thumb.Width; ++x) { output.WriteUInt32BigEndian(pixels[0]); pixels.Offset += 4; } } break; default: throw new NotSupportedException(); } } }