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 $
15 ; $Date: 2001-10-19 09:34:02 $
17 ; Routines to access linear VGA memory
19 ; $Log: not supported by cvs2svn $
20 ; Revision 1.1.1.1 2001/01/19 03:29:57 bradleyb
23 ; Revision 1.1.1.1 1999/06/14 21:57:07 donut
24 ; Import of d1x 1.37 source.
26 ; Revision 1.20 1994/11/28 17:08:30 john
27 ; Took out some unused functions in linear.asm, moved
28 ; gr_linear_movsd from linear.asm to bitblt.c, made sure that
29 ; the code in ibiblt.c sets the direction flags before rep movsing.
31 ; Revision 1.19 1994/11/27 22:57:56 john
32 ; Took out some code that was never called.
34 ; Revision 1.18 1994/09/12 14:40:16 john
37 ; Revision 1.17 1994/07/27 18:30:30 john
38 ; Took away the blending table.
40 ; Revision 1.16 1994/04/08 16:59:28 john
41 ; Add fading poly's; Made palette fade 32 instead of 16.
43 ; Revision 1.15 1993/12/21 20:10:03 john
44 ; *** empty log message ***
46 ; Revision 1.14 1993/12/21 19:58:31 john
47 ; added selector stuff
49 ; Revision 1.13 1993/12/21 11:40:51 john
50 ; *** empty log message ***
52 ; Revision 1.12 1993/12/09 15:01:52 john
53 ; Changed palette stuff majorly
55 ; Revision 1.11 1993/12/08 16:41:02 john
56 ; *** empty log message ***
58 ; Revision 1.10 1993/12/08 11:50:17 john
59 ; Fixed bug with gr_init
61 ; Revision 1.9 1993/12/07 12:32:12 john
62 ; moved bmd_palette to gr_palette
64 ; Revision 1.8 1993/12/03 12:11:25 john
65 ; *** empty log message ***
67 ; Revision 1.7 1993/11/16 11:29:08 john
68 ; *** empty log message ***
70 ; Revision 1.6 1993/10/15 16:22:13 john
71 ; *** empty log message ***
73 ; Revision 1.5 1993/09/29 16:15:28 john
74 ; added assembler linear_line
76 ; Revision 1.4 1993/09/26 18:59:27 john
79 ; Revision 1.3 1993/09/21 14:00:59 john
80 ; added code to save 43/50 line text modes.
82 ; Revision 1.2 1993/09/16 17:28:06 john
83 ; added code to save/restore video mode
85 ; Revision 1.1 1993/09/08 11:41:30 john
97 %define _gr_var_color gr_var_color
98 %define _gr_var_bitmap gr_var_bitmap
99 %define _gr_var_bwidth gr_var_bwidth
103 global _gr_var_bitmap
104 global _gr_var_bwidth
109 ; Local variables for gr_linear_line_
110 AdjUp dd 0 ;error term adjust up on each advance
111 AdjDown dd 0 ;error term adjust down when error term turns over
112 WholeStep dd 0 ;minimum run length
113 XAdvance dd 0 ;1 or -1, for direction in which X advances
120 ; Fast run length slice line drawing implementation for mode 0x13, the VGA's
121 ; 320x200 256-color mode.
122 ; Draws a line between the specified endpoints in color Color.
125 global _gr_linear_line
126 global gr_linear_line
132 push ebx ;preserve C register variables
146 mov ebp, [_gr_var_bwidth]
148 ; We'll draw top to bottom, to reduce the number of cases we have to handle,
149 ; and to make lines between the same endpoints always draw the same pixels.
153 jle LineIsTopToBottom
154 xchg [YEnd], eax ;swap endpoints
162 ; Point EDI to the first pixel to draw.
164 mul edx ;[YStart] * ebp
167 add edi, [_gr_var_bitmap]
168 add edi, eax ;EDI = [YStart] * ebp + [XStart]
169 ; = offset of initial pixel
171 ; Figure out how far we're going vertically (guaranteed to be positive).
173 sub ecx, [YStart] ;ECX = YDelta
175 ; Figure out whether we're going left or right, and how far we're going
176 ; horizontally. In the process, special-case vertical lines, for speed and
177 ; to avoid nasty boundary conditions and division by 0.
181 jnz NotVerticalLine ;XDelta == 0 means vertical line
182 ;it is a vertical line
183 ;yes, special case vertical line
185 mov eax, [_gr_var_color]
193 ; Special-case code for horizontal lines.
196 mov eax, [_gr_var_color]
197 mov ah,al ;duplicate in high byte for word access
198 and ebx,ebx ;left to right?
200 sub edi, edx ;currently right to left, point to left end so we
201 ; can go left to right (avoids unpleasantness with
202 ; right to left REP STOSW)
205 inc ecx ;# of pixels to draw
207 shr ecx, 1 ;# of words to draw
208 rep stosw ;do as many words as possible
210 rep stosb ;do the odd byte, if there is one
214 ; Special-case code for diagonal lines.
217 mov eax, [_gr_var_color]
218 add ebx, ebp ;advance distance from one pixel to next
228 mov ebx,1 ;assume left to right, so [XAdvance] = 1
229 ;***leaves flags unchanged***
230 jns LeftToRight ;left to right, all set
231 neg ebx ;right to left, so [XAdvance] = -1
235 ; Special-case horizontal lines.
237 and ecx, ecx ;YDelta == 0?
238 jz IsHorizontalLine ;yes
240 ; Special-case diagonal lines.
241 cmp ecx, edx ;YDelta == XDelta?
242 jz IsDiagonalLine ;yes
244 ; Determine whether the line is X or Y major, and handle accordingly.
249 ; X-major (more horizontal than vertical) line.
252 and ebx,ebx ;left to right?
253 jns DFSet ;yes, CLD is already set
254 std ;right to left, so draw backwards
257 sub edx,edx ;prepare for division
258 div ecx ;EAX = XDelta/YDelta
259 ; (minimum # of pixels in a run in this line)
260 ;EDX = XDelta % YDelta
261 mov ebx,edx ;error term adjust each time Y steps by 1;
262 add ebx,ebx ; used to tell when one extra pixel should be
263 mov [AdjUp], ebx ; drawn as part of a run, to account for
264 ; fractional steps along the X axis per
265 ; 1-pixel steps along Y
266 mov esi, ecx ;error term adjust when the error term turns
267 add esi, esi ; over, used to factor out the X step made at
268 mov [AdjDown], esi ; that time
270 ; Initial error term; reflects an initial step of 0.5 along the Y axis.
271 sub edx, esi ;(XDelta % YDelta) - (YDelta * 2)
272 ;DX = initial error term
273 ; The initial and last runs are partial, because Y advances only 0.5 for
274 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
275 ; between the initial and last runs.
276 mov esi, ecx ;SI = YDelta
277 mov ecx, eax ;whole step (minimum run length)
279 inc ecx ;initial pixel count = (whole step / 2) + 1;
280 ; (may be adjusted later). This is also the
281 ; final run pixel count
282 push ecx ;remember final run pixel count for later
283 ; If the basic run length is even and there's no fractional advance, we have
284 ; one pixel that could go to either the initial or last partial run, which
285 ; we'll arbitrarily allocate to the last run.
286 ; If there is an odd number of pixels per run, we have one pixel that can't
287 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
288 ; the error term so this pixel will be handled by the normal full-run loop.
289 add edx,esi ;assume odd length, add YDelta to error term
290 ; (add 0.5 of a pixel to the error term)
291 test al,1 ;is run length even?
292 jnz XMajorAdjustDone ;no, already did work for odd case, all set
293 sub edx,esi ;length is even, undo odd stuff we just did
294 and ebx,ebx ;is the adjust up equal to 0?
295 jnz XMajorAdjustDone ;no (don't need to check for odd length,
296 ; because of the above test)
297 dec ecx ;both conditions met; make initial run 1
301 mov [WholeStep],eax ;whole step (minimum run length)
302 mov eax, [_gr_var_color] ;AL = drawing color
303 ; Draw the first, partial run of pixels.
304 rep stosb ;draw the final run
305 add edi,ebp ;advance along the minor axis (Y)
306 ; Draw all full runs.
307 cmp esi,1 ;are there more than 2 scans, so there are
308 ; some full runs? (SI = # scans - 1)
309 jna XMajorDrawLast ;no, no full runs
310 dec edx ;adjust error term by -1 so we can use
312 shr esi,1 ;convert from scan to scan-pair count
313 jnc XMajorFullRunsOddEntry ;if there is an odd number of scans,
314 ; do the odd scan now
316 mov ecx, [WholeStep] ;run is at least this long
317 add edx,ebx ;advance the error term and add an extra
318 jnc XMajorNoExtra ; pixel if the error term so indicates
319 inc ecx ;one extra pixel in run
320 sub edx,[AdjDown] ;reset the error term
322 rep stosb ;draw this scan line's run
323 add edi,ebp ;advance along the minor axis (Y)
324 XMajorFullRunsOddEntry: ;enter loop here if there is an odd number
326 mov ecx,[WholeStep] ;run is at least this long
327 add edx,ebx ;advance the error term and add an extra
328 jnc XMajorNoExtra2 ; pixel if the error term so indicates
329 inc ecx ;one extra pixel in run
330 sub edx,[AdjDown] ;reset the error term
332 rep stosb ;draw this scan line's run
333 add edi,ebp ;advance along the minor axis (Y)
336 jnz XMajorFullRunsLoop
337 ; Draw the final run of pixels.
339 pop ecx ;get back the final run pixel length
340 rep stosb ;draw the final run
342 cld ;restore normal direction flag
344 ; Y-major (more vertical than horizontal) line.
346 mov [XAdvance],ebx ;remember which way X advances
349 sub edx,edx ;prepare for division
350 div ecx ;EAX = YDelta/XDelta
351 ; (minimum # of pixels in a run in this line)
352 ;EDX = YDelta % XDelta
353 mov ebx,edx ;error term adjust each time X steps by 1;
354 add ebx,ebx ; used to tell when one extra pixel should be
355 mov [AdjUp],ebx ; drawn as part of a run, to account for
356 ; fractional steps along the Y axis per
357 ; 1-pixel steps along X
358 mov esi,ecx ;error term adjust when the error term turns
359 add esi,esi ; over, used to factor out the Y step made at
360 mov [AdjDown], esi ; that time
362 ; Initial error term; reflects an initial step of 0.5 along the X axis.
363 sub edx,esi ;(YDelta % XDelta) - (XDelta * 2)
364 ;DX = initial error term
365 ; The initial and last runs are partial, because X advances only 0.5 for
366 ; these runs, rather than 1. Divide one full run, plus the initial pixel,
367 ; between the initial and last runs.
368 mov esi,ecx ;SI = XDelta
369 mov ecx,eax ;whole step (minimum run length)
371 inc ecx ;initial pixel count = (whole step / 2) + 1;
372 ; (may be adjusted later)
373 push ecx ;remember final run pixel count for later
375 ; If the basic run length is even and there's no fractional advance, we have
376 ; one pixel that could go to either the initial or last partial run, which
377 ; we'll arbitrarily allocate to the last run.
378 ; If there is an odd number of pixels per run, we have one pixel that can't
379 ; be allocated to either the initial or last partial run, so we'll add 0.5 to
380 ; the error term so this pixel will be handled by the normal full-run loop.
381 add edx,esi ;assume odd length, add XDelta to error term
382 test al,1 ;is run length even?
383 jnz YMajorAdjustDone ;no, already did work for odd case, all set
384 sub edx,esi ;length is even, undo odd stuff we just did
385 and ebx,ebx ;is the adjust up equal to 0?
386 jnz YMajorAdjustDone ;no (don't need to check for odd length,
387 ; because of the above test)
388 dec ecx ;both conditions met; make initial run 1
391 mov [WholeStep],eax ;whole step (minimum run length)
392 mov eax,[_gr_var_color] ;AL = drawing color
393 mov ebx, [XAdvance] ;which way X advances
395 ; Draw the first, partial run of pixels.
397 mov [edi],al ;draw the pixel
398 add edi,ebp ;advance along the major axis (Y)
401 add edi,ebx ;advance along the minor axis (X)
402 ; Draw all full runs.
403 cmp esi,1 ;# of full runs. Are there more than 2
404 ; columns, so there are some full runs?
405 ; (SI = # columns - 1)
406 jna YMajorDrawLast ;no, no full runs
407 dec edx ;adjust error term by -1 so we can use
409 shr esi,1 ;convert from column to column-pair count
410 jnc YMajorFullRunsOddEntry ;if there is an odd number of
411 ; columns, do the odd column now
413 mov ecx,[WholeStep] ;run is at least this long
414 add edx,[AdjUp] ;advance the error term and add an extra
415 jnc YMajorNoExtra ; pixel if the error term so indicates
416 inc ecx ;one extra pixel in run
417 sub edx,[AdjDown] ;reset the error term
421 mov [edi],al ;draw the pixel
422 add edi,ebp ;advance along the major axis (Y)
425 add edi,ebx ;advance along the minor axis (X)
426 YMajorFullRunsOddEntry: ;enter loop here if there is an odd number
428 mov ecx,[WholeStep] ;run is at least this long
429 add edx,[AdjUp] ;advance the error term and add an extra
430 jnc YMajorNoExtra2 ; pixel if the error term so indicates
431 inc ecx ;one extra pixel in run
432 sub edx, [AdjDown] ;reset the error term
436 mov [edi],al ;draw the pixel
437 add edi,ebp ;advance along the major axis (Y)
440 add edi,ebx ;advance along the minor axis (X)
443 jnz YMajorFullRunsLoop
444 ; Draw the final run of pixels.
446 pop ecx ;get back the final run pixel length
448 mov [edi],al ;draw the pixel
449 add edi,ebp ;advance along the major axis (Y)
456 pop ebx;restore C register variables
459 global _gr_linear_stosd
460 global gr_linear_stosd
465 ; EAX -> Destination buffer
466 ; EDX -> Byte to store
467 ; EBX -> Number of bytes to move