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; }
System.Drawing.Color ToColor(byte[] pixels, Palette palette, VirtScreen screen, int x, int y) { var index = pixels[y * screen.Width + x]; var c = palette.Colors[index]; return(System.Drawing.Color.FromArgb(c.R, c.G, c.B)); }
void UpdateDirtyScreen(VirtScreen vs) { // Do nothing for unused virtual screens if (vs.Height == 0) { return; } int i; int w = 8; int start = 0; for (i = 0; i < Gdi.NumStrips; i++) { if (vs.BDirty[i] != 0) { int top = vs.TDirty[i]; int bottom = vs.BDirty[i]; vs.TDirty[i] = vs.Height; vs.BDirty[i] = 0; if (i != (Gdi.NumStrips - 1) && vs.BDirty[i + 1] == bottom && vs.TDirty[i + 1] == top) { // Simple optimizations: if two or more neighboring strips // form one bigger rectangle, coalesce them. w += 8; continue; } DrawStripToScreen(vs, start * 8, w, top, bottom); w = 8; } start = i + 1; } }
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); }
System.Drawing.Color ToColor(Room room, VirtScreen screen, int x, int y) { var index = screen.Surfaces[0].Pixels[y * screen.Width + x]; var c = Game.Features.HasFlag(GameFeatures.SixteenColors) ? Palette.Cga.Colors[index] : room.Palette.Colors[index]; return(System.Drawing.Color.FromArgb(c.R, c.G, c.B)); }
void DumpRoomObjectImages(Room room, ObjectData obj, Gdi gdi) { var text = new ScummText(obj.Name); var sb = new StringBuilder(); sb.Append("Object #" + obj.Number).Append(" "); var decoder = new TextDecoder(sb); text.Decode(decoder); sb.AppendFormat(" size: {0}x{1}", obj.Width, obj.Height); Console.WriteLine(sb); var j = 0; foreach (var img in obj.Images) { // try // { var screen = new VirtScreen(0, obj.Width, obj.Height, PixelFormat.Indexed8, 2); if (img.IsBomp) { var bdd = new BompDrawData(); bdd.Src = img.Data; bdd.Dst = new PixelNavigator(screen.Surfaces[0]); bdd.X = 0; bdd.Y = 0; bdd.Width = obj.Width; bdd.Height = obj.Height; bdd.ScaleX = 255; bdd.ScaleY = 255; bdd.DrawBomp(); } else { gdi.DrawBitmap(img, screen, new Point(0, 0), obj.Width, obj.Height & 0xFFF8, 0, obj.Width / 8, room.Header.Width, DrawBitmaps.None, true); } using (var bmp = ToBitmap(room, screen)) { bmp.Save("obj_" + obj.Number + "_" + (++j) + ".png"); } // } // catch (Exception e) // { // Console.ForegroundColor = ConsoleColor.Red; // Console.WriteLine(e); // Console.ResetColor(); // Console.ReadLine(); // } } }
System.Drawing.Bitmap ToBitmap(Room room, VirtScreen screen) { var bmp = new System.Drawing.Bitmap(screen.Width, screen.Height); // DitherCGA(screen.Surfaces[0].Pixels, screen.Surfaces[0].Pitch, 0, 0, screen.Width, screen.Height); var palette = Game.Features.HasFlag(GameFeatures.SixteenColors) ? Palette.Ega : room.Palette; for (int x = 0; x < screen.Width; x++) { for (int y = 0; y < screen.Height; y++) { bmp.SetPixel(x, y, ToColor(screen.Surfaces[0].Pixels, palette, screen, x, y)); } } return(bmp); }
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 InitScreens(int b, int h) { if (_townsScreen != null) { if (_townsClearLayerFlag == 0 && MainVirtScreen != null && ((h - b) != MainVirtScreen.Height)) { _townsScreen.ClearLayer(0); } if (Game.GameId != GameId.Monkey1) { Gdi.Fill(TextSurface, new Rect(0, 0, _textSurface.Width * _textSurfaceMultiplier, _textSurface.Height * _textSurfaceMultiplier), 0); _townsScreen.ClearLayer(1); } } var format = Game.Features.HasFlag(GameFeatures.Is16BitColor) ? PixelFormat.Rgb16 : PixelFormat.Indexed8; _mainVirtScreen = new VirtScreen(b, ScreenWidth, h - b, format, 2, true); _textVirtScreen = new VirtScreen(0, ScreenWidth, b, format, 1); _verbVirtScreen = new VirtScreen(h, ScreenWidth, ScreenHeight - h, format, 1); // Since the size of screen 3 is fixed, there is no need to reallocate // it if its size changed. // Not sure what it is good for, though. I think it may have been used // in pre-V7 for the games messages (like 'Pause', Yes/No dialogs, // version display, etc.). I don't know about V7, maybe the same is the // case there. If so, we could probably just remove it completely. if (_game.Version >= 7) { _unkVirtScreen = new VirtScreen((ScreenHeight / 2) - 10, ScreenWidth, 13, format, 1); } else { _unkVirtScreen = new VirtScreen(80, ScreenWidth, 13, format, 1); } _screenB = b; _screenH = h; Gdi.Init(); }
void DumpRoomImage(Room room, Gdi gdi) { var name = room.Name ?? "room_" + room.Number; var screen = new VirtScreen(0, room.Header.Width, room.Header.Height, PixelFormat.Indexed8, 2); var numStrips = room.Header.Width / 8; gdi.NumStrips = numStrips; gdi.IsZBufferEnabled = false; if (room.Header.Height > 0) { gdi.RoomChanged(room); gdi.DrawBitmap(room.Image, screen, new Point(), room.Header.Width, room.Header.Height, 0, numStrips, room.Header.Width, 0, true); using (var bmpRoom = ToBitmap(room, screen)) { bmpRoom.Save(name + ".png"); } } DumpZPlanes(room, name); }
internal void MarkRectAsDirty(VirtScreen vs, int left, int right, int top, int bottom, int dirtybit = 0) { int lp, rp; if (left > right || top > bottom) { return; } if (top > vs.Height || bottom < 0) { return; } if (top < 0) { top = 0; } if (bottom > vs.Height) { bottom = vs.Height; } if (vs == MainVirtScreen && dirtybit != 0) { lp = left / 8 + _screenStartStrip; if (lp < 0) { lp = 0; } rp = (right + vs.XStart) / 8; if (_game.Version >= 7) { if (rp > 409) { rp = 409; } } else { if (rp >= 200) { rp = 200; } } for (; lp <= rp; lp++) { Gdi.SetGfxUsageBit(lp, dirtybit); } } // The following code used to be in the separate method setVirtscreenDirty lp = left / 8; rp = right / 8; if ((lp >= Gdi.NumStrips) || (rp < 0)) { return; } if (lp < 0) { lp = 0; } if (rp >= Gdi.NumStrips) { rp = Gdi.NumStrips - 1; } while (lp <= rp) { if (top < vs.TDirty[lp]) { vs.TDirty[lp] = top; } if (bottom > vs.BDirty[lp]) { vs.BDirty[lp] = bottom; } lp++; } }
internal void MarkRectAsDirty(VirtScreen vs, Rect r, int dirtybit = 0) { MarkRectAsDirty(vs, r.Left, r.Right, r.Top, r.Bottom, dirtybit); }
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); }
/// <summary> /// Blit the specified rectangle from the given virtual screen to the display. /// Note: t and b are in *virtual screen* coordinates, while x is relative to /// the *real screen*. This is due to the way tdirty/vdirty work: they are /// arrays which map 'strips' (sections of the real screen) to dirty areas as /// specified by top/bottom coordinate in the virtual screen. /// </summary> /// <param name="vs"></param> /// <param name="x"></param> /// <param name="width"></param> /// <param name="top"></param> /// <param name="bottom"></param> void DrawStripToScreen(VirtScreen vs, int x, int width, int top, int bottom) { // Short-circuit if nothing has to be drawn if (bottom <= top || top >= vs.Height) { return; } // Perform some clipping if (width > vs.Width - x) { width = vs.Width - x; } if (top < ScreenTop) { top = ScreenTop; } if (bottom > ScreenTop + ScreenHeight) { bottom = ScreenTop + ScreenHeight; } // Convert the vertical coordinates to real screen coords int y = vs.TopLine + top - ScreenTop; int height = bottom - top; if (width <= 0 || height <= 0) { return; } byte[] src; if (Game.Version < 7) { if (Game.Platform == Platform.FMTowns) { TownsDrawStripToScreen(vs, x, y, x, top, width, height); return; } var srcNav = new PixelNavigator(vs.Surfaces[0]); srcNav.GoTo(vs.XStart + x, top); var compNav = new PixelNavigator(_composite); var txtNav = new PixelNavigator(_textSurface); int m = _textSurfaceMultiplier; txtNav.GoTo(x * m, y * m); var vsPitch = vs.Pitch - width * vs.BytesPerPixel; var textPitch = _textSurface.Pitch - width * m; for (int h = height * m; h > 0; --h) { for (int w = width * m; w > 0; w--) { var temp = txtNav.Read(); int mask = temp ^ CharsetMaskTransparency; mask = (((mask & 0x7f) + 0x7f) | mask) & 0x80; mask = ((mask >> 7) + 0x7f) ^ 0x80; var dst = ((temp ^ srcNav.Read()) & mask) ^ temp; compNav.Write((byte)dst); srcNav.OffsetX(1); txtNav.OffsetX(1); compNav.OffsetX(1); } srcNav.OffsetX(vsPitch); txtNav.OffsetX(textPitch); } src = _composite.Pixels; } else { src = new byte[width * height * vs.BytesPerPixel]; var srcNav = new PixelNavigator(vs.Surfaces[0]); srcNav.GoTo(vs.XStart + x, top); for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { src[h * width + w] = srcNav.Read(); srcNav.OffsetX(1); } srcNav.Offset(-width, 1); } } // Finally blit the whole thing to the screen _gfxManager.CopyRectToScreen(src, width * vs.BytesPerPixel, x, y, width, height); }
static bool VirtScreenContains(VirtScreen vs, int y) { return(y >= vs.TopLine && y < vs.TopLine + vs.Height); }
internal void StartScene(byte room, Actor a = null, int objectNr = 0) { StopTalk(); FadeOut(_switchRoomEffect2); _newEffect = _switchRoomEffect; if (CurrentScript != 0xFF) { if (_slots[CurrentScript].Where == WhereIsObject.Room || _slots[CurrentScript].Where == WhereIsObject.FLObject) { //nukeArrays(CurrentScript); CurrentScript = 0xFF; } else if (_slots[CurrentScript].Where == WhereIsObject.Local) { //if (slots[CurrentScript].cutsceneOverride && _game.version >= 5) // error("Script %d stopped with active cutscene/override in exit", slots[CurrentScript].number); //nukeArrays(CurrentScript); CurrentScript = 0xFF; } } if (VariableNewRoom.HasValue) { _variables[VariableNewRoom.Value] = room; } RunExitScript(); KillScriptsAndResources(); if (_game.Version >= 4) { StopCycle(0); } for (var i = 1; i < Actors.Length; i++) { Actors[i].Hide(); } if (Game.Version >= 7) { // Set the shadow palette(s) to all black. This fixes // bug #795940, and actually makes some sense (after all, // shadows tend to be rather black, don't they? ;-) Array.Clear(_shadowPalette, 0, _shadowPalette.Length); } else { for (var i = 0; i < 256; i++) { Gdi.RoomPalette[i] = (byte)i; if (_shadowPalette != null) { _shadowPalette[i] = (byte)i; } } if (Game.Version < 5) { SetDirtyColors(0, 255); } } Variables[VariableRoom.Value] = room; _fullRedraw = true; _currentRoom = room; if (room >= 0x80 && Game.Version < 7) { _roomResource = _resourceMapper[room & 0x7F]; } else { _roomResource = room; } if (VariableRoomResource.HasValue) { Variables[VariableRoomResource.Value] = _roomResource; } if (room != 0) { ResourceManager.LoadRoom(room); } if (room != 0 && _game.Version == 5 && room == _roomResource) { Variables[VariableRoomFlag.Value] = 1; } ClearRoomObjects(); if (_currentRoom == 0) { if (roomData != null) { _ignoreEntryExitScript = true; roomData.ExitScript.Data = new byte[0]; //roomData.Objects.Clear(); } return; } roomData = _resManager.GetRoom(_roomResource); _ignoreEntryExitScript = false; if (roomData.HasPalette) { SetCurrentPalette(0); } Gdi.NumZBuffer = GetNumZBuffers(); Gdi.TransparentColor = roomData.TransparentColor; ResetRoomSubBlocks(); ResetRoomObjects(); _drawingObjects.Clear(); if (Game.Version >= 7) { // Resize main virtual screen in V7 games. This is necessary // because in V7, rooms may be higher than one screen, so we have // to accomodate for that. _mainVirtScreen = new VirtScreen(MainVirtScreen.TopLine, ScreenWidth, roomData.Header.Height - MainVirtScreen.TopLine, MainVirtScreen.PixelFormat, 2, true); } Gdi.SetMaskHeight(roomData.Header.Height); if (VariableRoomWidth.HasValue && VariableRoomHeight.HasValue) { Variables[VariableRoomWidth.Value] = roomData.Header.Width; Variables[VariableRoomHeight.Value] = roomData.Header.Height; } if (VariableCameraMinX.HasValue) { _variables[VariableCameraMinX.Value] = ScreenWidth / 2; } if (VariableCameraMaxX.HasValue) { _variables[VariableCameraMaxX.Value] = roomData.Header.Width - (ScreenWidth / 2); } if (Game.Version >= 7) { Variables[VariableCameraMinY.Value] = ScreenHeight / 2; Variables[VariableCameraMaxY.Value] = roomData.Header.Height - (ScreenHeight / 2); SetCameraAt(new Point((ScreenWidth / 2), (ScreenHeight / 2))); } else { _camera.Mode = CameraMode.Normal; _camera.CurrentPosition.X = _camera.DestinationPosition.X = (ScreenWidth / 2); _camera.CurrentPosition.Y = _camera.DestinationPosition.Y = (ScreenHeight / 2); } if (_roomResource == 0) { return; } Gdi.ClearGfxUsageBits(); if (_game.Version >= 5 && a != null) { var where = GetWhereIsObject(objectNr); if (where != WhereIsObject.Room && where != WhereIsObject.FLObject) { throw new NotSupportedException(string.Format("StartScene: Object {0} is not in room {1}", objectNr, _currentRoom)); } Point pos; int dir; GetObjectXYPos(objectNr, out pos, out dir); a.PutActor(pos, _currentRoom); a.SetDirection(dir + 180); a.StopActorMoving(); if (Game.GameId == Scumm.IO.GameId.SamNMax) { Camera.CurrentPosition.X = Camera.DestinationPosition.X = a.Position.X; SetCameraAt(a.Position); } } ShowActors(); EgoPositioned = false; TownsResetPalCycleFields(); RunEntryScript(); if (Game.Version >= 1 && Game.Version <= 2) { RunScript(5, false, false, new int[0]); } else if ((Game.Version >= 5) && (Game.Version <= 6)) { if (a != null && !EgoPositioned) { var pos = GetObjectXYPos(objectNr); a.PutActor(pos, _currentRoom); a.Moving = 0; } } else if (_game.Version >= 7) { if (Camera.ActorToFollow != 0) { a = Actors[Camera.ActorToFollow]; SetCameraAt(a.Position); } } _doEffect = true; // Hint the backend about the virtual keyboard during copy protection screens if (_game.GameId == GameId.Monkey2) { if (room == 108) { _inputManager.ShowVirtualKeyboard(); } else { _inputManager.HideVirtualKeyboard(); } } else if (_game.GameId == GameId.Monkey1 && _game.Variant == "ega") { // this is my estimation that the room code is 90 (untested) if (room == 90) { _inputManager.ShowVirtualKeyboard(); } else { _inputManager.HideVirtualKeyboard(); } } }