This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / 2d / linear.asm
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.
11 ;
12 ; $Source: /cvs/cvsroot/d2x/2d/linear.asm,v $
13 ; $Revision: 1.1.1.1 $
14 ; $Author: bradleyb $
15 ; $Date: 2001-01-19 03:29:57 $
16 ;
17 ; Routines to access linear VGA memory
18 ;
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.
22 ;
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.
27
28 ; Revision 1.19  1994/11/27  22:57:56  john
29 ; Took out some code that was never called.
30
31 ; Revision 1.18  1994/09/12  14:40:16  john
32 ; Neatend.
33
34 ; Revision 1.17  1994/07/27  18:30:30  john
35 ; Took away the blending table.
36
37 ; Revision 1.16  1994/04/08  16:59:28  john
38 ; Add fading poly's; Made palette fade 32 instead of 16.
39
40 ; Revision 1.15  1993/12/21  20:10:03  john
41 ; *** empty log message ***
42
43 ; Revision 1.14  1993/12/21  19:58:31  john
44 ; added selector stuff
45
46 ; Revision 1.13  1993/12/21  11:40:51  john
47 ; *** empty log message ***
48
49 ; Revision 1.12  1993/12/09  15:01:52  john
50 ; Changed palette stuff majorly
51
52 ; Revision 1.11  1993/12/08  16:41:02  john
53 ; *** empty log message ***
54
55 ; Revision 1.10  1993/12/08  11:50:17  john
56 ; Fixed bug with gr_init
57
58 ; Revision 1.9  1993/12/07  12:32:12  john
59 ; moved bmd_palette to gr_palette
60
61 ; Revision 1.8  1993/12/03  12:11:25  john
62 ; *** empty log message ***
63
64 ; Revision 1.7  1993/11/16  11:29:08  john
65 ; *** empty log message ***
66
67 ; Revision 1.6  1993/10/15  16:22:13  john
68 ; *** empty log message ***
69
70 ; Revision 1.5  1993/09/29  16:15:28  john
71 ; added assembler linear_line
72
73 ; Revision 1.4  1993/09/26  18:59:27  john
74 ; fade stuff
75
76 ; Revision 1.3  1993/09/21  14:00:59  john
77 ; added code to save 43/50 line text modes.
78
79 ; Revision 1.2  1993/09/16  17:28:06  john
80 ; added code to save/restore video mode
81
82 ; Revision 1.1  1993/09/08  11:41:30  john
83 ; Initial revision
84
85 ;
86 ;
87
88
89 [BITS 32]
90
91 section .data
92                 ; Put data here
93 %ifdef __ENV_LINUX__
94 %define _gr_var_color gr_var_color
95 %define _gr_var_bitmap gr_var_bitmap
96 %define _gr_var_bwidth gr_var_bwidth
97 %endif
98                 
99                 global _gr_var_color
100                 global _gr_var_bitmap
101                 global _gr_var_bwidth
102                 _gr_var_color   dd  0
103                 _gr_var_bitmap  dd  0
104                 _gr_var_bwidth  dd  0
105
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
111                 XStart          dd  0
112                 YStart          dd  0
113                 XEnd            dd  0
114                 YEnd            dd  0
115
116 section .text
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.
120
121
122 global _gr_linear_line
123 global gr_linear_line
124 _gr_linear_line:
125 gr_linear_line:
126
127         cld
128
129         push    ebx  ;preserve C register variables
130         push    esi
131         push    edi
132         push    ebp
133
134         mov     eax,[esp+20]
135         mov     edx,[esp+24]
136         mov     ebx,[esp+28]
137         mov     ecx,[esp+32]
138         mov     [XStart], eax
139         mov     [YStart], edx
140         mov     [XEnd], ebx
141         mov     [YEnd], ecx
142
143         mov     ebp, [_gr_var_bwidth]
144
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.
147
148         mov     eax,[YStart]
149         cmp     eax,[YEnd]
150         jle     LineIsTopToBottom
151         xchg    [YEnd], eax    ;swap endpoints
152         mov     [YStart], eax
153         mov     ebx, [XStart]
154         xchg    [XEnd], ebx
155         mov     [XStart], ebx
156
157 LineIsTopToBottom:
158
159 ; Point EDI to the first pixel to draw.
160         mov     edx,ebp
161         mul     edx             ;[YStart] * ebp
162         mov     esi, [XStart]
163         mov     edi, esi
164         add     edi, [_gr_var_bitmap]
165         add     edi, eax        ;EDI = [YStart] * ebp + [XStart]
166                                                         ; = offset of initial pixel
167
168 ; Figure out how far we're going vertically (guaranteed to be positive).
169         mov     ecx, [YEnd]
170         sub     ecx, [YStart]     ;ECX = YDelta
171
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.
175
176         mov     edx, [XEnd]
177         sub     edx, esi        ;XDelta
178         jnz     NotVerticalLine ;XDelta == 0 means vertical line
179                                                         ;it is a vertical line
180                                                         ;yes, special case vertical line
181
182         mov     eax, [_gr_var_color]
183 VLoop:
184         mov     [edi],al
185         add     edi,ebp
186         dec     ecx
187         jns     VLoop
188         jmp     Done
189
190 ; Special-case code for horizontal lines.
191
192 IsHorizontalLine:
193         mov     eax, [_gr_var_color]
194         mov     ah,al           ;duplicate in high byte for word access
195         and     ebx,ebx         ;left to right?
196         jns     DirSet          ;yes
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)
200 DirSet:
201         mov     ecx, edx
202         inc     ecx             ;# of pixels to draw
203
204         shr     ecx, 1          ;# of words to draw
205         rep     stosw           ;do as many words as possible
206         adc     ecx, ecx
207         rep     stosb           ;do the odd byte, if there is one
208
209         jmp     Done
210
211 ; Special-case code for diagonal lines.
212
213 IsDiagonalLine:
214         mov     eax, [_gr_var_color]
215         add     ebx, ebp    ;advance distance from one pixel to next
216
217 DLoop:
218         mov     [edi],al
219         add     edi, ebx
220         dec     ecx
221         jns     DLoop
222         jmp     Done
223
224 NotVerticalLine:
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
229         neg     edx                 ;|XDelta|
230
231 LeftToRight:
232 ; Special-case horizontal lines.
233
234         and     ecx, ecx            ;YDelta == 0?
235         jz      IsHorizontalLine    ;yes
236
237 ; Special-case diagonal lines.
238         cmp     ecx, edx            ;YDelta == XDelta?
239         jz      IsDiagonalLine      ;yes
240
241 ; Determine whether the line is X or Y major, and handle accordingly.
242         cmp     edx, ecx
243         jae     XMajor
244         jmp     YMajor
245
246 ; X-major (more horizontal than vertical) line.
247
248 XMajor:
249                 and     ebx,ebx         ;left to right?
250                 jns     DFSet           ;yes, CLD is already set
251         std                     ;right to left, so draw backwards
252 DFSet:
253                 mov     eax,edx         ;XDelta
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
266
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)
275                 shr     ecx,1
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
295                                 ; shorter
296
297 XMajorAdjustDone:
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
308                                 ; carry test
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
312 XMajorFullRunsLoop:
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
318 XMajorNoExtra:
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
322                                 ; of full runs
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
328 XMajorNoExtra2:
329                 rep     stosb           ;draw this scan line's run
330                 add     edi,ebp ;advance along the minor axis (Y)
331
332                 dec     esi
333         jnz     XMajorFullRunsLoop
334 ; Draw the final run of pixels.
335 XMajorDrawLast:
336                 pop     ecx             ;get back the final run pixel length
337         rep     stosb           ;draw the final run
338
339         cld                     ;restore normal direction flag
340         jmp     Done
341 ; Y-major (more vertical than horizontal) line.
342 YMajor:
343                 mov     [XAdvance],ebx    ;remember which way X advances
344                 mov     eax,ecx         ;YDelta
345                 mov     ecx,edx         ;XDelta
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
358
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)
367                 shr     ecx,1
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
371
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
386                                 ; shorter
387 YMajorAdjustDone:
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
391
392 ; Draw the first, partial run of pixels.
393 YMajorFirstLoop:
394                 mov     [edi],al        ;draw the pixel
395                 add     edi,ebp ;advance along the major axis (Y)
396                 dec     ecx
397         jnz     YMajorFirstLoop
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
405                                 ; carry test
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
409 YMajorFullRunsLoop:
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
415 YMajorNoExtra:
416                                 ;draw the run
417 YMajorRunLoop:
418                 mov     [edi],al        ;draw the pixel
419                 add     edi,ebp ;advance along the major axis (Y)
420                 dec     ecx
421         jnz     YMajorRunLoop
422                 add     edi,ebx         ;advance along the minor axis (X)
423 YMajorFullRunsOddEntry:         ;enter loop here if there is an odd number
424                                 ; of full runs
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
430 YMajorNoExtra2:
431                                 ;draw the run
432 YMajorRunLoop2:
433                 mov     [edi],al         ;draw the pixel
434                 add     edi,ebp ;advance along the major axis (Y)
435                 dec     ecx
436         jnz     YMajorRunLoop2
437                 add     edi,ebx           ;advance along the minor axis (X)
438
439                 dec     esi
440         jnz     YMajorFullRunsLoop
441 ; Draw the final run of pixels.
442 YMajorDrawLast:
443                 pop     ecx              ;get back the final run pixel length
444 YMajorLastLoop:
445                 mov     [edi],al         ;draw the pixel
446                 add     edi,ebp ;advance along the major axis (Y)
447                 dec     ecx
448         jnz     YMajorLastLoop
449 Done:
450         pop ebp
451         pop edi
452         pop esi
453         pop ebx;restore C register variables
454     ret
455
456 global _gr_linear_stosd
457 global gr_linear_stosd
458
459 _gr_linear_stosd:
460 gr_linear_stosd:
461
462                         ; EAX -> Destination buffer
463                         ; EDX -> Byte to store
464                         ; EBX -> Number of bytes to move
465
466                         push    ebx
467                         push    edi
468                         mov     eax,[esp+12]
469                         mov     edx,[esp+16]
470                         mov     ebx,[esp+20]
471                         mov     edi, eax
472                         mov     dh, dl
473                         mov     ax, dx
474                         shl     eax, 16
475                         mov     ax, dx
476                         cld
477                         mov     ecx, ebx
478                         shr     ecx, 2
479                         rep     stosd
480                         mov     ecx, ebx
481                         and     ecx, 011b
482                         rep     stosb
483                         pop     edi
484                         pop     ebx
485                         ret