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); }
void DrawFlashlight() { int i, j, x, y; var vs = MainVirtScreen; // Remove the flash light first if it was previously drawn if (_flashlight.IsDrawn) { MarkRectAsDirty(MainVirtScreen, _flashlight.X, _flashlight.X + _flashlight.W, _flashlight.Y, _flashlight.Y + _flashlight.H, Gdi.UsageBitDirty); if (_flashlight.PixelNavigator.HasValue) { Gdi.Fill(_flashlight.PixelNavigator.Value, 0, _flashlight.W, _flashlight.H); } _flashlight.IsDrawn = false; } if (_flashlight.XStrips == 0 || _flashlight.YStrips == 0) { return; } // Calculate the area of the flashlight if (Game.GameId == GameId.Zak || Game.GameId == GameId.Maniac) { x = _mousePos.X + vs.XStart; y = _mousePos.Y - vs.TopLine; } else { var a = Actors[Variables[VariableEgo.Value]]; x = a.Position.X; y = a.Position.Y; } _flashlight.W = _flashlight.XStrips * 8; _flashlight.H = _flashlight.YStrips * 8; _flashlight.X = x - _flashlight.W / 2 - _screenStartStrip * 8; _flashlight.Y = y - _flashlight.H / 2; if (Game.GameId == GameId.Loom) { _flashlight.Y -= 12; } // Clip the flashlight at the borders if (_flashlight.X < 0) { _flashlight.X = 0; } else if (_flashlight.X + _flashlight.W > Gdi.NumStrips * 8) { _flashlight.X = Gdi.NumStrips * 8 - _flashlight.W; } if (_flashlight.Y < 0) { _flashlight.Y = 0; } else if (_flashlight.Y + _flashlight.H > vs.Height) { _flashlight.Y = vs.Height - _flashlight.H; } // Redraw any actors "under" the flashlight for (i = _flashlight.X / 8; i < (_flashlight.X + _flashlight.W) / 8; i++) { Debug.Assert(0 <= i && i < Gdi.NumStrips); Gdi.SetGfxUsageBit(_screenStartStrip + i, Gdi.UsageBitDirty); vs.TDirty[i] = 0; vs.BDirty[i] = vs.Height; } var pn = new PixelNavigator(vs.Surfaces[0]); pn.GoTo(_flashlight.X + vs.XStart, _flashlight.Y); pn = new PixelNavigator(pn); _flashlight.PixelNavigator = pn; var bgbak = new PixelNavigator(vs.Surfaces[1]); bgbak.GoTo(_flashlight.X + vs.XStart, _flashlight.Y); Gdi.Blit(pn, bgbak, _flashlight.W, _flashlight.H); // Round the corners. To do so, we simply hard-code a set of nicely // rounded corners. var corner_data = new [] { 8, 6, 4, 3, 2, 2, 1, 1 }; int minrow = 0; int maxcol = (_flashlight.W - 1); int maxrow = (_flashlight.H - 1); for (i = 0; i < 8; i++, minrow++, maxrow--) { int d = corner_data[i]; for (j = 0; j < d; j++) { if (vs.BytesPerPixel == 2) { pn.GoTo(j, minrow); pn.WriteUInt16(0); pn.GoTo(maxcol - j, minrow); pn.WriteUInt16(0); pn.GoTo(j, maxrow); pn.WriteUInt16(0); pn.GoTo(maxcol - j, maxrow); pn.WriteUInt16(0); } else { pn.GoTo(j, minrow); pn.Write(0); pn.GoTo(maxcol - j, minrow); pn.Write(0); pn.GoTo(j, maxrow); pn.Write(0); pn.GoTo(maxcol - j, maxrow); pn.Write(0); } } } _flashlight.IsDrawn = true; }