1 ; $Id: linear.asm,v 1.3 2002-07-17 21:55:19 bradleyb Exp $
2 ;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 ;SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 ;IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 ;FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
14 ; Routines to access linear VGA memory
18 ; Revision 1.20 1994/11/28 17:08:30 john
19 ; Took out some unused functions in linear.asm, moved
20 ; gr_linear_movsd from linear.asm to bitblt.c, made sure that
21 ; the code in ibiblt.c sets the direction flags before rep movsing.
23 ; Revision 1.19 1994/11/27 22:57:56 john
24 ; Took out some code that was never called.
26 ; Revision 1.18 1994/09/12 14:40:16 john
29 ; Revision 1.17 1994/07/27 18:30:30 john
30 ; Took away the blending table.
32 ; Revision 1.16 1994/04/08 16:59:28 john
33 ; Add fading poly's; Made palette fade 32 instead of 16.
35 ; Revision 1.15 1993/12/21 20:10:03 john
36 ; *** empty log message ***
38 ; Revision 1.14 1993/12/21 19:58:31 john
39 ; added selector stuff
41 ; Revision 1.13 1993/12/21 11:40:51 john
42 ; *** empty log message ***
44 ; Revision 1.12 1993/12/09 15:01:52 john
45 ; Changed palette stuff majorly
47 ; Revision 1.11 1993/12/08 16:41:02 john
48 ; *** empty log message ***
50 ; Revision 1.10 1993/12/08 11:50:17 john
51 ; Fixed bug with gr_init
53 ; Revision 1.9 1993/12/07 12:32:12 john
54 ; moved bmd_palette to gr_palette
56 ; Revision 1.8 1993/12/03 12:11:25 john
57 ; *** empty log message ***
59 ; Revision 1.7 1993/11/16 11:29:08 john
60 ; *** empty log message ***
62 ; Revision 1.6 1993/10/15 16:22:13 john
63 ; *** empty log message ***
65 ; Revision 1.5 1993/09/29 16:15:28 john
66 ; added assembler linear_line
68 ; Revision 1.4 1993/09/26 18:59:27 john
71 ; Revision 1.3 1993/09/21 14:00:59 john
72 ; added code to save 43/50 line text modes.
74 ; Revision 1.2 1993/09/16 17:28:06 john
75 ; added code to save/restore video mode
77 ; Revision 1.1 1993/09/08 11:41:30 john
89 %define _gr_var_color gr_var_color
90 %define _gr_var_bitmap gr_var_bitmap
91 %define _gr_var_bwidth gr_var_bwidth
101 ; Local variables for gr_linear_line_
102 AdjUp dd 0 ;error term adjust up on each advance
103 AdjDown dd 0 ;error term adjust down when error term turns over
104 WholeStep dd 0 ;minimum run length
105 XAdvance dd 0 ;1 or -1, for direction in which X advances
112 ; Fast run length slice line drawing implementation for mode 0x13, the VGA's
113 ; 320x200 256-color mode.
114 ; Draws a line between the specified endpoints in color Color.
117 global _gr_linear_line
118 global gr_linear_line
124 push ebx ;preserve C register variables
138 mov ebp, [_gr_var_bwidth]
140 ; We'll draw top to bottom, to reduce the number of cases we have to handle,
141 ; and to make lines between the same endpoints always draw the same pixels.
145 jle LineIsTopToBottom
146 xchg [YEnd], eax ;swap endpoints
154 ; Point EDI to the first pixel to draw.
156 mul edx ;[YStart] * ebp
159 add edi, [_gr_var_bitmap]
160 add edi, eax ;EDI = [YStart] * ebp + [XStart]
161 ; = offset of initial pixel
163 ; Figure out how far we're going vertically (guaranteed to be positive).
165 sub ecx, [YStart] ;ECX = YDelta
167 ; Figure out whether we're going left or right, and how far we're going
168 ; horizontally. In the process, special-case vertical lines, for speed and
169 ; to avoid nasty boundary conditions and division by 0.
173 jnz NotVerticalLine ;XDelta == 0 means vertical line
174 ;it is a vertical line
175 ;yes, special case vertical line
177 mov eax, [_gr_var_color]
185 ; Special-case code for horizontal lines.
188 mov eax, [_gr_var_color]
189 mov ah,al ;duplicate in high byte for word access
190 and ebx,ebx ;left to right?
192 sub edi, edx ;currently right to left, point to left end so we
193 ; can go left to right (avoids unpleasantness with
194 ; right to left REP STOSW)
197 inc ecx ;# of pixels to draw
199 shr ecx, 1 ;# of words to draw
200 rep stosw ;do as many words as possible
202 rep stosb ;do the odd byte, if there is one
206 ; Special-case code for diagonal lines.
209 mov eax, [_gr_var_color]
210 add ebx, ebp ;advance distance from one pixel to next
220 mov ebx,1 ;assume left to right, so [XAdvance] = 1
221 ;***leaves flags unchanged***
222 jns LeftToRight ;left to right, all set
223 neg ebx ;right to left, so [XAdvance] = -1
227 ; Special-case horizontal lines.
229 and ecx, ecx ;YDelta == 0?
230 jz IsHorizontalLine ;yes
232 ; Special-case diagonal lines.
233 cmp ecx, edx ;YDelta == XDelta?
234 jz IsDiagonalLine ;yes
236 ; Determine whether the line is X or Y major, and handle accordingly.
241 ; X-major (more horizontal than vertical) line.
244 and ebx,ebx ;left to right?
245 jns DFSet ;yes, CLD is already set
246 std ;right to left, so draw backwards
249 sub edx,edx ;prepare for division
250 div ecx ;EAX = XDelta/YDelta
251 ; (minimum # of pixels in a run in this line)
252 ;EDX = XDelta % YDelta
253 mov ebx,edx ;error term adjust each time Y steps by 1;
254 add ebx,ebx ; used to tell when one extra pixel should be
255 mov [AdjUp], ebx ; drawn as part of a run, to account for
256 ; fractional steps along the X axis per
257 ; 1-pixel steps along Y
258 mov esi, ecx ;error term adjust when the error term turns
259 add esi, esi ; over, used to factor out the X step made at
260 mov [AdjDown], esi ; that time
262 ; Initial error term; reflects an initial step of 0.5 along the Y axis.
263 sub edx, esi ;(XDelta % YDelta) - (YDelta * 2)
264 ;DX = initial error term
265 ; The initial and last runs are partial, because Y advances only 0.5 for
266 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
267 ; between the initial and last runs.
268 mov esi, ecx ;SI = YDelta
269 mov ecx, eax ;whole step (minimum run length)
271 inc ecx ;initial pixel count = (whole step / 2) + 1;
272 ; (may be adjusted later). This is also the
273 ; final run pixel count
274 push ecx ;remember final run pixel count for later
275 ; If the basic run length is even and there's no fractional advance, we have
276 ; one pixel that could go to either the initial or last partial run, which
277 ; we'll arbitrarily allocate to the last run.
278 ; If there is an odd number of pixels per run, we have one pixel that can't
279 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
280 ; the error term so this pixel will be handled by the normal full-run loop.
281 add edx,esi ;assume odd length, add YDelta to error term
282 ; (add 0.5 of a pixel to the error term)
283 test al,1 ;is run length even?
284 jnz XMajorAdjustDone ;no, already did work for odd case, all set
285 sub edx,esi ;length is even, undo odd stuff we just did
286 and ebx,ebx ;is the adjust up equal to 0?
287 jnz XMajorAdjustDone ;no (don't need to check for odd length,
288 ; because of the above test)
289 dec ecx ;both conditions met; make initial run 1
293 mov [WholeStep],eax ;whole step (minimum run length)
294 mov eax, [_gr_var_color] ;AL = drawing color
295 ; Draw the first, partial run of pixels.
296 rep stosb ;draw the final run
297 add edi,ebp ;advance along the minor axis (Y)
298 ; Draw all full runs.
299 cmp esi,1 ;are there more than 2 scans, so there are
300 ; some full runs? (SI = # scans - 1)
301 jna XMajorDrawLast ;no, no full runs
302 dec edx ;adjust error term by -1 so we can use
304 shr esi,1 ;convert from scan to scan-pair count
305 jnc XMajorFullRunsOddEntry ;if there is an odd number of scans,
306 ; do the odd scan now
308 mov ecx, [WholeStep] ;run is at least this long
309 add edx,ebx ;advance the error term and add an extra
310 jnc XMajorNoExtra ; pixel if the error term so indicates
311 inc ecx ;one extra pixel in run
312 sub edx,[AdjDown] ;reset the error term
314 rep stosb ;draw this scan line's run
315 add edi,ebp ;advance along the minor axis (Y)
316 XMajorFullRunsOddEntry: ;enter loop here if there is an odd number
318 mov ecx,[WholeStep] ;run is at least this long
319 add edx,ebx ;advance the error term and add an extra
320 jnc XMajorNoExtra2 ; pixel if the error term so indicates
321 inc ecx ;one extra pixel in run
322 sub edx,[AdjDown] ;reset the error term
324 rep stosb ;draw this scan line's run
325 add edi,ebp ;advance along the minor axis (Y)
328 jnz XMajorFullRunsLoop
329 ; Draw the final run of pixels.
331 pop ecx ;get back the final run pixel length
332 rep stosb ;draw the final run
334 cld ;restore normal direction flag
336 ; Y-major (more vertical than horizontal) line.
338 mov [XAdvance],ebx ;remember which way X advances
341 sub edx,edx ;prepare for division
342 div ecx ;EAX = YDelta/XDelta
343 ; (minimum # of pixels in a run in this line)
344 ;EDX = YDelta % XDelta
345 mov ebx,edx ;error term adjust each time X steps by 1;
346 add ebx,ebx ; used to tell when one extra pixel should be
347 mov [AdjUp],ebx ; drawn as part of a run, to account for
348 ; fractional steps along the Y axis per
349 ; 1-pixel steps along X
350 mov esi,ecx ;error term adjust when the error term turns
351 add esi,esi ; over, used to factor out the Y step made at
352 mov [AdjDown], esi ; that time
354 ; Initial error term; reflects an initial step of 0.5 along the X axis.
355 sub edx,esi ;(YDelta % XDelta) - (XDelta * 2)
356 ;DX = initial error term
357 ; The initial and last runs are partial, because X advances only 0.5 for
358 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
359 ; between the initial and last runs.
360 mov esi,ecx ;SI = XDelta
361 mov ecx,eax ;whole step (minimum run length)
363 inc ecx ;initial pixel count = (whole step / 2) + 1;
364 ; (may be adjusted later)
365 push ecx ;remember final run pixel count for later
367 ; If the basic run length is even and there's no fractional advance, we have
368 ; one pixel that could go to either the initial or last partial run, which
369 ; we'll arbitrarily allocate to the last run.
370 ; If there is an odd number of pixels per run, we have one pixel that can't
371 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
372 ; the error term so this pixel will be handled by the normal full-run loop.
373 add edx,esi ;assume odd length, add XDelta to error term
374 test al,1 ;is run length even?
375 jnz YMajorAdjustDone ;no, already did work for odd case, all set
376 sub edx,esi ;length is even, undo odd stuff we just did
377 and ebx,ebx ;is the adjust up equal to 0?
378 jnz YMajorAdjustDone ;no (don't need to check for odd length,
379 ; because of the above test)
380 dec ecx ;both conditions met; make initial run 1
383 mov [WholeStep],eax ;whole step (minimum run length)
384 mov eax,[_gr_var_color] ;AL = drawing color
385 mov ebx, [XAdvance] ;which way X advances
387 ; Draw the first, partial run of pixels.
389 mov [edi],al ;draw the pixel
390 add edi,ebp ;advance along the major axis (Y)
393 add edi,ebx ;advance along the minor axis (X)
394 ; Draw all full runs.
395 cmp esi,1 ;# of full runs. Are there more than 2
396 ; columns, so there are some full runs?
397 ; (SI = # columns - 1)
398 jna YMajorDrawLast ;no, no full runs
399 dec edx ;adjust error term by -1 so we can use
401 shr esi,1 ;convert from column to column-pair count
402 jnc YMajorFullRunsOddEntry ;if there is an odd number of
403 ; columns, do the odd column now
405 mov ecx,[WholeStep] ;run is at least this long
406 add edx,[AdjUp] ;advance the error term and add an extra
407 jnc YMajorNoExtra ; pixel if the error term so indicates
408 inc ecx ;one extra pixel in run
409 sub edx,[AdjDown] ;reset the error term
413 mov [edi],al ;draw the pixel
414 add edi,ebp ;advance along the major axis (Y)
417 add edi,ebx ;advance along the minor axis (X)
418 YMajorFullRunsOddEntry: ;enter loop here if there is an odd number
420 mov ecx,[WholeStep] ;run is at least this long
421 add edx,[AdjUp] ;advance the error term and add an extra
422 jnc YMajorNoExtra2 ; pixel if the error term so indicates
423 inc ecx ;one extra pixel in run
424 sub edx, [AdjDown] ;reset the error term
428 mov [edi],al ;draw the pixel
429 add edi,ebp ;advance along the major axis (Y)
432 add edi,ebx ;advance along the minor axis (X)
435 jnz YMajorFullRunsLoop
436 ; Draw the final run of pixels.
438 pop ecx ;get back the final run pixel length
440 mov [edi],al ;draw the pixel
441 add edi,ebp ;advance along the major axis (Y)
448 pop ebx;restore C register variables
451 global _gr_linear_stosd
452 global gr_linear_stosd
457 ; EAX -> Destination buffer
458 ; EDX -> Byte to store
459 ; EBX -> Number of bytes to move