home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_BAS / PCXVGA.ZIP / PCXVGA.BAS
BASIC Source File  |  1994-01-08  |  13KB  |  479 lines

  1. $IF 0
  2. ┌──────────────────────────────────────────────────────────────────────────┐
  3. │ WESTFORD CUSTOM PC/FX          ·■·   PCXVGA.BAS   ·■·             1/6/93 │
  4. │ CIS: 76470,2417 ┌────────────────────────────────────────────────────────┘
  5. │ 508-692-8163 ┌──┘
  6. └──────────────┘
  7.                     Contains LoadPCX16, a 16 color PCX image file
  8.                         loader for VGA graphics mode 12h
  9.  
  10.  
  11. This file contains the following routines:
  12.  
  13. SUB LoadPCX16(pcx$, Sline%, Col%)    16 color PCX file loader
  14. SUB LoadColorPCX16                   loads 16 color PCX data to VGA DAC regs
  15. SUB VideoOff(action%)                     turns video display off/on
  16. FUNCTION GetKey                      waits for/retrieves keystroke
  17.  
  18.  
  19. IMPORTANT: LoadPCX16 calls the routine VideoOff to blank the screen
  20. while the PCX image is being loaded.  If you disable this feature,
  21. be sure to rem out both calls to VideoOff.
  22.  
  23. ALSO IMPORTANT: LoadPCX16 allows an image smaller than full-screen
  24. (640 X 480) to be repositioned on screen.  However, instead of the
  25. coordinate system (X,Y), with X and Y identifying pixel positions,
  26. LoadPCX16 employs (Sline%, Col%) with Sline% identifying a vertical
  27. screen pixel position and Col% following the text mode convention
  28. (in this case 0-79) for horizontal positioning.  The routine performs
  29. error-checking for available repositioning space on-screen.
  30.  
  31. As now written, the demo requires VGA.  LoadPCX16 calls the routine
  32. LoadColorPCX16, which employs BIOS calls available only on color VGA
  33. hardware.  Error checking for repositioning also assumes VGA mode 12h
  34. (640 X 480) only.  However, with appropriate revision, the routine
  35. should perform correctly on EGA hardware.  I have not personally tested
  36. the routine on an EGA system and would appreciate hearing from anyone
  37. who adapts LoadPCX16 for EGA use.
  38.  
  39. I first wrote LoadPCX16 in BASIC (PB 3.0c).  On my 386SX 16, loading the
  40. test file (a fairly complex image originally generated by FRACTINT)
  41. from a RAM drive took over 90 seconds.  The routine as presented here,
  42. converted almost entirely to assembly, loads the same image in 1.8 seconds.
  43.  
  44. My thanks to Murray Moffatt for his patience and persistence while
  45. testing LoadPCX16.
  46.  
  47.                                         ──  Greg Turgeon ──
  48. $ENDIF
  49.  
  50. $OPTIMIZE SPEED
  51. $LIB ALL OFF
  52. '============
  53. $LIB GRAPH ON
  54. $LIB VGA ON
  55. DECLARE FUNCTION GetStrLoc&(BYVAL AllocHandle%)        'must be declared
  56.  
  57. DEFINT A-Z
  58. %yes = -1 : %no = 0
  59.  
  60. IF istrue(bit(pbvScrnCard, 0)) then end              'mono?
  61. IF isfalse(bit(pbvScrnCard, 5)) then end         'VGA?
  62.  
  63. '''create variable to load w/PCX file header data
  64. TYPE PCXheader
  65.     Mfg AS byte
  66.     Version AS byte
  67.     Encoding AS byte
  68.     BitsPerPixel AS byte
  69.     Xmin AS integer
  70.     Ymin AS integer
  71.     Xmax AS integer
  72.     Ymax AS integer
  73.     HorizontalRes AS integer
  74.     VerticalRes AS integer
  75.     Pal AS string * 48
  76.     Reserved AS byte
  77.     NumColrPlanes AS byte
  78.     BytesPerSLine AS integer
  79.     PalInfo AS integer
  80.     Filler AS string * 58
  81. END TYPE
  82. DIM PIX1 AS SHARED PCXheader
  83.  
  84.  
  85. '''use command$ to identify pix to load
  86. pcx$=ucase$(command$)
  87. if isfalse(len(dir$(pcx$))) then
  88.     print : print "Cannot find PCX file "; pcx$
  89.    files "*.pcx"
  90.     end
  91. end if
  92.  
  93. call LoadPCX16(pcx$, Sline%, Col%)
  94. end
  95.  
  96. '===========================
  97. SUB LoadPCX16 (FileName$, BYVAL Sline%, BYVAL Col%)
  98. LOCAL MaxX%, MaxY%, FileBytes&, DOShandle%
  99. LOCAL PixWidth%, PixHeight%, FBytesSeg??, FBytesPtr??, ChunkSize%
  100. LOCAL PixBPerPlane%, BPerLine%, BPerPlane%, Plane%, BuffPtr%
  101. LOCAL ScreenLine%, Mover??, LineEnd??
  102.  
  103. PCXfile = freefile
  104. OPEN FileName$ FOR BINARY AS PCXfile
  105. DOShandle% = fileattr(PCXfile, 2)          'DOS handle needed for asm
  106. FileBytes& = lof(PCXfile)
  107.  
  108. '''load header into var & verify that PCX file is correct format
  109. get# PCXfile,, PIX1
  110. if PIX1.Mfg <> 10 OR PIX1.Version <> 5 then    'Mfg 10 = ZSoft, Version 5 = 3.0
  111.     close PCXfile
  112.     print : print "mfg: "; PIX1.mfg,  "Version"; PIX1.Version
  113.     print "Incorrect PCX version"
  114.    exit sub
  115. end if
  116.  
  117. PixWidth% = PIX1.Xmax - PIX1.Xmin
  118. PixHeight% = PIX1.Ymax - PIX1.Ymin
  119.  
  120. print
  121. print "Width: "; PixWidth%, "Height:"; PixHeight%
  122. print "Encoding type:"; PIX1.Encoding
  123. print "Bits per pixel per plane:"; PIX1.BitsPerPixel
  124. print "Horizontal resolution of originating system:"; PIX1.HorizontalRes;
  125. print "  Vertical resolution:"; PIX1.VerticalRes
  126. print "Number of color planes:"; PIX1.NumColrPlanes
  127. print "Number of bytes per scan line per plane:"; PIX1.BytesPerSLine
  128. print "Palette info (color/bw = 1, grayscale = 2):"; PIX1.PalInfo
  129. print "File size: "; FileBytes&; " bytes"
  130.  
  131. k = getkey
  132. if k = 27 then                'Esc to bypass loading
  133.     close PCXfile
  134.    exit sub
  135. end if
  136.  
  137. screen 12
  138. call VideoOff(%yes)
  139.  
  140. '''error checking: don't reposition image unless there's room
  141. MaxX% = 639 : MaxY% = 479
  142. if Sline% > (MaxY%-PixHeight%)-2 then Sline% = 0
  143. if Col% > ((MaxX%-PixWidth%)\8) then Col% = 0
  144.  
  145. mtimer
  146.  
  147. PixBPerLine% = PIX1.BytesPerSLine        'create for asm
  148. call LoadColorPCX16                            'load PIX1.Pal colors
  149. seek PCXfile, 128                                'start of screen data
  150.  
  151. ChunkSize% = fre(t$)                            'create largest buffer possible
  152. FileBuffer$ = string$(ChunkSize%, 0)    '(reduce size to smooth out display if
  153.                                                     'not blanking)
  154.  
  155. !     push     word ptr FileBuffer$
  156. !     call     getstrloc                    ;now dx:ax = loc, cx = length
  157. !     mov     FBytesSeg??, dx            ;save seg & addr of FileBuffer$
  158. !     mov     FBytesPtr??, ax
  159.  
  160. '''establish offset if repositioning image
  161. !    mov    ax, Sline%
  162. !    mov    dx, 80
  163. !    mul    dx
  164. !    add    ax, Col%
  165. !    mov    Mover??, ax
  166.  
  167. '''determine how many bytes per line for the current video mode
  168. '''bytes per line will = screen column figure in BIOS data area
  169. !    xor     bx, bx                        ;def seg=0:BPerLine%=peek(&h44A):def seg
  170. !    mov     es, bx
  171. !    mov     bx, &h44A
  172. !    mov     ax, es:[bx]
  173. !    mov     BPerLine%, ax
  174. !    call    LoadChunk                    ;load FileBuffer$
  175. !    mov    ScreenLine%, -1            ;start at -1 to allow for inc to 0
  176.  
  177. '''begin loading pix to screen
  178. NewLine:
  179. !    inc     ScreenLine%
  180. !    mov     dx, ScreenLine%
  181. !    cmp     dx, PixHeight%            ;if ScreenLine% > PixHeight%, then PixDone
  182. !    jle     LineOK
  183. !    jmp     PixDone
  184. LineOK:
  185. !    mov     ax, BPerLine%        ;Addr?? = BPerLine% * ScreenLine%
  186. !    imul     dx
  187. !    mov     di, ax                    ;di = target screen address for loading
  188. !    add    ax, PixBPerLine%     ;LineEnd?? = Addr??+PixBPerLine% (PIX1.BytesPerSLine)
  189. !    mov    LineEnd??, ax
  190.  
  191. '''si = ptr to position in FileBuffer$, Plane% = target video plane
  192. !    mov    Plane%, 0                ;begin each line w/plane 0
  193. !    call     SelectPlane
  194. NewByte:
  195. !    cmp     Plane%, 3                ;done with all 3 planes?
  196. !    ja        NewLine                    ;if yes
  197. !  call    GetNextByte                ;if no, load a byte into al from FileBuffer$
  198. !  mov     ah, al                  ;make a copy of NextByte?
  199. !  and     al, 192                 ;if top 2 bits not set, then load the one byte
  200. !  cmp     al, 192                 ;if set, then it's a repeater, so load the
  201. !  je     RepByte                    ;bytes and assume continuing on same line
  202. !  mov     al, ah                  ;restore al = NextByte?, and load byte
  203. !  push     di                            ;save di (stosb increases di)
  204. !    mov    dx, &h0A000                ;base video seg
  205. !    add    di, Mover??                ;add any repositioning value
  206. !  stosb                                ;load the byte to screen
  207. !  pop     di
  208. !  inc     di                            ;update position for loading
  209.  
  210. !  mov     ax, LineEnd??        ;check: at the end of a screen line?
  211. !    cmp    ax, di
  212. !    ja     NewByte              ;if no
  213. !  mov     ax, ScreenLine%         ;if yes, then move back to
  214. !  mov     bx, BPerLine%            ;
  215. !  imul     bx                   ;start of line and switch
  216. !  mov     di, ax               ;
  217. !  inc     Plane%                    ;to next video plane
  218. !  call     SelectPlane
  219. !  jmp     NewByte
  220.  
  221. RepByte:
  222. '''coming in, ah = NextByte?
  223. !  mov     al, ah               ;restore al = NextByte?
  224. !    and     al, 63                    ;clear bits 6&7 to leave the
  225. !    mov     cl, al               ;number of times to repeat
  226. !    xor    ch, ch
  227. !    call     GetNextByte          ;load the color byte into al
  228. DoTheReps:
  229. !    push     di
  230. !    mov    dx, &h0A000
  231. !    mov    es, dx                    ;di already = address
  232. !    add    di, Mover??                ;add any repositioning value
  233. !    stosb                                ;load to video
  234. !    pop     di
  235.  
  236. !    inc     di
  237. !    cmp    di, LineEnd??            ;at end of line?
  238. !    je     NextPlane            ;if yes, gosub NextPlane
  239. DoNextRep:
  240. !    loop     DoTheReps            ;if no
  241. !  jmp     NewByte
  242.  
  243. NextPlane:
  244. !    push    ax
  245. !    push    dx
  246. !    mov     ax, ScreenLine%      ;move back to start of line
  247. !    mov     dx, BPerLine%        ;and
  248. !    imul     dx                   ;move to next video plane
  249. !    mov     di, ax
  250. !    inc     Plane%
  251. !    pop    dx
  252. !    pop    ax
  253. !    call     SelectPlane
  254. !    jmp DoNextRep
  255.  
  256. PixDone:
  257. '''reset all planes
  258. !    mov    ax, &h0F02
  259. !    mov    dx, &h3C4
  260. !    out    dx, ax
  261.  
  262. close PCXfile
  263.  
  264. t1#=mtimer/1000000
  265. call VideoOff(%no)
  266. sound 250, .3 : getkey
  267.  
  268. screen 0
  269. print FileName$
  270. print "total time to display =";using"##.########";(t1#); : print " seconds"
  271. exit sub
  272.  
  273. '===========
  274. GetNextByte:
  275. '''don't push ax; it sends back NextByte?
  276. !    push     bx
  277. !    push     cx
  278. !    push     es
  279.  
  280. !     mov     es, FBytesSeg??
  281. !  mov     bx, FBytesPtr??
  282. !  add     bx, si                    ;si=FileBuffer$ byte ptr, so bx now -> NextByte?
  283. !  mov     al, byte ptr es:[bx]        ;now al = NextByte?
  284.  
  285. !    inc     si                            ;increase FileBuffer$ ptr
  286. !    dec     BuffPtr%                    ;decrease ptr for countdown
  287. !    jnz    ChunkNotDone         ;if more in FileBuffer$
  288. !  call     LoadChunk                ;if empty, then get more
  289.  
  290. ChunkNotDone:
  291. !    pop    es
  292. !    pop     cx
  293. !    pop     bx
  294. !    retn
  295.  
  296. '===========
  297. LoadChunk:
  298. !    push     ax
  299. !    push     bx
  300. !    push     cx
  301. !    push     dx
  302. !    push     ds
  303.  
  304. 'if FileBytes& =< ChunkSize% then ChunkSize% = FileBytes&
  305. !    mov     ax, FileBytes&[00]
  306. !    mov     dx, FileBytes&[02]
  307. !    cmp     dx, 0                        ;if dx <> 0 then FileBytes& must
  308. !    jg     SameSize             ;be > ChunkSize%
  309. !    cmp     ax, ChunkSize%
  310. !  jle     SameSize                    ;if FileBytes& < ChunkSize%, then make
  311. !    mov     ChunkSize%, ax       ;ChunkSize% = FileBytes& for final pass
  312. SameSize:
  313. !     mov     bx, FBytesSeg??
  314. !    mov     ds, bx
  315. !  mov     dx, FBytesPtr??
  316. !    mov     bx, DOShandle%
  317. !    mov     cx, ChunkSize%
  318. !    mov     ah, &h3F                    ;reload FileBuffer$
  319. !    int     &h21
  320. !    jnc     ReCalc
  321. ErrorHandler:
  322. !    mov     ChunkSize%, ax
  323. !    pop     ds
  324. !    pop     dx
  325. !    pop     cx
  326. !    pop     bx
  327. !    pop     ax
  328. close
  329. locate 1,1
  330. if istrue(ChunkSize%) then
  331.     sound 800, .5 : print "Error: "; ChunkSize%
  332. end if
  333. getkey
  334. screen 0
  335. end
  336. ReCalc:
  337. !    mov     ax, FileBytes&[00]   ;recalculate size of remaining FileBytes&
  338. !    mov     dx, FileBytes&[02]
  339. !    mov     bx, ChunkSize%            ;subtract portion already loaded to screen
  340. !    sub     ax, bx
  341. !    sbb     dx, 0
  342. !    mov     FileBytes&[02], dx
  343. !    mov     FileBytes&[00], ax
  344. !    xor     si, si                    ;si=FileBuffer$ ptr for loading; start at 0
  345. !    mov    ax, ChunkSize%
  346. !    mov     BuffPtr%, ax            ;ptr for countdown
  347.  
  348. !    pop     ds
  349. !    pop     dx
  350. !    pop     cx
  351. !    pop     bx
  352. !    pop     ax
  353. !    retn
  354.  
  355. '===========
  356. SelectPlane:
  357. !    push     ax
  358. !    push     bx
  359. !    push     cx
  360. !    push     dx
  361.  
  362. !    mov     ax, 1                        ;determine 2^plane
  363. !    cbw
  364. !    mov     cx, Plane%
  365. !    shl     ax, cl
  366. !    mov    ah, al                    ;ah now = plane desired
  367. !    mov     dx, &h3C4                ;plane select
  368. !    mov     al, 2
  369. !    out    dx, ax
  370.  
  371. !    pop     dx
  372. !    pop     cx
  373. !    pop     bx
  374. !    pop     ax
  375. !    retn
  376. END SUB
  377.  
  378.  
  379. '===========================
  380. SUB LoadColorPCX16
  381. NumBytes?? = len(PIX1.Pal)
  382. Addr1??=varptr(PIX1.Pal)
  383.  
  384. '''palette regs actually index -> DAC regs
  385. '''build array of the DAC regs to which palette regs (0-15) are indexed
  386. redim temp?(0:15)
  387. restore DefaultDACregs
  388. for a? = 0 to 15 : read temp?(a?) : next a?
  389. DACValSeg??=varseg(temp?(0)) : DACValPtr??=varptr(temp?(0))
  390.  
  391. '''reduce PCX 0-255 color values to 0-63
  392. !    push    ax
  393. !    push    bx
  394. !    push    cx
  395. !    push    dx
  396. !     push     es
  397. !    push     si
  398. !    push     di                   ;make both ds:si & es:di -> PIX1.Pal
  399.  
  400. !  mov     ax, ds               ;all fixed length strings are in ds
  401. !    mov     es, ax
  402. !    mov     ax, Addr1??
  403. !    mov     si, ax
  404. !    mov     di, ax
  405. !    mov     cx, NumBytes??
  406. !    cld                                ;increment
  407. Reducer:
  408. !    lodsb
  409. !    shr     al, 1                ;\4 to reduce
  410. !    shr     al, 1
  411. !    stosb
  412. !    loop     Reducer
  413.  
  414. '''load each DAC reg
  415. !    mov     si, Addr1??                ;now ds:[si] = PIX1.Pal
  416. !    mov    es, DACValSeg??
  417. !    mov    di, DACValPtr??        ;es:[di] = temp%(0)
  418. !    mov    cx, 16
  419. !    mov    ax, &h1010
  420. !    xor    bx, bx
  421.  
  422. LoadRegs:
  423. !    push    cx
  424. !    mov    bl, byte ptr es:[di]            ;pal reg
  425. !    mov    dh, byte ptr ds:[si]            ;red
  426. !    inc    si
  427. !    mov    ch, byte ptr ds:[si]       ;green
  428. !    inc    si
  429. !    mov    cl, byte ptr ds:[si]       ;blue
  430. !    inc    si
  431.  
  432. !     push     bp
  433. !     int     &h10
  434. !     pop     bp
  435.  
  436. !    pop    cx
  437. !    inc    di                                    ;next pal reg
  438. !    loop LoadRegs
  439.  
  440. !    pop     di
  441. !    pop     si
  442. !     pop     es
  443. !    pop    dx
  444. !    pop    cx
  445. !    pop    bx
  446. !    pop    ax
  447. erase temp?
  448. exit sub
  449.  
  450. DefaultDACregs:
  451. DATA    0,1,2,3,4,5,20,7,56,57,58,59,60,61,62,63
  452. END SUB
  453.  
  454.  
  455. '=========================
  456. Sub VideoOff(BYVAL action%) STATIC
  457. '''turns video off/on
  458. LOCAL DisAble?
  459. if istrue(action%) then DisAble? = 1
  460. !    mov     ah, &h12
  461. !    mov    al, DisAble?
  462. !    mov    bl, &h36
  463. !    int    &h10
  464. END SUB
  465.  
  466.  
  467. '===========================
  468. FUNCTION GetKey
  469. '''returns ascii of keypress, negative for extended key
  470. do : k$=Inkey$ : loop until len(k$)
  471. if len(k$)=1 then
  472.     temp1=ascii(k$)
  473. else
  474.     temp1=-ascii(right$(k$, 1))
  475. end if
  476. GetKey=temp1
  477. END FUNCTION
  478.  
  479.