]> 4ch.mooo.com Git - 16.git/blob - 16/lib/x/MXPG.ASM
modified: 16/DOS_GFX.EXE
[16.git] / 16 / lib / x / MXPG.ASM
1 ;-----------------------------------------------------------\r
2 ;\r
3 ; MXPG.ASM - Convex polygon fill with Gouraud shading\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  mxGouraudPoly\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         E1      DB      ?\r
26         C1      DB      ?\r
27         Y2      DW      ?\r
28         E2      DB      ?\r
29         C2      DB      ?\r
30 TSCAN   ENDS\r
31 \r
32 MAXSCANCOLUMNS  EQU     POLYSCANBUFSIZE / SIZE TSCAN\r
33 \r
34 MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'\r
35                 ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
36 \r
37 EXTRN   mx_VideoSegment : WORD\r
38 EXTRN   mx_CodeSegment  : WORD\r
39 EXTRN   mx_BytesPerLine : WORD\r
40 EXTRN   mx_ClipX1       : WORD\r
41 EXTRN   mx_ClipY1       : WORD\r
42 EXTRN   mx_ClipX2       : WORD\r
43 EXTRN   mx_ClipY2       : WORD\r
44 EXTRN   mx_ScanBuffer   : NEAR\r
45 \r
46 ;-----------------------------------------------------------\r
47 ;\r
48 ; Scans an edge using the DDA (digital differential analyzer) algorithm.\r
49 ; Also interpolates color for shading.\r
50 ;\r
51 ; Input:\r
52 ;       DS:BX   = pointer to start point (X1, Y1)\r
53 ;       DS:SI   = pointer to end point (X2, Y2)\r
54 ;       ES:DI   = pointer to edge buffer\r
55 ;       DX      = start color\r
56 ;       AX      = end color\r
57 ; Output:\r
58 ;       ES:DI   = updated pointer to edge buffer\r
59 ; Notes:\r
60 ;       must preserve DS:SI.\r
61 ;\r
62 subScan         PROC NEAR\r
63         mov     cx, ds:[si].X\r
64         sub     cx, ds:[bx].X           ; Get width\r
65         jg      @@1\r
66         ret\r
67 @@1:\r
68         push    bp                      ; Save BP\r
69         push    di                      ; Save scan info offset\r
70         push    cx                      ; Save height\r
71         push    ax                      ; Save colors\r
72         push    dx\r
73 \r
74         mov     ax, ds:[si].Y\r
75         mov     bx, ds:[bx].Y\r
76         sub     ax, bx                  ; Get height\r
77         jg      @@T2B                   ; Scan top to bottom\r
78         jl      @@B2T                   ; Scan bottom to top\r
79 \r
80 ; Special case: vertical line\r
81         mov     ax, bx\r
82 @@V:\r
83         mov     es:[di].Y1, ax\r
84         add     di, SIZE TSCAN\r
85         dec     cx\r
86         jnz     @@V\r
87         jmp     @@GetColorInfo\r
88 \r
89 ; Scan top to bottom\r
90 @@T2B:\r
91         cwd\r
92         div     cx\r
93         mov     bp, ax\r
94         xor     ax, ax\r
95         div     cx\r
96         xchg    ax, bx                  ; BP:BX = fixed 16:16 step\r
97         mov     dx, 8000h\r
98 @@T2BLoop:\r
99         mov     es:[di].Y1, ax\r
100         add     di, SIZE TSCAN\r
101         add     dx, bx\r
102         adc     ax, bp\r
103         dec     cx\r
104         jnz     @@T2BLoop\r
105         jmp     @@GetColorInfo\r
106 \r
107 ; Scan bottom to top\r
108 @@B2T:\r
109         neg     ax\r
110         cwd\r
111         div     cx\r
112         mov     bp, ax\r
113         xor     ax, ax\r
114         div     cx\r
115         xchg    ax, bx\r
116         mov     dx, 8000h\r
117 @@B2TLoop:\r
118         mov     es:[di].Y1, ax\r
119         add     di, SIZE TSCAN\r
120         sub     dx, bx\r
121         sbb     ax, bp\r
122         dec     cx\r
123         jnz     @@B2TLoop\r
124 \r
125 ; Now get the color info\r
126 @@GetColorInfo:\r
127         pop     bx                      ; Restore colors\r
128         pop     ax\r
129         pop     cx                      ; Height\r
130         pop     di                      ; ES:DI -> scan info\r
131 \r
132         sub     ax, bx                  ; Get color range\r
133         jg      @@CL2R\r
134         jl      @@CR2L\r
135 \r
136 ; Special case: same color\r
137         mov     ah, bl\r
138         mov     al, 80h\r
139 @@CV:\r
140         mov     WORD PTR es:[di].E1, ax\r
141         add     di, SIZE TSCAN\r
142         dec     cx\r
143         jnz     @@CV\r
144         jmp     @@Exit\r
145 \r
146 ; Scan left to right\r
147 @@CL2R:\r
148         cwd\r
149         div     cx\r
150         mov     bp, ax\r
151         xor     ax, ax\r
152         div     cx\r
153         xchg    ax, bx                  ; BP:BX = fixed 16:16 step\r
154         mov     dx, 8000h\r
155 @@CL2RLoop:\r
156         mov     es:[di].C1, al\r
157         mov     es:[di].E1, dh\r
158         add     di, SIZE TSCAN\r
159         add     dx, bx\r
160         adc     ax, bp\r
161         dec     cx\r
162         jnz     @@CL2RLoop\r
163         jmp     @@Exit\r
164 \r
165 ; Scan right to left\r
166 @@CR2L:\r
167         neg     ax\r
168         cwd\r
169         div     cx\r
170         mov     bp, ax\r
171         xor     ax, ax\r
172         div     cx\r
173         xchg    ax, bx\r
174         mov     dx, 8000h\r
175 \r
176 @@CR2LLoop:\r
177         mov     es:[di].C1, al\r
178         mov     es:[di].E1, dh\r
179         add     di, SIZE TSCAN\r
180         sub     dx, bx\r
181         sbb     ax, bp\r
182         dec     cx\r
183         jnz     @@CR2LLoop\r
184 \r
185 @@Exit:\r
186         pop     bp\r
187         ret\r
188 subScan         ENDP\r
189 \r
190 ;-----------------------------------------------------------\r
191 ;\r
192 ; Fills a scan column.\r
193 ;\r
194 ; Input:\r
195 ;       DS:SI   = current TSCAN\r
196 ;       ES:DI   = address of top pixel\r
197 ;       CX      = number of pixels to write\r
198 ;       DX      = base color\r
199 ; Output:\r
200 ;       none\r
201 ;\r
202 subFillScan     PROC NEAR\r
203         mov     ax, WORD PTR ds:[si].E2\r
204         mov     bx, WORD PTR ds:[si].E1\r
205         cmp     ah, bh\r
206         jg      @@L2R                   ; Color increases\r
207         jl      @@R2L                   ; Color decreases\r
208 \r
209 ; Special case: color doesn't change\r
210         add     ax, dx\r
211         mov     dx, [mx_BytesPerLine]\r
212 @@V:\r
213         mov     es:[di], ah\r
214         add     di, dx\r
215         dec     cx\r
216         jnz     @@V\r
217         ret\r
218 \r
219 ; Color increases\r
220 @@L2R:\r
221         .push   bp, si\r
222         mov     si, bx\r
223         add     si, dx                  ; Relocate color\r
224         sub     ax, bx\r
225         xor     dx, dx\r
226         div     cx\r
227         mov     bp, ax                  ; BP = color step, integer part\r
228         xor     ax, ax\r
229         div     cx\r
230         mov     bx, ax                  ; BX = color step, fractional part\r
231         mov     dx, 8000h\r
232         mov     ax, [mx_BytesPerLine]\r
233         xchg    si, ax\r
234 @@L2RLoop:\r
235         mov     es:[di], ah\r
236         add     dx, bx\r
237         adc     ax, bp\r
238         add     di, si\r
239         dec     cx\r
240         jnz     @@L2RLoop\r
241         .pop    bp, si\r
242         ret\r
243 \r
244 ; Color decreases\r
245 @@R2L:\r
246         .push   bp, si\r
247         mov     si, bx\r
248         add     si, dx                  ; Relocate color\r
249         sub     ax, bx\r
250         neg     ax\r
251         xor     dx, dx\r
252         div     cx\r
253         mov     bp, ax                  ; BP = color step, integer part\r
254         xor     ax, ax\r
255         div     cx\r
256         mov     bx, ax                  ; BX = color step, fractional part\r
257         mov     dx, 8000h\r
258         mov     ax, [mx_BytesPerLine]\r
259         xchg    si, ax\r
260 @@R2LLoop:\r
261         mov     es:[di], ah\r
262         sub     dx, bx\r
263         sbb     ax, bp\r
264         add     di, si\r
265         dec     cx\r
266         jnz     @@R2LLoop\r
267         .pop    bp, si\r
268         ret\r
269 subFillScan     ENDP\r
270 \r
271 ;-----------------------------------------------------------\r
272 ;\r
273 ; Fills a convex polygon with the specified color.\r
274 ; Interpolates pixel colors using the Gouraud algorithm.\r
275 ;\r
276 ; Input:\r
277 ;       Count   = number of vertexes\r
278 ;       Map     = indexes of points and colors (integer)\r
279 ;       Points  = array of points (integer X, Y coordinates)\r
280 ;       Colors  = array of colors (integer)\r
281 ;       Color   = base color\r
282 ; Output:\r
283 ;       none\r
284 ; Notes:\r
285 ;       vertexes must be in counterclockwise order, arrays are 0-based.\r
286 ;\r
287 mxGouraudPoly   PROC FAR\r
288         ARG     Color:WORD,     \\r
289                 Colors:DWORD,   \\r
290                 Points:DWORD,   \\r
291                 Map:DWORD,      \\r
292                 Count:WORD      = ARG_SIZE\r
293         LOCAL   WritePlane:BYTE:2,      \\r
294                 ScanOffsetT:WORD,       \\r
295                 ScanOffsetB:WORD,       \\r
296                 ScanCount:WORD,         \\r
297                 Holder:WORD,            \\r
298                 Height:WORD,            \\r
299                 MinIdxT:WORD,           \\r
300                 MinIdxB:WORD,           \\r
301                 MaxIdx:WORD,            \\r
302                 Width:WORD,             \\r
303                 BoxX1:WORD,             \\r
304                 BoxY1:WORD,             \\r
305                 BoxX2:WORD,             \\r
306                 BoxY2::WORD             = AUTO_SIZE\r
307         .enter  AUTO_SIZE\r
308         .push   ds, si, es, di\r
309         ASSUME  ds:NOTHING\r
310 \r
311 ; Check that at least three vertexes are specified\r
312         mov     cx, [Count]\r
313         cmp     cx, 3\r
314         jb      @@Exit\r
315 \r
316 ;------------------------------\r
317 ; Find bounding box for polygon\r
318         les     di, [Map]\r
319         lds     si, [Points]            ; Pointer to vertex array\r
320         mov     [BoxX1], 32767\r
321         mov     [BoxX2], -32768\r
322         mov     [BoxY1], 32767\r
323         mov     [BoxY2], -32768\r
324 \r
325         xor     dx, dx\r
326 @@MinMaxLoop:\r
327         mov     bx, es:[di]             ; Get index of vertex\r
328         .shl    bx, 2                   ; Get offset in point array\r
329         add     bx, si\r
330 \r
331 ; Check X range\r
332 @@CheckMinX:\r
333         mov     ax, ds:[bx].X           ; Get X coordinate\r
334         cmp     ax, [BoxX1]\r
335         jge     @@CheckMaxX\r
336         mov     [BoxX1], ax\r
337         mov     [MinIdxT], dx\r
338         mov     [MinIdxB], dx\r
339 @@CheckMaxX:\r
340         cmp     ax, [BoxX2]\r
341         jle     @@CheckMinY\r
342         mov     [BoxX2], ax\r
343         mov     [MaxIdx], dx\r
344 \r
345 ; Check Y range\r
346 @@CheckMinY:\r
347         mov     ax, ds:[bx].Y\r
348         cmp     ax, [BoxY1]\r
349         jge     @@CheckMaxY\r
350         mov     [BoxY1], ax\r
351 @@CheckMaxY:\r
352         cmp     ax, [BoxY2]\r
353         jle     @@CheckDone\r
354         mov     [BoxY2], ax\r
355 \r
356 ; Repeat thru all points\r
357 @@CheckDone:\r
358         inc     di                      ; Next map entry\r
359         inc     di\r
360         inc     dx\r
361         inc     dx\r
362         dec     cx\r
363         jnz     @@MinMaxLoop\r
364 \r
365 ;---------------------------------\r
366 ; Check if polygon is full clipped\r
367         mov     ax, [BoxX2]\r
368         cmp     ax, [mx_ClipX1]         ; Is poly full clipped?\r
369         jl      @@Exit\r
370         mov     bx, [BoxX1]\r
371         cmp     bx, [mx_ClipX2]         ; Is poly full clipped?\r
372         jg      @@Exit\r
373         sub     ax, bx                  ; Get width\r
374         jle     @@Exit                  ; Exit if not positive\r
375         mov     ax, [BoxY2]\r
376         cmp     ax, [mx_ClipY1]         ; Is poly full clipped?\r
377         jl      @@Exit\r
378         mov     bx, [BoxY1]\r
379         cmp     bx, [mx_ClipY2]         ; Is poly full clipped?\r
380         jg      @@Exit\r
381         sub     ax, bx                  ; Get height\r
382         jle     @@Exit                  ; Exit if not positive\r
383 \r
384         dec     [Count]\r
385         shl     [Count], 1              ; We'll work with word offsets\r
386         mov     es, [mx_CodeSegment]\r
387 \r
388 ;--------------\r
389 ; Scan top edge\r
390         mov     ax, OFFSET mx_ScanBuffer\r
391         mov     [ScanOffsetT], ax\r
392         mov     si, [MinIdxT]           ; Offset of bottom point index\r
393 @@STLoop:\r
394         lds     bx, [Map]               ; DS:BX -> map table\r
395         mov     di, ds:[bx+si]          ; Index of top point #1\r
396         dec     si                      ; Next point\r
397         dec     si\r
398         test    si, si\r
399         jnl     @@ST1\r
400         mov     si, [Count]\r
401 @@ST1:\r
402         mov     [MinIdxT], si           ; Save new index of top point\r
403         mov     si, ds:[bx+si]          ; Get index of top point #2\r
404         lds     bx, [Colors]            ; Get pointer to color array\r
405         shl     di, 1                   ; Convert indexes to offsets\r
406         shl     si, 1\r
407         mov     ax, ds:[bx+si]          ; Get colors\r
408         mov     dx, ds:[bx+di]\r
409         lds     bx, [Points]            ; DS:BX -> point array\r
410         shl     si, 1\r
411         shl     di, 1\r
412         add     si, bx                  ; DS:SI -> top point #2\r
413         add     bx, di                  ; DS:BX -> top point #1\r
414         mov     di, [ScanOffsetT]\r
415         call    subScan                 ; Scan edge\r
416         mov     [ScanOffsetT], di\r
417         mov     si, [MinIdxT]\r
418         cmp     si, [MaxIdx]            ; End of edge?\r
419         jne     @@STLoop                ; No, continue\r
420 \r
421 ;-----------------\r
422 ; Scan bottom edge\r
423         mov     ax, OFFSET mx_ScanBuffer + OFFSET Y2\r
424         mov     [ScanOffsetB], ax\r
425         mov     si, [MinIdxB]           ; Offset of bottom point index\r
426 @@SBLoop:\r
427         lds     bx, [Map]               ; DS:BX -> map table\r
428         mov     di, ds:[bx+si]          ; Index of bottom point #1\r
429         inc     si                      ; Next bottom point\r
430         inc     si\r
431         cmp     si, [Count]\r
432         jbe     @@SB1\r
433         xor     si, si\r
434 @@SB1:\r
435         mov     [MinIdxB], si           ; Save new index of bottom point\r
436         mov     si, ds:[bx+si]          ; Get index of bottom point #2\r
437         lds     bx, [Colors]            ; Get pointer to color array\r
438         shl     di, 1                   ; Convert indexes to offsets\r
439         shl     si, 1\r
440         mov     ax, ds:[bx+si]          ; Get colors\r
441         mov     dx, ds:[bx+di]\r
442         lds     bx, [Points]            ; DS:BX -> point array\r
443         shl     si, 1\r
444         shl     di, 1\r
445         add     si, bx                  ; DS:SI -> top point #2\r
446         add     bx, di                  ; DS:BX -> top point #1\r
447         mov     di, [ScanOffsetB]\r
448         call    subScan                 ; Scan edge\r
449         mov     [ScanOffsetB], di\r
450         mov     si, [MinIdxB]\r
451         cmp     si, [MaxIdx]            ; End of edge?\r
452         jne     @@SBLoop                ; No, continue\r
453 \r
454 ;--------------------\r
455 ; Clip left and right\r
456         mov     si, OFFSET mx_ScanBuffer\r
457         mov     ax, [BoxX1]\r
458         mov     cx, [BoxX2]\r
459         sub     cx, ax                  ; CX = bounding box width\r
460         mov     bx, [mx_ClipX1]\r
461         sub     bx, ax\r
462         jle     @@ClipL1                ; No need to clip left\r
463         sub     cx, bx                  ; Update width\r
464         add     ax, bx                  ; BoxX1 = mx_ClipX1\r
465         mov     [BoxX1], ax\r
466         .shl    bx, 3                   ; Warning!!! This is an hand-coded\r
467         add     si, bx                  ; multiply by the size of TSCAN\r
468 @@ClipL1:\r
469         mov     bx, ax\r
470         add     bx, cx                  ; Last scan column\r
471         sub     bx, [mx_ClipX2]\r
472         jle     @@ClipL2                ; No need to clip right\r
473         sub     cx, bx                  ; Clip right\r
474 @@ClipL2:\r
475         test    cx, cx                  ; Is clipped width positive?\r
476         jle     @@Exit                  ; No, exit\r
477         mov     [ScanCount], cx         ; Save number of columns to draw\r
478         mov     [ScanOffsetT], si       ; Remember offset of (clipped) buffer\r
479         mov     ds, [mx_CodeSegment]    ; DS:SI -> scan buffer\r
480 \r
481 ;------------------------------\r
482 ; Check if Y clipping is needed\r
483         mov     ax, [BoxY1]\r
484         cmp     ax, [mx_ClipY1]\r
485         jl      @@ClipTB                ; Need to clip top\r
486         mov     ax, [BoxY2]\r
487         cmp     ax, [mx_ClipY2]\r
488         jg      @@ClipTB                ; Need to clip bottom\r
489         jmp     @@ClipYExit             ; Skip Y clipping\r
490 \r
491 ;--------------------\r
492 ; Clip top and bottom\r
493 @@ClipTB:\r
494         mov     di, cx                  ; DI = scan count\r
495         inc     di                      ; Increment count for pre-loop test\r
496         sub     si, SIZE TSCAN\r
497 @@ClipYLoop:\r
498         dec     di                      ; Any column left?\r
499         jz      @@ClipYExit             ; No, exit\r
500         add     si, SIZE TSCAN\r
501         mov     ax, ds:[si].Y1          ; Y1\r
502         mov     cx, ds:[si].Y2          ; Y2\r
503         mov     dx, [mx_ClipY2]\r
504         cmp     ax, dx                  ; Full clipped?\r
505         jg      @@ClipYClip             ; Yes, skip this column\r
506         cmp     cx, dx                  ; Need to clip bottom?\r
507         jle     @@ClipY1                ; No, continue\r
508 ; Clip bottom, need to scale colors too\r
509         mov     ds:[si].Y2, dx\r
510         mov     bx, cx\r
511         sub     bx, dx                  ; Clip distance\r
512         sub     cx, ax                  ; Height\r
513         jle     @@ClipYClip\r
514         mov     ax, WORD PTR ds:[si].E1\r
515         sub     ax, WORD PTR ds:[si].E2\r
516         imul    bx\r
517         idiv    cx\r
518         add     WORD PTR ds:[si].E2, ax\r
519         mov     ax, ds:[si].Y1          ; Restore AX and CX\r
520         mov     cx, ds:[si].Y2\r
521 @@ClipY1:\r
522         mov     dx, [mx_ClipY1]\r
523         cmp     cx, dx                  ; Full top clipped?\r
524         jl      @@ClipYClip             ; Yes, skip\r
525         sub     cx, ax                  ; Get height\r
526         jle     @@ClipYClip             ; Skip if not positive\r
527         cmp     ax, dx                  ; Need to clip top?\r
528         jge     @@ClipYLoop             ; No, continue\r
529 ; Clip top, need to scale colors too\r
530         mov     ds:[si].Y1, dx          ; Y1 = mx_ClipY1\r
531         sub     dx, ax                  ; DX = number of pixels clipped\r
532         cmp     cx, dx\r
533         jbe     @@ClipYClip             ; Full clipped, skip\r
534         mov     ax, WORD PTR ds:[si].E2\r
535         sub     ax, WORD PTR ds:[si].E1 ; AX = color distance\r
536         imul    dx\r
537         idiv    cx\r
538         add     WORD PTR ds:[si].E1, ax ; Update starting color\r
539         jmp     @@ClipYLoop\r
540 @@ClipYClip:\r
541         mov     ds:[si].Y1, -1          ; Mark column as clipped\r
542         jmp     @@ClipYLoop\r
543 @@ClipYExit:\r
544 \r
545 ;-------------\r
546 ; Draw columns\r
547         mov     es, [mx_VideoSegment]\r
548         mov     si, [ScanOffsetT]\r
549         mov     cl, BYTE PTR [BoxX1]    ; Init write plane\r
550         and     cl, 03h\r
551         mov     al, 11h\r
552         shl     al, cl\r
553         mov     [WritePlane], al\r
554         .shr    [BoxX1], 2\r
555         mov     ax, [Color]             ; Make 8:8 fixed color\r
556         mov     ah, al\r
557         xor     al, al\r
558         mov     [Color], ax\r
559 @@DrawLoop:\r
560         mov     ax, ds:[si].Y1\r
561         test    ax, ax                  ; Was column clipped?\r
562         js      @@DrawNext              ; Yes, skip\r
563         mov     cx, ds:[si].Y2\r
564         sub     cx, ax                  ; CX = height\r
565         jle     @@DrawNext\r
566         mul     [mx_BytesPerLine]       ; Get pixel address\r
567         add     ax, [BoxX1]\r
568         mov     di, ax\r
569         mov     ah, [WritePlane]\r
570         mov     al, 02h\r
571         mov     dx, TS\r
572         out     dx, ax\r
573         mov     dx, [Color]\r
574         call    subFillScan\r
575 @@DrawNext:\r
576         rol     [WritePlane], 1\r
577         adc     [BoxX1], 0              ; Bump pointer to video memory if needed\r
578         add     si, SIZE TSCAN\r
579         dec     [ScanCount]\r
580         jnz     @@DrawLoop\r
581 \r
582 @@Exit:\r
583         xor     ax, ax\r
584         .pop    ds, si, es, di\r
585         .leave  ARG_SIZE\r
586 mxGouraudPoly   ENDP\r
587 \r
588 MX_TEXT         ENDS\r
589 END\r