--- /dev/null
+;-----------------------------------------------------------\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