]> 4ch.mooo.com Git - 16.git/blob - 16/xw/mxln.asm
more
[16.git] / 16 / xw / mxln.asm
1 ;-----------------------------------------------------------\r
2 ;\r
3 ; MXLN.ASM - Line function\r
4 ; Copyright (c) 1993,1994 by Alessandro Scotti\r
5 ;\r
6 ;-----------------------------------------------------------\r
7 WARN    PRO\r
8 NOWARN  RES\r
9 INCLUDE MODEX.DEF\r
10 \r
11 PUBLIC  mxLine\r
12 \r
13 MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
14         ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
15 \r
16 EXTRN   mx_BytesPerLine : WORD\r
17 EXTRN   mx_VideoSegment : WORD\r
18 \r
19 EXTRN   mx_ClipX1       : WORD\r
20 EXTRN   mx_ClipY1       : WORD\r
21 EXTRN   mx_ClipX2       : WORD\r
22 EXTRN   mx_ClipY2       : WORD\r
23 \r
24 tblDrawFunc     LABEL   WORD\r
25         DW      subWidthMove\r
26         DW      subHeightMove\r
27         DW      subWidthOp\r
28         DW      subHeightOp\r
29 \r
30 ;-----------------------------------------------------------\r
31 ;\r
32 ; Draws a line from (X1,Y1) to (X2,Y2) using the Bresenham\r
33 ; algorithm.\r
34 ;\r
35 ; Input:\r
36 ;       X1, Y1  = start point\r
37 ;       X2, Y2  = end point\r
38 ;       Color   = line color\r
39 ;       Op      = raster operator\r
40 ; Output:\r
41 ;       none\r
42 ;\r
43 ; Note: the end point (X2,Y2) *IS* drawed. I don't like this very much\r
44 ; but clipping is much simpler.\r
45 ;\r
46 mxLine  PROC FAR\r
47         ARG     Op:WORD,        \\r
48                 Color:WORD,     \\r
49                 Y2:WORD,        \\r
50                 X2:WORD,        \\r
51                 Y1:WORD,        \\r
52                 X1:WORD         = ARG_SIZE\r
53         LOCAL   Width:WORD,     \\r
54                 Height:WORD,    \\r
55                 ErrorAdd:WORD,  \\r
56                 ErrorSub:WORD,  \\r
57                 DeltaX:WORD,    \\r
58                 DeltaY:WORD,    \\r
59                 P1:BYTE,        \\r
60                 P2:BYTE,        \\r
61                 WritePlane:BYTE = AUTO_SIZE\r
62         .enter  AUTO_SIZE\r
63         .push   ds, si, di\r
64         ASSUME  ds:NOTHING\r
65 \r
66         mov     ax, [X1]\r
67         mov     bx, [Y1]\r
68         mov     cx, [X2]\r
69         mov     dx, [Y2]\r
70         call    subClipLine\r
71         jc      @@Exit                  ; Line is full clipped\r
72 \r
73 ; Get width\r
74         mov     si, cx\r
75         xchg    ax, si                  ; SI = X1, AX = X2\r
76         sub     ax, si\r
77         jge     @@1\r
78 ; Swap points, we want X1 < X2\r
79         xchg    si, cx                  ; Swap X1 and X2\r
80         xchg    bx, dx                  ; Swap Y1 and Y2\r
81         neg     ax\r
82 @@1:\r
83         mov     [Width], ax\r
84 \r
85 ; Get height\r
86         mov     cx, [mx_BytesPerLine]   ; We don't need X2 anymore\r
87         mov     ax, dx\r
88         sub     ax, bx\r
89         jge     @@2\r
90         neg     cx                      ; Move from bottom to top\r
91         neg     ax                      ; Get absolute value of AX\r
92 @@2:\r
93         mov     [Height], ax\r
94         mov     [DeltaY], cx\r
95 \r
96 ; Get pixel address and write plane\r
97         mov     ax, bx\r
98         mul     [mx_BytesPerLine]\r
99         mov     cx, si                  ; CX = X1\r
100         shr     si, 1\r
101         shr     si, 1\r
102         add     si, ax                  ; SI = pixel offset\r
103         and     cl, 03h\r
104         mov     ax, 1102h\r
105         shl     ah, cl\r
106         mov     [WritePlane], ah\r
107         mov     dx, TS\r
108         out     dx, ax                  ; Set write plane\r
109         mov     ax, [mx_VideoSegment]\r
110         mov     ds, ax                  ; DS:SI points to (X1,Y1)\r
111 \r
112 ; Select the function to handle the drawing loop\r
113         xor     bx, bx\r
114         mov     al, BYTE PTR [Op]\r
115         cmp     al, OP_MOVE\r
116         je      @@3\r
117         and     al, 03h\r
118         shl     al, 1\r
119         shl     al, 1\r
120         shl     al, 1\r
121         mov     ah, al\r
122         mov     al, 03h\r
123         mov     dx, GDC\r
124         out     dx, ax                  ; Set logical function\r
125         inc     bx\r
126         inc     bx\r
127 @@3:\r
128         mov     ax, [Width]\r
129         mov     cx, [Height]\r
130 ; Horizontal, vertical and diagonal lines are not optimized yet\r
131         cmp     ax, cx\r
132         jae     @@4\r
133         inc     bx\r
134 @@4:\r
135         shl     bx, 1\r
136         call    tblDrawFunc[bx]\r
137 \r
138 ; Reset logical function if needed\r
139         cmp     BYTE PTR [Op], OP_MOVE\r
140         je      @@Exit\r
141         mov     ax, 0003h\r
142         mov     dx, GDC\r
143         out     dx, ax\r
144 \r
145 @@Exit:\r
146         xor     ax, ax\r
147         .pop    ds, si, di\r
148         .leave  ARG_SIZE\r
149 \r
150 ;-----------------------------------------------------------\r
151 ;\r
152 ; Checks the coordinates of a line against the active\r
153 ; clip region.\r
154 ; Uses a variation of the Cohen-Sutherland algorithm developed\r
155 ; by Victor Duvanenko.\r
156 ;\r
157 ; Input:\r
158 ;       AX, BX  = X1, Y1\r
159 ;       CX, DX  = X2, Y2\r
160 ; Output:\r
161 ;       CF      = set if line is full clipped\r
162 ;       AX, BX  = clipped X1, Y1\r
163 ;       CX, DX  = clipped X2, Y2\r
164 ; Note:\r
165 ;       destroys SI, DI\r
166 ;\r
167 subClipLine     PROC    NEAR\r
168         mov     di, ax                  ; Copy X1 to DI and free AX\r
169         mov     si, dx                  ; Copy Y2 to SI and free DX\r
170 ; Compute clip codes for point (X2,Y2)=(CX,SI)\r
171         xor     al, al\r
172 @@P2X1: cmp     cx, [mx_ClipX1]\r
173         jge     @@P2X2\r
174         or      al, 1\r
175 @@P2X2: cmp     cx, [mx_ClipX2]\r
176         jle     @@P2Y1\r
177         or      al, 2\r
178 @@P2Y1: cmp     si, [mx_ClipY1]\r
179         jge     @@P2Y2\r
180         or      al, 4\r
181 @@P2Y2: cmp     si, [mx_ClipY2]\r
182         jle     @@P2XY\r
183         or      al, 8\r
184 @@P2XY: mov     [P2], al\r
185 ; Compute clip codes for point (X1,Y1)=(DI,BX)\r
186         xor     al, al\r
187 @@P1X1: cmp     di, [mx_ClipX1]\r
188         jge     @@P1X2\r
189         or      al, 1\r
190 @@P1X2: cmp     di, [mx_ClipX2]\r
191         jle     @@P1Y1\r
192         or      al, 2\r
193 @@P1Y1: cmp     bx, [mx_ClipY1]\r
194         jge     @@P1Y2\r
195         or      al, 4\r
196 @@P1Y2: cmp     bx, [mx_ClipY2]\r
197         jle     @@P1XY\r
198         or      al, 8\r
199 @@P1XY: mov     [P1], al\r
200 ; Check codes for trivial cases\r
201         mov     ah, [P2]\r
202         test    al, ah                  ; Is line invisible?\r
203         jnz     @@FullClip              ; Yes, exit\r
204         or      ah, al                  ; Both points clipped?\r
205         jz      @@Done                  ; Yes, exit\r
206 ; Calculate deltas\r
207         mov     ax, cx\r
208         sub     ax, di\r
209         mov     [DeltaX], ax\r
210         mov     ax, si\r
211         sub     ax, bx\r
212         mov     [DeltaY], ax\r
213         mov     al, [P1]                ; Init clipping code\r
214 ; Clipping loop\r
215 @@ClipLoop:\r
216         test    al, al                  ; Is first point clipped?\r
217         jnz     @@ClipX1                ; No, continue\r
218         xchg    cx, di                  ; Swap points...\r
219         xchg    bx, si\r
220         xchg    al, [P2]                ; ...and codes\r
221 ; Clip left: Y1 = Y1 + DeltaY*(mx_ClipX1-X1)/DeltaX\r
222 @@ClipX1:\r
223         test    al, 1\r
224         jz      @@ClipX2\r
225         mov     ax, [mx_ClipX1]\r
226         sub     ax, di\r
227         mov     di, [mx_ClipX1]\r
228         jmp     @@ClipX1X2\r
229 ; Clip right: Y1 = Y1 + DeltaY*(mx_ClipX2-X1)/DeltaX\r
230 @@ClipX2:\r
231         test    al, 2\r
232         jz      @@ClipY1\r
233         mov     ax, [mx_ClipX2]\r
234         sub     ax, di\r
235         mov     di, [mx_ClipX2]\r
236 @@ClipX1X2:\r
237         imul    [DeltaY]\r
238         idiv    [DeltaX]\r
239         add     bx, ax\r
240         mov     al, 8\r
241         cmp     bx, [mx_ClipY2]\r
242         jg      @@CheckLoop\r
243         mov     al, 4\r
244         cmp     bx, [mx_ClipY1]\r
245         jl      @@CheckLoop\r
246         xor     al, al\r
247         jmp     @@CheckLoop\r
248 ; Clip top: X1 = X1 + DeltaX*(mx_ClipY1-Y1)/DeltaY\r
249 @@ClipY1:\r
250         test    al, 4\r
251         jz      @@ClipY2\r
252         mov     ax, [mx_ClipY1]\r
253         sub     ax, bx\r
254         mov     bx, [mx_ClipY1]\r
255         jmp     @@ClipY1Y2\r
256 ; Clip bottom: X1 = X1 + DeltaX*(mx_ClipY2-Y1)/DeltaY\r
257 @@ClipY2:\r
258         mov     ax, [mx_ClipY2]\r
259         sub     ax, bx\r
260         mov     bx, [mx_ClipY2]\r
261 @@ClipY1Y2:\r
262         imul    [DeltaX]\r
263         idiv    [DeltaY]\r
264         add     di, ax\r
265         mov     al, 1\r
266         cmp     di, [mx_ClipX1]\r
267         jl      @@CheckLoop\r
268         mov     al, 2\r
269         cmp     di, [mx_ClipX2]\r
270         jg      @@CheckLoop\r
271         xor     al, al\r
272 @@CheckLoop:\r
273         mov     ah, [P2]\r
274         test    al, ah\r
275         jnz     @@FullClip\r
276         or      ah, al\r
277         jnz     @@ClipLoop\r
278 \r
279 @@Done:\r
280         mov     ax, di\r
281         mov     dx, si\r
282         clc\r
283         ret\r
284 @@FullClip:\r
285         stc\r
286         ret\r
287 subClipLine     ENDP\r
288 \r
289 ; Called when Width >= Height and Op = OP_MOVE\r
290 subWidthMove    PROC NEAR\r
291         mov     di, ax\r
292         neg     di                      ; Initialize error term\r
293         shl     cx, 1\r
294         mov     [ErrorAdd], cx\r
295         mov     cx, ax\r
296         shl     ax, 1\r
297         mov     [ErrorSub], ax\r
298         mov     al, 02h\r
299         mov     ah, [WritePlane]\r
300         mov     bl, BYTE PTR [Color]\r
301         mov     dx, TS\r
302         inc     cx\r
303 @@Loop:\r
304         mov     ds:[si], bl\r
305         dec     cx\r
306         jz      @@Exit\r
307         rol     ah, 1\r
308         adc     si, 0\r
309         out     dx, ax\r
310         add     di, [ErrorAdd]\r
311         jl      @@Loop\r
312         add     si, [DeltaY]\r
313         sub     di, [ErrorSub]\r
314         jmp     @@Loop\r
315 @@Exit:\r
316         ret\r
317 subWidthMove    ENDP\r
318 \r
319 ; Called when Width < Height and Op = OP_MOVE\r
320 subHeightMove   PROC NEAR\r
321         mov     di, cx\r
322         neg     di                      ; Initialize error term\r
323         shl     ax, 1\r
324         mov     [ErrorAdd], ax\r
325         mov     ax, cx\r
326         shl     ax, 1\r
327         mov     [ErrorSub], ax\r
328         mov     bl, BYTE PTR [Color]\r
329         mov     ah, [WritePlane]\r
330         mov     al, 02h\r
331         mov     dx, TS\r
332         inc     cx\r
333 @@Loop:\r
334         mov     ds:[si], bl\r
335         dec     cx\r
336         jz      @@Exit\r
337         add     si, [DeltaY]\r
338         add     di, [ErrorAdd]\r
339         jl      @@Loop\r
340         rol     ah, 1                   ; Next write plane\r
341         adc     si, 0                   ; Bump video offset if plane overflows\r
342         out     dx, ax\r
343         sub     di, [ErrorSub]          ; Adjust error down\r
344         jmp     @@Loop\r
345 @@Exit:\r
346         ret\r
347 subHeightMove   ENDP\r
348 \r
349 ; Called when Width >= Height and Op <> OP_MOVE\r
350 subWidthOp      PROC NEAR\r
351         mov     di, ax\r
352         neg     di                      ; Initialize error term\r
353         shl     cx, 1\r
354         mov     [ErrorAdd], cx\r
355         mov     cx, ax\r
356         shl     ax, 1\r
357         mov     [ErrorSub], ax\r
358         mov     al, 02h\r
359         mov     ah, [WritePlane]\r
360         mov     bl, BYTE PTR [Color]\r
361         mov     dx, TS\r
362         inc     cx\r
363 @@Loop:\r
364         mov     bh, ds:[si]             ; Latch data\r
365         mov     ds:[si], bl\r
366         dec     cx\r
367         jz      @@Exit\r
368         rol     ah, 1\r
369         adc     si, 0\r
370         out     dx, ax\r
371         add     di, [ErrorAdd]\r
372         jl      @@Loop\r
373         add     si, [DeltaY]\r
374         sub     di, [ErrorSub]\r
375         jmp     @@Loop\r
376 @@Exit:\r
377         ret\r
378 subWidthOp      ENDP\r
379 \r
380 ; Called when Width < Height and Op <> OP_MOVE\r
381 subHeightOp     PROC NEAR\r
382         mov     di, cx\r
383         neg     di                      ; Initialize error term\r
384         shl     ax, 1\r
385         mov     [ErrorAdd], ax\r
386         mov     ax, cx\r
387         shl     ax, 1\r
388         mov     [ErrorSub], ax\r
389         mov     bl, BYTE PTR [Color]\r
390         mov     ah, [WritePlane]\r
391         mov     al, 02h\r
392         mov     dx, TS\r
393         inc     cx\r
394 @@Loop:\r
395         mov     bh, ds:[si]\r
396         mov     ds:[si], bl\r
397         dec     cx\r
398         jz      @@Exit\r
399         add     si, [DeltaY]\r
400         add     di, [ErrorAdd]\r
401         jl      @@Loop\r
402         rol     ah, 1                   ; Next write plane\r
403         adc     si, 0                   ; Bump video offset if plane overflows\r
404         out     dx, ax\r
405         sub     di, [ErrorSub]          ; Adjust error down\r
406         jmp     @@Loop\r
407 @@Exit:\r
408         ret\r
409 subHeightOp     ENDP\r
410 \r
411 mxLine  ENDP\r
412 \r
413 MX_TEXT         ENDS\r
414 END\r