1 ;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
2 ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
3 ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
4 ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
5 ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
6 ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
7 ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
8 ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
9 ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
10 ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
13 ; Routines to access linear VGA memory
22 %define _gr_var_color gr_var_color
23 %define _gr_var_bitmap gr_var_bitmap
24 %define _gr_var_bwidth gr_var_bwidth
34 ; Local variables for gr_linear_line_
35 AdjUp dd 0 ;error term adjust up on each advance
36 AdjDown dd 0 ;error term adjust down when error term turns over
37 WholeStep dd 0 ;minimum run length
38 XAdvance dd 0 ;1 or -1, for direction in which X advances
45 ; Fast run length slice line drawing implementation for mode 0x13, the VGA's
46 ; 320x200 256-color mode.
47 ; Draws a line between the specified endpoints in color Color.
50 global _gr_linear_line
57 push ebx ;preserve C register variables
71 mov ebp, [_gr_var_bwidth]
73 ; We'll draw top to bottom, to reduce the number of cases we have to handle,
74 ; and to make lines between the same endpoints always draw the same pixels.
79 xchg [Y_End], eax ;swap endpoints
87 ; Point EDI to the first pixel to draw.
89 mul edx ;[YStart] * ebp
92 add edi, [_gr_var_bitmap]
93 add edi, eax ;EDI = [YStart] * ebp + [XStart]
94 ; = offset of initial pixel
96 ; Figure out how far we're going vertically (guaranteed to be positive).
98 sub ecx, [YStart] ;ECX = YDelta
100 ; Figure out whether we're going left or right, and how far we're going
101 ; horizontally. In the process, special-case vertical lines, for speed and
102 ; to avoid nasty boundary conditions and division by 0.
106 jnz NotVerticalLine ;XDelta == 0 means vertical line
107 ;it is a vertical line
108 ;yes, special case vertical line
110 mov eax, [_gr_var_color]
118 ; Special-case code for horizontal lines.
121 mov eax, [_gr_var_color]
122 mov ah,al ;duplicate in high byte for word access
123 and ebx,ebx ;left to right?
125 sub edi, edx ;currently right to left, point to left end so we
126 ; can go left to right (avoids unpleasantness with
127 ; right to left REP STOSW)
130 inc ecx ;# of pixels to draw
132 shr ecx, 1 ;# of words to draw
133 rep stosw ;do as many words as possible
135 rep stosb ;do the odd byte, if there is one
139 ; Special-case code for diagonal lines.
142 mov eax, [_gr_var_color]
143 add ebx, ebp ;advance distance from one pixel to next
153 mov ebx,1 ;assume left to right, so [XAdvance] = 1
154 ;***leaves flags unchanged***
155 jns LeftToRight ;left to right, all set
156 neg ebx ;right to left, so [XAdvance] = -1
160 ; Special-case horizontal lines.
162 and ecx, ecx ;YDelta == 0?
163 jz IsHorizontalLine ;yes
165 ; Special-case diagonal lines.
166 cmp ecx, edx ;YDelta == XDelta?
167 jz IsDiagonalLine ;yes
169 ; Determine whether the line is X or Y major, and handle accordingly.
174 ; X-major (more horizontal than vertical) line.
177 and ebx,ebx ;left to right?
178 jns DFSet ;yes, CLD is already set
179 std ;right to left, so draw backwards
182 sub edx,edx ;prepare for division
183 div ecx ;EAX = XDelta/YDelta
184 ; (minimum # of pixels in a run in this line)
185 ;EDX = XDelta % YDelta
186 mov ebx,edx ;error term adjust each time Y steps by 1;
187 add ebx,ebx ; used to tell when one extra pixel should be
188 mov [AdjUp], ebx ; drawn as part of a run, to account for
189 ; fractional steps along the X axis per
190 ; 1-pixel steps along Y
191 mov esi, ecx ;error term adjust when the error term turns
192 add esi, esi ; over, used to factor out the X step made at
193 mov [AdjDown], esi ; that time
195 ; Initial error term; reflects an initial step of 0.5 along the Y axis.
196 sub edx, esi ;(XDelta % YDelta) - (YDelta * 2)
197 ;DX = initial error term
198 ; The initial and last runs are partial, because Y advances only 0.5 for
199 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
200 ; between the initial and last runs.
201 mov esi, ecx ;SI = YDelta
202 mov ecx, eax ;whole step (minimum run length)
204 inc ecx ;initial pixel count = (whole step / 2) + 1;
205 ; (may be adjusted later). This is also the
206 ; final run pixel count
207 push ecx ;remember final run pixel count for later
208 ; If the basic run length is even and there's no fractional advance, we have
209 ; one pixel that could go to either the initial or last partial run, which
210 ; we'll arbitrarily allocate to the last run.
211 ; If there is an odd number of pixels per run, we have one pixel that can't
212 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
213 ; the error term so this pixel will be handled by the normal full-run loop.
214 add edx,esi ;assume odd length, add YDelta to error term
215 ; (add 0.5 of a pixel to the error term)
216 test al,1 ;is run length even?
217 jnz XMajorAdjustDone ;no, already did work for odd case, all set
218 sub edx,esi ;length is even, undo odd stuff we just did
219 and ebx,ebx ;is the adjust up equal to 0?
220 jnz XMajorAdjustDone ;no (don't need to check for odd length,
221 ; because of the above test)
222 dec ecx ;both conditions met; make initial run 1
226 mov [WholeStep],eax ;whole step (minimum run length)
227 mov eax, [_gr_var_color] ;AL = drawing color
228 ; Draw the first, partial run of pixels.
229 rep stosb ;draw the final run
230 add edi,ebp ;advance along the minor axis (Y)
231 ; Draw all full runs.
232 cmp esi,1 ;are there more than 2 scans, so there are
233 ; some full runs? (SI = # scans - 1)
234 jna XMajorDrawLast ;no, no full runs
235 dec edx ;adjust error term by -1 so we can use
237 shr esi,1 ;convert from scan to scan-pair count
238 jnc XMajorFullRunsOddEntry ;if there is an odd number of scans,
239 ; do the odd scan now
241 mov ecx, [WholeStep] ;run is at least this long
242 add edx,ebx ;advance the error term and add an extra
243 jnc XMajorNoExtra ; pixel if the error term so indicates
244 inc ecx ;one extra pixel in run
245 sub edx,[AdjDown] ;reset the error term
247 rep stosb ;draw this scan line's run
248 add edi,ebp ;advance along the minor axis (Y)
249 XMajorFullRunsOddEntry: ;enter loop here if there is an odd number
251 mov ecx,[WholeStep] ;run is at least this long
252 add edx,ebx ;advance the error term and add an extra
253 jnc XMajorNoExtra2 ; pixel if the error term so indicates
254 inc ecx ;one extra pixel in run
255 sub edx,[AdjDown] ;reset the error term
257 rep stosb ;draw this scan line's run
258 add edi,ebp ;advance along the minor axis (Y)
261 jnz XMajorFullRunsLoop
262 ; Draw the final run of pixels.
264 pop ecx ;get back the final run pixel length
265 rep stosb ;draw the final run
267 cld ;restore normal direction flag
269 ; Y-major (more vertical than horizontal) line.
271 mov [XAdvance],ebx ;remember which way X advances
274 sub edx,edx ;prepare for division
275 div ecx ;EAX = YDelta/XDelta
276 ; (minimum # of pixels in a run in this line)
277 ;EDX = YDelta % XDelta
278 mov ebx,edx ;error term adjust each time X steps by 1;
279 add ebx,ebx ; used to tell when one extra pixel should be
280 mov [AdjUp],ebx ; drawn as part of a run, to account for
281 ; fractional steps along the Y axis per
282 ; 1-pixel steps along X
283 mov esi,ecx ;error term adjust when the error term turns
284 add esi,esi ; over, used to factor out the Y step made at
285 mov [AdjDown], esi ; that time
287 ; Initial error term; reflects an initial step of 0.5 along the X axis.
288 sub edx,esi ;(YDelta % XDelta) - (XDelta * 2)
289 ;DX = initial error term
290 ; The initial and last runs are partial, because X advances only 0.5 for
291 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
292 ; between the initial and last runs.
293 mov esi,ecx ;SI = XDelta
294 mov ecx,eax ;whole step (minimum run length)
296 inc ecx ;initial pixel count = (whole step / 2) + 1;
297 ; (may be adjusted later)
298 push ecx ;remember final run pixel count for later
300 ; If the basic run length is even and there's no fractional advance, we have
301 ; one pixel that could go to either the initial or last partial run, which
302 ; we'll arbitrarily allocate to the last run.
303 ; If there is an odd number of pixels per run, we have one pixel that can't
304 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
305 ; the error term so this pixel will be handled by the normal full-run loop.
306 add edx,esi ;assume odd length, add XDelta to error term
307 test al,1 ;is run length even?
308 jnz YMajorAdjustDone ;no, already did work for odd case, all set
309 sub edx,esi ;length is even, undo odd stuff we just did
310 and ebx,ebx ;is the adjust up equal to 0?
311 jnz YMajorAdjustDone ;no (don't need to check for odd length,
312 ; because of the above test)
313 dec ecx ;both conditions met; make initial run 1
316 mov [WholeStep],eax ;whole step (minimum run length)
317 mov eax,[_gr_var_color] ;AL = drawing color
318 mov ebx, [XAdvance] ;which way X advances
320 ; Draw the first, partial run of pixels.
322 mov [edi],al ;draw the pixel
323 add edi,ebp ;advance along the major axis (Y)
326 add edi,ebx ;advance along the minor axis (X)
327 ; Draw all full runs.
328 cmp esi,1 ;# of full runs. Are there more than 2
329 ; columns, so there are some full runs?
330 ; (SI = # columns - 1)
331 jna YMajorDrawLast ;no, no full runs
332 dec edx ;adjust error term by -1 so we can use
334 shr esi,1 ;convert from column to column-pair count
335 jnc YMajorFullRunsOddEntry ;if there is an odd number of
336 ; columns, do the odd column now
338 mov ecx,[WholeStep] ;run is at least this long
339 add edx,[AdjUp] ;advance the error term and add an extra
340 jnc YMajorNoExtra ; pixel if the error term so indicates
341 inc ecx ;one extra pixel in run
342 sub edx,[AdjDown] ;reset the error term
346 mov [edi],al ;draw the pixel
347 add edi,ebp ;advance along the major axis (Y)
350 add edi,ebx ;advance along the minor axis (X)
351 YMajorFullRunsOddEntry: ;enter loop here if there is an odd number
353 mov ecx,[WholeStep] ;run is at least this long
354 add edx,[AdjUp] ;advance the error term and add an extra
355 jnc YMajorNoExtra2 ; pixel if the error term so indicates
356 inc ecx ;one extra pixel in run
357 sub edx, [AdjDown] ;reset the error term
361 mov [edi],al ;draw the pixel
362 add edi,ebp ;advance along the major axis (Y)
365 add edi,ebx ;advance along the minor axis (X)
368 jnz YMajorFullRunsLoop
369 ; Draw the final run of pixels.
371 pop ecx ;get back the final run pixel length
373 mov [edi],al ;draw the pixel
374 add edi,ebp ;advance along the major axis (Y)
381 pop ebx;restore C register variables
384 global _gr_linear_stosd
385 global gr_linear_stosd
390 ; EAX -> Destination buffer
391 ; EDX -> Byte to store
392 ; EBX -> Number of bytes to move