home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / dev / gui / LayerHook.lha / ImageBackFill.c next >
Encoding:
C/C++ Source or Header  |  1995-03-19  |  10.4 KB  |  273 lines

  1. /*
  2. ** $VER: ImageBackFill.c 1.231 (19.3.95)
  3. **
  4. ** Tests backfill hooks in screens
  5. **
  6. ** Make>> smake
  7. **
  8. ** (W) 1992-95 by Pierre Carrette & Walter Dörwald
  9. */
  10.  
  11. #include "ImageBackFill.h"
  12.  
  13. struct BackFillMsg
  14. {
  15.     struct Layer    *Layer;
  16.     struct Rectangle Bounds;
  17.     LONG             OffsetX;
  18.     LONG             OffsetY;
  19. };
  20.  
  21. // this seems to be a bug (or feature) in SAS/C: -6%5 gives -1 instead of 4
  22. #define MOD(x,y) ((x)<0 ? (y)-((-(x))%(y)) : (x)%(y))
  23.  
  24. #define RECTSIZEX(r) ((r)->MaxX-(r)->MinX+1)
  25. #define RECTSIZEY(r) ((r)->MaxY-(r)->MinY+1)
  26.  
  27. /****** CopyTiledBitMap ****************************************************************************
  28. *
  29. *   NAME
  30. *    CopyTiledBitMap() -- fill bitmap with bitmap pattern
  31. *
  32. *   SYNOPSIS
  33. *    CopyTiledBitMap(Src,SrcOffsetX,SrcOffsetY,SrcSizeX,SrcSizeY,Dst,DstBounds)
  34.  
  35. *    void CopyTiledBitMap(struct BitMap *,WORD,WORD,WORD,WORD,struct BitMap *,struct Rectangle *)
  36. *
  37. *   FUNCTION
  38. *    fills the destination bitmap with repeated (tiled) copies of the source bitmap
  39. *
  40. *   INPUTS
  41. *    Src = source bitmap.
  42. *    SrcOffsetX = offset (in x direction) to use in the blit.
  43. *    SrcOffsetY = offset (in y direction) to use in the blit.
  44. *                 The pixel at position (SrcOffsetX,SrcOffsetY) in the source bitmap
  45. *                 will be the first visible one in the upper left corner of DstBounds.
  46. *    SrcSizeX = width of the source bitmap Src.
  47. *    SrcSizeY = height of the source bitmap Src.
  48. *    Dst = destination bitmap.
  49. *    DstBounds = this rectangle in the destination bitmap will be filled.
  50. *
  51. *   RESULT
  52. *    None.
  53. *
  54. *   EXAMPLE
  55. *    This function is most useful in backfill hooks.
  56. *
  57. *   NOTES
  58. *    The following relations must hold:
  59. *        0 <= SrcOffsetX < SrcSizeX
  60. *        0 <= SrcOffsetY < SrcSizeY
  61. *    I.e. if calculating the offset involves some kind of modulo-operations
  62. *    they have to be done before calling this function
  63. *
  64. *   BUGS
  65. *
  66. *   AUTHOR
  67. *    Copyright © 1995 by Walter Dörwald
  68. *
  69. *   SEE ALSO
  70. *
  71. ****************************************************************************************************
  72. *
  73. *    This function uses an "exponential" blit to fill the dest rect.
  74. *    Suppose we have a 64×64 source bitmap and want to use offset 0,0
  75. *    (i.e. the upper left corner of the source bitmap is copied to the
  76. *    upper left corner of the dest rect. Let the dest rect be 320×320
  77. *    with upper left corner (0,0). Thus we'll blit 5×5 copies of the
  78. *    source bitmap to the destination.
  79. *    Doing this with two nested loops would thus require 25 blits, or
  80. *    x·y blits for x horizontal tiles and y vertical tiles.
  81. *    First one copy of the source bitmap is blitted to the upper left
  82. *    corner of the dest rect:
  83. *
  84. *        #....
  85. *        .....
  86. *        .....
  87. *        .....
  88. *        .....
  89. *
  90. *    This copy is then blitted to the right:
  91. *
  92. *        ##...
  93. *        .....
  94. *        .....
  95. *        .....
  96. *        .....
  97. *
  98. *    *Both* copies are once again blitted to the right
  99. *
  100. *        ####.
  101. *        .....
  102. *        .....
  103. *        .....
  104. *        .....
  105. *
  106. *    Finally the first row is filled with one blit:
  107. *
  108. *        #####
  109. *        .....
  110. *        .....
  111. *        .....
  112. *        .....
  113. *
  114. *    Now the same is done vertically to fill the complete rect:
  115. *
  116. *        #####   #####   #####
  117. *        #####   #####   #####
  118. *        .....   #####   #####
  119. *        .....   #####   #####
  120. *        .....   .....   #####
  121. *
  122. *    This requires 7 blit, or generally 1+ceil(log_2(x))+ceil(log_2(y))
  123. *
  124. *    The blits are done first in x direction and then in y direction
  125. *    to minimize potential masking effects at the left and right border.
  126. *
  127. *    If the offsets into the source bitmap are not 0, part of a second tile
  128. *    is blitted to the destination bitmap to once again get a tile of the
  129. *    required size.
  130. */
  131.  
  132. void CopyTiledBitMap(struct BitMap *Src,WORD SrcOffsetX,WORD SrcOffsetY,WORD SrcSizeX,WORD SrcSizeY,struct BitMap *Dst,struct Rectangle *DstBounds)
  133. {
  134.     WORD FirstSizeX;  // the width of the rectangle to blit as the first column
  135.     WORD FirstSizeY;  // the height of the rectangle to blit as the first row
  136.     WORD SecondMinX;  // the left edge of the second column
  137.     WORD SecondMinY;  // the top edge of the second column
  138.     WORD SecondSizeX; // the width of the second column
  139.     WORD SecondSizeY; // the height of the second column
  140.     WORD Pos;         // used as starting position in the "exponential" blit
  141.     WORD Size;        // used as bitmap size in the "exponential" blit
  142.  
  143.     FirstSizeX = MIN(SrcSizeX-SrcOffsetX,RECTSIZEX(DstBounds)); // the width of the first tile, this is either the rest of the tile right to SrcOffsetX or the width of the dest rect, if the rect is narrow
  144.     SecondMinX = DstBounds->MinX+FirstSizeX; // the start for the second tile (if used)
  145.     SecondSizeX = MIN(SrcOffsetX,DstBounds->MaxX-SecondMinX+1); // the width of the second tile (we want the whole tile to be SrcSizeX pixels wide, if we use SrcSizeX-SrcOffsetX pixels for the left part we'll use SrcOffsetX for the right part)
  146.  
  147.     FirstSizeY = MIN(SrcSizeY-SrcOffsetY,RECTSIZEY(DstBounds)); // the same values are calculated for y direction
  148.     SecondMinY = DstBounds->MinY+FirstSizeY;
  149.     SecondSizeY = MIN(SrcOffsetY,DstBounds->MaxY-SecondMinY+1);
  150.  
  151.     BltBitMap(Src,SrcOffsetX,SrcOffsetY,Dst,DstBounds->MinX,DstBounds->MinY,FirstSizeX,FirstSizeY,0xC0,-1,NULL); // blit the first piece of the tile
  152.     if (SecondSizeX>0) // if SrcOffset was 0 or the dest rect was to narrow, we won't need a second column
  153.         BltBitMap(Src,0,SrcOffsetY,Dst,SecondMinX,DstBounds->MinY,SecondSizeX,FirstSizeY,0xC0,-1,NULL);
  154.     if (SecondSizeY>0) // is a second row necessary?
  155.     {
  156.         BltBitMap(Src,SrcOffsetX,0,Dst,DstBounds->MinX,SecondMinY,FirstSizeX,SecondSizeY,0xC0,-1,NULL);
  157.         if (SecondSizeX>0)
  158.             BltBitMap(Src,0,0,Dst,SecondMinX,SecondMinY,SecondSizeX,SecondSizeY,0xC0,-1,NULL);
  159.     }
  160.  
  161.     // this loop generates the first row of the tiles
  162.     for (Pos = DstBounds->MinX+SrcSizeX,Size = MIN(SrcSizeX,DstBounds->MaxX-Pos+1);Pos<=DstBounds->MaxX;)
  163.     {
  164.         BltBitMap(Dst,DstBounds->MinX,DstBounds->MinY,Dst,Pos,DstBounds->MinY,Size,MIN(SrcSizeY,RECTSIZEY(DstBounds)),0xC0,-1,NULL);
  165.         Pos += Size;
  166.         Size = MIN(Size<<1,DstBounds->MaxX-Pos+1);
  167.     }
  168.  
  169.     // this loop blit the first row down several times to fill the whole dest rect
  170.     for (Pos = DstBounds->MinY+SrcSizeY,Size = MIN(SrcSizeY,DstBounds->MaxY-Pos+1);Pos<=DstBounds->MaxY;)
  171.     {
  172.         BltBitMap(Dst,DstBounds->MinX,DstBounds->MinY,Dst,DstBounds->MinX,Pos,RECTSIZEX(DstBounds),Size,0xC0,-1,NULL);
  173.         Pos += Size;
  174.         Size = MIN(Size<<1,DstBounds->MaxY-Pos+1);
  175.     }
  176. }
  177.  
  178. // This function must be compiled without stack checking
  179. static void __saveds __asm WindowPatternBackFillFunc(register __a0 struct Hook *Hook,register __a2 struct RastPort *RP,register __a1 struct BackFillMsg *BFM)
  180. {
  181.     WORD OffsetX; // the offset within the tile in x direction
  182.     WORD OffsetY; // the offset within the tile in y direction
  183.  
  184.     struct BackFillInfo *BFI = (struct BackFillInfo *)Hook; // get the data for our backfillhook (but __saveds is nonetheless required because this function needs GfxBase)
  185.  
  186.     struct RastPort cRP;
  187.  
  188.     cRP = *RP;        // copy the rastport
  189.     cRP.Layer = NULL; // eliminate bogus clipping from our copy
  190.  
  191.     OffsetX = BFM->Bounds.MinX-BFI->Options.OffsetX; // The first tile normally isn't totally visible => calculate the offset (offset 0 would mean that the left edge of the damage rectangle coincides with the left edge of a tile)
  192.     if (BFI->Options.CenterX) // horizontal centering?
  193.         OffsetX -= (BFI->Screen->Width-BFI->BitMapHeader->bmh_Width)/2;
  194.  
  195.     OffsetY = BFM->Bounds.MinY-BFI->Options.OffsetY; // The same values are calculated for y direction
  196.     if (BFI->Options.OffsetTitleY) // shift the tiles down?
  197.         OffsetY -= BFI->Screen->BarHeight+1;
  198.     if (BFI->Options.CenterY) // horizontal centering?
  199.         OffsetY -= (BFI->Screen->Height-BFI->BitMapHeader->bmh_Height)/2;
  200.  
  201.     CopyTiledBitMap(BFI->BitMap,MOD(OffsetX,BFI->BitMapHeader->bmh_Width),MOD(OffsetY,BFI->BitMapHeader->bmh_Height),BFI->CopyWidth,BFI->CopyHeight,cRP.BitMap,&BFM->Bounds);
  202. }
  203.  
  204. // this function calculates the sizes to be used for the copy of the bitmap
  205. static void CalculateCopySizes(struct BackFillInfo *BFI)
  206. {
  207.     BFI->CopyWidth = (BFI->BitMapHeader->bmh_Width>BFI->Options.MaxCopyWidth) ? BFI->BitMapHeader->bmh_Width : BFI->Options.MaxCopyWidth-BFI->Options.MaxCopyWidth%BFI->BitMapHeader->bmh_Width;
  208.     BFI->CopyHeight = (BFI->BitMapHeader->bmh_Height>BFI->Options.MaxCopyHeight) ? BFI->BitMapHeader->bmh_Height : BFI->Options.MaxCopyHeight-BFI->Options.MaxCopyHeight%BFI->BitMapHeader->bmh_Height;
  209. }
  210.  
  211. BOOL LoadBackgroundImage(struct BackFillInfo *BFI,STRPTR PicName,struct Screen *Scr,struct BackFillOptions *BFO)
  212. {
  213.     if (DataTypesBase) // safety check, if not used with V39++
  214.     {
  215.         memset(BFI,0,sizeof(*BFI));
  216.         BFI->Hook.h_Entry = (ULONG (*)())WindowPatternBackFillFunc;
  217.         BFI->Screen = Scr;
  218.         BFI->Options = *BFO;
  219.  
  220.         if (BFI->PictureObject = NewDTObject(PicName,
  221.                                              DTA_SourceType       ,DTST_FILE,
  222.                                              DTA_GroupID          ,GID_PICTURE,
  223.                                              PDTA_Remap           ,TRUE,
  224.                                              PDTA_Screen          ,Scr,
  225.                                              PDTA_FreeSourceBitMap,TRUE,
  226.                                              OBP_Precision        ,PRECISION_IMAGE,
  227.                                              TAG_DONE))
  228.         {
  229.             if (DoMethod(BFI->PictureObject,DTM_PROCLAYOUT,NULL,1))
  230.             {
  231.                 struct BitMap *BitMap;
  232.  
  233.                 GetDTAttrs(BFI->PictureObject,PDTA_BitMapHeader,&BFI->BitMapHeader,TAG_DONE);
  234.  
  235.                 GetDTAttrs(BFI->PictureObject,PDTA_DestBitMap,&BitMap,TAG_DONE);
  236.                 if (!BitMap)
  237.                     GetDTAttrs(BFI->PictureObject,PDTA_BitMap,&BitMap,TAG_DONE);
  238.                 if (BitMap)
  239.                 {
  240.                     LONG Depth = GetBitMapAttr(BitMap,BMA_DEPTH);
  241.  
  242.                     CalculateCopySizes(BFI);
  243.  
  244.                     // the bitmap is copied to a friend bitmap of the screen to speed up rendering with gfxboards (no c2p/p2c!); this additionally allows to use this copy as a "picture cache", i.e. if the picture is 2x2 the copy can be made 16x16 (with 64 tiles) or whatever to speed up rendering
  245.                     if (BFI->BitMap = AllocBitMap(BFI->CopyWidth,BFI->CopyHeight,Depth,Depth==8 ? BMF_MINPLANES : 0L,Scr->RastPort.BitMap))
  246.                     {
  247.                         struct Rectangle CopyBounds;
  248.                         CopyBounds.MinX = 0;
  249.                         CopyBounds.MinY = 0;
  250.                         CopyBounds.MaxX = BFI->CopyWidth-1;
  251.                         CopyBounds.MaxY = BFI->CopyHeight-1;
  252.  
  253.                         CopyTiledBitMap(BitMap,0,0,BFI->BitMapHeader->bmh_Width,BFI->BitMapHeader->bmh_Height,BFI->BitMap,&CopyBounds); // blit the tiles to the bitmap
  254.  
  255.                         return (TRUE);
  256.                     }
  257.                 }
  258.             }
  259.         }
  260.         memset(BFI,0,sizeof(*BFI));
  261.     }
  262.     return (FALSE);
  263. }
  264.  
  265. void UnloadBackgroundImage(struct BackFillInfo *BFI)
  266. {
  267.     WaitBlit();
  268.     // both frees work with NULL
  269.     FreeBitMap(BFI->BitMap);
  270.     DisposeDTObject(BFI->PictureObject); // datatype object is freed here, because - although a different bitmap is used for blitting to the screen - the pens have to stay allocated
  271.     memset(BFI,0,sizeof(*BFI));
  272. }
  273.