public int DrawCostume(VirtScreen vs, int numStrips, Actor actor, bool drawToBackBuf) { var pixelsNavigator = new PixelNavigator(vs.Surfaces[drawToBackBuf ? 1 : 0]); pixelsNavigator.OffsetX(vs.XStart); ActorX += (vs.XStart & 7); pixelsNavigator.OffsetX(-(vs.XStart & 7)); startNav = new PixelNavigator(pixelsNavigator); if (_vm.Game.IsOldBundle) { _xmove = -72; _ymove = -100; } else { _xmove = _ymove = 0; } int result = 0; for (int i = 0; i < 16; i++) { result |= DrawLimb(actor, i); } return(result); }
void DrawStripV1Object(PixelNavigator navDst, int stripnr, int width, int height) { int charIdx; height /= 8; width /= 8; for (var y = 0; y < height; y++) { _v1.Colors[3] = (byte)(objectMap[(y + height) * width + stripnr] & 7); charIdx = objectMap[y * width + stripnr] * 8; for (var i = 0; i < 8; i++) { byte c = _v1.CharMap[charIdx + i]; var color = _v1.Colors[(c >> 6) & 3]; navDst.Write(0, color); navDst.Write(1, color); color = _v1.Colors[(c >> 4) & 3]; navDst.Write(2, color); navDst.Write(3, color); color = _v1.Colors[(c >> 2) & 3]; navDst.Write(4, color); navDst.Write(5, color); color = _v1.Colors[(c >> 0) & 3]; navDst.Write(6, color); navDst.Write(7, color); navDst.OffsetY(1); } } }
void DrawStripV1Background(PixelNavigator navDst, int stripnr, int height) { int charIdx; height /= 8; for (int y = 0; y < height; y++) { _v1.Colors[3] = (byte)(_v1.ColorMap[y + stripnr * height] & 7); // Check for room color change in V1 zak if (RoomPalette[0] == 255) { _v1.Colors[2] = RoomPalette[2]; _v1.Colors[1] = RoomPalette[1]; } charIdx = _v1.PicMap[y + stripnr * height] * 8; for (int i = 0; i < 8; i++) { byte c = _v1.CharMap[charIdx + i]; var color = _v1.Colors[(c >> 6) & 3]; navDst.Write(0, color); navDst.Write(1, color); color = _v1.Colors[(c >> 4) & 3]; navDst.Write(2, color); navDst.Write(3, color); color = _v1.Colors[(c >> 2) & 3]; navDst.Write(4, color); navDst.Write(5, color); color = _v1.Colors[(c >> 0) & 3]; navDst.Write(6, color); navDst.Write(7, color); navDst.OffsetY(1); } } }
public PixelNavigator GetMaskBuffer(int x, int y, int i) { var nav = new PixelNavigator(maskBuffer[i], NumStrips, 1); nav.GoTo(x, y); return(nav); }
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); } }
void DrawStripRaw(PixelNavigator navDst, BinaryReader src, int height, bool transpCheck) { int x; if (game.Features.HasFlag(GameFeatures.Old256)) { int h = height; x = 8; while (true) { navDst.Write(RoomPalette[src.ReadByte()]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } } do { for (x = 0; x < 8; x++) { int color = src.ReadByte(); if (!transpCheck || color != TransparentColor) { navDst.OffsetX(x); WriteRoomColor(navDst, color); navDst.OffsetX(-x); } } navDst.OffsetY(1); } while ((--height) != 0); }
void DrawStripV1Mask(PixelNavigator navDst, int stripnr, int width, int height) { int maskIdx; height /= 8; width /= 8; for (var y = 0; y < height; y++) { if (_objectMode) { maskIdx = objectMap[(y + 2 * height) * width + stripnr] * 8; } else { maskIdx = _v1.MaskMap[y + stripnr * height] * 8; } for (var i = 0; i < 8; i++) { byte c = _v1.MaskChar[maskIdx + i]; // V1/V0 masks are inverted compared to what ScummVM expects navDst.Write((byte)(c ^ 0xFF)); navDst.OffsetY(1); } } }
static void DecompressMaskImg(PixelNavigator dst, Stream src, int height) { while (height != 0) { var b = (byte)src.ReadByte(); if ((b & 0x80) != 0) { b &= 0x7F; var c = (byte)src.ReadByte(); do { dst.Write(c); dst.OffsetY(1); --height; } while (--b != 0 && height != 0); } else { do { dst.Write((byte)src.ReadByte()); dst.OffsetY(1); --height; } while (--b != 0 && height != 0); } } }
void DrawStripV1Background(PixelNavigator navDst, int stripnr, int height) { int charIdx; height /= 8; for (int y = 0; y < height; y++) { _v1.Colors[3] = (byte)(_v1.ColorMap[y + stripnr * height] & 7); // Check for room color change in V1 zak if (RoomPalette[0] == 255) { _v1.Colors[2] = RoomPalette[2]; _v1.Colors[1] = RoomPalette[1]; } charIdx = _v1.PicMap[y + stripnr * height] * 8; for (int i = 0; i < 8; i++) { byte c = _v1.CharMap[charIdx + i]; var color = _v1.Colors[(c >> 6) & 3]; navDst.Write(0, color); navDst.Write(1, color); color = _v1.Colors[(c >> 4) & 3]; navDst.Write(2, color); navDst.Write(3, color); color = _v1.Colors[(c >> 2) & 3]; navDst.Write(4, color); navDst.Write(5, color); color = _v1.Colors[(c >> 0) & 3]; navDst.Write(6, color); navDst.Write(7, color); navDst.OffsetY(1); } } }
static void DecompressMaskImgOr(PixelNavigator dst, Stream src, int height) { byte b, c; while (height != 0) { b = (byte)src.ReadByte(); if ((b & 0x80) != 0) { b &= 0x7F; c = (byte)src.ReadByte(); do { dst.Write((byte)(dst.Read() | c)); dst.OffsetY(1); --height; } while ((--b != 0) && (height != 0)); } else { do { dst.Write((byte)(dst.Read() | src.ReadByte())); dst.OffsetY(1); --height; } while ((--b != 0) && (height != 0)); } } }
void UnkDecode10(PixelNavigator navDst, BinaryReader src, int height) { int h = height; int numcolors = src.ReadByte(); var local_palette = src.ReadBytes(numcolors); int x = 8; while (true) { int color = src.ReadByte(); if (color < numcolors) { navDst.Write(RoomPalette[local_palette[color]]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } else { int run = color - numcolors + 1; color = src.ReadByte(); for (var i = 0; i < run; i++) { navDst.Write(RoomPalette[color]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } } } }
void WriteRoomColor(PixelNavigator navDst, int color) { // As described in bug #1294513 "FOA/Amiga: Palette problem (Regression)" // the original AMIGA version of Indy4: The Fate of Atlantis allowed // overflowing of the palette index. To have the same result in our code, // we need to do an logical AND 0xFF here to keep the result in [0, 255]. navDst.Write(RoomPalette[(color + paletteMod) & 0xFF]); }
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 PixelNavigator(PixelNavigator navigator) : this() { _startOffset = navigator._offset; _offset = _startOffset; _pixels = navigator._pixels; Pitch = navigator.Pitch; BytesByPixel = navigator.BytesByPixel; Width = navigator.Width; Height = navigator.Height; }
public PixelNavigator(PixelNavigator navigator) : this() { _startOffset = navigator._offset; _offset = _startOffset; _pixels = navigator._pixels; Pitch = navigator.Pitch; BytesByPixel = navigator.BytesByPixel; Width = navigator.Width; Height = navigator.Height; }
public static void BompApplyShadow0(byte[] lineBuffer, int linePos, PixelNavigator dst, int size) { while (size-- > 0) { byte tmp = lineBuffer[linePos++]; if (tmp != 255) { dst.Write(tmp); } dst.OffsetX(1); } }
static void Clear8Col(PixelNavigator nav, int height) { do { for (int i = 0; i < 8; i++) { nav.Write(0); nav.OffsetX(1); } nav.Offset(-8, 1); } while ((--height) != 0); }
public static void Fill(PixelNavigator dst, ushort color, int width, int height) { for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { dst.WriteUInt16(color); dst.OffsetX(1); } dst.Offset(-width, 1); } }
protected virtual bool DrawStrip(PixelNavigator navDst, int width, int height, int stripnr, BinaryReader smapReader) { // Do some input verification and make sure the strip/strip offset // are actually valid. Normally, this should never be a problem, // but if e.g. a savegame gets corrupted, we can easily get into // trouble here. See also bug #795214. long offset = -1; long smapLen; if (game.Features.HasFlag(GameFeatures.SixteenColors)) { smapLen = smapReader.ReadInt16(); if (stripnr * 2 + 2 < smapLen) { smapReader.BaseStream.Seek(stripnr * 2, SeekOrigin.Current); offset = smapReader.ReadInt16(); } } else if (game.Version < 5) { smapLen = smapReader.ReadInt32(); if (stripnr * 4 + 4 < smapLen) { smapReader.BaseStream.Seek(stripnr * 4, SeekOrigin.Current); offset = smapReader.ReadInt32(); } } else if (game.Version == 8) { smapLen = smapReader.BaseStream.Length; // Skip to the BSTR->WRAP->OFFS chunk smapReader.BaseStream.Seek(24, SeekOrigin.Current); if (stripnr * 4 + 8 < smapLen) { smapReader.BaseStream.Seek(stripnr * 4, SeekOrigin.Current); offset = 16 + smapReader.ReadUInt32(); } } else { smapLen = smapReader.BaseStream.Length; if (stripnr * 4 + 8 < smapLen) { smapReader.BaseStream.Seek(stripnr * 4, SeekOrigin.Begin); offset = smapReader.ReadUInt32() - 8; } } ScummHelper.AssertRange(0, offset, smapLen - 1, "screen strip"); smapReader.BaseStream.Seek(offset, SeekOrigin.Begin); return(DecompressBitmap(navDst, smapReader, height)); }
public void ResetBackground(int top, int bottom, int strip) { var vs = _vm.MainVirtScreen; if (top < 0) { top = 0; } if (bottom > vs.Height) { bottom = vs.Height; } if (top >= bottom) { return; } if (strip < 0 || strip >= NumStrips) { throw new ArgumentOutOfRangeException("strip"); } if (top < vs.TDirty[strip]) { vs.TDirty[strip] = top; } if (bottom > vs.BDirty[strip]) { vs.BDirty[strip] = bottom; } int numLinesToProcess = bottom - top; if (numLinesToProcess > 0) { var navDest = new PixelNavigator(vs.Surfaces[0]); navDest.GoTo(strip * 8 + vs.XStart, top); if (_vm.IsLightOn()) { var bgBakNav = new PixelNavigator(vs.Surfaces[1]); bgBakNav.GoTo(strip * 8 + vs.XStart, top); Copy8Col(navDest, bgBakNav, numLinesToProcess); } else { Clear8Col(navDest, numLinesToProcess); } } }
protected override bool DrawStrip(PixelNavigator navDst, int width, int height, int stripnr, System.IO.BinaryReader smapReader) { if (_objectMode) { DrawStripV1Object(navDst, stripnr, width, height); } else { DrawStripV1Background(navDst, stripnr, height); } return false; }
protected override bool DrawStrip(PixelNavigator navDst, int width, int height, int stripnr, System.IO.BinaryReader smapReader) { if (_objectMode) { DrawStripV1Object(navDst, stripnr, width, height); } else { DrawStripV1Background(navDst, stripnr, height); } return(false); }
public PixelNavigator? GetLayerPixels(int layer, int x, int y) { if (layer < 0 || layer > 1) return null; var l = _layers[layer]; if (!l.ready) return null; var pn = new PixelNavigator(l.pixels, l.pitch / l.bpp, l.bpp); pn.GoTo(x, y); return pn; }
static bool NextRow(ref PixelNavigator navDst, ref int x, ref int y, int height) { navDst.OffsetY(1); if (--y == 0) { if ((--x) == 0) { return(false); } navDst.Offset(1, -height); y = height; } return(true); }
static void Copy8Col(PixelNavigator navDst, PixelNavigator navSource, int height) { do { for (int i = 0; i < 8; i++) { navDst.Write(navSource.Read()); navDst.OffsetX(1); navSource.OffsetX(1); } navDst.Offset(-8, 1); navSource.Offset(-8, 1); } while ((--height) != 0); }
public static void Blit(PixelNavigator dst, PixelNavigator src, int width, int height) { for (var h = 0; h < height; h++) { for (int w = 0; w < width; w++) { dst.Write(src.Read()); src.OffsetX(1); dst.OffsetX(1); } src.Offset(-width, 1); dst.Offset(-width, 1); } }
void LINE(int c, int p, byte color, byte[] palette, PixelNavigator dst, PixelNavigator mask, int destX) { var pcolor = (color >> c) & 3; if (pcolor != 0) { if (!MASK_AT(p, mask, destX)) { dst.Write(p, palette[pcolor]); } if (!MASK_AT(p + 1, mask, destX)) { dst.Write(p + 1, palette[pcolor]); } } }
void Line(int c, int p, Codec1 v1, PixelNavigator?mask, PixelNavigator dst, byte color, byte[] palette) { var pcolor = (color >> c) & 3; if (pcolor != 0) { if (!MaskAt(p, v1, mask)) { dst.Write(p, palette[pcolor]); } if (!MaskAt(p + 1, v1, mask)) { dst.Write(p + 1, palette[pcolor]); } } }
void UnkDecode9(PixelNavigator navDst, BinaryReader src, int height) { int c, color; int i; int buffer = 0; int mask = 128; int h = height; byte run = 0; int x = 8; while (true) { c = ReadNBits(src, 4, ref mask, ref buffer); switch (c >> 2) { case 0: color = ReadNBits(src, 4, ref mask, ref buffer); for (i = 0; i < ((c & 3) + 2); i++) { navDst.Write(RoomPalette[run * 16 + color]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } break; case 1: for (i = 0; i < ((c & 3) + 1); i++) { color = ReadNBits(src, 4, ref mask, ref buffer); navDst.Write(RoomPalette[run * 16 + color]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } break; case 2: run = (byte)ReadNBits(src, 4, ref mask, ref buffer); break; } } }
void DrawStripBasicV(PixelNavigator navDst, BinaryReader src, int height, bool transpCheck) { byte color = src.ReadByte(); uint bits = src.ReadByte(); byte cl = 8; int inc = -1; int x = 8; do { int h = height; do { FillBits(ref cl, ref bits, src); if (!transpCheck || color != transparentColor) { WriteRoomColor(navDst, color); } navDst.OffsetY(1); if (!ReadBit(ref cl, ref bits)) { } else if (!ReadBit(ref cl, ref bits)) { FillBits(ref cl, ref bits, src); color = (byte)(bits & decompMask); bits >>= decompShr; cl -= decompShr; inc = -1; } else if (!ReadBit(ref cl, ref bits)) { color = (byte)(color + inc); } else { inc = -inc; color = (byte)(color + inc); } } while ((--h) != 0); navDst.Offset(1, -height); } while ((--x) != 0); }
public PixelNavigator?GetLayerPixels(int layer, int x, int y) { if (layer < 0 || layer > 1) { return(null); } var l = _layers[layer]; if (!l.ready) { return(null); } var pn = new PixelNavigator(l.pixels, l.pitch / l.bpp, l.bpp); pn.GoTo(x, y); return(pn); }
void UnkDecode11(PixelNavigator navDst, BinaryReader src, int height) { int i; int buffer = 0, mask = 128; int inc = 1; int color = src.ReadByte(); int x = 8; do { int h = height; do { navDst.Write(RoomPalette[color]); navDst.OffsetY(1); for (i = 0; i < 3; i++) { if (!ReadBit256(src, ref mask, ref buffer)) { break; } } switch (i) { case 1: inc = -inc; color -= inc; break; case 2: color -= inc; break; case 3: inc = 1; color = ReadNBits(src, 8, ref mask, ref buffer); break; } } while ((--h) != 0); navDst.Offset(1, -height); } while ((--x) != 0); }
public void DrawChar(PixelNavigator dst, char c, int x, int y, byte color) { var width = Math.Min((int)_chars[c].Width, dst.Width - x); var height = Math.Min((int)_chars[c].Height, dst.Height - y); var src = UnpackChar(c); var srcPitch = _chars[c].Width; var srcPos = 0; var minX = x < 0 ? -x : 0; var minY = y < 0 ? -y : 0; if (height <= 0 || width <= 0) { return; } if (minY != 0) { srcPos += minY * srcPitch; dst.OffsetY(minY); } for (int ty = minY; ty < height; ty++) { for (int tx = minX; tx < width; tx++) { if (src[srcPos + tx] != _chars[c].Transparency) { if (src[srcPos + tx] == 1) { dst.Write(tx, color); } else { dst.Write(tx, src[srcPos + tx]); } } } srcPos += srcPitch; dst.OffsetY(1); } }
public void DrawChar(PixelNavigator dst, char c, int x, int y, byte color) { var width = Math.Min((int)_chars[c].Width, dst.Width - x); var height = Math.Min((int)_chars[c].Height, dst.Height - y); var src = UnpackChar(c); var srcPitch = _chars[c].Width; var srcPos = 0; var minX = x < 0 ? -x : 0; var minY = y < 0 ? -y : 0; if (height <= 0 || width <= 0) { return; } if (minY != 0) { srcPos += minY * srcPitch; dst.OffsetY(minY); } for (int ty = minY; ty < height; ty++) { for (int tx = minX; tx < width; tx++) { if (src[srcPos + tx] != _chars[c].Transparency) { if (src[srcPos + tx] == 1) { dst.Write(tx, color); } else { dst.Write(tx, src[srcPos + tx]); } } } srcPos += srcPitch; dst.OffsetY(1); } }
void UnkDecode8(PixelNavigator navDst, BinaryReader src, int height) { int h = height; int x = 8; while (true) { int run = src.ReadByte() + 1; int color = src.ReadByte(); for (var i = 0; i < run; i++) { navDst.Write(RoomPalette[color]); if (!NextRow(ref navDst, ref x, ref h, height)) { return; } } } }
static void BompApplyShadow3(byte[] shadowPalette, byte[] lineBuffer, int linePos, PixelNavigator dst, int size, byte transparency) { while (size-- > 0) { byte tmp = lineBuffer[linePos++]; if (tmp != transparency) { if (tmp < 8) { tmp = shadowPalette[dst.Read() + (tmp << 8)]; } dst.Write(tmp); } dst.OffsetX(1); } }
public void DrawBomp() { Rect clip; byte skip_y_bits = 0x80; byte skip_y_new = 0; byte[] bomp_scaling_x = new byte[64]; byte[] bomp_scaling_y = new byte[64]; if (X < 0) { clip.Left = -X; } else { clip.Left = 0; } if (Y < 0) { clip.Top = -Y; } else { clip.Top = 0; } clip.Right = Width; if (clip.Right > Dst.Width - X) { clip.Right = Dst.Width - X; } clip.Bottom = Height; if (clip.Bottom > Dst.Height - Y) { clip.Bottom = Dst.Height - Y; } var src = Src; var pn = new PixelNavigator(Dst); pn.GoTo(X + clip.Left, Y); var maskbit = ScummHelper.RevBitMask((X + clip.Left) & 7); PixelNavigator maskPtr = new PixelNavigator(); // Mask against any additionally imposed mask if (MaskPtr.HasValue) { maskPtr = MaskPtr.Value; maskPtr.GoTo((X + clip.Left) / 8, Y); } var scalingYPtr = 0; // Setup vertical scaling if (ScaleY != 255) { var scaleBottom = SetupBompScale(bomp_scaling_y, Height, ScaleY); skip_y_new = bomp_scaling_y[scalingYPtr++]; skip_y_bits = 0x80; if (clip.Bottom > scaleBottom) { clip.Bottom = scaleBottom; } } // Setup horizontal scaling if (ScaleX != 255) { var scaleRight = SetupBompScale(bomp_scaling_x, Width, ScaleX); if (clip.Right > scaleRight) { clip.Right = scaleRight; } } var width = clip.Right - clip.Left; if (width <= 0) return; int pos_y = 0; var line_buffer = new byte[1024]; byte tmp; using (var br = new BinaryReader(new MemoryStream(src))) { // Loop over all lines while (pos_y < clip.Bottom) { br.ReadUInt16(); // Decode a single (bomp encoded) line, reversed if we are in mirror mode if (Mirror) BompDecodeLineReverse(br, line_buffer, 0, Width); else // Decode a single (bomp encoded) line BompDecodeLine(br, line_buffer, 0, Width); // If vertical scaling is enabled, do it if (ScaleY != 255) { // A bit set means we should skip this line... tmp = (byte)(skip_y_new & skip_y_bits); // Advance the scale-skip bit mask, if it's 0, get the next scale-skip byte skip_y_bits /= 2; if (skip_y_bits == 0) { skip_y_bits = 0x80; skip_y_new = bomp_scaling_y[scalingYPtr++]; } // Skip the current line if the above check tells us to if (tmp != 0) continue; } // Perform horizontal scaling if (ScaleX != 255) { BompScaleFuncX(line_buffer, bomp_scaling_x, 0, 0x80, Width); } // The first clip.top lines are to be clipped, i.e. not drawn if (clip.Top > 0) { clip.Top--; } else { // Replace the parts of the line which are masked with the transparency color if (MaskPtr.HasValue) BompApplyMask(line_buffer, clip.Left, maskPtr, (byte)maskbit, width, 255); // Apply custom color map, if available if (ActorPalette != null) BompApplyActorPalette(ActorPalette, line_buffer, clip.Left, width); // Finally, draw the decoded, scaled, masked and recolored line onto // the target surface, using the specified shadow mode BompApplyShadow(ShadowMode, ShadowPalette, line_buffer, clip.Left, pn, width, 255); } // Advance to the next line pos_y++; if (MaskPtr.HasValue) { maskPtr.OffsetY(1); } pn.OffsetY(1); } } }
public static void BompApplyShadow(int shadowMode, byte[] shadowPalette, byte[] lineBuffer, int linePos, PixelNavigator dst, int size, byte transparency) { Debug.Assert(size > 0); switch (shadowMode) { case 0: BompApplyShadow0(lineBuffer, linePos, dst, size); break; case 1: BompApplyShadow1(shadowPalette, lineBuffer, linePos, dst, size, transparency); break; case 3: BompApplyShadow3(shadowPalette, lineBuffer, linePos, dst, size, transparency); break; default: throw new ArgumentException(string.Format("Unknown shadow mode {0}", shadowMode)); } }
public static void BompApplyShadow0(byte[] lineBuffer, int linePos, PixelNavigator dst, int size) { while (size-- > 0) { byte tmp = lineBuffer[linePos++]; if (tmp != 255) { dst.Write(tmp); } dst.OffsetX(1); } }
void Proc3Amiga(Codec1 v1) { byte len; int color; bool masked; var mask = new PixelNavigator(v1.MaskPtr); mask.OffsetX(v1.X / 8); var dst = new PixelNavigator(v1.DestPtr); byte height = (byte)_height; byte width = (byte)_width; _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); var maskbit = (byte)ScummHelper.RevBitMask(v1.X & 7); var y = v1.Y; var oldXpos = v1.X; var oldScaleIndexX = _scaleIndexX; // Indy4 Amiga always uses the room map to match colors to the currently // setup palette in the actor code in the original, thus we need to do this // mapping over here too. var amigaMap = (_vm.Game.Platform == Platform.Amiga && _vm.Game.GameId == GameId.Indy4) ? _vm.Gdi.RoomPalette : null; do { len = _loaded.CostumeReader.ReadByte(); color = len >> v1.Shr; len &= v1.Mask; if (len == 0) len = _loaded.CostumeReader.ReadByte(); do { if (ScaleY == 255 || v1.Scaletable[_scaleIndexY] < ScaleY) { masked = (y < 0 || y >= _h) || (v1.X < 0 || v1.X >= _w) || ((mask.Read() & maskbit) != 0); if (color != 0 && !masked) { byte pcolor; if (amigaMap != null) pcolor = amigaMap[_palette[color]]; else pcolor = (byte)_palette[color]; dst.Write(pcolor); } if (ScaleX == 255 || v1.Scaletable[_scaleIndexX] < ScaleX) { v1.X += v1.ScaleXStep; dst.OffsetX(v1.ScaleXStep); maskbit = (byte)ScummHelper.RevBitMask(v1.X & 7); } _scaleIndexX += (byte)v1.ScaleXStep; mask = new PixelNavigator(v1.MaskPtr); mask.OffsetX(v1.X / 8); } if (--width == 0) { if (--height == 0) return; if (y >= _h) return; if (v1.X != oldXpos) { dst.Offset(-(v1.X - oldXpos), 1); mask = new PixelNavigator(v1.MaskPtr); mask.OffsetY(1); v1.MaskPtr = mask; mask.OffsetX(oldXpos / 8); maskbit = (byte)ScummHelper.RevBitMask(oldXpos & 7); y++; } width = (byte)_width; v1.X = oldXpos; _scaleIndexX = oldScaleIndexX; _scaleIndexY++; } } while (--len != 0); } while (true); }
public static void BompApplyMask(byte[] line_buffer, int linePos, PixelNavigator mask, byte maskbit, int size, byte transparency) { while (true) { do { if (size-- == 0) return; if ((mask.Read() & maskbit) != 0) { line_buffer[linePos] = transparency; } linePos++; maskbit >>= 1; } while (maskbit != 0); mask.OffsetX(1); maskbit = 128; } }
protected override void PrepareDrawBitmap(ImageData img, VirtScreen vs, Point p, int width, int height, int stripnr, int numstrip) { var ptr = img.Data; // // Since V3, all graphics data was encoded in strips, which is very efficient // for redrawing only parts of the screen. However, V2 is different: here // the whole graphics are encoded as one big chunk. That makes it rather // difficult to draw only parts of a room/object. We handle the V2 graphics // differently from all other (newer) graphic formats for this reason. // var table = (_objectMode ? null : _roomStrips); int left = (stripnr * 8); int right = left + (numstrip * 8); PixelNavigator navDst; var srcOffset = 0; byte color, data = 0; int run; bool dither = false; byte[] dither_table = new byte[128]; var ditherOffset = 0; int theX, theY, maxX; var surface = vs.HasTwoBuffers ? vs.Surfaces[1] : vs.Surfaces[0]; navDst = new PixelNavigator(surface); navDst.GoTo(p.X * 8, p.Y); var mask_ptr = GetMaskBuffer(p.X, p.Y, 1); if (table != null) { run = table.run[stripnr]; color = (byte)table.color[stripnr]; srcOffset = table.offsets[stripnr]; theX = left; maxX = right; } else { run = 1; color = 0; srcOffset = 0; theX = 0; maxX = width; } // Decode and draw the image data. Debug.Assert(height <= 128); for (; theX < maxX; theX++) { ditherOffset = 0; for (theY = 0; theY < height; theY++) { if (--run == 0) { data = ptr[srcOffset++]; if ((data & 0x80) != 0) { run = data & 0x7f; dither = true; } else { run = data >> 4; dither = false; } color = RoomPalette[data & 0x0f]; if (run == 0) { run = ptr[srcOffset++]; } } if (!dither) { dither_table[ditherOffset] = color; } if (left <= theX && theX < right) { navDst.Write(dither_table[ditherOffset++]); navDst.OffsetY(1); } } if (left <= theX && theX < right) { navDst.Offset(1, -height); } } // Draw mask (zplane) data theY = 0; if (table != null) { srcOffset = table.zoffsets[stripnr]; run = table.zrun[stripnr]; theX = left; } else { run = ptr[srcOffset++]; theX = 0; } while (theX < right) { byte runFlag = (byte)(run & 0x80); if (runFlag != 0) { run &= 0x7f; data = ptr[srcOffset++]; } do { if (runFlag == 0) data = ptr[srcOffset++]; if (left <= theX) { mask_ptr.Write(data); mask_ptr.OffsetY(1); } theY++; if (theY >= height) { if (left <= theX) { mask_ptr.Offset(1, -height); } theY = 0; theX += 8; if (theX >= right) break; } } while ((--run) != 0); run = ptr[srcOffset++]; } }
static byte[] Capture(VirtScreen screen, int x, int y, int w, int h) { var pixels = new byte[w * h]; var nav = new PixelNavigator(screen.Surfaces[0]); nav.GoTo(x, y); for (int height = 0; height < h; height++) { for (int width = 0; width < w; width++) { pixels[height * w + width] = nav.Read(); nav.OffsetX(1); } nav.Offset(-w, 1); } return pixels; }
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 PrintCharIntern(byte[] fontPtr, int charPos, int origWidth, int origHeight, int width, int height, VirtScreen vs, bool ignoreCharsetMask) { int drawTop = Top - vs.TopLine; PixelNavigator? back = null; PixelNavigator dstPtr; Surface dstSurface; if ((ignoreCharsetMask || !vs.HasTwoBuffers)) { dstSurface = vs.Surfaces[0]; dstPtr = new PixelNavigator(vs.Surfaces[0]); dstPtr.GoTo(vs.XStart + Left, drawTop); } else { dstSurface = Vm.TextSurface; dstPtr = new PixelNavigator(dstSurface); dstPtr.GoTo(Left, Top - Vm.ScreenTop); } if (BlitAlso && vs.HasTwoBuffers) { back = dstPtr; dstSurface = vs.Surfaces[0]; dstPtr = new PixelNavigator(dstSurface); dstPtr.GoTo(vs.XStart + Left, drawTop); } if (!ignoreCharsetMask && vs.HasTwoBuffers) { drawTop = Top - Vm.ScreenTop; } DrawBitsN(dstSurface, dstPtr, fontPtr, charPos, fontPtr[_fontPos], drawTop, origWidth, origHeight); if (BlitAlso && vs.HasTwoBuffers) { // FIXME: Revisiting this code, I think the _blitAlso mode is likely broken // right now -- we are copying stuff from "dstPtr" to "back", but "dstPtr" really // only conatains charset data... // One way to fix this: don't copy etc.; rather simply render the char twice, // once to each of the two buffers. That should hypothetically yield // identical results, though I didn't try it and right now I don't know // any spots where I can test this... if (!ignoreCharsetMask) throw new NotSupportedException("This might be broken -- please report where you encountered this to Fingolfin"); // Perform some clipping int w = Math.Min(width, dstSurface.Width - Left); int h = Math.Min(height, dstSurface.Height - drawTop); if (Left < 0) { w += Left; back.Value.OffsetX(-Left); dstPtr.OffsetX(-Left); } if (drawTop < 0) { h += drawTop; back.Value.OffsetY(-drawTop); dstPtr.OffsetY(-drawTop); } // Blit the image data if (w > 0) { while (h-- > 0) { for (int i = 0; i < w; i++) { back.Value.Write(dstPtr.Read()); back.Value.OffsetX(1); dstPtr.OffsetX(1); } back.Value.Offset(-w, 1); dstPtr.Offset(-w, 1); } } } }
protected override bool DrawStrip(PixelNavigator navDst, int width, int height, int stripnr, BinaryReader smapReader) { return false; }
protected virtual void KernelGetFunctions() { var vs = MainVirtScreen; var args = GetStackList(30); switch (args[0]) { case 113: // WORKAROUND for bug #899249: The scripts used for screen savers // in Sam & Max use hard coded values for the maximum height and width. // This causes problems in rooms (ie. Credits) where their values are // lower, so we set result to zero if out of bounds. if (args[1] >= 0 && args[1] <= vs.Width && args[2] >= 0 && args[2] <= vs.Height) { var nav = new PixelNavigator(vs.Surfaces[0]); nav.GoTo(args[1], args[2]); var pixel = nav.Read(); Push(pixel); } else { Push(0); } break; case 115: Push(GetSpecialBox(new Point((short)args[1], (short)args[2]))); break; case 116: Push(CheckXYInBoxBounds(args[3], new Point((short)args[1], (short)args[2]))); break; case 206: Push(RemapPaletteColor(args[1], args[2], args[3], -1)); break; case 207: { var i = GetObjectIndex(args[1]); Debug.Assert(i != 0); Push(_objs[i].Position.X); } break; case 208: { var i = GetObjectIndex(args[1]); Debug.Assert(i != 0); Push(_objs[i].Position.Y); } break; case 209: { var i = GetObjectIndex(args[1]); Debug.Assert(i != 0); Push(_objs[i].Width); } break; case 210: { var i = GetObjectIndex(args[1]); Debug.Assert(i != 0); Push(_objs[i].Height); } break; case 211: /* 13 = thrust 336 = thrust 328 = thrust 27 = abort 97 = left 331 = left 115 = right 333 = right */ Push(GetKeyState(args[1])); break; case 212: { var a = Actors[args[1]]; // This is used by walk scripts Push(a.Frame); } break; case 213: { var slot = GetVerbSlot(args[1], 0); Push(Verbs[slot].CurRect.Left); } break; case 214: { var slot = GetVerbSlot(args[1], 0); Push(Verbs[slot].CurRect.Top); } break; case 215: if ((_extraBoxFlags[args[1]] & 0x00FF) == 0x00C0) { Push(_extraBoxFlags[args[1]]); } else { Push((int)GetBoxFlags((byte)args[1])); } break; default: throw new NotSupportedException(string.Format("KernelGetFunctions: default case {0}", args[0])); } }
protected void GetPixel(int x, int y) { var vs = FindVirtScreen(y); if (vs == null || x > ScreenWidth - 1 || x < 0) { Push(-1); return; } var nav = new PixelNavigator(vs.Surfaces[0]); nav.GoTo(x, y - vs.TopLine); var pixel = nav.Read(); Push(pixel); }
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); }
void Proc3(Codec1 v1) { int y = v1.Y; _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); var dst = new PixelNavigator(v1.DestPtr); var len = v1.RepLen; uint color = v1.RepColor; var height = (uint)_height; var scaleIndexY = _scaleIndexY; var maskbit = (byte)ScummHelper.RevBitMask(v1.X & 7); var mask = new PixelNavigator(v1.MaskPtr); mask.OffsetX(v1.X / 8); bool ehmerde = (len != 0); do { if (!ehmerde) { len = _loaded.CostumeReader.ReadByte(); color = (uint)(len >> v1.Shr); len &= v1.Mask; if (len == 0) len = _loaded.CostumeReader.ReadByte(); } do { if (!ehmerde) { if (ScaleY == 255 || v1.Scaletable[scaleIndexY++] < ScaleY) { var masked = (y < 0 || y >= _h) || (v1.X < 0 || v1.X >= _w) || ((mask.Read() & maskbit) != 0); if (color != 0 && !masked) { byte pcolor; if ((ShadowMode & 0x20) != 0) { pcolor = ShadowTable[dst.Read()]; } else { pcolor = (byte)_palette[color]; if (pcolor == 13 && ShadowTable != null) pcolor = ShadowTable[dst.Read()]; } dst.Write(pcolor); } dst.OffsetY(1); mask.OffsetY(1); y++; } if ((--height) == 0) { if ((--v1.SkipWidth) == 0) return; height = (uint)_height; y = v1.Y; scaleIndexY = _scaleIndexY; if (ScaleX == 255 || v1.Scaletable[_scaleIndexX] < ScaleX) { v1.X += v1.ScaleXStep; if (v1.X < 0 || v1.X >= _w) return; maskbit = (byte)ScummHelper.RevBitMask(v1.X & 7); v1.DestPtr.OffsetX(v1.ScaleXStep); } _scaleIndexX = (byte)(_scaleIndexX + v1.ScaleXStep); dst = new PixelNavigator(v1.DestPtr); mask = new PixelNavigator(v1.MaskPtr); mask.OffsetX(v1.X / 8); } } ehmerde = false; } while ((--len) != 0); } while (true); }
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 override void PrintChar(int chr, bool ignoreCharsetMask) { Rect shadow; Debug.Assert(_current != null); if (chr == '@') return; shadow.Left = Left; shadow.Top = Top; if (FirstChar) { Str.Left = (shadow.Left >= 0) ? shadow.Left : 0; Str.Top = (shadow.Top >= 0) ? shadow.Top : 0; Str.Right = Str.Left; Str.Bottom = Str.Top; FirstChar = false; } int width = _current.GetCharWidth((char)chr); int height = _current.GetCharHeight((char)chr); // bool is2byte = chr >= 256 && _vm._useCJKMode; // if (is2byte) // width = _vm._2byteWidth; shadow.Right = Left + width; shadow.Bottom = Top + height; Surface s; if (!ignoreCharsetMask) { HasMask = true; TextScreen = Vm.MainVirtScreen; } int offsetX = 0; int drawTop = Top; if (ignoreCharsetMask) { VirtScreen vs = Vm.MainVirtScreen; s = vs.Surfaces[0]; offsetX = vs.XStart; } else { s = Vm.TextSurface; drawTop -= Vm.ScreenTop; } var dst = new PixelNavigator(s); dst.GoTo(Left + offsetX, drawTop); // if (chr >= 256 && _vm._useCJKMode) // _current.draw2byte(s, chr, _left, drawTop, _color); // else _current.DrawChar(dst, (char)chr, Left, drawTop, Color); Vm.MarkRectAsDirty(Vm.MainVirtScreen, shadow); if (Str.Left > Left) Str.Left = Left; // Original keeps glyph width and character dimensions separately // if ((_vm._language == Common::ZH_TWN || _vm._language == Common::KO_KOR) && is2byte) // width++; Left += width; if (Str.Right < shadow.Right) Str.Right = shadow.Right; if (Str.Bottom < shadow.Bottom) Str.Bottom = shadow.Bottom; }
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); } }
void Line(int c, int p, Codec1 v1, PixelNavigator? mask, PixelNavigator dst, byte color, byte[] palette) { var pcolor = (color >> c) & 3; if (pcolor != 0) { if (!MaskAt(p, v1, mask)) dst.Write(p, palette[pcolor]); if (!MaskAt(p + 1, v1, mask)) dst.Write(p + 1, palette[pcolor]); } }
public int DrawCostume(VirtScreen vs, int numStrips, Actor actor, bool drawToBackBuf) { var pixelsNavigator = new PixelNavigator(vs.Surfaces[drawToBackBuf ? 1 : 0]); pixelsNavigator.OffsetX(vs.XStart); ActorX += (vs.XStart & 7); _w = vs.Width; _h = vs.Height; pixelsNavigator.OffsetX(-(vs.XStart & 7)); startNav = new PixelNavigator(pixelsNavigator); if (_vm.Game.Version <= 1) { _xmove = 0; _ymove = 0; } else if (_vm.Game.IsOldBundle) { _xmove = -72; _ymove = -100; } else { _xmove = _ymove = 0; } int result = 0; for (int i = 0; i < 16; i++) result |= DrawLimb(actor, i); return result; }
bool MaskAt(int xoff, Codec1 v1, PixelNavigator? mask) { return (mask.HasValue && ((mask.Value.Read(((v1.X + xoff) / 8)) & ScummHelper.RevBitMask((v1.X + xoff) & 7)) != 0)); }
protected void RestoreBackground(Rect rect, byte backColor = 0) { VirtScreen vs; if (rect.Top < 0) rect.Top = 0; if (rect.Left >= rect.Right || rect.Top >= rect.Bottom) return; if ((vs = FindVirtScreen(rect.Top)) == null) return; if (rect.Left > vs.Width) return; // Convert 'rect' to local (virtual screen) coordinates rect.Top -= vs.TopLine; rect.Bottom -= vs.TopLine; rect.Clip(vs.Width, vs.Height); int height = rect.Height; int width = rect.Width; if (_game.Platform == Platform.FMTowns && Game.GameId == GameId.Monkey1 && vs == VerbVirtScreen && rect.Bottom <= 154) rect.Right = 319; MarkRectAsDirty(vs, rect.Left, rect.Right, rect.Top, rect.Bottom, Gdi.UsageBitRestored); var screenBuf = new PixelNavigator(vs.Surfaces[0]); screenBuf.GoTo(vs.XStart + rect.Left, rect.Top); if (height == 0) return; if (vs.HasTwoBuffers && _currentRoom != 0 && IsLightOn()) { var back = new PixelNavigator(vs.Surfaces[1]); back.GoTo(vs.XStart + rect.Left, rect.Top); Gdi.Blit(screenBuf, back, width, height); if (vs == MainVirtScreen && _charset.HasMask) { if (_game.Platform == Platform.FMTowns) { var mask = new PixelNavigator(_textSurface); mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier); Gdi.Fill(mask, 0, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); } else { var mask = new PixelNavigator(_textSurface); mask.GoTo(rect.Left, rect.Top - ScreenTop); Gdi.Fill(mask, CharsetMaskTransparency, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); } } } else { if (Game.Platform == Platform.FMTowns) { backColor |= (byte)(backColor << 4); var mask = new PixelNavigator(_textSurface); mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier); Gdi.Fill(mask, backColor, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier); } if (Game.Features.HasFlag(GameFeatures.Is16BitColor)) Gdi.Fill(screenBuf, _16BitPalette[backColor], width, height); else Gdi.Fill(screenBuf, backColor, width, height); } }
int MainRoutine(int xmoveCur, int ymoveCur) { int i, skip = 0; byte drawFlag = 1; bool use_scaling; byte startScaleIndexX; int ex1, ex2; var rect = new Rect(); int step; var v1 = new Codec1(); const int ScaletableSize = 128; bool newAmiCost = (_vm.Game.Version == 5) && (_vm.Game.Platform == Platform.Amiga); v1.Scaletable = smallCostumeScaleTable; if (_loaded.NumColors == 32) { v1.Mask = 7; v1.Shr = 3; } else { v1.Mask = 15; v1.Shr = 4; } _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); switch (_loaded.Format) { case 0x60: case 0x61: // This format is used e.g. in the Sam&Max intro ex1 = _loaded.CostumeReader.ReadByte(); ex2 = _loaded.CostumeReader.ReadByte(); _srcptr += 2; if (ex1 != 0xFF || ex2 != 0xFF) { _loaded.CostumeReader.BaseStream.Seek(_loaded.FrameOffsets + ex1 * 2, System.IO.SeekOrigin.Begin); ex1 = _loaded.CostumeReader.ReadUInt16(); _loaded.CostumeReader.BaseStream.Seek(_loaded.BasePtr + ex1 + ex2 * 2, System.IO.SeekOrigin.Begin); _srcptr = _loaded.BasePtr + _loaded.CostumeReader.ReadUInt16() + 14; } break; } use_scaling = (ScaleX != 0xFF) || (ScaleY != 0xFF); v1.X = ActorX; v1.Y = ActorY; if (use_scaling) { /* Scale direction */ v1.ScaleXStep = -1; if (xmoveCur < 0) { xmoveCur = -xmoveCur; v1.ScaleXStep = 1; } // It's possible that the scale indexes will overflow and wrap // around to zero, so it's important that we use the same // method of accessing it both when calculating the size of the // scaled costume, and when drawing it. See bug #1519667. if (_mirror) { /* Adjust X position */ startScaleIndexX = _scaleIndexX = (byte)(ScaletableSize - xmoveCur); for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[_scaleIndexX++] < ScaleX) v1.X -= v1.ScaleXStep; } rect.Left = rect.Right = v1.X; _scaleIndexX = startScaleIndexX; for (i = 0; i < _width; i++) { if (rect.Right < 0) { skip++; startScaleIndexX = _scaleIndexX; } if (v1.Scaletable[_scaleIndexX++] < ScaleX) rect.Right++; } } else { /* No mirror */ /* Adjust X position */ startScaleIndexX = _scaleIndexX = (byte)(xmoveCur + ScaletableSize); for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[_scaleIndexX--] < ScaleX) v1.X += v1.ScaleXStep; } rect.Left = rect.Right = v1.X; _scaleIndexX = startScaleIndexX; for (i = 0; i < _width; i++) { if (rect.Left >= _w) { startScaleIndexX = _scaleIndexX; skip++; } if (v1.Scaletable[_scaleIndexX--] < ScaleX) rect.Left--; } } _scaleIndexX = startScaleIndexX; if (skip != 0) skip--; step = -1; if (ymoveCur < 0) { ymoveCur = -ymoveCur; step = 1; } _scaleIndexY = (byte)(ScaletableSize - ymoveCur); for (i = 0; i < ymoveCur; i++) { if (v1.Scaletable[_scaleIndexY++] < ScaleY) v1.Y -= step; } rect.Top = rect.Bottom = v1.Y; _scaleIndexY = (byte)(ScaletableSize - ymoveCur); for (i = 0; i < _height; i++) { if (v1.Scaletable[_scaleIndexY++] < ScaleY) rect.Bottom++; } _scaleIndexY = (byte)(ScaletableSize - ymoveCur); } else { if (!_mirror) xmoveCur = -xmoveCur; v1.X += xmoveCur; v1.Y += ymoveCur; if (_mirror) { rect.Left = v1.X; rect.Right = v1.X + _width; } else { rect.Left = v1.X - _width; rect.Right = v1.X; } rect.Top = v1.Y; rect.Bottom = rect.Top + _height; } v1.SkipWidth = _width; v1.ScaleXStep = _mirror ? 1 : -1; if (_vm.Game.Version == 1) // V1 games uses 8 x 8 pixels for actors _vm.MarkRectAsDirty(_vm.MainVirtScreen, rect.Left, rect.Right + 8, rect.Top, rect.Bottom, ActorID); else _vm.MarkRectAsDirty(_vm.MainVirtScreen, rect.Left, rect.Right + 1, rect.Top, rect.Bottom, ActorID); if (rect.Top >= _h || rect.Bottom <= 0) return 0; if (rect.Left >= _w || rect.Right <= 0) return 0; v1.RepLen = 0; if (_mirror) { if (!use_scaling) skip = -v1.X; if (skip > 0) { if (!newAmiCost && _loaded.Format != 0x57) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = 0; } } else { skip = rect.Right - _w; if (skip <= 0) { drawFlag = 2; } else { v1.SkipWidth -= skip; } } } else { if (!use_scaling) skip = rect.Right - _w; if (skip > 0) { if (!newAmiCost && _loaded.Format != 0x57) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = _w - 1; } } else { // V1 games uses 8 x 8 pixels for actors if (_loaded.Format == 0x57) skip = -8 - rect.Left; else skip = -1 - rect.Left; if (skip <= 0) drawFlag = 2; else v1.SkipWidth -= skip; } } if (v1.SkipWidth <= 0) return 0; if (rect.Left < 0) rect.Left = 0; if (rect.Top < 0) rect.Top = 0; if (rect.Top > _h) rect.Top = _h; if (rect.Bottom > _h) rect.Bottom = _h; if (DrawTop > rect.Top) DrawTop = rect.Top; if (DrawBottom < rect.Bottom) DrawBottom = rect.Bottom; if (_height + rect.Top >= 256) { return 2; } _pixelsNavigator = new PixelNavigator(startNav); _pixelsNavigator.Offset(v1.X, v1.Y); v1.DestPtr = _pixelsNavigator; v1.MaskPtr = _vm.GetMaskBuffer(0, v1.Y, ZBuffer); if (_loaded.Format == 0x57) { // The v1 costume renderer needs the actor number, which is // the same thing as the costume renderer's _actorID. ProcC64(v1, ActorID); } else if (newAmiCost) { Proc3Amiga(v1); } else { Proc3(v1); } return drawFlag; }
void CheckV2MouseOver(Point pos) { var vs = VerbVirtScreen; Rect rect; int i, x, y, new_box = -1; // Don't do anything unless the inventory is active if (!_userState.HasFlag(UserStates.IFaceInventory)) { _mouseOverBoxV2 = -1; return; } if (_cursor.State > 0) { for (i = 0; i < _mouseOverBoxesV2.Length; i++) { if (_mouseOverBoxesV2[i].rect.Contains(pos.X, pos.Y - vs.TopLine)) { new_box = i; break; } } } if ((new_box != _mouseOverBoxV2) || (Game.Version == 0)) { if (_mouseOverBoxV2 != -1) { rect = _mouseOverBoxesV2[_mouseOverBoxV2].rect; var dst = new PixelNavigator(vs.Surfaces[0]); dst.GoTo(rect.Left, rect.Top); // Remove highlight. for (y = rect.Height - 1; y >= 0; y--) { for (x = rect.Width - 1; x >= 0; x--) { if (dst.Read() == _mouseOverBoxesV2[_mouseOverBoxV2].hicolor) dst.Write(_mouseOverBoxesV2[_mouseOverBoxV2].color); dst.OffsetX(1); } dst.Offset(-rect.Width, 1); } MarkRectAsDirty(VerbVirtScreen, rect); } if (new_box != -1) { rect = _mouseOverBoxesV2[new_box].rect; var dst = new PixelNavigator(vs.Surfaces[0]); dst.GoTo(rect.Left, rect.Top); // Apply highlight for (y = rect.Height - 1; y >= 0; y--) { for (x = rect.Width - 1; x >= 0; x--) { if (dst.Read() == _mouseOverBoxesV2[new_box].color) dst.Write(_mouseOverBoxesV2[new_box].hicolor); dst.OffsetX(1); } dst.Offset(-rect.Width, 1); } MarkRectAsDirty(VerbVirtScreen, rect); } _mouseOverBoxV2 = (sbyte)new_box; } }
protected void TownsDrawStripToScreen(VirtScreen vs, int dstX, int dstY, int srcX, int srcY, int width, int height) { if (width <= 0 || height <= 0) return; int m = _textSurfaceMultiplier; var src1 = new PixelNavigator(vs.Surfaces[0]); src1.GoTo(vs.XStart + srcX, srcY); var src2 = new PixelNavigator(_textSurface); src2.GoTo(srcX * m, (srcY + vs.TopLine - ScreenTop) * m); var dst1 = new PixelNavigator(_townsScreen.GetLayerPixels(0, dstX, dstY).Value); var dst2 = new PixelNavigator(_townsScreen.GetLayerPixels(1, dstX * m, dstY * m).Value); int dp1 = _townsScreen.GetLayerPitch(0) - width * _townsScreen.GetLayerBpp(0); int dp2 = _townsScreen.GetLayerPitch(1) - width * m * _townsScreen.GetLayerBpp(1); int sp1 = vs.Pitch - (width * Surface.GetBytesPerPixel(vs.PixelFormat)); int sp2 = _textSurface.Pitch - width * m; if (vs == MainVirtScreen || Game.GameId == GameId.Indy3 || Game.GameId == GameId.Zak) { for (int h = 0; h < height; ++h) { if (Surface.GetBytesPerPixel(_gfxManager.PixelFormat) == 2) { for (int w = 0; w < width; ++w) { dst1.WriteUInt16(_16BitPalette[src1.Read()]); src1.OffsetX(1); dst1.OffsetX(1); } src1.OffsetX(sp1 / src1.BytesByPixel); dst1.OffsetX(dp1 / dst1.BytesByPixel); } else { for (int i = 0; i < width; i++) { dst1.Write(src1.Read()); dst1.OffsetX(1); src1.OffsetX(1); } } for (int sH = 0; sH < m; ++sH) { for (int i = 0; i < width * m; i++) { dst2.Write(src2.Read()); src2.OffsetX(1); dst2.OffsetX(1); } src2.OffsetX(_textSurface.Width - (width * m)); dst2.OffsetX(dst2.Width - (width * m)); } } } else { dst1 = new PixelNavigator(dst2); for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { var t = (src1.Read()) & 0x0f; src1.OffsetX(1); for (int i = 0; i < m; i++) { dst1.Write((byte)((t << 4) | t)); dst1.OffsetX(1); } } dst1 = new PixelNavigator(dst2); var src3 = new PixelNavigator(src2); if (m == 2) { dst2.OffsetY(1); src3.OffsetY(1); } for (int w = 0; w < width * m; ++w) { dst2.Write((byte)(src3.Read() | dst1.Read() & _townsLayer2Mask[src3.Read()])); dst2.OffsetX(1); dst1.Write((byte)(src2.Read() | dst1.Read() & _townsLayer2Mask[src2.Read()])); src2.OffsetX(1); src3.OffsetX(1); dst1.OffsetX(1); } src1.OffsetX(sp1 / src1.BytesByPixel); src2 = new PixelNavigator(src3); src2.OffsetX(sp2 / src2.BytesByPixel); dst1 = new PixelNavigator(dst2); dst1.OffsetX(dp2 / dst1.BytesByPixel); dst2.OffsetX(dp2 / dst2.BytesByPixel); } } _townsScreen.AddDirtyRect(dstX * m, dstY * m, width * m, height * m); }