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.
12 ; $Source: /cvs/cvsroot/d2x/2d/linear.asm,v $
13 ; $Revision: 1.1.1.1 $
15 ; $Date: 2001-01-19 03:29:57 $
17 ; Routines to access linear VGA memory
19 ; $Log: not supported by cvs2svn $
20 ; Revision 1.1.1.1 1999/06/14 21:57:07 donut
21 ; Import of d1x 1.37 source.
23 ; Revision 1.20 1994/11/28 17:08:30 john
24 ; Took out some unused functions in linear.asm, moved
25 ; gr_linear_movsd from linear.asm to bitblt.c, made sure that
26 ; the code in ibiblt.c sets the direction flags before rep movsing.
28 ; Revision 1.19 1994/11/27 22:57:56 john
29 ; Took out some code that was never called.
31 ; Revision 1.18 1994/09/12 14:40:16 john
34 ; Revision 1.17 1994/07/27 18:30:30 john
35 ; Took away the blending table.
37 ; Revision 1.16 1994/04/08 16:59:28 john
38 ; Add fading poly's; Made palette fade 32 instead of 16.
40 ; Revision 1.15 1993/12/21 20:10:03 john
41 ; *** empty log message ***
43 ; Revision 1.14 1993/12/21 19:58:31 john
44 ; added selector stuff
46 ; Revision 1.13 1993/12/21 11:40:51 john
47 ; *** empty log message ***
49 ; Revision 1.12 1993/12/09 15:01:52 john
50 ; Changed palette stuff majorly
52 ; Revision 1.11 1993/12/08 16:41:02 john
53 ; *** empty log message ***
55 ; Revision 1.10 1993/12/08 11:50:17 john
56 ; Fixed bug with gr_init
58 ; Revision 1.9 1993/12/07 12:32:12 john
59 ; moved bmd_palette to gr_palette
61 ; Revision 1.8 1993/12/03 12:11:25 john
62 ; *** empty log message ***
64 ; Revision 1.7 1993/11/16 11:29:08 john
65 ; *** empty log message ***
67 ; Revision 1.6 1993/10/15 16:22:13 john
68 ; *** empty log message ***
70 ; Revision 1.5 1993/09/29 16:15:28 john
71 ; added assembler linear_line
73 ; Revision 1.4 1993/09/26 18:59:27 john
76 ; Revision 1.3 1993/09/21 14:00:59 john
77 ; added code to save 43/50 line text modes.
79 ; Revision 1.2 1993/09/16 17:28:06 john
80 ; added code to save/restore video mode
82 ; Revision 1.1 1993/09/08 11:41:30 john
94 %define _gr_var_color gr_var_color
95 %define _gr_var_bitmap gr_var_bitmap
96 %define _gr_var_bwidth gr_var_bwidth
100 global _gr_var_bitmap
101 global _gr_var_bwidth
106 ; Local variables for gr_linear_line_
107 AdjUp dd 0 ;error term adjust up on each advance
108 AdjDown dd 0 ;error term adjust down when error term turns over
109 WholeStep dd 0 ;minimum run length
110 XAdvance dd 0 ;1 or -1, for direction in which X advances
117 ; Fast run length slice line drawing implementation for mode 0x13, the VGA's
118 ; 320x200 256-color mode.
119 ; Draws a line between the specified endpoints in color Color.
122 global _gr_linear_line
123 global gr_linear_line
129 push ebx ;preserve C register variables
143 mov ebp, [_gr_var_bwidth]
145 ; We'll draw top to bottom, to reduce the number of cases we have to handle,
146 ; and to make lines between the same endpoints always draw the same pixels.
150 jle LineIsTopToBottom
151 xchg [YEnd], eax ;swap endpoints
159 ; Point EDI to the first pixel to draw.
161 mul edx ;[YStart] * ebp
164 add edi, [_gr_var_bitmap]
165 add edi, eax ;EDI = [YStart] * ebp + [XStart]
166 ; = offset of initial pixel
168 ; Figure out how far we're going vertically (guaranteed to be positive).
170 sub ecx, [YStart] ;ECX = YDelta
172 ; Figure out whether we're going left or right, and how far we're going
173 ; horizontally. In the process, special-case vertical lines, for speed and
174 ; to avoid nasty boundary conditions and division by 0.
178 jnz NotVerticalLine ;XDelta == 0 means vertical line
179 ;it is a vertical line
180 ;yes, special case vertical line
182 mov eax, [_gr_var_color]
190 ; Special-case code for horizontal lines.
193 mov eax, [_gr_var_color]
194 mov ah,al ;duplicate in high byte for word access
195 and ebx,ebx ;left to right?
197 sub edi, edx ;currently right to left, point to left end so we
198 ; can go left to right (avoids unpleasantness with
199 ; right to left REP STOSW)
202 inc ecx ;# of pixels to draw
204 shr ecx, 1 ;# of words to draw
205 rep stosw ;do as many words as possible
207 rep stosb ;do the odd byte, if there is one
211 ; Special-case code for diagonal lines.
214 mov eax, [_gr_var_color]
215 add ebx, ebp ;advance distance from one pixel to next
225 mov ebx,1 ;assume left to right, so [XAdvance] = 1
226 ;***leaves flags unchanged***
227 jns LeftToRight ;left to right, all set
228 neg ebx ;right to left, so [XAdvance] = -1
232 ; Special-case horizontal lines.
234 and ecx, ecx ;YDelta == 0?
235 jz IsHorizontalLine ;yes
237 ; Special-case diagonal lines.
238 cmp ecx, edx ;YDelta == XDelta?
239 jz IsDiagonalLine ;yes
241 ; Determine whether the line is X or Y major, and handle accordingly.
246 ; X-major (more horizontal than vertical) line.
249 and ebx,ebx ;left to right?
250 jns DFSet ;yes, CLD is already set
251 std ;right to left, so draw backwards
254 sub edx,edx ;prepare for division
255 div ecx ;EAX = XDelta/YDelta
256 ; (minimum # of pixels in a run in this line)
257 ;EDX = XDelta % YDelta
258 mov ebx,edx ;error term adjust each time Y steps by 1;
259 add ebx,ebx ; used to tell when one extra pixel should be
260 mov [AdjUp], ebx ; drawn as part of a run, to account for
261 ; fractional steps along the X axis per
262 ; 1-pixel steps along Y
263 mov esi, ecx ;error term adjust when the error term turns
264 add esi, esi ; over, used to factor out the X step made at
265 mov [AdjDown], esi ; that time
267 ; Initial error term; reflects an initial step of 0.5 along the Y axis.
268 sub edx, esi ;(XDelta % YDelta) - (YDelta * 2)
269 ;DX = initial error term
270 ; The initial and last runs are partial, because Y advances only 0.5 for
271 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
272 ; between the initial and last runs.
273 mov esi, ecx ;SI = YDelta
274 mov ecx, eax ;whole step (minimum run length)
276 inc ecx ;initial pixel count = (whole step / 2) + 1;
277 ; (may be adjusted later). This is also the
278 ; final run pixel count
279 push ecx ;remember final run pixel count for later
280 ; If the basic run length is even and there's no fractional advance, we have
281 ; one pixel that could go to either the initial or last partial run, which
282 ; we'll arbitrarily allocate to the last run.
283 ; If there is an odd number of pixels per run, we have one pixel that can't
284 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
285 ; the error term so this pixel will be handled by the normal full-run loop.
286 add edx,esi ;assume odd length, add YDelta to error term
287 ; (add 0.5 of a pixel to the error term)
288 test al,1 ;is run length even?
289 jnz XMajorAdjustDone ;no, already did work for odd case, all set
290 sub edx,esi ;length is even, undo odd stuff we just did
291 and ebx,ebx ;is the adjust up equal to 0?
292 jnz XMajorAdjustDone ;no (don't need to check for odd length,
293 ; because of the above test)
294 dec ecx ;both conditions met; make initial run 1
298 mov [WholeStep],eax ;whole step (minimum run length)
299 mov eax, [_gr_var_color] ;AL = drawing color
300 ; Draw the first, partial run of pixels.
301 rep stosb ;draw the final run
302 add edi,ebp ;advance along the minor axis (Y)
303 ; Draw all full runs.
304 cmp esi,1 ;are there more than 2 scans, so there are
305 ; some full runs? (SI = # scans - 1)
306 jna XMajorDrawLast ;no, no full runs
307 dec edx ;adjust error term by -1 so we can use
309 shr esi,1 ;convert from scan to scan-pair count
310 jnc XMajorFullRunsOddEntry ;if there is an odd number of scans,
311 ; do the odd scan now
313 mov ecx, [WholeStep] ;run is at least this long
314 add edx,ebx ;advance the error term and add an extra
315 jnc XMajorNoExtra ; pixel if the error term so indicates
316 inc ecx ;one extra pixel in run
317 sub edx,[AdjDown] ;reset the error term
319 rep stosb ;draw this scan line's run
320 add edi,ebp ;advance along the minor axis (Y)
321 XMajorFullRunsOddEntry: ;enter loop here if there is an odd number
323 mov ecx,[WholeStep] ;run is at least this long
324 add edx,ebx ;advance the error term and add an extra
325 jnc XMajorNoExtra2 ; pixel if the error term so indicates
326 inc ecx ;one extra pixel in run
327 sub edx,[AdjDown] ;reset the error term
329 rep stosb ;draw this scan line's run
330 add edi,ebp ;advance along the minor axis (Y)
333 jnz XMajorFullRunsLoop
334 ; Draw the final run of pixels.
336 pop ecx ;get back the final run pixel length
337 rep stosb ;draw the final run
339 cld ;restore normal direction flag
341 ; Y-major (more vertical than horizontal) line.
343 mov [XAdvance],ebx ;remember which way X advances
346 sub edx,edx ;prepare for division
347 div ecx ;EAX = YDelta/XDelta
348 ; (minimum # of pixels in a run in this line)
349 ;EDX = YDelta % XDelta
350 mov ebx,edx ;error term adjust each time X steps by 1;
351 add ebx,ebx ; used to tell when one extra pixel should be
352 mov [AdjUp],ebx ; drawn as part of a run, to account for
353 ; fractional steps along the Y axis per
354 ; 1-pixel steps along X
355 mov esi,ecx ;error term adjust when the error term turns
356 add esi,esi ; over, used to factor out the Y step made at
357 mov [AdjDown], esi ; that time
359 ; Initial error term; reflects an initial step of 0.5 along the X axis.
360 sub edx,esi ;(YDelta % XDelta) - (XDelta * 2)
361 ;DX = initial error term
362 ; The initial and last runs are partial, because X advances only 0.5 for
363 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
364 ; between the initial and last runs.
365 mov esi,ecx ;SI = XDelta
366 mov ecx,eax ;whole step (minimum run length)
368 inc ecx ;initial pixel count = (whole step / 2) + 1;
369 ; (may be adjusted later)
370 push ecx ;remember final run pixel count for later
372 ; If the basic run length is even and there's no fractional advance, we have
373 ; one pixel that could go to either the initial or last partial run, which
374 ; we'll arbitrarily allocate to the last run.
375 ; If there is an odd number of pixels per run, we have one pixel that can't
376 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
377 ; the error term so this pixel will be handled by the normal full-run loop.
378 add edx,esi ;assume odd length, add XDelta to error term
379 test al,1 ;is run length even?
380 jnz YMajorAdjustDone ;no, already did work for odd case, all set
381 sub edx,esi ;length is even, undo odd stuff we just did
382 and ebx,ebx ;is the adjust up equal to 0?
383 jnz YMajorAdjustDone ;no (don't need to check for odd length,
384 ; because of the above test)
385 dec ecx ;both conditions met; make initial run 1
388 mov [WholeStep],eax ;whole step (minimum run length)
389 mov eax,[_gr_var_color] ;AL = drawing color
390 mov ebx, [XAdvance] ;which way X advances
392 ; Draw the first, partial run of pixels.
394 mov [edi],al ;draw the pixel
395 add edi,ebp ;advance along the major axis (Y)
398 add edi,ebx ;advance along the minor axis (X)
399 ; Draw all full runs.
400 cmp esi,1 ;# of full runs. Are there more than 2
401 ; columns, so there are some full runs?
402 ; (SI = # columns - 1)
403 jna YMajorDrawLast ;no, no full runs
404 dec edx ;adjust error term by -1 so we can use
406 shr esi,1 ;convert from column to column-pair count
407 jnc YMajorFullRunsOddEntry ;if there is an odd number of
408 ; columns, do the odd column now
410 mov ecx,[WholeStep] ;run is at least this long
411 add edx,[AdjUp] ;advance the error term and add an extra
412 jnc YMajorNoExtra ; pixel if the error term so indicates
413 inc ecx ;one extra pixel in run
414 sub edx,[AdjDown] ;reset the error term
418 mov [edi],al ;draw the pixel
419 add edi,ebp ;advance along the major axis (Y)
422 add edi,ebx ;advance along the minor axis (X)
423 YMajorFullRunsOddEntry: ;enter loop here if there is an odd number
425 mov ecx,[WholeStep] ;run is at least this long
426 add edx,[AdjUp] ;advance the error term and add an extra
427 jnc YMajorNoExtra2 ; pixel if the error term so indicates
428 inc ecx ;one extra pixel in run
429 sub edx, [AdjDown] ;reset the error term
433 mov [edi],al ;draw the pixel
434 add edi,ebp ;advance along the major axis (Y)
437 add edi,ebx ;advance along the minor axis (X)
440 jnz YMajorFullRunsLoop
441 ; Draw the final run of pixels.
443 pop ecx ;get back the final run pixel length
445 mov [edi],al ;draw the pixel
446 add edi,ebp ;advance along the major axis (Y)
453 pop ebx;restore C register variables
456 global _gr_linear_stosd
457 global gr_linear_stosd
462 ; EAX -> Destination buffer
463 ; EDX -> Byte to store
464 ; EBX -> Number of bytes to move