More VGA tests (sprinkled with some Borland/Microsoft compatibility dust)
This commit is contained in:
parent
69d4893ec6
commit
0313c2d67a
6 changed files with 940 additions and 0 deletions
250
tests/pc/vga/L34-1.ASM
Normal file
250
tests/pc/vga/L34-1.ASM
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
; Fills a band across the screen with vertical bars in all 256
|
||||
; attributes, then cycles a portion of the palette until a key is
|
||||
; pressed.
|
||||
; Assemble with MASM or TASM
|
||||
;
|
||||
USE_BIOS equ 1 ;set to 1 to use BIOS functions to access the
|
||||
; DAC, 0 to read and write the DAC directly
|
||||
GUARD_AGAINST_INTS equ 1 ;1 to turn off interrupts and set write index
|
||||
; before loading each DAC location, 0 to rely
|
||||
; on the DAC auto-incrementing
|
||||
WAIT_VSYNC equ 1 ;set to 1 to wait for the leading edge of
|
||||
; vertical sync before accessing the DAC, 0
|
||||
; not to wait
|
||||
NOT_8088 equ 0 ;set to 1 to use REP INSB and REP OUTSB when
|
||||
; accessing the DAC directly, 0 to use
|
||||
; IN/STOSB and LODSB/OUT
|
||||
CYCLE_SIZE equ 256 ;# of DAC locations to cycle, 256 max
|
||||
SCREEN_SEGMENT equ 0a000h ;mode 13h display memory segment
|
||||
SCREEN_WIDTH_IN_BYTES equ 320 ;# of bytes across the screen in mode 13h
|
||||
INPUT_STATUS_1 equ 03dah ;input status 1 register port
|
||||
DAC_READ_INDEX equ 03c7h ;DAC Read Index register
|
||||
DAC_WRITE_INDEX equ 03c8h ;DAC Write Index register
|
||||
DAC_DATA equ 03c9h ;DAC Data register
|
||||
|
||||
if NOT_8088
|
||||
.286
|
||||
endif ;NOT_8088
|
||||
|
||||
.model small
|
||||
.stack 100h
|
||||
.data
|
||||
;Storage for all 256 DAC locations, organized as one three-byte
|
||||
; (actually three 6-bit values; upper two bits of each byte aren't
|
||||
; significant) RGB triplet per color.
|
||||
PaletteTemp db 256*3 dup(?)
|
||||
.code
|
||||
start:
|
||||
mov ax,@data
|
||||
mov ds,ax
|
||||
|
||||
;Select VGA's standard 256-color graphics mode, mode 13h.
|
||||
mov ax,0013h ;AH = 0: set mode function,
|
||||
int 10h ; AL = 13h: mode # to set
|
||||
|
||||
;Read all 256 DAC locations into PaletteTemp (3 6-bit values, one
|
||||
; each for red, green, and blue, per DAC location).
|
||||
|
||||
if WAIT_VSYNC
|
||||
;Wait for the leading edge of the vertical sync pulse; this ensures
|
||||
; that we read the DAC starting during the vertical non-display
|
||||
; period.
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitNotVSync: ;wait to be out of vertical sync
|
||||
in al,dx
|
||||
and al,08h
|
||||
jnz WaitNotVSync
|
||||
WaitVSync: ;wait until vertical sync begins
|
||||
in al,dx
|
||||
and al,08h
|
||||
jz WaitVSync
|
||||
endif ;WAIT_VSYNC
|
||||
|
||||
if USE_BIOS
|
||||
mov ax,1017h ;AH = 10h: set DAC function,
|
||||
; AL = 17h: read DAC block subfunction
|
||||
sub bx,bx ;start with DAC location 0
|
||||
mov cx,256 ;read out all 256 locations
|
||||
mov dx,seg PaletteTemp
|
||||
mov es,dx
|
||||
mov dx,offset PaletteTemp ;point ES:DX to array in which
|
||||
; the DAC values are to be stored
|
||||
int 10h ;read the DAC
|
||||
else ;!USE_BIOS
|
||||
if GUARD_AGAINST_INTS
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
mov di,seg PaletteTemp
|
||||
mov es,di
|
||||
mov di,offset PaletteTemp ;dump the DAC into this array
|
||||
sub ah,ah ;start with DAC location 0
|
||||
DACStoreLoop:
|
||||
mov dx,DAC_READ_INDEX
|
||||
mov al,ah
|
||||
cli
|
||||
out dx,al ;set the DAC location #
|
||||
mov dx,DAC_DATA
|
||||
in al,dx ;get the red component
|
||||
stosb
|
||||
in al,dx ;get the green component
|
||||
stosb
|
||||
in al,dx ;get the blue component
|
||||
stosb
|
||||
sti
|
||||
inc ah
|
||||
loop DACStoreLoop
|
||||
else ;!GUARD_AGAINST_INTS
|
||||
mov dx,DAC_READ_INDEX
|
||||
sub al,al
|
||||
out dx,al ;set the initial DAC location to 0
|
||||
mov di,seg PaletteTemp
|
||||
mov es,di
|
||||
mov di,offset PaletteTemp ;dump the DAC into this array
|
||||
mov dx,DAC_DATA
|
||||
if NOT_8088
|
||||
mov cx,CYCLE_SIZE*3
|
||||
rep insb ;read CYCLE_SIZE DAC locations at once
|
||||
else ;!NOT_8088
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
DACStoreLoop:
|
||||
in al,dx ;get the red component
|
||||
stosb
|
||||
in al,dx ;get the green component
|
||||
stosb
|
||||
in al,dx ;get the blue component
|
||||
stosb
|
||||
loop DACStoreLoop
|
||||
endif ;NOT_8088
|
||||
endif ;GUARD_AGAINST_INTS
|
||||
endif ;USE_BIOS
|
||||
|
||||
;Draw a series of 1-pixel-wide vertical bars across the screen in
|
||||
; attributes 1 through 255.
|
||||
mov ax,SCREEN_SEGMENT
|
||||
mov es,ax
|
||||
mov di,50*SCREEN_WIDTH_IN_BYTES ;point ES:DI to the start
|
||||
; of line 50 on the screen
|
||||
cld
|
||||
mov dx,100 ;draw 100 lines high
|
||||
RowLoop:
|
||||
mov al,1 ;start each line with attr 1
|
||||
mov cx,SCREEN_WIDTH_IN_BYTES ;do a full line across
|
||||
ColumnLoop:
|
||||
stosb ;draw a pixel
|
||||
add al,1 ;increment the attribute
|
||||
adc al,0 ;if the attribute just turned
|
||||
; over to 0, increment it to 1
|
||||
; because we're not going to
|
||||
; cycle DAC location 0, so
|
||||
; attribute 0 won't change
|
||||
loop ColumnLoop
|
||||
dec dx
|
||||
jnz RowLoop
|
||||
|
||||
;Cycle the specified range of DAC locations until a key is pressed.
|
||||
CycleLoop:
|
||||
;Rotate colors 1-255 one position in the PaletteTemp array;
|
||||
; location 0 is always left unchanged so that the background
|
||||
; and border don't change.
|
||||
push word ptr PaletteTemp+(1*3) ;set aside PaletteTemp
|
||||
push word ptr PaletteTemp+(1*3)+2 ; setting for attr 1
|
||||
mov cx,254
|
||||
mov si,offset PaletteTemp+(2*3)
|
||||
mov di,offset PaletteTemp+(1*3)
|
||||
mov ax,ds
|
||||
mov es,ax
|
||||
mov cx,254*3/2
|
||||
rep movsw ;rotate PaletteTemp settings
|
||||
; for attrs 2 through 255 to
|
||||
; attrs 1 through 254
|
||||
pop bx ;get back original settings
|
||||
pop ax ; for attribute 1 and move
|
||||
stosw ; them to the PaletteTemp
|
||||
mov es:[di],bl ; location for attribute 255
|
||||
|
||||
if WAIT_VSYNC
|
||||
;Wait for the leading edge of the vertical sync pulse; this ensures
|
||||
; that we reload the DAC starting during the vertical non-display
|
||||
; period.
|
||||
mov dx,INPUT_STATUS_1
|
||||
WaitNotVSync2: ;wait to be out of vertical sync
|
||||
in al,dx
|
||||
and al,08h
|
||||
jnz WaitNotVSync2
|
||||
WaitVSync2: ;wait until vertical sync begins
|
||||
in al,dx
|
||||
and al,08h
|
||||
jz WaitVSync2
|
||||
endif ;WAIT_VSYNC
|
||||
|
||||
if USE_BIOS
|
||||
;Set the new, rotated palette.
|
||||
mov ax,1012h ;AH = 10h: set DAC function,
|
||||
; AL = 12h: set DAC block subfunction
|
||||
sub bx,bx ;start with DAC location 0
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to set
|
||||
mov dx,seg PaletteTemp
|
||||
mov es,dx
|
||||
mov dx,offset PaletteTemp ;point ES:DX to array from which
|
||||
; to load the DAC
|
||||
int 10h ;load the DAC
|
||||
else ;!USE_BIOS
|
||||
if GUARD_AGAINST_INTS
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
mov si,offset PaletteTemp ;load the DAC from this array
|
||||
sub ah,ah ;start with DAC location 0
|
||||
DACLoadLoop:
|
||||
mov dx,DAC_WRITE_INDEX
|
||||
mov al,ah
|
||||
cli
|
||||
out dx,al ;set the DAC location #
|
||||
mov dx,DAC_DATA
|
||||
lodsb
|
||||
out dx,al ;set the red component
|
||||
lodsb
|
||||
out dx,al ;set the green component
|
||||
lodsb
|
||||
out dx,al ;set the blue component
|
||||
sti
|
||||
inc ah
|
||||
loop DACLoadLoop
|
||||
else ;!GUARD_AGAINST_INTS
|
||||
mov dx,DAC_WRITE_INDEX
|
||||
sub al,al
|
||||
out dx,al ;set the initial DAC location to 0
|
||||
mov si,offset PaletteTemp ;load the DAC from this array
|
||||
mov dx,DAC_DATA
|
||||
if NOT_8088
|
||||
mov cx,CYCLE_SIZE*3
|
||||
rep outsb ;load CYCLE_SIZE DAC locations at once
|
||||
else ;!NOT_8088
|
||||
mov cx,CYCLE_SIZE ;# of DAC locations to load
|
||||
DACLoadLoop:
|
||||
lodsb
|
||||
out dx,al ;set the red component
|
||||
lodsb
|
||||
out dx,al ;set the green component
|
||||
lodsb
|
||||
out dx,al ;set the blue component
|
||||
loop DACLoadLoop
|
||||
endif ;NOT_8088
|
||||
endif ;GUARD_AGAINST_INTS
|
||||
endif ;USE_BIOS
|
||||
|
||||
;See if a key has been pressed.
|
||||
mov ah,0bh ;DOS check standard input status fn
|
||||
int 21h
|
||||
and al,al ;is a key pending?
|
||||
jz CycleLoop ;no, cycle some more
|
||||
|
||||
;Clear the keypress.
|
||||
mov ah,1 ;DOS keyboard input fn
|
||||
int 21h
|
||||
|
||||
;Restore text mode and done.
|
||||
mov ax,0003h ;AH = 0: set mode function,
|
||||
int 10h ; AL = 03h: mode # to set
|
||||
mov ah,4ch ;DOS terminate process fn
|
||||
int 21h
|
||||
|
||||
end start
|
||||
|
||||
191
tests/pc/vga/L35-1.C
Normal file
191
tests/pc/vga/L35-1.C
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* C implementation of Bresenham's line drawing algorithm
|
||||
* for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12.
|
||||
*
|
||||
* Compiled with Borland C++
|
||||
*
|
||||
* By Michael Abrash
|
||||
*/
|
||||
|
||||
#include <dos.h> /* contains MK_FP macro */
|
||||
#include "regs.h"
|
||||
|
||||
#define EVGA_SCREEN_WIDTH_IN_BYTES 80
|
||||
/* memory offset from start of
|
||||
one row to start of next */
|
||||
#define EVGA_SCREEN_SEGMENT 0xA000
|
||||
/* display memory segment */
|
||||
#define GC_INDEX 0x3CE
|
||||
/* Graphics Controller
|
||||
Index register port */
|
||||
#define GC_DATA 0x3CF
|
||||
/* Graphics Controller
|
||||
Data register port */
|
||||
#define SET_RESET_INDEX 0 /* indexes of needed */
|
||||
#define ENABLE_SET_RESET_INDEX 1 /* Graphics Controller */
|
||||
#define BIT_MASK_INDEX 8 /* registers */
|
||||
|
||||
/*
|
||||
* Draws a dot at (X0,Y0) in whatever color the EGA/VGA hardware is
|
||||
* set up for. Leaves the bit mask set to whatever value the
|
||||
* dot required.
|
||||
*/
|
||||
void EVGADot(X0, Y0)
|
||||
unsigned int X0; /* coordinates at which to draw dot, with */
|
||||
unsigned int Y0; /* (0,0) at the upper left of the screen */
|
||||
{
|
||||
unsigned char far *PixelBytePtr;
|
||||
unsigned char PixelMask;
|
||||
|
||||
/* Calculate the offset in the screen segment of the byte in
|
||||
which the pixel lies */
|
||||
PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT,
|
||||
( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 ));
|
||||
|
||||
/* Generate a mask with a 1 bit in the pixel's position within the
|
||||
screen byte */
|
||||
PixelMask = 0x80 >> ( X0 & 0x07 );
|
||||
|
||||
/* Set up the Graphics Controller's Bit Mask register to allow
|
||||
only the bit corresponding to the pixel being drawn to
|
||||
be modified */
|
||||
outportb(GC_INDEX, BIT_MASK_INDEX);
|
||||
outportb(GC_DATA, PixelMask);
|
||||
|
||||
/* Draw the pixel. Because of the operation of the set/reset
|
||||
feature of the EGA/VGA, the value written doesn't matter.
|
||||
The screen byte is ORed in order to perform a read to latch the
|
||||
display memory, then perform a write in order to modify it. */
|
||||
*PixelBytePtr |= 0xFE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
|
||||
*/
|
||||
void Octant0(X0, Y0, DeltaX, DeltaY, XDirection)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line (both > 0) */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
{
|
||||
int DeltaYx2;
|
||||
int DeltaYx2MinusDeltaXx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaYx2 = DeltaY * 2;
|
||||
DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
|
||||
ErrorTerm = DeltaYx2 - (int) DeltaX;
|
||||
|
||||
/* Draw the line */
|
||||
EVGADot(X0, Y0); /* draw the first pixel */
|
||||
while ( DeltaX-- ) {
|
||||
/* See if it's time to advance the Y coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the Y coordinate & adjust the error term
|
||||
back down */
|
||||
Y0++;
|
||||
ErrorTerm += DeltaYx2MinusDeltaXx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaYx2;
|
||||
}
|
||||
X0 += XDirection; /* advance the X coordinate */
|
||||
EVGADot(X0, Y0); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
|
||||
*/
|
||||
void Octant1(X0, Y0, DeltaX, DeltaY, XDirection)
|
||||
unsigned int X0, Y0; /* coordinates of start of the line */
|
||||
unsigned int DeltaX, DeltaY; /* length of the line (both > 0) */
|
||||
int XDirection; /* 1 if line is drawn left to right,
|
||||
-1 if drawn right to left */
|
||||
{
|
||||
int DeltaXx2;
|
||||
int DeltaXx2MinusDeltaYx2;
|
||||
int ErrorTerm;
|
||||
|
||||
/* Set up initial error term and values used inside drawing loop */
|
||||
DeltaXx2 = DeltaX * 2;
|
||||
DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
|
||||
ErrorTerm = DeltaXx2 - (int) DeltaY;
|
||||
|
||||
EVGADot(X0, Y0); /* draw the first pixel */
|
||||
while ( DeltaY-- ) {
|
||||
/* See if it's time to advance the X coordinate */
|
||||
if ( ErrorTerm >= 0 ) {
|
||||
/* Advance the X coordinate & adjust the error term
|
||||
back down */
|
||||
X0 += XDirection;
|
||||
ErrorTerm += DeltaXx2MinusDeltaYx2;
|
||||
} else {
|
||||
/* Add to the error term */
|
||||
ErrorTerm += DeltaXx2;
|
||||
}
|
||||
Y0++; /* advance the Y coordinate */
|
||||
EVGADot(X0, Y0); /* draw a pixel */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a line on the EGA or VGA.
|
||||
*/
|
||||
void EVGALine(X0, Y0, X1, Y1, Color)
|
||||
int X0, Y0; /* coordinates of one end of the line */
|
||||
int X1, Y1; /* coordinates of the other end of the line */
|
||||
char Color; /* color to draw line in */
|
||||
{
|
||||
int DeltaX, DeltaY;
|
||||
int Temp;
|
||||
|
||||
/* Set the drawing color */
|
||||
|
||||
/* Put the drawing color in the Set/Reset register */
|
||||
outportb(GC_INDEX, SET_RESET_INDEX);
|
||||
outportb(GC_DATA, Color);
|
||||
/* Cause all planes to be forced to the Set/Reset color */
|
||||
outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
|
||||
outportb(GC_DATA, 0xF);
|
||||
|
||||
/* Save half the line-drawing cases by swapping Y0 with Y1
|
||||
and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
|
||||
is always > 0, and only the octant 0-3 cases need to be
|
||||
handled. */
|
||||
if ( Y0 > Y1 ) {
|
||||
Temp = Y0;
|
||||
Y0 = Y1;
|
||||
Y1 = Temp;
|
||||
Temp = X0;
|
||||
X0 = X1;
|
||||
X1 = Temp;
|
||||
}
|
||||
|
||||
/* Handle as four separate cases, for the four octants in which
|
||||
Y1 is greater than Y0 */
|
||||
DeltaX = X1 - X0; /* calculate the length of the line
|
||||
in each coordinate */
|
||||
DeltaY = Y1 - Y0;
|
||||
if ( DeltaX > 0 ) {
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, 1);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, 1);
|
||||
}
|
||||
} else {
|
||||
DeltaX = -DeltaX; /* absolute value of DeltaX */
|
||||
if ( DeltaX > DeltaY ) {
|
||||
Octant0(X0, Y0, DeltaX, DeltaY, -1);
|
||||
} else {
|
||||
Octant1(X0, Y0, DeltaX, DeltaY, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the state of the EGA/VGA to normal */
|
||||
outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
|
||||
outportb(GC_DATA, 0);
|
||||
outportb(GC_INDEX, BIT_MASK_INDEX);
|
||||
outportb(GC_DATA, 0xFF);
|
||||
}
|
||||
81
tests/pc/vga/L35-2.C
Normal file
81
tests/pc/vga/L35-2.C
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Sample program to illustrate EGA/VGA line drawing routines.
|
||||
*
|
||||
* Compiled with Borland C++
|
||||
*
|
||||
* By Michael Abrash
|
||||
*/
|
||||
|
||||
#include <dos.h>
|
||||
#include "regs.h"
|
||||
|
||||
#define GRAPHICS_MODE 0x10
|
||||
#define TEXT_MODE 0x03
|
||||
#define BIOS_VIDEO_INT 0x10
|
||||
#define X_MAX 640 /* working screen width */
|
||||
#define Y_MAX 348 /* working screen height */
|
||||
|
||||
extern void EVGALine();
|
||||
|
||||
/*
|
||||
* Subroutine to draw a rectangle full of vectors, of the specified
|
||||
* length and color, around the specified rectangle center.
|
||||
*/
|
||||
void VectorsUp(XCenter, YCenter, XLength, YLength, Color)
|
||||
int XCenter, YCenter; /* center of rectangle to fill */
|
||||
int XLength, YLength; /* distance from center to edge
|
||||
of rectangle */
|
||||
int Color; /* color to draw lines in */
|
||||
{
|
||||
int WorkingX, WorkingY;
|
||||
|
||||
/* Lines from center to top of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingX < ( XCenter + XLength ); WorkingX++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to right of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter - YLength;
|
||||
for ( ; WorkingY < ( YCenter + YLength ); WorkingY++ )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to bottom of rectangle */
|
||||
WorkingX = XCenter + XLength - 1;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingX >= ( XCenter - XLength ); WorkingX-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color);
|
||||
|
||||
/* Lines from center to left of rectangle */
|
||||
WorkingX = XCenter - XLength;
|
||||
WorkingY = YCenter + YLength - 1;
|
||||
for ( ; WorkingY >= ( YCenter - YLength ); WorkingY-- )
|
||||
EVGALine(XCenter, YCenter, WorkingX, WorkingY, Color );
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample program to draw four rectangles full of lines.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
char temp;
|
||||
|
||||
/* Set graphics mode */
|
||||
USES_REGS;
|
||||
_AX = GRAPHICS_MODE;
|
||||
geninterrupt(BIOS_VIDEO_INT);
|
||||
|
||||
/* Draw each of four rectangles full of vectors */
|
||||
VectorsUp(X_MAX / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 1);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX / 4, X_MAX / 4, Y_MAX / 4, 2);
|
||||
VectorsUp(X_MAX / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 3);
|
||||
VectorsUp(X_MAX * 3 / 4, Y_MAX * 3 / 4, X_MAX / 4, Y_MAX / 4, 4);
|
||||
|
||||
/* Wait for the enter key to be pressed */
|
||||
scanf("%c", &temp);
|
||||
|
||||
/* Back to text mode */
|
||||
_AX = TEXT_MODE;
|
||||
geninterrupt(BIOS_VIDEO_INT);
|
||||
}
|
||||
366
tests/pc/vga/L35-3.ASM
Normal file
366
tests/pc/vga/L35-3.ASM
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
; Fast assembler implementation of Bresenham's line drawing algorithm
|
||||
; for the EGA and VGA. Works in modes 0Eh, 0Fh, 10h, and 12h.
|
||||
; C near-callable.
|
||||
; Bit mask accumulation technique when |DeltaX| >= |DeltaY|
|
||||
; suggested by Jim Mackraz.
|
||||
;
|
||||
; Assembled with MASM
|
||||
;
|
||||
; By Michael Abrash
|
||||
;
|
||||
;****************************************************************
|
||||
; C-compatible line-drawing entry point at _EVGALine. *
|
||||
; Near C-callable as: *
|
||||
; EVGALine(X0, Y0, X1, Y1, Color); *
|
||||
;****************************************************************
|
||||
;
|
||||
.model small
|
||||
.code
|
||||
;
|
||||
; Equates.
|
||||
;
|
||||
EVGA_SCREEN_WIDTH_IN_BYTES equ 80 ;memory offset from start of
|
||||
; one row to start of next
|
||||
; in display memory
|
||||
EVGA_SCREEN_SEGMENT equ 0a000h ;display memory segment
|
||||
GC_INDEX equ 3ceh ;Graphics Controller
|
||||
; Index register port
|
||||
SET_RESET_INDEX equ 0 ;indexes of needed
|
||||
ENABLE_SET_RESET_INDEX equ 1 ; Graphics Controller
|
||||
BIT_MASK_INDEX equ 8 ; registers
|
||||
|
||||
;
|
||||
; Stack frame.
|
||||
;
|
||||
EVGALineParms struc
|
||||
dw ? ;pushed BP
|
||||
dw ? ;pushed return address (make double
|
||||
; word for far call)
|
||||
X0 dw ? ;starting X coordinate of line
|
||||
Y0 dw ? ;starting Y coordinate of line
|
||||
X1 dw ? ;ending X coordinate of line
|
||||
Y1 dw ? ;ending Y coordinate of line
|
||||
Color db ? ;color of line
|
||||
db ? ;dummy to pad to word size
|
||||
EVGALineParms ends
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing macros. *
|
||||
;****************************************************************
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of |DeltaX| >= |DeltaY|.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE1 macro MOVE_LEFT
|
||||
local LineLoop, MoveXCoord, NextPixel, Line1End
|
||||
local MoveToNextByte, ResetBitMaskAccumulator
|
||||
mov cx,bx ;# of pixels in line
|
||||
jcxz Line1End ;done if there are no more pixels
|
||||
; (there's always at least the one pixel
|
||||
; at the start location)
|
||||
shl si,1 ;DeltaY * 2
|
||||
mov bp,si ;error term
|
||||
sub bp,bx ;error term starts at DeltaY * 2 - DeltaX
|
||||
shl bx,1 ;DeltaX * 2
|
||||
sub si,bx ;DeltaY * 2 - DeltaX * 2 (used in loop)
|
||||
add bx,si ;DeltaY * 2 (used in loop)
|
||||
mov ah,al ;set aside pixel mask for initial pixel
|
||||
; with AL (the pixel mask accumulator) set
|
||||
; for the initial pixel
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the Y coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
js MoveXCoord ;yes, stay at the same Y coordinate
|
||||
;
|
||||
; Advance the Y coordinate, first writing all pixels in the current
|
||||
; byte, then move the pixel mask either left or right, depending
|
||||
; on MOVE_LEFT.
|
||||
;
|
||||
out dx,al ;set up bit mask for pixels in this byte
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES ;increment Y coordinate
|
||||
add bp,si ;adjust error term back down
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc ResetBitMaskAccumulator ;didn't wrap to next byte
|
||||
jmp short MoveToNextByte ;did wrap to next byte
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address and writing pixels
|
||||
; in this byte when pixel mask wraps.
|
||||
;
|
||||
MoveXCoord:
|
||||
add bp,bx ;increment error term & keep same
|
||||
if MOVE_LEFT
|
||||
rol ah,1 ;move pixel mask 1 pixel to the left
|
||||
else
|
||||
ror ah,1 ;move pixel mask 1 pixel to the right
|
||||
endif
|
||||
jnc NextPixel ;if still in same byte, no need to
|
||||
; modify display memory yet
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
MoveToNextByte:
|
||||
if MOVE_LEFT
|
||||
dec di ;next pixel is in byte to left
|
||||
else
|
||||
inc di ;next pixel is in byte to right
|
||||
endif
|
||||
ResetBitMaskAccumulator:
|
||||
sub al,al ;reset pixel mask accumulator
|
||||
NextPixel:
|
||||
or al,ah ;add the next pixel to the pixel mask
|
||||
; accumulator
|
||||
loop LineLoop
|
||||
;
|
||||
; Write the pixels in the final byte.
|
||||
;
|
||||
Line1End:
|
||||
out dx,al ;set up bit mask for pixels in this byte.
|
||||
xchg byte ptr [di],al
|
||||
;load latches and write pixels, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
endm
|
||||
|
||||
;
|
||||
; Macro to loop through length of line, drawing each pixel in turn.
|
||||
; Used for case of DeltaX < DeltaY.
|
||||
; Input:
|
||||
; MOVE_LEFT: 1 if DeltaX < 0, 0 else
|
||||
; AL: pixel mask for initial pixel
|
||||
; BX: |DeltaX|
|
||||
; DX: address of GC data register, with index register set to
|
||||
; index of Bit Mask register
|
||||
; SI: DeltaY
|
||||
; ES:DI: display memory address of byte containing initial
|
||||
; pixel
|
||||
;
|
||||
LINE2 macro MOVE_LEFT
|
||||
local LineLoop, MoveYCoord, ETermAction, Line2End
|
||||
mov cx,si ;# of pixels in line
|
||||
jcxz Line2End ;done if there are no more pixels
|
||||
shl bx,1 ;DeltaX * 2
|
||||
mov bp,bx ;error term
|
||||
sub bp,si ;error term starts at DeltaX * 2 - DeltaY
|
||||
shl si,1 ;DeltaY * 2
|
||||
sub bx,si ;DeltaX * 2 - DeltaY * 2 (used in loop)
|
||||
add si,bx ;DeltaX * 2 (used in loop)
|
||||
;
|
||||
; Set up initial bit mask & write initial pixel.
|
||||
;
|
||||
out dx,al
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
LineLoop:
|
||||
;
|
||||
; See if it's time to advance the X coordinate yet.
|
||||
;
|
||||
and bp,bp ;see if error term is negative
|
||||
jns ETermAction ;no, advance X coordinate
|
||||
add bp,si ;increment error term & keep same
|
||||
jmp short MoveYCoord; X coordinate
|
||||
ETermAction:
|
||||
;
|
||||
; Move pixel mask one pixel (either right or left, depending
|
||||
; on MOVE_LEFT), adjusting display memory address when pixel mask wraps.
|
||||
;
|
||||
if MOVE_LEFT
|
||||
rol al,1
|
||||
sbb di,0
|
||||
else
|
||||
ror al,1
|
||||
adc di,0
|
||||
endif
|
||||
out dx,al ;set new bit mask
|
||||
add bp,bx ;adjust error term back down
|
||||
;
|
||||
; Advance Y coordinate.
|
||||
;
|
||||
MoveYCoord:
|
||||
add di,EVGA_SCREEN_WIDTH_IN_BYTES
|
||||
;
|
||||
; Write the next pixel.
|
||||
;
|
||||
xchg byte ptr [di],ah
|
||||
;load latches and write pixel, with bit mask
|
||||
; preserving other latched bits. Because
|
||||
; set/reset is enabled for all planes, the
|
||||
; value written actually doesn't matter
|
||||
;
|
||||
loop LineLoop
|
||||
Line2End:
|
||||
endm
|
||||
|
||||
;****************************************************************
|
||||
; Line drawing routine. *
|
||||
;****************************************************************
|
||||
|
||||
public _EVGALine
|
||||
_EVGALine proc near
|
||||
push bp
|
||||
mov bp,sp
|
||||
push si ;preserve register variables
|
||||
push di
|
||||
push ds
|
||||
;
|
||||
; Point DS to display memory.
|
||||
;
|
||||
mov ax,EVGA_SCREEN_SEGMENT
|
||||
mov ds,ax
|
||||
;
|
||||
; Set the Set/Reset and Set/Reset Enable registers for
|
||||
; the selected color.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,[bp+Color]
|
||||
out dx,al
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
mov al,0ffh
|
||||
out dx,al
|
||||
;
|
||||
; Get DeltaY.
|
||||
;
|
||||
mov si,[bp+Y1] ;line Y start
|
||||
mov ax,[bp+Y0] ;line Y end, used later in
|
||||
;calculating the start address
|
||||
sub si,ax ;calculate DeltaY
|
||||
jns CalcStartAddress;if positive, we're set
|
||||
;
|
||||
; DeltaY is negative -- swap coordinates so we're always working
|
||||
; with a positive DeltaY.
|
||||
;
|
||||
mov ax,[bp+Y1] ;set line start to Y1, for use
|
||||
; in calculating the start address
|
||||
mov dx,[bp+X0]
|
||||
xchg dx,[bp+X1]
|
||||
mov [bp+X0],dx ;swap X coordinates
|
||||
neg si ;convert to positive DeltaY
|
||||
;
|
||||
; Calculate the starting address in display memory of the line.
|
||||
; Hardwired for a screen width of 80 bytes.
|
||||
;
|
||||
CalcStartAddress:
|
||||
shl ax,1 ;Y0 * 2 ;Y0 is already in AX
|
||||
shl ax,1 ;Y0 * 4
|
||||
shl ax,1 ;Y0 * 8
|
||||
shl ax,1 ;Y0 * 16
|
||||
mov di,ax
|
||||
shl ax,1 ;Y0 * 32
|
||||
shl ax,1 ;Y0 * 64
|
||||
add di,ax ;Y0 * 80
|
||||
mov dx,[bp+X0]
|
||||
mov cl,dl ;set aside lower 3 bits of column for
|
||||
and cl,7 ; pixel masking
|
||||
shr dx,1
|
||||
shr dx,1
|
||||
shr dx,1 ;get byte address of column (X0/8)
|
||||
add di,dx ;offset of line start in display segment
|
||||
;
|
||||
; Set up GC Index register to point to the Bit Mask register.
|
||||
;
|
||||
mov dx,GC_INDEX
|
||||
mov al,BIT_MASK_INDEX
|
||||
out dx,al
|
||||
inc dx ;leave DX pointing to the GC Data register
|
||||
;
|
||||
; Set up pixel mask (in-byte pixel address).
|
||||
;
|
||||
mov al,80h
|
||||
shr al,cl
|
||||
;
|
||||
; Calculate DeltaX.
|
||||
;
|
||||
mov bx,[bp+X1]
|
||||
sub bx,[bp+X0]
|
||||
;
|
||||
; Handle correct one of four octants.
|
||||
;
|
||||
js NegDeltaX
|
||||
cmp bx,si
|
||||
jb Octant1
|
||||
;
|
||||
; DeltaX >= DeltaY >= 0.
|
||||
;
|
||||
LINE1 0
|
||||
jmp EVGALineDone
|
||||
;
|
||||
; DeltaY > DeltaX >= 0.
|
||||
;
|
||||
Octant1:
|
||||
LINE2 0
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
NegDeltaX:
|
||||
neg bx ;|DeltaX|
|
||||
cmp bx,si
|
||||
jb Octant2
|
||||
;
|
||||
; |DeltaX| >= DeltaY and DeltaX < 0.
|
||||
;
|
||||
LINE1 1
|
||||
jmp short EVGALineDone
|
||||
;
|
||||
; |DeltaX| < DeltaY and DeltaX < 0.
|
||||
;
|
||||
Octant2:
|
||||
LINE2 1
|
||||
;
|
||||
EVGALineDone:
|
||||
;
|
||||
; Restore EVGA state.
|
||||
;
|
||||
mov al,0ffh
|
||||
out dx,al ;set Bit Mask register to 0ffh
|
||||
dec dx
|
||||
mov al,ENABLE_SET_RESET_INDEX
|
||||
out dx,al
|
||||
inc dx
|
||||
sub al,al
|
||||
out dx,al ;set Enable Set/Reset register to 0
|
||||
;
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
ret
|
||||
_EVGALine endp
|
||||
|
||||
end
|
||||
25
tests/pc/vga/MAKEFILE
Normal file
25
tests/pc/vga/MAKEFILE
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
CL=C:\MSDEV\BIN\WIN95\C816\BIN\CL.EXE
|
||||
INCLUDE=C:\MSDEV\BIN\WIN95\C816\INC
|
||||
LIB=C:\MSDEV\BIN\WIN95\C816\LIB
|
||||
MASM=C:\MSDEV\BIN\WIN95\MASM\MASM.EXE
|
||||
LINK=C:\MSDEV\BIN\WIN95\C816\BIN\LINK.EXE
|
||||
|
||||
.C.OBJ:
|
||||
$(CL) /c $<
|
||||
|
||||
.ASM.OBJ:
|
||||
$(MASM) $<;
|
||||
|
||||
.ASM.EXE:
|
||||
$(MASM) $*;
|
||||
$(LINK) $*;
|
||||
|
||||
ALL: L23-1.EXE L24-1.EXE L25-1.EXE L25-2.EXE L25-3.EXE L25-4.EXE L26-1.EXE L26-2.EXE L27-1.EXE L27-2.EXE L27-3.EXE \
|
||||
L28-1.EXE L28-2.EXE L28-3.EXE L29-1.EXE L29-2.EXE L29-3.EXE L29-4.EXE L30-1.EXE L30-2.EXE L31-1.EXE L31-2.EXE \
|
||||
L33-1.EXE L34-1.EXE L35-2.EXE L35-3.EXE
|
||||
|
||||
L35-2.EXE: L35-2.OBJ L35-1.OBJ
|
||||
$(LINK) $**,$@;
|
||||
|
||||
L35-3.EXE: L35-2.OBJ L35-3.OBJ
|
||||
$(LINK) $**,$@;
|
||||
27
tests/pc/vga/REGS.H
Normal file
27
tests/pc/vga/REGS.H
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifdef __TURBOC__
|
||||
#define USES_REGS
|
||||
#else
|
||||
#define USES_REGS union REGS reg; struct SREGS sreg;
|
||||
#define _AH reg.h.ah
|
||||
#define _AL reg.h.al
|
||||
#define _BH reg.h.bh
|
||||
#define _BL reg.h.bl
|
||||
#define _CH reg.h.ch
|
||||
#define _CL reg.h.cl
|
||||
#define _DH reg.h.dh
|
||||
#define _DL reg.h.dl
|
||||
#define _AX reg.x.ax
|
||||
#define _BX reg.x.bx
|
||||
#define _CX reg.x.cx
|
||||
#define _DX reg.x.dx
|
||||
#define _SI reg.x.si
|
||||
#define _DI reg.x.di
|
||||
#define _DS sreg.ds
|
||||
#define _ES sreg.es
|
||||
#define _SS sreg.ss
|
||||
#define geninterrupt(n) int86x(n,®,®,&sreg)
|
||||
#define inport(port) _inpw(port)
|
||||
#define inportb(port) _inp(port)
|
||||
#define outport(port,data) _outpw(port,data)
|
||||
#define outportb(port,data) _outp(port,data)
|
||||
#endif
|
||||
Loading…
Reference in a new issue