e9936fe0231d8cb44861c927b3cd5de5d002ad0a
[ctsim.git] / libctgraphics / bresenham.cpp
1 /* ; FILE IDENTIFICATION
2 ;
3 ;               Name:  CRT_LINE.ASM
4 ;            Purpose:  Draw lines on screen using Bresenham's integer algorithm
5 ;         Programmer:  Kevin Rosenberg
6 ;       Date Started:  1 Jun 84
7 ;  Last Modification: 15 Jul 85, Version 1.0
8 ;       
9 ; CORRESPONDENCE
10 ;       Kevin Rosenberg
11 ;       2515 E. 16th St.
12 ;       Newport Beach, CA 92663
13 ;       (714) 642-0119 (voice)
14 ;       (714) 842-6348 (E-Mail on Consultant's Exchange RBBS)
15 ;       Compuserve 73775,1232
16 ;
17 ; LANGAUGE
18 ;       IBM macro v1.000000000
19 ;
20 ; LANGAUGE INTERFACE
21 ;       Public routines callable from Lattice C v2.0+
22 ;           Works with S & L memory models.  Can easily add support for the
23 ;           other models by changing the STK structure below.
24 ;
25 ; NEEDED FILES
26 ;       egadrive.inc    Definitions, macros, & procedures for driving EGA
27 ;       hidden.inc      Defines OPTIONAL public procedure, crt_hdn_line().
28 ;       dos.mac         Lattice's file containing memory model macros
29 ;                       See inclusion statement for more documentation
30 ;
31 ; GRAPHIC MODES SUPPORTED
32 ;       - Standard CGA modes -- BIOS codes 4, 5, & 6 -- are support through
33 ;         the ROM BIOS pixel setting routine.  Things could be speeded up
34 ;         by a factor of 7-15 by writing to the video buffer directly.
35 ;       - You may remove support for the CGA completely by changing the
36 ;         EQU of STD_GRF to 0, a slight speed increase in EGA operations
37 ;         is the gain.
38 ;       - All EGA graphic modes are supported with optimized direct pixel
39 ;         accessing.  Note: mode 13 (320x200) is bugged, see LOG date 6-20-85
40 ;
41 ; LANGUAGE INTERFACE
42 ;       Lattice C v2.0+
43 ;
44 ; HISTORY LOG
45 ;    7-15-85
46 ;       Released in PD as version 1.0
47 ;    6-27-85
48 ;       Put EGA routines in INCLUDE file EGADRIVE.INC
49 ;       Put Hidden line routines in OPTIONAL INCLUDE file HIDDEN.INC
50 ;    6-20-85
51 ;       Tested with video modes 13 (320x200) & 14 (640x200).  Mode 14 worked
52 ;       ok, mode 13 was missing every other vertical line:  I'm probably
53 ;       not setting one of the myriad of registers correctly.  Since I'll
54 ;       never use mode 13, I won't investigate it further.
55 ;    6-05-85
56 ;       Added & updated documentation
57 ;    2-28-85
58 ;       Added hidden line routines
59 ;          PUBLIC crt_hdn_line plus internal routines
60 ;          (see function summary for more info)
61 ;    1-20-85
62 ;       Added global variable STD_GRF
63 ;          Will support standard graphic modes if it is set to non-zero value;
64 ;          however, the slow ROM BIOS is used as well as a slight overhead
65 ;          for the EG code.  IT IS MUCH FASTER TO USE THE EGA ENHANCED
66 ;          (350 line) GRAPHIC MODES.
67 ;    1-09-85
68 ;       Convert to support IBM's Enhanced graphics adapter.
69 ;       Remove all optimized code for color graphics adapter (CGA)
70 ;    7-16-84
71 ;       Changed calls to ROM that set pixels to speedy routines which use
72 ;       incremental address calculation and direct writing the to graphics
73 ;       buffer.
74 ;    1-12-84
75 ;       File creation:
76 ;            Converted C function, bresline.c, to assembly langauge.
77 ;            Retained C source of Bresenham's integer rastering algorithm
78 ;            as comments.
79 ;
80 ; FUNCTION SUMMARY 
81 ;
82 ;       crt_line_page (page)
83 ;               Set graphics page to plot lines on [default = 0]
84 ;
85 ;       crt_line_style (style)
86 ;               Set line style [Default = solid line]
87 ;
88 ;       crt_line (x1, y1, x2, y1, color)
89 ;               Plots a line on the screen using Bresenham's integer algorithm
90 ;
91 ;       crt_hdn_line (x1, y1, x2, y1, color, col_min, col_max)
92 ;               OPTIONAL routine to plots lines using hidden areas
93 ;               INCLUDE file HIDDEN.INC if you wish to use this routine
94 ;
95 ;       crt_init_hdn (col_min, col_max)
96 ;               Initializes vectors for use with crt_hdn_line()
97 ;
98 ;
99 ;       int x1, y1 - starting point
100 ;       int x2, y2 - end point
101 ;       int color  - color to draw line, as defined by IBM bios setting
102 ;       int linestyle - 16 bit wide dot setting pattern
103 ;       int col_min[640]  Minimum values for each X column (initialize to 349)
104 ;       int col_max[640]  Maximum values for each X column (initialize to 0)
105 ;                         (Do not display any points between the min & max,
106 ;                          and update these values for each new min & max)
107 ;                         If a vector == NULL, then do not clip against that
108 ;                         boundary.
109 ;
110 ; REFERENCES FOR BRESENHAM'S ALGORITHM
111 ;       Newman & Sproll, "Principals of Interactive Computer Graphics",
112 ;          page 25.
113 ;       Foley & van Dam, "Fundementals of Interactive Computer Graphics",
114 ;          page 433
115 */
116
117 ;------ Bresenham variables
118
119         deltx           dw      ?
120         delty           dw      ?
121         absdx           dw      ?
122         absdy           dw      ?
123         min_inc         dw      ?       ; (-1, 1) indicates direction of minor axis
124         dinc1           dw      ?       ; d increment if (d >= 0)
125         dinc2           dw      ?       ; d increment if (d < 0)
126
127
128
129
130 ;------------------------------------------------------------------------------
131 ; PROCEDURE
132 ;       crt_line [PUBLIC]       Plot a line on the screen using Bresenham's alg
133 ;
134 ; SYNOPSIS
135 ;       crt_line (x1, y1, x2, y2, color)
136
137 void bresenham (int x1, int y1, int x2, int y2)
138 {
139         delta_x = x2 - x1;
140         dx_abs = (delta_x >= 0 ? delta_x : -delta_x);
141
142         delta_y = y2 - y1;
143         dy_abs = (delta_y >= 0 ? delta_y : -delta_y);
144
145 if (dx_abs > dy_abs) 
146     bresx();
147 else
148    bresy();
149 }
150
151 lastx= x2;
152 lasty = y2;
153
154
155 ;------------------------------------------------------------------------------
156 ; MACRO NAME
157 ;       BRES
158 ;
159 ; FUNCTION
160 ;       Do inner most loop to draw pictures
161 ;
162 ; SYNOPSIS
163 ;       BRES P1,P2
164 ;       P1      Major axis & direction 
165 ;       P2      Minor axis 
166 ;
167 ; EXAMPLES
168 ;       BRES INC_COL,ROW
169 ;
170 ; INPUT
171 ;       (DI)            Address of local routine to call when setting pixel
172 ;       (BX)            Decision variable
173 ;       (CX)            Number of points to plot on major axis (loop counter)
174 ;       [bp].min_inc    Direction of minor axis increments
175 ;       [bp].dinc1      Bresenham decision increments (see references)
176 ;       [bp].dinc2
177 ;       MACROS          ADDR_INC_ROW, _DEC_ROW, _INC_COL, _DEC_COL
178 ;
179 ; REGISTERS USED BY PIXEL SETTING ROUTINES
180 ;       (SI)            Offset in EGA buffer
181 ;       (AH)            Bitmask
182 ;
183 ; REGISTERS AVAILABLE FOR USE
184 ;       (AL)
185 ;       (DX)
186 ;
187 ; CALLS
188 ;       LS_PSET, this routine uses the addr in (DI) to set a point if
189 ;                the linestyle allows.
190 ;------------------------------------------------------------------------------
191
192 BRES    MACRO   P1,P2
193         LOCAL   b0,b1
194         cmp     [bp].min_inc,0  ;if (min_inc >= 0)
195         jl      b0
196         _BRES   P1,INC_&P2      ;       inc_minor_axis
197         jmp     b1              ;else
198 b0:     _BRES   P1,DEC_&P2      ;       dec_minor_axis
199 b1:
200         ENDM
201
202
203 _BRES   MACRO   P1,P2
204         LOCAL   bres0,bres1,bres2
205 bres0:                          ; do {
206         LS_PSET                 ;       ls_pset() /* set pix using linestyle */
207
208         ADDR_&P1                        ;       P1 (change major axis)
209
210         cmp     bx,0            ;
211         jge     bres1           ;       if (d < 0)
212         add     bx,[bp].dinc2   ;           d += dinc2;
213         jmp     bres2           ;       else {
214 bres1:                          ;
215         add     bx,[bp].dinc1   ;           d += dinc1
216         ADDR_&P2                        ;           P2 (change minor axis)
217                                 ;       }
218 bres2:
219         loop    bres0           ; } while (--count > 0)
220         ENDM
221
222 bresx()
223 {
224     /*    draws a line then abs(dx) >= abs(dy) */
225
226     int npix = dx_abs + 1;
227
228     /* determine direction of minor axis */
229
230     int  min_inc = 1;
231     if (delta_y < 0)
232         min_inc = -1;
233
234     /* Put decision variable in d */
235
236     int d = dy_abs * 2 - dx_abs;
237     int dinc1 = (dy_abs - dx_abs) * 2;
238     int dinc2 = 2 * dy_abs;
239
240     if (x1 <= x2)
241         bres(INC_COL, ROW);
242     else 
243         breas (DEC_COL, ROW)l
244
245             }
246
247
248 void bresy()
249 {
250     /*;    bresy [LOCAL]        For plotting lines with abs(dy) > abs(sx)
251
252  NOTES
253     Logic identical to bresx's, substitution x for y and
254     vice versa.  I separate the into two routines rather
255     than having the main loop spending time determining
256     which are the major & minor axis. 
257     */
258
259
260     int count = dy_abs + 1;
261
262     /* check direction of minor axis */
263
264     min_inc = 1;
265     if (delta_x < 0)
266         min_inc = -1;
267
268
269     int d = dx_abs * 2 - dy_abs;
270     dinc1 = (dx_abs - dy_abs) * 2;
271     dinc2 = 2 * dx_abs;
272
273     if (y1 <= y2)
274         bres(INC_ROW,COL);
275     else
276         bres(DEL_ROW,COL);
277 }
278