void Codec1IgnorePakCols(Codec1 v1, int num) { _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); num *= _height; do { v1.RepLen = _loaded.CostumeReader.ReadByte(); v1.RepColor = (byte)(v1.RepLen >> v1.Shr); v1.RepLen &= v1.Mask; if (v1.RepLen == 0) { v1.RepLen = _loaded.CostumeReader.ReadByte(); } do { if ((--num) == 0) { _srcptr = _loaded.CostumeReader.BaseStream.Position; return; } } while ((--v1.RepLen) != 0); } while (true); }
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 Codec1IgnorePakCols(Codec1 v1, int num) { num *= _height; do { v1.RepLen = akcd[_srcptr++]; v1.RepColor = (byte)(v1.RepLen >> v1.Shr); v1.RepLen &= v1.Mask; if (v1.RepLen == 0) { v1.RepLen = akcd[_srcptr++]; } do { if (--num == 0) { return; } } while (--v1.RepLen != 0); } while (true); }
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); }
void ProcC64(Codec1 v1, int actor) { // const byte *mask, *src; // byte *dst; byte len; int y; uint height; byte color; bool rep; y = v1.Y; _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); var dst = v1.DestPtr; len = v1.RepLen; color = v1.RepColor; height = (uint)_height; v1.SkipWidth /= 8; // Set up the palette data byte[] palette = new byte[4]; if (_vm.GetCurrentLights().HasFlag(LightModes.ActorUseColors)) { if (_vm.Game.GameId == GameId.Maniac) { palette[1] = v1MMActorPalatte1[actor]; palette[2] = v1MMActorPalatte2[actor]; } else { // Adjust for C64 version of Zak McKracken palette[1] = (byte)(_vm.Game.Platform == Platform.C64 ? 10 : 8); palette[2] = (byte)_palette[actor]; } } else { palette[2] = 11; palette[3] = 11; } var mask = v1.MaskPtr; var skipInit = false; if (len != 0) skipInit = true; do { if (!skipInit) { len = Init(ref color); } else { skipInit = false; } rep = (len & 0x80) != 0; len &= 0x7f; while ((len--) != 0) { if (!rep) color = _loaded.CostumeReader.ReadByte(); if (0 <= y && y < _h && 0 <= v1.X && v1.X < _w) { if (!_mirror) { Line(0, 0, v1, mask, dst, color, palette); Line(2, 2, v1, mask, dst, color, palette); Line(4, 4, v1, mask, dst, color, palette); Line(6, 6, v1, mask, dst, color, palette); } else { Line(6, 0, v1, mask, dst, color, palette); Line(4, 2, v1, mask, dst, color, palette); Line(2, 4, v1, mask, dst, color, palette); Line(0, 6, v1, mask, dst, color, palette); } } dst.OffsetY(1); y++; mask.OffsetY(1); if ((--height) == 0) { if ((--v1.SkipWidth) == 0) return; height = (uint)_height; y = v1.Y; v1.X += 8 * v1.ScaleXStep; if (v1.X < 0 || v1.X >= _w) return; mask = v1.MaskPtr; v1.DestPtr.OffsetX(8 * v1.ScaleXStep); dst = v1.DestPtr; } } } while (true); }
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]); } }
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)); }
void Codec1IgnorePakCols(Codec1 v1, int num) { _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); num *= _height; do { v1.RepLen = _loaded.CostumeReader.ReadByte(); v1.RepColor = (byte)(v1.RepLen >> v1.Shr); v1.RepLen &= v1.Mask; if (v1.RepLen == 0) v1.RepLen = _loaded.CostumeReader.ReadByte(); do { if ((--num) == 0) { _srcptr = _loaded.CostumeReader.BaseStream.Position; return; } } while ((--v1.RepLen) != 0); } while (true); }
byte Codec1(int xmoveCur, int ymoveCur) { int num_colors; bool use_scaling; int i, j; int skip = 0, startScaleIndexX, startScaleIndexY; Rect rect; int step; byte drawFlag = 1; var v1 = new Codec1(); int scaletableSize = 384; /* implement custom scale table */ // FIXME. HACK // For some illogical reason gcc 3.4.x produces wrong code if // smallCostumeScaleTable from costume.cpp is used here // So I had to put copy of it back here as it was before 1.227 revision // of this file. v1.Scaletable = bigCostumeScaleTable; var table = ((ScummEngine7)_vm).GetStringAddressVar(((ScummEngine7)_vm).VariableCustomScaleTable); if (table != null) { v1.Scaletable = table; } // Setup color decoding variables num_colors = akpl.Length; if (num_colors == 32) { v1.Mask = 7; v1.Shr = 3; } else if (num_colors == 64) { v1.Mask = 3; v1.Shr = 2; } else { v1.Mask = 15; v1.Shr = 4; } use_scaling = (ScaleX != 0xFF) || (ScaleY != 0xFF); v1.X = ActorX; v1.Y = ActorY; v1.BoundsRect.Left = 0; v1.BoundsRect.Top = 0; v1.BoundsRect.Right = _vm.MainVirtScreen.Width; v1.BoundsRect.Bottom = _vm.MainVirtScreen.Height; if (use_scaling) { /* Scale direction */ v1.ScaleXStep = -1; if (xmoveCur < 0) { xmoveCur = -xmoveCur; v1.ScaleXStep = 1; } if (_mirror) { /* Adjust X position */ startScaleIndexX = j = scaletableSize - xmoveCur; for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[j++] < ScaleX) v1.X -= v1.ScaleXStep; } rect.Left = rect.Right = v1.X; j = startScaleIndexX; for (i = 0, skip = 0; i < _width; i++) { if (rect.Right < 0) { skip++; startScaleIndexX = j; } if (v1.Scaletable[j++] < ScaleX) rect.Right++; } } else { /* No mirror */ /* Adjust X position */ startScaleIndexX = j = scaletableSize + xmoveCur; for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[j--] < ScaleX) v1.X += v1.ScaleXStep; } rect.Left = rect.Right = v1.X; j = startScaleIndexX; for (i = 0; i < _width; i++) { if (rect.Left >= v1.BoundsRect.Right) { startScaleIndexX = j; skip++; } if (v1.Scaletable[j--] < ScaleX) rect.Left--; } } if (skip != 0) skip--; step = -1; if (ymoveCur < 0) { ymoveCur = -ymoveCur; step = -step; } startScaleIndexY = scaletableSize - ymoveCur; for (i = 0; i < ymoveCur; i++) { if (v1.Scaletable[startScaleIndexY++] < ScaleY) v1.Y -= step; } rect.Top = rect.Bottom = v1.Y; startScaleIndexY = scaletableSize - ymoveCur; for (i = 0; i < _height; i++) { if (v1.Scaletable[startScaleIndexY++] < ScaleY) rect.Bottom++; } startScaleIndexY = 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; startScaleIndexX = scaletableSize; startScaleIndexY = scaletableSize; } v1.ScaleXIndex = startScaleIndexX; v1.ScaleYIndex = startScaleIndexY; v1.SkipWidth = _width; v1.ScaleXStep = _mirror ? 1 : -1; if (ActorHitMode) { if (ActorHitX < rect.Left || ActorHitX >= rect.Right || ActorHitY < rect.Top || ActorHitY >= rect.Bottom) return 0; } else MarkRectAsDirty(rect); if (rect.Top >= v1.BoundsRect.Bottom || rect.Bottom <= v1.BoundsRect.Top) return 0; if (rect.Left >= v1.BoundsRect.Right || rect.Right <= v1.BoundsRect.Left) return 0; v1.RepLen = 0; if (_mirror) { if (!use_scaling) skip = v1.BoundsRect.Left - v1.X; if (skip > 0) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = v1.BoundsRect.Left; } else { skip = rect.Right - v1.BoundsRect.Right; if (skip <= 0) { drawFlag = 2; } else { v1.SkipWidth -= skip; } } } else { if (!use_scaling) skip = rect.Right - v1.BoundsRect.Right + 1; if (skip > 0) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = v1.BoundsRect.Right - 1; } else { skip = (v1.BoundsRect.Left - 1) - rect.Left; if (skip <= 0) drawFlag = 2; else v1.SkipWidth -= skip; } } if (v1.SkipWidth <= 0 || _height <= 0) return 0; if (rect.Left < v1.BoundsRect.Left) rect.Left = v1.BoundsRect.Left; if (rect.Top < v1.BoundsRect.Top) rect.Top = v1.BoundsRect.Top; if (rect.Top > v1.BoundsRect.Bottom) rect.Top = v1.BoundsRect.Bottom; if (rect.Bottom > v1.BoundsRect.Bottom) rect.Bottom = v1.BoundsRect.Bottom; if (DrawTop > rect.Top) DrawTop = rect.Top; if (DrawBottom < rect.Bottom) DrawBottom = rect.Bottom; _pixelsNavigator = new PixelNavigator(startNav); _pixelsNavigator.Offset(v1.X, v1.Y); v1.DestPtr = _pixelsNavigator; Codec1GenericDecode(v1); return drawFlag; }
byte Codec1(int xmoveCur, int ymoveCur) { int num_colors; bool use_scaling; int i, j; int skip = 0, startScaleIndexX, startScaleIndexY; Rect rect; int step; byte drawFlag = 1; var v1 = new Codec1(); int scaletableSize = 384; /* implement custom scale table */ // FIXME. HACK // For some illogical reason gcc 3.4.x produces wrong code if // smallCostumeScaleTable from costume.cpp is used here // So I had to put copy of it back here as it was before 1.227 revision // of this file. v1.Scaletable = bigCostumeScaleTable; var table = ((ScummEngine7)_vm).GetStringAddressVar(((ScummEngine7)_vm).VariableCustomScaleTable); if (table != null) { v1.Scaletable = table; } // Setup color decoding variables num_colors = akpl.Length; if (num_colors == 32) { v1.Mask = 7; v1.Shr = 3; } else if (num_colors == 64) { v1.Mask = 3; v1.Shr = 2; } else { v1.Mask = 15; v1.Shr = 4; } use_scaling = (ScaleX != 0xFF) || (ScaleY != 0xFF); v1.X = ActorX; v1.Y = ActorY; v1.BoundsRect.Left = 0; v1.BoundsRect.Top = 0; v1.BoundsRect.Right = _vm.MainVirtScreen.Width; v1.BoundsRect.Bottom = _vm.MainVirtScreen.Height; if (use_scaling) { /* Scale direction */ v1.ScaleXStep = -1; if (xmoveCur < 0) { xmoveCur = -xmoveCur; v1.ScaleXStep = 1; } if (_mirror) { /* Adjust X position */ startScaleIndexX = j = scaletableSize - xmoveCur; for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[j++] < ScaleX) { v1.X -= v1.ScaleXStep; } } rect.Left = rect.Right = v1.X; j = startScaleIndexX; for (i = 0, skip = 0; i < _width; i++) { if (rect.Right < 0) { skip++; startScaleIndexX = j; } if (v1.Scaletable[j++] < ScaleX) { rect.Right++; } } } else { /* No mirror */ /* Adjust X position */ startScaleIndexX = j = scaletableSize + xmoveCur; for (i = 0; i < xmoveCur; i++) { if (v1.Scaletable[j--] < ScaleX) { v1.X += v1.ScaleXStep; } } rect.Left = rect.Right = v1.X; j = startScaleIndexX; for (i = 0; i < _width; i++) { if (rect.Left >= v1.BoundsRect.Right) { startScaleIndexX = j; skip++; } if (v1.Scaletable[j--] < ScaleX) { rect.Left--; } } } if (skip != 0) { skip--; } step = -1; if (ymoveCur < 0) { ymoveCur = -ymoveCur; step = -step; } startScaleIndexY = scaletableSize - ymoveCur; for (i = 0; i < ymoveCur; i++) { if (v1.Scaletable[startScaleIndexY++] < ScaleY) { v1.Y -= step; } } rect.Top = rect.Bottom = v1.Y; startScaleIndexY = scaletableSize - ymoveCur; for (i = 0; i < _height; i++) { if (v1.Scaletable[startScaleIndexY++] < ScaleY) { rect.Bottom++; } } startScaleIndexY = 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; startScaleIndexX = scaletableSize; startScaleIndexY = scaletableSize; } v1.ScaleXIndex = startScaleIndexX; v1.ScaleYIndex = startScaleIndexY; v1.SkipWidth = _width; v1.ScaleXStep = _mirror ? 1 : -1; if (ActorHitMode) { if (ActorHitX < rect.Left || ActorHitX >= rect.Right || ActorHitY < rect.Top || ActorHitY >= rect.Bottom) { return(0); } } else { MarkRectAsDirty(rect); } if (rect.Top >= v1.BoundsRect.Bottom || rect.Bottom <= v1.BoundsRect.Top) { return(0); } if (rect.Left >= v1.BoundsRect.Right || rect.Right <= v1.BoundsRect.Left) { return(0); } v1.RepLen = 0; if (_mirror) { if (!use_scaling) { skip = v1.BoundsRect.Left - v1.X; } if (skip > 0) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = v1.BoundsRect.Left; } else { skip = rect.Right - v1.BoundsRect.Right; if (skip <= 0) { drawFlag = 2; } else { v1.SkipWidth -= skip; } } } else { if (!use_scaling) { skip = rect.Right - v1.BoundsRect.Right + 1; } if (skip > 0) { v1.SkipWidth -= skip; Codec1IgnorePakCols(v1, skip); v1.X = v1.BoundsRect.Right - 1; } else { skip = (v1.BoundsRect.Left - 1) - rect.Left; if (skip <= 0) { drawFlag = 2; } else { v1.SkipWidth -= skip; } } } if (v1.SkipWidth <= 0 || _height <= 0) { return(0); } if (rect.Left < v1.BoundsRect.Left) { rect.Left = v1.BoundsRect.Left; } if (rect.Top < v1.BoundsRect.Top) { rect.Top = v1.BoundsRect.Top; } if (rect.Top > v1.BoundsRect.Bottom) { rect.Top = v1.BoundsRect.Bottom; } if (rect.Bottom > v1.BoundsRect.Bottom) { rect.Bottom = v1.BoundsRect.Bottom; } if (DrawTop > rect.Top) { DrawTop = rect.Top; } if (DrawBottom < rect.Bottom) { DrawBottom = rect.Bottom; } _pixelsNavigator = new PixelNavigator(startNav); _pixelsNavigator.Offset(v1.X, v1.Y); v1.DestPtr = _pixelsNavigator; Codec1GenericDecode(v1); return(drawFlag); }
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); }
void ProcC64(Codec1 v1, int actor) { // const byte *mask, *src; // byte *dst; byte len; int y; uint height; byte color; bool rep; y = v1.Y; _loaded.CostumeReader.BaseStream.Seek(_srcptr, System.IO.SeekOrigin.Begin); var dst = v1.DestPtr; len = v1.RepLen; color = v1.RepColor; height = (uint)_height; v1.SkipWidth /= 8; // Set up the palette data byte[] palette = new byte[4]; if (_vm.GetCurrentLights().HasFlag(LightModes.ActorUseColors)) { if (_vm.Game.GameId == GameId.Maniac) { palette[1] = v1MMActorPalatte1[actor]; palette[2] = v1MMActorPalatte2[actor]; } else { // Adjust for C64 version of Zak McKracken palette[1] = (byte)(_vm.Game.Platform == Platform.C64 ? 10 : 8); palette[2] = (byte)_palette[actor]; } } else { palette[2] = 11; palette[3] = 11; } var mask = v1.MaskPtr; var skipInit = false; if (len != 0) { skipInit = true; } do { if (!skipInit) { len = Init(ref color); } else { skipInit = false; } rep = (len & 0x80) != 0; len &= 0x7f; while ((len--) != 0) { if (!rep) { color = _loaded.CostumeReader.ReadByte(); } if (0 <= y && y < _h && 0 <= v1.X && v1.X < _w) { if (!_mirror) { Line(0, 0, v1, mask, dst, color, palette); Line(2, 2, v1, mask, dst, color, palette); Line(4, 4, v1, mask, dst, color, palette); Line(6, 6, v1, mask, dst, color, palette); } else { Line(6, 0, v1, mask, dst, color, palette); Line(4, 2, v1, mask, dst, color, palette); Line(2, 4, v1, mask, dst, color, palette); Line(0, 6, v1, mask, dst, color, palette); } } dst.OffsetY(1); y++; mask.OffsetY(1); if ((--height) == 0) { if ((--v1.SkipWidth) == 0) { return; } height = (uint)_height; y = v1.Y; v1.X += 8 * v1.ScaleXStep; if (v1.X < 0 || v1.X >= _w) { return; } mask = v1.MaskPtr; v1.DestPtr.OffsetX(8 * v1.ScaleXStep); dst = v1.DestPtr; } } } while (true); }
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)); }
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 Codec1GenericDecode(Codec1 v1) { bool skip_column = false; var y = v1.Y; var src = _srcptr; var dst = v1.DestPtr; var len = v1.RepLen; var color = v1.RepColor; var height = _height; var scaleytab = v1.ScaleYIndex; var maskbit = ScummHelper.RevBitMask(v1.X & 7); var mask = _vm.GetMaskBuffer(v1.X - (_vm.MainVirtScreen.XStart & 7), v1.Y, ZBuffer); bool ehmerde = (len != 0); do { if (!ehmerde) { len = akcd[src++]; color = (byte)(len >> v1.Shr); len &= v1.Mask; if (len == 0) len = akcd[src++]; } do { if (!ehmerde) { if (ScaleY == 255 || v1.Scaletable[scaleytab++] < ScaleY) { if (ActorHitMode) { if (color != 0 && y == ActorHitY && v1.X == ActorHitX) { ActorHitResult = true; return; } } else { bool masked = (y < v1.BoundsRect.Top || y >= v1.BoundsRect.Bottom) || (v1.X < 0 || v1.X >= v1.BoundsRect.Right) || ((mask.Read() & maskbit) != 0); if (color != 0 && !masked && !skip_column) { var pcolor = _palette[color]; if (ShadowMode == 1) { if (pcolor == 13) pcolor = ShadowTable[dst.Read()]; } else if (ShadowMode == 2) { throw new NotImplementedException("codec1_spec2"); // TODO } else if (ShadowMode == 3) { if (_vm.Game.Features.HasFlag(GameFeatures.Is16BitColor)) { ushort srcColor = (ushort)((pcolor >> 1) & 0x7DEF); ushort dstColor = (ushort)((dst.ReadUInt16() >> 1) & 0x7DEF); pcolor = (ushort)(srcColor + dstColor); } else if (pcolor < 8) { pcolor = (ushort)((pcolor << 8) + dst.Read()); pcolor = ShadowTable[pcolor]; } } if (_vm.MainVirtScreen.BytesPerPixel == 2) { dst.WriteUInt16(pcolor); } else { dst.Write((byte)pcolor); } } } dst.OffsetY(1); mask.OffsetY(1); y++; } if (--height == 0) { if (--v1.SkipWidth == 0) return; height = _height; y = v1.Y; scaleytab = v1.ScaleYIndex; if (ScaleX == 255 || v1.Scaletable[v1.ScaleXIndex] < ScaleX) { v1.X += v1.ScaleXStep; if (v1.X < 0 || v1.X >= v1.BoundsRect.Right) return; maskbit = ScummHelper.RevBitMask(v1.X & 7); v1.DestPtr.OffsetX(v1.ScaleXStep); skip_column = false; } else skip_column = true; v1.ScaleXIndex += v1.ScaleXStep; dst = v1.DestPtr; mask = _vm.GetMaskBuffer(v1.X - (_vm.MainVirtScreen.XStart & 7), v1.Y, ZBuffer); } } ehmerde = false; } while (--len != 0); } while (true); }
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); }
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); }
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 Codec1GenericDecode(Codec1 v1) { bool skip_column = false; var y = v1.Y; var src = _srcptr; var dst = v1.DestPtr; var len = v1.RepLen; var color = v1.RepColor; var height = _height; var scaleytab = v1.ScaleYIndex; var maskbit = ScummHelper.RevBitMask(v1.X & 7); var mask = _vm.GetMaskBuffer(v1.X - (_vm.MainVirtScreen.XStart & 7), v1.Y, ZBuffer); bool ehmerde = (len != 0); do { if (!ehmerde) { len = akcd[src++]; color = (byte)(len >> v1.Shr); len &= v1.Mask; if (len == 0) { len = akcd[src++]; } } do { if (!ehmerde) { if (ScaleY == 255 || v1.Scaletable[scaleytab++] < ScaleY) { if (ActorHitMode) { if (color != 0 && y == ActorHitY && v1.X == ActorHitX) { ActorHitResult = true; return; } } else { bool masked = (y < v1.BoundsRect.Top || y >= v1.BoundsRect.Bottom) || (v1.X < 0 || v1.X >= v1.BoundsRect.Right) || ((mask.Read() & maskbit) != 0); if (color != 0 && !masked && !skip_column) { var pcolor = _palette[color]; if (ShadowMode == 1) { if (pcolor == 13) { pcolor = ShadowTable[dst.Read()]; } } else if (ShadowMode == 2) { throw new NotImplementedException("codec1_spec2"); // TODO } else if (ShadowMode == 3) { if (_vm.Game.Features.HasFlag(GameFeatures.Is16BitColor)) { ushort srcColor = (ushort)((pcolor >> 1) & 0x7DEF); ushort dstColor = (ushort)((dst.ReadUInt16() >> 1) & 0x7DEF); pcolor = (ushort)(srcColor + dstColor); } else if (pcolor < 8) { pcolor = (ushort)((pcolor << 8) + dst.Read()); pcolor = ShadowTable[pcolor]; } } if (_vm.MainVirtScreen.BytesPerPixel == 2) { dst.WriteUInt16(pcolor); } else { dst.Write((byte)pcolor); } } } dst.OffsetY(1); mask.OffsetY(1); y++; } if (--height == 0) { if (--v1.SkipWidth == 0) { return; } height = _height; y = v1.Y; scaleytab = v1.ScaleYIndex; if (ScaleX == 255 || v1.Scaletable[v1.ScaleXIndex] < ScaleX) { v1.X += v1.ScaleXStep; if (v1.X < 0 || v1.X >= v1.BoundsRect.Right) { return; } maskbit = ScummHelper.RevBitMask(v1.X & 7); v1.DestPtr.OffsetX(v1.ScaleXStep); skip_column = false; } else { skip_column = true; } v1.ScaleXIndex += v1.ScaleXStep; dst = v1.DestPtr; mask = _vm.GetMaskBuffer(v1.X - (_vm.MainVirtScreen.XStart & 7), v1.Y, ZBuffer); } } ehmerde = false; } while (--len != 0); } while (true); }
void Codec1IgnorePakCols(Codec1 v1, int num) { num *= _height; do { v1.RepLen = akcd[_srcptr++]; v1.RepColor = (byte)(v1.RepLen >> v1.Shr); v1.RepLen &= v1.Mask; if (v1.RepLen == 0) v1.RepLen = akcd[_srcptr++]; do { if (--num == 0) return; } while (--v1.RepLen != 0); } while (true); }