[mod.amiga.sources] LoadILBM_SaveACBM

doc@pucc-j.UUCP (06/28/86)

Reply-To: ihnp4!cbmvax!carolyn@ecn (Carolyn Scheppner)

REM - LoadILBM-SaveACBM
REM -  by Carolyn Scheppner  CBM  04/86

REM - This program loads an IFF ILBM
REM -  (Graphicraft,Deluxe Paint, etc.)
REM -  into a custom screen/window.
REM -  If a Graphicraft color cycling
REM -  chunk (CCRT) is found, it will
REM -  also demo the color cycling.

REM - If the user wishes, the screen
REM -  is then saved in a file format
REM -  (ACBM - Amiga Contiguous BitMap)
REM -  which an AmigaBasic program can
REM -  load more quickly. (LoadACBM)
REM -  The ACBM form is similar to
REM -  an ILBM form, except an ABIT
REM -  chunk replaces the interleaved 
REM -  BODY chunk.  ABIT contains
REM -  sequential contiguous Amiga
REM -  BitPlane data.

REM - Requires exec, graphics and dos
REM -  .bmaps (Use NewConvertFD)
REM

Main:

PRINT "LoadILBM-SaveACBM --- ILBM loader and converter"
PRINT
PRINT " This program loads and displays an IFF ILBM pic file"
PRINT "(Graphicraft, DPaint, Images) and optionally saves it"
PRINT "in ACBM format (see comments for description)."
PRINT "ACBM files can be loaded more quickly from Basic."
PRINT
PRINT " Uncompacted ILBMs (Graphicraft) load fairly quickly but"
PRINT "compacted ILBMs (DPaint, Images) have long load times."
PRINT "Screen blanking during the load has been commented out"
PRINT "so the progress of the load can be monitored."
PRINT 

DIM bPlane&(5), cTabWork%(32), cTabSave%(32)

REM - Must create cycling variables
REM -  because this version of SaveACBM
REM -  always saves a CCRT chunk
ccrtDir%   = 0
ccrtStart% = 0
ccrtEnd%   = 0
ccrtSecs&  = 0
ccrtMics&  = 0


REM - Functions from dos.library                   
DECLARE FUNCTION xOpen&  LIBRARY
DECLARE FUNCTION xRead&  LIBRARY
DECLARE FUNCTION xWrite& LIBRARY
DECLARE FUNCTION IoErr&  LIBRARY
REM - xClose returns no value

REM - Functions from exec.library
DECLARE FUNCTION AllocMem&() LIBRARY
REM - FreeMem returns no value

PRINT:PRINT "Looking for bmaps ... ";
LIBRARY "dos.library"
LIBRARY "exec.library"
LIBRARY "graphics.library"
PRINT "found them."
PRINT:PRINT "ENTER FILESPECS:"
PRINT "( Try Heart.ILBM, MedRes.ILBM or HiRes.ILBM )"
PRINT "( To view ILBM without converting, enter <RET> for ACBM filespec )"
PRINT

GetNames:
INPUT "   IFF ILBM filespec";ILBMname$
IF (ILBMname$ = "") GOTO Mcleanup2

INPUT "   ACBM filespec";ACBMname$
PRINT

REM - Load the IFF ILBM pic
loadError$ = ""
GOSUB LoadILBM
IF loadError$ <> "" THEN GOTO Mcleanup

REM - Demo Graphicraft color cycling
IF foundCCRT AND ccrtDir% THEN
   REM - Save colors
   FOR kk = 0 TO nColors% -1
      cTabSave%(kk) = PEEKW(colorTab&+(kk*2))   
      cTabWork%(kk) = cTabSave%(kk)
   NEXT
   
   REM - Cycle colors
   FOR kk = 0 TO 80
      IF ccrtDir% = 1 THEN
         GOSUB Fcycle
      ELSE   
         GOSUB Bcycle
      END IF

      CALL LoadRGB4&(sViewPort&,VARPTR(cTabWork%(0)),nColors%)
      REM - Delays approximated
      FOR de1 = 0 TO ccrtSecs& * 3000
         FOR de2 = 0 TO ccrtMics& / 500
         NEXT
      NEXT
   NEXT

   REM - Restore colors
   CALL LoadRGB4&(sViewPort&,VARPTR(cTabSave%(0)),nColors%)
END IF


REM - Save screen as ACBM file
IF (loadError$ = "") AND (ACBMname$<>"") THEN
   saveError$ = ""
   GOSUB SaveACBM
END IF

Mcleanup:
FOR de = 1 TO 20000:NEXT
WINDOW CLOSE 2
SCREEN CLOSE 2

Mcleanup2:
LIBRARY CLOSE
IF loadError$ <> "" THEN PRINT loadError$
IF saveError$ <> "" THEN PRINT saveError$

END


Bcycle:  'Backward color cycle
cTemp% = cTabWork%(ccrtEnd%)
FOR jj = ccrtEnd%-1 TO ccrtStart% STEP -1
   cTabWork%(jj+1) = cTabWork%(jj)
NEXT
cTabWork%(ccrtStart%) = cTemp%
RETURN

Fcycle:  'Forward color cycle
cTemp% = cTabWork%(ccrtStart%)
FOR jj = ccrtStart%+1 TO ccrtEnd%
   cTabWork%(jj-1) = cTabWork%(jj)
NEXT
cTabWork%(ccrtEnd%) = cTemp%
RETURN


LoadILBM:
REM - Requires the following variables
REM - to have been initialized:
REM -    ILBMname$ (IFF filename)

REM - init variables
f$ = ILBMname$
fHandle& = 0
mybuf& = 0
foundBMHD = 0
foundCMAP = 0
foundCAMG = 0
foundCCRT = 0
foundBODY = 0

REM - From include/libraries/dos.h
REM - MODE_NEWFILE = 1006 
REM - MODE_OLDFILE = 1005

filename$ = f$ + CHR$(0)
fHandle& = xOpen&(SADD(filename$),1005)
IF fHandle& = 0 THEN
   loadError$ = "Can't open/find pic file"
   GOTO Lcleanup
END IF


REM - Alloc ram for work buffers
ClearPublic& = 65537&
mybufsize& = 360
mybuf& = AllocMem&(mybufsize&,ClearPublic&)
IF mybuf& = 0 THEN
   loadError$ = "Can't alloc buffer"
   GOTO Lcleanup
END IF

inbuf& = mybuf&
cbuf& = mybuf& + 120
ctab& = mybuf& + 240


REM - Should read  FORMnnnnILBM
rLen& = xRead&(fHandle&,inbuf&,12)
tt$ = ""
FOR kk = 8 TO 11
   tt% = PEEK(inbuf& + kk)
   tt$ = tt$ + CHR$(tt%)
NEXT

IF tt$ <> "ILBM" THEN 
   loadError$ = "Not standard ILBM pic file"
   GOTO Lcleanup
END IF

REM - Read ILBM chunks

ChunkLoop:
REM - Get Chunk name/length
 rLen& = xRead&(fHandle&,inbuf&,8)
 icLen& = PEEKL(inbuf& + 4)
 tt$ = ""
 FOR kk = 0 TO 3
    tt% = PEEKK(inbuf& + kk)
    tt$ = tt$ + CHR$(tt%)
 NEXT   
    
IF tt$ = "BMHD" THEN  'BitMap header 
   foundBMHD = 1
   rLen& = xRead&(fHandle&,inbuf&,icLen&)
   iWidth%  = PEEKW(inbuf&)
   iHeight% = PEEKW(inbuf& + 2)
   iDepth%  = PEEK(inbuf& + 8)  
   iCompr%  = PEEK(inbuf& + 10)
   scrWidth%  = PEEKW(inbuf& + 16)
   scrHeight% = PEEKW(inbuf& + 18)

   iRowBytes% = iWidth% /8
   scrRowBytes% = scrWidth% / 8
   nColors%  = 2^(iDepth%)

   REM - Enough free ram to display ?
   AvailRam& = FRE(-1)
   NeededRam& = ((scrWidth%/8)*scrHeight%*(iDepth%+1))+5000
   IF AvailRam& < NeededRam& THEN
      loadError$ = "Not enough free ram"
      GOTO Lcleanup
   END IF

   kk = 1
   IF scrWidth% > 320 THEN kk = kk + 1
   IF scrHeight% > 200  THEN kk = kk + 2
   SCREEN 2,scrWidth%,scrHeight%,iDepth%,kk
   WINDOW 2,"LoadILBM-SaveACBM",,15,2

   REM - Get addresses of structures
   GOSUB GetScrAddrs

   REM - Black out screen
   REM CALL LoadRGB4&(sViewPort&,ctab&,nColors%)


ELSEIF tt$ = "CMAP" THEN  'ColorMap
   foundCMAP = 1
   rLen& = xRead&(fHandle&,cbuf&,icLen&)

   REM - Build Color Table
   FOR kk = 0 TO nColors% - 1
      red% = PEEK(cbuf&+(kk*3))
      gre% = PEEK(cbuf&+(kk*3)+1)
      blu% = PEEK(cbuf&+(kk*3)+2)
      regTemp% = (red%*16)+(gre%)+(blu%/16)
      POKEW(ctab&+(2*kk)),regTemp%
   NEXT


ELSEIF tt$ = "CAMG" THEN  'Amiga ViewPort Modes
   foundCAMG = 1
   rLen& = xRead&(fHandle&,inbuf&,icLen&)
   camgModes& = PEEKL(inbuf&)


ELSEIF tt$ = "CCRT" THEN 'Graphicraft color cycle info
   foundCCRT = 1
   rLen& = xRead&(fHandle&,inbuf&,icLen&)
   ccrtDir%    = PEEKW(inbuf&)
   ccrtStart%  = PEEK(inbuf& + 2)
   ccrtEnd%    = PEEK(inbuf& + 3)
   ccrtSecs&   = PEEKL(inbuf& + 4)
   ccrtMics&   = PEEKL(inbuf& + 8)


ELSEIF tt$ = "BODY" THEN  'BitMap 
   foundBODY = 1
  
   IF iCompr% = 0 THEN  'no compression
      FOR rr = 0 TO iHeight% -1
         FOR pp = 0 TO iDepth% -1
            scrRow& = bPlane&(pp)+(rr*scrRowBytes%)
            rLen& = xRead&(fHandle&,scrRow&,iRowBytes%)   
         NEXT
      NEXT


   ELSEIF iCompr% = 1 THEN  'cmpByteRun1
      FOR rr = 0 TO iHeight% -1
         FOR pp = 0 TO iDepth% -1
            scrRow& = bPlane&(pp)+(rr*scrRowBytes%)
            bCnt% = 0
            
            WHILE (bCnt% < iRowBytes%)
               rLen& = xRead&(fHandle&,inbuf&,1)
               inCode% = PEEK(inbuf&)
               IF inCode% < 128 THEN
                  rLen& = xRead&(fHandle&,scrRow& + bCnt%, inCode%+1)
                  bCnt% = bCnt% + inCode% + 1
               ELSEIF inCode% > 128 THEN
                  rLen& = xRead&(fHandle&,inbuf&,1)   
                  inByte% = PEEK(inbuf&)
                  FOR kk = bCnt% TO bCnt% + 257 - inCode%
                     POKE(scrRow&+kk),inByte%
                  NEXT   
                  bCnt% = bCnt% + 257 - inCode%
               END IF
            WEND
         NEXT
      NEXT
         
   ELSE
      loadError$ = "Unknown compression algorithm"
      GOTO Lcleanup
   END IF


ELSE 
   REM - Reading unknown chunk  
   FOR kk = 1 TO icLen&
      rLen& = xRead&(fHandle&,inbuf&,1)
   NEXT
   REM - If odd length, read 1 more byte
   IF (icLen& OR 1) = icLen& THEN 
      rLen& = xRead&(fHandle&,inbuf&,1)
   END IF
      
END IF


REM - Done if got all chunks 
IF foundBMHD AND foundCMAP AND foundBODY THEN
   GOTO GoodLoad
END IF

REM - Good read, get next chunk
IF rLen& > 0 THEN GOTO ChunkLoop

IF rLen& < 0 THEN  'Read error
   loadError$ = "Read error"
   GOTO Lcleanup
END IF   

REM - rLen& = 0 means EOF
IF (foundBMHD=0) OR (foundBODY=0) OR (foundCMAP=0) THEN
   loadError$ = "Needed ILBM chunks not found"
   GOTO Lcleanup
END IF


GoodLoad:
loadError$ = ""

REM  Load proper Colors
IF foundCMAP THEN 
   CALL LoadRGB4&(sViewPort&,ctab&,nColors%)
END IF

Lcleanup:
IF fHandle& <> 0 THEN CALL xClose&(fHandle&)
IF mybuf& <> 0 THEN CALL FreeMem&(mybuf&,mybufsize&)

RETURN



SaveACBM:
REM - Saves current window's screen
REM - Requires the following variables
REM - to have been initialized:
REM -    ACBMname$ (ACBM filespec)
REM - Also, if cycling info is to be stored
REM -    ccrtDir% (1,-1, or 0 = none)
REM -    ccrtStart% (low cycle reg)
REM -    ccrtEnd%   (high cycle reg)
REM -    ccrtSecs&  (cycle time in seconds)
REM -    ccrtMics&  (cycle time in microseconds)
REM 
REM
REM - Format of ACBM file:
REM -    LONG   "FORM"
REM -    LONG   size of rest of file
REM -    LONG   "ACBM" (form type)
REM 
REM -    LONG   "BMHD" (std IFF BitMap header chunk)
REM -    LONG   size of BMHD chunk = 20
REM -    UWORD  w (bitmap width in pixels)
REM -    UWORD  h (bitmap height)
REM -    WORD   x (nw corner) = 0
REM -    WORD   y (nw corner) = 0
REM -    UBYTE  nPlanes
REM -    UBYTE  masking = 0
REM -    UBYTE  compression = 0
REM -    UBYTE  pad1 = 0
REM -    UWORD  transparentColor = 0
REM -    UBYTE  xAspect (pixel) = 10
REM -    UBYTE  yAspect (pixel) = 11
REM -    WORD   pageWidth (screen width in pixels)    
REM -    WORD   pageHeight (screen height in pixels)
REM 
REM -    LONG   "CMAP" (std IFF ColorMap chunk)
REM -    LONG   size of CMAP chunk
REM -    UBYTE  Sets of 3 UBYTES (red, green, blue)
REM -           (2^nPlanes sets)
REM -           (rgb values LEFT justified in each UBYTE)
REM
REM -    LONG   "CAMG" (Amiga ViewPort Modes)
REM -    LONG   size of CAMG chunk
REM -    LONG   Mode
REM
REM -    LONG   "CCRT"  (Graphicraft color cycle info)
REM -    WORD   direction (1,-1, or 0 = none)
REM -    UBYTE  start  (low cycle reg)
REM -    UBYTE  end    (high cycle reg)
REM -    LONG   seconds (cycle time)
REM -    LONG   microseconds (cycle time)
REM -    WORD   pad = 0
REM
REM      (Amiga bitplanes 0, 1, etc)
REM -    LONG   "ABIT"
REM -    LONG   size of ABIT chunk
REM -           BitPlanes 0 thru nPlanes - 1
REM -          (each is h * (w/8) bytes)


REM - init variables
f$ = ACBMname$
fHandle& = 0
mybuf& = 0

filename$ = f$ + CHR$(0)
fHandle& = xOpen&(SADD(filename$),1006)
IF fHandle& = 0 THEN
   saveError$ = "Can't open output file"
   GOTO Scleanup
END IF

REM - Alloc ram for work buffers
ClearPublic& = 65537&
mybufsize& = 120
mybuf& = AllocMem&(mybufsize&,ClearPublic&)
IF mybuf& = 0 THEN
   saveError$ = "Can't alloc buffer"
   GOTO Scleanup
END IF

cbuf& = mybuf&

REM - Get addresses of screen structures
GOSUB GetScrAddrs

zero& = 0
pad%  = 0
aspect% = &HA0B

REM - Compute chunk sizes
BMHDsize& = 20
CMAPsize& = (2^scrDepth%) * 3
CAMGsize& = 4
CCRTsize& = 14
ABITsize& = (scrWidth%/8) * scrHeight% * scrDepth%
REM - FORMsize& = Chunk sizes + 8 bytes per Chunk header + "ACBM"
FORMsize& = BMHDsize&+CMAPsize&+CAMGsize&+CCRTsize&+ABITsize&+44

REM - Write FORM header
tt$ = "FORM"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(FORMsize&),4)
tt$ = "ACBM"
wLen& = xWrite&(fHandle&,SADD(tt$),4)

IF wLen& <= 0 THEN
   saveError$ = "Error writing FORM header"
   GOTO Scleanup
END IF   

REM - Write out BMHD chunk
tt$ = "BMHD"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(BMHDsize&),4)
wLen& = xWrite&(fHandle&,VARPTR(scrWidth%),2)
wLen& = xWrite&(fHandle&,VARPTR(scrHeight%),2)
wLen& = xWrite&(fHandle&,VARPTR(zero&),4)
temp% = (256 * scrDepth%)
wLen& = xWrite&(fHandle&,VARPTR(temp%),2)
wLen& = xWrite&(fHandle&,VARPTR(zero&),4)
wLen& = xWrite&(fHandle&,VARPTR(aspect%),2)
wLen& = xWrite&(fHandle&,VARPTR(scrWidth%),2)
wLen& = xWrite&(fHandle&,VARPTR(scrHeight%),2)

IF wLen& <= 0 THEN
   saveError$ = "Error writing BMHD"
   GOTO Scleanup
END IF   

REM - Write CMAP chunk
tt$ = "CMAP"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(CMAPsize&),4)

REM - Build IFF ColorMap
FOR kk = 0 TO nColors% - 1
   regTemp% = PEEKW(colorTab& + (2*kk))
   POKE(cbuf&+(kk*3)),(regTemp% AND &HF00) / 16
   POKE(cbuf&+(kk*3)+1),(regTemp% AND &HF0) 
   POKE(cbuf&+(kk*3)+2),(regTemp% AND &HF) * 16
NEXT

wLen& = xWrite&(fHandle&,cbuf&,CMAPsize&)

IF wLen& <= 0 THEN
   saveError$ = "Error writing CMAP"
   GOTO Scleanup
END IF   

REM - Write CAMG chunk
tt$ = "CAMG"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(CAMGsize&),4)
vpModes& = PEEKW(sViewPort& + 32)
wLen& = xWrite&(fHandle&,VARPTR(vpModes&),4)

IF wLen& <= 0 THEN
   saveError$ = "Error writing CAMG"
   GOTO Scleanup
END IF   

REM - Write CCRT chunk
tt$ = "CCRT"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(CCRTsize&),4)
wLen& = xWrite&(fHandle&,VARPTR(ccrtDir%),2)
temp% = (256*ccrtStart%) + ccrtEnd%
wLen& = xWrite&(fHandle&,VARPTR(temp%),2)
wLen& = xWrite&(fHandle&,VARPTR(ccrtSecs&),4)
wLen& = xWrite&(fHandle&,VARPTR(ccrtMics&),4)
wLen& = xWrite&(fHandle&,VARPTR(pad%),2)

IF wLen& <= 0 THEN
   saveError$ = "Error writing CCRT"
   GOTO Scleanup
END IF   



REM - Write ABIT chunk, bitplanes
tt$ = "ABIT"
wLen& = xWrite&(fHandle&,SADD(tt$),4)
wLen& = xWrite&(fHandle&,VARPTR(ABITsize&),4)

bpLen& = (scrWidth% / 8) * scrHeight%
FOR pp = 0 TO scrDepth% -1
   wLen& = xWrite&(fHandle&,bPlane&(pp),bpLen&)
   IF wLen& <= 0 THEN
      saveError$ = "Error writing bit plane"+STR$(pp)
      GOTO Scleanup
   END IF   
NEXT   

GoodSave:   
saveError$ = ""

Scleanup:
IF fHandle& <> 0 THEN CALL xClose&(fHandle&)
IF mybuf& <> 0 THEN CALL FreeMem&(mybuf&,mybufsize&)
RETURN


GetScrAddrs:
REM - Get addresses of screen structures
   sWindow&   = WINDOW(7)
   sScreen&   = PEEKL(sWindow& + 46)
   sViewPort& = sScreen& + 44
   sRastPort& = sScreen& + 84
   sColorMap& = PEEKL(sViewPort& + 4)
   colorTab&  = PEEKL(sColorMap& + 4)
   sBitMap&   = PEEKL(sRastPort& + 4)

   REM - Get screen parameters
   scrWidth%  = PEEKW(sScreen& + 12)
   scrHeight% = PEEKW(sScreen& + 14)
   scrDepth%  = PEEK(sBitMap& + 5)
   nColors%   = 2^scrDepth%

   REM - Get addresses of Bit Planes 
   FOR kk = 0 TO scrDepth% - 1
      bPlane&(kk) = PEEKL(sBitMap&+8+(kk*4))
   NEXT
RETURN