;---------------------------Module-Header------------------------------; ; Module Name: fastfill.asm ; ; Draws fast unclipped, non-complex polygons. ; ; Copyright (c) 1994 Microsoft Corporation ;-----------------------------------------------------------------------; .386 .model small,c assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT assume fs:nothing,gs:nothing .xlist include stdcall.inc ;calling convention cmacros include i386\strucs.inc include i386\hw.inc .list .data ; The number of FIFO slots that are empty after we've done an ; IO_FIFO_WAIT(8): IO_ALL_EMPTY_FIFO_COUNT equ 8 ; All the state information for running an edge DDA: EDGEDATA struc ed_x dd ? ed_dx dd ? ed_lError dd ? ed_lErrorUp dd ? ed_lErrorDown dd ? ed_pptfx dd ? ed_dptfx dd ? ed_cy dd ? EDGEDATA ends .code ;---------------------------Public-Routine------------------------------; ; BOOL bIoFastFill(cEdges, pptfxFirst, ulHwForeMix, ulHwBackMix, ; iSolidColor, prb) ; ; Draws fast polygons. Or at least attempts to. ; ; This routine could take great advantage of the ATI SCAN_TO_X ; instruction. Alas, but I have limited time... ; ; Input: ; ; ppdev - Points to the PDEV. ; cEdges - Number of edges in 'pptfxFirst' buffer, including the ; 'close figure' edge (so it's also the same as the number ; of points in the list). ; pptfxFirst - Points to buffer of edges. The last point in not ; necessarily coincident with the first. ; ulHwForeMix - Foreground hardware mix. ; ulHwBackMix - Background hardware mix. ; iSolidColor - Fill colour. ; prb - Not used. ; ; Output: ; ; eax - Returns 1 if the polygon was drawn, 0 if the polygon was ; too complex. ;-----------------------------------------------------------------------; cProc bIoFastFill,28,< \ uses esi edi ebx, \ ppdev: ptr, \ cEdges: dword,\ pptfxFirst: ptr, \ ulHwForeMix: dword,\ ulHwBackMix: dword,\ iSolidColor: dword,\ prb: ptr > local edLeft[size EDGEDATA]: byte ;DDA state for left edge local edRight[size EDGEDATA]: byte ;DDA state for right edge local yTrapezoid: dword ;Current scan of trapezoid, in ; ABSOLUTE coordinates local cyTrapezoid: dword ;Scans remaining to be drawn in ; current trapezoid local pptfxLast: dword ;Points to last point in buffer local iEdge: dword ;Edge number for DDA loop local cFifoEmpty: dword ;Number of remaining free FIFOs local xOffset: dword ;DFB 'x' offset local yOffset: dword ;DFB 'y' offset mov esi,pptfxFirst mov ecx,cEdges dec ecx mov edi,esi ;edi = pptfxTop = pptfxFirst lea eax,[esi+ecx*8] mov pptfxLast,eax ;pptfxLast = pptfxFirst + cEdges - 1 mov eax,[esi].ptl_y mov ebx,[esi+8].ptl_y mov edx,eax ;edx = pptfxFirst->y cmp ebx,eax jle short io_u_collect_all_ups io_d_collect_all_downs: dec ecx jz short io_setup_for_filling add esi,8 mov eax,ebx mov ebx,[esi+8].ptl_y cmp ebx,eax jge short io_d_collect_all_downs io_d_collect_all_ups: dec ecx jz short io_setup_for_filling_check add esi,8 mov eax,ebx mov ebx,[esi+8].ptl_y cmp ebx,eax jle short io_d_collect_all_ups mov edi,esi ;edi = pptfxTop = pptfxScan io_d_collect_all_downs_again: cmp ebx,edx jg short io_return_false dec ecx jz short io_setup_for_filling add esi,8 mov eax,ebx mov ebx,[esi+8].ptl_y cmp ebx,eax jge short io_d_collect_all_downs_again io_return_false: sub eax,eax cRet bIoFastFill io_u_collect_all_ups: add edi,8 dec ecx jz io_setup_for_filling mov eax,ebx mov ebx,[edi+8].ptl_y cmp ebx,eax jle short io_u_collect_all_ups mov esi,edi ;esi = pptfxScan = pptfxTop io_u_collect_all_downs: dec ecx jz io_setup_for_filling add esi,8 mov eax,ebx mov ebx,[esi+8].ptl_y cmp ebx,eax jge short io_u_collect_all_downs io_u_collect_all_ups_again: cmp ebx,edx jl short io_return_false dec ecx jz io_setup_for_filling add esi,8 mov eax,ebx mov ebx,[esi+8].ptl_y cmp ebx,eax jle short io_u_collect_all_ups_again sub eax,eax cRet bIoFastFill io_setup_for_filling_check: cmp ebx,edx jge short io_setup_for_filling lea edi,[esi+8] public io_setup_for_filling io_setup_for_filling:: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Some initialization ; edi = pptfxTop mov ecx,[edi].ptl_y add ecx,15 sar ecx,4 mov yTrapezoid,ecx ;yTrapezoid = (pptfxTop->y + 15) >> 4 mov edLeft.ed_cy,0 mov edLeft.ed_dptfx,-8 mov edLeft.ed_pptfx,edi mov edRight.ed_cy,0 mov edRight.ed_dptfx,8 mov edRight.ed_pptfx,edi mov esi,ppdev ;esi = ppdev ; ecx = yTrapezoid ; esi = ppdev mov eax,[esi].pdev_yOffset mov yOffset,eax ;yOffset = ppdev->yOffset add ecx,eax ;ecx = yTrapezoid += yOffset mov yTrapezoid,ecx ;yTrapezoid is kept in absolute ; coordinates mov ebx,[esi].pdev_xOffset mov xOffset,ebx ;xOffset = ppdev->xOffset ; This will guarantee that we have IO_ALL_EMPTY_FIFO_COUNT slots ; available. mov edx,CMD @@: in ax,dx and eax,FIFO_8_EMPTY ;IO_FIFO_WAIT(8) jnz short @b ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Setup hardware for a solid colour public io_initialize_solid io_initialize_solid:: ;ecx = yTrapezoid ;esi = ppdev mov cFifoEmpty,IO_ALL_EMPTY_FIFO_COUNT - 4 mov eax,ulHwForeMix or eax,FOREGROUND_COLOR mov edx,[esi].pdev_ioFrgd_mix out dx,ax ;IO_FRGD_MIX(FOREGROUND_COLOR | ; ulHwForeMix) mov eax,DATA_EXTENSION mov edx,PIX_CNTL out dx,ax ;IO_PIX_CNTL(ALL_ONES) mov eax,RECT_HEIGHT out dx,ax ;IO_MIN_AXIS_PCNT(0) mov eax,iSolidColor mov edx,[esi].pdev_ioFrgd_color out dx,ax ;IO_FRGD_COLOR(iSolidColor) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DDA initialization public io_new_trapezoid io_new_trapezoid:: lea edi,[edLeft+size EDGEDATA] mov iEdge,1 io_other_edge: sub edi,size EDGEDATA cmp [edi].ed_cy,0 jg io_check_if_another_edge io_need_new_dda: dec cEdges jl io_return_true mov edx,[edi].ed_pptfx ;edx = ped->pptfx mov ebx,[edx].ptl_x ;ebx = xStart = ped->pptfx->x mov ecx,[edx].ptl_y ;ecx = yStart = ped->pptfx->y add edx,[edi].ed_dptfx ;edx += ped->ed_dptfx cmp edx,pptfxFirst ;See if edx wrapped around ends of jae short @f ; the buffer mov edx,pptfxLast @@: cmp edx,pptfxLast jbe short @f mov edx,pptfxFirst @@: mov [edi].ed_pptfx,edx ;ped->pptfx = edx mov eax,[edx].ptl_y add eax,15 sar eax,4 add eax,yOffset ;Convert to absolute coordinates sub eax,yTrapezoid ;eax = ((ped->pptfx->y + 15) >> 4) ; - yTrapezoid jle short io_need_new_dda ;Edge has to cross a scan mov [edi].ed_cy,eax ;ped->cy = eax public io_calculate_deltas io_calculate_deltas:: mov esi,[edx].ptl_y sub esi,ecx ;esi = dN = ped->pptfx->y - yStart mov [edi].ed_lErrorDown,esi ;ped->lErrorDown = dN mov eax,[edx].ptl_x sub eax,ebx ;eax = dM = ped->pptfx->x - xStart jge short io_to_right neg eax ;eax = dM = -dM cmp eax,esi jge short io_x_major_to_left sub esi,eax mov edx,esi ;edx = lErrorUp = dN - dM mov eax,-1 ;eax = dx = -1 jmp short io_calc_rest_of_dda io_x_major_to_left: sub edx,edx div esi ;edx = lErrorUp = dM % dN neg eax ;eax = dx = - dM / dN test edx,edx jz short io_calc_rest_of_dda sub esi,edx mov edx,esi ;edx = lErrorUp = dN - (dM % dN) dec eax ;eax = dx = (-dM / dN) - 1 jmp short io_calc_rest_of_dda io_to_right: cmp eax,esi jge short io_x_major_io_to_right mov edx,eax ;edx = lErrorUp = dM sub eax,eax ;eax = dx = 0 jmp short io_calc_rest_of_dda io_x_major_io_to_right: sub edx,edx div esi ;edx = lErrorUp = dM % dN ;eax = dx = dM / dN public io_calc_rest_of_dda io_calc_rest_of_dda:: mov [edi].ed_lErrorUp,edx ;ped->lErrorUp = lErrorUp mov [edi].ed_dx,eax ;ped->dx = dx mov esi,-1 ;esi = lError = -1 (meaning that the ; initial error is zero) ; eax = dx ; ebx = xStart ('x' position of start point of edge) ; ecx = yStart ('y' position of start point of edge) ; edx = lErrorUp ; esi = lError ; edi = ped and ecx,15 jz short io_on_integer_row xor ecx,0fh ;ecx = 15 - (yStart & 15) io_advance_to_integer_row: add ebx,eax ;ebx = x += ped->dx add esi,edx ;esi = lError += lErrorUp jl short @f sub esi,[edi].ed_lErrorDown ;esi = lError -= lErrorDown inc ebx ;ebx = x++ @@: dec ecx jge short io_advance_to_integer_row io_on_integer_row: mov edx,ebx ;edx = ebx = x and edx,15 ;edx = (x & 15) jz short io_on_integer_column xor edx,0fh inc edx ;edx = 16 - (x & 15) imul edx,[edi].ed_lErrorDown sub esi,edx ;esi = lError -= lErrorDown ; * (16 - (x & 15)) add ebx,15 ;ebx = x += 15 io_on_integer_column: sar ebx,4 sar esi,4 add ebx,xOffset mov [edi].ed_x,ebx ;ped->x = (x >> 4) + ppdev->xOffset mov [edi].ed_lError,esi ;ped->lError = (lError >> 4) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Get ready to do the DDAs public io_check_if_another_edge io_check_if_another_edge:: dec iEdge jge io_other_edge ; This obtuse chunk of code calculates: ; ; cyTrapezoid = min(edLeft.ed_cy, edRight.ed_cy) ; edLeft.ed_cy -= original edRight.ed_cy ; edRight.ed_cy -= original edLeft.ed_cy mov eax,edLeft.ed_cy mov ebx,edRight.ed_cy sub eax,ebx sbb ecx,ecx mov edLeft.ed_cy,eax neg eax mov edRight.ed_cy,eax and ecx,eax sub ebx,ecx mov cyTrapezoid,ebx ; We bias the right edge by one because the S3 always expects ; widths to be the actual width less one: mov ebx,edLeft.ed_x mov esi,edRight.ed_x dec esi mov ecx,edLeft.ed_lError mov edi,edRight.ed_lError ;----------------------------------------------------------------------; ; Solid draw ;----------------------------------------------------------------------; public io_solid_draw io_solid_draw:: ; eax = ; ebx = edLeft.ed_x ; ecx = edLeft.ed_lError ; esi = edRight.ed_x - 1 ; edi = edRight.ed_lError cmp edLeft.ed_lErrorUp,0 jnz io_solid_dda cmp edRight.ed_lErrorUp,0 jnz io_solid_dda cmp edLeft.ed_dx,0 jnz io_solid_dda cmp edRight.ed_dx,0 jnz io_solid_dda cmp cyTrapezoid,1 je io_solid_dda ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Vertical-edge special case for solid colours public io_solid_vertical io_solid_vertical:: mov eax,esi sub eax,ebx jl short io_solid_vertical_zero_or_less_width sub cFifoEmpty,5 ;NOTE: If this count is changed, change ; io_solid_vertical_wait_for_fifo! jl short io_solid_vertical_wait_for_fifo io_solid_vertical_fifo_clear: mov edx,MAJ_AXIS_PCNT out dx,ax ;IO_MAJ_AXIS_PCNT( ; edRight.x - edLeft.x - 1) mov eax,yTrapezoid mov edx,CUR_Y out dx,ax ;IO_CUR_Y(yTrapezoid) mov eax,cyTrapezoid add yTrapezoid,eax ;yTrapezoid += cyTrapezoid dec eax or eax,RECT_HEIGHT mov edx,MIN_AXIS_PCNT out dx,ax ;IO_MIN_AXIS_PCNT(cyTrapezoid - 1) mov eax,ebx mov edx,CUR_X out dx,ax ;IO_CUR_X(edLeft.x) mov eax,(RECTANGLE_FILL + DRAWING_DIR_TBLRXM + \ DRAW + WRITE) mov edx,CMD out dx,ax ;IO_CMD(...) mov eax,RECT_HEIGHT mov edx,MIN_AXIS_PCNT out dx,ax ;IO_MIN_AXIS_PCNT(0) ; Save our register variables because an edge can continue into ; the next trapezoid (this is significant if we swapped edges): inc esi ;undo right bias mov edLeft.ed_x,ebx mov edRight.ed_x,esi jmp io_new_trapezoid io_solid_vertical_wait_for_fifo: push eax mov edx,CMD @@: in ax,dx and eax,FIFO_8_EMPTY ;IO_FIFO_WAIT(8) jnz short @b mov cFifoEmpty,IO_ALL_EMPTY_FIFO_COUNT - 6 pop eax jmp short io_solid_vertical_fifo_clear io_solid_vertical_zero_or_less_width: inc eax jnz short io_solid_vertical_swap_edges mov eax,cyTrapezoid add yTrapezoid,eax ;yTrapezoid += cyTrapezoid jmp io_new_trapezoid io_solid_vertical_swap_edges: push offset io_solid_vertical jmp io_swap_edges ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Run the DDAs for solid colours public io_solid_dda_loop io_solid_dda_loop:: dec cyTrapezoid jz io_solid_dda_ret public io_solid_dda io_solid_dda:: mov eax,esi sub eax,ebx jl short io_solid_dda_zero_or_less_width sub cFifoEmpty,4 ;NOTE: If this count is changed, change ; io_solid_wait_for_fifo! jl short io_solid_wait_for_fifo io_solid_dda_fifo_clear: mov edx,MAJ_AXIS_PCNT out dx,ax ;IO_MAJ_AXIS_PCNT( ; edRight.x - edLeft.x - 1) mov eax,ebx mov edx,CUR_X out dx,ax ;IO_CUR_X(edLeft.x) mov eax,yTrapezoid mov edx,CUR_Y out dx,ax ;IO_CUR_Y(yTrapezoid) inc eax mov yTrapezoid,eax ;yTrapezoid++ mov eax,(RECTANGLE_FILL + DRAWING_DIR_TBLRXM + \ DRAW + WRITE) mov edx,CMD out dx,ax ;IO_CMD(...) io_solid_dda_continue_after_zero: add ebx,edLeft.ed_dx add ecx,edLeft.ed_lErrorUp jl short @f inc ebx sub ecx,edLeft.ed_lErrorDown @@: add esi,edRight.ed_dx add edi,edRight.ed_lErrorUp jl short io_solid_dda_loop inc esi sub edi,edRight.ed_lErrorDown dec cyTrapezoid jnz short io_solid_dda io_solid_dda_ret: inc esi ;undo right bias ; Save our register variables because an edge can continue into ; the next trapezoid: mov edLeft.ed_x,ebx mov edLeft.ed_lError,ecx mov edRight.ed_x,esi mov edRight.ed_lError,edi jmp io_new_trapezoid public io_solid_wait_for_fifo io_solid_wait_for_fifo:: push eax mov edx,CMD @@: in ax,dx and eax,FIFO_8_EMPTY ;IO_FIFO_WAIT(8) jnz short @b mov cFifoEmpty,IO_ALL_EMPTY_FIFO_COUNT - 4 pop eax jmp short io_solid_dda_fifo_clear io_solid_dda_zero_or_less_width: inc eax jnz short io_solid_dda_swap_edges inc yTrapezoid ;yTrapezoid++ jmp short io_solid_dda_continue_after_zero io_solid_dda_swap_edges: push offset io_solid_dda jmp io_swap_edges ;----------------------------------------------------------------------; ; Swap edges ;----------------------------------------------------------------------; public io_swap_edges io_swap_edges:: mov eax,edLeft.ed_cy mov edx,edRight.ed_cy mov edRight.ed_cy,eax mov edLeft.ed_cy,edx ;xchg 'cy' mov eax,edLeft.ed_dptfx mov edx,edRight.ed_dptfx mov edRight.ed_dptfx,eax mov edLeft.ed_dptfx,edx ;xchg 'dptfx' mov eax,edLeft.ed_pptfx mov edx,edRight.ed_pptfx mov edRight.ed_pptfx,eax mov edLeft.ed_pptfx,edx ;xchg 'pptfx' mov eax,edLeft.ed_dx mov edx,edRight.ed_dx mov edRight.ed_dx,eax mov edLeft.ed_dx,edx ;xchg 'dx' mov eax,edLeft.ed_lErrorUp mov edx,edRight.ed_lErrorUp mov edRight.ed_lErrorUp,eax mov edLeft.ed_lErrorUp,edx ;xchg 'lErrorUp' mov eax,edLeft.ed_lErrorDown mov edx,edRight.ed_lErrorDown mov edRight.ed_lErrorDown,eax mov edLeft.ed_lErrorDown,edx;xchg 'lErrorDown' xchg ecx,edi ;xchg 'lError' xchg ebx,esi ;xchg 'x' inc ebx dec esi ;don't forget right bias PLAIN_RET io_return_true: mov eax,1 cRet bIoFastFill endProc bIoFastFill end