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