home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-03-22 | 16.2 KB | 439 lines | [TEXT/PJMM] |
- unit FastLoad;
-
- {This unit holds routines for loading faces pointing into parts of offscreen buffers. This is useful for}
- {loading large numbers of faces really fast (since it is drawn in one operation, and much fewer Memory}
- {Management and Resource Manager operations are needed), but also for odd sprites that "peek" into}
- {other parts of offscreens.}
-
- {The call Load2DFaceArray is the most interesting one. It loads one PICT resource to a large number}
- {of faces (hundreds) in a fraction of a second.}
-
- {/Ingemar Ragnemalm december 1995}
- {Revised may 1996}
- {Revised again august 1996}
- {(Revisions above fix some hard-coded values, adds row list support, and fixes bugs.)}
- {Revised once more november 1996. Port restored by LoadFaceArray/Load2DFaceArray.}
- {Outcommented code removed.}
- {Revised again jan 97: Now row lists work properly.}
- {Bug fix march 97: The allocation of the "faces" array is now calculated with Longints,}
- {which allows a bigger number of faces.}
-
- interface
- uses
- {$ifc UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
- Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
- GestaltEqu, Files, Errors, Devices,
- {$endc}
- SAT;
-
- type
- FaceArr = array[0..1000] of Face;
- FaceArrPtr = ^FaceArr;
-
- {PeekFaceInOffscreen: A variation on BuildFaceInOffscreen, intended for special effects. It doesn't}
- {allocate the face data, but demands that the face already exists. Use it for making a sprite face}
- {peek into some image buffer other than its own private one.}
- procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect;{}
- needsRegion, makeRowList: Boolean);
-
- {BuildFaceInOffscreen: This is the heart of FastLoad. It builds a face pointing into some image of}
- {your choice.}
- procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
- needsRegion, makeRowList: Boolean);
-
- {LoadFaceArray and Load2DFaceArray: High-level functions, for loading faces arrange in arrays}
- {in PICTs.}
- function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
- needsRegion, makeRowList: Boolean): FaceArrPtr;
- function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer;{}
- facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
-
- {Note: The two Booleans needsRegion and makeRowList, used in all routines above, tell whether you}
- {want certain extra data in the face. Set needsRegion to true if you want to run your program to run}
- {as fast as possible WITHOUT blitters, using only QuickDraw. Set makeRowList of you want it to run}
- {with optimal speed WITH blitters. If both are false, it will load extremely fast, but the animation may}
- {not run quite as fast.}
-
- {This routine is in SAT.lib, but not in the interface files! It is for internal use by the unit.}
- procedure SATMakeRowList (portRect: Rect; baseAddr: Ptr; rowBytes: integer; var rows: Ptr; depth: Integer);
-
- implementation
-
-
- type
- BMPtr = ^BitMap;
-
- FourBitStuff = record
- evenData, oddData: Ptr;
- oddMask: BitMap;
- oddRowBytes: integer;
- destRect: Rect; {Behövs för safe}
- oddRows, oddMaskRows: Ptr;
- end;
- FourBitPtr = ^FourBitStuff;
-
-
- {BuildFaceInOffscreen builds a face that points into two offscreen imgaes, one for the image data}
- {and one for the mask. This can be used for loading faces quickly, but also for making weirds}
- {sprites who peek into other parts of the screen.}
- {}
- {This will probably NEVER get really good in 4-bit color.}
-
- procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
- var
- b2: Rect;
- begin
- 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}
- theFace.iconMask.rowBytes := maskOff.rowBytes;
- theFace.iconMask.bounds := bounds;
- OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
- theFace.rowBytes := imageOff.rowBytes;
-
- b2 := bounds;
- OffsetRect(b2, -b2.left, -b2.top);
-
- if gSAT.initDepth = 1 then
- begin
- theFace.colorData := NewPtrClear(sizeOf(BitMap));
- if theFace.colorData <> nil then
- begin
- BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
- BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
- BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
- end;
- end
- else if gSAT.initDepth = 4 then
- {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
- {since it is better than crashing.}
- begin
- theFace.colorData := NewPtrClear(sizeof(FourBitStuff));
-
- if theFace.colorData <> nil then
- with FourBitPtr(theFace.colorData)^ do
- begin
- {theFace.rowBytes := imageOff.rowBytes;}
- evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
-
- oddRowBytes := imageOff.rowBytes;
- oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
-
- destRect := theFace.iconMask.bounds;
- oddRows := nil;
- if makeRowList then
- SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
-
- BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
-
- oddMaskRows := nil;
- if makeRowList then
- SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
- theFace.maskRows := nil;
- if makeRowList then
- SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
- end;
- end
- else
- begin
- theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
- theFace.maskRows := nil;
- if makeRowList then
- SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
- end;
-
- theFace.next := nil;
-
- {Build region. This is time consuming, but can be skipped. Without them, drawing without blitters can slow down a bit.}
- {Another option is to use one region for several masks, when we know some masks are equal.}
- if needsRegion then
- begin
- theFace.maskRgn := NewRgn;
- if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
- ;
- end
- else
- theFace.maskRgn := nil;
-
- {Hooks that we don't use here:}
- theFace.redrawProc := nil;
- theFace.drawProc := nil;
- end; {BuildFaceInOffscreen}
-
-
- {PeekFaceInOffscreen is very similar to BuildFaceInOffscreen, but doesn't build the face, but just changes its}
- {pointers to another place in the offscreens, in order to change where it points. You can then have it pointing}
- {anywhere, into other ports, to the screen etc. However, if the memory it points to changes, sprites using}
- {the face have to set their "dirty" flag in order to work with SATRun2 unless they move all the time!}
-
- {The differences to BuildFaceInOffscreen are that}
- {- it doesn't allocate pointers, nor initialize any parts of the face. The face is assumed to be in use already.}
- {- the SATPorts are passed as pointers, and may be nil. If one of them is nil, that part of the procedure will}
- {not be run. That lets you keep the mask and change the image.}
-
- {Note: This hasn't been tested a lot since the last update.}
-
- procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPortPtr; bounds: Rect; needsRegion, makeRowList: Boolean);
- var
- b2: Rect;
- begin
- if maskOff <> nil then
- begin
- 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}
- theFace.iconMask.rowBytes := maskOff^.rowBytes;
- theFace.iconMask.bounds := bounds;
- OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
- end;
-
- if imageOff <> nil then
- begin
- theFace.rowBytes := imageOff^.rowBytes;
- b2 := bounds;
- OffsetRect(b2, -b2.left, -b2.top);
-
- if gSAT.initDepth = 1 then
- begin
- if theFace.colorData <> nil then
- begin
- BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
- BMPtr(theFace.colorData)^.rowBytes := imageOff^.rowBytes;
- BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
- end;
- end
- else if gSAT.initDepth = 4 then
- {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
- {since it is better than crashing.}
- begin
- if theFace.colorData <> nil then
- with FourBitPtr(theFace.colorData)^ do
- begin
- theFace.rowBytes := imageOff^.rowBytes;
- evenData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, evenData, theFace.rowBytes, theFace.rows, 4);
-
- oddRowBytes := imageOff^.rowBytes;
- oddData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
-
- destRect := theFace.iconMask.bounds;
- oddRows := nil;
- if makeRowList then
- SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
-
- BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
-
- oddMaskRows := nil;
- if makeRowList then
- SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
- theFace.maskRows := nil;
- if makeRowList then
- SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
- end;
- end
- else
- begin
- theFace.colorData := Ptr(Longint(imageOff^.baseAddr) + Longint(imageOff^.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
- theFace.rows := nil;
- if makeRowList then
- SATMakeRowList(b2, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
- theFace.maskRows := nil;
- if makeRowList then
- SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
- end;
-
- {theFace.rowBytes := imageOff^.rowBytes;}
- end;
-
- {Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
- {giving up the safety backdoor! Another option is to use on region for several masks, when we know}
- {some masks are equal.}
- if needsRegion then
- begin
- if theFace.maskRgn = nil then
- theFace.maskRgn := NewRgn;
- if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
- ;
- end
- else
- ;
- end; {PeekFaceInOffscreen}
-
-
- {CreateBWOffscreen is useful for creating a B/W offscreeen buffer for masks}
-
- procedure CreateBWOffscreen (var portP: SATPort; frame: Rect);
- var
- savePort: GrafPtr;
- begin
- GetPort(savePort);
-
- portP.device := nil;
- portP.port := GrafPtr(NewPtr(sizeof(GrafPort)));
- CheckNoMem(Ptr(portP.port)); {Emergency exit}
-
- OpenPort(portP.port);
- portP.port^.portRect := frame;
- portP.port^.portBits.bounds := portP.port^.portRect;
-
- RectRgn(portP.port^.visRgn, frame);
- ClipRect(frame);
-
- portP.port^.portBits.rowBytes := longint(((portP.port^.portRect.right - portP.port^.portRect.left + 31) div 32) * 4);
- portP.port^.portBits.baseAddr := NewPtr(portP.port^.portBits.rowBytes * longint(portP.port^.portRect.bottom - portP.port^.portRect.top));
- CheckNoMem(portP.port^.portBits.baseAddr); {Emergency exit}
-
- SetPort(portP.port);
- EraseRect(portP.port^.portRect);
-
- portP.baseAddr := portP.port^.portBits.baseAddr;
- portP.bounds := portP.port^.portBits.bounds;
- portP.rowBytes := portP.port^.portBits.rowBytes;
-
- {portP.rows:=nil;}
- {with portP.port^ do}
- {SATMakeRowList(portRect, portBits.baseAddr, portBits.rowBytes, portP.rows, 1);}
-
- SetPort(savePort);
- end; {CreateBWOffscreen}
-
- {LoadFaceArray loads a set of faces to a one-dimensional array of faces, arranged vertically in a PICT}
- {resource. It is extended to 2-dimensional arrays by Load2DFaceArray below. NOT TESTED MUCH!}
- function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
- needsRegion, makeRowList: Boolean): FaceArrPtr;
- var
- fr, mr: Rect;
- savePort, facesOff, masksOff: SATPort;
- i: Integer;
- faces: FaceArrPtr;
- facesPict, masksPict: PicHandle;
- bounds: Rect;
- begin
- SATGetPort(savePort);
-
- LoadFaceArray := nil;
- faces := FaceArrPtr(NewPtr(Longint(SizeOf(Face)) * numFaces));
- if faces = nil then
- Exit(LoadFaceArray);
-
- facesPict := GetPicture(facesPictId);
- if facesPict = nil then
- begin
- DisposePtr(Ptr(faces));
- Exit(LoadFaceArray);
- end;
- masksPict := GetPicture(masksPictId);
- if masksPict = nil then
- begin
- ReleaseResource(Handle(facesPict));
- DisposePtr(Ptr(faces));
- Exit(LoadFaceArray);
- end;
-
- fr := facesPict^^.picFrame;
- OffsetRect(fr, -fr.left, -fr.top);
-
- SATMakeOffscreen(facesOff, fr);
- SATSetPort(facesOff);
- DrawPicture(facesPict, fr);
-
- mr := masksPict^^.picFrame;
- OffsetRect(mr, -mr.left, -mr.top);
-
- CreateBWOffscreen(masksOff, mr);
- SATSetPort(masksOff);
- DrawPicture(masksPict, mr);
-
- ReleaseResource(Handle(facesPict));
- ReleaseResource(Handle(masksPict));
-
- {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures!}
-
- for i := 0 to numFaces - 1 do
- begin
- SetRect(bounds, 0, i * sizeV, sizeH, (i + 1) * sizeV);
- BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
- end;
-
- LoadFaceArray := faces;
- SATSetPort(savePort);
- end; {LoadFaceArray}
-
-
- {Load2DFaceArray loads a set of faces to a two-dimensional array of faces, arranged as a grid in a PICT}
- {resource. IMPORTANT! All faces must have a width divisible by 8, or better, 16 or even 32!}
- function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
- facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
- var
- fr, mr: Rect;
- savePort, facesOff, masksOff: SATPort;
- i, h, v: Integer;
- faces: FaceArrPtr;
- facesPict, masksPict: PicHandle;
- bounds: Rect;
- begin
- SATGetPort(savePort);
-
- Load2DFaceArray := nil;
- faces := FaceArrPtr(NewPtr(Longint(SizeOf(Face)) * numFaces));
- if faces = nil then
- Exit(Load2DFaceArray);
-
- facesPict := GetPicture(facesPictId);
- if facesPict = nil then
- begin
- DisposePtr(Ptr(faces));
- Exit(Load2DFaceArray);
- end;
- masksPict := GetPicture(masksPictID);
- if masksPict = nil then
- begin
- ReleaseResource(Handle(facesPict));
- DisposePtr(Ptr(faces));
- Exit(Load2DFaceArray);
- end;
-
- fr := facesPict^^.picFrame;
- OffsetRect(fr, -fr.left, -fr.top);
-
- SATMakeOffscreen(facesOff, fr);
- SATSetPort(facesOff);
- DrawPicture(facesPict, fr);
-
- mr := masksPict^^.picFrame;
- OffsetRect(mr, -mr.left, -mr.top);
-
- CreateBWOffscreen(masksOff, mr);
- SATSetPort(masksOff);
- DrawPicture(masksPict, mr);
-
- ReleaseResource(Handle(facesPict));
- ReleaseResource(Handle(masksPict));
-
- {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures,}
- {arranged with facesPerRow faces per row!}
-
- for i := 0 to numFaces - 1 do
- begin
- h := i mod facesPerRow; {0..facesPerRow-1}
- v := i div facesPerRow; {0 and up}
- SetRect(bounds, h * sizeH, v * sizeV, (h + 1) * sizeH, (v + 1) * sizeV);
- BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
- end;
-
- Load2DFaceArray := faces;
- SATSetPort(savePort);
- end; {Load2DFaceArray}
-
- end.