home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d8xx / d832 / term.lha / Term / term-3.1-Source.lha / termSaveWindow.c < prev    next >
C/C++ Source or Header  |  1993-01-24  |  14KB  |  677 lines

  1. /*
  2. **    termSaveWindow.c
  3. **
  4. **    Support routines for saving IFF-ILBM files
  5. **
  6. **    Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Current compression mode. */
  13.  
  14. #define DUMP        0
  15. #define RUN        1
  16.  
  17.     /* ByteRun compression data. */
  18.  
  19. #define MINRUN        3
  20. #define MAXRUN        128
  21. #define MAXDAT        128
  22.  
  23.     /* Chunk types. */
  24.  
  25. #define ID_ILBM        MAKE_ID('I','L','B','M')
  26. #define ID_ANNO        MAKE_ID('A','N','N','O')
  27. #define ID_BMHD        MAKE_ID('B','M','H','D')
  28. #define ID_CMAP        MAKE_ID('C','M','A','P')
  29. #define ID_CAMG        MAKE_ID('C','A','M','G')
  30. #define ID_BODY        MAKE_ID('B','O','D','Y')
  31.  
  32.     /* Masking technique. */
  33.  
  34. #define mskNone        0
  35.  
  36.     /* Compression techniques. */
  37.  
  38. #define cmpNone        0
  39. #define cmpByteRun1    1
  40.  
  41.     /* A bitmap header. */
  42.  
  43. typedef struct
  44. {
  45.     UWORD        w,h;            /* raster width & height in pixels */
  46.     WORD        x,y;            /* position for this image */
  47.     UBYTE        nPlanes;        /* # source bitplanes */
  48.     UBYTE        masking;        /* masking technique */
  49.     UBYTE        compression;        /* compression algorithm */
  50.     UBYTE        pad1;            /* UNUSED.  For consistency, put 0 here.*/
  51.     UWORD        transparentColor;    /* transparent "color number" */
  52.     UBYTE        xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  53.     WORD        pageWidth,pageHeight;    /* source "page" size in pixels */
  54. } BitMapHeader;
  55.  
  56.     /* A single 8-bit colour register. */
  57.  
  58. typedef struct
  59. {
  60.     UBYTE        red,            /* red component, 0..255 */
  61.             green,            /* green component, 0..255 */
  62.             blue;            /* blue component, 0..255 */
  63. } ColorRegister;
  64.  
  65.     /* Local packer data. */
  66.  
  67. STATIC LONG        PackedBytes;
  68. STATIC BYTE        Buffer[MAXDAT + 1];
  69.  
  70.     /* PutDump(register PLANEPTR Destination,register LONG Count):
  71.      *
  72.      *    Output a byte dump.
  73.      */
  74.  
  75. STATIC PLANEPTR __regargs
  76. PutDump(register PLANEPTR Destination,register LONG Count)
  77. {
  78.     register PLANEPTR Source = Buffer;
  79.  
  80.     *Destination++     = Count - 1;
  81.      PackedBytes    += Count + 1;
  82.  
  83.     while(Count--)
  84.         *Destination++ = *Source++;
  85.  
  86.     return(Destination);
  87. }
  88.  
  89.     /* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
  90.      *
  91.      *    Output a byte run.
  92.      */
  93.  
  94. STATIC PLANEPTR __regargs
  95. PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
  96. {
  97.     *Destination++     = -(Count - 1);
  98.     *Destination++     = Char;
  99.      PackedBytes    += 2;
  100.  
  101.     return(Destination);
  102. }
  103.  
  104.     /* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
  105.      *
  106.      *    Pack a row of bitmap data using ByteRun compression,
  107.      *    based on the original "EA IFF 85" pack.c example code.
  108.      */
  109.  
  110. STATIC LONG __regargs
  111. PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
  112. {
  113.     register PLANEPTR Source = *SourcePtr;
  114.  
  115.     WORD    Buffered    = 1,
  116.         RunStart    = 0;
  117.     BYTE    Mode        = DUMP,
  118.         LastChar,
  119.         Char;
  120.  
  121.     PackedBytes = 0;
  122.  
  123.     Buffer[0] = LastChar = Char = *Source++;
  124.  
  125.     RowSize--;
  126.  
  127.     while(RowSize--)
  128.     {
  129.         Buffer[Buffered++] = Char = *Source++;
  130.  
  131.         if(Mode)
  132.         {
  133.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  134.             {
  135.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  136.                 Buffer[0]    = Char;
  137.                 Buffered    = 1;
  138.                 RunStart    = 0;
  139.                 Mode        = DUMP;
  140.             }
  141.         }
  142.         else
  143.         {
  144.             if(Buffered > MAXDAT)
  145.             {
  146.                 Destination    = PutDump(Destination,Buffered - 1);
  147.                 Buffer[0]    = Char;
  148.                 Buffered    = 1;
  149.                 RunStart    = 0;
  150.             }
  151.             else
  152.             {
  153.                 if(Char == LastChar)
  154.                 {
  155.                     if(Buffered - RunStart >= MINRUN)
  156.                     {
  157.                         if(RunStart)
  158.                             Destination = PutDump(Destination,RunStart);
  159.  
  160.                         Mode = RUN;
  161.                     }
  162.                     else
  163.                     {
  164.                         if(!RunStart)
  165.                             Mode = RUN;
  166.                     }
  167.                 }
  168.                 else
  169.                     RunStart = Buffered - 1;
  170.             }
  171.         }
  172.  
  173.         LastChar = Char;
  174.     }
  175.  
  176.     if(Mode)
  177.         PutRun(Destination,Buffered - RunStart,LastChar);
  178.     else
  179.         PutDump(Destination,Buffered);
  180.  
  181.     *SourcePtr = Source;
  182.  
  183.     return(PackedBytes);
  184. }
  185.  
  186.     /* PutANNO(struct IFFHandle *Handle):
  187.      *
  188.      *    Output `ANNO' chunk.
  189.      */
  190.  
  191. STATIC BYTE __regargs
  192. PutANNO(struct IFFHandle *Handle)
  193. {
  194.     extern    UBYTE    VersTag[];
  195.         WORD    Len;
  196.  
  197.     Len = strlen(&VersTag[1]);
  198.  
  199.         /* Push the `ANNO' chunk on the stack. */
  200.  
  201.     if(!PushChunk(Handle,0,ID_ANNO,Len))
  202.     {
  203.             /* Write the creator string. */
  204.  
  205.         if(WriteChunkBytes(Handle,&VersTag[1],Len) == Len)
  206.         {
  207.                 /* Pop the `ANNO' chunk. */
  208.  
  209.             if(!PopChunk(Handle))
  210.                 return(TRUE);
  211.         }
  212.     }
  213.  
  214.     return(FALSE);
  215. }
  216.  
  217.     /* PutBMHD():
  218.      *
  219.      *    Output `BMHD' chunk.
  220.      */
  221.  
  222. STATIC BYTE __regargs
  223. PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression,LONG Left,LONG Top,LONG Width,LONG Height)
  224. {
  225.     struct DisplayInfo DisplayInfo;
  226.  
  227.         /* Get the display aspect ratio. */
  228.  
  229.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Window -> WScreen -> ViewPort)))
  230.     {
  231.         BitMapHeader Header;
  232.  
  233.             /* Fill in the bitmap header. */
  234.  
  235.         Header . w            = Width;
  236.         Header . h            = Height;
  237.         Header . pageWidth        = Window -> WScreen -> Width;
  238.         Header . pageHeight        = Window -> WScreen -> Height;
  239.         Header . x            = Left;
  240.         Header . y            = Top;
  241.         Header . nPlanes        = Window -> WScreen -> RastPort . BitMap -> Depth;
  242.         Header . masking        = mskNone;
  243.         Header . compression        = Compression;
  244.         Header . pad1            = 0;
  245.         Header . transparentColor    = 0;
  246.         Header . xAspect        = DisplayInfo . Resolution . x;
  247.         Header . yAspect        = DisplayInfo . Resolution . y;
  248.  
  249.             /* Push the `BMHD' chunk on the stack. */
  250.  
  251.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
  252.         {
  253.                 /* Write the bitmap header. */
  254.  
  255.             if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
  256.             {
  257.                     /* Pop the `BMHD' chunk. */
  258.  
  259.                 if(!PopChunk(Handle))
  260.                     return(TRUE);
  261.             }
  262.         }
  263.     }
  264.  
  265.     return(FALSE);
  266. }
  267.  
  268.     /* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
  269.      *
  270.      *    Output `CMAP' chunk, only 4-bit colour registers
  271.      *    are supported so far.
  272.      */
  273.  
  274. STATIC BYTE __regargs
  275. PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
  276. {
  277.         /* Push the `CMAP' chunk on the stack. */
  278.  
  279.     if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
  280.     {
  281.         ColorRegister    Colour;
  282.         LONG        i;
  283.         ULONG        Value,
  284.                 R,G,B;
  285.  
  286.             /* Read and convert all the
  287.              * ColorMap entries (4 bit colour
  288.              * components only).
  289.              */
  290.  
  291.         for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
  292.         {
  293.                 /* Read colour value. */
  294.  
  295.             Value = GetRGB4(VPort -> ColorMap,i);
  296.  
  297.                 /* Split the value into components. */
  298.  
  299.             R = (Value >> 8) & 0xF;
  300.             G = (Value >> 4) & 0xF;
  301.             B = (Value     ) & 0xF;
  302.  
  303.                 /* Store the colour components. */
  304.  
  305.             Colour . red    = (R << 4) | R;
  306.             Colour . green    = (G << 4) | G;
  307.             Colour . blue    = (B << 4) | B;
  308.  
  309.                 /* Write the colours. */
  310.  
  311.             if(WriteChunkBytes(Handle,&Colour,3) != 3)
  312.                 return(FALSE);
  313.         }
  314.  
  315.             /* Pop the `CMAP' chunk. */
  316.  
  317.         if(!PopChunk(Handle))
  318.             return(TRUE);
  319.     }
  320.  
  321.     return(FALSE);
  322. }
  323.  
  324.     /* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
  325.      *
  326.      *    Output `CAMG' chunk.
  327.      */
  328.  
  329. STATIC BYTE __regargs
  330. PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
  331. {
  332.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  333.     {
  334.         ULONG ViewModes = GetVPModeID(VPort);
  335.  
  336.         if(WriteChunkBytes(Handle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
  337.         {
  338.             if(!PopChunk(Handle))
  339.                 return(TRUE);
  340.         }
  341.     }
  342.  
  343.     return(FALSE);
  344. }
  345.  
  346.     /* PutBODY(struct IFFHandle *Handle)
  347.      *
  348.      *    Output `BODY' chunk.
  349.      */
  350.  
  351. STATIC BYTE __regargs
  352. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
  353. {
  354.     BYTE Success = FALSE;
  355.  
  356.     PLANEPTR *Planes;
  357.  
  358.         /* Allocate temporary bitplane pointers. */
  359.  
  360.     if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
  361.     {
  362.         register LONG i;
  363.  
  364.             /* Copy the bitplane pointers. */
  365.  
  366.         for(i = 0 ; i < BitMap -> Depth ; i++)
  367.             Planes[i] = BitMap -> Planes[i];
  368.  
  369.             /* Are we to compress the data? */
  370.  
  371.         if(Compression == cmpByteRun1)
  372.         {
  373.             PLANEPTR PackBuffer;
  374.  
  375.                 /* Allocate line compression buffer. */
  376.  
  377.             if(PackBuffer = (PLANEPTR)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
  378.             {
  379.                     /* Push the `BODY' chunk on the stack. */
  380.  
  381.                 if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  382.                 {
  383.                     register LONG    PackedBytes,
  384.                             j;
  385.  
  386.                         /* So far, we are quite successful,
  387.                          * any write access to fail will
  388.                          * cause `Success' to drop to FALSE.
  389.                          */
  390.  
  391.                     Success = TRUE;
  392.  
  393.                         /* Compress all the rows. */
  394.  
  395.                     for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  396.                     {
  397.                             /* Compress all the planes. */
  398.  
  399.                         for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  400.                         {
  401.                                 /* Do the compression. */
  402.  
  403.                             PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  404.  
  405.                                 /* Write the compressed data. */
  406.  
  407.                             if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
  408.                                 Success = FALSE;
  409.                         }
  410.                     }
  411.  
  412.                         /* Pop the `BODY' chunk. */
  413.  
  414.                     if(PopChunk(Handle))
  415.                         Success = FALSE;
  416.                 }
  417.  
  418.                     /* Free the line compression buffer. */
  419.  
  420.                 FreeVec(PackBuffer);
  421.             }
  422.         }
  423.         else
  424.         {
  425.                 /* Push the `BODY' chunk on the stack. */
  426.  
  427.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  428.             {
  429.                 register LONG j;
  430.  
  431.                     /* So far, we are quite successful,
  432.                      * any write access to fail will
  433.                      * cause `Success' to drop to FALSE.
  434.                      */
  435.  
  436.                 Success = TRUE;
  437.  
  438.                     /* Compress all the rows. */
  439.  
  440.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  441.                 {
  442.                         /* Compress all the planes. */
  443.  
  444.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  445.                     {
  446.                             /* Write the row. */
  447.  
  448.                         if(WriteChunkBytes(Handle,Planes[j],BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
  449.                             Success = FALSE;
  450.                         else
  451.                             Planes[j] += BitMap -> BytesPerRow;
  452.                     }
  453.                 }
  454.  
  455.                     /* Pop the `BODY' chunk. */
  456.  
  457.                 if(PopChunk(Handle))
  458.                     Success = FALSE;
  459.             }
  460.         }
  461.  
  462.             /* Free the temporary bitplane pointers. */
  463.  
  464.         FreeVec(Planes);
  465.     }
  466.  
  467.         /* Return the result. */
  468.  
  469.     return(Success);
  470. }
  471.  
  472.     /* SaveWindow(STRPTR Name,struct Window *Window):
  473.      *
  474.      *    Save the contents of a window to a file.
  475.      */
  476.  
  477. BYTE
  478. SaveWindow(STRPTR Name,struct Window *Window)
  479. {
  480.     struct RastPort        *RPort;
  481.     BYTE             Success    = FALSE,
  482.                  NewFile    = FALSE,
  483.                  Locked        = TRUE;
  484.  
  485.     LockLayerRom(Window -> RPort -> Layer);
  486.  
  487.         /* Allocate a dummy rastport, we will need only
  488.          * to copy the contents of the window into the
  489.          * bitmap.
  490.          */
  491.  
  492.     if(RPort = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  493.     {
  494.         struct BitMap *BitMap;
  495.  
  496.             /* Initialize the rastport with defaults. */
  497.  
  498.         InitRastPort(RPort);
  499.  
  500.             /* Allocate a bitmap. */
  501.  
  502.         if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  503.         {
  504.             LONG    Width    = Window -> Width    - (Window -> BorderLeft + Window -> BorderRight),
  505.                 Height    = Window -> Height    - (Window -> BorderTop + Window -> BorderBottom),
  506.                 Left    = Window -> LeftEdge + Window -> BorderLeft,
  507.                 Top    = Window -> TopEdge + Window -> BorderTop;
  508.             WORD    i;
  509.  
  510.                 /* Put it into the rastport. */
  511.  
  512.             RPort -> BitMap = BitMap;
  513.  
  514.                 /* Initialize it with the window dimensions. */
  515.  
  516.             InitBitMap(BitMap,Window -> WScreen -> RastPort . BitMap -> Depth,Width,Height);
  517.  
  518.                 /* Flag success so any allocation
  519.                  * to fail in the bitplane allocation
  520.                  * loop will indicate failure.
  521.                  */
  522.  
  523.             Success = TRUE;
  524.  
  525.                 /* Allocate all the bitplanes necessary. */
  526.  
  527.             for(i = 0 ; Success && i < BitMap -> Depth ; i++)
  528.             {
  529.                 if(!(BitMap -> Planes[i] = AllocRaster(Width,Height)))
  530.                     Success = FALSE;
  531.             }
  532.  
  533.                 /* Did we get all the planes we wanted? */
  534.  
  535.             if(Success)
  536.             {
  537.                 struct IFFHandle *Handle;
  538.  
  539.                     /* Copy the window contents to the
  540.                      * local bitmap.
  541.                      */
  542.  
  543.                 ClipBlit(Window -> RPort,Window -> BorderLeft,Window -> BorderTop,RPort,0,0,Width,Height,0xC0);
  544.  
  545.                     /* Release the lock on the window layer. */
  546.  
  547.                 UnlockLayerRom(Window -> RPort -> Layer);
  548.  
  549.                 Locked = FALSE;
  550.  
  551.                     /* Reset the success indicator. */
  552.  
  553.                 Success = FALSE;
  554.  
  555.                     /* Allocate an iff handle. */
  556.  
  557.                 if(Handle = AllocIFF())
  558.                 {
  559.                         /* Open a file for write access. */
  560.  
  561.                     if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  562.                     {
  563.                             /* Remember that we succeeded
  564.                              * in creating a new file.
  565.                              */
  566.  
  567.                         NewFile = TRUE;
  568.  
  569.                             /* Tell iffparse.library that it's
  570.                              * a plain AmigaDOS file handle.
  571.                              */
  572.  
  573.                         InitIFFasDOS(Handle);
  574.  
  575.                             /* Open the file for writing. */
  576.  
  577.                         if(!OpenIFF(Handle,IFFF_WRITE))
  578.                         {
  579.                                 /* Push parent chunk on the
  580.                                  * stack.
  581.                                  */
  582.  
  583.                             if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  584.                             {
  585.                                     /* Output all the chunk data. */
  586.  
  587.                                 if(PutANNO(Handle))
  588.                                 {
  589.                                     UBYTE Compression;
  590.  
  591.                                         /* Don't compress the bitmap if
  592.                                          * isn't really worth it.
  593.                                          */
  594.  
  595.                                     if(BitMap -> BytesPerRow > 4)
  596.                                         Compression = cmpByteRun1;
  597.                                     else
  598.                                         Compression = cmpNone;
  599.  
  600.                                     if(PutBMHD(Handle,Window,Compression,Left,Top,Width,Height))
  601.                                     {
  602.                                         if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
  603.                                         {
  604.                                             if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
  605.                                             {
  606.                                                 if(PutBODY(Handle,BitMap,Compression))
  607.                                                 {
  608.                                                         /* Pop the parent chunk
  609.                                                          * from the stack.
  610.                                                          */
  611.  
  612.                                                     if(!PopChunk(Handle))
  613.                                                         Success = TRUE;
  614.                                                 }
  615.                                             }
  616.                                         }
  617.                                     }
  618.                                 }
  619.                             }
  620.  
  621.                                 /* Close the iff handle. */
  622.  
  623.                             CloseIFF(Handle);
  624.                         }
  625.  
  626.                             /* Close the file. */
  627.  
  628.                         if(!Close(Handle -> iff_Stream))
  629.                             Success = FALSE;
  630.                     }
  631.  
  632.                         /* Free the iff handle. */
  633.  
  634.                     FreeIFF(Handle);
  635.                 }
  636.             }
  637.  
  638.                 /* Free all bitplanes. */
  639.  
  640.             for(i = 0 ; i < BitMap -> Depth ; i++)
  641.             {
  642.                 if(BitMap -> Planes[i])
  643.                     FreeRaster(BitMap -> Planes[i],Width,Height);
  644.             }
  645.  
  646.                 /* Free the bitmap. */
  647.  
  648.             FreeVec(BitMap);
  649.         }
  650.  
  651.             /* Free the rastport. */
  652.  
  653.         FreeVec(RPort);
  654.     }
  655.  
  656.         /* Release the window layer in case it is still locked. */
  657.  
  658.     if(Locked)
  659.         UnlockLayerRom(Window -> RPort -> Layer);
  660.  
  661.         /* If successful, clear the `executable' bit. */
  662.  
  663.     if(Success)
  664.         SetProtection(Name,FIBF_EXECUTE);
  665.     else
  666.     {
  667.             /* Delete the remains of the file. */
  668.  
  669.         if(NewFile)
  670.             DeleteFile(Name);
  671.     }
  672.  
  673.         /* Return the result. */
  674.  
  675.     return(Success);
  676. }
  677.