;----------------------------------------------------------------------- ; MODULE XVBITMAP ; ; Video Bitmap functions - Video Ram <-> Video Ram ; ; 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 $ The XVBITMAP module implements yet another type of bitmap to complement planar and compiled bitmaps, VRAM based bitmaps. If a 4 cylinder car is analagous to planar bitmaps, that is thrifty on memory consumption but low performance and and a V8 is analagous to Compiled bitmaps, memory guzzlers that really fly, then VRAM based bitmaps are the 6 cylinder modest performers with acceptable memory consumption. To summarise their selling points, VBM's are moderately fast with fair memory consumption, and unlike compiled bitmaps, can be clipped. The disadvantages are that they are limited by the amount of free video ram and have a complex structure. The VRAM bitmap format is rather complex consisting of components stored in video ram and components in system ram working together. This complexity necessitates the existence of a creation function "x_make_vbm" which takes an input linear bitmap and generates the equivalent VBM (VRAM Bit Map). VBM structure: WORD 0 Size Total size of this VBM structure in bytes WORD 1 ImageWidth Width in bytes of the image (for all alignments) WORD 2 ImageHeight Height in scan lines of the image WORD 3 Alignment 0 ImagePtr Offset in VidRAM of this aligned image +--WORD 4 MaskPtr Offset (within this structure's DS) of | . alignment masks | . | . | WORD 9 Alignment 3 ImagePtr Offset in VidRAM of this aligned image +|--WORD 10 MaskPtr Offset (within this structure's DS) of || alignment masks || |+->BYTE 21 (WORD 11) -------+-- Image masks for alignment 0 | . | | . | | BYTE 21 + ImageWidth*ImageHeight -----+ | | . | . (similaly for alignments 1 - 2 ) | . | +-->BYTE 21 + 3*ImageWidth*ImageHeight + 1-+-- Image masks for alignment 3 . | . | BYTE 21 + 4*(ImageWidth*ImageHeight) --+ . . << Similarly for alignments 2 and 3 >> . . BYTE 21 + 4*(ImageWidth*ImageHeight) ------------- (And dont forget the corresponding data in video ram) $ include xlib.inc include xvbitmap.inc VBM_info_struc struc Size dw ? ImageWidth dw ? ImageHeight dw ? ; AlignData dw ? VBM_info_struc ends AlignData equ 6 VBM_alignment_struc struc ImagePtr dw ? MaskPtr dw ? VBM_alignment_struc ends .code ;---------------------------------------------------------------------- ; x_store_vbm_image ; ; Store the linear bitmap in video RAM using the specified alignment and ; start address. Returns number video ram bytes used. ; ; THIS FUNCTION IS FOR USE BY x_make_masked_vbm ; ; Prototype: ; ; x_store_vbm_image(unsigned int vramoffs, unsigned int Align, ; char far *lbm); ; ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_store_vbm_image proc ARG VramOffs:word,Align:word,LBitmap:dword LOCAL BMWidth:byte=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov ax,SCREEN_SEG ; Point ES to screen segment mov es,ax mov di,[VramOffs] ; Point ES:DI to VRAM dest start mov bx,[Align] ; Set BL to first pixel plane align and bl,03h lds si,[LBitmap] ; DS:SI -> source linear Bitmap lodsw ; Al = B.M. width (bytes) AH = B.M. mov bh,ah ; Save source bitmap dimensions mov [BMWidth],al ; mov dx,SC_INDEX ; Initialize Map Mask for plane mov al,MAP_MASK ; selection out dx,al inc dx xor ch,ch ; clear CH @@RowLoop: mov cl,bl ; Set initial plane for current mov ah,11h ; allignment shl ah,cl mov cl,[BMWidth] ; Initialize column counter @@ColLoop: mov al,ah out dx,al ; set vga write plane lodsb ; load next LBM pixel mov es:[di],al ; store it in Video Ram shl ah,1 ; rotate plane mask jnb @@NoAddrIncr ; Time to increment dest address ? inc di ; Yes: increment addr and reset mov ah,11h ; plane mask to plane 0 @@NoAddrIncr: loop @@ColLoop ; Loop to next pixel column cmp ah,11h ; je @@skip inc di ; Increment dest addr ;@@skip: dec bh ; Decrement row counter jnz @@RowLoop ; Jump if more rows to go mov ax,di ; calculate video RAM consumed and sub ax,[VramOffs] ; return value pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_store_vbm_image endp _x_put_masked_vbm proc ARG X:word,Y:word,ScrnOffs:word,SrcVBM:dword LOCAL VBMWidth:word,VBMHeight:word,NextLineIncr:word=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov ax,SCREEN_SEG ; Point es to VGA segment mov es,ax mov ax,[Y] ; Calculate dest screen row mov cx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul cx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov si,[X] ; Load X coord into CX and make a mov bx,si ; copy in DX shr bx,2 ; Find starting byte in dest row add di,bx ; add to DI giving screen offset of ; first pixel's byte and si,3 ; get pixel alignment in si lds bx,[SrcVBM] ; DS:BX -> VBM data structure shl si,2 ; si = offset of data for curr ; alignment mov ax,word ptr [bx+ImageHeight] ; Get image height mov [VBMHeight],ax mov ax,word ptr [bx+ImageWidth] ; Get image width mov [VBMWidth],ax sub cx,ax ; NextLineIncr = bytes to the begin. mov [NextLineIncr],cx ; of bitmaps next row on screen mov dx,[bx+MaskPtr+AlignData+si] ; DS:SI -> mask data mov bx,[bx+ImagePtr+AlignData+si] ; ES:BX -> source video bitmap mov si,dx mov dx,GC_INDEX ; Set bit mask for all bits from mov ax,BIT_MASK ; VGA latches and none from CPU out dx,ax mov dx,SC_INDEX ; Point SC register to map mask mov al,MAP_MASK ; in preperation for masking data out dx,al inc dx ; Point dx to SC data register mov ah,byte ptr [VBMHeight] ; AH = Scanline loop counter @@RowLoop: mov cx,[VBMWidth] ; Width in bytes across @@ColumnLoop: lodsb out dx,al mov al,es:[bx] ; load latches from source bitmap stosb ; store latches to dest. bitmap inc bx loop @@ColumnLoop add di,[NextLineIncr] ; point to start of next dest row dec ah ; decrement scan line counter jnz @@RowLoop ; jump if more scanlines left mov dx,GC_INDEX+1 ; Restore bitmask to the default - mov al,0ffh ; all data from cpu out dx,al pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_masked_vbm endp _x_put_masked_vbm_clipx proc ARG X:word,Y:word,ScrnOffs:word,SrcVBM:dword LOCAL DataInc,LeftSkip,VBMWidth,VBMHeight,NextLineIncr:word=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov di,[X] ; load X coord int DI and make a mov si,di ; copy in SI sar di,2 ; Find Byte offset of X coord and si,3 ; Calculate pixels plane alignment shl si,2 ; Prepare to lookup mask & data les bx,[SrcVBM] ; ES:BX -> begining of VBM data mov cx,es:[bx+ImageWidth] ; Get image width and save in CX ;;;;; CLIP PROCESSING FOR LEFT CLIP BORDER ;;;;;;;;;;;;;;;;;;; mov dx,[_LeftClip] sub dx,di jle @@NotLeftClip cmp dx,cx jnl @@NotVisible add di,dx mov [LeftSkip],dx mov [DataInc],dx sub cx,dx jmp short @@HorizClipDone ;;;; EXIT FOR COMPLETELY OBSCURED V.B.M's ;;;;;;;;;;;;;;;;;;;;;; @@NotVisible: mov ax,1 pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret ;;;;; CLIP PROCESSING FOR RIGHT CLIP BORDER ;;;;;;;;;;;;;;;;;;; @@NotLeftClip: mov dx,[_RightClip] sub dx,di js @@NotVisible mov [LeftSkip],0 mov [DataInc],0 cmp dx,cx jge @@HorizClipDone inc dx sub cx,dx mov [DataInc],cx mov cx,dx @@HorizClipDone: add di,[ScrnOffs] ; Add the current page offset mov [VBMWidth],cx mov ax,es:[bx+ImageHeight] ; Get image height and save in AX mov [VBMHeight],ax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax,[Y] ; Calculate dest screen row mov cx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul cx ; width then adding screen offset add di,ax ; Add Dest Screen Row to di sub cx,[VBMWidth] mov [NextLineIncr],cx mov ax,es ; copy ES to DS mov ds,ax mov ax,SCREEN_SEG ; Point es to VGA segment mov es,ax mov ax,[bx+MaskPtr+AlignData+si] ; DS:SI -> mask data mov bx,[bx+ImagePtr+AlignData+si] ; ES:BX -> source video bitmap mov si,ax mov ax,[LeftSkip] ; Skip data/mask bytes in add bx,ax ; each row that have been clipped add si,ax ; by the L.H.S border mov dx,GC_INDEX ; Set bit mask for all bits from mov ax,BIT_MASK ; VGA latches and none from CPU out dx,ax mov dx,SC_INDEX ; Point SC register to map mask mov al,MAP_MASK ; in preperation for masking data out dx,al inc dx ; Point dx to SC data register mov ah,byte ptr [VBMHeight] ; AH = Scanline loop counter @@RowLoop: mov cx,[VBMWidth] ; Width in bytes across @@ColumnLoop: lodsb out dx,al mov al,es:[bx] ; load latches from source bitmap stosb ; store latches to dest. bitmap inc bx loop @@ColumnLoop add bx,[DataInc] add si,[DataInc] add di,[NextLineIncr] ; point to start of next dest row dec byte ptr ah ; decrement scan line counter jnz @@RowLoop ; jump if more scanlines left mov dx,GC_INDEX+1 ; Restore bitmask to the default - mov al,0ffh ; all data from cpu out dx,al xor ax,ax pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_masked_vbm_clipx endp _x_put_masked_vbm_clipy proc ARG X:word,Y:word,ScrnOffs:word,SrcVBM:dword LOCAL VBMWidth,VBMHeight,TopRow,NextLineIncr:word=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov di,[X] ; load X coord int DI and make a mov si,di ; copy in SI and si,3 ; Calculate pixels plane alignment shl si,2 ; Prepare to lookup mask & data les bx,[SrcVBM] ; ES:BX -> begining of VBM data mov ax,es:[bx+ImageHeight] ; Get image height and save in AX ;;;;; CLIP PROCESSING FOR TOP CLIP BORDER ;;;;;;;;;;;;;;;;;;;;; mov dx,[_TopClip] ; Compare u.l. Y coord with Top sub dx,[Y] ; clipping border jle @@NotTopClip ; jump if VBM not clipped from above cmp dx,ax jnl @@NotVisible ; jump if VBM is completely obscured mov [TopRow],dx sub ax,dx add [Y],dx jmp short @@VertClipDone ;;;; EXIT FOR COMPLETELY OBSCURED V.B.M's ;;;;;;;;;;;;;;;;;;;;;; @@NotVisible: mov ax,1 pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret ;;;;; CLIP PROCESSING FOR BOTTOM CLIP BORDER ;;;;;;;;;;;;;;;;;;; @@NotTopClip: mov dx,[_BottomClip] sub dx,[Y] js @@NotVisible mov [TopRow],0 cmp dx,ax jg @@VertClipDone inc dx mov ax,dx @@VertClipDone: shr di,2 ; Find Byte offset of X coord add di,[ScrnOffs] ; Add the current page offset mov cx,es:[bx+ImageWidth] ; Get image width and save in CX mov [VBMWidth],cx mov [VBMHeight],ax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax,[Y] ; Calculate dest screen row mov cx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul cx ; width then adding screen offset add di,ax ; Add Dest Screen Row to di sub cx,[VBMWidth] mov [NextLineIncr],cx mov ax,es ; copy ES to DS mov ds,ax mov ax,SCREEN_SEG ; Point es to VGA segment mov es,ax mov ax,[bx+MaskPtr+AlignData+si] ; DS:SI -> mask data mov bx,[bx+ImagePtr+AlignData+si] ; ES:BX -> source video bitmap mov si,ax mov ax,[VBMWidth] ; Increment DS:BX and DS:SI to mul [TopRow] ; skip image/mask data that has add bx,ax ; been clipped by the top border add si,ax mov dx,GC_INDEX ; Set bit mask for all bits from mov ax,BIT_MASK ; VGA latches and none from CPU out dx,ax mov dx,SC_INDEX ; Point SC register to map mask mov al,MAP_MASK ; in preperation for masking data out dx,al inc dx ; Point dx to SC data register mov ah,byte ptr [VBMHeight] ; AH = Scanline loop counter @@RowLoop: mov cx,[VBMWidth] ; Width in bytes across @@ColumnLoop: lodsb out dx,al mov al,es:[bx] ; load latches from source bitmap stosb ; store latches to dest. bitmap inc bx loop @@ColumnLoop add di,[NextLineIncr] ; point to start of next dest row dec byte ptr ah ; decrement scan line counter jnz @@RowLoop ; jump if more scanlines left mov dx,GC_INDEX+1 ; Restore bitmask to the default - mov al,0ffh ; all data from cpu out dx,al xor ax,ax pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_masked_vbm_clipy endp _x_put_masked_vbm_clipxy proc ARG X:word,Y:word,ScrnOffs:word,SrcVBM:dword LOCAL DataInc,LeftSkip,VBMWidth,VBMHeight,TopRow,NextLineIncr:word=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov di,[X] ; load X coord int DI and make a mov si,di ; copy in SI sar di,2 ; Find Byte offset of X coord and si,3 ; Calculate pixels plane alignment shl si,2 ; Prepare to lookup mask & data les bx,[SrcVBM] ; ES:BX -> begining of VBM data mov cx,es:[bx+ImageWidth] ; Get image width and save in CX mov ax,es:[bx+ImageHeight] ; Get image height and save in AX ;;;;; CLIP PROCESSING FOR TOP CLIP BORDER ;;;;;;;;;;;;;;;;;;;;; mov dx,[_TopClip] ; Compare u.l. Y coord with Top sub dx,[Y] ; clipping border jle @@NotTopClip ; jump if VBM not clipped from above cmp dx,ax jnl @@NotVisible ; jump if VBM is completely obscured mov [TopRow],dx sub ax,dx add [Y],dx jmp short @@VertClipDone ;;;; EXIT FOR COMPLETELY OBSCURED V.B.M's ;;;;;;;;;;;;;;;;;;;;;; @@NotVisible: mov ax,1 pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret ;;;;; CLIP PROCESSING FOR BOTTOM CLIP BORDER ;;;;;;;;;;;;;;;;;;; @@NotTopClip: mov dx,[_BottomClip] sub dx,[Y] js @@NotVisible mov [TopRow],0 cmp dx,ax jg @@VertClipDone inc dx mov ax,dx @@VertClipDone: ;;;;; CLIP PROCESSING FOR LEFT CLIP BORDER ;;;;;;;;;;;;;;;;;;; mov dx,[_LeftClip] sub dx,di jle @@NotLeftClip cmp dx,cx jnl @@NotVisible add di,dx mov [LeftSkip],dx mov [DataInc],dx sub cx,dx jmp short @@HorizClipDone ;;;;; CLIP PROCESSING FOR RIGHT CLIP BORDER ;;;;;;;;;;;;;;;;;;; @@NotLeftClip: mov dx,[_RightClip] sub dx,di js @@NotVisible mov [LeftSkip],0 mov [DataInc],0 cmp dx,cx jge @@HorizClipDone inc dx sub cx,dx mov [DataInc],cx mov cx,dx @@HorizClipDone: add di,[ScrnOffs] ; Add the current page offset mov [VBMWidth],cx mov [VBMHeight],ax ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; mov ax,[Y] ; Calculate dest screen row mov cx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul cx ; width then adding screen offset add di,ax ; Add Dest Screen Row to di sub cx,[VBMWidth] mov [NextLineIncr],cx mov ax,es ; copy ES to DS mov ds,ax mov ax,SCREEN_SEG ; Point es to VGA segment mov es,ax mov ax,[bx+MaskPtr+AlignData+si] ; DS:SI -> mask data mov bx,[bx+ImagePtr+AlignData+si] ; ES:BX -> source video bitmap mov si,ax mov ax,[VBMWidth] ; Increment DS:BX and DS:SI to add ax,[DataInc] ; skip image/mask data that has mul [TopRow] ; been clipped by the top border add ax,[LeftSkip] ; Skip also data/mask bytes in add bx,ax ; each row that have been clipped add si,ax ; by the L.H.S border mov dx,GC_INDEX ; Set bit mask for all bits from mov ax,BIT_MASK ; VGA latches and none from CPU out dx,ax mov dx,SC_INDEX ; Point SC register to map mask mov al,MAP_MASK ; in preperation for masking data out dx,al inc dx ; Point dx to SC data register mov ah,byte ptr [VBMHeight] ; AH = Scanline loop counter @@RowLoop: mov cx,[VBMWidth] ; Width in bytes across @@ColumnLoop: lodsb out dx,al mov al,es:[bx] ; load latches from source bitmap stosb ; store latches to dest. bitmap inc bx loop @@ColumnLoop add bx,[DataInc] add si,[DataInc] add di,[NextLineIncr] ; point to start of next dest row dec byte ptr ah ; decrement scan line counter jnz @@RowLoop ; jump if more scanlines left mov dx,GC_INDEX+1 ; Restore bitmask to the default - mov al,0ffh ; all data from cpu out dx,al xor ax,ax pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_masked_vbm_clipxy endp end