;----------------------------------------------------------------------- ; MODULE XFILL ; ; Point functions all MODE X 256 Color resolutions ; ; Compile with Tasm. ; C callable. ; ; ; ****** XLIB - Mode X graphics library **************** ; ****** **************** ; ****** Written By Themie Gouthas **************** ; ; egg@dstos3.dsto.gov.au ; teg@bart.dsto.gov.au ;----------------------------------------------------------------------- COMMENT $ This code is my interpretation of a simple "C" flood filling algorithm titled: * A Seed Fill Algorithm * by Paul Heckbert * from "Graphics Gems", Academic Press, 1990 The original C source is readily available at numerous internet archive sites. Its been modified and optimized for tweaked 13h modes (Mode X derrivatives). The most fundamental change is that it fills a column at a time rather than a row at a time to minimize the number of plane setting "out"s. And of course the border fill variant was a logical and useful further modification. Both functions return the number of pixels filled.. WARNING: These fill functions make heavy use of the stack and no stack checking is performed, so caution is advised. $ include xlib.inc include xfill.inc .code _x_flood_fill proc ARG X:word,Y:word,PgOfs:word,Color:word LOCAL len:word,y1:word,y2:word,deltax:word,floodval:word,\ stackptr:word,FillCount:word=STK push bp mov bp,sp sub sp,STK mov [FillCount],0 push di si mov si,[Y] mov ax,[_ScrnLogicalByteWidth] mul si ;offset of pixel's scan line in page mov di,[X] mov bx,di shr di,2 ;X/4 = offset of pixel in scan line add di,ax ;offset of pixel in page add di,[PgOfs] ;offset of pixel in display memory mov ax,SCREEN_SEG mov es,ax ;point ES:DI to the pixel's address ;---- Select read plane ------ mov ah,bl and ah,011b ;AH = pixel's plane mov al,READ_MAP ;AL = index in GC of the Read Map reg mov dx,GC_INDEX ;set the Read Map to read the pixel's out dx,ax ; plane mov al,es:[di] ;read the pixel's color cmp al,byte ptr Color ;Is dest pixel the same color as the flood? je @@Done2 ; if it is abort. mov cx,_LeftClip ; Is the dest. pixel out of the clipping window? sal cx,2 ; if not abort. cmp bx,cx jl @@Done2 mov cx,_RightClip sal cx,2 cmp bx,cx jg @@Done2 mov floodval,ax ; store the color to flood ;-- Push fill segment --- push bx ; X push si ; Y push si ; Y mov cx,1 ; deltaX (either 1 or -1 indicating direction) push cx mov stackptr,1 mov deltax,-1 ; Initialize first column scan mov y1,si ; then bypass some of the preliminary crap in mov y2,si ; the main fill loop jmp short @@entry @@Done2:mov ax,[FillCount] pop si di mov sp,bp pop bp ret @@NextScanCol: dec stackptr js @@Done2 @@WhileLoop: pop cx ; get fill segment from stack mov deltax,cx ; ie deltaX, Y1, Y2, X pop ax mov y2,ax pop si mov y1,si pop bx sub ax,si ; Acculmulate number of filled pixels jns @@PositiveY neg ax @@PositiveY: add FillCount,ax add bx,cx ; move to new column according to deltaX mov ax,bx ; Make sure the column is within the clipping sar ax,2 ; rectangle cmp ax,_LeftClip jl @@NextScanCol cmp ax,_RightClip jg @@NextScanCol ;---- Select read plane ------ mov ah,bl and ah,011b ;AH = pixel's plane mov al,READ_MAP ;AL = index in GC of the Read Map reg mov dx,GC_INDEX ;set the Read Map to read the pixel's out dx,ax ; plane @@entry: ;---- Select write plane ------ mov cl,bl and cl,011b ;CL = pixel's plane mov ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg shl ah,cl ;set only the bit for the pixel's ; plane to 1 mov dx,SC_INDEX ;set the Map Mask to enable only the out dx,ax ; pixel's plane mov ax,_ScrnLogicalByteWidth ; store logical width in CX mov cx,ax ; get offset of scan row mul si ; set ES:DI -> mov di,bx ; address of pixel at x,y1 shr di,2 add di,ax add di,PgOfs ;ES:DI->first pixel of column segment to fill mov dx,di ; save y1 offset for after upward fill mov al,byte ptr Color mov ah,byte ptr floodval @@FillColUpward: cmp si,_TopClip ; Dont fill beyond clip boundaries jl @@UpwardFillDone cmp es:[di],ah ; if flood pixel color then replace jne @@UpwardFillDone ; with new color otherwise column is done mov es:[di],al sub di,cx dec si jmp short @@FillColUpward @@UpwardFillDone: cmp si,y1 jge @@Skip inc si mov len,si cmp si,y1 jge @@AtColumnTop push bx ; queue an upward leak check push si mov ax,y1 dec ax push ax mov ax,deltax neg ax push ax inc stackptr @@AtColumnTop: mov si,y1 mov di,dx add di,cx inc si @@ColumnLoop: mov ah,byte ptr floodval mov al,byte ptr Color @@DownwardFill: cmp si,_BottomClip jg @@DownwardFillDone cmp es:[di],ah jne @@DownwardFillDone mov es:[di],al add di,cx inc si jmp short @@DownwardFill @@DownwardFillDone: push bx ; queue an upward leak check mov ax,len push ax mov ax,si dec ax push ax mov ax,deltax push ax inc stackptr mov ax,y2 inc ax cmp si,ax jle @@Skip push bx ; queue a downward leak check push ax mov ax,si dec ax push ax mov ax,deltax neg ax push ax inc stackptr @@Skip: mov ah,byte ptr floodval mov dx,y2 @@Backtrack: add di,cx inc si cmp si,dx jg @@BacktrackDone cmp byte ptr es:[di],ah jne @@Backtrack @@BacktrackDone: mov len,si cmp si,dx jle @@ColumnLoop dec stackptr js @@Done jmp @@WhileLoop @@Done: mov ax,[FillCount] pop si di mov sp,bp pop bp ret _x_flood_fill endp _x_boundary_fill proc ARG X:word,Y:word,PgOfs:word,BoundaryColor:word,Color:word LOCAL len:word,y1:word,y2:word,deltax:word,y1_offs:word,\ stackptr:word,FillCount:word=STK push bp mov bp,sp sub sp,STK mov [FillCount],0 push di si mov si,[Y] mov ax,[_ScrnLogicalByteWidth] mul si ;offset of pixel's scan line in page mov di,[X] mov bx,di shr di,2 ;X/4 = offset of pixel in scan line add di,ax ;offset of pixel in page add di,[PgOfs] ;offset of pixel in display memory mov ax,SCREEN_SEG mov es,ax ;point ES:DI to the pixel's address ;---- Select read plane ------ mov ah,bl and ah,011b ;AH = pixel's plane mov al,READ_MAP ;AL = index in GC of the Read Map reg mov dx,GC_INDEX ;set the Read Map to read the pixel's out dx,ax ; plane mov al,es:[di] ;read the pixel's color cmp al,byte ptr Color ;Is dest pixel the same color as the flood? je @@Done2 cmp al,byte ptr BoundaryColor ;Is dest pixel the same color je @@Done2 ; as the boundary color? mov cx,_LeftClip ; Is the dest. pixel out of the clipping window? sal cx,2 cmp bx,cx jl @@Done2 mov cx,_RightClip sal cx,2 cmp bx,cx jg @@Done2 push bx ; X push si ; Y push si ; Y mov cx,1 ; DX push cx mov stackptr,1 mov al,byte ptr BoundaryColor mov byte ptr [Color+1],al mov deltax,-1 mov y1,si mov y2,si jmp short @@entry @@Done2:mov ax,[FillCount] pop si di mov sp,bp pop bp ret @@NextScanCol: dec stackptr js @@Done2 @@WhileLoop: pop cx mov deltax,cx pop ax mov y2,ax pop si mov y1,si pop bx add bx,cx ; bx = X sub ax,si ; Acculmulate number of filled pixels jns @@PositiveY neg ax @@PositiveY: add FillCount,ax mov ax,bx ; Make sure the column is within the clipping sar ax,2 ; rectangle cmp ax,_LeftClip jl @@NextScanCol cmp ax,_RightClip jg @@NextScanCol ;---- Select read plane ------ mov ah,bl and ah,011b ;AH = pixel's plane mov al,READ_MAP ;AL = index in GC of the Read Map reg mov dx,GC_INDEX ;set the Read Map to read the pixel's out dx,ax ; plane @@entry: ;---- Select write plane ------ mov cl,bl and cl,011b ;CL = pixel's plane mov ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg shl ah,cl ;set only the bit for the pixel's ; plane to 1 mov dx,SC_INDEX ;set the Map Mask to enable only the out dx,ax ; pixel's plane mov ax,_ScrnLogicalByteWidth ; store logical width in CX mov cx,ax ; get offset of scan row mul si ; set ES:DI -> mov di,bx ; address of pixel at x,y1 shr di,2 add di,ax add di,PgOfs mov y1_offs,di ; save y1 offset for after upward fill mov ax,Color ; al = Color ah = BoundaryColor @@FillColUpward: cmp si,_TopClip ; Dont fill beyond clip boundaries jl @@UpwardFillDone mov dl,es:[di] cmp dl,ah je @@UpwardFillDone cmp dl,al je @@UpwardFillDone mov es:[di],al sub di,cx dec si jmp short @@FillColUpward @@UpwardFillDone: cmp si,y1 jge @@Skip inc si mov len,si cmp si,y1 jge @@AtColumnTop push bx ; queue an upward leak check push si mov ax,y1 dec ax push ax mov ax,deltax neg ax push ax inc stackptr @@AtColumnTop: mov si,y1 mov di,y1_offs add di,cx inc si @@ColumnLoop: mov ax,Color ; al = Color ah = BoundaryColor @@DownwardFill: cmp si,_BottomClip jg @@DownwardFillDone cmp es:[di],ah je @@DownwardFillDone cmp es:[di],al je @@DownwardFillDone mov es:[di],al add di,cx inc si jmp short @@DownwardFill @@DownwardFillDone: push bx ; queue an upward leak check mov ax,len push ax mov ax,si dec ax push ax mov ax,deltax push ax inc stackptr mov ax,y2 inc ax cmp si,ax jle @@Skip push bx ; queue a downward leak check push ax mov ax,si dec ax push ax mov ax,deltax neg ax push ax inc stackptr @@Skip: mov ax,Color ; al = Color ah = BoundaryColor @@Backtrack: add di,cx inc si cmp si,y2 jg @@BacktrackDone mov dl,byte ptr es:[di] cmp dl,al je @@Backtrack cmp dl,ah je @@Backtrack @@BacktrackDone: mov len,si cmp si,y2 jle @@ColumnLoop dec stackptr js @@Done jmp @@WhileLoop @@Done: mov ax,[FillCount] pop si di mov sp,bp pop bp ret _x_boundary_fill endp end