home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_PAS
/
XLIB_TP5.ZIP
/
UNITS
/
X_BITMAP.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-01-23
|
118KB
|
3,249 lines
{$G+}
Unit X_Bitmap;
(*
Bitmap procedures. (load,save,put,convert)
****** XLIB - Mode X graphics library ****************
****** ****************
****** Written By Themie Gouthas ( C-Version ) ****************
****** Converted By Christian Harms in TP ****************
Gouthas : egg@dstos3.dsto.gov.au or teg@bart.dsto.gov.au
Harms : harms@minnie.informatik.uni-stuttgart.de
- Planar Bitmap (pbm) functions - System Ram <-> Video Ram
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
or in Pascal :
record pbm of
X_Byte,Y_Pixel : Byte;
Plane0,Plane1,Plane2,Plane3 : Array[1..Y_Pixel,1..X_Byte] of Byte;
end;
But these Stucture are not interessting, because all pbm's are used
from pure asm-Procedures.
These functions provide the fastest possible bitmap blts from system ram
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.
- Linear Bitmap (lbm) can only converted from/in pbm, but the are easy to
change with Turbo Pascal.
record lbm of
X,Y : Byte;
Pixel : Array[1..Y,1..X] of Byte;
end;
- Compiled Bitmap (cbm) is the fastes Bitmap format in XLib_TP, but the
size can be x3 of pbm (Speed x6).
cbm are fixed to one ScreenWidth after converting in cbm (!)and you can
only cbm as masked bitmaps.
- Interpreted Bitmap (ibm) is a format to save space. ibm can be to 50%
of the pbm, the speed is 50% - 100 % faster then pbm.
format : byte 0 : The bitmap width
byte 1 The bitmap height
next bytes will be interpreted
if zero , add ScreenPointer with next byte
else copy the next n bytes to screen
if x=MaxX then add ScrennPointer do next BitmapbeginLine
next Loop
pack - example :
black line (0,0,0,0,0,0,0,0,0,0) as (0,10);
color line (2,3,2,3,2,3,2,3,2,3) as (10,2,3,2,3,2,3,2,3,2,3);
normal line (0,0,0,0,0,9,8,7,6,5) as (0,5, 5,9,8,7,6,5);
Smaller than pbm, if some pixels with color 0 in bitmap
Faster than pbm, because no every pixel-compares
- The VBM format 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_lbm_to_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)
*)
interface
const EXT_pbm = 'PBM';
EXT_lbm = 'BM';
EXT_ibm = 'IBM';
(* var Bitmap could be an Array of Byte or a pointer (MUST allocated !) *)
(* Some of the procedure work with Heap-memory. No Size checking included !*)
(******************************* PBM ***************************************)
(* Put Planar Bitmap from System RAM to Pos.(X,Y). *)
procedure x_put_pbm(X,Y:Word;var Bitmap);
(* Put Planar Bitmap from System RAM to Pos.(X,Y) by skipping all 0-Pixel. *)
procedure x_put_masked_pbm(X,Y:Word;var Bitmap);
(* All put procedures with clipping. *)
procedure x_put_pbm_clipy(X,Y:Word;Var Bitmap);
procedure x_put_pbm_clipx(X,Y:Word;Var Bitmap);
procedure x_put_pbm_clipxy(X,Y:Word;Var Bitmap);
procedure x_put_masked_pbm_clipy(X,Y:Word;Var Bitmap);
procedure x_put_masked_pbm_clipx(X,Y:Word;Var Bitmap);
procedure x_put_masked_pbm_clipxy(X,Y:Word;Var Bitmap);
(* Copy Planar Bitmap from Pos.(X1,Y1,X2,Y2) to System Ram. *)
procedure x_get_pbm(X1,Y1,X2,Y2:Word;var Bitmap);
(* Return the Memory for the Bitmap to store in System Ram. *)
function x_pbm_size(x1,y1,x2,y2:Word):Word;
function x_sizeof_pbm(var BitMap):Word;
procedure x_get_pbm_sizeXY(var x,y:Word;var Bitmap);
(* Save Planar Bitmap to File with Name. Name with .pbm automatical *)
procedure x_save_pbm(var Name:String;var Bitmap);
(* Load Planar Bitmap from File with Name. *)
procedure x_load_pbm(var Name:String;var Bitmap);
procedure x_load_put_pbm(X,Y:Word;Name:String);
procedure x_get_save_pbm(X1,Y1,X2,Y2:Word;Name:String);
(* Converted Linear Bitmap to Planar Bitmap. True,if succesful. *)
function x_lbm_to_pbm(var src_bm,dest_pbm):Boolean;
(* Converted Planar Bitmap to Linear Bitmap. True,if succesful. *)
function x_pbm_to_lbm(var src_pbm,dest_lbm):Boolean;
(******************************* LBM ***************************************)
procedure x_save_lbm(var Name:String;var Bitmap);
procedure x_load_lbm(var Name:String;var Bitmap);
function x_lbm_size(x1,y1,x2,y2:Word):Word;
function x_sizeof_lbm(var BitMap):Word;
(**************************** PCX -> LBM ***********************************
* PCXVIEW - by Lee Hamel (Patch), hamell@cx.pdx.edu, *Avalanche* coder *
* July 14th, 1993 *
***************************************************************************
* converted to TP/asm by Christian Harms , harms@129.69.212.10 (or .13) *
***************************************************************************
Limitations : max_PCX-filesize : 65 kB
Bitmapsize : 255x255 pixel *)
(* If the size=0, then it isn't a 256-Color PCX-pictures or the image size
is to big for later converting in pbm. *)
function x_get_PCX_Size(Name:String):Word;
(* Load the pcx-image and encode into Bitmap as lbm. *)
(* True, if encoding ok. *)
function x_Load_PCX_as_LBM(Name:String;Var Bitmap):Boolean;
(******************************* CBM ***************************************)
(* Converted Planar Bitmap into Compiled Bitmap *)
procedure x_pbm_to_cbm(logical_width:Word;Var pbm,cbm);
(* Return the used size of the cbm from the source pbm. *)
function x_sizeof_cpbm (logical_width:Word;Var pbm):Word;
(* Put Compiled Bitmap from System RAM to Pos (X,Y) only as masked version*)
procedure x_put_cbm(XPos,YPos:Word;Var Sprite);
(******************************* IBM ***************************************)
(* Converted Planar Bitmap into Interpreted Bitmap *)
procedure x_pbm_to_ibm(Var pbm,ibm);
(* Return the used size of the ibm from the source pbm. *)
function x_sizeof_ipbm (Var pbm):Word;
(* Put Interpreted Bitmap from System RAM to Pos (X,Y) . *)
procedure x_put_ibm(x,y:WOrd;Var ibm);
(* Put Interpreted Bitmap from System RAM to Pos (X,Y) . *)
procedure x_put_masked_ibm(X,Y:Word;Var ibm);
(* Load Interpreted Bitmap from File with Name. *)
procedure x_load_ibm(var Name:String;var Bitmap);
(******************************* VBM ***************************************)
(* Converted Linear Bitmap into Video Bitmap *)
function x_lbm_to_vbm(Var lbm;Var VramStart:Word):Pointer;
procedure x_put_masked_vbm(X,Y:Word;var SrcVBM);
procedure x_put_masked_vbm_clipx(X,Y:Word;Var SrcVBM);
procedure x_put_masked_vbm_clipy(X,Y:Word;Var SrcVBM);
procedure x_put_masked_vbm_clipxy(X,Y:Word;Var SrcVBM);
implementation
uses X_Const,X_Main,X_FileIO,crt;
const ColumnMask :Array[0..3] of Byte = ($11,$22,$44,$88);
(* ---------------------------------------------------------------------- *)
(* 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,Bitmap) *)
(* *)
(* *)
(* LIMITATIONS: No clipping is supported *)
(* Only supports bitmaps with widths which are a multiple of *)
(* 4 pixels *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_put_masked_pbm(X,Y:Word;var Bitmap); assembler;
var Plane,BMHeight:Byte;
LineInc:Word;
asm;
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,ScreenOfs (* 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,dword ptr[Bitmap] (* DS:SI -> Bitmap data *)
lodsw (* Al = B.M. width (bytes) AH = B.M. *)
(* height *)
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 *)
end;
(* ---------------------------------------------------------------------- *)
(* 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,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 *)
(* ---------------------------------------------------------------------- *)
procedure x_put_pbm(X,Y:Word;var Bitmap); assembler;
var Plane,BMHeight:Byte;
LineInc :Word;
asm;
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,ScreenOfs (* 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,1;shr dx,1 (* Find starting byte in dest row *)
add di,dx (* add to DI giving screen offset of *)
(* first pixel's byte *)
lds si,dword ptr[Bitmap] (* DS:SI -> Bitmap data *)
lodsw (* Al = B.M. width (bytes) AH = B.M. *)
(* height *)
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 *)
end;
(* ---------------------------------------------------------------------- *)
(* 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(X1,Y1,X2,Y2,Bitmap) *)
(* *)
(* *)
(* LIMITATIONS: No clipping is supported *)
(* Only supports bitmaps with widths which are a multiple of *)
(* 4 pixels *)
(* X2-X1<256, Y2-Y1<256 *)
(* FEATURES : Automatically selects REP MOVSB or REP MOVSW depending on *)
(* source bitmap width, by modifying opcode (*-). *)
(* *)
(* Written by Themie Gouthas *)
(* ---------------------------------------------------------------------- *)
procedure x_get_pbm(X1,Y1,X2,Y2:Word;var Bitmap); assembler;
var Plane,SrcWidth,SrcHeight:Byte;
LineInc:Word;
asm;
mov ax,X2 (* Store X2 in SrcWidth . *)
sub ax,X1
add ax,3
shr ax,1;shr ax,1
mov SrcWidth,al
mov ax,Y2 (* Store Y2 in SrcHeight . *)
sub ax,Y1
mov SrcHeight,al
push ds
cld
mov ax,Y1 (* Calculate screen row *)
mov bx,ScrnLogicalByteWidth (* by mult. Y coord by Screen *)
mul bx (* width then adding screen offset *)
mov si,ScreenOfs (* store result in SI *)
add si,ax
mov cx,X1 (* Load X coord into CX and make a *)
mov dx,cx (* copy in DX *)
shr dx,1;shr dx,1 (* 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,dword ptr [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 *)
end;
(* global clipping variables *)
var TopBound,BottomBound,LeftBound,RightBound:Word;
(*
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.
*)
(*---------------------------------------------------------------------- *)
(* x_put_masked_pbm_clipx - mask write a planar bitmap from system ram to video *)
(* ram all zero source bitmap bytes indicate destination *)
(* byte to be left unchanged. *)
(* Performs clipping in x directions. similar to *)
(* "x_put_masked_pbm". *)
(* *)
(* See Also: x_put_masked_pbm, x_put_masked_pbm_clipxy *)
(* *)
(* Clipping region variables: LeftClip,RightClip *)
(* *)
(* Written by Themie Gouthas *)
(* *)
(* This code is a SLOW hack, any better ideas are welcome *)
(*---------------------------------------------------------------------- *)
procedure x_put_masked_pbm_clipx(X,Y:Word;Var Bitmap); assembler;
Var Plane:Byte;
CType,LeftSkip,DataInc,Width,Height,TopRow,LineInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap] (* Point ES:SI to start of bitmap *)
xor ax,ax (* Clear AX *)
mov [CType],ax (* Clear Clip type descision var *)
mov al,byte ptr es:[si] (* AX=width(byte coverted to word)*)
mov di,[X] (* DI = X coordinate of dest *)
mov cx,di (* copy to CX *)
sar di,2 (* convert to offset in row *)
(**** CLIP PROCESSING FOR LEFT CLIP BORDER ******************)
mov dx,[LeftClip] (* Is X Coord to the right of *)
sub dx,di (* LeftClip ? *)
jle @@NotLeftClip (* Yes! => no left clipping *)
cmp dx,ax (* Is dist of X Coord from *)
jnl @@NotVisible (* ClipLeft > Width ? yes => the *)
(* bitmap is not visible *)
add di,dx
mov [LeftSkip],dx
mov [DataInc],dx
sub ax,dx
mov [CType],1
jmp @@HorizClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(**** CLIP PROCESSING FOR RIGHT CLIP BORDER ******************)
@@NotLeftClip:
mov dx,[RightClip]
sub dx,di
js @@NotVisible
mov [LeftSkip],0
mov [DataInc],0
cmp dx,ax
jge @@HorizClipDone (* was jg *)
inc dx
sub ax,dx
mov [DataInc],ax
mov ax,dx
mov [CType],-1
@@HorizClipDone:
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
mov [Width],ax (* Save width and height of clipped *)
mov [Height],bx (* image *)
add si,2 (* Skip dimension bytes in source *)
add si,[LeftSkip] (* Skip pixels in front of row that *)
(* are clipped *)
mov bx,[ScrnLogicalByteWidth] (* Set BX to Logical Screen Width *)
mov dx,bx (* BX - Width of image = No. bytes*)
sub dx,ax (* to first byte of next screen *)
mov [LineInc],dx (* row. *)
mov ax,[Y] (* Calculate screen start row *)
mul bx (* then adding screen offset *)
add di,ax
add di,[ScreenOfs]
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
and cx,3
mov ah,11h (* Set up initial plane mask *)
shl ah,cl
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 *)
mov bh,byte ptr [Width] (* set bh to width for fast looping *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,bh (* Reset Column counter cl *)
jcxz @@NoWidth
@@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
@@NoWidth:
add si,[DataInc] (* Move to next source row *)
add di,[LineInc] (* Move to next screen 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 *)
(* Plane Transition (A HACK but it works!) *)
jnb @@Nocarry (* Jump if not plane transition *)
mov bl,ah (* Save Plane Mask *)
mov ax,[CType] (* set AX to clip type inc variable *)
add bh,al (* Update advancing variables *)
sub [DataInc],ax (* *)
sub [LineInc],ax (* *)
cmp al,0 (* What type of clip do we have *)
mov ah,bl (* restore Plane mask *)
jg @@RightAdvance (* jump on a right clip! *)
inc di (* otherwise increment DI *)
jmp @@Nocarry
@@RightAdvance:
dec si
@@Nocarry:
dec [Plane] (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@Ok:
end;
(*---------------------------------------------------------------------- *)
(* x_put_masked_pbm_clipy - mask write a planar bitmap from system ram to video *)
(* ram all zero source bitmap bytes indicate destination *)
(* byte to be left unchanged. *)
(* Performs clipping in y direction. similar to *)
(* "x_put_masked_pbm". *)
(*
(* See Also: x_put_masked_pbm, x_put_masked_pbm_clipx, x_put_masked_pbm_clipy *)
(* *)
(* Clipping region variables: TopClip,BottomClip *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_put_masked_pbm_clipy(X,Y:Word;Var Bitmap); assembler;
var Width,Height,TopRow,LineInc,PlaneInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap]
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
xor ah,ah
mov al,byte ptr es:[si] (* AX = width *)
mov cx,ax (* Save AX *)
mul bx (* AX = AX*BX = bytes/plane *)
mov [PlaneInc],ax (* save as PlaneInc *)
mov ax,cx (* Restore AX *)
mov di,[X]
mov cx,di
shr di,2
(**** 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,bx
jnl @@NotVisible (* jump if VBM is completely obscured *)
mov [TopRow],dx
sub bx,dx
add [Y],dx
jmp @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(**** CLIP PROCESSING FOR BOTTOM CLIP BORDER ******************)
@@NotTopClip:
mov dx,[BottomClip]
sub dx,[Y]
js @@NotVisible
mov [TopRow],0
cmp dx,bx
jg @@VertClipDone
inc dx
mov bx,dx
@@VertClipDone:
mov [Width],ax
mov [Height],bx (* Calculate relative offset in data *)
mul [TopRow] (* of first visible scanline *)
add ax,2 (* Skip dimension bytes in source *)
add si,ax (* Skip top rows that arent visible *)
mov ax,[Y] (* Calculate screen row *)
mov bx,[ScrnLogicalByteWidth] (* by mult. Y coord by Screen *)
mul bx (* width then adding screen offset *)
add di,ax
add di,[ScreenOfs]
sub bx,[Width] (* calculate difference from end of *)
mov [LineInc],bx (* b.m. in curr line to beginning of *)
(* b.m. on next scan line *)
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
mov ah,11h (* Set up initial plane mask *)
and cx,3
shl ah,cl
mov dx,SC_INDEX (* Prepare VGA for cpu to video writes *)
mov al,MAP_MASK
out dx,al
inc dx
mov bh,4 (* Set plane counter to 4 *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
push si (* Save Bitmaps data offset *)
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,byte ptr [Width] (* 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 si (* Restore SI and set to offset of*)
add si,[PlaneInc] (* first vis pixel in next plane data *)
pop di (* Restore bitmaps start dest byte*)
rol ah,1 (* Shift mask for next plane *)
adc di,0 (* if carry increment screen offset *)
dec bh (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@Ok:
end;
(*---------------------------------------------------------------------- *)
(* x_put_masked_pbm_clipxy - Write a planar bitmap from system ram to video *)
(* RAM with clipping in x and y directions. similar to *)
(* "x_put_masked_pbm". *)
(* *)
(* See Also: x_put_masked_pbm, x_put_masked_pbm_clipx, x_put_masked_pbm_clipxy *)
(* *)
(* Clipping region variables: LeftClip,RightClip,TopClip,BottomClip *)
(* *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_put_masked_pbm_clipxy(X,Y:Word;Var Bitmap); assembler;
Var Plane:Byte;
CType,LeftSkip,DataInc,Width,Height,TopRow,LineInc,PlaneInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap]
xor ax,ax
mov [CType],ax
mov al,byte ptr es:[si] (* AX = width *)
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
mov cx,ax (* Save AX *)
mul bx (* AX = AX*BX = bytes/plane *)
mov [PlaneInc],ax (* save as PlaneInc *)
mov ax,cx (* Restore AX *)
mov di,[X] (* DI = X coordinate of dest. *)
mov cx,di (* save in CX *)
sar di,2 (* convert to address byte *)
(**** 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,bx
jnl @@NotVisible (* jump if VBM is completely obscured *)
mov [TopRow],dx
sub bx,dx
add [Y],dx
jmp @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @OK
(**** CLIP PROCESSING FOR BOTTOM CLIP BORDER ******************)
@@NotTopClip:
mov dx,[BottomClip]
sub dx,[Y]
js @@NotVisible
mov [TopRow],0
cmp dx,bx
jg @@VertClipDone
inc dx
mov bx,dx
@@VertClipDone:
(**** CLIP PROCESSING FOR LEFT CLIP BORDER ********************)
mov dx,[LeftClip]
sub dx,di
jle @@NotLeftClip
cmp dx,ax
jnl @@NotVisible
add di,dx
mov [LeftSkip],dx
mov [DataInc],dx
sub ax,dx
mov [CType],1
jmp @@HorizClipDone
(**** CLIP PROCESSING FOR RIGHT CLIP BORDER *******************)
@@NotLeftClip:
mov dx,[RightClip]
sub dx,di
js @@NotVisible
mov [LeftSkip],0
mov [DataInc],0
cmp dx,ax
jge @@HorizClipDone (* was jg *)
inc dx
sub ax,dx
mov [DataInc],ax
mov ax,dx
mov [CType],-1
@@HorizClipDone:
mov [Width],ax (* Save width and height of clipped *)
mov [Height],bx (* image *)
add ax,[DataInc] (* AX = original width of image *)
mul [TopRow] (* Calculate bytes in clipped top *)
add si,ax (* rows *)
add si,2 (* Skip dimension bytes in source *)
add si,[LeftSkip] (* Skip pixels in front of row that *)
(* are clipped *)
mov bx,[ScrnLogicalByteWidth] (* Set BX to Logical Screen Width *)
mov dx,bx (* BX - Width of image = No. bytes*)
sub dx,[Width] (* to first byte of next screen *)
mov [LineInc],dx (* row. *)
mov ax,[Y] (* Calculate screen start row *)
mul bx (* then adding screen offset *)
add di,ax
add di,[ScreenOfs]
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
and cx,3
mov ah,11h (* Set up initial plane mask *)
shl ah,cl
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 *)
mov bh,byte ptr [Width] (* set bh to width for fast looping *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
push si
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,bh (* Reset Column counter cl *)
jcxz @@NoWidth
@@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
@@NoWidth:
add si,[DataInc] (* Move to next source row *)
add di,[LineInc] (* Move to next screen row *)
dec bl (* decrement row counter *)
jnz @@RowLoop (* Jump if more rows left *)
pop si (* Restore SI and set to offset of*)
add si,[PlaneInc] (* first vis pixel in next plane data *)
pop di (* Restore bitmaps start dest byte*)
rol ah,1 (* Shift mask for next plane *)
(* Plane Transition (A HACK but it works!) *)
jnb @@Nocarry (* Jump if not plane transition *)
mov bl,ah (* Save Plane Mask *)
mov ax,[CType] (* set AX to clip type inc variable *)
add bh,al (* Update advancing variables *)
sub [DataInc],ax (* *)
sub [LineInc],ax (* *)
cmp al,0 (* What type of clip do we have *)
mov ah,bl (* restore Plane mask *)
jg @@RightAdvance (* jump on a right clip! *)
inc di (* otherwise increment DI *)
jmp @@Nocarry
@@RightAdvance:
dec si
@@Nocarry:
dec [Plane] (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@OK:
end;
(*---------------------------------------------------------------------- *)
(* x_put_pbm_clipx - Write a planar bitmap from system ram to video ram *)
(* with clipping in x and y directions. similar to *)
(* "x_put_pbm". *)
(* *)
(* See Also: x_put_pbm_clip *)
(* *)
(* *)
(* See Also: x_put_pbm,x_put_pbm_clipy,x_put_pbm_clipxy *)
(* *)
(* Clipping region variables: LeftClip,RightClip *)
(* *)
(* Written by Themie Gouthas *)
(* *)
(* This code is a SLOW hack, any better ideas are welcome *)
(*---------------------------------------------------------------------- *)
procedure x_put_pbm_clipx(X,Y:Word;Var Bitmap); assembler;
var Plane:Byte;
CType,LeftSkip,DataInc,Width,Height,TopRow,LineInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap]
xor ax,ax
mov [CType],ax
mov al,byte ptr es:[si] (* AX = width *)
mov di,[X] (* DI = X coordinate of dest. *)
mov cx,di (* save in CX *)
sar di,2 (* convert to address byte *)
(**** CLIP PROCESSING FOR LEFT CLIP BORDER *******************)
mov dx,[LeftClip]
sub dx,di
jle @@NotLeftClip
cmp dx,ax
jnl @@NotVisible
add di,dx
mov [LeftSkip],dx
mov [DataInc],dx
sub ax,dx
mov [CType],1
jmp @@HorizClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(**** CLIP PROCESSING FOR RIGHT CLIP BORDER *******************)
@@NotLeftClip:
mov dx,[RightClip]
sub dx,di
js @@NotVisible
mov [LeftSkip],0
mov [DataInc],0
cmp dx,ax
jge @@HorizClipDone (* was jg *)
inc dx
sub ax,dx
mov [DataInc],ax
mov ax,dx
mov [CType],-1
@@HorizClipDone:
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
mov [Width],ax (* Save width and height of clipped *)
mov [Height],bx (* image *)
add si,2 (* Skip dimension bytes in source *)
add si,[LeftSkip] (* Skip pixels in front of row that *)
(* are clipped *)
mov bx,[ScrnLogicalByteWidth] (* Set BX to Logical Screen Width *)
mov dx,bx (* BX - Width of image = No. bytes*)
sub dx,ax (* to first byte of next screen *)
mov [LineInc],dx (* row. *)
mov ax,[Y] (* Calculate screen start row *)
mul bx (* then adding screen offset *)
add di,ax
add di,[ScreenOfs]
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
and cx,3
mov ah,11h (* Set up initial plane mask *)
shl ah,cl
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 *)
mov bh,byte ptr [Width] (* set bh to width for fast looping *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,bh (* Reset Column counter cl *)
shr cl,1
rep movsw (* Copy a complete row *)
adc cl,0
rep movsb
add si,[DataInc] (* Move to next source row *)
add di,[LineInc] (* Move to next screen 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 *)
(* Plane Transition (A HACK but it works!) *)
jnb @@Nocarry (* Jump if not plane transition *)
mov bl,ah (* Save Plane Mask *)
mov ax,[CType] (* set AX to clip type inc variable *)
add bh,al (* Update advancing variables *)
sub [DataInc],ax (* *)
sub [LineInc],ax (* *)
cmp al,0 (* What type of clip do we have *)
mov ah,bl (* restore Plane mask *)
jg @@RightAdvance (* jump on a right clip! *)
inc di (* otherwise increment DI *)
jmp @@Nocarry
@@RightAdvance:
dec si
@@Nocarry:
dec [Plane] (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@OK:
end;
(*---------------------------------------------------------------------- *)
(* x_put_pbm_clipy - Write a planar bitmap from system ram to video ram *)
(* with clipping in y direction only. similar to *)
(* "x_put_pbm". *)
(* *)
(* See Also: x_put_pbm,x_put_pbm_clipx,x_put_pbm_clipxy *)
(* *)
(* Clipping region variables: TopClip,BottomClip *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_put_pbm_clipy(X,Y:Word;Var Bitmap); assembler;
var Width,Height,TopRow,LineInc,PlaneInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap]
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
mov [Height],bx
xor ah,ah
mov al,byte ptr es:[si] (* AX = width *)
mov [Width],ax
mov cx,ax (* Save AX *)
mul bx (* AX = AX*BX = bytes/plane *)
mov [PlaneInc],ax (* save as PlaneInc *)
mov ax,cx (* Restore AX *)
mov di,[X]
mov cx,di
and cx,3
shr di,2
(**** 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,bx
jnl @@NotVisible (* jump if VBM is completely obscured *)
mov [TopRow],dx
sub bx,dx
add [Y],dx
jmp @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @OK
(**** CLIP PROCESSING FOR BOTTOM CLIP BORDER ******************)
@@NotTopClip:
mov dx,[BottomClip]
sub dx,[Y]
js @@NotVisible
mov [TopRow],0
cmp dx,bx
jg @@VertClipDone
inc dx
mov bx,dx
@@VertClipDone:
mov [Height],bx (* Calculate relative offset in data *)
mul [TopRow] (* of first visible scanline *)
add ax,2 (* Skip dimension bytes in source *)
add si,ax (* Skip top rows that arent visible *)
mov ax,[Y] (* Calculate screen row *)
mov bx,[ScrnLogicalByteWidth] (* by mult. Y coord by Screen *)
mul bx (* width then adding screen offset *)
add di,ax
add di,[ScreenOfs]
sub bx,[Width] (* calculate difference from end of *)
mov [LineInc],bx (* b.m. in curr line to beginning of*)
(* b.m. on next scan line *)
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
mov ah,11h (* Set up initial plane mask *)
shl ah,cl
mov dx,SC_INDEX (* Prepare VGA for cpu to video writes *)
mov al,MAP_MASK
out dx,al
inc dx
mov bh,4 (* Set plane counter to 4 *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
push si (* Save Bitmaps data offset *)
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,byte ptr [Width] (* Reset Column counter cl *)
shr cl,1
rep movsw (* Copy a complete row *)
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 si (* Restore SI and set to offset of*)
add si,[PlaneInc] (* first vis pixel in next plane data *)
pop di (* Restore bitmaps start dest byte*)
rol ah,1 (* Shift mask for next plane *)
adc di,0 (* if carry increment screen offset *)
dec bh (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@OK:
end;
(*---------------------------------------------------------------------- *)
(* x_put_pbm_clipxy - Write a planar bitmap from system ram to video ram *)
(* with clipping in x and y directions. similar to *)
(* "x_put_pbm". *)
(* *)
(* See Also: x_put_pbm,x_put_pbm_clipy,x_put_pbm_clipx *)
(* *)
(* Clipping region variables: LeftClip,RightClip,TopClip,BottomClip *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
procedure x_put_pbm_clipxy(X,Y:Word;Var Bitmap); assembler;
var Plane:Byte;
CType,LeftSkip,DataInc,Width,Height,TopRow,LineInc,PlaneInc:Word;
asm
push si
push di
push ds
cld
les si,[Bitmap]
xor ax,ax
mov [CType],ax
mov al,byte ptr es:[si] (* AX = width *)
xor bh,bh
mov bl,byte ptr es:[si+1] (* BX = height *)
mov cx,ax (* Save AX *)
mul bx (* AX = AX*BX = bytes/plane *)
mov [PlaneInc],ax (* save as PlaneInc *)
mov ax,cx (* Restore AX *)
mov di,[X] (* DI = X coordinate of dest. *)
mov cx,di (* save in CX *)
sar di,2 (* convert to address byte *)
(**** 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,bx
jnl @@NotVisible (* jump if VBM is completely obscured *)
mov [TopRow],dx
sub bx,dx
add [Y],dx
jmp @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED P.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @OK
(**** CLIP PROCESSING FOR BOTTOM CLIP BORDER *******************)
@@NotTopClip:
mov dx,[BottomClip]
sub dx,[Y]
js @@NotVisible
mov [TopRow],0
cmp dx,bx
jg @@VertClipDone
inc dx
mov bx,dx
@@VertClipDone:
(**** CLIP PROCESSING FOR LEFT CLIP BORDER ********************)
mov dx,[LeftClip]
sub dx,di
jle @@NotLeftClip
cmp dx,ax
jnl @@NotVisible
add di,dx
mov [LeftSkip],dx
mov [DataInc],dx
sub ax,dx
mov [CType],1
jmp @@HorizClipDone
(**** CLIP PROCESSING FOR RIGHT CLIP BORDER *******************)
@@NotLeftClip:
mov dx,[RightClip]
sub dx,di
js @@NotVisible
mov [LeftSkip],0
mov [DataInc],0
cmp dx,ax
jge @@HorizClipDone (* was jg *)
inc dx
sub ax,dx
mov [DataInc],ax
mov ax,dx
mov [CType],-1
@@HorizClipDone:
mov [Width],ax (* Save width and height of clipped *)
mov [Height],bx (* image *)
add ax,[DataInc] (* AX = original width of image *)
mul [TopRow] (* Calculate bytes in clipped top *)
add si,ax (* rows *)
add si,2 (* Skip dimension bytes in source *)
add si,[LeftSkip] (* Skip pixels in front of row that *)
(* are clipped *)
mov bx,[ScrnLogicalByteWidth] (* Set BX to Logical Screen Width *)
mov dx,bx (* BX - Width of image = No. bytes*)
sub dx,[Width] (* to first byte of next screen *)
mov [LineInc],dx (* row. *)
mov ax,[Y] (* Calculate screen start row *)
mul bx (* then adding screen offset *)
add di,ax
add di,[ScreenOfs]
mov ax,es (* copy ES to DS *)
mov ds,ax
mov ax,SCREEN_SEG (* Point ES to VGA segment *)
mov es,ax
and cx,3
mov ah,11h (* Set up initial plane mask *)
shl ah,cl
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 *)
mov bh,byte ptr [Width] (* set bh to width for fast looping *)
@@PlaneLoop:
push di (* Save bitmap's start dest. offset *)
push si
mov bl,byte ptr [Height] (* Reset row counter (BL) *)
mov al,ah
out dx,al (* set vga write plane *)
@@RowLoop:
mov cl,bh (* Reset Column counter cl *)
shr cl,1
rep movsw (* Copy a complete row *)
adc cl,0
rep movsb
add si,[DataInc] (* Move to next source row *)
add di,[LineInc] (* Move to next screen row *)
dec bl (* decrement row counter *)
jnz @@RowLoop (* Jump if more rows left *)
pop si (* Restore SI and set to offset of*)
add si,[PlaneInc] (* first vis pixel in next plane data *)
pop di (* Restore bitmaps start dest byte*)
rol ah,1 (* Shift mask for next plane *)
(* Plane Transition (A HACK but it works!) *)
jnb @@Nocarry (* Jump if not plane transition *)
mov bl,ah (* Save Plane Mask *)
mov ax,[CType] (* set AX to clip type inc variable *)
add bh,al (* Update advancing variables *)
sub [DataInc],ax (* *)
sub [LineInc],ax (* *)
cmp al,0 (* What type of clip do we have *)
mov ah,bl (* restore Plane mask *)
jg @@RightAdvance (* jump on a right clip! *)
inc di (* otherwise increment DI *)
jmp @@Nocarry
@@RightAdvance:
dec si
@@Nocarry:
dec [Plane] (* Decrement plane counter *)
jnz @@PlaneLoop (* Jump if more planes left *)
xor ax,ax
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
@OK:
end;
(*----------------------------------------------------------------------- *)
(* x_pbm_to_bm *)
(* *)
(* This function converts a bitmap in the planar format to the linear format*)
(* as used by x_compile_bitmap. *)
(* *)
(* WARNING: the source and destination bitmaps must be pre - allocated *)
(* *)
(* NOTE: This function can only convert planar bitmaps that are suitable. *)
(* If the source planar bitmap's width (per plane) is >= 256/4 *)
(* it cannot be converted. In this situation an error code *)
(* BM_WIDTH_ERROR. On successful conversion True is returned. *)
(* *)
(* C callable as: *)
(* int x_pbm_to_bm(char far * source_pbm, char far * dest_bm)(* *)
(* *)
(* Written By Themie Gouthas *)
function x_pbm_to_lbm(var src_pbm,dest_lbm):Boolean; assembler;
asm
push ds
les di,dest_lbm (* es:di -> destination bitmap *)
lds si,src_pbm (* ds:si -> source planar bitmap *)
lodsb (* load AL with source pbm pixel width per plane *)
mov bl,al (* save in CL *)
xor ah,ah (* convert to word *)
shl ax,2 (* mult by 4 giving source image width *)
cmp ax,255 (* if the result > 255 then we have exceeded *)
ja @@WidthError (* the max width of linear bm. *)
stosb (* write do dest_bm *)
lodsb (* tranfer source pbm height in pixels to *)
stosb (* dest_bm *)
xor ah,ah (* convert to word *)
mul bl (* AX = AX * BL ie. total no. pixels per plane*)
mov dx,di (* save DI, the pointer to the destination bm *)
mov bl,3 (* set plane loop counter (BL) *)
@@PlaneLoop:
mov cx,ax (* set CX to total number of pixels per plane *)
@@PixelLoop:
movsb (* transfer pixel *)
add di,3 (* increment destination to compensate for plane *)
loop @@PixelLoop
inc dx (* increment original di for next pixel plane *)
mov di,dx (* and restore di from incremented original *)
dec bl (* decrement plane counter *)
jns @@PlaneLoop (* loop if more planes left *)
mov ax,Word(True)
jmp @@Done
@@WidthError:
mov ax,Word(false)
@@Done:
pop ds
end;
(* ----------------------------------------------------------------------- *)
(* x_bm_to_pbm *)
(* *)
(* This function converts a bitmap in the linear format as used by *)
(* x_compile_bitmap to the planar formap. *)
(* *)
(* WARNING: the source and destination bitmaps must be pre - allocated *)
(* *)
(* NOTE: This function can only convert linear bitmaps that are suitable. *)
(* If the source linear bitmap's width is not a multiple of 4 *)
(* it cannot be converted. In this situation an error code *)
(* BM_WIDTH_ERROR. On successful conversion True is returned. *)
(* *)
(* int x_bm_to_pbm(source_pbm,dest_bm); *)
(* *)
(* Written By Themie Gouthas *)
function x_lbm_to_pbm(var src_bm,dest_pbm):Boolean; assembler;
asm
push ds
les di,dest_pbm (* es:di -> destination planar bitmap *)
lds si,src_bm (* ds:si -> source bitmap *)
lodsb (* load AX with source bitmap width *)
test al,03h (* Check that width is a multiple of 4 *)
jnz @@WidthIncompatible
shr al,1;shr al,1 (* divide by 4 giving width of plane *)
stosb (* store destination planar bitmap width *)
mov bl,al (* and copy to bl *)
lodsb
stosb (* Transfer source bitmap height to dest pbm *)
xor ah,ah (* Conver height to word *)
mul bl (* calculate the total no. of pixels / plane *)
mov dx,si (* save source offset *)
mov bl,3
@@PlaneLoop:
mov cx,ax (* set CX to total number of pixels per plane *)
@@PixelLoop:
movsb (* transfer pixel *)
add si,3 (* increment src offset to compensate for plane *)
loop @@PixelLoop
inc dx (* increment original si for next pixel plane *)
mov si,dx (* and restore si from incremented original *)
dec bl (* decrement plane counter *)
jns @@PlaneLoop (* loop if more planes left *)
mov ax,Word(True)
jmp @@Done
@@WidthIncompatible:
mov ax,Word(False)
@@Done:
pop ds
end;
function x_pbm_size(x1,y1,x2,y2:Word):Word; assembler;
asm
mov ax,x2
sub ax,x1
inc ax
mov bx,y2
sub bx,y1
inc bx
mul bx
inc ax
inc ax (* x_pbm_size:=2+(x2-x1+1)*(y2-y1+1); *)
end;
function x_sizeof_pbm(var BitMap):Word; assembler;
asm
les di,dword ptr [Bitmap]
mov al,es:[di]
xor ah,ah
shl al,1
shl al,1
mov bl,es:[di+1]
mul bl
inc ax
inc ax
end;
procedure x_get_pbm_sizeXY(var x,y:Word;var Bitmap); assembler;
asm
les di,dword ptr [Bitmap]
mov ax,es:[di]
xor bx,bx
mov bl,ah
les di,dword ptr[y]
mov es:[di],bx
shl al,2
xor ah,ah
les di,dword ptr[x]
mov es:[di],ax
end;
function x_lbm_size(x1,y1,x2,y2:Word):Word;
begin;
x_lbm_size:=x_pbm_size(x1,y1,x2,y2);
end;
function x_sizeof_lbm(var BitMap):Word; assembler;
asm
les di,dword ptr [Bitmap]
mov al,es:[di]
xor ah,ah
mov bl,es:[di+1]
inc bl
mul bl
inc ax
inc ax
end;
type PCX_Header = record
Manufacturer,version,encoding,bits_per_pixel : Byte;
xmin,ymin,xmax,ymax,Hres,Vres : Word;
pal : Array[0..47] of Byte;
reserved,color_planes : Byte;
bytes_per_line,palette_type : Word;
filler : Array[0..57] of Byte;
end;
function x_get_pcx_size(Name:String):Word;
var F:File;
Header:PCX_Header;
Code:Integer;
C:Byte;
x,y:Word;
begin;
x_get_pcx_size:=0;
if F_Size(Name)-sizeof(Header)-3*256>$FFFF then exit;
if not F_Open_Read(F,Name) then exit;
BlockRead(F,Header,sizeof(Header),code);
if code<>sizeof(Header) then exit;
if (Header.manufacturer<>$0A)and(header.version<>5) then begin;F_Close(F);exit;end;
F_Close(f);
x:=(Header.xmax-header.xmin+4)and not 3;
y:=Header.ymax-Header.ymin+1;
if (x>253)or(y>255) then exit;
x_get_pcx_size:=x*y+2;
end;
function x_Load_PCX_as_LBM;
var code,width,depth : Word;
bytes,Add_X : Byte;
F : File;
Header : ^PCX_Header;
Buffer : Pointer;
Size : LongInt;
begin;
x_Load_PCX_as_LBM:=False;
if x_get_pcx_size(Name)=0 then exit;
if not F_Open_Read(F,Name) then exit;
New(Header);
BlockRead(F,Header^,sizeof(PCX_Header),code);
width:=(Header^.xmax-header^.xmin+4) and not 3;
depth:=Header^.ymax-Header^.ymin+1;
bytes:=Header^.bytes_per_line-1;
Add_X:=width-(Header^.xmax-header^.xmin+1);
Dispose(Header);
Size:=F_Size(Name)-sizeof(PCX_Header)-3*255;
GetMEM(Buffer,size);
BlockRead(F,Buffer^,size);
F_Close(F);
(* es:di Bitmap
ds:si Buffer
dl n is the bytepointer each line
dh i is the linepointer
bl bytes bytecount of line in pcx-pictures
bh add_X the (mod 4) rows in the lbm
ah depth-1 count of lines in pcx-pictures
*)
asm
les di,dword ptr [Bitmap] (* Set x,y in LBM *)
mov ax,width
stosb
mov ax,depth
stosb
mov dh,0 (* i:=0 *)
mov bl,bytes
mov ax,depth
shl ax,8
dec ah
mov bh,add_X
push ds
lds si,dword ptr [Buffer]
@Next_Line:
jmp @Get_Line
@Next_MEM:
push bx
shr bx,8
add di,bx
pop bx
inc dh
cmp dh,ah
je @Pic_Ready
jmp @Next_Line
@Get_Line:
mov dl,0 (* n:=0; *)
@Loop:
cmp dl,bl (* while (n<bytes) do *)
ja @next_mem
@nothing: (* begin; *)
lodsb (* BlockRead(f,c,1); *)
mov cl,al (* save the value c *)
and al,$c0
cmp al,$c0 (* if (c and $c0)=$c0 then *)
jne @Part2
(* begin; *)
and cl,$3f (* run:=c and $3f; *)
add dl,cl (* Inc(n,run); *)
xor ch,ch
lodsb (* BlockRead(f,c,1); *)
rep stosb (* write to Bitmap *)
jmp @Loop (* end *)
@Part2: (* else begin; *)
mov al,cl
stosb (* write to Bitmap *)
inc dl (* Inc(n); *)
jmp @Loop (* end; *)
@Pic_Ready:
pop ds
end;
(* for i:=0 to 255 do for j:=0 to 2 do pal[i,j]:=pal[i,j] shr 2;*)
FreeMEM(Buffer,size);
X_Load_PCX_as_LBM:=True;
end;
(* Intern use by x_load_pbm , x_load_lbm , x_load_ibm *)
procedure x_load_bitmap(var Name:String;Ext:String;var Bitmap);
var F:File;
begin;
Name:=Only_one_Ext(Name,ext);
if F_Open_Read(F,Name) then
begin;
BlockRead(f,Bitmap,F_Size(Name));
F_Close(F);
end
else fillchar(Bitmap,2,0);
end;
procedure x_save_pbm(var Name:String;var Bitmap);
var F : File;
begin;
Name:=Only_one_Ext(Name,EXT_pbm);
F_Open_Write(F,Name);
BlockWrite(f,BitMap,x_sizeof_pbm(BitMap));
F_Close(f);
end;
procedure x_load_pbm(var Name:String;var Bitmap); (* able with MasterFile *)
begin;
x_load_bitmap(Name,EXT_pbm,Bitmap);
end;
procedure x_save_lbm(var Name:String;var Bitmap);
var F : File;
begin;
Name:=Only_one_Ext(Name,EXT_lbm);
F_Open_Write(F,Name);
BlockWrite(f,BitMap,x_sizeof_lbm(Bitmap));
F_Close(f);
end;
procedure x_load_lbm(var Name:String;var Bitmap); (* able with MasterFile *)
var F : File;
begin;
x_load_bitmap(Name,EXT_lbm,Bitmap);
end;
procedure x_get_save_pbm(X1,Y1,X2,Y2:Word;Name:String);
var F : File;
B : Pointer;
Size : Word;
begin;
Size:=x_pbm_size(X1,Y1,X2,Y2);
GetMEM(B,Size);
x_get_pbm(X1,Y1,X2,Y2,B^);
x_save_pbm(Name,B^);
FreeMEM(B,Size);
end;
procedure x_load_put_pbm(X,Y:Word;Name:String);
var F : File;
B : Pointer;
Size : Word;
begin;
Size:=F_Size(Name);
GetMEM(B,Size);
x_load_pbm(Name,B^);
x_put_pbm(X,Y,B^);
FreeMEM(B,Size);
end;
const ROL_AL = $c0d0; (* rol al *)
SHORT_STORE_8 = $44c6; (* mov [si]+disp8, imm8 *)
STORE_8 = $84c6; (* mov [si]+disp16, imm8 *)
SHORT_STORE_16 = $44c7; (* mov [si]+disp8, imm16 *)
STORE_16 = $84c7; (* mov [si]+disp16, imm16 *)
ADC_SI_IMMED = $d683; (* adc si,imm8 *)
OUT_AL = $ee; (* out dx,al *)
RETURN = $cb; (* ret *)
procedure x_pbm_to_cbm(logical_width:Word;Var pbm,cbm); assembler;
var bwidth,scanx,scany,cbmx,cbmy,column,set_column,input_size:Word;
asm
push si
push di
push ds
mov word ptr [scanx],0
mov word ptr [scany],0
mov word ptr [cbmx],0
mov word ptr [cbmy],0
mov word ptr [column],0
mov word ptr [set_column],0
lds si,[pbm] (* 32-bit pointer to source pbm *)
les di,[cbm] (* 32-bit pointer to destination stream *)
lodsb (* load width byte *)
xor ah, ah (* convert to word *)
mov [bwidth], ax (* save for future reference *)
mov bl, al (* copy width byte to bl *)
lodsb (* load height byte -- already a word since ah=0 *)
mul bl (* mult height word by width byte *)
mov [input_size], ax(* to get pixel total *)
@@MainLoop:
mov bx, [scanx] (* position in original pbm *)
add bx, [scany]
mov al, [si+bx] (* get pixel *)
or al, al (* skip empty pixels *)
jnz @@NoAdvance
jmp @@Advance
@@NoAdvance:
mov dx, [set_column]
cmp dx, [column]
je @@SameColumn
@@ColumnLoop:
mov word ptr es:[di],ROL_AL (* emit code to move to new column *)
add di,2
mov word ptr es:[di],ADC_SI_IMMED
add di,2
mov byte ptr es:[di],0
inc di
inc dx
cmp dx, [column]
jl @@ColumnLoop
mov byte ptr es:[di],OUT_AL (* emit code to set VGA mask for new column *)
inc di
mov [set_column], dx
@@SameColumn:
mov dx, [cbmy] (* calculate cbm position *)
add dx, [cbmx]
sub dx, 128
inc word ptr [scanx]
mov cx, [scanx] (* within four pixels of right edge? *)
cmp cx, [bwidth]
jge @@OnePixel
inc word ptr [cbmx]
mov ah, [si+bx+1] (* get second pixel *)
or ah, ah
jnz @@TwoPixels
@@OnePixel:
cmp dx, 127 (* can we use shorter form? *)
jg @@OnePixLarge
cmp dx, -128
jl @@OnePixLarge
mov word ptr es:[di],SHORT_STORE_8
add di,2
mov byte ptr es:[di],dl (* 8-bit position in cbm *)
inc di
jmp @@EmitOnePixel
@@OnePixLarge:
mov word ptr es:[di],STORE_8
add di,2
mov word ptr es:[di],dx (* position in cbm *)
add di,2
@@EmitOnePixel:
mov byte ptr es:[di],al
inc di
jmp @@Advance
@@TwoPixels:
cmp dx, 127
jg @@TwoPixLarge
cmp dx, -128
jl @@TwoPixLarge
mov word ptr es:[di],SHORT_STORE_16
add di,2
mov byte ptr es:[di],dl (* 8-bit position in cbm *)
inc di
jmp @@EmitTwoPixels
@@TwoPixLarge:
mov word ptr es:[di],STORE_16
add di,2
mov word ptr es:[di],dx (* position in cbm *)
add di,2
@@EmitTwoPixels:
mov word ptr es:[di],ax
add di,2
@@Advance:
inc word ptr [cbmx]
mov ax, [scanx]
inc ax
cmp ax, [bwidth]
jl @@AdvanceDone
mov dx, [cbmy]
add dx, [logical_width]
mov cx, [scany]
add cx, [bwidth]
cmp cx, [input_size]
jl @@NoNewColumn
inc word ptr [column]
mov cx, [column]
cmp cx, 4
je @@Exit (* Column 4: there is no column 4. *)
xor cx, cx (* scany and cbmy are 0 again for *)
mov dx, cx (* the new column *)
add si, [input_size]
@@NoNewColumn:
mov [cbmy], dx
mov [scany], cx
xor ax, ax
mov word ptr [cbmx], 0
@@AdvanceDone:
mov [scanx], ax
jmp @@MainLoop
@@Exit:
mov byte ptr es:[di],RETURN
inc di
mov byte ptr es:[di],RETURN
inc di
mov ax,di
sub ax,word ptr [cbm] (* size of generated code *)
pop ds
pop di
pop si
end;
(* *)
(* x_sizeof_cpbm Returns wanted size for the converted pbm *)
(* *)
function x_sizeof_cpbm (logical_width:Word;Var pbm):Word; assembler;
var bwidth,scanx,scany,cbmx,cbmy,column,set_column,input_size:Word;
asm
push si
push di
push ds
mov word ptr [scanx], 0
mov word ptr [scany], 0
mov word ptr [cbmx], 0
mov word ptr [cbmy], 0
mov word ptr [column], 0
mov word ptr [set_column], 0
lds si,[pbm] (* 32-bit pointer to source pbm *)
mov di, 1 (* initial size is just the size of the far RET*)
lodsb (* load width byte *)
xor ah, ah (* convert to word *)
mov [bwidth], ax (* save for future reference *)
mov bl, al (* copy width byte to bl *)
lodsb (* load height byte -- already a word since ah=0 *)
mul bl (* mult height word by width byte *)
mov [input_size], ax(* to get pixel total *)
@@MainLoop:
mov bx, [scanx] (* position in original pbm *)
add bx, [scany]
mov al, [si+bx] (* get pixel *)
or al, al (* skip empty pixels *)
jnz @@NoAdvance
jmp @@Advance
@@NoAdvance:
mov dx, [set_column]
cmp dx, [column]
je @@SameColumn
@@ColumnLoop:
add di, 5 (* size of code to move to new column *)
inc dx
cmp dx,[column]
jl @@ColumnLoop
inc di (* size of code to set VGA mask *)
mov [set_column], dx
@@SameColumn:
mov dx, [cbmy] (* calculate cbm position *)
add dx, [cbmx]
sub dx, 128
inc word ptr [scanx]
mov cx, [scanx] (* within four pixels of right edge? *)
cmp cx, [bwidth]
jge @@OnePixel
inc word ptr [cbmx]
mov ah,[si+bx+1] (* get second pixel *)
or ah, ah
jnz @@TwoPixels
@@OnePixel:
cmp dx, 127 (* can we use shorter form? *)
jg @@OnePixLarge
cmp dx, -128
jl @@OnePixLarge
add di, 4 (* size of 8-bit position in cbm plus one pixel*)
jmp @@EmitOnePixel
@@OnePixLarge:
add di, 5 (* size of position in cbm plus one pixels *)
@@EmitOnePixel:
jmp @@Advance
@@TwoPixels:
cmp dx, 127
jg @@TwoPixLarge
cmp dx, -128
jl @@TwoPixLarge
add di, 5 (* size of 8-bit position in cbm plus two pixels *)
jmp @@EmitTwoPixels
@@TwoPixLarge:
add di, 6 (* size of 16-bit position in cbm plus two pixels*)
@@EmitTwoPixels:
@@Advance:
inc word ptr [cbmx]
mov ax, [scanx]
inc ax
cmp ax, [bwidth]
jl @@AdvanceDone
mov dx, [cbmy]
add dx, [logical_width]
mov cx, [scany]
add cx, [bwidth]
cmp cx, [input_size]
jl @@NoNewColumn
inc word ptr [column]
mov cx, [column]
cmp cx, 4
je @@Exit (* Column 4: there is no column 4. *)
xor cx,cx (* scany and cbmy are 0 again for *)
mov dx,cx (* the new column *)
add si, [input_size]
@@NoNewColumn:
mov [cbmy], dx
mov [scany], cx
xor ax, ax
mov word ptr [cbmx], ax
@@AdvanceDone:
mov [scanx], ax
jmp @@MainLoop
@@Exit:
mov ax, di (* size of generated code *)
pop ds
pop di
pop si
end;
(* *)
(* x_put_cbm *)
(* *)
(* Displays a compiled bitmap generated by x_pbm_to_cbm at given *)
(* coordinates, on a given screen page. *)
(* *)
(* ax, bx, cx, and dx are squashed like insignificant insects. *)
procedure x_put_cbm(XPos,YPos:Word;Var Sprite); assembler;
asm
push si
push ds
mov ax, [ScrnLogicalByteWidth] (* global Xlib variable *)
mul word ptr [YPos] (* height in bytes *)
mov si, [XPos]
mov bx, si
sar si, 1
sar si, 1 (* width in bytes *)
add si, ax
add si, [ScreenOfs](* (YPos * screen width) + *)
add si, 128 (* (Xpos / 4) + page base + 128 ==> starting pos *)
and bx, 3
mov ah, [offset ColumnMask+bx]
mov dx, SC_INDEX
mov al, MAP_MASK
out dx, ax
inc dx (* ready to send out other masks as bytes *)
mov al, ah
mov bx, SCREEN_SEG
mov ds, bx (* We do this so the compiled shape won't need *)
(* segment overrides. *)
call dword ptr [Sprite] (* the business end of the routine *)
pop ds
pop si
end;
(***************************************************************************)
(****************************** IBM ****************************************)
(***************************************************************************)
(* internal use of pbm_to_ibm *)
procedure IncP(Var P); assembler;
asm
les di,Dword ptr [P]
mov ax,es:[di]
inc ax
mov es:[di],ax
end;
procedure x_pbm_to_ibm(Var pbm,ibm);
type byte_A=Array[0..$ff]of Byte;
var pbmP : ^byte_A;
ibmP : ^Byte;
x,y,p,i,j,l,lastX:Word;
procedure Store(B:Byte);begin;ibmP^:=B;IncP(ibmP);end;
begin;
x_get_pbm_sizeXY(x,y,pbm);
x:=x shr 2;
pbmP:=addr(pbm);
ibmP:=addr(ibm);
Store(x shl 2); IncP(pbmP);
Store(y); IncP(pbmP);
for j:=1 to y*4 do
begin;
lastx:=0;
for i:=0 to x do
begin;
if ((pbmP^[i]=0)<>(pbmP^[LastX]=0))or
(i=x) then
begin;
if (pbmP^[LastX]=0) then
begin;
Store(0);
Store(i-LastX);
LastX:=i;
end else
begin;
Store(i-LastX);
for l:=LastX to i-1 do Store(pbmP^[l]);
LastX:=i;
end;
end;
end;
for l:=1 to x do IncP(pbmP);
end;
end;
function x_sizeof_ipbm (Var pbm):Word;
type byte_A=Array[0..$ff]of Byte;
var pbmP : ^byte_A;
x,y,p,i,j,l,lastX,Size:Word;
begin;
x_get_pbm_sizeXY(x,y,pbm);
x:=x shr 2;
pbmP:=addr(pbm);
IncP(pbmP);
IncP(pbmP);
Size:=2;
for j:=1 to y*4 do
begin;
lastx:=0;
for i:=0 to x do
begin;
if ((pbmP^[i]=0)<>(pbmP^[LastX]=0))or
(i=x) then
begin;
if (pbmP^[LastX]=0) then
begin;
Inc(Size,2);
LastX:=i;
end else
begin;
Inc(Size,i-LastX+1);
LastX:=i;
end;
end;
end;
for l:=0 to x-1 do IncP(pbmP);
end;
x_sizeof_ipbm:=Size;
end;
procedure x_put_ibm(x,y:WOrd;Var ibm); assembler;
var Next_Line,x1,y1,maxX,maxY : Word;
Plane : Byte;
asm
push ds
mov ax,SCREEN_SEG (* es:di points in Screen *)
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,ScreenOfs (* store result in DI *)
add di,ax
push di
mov dx,ScrnLogicalByteWidth
lds si,dword ptr [ibm] (* ds:si points in ibm *)
xor ax,ax
mov al,ds:[si]
shr al,2
mov maxX,ax
sub dx,ax
mov Next_Line,dx
inc si
mov al,ds:[si]
mov maxY,ax
inc si
mov Plane,0
@Plane_Loop:
mov y1,0
mov cx,x
add cl,Plane
(* SELECT WRITE PLANE *)
and cl,011b (* CL = plane *)
mov ax,0100h + MAP_MASK (* AL = index in SC of Map Mask reg *)
shl ah,cl (* set only the bit for the required *)
(* plane to 1 *)
mov dx,SC_INDEX (* set the Map Mask to enable only the *)
out dx,ax (* pixel's plane *)
pop di
push di
mov ax,x
add al,Plane
adc ah,0
shr ax,2
add di,ax
xor dx,dx
@Lines:
xor ah,ah
lodsb
or al,al
jz @black
@color: xor cx,cx (* count for next n color pixel found *)
mov cl,al
add dx,cx
and al,1
jz @word_Move
@byte_Move:movsb
@word_move:shr cx,1
rep movsw
jmp @Ok
@black: lodsb (* 0 found, fill with pixel 0 *)
xor ch,ch
mov cl,al
add dx,cx
and al,1
jz @Word_Mov
@byte_Mov: xor al,al
stosb
@word_mov: shr cx,1
rep stosw
@Ok:
cmp dx,maxX
jne @Lines
xor dx,dx
add di,Next_Line
inc y1
mov ax,maxY
cmp y1,ax
jne @Lines
Inc Plane
cmp Plane,4
jne @Plane_Loop
pop di
pop ds
end;
procedure x_put_masked_ibm(x,y:WOrd;Var ibm); assembler;
var Next_Line,x1,y1,maxX,maxY : Word;
Plane : Byte;
asm
push ds
mov ax,SCREEN_SEG (* es:di points in Screen *)
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,ScreenOfs (* store result in DI *)
add di,ax
push di
mov dx,ScrnLogicalByteWidth
lds si,dword ptr [ibm] (* ds:si points in ibm *)
xor ax,ax
mov al,ds:[si]
shr al,2
mov maxX,ax
sub dx,ax
mov Next_Line,dx
inc si
mov al,ds:[si]
mov maxY,ax
inc si
mov Plane,0
@Plane_Loop:
mov y1,0
mov cx,x
add cl,Plane
(* SELECT WRITE PLANE *)
and cl,011b (* CL = plane *)
mov ax,0100h + MAP_MASK (* AL = index in SC of Map Mask reg *)
shl ah,cl (* set only the bit for the required *)
(* plane to 1 *)
mov dx,SC_INDEX (* set the Map Mask to enable only the *)
out dx,ax (* pixel's plane *)
pop di
push di
mov ax,x
add al,Plane
adc ah,0
shr ax,2
add di,ax
xor dx,dx
@Lines:
xor ah,ah
lodsb
or al,al
jz @black
@color: xor cx,cx (* count for next n color pixel found *)
mov cl,al
add dx,cx
and al,1
jz @word_Move
@byte_Move:movsb
@word_move:shr cx,1
rep movsw
jmp @Ok
@black: lodsb (* 0 found, add n screenpointer for trans. *)
add dx,ax (* pixels *)
add di,ax
@Ok:
cmp dx,maxX
jne @Lines
xor dx,dx
add di,Next_Line
inc y1
mov ax,maxY
cmp y1,ax
jne @Lines
Inc Plane
cmp Plane,4
jne @Plane_Loop
pop di
pop ds
end;
procedure x_load_ibm(var Name:String;var Bitmap); (* able with MasterFile *)
begin;
x_load_bitmap(Name,EXT_ibm,Bitmap);
end;
(***************************************************************************)
(****************************** VBM ****************************************)
(***************************************************************************)
type VBM_info_struc = record
Size : Word;
ImageWidth : Word;
ImageHeight : Word;
{ AlignData : Word;}
end;
VBM_alignment_struc = record
ImagePtr : Word;
MaskPtr : Word;
end;
const AlignData = 6;
(*---------------------------------------------------------------------- *)
(* 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 *)
(* *)
(* Returns the VideoOffs *)
(* *)
(* function x_store_vbm_image(VramOffs,Align:Word;Var Lbm):Word; *)
(* *)
(* Written by Themie Gouthas *)
(*---------------------------------------------------------------------- *)
function x_store_vbm_image(VramOffs,Align:Word;Var Lbm):Word; Assembler;
var BMWidth:Byte;
asm
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,[Lbm] (* 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 a*)
sub ax,[VramOffs] (* return value *)
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
end;
(* Alignment structures, 4 of which make up the header section of the *)
(* video bitmap *)
type alignment = record
ImagePtr : Word;
MaskPtr : Word;
end;
alignment_header = record
Size : Word;
ImageWidth : Word;
Imageheight : Word;
alignments : Array[0..3] of alignment;
end;
(* Structure to extract width/height frol LBM (linear bit map) *)
lbm_header = record
width,height: Byte;
end;
(*************************************************************************)
(* *)
(* Generates all four possible mode X image/mask alignments, stores *)
(* image alignments in display memory, allocates memory for and generates*)
(* mask alignments, and fills out a VBM aligned masked image structure. *)
(* Each non-zero byte in source bitmap corresponds to image pixel to be *)
(* drawn. *)
(* On success returns a far pointer to the new VBM structure otherwise *)
(* it returns NULL *)
(* *)
(* Source Language: C *)
(* *)
(* Parameters: *)
(* lbm pointer to linear bitmap *)
(* vramStart contains the next available video offset which is *)
(* also updated after calling this function *)
(* *)
(*************************************************************************)
function x_lbm_to_vbm(Var lbm;Var VramStart:Word):Pointer;
type PByte = ^Byte;
procedure IncP(Var P:PByte); assembler;
asm
les di,Dword ptr [P]
mov ax,es:[di]
inc ax
mov es:[di],ax
end;
var lbm_headr : ^lbm_header;
vbm_headr : ^alignment_header;
vbm_mask_ptr,p,lbm_pixel_ptr : PByte;
align,BitNum,TempImageWidth : Integer;
TempWidth,TempHeight,TempSize,MaskSize,VramOffs,MaskSpace : Word;
scanline : Integer;
MaskTemp,i : Byte;
begin;
MaskSpace := 0;
VramOffs := VramStart;
lbm_headr := addr(lbm);
TempWidth := (lbm_headr^.width+3)div 4+1;
TempHeight:= lbm_headr^.height;
TempSize := TempWidth*TempHeight;
if MemAvail<22+TempSize*4 then begin;x_lbm_to_vbm:=NIL;exit;end;
GetMEM(vbm_headr,22+TempSize*4);
MaskSpace:=22;
vbm_headr^.ImageWidth := TempWidth;
vbm_headr^.ImageHeight := TempHeight;
vbm_headr^.size := 22+TempSize*4;
for align:=0 to 3 do
begin;
vbm_headr^.alignments[align].ImagePtr := VramOffs;
VramOffs:=x_store_vbm_image(VramOffs,align,lbm);
Inc(MaskSpace,TempSize);
Inc(VramOffs,TempSize);
end;
vbm_mask_ptr := ptr(seg(vbm_headr^),ofs(vbm_headr^)+22);
for align:=0 to 3 do
begin;
lbm_pixel_ptr := ptr(seg(lbm),ofs(lbm)+2);
vbm_headr^.alignments[align].MaskPtr := ofs(vbm_mask_ptr^);
for scanline:=0 to TempHeight-1 do
begin;
BitNum :=align;
MaskTemp:=0;
for TempImageWidth:=lbm_headr^.width downto 1 do
begin;
MaskTemp := MaskTemp or (Byte(lbm_pixel_ptr^<>0) shl BitNum);
IncP(lbm_pixel_ptr);
Inc(BitNum);
if (BitNum > 3) then
begin;
vbm_mask_ptr^:=MaskTemp;
IncP(vbm_mask_ptr);
MaskTemp:=0;
BitNum:=0;
end;
{ Dec(TempImageWidth);}
end;
if BitNum<>0 then vbm_mask_ptr^:=MaskTemp
else vbm_mask_ptr^:=0;
IncP(vbm_mask_ptr);
end;
end;
VramStart:=VramOffs;
x_lbm_to_vbm:=vbm_headr;
end;
procedure x_put_masked_vbm(X,Y:Word;var SrcVBM); assembler;
var VBMWidth,VBMHeight,NextLineIncr:Word;
asm
push si
push di
push ds
cld
mov ax,[x]
and ax,not 3
or ax,3
mov [x],ax
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,[ScreenOfs] (* 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,1 (* Find starting byte in dest row*)
shr bx,1
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,1 (* si = offset of data for curr *)
shl si,1 (* alignment *)
{ mov ax,word ptr [bx+ImageHeight] }(* Get image height *)
mov ax,word ptr [bx+4]
mov [VBMHeight],ax
{ mov ax,word ptr [bx+ImageWidth] }(* Get image width *)
mov ax,word ptr [bx+2]
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 dx,[bx+2+AlignData+si]
{ mov bx,[bx+ImagePtr+AlignData+si]}(* ES:BX -> source video bitmap*)
mov bx,[bx+0+AlignData+si]
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
end;
procedure x_put_masked_vbm_clipx(X,Y:Word;Var SrcVBM); assembler;
var DataInc,LeftSkip,VBMWidth,VBMHeight,NextLineIncr:Word;
asm
push si
push di
push ds
cld
mov ax,[x]
and ax,not 3
or ax,3
mov [x],ax
mov di,[X] (* load X coord int DI and make a *)
mov si,di (* copy in SI *)
sar di,1 (* Find Byte offset of X coord *)
sar di,1
and si,3 (* Calculate pixels plane alignment *)
shl si,1 (* Prepare to lookup mask & data *)
shl si,1
les bx,[SrcVBM] (* ES:BX -> begining of VBM data *)
{ mov cx,es:[bx+ImageWidth]} (* Get image width and save in CX *)
mov cx,es:[bx+2]
(**** 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 @@HorizClipDone
(*** EXIT FOR COMPLETELY OBSCURED V.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(**** 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,[ScreenOfs] (* Add the current page offset *)
mov [VBMWidth],cx
{ mov ax,es:[bx+ImageHeight]} (* Get image height and save in AX *)
mov ax,es:[bx+4]
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 ax,[bx+2+AlignData+si]
{ mov bx,[bx+ImagePtr+AlignData+si]}(* ES:BX -> source video bitmap*)
mov bx,[bx+0+AlignData+si]
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 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
@Ok:
end;
procedure x_put_masked_vbm_clipy(X,Y:Word;Var SrcVBM); assembler;
var VBMWidth,VBMHeight,TopRow,NextLineIncr:Word;
asm
push si
push di
push ds
cld
mov ax,[x]
and ax,not 3
or ax,3
mov [x],ax
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,1 (* Prepare to lookup mask & data *)
shl si,1
les bx,[SrcVBM] (* ES:BX -> begining of VBM data *)
{ mov ax,es:[bx+ImageHeight]} (* Get image height and save in AX *)
mov ax,es:[bx+2]
(**** 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 @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED V.B.M's *********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(**** 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,1 (* Find Byte offset of X coord *)
shr di,1
add di,[ScreenOfs] (* Add the current page offset *)
{ mov cx,es:[bx+ImageWidth]} (* Get image width and save in CX *)
mov cx,es:[bx+2]
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 ax,[bx+2+AlignData+si]
{ mov bx,[bx+ImagePtr+AlignData+si]}(* ES:BX -> source video bitmap*)
mov bx,[bx+0+AlignData+si]
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 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
@Ok:
end;
procedure x_put_masked_vbm_clipxy(X,Y:Word;Var SrcVBM); assembler;
var DataInc,LeftSkip,VBMWidth,VBMHeight,TopRow,NextLineIncr:Word;
asm
push si
push di
push ds
cld
mov ax,[x]
and ax,not 3
or ax,3
mov [x],ax
mov di,[X] (* load X coord int DI and make a *)
mov si,di (* copy in SI *)
sar di,1 (* Find Byte offset of X coord *)
sar di,1
and si,3 (* Calculate pixels plane alignment *)
shl si,1 (* Prepare to lookup mask & data *)
shl si,1
les bx,[SrcVBM] (* ES:BX -> begining of VBM data *)
{ mov cx,es:[bx+ImageWidth]} (* Get image width and save in CX *)
mov cx,es:[bx+2]
{ mov ax,es:[bx+ImageHeight]} (* Get image height and save in AX *)
mov ax,es:[bx+4]
(**** 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 @@VertClipDone
(*** EXIT FOR COMPLETELY OBSCURED V.B.M's ********************)
@@NotVisible:
mov ax,1
pop ds (* restore data segment *)
pop di (* restore registers *)
pop si
jmp @Ok
(*** 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 @@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,[ScreenOfs] (* 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 ax,[bx+2+AlignData+si]
{ mov bx,[bx+ImagePtr+AlignData+si]} (* ES:BX -> source video bitmap*)
mov bx,[bx+0+AlignData+si]
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 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
@Ok:
end;
(* unit end - yeahhh *)
end.