home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_PAS
/
XLIB_TP5.ZIP
/
UNITS
/
X_MAIN.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-01-22
|
66KB
|
1,949 lines
{$G+} (* Code for 286 or better *)
unit X_Main;
(*
Global basic procedures.
****** XLIB - Mode X graphics library ****************
****** ****************
****** Written By Themie Gouthas ( C-Version ) ****************
****** Converted By Christian Harms in TP ****************
Gouthas : egg@dstos3.dsto.gov.au or teg@bart.dsto.gov.au
Harms : harms@minnie.informatik.uni-stuttgart.de
*)
interface
uses X_Const;
(* Set Mode X - see Video-Modes in unit X_Const . *)
procedure x_set_mode(mode,logicalscrwidth:Word);
(* return count of avaible modi *)
function x_Max_Modi:Byte;
(* set X and Y to GetMaxX and GetMaxY in the mode Mode *)
procedure x_Mode_Info(Mode:Byte;var X,Y:Word);
(* set TextMode back. *)
procedure x_Text_Mode;
(* Set the write/read plane - only for intern functions. *)
procedure x_select_default_plane(Plane:Byte);
(* Set upper, left Corner of activ page (page to draw) *)
procedure x_set_activ_start_addr(x,y:Word);
(* Set upper, left Corner of visible pager (page you can see) *)
procedure x_set_visible_start_addr(x,y:Word);
(* Set Splitscreen if line>=GetMaxY then no_splitScreen. *)
procedure x_set_splitscreen(Line : Word);
(* Set Clipping window for bitmaps. *)
procedure x_set_clip_rect(left,top,right,bottom:Word);
(* Clear the whole virtuell Screen. *)
procedure X_ClearAll;
(* Clear from Line1 to Line 2 *)
procedure ClearScreen(Line1,Line2,Color:Word);
(* Look at TP-Help Point cursor on name and press Ctrl+F1 *)
procedure PutPixel(x,y:Word;Color:Byte);
function GetPixel(x,y: Word): Byte;
procedure Line(x1,y1,x2,y2,Color:Word);
procedure rectangle(x1,y1,x2,y2,Color:Word); (* not filled *)
procedure triangle(x1,y1,x2,y2,x3,y3,Color:Word); (* not filled *)
procedure LineTo(x,y,Color:Integer);
procedure MoveTo(x,y:Integer);
procedure x_circle(x,y,r,Color:Word);
procedure x_filled_circle(x,y,r,Color:Word);
implementation
uses My_Asm;
(* Mode X CRTC register tweaks for various resolutions *)
const X320Y200 : Array[0..4] of Word =
( $0200, (* 0e3h ; dot clock / Nº of CRTC Registers to update *)
$0014, (* turn off dword mode *)
$e317, (* turn on byte mode *)
320, (* width *)
200); (* height *)
X320Y240 : Array[0..12] of Word =
( $0ae3, (* dot clock *)
$0d06,(* vertical total *)
$3e07,(* overflow (bit 8 of vertical counts) *)
$4109,(* cell height (2 to double-scan) *)
$ea10,(* v sync start *)
$ac11,(* v sync end and protect cr0-cr7 *)
$df12,(* vertical displayed *)
$0014,(* turn off ord mode *)
$e715,(* v blank start *)
$0616,(* v blank end *)
$e317,(* turn on byte mode *)
320, (* width *)
240); (* height *)
X360Y200 : Array[0..10] of Word =
( $08e7, (* dot clock *)
$6b00,(* horz total *)
$5901,(* horz displayed *)
$5a02,(* start horz blanking *)
$8e03,(* end horz blanking *)
$5e04,(* start sync *)
$8a05,(* end sync *)
$0014,(* turn off ord mode *)
$e317,(* turn on byte mode *)
360, (* width *)
200); (* height *)
X360Y240 : Array[0..19] of Word =
( $11e7, (* dot clock *)
$6b00,(* horz total *)
$5901,(* horz displayed *)
$5a02,(* start horz blanking *)
$8e03,(* end horz blanking *)
$5e04,(* start sync *)
$8a05,(* end sync *)
$0d06,(* vertical total *)
$3e07,(* overflow (bit 8 of vertical counts) *)
$4109,(* cell height (2 to double-scan) *)
$ea10, (* v sync start *)
$ac11, (* v sync end and protect cr0-cr7 *)
$df12, (* vertical displayed *)
$2d13, (* offset; *)
$0014, (* turn off ord mode *)
$e715, (* v blank start *)
$0616, (* v blank end *)
$e317, (* turn on byte mode *)
360,
240);
X376Y282 : Array[0..20] of Word =
( $12e7,
$6e00, (* horz total *)
$5d01, (* horz displayed *)
$5e02, (* start horz blanking *)
$9103, (* end horz blanking *)
$6204, (* start h sync *)
$8f05, (* end h sync *)
$6206, (* vertical total *)
$f007, (* overflow *)
$6109, (* cell height *)
$310f, (* *)
$3710, (* v sync start *)
$8911, (* v sync end and protect cr0-cr7 *)
$3312, (* vertical displayed *)
$2f13, (* offset *)
$0014, (* turn off ord mode *)
$3c15, (* v blank start *)
$5c16, (* v blank end *)
$e317, (* turn on byte mode *)
376,
282);
X320Y400 : Array[0..5] of Word =
( $03e3, (* dot clock *)
$4009, (* cell height *)
$0014, (* turn off ord mode *)
$e317, (* turn on byte mode *)
320, (* width *)
400); (* height *)
X320Y480 : Array[0..12] of Word =
( $0Ae3, (* dotclock *)
$0d06, (* vertical total *)
$3e07, (* overflow (bit 8 of vertical counts) *)
$4009, (* cell height (2 to double-scan) *)
$ea10, (* v sync start *)
$ac11, (* v sync end and protect cr0-cr7 *)
$df12, (* vertical displayed *)
$0014, (* turn off ord mode *)
$e715, (* v blank start *)
$0616, (* v blank end *)
$e317, (* turn on byte mode *)
320, (* width *)
480); (* height *)
X360Y400 : Array[0..11] of Word =
( $09e7, (* dot clock *)
$6b00, (* horz total *)
$5901, (* horz displayed *)
$5a02, (* start horz blanking *)
$8e03, (* end horz blanking *)
$5e04, (* start sync *)
$8a05, (* end sync *)
$4009, (* cell height *)
$0014, (* turn off ord mode *)
$e317, (* turn on byte mode *)
360, (* width *)
400); (* height *)
X360Y480 : Array[0..19] of Word =
( $11e7,
$6b00, (* horz total *)
$5901, (* horz displayed *)
$5a02, (* start horz blanking *)
$8e03, (* end horz blanking *)
$5e04, (* start h sync *)
$8a05, (* end h sync *)
$0d06, (* vertical total *)
$3e07, (* overflow *)
$4009, (* cell height *)
$ea10, (* v sync start *)
$ac11, (* v sync end and protect cr0-cr7 *)
$df12, (* vertical displayed *)
$2d13, (* offset *)
$0014, (* turn off ord mode *)
$e715, (* v blank start *)
$0616, (* v blank end *)
$e317, (* turn on byte mode *)
360,
480);
X360Y360 : Array[0..17] of Word =
( $0fe7,
$6b00, (* horz total *)
$5901, (* horz displayed *)
$5a02, (* start horz blanking *)
$8e03, (* end horz blanking *)
$5e04, (* start h sync *)
$8a05, (* end h sync *)
$4009, (* cell height *)
$8810, (* v sync start *)
$8511, (* v sync end and protect cr0-cr7 *)
$6712, (* vertical displayed *)
$2d13, (* offset *)
$0014, (* turn off ord mode *)
$6d15, (* v blank start *)
$ba16, (* v blank end *)
$e317, (* turn on byte mode *)
360,
360);
X376Y308 : Array[0..20] of Word =
( $12e7,
$6e00, (* horz total *)
$5d01, (* horz displayed *)
$5e02, (* start horz blanking *)
$9103, (* end horz blanking *)
$6204, (* start h sync *)
$8f05, (* end h sync *)
$6206, (* vertical total *)
$0f07, (* overflow *)
$4009, (* *)
$310f, (* *)
$3710, (* v sync start *)
$8911, (* v sync end and protect cr0-cr7 *)
$3312, (* vertical displayed *)
$2f13, (* offset *)
$0014, (* turn off ord mode *)
$3c15, (* v blank start *)
$5c16, (* v blank end *)
$e317, (* turn on byte mode *)
376,
308);
X376Y564 : Array[0..20] of Word =
( $12e7,
$6e00, (* horz total *)
$5d01, (* horz displayed *)
$5e02, (* start horz blanking *)
$9103, (* end horz blanking *)
$6204, (* start h sync *)
$8f05, (* end h sync *)
$6206, (* vertical total *)
$f007, (* overflow *)
$6009, (* *)
$310f, (* *)
$3710, (* v sync start *)
$8911, (* v sync end and protect cr0-cr7 *)
$3312, (* vertical displayed *)
$2f13, (* offset *)
$0014, (* turn off ord mode *)
$3c15, (* v blank start *)
$5c16, (* v blank end *)
$e317, (* turn on byte mode *)
376,
564);
X256Y200 : Array[0..10] of Word =
( $08e3, (* dot clock, Number of CRTC Registers to update *)
$5f00, (* horz total *)
$3f01, (* horz displayed *)
$4202, (* start horz blanking *)
$9f03, (* end horz blanking *)
$4c04, (* start h sync *)
$0005, (* end h sync *)
$0014, (* turn off dword mode *)
$e317, (* turn on byte mode *)
256,
200);
X256Y240 : Array[0..18] of Word =
( $10e3, (* dot clock, Number of CRTC Registers to update *)
$5f00, (* horz total *)
$3f01, (* horz displayed *)
$4202, (* start horz blanking *)
$9f03, (* end horz blanking *)
$4c04, (* start h sync *)
$0005, (* end h sync *)
$0d06, (* vertical total *)
$3e07, (* overflow (bit 8 of vertical counts) *)
$4109, (* cell height (2 to double-scan) *)
$ea10, (* v sync start *)
$ac11, (* v sync end and protect cr0-cr7 *)
$df12, (* vertical displayed *)
$0014, (* turn off dword mode *)
$e715, (* v blank start *)
$0616, (* v blank end *)
$e317, (* turn on byte mode *)
256,
240);
LAST_X_MODE=13;
ModeTable : Array[0..Last_X_MODE] of Word =
( ofs(X320Y200),
ofs(X320Y240),
ofs(X360Y200),
ofs(X360Y240),
ofs(X376Y282),
ofs(X320Y400),
ofs(X320Y480),
ofs(X360Y400),
ofs(X360Y480),
ofs(X360Y360),
ofs(X376Y308),
ofs(X376Y564),
ofs(X256Y200),
ofs(X256Y240) );
(* Index/data pairs for CRT Controller registers that differ between *)
(* mode 13h and mode X. *)
(* Pelpan values for 0,1,2,3 pixel panning to the left, respectively *)
PelPanMask : Array[0..3] of Byte = (0,2,4,6);
var DoubleScanFlag:Boolean; (* Flag to indicate double scanned mode *)
function X_Max_Modi:Byte;
begin;
X_Max_Modi:=SizeOf(ModeTable) div 2-1;
end;
procedure X_Mode_Info(Mode:Byte;var X,Y:Word); assembler;
asm;
xor ax,ax
mov al,Mode
mov di,ax
shl di,1
add di,OFFSET ModeTable
mov di,ds:[di]
inc di
xor ah,ah
mov al,ds:[di]
dec di
shl ax,1
add di,ax
mov cx,ds:[di+2] (* cx := X *)
mov dx,ds:[di+4] (* dx := Y *)
les si,dword ptr [X]
mov es:[si],cx
les si,dword ptr [Y]
mov es:[si],dx
end;
(* ------------------------------------------------------------------------ *)
(* Local Logical Screen Width setting function *)
(* cx = Requitrd Logical Width *)
(* *)
(* WARNING: no registers are preserved *)
procedure SetLogicalScrWidth; assembler;
asm
mov dx,CRTC_INDEX
mov al,CRTC_OFFSET
out dx,al
inc dx
mov ax,cx
cmp ax,ScrnPhysicalPixelWidth(* Is logical width >= physical width *)
jge @@ValidLogicalWidth (* yes - continue *)
mov ax,bx (* no - set logical width = physical *)
@@ValidLogicalWidth:
shr ax,3
out dx,al
(* The EXACT logical pixel width may not have been possible since *)
(* it should be divisible by 8. Round down to the closest possible *)
(* width and update the status variables *)
shl ax,1
mov bx,ax
mov ScrnLogicalByteWidth,ax (* Store the byte width of virtual *)
mov RightClip,ax (* Set default Right clip column *)
(* screen *)
sub ax,ScrnPhysicalByteWidth (* Calculate and store Max X position*)
shl ax,2 (* of physical screen in virtual *)
mov MaxScrollX,ax (* screen in pixels *)
mov ax,bx (* set ax to byte width of virt scrn *)
shl ax,2 (* convert to pixels *)
mov ScrnLogicalPixelWidth,ax (* store virt scrn pixel width *)
mov cx,ax (* save ax (return value) *)
(* calculate no. non split screen rows in video ram *)
mov ax,$ffff (* cx = Maximum video ram offset *)
sub dx,dx (* DX:AX is divide operand, set DX = 0 *)
div bx (* divide ax by ScrnLogicalByteWidth *)
mov ScrnLogicalHeight,ax (* Save Screen Logical Height *)
mov BottomClip,ax (* Set default bottom clip row *)
sub ax,ScrnPhysicalHeight (* Update the maximum Y position of *)
mov MaxScrollY,ax (* Physical screen in logical screen *)
mov ax,cx (* restore ax (return value) *)
(* calculate initial NonVisual *)
mov ax,ScrnLogicalByteWidth
mul ScrnPhysicalHeight
mov NonVisual_Offs,ax
@@Done:
end;
(* ----------------------------------------------------------------------- *)
(* Mode X graphics mode set with a virtual screen *)
(* logical screen width. *)
(* *)
(* returns the actual width of the allocated virtual screen in pixels *)
(* if a valid mode was selected otherwise returns -1 *)
(* *)
(* Saves virtual screen pixel width in ScrnLogicalPixelWidth. *)
(* Saves virtual screen byte width in ScrnLogicalByteWidth. *)
(* Physical screen dimensions are set in ScrnPhysicalPixelWidth, *)
(* ScrnPhysicalByteWidth and ScrnPhysicalHeight *)
(* *)
(* *)
(* Modes: 0 = 320 x 200 (256 color) NOTE: Some of these modes require *)
(* 1 = 320 x 240 (256 color) vertical size adjustment. *)
(* 2 = 360 x 200 (256 color) *)
(* 3 = 360 x 240 (256 color) *)
(* 4 = 376 x 282 (256 color) *)
(* 5 = 320 x 400 (256 color) *)
(* 6 = 320 x 480 (256 color) *)
(* 7 = 360 x 400 (256 color) *)
(* 8 = 360 x 480 (256 color) *)
(* 9 = 360 x 360 (256 color) *)
(* 10 = 376 x 308 (256 color) *)
(* 11 = 376 x 564 (256 color) *)
(* *)
(* Written by Themie Gouthas, *)
(* parts adapted from M. Abrash code. *)
(* ------------------------------------------------------------------------ *)
procedure x_set_mode(mode,logicalscrwidth:Word); assembler;
asm
mov InGraphics,0
mov ErrorValue,0
mov DoubleScanFlag,0
mov CurrXMode,0
mov ScrnPhysicalByteWidth,0
mov ScrnPhysicalPixelWidth,0
mov ScrnPhysicalHeight,0
mov SplitScrnOffs,0
mov SplitScrnScanLine,0
mov SplitScrnVisibleHeight,0
mov SplitScrnActive,0
mov Page0_Offs,0
mov Page1_Offs,0
mov Page2_Offs,0
mov ScrnLogicalByteWidth,0
mov ScrnLogicalPixelWidth,0
mov ScrnLogicalHeight,0
mov MaxScrollX,0
mov MaxScrollY,0
mov DoubleBufferActive,0
mov VisiblePageIdx,0
mov HiddenPageOffs,0
mov VisiblePageOffs,0
mov NonVisual_Offs,0
mov TopClip,0
mov BottomClip,0
mov LeftClip,0
mov RightClip,0
mov PhysicalStartPixelX,0
mov PhysicalStartByteX,0
mov PhysicalStartY,0
mov Active_StartX,0
mov Active_StartY,0
cld
mov ax,ds
mov es,ax
mov cx,mode
cmp cx,LAST_X_MODE (* have we selected a valid mode *)
jle @@ValidMode (* Yes ! *)
mov InGraphics,FALSE (* No return -1 *)
mov ax,-1
jmp @Ende
@@ValidMode:
mov CurrXMode,cx
mov InGraphics,TRUE
xor al,al
cmp cx,3
jg @@SetDoubleScanFlag
mov al,TRUE
@@SetDoubleScanFlag:
mov DoubleScanFlag,al
push cx (* some bios's dont preserve cx *)
mov ax,13h (* let the BIOS set standard 256-color *)
int 10h (* mode (320x200 linear) *)
pop cx
mov dx,SC_INDEX
mov ax,0604h
out dx,ax (* disable chain4 mode *)
mov ax,0100h
out dx,ax (* synchronous reset while setting Misc*)
(* Output for safety, even though clock*)
(* unchanged *)
mov bx,offset ModeTable
shl cx,1
add bx,cx
mov si, word ptr [bx]
lodsb
or al,al
jz @@DontSetDot
mov dx,MISC_OUTPUT
out dx,al (* select the dot clock and Horiz *)
(* scanning rate *)
@@DontSetDot:
mov dx,SC_INDEX
mov ax,0300h
out dx,ax (* undo reset (restart sequencer) *)
mov dx,CRTC_INDEX (* reprogram the CRT Controller *)
mov al,11h (* VSync End reg contains register write *)
out dx,al (* protect bit *)
inc dx (* CRT Controller Data register *)
in al,dx (* get current VSync End register setting*)
and al,$7f (* remove write protect on various *)
out dx,al (* CRTC registers *)
dec dx (* CRT Controller Index *)
cld
xor cx,cx
lodsb
mov cl,al
@@SetCRTParmsLoop:
lodsw (* get the next CRT Index/Data pair *)
out dx,ax (* set the next CRT Index/Data pair *)
loop @@SetCRTParmsLoop
mov dx,SC_INDEX
mov ax,0f02h
out dx,ax (* enable writes to all four planes *)
mov ax,SCREEN_SEG (* now clear all display memory, 8 pixels*)
mov es,ax (* at a time *)
sub di,di (* point ES:DI to display memory *)
sub ax,ax (* clear to zero-value pixels *)
mov cx,$8000 (* # of words in display memory *)
rep stosw (* clear all of display memory *)
(* Fix for single line *)
(* mov dx,CRTC_INDEX *)
(* mov al,MAX_SCAN_LINE *)
(* out dx,al *)
(* inc dx *)
(* mov al,0C0h *)
(* out dx,al *)
(* Set pysical screen dimensions *)
lodsw (* Load scrn pixel width *)
mov ScrnPhysicalPixelWidth,ax (* from tweak table and store *)
mov SplitScrnScanLine,ax (* No splitscrn == *)
(* splitscrn=PhysicalscrnHeight *)
mov bx,ax (* Copy width for later use *)
shr ax,2 (* Convert to byte width *)
mov ScrnPhysicalByteWidth,ax (* Store for later use *)
lodsw (* Load Screen Phys. Height *)
mov ScrnPhysicalHeight,ax (* Store for later use *)
(* Mode X is set, now set the required logical page width. *)
mov cx,logicalscrwidth
call SetLogicalScrWidth
mov ax,GetMaxY
mov SplitScrnScanLine,ax
xor ax,ax
mov cx,ScrnLogicalByteWidth
mov es,ax
mov bx,$44a
mov es:[bx],cx (* Update Bios-ScreenWidth *)
mov cx,logicalscrwidth
mov dx,Crtc_Index
mov al,CRTC_OFFSET
out dx,al
inc dx
mov ax,cx
cmp ax,ScrnPhysicalPixelWidth
jge @@ValidLogicalWidth
mov ax,bx
@@ValidLogicalWidth:
shr ax,3
out dx,al
shl ax,1
mov bx,ax
mov ScrnLogicalByteWidth,ax
mov RightClip,ax
sub ax,ScrnPhysicalByteWidth
shl ax,2
mov MaxScrollX,ax
mov ax,bx
shl ax,2
mov ScrnLogicalPixelWidth,ax
mov cx,ax
mov ax,0ffffh
sub dx,dx
div bx
mov ScrnLogicalHeight,ax
mov BottomClip,ax
sub ax,ScrnPhysicalHeight
mov MaxScrollY,ax
mov ax,cx
mov ax,ScrnLogicalByteWidth
mul ScrnPhysicalHeight
mov NonVisual_Offs,ax
@@Done:
@ende: (* Call to unchain to save Mode-X in TP *)
{ mov ax,$CB00
int $10 }
end;
procedure X_Text_Mode;assembler;
asm;
mov ax,03
int $10;
end;
(*---------------------------------------------------------------------- *)
(* Mode X (256 color mode) set default access video plane *)
(* *)
(* x_select_default_plane(plane:Byte); *)
(* *)
(* Enables Read/Write access to a plane using general memory access *)
(* methods *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_select_default_plane(Plane:Byte); assembler;
asm
mov cl,byte ptr [Plane]
(* SELECT WRITE PLANE *)
and cl,011b (* CL = plane *)
mov ax,0100h + MAP_MASK (* AL = index in SC of Map Mask reg *)
shl ah,cl (* set only the bit for the required *)
(* plane to 1 *)
mov dx,SC_INDEX (* set the Map Mask to enable only the *)
out dx,ax (* pixel's plane *)
(* SELECT READ PLANE *)
mov ah,cl (* AH = plane *)
mov al,READ_MAP (* AL = index in GC of the Read Map reg *)
mov dx,GC_INDEX (* set the Read Map to read the pixel's *)
out dx,ax (* plane *)
end;
{
(* ----------------------------------------------------------------------
(* Mode X (256 color mode) Set Mode X split screen starting row
(* The split screen resides on the bottom half of the screen and has a
(* starting address of A000:0000
(*
(* C near-callable as:
(* void x_set_splitscreen(unsigned int line)(*
(*
(* Updates _Page0_Offs to reflect the existence of the split screen region
(* ie _MainScrnOffset is set to the offset of the first pixel beyond the split
(* screen region
(*
(* Written by Themie Gouthas
(* ----------------------------------------------------------------------
}
procedure x_set_splitscreen(Line : Word);
VAR CRTC: Word ABSOLUTE $0000:$0463;
BEGIN
if DoubleScanFlag then Inc(Line,Line);
Port[CRTC] := $18; (* Index für Line Compare Reg. *)
Port[CRTC+1] := Lo(line); (* Lowbyte laden *)
Port[CRTC] := $07; (* Index für Overflow Reg. *)
IF (Line AND $100) > 0 THEN
(* Line Compare-Bit 8 = 1, also Overflow-Bit 4 setzen: *)
Port[CRTC+1] := Port[CRTC+1] OR $10
ELSE
(* Line Compare-Bit 8 = 0, also Overflow-Bit 4 zurücksetzen: *)
Port[CRTC+1] := Port[CRTC+1] AND NOT $10;
Port[CRTC] := $09; (* Index für Max. Scanline Reg. *)
IF (Line AND $200) > 0 THEN
(* Line Compare-Bit 9 = 1, Max. Scanline-Bit 6 setzen: *)
Port[CRTC+1] := Port[CRTC+1] OR $40
ELSE
(* Line Compare-Bit 9 = 0, Max. Scanline-Bit 6 zurücksetzen: *)
Port[CRTC+1] := Port[CRTC+1] AND NOT $40;
SplitScrnOffs:=0;
SplitScrnScanLine:=Line;
SplitScrnVisibleHeight:=GetMaxY-Line;
END;
(* ----------------------------------------------------------------------- *)
(* Mode X (256 color mode) Set Mode X non split screen start address *)
(* of logical screen. *)
(* C near-callable as: *)
(* *)
(* void x_set_start_addr(unsigned int x, unsigned int y)(* *)
(* *)
(* Params: StartOffset is offset of first byte of logical screen ram *)
(* (Useful if you want to double buffer by splitting your non *)
(* split screen video ram into 2 pages) *)
(* X,Y coordinates of the top left hand corner of the physical screen *)
(* within the logical screen *)
(* X must not exceed (Logical screen width - Physical screen width)*)
(* Y must not exceed (Logical screen height - Physical screen height)*)
(* *)
(* *)
(* Written by Themie Gouthas, *)
(* Parts addapted from M. Abrash code published in DDJ Mag. *)
(* ------------------------------------------------------------------------ *)
procedure x_set_activ_start_addr(x,y:Word);
begin;
if x>ScrnLogicalPixelWidth-ScrnPhysicalPixelWidth then
x:=(ScrnLogicalPixelWidth-ScrnPhysicalPixelWidth) and $FFF8;
if y>ScrnLogicalHeight-ScrnPhysicalHeight then
y:=ScrnLogicalHeight-ScrnPhysicalHeight;
ScreenOfs:=y*ScrnLogicalByteWidth+x div 4;
end;
procedure x_set_visible_start_addr(x,y:Word); assembler;
asm
mov si,x
mov ax,ScrnLogicalByteWidth (* Calculate Offset increment *)
mov cx,y (* for Y *)
mul cx
cmp DoubleBufferActive,TRUE (* Do we have double buffering ? *)
je @@PageResolution
@PageFlipEntry1:
add ax,Page0_Offs (* no - add page 0 offset *)
jmp @@AddColumn
@PageFlipEntry2:
mov PhysicalStartPixelX,si
mov PhysicalStartY,cx
@@PageResolution:
add ax,VisiblePageOffs (* Add visible page offset *)
@@AddColumn:
mov cx,si
shr cx,2
mov PhysicalStartByteX,cx
add ax,cx (* add the column offset for X *)
mov bh,al (* setup CRTC start addr regs and *)
(* values in word registers for *)
mov ch,ah (* fast word outs *)
@StartAddrEntry:
mov bl,ADDR_LOW
mov cl,ADDR_HIGH
and si,0003h (* select pel pan register value for the *)
mov ah,[offset PelPanMask+si] (* required x coordinate *)
mov al,PEL_PANNING+20h
mov si,ax
mov dx,INPUT_STATUS_0 (* Wait for trailing edge of Vsync pulse *)
@@WaitDE:
in al,dx
test al,01h
jnz @@WaitDE (* display enable is active low (0 = active)*)
mov dx,CRTC_INDEX
mov ax,bx
out dx,ax (* start address low *)
mov ax,cx
out dx,ax (* start address high *)
mov dx,AC_INDEX
mov ax,si (* Point the attribute controller to pel pan*)
out dx,al (* reg. Bit 5 also set to prevent blanking *)
mov al,ah
out dx,al (* load new Pel Pan setting. *)
(* Now wait for vertical sync, so the other page will be invisible when *)
(* we start drawing to it. *)
mov dx,INPUT_STATUS_0 (* Wait for trailing edge of Vsync pulse *)
@@WaitVS:
in al,dx
test al,08h
jz @@WaitVS (* display enable is active low (0 = active) *)
mov ErrorValue,OK
end;
(* -----------------------------------------------------------------------*)
(* Set Clipping rectangle *)
(* C callable as: *)
(* *)
(* *)
(* int x_set_clip_rect(WORD left,WORD top, WORD right, WORD bottom); *)
(* *)
(* *)
(* NOTE clipping is byte oriented. "left" and "right" are in bytes not pixels. *)
(* Only selected functions perform any clipping at all. *)
(* *)
(* Written by Themie Gouthas *)
(* -----------------------------------------------------------------------*)
procedure x_set_clip_rect(left,top,right,bottom:Word); assembler;
asm
mov cl,2
mov ax,[left]
mov bx,[right]
cmp bx,ax
jns @@CorrectXOrder
xchg bx,ax
@@CorrectXOrder:
shr ax,cl
shr bx,cl
mov [LeftClip],ax
mov [RightClip],bx
mov ax,[top]
mov bx,[bottom]
cmp bx,ax
jns @@CorrectYOrder
xchg bx,ax
@@CorrectYOrder:
mov [TopClip],ax
mov [BottomClip],bx
end;
procedure X_ClearAll; assembler;
asm;
mov ax,0F00h + MAP_MASK (* AL = index in SC of Map Mask reg *)
mov dx,SC_INDEX (* set the Map Mask to enable all *)
out dx,ax (* pixel's planes *)
mov ax,SCREEN_SEG
mov es,ax
xor ax,ax
mov di,ax
mov cx,$FFFF
rep stosb
end;
procedure ClearScreen(Line1,Line2,Color:Word); assembler;
asm;
mov ax,0F00h + MAP_MASK (* AL = index in SC of Map Mask reg *)
mov dx,SC_INDEX (* set the Map Mask to enable all *)
out dx,ax (* pixel's planes *)
mov ax,SCREEN_SEG
mov es,ax
mov ax,Line1
mov bx,ScrnLogicalByteWidth
mul bx
mov di,ax
mov ax,Line2
sub ax,Line1
mov bx,ScrnLogicalByteWidth
mul bx
mov cx,ax
mov ax,Color
rep stosb
end;
(* --------------------------------------------------------------------- *)
(* Mode X (256 color mode) write pixel routine. *)
(* *)
(* Based on code originally published in DDJ Mag by M. Abrash *)
(* *)
{$F+}
procedure PutPixel (x,y:Word;Color:Byte); assembler;
asm;
mov ax,X_Const.ScrnLogicalByteWidth
mul Y (* offset of pixel's scan line in page *)
mov bx,X
shr bx,2 (* X/4 = offset of pixel in scan line *)
add bx,ax (* offset of pixel in page *)
add bx,X_Const.ScreenOfs (* offset of pixel in display memory *)
mov ax,SCREEN_SEG
mov es,ax (* point ES:BX to the pixel's address *)
mov cl,byte ptr [X]
and cl,011b (* CL = pixel's plane *)
mov ax,$100 + MAP_MASK (* AL = index in SC of Map Mask reg *)
shl ah,cl (* set only the bit for the pixel's *)
(* plane to 1 *)
mov dx,SC_INDEX (* set the Map Mask to enable only the *)
out dx,ax (* pixel's plane *)
mov al,byte ptr [Color]
mov es:[bx],al (* draw the pixel in the desired color *)
end;
(* --------------------------------------------------------------------- *)
(* Mode X read pixel routine. *)
(* *)
(* Based on code originally published in DDJ Mag by M. Abrash *)
(* *)
function GetPixel(x,y:Word):Byte; assembler;
asm;
mov ax,X_Const.ScrnLogicalByteWidth
mul [Y] (* offset of pixel's scan line in page *)
mov bx,[X]
shr bx,2 (* X/4 = offset of pixel in scan line *)
add bx,ax (* offset of pixel in page *)
add bx,X_Const.ScreenOfs (* offset of pixel in display memory *)
mov ax,SCREEN_SEG
mov es,ax (* point ES:BX to the pixel's address *)
mov ah,byte ptr [X]
and ah,011b (* AH = pixel's plane *)
mov al,READ_MAP (* AL = index in GC of the Read Map reg *)
mov dx,GC_INDEX (* set the Read Map to read the pixel's *)
out dx,ax (* plane *)
mov al,es:[bx] (* read the pixel's color *)
sub ah,ah (* convert it to an unsigned int *)
end;
{$F-}
(* --------------------------------------------------------------------- *)
(* Line drawing function for all MODE X 256 Color resolutions. *)
(* Based on code from "PC and PS/2 Video Systems" by Richard Wilton. *)
(* *)
procedure Line(x1,y1,x2,y2,Color:Word); assembler;
var vertincr,incr1,incr2,routine:word;
label HiSlopeLine,LoSlopeLine;
asm;
mov ax,0a000h
mov es,ax
mov dx,3c4h (* setup for plane mask access *)
(* check for vertical line *)
mov si,X_Const.ScrnLogicalByteWidth
mov cx,x2
sub cx,x1
jz @VertLine
(* force x1 < x2 *)
jns @L01
neg cx
mov bx,x2
xchg bx,x1
mov x2,bx
mov bx,y2
xchg bx,y1
mov y2,bx
(* calc dy = abs(y2 - y1) *)
@L01:
mov bx,y2
sub bx,y1
jnz @skip
jmp @HorizLine
@skip: jns @L03
neg bx
neg si
(* select appropriate routine for slope of line *)
@L03:
mov vertincr,si
mov routine,offset LoSlopeLine
cmp bx,cx
jle @L04
mov routine,offset HiSlopeLine
xchg bx,cx
(* calc initial decision variable and increments *)
@L04:
shl bx,1
mov incr1,bx
sub bx,cx
mov si,bx
sub bx,cx
mov incr2,bx
(* calc first pixel address *)
push cx
mov ax,y1
mov bx,x1
mov cl,bl (* ModeXAddr *)
push dx
mov dx,ScrnLogicalByteWidth
mul dx
pop dx
shr bx,2
add bx,ax
add bx,ScreenOfs
and cl,3
mov di,bx
mov al,1
shl al,cl
mov ah,al (* duplicate nybble *)
shl al,4
add ah,al
mov bl,ah
pop cx
inc cx
jmp routine
(* routine for verticle lines *)
@VertLine:
mov ax,y1
mov bx,y2
mov cx,bx
sub cx,ax
jge @L31
neg cx
mov ax,bx
@L31:
inc cx
mov bx,x1
push cx
mov cl,bl (* ModeXAddr *)
push dx
mov dx,ScrnLogicalByteWidth
mul dx
pop dx
shr bx,2
add bx,ax
add bx,ScreenOfs
and cl,3
mov ah,1
shl ah,cl
mov al,02
out dx,ax
pop cx
mov ax, word ptr [Color]
(* draw the line *)
@L32:
mov es:[bx],al
add bx,si
loop @L32
jmp @Lexit
(* routine for horizontal line *)
@HorizLine:
push ds
mov ax,y1
mov bx,x1
mov cl,bl (* ModeXAddr *)
push dx
mov dx,ScrnLogicalByteWidth
mul dx
pop dx
shr bx,2
add bx,ax
add bx,ScreenOfs
and cl,3
mov di,bx (* set dl = first byte mask *)
mov dl,00fh
shl dl,cl
mov cx,x2 (* set dh = last byte mask *)
and cl,3
mov dh,00eh
shl dh,cl
not dh
(* determine byte offset of first and last pixel in line *)
mov ax,x2
mov bx,x1
shr ax,2 (* set ax = last byte column *)
shr bx,2 (* set bx = first byte column *)
mov cx,ax (* cx = ax - bx *)
sub cx,bx
mov ax,dx (* mov end byte masks to ax *)
mov dx,3c4h (* setup dx for VGA outs *)
mov bx, Color
(* set pixels in leftmost byte of line *)
or cx,cx (* is start and end pt in same byte *)
jnz @L42 (* no ! *)
and ah,al (* combine start and end masks *)
jmp @L44
@L42: push ax
mov ah,al
mov al,02
out dx,ax
mov al,bl
stosb
dec cx
(* draw remainder of the line *)
@L43:
mov ah,0Fh
mov al,02
out dx,ax
mov al,bl
rep stosb
pop ax
(* set pixels in rightmost byte of line *)
@L44:
mov al,02
out dx, ax
mov byte ptr es:[di],bl
pop ds
jmp @Lexit
(* routine for dy >= dx (slope <= 1) *)
LoSlopeLine:
mov al,02
mov bh,byte ptr [Color]
@L10:
mov ah,bl
@L11:
or ah,bl
rol bl,1
jc @L14
(* bit mask not shifted out *)
or si,si
jns @L12
add si,incr1
loop @L11
out dx,ax
mov es:[di],bh
jmp @Lexit
@L12:
add si,incr2
out dx,ax
mov es:[di],bh
add di,vertincr
loop @L10
jmp @Lexit
(* bit mask shifted out *)
@L14: out dx,ax
mov es:[di],bh
inc di
or si,si
jns @L15
add si,incr1
loop @L10
jmp @Lexit
@L15:
add si,incr2
add di,vertincr
loop @L10
jmp @Lexit
(* routine for dy > dx (slope > 1) *)
HiSlopeLine:
mov bx,vertincr
mov al,02
@L21: out dx,ax
push ax
mov ax,Color
mov es:[di],al
pop ax
add di,bx
@L22:
or si,si
jns @L23
add si,incr1
loop @L21
jmp @Lexit
@L23:
add si,incr2
rol ah,1
adc di,0
@lx21: loop @L21
(* return to caller *)
@Lexit:
end;
procedure rectangle(x1,y1,x2,y2,Color:Word);
begin;
Line(x1,y1,x2,y1,Color);
Line(x1,y1,x1,y2,Color);
Line(x1,y2,x2,y2,Color);
Line(x2,y1,x2,y2,Color);
end;
procedure triangle(x1,y1,x2,y2,x3,y3,Color:Word);
begin;
Line(x1,y1,x2,y2,Color);
Line(x2,y2,x3,y2,Color);
Line(x3,y3,x1,y1,Color);
end;
var my_X,my_Y:Integer;
procedure MoveTo(x,y:Integer); (* doc in graph.tpu *)
begin;
my_X:=X;
my_Y:=Y;
end;
procedure LineTo(x,y,Color:Integer); (* doc in graph.tpu *)
begin;
Line(my_X,My_Y,x,y,Color);
my_X:=X;
my_Y:=Y;
end;
(* Draw a circle. *)
(* *)
(* C near-callable as: *)
(* int x_circle (WORD Left, WORD Top, WORD Diameter, *)
(* WORD Color, WORD ScreenOffs)(* *)
(* *)
(* No clipping is performed. *)
(* *)
(* ax, bx, cx, and dx bite the dust, as Homer would say. *)
(* we plot into eight arcs at once: *)
(* 4 0 *)
(* 6 \|/ 2 *)
(* --*-- *)
(* 7 /|\ 3 *)
(* 5 1 *)
(* *)
(* 0, 1, 4, and 5 are considered x-major(* the rest, y-major. *)
(* *)
(* The x-major plots grow out from the top and bottom of the circle, *)
(* while the y-major plots start at the left and right edges. *)
const ColumnMask:Array[0..3] of Byte = ($11,$22,$44,$88);
procedure x_circle(x,y,r,Color:Word); assembler;
var offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,
mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error:word;
left,top,Diameter:Word;
asm
push ds
(* convert x,y,r in left,top,Diameter *)
mov bx,r
mov ax,x
sub ax,bx
mov left,ax
mov ax,y
sub ax,bx
mov top,ax
shl bx,1
mov Diameter,bx
(* find starting locations of plots 2, 3, 6, and 7 *)
mov di, ScrnLogicalByteWidth
xor dx, dx
mov ax, Diameter (* find vertical midpoint *)
dec ax
shr ax, 1
adc dx, 0 (* remember if it's rounded *)
mov shrunk_radius, ax (* radius, rounded down for adding *)
mov diameter_even, dx (* (diameter - 1) & 1, effectively *)
add ax, Top
mul di (* vertical midpoint in bytes *)
add ax, ScreenOfs
mov bx, Left
mov cx, bx (* save for later *)
mov si, bx
shr si, 2
add si, ax
mov offset6, si
and bx, 3 (* column of left side *)
mov bl, ds:[offset ColumnMask+bx]
mov mask6n7, bx
add cx, Diameter
dec cx
mov bx, cx
shr cx, 2
add cx, ax
mov offset2, cx
and bx, 3 (* column of right side*)
mov bl, ds:[offset ColumnMask+bx]
mov mask2n3, bx
cmp diameter_even, 1
jne @@MiddlePlotsOverlap
add si, di
add cx, di
@@MiddlePlotsOverlap:
mov offset7, si
mov offset3, cx
(* starting locations of 0, 1, 4, and 5 *)
mov bx, Left
add bx, shrunk_radius (* find horizontal midpoint *)
mov ax, Top (* top in bytes *)
mul di
add ax, ScreenOfs
mov si, ax
mov ax, Diameter (* bottom in bytes *)
dec ax
mul di
add ax, si
mov di, bx (* horizontal midpoint in bytes *)
shr di, 2
add si, di (* top midpoint in bytes *)
mov offset4, si
add di, ax (* bottom midpoint in bytes *)
mov offset5, di
and bx, 3 (* column of horizontal midpoint*)
mov bl, ds:[offset ColumnMask+bx]
mov mask4n5, bx
cmp diameter_even, 1
jne @@TopAndBottomPlotsOverlap
rol bl, 1
jnc @@TopAndBottomPlotsOverlap
inc si
inc di
@@TopAndBottomPlotsOverlap:
mov offset0, si
mov offset1, di
mov mask0n1, bx
(* we've got our eight plots in their starting positions, so *)
(* it's time to sort out the registers *)
mov bx, ScrnLogicalByteWidth
mov dx, SCREEN_SEG
mov ds, dx
mov dx, SC_INDEX (* set VGA to accept column masks *)
mov al, MAP_MASK
out dx, al
inc dx (* gun the engine... *)
mov si, Diameter (* initial y is radius -- 2 #s per pixel *)
inc si
mov cx, si
neg cx
add cx, 2
mov error, cx (* error = -y + one pixel since we're a step ahead *)
xor cx, cx (* initial x = 0 *)
mov ah, byte ptr Color
jmp @@CircleCalc (* let's actually put something on the screen! *)
(* move the x-major plots horizontally and the y-major plots vertically *)
@@NoAdvance:
mov al, byte ptr mask0n1
out dx, al
mov di, offset0 (* plot 0 *)
mov [di], ah
rol al, 1 (* advance 0 right *)
mov byte ptr mask0n1, al
adc di, 0
mov offset0, di
mov di, offset1
mov [di], ah (* plot 1 *)
ror al, 1 (* what was that bit again? *)
adc di, 0 (* advance 1 right *)
mov offset1, di
mov al, byte ptr mask2n3
out dx, al
mov di, offset2
mov [di], ah (* plot 2 *)
sub di, bx (* advance 2 up *)
mov offset2, di
mov di, offset3
mov [di], ah (* plot 3 *)
add di, bx (* advance 3 down *)
mov offset3, di
mov al, byte ptr mask4n5
out dx, al
mov di, offset4
mov [di], ah
ror al, 1
mov byte ptr mask4n5, al
sbb di, 0
mov offset4, di
mov di, offset5
mov [di], ah
rol al, 1
sbb di, 0
mov offset5, di
mov al, byte ptr mask6n7
out dx, al
mov di, offset6
mov [di], ah
sub di, bx
mov offset6, di
mov di, offset7
mov [di], ah
add di, bx
mov offset7, di
jmp @@CircleCalc
(* move all plots diagonally *)
@@Advance:
mov al, byte ptr mask0n1
out dx, al
mov di, offset0
mov [di], ah (* plot 0 *)
rol al, 1 (* advance 0 right and down *)
mov byte ptr mask0n1, al
adc di, bx
mov offset0, di
mov di, offset1
mov [di], ah (* plot 1 *)
ror al, 1 (* what was that bit again? *)
adc di, 0 (* advance 1 right and up *)
sub di, bx
mov offset1, di
mov al, byte ptr mask2n3
out dx, al
mov di, offset2
mov [di], ah (* plot 2 *)
ror al, 1 (* advance 2 up and left *)
mov byte ptr mask2n3, al
sbb di, bx
mov offset2, di
mov di, offset3
mov [di], ah (* plot 3 *)
rol al, 1
sbb di, 0 (* advance 3 down and left *)
add di, bx
mov offset3, di
mov al, byte ptr mask4n5
out dx, al
mov di, offset4
mov [di], ah
ror al, 1
mov byte ptr mask4n5, al
sbb di, 0
add di, bx
mov offset4, di
mov di, offset5
mov [di], ah
rol al, 1
sbb di, bx
mov offset5, di
mov al, byte ptr mask6n7
out dx, al
mov di, offset6
mov [di], ah
rol al, 1
mov byte ptr mask6n7, al
adc di, 0
sub di, bx
mov offset6, di
mov di, offset7
mov [di], ah
ror al, 1
adc di, bx
mov offset7, di
(* do you realize the entire function has been set up for this little jot? *)
(* keep in mind that radii values are 2 per pixel *)
@@CircleCalc:
add cx, 2 (* x += 1 *)
mov di, error
add di, cx (* error += (2 * x) + 1 *)
inc di
jl @@CircleNoError
cmp cx, si (* x > y? *)
ja @@FleeFlyFlowFum
sub si, 2 (* y -= 1 *)
sub di, si (* error -= (2 * y) *)
mov error, di
jmp @@Advance
@@CircleNoError:
mov error, di
jmp @@NoAdvance
@@FleeFlyFlowFum:
pop ds
end;
(* *)
(* x_filled_circle *)
(* *)
(* Draw a disc. *)
(* *)
(* C near-callable as: *)
(* int x_filled_circle (WORD Left, WORD Top, WORD Diameter, *)
(* WORD Color, WORD ScreenOffs); *)
(* *)
(* No clipping is performed. *)
(* *)
(* ax, bx, cx, dx, and es bite the dust, as Homer would say. *)
(* DF is set to 0 (strings go forward). *)
(* the only entries of these tables which are used are positions *)
(* 1, 2, 4, and 8 *)
const LeftMaskTable :Array[0..8] of Byte=(0, $ff, $ee, 0, $cc, 0, 0, 0, $88);
RightMaskTable:Array[0..8] of Byte=(0, $11, $33, 0, $77, 0, 0, 0, $ff);
procedure x_filled_circle(x,y,r,Color:Word); assembler;
var offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,
mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error,
jump_vector:Word;
left,top,Diameter:Word;
asm
cld (* strings march forward *)
(* convert x,y,r in left,top,Diameter *)
mov bx,r
mov ax,x
sub ax,bx
mov left,ax
mov ax,y
sub ax,bx
mov top,ax
shl bx,1
mov Diameter,bx
(* this first part is identical to the other function -- *)
(* the only differences, in fact, are in the drawing and moving around *)
(* find starting locations of plots 2, 3, 6, and 7 *)
mov di, ScrnLogicalByteWidth
xor dx, dx
mov ax, Diameter (* find vertical midpoint *)
dec ax
shr ax, 1
adc dx, 0 (* remember if it's rounded *)
mov shrunk_radius, ax (* radius, rounded down for adding *)
mov diameter_even, dx (* (diameter - 1) & 1, effectively *)
add ax, Top
mul di (* vertical midpoint in bytes *)
add ax, ScreenOfs
mov bx, Left
mov cx, bx (* save for later *)
mov si, bx
shr si, 2
add si, ax
mov offset6, si
and bx, 3 (* column of left side *)
mov bl, ds:[offset ColumnMask+bx]
mov mask6n7, bx
add cx, Diameter
dec cx
mov bx, cx
shr cx, 2
add cx, ax
mov offset2, cx
and bx, 3 (* column of right side *)
mov bl, ds:[offset ColumnMask+bx]
mov mask2n3, bx
cmp diameter_even, 1
jne @@MiddlePlotsOverlap
add si, di
add cx, di
@@MiddlePlotsOverlap:
mov offset7, si
mov offset3, cx
(* starting locations of 0, 1, 4, and 5 *)
mov bx, Left
add bx, shrunk_radius (* find horizontal midpoint *)
mov ax, Top (* top in bytes *)
mul di
add ax, ScreenOfs
mov si, ax
mov ax, Diameter (* bottom in bytes *)
dec ax
mul di
add ax, si
mov di, bx (* horizontal midpoint in bytes *)
shr di, 2
add si, di (* top midpoint in bytes *)
mov offset4, si
add di, ax (* bottom midpoint in bytes *)
mov offset5, di
and bx, 3 (* column of horizontal midpoint *)
mov bl, ds:[offset ColumnMask+bx]
mov mask4n5, bx
cmp diameter_even, 1
jne @@TopAndBottomPlotsOverlap
rol bl, 1
jnc @@TopAndBottomPlotsOverlap
inc si
inc di
@@TopAndBottomPlotsOverlap:
mov offset0, si
mov offset1, di
mov mask0n1, bx
(* we've got our eight plots in their starting positions, so *)
(* it's time to sort out the registers *)
mov bx, ScrnLogicalByteWidth
mov dx, SCREEN_SEG
mov es, dx
mov dx, SC_INDEX (* set VGA to accept column masks *)
mov al, MAP_MASK
out dx, al
inc dx (* gun the engine... *)
mov si, Diameter (* initial y is radius -- 2 #s per pixel *)
inc si
mov cx, si
neg cx
add cx, 2
mov error, cx (* error = -y + one pixel since we're a step ahead *)
xor cx, cx (* initial x = 0 *)
mov ah, byte ptr Color
jmp @@FilledCircleCalc (* let's actually put something on the screen! *)
(* plotting is completely different from in the other function (naturally) *)
@@PlotLines:
push cx (* we'll need cx for string stores
(* draw x-major horz. lines, from plot 4 to plot 0 and from plot 5 to plot 1 *)
mov di, mask0n1
and di, 0000fh (* we only want the lower nybble for the mask table *)
mov al, ds:[offset RightMaskTable+di]
mov di, offset0 (* left and right offsets the same? *)
cmp di, offset4
jne @@PlotXMajorNontrivial (* try and say this one 10 times fast! *)
mov di, mask4n5
and di, 0000fh
and al, ds:[offset LeftMaskTable+di] (* intersection of left & right masks *)
out dx, al (* set mask *)
mov di, offset4
mov es:[di], ah
mov di, offset5
mov es:[di], ah
jmp @@PlotYMajor
@@PlotXMajorNontrivial:
out dx, al (* draw right edge *)
mov es:[di], ah
mov di, offset1
mov es:[di], ah
mov di, mask4n5 (* draw left edge *)
and di, $000f
mov al, ds:[offset LeftMaskTable+di]
out dx, al
mov di, offset4
mov es:[di], ah
mov di, offset5
mov es:[di], ah
mov al, 0ffh (* set mask for middle chunks *)
out dx, al
mov al, ah (* ready to store two pixels at a time *)
inc di (* move string start past left edge *)
mov cx, offset1 (* store line from plot 5 to plot 1, exclusive *)
sub cx, di (* width of section in bytes *)
push cx
shr cx, 1 (* draw midsection eight pixels at a time *)
rep stosw
adc cx, 0 (* draw last four pixels, if such there are *)
rep stosb
mov di, offset4 (* draw line from plot 4 to plot 0 *)
inc di (* move past left edge *)
pop cx
shr cx, 1
rep stosw
adc cx, 0
rep stosb
@@PlotYMajor:
(* draw y-major horz. lines, from plot 6 to plot 2 and from plot 7 to plot 3 *)
mov di, mask2n3
and di, 0000fh (* we only want the lower nybble for the mask table *)
mov al, ds:[offset RightMaskTable+di]
mov di, offset2 (* left and right offsets the same? *)
cmp di, offset6
jne @@PlotYMajorNontrivial (* try and say this one 10 times fast! *)
mov di, mask6n7
and di, $000f
and al, ds:[offset LeftMaskTable+di] (* intersection of left & right masks *)
out dx, al (* set mask *)
mov di, offset6
mov es:[di], ah
mov di, offset7
mov es:[di], ah
jmp @@ClimaxOfPlot
@@PlotYMajorNontrivial:
out dx, al (* draw right edge *)
mov es:[di], ah
mov di, offset3
mov es:[di], ah
mov di, mask6n7 (* draw left edge *)
and di, $000f
mov al, ds:[offset LeftMaskTable+di]
out dx, al
mov di, offset6
mov es:[di], ah
mov di, offset7
mov es:[di], ah
mov al, $ff (* set mask for middle chunks *)
out dx, al
mov al, ah (* ready to store two pixels at a time *)
inc di (* move string start past left edge *)
mov cx, offset3 (* draw line from plot 7 to plot 3, exclusive *)
sub cx, di (* width of section in bytes *)
push cx
shr cx, 1 (* store midsection *)
rep stosw
adc cx, 0
rep stosb
mov di, offset6 (* draw line from plot 6 to plot 2 *)
inc di (* move past left edge *)
pop cx
shr cx, 1
rep stosw
adc cx, 0
rep stosb
@@ClimaxOfPlot:
pop cx
jmp [jump_vector] (* either @@Advance or @@NoAdvance *)
(* unlike their counterparts in the other function, these do not draw -- *)
(* they only move the eight pointers *)
(* move the x-major plots horizontally and the y-major plots vertically *)
@@NoAdvance:
mov al, byte ptr mask0n1 (* advance left x-major plots *)
mov di, offset0
rol al, 1 (* advance 0 right *)
mov byte ptr mask0n1, al
adc di, 0
mov offset0, di
mov di, offset1
ror al, 1 (* what was that bit again? *)
adc di, 0 (* advance 1 right *)
mov offset1, di
mov al, byte ptr mask4n5 (* advance left x-major plots *)
mov di, offset4
ror al, 1
mov byte ptr mask4n5, al
sbb di, 0
mov offset4, di
mov di, offset5
rol al, 1
sbb di, 0
mov offset5, di
mov al, byte ptr mask2n3
mov di, offset2
sub di, bx (* advance 2 up *)
mov offset2, di
mov di, offset3
add di, bx (* advance 3 down *)
mov offset3, di
mov al, byte ptr mask6n7
mov di, offset6
sub di, bx
mov offset6, di
mov di, offset7
add di, bx
mov offset7, di
jmp @@FilledCircleCalc
(* move all plots diagonally *)
@@Advance:
mov al, byte ptr mask0n1
mov di, offset0
rol al, 1 (* advance 0 right and down *)
mov byte ptr mask0n1, al
adc di, bx
mov offset0, di
mov di, offset1
ror al, 1 (* what was that bit again? *)
adc di, 0 (* advance 1 right and up *)
sub di, bx
mov offset1, di
mov al, byte ptr mask2n3
mov di, offset2
ror al, 1 (* advance 2 up and left *)
mov byte ptr mask2n3, al
sbb di, bx
mov offset2, di
mov di, offset3
rol al, 1
sbb di, 0 (* advance 3 down and left *)
add di, bx
mov offset3, di
mov al, byte ptr mask4n5
mov di, offset4
ror al, 1
mov byte ptr mask4n5, al
sbb di, 0
add di, bx
mov offset4, di
mov di, offset5
rol al, 1
sbb di, bx
mov offset5, di
mov al, byte ptr mask6n7
mov di, offset6
rol al, 1
mov byte ptr mask6n7, al
adc di, 0
sub di, bx
mov offset6, di
mov di, offset7
ror al, 1
adc di, bx
mov offset7, di
(* do you realize the entire function has been set up around this little jot? *)
(* keep in mind that radii values are 2 per pixel *)
@@FilledCircleCalc:
add cx, 2 (* x += 1 *)
mov di, error
add di, cx (* error += (2 * x) + 1 *)
inc di
jl @@FilledCircleNoError
cmp cx, si (* x > y? *)
ja @@FleeFlyFlowFum
sub si, 2 (* y -= 1 *)
sub di, si (* error -= (2 * y) *)
mov error, di
mov jump_vector, offset @@Advance
jmp @@PlotLines
@@FilledCircleNoError:
mov error, di
mov jump_vector, offset @@NoAdvance
jmp @@PlotLines
@@FleeFlyFlowFum:
end;
end.