[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]
{
Mario van den Ancker,
Amsterdam, The Netherlands.
E-mail: mario@astro.uva.nl
WWW: http://www.astro.uva.nl/mario/
----8<---------8<---------8<---------8<---------8<---------8<---------8<----
}
Program SplitScreen;
{ SplitScrn.pas - by Mario van den Ancker
E-Mail: mario@astro.uva.nl
WWW: http://www.astro.uva.nl/mario/
Program to demonstrate how to split the screen using the VGA hardware
in 320x240x256 ModeX. Requires TP 6.0 or higher. Donated to the public
domain. }
Uses Crt;
type
RGB = Array[1..3] of Byte;
TPalette = Array[0..255] of RGB;
const
MaxX = 319; { dimensions of screen. }
MaxY = 239;
SEGA000: Word = $A000;
Palette: TPalette = (
(0, 0, 0), (0, 0, 63), (1, 0, 62), (3, 0, 60),
(5, 0, 58), (7, 0, 56), (9, 0, 54), (10, 0, 53),
(11, 0, 52), (13, 0, 50), (14, 0, 49), (15, 0, 48),
(16, 0, 47), (17, 1, 46), (18, 1, 45), (19, 1, 44),
(19, 1, 44), (20, 1, 43), (21, 1, 42), (21, 1, 42),
(22, 1, 41), (23, 1, 40), (23, 1, 40), (24, 1, 39),
(25, 1, 38), (25, 1, 38), (26, 1, 37), (26, 1, 37),
(27, 1, 36), (27, 2, 36), (28, 2, 35), (28, 2, 35),
(29, 2, 34), (29, 2, 34), (30, 2, 33), (30, 2, 33),
(31, 2, 32), (31, 2, 32), (32, 2, 31), (32, 2, 31),
(32, 3, 31), (33, 3, 30), (33, 3, 30), (34, 3, 29),
(34, 3, 29), (34, 3, 29), (35, 3, 28), (35, 3, 28),
(35, 3, 28), (35, 3, 28), (36, 3, 27), (36, 3, 27),
(37, 4, 26), (37, 4, 26), (37, 4, 26), (37, 4, 26),
(38, 4, 25), (38, 4, 25), (38, 4, 25), (38, 4, 25),
(39, 4, 24), (39, 4, 24), (39, 4, 24), (40, 5, 23),
(40, 5, 23), (40, 5, 23), (40, 5, 23), (41, 5, 22),
(41, 5, 22), (41, 5, 22), (41, 5, 22), (41, 5, 22),
(42, 5, 21), (42, 6, 21), (42, 6, 21), (42, 6, 21),
(43, 6, 20), (43, 6, 20), (43, 6, 20), (43, 6, 20),
(43, 6, 20), (43, 6, 20), (44, 7, 19), (44, 7, 19),
(44, 7, 19), (44, 7, 19), (44, 7, 19), (45, 7, 18),
(45, 7, 18), (45, 8, 18), (45, 8, 18), (45, 8, 18),
(45, 8, 18), (46, 8, 17), (46, 8, 17), (46, 8, 17),
(46, 9, 17), (47, 9, 16), (47, 9, 16), (47, 9, 16),
(47, 9, 16), (47, 9, 16), (47, 9, 16), (47, 9, 16),
(48, 10, 15), (48, 10, 15), (48, 10, 15), (48, 10, 15),
(48, 10, 15), (48, 10, 15), (48, 11, 15), (49, 11, 14),
(49, 11, 14), (49, 11, 14), (49, 11, 14), (49, 11, 14),
(50, 11, 13), (50, 12, 13), (50, 12, 13), (50, 12, 13),
(50, 12, 13), (50, 13, 13), (50, 13, 13), (50, 13, 13),
(51, 13, 12), (51, 13, 12), (51, 13, 12), (51, 14, 12),
(51, 14, 12), (51, 14, 12), (51, 14, 12), (51, 14, 12),
(52, 15, 11), (52, 15, 11), (52, 15, 11), (52, 15, 11),
(52, 15, 11), (52, 15, 11), (53, 16, 10), (53, 16, 10),
(53, 16, 10), (53, 16, 10), (53, 17, 10), (53, 17, 10),
(53, 17, 10), (53, 17, 10), (53, 18, 10), (54, 18, 9),
(54, 18, 9), (54, 18, 9), (54, 19, 9), (54, 19, 9),
(54, 19, 9), (54, 19, 9), (54, 19, 9), (54, 20, 9),
(54, 20, 9), (55, 20, 8), (55, 20, 8), (55, 21, 8),
(55, 21, 8), (55, 21, 8), (55, 21, 8), (55, 22, 8),
(56, 22, 7), (56, 22, 7), (56, 22, 7), (56, 23, 7),
(56, 23, 7), (56, 23, 7), (56, 24, 7), (56, 24, 7),
(56, 24, 7), (56, 24, 7), (56, 25, 7), (57, 25, 6),
(57, 25, 6), (57, 26, 6), (57, 26, 6), (57, 26, 6),
(57, 27, 6), (57, 27, 6), (57, 27, 6), (57, 28, 6),
(57, 28, 6), (57, 28, 6), (58, 29, 5), (58, 29, 5),
(58, 29, 5), (58, 30, 5), (58, 30, 5), (58, 30, 5),
(58, 31, 5), (58, 31, 5), (58, 32, 5), (59, 32, 4),
(59, 32, 4), (59, 33, 4), (59, 33, 4), (59, 33, 4),
(59, 34, 4), (59, 34, 4), (59, 35, 4), (59, 35, 4),
(59, 35, 4), (59, 36, 4), (59, 36, 4), (59, 37, 4),
(60, 37, 3), (60, 38, 3), (60, 38, 3), (60, 38, 3),
(60, 39, 3), (60, 39, 3), (60, 40, 3), (60, 40, 3),
(60, 41, 3), (60, 41, 3), (60, 42, 3), (60, 42, 3),
(60, 42, 3), (61, 43, 2), (61, 43, 2), (61, 44, 2),
(61, 44, 2), (61, 45, 2), (61, 45, 2), (61, 46, 2),
(61, 46, 2), (61, 47, 2), (61, 47, 2), (61, 48, 2),
(61, 49, 2), (61, 49, 2), (61, 50, 2), (62, 50, 1),
(62, 51, 1), (62, 51, 1), (62, 52, 1), (62, 52, 1),
(62, 53, 1), (62, 54, 1), (62, 54, 1), (62, 55, 1),
(62, 55, 1), (62, 56, 1), (63, 57, 0), (63, 57, 0),
(63, 58, 0), (63, 59, 0), (63, 59, 0), (63, 60, 0),
(63, 61, 0), (63, 61, 0), (63, 62, 0), (63, 63, 0));
var
x, y: Integer;
i: Byte;
{ Waits for VGA's vertical retrace. }
procedure WaitVRetrace; Assembler;
Asm
mov dx, 3dah
@@1:
in al, dx
and al, 08h
jnz @@1
@@2:
in al, dx
and al, 08h
jz @@2
end;
{ Sets a complete palette. }
procedure SetPal(var Palet: TPalette); Assembler;
Asm
call WaitVRetrace
push ds
lds si, Palet
mov dx, 3c8h
mov al, 0
out dx, al
inc dx
mov cx, 768
rep outsb
pop ds
end;
{ Initializes 320x240x256 ModeX. Virtual screen is 320x800x256. }
procedure SetModeX; Assembler;
Asm
{ First get in MCGA mode. }
mov ax, 13h
int 10h
{ Unchain. }
cli
mov dx, 3c4h
mov ax, 0604h
out dx, ax
mov ax, 0f02h
out dx, ax
{ Clear complete VGA memory. }
mov ax, 0f02h { Select all bitplanes. }
out dx, ax
mov es, SEGA000
xor di, di { Clear di }
xor ax, ax { Clear ax }
mov cx, 7fffh
cld
rep stosw { Clear garbage off the screen. }
{ Now setup 320x240x256 ModeX. }
mov dx, 03c2h
mov al, 0e3h
out dx, al
mov dx, 03d4h
mov ax, 02c11h
out dx, ax
mov ax, 0d06h
out dx, ax
mov ax, 3e07h
out dx, ax
mov ax, 0ea10h
out dx, ax
mov ax, 0ac11h
out dx, ax
mov ax, 0df12h
out dx, ax
mov ax, 0e715h
out dx, ax
mov ax, 0616h
out dx, ax
sti
end;
{ Flips screen back to text mode. }
procedure SetTextMode; Assembler;
asm
mov ax, 0003h
int 10h
end;
{ Moves offset of screen to (x, y). }
procedure ScreenOffset(x, y: Word); Assembler;
Asm
cli
mov ax, y
mov bx, ax
shl bx, 6
shl ax, 4
add bx, ax { bx = y*80 }
mov ax, x
add bx, ax { bx = y*80 + x }
mov ah, bh
mov al, 0ch
mov dx, 3d4h
out dx, ax
mov ah, bl
mov al, 0dh
out dx, ax
sti
end;
{ Splits the screen. The offset of this split screen in VGA memory is always
0. The split screen can be hidden by setting it to a line > MaxY. }
procedure SetSplitscreen(Line: Word); Assembler;
Asm
mov bx, Line
shl bx, 1
dec bx
cli
mov dx, 3d4h { CRTC base address }
mov ah, bl
mov al, 18h { CRTC line compare reg. index }
out dx, ax
mov ah, bh
and ah, 1
shl ah, 4
mov al, 07h { CRTC overflow register index }
out dx, al
inc dx
in al, dx
and al, not 10h
or al, ah
out dx, al
dec dx
mov ah, bh
and ah, 2
ror ah, 3
mov al, 09h { CRTC maximum scan line register index }
out dx, al
inc dx
in al, dx
and al, not 40h
or al, ah
out dx, al
sti
end;
{ Puts a pixel on the screen in ModeX. x should be between 0 and 319. y
should be between 0 and 799. Whether or not the pixel is visible on the
screen is determined by what part of the VGA memory we are displaying, as
can be set by ScreenOffset and SplitScreen. }
procedure PutPixel(x, y: Word; Color: Byte); Assembler;
Asm
mov ax, y
mov bx, ax
shl bx, 4
shl ax, 6
add bx, ax { bx = y*80 }
mov ax, x
mov cl, al
and cl, 03h
shr ax, 2
add bx, ax
mov ah, 1
shl ah, cl
mov dx, 3c4h { Sequencer Register }
mov al, 2 { Map Mask Index }
out dx, ax
mov es, SEGA000
mov al, Color
mov es:[bx], al
end;
{ Simple 'n slow rectangle drawing routine. }
procedure Rect(x1, y1, x2, y2: Word; Color: Byte);
var
i: Integer;
begin
for i := x1 to x2 do
begin
PutPixel(i, y1, Color);
PutPixel(i, y2, Color);
end;
for i := y1 to y2 do
begin
PutPixel(x1, i, Color);
PutPixel(x2, i, Color);
end;
end;
{ Puts a character on the screen using the VGA ROM font. }
procedure PutChar(x, y: Word; Color: Byte; ch: Char);
var
i, j: Byte;
pre: Word;
begin
pre := $FA6E + (Ord(ch) shl 3);
for i := 0 to 7 do
for j := 0 to 7 do
if (((Mem[$F000:pre+i] shl j) and 128) <> 0) then
PutPixel(x+j, y+i, Color);
end;
{ Puts a string on the screen using the VGA ROM font. }
procedure PutString(x, y: Word; Color: Byte; Str: String);
var
i: Byte;
begin
for i := 1 to length(Str) do
PutChar(x + ((i-1) shl 3), y, Color, Str[i]);
end;
begin
{ Initialize display and palette. }
SetModeX;
SetPal(Palette);
{ Set virtual screen to start at line 64 and put simple background
pattern on screen. }
ScreenOffset(0, 64);
for x := 0 to MaxX do
for y := 0 to MaxY do
begin
i := x xor y;
if (i = 0) then i := 1; { Using colour 0 (black) looks ugly... }
PutPixel(x, y+64, i);
end;
{ We're gonna use lines 0-63 in VGA memory for our split screen.
Let's write a background pattern and some text to that region. }
for i := 0 to 31 do
Rect(i, i, MaxX-i, 63-i, i shl 2);
PutString(24, 23, 255, 'Split Screen in 320x240x256 ModeX!');
PutString(52, 35, 255, 'Press any key to continue...');
{ Now scroll the split screen on the display.... }
for y := 0 to 63 do
begin
SetSplitScreen(MaxY-y);
WaitVRetrace;
end;
Repeat Until KeyPressed;
{ And scroll the split screen off the display... }
for y := 63 downto 0 do
begin
SetSplitScreen(MaxY-y);
WaitVRetrace;
end;
{ Finito: back to Text mode! }
SetTextMode;
end.
[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]