unit VSwap;

{$O+,F+,S-}

interface

const

  smFont8x8       = $100;
  smGraphics      = $200;
  smNoClearScreen = $8000;

type

  ScreenType = (scUser, scTurbo, scCheck);

const

  InitMode: Byte = 0;
  Ega43Lines: Boolean = False;
  DualMonitor: Boolean = False;
  EgaPaletteSave: Boolean = False;
  GraphicsSwap: Boolean = False;
  VUseEms: Boolean = True;
  SnowCheck: Boolean = True;
  ScreenSize: Word = 0;
  CursorPos: Word = 0;

function  GetMode: Word;
procedure SetMode(Mode: Word);
procedure SwapScreen(Screen: ScreenType; SaveMouse: Boolean);
procedure GetUserScreen(X, Y: Word; var Buf; Size: Word);
procedure ShowTurboScreen;
procedure CheckUserScreen;
procedure ShowUserScreen;
procedure InitVSwap;
procedure DoneVSwap;

implementation

uses Drivers, Mem, Memory;

const

  Mda  = $01;
  Cga  = $02;
  Ega  = $04;
  MCga = $08;
  Vga  = $10;

type

  TVideoState = record
    Equipment: Word;
    VideoMode: Byte;
    NumCols: Word;
    RegenSize: Word;
    StartAddr: Word;
    CursorPos: array[0..7] of Word;
    CursorShape: Word;
    ActivePage: Byte;
    Addr6845: Word;
    CrtMode: Byte;
    CrtPalette: Byte;
    EgaRows: Byte;
    EgaBytesPerChar: Word;
    EgaMisc: array[0..3] of Byte;
  end;

  TEgaPalette = array[0..17] of Byte;

  TSavedScreen = record
    Mode: Word;
    VideoState: TVideoState;
    Palette: TEgaPalette;
    MouseState: Pointer;
  end;

  PEgaPtrs = ^TEgaPtrs;
  TEgaPtrs = array[0..6] of Pointer;

const

  CurrentScreen: ScreenType = scUser;
  FirstOn: Boolean = True;
  ModeChanged: Boolean = False;
  CgaSwapAreaSize: Word = 0;
  EgaSwapAreaSize: Word = 0;
  SaveEgaPtrs: PEgaPtrs = nil;

var

  MonitorTypes: Word;
  MouseSaveSize: Word;
  CgaSwapArea: Pointer;
  EgaSwapArea: Pointer;
  Screens: array[ScreenType] of TSavedScreen;
  NewEgaPtrs: TEgaPtrs;
  NewArea: array[0..255] of Byte;

  Addr6845: Word absolute $40:$63;
  EgaPtrs: PEgaPtrs absolute $40:$A8;

procedure Int10; near; assembler;
asm
        PUSH    ES
        PUSH    DI
        PUSH    SI
        PUSH    BP
        INT     10H
        POP     BP
        POP     SI
        POP     DI
        POP     ES
end;

procedure Check6845; near; assembler;
asm
        PUSH    AX
        MOV     AL,0FH
        OUT     DX,AL
        INC     DX
        IN      AL,DX
        PUSH    AX
        MOV     AL,66H
        OUT     DX,AL
        MOV     CX,256
@@1:    LOOP    @@1
        IN      AL,DX
        CMP     AL,66H
        POP     AX
        OUT     DX,AL
        POP     AX
end;

procedure DetectMonitors; near; assembler;
const
  MonitorCodes: array[0..13] of Byte=
    (0, Mda, Cga, 0, Ega, Ega, 0, Vga, Vga, 0, MCga, MCga, MCga, 0);
asm
        MOV     AX,40H
        MOV     ES,AX
        MOV     AX,1A00H
        CALL    Int10
        CMP     AL,1AH
        JNE     @@1
        XCHG    AX,BX
        MOV     BX,OFFSET MonitorCodes
        XLAT
        XCHG    AL,AH
        XLAT
        CMP     ES:49H.Byte,smMono
        JE      @@4
        XCHG    AL,AH
        JMP     @@4
@@1:    MOV     BL,10H
        MOV     AH,12H
        CALL    Int10
        XOR     AX,AX
        CMP     BL,10H
        JE      @@2
        MOV     AL,Ega
        OR      BH,BH
        JZ      @@2
        XCHG    AL,AH
@@2:    OR      AL,AL
        JNZ     @@3
        MOV     DX,3D4H
        CALL    Check6845
        JNZ     @@3
        MOV     AL,Cga
@@3:    OR      AH,AH
        JNZ     @@4
        MOV     DX,3B4H
        CALL    Check6845
        JNZ     @@4
        MOV     AH,Mda
@@4:    MOV     MonitorTypes,AX
end;

function GetMonitorTypes: Word; assembler;
asm
        MOV     AX,40H
        MOV     ES,AX
        MOV     AX,MonitorTypes
        CMP     ES:49H.Byte,smMono
        JNE     @@1
        XCHG    AL,AH
@@1:
end;

function GetMode: Word; assembler;
asm
        MOV	AX,40H
        MOV	ES,AX
        MOV	AL,ES:49H
        MOV	AH,0
        MOV	DX,MonitorTypes
        CMP	AL,smCO80+1
        JB	@@1
        CMP	AL,smMono
        JNE	@@2
        XCHG	DL,DH
        TEST	DL,Mda
        JZ	@@1
        TEST	ES:65H.Byte,2
        JZ	@@2
        MOV	AH,smGraphics SHR 8
        JMP	@@2
@@1:    TEST	DL,Ega+Vga
        JZ	@@2
        CMP	ES:84H.Byte,24
        JE	@@2
        MOV	AH,smFont8x8 SHR 8
@@2:
end;

procedure DoSetMode; near; assembler;
const
  CrtData: array[0..11] of Byte =
    ($35, $2D, $2E, $07, $5B, $02, $57, $57, $02, $03, $00, $00);
  ModeSelect: array[0..8] of Byte =
    ($2C, $28, $2D, $29, $2A, $2E, $1E, $29, $0B);
  ScrWidth: array[0..8] of Byte =
    (40, 40, 80, 80, 40, 40, 80, 80, 80);
  RegenSize: array[0..8] of Byte =
    ($08, $08, $10, $10, $40, $40, $40, $10, $80);
asm
        TEST    AH,smNoClearScreen SHR 8
        JZ      @@1
        TEST    DL,Ega+MCga+Vga
        JZ      @@2
        OR      AL,80H
@@1:    MOV     AH,0
        CALL    Int10
        AND     ES:87H.Byte,7FH
        JMP     @@9
@@2:    OR      ES:87H.Byte,8
        MOV     BL,AL
        XOR     BH,BH
        MOV     DI,49H
        CLD
        STOSB
        MOV     CX,1DH
        XOR     AL,AL
        REP     STOSB
        PUSH    DS
        TEST    AH,smGraphics SHR 8
        JZ      @@3
        MOV     DX,3BFH
        MOV     AL,1
        OUT     DX,AL
        MOV     BL,8
        MOV     SI,OFFSET CrtData
        MOV     CX,12
        JMP     @@4
@@3:    XOR     AL,AL
        MOV     DX,3D4H
        XOR     SI,SI
        MOV     DS,SI
        LDS     SI,DS:(1DH*4)
        MOV     CX,16
        CMP     BL,smBW80
        JB      @@5
        ADD     SI,CX
        CMP     BL,smCO80+1
        JB      @@5
        ADD     SI,CX
        CMP     BL,smMono
        JB      @@5
        ADD     SI,CX
@@4:    MOV     AL,1
        MOV     DX,3B4H
@@5:    MOV     ES:Addr6845,DX
        ADD     DL,4
        OUT     DX,AL
        SUB     DL,4
        MOV     AX,[SI+10]
        XCHG    AL,AH
        MOV     ES:60H,AX
        PUSH    BX
        XOR     BX,BX
@@6:    MOV     AL,BL
        OUT     DX,AL
        JMP     @@7
@@7:    MOV     AL,[BX+SI]
        INC     DX
        OUT     DX,AL
        DEC     DX
        INC     BX
        LOOP    @@6
        POP     BX
        POP     DS
        MOV     AL,ModeSelect.Byte[BX]
        MOV     ES:65H,AL
        ADD     DL,4
        OUT     DX,AL
        MOV     AL,30H
        CMP     BL,6
        JNE     @@8
        MOV     AL,3FH
@@8:    MOV     ES:66H,AL
        INC     DX
        OUT     DX,AL
        MOV     AL,ScrWidth.Byte[BX]
        XOR     AH,AH
        MOV     ES:4AH,AX
        XOR     AL,AL
        MOV     AH,RegenSize.Byte[BX]
        MOV     ES:4CH,AX
@@9:
end;

procedure SetMode(Mode: Word); assembler;
asm
        MOV     AX,40H
        MOV     ES,AX
        MOV     AX,Mode
        MOV     CL,20H
        MOV     DX,MonitorTypes
        CMP     AL,smMono
        JNE     @@1
        MOV     CL,30H
        XCHG    DL,DH
@@1:    AND     ES:10H.Byte,0CFH
        OR      ES:10H,CL
        AND     ES:87H.Byte,0FEH
        PUSH    AX
        CALL    DoSetMode
        POP     AX
        TEST    AH,smFont8x8 SHR 8
        JZ      @@2
        MOV     AX,1112H
        MOV     BL,0
        CALL    Int10
        CMP     ES:84H.Byte,42
        JNE     @@2
        OR      ES:87H.Byte,1
        MOV     AH,1
        MOV     CX,600H
        CALL    Int10
        MOV     AH,12H
        MOV     BL,20H
        CALL    Int10
@@2:
end;

procedure SaveVideoState(var VS: TVideoState); near; assembler;
asm
        PUSH    DS
        LES     DI,VS
        MOV     SI,40H
        MOV     DS,SI
        CLD
        MOV     SI,10H
        MOVSW
        MOV     SI,49H
        MOV     CX,1EH
        REP     MOVSB
        MOV     SI,84H
        MOV     CX,7
        REP     MOVSB
        POP     DS
end;

procedure RestoreVideoState(var VS: TVideoState); near; assembler;
asm
        PUSH    DS
        LDS     SI,VS
        MOV     DI,40H
        MOV     ES,DI
        CLD
        MOV     DI,10H
        MOVSW
        MOV     DI,49H
        MOV     CX,1EH
        REP     MOVSB
        MOV     DI,84H
        MOV     CX,7
        REP     MOVSB
        POP     DS
        MOV     DX,ES:Addr6845
        ADD     DL,4
        MOV     AL,ES:65H
        OUT     DX,AL
        CMP     ES:49H.Byte,4
        JAE     @@1
        MOV     AL,ES:62H
        MOV     AH,5
        CALL    Int10
@@1:    MOV     BL,ES:62H
        XOR     BH,BH
        SHL     BX,1
        MOV     DX,ES:50H[BX]
        MOV     BH,ES:62H
        MOV     AH,2
        CALL    Int10
        MOV     CX,ES:60H
        MOV     AH,1
        CALL    Int10
end;

procedure SaveEgaPalette(var Buf: TEgaPalette); near; assembler;
asm
        PUSH    DS
        LES     DI,Buf
        CLD
        CMP     EgaPaletteSave,0
        JE      @@3
        MOV     AX,MonitorTypes
        MOV     DX,40H
        MOV     DS,DX
        CMP     DS:49H.Byte,smMono
        JNE     @@1
        MOV     AL,AH
@@1:    TEST    AL,Ega
        JZ      @@2
        LDS     SI,DS:EgaPtrs
        LDS     SI,[SI+4]
        MOV     AX,DS
        OR      AX,SI
        JZ      @@3
        MOV     AL,1
        STOSB
        MOV     CX,17
        REP     MOVSB
        JMP     @@4
@@2:    TEST    AL,Vga
        JZ      @@3
        MOV     AL,1
        STOSB
        MOV     DX,DI
        MOV     AX,1009H
        CALL    Int10
        JMP     @@4
@@3:    MOV     CX,18
        XOR     AL,AL
        REP     STOSB
@@4:    POP     DS
end;

procedure RestoreEgaPalette(var Buf: TEgaPalette); near; assembler;
asm
        LES     BX,Buf
        CMP     ES:[BX].Byte,0
        JE      @@1
        MOV     AX,1002H
        LEA     DX,[BX+1]
        CALL    Int10
@@1:
end;

procedure CalcStep; near; assembler;
asm
        CMP     GraphicsSwap,1
        JB      @@2
        MOV     AX,40H
        MOV     ES,AX
        MOV     AL,ES:49H
        CMP     AL,0DH
        JB      @@2
        CMP     AL,14H
        CMC
        JC      @@2
        XOR     BX,BX
        CMP     AL,0FH
        JB      @@1
        TEST    MonitorTypes,Ega+Ega*256
        JZ      @@1
        TEST    ES:87H.Byte,60H
        JNZ     @@1
        INC     BX
@@1:    CLC
@@2:
end;

procedure MoveFromScreen; near; assembler;
asm
        MOV     CX,4096
        CLD
@@1:    MOVSB
        ADD     SI,BX
        LOOP    @@1
end;

procedure SaveEgaGraphics; near; assembler;
asm
        CALL    CalcStep
        JC      @@2
        PUSH    DS
        MOV     DX,3CEH
        MOV     AX,204H
        OUT     DX,AX
        MOV     AX,5
        OUT     DX,AX
        LES     DI,EgaSwapArea
        MOV     SI,0A000H
        MOV     DS,SI
        XOR     SI,SI
        CALL    MoveFromScreen
        OR      BX,BX
        JZ      @@1
        MOV     SI,4000H
@@1:    CALL    MoveFromScreen
        POP     DS
@@2:
end;

procedure MoveToScreen; near; assembler;
asm
        MOV     CX,4096
        CLD
@@1:    MOVSB
        ADD     DI,BX
        LOOP    @@1
end;

procedure RestoreEgaGraphics; near; assembler;
asm
        CALL    CalcStep
        JC      @@2
        PUSH    DS
        MOV     DX,3C4H
        MOV     AX,402H
        OUT     DX,AX
        LDS     SI,EgaSwapArea
        MOV     DI,0A000H
        MOV     ES,DI
        XOR     DI,DI
        CALL    MoveToScreen
        OR      BX,BX
        JZ      @@1
        MOV     DI,4000H
@@1:    CALL    MoveToScreen
        MOV     AX,0F02H
        OUT     DX,AX
        POP     DS
@@2:
end;

procedure SaveMouseState(MS: Pointer); assembler;
asm
        CMP     ButtonCount,0
        JE      @@1
        MOV     AX,14H
        XOR     CX,CX
        XOR     DX,DX
        MOV     ES,DX
        INT     33H
        MOV     AX,ES
        LES     DI,MS
        CLD
        STOSW
        XCHG    AX,DX
        STOSW
        XCHG    AX,CX
        STOSW
        MOV     DX,DI
        MOV     AX,16H
        INT     33H
@@1:
end;

procedure RestoreMouseState(MS: Pointer); assembler;
asm
        CMP     ButtonCount,0
        JE      @@1
        LES     DX,MS
        ADD     DX,6
        MOV     AX,17H
        INT     33H
        PUSH    DS
        LDS     SI,MS
        CLD
        LODSW
        MOV     ES,AX
        LODSW
        XCHG    AX,DX
        LODSW
        XCHG    AX,CX
        POP     DS
        MOV     AX,14H
        INT     33H
@@1:
end;

procedure TurnCga(State: Boolean); near; assembler;
asm
        MOV     DX,40H
        MOV     ES,DX
        MOV     DX,MonitorTypes
        CMP     ES:49H.Byte,smMono
        JNE     @@1
        XCHG    DL,DH
@@1:    TEST    DL,Cga
        JZ      @@3
        CMP     SnowCheck,0
        JE      @@3
        MOV     DX,ES:Addr6845
        ADD     DX,4
        MOV     AL,ES:65H
        CMP     State,0
        JNE     @@2
        AND     AL,0F7H
@@2:    OUT     DX,AL
@@3:
end;

procedure DoSwapText; near; assembler;
var
  P1, P2: Pointer;
  Buf: array[0..1023] of Byte;
asm
        PUSH    DS
        LES     DI,CgaSwapArea
        MOV     DX,CgaSwapAreaSize
        MOV     AX,40H
        MOV     DS,AX
        MOV     AX,0B800H
        CMP     DS:49H.Byte,smMono
        JNE     @@1
        MOV     AX,0B000H
@@1:    MOV     P1.Word[0],DI
        MOV     P1.Word[2],ES
        MOV     P2.Word[0],0
        MOV     P2.Word[2],AX
        CLD
@@2:    MOV     CX,1024
        CMP     CX,DX
        JB      @@3
        MOV     CX,DX
@@3:    LDS     SI,P2
        LEA     DI,Buf
        PUSH    SS
        POP     ES
        PUSH    CX
        REP     MOVSB
        POP     CX
        LDS     SI,P1
        LES     DI,P2
        PUSH    CX
        REP     MOVSB
        POP     CX
        LEA     SI,Buf
        PUSH    SS
        POP     DS
        LES     DI,P1
        PUSH    CX
        REP     MOVSB
        POP     CX
        ADD     P1.Word[0],CX
        ADD     P2.Word[0],CX
        SUB     DX,CX
        JNZ     @@2
        POP     DS
end;

procedure SwapText; near;
begin
  TurnCga(False);
  DoSwapText;
  TurnCga(True);
end;

procedure CalcScreenSize; near; assembler;
asm
        XOR     BX,BX
        XOR     CX,CX
        CMP     DualMonitor,0
        JNE     @@3
        MOV     AX,40H
        MOV     ES,AX
        MOV     AL,ES:49H
        MOV     DX,MonitorTypes
        CMP     AL,smCO80+1
        JB      @@1
        CMP     AL,smMono
        JNE     @@3
        XCHG    DL,DH
@@1:    MOV     BL,ES:4AH
        MOV     BH,25
        TEST    DL,Ega+Vga
        JZ      @@2
        MOV     BH,ES:84H
        INC     BH
@@2:    MOV     CX,ES:50H
@@3:    MOV     ScreenSize,BX
        MOV     CursorPos,CX
end;

procedure GetUserScreen(X, Y: Word; var Buf; Size: Word); assembler;
asm
        LES     DI,Buf
        CLD
        MOV     DX,Size
        MOV     AX,Y
        CMP     AL,ScreenSize.Byte[1]
        JAE     @@2
        MOV     CL,ScreenSize.Byte[0]
        XOR     CH,CH
        MUL     CL
        ADD     AX,X
        SHL     AX,1
        SUB     CX,X
        JBE     @@2
        CMP     CX,DX
        JBE     @@1
        MOV     CX,DX
@@1:    SUB     DX,CX
        PUSH    DS
        LDS     SI,CgaSwapArea
        ADD     SI,AX
        REP     MOVSW
        POP     DS
@@2:    MOV     CX,DX
        MOV     AX,0720H
        REP     STOSW
end;

procedure ResetMouse; near; assembler;
asm
        CMP     ButtonCount,0
        JE      @@1
        XOR     AX,AX
        INT     33H
@@1:
end;

procedure SwapScreen(Screen: ScreenType; SaveMouse: Boolean);
begin
  if Screen <> CurrentScreen then
  begin
    with Screens[CurrentScreen] do
    begin
      Mode := GetMode;
      SaveVideoState(VideoState);
      SaveEgaPalette(Palette);
      if SaveMouse or (CurrentScreen = scTurbo) then
      begin
        SaveMouseState(MouseState);
        if not FirstOn then
          HideMouse;
      end;
      if not DualMonitor then
        if CurrentScreen = scUser then
          SaveEgaGraphics
        else
          SwapText;
      CalcScreenSize;
    end;
    CurrentScreen := Screen;
    with Screens[CurrentScreen] do
    begin
      if ModeChanged then
        SetMode(Mode)
      else
      begin
        if (VideoState.Addr6845 = Addr6845) and (GetMode <> Mode) then
          SetMode(Mode or smNoClearScreen);
        if not DualMonitor then
          if CurrentScreen = scUser then
            RestoreEgaGraphics
          else
            SwapText;
      end;
      if FirstOn then
      begin
        if DualMonitor then
          ResetMouse
      end else
      begin
        RestoreVideoState(VideoState);
        RestoreEgaPalette(Palette);
        if SaveMouse or (CurrentScreen = scTurbo) then
          RestoreMouseState(MouseState);
      end;
      ModeChanged := False;
      FirstOn := False;
    end;
  end;
end;

procedure ClearCgaSwapArea; near; assembler;
asm
        LES     DI,CgaSwapArea
        MOV     CX,CgaSwapAreaSize
        SHR     CX,1
        MOV     AX,0720H
        CLD
        REP     STOSW
end;

procedure CopyStatus(var S1, S2: TSavedScreen); near;
begin
  Move(S1, S2, Sizeof(S1) - Sizeof(Pointer));
  Move(S1.MouseState^, S2.MouseState^, MouseSaveSize);
end;

procedure CheckUserScreen;
begin
  if Screens[scUser].Mode <> Screens[scCheck].Mode then
  begin
    ModeChanged := True;
    FillChar(Screens[scCheck].VideoState.CursorPos, 8 * Sizeof(Word), 0);
  end else
    Move(Screens[scUser].VideoState.CursorPos,
      Screens[scCheck].VideoState.CursorPos, 8 * Sizeof(Word));
  CopyStatus(Screens[scCheck], Screens[scUser]);
end;

procedure RestoreCursorLines; assembler;
asm
        MOV     AH,1
        MOV     CX,CursorLines
        INT     10H
end;

function GetMemory(Amount: Word): Pointer;
begin
  GetMemory:=Ptr(AllocMem((Amount + 15) shr 4, VUseEms), 0);
end;

procedure ShowTurboScreen;
begin
  CgaSwapArea := GetMemory(CgaSwapAreaSize);
  EgaSwapArea := GetMemory(EgaSwapAreaSize);
  ClearCgaSwapArea;
  SwapScreen(scTurbo, True);
  CopyStatus(Screens[scUser], Screens[scCheck]);
  ScreenMode := Screens[scTurbo].Mode;
  InitVideo;
end;

procedure ShowUserScreen;
begin
  if DualMonitor then
    DoneVideo
  else
    RestoreCursorLines;
  CheckUserScreen;
  SwapScreen(scUser, True);
end;

procedure CalcMouseSaveStateSize; near; assembler;
asm
        XOR     BX,BX
        CMP     BL,ButtonCount
        JE      @@1
        MOV     AX,15H
        INT     33H
        ADD     BX,6
@@1:    MOV     MouseSaveSize,BX
end;

procedure InitVSwap;
var
  CurMonitor: Byte;
  CurMode: Word;
  VS: TVideoState;
begin
  DetectMonitors;
  CurMode := GetMode;
  if DualMonitor and (Hi(GetMonitorTypes) <> 0) then
  begin
    if Lo(CurMode) = smMono then
      CurMode := smCO80
    else
      CurMode := smMono;
    EgaPaletteSave := False;
    GraphicsSwap := False;
    ModeChanged := True;
  end else
  begin
    if InitMode <> 0 then
      CurMode := InitMode
    else
      CurMode := Lo(CurMode);
    if (CurMode <> smBW80) and (CurMode <> smCO80) and (CurMode <> smMono) then
      CurMode := smCO80;
    DualMonitor := False;
  end;
  if CurMode = smMono then
    CurMonitor := Hi(MonitorTypes)
  else
    CurMonitor := Lo(MonitorTypes);
  if not DualMonitor then
    case CurMonitor of
      Ega:
        CgaSwapAreaSize := 6880;
      Vga:
        CgaSwapAreaSize := 8000;
    else
      CgaSwapAreaSize := 4000;
    end;
  if GraphicsSwap and (CurMonitor and (Ega + MCga + Vga) <> 0) then
    EgaSwapAreaSize := 8192
  else
    GraphicsSwap := False;
  if Ega43Lines and (CurMonitor and (Ega + Vga) <> 0) then
    Screens[scTurbo].Mode := CurMode or smFont8x8
  else
    Screens[scTurbo].Mode := CurMode;
  if EgaPaletteSave and (CurMonitor and Ega <> 0) and (EgaPtrs^[1] = nil) then
  begin
    SaveEgaPtrs := EgaPtrs;
    NewEgaPtrs := EgaPtrs^;
    NewEgaPtrs[1] := @NewArea;
    EgaPtrs := @NewEgaPtrs;
    NewArea[0] := $FF;
    SaveVideoState(VS);
    SetMode(GetMode or smNoClearScreen);
    RestoreVideoState(VS);
    if NewArea[0] = $FF then
      DoneVSwap;
  end;
  CalcMouseSaveStateSize;
  if ButtonCount <> 0 then
  begin
    GetMem(Screens[scTurbo].MouseState, MouseSaveSize);
    GetMem(Screens[scUser].MouseState, MouseSaveSize);
    GetMem(Screens[scCheck].MouseState, MouseSaveSize);
  end;
end;

procedure DoneVSwap;
begin
  if SaveEgaPtrs <> nil then
  begin
    EgaPtrs := SaveEgaPtrs;
    SaveEgaPtrs := nil;
  end;
end;

end.
