home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
ddjmag
/
ddj8905.arc
/
VUPORT.ASC
< prev
Wrap
Text File
|
1989-05-12
|
38KB
|
1,023 lines
_Graphics Programming_
by Kent Porter
[LISTING ONE]
1| ; DRAWPT.ASM: Writes pixel directly to 6845 Video Controller
2| ; Microsoft MASM 5.1
3| ; C prototype is
4| ; void far draw_point (int x, int y);
5| ; To be included in GRAFIX.LIB
6| ; K. Porter, «MDUL»DDJ«MDNM» Graphics Programming Column, February '89
7|
8| .MODEL LARGE
9| .CODE
10| PUBLIC _draw_point
11|
12| ; Externals in GRAFIX.LIB
13| EXTRN _color1 : BYTE ; Pixel color reg value
14| EXTRN _vuport : WORD ; far ptr to vuport structure
15|
16| ; Arguments passed from C
17| x EQU [bp+6] ; Arguments passed from C
18| y EQU [bp+8]
19|
20| _draw_point PROC FAR
21| push bp ; Entry processing
22| mov bp, sp
23|
24| ; Point ES:[BX] to vuport structure
25| mov ax, _vuport+2 ; get pointer segment
26| mov es, ax
27| mov bx, _vuport ; get offset
28|
29| ; Clip if coordinates outside viewport
30| mov cx, y ; get y
31| cmp cx, es:[bx+6] ; is y within viewport?
32| jl checkx ; ok if so
33| jmp exit ; else quit
34| checkx: mov ax, x ; get x
35| cmp ax, es:[bx+4] ; is x within viewport?
36| jl remap ; ok if so
37| jmp exit ; else quit
38|
39| ; Map pixel coordinates to current viewport
40| remap: add ax, es:[bx] ; offset x by vuport.left
41| mov x, ax ; save remapped X
42| add cx, es:[bx+2] ; offset y by vuport.top
43| mov y, cx ; save remapped Y
44|
45| ; Point ES to video memory segment
46| vmem: mov ax, 0A000h
47| mov es, ax
48|
49| ; Row offset = y * 80;
50| mov bx, y ; Get y argument
51| mov ax, 80
52| mul bx ; Result in AX
53| mov bx, ax ; Row offset in BX
54|
55| ; Column offset = x SHR 3
56| mov ax, x ; Get x
57| mov cl, 3 ; Shift operand
58| shr ax, cl ; Column offset
59|
60| ; Complete address of pixel byte
61| add bx, ax ; ES:BX = address
62|
63| ; Build bit mask for pixel
64| mov cx, x ; Get x again
65| and cx, 7 ; Isolate low-order bits
66| xor cl, 7 ; Number of bits to shift
67| mov ah, 1 ; Start bit mask
68| shl ah, cl ; Shift for pixel
69| mov cl, ah ; Save it
70|
71| ; Use write mode 2 (single-pixel update)
72| mov dx, 03CEh ; 6845 command register
73| mov al, 5 ; Specify mode register
74| mov ah, 2 ; Read mode 0, write mode 2
75| out dx, ax ; Send
76| ; Following added May '89
77| mov al, 3 ; Specify function select reg
78| xor ah, ah ; Replace-pixel mode
79| out dx, ax ; Send
80|
81| ; Set 6845 bit mask register
82| mov al, 8 ; Specify bit mask register
83| mov ah, cl ; al = mask
84| out dx, ax ; Send bit mask
85|
86| ; Draw the pixel
87| mov al, es:[bx] ; Load 6845 latch registers
88| xor al, al ; Clear
89| mov byte ptr es:[bx], al ; Zero the pixel for replace
90| mov al, _color1 ; Get the pixel value
91| mov es:[bx], al ; Write the pixel
92|
93| ; Restore video controller to default state
94| mov dx, 03CEh
95| mov ax, 0005h ; write mode 0, read mode 0
96| out dx, ax
97| mov ax, 0FF08h ; default bit mask
98| out dx, ax
99| mov ax, 0003h ; default function select
100| out dx, ax
101| xor ax, ax ; zero Set/Reset
102| out dx, ax
103| mov ax, 0001h ; zero Enable Set/Reset
104| out dx, ax
105| mov dx, 03C4h ; 6845 address reg
106| mov ax, 0F02h ; Data reg, enable all planes
107| out dx, ax
108|
109| exit:
110| mov sp, bp
111| pop bp
112| retf
113| _draw_point ENDP
114| END
[LISTING TWO]
1| ; HLINE.ASM: Fast horizontal line drawing routine
2| ; Uses 6845 Write Mode 0 to update 8 pixels at a time on EGA/VGA
3| ; C prototype is
4| ; void far hline (int x, int y, int length_in_pixels);
5| ; Writes in current color1 from GRAFIX.LIB
6| ; Microsoft MASM 5.1
7| ; K. Porter, «MDUL»DDJ«MDNM» Graphics Programming Column, March 89
8|
9| .MODEL LARGE
10| .CODE
11| PUBLIC _hline
12| EXTRN _color1 : BYTE ; Current palette reg for pixel
13| EXTRN _draw_point : PROC ; Pixel writing routine
14| EXTRN _vuport : WORD ; far ptr to vuport structure
15|
16| ; Declare arguments passed by caller
17| x EQU [bp+6]
18| y EQU [bp+8]
19| len EQU [bp+10]
20|
21| ; Declare auto variables
22| last EQU [bp- 2] ; Last byte to write
23| solbits EQU [bp- 4] ; Mask for start of line
24| oddsol EQU [bp- 6] ; # odd bits at start of line
25| eolbits EQU [bp- 8] ; Mask for end of line
26| oddeol EQU [bp-10] ; # odd bits at end of line
27| ; ----------------------------
28|
29| _hline PROC FAR ; ENTRY POINT TO PROC
30| push bp ; entry processing
31| mov bp, sp
32| sub sp, 10 ; make room for auto variables
33| xor ax, ax ; initialize auto variables
34| mov last, ax
35| mov solbits, ax
36| mov oddsol, ax
37| mov eolbits, ax
38| mov oddeol, ax
39|
40| ; Do nothing if line length is zero
41| mov bx, len ; get line length
42| cmp bx, 0 ; length = 0?
43| jnz chlen ; if not, go on
44| jmp quit ; else nothing to draw
45|
46| ; Call draw_point() with a loop if line length < 8
47| chlen: cmp bx, 8
48| jnb getvp ; go if len >= 8
49| mov ax, y ; get args
50| mov cx, x
51| drpt: push bx ; push remaining length
52| push ax ; push args to draw_point()
53| push cx
54| call _draw_point ; draw next pixel
55| pop cx ; clear args from stack
56| pop ax
57| pop bx ; fetch remaining length
58| inc cx ; next x
59| dec bx ; count pixel drawn
60| jnz drpt ; loop until thru
61| jmp quit ; then exit
62|
63| ; Point ES:[BX] to vuport structure
64| getvp: mov ax, _vuport+2 ; get pointer segment
65| mov es, ax
66| mov bx, _vuport ; get offset
67|
68| ; Clip if starting coordinates outside viewport
69| mov cx, y ; get y
70| cmp cx, es:[bx+6] ; is y within viewport?
71| jl checkx ; ok if so
72| jmp quit ; else quit
73| checkx: mov ax, x ; get x
74| cmp ax, es:[bx+4] ; is x within viewport?
75| jl remap ; ok if so
76| jmp quit ; else quit
77|
78| ; Map starting coordinates to current viewport
79| remap: add ax, es:[bx] ; offset x by vuport.left
80| mov x, ax ; save remapped X
81| add cx, es:[bx+2] ; offset y by vuport.top
82| mov y, cx ; save remapped Y
83|
84| ; Clip line length to viewport width
85| mov ax, es:[bx+4] ; get vuport.width
86| sub ax, x ; maxlength = width - starting x
87| add ax, es:[bx] ; + vuport.left
88| cmp ax, len ; if maxlength > length
89| jg wm0 ; length is ok
90| mov len, ax ; else length = maxlength
91|
92| ; Set 6845 for write mode 0, all planes enabled, color selected
93| wm0: mov dx, 03CEh
94| mov ax, 0005h ; Set write mode
95| out dx, ax
96| mov ax, 0FF00h ; Set/Reset reg, enable all planes
97| out dx, ax
98| mov ax, 0FF01h ; Enable set/reset reg, all planes
99| out dx, ax
100| mov dx, 03C4h ; 6845 address reg
101| mov al, 2 ; Data reg
102| mov ah, _color1 ; Palette reg planes enabled
103| out dx, ax ; Set color code
104| ; Following added May '89
105| mov ah, 3 ; Function select reg
106| xor al, al ; Pixel-replace mode
107| out dx, ax
108|
109| ; Compute x coord for last byte to be written
110| mov bx, x ; get start of line
111| add bx, len ; end = start + length
112| mov cx, bx
113| and cx, 0FFF8h ; x coordinate where odd bits
114| mov last, cx ; at end of line begin
115|
116| ; Compute number of odd pixels at end of line
117| sub bx, cx
118| mov oddeol, bx ; save it
119|
120| ; Construct pixel mask for last byte of line
121| cmp bx, 0
122| jz bsol ; go if no odd pixels
123| xor ax, ax
124| eolb: shr ax, 1 ; shift right and
125| or ax, 80h ; set H/O bit
126| dec bl ; until mask is built
127| jnz eolb
128| mov eolbits, ax ; then save mask
129|
130| ; Compute number of odd pixels at start of line
131| bsol: mov cx, x ; get starting X again
132| and cx, 7 ; # of pixels from start of byte
133| jz saddr ; go if none
134| mov bx, 8
135| sub bx, cx ; # of pixels to write
136| mov oddsol, bx ; save
137|
138| ; Construct pixel mask for first byte of line
139| xor ax, ax
140| solb: shl ax, 1 ; shift left and
141| or ax, 1 ; set L/O bit
142| dec bl ; until mask is built
143| jnz solb
144| mov solbits, ax ; then save mask
145|
146| ; Translate last byte X into an address
147| saddr: mov ax, 0A000h
148| mov es, ax ; ES ==> video buffer
149| mov bx, y ; get row
150| mov ax, 80
151| mul bx
152| mov bx, ax ; BX = row offset = row * 80
153| push bx ; save row offset
154| mov ax, last ; get last byte X
155| mov cl, 3
156| shr ax, cl ; shift for col offset
157| add bx, ax ; last offs = row offs + col offs
158| mov last, bx
159|
160| ; Compute address of first byte (ES:[BX])
161| pop bx ; fetch row offset
162| mov ax, x ; get col offset
163| mov cl, 3
164| shr ax, cl ; shift right 3 for col offset
165| add bx, ax ; offset = row offs + col offs
166| cmp bx, last ; is first byte also last?
167| jz weol ; skip to end mask if so
168|
169| ; Write start of line
170| mov dx, 03CEh ; 6845 port
171| mov ah, solbits ; start-of-line mask
172| cmp ah, 0
173| jz w8 ; go if empty mask
174| mov al, 8 ; set bit mask reg
175| out dx, ax
176| mov cl, es:[bx] ; load 6845 latches
177| mov ax, solbits
178| neg al ; complement
179| dec al ; for reversed bit mask
180| and al, cl ; filter previously unset pixels
181| mov es:[bx], al ; clear affected bits
182| mov al, _color1
183| mov es:[bx], al ; set affected bits
184| inc bx ; next byte
185| cmp bx, last ; ready for end of line yet?
186| jae weol ; go if so
187|
188| ; Write 8 pixels at a time until last byte in line
189| w8: mov ax, 0FF08h ; update all pixels in byte
190| out dx, ax ; set bit mask reg
191| mov al, es:[bx] ; load 6845 latches
192| xor al, al
193| mov es:[bx], al ; clear all pixels
194| mov al, _color1
195| mov es:[bx], al ; set all bits
196| inc bx ; next byte
197| cmp bx, last ; thru?
198| jnz w8 ; loop if not
199|
200| ; Write end of line
201| weol: mov dx, 03CEh ; 6845 port
202| mov ah, eolbits ; end-of-line mask
203| cmp ah, 0
204| jz rvc ; go if empty mask
205| mov al, 8 ; set bit mask reg
206| out dx, ax
207| mov cl, es:[bx] ; load 6845 latches
208| mov ax, eolbits
209| neg al ; complement
210| dec al ; for reversed bit mask
211| and al, cl ; filter previously unset pixels
212| mov es:[bx], al ; clear affected bits
213| mov al, _color1
214| mov es:[bx], al ; set affected bits
215|
216| ; Restore video controller to default state
217| rvc: mov dx, 03CEh
218| mov ax, 0005h ; write mode 0, read mode 0
219| out dx, ax
220| mov ax, 0FF08h ; default bit mask
221| out dx, ax
222| mov ax, 0003h ; default function select
223| out dx, ax
224| xor ax, ax ; zero Set/Reset
225| out dx, ax
226| mov ax, 0001h ; zero Enable Set/Reset
227| out dx, ax
228| mov dx, 03C4h ; 6845 address reg
229| mov ax, 0F02h ; Data reg, enable all planes
230| out dx, ax
231|
232| ; End of routine
233| quit: mov sp, bp
234| pop bp
235| retf
236| _hline ENDP
237| END
238|
239|
[LISTING THREE]
/* From May, '89 */
/* ------------- */
typedef int VP_HAN; /* viewport handle type */
void far default_viewport (int height); /* init default viewport */
VP_HAN far vp_open (int x, int y, int width, int height);
/* open viewport, make it active */
int far vp_use (VP_HAN vp); /* make vp active */
void far vp_close (VP_HAN vp); /* close viewport */
void far vp_outline (VP_HAN vp); /* outline vp */
VP_HAN far vp_active (void); /* get handle of active vp */
int far vp_width (void) /* get active vp width */
int far vp_height (void) /* get active vp height */
[LISTING FOUR]
/* VUPORT.C: Library source for viewport support */
/* This is part of the GRAFIX library */
/* K. Porter, «MDUL»DDJ«MDNM» Graphics Programming Column, May '89 */
#include <stdio.h>
#include <stdlib.h>
#include "grafix.h"
typedef struct vpnode { /* viewport descriptor node */
int left, top, width, height,
handle;
struct vpnode far *next, far *prev;
} VPNODE;
#if !defined TRUE
#define FALSE 0
#define TRUE !FALSE
#endif
VPNODE far *vplist = NULL; /* pointer to list of vpnodes */
VPNODE def_vp = {0, 0, 640, 350, 0}; /* default viewport */
VPNODE far *vuport = &def_vp; /* ptr to current viewport */
/* -------------------------- */
void far default_viewport (int height)
{ /* initialize default viewport */
vuport->height = height;
} /* ------------------------ */
VP_HAN far vp_open (int x, int y, int width, int height)
{ /* open a viewport */
VPNODE far *newvp, far *listnode;
newvp = malloc (sizeof *newvp); /* make space */
newvp->next = newvp->prev = NULL; /* init list ptrs */
newvp->left = x; /* set descriptor */
newvp->top = y;
newvp->width = width;
newvp->height = height;
newvp->handle = 1;
if (vplist == NULL)
vplist = newvp; /* set first viewport */
else {
listnode = vplist; /* add viewport to list */
while (listnode->next != NULL)
listnode = listnode->next; /* find tail */
listnode->next = newvp; /* update pointers */
newvp->prev = listnode;
newvp->handle = listnode->handle + 1; /* and handle */
}
vuport = newvp; /* make new viewport active */
return newvp->handle;
} /* ------------------------------------------------------ */
int far vp_use (VP_HAN vp) /* make vp active */
{
VPNODE far *port;
int success = FALSE;
if (vp == 0) { /* switch to default viewport */
vuport = &def_vp;
success = TRUE;
} else { /* find desired viewport */
port = vplist;
do {
if (port->handle == vp) {
success = TRUE;
break; /* jump out of loop when found */
}
port = port->next;
} while (port != NULL);
if (success)
vuport = port; /* make active */
}
return success;
} /* ------------------------------------------------------ */
void far vp_close (VP_HAN vp) /* close a viewport */
{
VPNODE far *port;
if (vp == 0) return; /* can't close default vp */
port = vplist;
while (port->next != NULL) { /* find desired viewport */
if (port->handle == vp)
break;
port = port->next;
}
if (port != NULL) { /* viewport was found */
if (port->next != NULL) /* so remove from list */
port->next->prev = port->prev;
if (port->prev != NULL)
port->prev->next = port->next;
if (port == vplist) /* if removing head */
vplist = port->next;
if (port == vuport) /* if removing active vp */
vuport = &def_vp;
free (port);
}
} /* ------------------------------------------------------ */
void far vp_outline (VP_HAN vp) /* outline vp */
/* outline is immediately outside viewport area */
{
VP_HAN active;
int x, y, w, h;
active = vp_active(); /* save current viewport */
if (vp_use (vp)) {
x = vuport->left-1;
y = vuport->top-1;
w = vuport->width+1;
h = vuport->height+1;
/* draw outline */
vp_use (0); /* full screen */
draw_rect (x, y, w, h);
vp_use (active); /* restore active viewport */
}
} /* ------------------------------------------------------ */
VP_HAN far vp_active (void) /* get handle of active vp */
{
return vuport->handle;
} /* ------------------------------------------------------ */
int far vp_width (void) /* get active vp width */
{
return vuport->width;
} /* ------------------------------------------------------ */
int far vp_height (void) /* get active vp height */
{
return vuport->height;
} /* ------------------------------------------------------ */
[LISTING FIVE]
/* VP.C: Draws several viewports */
/* Hex star inside each */
/* K. Porter, «MDUL»DDJ«MDNM» Graphics Programming Col, 5/89 */
#include "grafix.h"
#include <conio.h>
int hex1[] = {25,55, 110,20, 110,90, 25,55};
int hex2[] = {55,20, 135,55, 55,90, 55,20};
void main()
{
VP_HAN vp1, vp2, vp3;
if (init_video (EGA)) {
/* Draw star in default viewport */
set_color1 (5); /* magenta */
polyline (3, hex1);
polyline (3, hex2);
set_color1 (9);
/* Draw star in unbordered viewport */
set_color1 (1); /* blue */
vp1 = vp_open (60, 250, 200, 95);
polyline (3, hex1);
polyline (3, hex2);
/* Draw star in small bordered viewport */
vp2 = vp_open (200, 150, 100, 75);
vp_outline (vp2);
set_color1 (15); /* white */
polyline (3, hex1);
polyline (3, hex2);
/* Draw star in filled bordered viewport */
vp3 = vp_open (400, 60, 140, 100);
vp_outline (vp3);
set_color1 (2); /* green */
fill_rect (0, 0, vp_width(), vp_height());
set_color1 (4); /* red */
polyline (3, hex1);
polyline (3, hex2);
/* Wait for keypress, then close vp's and quit */
getch();
vp_close (vp1);
vp_close (vp2);
vp_close (vp3);
}
}
[LISTING SIX]
/* LINEGRAF.C: Self-scaling viewports showing a line graph */
/* K. Porter, «MDUL»DDJ«MDNM» Graphics Programming Column, May '89 */
#include "grafix.h"
#include <conio.h>
int data [] = {30, 70, 10, 40, 30, 80, 60, 90, 40, 50, 40};
void main ()
{
void graph (void);
VP_HAN vp1, vp2, vp3;
if (init_video (EGA)) {
/* Open three viewports */
vp1 = vp_open ( 1, 1, 360, 150);
vp2 = vp_open ( 1, 170, 638, 170);
vp3 = vp_open (500, 50, 80, 50);
/* First version upper left quadrant */
vp_use (vp1);
set_color1 (14); /* yellow */
vp_outline (vp1);
graph();
getch(); /* wait for keypress */
vp_close (vp1);
/* Second across bottom */
vp_use (vp2);
set_color1 (2); /* green */
vp_outline (vp2);
graph();
getch(); /* wait for keypress */
vp_close (vp2);
/* Third at upper right */
vp_use (vp3);
set_color1 (3); /* cyan */
vp_outline (vp3);
graph();
getch(); /* wait for keypress */
vp_close (vp3);
}
} /* ------------------------ */
void graph (void) /* draw self-scaling line graph */
{
int npts, p, prevx, prevy, curx, cury;
double vint, hint;
npts = sizeof (data) / sizeof (int); /* # data points */
/* Scaling factors for data points */
hint = (double) vp_width() / (npts - 1); /* horizontal */
vint = (double) vp_height() / 100.0; /* vertical */
/* Draw the graph */
prevx = 0; prevy = vp_height() - (int)(data[0] * vint);
for (p = 1; p < npts; p++) {
curx = (int)(p * hint);
cury = vp_height() - (int)(data[p] * vint);
draw_line (prevx, prevy, curx, cury);
prevx = curx; prevy = cury;
}
}
[GRAFIX.C, NOT A NUMBER LISTING IN DDJ 5/89]
/* Library source file GRAFIX.C */
/* EGA/VGA graphics subsystem */
/* Following library routines are external: */
/* DRAWPT.ASM Feb '89 */
/* HLINE.ASM Mar '89 */
/* EGAPALET.C Apr '89 */
/* PIXEL.ASM May '89 */
/* VUPORT.C May '89 */
/* K. Porter, DDJ Graphics Programming Column */
/* ------------------------------------------ */
#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "grafix.h"
#if !defined TRUE
#define FALSE 0
#define TRUE !FALSE
#endif
/* Variables global to this library */
int color1, /* foreground color */
oldmode = 0, /* pre-graphics mode */
grafixmode = 0, /* default graphics mode */
ega = FALSE, /* equipment Booleans */
vga = FALSE,
colormonitor = FALSE,
curpos, /* text cursor position */
textpage; /* active text page */
unsigned vidmem; /* video buffer segment */
char far *vidsave; /* video buffer save area */
/* -------------------------------------------------------- */
int far init_video (int mode)
/* Initializes video adapter and defaults for mode */
/* Sets up pc_textmode() to be called on pgm termination */
/* Returns TRUE or FALSE indicating success */
/* This function will be expanded in a later version */
{
union REGS r;
int result = FALSE;
/* Determine attached adapter and monitor */
r.h.ah = 0x1A; /* VGA inquiry function */
r.h.al = 0;
int86 (0x10, &r, &r); /* ROM BIOS call */
if (r.h.al == 0x1A)
switch (r.h.bl) {
case 4 : ega = TRUE; /* EGA color */
colormonitor = TRUE;
break;
case 5 : ega = TRUE; /* EGA mono */
break;
case 7 : ega = TRUE; /* VGA mono */
vga = TRUE;
break;
case 8 : ega = TRUE; /* VGA color */
vga = TRUE;
colormonitor = TRUE;
}
else { /* No VGA, so check for EGA */
r.h.ah = 0x12;
r.x.bx = 0x10;
int86 (0x10, &r, &r);
if (r.x.bx != 0x10) { /* if EGA present... */
ega = TRUE; /* set flag */
r.h.ah = 0x12;
r.h.bl = 0x10; /* find out which monitor */
int86 (0x10, &r, &r);
if (r.h.bl != 0)
colormonitor = TRUE; /* EGA color */
}
}
/* Proceed only if EGA or VGA present */
if (ega | vga) {
set_color1 (15); /* default pixel color */
r.h.ah = 0x0F; /* get current screen mode */
int86 (0x10, &r, &r);
oldmode = r.h.al; /* store it */
textpage = r.h.bh; /* also active text page */
if (colormonitor) /* point to video memory */
vidmem = 0xB800;
else
vidmem = 0xB000;
vidsave = malloc (4096); /* allocate save area */
movedata /* save text screen contents */
(vidmem, 0, FP_SEG (vidsave), FP_OFF (vidsave), 4096);
r.h.ah = 3; /* get text cursor position */
r.h.bh = textpage;
int86 (0x10, &r, &r);
curpos = r.x.dx; /* and save it */
if ((mode == EGA) && ega) {
r.h.ah = 0;
r.h.al = mode; /* set EGA mode */
int86 (0x10, &r, &r);
grafixmode = mode; /* save mode */
atexit (pc_textmode); /* register exit function */
result = TRUE;
} else
if ((mode == VGA16) && vga) { /* typo fixed 5/89 */
r.h.ah = 0;
r.h.al = mode;
int86 (0x10, &r, &r);
grafixmode = mode;
atexit (pc_textmode);
result = TRUE;
}
}
if (!result) { /* unable to switch to graphics */
oldmode = 0; /* so cancel text screen save */
free (vidsave);
vidsave = 0;
}
if (mode == VGA16 && vga) /* viewport init added May '89 */
default_viewport (480);
return result;
} /* ------------------------------------------------------ */
void far pc_textmode (void)
/* SPECIFIC TO MS-DOS */
/* Restore text mode */
/* Automatically called on pgm termination */
{
union REGS r;
if (oldmode) { /* if not in text mode now... */
r.h.ah = 0;
r.h.al = oldmode; /* restore text mode */
int86 (0x10, &r, &r);
movedata /* restore text screen */
(FP_SEG (vidsave), FP_OFF (vidsave), vidmem, 0, 4096);
free (vidsave); /* free allocated memory */
vidsave = 0; /* zero pointer */
oldmode = 0; /* reset */
r.h.ah = 2; /* restore old cursor position */
r.h.bh = textpage;
r.x.dx = curpos;
int86 (0x10, &r, &r);
}
} /* ------------------------------------------------------ */
void far set_color1 (int palette_reg)
/* Select pixel color from palette register */
{
color1 = palette_reg;
} /* ------------------------------------------------------ */
void far draw_line (int x1, int y1, int x2, int y2)
/* Bresenham line drawing algorithm */
/* x1, y1 and x2, y2 are end points */
{
int w, h, d, dxd, dyd, dxn, dyn, dinc, ndinc, p;
register x, y;
/* Set up */
x = x1; y = y1; /* start of line */
w = x2 - x1; /* width domain of line */
h = y2 - y1; /* height domain of line */
/* Determine drawing direction */
if (w < 0) { /* drawing right to left */
w = -w; /* absolute width */
dxd = -1; /* x increment is negative */
} else /* drawing left to right */
dxd = 1; /* so x incr is positive */
if (h < 0) { /* drawing bottom to top */
h = -h; /* so get absolute height */
dyd = -1; /* y incr is negative */
} else /* drawing top to bottom */
dyd = 1; /* so y incr is positive */
/* Determine major axis of motion */
if (w < h) { /* major axis is Y */
p = h, h = w, w = p; /* exchange height and width */
dxn = 0;
dyn = dyd;
} else { /* major axis is X */
dxn = dxd;
dyn = 0;
}
/* Set control variables */
ndinc = h * 2; /* Non-diagonal increment */
d = ndinc - w; /* pixel selection variable */
dinc = d - w; /* Diagonal increment */
/* Loop to draw the line */
for (p = 0; p <= w; p++) {
draw_point (x, y);
if (d < 0) { /* step non-diagonally */
x += dxn;
y += dyn;
d += ndinc;
} else { /* step diagonally */
x += dxd;
y += dyd;
d += dinc;
}
}
} /* ------------------------------------------------------ */
void far draw_rect (int xleft, int ytop, int w, int h)
/* Draw outline rectangle in color1 from top left corner */
/* w and h are width and height */
/* xleft and ytop are top left corner */
{
draw_line (xleft, ytop, xleft+w, ytop); /* top */
draw_line (xleft+w, ytop, xleft+w, ytop+h); /* right */
draw_line (xleft+w, ytop+h, xleft, ytop+h); /* bottom */
draw_line (xleft, ytop+h, xleft, ytop); /* left */
} /* ------------------------------------------------------ */
void far polyline (int edges, int vertex[])
/* Draw multipoint line of n edges from n+1 vertices where: */
/* vertex [0] = x0 vertex [1] = y0 */
/* vertex [2] = x1 vertex [3] = y1 */
/* etc. */
{
int x1, y1, x2, y2, v;
x1 = vertex[0];
y1 = vertex[1];
for (v = 2; v < (edges+1)*2; v+= 2) {
x2 = vertex[v];
y2 = vertex[v+1];
draw_line (x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
} /* ------------------------------------------------------ */
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);
} /* ------------------------------------------------------ */
[GRAPHIX.H, NOT A NUMBERED LISTING IN DDJ, 5/89]
/* Include file for GRAFIX.LIB */
/* EGA/VGA graphics subsystem */
/* K. Porter, DDJ Graphics Programming Column */
/* ------------------------------------------ */
/* Color constants from April, 89 */
#define Black 0 /* standard colors */
#define Blue 1
#define Green 2
#define Cyan 3
#define Red 4
#define Magenta 5
#define Brown 0x14
#define LtGray 7
#define DkGray 0x38
#define LtBlue 0x39
#define LtGreen 0x3A
#define LtCyan 0x3B
#define LtRed 0x3C
#define LtMagenta 0x3D
#define Yellow 0x3E
#define White 0x3F
#define RED0 0x00 /* basic hues for mixing */
#define RED1 0x20
#define RED2 0x04
#define RED3 0x24
#define GRN0 0x00
#define GRN1 0x10
#define GRN2 0x02
#define GRN3 0x12
#define BLU0 0x00
#define BLU1 0x08
#define BLU2 0x01
#define BLU3 0x09
#if !defined byte
#define byte unsigned char
#endif
/* Supported video modes */
#define EGA 0x10 /* EGA 640 x 350, 16/64 colors */
#define VGA16 0x11 /* VGA 640 x 480, 16/64 colors */
/* Function prototypes */
/* From February, '89 */
/* ------------------ */
int far init_video (int mode); /* init display in video mode */
void far pc_textmode (void); /* PC text mode */
void far draw_point (int x, int y); /* write pixel in color1 */
void far set_color1 (int palette_reg); /* set foreground color */
/* From March, '89 */
/* --------------- */
void far draw_line (int x1, int y1, int x2, int y2);
/* Bresenham line drawing algorithm */
void far draw_rect (int left, int top, int width, int height);
/* draw rectangle from top left corner */
void far polyline (int edges, int vertices[]); /* draw polyline */
void far hline (int x, int y, int len); /* horizontal line */
void far fill_rect (int left, int top, int width, int height);
/* draw solid rectangle in color1 starting at top left corner */
/* From April, '89 */
/* --------------- */
byte far ega_palreg (int preg); /* color in EGA palette reg */
void far set_ega_palreg (int reg, int color); /* set palette reg */
byte far colorblend (byte r, byte g, byte b); /* blend hues */
void far get_ega_colormix (int preg, int *r, int *g, int *b);
/* get mix of red, green, and blue in EGA pal register preg */
/* From May, '89 */
/* ------------- */
typedef int VP_HAN; /* viewport handle type */
void far default_viewport (int height); /* init default viewport */
VP_HAN far vp_open (int x, int y, int width, int height);
/* open viewport, make it active */
int far vp_use (VP_HAN vp); /* make vp active */
void far vp_close (VP_HAN vp); /* close viewport */
VP_HAN far vp_active (void); /* get handle of active vp */
void far vp_outline (VP_HAN vp); /* outline vp */
int far vp_width (void); /* get active viewport width */
int far vp_height (void); /* and height */