Category : Files from Magazines
Archive   : DDJ0791.ZIP
Filename : VGA.ASC
by Ben Myers
[LISTING ONE]
PAGE 80,132
TITLE EGA/VGA screen save/restore (Turbo Pascal 4.0+ or Quick Pascal 1.0)
; GRFSAVE.ASM -
; (C)Copyright 1989-1990 Spirit of Performance, Inc.
; All rights reserved. Unauthorized use or copying prohibited by law.
CODE SEGMENT WORD PUBLIC
ASSUME CS:CODE
PUBLIC Write_VGA_Plane ; Write video plane from caller's memory.
PUBLIC Read_VGA_Plane ; Read video plane, move it to caller's memory.
; procedure Write_VGA_Plane (Plane, Count : word; var Plane_Array );
; procedure Read_VGA_Plane (Plane, Count : word; var Plane_Array );
; Parameters: Plane - Graphics plane number to move ( range 0-3 )
; Count - Byte count to move
; Plane_Array - Array for video plane values
Plane_Array EQU DWORD PTR [bp+06h]
Count EQU WORD PTR [bp+0Ah]
Plane EQU WORD PTR [bp+0Ch]
Write_VGA_Plane PROC FAR
push bp ; Save Turbo's BP
mov bp,sp ; Set up stack frame
mov bx,ds ; Save Turbo's DS
mov di,0A000h ; EGA/VGA buffer segment:offset, A000:0000
mov es,di
xor di,di ; ES:DI is start of video buffer
mov dx,3CEh ; DX = Graphics Controller I/O Port
mov ax,0005h ; AH = 00h (Read mode 0, write mode 0)
; AL = Mode register number (5)
out dx,ax ; load Mode register
mov ax,0001h ; AH = 00h (mask for Enable Set/Reset),
; also the default for modes 12h and 10h
; AL = Enable Set/Reset register number (1)
out dx,ax ; load Enable Set/Reset register
mov ax,0003h ; AH = Replace bit planes with memory,
; no bit rotation, also the default
; AL = Data Rotate/Function Select register
; number (3)
out dx,ax ; load Data Rotate/Function Select register
; AL = Bit Mask Register (8)
mov ax,0FF08h ; AH = bit mask
out dx,ax ; Set bit mask register for all bits
mov dx,3C4h ; DX = Sequencer I/O Port
mov cx,ss:Plane ; Get Plane number from caller
and cl,03h ; Force it to range 0 to 3
mov ah,1 ; Set up AH with bit number of plane to restore
shl ah,cl ; where bit 0 = plane 0, etc.
mov al,02h ; AL = Map Mask Register number (2)
out dx,ax ; load Map Mask register with plane number
mov cx,ss:Count ; byte count to move (size of plane for
; EGA/VGA card in current mode )
lds si,ss:Plane_Array ; Addr of array to restore plane values from
rep movsb ; Move the data
; Or replace the above instruction by the slower but equivalent loop construct
; below in the event that your VGA card doesn't respond properly.
@@:
; lodsb ; Get a byte from save area plane
; stosb ; Form a byte for current plane
; loop @B ; Do next byte, until all have been done.
; Now reset the VGA registers used back to the defaults expected.
mov dx,3CEh ; DX = Graphics Controller I/O Port
mov ax,0001 ; AH = 0 (default Enable Set/Reset Value)
; AL = Enable Set/Reset register number (1)
out dx,ax ; restore default Enable Set/Reset register
mov dx,3C4h ; DX = Sequencer I/O port
; AH = all planes enabled
mov ax,0F02h ; AL = Map Mask Register number (2)
out dx,ax ; restore Map Mask register to do all planes.
mov ds,bx ; Restore Turbo's DS
pop bp ; Restore Turbo's BP
ret 8 ; Remove params & return to call
Write_VGA_Plane ENDP
; procedure Read_VGA_Plane (Plane, Count : word; var Plane_Array );
Read_VGA_Plane PROC FAR
push bp ; Save Turbo's BP
mov bp,sp ; Set up stack frame
mov bx,ds ; Save Turbo's DS
mov si,0A000h ; EGA/VGA buffer segment:offset, A000:0000
mov ds,si
xor si,si ; DS:SI is start of video buffer
mov dx,3CEh ; DX = Graphics Controller I/O Port
mov ax,0005h ; AH = 00h (Read mode 0, write mode 0)
; AL = 5 (Mode register number)
out dx,ax ; load Mode register
;; int 3 ; Enable breakpoint for debugging.
mov ax,ss:Plane ; Get Plane number
mov ah,al ; AH = color plane to get
mov al,04h ; AL = Read Map Select Register number (4)
out dx,ax ; load Read Map Select register
mov cx,ss:Count ; byte count to move (size of plane for
; EGA/VGA card in current mode )
les di,ss:Plane_Array ; Address of array to store plane values.
rep movsb ; Move the data from video buffer to save area
; Or replace the above instruction by the slower but equivalent loop construct
; below in the event that your VGA card doesn't respond properly.
@@:
; lodsb ; Get a byte from plane of video buffer
; stosb ; Save it.
; loop @B ; Do next byte, until all have been done.
; Now reset the VGA registers used back to the defaults expected.
mov ax,1005h ; AH = 10h, defaults for modes 12h and 10h
; AL = Mode register number (5)
out dx,ax ; restore default mode register
mov ax,0004h ; AL = Read Map Select Register number (4)
out dx,ax ; load Read Map Select register default value
mov ds,bx ; Restore Turbo's DS
pop bp ; Restore Turbo's BP
ret 8 ; Remove params & return to call
Read_VGA_Plane ENDP
CODE ENDS
END
[LISTING TWO]
{
GRFSAVE1.PAS - Unit to save and restore graphics screens
Version 1.40 (03-19-90) --depends on MSgraph Unit for
manifest constants indentifying graphics modes.
procedure Write_VGA_Plane (Plane, Count : word; var Plane_Array );
procedure Read_VGA_Plane (Plane, Count : word; var Plane_Array );
Parameters: Plane - Graphics plane number to move ( range 0-3 )
Count - Byte count to move
Plane_Array - Array for video plane values
(C)Copyright 1989-1990 Spirit of Performance, Inc.
All rights reserved. Unauthorized use or copying prohibited by law.
}
{$R-,S-,I-,D+,F+,V-,B-,N-,L+ }
UNIT GRFSAVE;
INTERFACE
USES MsGraph;
const
Max_Planes = 4;
procedure Init_Screen_Save ( Plane_Size : longint; Number_Of_Planes : word );
Function HeapFunc ( Size: word ) : integer;
function Save_Screen ( Mode : integer ) : integer;
procedure Restore_Screen;
procedure Write_VGA_Plane (Plane, Count : word; var Plane_Array );
procedure Read_VGA_Plane (Plane, Count : word; var Plane_Array );
IMPLEMENTATION
var
{ Video plane size and number of planes in bytes }
{ ****** When video plane size gets above 64K, need to change below }
Video_Plane_Size : word; { in bytes }
Number_GPlanes : word;
Plane_Counter : word;
Plane_Ptrs : array [1..Max_Planes] of pointer;
Planes_Saved : integer;
Saved_Graphics_Mode : integer;
Monochrome_Buffer : ARRAY[ 0..$7FFF ] OF byte ABSOLUTE $B800:$0000;
VGA_Buffer : ARRAY[ 0..$7FFF ] OF byte ABSOLUTE $A000:$0000;
procedure Init_Screen_Save;
{ Initialize unit with parameters }
begin
Video_Plane_Size := Plane_Size;
Number_GPlanes := Number_Of_Planes;
end;
Function HeapFunc;
{ Simple heap error function overrides run time error to avoid program
abort. }
begin
HeapFunc := 1; { return an error indicator to caller }
end;
{$L d:\tpsource\GRFSAVE.obj }
procedure Write_VGA_Plane; external;
procedure Read_VGA_Plane; external;
function Save_Screen;
{ Saves graphics planes for current graphics mode.
Returns number of planes saved, in case caller cares.
}
begin
Saved_Graphics_Mode := Mode;
Planes_Saved := 0;
HeapError := @HeapFunc;
case Saved_Graphics_Mode of
_HRes16Color, { 640 x 200, 16 color }
_EResColor , { 640 x 350, 4 or 16 color }
_VRes16Color: { 640 x 480, 16 color }
for Plane_Counter := 1 to Number_GPlanes do
begin
{ Get memory to save a plane }
GetMem( Plane_Ptrs[Plane_Counter], Video_Plane_Size);
if Plane_Ptrs[Plane_Counter] <> nil then
{ Move the plane if GetMem succeeded }
begin
Read_VGA_Plane (Plane_Counter-1, Video_Plane_Size,
Plane_Ptrs[Plane_Counter]^ );
inc ( Planes_Saved );
end;
end;
_HResBW , { 640 x 200, BW }
_HercMono: { 720 x 348, BW for HGC }
begin
GetMem( Plane_Ptrs[1], Video_Plane_Size);
if Plane_Ptrs[Plane_Counter] <> nil then
begin
Move ( Monochrome_Buffer, Plane_Ptrs[1]^, Video_Plane_Size );
Planes_Saved := 1;
end;
end;
_EResNoColor, { 640 x 350, BW }
_VRes2Color : { 640 x 480, BW }
begin
GetMem( Plane_Ptrs[1], Video_Plane_Size);
if Plane_Ptrs[Plane_Counter] <> nil then
begin
Move ( VGA_Buffer, Plane_Ptrs[1]^, Video_Plane_Size );
Planes_Saved := 1;
end;
end;
end; {case Saved_Graphics_Mode}
if Planes_Saved <> Number_GPlanes then
{ Unsuccessful, so reset count of planes saved }
Planes_Saved := 0;
Save_Screen := Planes_Saved;
end;
procedure Restore_Screen;
begin
if Planes_Saved <> 0 then
case Saved_Graphics_Mode of
_HRes16Color, { 640 x 200, 16 color }
_EResColor , { 640 x 350, 4 or 16 color }
_VRes16Color: { 640 x 480, 16 color }
for Plane_Counter := 1 to Number_GPlanes do
if Plane_Ptrs[Plane_Counter] <> nil then
Write_VGA_Plane (Plane_Counter-1, Video_Plane_Size,
Plane_Ptrs[Plane_Counter]^ );
_HResBW , { 640 x 200, BW }
_HercMono: { 720 x 348, BW for HGC }
Move ( Plane_Ptrs[1]^, Monochrome_Buffer, Video_Plane_Size );
_EResNoColor, { 640 x 350, BW }
_VRes2Color : { 640 x 480, BW }
Move ( Plane_Ptrs[1]^, VGA_Buffer, Video_Plane_Size );
end; {case Saved_Graphics_Mode}
end;
END.
[LISTING THREE]
PROGRAM savedemo;
{ savedemo.PAS - Demonstrate EGA/VGA graphics screen save/restore
Version 1.00, 19 Mar 1990
Uses for Microsoft Graphics Interface and selected MASM functions.
(c)Copyright 1989-1990 Spirit of Performance, Inc.
}
USES
DOS, MSGraph, Crt, GrfSave1;
type
TimeRec = record
Hour : word;
Minute : word;
Second : word;
FracSec : word;
Floating_Time : real;
end;
var
Start_Time : TimeRec;
Stop_Time : TimeRec;
Function Elapsed_Time ( Stop_Time, Start_Time : TimeRec ) : real;
const
R3600 : real = 3600.0;
R60 : real = 60.0;
R100 : real = 100.0;
begin { Elapsed_Time }
with Start_Time do
begin
Floating_Time := (Hour * R3600) + (Minute * R60) + Second
+ (FracSec / R100);
end;
if Stop_Time.Hour < Start_Time.Hour then inc(Stop_Time.Hour, 24);
with Stop_Time do
begin
Floating_Time := (Hour * R3600) + (Minute * R60) + Second
+ (FracSec / R100);
end;
Elapsed_Time := Stop_Time.Floating_Time - Start_Time.Floating_Time;
end; { Elapsed_Time }
TYPE
ViewPortType = record
x1, y1, x2, y2 : word;
end;
VAR
errorcode : Integer;
x,y : Integer;
maxx, maxy : Integer; { Maximum addressable pixels }
c : Char;
vc : _VideoConfig;
CurrentView : ViewPortType;
lCount : longint;
OldExitProc : Pointer; { Saves exit procedure address }
Plane_Count : integer;
var
Video_Plane_Size : longint;
Number_GPlanes : word;
CONST
Version_ID : string = ( 'Version 1.00, 19 Mar 1990' );
Patterns : Array [0..11] of _FillMask =
(
(0,0,0,0,0,0,0,0),
($FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF),
($FF, 0, $FF, 0, $FF, 0, $FF, 0),
($44, $88, $11, $22, $44, $88, $11, $22),
($77, $EE, $DD, $BB, $77, $EE, $DD, $BB),
($77, $BB, $DD, $EE, $77, $BB, $DD, $EE),
($88, $44, $22, $11, $88, $44, $22, $11),
($11, $AA, $44, $AA, $11, $AA, $44, $AA),
($55, $AA, $55, $AA, $55, $AA, $55, $AA),
($F0, $0F, $F0, $0F, $F0, $0F, $F0, $0F),
(1, 0, 0, 0, 1, 0, 0, 0),
(5, 0, 5, 0, 5, 0, 5, 0));
CleanUp_Reqd : Boolean = TRUE;
{$F+}
procedure MyExitProc;
{ Procedure to clean up on early program termination }
begin
ExitProc := OldExitProc; { Restore exit procedure address }
if CleanUp_Reqd then
begin { Restore original video mode. }
errorcode := _SetVideoMode( _DefaultMode );
end;
end; { MyExitProc }
{$F-}
Procedure GetViewSettings (var ReqView : ViewPortType);
begin
ReqView := CurrentView;
end;
Procedure SetView (xa, ya, xb, yb : word);
begin
_SetViewPort(xa, ya, xb, yb);
_SetClipRgn (xa, ya, xb, yb);
with CurrentView do
begin
x1 := xa; y1 := ya;
x2 := xb; y2 := yb;
end;
end;
procedure FullPort;
{ Set the view port to the entire screen }
begin
SetView(0, 0, maxx, maxy);
end; { FullPort }
procedure MainWindow(Header : string);
{ Make a default window and view port for demos }
begin
_SetTextColor(vc.numcolors-1); { Reset the colors }
_SetBkColor(0);
_SetColor(vc.numcolors-1);
_ClearScreen(_GClearScreen); { Clear the screen }
FullPort; { Full screen view port }
_SetTextPosition( 1, (vc.NumTextCols - length(Header)) div 2);
_OutText(Header); { Draw the header text }
{ Move the edges in to leave room for text at top and bottom }
SetView(0, vc.NumYPixels div vc.NumTextRows + 1 , maxx,
maxy-(vc.NumYPixels div vc.NumTextRows)-1);
end; { MainWindow }
procedure StatusLine(Msg : string);
{ Display a status line at the bottom of the screen }
begin
FullPort;
_SetLineStyle($FFFF);
_SetFillMask(Patterns[0]);
_SetColor(0); { Set the drawing color to black }
_Rectangle(_GFillInterior,
0, vc.NumYPixels-(vc.NumYPixels div vc.NumTextRows+1),
maxx, maxy); { Erase old status line }
_SetTextPosition( vc.NumTextRows,
(vc.NumTextCols - length(Msg)) div 2);
_SetTextColor(vc.numcolors-1); { Set the color for header }
_SetBkColor(0);
_OutText(Msg); { Write the status message }
{ Go back to the main window }
SetView(0, vc.NumYPixels div vc.NumTextRows +1 , vc.NumXPixels,
vc.NumYPixels-(vc.NumYPixels div vc.NumTextRows+1));
_SetTextPosition( 1, 1 );
end; { StatusLine }
procedure WaitToGo; { Wait for user to abort program or continue }
const
Esc = #27;
var
Ch : char;
begin
StatusLine('Esc aborts or press a key...');
with Start_Time do GetTime ( Hour, Minute, Second, FracSec );
repeat
with Stop_Time do GetTime ( Hour, Minute, Second, FracSec );
{ Wait for keypress no more then 5 seconds, then go on without it }
until KeyPressed or (Elapsed_Time ( Stop_Time, Start_Time ) > 5.0);
if Keypressed then
begin
Ch := ReadKey;
if Ch = #0 then Ch := readkey; { trap function keys }
if Ch = Esc then
Halt(0); { terminate program }
end;
end; { WaitToGo }
procedure DrawRectangles;
{ Draw rectangles on the screen }
var
MaxSize : word;
XCenter, YCenter : word;
ViewInfo : ViewPortType;
YMax, XMax : word;
jCount : word;
begin { DrawRectangles }
MainWindow('Draw Rectangles');
StatusLine('');
GetViewSettings(ViewInfo);
with ViewInfo do
begin
XMax := (x2-x1-1);
YMax := (y2-y1-1);
end;
MaxSize := XMax shr 1;
XCenter := XMax shr 1;
YCenter := YMax shr 1;
for lCount := 1 to MaxSize do
begin
_SetColor(lCount mod vc.numcolors);
_Rectangle(_GBorder, XCenter+lCount, YCenter+lCount,
XCenter-LCount, YCenter-LCount);
end;
WaitToGo;
end; { DrawRectangles }
procedure DrawCircles;
{ Draw concentric circles on the screen }
var
MaxRadius : word;
XCenter, YCenter : word;
ViewInfo : ViewPortType;
YMax, XMax : word;
begin { DrawCircles }
MainWindow('Draw Circles');
StatusLine('');
GetViewSettings(ViewInfo);
with ViewInfo do
begin
XMax := (x2-x1-1);
YMax := (y2-y1-1);
end;
MaxRadius := XMax shr 1;
XCenter := XMax shr 1;
YCenter := YMax shr 1;
for lCount := 1 to MaxRadius do
begin
_SetColor(lCount mod vc.numcolors);
_Ellipse(_GBorder, XCenter + lCount, YCenter + lCount,
XCenter - lCount, YCenter - lCount);
end;
WaitToGo;
end; { DrawCircles }
BEGIN
OldExitProc := ExitProc; { save previous exit proc }
ExitProc := @MyExitProc; { insert our exit proc in chain }
_GetVideoConfig( vc );
DirectVideo := FALSE; { No direct writes allowed in graphics modes }
{ Set graphics mode with highest resolution. }
if (_SetVideoMode( _MaxResMode) = 0) then
Halt( 1 );
_GetVideoConfig( vc );
if vc.mode <> _HercMono then
begin
Video_Plane_Size := vc.numxpixels div 8;
Video_Plane_Size := Video_Plane_Size * vc.numypixels;
end
else
Video_Plane_Size := 32768;
if vc.numcolors = 2 then
Number_GPlanes := 1 { B&W modes have 1 plane only }
else
Number_GPlanes := 4; { Assume that color modes have 4 planes }
Init_Screen_Save (Video_Plane_Size, Number_GPlanes);
_SetColor( vc.numcolors-1 );
DrawRectangles;
Plane_Count := Save_Screen (vc.mode); { Save the first screen }
DrawCircles;
Restore_Screen; { Restore the rectangles }
WaitToGo; { Wait before terminating }
{ Restore original video mode. }
errorcode := _SetVideoMode( _DefaultMode );
CleanUp_Reqd := FALSE;
END.
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/