;----------------------------------------------------------------------- ; MODULE XPBITMAP ; ; Planar Bitmap functions - System 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 $ This module implements a set of functions to operate on planar bitmaps. Planar bitmaps as used by these functions have the following structure: BYTE 0 The bitmap width in bytes (4 pixel groups) range 1..255 BYTE 1 The bitmap height in rows range 1..255 BYTE 2..n1 The plane 0 pixels width*height bytes BYTE n1..n2 The plane 1 pixels width*height bytes BYTE n2..n3 The plane 2 pixels width*height bytes BYTE n3..n4 The plane 3 pixels width*height bytes These functions provide the fastest possible bitmap blts from system ram to to video and further, the single bitmap is applicable to all pixel allignments. The masked functions do not need separate masks since all non zero pixels are considered to be masking pixels, hence if a pixel is 0 the corresponding screen destination pixel is left unchanged. $ include xlib.inc include xpbitmap.inc LOCALS .code ;---------------------------------------------------------------------- ; x_flip_masked_pbm - mask write a planar bitmap from system ram to video ram ; all zero source bitmap bytes indicate destination byte to be left unchanged ; If "Orientation" is set then the bitmap is flipped from left to right as ; it is drawn ; ; Source Bitmap structure: ; ; Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1).., ; Bitmap data (plane 2)..,Bitmap data (plane 3).. ; ; note width is in bytes ie lots of 4 pixels ; ; x_flip_masked_pbm(X,Y,ScrnOffs,char far * Bitmap, Orientation) ; ; ; LIMITATIONS: No clipping is supported ; Only supports bitmaps with widths which are a multiple of ; 4 pixels ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_flip_masked_pbm proc ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word LOCAL Plane:byte,BMHeight:byte,LineInc: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 mov es,ax mov ax,[Y] ; Calculate dest screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul bx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in dest row add di,dx ; add to DI giving screen offset of ; first pixel's byte lds si,[Bitmap] ; DS:SI -> Bitmap data lodsw ; Al = B.M. width (bytes) AH = B.M. ; height cmp Orientation,0 jz UnFlippedMasked mov [BMHeight],ah ; Save source bitmap dimensions xor ah,ah ; LineInc = bytes to the begin. add bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov bh,al ; Use bh as column loop count and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov dx,SC_INDEX ; Prepare VGA for cpu to video writes mov al,MAP_MASK out dx,al inc dx mov [Plane],4 ; Set plane counter to 4 @@PlaneLoop: push di ; Save bitmap's start dest. offset mov bl,[BMHeight] ; Reset row counter (BL) mov al,ah out dx,al ; set vga write plane @@RowLoop: mov cl,bh ; Reset Column counter cl @@ColLoop: lodsb ; Get next source bitmap byte or al,al ; If not zero then write to dest. jz @@NoPixel ; otherwise skip to next byte mov es:[di],al @@NoPixel: dec di loop @@ColLoop ; loop if more columns left add di,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop di ; Restore bitmaps start dest byte ror ah,1 ; Shift mask for next plane sbb di,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_flip_masked_pbm endp ;---------------------------------------------------------------------- ; x_put_masked_pbm - mask write a planar bitmap from system ram to video ram ; all zero source bitmap bytes indicate destination byte to be left unchanged ; ; Source Bitmap structure: ; ; Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1).., ; Bitmap data (plane 2)..,Bitmap data (plane 3).. ; ; note width is in bytes ie lots of 4 pixels ; ; x_put_masked_pbm(X,Y,ScrnOffs,char far * Bitmap) ; ; ; LIMITATIONS: No clipping is supported ; Only supports bitmaps with widths which are a multiple of ; 4 pixels ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_put_masked_pbm proc ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword LOCAL Plane:byte,BMHeight:byte,LineInc: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 mov es,ax mov ax,[Y] ; Calculate dest screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul bx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in dest row add di,dx ; add to DI giving screen offset of ; first pixel's byte lds si,[Bitmap] ; DS:SI -> Bitmap data lodsw ; Al = B.M. width (bytes) AH = B.M. ; height UnFlippedMasked: mov [BMHeight],ah ; Save source bitmap dimensions xor ah,ah ; LineInc = bytes to the begin. sub bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov bh,al ; Use bh as column loop count and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov dx,SC_INDEX ; Prepare VGA for cpu to video writes mov al,MAP_MASK out dx,al inc dx mov [Plane],4 ; Set plane counter to 4 @@PlaneLoop: push di ; Save bitmap's start dest. offset mov bl,[BMHeight] ; Reset row counter (BL) mov al,ah out dx,al ; set vga write plane @@RowLoop: mov cl,bh ; Reset Column counter cl @@ColLoop: lodsb ; Get next source bitmap byte or al,al ; If not zero then write to dest. jz @@NoPixel ; otherwise skip to next byte mov es:[di],al @@NoPixel: inc di loop @@ColLoop ; loop if more columns left add di,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop di ; Restore bitmaps start dest byte rol ah,1 ; Shift mask for next plane adc di,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_masked_pbm endp ;---------------------------------------------------------------------- ; x_put_pbm - Write a planar bitmap from system ram to video ram ; ; Source Bitmap structure: ; ; Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1).., ; Bitmap data (plane 2)..,Bitmap data (plane 3).. ; ; note width is in bytes ie lots of 4 pixels ; ; x_put_pbm(X,Y,ScrnOffs,char far * Bitmap) ; ; ; LIMITATIONS: No clipping is supported ; Only supports bitmaps with widths which are a multiple of ; 4 pixels ; FEATURES : Automatically selects REP MOVSB or REP MOVSW depending on ; source bitmap width, by modifying opcode ;-). ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_put_pbm proc ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword LOCAL Plane:byte,BMHeight:byte,LineInc: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 mov es,ax mov ax,[Y] ; Calculate dest screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul bx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in dest row add di,dx ; add to DI giving screen offset of ; first pixel's byte lds si,[Bitmap] ; DS:SI -> Bitmap data lodsw ; Al = B.M. width (bytes) AH = B.M. ; height UnFlipped: mov [BMHeight],ah ; Save source bitmap dimensions xor ah,ah ; LineInc = bytes to the begin. sub bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov bh,al ; Self Modifying, Shame, shame shame.. and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov dx,SC_INDEX ; Prepare VGA for cpu to video writes mov al,MAP_MASK out dx,al inc dx mov [Plane],4 ; Set plane counter to 4 @@PlaneLoop: push di mov bl,[BMHeight] mov al,ah out dx,al @@RowLoop: mov cl,bh shr cl,1 rep movsw ; Copy a complete row for curr plane adc cl,0 rep movsb add di,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop di ; Restore bitmaps start dest byte rol ah,1 ; Shift mask for next plane adc di,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_put_pbm endp ;---------------------------------------------------------------------- ; x_flip_pbm - Write a planar bitmap from system ram to video ram ; If "Orientation" is set then the bitmap is flipped from left to right as ; it is drawn ; ; Source Bitmap structure: ; ; Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1).., ; Bitmap data (plane 2)..,Bitmap data (plane 3).. ; ; note width is in bytes ie lots of 4 pixels ; ; x_flip_pbm(X,Y,ScrnOffs,char far * Bitmap, WORD orientation) ; ; ; LIMITATIONS: No clipping is supported ; Only supports bitmaps with widths which are a multiple of ; 4 pixels ; ; NOTES: The flipped put function is slower than the standard put function ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_flip_pbm proc ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word LOCAL Plane:byte,BMHeight:byte,LineInc: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 mov es,ax mov ax,[Y] ; Calculate dest screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul bx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in dest row add di,dx ; add to DI giving screen offset of ; first pixel's byte lds si,[Bitmap] ; DS:SI -> Bitmap data lodsw ; Al = B.M. width (bytes) AH = B.M. ; height cmp Orientation,0 jz UnFlipped mov [BMHeight],ah ; Save source bitmap dimensions xor ah,ah ; LineInc = bytes to the begin. add bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov bh,al ; Use bh as column loop count and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov dx,SC_INDEX ; Prepare VGA for cpu to video writes mov al,MAP_MASK out dx,al inc dx mov [Plane],4 ; Set plane counter to 4 @@PlaneLoop: push di ; Save bitmap's start dest. offset mov bl,[BMHeight] ; Reset row counter (BL) mov al,ah out dx,al ; set vga write plane @@RowLoop: mov cl,bh ; Reset Column counter cl @@ColLoop: lodsb mov es:[di],al dec di sub di,2 loop @@ColLoop ; loop if more columns left @@DoneCol: add di,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop di ; Restore bitmaps start dest byte ror ah,1 ; Shift mask for next plane sbb di,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_flip_pbm endp ;---------------------------------------------------------------------- ; x_get_pbm - Read a planar bitmap to system ram from video ram ; ; Source Bitmap structure: ; ; Width:byte, Height:byte, Bitmap data (plane 0)...Bitmap data (plane 1).., ; Bitmap data (plane 2)..,Bitmap data (plane 3).. ; ; note width is in bytes ie lots of 4 pixels ; ; x_get_pbm(X,Y,BMwidth,BMheight,ScrnOffs,char far * Bitmap) ; ; ; LIMITATIONS: No clipping is supported ; Only supports bitmaps with widths which are a multiple of ; 4 pixels ; FEATURES : Automatically selects REP MOVSB or REP MOVSW depending on ; source bitmap width, by modifying opcode ;-). ; ; Written by Themie Gouthas ;---------------------------------------------------------------------- _x_get_pbm proc ARG X:word,Y:word,SrcWidth:byte,SrcHeight:byte,ScrnOffs:word,Bitmap:dword LOCAL Plane:byte,LineInc:word=LocalStk push bp mov bp,sp sub sp,LocalStk ; Create space for local variables push si push di push ds cld mov ax,[Y] ; Calculate screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. Y coord by Screen mul bx ; width then adding screen offset mov si,[ScrnOffs] ; store result in SI add si,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in screen row add si,dx ; add to SI giving screen offset of ; first pixel's byte mov ax,SCREEN_SEG mov ds,ax les di,[Bitmap] ; ES:DI -> Bitmap data mov al,[SrcWidth] mov ah,[SrcHeight] stosw ; Al = B.M. width (bytes) AH = B.M. ; height xor ah,ah ; LineInc = bytes to the begin. sub bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov bh,al ; Self Modifying, Shame, shame shame.. and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov dx,GC_INDEX ; Prepare VGA for cpu to video reads mov al,READ_MAP out dx,al inc dx mov [Plane],4 ; Set plane counter (BH) to 4 mov al,cl @@PlaneLoop: push si mov bl,[SrcHeight] out dx,al @@RowLoop: mov cl,bh shr cl,1 rep movsw ; Copy a complete row for curr plane adc cl,0 rep movsb add si,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop si ; Restore bitmaps start dest byte inc al ; Select next plane to read from and al,3 ; rol ah,1 ; Shift mask for next plane adc si,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret _x_get_pbm endp end ARG X:word,Y:word,ScrnOffs:word,Bitmap:dword,Orientation:word LOCAL Plane:byte,BMHeight:byte,LineInc:word,Columns: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 mov es,ax mov ax,[Y] ; Calculate dest screen row mov bx,[_ScrnLogicalByteWidth] ; by mult. dest Y coord by Screen mul bx ; width then adding screen offset mov di,[ScrnOffs] ; store result in DI add di,ax mov cx,[X] ; Load X coord into CX and make a mov dx,cx ; copy in DX shr dx,2 ; Find starting byte in dest row add di,dx ; add to DI giving screen offset of ; first pixel's byte lds si,[Bitmap] ; DS:SI -> Bitmap data lodsw ; Al = B.M. width (bytes) AH = B.M. ; height cmp Orientation,0 jz UnFlipped mov [BMHeight],ah ; Save source bitmap dimensions xor ah,ah ; LineInc = bytes to the begin. add bx,ax ; of bitmaps next row on screen mov [LineInc],bx mov [Columns],al ; Use bh as column loop count and cx,0003h ; mask X coord giving plane of 1st ; bitmap pixel(zero CH coincidentally) mov ah,11h ; Init. mask for VGA plane selection shl ah,cl ; Shift for starting pixel plane mov bh,ah mov dx,SC_INDEX ; Prepare VGA for cpu to video writes mov al,MAP_MASK out dx,al inc dx mov [Plane],4 ; Set plane counter to 4 @@PlaneLoop: push di ; Save bitmap's start dest. offset mov bl,[BMHeight] ; Reset row counter (BL) mov al,bh out dx,al ; set vga write plane @@RowLoop: mov cl,[Columns] ; Reset Column counter cl shr cx,1 jnc @@ColLoop lodsb mov es:[di],al dec di @@ColLoop: lodsw ; Get next source bitmap byte xchg al,ah mov es:[di],ax sub di,2 loop @@ColLoop ; loop if more columns left add di,[LineInc] ; Move to next row dec bl ; decrement row counter jnz @@RowLoop ; Jump if more rows left pop di ; Restore bitmaps start dest byte ror bh,1 ; Shift mask for next plane sbb di,0 ; If wrapped increment dest address dec [Plane] ; Decrement plane counter jnz @@PlaneLoop ; Jump if more planes left pop ds ; restore data segment pop di ; restore registers pop si mov sp,bp ; dealloc local variables pop bp ret