home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / SAT 2.4.0 / SAT 2.4.0 update 2 / FastLoad.p next >
Encoding:
Text File  |  1997-03-22  |  16.2 KB  |  439 lines  |  [TEXT/PJMM]

  1. unit FastLoad;
  2.  
  3. {This unit holds routines for loading faces pointing into parts of offscreen buffers. This is useful for}
  4. {loading large numbers of faces really fast (since it is drawn in one operation, and much fewer Memory}
  5. {Management and Resource Manager operations are needed), but also for odd sprites that "peek" into}
  6. {other parts of offscreens.}
  7.  
  8. {The call Load2DFaceArray is the most interesting one. It loads one PICT resource to a large number}
  9. {of faces (hundreds) in a fraction of a second.}
  10.  
  11. {/Ingemar Ragnemalm december 1995}
  12. {Revised may 1996}
  13. {Revised again august 1996}
  14. {(Revisions above fix some hard-coded values, adds row list support, and fixes bugs.)}
  15. {Revised once more november 1996. Port restored by LoadFaceArray/Load2DFaceArray.}
  16. {Outcommented code removed.}
  17. {Revised again jan 97: Now row lists work properly.}
  18. {Bug fix march 97: The allocation of the "faces" array is now calculated with Longints,}
  19. {which allows a bigger number of faces.}
  20.  
  21. interface
  22.     uses
  23. {$ifc UNDEFINED THINK_PASCAL}
  24.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
  25.         Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
  26.         GestaltEqu, Files, Errors, Devices, 
  27. {$endc}
  28.         SAT;
  29.  
  30.     type
  31.         FaceArr = array[0..1000] of Face;
  32.         FaceArrPtr = ^FaceArr;
  33.  
  34. {PeekFaceInOffscreen: A variation on BuildFaceInOffscreen, intended for special effects. It doesn't}
  35. {allocate the face data, but demands that the face already exists. Use it for making a sprite face}
  36. {peek into some image buffer other than its own private one.}
  37.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect;{}
  38.                                     needsRegion, makeRowList: Boolean);
  39.  
  40. {BuildFaceInOffscreen: This is the heart of FastLoad. It builds a face pointing into some image of}
  41. {your choice.}
  42.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
  43.                                     needsRegion, makeRowList: Boolean);
  44.  
  45. {LoadFaceArray and Load2DFaceArray: High-level functions, for loading faces arrange in arrays}
  46. {in PICTs.}
  47.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  48.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  49.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer;{}
  50.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  51.  
  52. {Note: The two Booleans needsRegion and makeRowList, used in all routines above, tell whether you}
  53. {want certain extra data in the face. Set needsRegion to true if you want to run your program to run}
  54. {as fast as possible WITHOUT blitters, using only QuickDraw. Set makeRowList of you want it to run}
  55. {with optimal speed WITH blitters. If both are false, it will load extremely fast, but the animation may}
  56. {not run quite as fast.}
  57.  
  58. {This routine is in SAT.lib, but not in the interface files! It is for internal use by the unit.}
  59.     procedure SATMakeRowList (portRect: Rect; baseAddr: Ptr; rowBytes: integer; var rows: Ptr; depth: Integer);
  60.  
  61. implementation
  62.  
  63.  
  64.     type
  65.         BMPtr = ^BitMap;
  66.  
  67.         FourBitStuff = record
  68.                 evenData, oddData: Ptr;
  69.                 oddMask: BitMap;
  70.                 oddRowBytes: integer;
  71.                 destRect: Rect; {Behövs för safe}
  72.                 oddRows, oddMaskRows: Ptr;
  73.             end;
  74.         FourBitPtr = ^FourBitStuff;
  75.  
  76.  
  77. {BuildFaceInOffscreen builds a face that points into two offscreen imgaes, one for the image data}
  78. {and one for the mask. This can be used for loading faces quickly, but also for making weirds}
  79. {sprites who peek into other parts of the screen.}
  80. {}
  81. {This will probably NEVER get really good in 4-bit color.}
  82.  
  83.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
  84.         var
  85.             b2: Rect;
  86.     begin
  87.         theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  88.         theFace.iconMask.rowBytes := maskOff.rowBytes;
  89.         theFace.iconMask.bounds := bounds;
  90.         OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  91.         theFace.rowBytes := imageOff.rowBytes;
  92.  
  93.         b2 := bounds;
  94.         OffsetRect(b2, -b2.left, -b2.top);
  95.  
  96.         if gSAT.initDepth = 1 then
  97.             begin
  98.                 theFace.colorData := NewPtrClear(sizeOf(BitMap));
  99.                 if theFace.colorData <> nil then
  100.                     begin
  101.                         BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  102.                         BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
  103.                         BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
  104.                         theFace.rows := nil;
  105.                         if makeRowList then
  106.                             SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  107.                     end;
  108.             end
  109.         else if gSAT.initDepth = 4 then
  110. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  111. {since it is better than crashing.}
  112.             begin
  113.                 theFace.colorData := NewPtrClear(sizeof(FourBitStuff));
  114.  
  115.                 if theFace.colorData <> nil then
  116.                     with FourBitPtr(theFace.colorData)^ do
  117.                         begin
  118. {theFace.rowBytes := imageOff.rowBytes;}
  119.                             evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  120.                             theFace.rows := nil;
  121.                             if makeRowList then
  122.                                 SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
  123.  
  124.                             oddRowBytes := imageOff.rowBytes;
  125.                             oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  126.  
  127.                             destRect := theFace.iconMask.bounds;
  128.                             oddRows := nil;
  129.                             if makeRowList then
  130.                                 SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  131.  
  132.                             BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  133.  
  134.                             oddMaskRows := nil;
  135.                             if makeRowList then
  136.                                 SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  137.                             theFace.maskRows := nil;
  138.                             if makeRowList then
  139.                                 SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  140.                         end;
  141.             end
  142.         else
  143.             begin
  144.                 theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  145.                 theFace.rows := nil;
  146.                 if makeRowList then
  147.                     SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  148.                 theFace.maskRows := nil;
  149.                 if makeRowList then
  150.                     SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  151.             end;
  152.  
  153.         theFace.next := nil;
  154.  
  155. {Build region. This is time consuming, but can be skipped. Without them, drawing without blitters can slow down a bit.}
  156. {Another option is to use one region for several masks, when we know some masks are equal.}
  157.         if needsRegion then
  158.             begin
  159.                 theFace.maskRgn := NewRgn;
  160.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  161.                     ;
  162.             end
  163.         else
  164.             theFace.maskRgn := nil;
  165.  
  166. {Hooks that we don't use here:}
  167.         theFace.redrawProc := nil;
  168.         theFace.drawProc := nil;
  169.     end; {BuildFaceInOffscreen}
  170.  
  171.  
  172. {PeekFaceInOffscreen is very similar to BuildFaceInOffscreen, but doesn't build the face, but just changes its}
  173. {pointers to another place in the offscreens, in order to change where it points. You can then have it pointing}
  174. {anywhere, into other ports, to the screen etc. However, if the memory it points to changes, sprites using}
  175. {the face have to set their "dirty" flag in order to work with SATRun2 unless they move all the time!}
  176.  
  177. {The differences to BuildFaceInOffscreen are that}
  178. {- it doesn't allocate pointers, nor initialize any parts of the face. The face is assumed to be in use already.}
  179. {- the SATPorts are passed as pointers, and may be nil. If one of them is nil, that part of the procedure will}
  180. {not be run. That lets you keep the mask and change the image.}
  181.  
  182. {Note: This hasn't been tested a lot since the last update.}
  183.  
  184.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect; needsRegion, makeRowList: Boolean);
  185.         var
  186.             b2: Rect;
  187.     begin
  188.         if maskOff <> nil then
  189.             begin
  190.                 theFace.iconMask.baseAddr := Ptr(Longint(maskOff^.baseAddr) + Longint(maskOff^.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  191.                 theFace.iconMask.rowBytes := maskOff^.rowBytes;
  192.                 theFace.iconMask.bounds := bounds;
  193.                 OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  194.             end;
  195.  
  196.         if imageOff <> nil then
  197.             begin
  198.                 theFace.rowBytes := imageOff^.rowBytes;
  199.                 b2 := bounds;
  200.                 OffsetRect(b2, -b2.left, -b2.top);
  201.  
  202.                 if gSAT.initDepth = 1 then
  203.                     begin
  204.                         if theFace.colorData <> nil then
  205.                             begin
  206.                                 BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  207.                                 BMPtr(theFace.colorData)^.rowBytes := imageOff^.rowBytes;
  208.                                 BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left div 8);
  209.                                 theFace.rows := nil;
  210.                                 if makeRowList then
  211.                                     SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  212.                             end;
  213.                     end
  214.                 else if gSAT.initDepth = 4 then
  215. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  216. {since it is better than crashing.}
  217.                     begin
  218.                         if theFace.colorData <> nil then
  219.                             with FourBitPtr(theFace.colorData)^ do
  220.                                 begin
  221.                                     theFace.rowBytes := imageOff^.rowBytes;
  222.                                     evenData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  223.                                     theFace.rows := nil;
  224.                                     if makeRowList then
  225.                                         SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
  226.  
  227.                                     oddRowBytes := imageOff^.rowBytes;
  228.                                     oddData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  229.  
  230.                                     destRect := theFace.iconMask.bounds;
  231.                                     oddRows := nil;
  232.                                     if makeRowList then
  233.                                         SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  234.  
  235.                                     BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  236.  
  237.                                     oddMaskRows := nil;
  238.                                     if makeRowList then
  239.                                         SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  240.                                     theFace.maskRows := nil;
  241.                                     if makeRowList then
  242.                                         SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  243.                                 end;
  244.                     end
  245.                 else
  246.                     begin
  247.                         theFace.colorData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  248.                         theFace.rows := nil;
  249.                         if makeRowList then
  250.                             SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  251.                         theFace.maskRows := nil;
  252.                         if makeRowList then
  253.                             SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  254.                     end;
  255.  
  256. {theFace.rowBytes := imageOff^.rowBytes;}
  257.             end;
  258.  
  259. {Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
  260. {giving up the safety backdoor! Another option is to use on region for several masks, when we know}
  261. {some masks are equal.}
  262.         if needsRegion then
  263.             begin
  264.                 if theFace.maskRgn = nil then
  265.                     theFace.maskRgn := NewRgn;
  266.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  267.                     ;
  268.             end
  269.         else
  270.             ;
  271.     end; {PeekFaceInOffscreen}
  272.  
  273.  
  274. {CreateBWOffscreen is useful for creating a B/W offscreeen buffer for masks}
  275.  
  276.     procedure CreateBWOffscreen (var portP: SATPort; frame: Rect);
  277.         var
  278.             savePort: GrafPtr;
  279.     begin
  280.         GetPort(savePort);
  281.  
  282.         portP.device := nil;
  283.         portP.port := GrafPtr(NewPtr(sizeof(GrafPort)));
  284.         CheckNoMem(Ptr(portP.port));                        {Emergency exit}
  285.  
  286.         OpenPort(portP.port);
  287.         portP.port^.portRect := frame;
  288.         portP.port^.portBits.bounds := portP.port^.portRect;
  289.  
  290.         RectRgn(portP.port^.visRgn, frame);
  291.         ClipRect(frame);
  292.  
  293.         portP.port^.portBits.rowBytes := longint(((portP.port^.portRect.right - portP.port^.portRect.left + 31) div 32) * 4);
  294.         portP.port^.portBits.baseAddr := NewPtr(portP.port^.portBits.rowBytes * longint(portP.port^.portRect.bottom - portP.port^.portRect.top));
  295.         CheckNoMem(portP.port^.portBits.baseAddr); {Emergency exit}
  296.  
  297.         SetPort(portP.port);
  298.         EraseRect(portP.port^.portRect);
  299.  
  300.         portP.baseAddr := portP.port^.portBits.baseAddr;
  301.         portP.bounds := portP.port^.portBits.bounds;
  302.         portP.rowBytes := portP.port^.portBits.rowBytes;
  303.  
  304. {portP.rows:=nil;}
  305. {with portP.port^ do}
  306. {SATMakeRowList(portRect, portBits.baseAddr, portBits.rowBytes, portP.rows, 1);}
  307.  
  308.         SetPort(savePort);
  309.     end; {CreateBWOffscreen}
  310.  
  311. {LoadFaceArray loads a set of faces to a one-dimensional array of faces, arranged vertically in a PICT}
  312. {resource. It is extended to 2-dimensional arrays by Load2DFaceArray below. NOT TESTED MUCH!}
  313.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  314.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  315.         var
  316.             fr, mr: Rect;
  317.             savePort, facesOff, masksOff: SATPort;
  318.             i: Integer;
  319.             faces: FaceArrPtr;
  320.             facesPict, masksPict: PicHandle;
  321.             bounds: Rect;
  322.     begin
  323.         SATGetPort(savePort);
  324.  
  325.         LoadFaceArray := nil;
  326.         faces := FaceArrPtr(NewPtr(Longint(SizeOf(Face)) * numFaces));
  327.         if faces = nil then
  328.             Exit(LoadFaceArray);
  329.  
  330.         facesPict := GetPicture(facesPictId);
  331.         if facesPict = nil then
  332.             begin
  333.                 DisposePtr(Ptr(faces));
  334.                 Exit(LoadFaceArray);
  335.             end;
  336.         masksPict := GetPicture(masksPictId);
  337.         if masksPict = nil then
  338.             begin
  339.                 ReleaseResource(Handle(facesPict));
  340.                 DisposePtr(Ptr(faces));
  341.                 Exit(LoadFaceArray);
  342.             end;
  343.  
  344.         fr := facesPict^^.picFrame;
  345.         OffsetRect(fr, -fr.left, -fr.top);
  346.  
  347.         SATMakeOffscreen(facesOff, fr);
  348.         SATSetPort(facesOff);
  349.         DrawPicture(facesPict, fr);
  350.  
  351.         mr := masksPict^^.picFrame;
  352.         OffsetRect(mr, -mr.left, -mr.top);
  353.  
  354.         CreateBWOffscreen(masksOff, mr);
  355.         SATSetPort(masksOff);
  356.         DrawPicture(masksPict, mr);
  357.  
  358.         ReleaseResource(Handle(facesPict));
  359.         ReleaseResource(Handle(masksPict));
  360.  
  361. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures!}
  362.  
  363.         for i := 0 to numFaces - 1 do
  364.             begin
  365.                 SetRect(bounds, 0, i * sizeV, sizeH, (i + 1) * sizeV);
  366.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  367.             end;
  368.  
  369.         LoadFaceArray := faces;
  370.         SATSetPort(savePort);
  371.     end; {LoadFaceArray}
  372.  
  373.  
  374. {Load2DFaceArray loads a set of faces to a two-dimensional array of faces, arranged as a grid in a PICT}
  375. {resource. IMPORTANT! All faces must have a width divisible by 8, or better, 16 or even 32!}
  376.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  377.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  378.         var
  379.             fr, mr: Rect;
  380.             savePort, facesOff, masksOff: SATPort;
  381.             i, h, v: Integer;
  382.             faces: FaceArrPtr;
  383.             facesPict, masksPict: PicHandle;
  384.             bounds: Rect;
  385.     begin
  386.         SATGetPort(savePort);
  387.  
  388.         Load2DFaceArray := nil;
  389.         faces := FaceArrPtr(NewPtr(Longint(SizeOf(Face)) * numFaces));
  390.         if faces = nil then
  391.             Exit(Load2DFaceArray);
  392.  
  393.         facesPict := GetPicture(facesPictId);
  394.         if facesPict = nil then
  395.             begin
  396.                 DisposePtr(Ptr(faces));
  397.                 Exit(Load2DFaceArray);
  398.             end;
  399.         masksPict := GetPicture(masksPictID);
  400.         if masksPict = nil then
  401.             begin
  402.                 ReleaseResource(Handle(facesPict));
  403.                 DisposePtr(Ptr(faces));
  404.                 Exit(Load2DFaceArray);
  405.             end;
  406.  
  407.         fr := facesPict^^.picFrame;
  408.         OffsetRect(fr, -fr.left, -fr.top);
  409.  
  410.         SATMakeOffscreen(facesOff, fr);
  411.         SATSetPort(facesOff);
  412.         DrawPicture(facesPict, fr);
  413.  
  414.         mr := masksPict^^.picFrame;
  415.         OffsetRect(mr, -mr.left, -mr.top);
  416.  
  417.         CreateBWOffscreen(masksOff, mr);
  418.         SATSetPort(masksOff);
  419.         DrawPicture(masksPict, mr);
  420.  
  421.         ReleaseResource(Handle(facesPict));
  422.         ReleaseResource(Handle(masksPict));
  423.  
  424. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures,}
  425. {arranged with facesPerRow faces per row!}
  426.  
  427.         for i := 0 to numFaces - 1 do
  428.             begin
  429.                 h := i mod facesPerRow;    {0..facesPerRow-1}
  430.                 v := i div facesPerRow;        {0 and up}
  431.                 SetRect(bounds, h * sizeH, v * sizeV, (h + 1) * sizeH, (v + 1) * sizeV);
  432.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  433.             end;
  434.  
  435.         Load2DFaceArray := faces;
  436.         SATSetPort(savePort);
  437.     end; {Load2DFaceArray}
  438.  
  439. end.