home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_BAS
/
PCXVGA.ZIP
/
PCXVGA.BAS
Wrap
BASIC Source File
|
1994-01-08
|
13KB
|
479 lines
$IF 0
┌──────────────────────────────────────────────────────────────────────────┐
│ WESTFORD CUSTOM PC/FX ·■· PCXVGA.BAS ·■· 1/6/93 │
│ CIS: 76470,2417 ┌────────────────────────────────────────────────────────┘
│ 508-692-8163 ┌──┘
└──────────────┘
Contains LoadPCX16, a 16 color PCX image file
loader for VGA graphics mode 12h
This file contains the following routines:
SUB LoadPCX16(pcx$, Sline%, Col%) 16 color PCX file loader
SUB LoadColorPCX16 loads 16 color PCX data to VGA DAC regs
SUB VideoOff(action%) turns video display off/on
FUNCTION GetKey waits for/retrieves keystroke
IMPORTANT: LoadPCX16 calls the routine VideoOff to blank the screen
while the PCX image is being loaded. If you disable this feature,
be sure to rem out both calls to VideoOff.
ALSO IMPORTANT: LoadPCX16 allows an image smaller than full-screen
(640 X 480) to be repositioned on screen. However, instead of the
coordinate system (X,Y), with X and Y identifying pixel positions,
LoadPCX16 employs (Sline%, Col%) with Sline% identifying a vertical
screen pixel position and Col% following the text mode convention
(in this case 0-79) for horizontal positioning. The routine performs
error-checking for available repositioning space on-screen.
As now written, the demo requires VGA. LoadPCX16 calls the routine
LoadColorPCX16, which employs BIOS calls available only on color VGA
hardware. Error checking for repositioning also assumes VGA mode 12h
(640 X 480) only. However, with appropriate revision, the routine
should perform correctly on EGA hardware. I have not personally tested
the routine on an EGA system and would appreciate hearing from anyone
who adapts LoadPCX16 for EGA use.
I first wrote LoadPCX16 in BASIC (PB 3.0c). On my 386SX 16, loading the
test file (a fairly complex image originally generated by FRACTINT)
from a RAM drive took over 90 seconds. The routine as presented here,
converted almost entirely to assembly, loads the same image in 1.8 seconds.
My thanks to Murray Moffatt for his patience and persistence while
testing LoadPCX16.
── Greg Turgeon ──
$ENDIF
$OPTIMIZE SPEED
$LIB ALL OFF
'============
$LIB GRAPH ON
$LIB VGA ON
DECLARE FUNCTION GetStrLoc&(BYVAL AllocHandle%) 'must be declared
DEFINT A-Z
%yes = -1 : %no = 0
IF istrue(bit(pbvScrnCard, 0)) then end 'mono?
IF isfalse(bit(pbvScrnCard, 5)) then end 'VGA?
'''create variable to load w/PCX file header data
TYPE PCXheader
Mfg AS byte
Version AS byte
Encoding AS byte
BitsPerPixel AS byte
Xmin AS integer
Ymin AS integer
Xmax AS integer
Ymax AS integer
HorizontalRes AS integer
VerticalRes AS integer
Pal AS string * 48
Reserved AS byte
NumColrPlanes AS byte
BytesPerSLine AS integer
PalInfo AS integer
Filler AS string * 58
END TYPE
DIM PIX1 AS SHARED PCXheader
'''use command$ to identify pix to load
pcx$=ucase$(command$)
if isfalse(len(dir$(pcx$))) then
print : print "Cannot find PCX file "; pcx$
files "*.pcx"
end
end if
call LoadPCX16(pcx$, Sline%, Col%)
end
'===========================
SUB LoadPCX16 (FileName$, BYVAL Sline%, BYVAL Col%)
LOCAL MaxX%, MaxY%, FileBytes&, DOShandle%
LOCAL PixWidth%, PixHeight%, FBytesSeg??, FBytesPtr??, ChunkSize%
LOCAL PixBPerPlane%, BPerLine%, BPerPlane%, Plane%, BuffPtr%
LOCAL ScreenLine%, Mover??, LineEnd??
PCXfile = freefile
OPEN FileName$ FOR BINARY AS PCXfile
DOShandle% = fileattr(PCXfile, 2) 'DOS handle needed for asm
FileBytes& = lof(PCXfile)
'''load header into var & verify that PCX file is correct format
get# PCXfile,, PIX1
if PIX1.Mfg <> 10 OR PIX1.Version <> 5 then 'Mfg 10 = ZSoft, Version 5 = 3.0
close PCXfile
print : print "mfg: "; PIX1.mfg, "Version"; PIX1.Version
print "Incorrect PCX version"
exit sub
end if
PixWidth% = PIX1.Xmax - PIX1.Xmin
PixHeight% = PIX1.Ymax - PIX1.Ymin
print
print "Width: "; PixWidth%, "Height:"; PixHeight%
print "Encoding type:"; PIX1.Encoding
print "Bits per pixel per plane:"; PIX1.BitsPerPixel
print "Horizontal resolution of originating system:"; PIX1.HorizontalRes;
print " Vertical resolution:"; PIX1.VerticalRes
print "Number of color planes:"; PIX1.NumColrPlanes
print "Number of bytes per scan line per plane:"; PIX1.BytesPerSLine
print "Palette info (color/bw = 1, grayscale = 2):"; PIX1.PalInfo
print "File size: "; FileBytes&; " bytes"
k = getkey
if k = 27 then 'Esc to bypass loading
close PCXfile
exit sub
end if
screen 12
call VideoOff(%yes)
'''error checking: don't reposition image unless there's room
MaxX% = 639 : MaxY% = 479
if Sline% > (MaxY%-PixHeight%)-2 then Sline% = 0
if Col% > ((MaxX%-PixWidth%)\8) then Col% = 0
mtimer
PixBPerLine% = PIX1.BytesPerSLine 'create for asm
call LoadColorPCX16 'load PIX1.Pal colors
seek PCXfile, 128 'start of screen data
ChunkSize% = fre(t$) 'create largest buffer possible
FileBuffer$ = string$(ChunkSize%, 0) '(reduce size to smooth out display if
'not blanking)
! push word ptr FileBuffer$
! call getstrloc ;now dx:ax = loc, cx = length
! mov FBytesSeg??, dx ;save seg & addr of FileBuffer$
! mov FBytesPtr??, ax
'''establish offset if repositioning image
! mov ax, Sline%
! mov dx, 80
! mul dx
! add ax, Col%
! mov Mover??, ax
'''determine how many bytes per line for the current video mode
'''bytes per line will = screen column figure in BIOS data area
! xor bx, bx ;def seg=0:BPerLine%=peek(&h44A):def seg
! mov es, bx
! mov bx, &h44A
! mov ax, es:[bx]
! mov BPerLine%, ax
! call LoadChunk ;load FileBuffer$
! mov ScreenLine%, -1 ;start at -1 to allow for inc to 0
'''begin loading pix to screen
NewLine:
! inc ScreenLine%
! mov dx, ScreenLine%
! cmp dx, PixHeight% ;if ScreenLine% > PixHeight%, then PixDone
! jle LineOK
! jmp PixDone
LineOK:
! mov ax, BPerLine% ;Addr?? = BPerLine% * ScreenLine%
! imul dx
! mov di, ax ;di = target screen address for loading
! add ax, PixBPerLine% ;LineEnd?? = Addr??+PixBPerLine% (PIX1.BytesPerSLine)
! mov LineEnd??, ax
'''si = ptr to position in FileBuffer$, Plane% = target video plane
! mov Plane%, 0 ;begin each line w/plane 0
! call SelectPlane
NewByte:
! cmp Plane%, 3 ;done with all 3 planes?
! ja NewLine ;if yes
! call GetNextByte ;if no, load a byte into al from FileBuffer$
! mov ah, al ;make a copy of NextByte?
! and al, 192 ;if top 2 bits not set, then load the one byte
! cmp al, 192 ;if set, then it's a repeater, so load the
! je RepByte ;bytes and assume continuing on same line
! mov al, ah ;restore al = NextByte?, and load byte
! push di ;save di (stosb increases di)
! mov dx, &h0A000 ;base video seg
! add di, Mover?? ;add any repositioning value
! stosb ;load the byte to screen
! pop di
! inc di ;update position for loading
! mov ax, LineEnd?? ;check: at the end of a screen line?
! cmp ax, di
! ja NewByte ;if no
! mov ax, ScreenLine% ;if yes, then move back to
! mov bx, BPerLine% ;
! imul bx ;start of line and switch
! mov di, ax ;
! inc Plane% ;to next video plane
! call SelectPlane
! jmp NewByte
RepByte:
'''coming in, ah = NextByte?
! mov al, ah ;restore al = NextByte?
! and al, 63 ;clear bits 6&7 to leave the
! mov cl, al ;number of times to repeat
! xor ch, ch
! call GetNextByte ;load the color byte into al
DoTheReps:
! push di
! mov dx, &h0A000
! mov es, dx ;di already = address
! add di, Mover?? ;add any repositioning value
! stosb ;load to video
! pop di
! inc di
! cmp di, LineEnd?? ;at end of line?
! je NextPlane ;if yes, gosub NextPlane
DoNextRep:
! loop DoTheReps ;if no
! jmp NewByte
NextPlane:
! push ax
! push dx
! mov ax, ScreenLine% ;move back to start of line
! mov dx, BPerLine% ;and
! imul dx ;move to next video plane
! mov di, ax
! inc Plane%
! pop dx
! pop ax
! call SelectPlane
! jmp DoNextRep
PixDone:
'''reset all planes
! mov ax, &h0F02
! mov dx, &h3C4
! out dx, ax
close PCXfile
t1#=mtimer/1000000
call VideoOff(%no)
sound 250, .3 : getkey
screen 0
print FileName$
print "total time to display =";using"##.########";(t1#); : print " seconds"
exit sub
'===========
GetNextByte:
'''don't push ax; it sends back NextByte?
! push bx
! push cx
! push es
! mov es, FBytesSeg??
! mov bx, FBytesPtr??
! add bx, si ;si=FileBuffer$ byte ptr, so bx now -> NextByte?
! mov al, byte ptr es:[bx] ;now al = NextByte?
! inc si ;increase FileBuffer$ ptr
! dec BuffPtr% ;decrease ptr for countdown
! jnz ChunkNotDone ;if more in FileBuffer$
! call LoadChunk ;if empty, then get more
ChunkNotDone:
! pop es
! pop cx
! pop bx
! retn
'===========
LoadChunk:
! push ax
! push bx
! push cx
! push dx
! push ds
'if FileBytes& =< ChunkSize% then ChunkSize% = FileBytes&
! mov ax, FileBytes&[00]
! mov dx, FileBytes&[02]
! cmp dx, 0 ;if dx <> 0 then FileBytes& must
! jg SameSize ;be > ChunkSize%
! cmp ax, ChunkSize%
! jle SameSize ;if FileBytes& < ChunkSize%, then make
! mov ChunkSize%, ax ;ChunkSize% = FileBytes& for final pass
SameSize:
! mov bx, FBytesSeg??
! mov ds, bx
! mov dx, FBytesPtr??
! mov bx, DOShandle%
! mov cx, ChunkSize%
! mov ah, &h3F ;reload FileBuffer$
! int &h21
! jnc ReCalc
ErrorHandler:
! mov ChunkSize%, ax
! pop ds
! pop dx
! pop cx
! pop bx
! pop ax
close
locate 1,1
if istrue(ChunkSize%) then
sound 800, .5 : print "Error: "; ChunkSize%
end if
getkey
screen 0
end
ReCalc:
! mov ax, FileBytes&[00] ;recalculate size of remaining FileBytes&
! mov dx, FileBytes&[02]
! mov bx, ChunkSize% ;subtract portion already loaded to screen
! sub ax, bx
! sbb dx, 0
! mov FileBytes&[02], dx
! mov FileBytes&[00], ax
! xor si, si ;si=FileBuffer$ ptr for loading; start at 0
! mov ax, ChunkSize%
! mov BuffPtr%, ax ;ptr for countdown
! pop ds
! pop dx
! pop cx
! pop bx
! pop ax
! retn
'===========
SelectPlane:
! push ax
! push bx
! push cx
! push dx
! mov ax, 1 ;determine 2^plane
! cbw
! mov cx, Plane%
! shl ax, cl
! mov ah, al ;ah now = plane desired
! mov dx, &h3C4 ;plane select
! mov al, 2
! out dx, ax
! pop dx
! pop cx
! pop bx
! pop ax
! retn
END SUB
'===========================
SUB LoadColorPCX16
NumBytes?? = len(PIX1.Pal)
Addr1??=varptr(PIX1.Pal)
'''palette regs actually index -> DAC regs
'''build array of the DAC regs to which palette regs (0-15) are indexed
redim temp?(0:15)
restore DefaultDACregs
for a? = 0 to 15 : read temp?(a?) : next a?
DACValSeg??=varseg(temp?(0)) : DACValPtr??=varptr(temp?(0))
'''reduce PCX 0-255 color values to 0-63
! push ax
! push bx
! push cx
! push dx
! push es
! push si
! push di ;make both ds:si & es:di -> PIX1.Pal
! mov ax, ds ;all fixed length strings are in ds
! mov es, ax
! mov ax, Addr1??
! mov si, ax
! mov di, ax
! mov cx, NumBytes??
! cld ;increment
Reducer:
! lodsb
! shr al, 1 ;\4 to reduce
! shr al, 1
! stosb
! loop Reducer
'''load each DAC reg
! mov si, Addr1?? ;now ds:[si] = PIX1.Pal
! mov es, DACValSeg??
! mov di, DACValPtr?? ;es:[di] = temp%(0)
! mov cx, 16
! mov ax, &h1010
! xor bx, bx
LoadRegs:
! push cx
! mov bl, byte ptr es:[di] ;pal reg
! mov dh, byte ptr ds:[si] ;red
! inc si
! mov ch, byte ptr ds:[si] ;green
! inc si
! mov cl, byte ptr ds:[si] ;blue
! inc si
! push bp
! int &h10
! pop bp
! pop cx
! inc di ;next pal reg
! loop LoadRegs
! pop di
! pop si
! pop es
! pop dx
! pop cx
! pop bx
! pop ax
erase temp?
exit sub
DefaultDACregs:
DATA 0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63
END SUB
'=========================
Sub VideoOff(BYVAL action%) STATIC
'''turns video off/on
LOCAL DisAble?
if istrue(action%) then DisAble? = 1
! mov ah, &h12
! mov al, DisAble?
! mov bl, &h36
! int &h10
END SUB
'===========================
FUNCTION GetKey
'''returns ascii of keypress, negative for extended key
do : k$=Inkey$ : loop until len(k$)
if len(k$)=1 then
temp1=ascii(k$)
else
temp1=-ascii(right$(k$, 1))
end if
GetKey=temp1
END FUNCTION