]> 4ch.mooo.com Git - 16.git/blobdiff - 16/xw/mxpf.asm
wwww
[16.git] / 16 / xw / mxpf.asm
diff --git a/16/xw/mxpf.asm b/16/xw/mxpf.asm
new file mode 100755 (executable)
index 0000000..db0da89
--- /dev/null
@@ -0,0 +1,420 @@
+;-----------------------------------------------------------\r
+;\r
+; MXPG.ASM - Convex polygon fill\r
+; Copyright (c) 1994 by Alessandro Scotti\r
+;\r
+;-----------------------------------------------------------\r
+WARN    PRO\r
+NOWARN  RES\r
+INCLUDE MODEX.DEF\r
+\r
+PUBLIC  mxFillPoly\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; "Local" definitions\r
+;\r
+TPOINT  STRUC\r
+        X       DW      ?\r
+        Y       DW      ?\r
+TPOINT  ENDS\r
+\r
+; Do NOT change order!\r
+TSCAN   STRUC\r
+        Y1      DW      ?\r
+        Y2      DW      ?\r
+TSCAN   ENDS\r
+\r
+MAXSCANCOLUMNS  EQU     POLYSCANBUFSIZE / SIZE TSCAN\r
+\r
+MX_TEXT         SEGMENT USE16 PARA PUBLIC 'CODE'\r
+                ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
+\r
+EXTRN   mx_VideoSegment : WORD\r
+EXTRN   mx_CodeSegment  : WORD\r
+EXTRN   mx_BytesPerLine : WORD\r
+EXTRN   mx_ClipX1       : WORD\r
+EXTRN   mx_ClipY1       : WORD\r
+EXTRN   mx_ClipX2       : WORD\r
+EXTRN   mx_ClipY2       : WORD\r
+EXTRN   mx_ScanBuffer   : NEAR\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Scans an edge using the DDA (digital differential analyzer) algorithm.\r
+;\r
+; Input:\r
+;       DS:BX   = pointer to start point (X1, Y1)\r
+;       DS:SI   = pointer to end point (X2, Y2)\r
+;       ES:DI   = pointer to edge buffer\r
+; Output:\r
+;       ES:DI   = updated pointer to edge buffer\r
+; Notes:\r
+;       must preserve DS:SI.\r
+;\r
+subScan         PROC NEAR\r
+        mov     cx, ds:[si].X\r
+        sub     cx, ds:[bx].X           ; Get width\r
+        jg      @@1\r
+        ret\r
+@@1:\r
+        push    bp                      ; Save BP\r
+\r
+        mov     ax, ds:[si].Y\r
+        mov     bx, ds:[bx].Y\r
+        sub     ax, bx                  ; Get height\r
+        jg      @@T2B                   ; Scan top to bottom\r
+        jl      @@B2T                   ; Scan bottom to top\r
+\r
+; Special case: vertical line\r
+        mov     ax, bx\r
+@@V:\r
+        mov     es:[di].Y1, ax\r
+        add     di, SIZE TSCAN\r
+        dec     cx\r
+       jnz     @@V\r
+        jmp     @@Exit\r
+\r
+; Scan top to bottom\r
+@@T2B:\r
+        cwd\r
+        div     cx\r
+        mov     bp, ax\r
+        xor     ax, ax\r
+        div     cx\r
+        xchg    ax, bx                  ; BP:BX = fixed 16:16 step\r
+        mov     dx, 8000h\r
+@@T2BLoop:\r
+        mov     es:[di].Y1, ax\r
+        add     di, SIZE TSCAN\r
+        add     dx, bx\r
+        adc     ax, bp\r
+        dec     cx\r
+        jnz     @@T2BLoop\r
+        jmp     @@Exit\r
+\r
+; Scan bottom to top\r
+@@B2T:\r
+        neg     ax\r
+        cwd\r
+        div     cx\r
+        mov     bp, ax\r
+        xor     ax, ax\r
+        div     cx\r
+        xchg    ax, bx\r
+        mov     dx, 8000h\r
+@@B2TLoop:\r
+        mov     es:[di].Y1, ax\r
+        add     di, SIZE TSCAN\r
+        sub     dx, bx\r
+        sbb     ax, bp\r
+        dec     cx\r
+        jnz     @@B2TLoop\r
+\r
+@@Exit:\r
+        pop     bp                      ; Restore BP\r
+        ret\r
+subScan         ENDP\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Fills a convex polygon with the specified color.\r
+;\r
+; Input:\r
+;       Count   = number of vertexes\r
+;       Map     = indexes of points and colors (integer)\r
+;       Points  = array of points (integer X, Y coordinates)\r
+;       Color   = base color\r
+; Output:\r
+;       none\r
+; Notes:\r
+;       vertexes must be in counterclockwise order, arrays are 0-based.\r
+;\r
+mxFillPoly      PROC FAR\r
+        ARG     Color:WORD,     \\r
+                Points:DWORD,   \\r
+                Map:DWORD,      \\r
+                Count:WORD      = ARG_SIZE\r
+        LOCAL   WritePlane:BYTE:2,      \\r
+                ScanOffsetT:WORD,       \\r
+                ScanOffsetB:WORD,       \\r
+                ScanCount:WORD,         \\r
+                Holder:WORD,            \\r
+                Height:WORD,            \\r
+                MinIdxT:WORD,           \\r
+                MinIdxB:WORD,           \\r
+                MaxIdx:WORD,            \\r
+                Width:WORD,             \\r
+                BoxX1:WORD,             \\r
+                BoxY1:WORD,             \\r
+                BoxX2:WORD,             \\r
+                BoxY2::WORD             = AUTO_SIZE\r
+        .enter  AUTO_SIZE\r
+        .push   ds, si, es, di\r
+        ASSUME  ds:NOTHING\r
+\r
+; Check that at least three vertexes are specified\r
+        mov     cx, [Count]\r
+        cmp     cx, 3\r
+        jb      @@Exit\r
+\r
+;------------------------------\r
+; Find bounding box for polygon\r
+        les     di, [Map]\r
+        lds     si, [Points]            ; Pointer to vertex array\r
+        mov     [BoxX1], 32767\r
+        mov     [BoxX2], -32768\r
+        mov     [BoxY1], 32767\r
+        mov     [BoxY2], -32768\r
+\r
+        xor     dx, dx\r
+@@MinMaxLoop:\r
+        mov     bx, es:[di]             ; Get index of vertex\r
+        .shl    bx, 2                   ; Get offset in point array\r
+        add     bx, si\r
+\r
+; Check X range\r
+@@CheckMinX:\r
+        mov     ax, ds:[bx].X           ; Get X coordinate\r
+        cmp     ax, [BoxX1]\r
+        jge     @@CheckMaxX\r
+        mov     [BoxX1], ax\r
+        mov     [MinIdxT], dx\r
+        mov     [MinIdxB], dx\r
+@@CheckMaxX:\r
+        cmp     ax, [BoxX2]\r
+        jle     @@CheckMinY\r
+        mov     [BoxX2], ax\r
+        mov     [MaxIdx], dx\r
+\r
+; Check Y range\r
+@@CheckMinY:\r
+        mov     ax, ds:[bx].Y\r
+        cmp     ax, [BoxY1]\r
+        jge     @@CheckMaxY\r
+        mov     [BoxY1], ax\r
+@@CheckMaxY:\r
+        cmp     ax, [BoxY2]\r
+        jle     @@CheckDone\r
+        mov     [BoxY2], ax\r
+\r
+; Repeat thru all points\r
+@@CheckDone:\r
+        inc     di                      ; Next map entry\r
+        inc     dx\r
+        inc     di\r
+        inc     dx\r
+        dec     cx\r
+        jnz     @@MinMaxLoop\r
+\r
+;---------------------------------\r
+; Check if polygon is full clipped\r
+        mov     ax, [BoxX2]\r
+        cmp     ax, [mx_ClipX1]         ; Is poly full clipped?\r
+        jl      @@Exit\r
+        mov     bx, [BoxX1]\r
+        cmp     bx, [mx_ClipX2]         ; Is poly full clipped?\r
+        jg      @@Exit\r
+        sub     ax, bx                  ; Get width\r
+        jle     @@Exit                  ; Exit if not positive\r
+        mov     ax, [BoxY2]\r
+        cmp     ax, [mx_ClipY1]         ; Is poly full clipped?\r
+        jl      @@Exit\r
+        mov     bx, [BoxY1]\r
+        cmp     bx, [mx_ClipY2]         ; Is poly full clipped?\r
+        jg      @@Exit\r
+        sub     ax, bx                  ; Get height\r
+        jle     @@Exit                  ; Exit if not positive\r
+\r
+        dec     [Count]\r
+        shl     [Count], 1              ; We'll work with word offsets\r
+        mov     es, [mx_CodeSegment]\r
+\r
+;--------------\r
+; Scan top edge\r
+        mov     ax, OFFSET mx_ScanBuffer\r
+        mov     [ScanOffsetT], ax\r
+        mov     si, [MinIdxT]           ; Offset of bottom point index\r
+@@STLoop:\r
+        lds     bx, [Map]               ; DS:BX -> map table\r
+        mov     di, ds:[bx+si]          ; Index of top point #1\r
+        dec     si                      ; Next point\r
+        dec     si\r
+        test    si, si\r
+        jnl     @@ST1\r
+        mov     si, [Count]\r
+@@ST1:\r
+        mov     [MinIdxT], si           ; Save new index of top point\r
+        mov     si, ds:[bx+si]          ; Get index of top point #2\r
+        .shl    di, 2                   ; Convert indexes to offsets\r
+        .shl    si, 2\r
+        lds     bx, [Points]            ; DS:BX -> point array\r
+        add     si, bx                  ; DS:SI -> top point #2\r
+        add     bx, di                  ; DS:BX -> top point #1\r
+        mov     di, [ScanOffsetT]\r
+        call    subScan                 ; Scan edge\r
+        mov     [ScanOffsetT], di\r
+        mov     si, [MinIdxT]\r
+        cmp     si, [MaxIdx]            ; End of edge?\r
+        jne     @@STLoop                ; No, continue\r
+\r
+;-----------------\r
+; Scan bottom edge\r
+        mov     ax, OFFSET mx_ScanBuffer + OFFSET Y2\r
+        mov     [ScanOffsetB], ax\r
+        mov     si, [MinIdxB]           ; Offset of bottom point index\r
+@@SBLoop:\r
+        lds     bx, [Map]               ; DS:BX -> map table\r
+        mov     di, ds:[bx+si]          ; Index of bottom point #1\r
+        inc     si                      ; Next bottom point\r
+        inc     si\r
+        cmp     si, [Count]\r
+        jbe     @@SB1\r
+        xor     si, si\r
+@@SB1:\r
+        mov     [MinIdxB], si           ; Save new index of bottom point\r
+        mov     si, ds:[bx+si]          ; Get index of bottom point #2\r
+        .shl    di, 2                   ; Convert indexes to offsets\r
+        .shl    si, 2\r
+        lds     bx, [Points]            ; DS:BX -> point array\r
+        add     si, bx                  ; DS:SI -> top point #2\r
+        add     bx, di                  ; DS:BX -> top point #1\r
+        mov     di, [ScanOffsetB]\r
+        call    subScan                 ; Scan edge\r
+        mov     [ScanOffsetB], di\r
+        mov     si, [MinIdxB]\r
+        cmp     si, [MaxIdx]            ; End of edge?\r
+        jne     @@SBLoop                ; No, continue\r
+\r
+;--------------------\r
+; Clip left and right\r
+        mov     si, OFFSET mx_ScanBuffer\r
+        mov     ax, [BoxX1]\r
+        mov     cx, [BoxX2]\r
+        sub     cx, ax                  ; CX = bounding box width\r
+        mov     bx, [mx_ClipX1]\r
+        sub     bx, ax\r
+        jle     @@ClipL1                ; No need to clip left\r
+        sub     cx, bx                  ; Update width\r
+        add     ax, bx                  ; BoxX1 = mx_ClipX1\r
+        mov     [BoxX1], ax\r
+        .shl    bx, 2                   ; Warning!!! This is an hand-coded\r
+        add     si, bx                  ; multiply by the size of TSCAN\r
+@@ClipL1:\r
+        mov     bx, ax\r
+        add     bx, cx                  ; Last scan column\r
+        sub     bx, [mx_ClipX2]\r
+        jle     @@ClipL2                ; No need to clip right\r
+        sub     cx, bx                  ; Clip right\r
+@@ClipL2:\r
+        test    cx, cx                  ; Is clipped width positive?\r
+        jle     @@Exit                  ; No, exit\r
+        mov     [ScanCount], cx         ; Save number of columns to draw\r
+        mov     [ScanOffsetT], si       ; Remember offset of (clipped) buffer\r
+        mov     ds, [mx_CodeSegment]    ; DS:SI -> scan buffer\r
+\r
+;------------------------------\r
+; Check if Y clipping is needed\r
+        mov     ax, [BoxY1]\r
+        cmp     ax, [mx_ClipY1]\r
+        jl      @@ClipTB                ; Need to clip top\r
+        mov     ax, [BoxY2]\r
+        cmp     ax, [mx_ClipY2]\r
+        jg      @@ClipTB                ; Need to clip bottom\r
+        jmp     @@ClipYExit             ; Skip Y clipping\r
+\r
+;--------------------\r
+; Clip top and bottom\r
+@@ClipTB:\r
+        mov     di, cx                  ; DI = scan count\r
+        inc     di                      ; Increment count for pre-loop test\r
+        sub     si, SIZE TSCAN\r
+@@ClipYLoop:\r
+        dec     di                      ; Any column left?\r
+        jz      @@ClipYExit             ; No, exit\r
+        add     si, SIZE TSCAN\r
+        mov     ax, ds:[si].Y1          ; Y1\r
+        mov     cx, ds:[si].Y2          ; Y2\r
+        mov     dx, [mx_ClipY2]\r
+        cmp     ax, dx                  ; Full clipped?\r
+        jg      @@ClipYClip             ; Yes, skip this column\r
+        cmp     cx, dx                  ; Need to clip bottom?\r
+        jle     @@ClipY1                ; No, continue\r
+; Clip bottom\r
+        mov     ds:[si].Y2, dx\r
+        mov     bx, cx\r
+        sub     bx, dx                  ; Clip distance\r
+        sub     cx, ax                  ; Height\r
+        jle     @@ClipYClip\r
+        mov     cx, ds:[si].Y2\r
+@@ClipY1:\r
+        mov     dx, [mx_ClipY1]\r
+        cmp     cx, dx                  ; Full top clipped?\r
+        jl      @@ClipYClip             ; Yes, skip\r
+        sub     cx, ax                  ; Get height\r
+        jle     @@ClipYClip             ; Skip if not positive\r
+        cmp     ax, dx                  ; Need to clip top?\r
+        jge     @@ClipYLoop             ; No, continue\r
+; Clip top\r
+        mov     ds:[si].Y1, dx          ; Y1 = mx_ClipY1\r
+        sub     dx, ax                  ; DX = number of pixels clipped\r
+        cmp     cx, dx\r
+        ja      @@ClipYLoop             ; Not clipped, continue\r
+@@ClipYClip:\r
+        mov     ds:[si].Y1, -1          ; Mark column as clipped\r
+        jmp     @@ClipYLoop\r
+@@ClipYExit:\r
+\r
+;-------------\r
+; Draw columns\r
+        mov     es, [mx_VideoSegment]\r
+        mov     si, [ScanOffsetT]\r
+        mov     cl, BYTE PTR [BoxX1]    ; Init write plane\r
+        and     cl, 03h\r
+        mov     al, 11h\r
+        shl     al, cl\r
+        mov     [WritePlane], al\r
+        .shr    [BoxX1], 2\r
+@@DrawLoop:\r
+        mov     ax, ds:[si].Y1\r
+        test    ax, ax                  ; Was column clipped?\r
+        js      @@DrawNext              ; Yes, skip\r
+        mov     cx, ds:[si].Y2\r
+        sub     cx, ax                  ; CX = height\r
+        jle     @@DrawNext\r
+        mul     [mx_BytesPerLine]       ; Get pixel address\r
+        add     ax, [BoxX1]\r
+        mov     di, ax\r
+        mov     ah, [WritePlane]\r
+        mov     dx, TS\r
+        mov     al, 02h\r
+        out     dx, ax\r
+        mov     ax, [Color]\r
+        mov     dx, [mx_BytesPerLine]\r
+        shr     cx, 1\r
+        jnc     @@FillScan\r
+        mov     es:[di], al\r
+        add     di, dx\r
+        jcxz    @@DrawNext\r
+@@FillScan:\r
+        mov     es:[di], al\r
+        add     di, dx\r
+        mov     es:[di], al\r
+        add     di, dx\r
+        dec     cx\r
+        jnz     @@FillScan\r
+@@DrawNext:\r
+        rol     [WritePlane], 1\r
+        adc     [BoxX1], 0              ; Bump pointer to video memory if needed\r
+        add     si, SIZE TSCAN\r
+        dec     [ScanCount]\r
+        jnz     @@DrawLoop\r
+\r
+@@Exit:\r
+        xor     ax, ax\r
+        .pop    ds, si, es, di\r
+        .leave  ARG_SIZE\r
+mxFillPoly      ENDP\r
+\r
+MX_TEXT         ENDS\r
+END\r