VGA Trainer Program: part 10
Õ-------------------------------¸
| W E L C O M E |
| To the VGA Trainer Program | |
| By | |
| DENTHOR of ASPHYXIA | | |
Ô-------------------------------¾ | |
--------------------------------Ù |
--------------------------------Ù
--==[ PART 10 ]==--
Introduction
Wow! The trainer has finally reached part 10! This will also be the first part introduced simultaneously to local BBS's and the INTERNET at the same time! Yes folks, I put up a copy of previous tutorials onto various ftp sites, and awaited the flames saying that the net.gurus already knew this stuff, and why was I wasting disk space! The flames did not appear (well, except for one), and I got some messages saying keep it up, so from now on I will upload all future trainers to ftp sites too (wasp.eng.ufl.edu , cs.uwp.edu etc.). I will also leave a notice in the USENET groups comp.lang.pascal and comp.sys.ibm.pc.demos when a new part is finished (Until enough people say stop ;-))
I can also be reached at my new E-Mail address, smith9@batis.bis.und.ac.za
Well, this tutorial is on Chain-4. When asked to do a trainer on Chain-4, I felt that I would be walking on much travelled ground (I have seen numerous trainers on the subject), but the people who asked me said that they hadn't seen any, so could I do one anyway? Who am I to say no?
The sample program attached isn't that great, but I am sure that all you people out there can immediately see the potential that Chain-4 holds.
If you would like to contact me, or the team, there are many ways you can do it :
- Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS.
- Write to Denthor, EzE or Goth on Connectix.
- Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa
- Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-))
- Write to smith9@batis.bis.und.ac.za in E-Mail.
NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it.
NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you!
What is Chain-4?
You people out there all have at least 256k vga cards. Most of you have 512k vga cards, and some have 1MB vga cards. But what you see on your screen, as discussed in previous trainers, is 64k of data! What happened to the other 192k??? Chain-4 is a method of using all 256k at one time.
The way this is done is simple. 1 screen = 64k. 64k * 4 = 256k. Therefore, chain-4 allows you to write to four screens, while displaying one of them. You can then move around these four screens to see the data on them. Think of the Chain-4 screen as a big canvas. The viewport, the bit you see out of, is a smaller rectangle which can be anywhere over the bigger canvas.
+----------------------------+ Chain-4 screen
| +--+ |
| | | <- Viewport |
| +--+ |
| |
+----------------------------+
The size of the chain-4 screen
The Chain-4 screen, can be any size that adds up to 4 screens.
For example, it can be 4 screens across and one screen down, or one screen across and 4 screens down, or two screens across and two screens down, and any size in between.
In the sample program, the size is a constant. The size * 8 is how many pixels across there are on the chain-4 screen, ie
- Size = 40 = 320 pixels across = 1 screen across, 4 screens down
- Size = 80 = 640 pixels across = 2 screens across, 2 screens down
- etc.
We need to know the size of the screen for almost all dealings with the Chain-4 screen, for obvious reasons.
Layout of the chain-4 screen, and accessing it
If you will remember all the way back to Part 1 of this series, I explained that the memory layout of the MCGA screen is linear. Ie, the top left hand pixel was pixel zero, the one to the right of it was number one, the next one was number two etc. With Chain-4, things are very different.
Chain-4 gets the 4 screens and chains them together (hence the name :)). Each screen has a different plane value, and must be accessed differently. The reason for this is that a segment of memory is only 64k big, so that we could not fit the entire Chain-4 screen into one segment.
All Chain-4 screens are accessed from $a000, just like in MCGA mode. What we do is, before we write to the screen, find out what plane we are writing to, set that plane, then plot the pixel. Here is how we find out how far in to plot the pixel and what plane it is on :
Instead of the linear model of MCGA mode, ie :
Ú--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--¿
|00|01|02|03|04|05|06|07|08|09|10|11| ...
Each plane of the Chain-4 screen accesses the memory in this way :
Plane 0 :
Ú--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--¿
|00| | | |01| | | |02| | | | ...
Plane 1 :
Ú--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--¿
| |00| | | |01| | | |02| | | ...
Plane 2 :
Ú--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--¿
| | |00| | | |01| | | |02| | ...
Plane 3 :
Ú--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--Â--¿
| | | |00| | | |01| | | |02| ...
In this way, by choosing the right plane to write to, we can access all of the 256k of memory available to us. The plane that we write to can easily be found by the simple calculation of x mod 4, and the x coordinate is also found by x div 4. We work out our y by multiplying it by the size of our chain-4 screen.
NOTE : It is possible to write to all four planes at once by setting the correct port values.
Uses of Chain-4
The uses of Chain-4 are many. One could write data to one screen, then flip to it (the move_to command is almost instantaneous). This means that 64k of memory does not need to be set aside for a virtual screen, you are using the vga cards memory instead!
Scrolling is much easier to code for in Chain-4 mode.
It is possible to "tweak" the mode into other resolutions. In our demo, our vectors were in 320x240 mode, and our dot vectors were in 320x400 mode.
The main disadvantage of chain-4 as I see it is the plane swapping, which can be slow. With a bit of clever coding however, these can be kept down to a minimum.
The sample programs
The first sample program is GFX.PAS. This is a until in which I have placed most of our routines from previous tuts. All the procedures and variables you can see under the INTERFACE section can be used in any program with GFX in the USES clause. In other words, I could do this :
USES GFX,crt;
BEGIN
Setupvirtual;
cls (vaddr,0);
Shutdown;
END.
This program would compile perfectly. What I suggest you do is this : Rename the file to a name that suites you (eg your group name), change the first line of the unit to that name, then add all useful procedures etc. to the unit. Make it grow :-).
The second file is the sample program (note the USES GFX,crt; up near the top!). The program is easy to understand and is documented. The bit that I want to draw your attention to is the constant, BIT. Because I am distributing this file to many places in text form, not binary form, I could not just add a .CEL file with the program. So what I did was write some text in one color then saved it as a .CEL . I then wrote a ten line program that did the following : Moving from left to right, it counted how many pixels were of color zero, then saved the byte value to an array. When it came across color one, is counted for how long that went on then saved the byte value and saved it to an array and so on. When it was finished, I converted the array into a text file in the CONST format. Not too cunning, but I thought I had better explain it ;-)
In closing
There are other documents and sample programs available on Chain-4 and it's like : Try XLIB for one...
Finally! Some BBS's have joined my BBS list! (Okay, only two new ones, but it's a start ;-)) All you international BBS's! If you will regularly download the tuts from an FTP site, give me your names!
I own a car. The car's name is Bob. A few days ago, Bob was in an accident, and now has major damage to his front. Knowing insurance, I probably won't get much, probably nothing (the other guy wasn't insured, and I am only 18 :( ). I will probably have to find work in order to pay for my repairs. The point to this meandering is this : I am upset, so if you think you are getting a quote, you can just forget it.
Oh, well. Life goes on!
See you next time,
- Denthor
These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical)
É--------------------------Ë----------------Ë-----Ë---Ë----Ë----»
|BBS Name |Telephone No. |Open |Msg|File|Past|
Ì--------------------------Î----------------Î-----Î---Î----Î----¹
|ASPHYXIA BBS #1 |(031) 765-5312 |ALL | * | * | * |
|ASPHYXIA BBS #2 |(031) 765-6293 |ALL | * | * | * |
|Connectix BBS |(031) 266-9992 |ALL | | * | * |
|POP! |(012) 661-1257 |ALL | | * | * |
|Pure Surf BBS |(031) 561-5943 |A/H | | * | * |
È--------------------------Ê----------------Ê-----Ê---Ê----Ê----¼
For international users : If you live outside the Republic of South Africa, do the following : Dial +27, don't dial the first 0, but dial the rest of the number. Eg, for the ASPHYXIA BBS : +27-31-765-5312
Open = Open at all times or only A/H
Msg = Available in message base
File = Available in file base
Past = Previous Parts available
TUTPRO10.PAS
Uses Crt,GFX;
Const Size : Byte = 80; { Size = 40 = 1 across, 4 down }
{ Size = 80 = 2 across, 2 down }
{ Size = 160 = 4 across, 1 down }
bit : Array [1..897] of byte = (
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,2,151,5,149,6,148,7,147,8,49,2,95,8,49,
4,93,9,49,3,93,4,2,3,49,4,92,4,3,3,48,4,92,4,3,4,48,4,91,4,4,3,48,4,92,4,3,4,
48,3,58,2,32,4,4,4,47,4,57,3,31,4,5,3,48,3,57,4,30,4,5,4,47,3,57,5,29,4,6,4,46,
4,57,4,29,4,7,3,47,3,58,2,30,4,7,4,46,4,90,4,7,4,46,3,90,4,8,4,27,2,16,3,90,4,
8,9,22,3,16,3,89,4,5,13,8,6,8,3,15,3,90,4,2,15,6,10,6,3,16,3,6,1,21,1,9,2,7,1,
21,6,14,18,9,5,2,4,5,4,1,4,10,3,4,5,10,2,7,3,8,2,5,3,9,3,7,8,13,13,1,4,9,4,5,3,
5,3,1,6,9,3,3,6,9,4,5,4,8,3,3,4,9,3,6,9,11,10,6,4,8,4,6,3,4,11,8,3,2,7,9,5,4,4,
9,3,2,4,9,3,6,4,4,2,8,10,9,4,7,4,6,3,5,5,3,3,8,3,1,8,8,5,4,5,8,3,3,3,9,4,5,4,5,
2,5,10,12,4,7,3,5,5,4,5,4,3,7,3,1,4,1,3,9,4,5,4,9,3,2,3,10,3,6,3,5,3,4,10,13,3,
8,3,2,7,5,4,5,3,7,7,1,3,9,4,5,5,9,3,1,3,10,3,6,3,5,4,4,5,1,4,12,4,8,3,2,5,6,4,
5,4,6,6,2,4,8,4,5,5,10,6,10,4,5,4,5,3,5,2,3,4,13,4,8,3,3,1,9,3,6,3,7,5,3,3,5,1,
3,3,5,5,4,2,5,5,11,3,6,3,5,4,10,3,14,4,8,3,12,3,6,4,6,5,3,3,5,2,2,4,4,6,4,2,5,
5,6,1,3,4,5,3,6,3,10,4,14,4,5,1,2,4,11,3,6,3,7,5,3,3,4,3,1,4,4,6,4,3,5,4,6,2,3,
3,6,3,5,4,9,4,15,3,5,2,3,4,9,3,6,4,7,4,3,3,5,2,2,3,4,7,3,3,6,3,6,3,2,4,5,4,5,3,
10,3,15,4,4,3,4,3,9,3,6,3,7,4,4,3,4,3,1,4,3,3,1,3,3,3,6,4,6,2,3,3,6,3,5,4,9,4,
15,4,4,3,4,4,7,3,6,4,7,4,3,3,4,3,2,3,3,3,2,3,2,4,5,5,5,3,2,4,6,3,5,4,8,4,16,4,
4,2,6,3,7,3,5,4,7,4,4,3,3,3,3,8,2,3,2,4,5,6,4,3,3,3,7,3,4,5,8,4,16,4,4,2,6,3,6,
3,5,4,8,3,5,8,3,9,2,3,1,4,6,6,3,3,4,3,7,3,3,6,7,4,17,4,4,3,5,3,6,3,4,4,9,3,5,8,
3,7,3,8,6,3,1,4,1,4,3,4,7,3,2,3,1,3,7,4,17,4,4,3,5,3,5,11,9,3,6,7,4,6,4,7,6,3,
2,8,4,3,8,7,2,3,6,4,18,3,5,4,3,4,5,10,10,3,6,6,6,4,4,6,7,3,4,6,5,3,8,7,2,4,4,4,
19,3,5,10,5,3,1,6,11,3,7,3,16,5,7,4,4,5,6,3,8,6,3,5,3,4,19,3,6,9,5,3,18,2,25,5,
9,3,6,3,7,2,10,3,6,4,3,3,20,3,8,5,6,3,44,6,10,2,39,3,3,2,22,2,19,3,43,7,101,3,
42,8,102,3,41,4,1,4,101,4,39,5,2,3,102,3,39,4,4,3,102,3,38,4,4,4,101,3,38,4,5,
3,102,3,37,4,5,4,101,4,36,4,6,3,102,3,37,3,6,4,102,3,36,4,6,3,102,3,37,3,6,3,
103,3,37,3,5,4,102,4,37,3,4,4,103,3,38,10,104,3,38,9,105,2,40,7,106,2,41,4,0);
{--------------------------------------------------------------------------}
Procedure InitChain4; ASSEMBLER;
{ This procedure gets you into Chain 4 mode }
Asm
mov ax, 13h
int 10h { Get into MCGA Mode }
mov dx, 3c4h { Port 3c4h = Sequencer Address Register }
mov al, 4 { Index 4 = memory mode }
out dx, al
inc dx { Port 3c5h ... here we set the mem mode }
in al, dx
and al, not 08h
or al, 04h
out dx, al
mov dx, 3ceh
mov al, 5
out dx, al
inc dx
in al, dx
and al, not 10h
out dx, al
dec dx
mov al, 6
out dx, al
inc dx
in al, dx
and al, not 02h
out dx, al
mov dx, 3c4h
mov ax, (0fh shl 8) + 2
out dx, ax
mov ax, 0a000h
mov es, ax
sub di, di
mov ax, 0000h {8080h}
mov cx, 32768
cld
rep stosw { Clear garbage off the screen ... }
mov dx, 3d4h
mov al, 14h
out dx, al
inc dx
in al, dx
and al, not 40h
out dx, al
dec dx
mov al, 17h
out dx, al
inc dx
in al, dx
or al, 40h
out dx, al
mov dx, 3d4h
mov al, 13h
out dx, al
inc dx
mov al, [Size] { Size * 8 = Pixels across. Only 320 are visible}
out dx, al
End;
{--------------------------------------------------------------------------}
Procedure C4PutPixel(X,Y : Word; Col : Byte); ASSEMBLER;
{ This puts a pixel on the chain 4 screen }
Asm
mov ax,[y]
xor bx,bx
mov bl,[size]
imul bx
shl ax,1
mov bx,ax
mov ax, [X]
mov cx, ax
shr ax, 2
add bx, ax
and cx, 00000011b
mov ah, 1
shl ah, cl
mov dx, 3c4h { Sequencer Register }
mov al, 2 { Map Mask Index }
out dx, ax
mov ax, 0a000h
mov es, ax
mov al, [col]
mov es: [bx], al
End;
{--------------------------------------------------------------------------}
Procedure Plane(Which : Byte); ASSEMBLER;
{ This sets the plane to write to in Chain 4}
Asm
mov al, 2h
mov ah, 1
mov cl, [Which]
shl ah, cl
mov dx, 3c4h { Sequencer Register }
out dx, ax
End;
{--------------------------------------------------------------------------}
procedure moveto(x, y : word);
{ This moves to position x*4,y on a chain 4 screen }
var o : word;
begin
o := y*size*2+x;
asm
mov bx, [o]
mov ah, bh
mov al, 0ch
mov dx, 3d4h
out dx, ax
mov ah, bl
mov al, 0dh
mov dx, 3d4h
out dx, ax
end;
end;
{--------------------------------------------------------------------------}
Procedure Putpic (x,y:integer);
{ This put's the picture at coordinates x,y on the chain-4 screen }
Var loop1,loop2:integer;
depth,cur:integer;
BEGIN
depth:=1;
cur:=0;
For loop1:=1 to 897 do BEGIN
for loop2:=1 to bit [loop1] do BEGIN
if cur<>0 then c4putpixel ((depth mod 155)+x,(depth div 155)+y,depth div 155);
inc (depth);
END;
cur:=(cur+1) mod 2;
END;
END;
Procedure Play;
Var loop1,loop2:integer;
xpos,ypos,xdir,ydir:integer;
ch:char;
Begin
for loop1:=1 to 62 do
pal (loop1,loop1,0,62-loop1); { This sets up the pallette for the pic }
MoveTo(0,0); { This moves the view to the top left hand corner }
for loop1:=0 to 3 do
for loop2:=0 to 5 do
putpic (loop1*160,loop2*66); { This places the picture all over the
chain-4 screen }
readkey;
ch:=#0;
xpos:=random (78)+1;
ypos:=random (198)+1; { Random start positions for the view }
xdir:=1;
ydir:=1;
repeat
moveto (xpos,ypos);
waitretrace; { Take this out and watch the screen go crazy! }
xpos:=xpos+xdir;
ypos:=ypos+ydir;
if (xpos>79) or (xpos<1) then xdir:=-xdir;
if (ypos>199) or (ypos<1) then ydir:=-ydir; { Hit a boundry, change
direction! }
if keypressed then ch:=readkey;
until ch=#27; { Quit when escape is pressed }
End;
BEGIN
clrscr;
writeln ('Hello there! Here is the tenth tutorial, on Chain-4! You will notice');
writeln ('that there are two pascal files here : one is a unit containing all');
writeln ('our base graphics routines, and one is the demo program.');
writeln;
writeln ('In the demo program, we will do the necessary port stuff to get into');
writeln ('Chain-4. Once in Chain-4 mode, I will put down text saying ASPHYXIA');
writeln ('over the entire screen. After a key is pressed, the viewport will');
writeln ('bounce around, displaying the entire Chain-4 screen. The program will');
writeln ('end when [ESC] is pressed. The code here is really basic (except for');
writeln ('those port values), and should be very easy to understand.');
writeln;
writeln;
Write (' Hit any key to contine ...');
Readkey;
initChain4;
play;
SetText;
Writeln ('All done. This concludes the tenth sample program in the ASPHYXIA');
Writeln ('Training series. You may reach DENTHOR under the names of GRANT');
Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid');
Writeln ('Connectix BBS user, and occasionally read RSAProg. E-mail me at :');
Writeln (' smith9@batis.bis.und.ac.za');
Writeln ('The numbers are available in the main text. You may also write to me at:');
Writeln (' Grant Smith');
Writeln (' P.O. Box 270');
Writeln (' Kloof');
Writeln (' 3640');
Writeln (' Natal');
Writeln (' South Africa');
Writeln ('I hope to hear from you soon!');
Writeln; Writeln;
Write ('Hit any key to exit ...');
Readkey;
END.
GFX.PAS
Unit GFX;
INTERFACE
USES crt;
CONST VGA = $A000;
TYPE Virtual = Array [1..64000] of byte; { The size of our Virtual Screen }
VirtPtr = ^Virtual; { Pointer to the virtual screen }
VAR Virscr : VirtPtr; { Our first Virtual screen }
Vaddr : word; { The segment of our virtual screen}
Procedure SetMCGA;
{ This procedure gets you into 320x200x256 mode. }
Procedure SetText;
{ This procedure returns you to text mode. }
Procedure Cls (Where:word;Col : Byte);
{ This clears the screen to the specified color }
Procedure SetUpVirtual;
{ This sets up the memory needed for the virtual screen }
Procedure ShutDown;
{ This frees the memory used by the virtual screen }
procedure flip(source,dest:Word);
{ This copies the entire screen at "source" to destination }
Procedure Pal(Col,R,G,B : Byte);
{ This sets the Red, Green and Blue values of a certain color }
Procedure GetPal(Col : Byte; Var R,G,B : Byte);
{ This gets the Red, Green and Blue values of a certain color }
procedure WaitRetrace;
{ This waits for a vertical retrace to reduce snow on the screen }
Procedure Hline (x1,x2,y:word;col:byte;where:word);
{ This draws a horizontal line from x1 to x2 on line y in color col }
Procedure Line(a,b,c,d:integer;col:byte;where:word);
{ This draws a solid line from a,b to c,d in colour col }
Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
{ This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
in color col }
Function rad (theta : real) : real;
{ This calculates the degrees of an angle }
Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
{ This puts a pixel on the screen by writing directly to memory. }
Function Getpixel (X,Y : Integer; where:word) :Byte;
{ This gets the pixel on the screen by reading directly to memory. }
IMPLEMENTATION
{--------------------------------------------------------------------------}
Procedure SetMCGA; { This procedure gets you into 320x200x256 mode. }
BEGIN
asm
mov ax,0013h
int 10h
end;
END;
{--------------------------------------------------------------------------}
Procedure SetText; { This procedure returns you to text mode. }
BEGIN
asm
mov ax,0003h
int 10h
end;
END;
{--------------------------------------------------------------------------}
Procedure Cls (Where:word;Col : Byte); assembler;
{ This clears the screen to the specified color }
asm
push es
mov cx, 32000;
mov es,[where]
xor di,di
mov al,[col]
mov ah,al
rep stosw
pop es
End;
{--------------------------------------------------------------------------}
Procedure SetUpVirtual;
{ This sets up the memory needed for the virtual screen }
BEGIN
GetMem (VirScr,64000);
vaddr := seg (virscr^);
END;
{--------------------------------------------------------------------------}
Procedure ShutDown;
{ This frees the memory used by the virtual screen }
BEGIN
FreeMem (VirScr,64000);
END;
{--------------------------------------------------------------------------}
procedure flip(source,dest:Word); assembler;
{ This copies the entire screen at "source" to destination }
asm
push ds
mov ax, [Dest]
mov es, ax
mov ax, [Source]
mov ds, ax
xor si, si
xor di, di
mov cx, 32000
rep movsw
pop ds
end;
{--------------------------------------------------------------------------}
Procedure Pal(Col,R,G,B : Byte); assembler;
{ This sets the Red, Green and Blue values of a certain color }
asm
mov dx,3c8h
mov al,[col]
out dx,al
inc dx
mov al,[r]
out dx,al
mov al,[g]
out dx,al
mov al,[b]
out dx,al
end;
{--------------------------------------------------------------------------}
Procedure GetPal(Col : Byte; Var R,G,B : Byte);
{ This gets the Red, Green and Blue values of a certain color }
Var
rr,gg,bb : Byte;
Begin
asm
mov dx,3c7h
mov al,col
out dx,al
add dx,2
in al,dx
mov [rr],al
in al,dx
mov [gg],al
in al,dx
mov [bb],al
end;
r := rr;
g := gg;
b := bb;
end;
{--------------------------------------------------------------------------}
procedure WaitRetrace; assembler;
{ This waits for a vertical retrace to reduce snow on the screen }
label
l1, l2;
asm
mov dx,3DAh
l1:
in al,dx
and al,08h
jnz l1
l2:
in al,dx
and al,08h
jz l2
end;
{--------------------------------------------------------------------------}
Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler;
{ This draws a horizontal line from x1 to x2 on line y in color col }
asm
mov ax,where
mov es,ax
mov ax,y
mov di,ax
shl ax,8
shl di,6
add di,ax
add di,x1
mov al,col
mov ah,al
mov cx,x2
sub cx,x1
shr cx,1
jnc @start
stosb
@Start :
rep stosw
end;
{--------------------------------------------------------------------------}
Procedure Line(a,b,c,d:integer;col:byte;where:word);
{ This draws a solid line from a,b to c,d in colour col }
function sgn(a:real):integer;
begin
if a>0 then sgn:=+1;
if a<0 then sgn:=-1;
if a=0 then sgn:=0;
end;
var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
begin
u:= c - a;
v:= d - b;
d1x:= SGN(u);
d1y:= SGN(v);
d2x:= SGN(u);
d2y:= 0;
m:= ABS(u);
n := ABS(v);
IF NOT (M>N) then
BEGIN
d2x := 0 ;
d2y := SGN(v);
m := ABS(v);
n := ABS(u);
END;
s := m shr 1;
FOR i := 0 TO m DO
BEGIN
putpixel(a,b,col,where);
s := s + n;
IF not (s<m) THEN
BEGIN
s := s - m;
a:= a + d1x;
b := b + d1y;
END
ELSE
BEGIN
a := a + d2x;
b := b + d2y;
END;
end;
END;
{--------------------------------------------------------------------------}
Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
{ This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
in color col }
var
x:integer;
mny,mxy:integer;
mnx,mxx,yc:integer;
mul1,div1,
mul2,div2,
mul3,div3,
mul4,div4:integer;
begin
mny:=y1; mxy:=y1;
if y2<mny then mny:=y2;
if y2>mxy then mxy:=y2;
if y3<mny then mny:=y3;
if y3>mxy then mxy:=y3; { Choose the min y mny and max y mxy }
if y4<mny then mny:=y4;
if y4>mxy then mxy:=y4;
if mny<0 then mny:=0;
if mxy>199 then mxy:=199;
if mny>199 then exit;
if mxy<0 then exit; { Verticle range checking }
mul1:=x1-x4; div1:=y1-y4;
mul2:=x2-x1; div2:=y2-y1;
mul3:=x3-x2; div3:=y3-y2;
mul4:=x4-x3; div4:=y4-y3; { Constansts needed for intersection calc }
for yc:=mny to mxy do
begin
mnx:=320;
mxx:=-1;
if (y4>=yc) or (y1>=yc) then
if (y4<=yc) or (y1<=yc) then { Check that yc is between y1 and y4 }
if not(y4=y1) then
begin
x:=(yc-y4)*mul1 div div1+x4; { Point of intersection on x axis }
if x<mnx then
mnx:=x;
if x>mxx then
mxx:=x; { Set point as start or end of horiz line }
end;
if (y1>=yc) or (y2>=yc) then
if (y1<=yc) or (y2<=yc) then { Check that yc is between y1 and y2 }
if not(y1=y2) then
begin
x:=(yc-y1)*mul2 div div2+x1; { Point of intersection on x axis }
if x<mnx then
mnx:=x;
if x>mxx then
mxx:=x; { Set point as start or end of horiz line }
end;
if (y2>=yc) or (y3>=yc) then
if (y2<=yc) or (y3<=yc) then { Check that yc is between y2 and y3 }
if not(y2=y3) then
begin
x:=(yc-y2)*mul3 div div3+x2; { Point of intersection on x axis }
if x<mnx then
mnx:=x;
if x>mxx then
mxx:=x; { Set point as start or end of horiz line }
end;
if (y3>=yc) or (y4>=yc) then
if (y3<=yc) or (y4<=yc) then { Check that yc is between y3 and y4 }
if not(y3=y4) then
begin
x:=(yc-y3)*mul4 div div4+x3; { Point of intersection on x axis }
if x<mnx then
mnx:=x;
if x>mxx then
mxx:=x; { Set point as start or end of horiz line }
end;
if mnx<0 then
mnx:=0;
if mxx>319 then
mxx:=319; { Range checking on horizontal line }
if mnx<=mxx then
hline (mnx,mxx,yc,color,where); { Draw the horizontal line }
end;
end;
{--------------------------------------------------------------------------}
Function rad (theta : real) : real;
{ This calculates the degrees of an angle }
BEGIN
rad := theta * pi / 180
END;
{--------------------------------------------------------------------------}
Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler;
{ This puts a pixel on the screen by writing directly to memory. }
Asm
mov ax,[where]
mov es,ax
mov bx,[X]
mov dx,[Y]
mov di,bx
mov bx, dx {; bx = dx}
shl dx, 8
shl bx, 6
add dx, bx {; dx = dx + bx (ie y*320)}
add di, dx {; finalise location}
mov al, [Col]
stosb
End;
{--------------------------------------------------------------------------}
Function Getpixel (X,Y : Integer; where:word):byte; assembler;
{ This puts a pixel on the screen by writing directly to memory. }
Asm
mov ax,[where]
mov es,ax
mov bx,[X]
mov dx,[Y]
mov di,bx
mov bx, dx {; bx = dx}
shl dx, 8
shl bx, 6
add dx, bx {; dx = dx + bx (ie y*320)}
add di, dx {; finalise location}
lodsb
End;
{--------------------------------------------------------------------------}
Procedure LoadCEL (FileName : string; ScrPtr : pointer);
{ This loads the cel 'filename' into the pointer scrptr }
var
Fil : file;
Buf : array [1..1024] of byte;
BlocksRead, Count : word;
begin
assign (Fil, FileName);
reset (Fil, 1);
BlockRead (Fil, Buf, 800); { Read and ignore the 800 byte header }
Count := 0; BlocksRead := $FFFF;
while (not eof (Fil)) and (BlocksRead <> 0) do begin
BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);
Count := Count + 1024;
end;
close (Fil);
end;
BEGIN
END.