home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1989
/
03
/
porter.lst
< prev
next >
Wrap
File List
|
1989-02-10
|
17KB
|
463 lines
_GRAPHICS PROGRAMMING COLUMN_
by Kent Porter
[LISTING ONE]
1| void far draw_line (int x1, int y1, int x2, int y2)
2| /* Bresenham line drawing algorithm */
3| /* x1, y1 and x2, y2 are end points */
4| {
5| int w, h, d, dxd, dyd, dxn, dyn, dinc, ndinc, p;
6| register x, y;
7|
8| /* Set up */
9| x = x1; y = y1; /* start of line */
10| w = x2 - x1; /* width domain of line */
11| h = y2 - y1; /* height domain of line */
12|
13| /* Determine drawing direction */
14| if (w < 0) { /* drawing right to left */
15| w = -w; /* absolute width */
16| dxd = -1; /* x increment is negative */
17| } else /* drawing left to right */
18| dxd = 1; /* so x incr is positive */
19| if (h < 0) { /* drawing bottom to top */
20| h = -h; /* so get absolute height */
21| dyd = -1; /* y incr is negative */
22| } else /* drawing top to bottom */
23| dyd = 1; /* so y incr is positive */
24|
25| /* Determine major axis of motion */
26| if (w < h) { /* major axis is Y */
27| p = h, h = w, w = p; /* exchange height and width */
28| dxn = 0;
29| dyn = dyd;
30| } else { /* major axis is X */
31| dxn = dxd;
32| dyn = 0;
33| }
34|
35| /* Set control variables */
36| ndinc = h * 2; /* Non-diagonal increment */
37| d = ndinc - w; /* pixel selection variable */
38| dinc = d - w; /* Diagonal increment */
39|
40| /* Loop to draw the line */
41| for (p = 0; p <= w; p++) {
42| draw_point (x, y);
43| if (d < 0) { /* step non-diagonally */
44| x += dxn;
45| y += dyn;
46| d += ndinc;
47| } else { /* step diagonally */
48| x += dxd;
49| y += dyd;
50| d += dinc;
51| }
52| }
53| }
[LISTING TWO]
/* SPOKES.C: Bresenham demo */
/* Multicolored spokes emanate from center of screen */
#include <conio.h>
#include <stdio.h>
#include "grafix.h"
#define CX 320 /* Center of screen */
#define CY 175
void main()
{
int x, y, color = 1, next (int);
if (init_video (EGA)) {
/* Spokes from center to top and bottom */
for (x = 0; x <= 640; x += 80) {
color = next (color);
draw_line (x, 0, CX, CY);
color = next (color);
draw_line (x, 349, CX, CY);
}
/* Spokes from center to sides */
for (y = 70; y < 350; y += 70) {
color = next (color);
draw_line (639, y, CX, CY);
color = next (color);
draw_line (0, y, CX, CY);
}
getch(); /* Wait for a keystroke */
} else
puts ("EGA not present in system: program ended");
} /* ------------------------ */
int next (int hue) /* set/return next color */
{
set_color1 (hue++);
return ((hue > 15) ? 1 : hue); /* wrap around */
}
[LISTING THREE]
1| void far draw_rect (int xleft, int ytop, int w, int h)
2| /* Draw outline rectangle in color1 from top left corner */
3| /* w and h are width and height */
4| /* xleft and ytop are top left corner */
5| {
6| draw_line (xleft, ytop, xleft+w, ytop); /* top */
7| draw_line (xleft+w, ytop, xleft+w, ytop+h); /* right */
8| draw_line (xleft+w, ytop+h, xleft, ytop+h); /* bottom */
9| draw_line (xleft, ytop+h, xleft, ytop); /* left */
10| } /* ------------------------------------------------------ */
11|
12| void far polyline (int edges, int vertex[])
13| /* Draw multipoint line of n edges from n+1 vertices where: */
14| /* vertex [0] = x0 vertex [1] = y0 */
15| /* vertex [2] = x1 vertex [3] = y1 */
16| /* etc. */
17| {
18| int x1, y1, x2, y2, v;
19|
20| x1 = vertex[0];
21| y1 = vertex[1];
22| for (v = 2; v < (edges+1)*2; v+= 2) {
23| x2 = vertex[v];
24| y2 = vertex[v+1];
25| draw_line (x1, y1, x2, y2);
26| x1 = x2;
27| y1 = y2;
28| }
29| } /* ------------------------------------------------------ */
[LISTING FOUR]
/* BOXES.C: Demo of draw_rect() in GRAFIX.LIB */
/* Draws a big rectangle and four smaller ones */
/* K. Porter, DDJ Graphics Programming Column, March 89 */
/* ---------------------------------------------------- */
#include <conio.h>
#include "grafix.h"
main ()
{
if (init_video (EGA)) {
set_color1 (15);
draw_rect (100, 100, 440, 230);
set_color1 (14);
draw_rect (110, 110, 420, 30);
set_color1 (13);
draw_rect (110, 105, 220, 220);
set_color1 (12);
draw_rect (340, 150, 190, 100);
set_color1 (11);
draw_rect (340, 260, 190, 60);
getch(); /* wait for keystroke */
}
}
[LISTING FIVE]
/* STAR.C: Draws a star using polyline */
#include <conio.h>
#include "grafix.h"
int vert [] = { /* vertices of star */
320, 60, 420,280, 150,140,
490,140, 220,280, 320, 60
};
void main ()
{
if (init_video (EGA)) {
polyline (5, vert); /* draw */
getch(); /* wait for key */
}
}
[LISTING SIX]
; HLINE.ASM: Fast horizontal line drawing routine
; Uses 6845 Write Mode 0 to update 8 pixels at a time on EGA/VGA
; C prototype is
; void far hline (int x, int y, int length_in_pixels);
; Writes in current color1 from GRAFIX.LIB
; Microsoft MASM 5.1
; K. Porter, DDJ Graphics Programming Column, March 89
.MODEL LARGE
.CODE
PUBLIC _hline
EXTRN _color1 : BYTE ; Current palette reg for pixel
EXTRN _draw_point : PROC ; Pixel writing routine
EXTRN _vuport : WORD ; far ptr to vuport structure
; Declare arguments passed by caller
x EQU [bp+6]
y EQU [bp+8]
len EQU [bp+10]
; Declare auto variables
last EQU [bp- 2] ; Last byte to write
solbits EQU [bp- 4] ; Mask for start of line
oddsol EQU [bp- 6] ; # odd bits at start of line
eolbits EQU [bp- 8] ; Mask for end of line
oddeol EQU [bp-10] ; # odd bits at end of line
; ----------------------------
_hline PROC FAR ; ENTRY POINT TO PROC
push bp ; entry processing
mov bp, sp
sub sp, 10 ; make room for auto variables
xor ax, ax ; initialize auto variables
mov last, ax
mov solbits, ax
mov oddsol, ax
mov eolbits, ax
mov oddeol, ax
; Do nothing if line length is zero
mov bx, len ; get line length
cmp bx, 0 ; length = 0?
jnz chlen ; if not, go on
jmp quit ; else nothing to draw
; Call draw_point() with a loop if line length < 8
chlen: cmp bx, 8
jnb getvp ; go if len >= 8
mov ax, y ; get args
mov cx, x
drpt: push bx ; push remaining length
push ax ; push args to draw_point()
push cx
call _draw_point ; draw next pixel
pop cx ; clear args from stack
pop ax
pop bx ; fetch remaining length
inc cx ; next x
dec bx ; count pixel drawn
jnz drpt ; loop until thru
jmp quit ; then exit
; Point ES:[BX] to vuport structure
getvp: mov ax, _vuport+2 ; get pointer segment
mov es, ax
mov bx, _vuport ; get offset
; Clip if starting coordinates outside viewport
mov cx, y ; get y
cmp cx, es:[bx+6] ; is y within viewport?
jl checkx ; ok if so
jmp quit ; else quit
checkx: mov ax, x ; get x
cmp ax, es:[bx+4] ; is x within viewport?
jl remap ; ok if so
jmp quit ; else quit
; Map starting coordinates to current viewport
remap: add ax, es:[bx] ; offset x by vuport.left
mov x, ax ; save remapped X
add cx, es:[bx+2] ; offset y by vuport.top
mov y, cx ; save remapped Y
; Clip line length to viewport width
mov ax, es:[bx+4] ; get vuport.width
sub ax, x ; maxlength = width - starting x
add ax, es:[bx] ; + vuport.left
cmp ax, len ; if maxlength > length
jg wm0 ; length is ok
mov len, ax ; else length = maxlength
; Set 6845 for write mode 0, all planes enabled, color selected
wm0: mov dx, 03CEh
mov ax, 0005h ; Set write mode
out dx, ax
mov ax, 0FF00h ; Set/Reset reg, enable all planes
out dx, ax
mov ax, 0FF01h ; Enable set/reset reg, all planes
out dx, ax
mov dx, 03C4h ; 6845 address reg
mov al, 2 ; Data reg
mov ah, _color1 ; Palette reg planes enabled
out dx, ax ; Set color code
; Compute x coord for last byte to be written
mov bx, x ; get start of line
add bx, len ; end = start + length
mov cx, bx
and cx, 0FFF8h ; x coordinate where odd bits
mov last, cx ; at end of line begin
; Compute number of odd pixels at end of line
sub bx, cx
mov oddeol, bx ; save it
; Construct pixel mask for last byte of line
cmp bx, 0
jz bsol ; go if no odd pixels
xor ax, ax
eolb: shr ax, 1 ; shift right and
or ax, 80h ; set H/O bit
dec bl ; until mask is built
jnz eolb
mov eolbits, ax ; then save mask
; Compute number of odd pixels at start of line
bsol: mov cx, x ; get starting X again
and cx, 7 ; # of pixels from start of byte
jz saddr ; go if none
mov bx, 8
sub bx, cx ; # of pixels to write
mov oddsol, bx ; save
; Construct pixel mask for first byte of line
xor ax, ax
solb: shl ax, 1 ; shift left and
or ax, 1 ; set L/O bit
dec bl ; until mask is built
jnz solb
mov solbits, ax ; then save mask
; Translate last byte X into an address
saddr: mov ax, 0A000h
mov es, ax ; ES ==> video buffer
mov bx, y ; get row
mov ax, 80
mul bx
mov bx, ax ; BX = row offset = row * 80
push bx ; save row offset
mov ax, last ; get last byte X
mov cl, 3
shr ax, cl ; shift for col offset
add bx, ax ; last offs = row offs + col offs
mov last, bx
; Compute address of first byte (ES:[BX])
pop bx ; fetch row offset
mov ax, x ; get col offset
mov cl, 3
shr ax, cl ; shift right 3 for col offset
add bx, ax ; offset = row offs + col offs
cmp bx, last ; is first byte also last?
jz weol ; skip to end mask if so
; Write start of line
mov dx, 03CEh ; 6845 port
mov ah, solbits ; start-of-line mask
cmp ah, 0
jz w8 ; go if empty mask
mov al, 8 ; set bit mask reg
out dx, ax
mov cl, es:[bx] ; load 6845 latches
mov ax, solbits
neg al ; complement
dec al ; for reversed bit mask
and al, cl ; filter previously unset pixels
mov es:[bx], al ; clear affected bits
mov al, _color1
mov es:[bx], al ; set affected bits
inc bx ; next byte
cmp bx, last ; ready for end of line yet?
jae weol ; go if so
; Write 8 pixels at a time until last byte in line
w8: mov ax, 0FF08h ; update all pixels in byte
out dx, ax ; set bit mask reg
mov al, es:[bx] ; load 6845 latches
xor al, al
mov es:[bx], al ; clear all pixels
mov al, _color1
mov es:[bx], al ; set all bits
inc bx ; next byte
cmp bx, last ; thru?
jnz w8 ; loop if not
; Write end of line
weol: mov dx, 03CEh ; 6845 port
mov ah, eolbits ; end-of-line mask
cmp ah, 0
jz rvc ; go if empty mask
mov al, 8 ; set bit mask reg
out dx, ax
mov cl, es:[bx] ; load 6845 latches
mov ax, eolbits
neg al ; complement
dec al ; for reversed bit mask
and al, cl ; filter previously unset pixels
mov es:[bx], al ; clear affected bits
mov al, _color1
mov es:[bx], al ; set affected bits
; Restore video controller to default state
rvc: mov dx, 03CEh
mov ax, 0005h ; write mode 0, read mode 0
out dx, ax
mov ax, 0FF08h ; default bit mask
out dx, ax
mov ax, 0003h ; default function select
out dx, ax
xor ax, ax ; zero Set/Reset
out dx, ax
mov ax, 0001h ; zero Enable Set/Reset
out dx, ax
mov dx, 03C4h ; 6845 address reg
mov ax, 0F02h ; Data reg, enable all planes
out dx, ax
; End of routine
quit: mov sp, bp
pop bp
retf
_hline ENDP
END
[LISTING SEVEN]
void far fill_rect (int xleft, int ytop, int w, int h)
/* Draw solid rectangle in color1 from top left corner */
{
register y;
for (y = ytop; y < ytop+h; y++)
hline (xleft, y, w);
} /* ------------------------------------------------------ */
[LISTING EIGHT]
/* COLORS.C: Shows all colors in default palette */
#include "grafix.h"
#include <conio.h>
void main ()
{
int r, c, color;
if (init_video (EGA)) {
for (r = 0; r < 4; r++)
for (c = 0; c < 4; c++) {
color = (r * 4) + c; /* next color */
set_color1 (color);
fill_rect ((c*160), (r*80), 158, 79);
}
getch(); /* wait for keypress */
}
}