+++ /dev/null
-;-----------------------------------------------------------\r
-;\r
-; MXPG.ASM - Convex polygon fill with Gouraud shading\r
-; Copyright (c) 1994 by Alessandro Scotti\r
-;\r
-;-----------------------------------------------------------\r
-WARN PRO\r
-NOWARN RES\r
-INCLUDE MODEX.DEF\r
-\r
-PUBLIC mxGouraudPoly\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
- E1 DB ?\r
- C1 DB ?\r
- Y2 DW ?\r
- E2 DB ?\r
- C2 DB ?\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
-; Also interpolates color for shading.\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
-; DX = start color\r
-; AX = end color\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
- push di ; Save scan info offset\r
- push cx ; Save height\r
- push ax ; Save colors\r
- push dx\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 @@GetColorInfo\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 @@GetColorInfo\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
-; Now get the color info\r
-@@GetColorInfo:\r
- pop bx ; Restore colors\r
- pop ax\r
- pop cx ; Height\r
- pop di ; ES:DI -> scan info\r
-\r
- sub ax, bx ; Get color range\r
- jg @@CL2R\r
- jl @@CR2L\r
-\r
-; Special case: same color\r
- mov ah, bl\r
- mov al, 80h\r
-@@CV:\r
- mov WORD PTR es:[di].E1, ax\r
- add di, SIZE TSCAN\r
- dec cx\r
- jnz @@CV\r
- jmp @@Exit\r
-\r
-; Scan left to right\r
-@@CL2R:\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
-@@CL2RLoop:\r
- mov es:[di].C1, al\r
- mov es:[di].E1, dh\r
- add di, SIZE TSCAN\r
- add dx, bx\r
- adc ax, bp\r
- dec cx\r
- jnz @@CL2RLoop\r
- jmp @@Exit\r
-\r
-; Scan right to left\r
-@@CR2L:\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
-\r
-@@CR2LLoop:\r
- mov es:[di].C1, al\r
- mov es:[di].E1, dh\r
- add di, SIZE TSCAN\r
- sub dx, bx\r
- sbb ax, bp\r
- dec cx\r
- jnz @@CR2LLoop\r
-\r
-@@Exit:\r
- pop bp\r
- ret\r
-subScan ENDP\r
-\r
-;-----------------------------------------------------------\r
-;\r
-; Fills a scan column.\r
-;\r
-; Input:\r
-; DS:SI = current TSCAN\r
-; ES:DI = address of top pixel\r
-; CX = number of pixels to write\r
-; DX = base color\r
-; Output:\r
-; none\r
-;\r
-subFillScan PROC NEAR\r
- mov ax, WORD PTR ds:[si].E2\r
- mov bx, WORD PTR ds:[si].E1\r
- cmp ah, bh\r
- jg @@L2R ; Color increases\r
- jl @@R2L ; Color decreases\r
-\r
-; Special case: color doesn't change\r
- add ax, dx\r
- mov dx, [mx_BytesPerLine]\r
-@@V:\r
- mov es:[di], ah\r
- add di, dx\r
- dec cx\r
- jnz @@V\r
- ret\r
-\r
-; Color increases\r
-@@L2R:\r
- .push bp, si\r
- mov si, bx\r
- add si, dx ; Relocate color\r
- sub ax, bx\r
- xor dx, dx\r
- div cx\r
- mov bp, ax ; BP = color step, integer part\r
- xor ax, ax\r
- div cx\r
- mov bx, ax ; BX = color step, fractional part\r
- mov dx, 8000h\r
- mov ax, [mx_BytesPerLine]\r
- xchg si, ax\r
-@@L2RLoop:\r
- mov es:[di], ah\r
- add dx, bx\r
- adc ax, bp\r
- add di, si\r
- dec cx\r
- jnz @@L2RLoop\r
- .pop bp, si\r
- ret\r
-\r
-; Color decreases\r
-@@R2L:\r
- .push bp, si\r
- mov si, bx\r
- add si, dx ; Relocate color\r
- sub ax, bx\r
- neg ax\r
- xor dx, dx\r
- div cx\r
- mov bp, ax ; BP = color step, integer part\r
- xor ax, ax\r
- div cx\r
- mov bx, ax ; BX = color step, fractional part\r
- mov dx, 8000h\r
- mov ax, [mx_BytesPerLine]\r
- xchg si, ax\r
-@@R2LLoop:\r
- mov es:[di], ah\r
- sub dx, bx\r
- sbb ax, bp\r
- add di, si\r
- dec cx\r
- jnz @@R2LLoop\r
- .pop bp, si\r
- ret\r
-subFillScan ENDP\r
-\r
-;-----------------------------------------------------------\r
-;\r
-; Fills a convex polygon with the specified color.\r
-; Interpolates pixel colors using the Gouraud algorithm.\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
-; Colors = array of colors (integer)\r
-; Color = base color\r
-; Output:\r
-; none\r
-; Notes:\r
-; vertexes must be in counterclockwise order, arrays are 0-based.\r
-;\r
-mxGouraudPoly PROC FAR\r
- ARG Color:WORD, \\r
- Colors:DWORD, \\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 di\r
- inc dx\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
- lds bx, [Colors] ; Get pointer to color array\r
- shl di, 1 ; Convert indexes to offsets\r
- shl si, 1\r
- mov ax, ds:[bx+si] ; Get colors\r
- mov dx, ds:[bx+di]\r
- lds bx, [Points] ; DS:BX -> point array\r
- shl si, 1\r
- shl di, 1\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
- lds bx, [Colors] ; Get pointer to color array\r
- shl di, 1 ; Convert indexes to offsets\r
- shl si, 1\r
- mov ax, ds:[bx+si] ; Get colors\r
- mov dx, ds:[bx+di]\r
- lds bx, [Points] ; DS:BX -> point array\r
- shl si, 1\r
- shl di, 1\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, 3 ; 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, need to scale colors too\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 ax, WORD PTR ds:[si].E1\r
- sub ax, WORD PTR ds:[si].E2\r
- imul bx\r
- idiv cx\r
- add WORD PTR ds:[si].E2, ax\r
- mov ax, ds:[si].Y1 ; Restore AX and CX\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, need to scale colors too\r
- mov ds:[si].Y1, dx ; Y1 = mx_ClipY1\r
- sub dx, ax ; DX = number of pixels clipped\r
- cmp cx, dx\r
- jbe @@ClipYClip ; Full clipped, skip\r
- mov ax, WORD PTR ds:[si].E2\r
- sub ax, WORD PTR ds:[si].E1 ; AX = color distance\r
- imul dx\r
- idiv cx\r
- add WORD PTR ds:[si].E1, ax ; Update starting color\r
- jmp @@ClipYLoop\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
- mov ax, [Color] ; Make 8:8 fixed color\r
- mov ah, al\r
- xor al, al\r
- mov [Color], ax\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 al, 02h\r
- mov dx, TS\r
- out dx, ax\r
- mov dx, [Color]\r
- call subFillScan\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
-mxGouraudPoly ENDP\r
-\r
-MX_TEXT ENDS\r
-END\r