]> 4ch.mooo.com Git - 16.git/blob - 16/xw/mxpf.asm
wwww
[16.git] / 16 / xw / mxpf.asm
1 ;-----------------------------------------------------------\r
2 ;\r
3 ; MXPG.ASM - Convex polygon fill\r
4 ; Copyright (c) 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  mxFillPoly\r
12 \r
13 ;-----------------------------------------------------------\r
14 ;\r
15 ; "Local" definitions\r
16 ;\r
17 TPOINT  STRUC\r
18         X       DW      ?\r
19         Y       DW      ?\r
20 TPOINT  ENDS\r
21 \r
22 ; Do NOT change order!\r
23 TSCAN   STRUC\r
24         Y1      DW      ?\r
25         Y2      DW      ?\r
26 TSCAN   ENDS\r
27 \r
28 MAXSCANCOLUMNS  EQU     POLYSCANBUFSIZE / SIZE TSCAN\r
29 \r
30 MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'\r
31                 ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
32 \r
33 EXTRN   mx_VideoSegment : WORD\r
34 EXTRN   mx_CodeSegment  : WORD\r
35 EXTRN   mx_BytesPerLine : WORD\r
36 EXTRN   mx_ClipX1       : WORD\r
37 EXTRN   mx_ClipY1       : WORD\r
38 EXTRN   mx_ClipX2       : WORD\r
39 EXTRN   mx_ClipY2       : WORD\r
40 EXTRN   mx_ScanBuffer   : NEAR\r
41 \r
42 ;-----------------------------------------------------------\r
43 ;\r
44 ; Scans an edge using the DDA (digital differential analyzer) algorithm.\r
45 ;\r
46 ; Input:\r
47 ;       DS:BX   = pointer to start point (X1, Y1)\r
48 ;       DS:SI   = pointer to end point (X2, Y2)\r
49 ;       ES:DI   = pointer to edge buffer\r
50 ; Output:\r
51 ;       ES:DI   = updated pointer to edge buffer\r
52 ; Notes:\r
53 ;       must preserve DS:SI.\r
54 ;\r
55 subScan         PROC NEAR\r
56         mov     cx, ds:[si].X\r
57         sub     cx, ds:[bx].X           ; Get width\r
58         jg      @@1\r
59         ret\r
60 @@1:\r
61         push    bp                      ; Save BP\r
62 \r
63         mov     ax, ds:[si].Y\r
64         mov     bx, ds:[bx].Y\r
65         sub     ax, bx                  ; Get height\r
66         jg      @@T2B                   ; Scan top to bottom\r
67         jl      @@B2T                   ; Scan bottom to top\r
68 \r
69 ; Special case: vertical line\r
70         mov     ax, bx\r
71 @@V:\r
72         mov     es:[di].Y1, ax\r
73         add     di, SIZE TSCAN\r
74         dec     cx\r
75         jnz     @@V\r
76         jmp     @@Exit\r
77 \r
78 ; Scan top to bottom\r
79 @@T2B:\r
80         cwd\r
81         div     cx\r
82         mov     bp, ax\r
83         xor     ax, ax\r
84         div     cx\r
85         xchg    ax, bx                  ; BP:BX = fixed 16:16 step\r
86         mov     dx, 8000h\r
87 @@T2BLoop:\r
88         mov     es:[di].Y1, ax\r
89         add     di, SIZE TSCAN\r
90         add     dx, bx\r
91         adc     ax, bp\r
92         dec     cx\r
93         jnz     @@T2BLoop\r
94         jmp     @@Exit\r
95 \r
96 ; Scan bottom to top\r
97 @@B2T:\r
98         neg     ax\r
99         cwd\r
100         div     cx\r
101         mov     bp, ax\r
102         xor     ax, ax\r
103         div     cx\r
104         xchg    ax, bx\r
105         mov     dx, 8000h\r
106 @@B2TLoop:\r
107         mov     es:[di].Y1, ax\r
108         add     di, SIZE TSCAN\r
109         sub     dx, bx\r
110         sbb     ax, bp\r
111         dec     cx\r
112         jnz     @@B2TLoop\r
113 \r
114 @@Exit:\r
115         pop     bp                      ; Restore BP\r
116         ret\r
117 subScan         ENDP\r
118 \r
119 ;-----------------------------------------------------------\r
120 ;\r
121 ; Fills a convex polygon with the specified color.\r
122 ;\r
123 ; Input:\r
124 ;       Count   = number of vertexes\r
125 ;       Map     = indexes of points and colors (integer)\r
126 ;       Points  = array of points (integer X, Y coordinates)\r
127 ;       Color   = base color\r
128 ; Output:\r
129 ;       none\r
130 ; Notes:\r
131 ;       vertexes must be in counterclockwise order, arrays are 0-based.\r
132 ;\r
133 mxFillPoly      PROC FAR\r
134         ARG     Color:WORD,     \\r
135                 Points:DWORD,   \\r
136                 Map:DWORD,      \\r
137                 Count:WORD      = ARG_SIZE\r
138         LOCAL   WritePlane:BYTE:2,      \\r
139                 ScanOffsetT:WORD,       \\r
140                 ScanOffsetB:WORD,       \\r
141                 ScanCount:WORD,         \\r
142                 Holder:WORD,            \\r
143                 Height:WORD,            \\r
144                 MinIdxT:WORD,           \\r
145                 MinIdxB:WORD,           \\r
146                 MaxIdx:WORD,            \\r
147                 Width:WORD,             \\r
148                 BoxX1:WORD,             \\r
149                 BoxY1:WORD,             \\r
150                 BoxX2:WORD,             \\r
151                 BoxY2::WORD             = AUTO_SIZE\r
152         .enter  AUTO_SIZE\r
153         .push   ds, si, es, di\r
154         ASSUME  ds:NOTHING\r
155 \r
156 ; Check that at least three vertexes are specified\r
157         mov     cx, [Count]\r
158         cmp     cx, 3\r
159         jb      @@Exit\r
160 \r
161 ;------------------------------\r
162 ; Find bounding box for polygon\r
163         les     di, [Map]\r
164         lds     si, [Points]            ; Pointer to vertex array\r
165         mov     [BoxX1], 32767\r
166         mov     [BoxX2], -32768\r
167         mov     [BoxY1], 32767\r
168         mov     [BoxY2], -32768\r
169 \r
170         xor     dx, dx\r
171 @@MinMaxLoop:\r
172         mov     bx, es:[di]             ; Get index of vertex\r
173         .shl    bx, 2                   ; Get offset in point array\r
174         add     bx, si\r
175 \r
176 ; Check X range\r
177 @@CheckMinX:\r
178         mov     ax, ds:[bx].X           ; Get X coordinate\r
179         cmp     ax, [BoxX1]\r
180         jge     @@CheckMaxX\r
181         mov     [BoxX1], ax\r
182         mov     [MinIdxT], dx\r
183         mov     [MinIdxB], dx\r
184 @@CheckMaxX:\r
185         cmp     ax, [BoxX2]\r
186         jle     @@CheckMinY\r
187         mov     [BoxX2], ax\r
188         mov     [MaxIdx], dx\r
189 \r
190 ; Check Y range\r
191 @@CheckMinY:\r
192         mov     ax, ds:[bx].Y\r
193         cmp     ax, [BoxY1]\r
194         jge     @@CheckMaxY\r
195         mov     [BoxY1], ax\r
196 @@CheckMaxY:\r
197         cmp     ax, [BoxY2]\r
198         jle     @@CheckDone\r
199         mov     [BoxY2], ax\r
200 \r
201 ; Repeat thru all points\r
202 @@CheckDone:\r
203         inc     di                      ; Next map entry\r
204         inc     dx\r
205         inc     di\r
206         inc     dx\r
207         dec     cx\r
208         jnz     @@MinMaxLoop\r
209 \r
210 ;---------------------------------\r
211 ; Check if polygon is full clipped\r
212         mov     ax, [BoxX2]\r
213         cmp     ax, [mx_ClipX1]         ; Is poly full clipped?\r
214         jl      @@Exit\r
215         mov     bx, [BoxX1]\r
216         cmp     bx, [mx_ClipX2]         ; Is poly full clipped?\r
217         jg      @@Exit\r
218         sub     ax, bx                  ; Get width\r
219         jle     @@Exit                  ; Exit if not positive\r
220         mov     ax, [BoxY2]\r
221         cmp     ax, [mx_ClipY1]         ; Is poly full clipped?\r
222         jl      @@Exit\r
223         mov     bx, [BoxY1]\r
224         cmp     bx, [mx_ClipY2]         ; Is poly full clipped?\r
225         jg      @@Exit\r
226         sub     ax, bx                  ; Get height\r
227         jle     @@Exit                  ; Exit if not positive\r
228 \r
229         dec     [Count]\r
230         shl     [Count], 1              ; We'll work with word offsets\r
231         mov     es, [mx_CodeSegment]\r
232 \r
233 ;--------------\r
234 ; Scan top edge\r
235         mov     ax, OFFSET mx_ScanBuffer\r
236         mov     [ScanOffsetT], ax\r
237         mov     si, [MinIdxT]           ; Offset of bottom point index\r
238 @@STLoop:\r
239         lds     bx, [Map]               ; DS:BX -> map table\r
240         mov     di, ds:[bx+si]          ; Index of top point #1\r
241         dec     si                      ; Next point\r
242         dec     si\r
243         test    si, si\r
244         jnl     @@ST1\r
245         mov     si, [Count]\r
246 @@ST1:\r
247         mov     [MinIdxT], si           ; Save new index of top point\r
248         mov     si, ds:[bx+si]          ; Get index of top point #2\r
249         .shl    di, 2                   ; Convert indexes to offsets\r
250         .shl    si, 2\r
251         lds     bx, [Points]            ; DS:BX -> point array\r
252         add     si, bx                  ; DS:SI -> top point #2\r
253         add     bx, di                  ; DS:BX -> top point #1\r
254         mov     di, [ScanOffsetT]\r
255         call    subScan                 ; Scan edge\r
256         mov     [ScanOffsetT], di\r
257         mov     si, [MinIdxT]\r
258         cmp     si, [MaxIdx]            ; End of edge?\r
259         jne     @@STLoop                ; No, continue\r
260 \r
261 ;-----------------\r
262 ; Scan bottom edge\r
263         mov     ax, OFFSET mx_ScanBuffer + OFFSET Y2\r
264         mov     [ScanOffsetB], ax\r
265         mov     si, [MinIdxB]           ; Offset of bottom point index\r
266 @@SBLoop:\r
267         lds     bx, [Map]               ; DS:BX -> map table\r
268         mov     di, ds:[bx+si]          ; Index of bottom point #1\r
269         inc     si                      ; Next bottom point\r
270         inc     si\r
271         cmp     si, [Count]\r
272         jbe     @@SB1\r
273         xor     si, si\r
274 @@SB1:\r
275         mov     [MinIdxB], si           ; Save new index of bottom point\r
276         mov     si, ds:[bx+si]          ; Get index of bottom point #2\r
277         .shl    di, 2                   ; Convert indexes to offsets\r
278         .shl    si, 2\r
279         lds     bx, [Points]            ; DS:BX -> point array\r
280         add     si, bx                  ; DS:SI -> top point #2\r
281         add     bx, di                  ; DS:BX -> top point #1\r
282         mov     di, [ScanOffsetB]\r
283         call    subScan                 ; Scan edge\r
284         mov     [ScanOffsetB], di\r
285         mov     si, [MinIdxB]\r
286         cmp     si, [MaxIdx]            ; End of edge?\r
287         jne     @@SBLoop                ; No, continue\r
288 \r
289 ;--------------------\r
290 ; Clip left and right\r
291         mov     si, OFFSET mx_ScanBuffer\r
292         mov     ax, [BoxX1]\r
293         mov     cx, [BoxX2]\r
294         sub     cx, ax                  ; CX = bounding box width\r
295         mov     bx, [mx_ClipX1]\r
296         sub     bx, ax\r
297         jle     @@ClipL1                ; No need to clip left\r
298         sub     cx, bx                  ; Update width\r
299         add     ax, bx                  ; BoxX1 = mx_ClipX1\r
300         mov     [BoxX1], ax\r
301         .shl    bx, 2                   ; Warning!!! This is an hand-coded\r
302         add     si, bx                  ; multiply by the size of TSCAN\r
303 @@ClipL1:\r
304         mov     bx, ax\r
305         add     bx, cx                  ; Last scan column\r
306         sub     bx, [mx_ClipX2]\r
307         jle     @@ClipL2                ; No need to clip right\r
308         sub     cx, bx                  ; Clip right\r
309 @@ClipL2:\r
310         test    cx, cx                  ; Is clipped width positive?\r
311         jle     @@Exit                  ; No, exit\r
312         mov     [ScanCount], cx         ; Save number of columns to draw\r
313         mov     [ScanOffsetT], si       ; Remember offset of (clipped) buffer\r
314         mov     ds, [mx_CodeSegment]    ; DS:SI -> scan buffer\r
315 \r
316 ;------------------------------\r
317 ; Check if Y clipping is needed\r
318         mov     ax, [BoxY1]\r
319         cmp     ax, [mx_ClipY1]\r
320         jl      @@ClipTB                ; Need to clip top\r
321         mov     ax, [BoxY2]\r
322         cmp     ax, [mx_ClipY2]\r
323         jg      @@ClipTB                ; Need to clip bottom\r
324         jmp     @@ClipYExit             ; Skip Y clipping\r
325 \r
326 ;--------------------\r
327 ; Clip top and bottom\r
328 @@ClipTB:\r
329         mov     di, cx                  ; DI = scan count\r
330         inc     di                      ; Increment count for pre-loop test\r
331         sub     si, SIZE TSCAN\r
332 @@ClipYLoop:\r
333         dec     di                      ; Any column left?\r
334         jz      @@ClipYExit             ; No, exit\r
335         add     si, SIZE TSCAN\r
336         mov     ax, ds:[si].Y1          ; Y1\r
337         mov     cx, ds:[si].Y2          ; Y2\r
338         mov     dx, [mx_ClipY2]\r
339         cmp     ax, dx                  ; Full clipped?\r
340         jg      @@ClipYClip             ; Yes, skip this column\r
341         cmp     cx, dx                  ; Need to clip bottom?\r
342         jle     @@ClipY1                ; No, continue\r
343 ; Clip bottom\r
344         mov     ds:[si].Y2, dx\r
345         mov     bx, cx\r
346         sub     bx, dx                  ; Clip distance\r
347         sub     cx, ax                  ; Height\r
348         jle     @@ClipYClip\r
349         mov     cx, ds:[si].Y2\r
350 @@ClipY1:\r
351         mov     dx, [mx_ClipY1]\r
352         cmp     cx, dx                  ; Full top clipped?\r
353         jl      @@ClipYClip             ; Yes, skip\r
354         sub     cx, ax                  ; Get height\r
355         jle     @@ClipYClip             ; Skip if not positive\r
356         cmp     ax, dx                  ; Need to clip top?\r
357         jge     @@ClipYLoop             ; No, continue\r
358 ; Clip top\r
359         mov     ds:[si].Y1, dx          ; Y1 = mx_ClipY1\r
360         sub     dx, ax                  ; DX = number of pixels clipped\r
361         cmp     cx, dx\r
362         ja      @@ClipYLoop             ; Not clipped, continue\r
363 @@ClipYClip:\r
364         mov     ds:[si].Y1, -1          ; Mark column as clipped\r
365         jmp     @@ClipYLoop\r
366 @@ClipYExit:\r
367 \r
368 ;-------------\r
369 ; Draw columns\r
370         mov     es, [mx_VideoSegment]\r
371         mov     si, [ScanOffsetT]\r
372         mov     cl, BYTE PTR [BoxX1]    ; Init write plane\r
373         and     cl, 03h\r
374         mov     al, 11h\r
375         shl     al, cl\r
376         mov     [WritePlane], al\r
377         .shr    [BoxX1], 2\r
378 @@DrawLoop:\r
379         mov     ax, ds:[si].Y1\r
380         test    ax, ax                  ; Was column clipped?\r
381         js      @@DrawNext              ; Yes, skip\r
382         mov     cx, ds:[si].Y2\r
383         sub     cx, ax                  ; CX = height\r
384         jle     @@DrawNext\r
385         mul     [mx_BytesPerLine]       ; Get pixel address\r
386         add     ax, [BoxX1]\r
387         mov     di, ax\r
388         mov     ah, [WritePlane]\r
389         mov     dx, TS\r
390         mov     al, 02h\r
391         out     dx, ax\r
392         mov     ax, [Color]\r
393         mov     dx, [mx_BytesPerLine]\r
394         shr     cx, 1\r
395         jnc     @@FillScan\r
396         mov     es:[di], al\r
397         add     di, dx\r
398         jcxz    @@DrawNext\r
399 @@FillScan:\r
400         mov     es:[di], al\r
401         add     di, dx\r
402         mov     es:[di], al\r
403         add     di, dx\r
404         dec     cx\r
405         jnz     @@FillScan\r
406 @@DrawNext:\r
407         rol     [WritePlane], 1\r
408         adc     [BoxX1], 0              ; Bump pointer to video memory if needed\r
409         add     si, SIZE TSCAN\r
410         dec     [ScanCount]\r
411         jnz     @@DrawLoop\r
412 \r
413 @@Exit:\r
414         xor     ax, ax\r
415         .pop    ds, si, es, di\r
416         .leave  ARG_SIZE\r
417 mxFillPoly      ENDP\r
418 \r
419 MX_TEXT         ENDS\r
420 END\r