home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Snippets / OffscreenToys 1.4 / OffscreenToysUtils.p < prev   
Encoding:
Text File  |  1995-11-22  |  10.6 KB  |  358 lines  |  [TEXT/PJMM]

  1. {Minimalist's offscreen package - reuseable code from OffscreenToys.}
  2.  
  3. {This unit implements glue for using "cicn" resources and GWorlds. It works on all Macs I can}
  4. {imagine, including Macs without 32-bit QD or Color QD.}
  5. {Note: Assumes that ALRT #129 is present, for error messages.}
  6.  
  7. unit OffscreenToysUtils;
  8.  
  9. interface
  10.     uses
  11. {$IFC UNDEFINED THINK_PASCAL}
  12.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit,{}
  13.         TextEdit, Traps, Memory, Icons, {}
  14.         SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, Packages, {}
  15. {$ENDC}
  16.         QDOffScreen;
  17.  
  18. {$IFC UNDEFINED GENERATINGPOWERPC}
  19. {$SETC GENERATINGPOWERPC = false}
  20. {$ENDC}
  21.  
  22. {Glue for GWorlds}
  23.     procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
  24.     procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
  25.  
  26. {Glue for cicns}
  27.     function OTGetCicn (cicnId: integer): CIconHandle;
  28.     procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
  29.     procedure OTDisposeCicn (theCicn: CIconHandle);
  30.     function OTGetBoostCicn (cicnId: integer): GrafPtr;
  31.     procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
  32.  
  33. {NewPtr with built-in error check}
  34.     function OTNewPtr (size: Longint): Ptr;
  35.  
  36. {Glue for making GWorlds}
  37.     procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
  38.     procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
  39.  
  40. {Apples code for TrapAvailable}
  41.     function TrapAvailable (theTrap: Integer): Boolean;
  42.  
  43. {Initialize the globals - must be done first!}
  44.     procedure OTInitGlobals;
  45.  
  46.     var
  47.         gColorQDFlag: Boolean;    {True if 32-bit QD exists. If not, we run everything in b/w.}
  48.         gHasWNE: Boolean;        {True if we can use WaitNextEvent}
  49.         gSoundFlag: Boolean;        {True if Sound Manager is around.}
  50.  
  51. implementation
  52.  
  53. {Taken out from:}
  54. { --- PART 2: Various general, reuseable routines, mostly glue: ---------------------}
  55.  
  56. {Rand: simply make a random number between 0 and range-1.}
  57.  
  58.     function Rand (range: integer): integer;
  59.     begin
  60.         Rand := abs(Random mod range)
  61.     end;
  62.  
  63. {BailOut: Emergency exit. We go here on errors (i.e. out of memory). Here, I assume that}
  64. {the problem is out of memory. Note: Assumes that ALRT #129 is present!}
  65.  
  66.     procedure BailOut;
  67.     begin
  68.         ParamText('Out of memory!', ' ', '', '');
  69.         if Alert(129, nil) = 1 then
  70.             ;
  71.         Halt;
  72.     end; {BailOut}
  73.  
  74. {OTGetGWorld and OTSetGWorld: Glue to GetGWorld and SetGWorld, so this will work}
  75. {without 32-bit QD, if necessary.}
  76.  
  77.     procedure OTGetGWorld (var thePort: GrafPtr; var theDevice: GDHandle);
  78.     begin
  79.         theDevice := nil;
  80.         if gColorQDFlag then
  81.             GetGWorld(CGrafPtr(thePort), theDevice)
  82.         else
  83.             GetPort(thePort);
  84.     end;
  85.  
  86.     procedure OTSetGWorld (thePort: GrafPtr; theDevice: GDHandle);
  87.     begin
  88.         if gColorQDFlag then
  89.             SetGWorld(CGrafPtr(thePort), theDevice)
  90.         else
  91.             SetPort(thePort);
  92.     end;
  93.  
  94. {OTGetCicn: Glue to GetCIcon, loads a cicn resource}
  95.  
  96.     function OTGetCicn (cicnId: integer): CIconHandle;
  97.         var
  98.             h: Handle;
  99.     begin
  100.         if gColorQDFlag then
  101.             begin
  102.                 OTGetCicn := GetCIcon(cicnId);
  103.                 h := GetResource('cicn', cicnID);
  104.                 ReleaseResource(h);
  105.             end
  106.         else
  107.             OTGetCicn := CIconHandle(GetResource('cicn', cicnId));
  108.     end;
  109.  
  110. {OTPlotCicn: Glue to PlotCIcon, plots a cicn.}
  111.  
  112.     procedure OTPlotCicn (theCicn: CIconHandle; destWorld: GrafPtr; r: Rect);
  113.         var
  114.             tempIconBMap, tempIconMask: BitMap;
  115.             savePort: GrafPtr;
  116.             saveDevice: GDHandle;
  117.             datasize: integer;
  118.     begin
  119.         OTGetGWorld(savePort, saveDevice);
  120.         if destWorld <> nil then
  121.             OTSetGWorld(destWorld, nil)
  122.         else
  123.             destWorld := savePort; {So that CopyMask has a GrafPtr!}
  124.         if theCicn <> nil then {If we have a cicn}
  125.             if gColorQDFlag then {We have color - then it's easy.}
  126.                 PlotCicon(r, theCicn)
  127.             else
  128. {No color: Use CopyMask.}
  129. {NOTE: This only works for 9 pixels or wider cicn's! (Old QuickDraw can't handle 1 byte wide bitmaps.)}
  130. {There is a workaround for this, but that is *really* tedious.}
  131.                 begin
  132.                     HLock(Handle(theCicn));
  133. {Make the base address pointers valid}
  134.                     with theCicn^^.iconBMap do
  135.                         datasize := rowBytes * (bounds.bottom - bounds.top);
  136.                     theCicn^^.iconBMap.baseAddr := Ptr(longint(@theCicn^^.iconMaskData[0]) + datasize); {Bitmappen måste vara giltig fört!}
  137.                     theCicn^^.iconMask.baseAddr := @theCicn^^.iconMaskData[0]; {Maskbitmappen måste också vara giltig först!}
  138. {Draw with CopyMask}
  139.                     CopyMask(theCicn^^.iconBMap, theCicn^^.iconMask, destWorld^.portBits, theCicn^^.iconBMap.bounds, theCicn^^.iconBMap.bounds, r);
  140.                     HUnLock(Handle(theCicn));
  141.                 end;
  142.         OTSetGWorld(savePort, saveDevice);
  143.     end;
  144.  
  145.     procedure OTDisposeCicn (theCicn: CIconHandle);
  146.     begin
  147.         if gColorQDFlag then
  148.             DisposeCIcon(theCicn)
  149.         else
  150.             ReleaseResource(Handle(theCicn));
  151.     end;
  152.  
  153. {To avoid a lot of boring checks later, we have a glue for NewPtr, making it emergency}
  154. {exit on out of memory. (This is of course often not what you want, but this is a demo!)}
  155.  
  156.     function OTNewPtr (size: Longint): Ptr;
  157.     begin
  158.         OTNewPtr := NewPtrClear(size);
  159.         if MemError <> noErr then
  160.             BailOut;
  161.     end;
  162.  
  163. {OTNewGWorld: Glue to NewGWorld}
  164. {I declare offscreenGWorld as GrafPtr to save us a bunch of typecasts later (in CopyBits).}
  165. {Most parameters to NewGWorld omitted - NewGWorld is smart enough to make the defaults useable.}
  166.  
  167.     procedure OTNewGWorld (var offscreenGWorld: GrafPtr; boundsRect: Rect);
  168.         var
  169.             theDevice, oldDevice: GDHandle;
  170.             ourCMHandle: CTabHandle;
  171.             err: OsErr;
  172.  
  173.             saveGD: GDHandle;
  174.             savePort: GrafPtr;
  175.     begin
  176.         OTGetGWorld(savePort, saveGD);
  177.  
  178.         if gColorQDFlag then
  179.             begin
  180. {$IFC UNDEFINED THINK_PASCAL}
  181.                 if noErr <> NewGWorld(GWorldPtr(offscreenGWorld), 0, boundsRect, nil, nil, pixelsLocked) then
  182. {$ELSEC}
  183.                     if noErr <> NewGWorld(GWorldPtr(offscreenGWorld), 0, boundsRect, nil, nil, [pixelsLocked]) then
  184. {$ENDC}
  185.                         BailOut;
  186. {We lock the offscreen pixmap so we can CopyBits and PlotCIcon to it.}
  187.                 if LockPixels(CGrafPtr(offscreenGWorld)^.portPixMap) then
  188.                     ;
  189. {Note: We should unlock it (UnlockPixels) when not animating, to avoid memory fragmentation,}
  190. {but you can bother with that later if it's a problem.}
  191.             end
  192.         else
  193.             begin
  194. {Not color - setup in b/w}
  195.                 offscreenGWorld := GrafPtr(OTnewPtr(sizeof(GrafPort)));
  196.                 OpenPort(offscreenGWorld);
  197.                 offscreenGWorld^.portRect := boundsRect;
  198.                 offscreenGWorld^.portBits.bounds := offscreenGWorld^.portRect;
  199.  
  200.                 RectRgn(offscreenGWorld^.visRgn, boundsRect);
  201.                 ClipRect(boundsRect);
  202.  
  203.                 offscreenGWorld^.portBits.rowBytes := longint(((offscreenGWorld^.portRect.right - offscreenGWorld^.portRect.left + 15) div 16) * 2);
  204.                 offscreenGWorld^.portBits.baseAddr := OTnewPtr(offscreenGWorld^.portBits.rowBytes * longint(offscreenGWorld^.portRect.bottom - offscreenGWorld^.portRect.top));
  205.             end;
  206.  
  207.         OTSetGWorld(savePort, saveGD);
  208.     end;
  209.  
  210. {OTDisposeGWorld: Glue to DisposeGWorld}
  211.  
  212.     procedure OTDisposeGWorld (var offscreenGWorld: GrafPtr);
  213.     begin
  214.         if gColorQDFlag then
  215.             begin
  216.                 DisposeGWorld(GWorldPtr(offscreenGWorld));
  217.             end
  218.         else
  219.             begin
  220.                 DisposePtr(offscreenGWorld^.portBits.baseAddr);
  221.                 DisposePtr(Ptr(offscreenGWorld));
  222.             end;
  223.         offscreenGWorld := nil;
  224.     end;
  225.  
  226.  
  227. {TrapAvailable from IM6-3-8}
  228.     function NumToolboxTraps: Integer;
  229.     begin
  230.         if NGetTrapAddress($A86E, ToolTrap) = NGetTrapAddress($aa6e, ToolTrap) then {_InitGraf}
  231.             NumToolboxTraps := $200
  232.         else
  233.             NumToolboxTraps := $400;
  234.     end;
  235.     function GetTrapType (theTrap: Integer): TrapType;
  236.         const
  237.             TrapMask = $800;
  238.     begin
  239.         if band(theTrap, TrapMask) > 0 then
  240.             GetTrapType := ToolTrap
  241.         else
  242.             GetTrapType := OSTrap;
  243.     end;
  244.     function TrapAvailable (theTrap: Integer): Boolean;
  245.         var
  246.             tType: TrapType;
  247.     begin
  248.         tType := GetTrapType(theTrap);
  249.         if tType = ToolTrap then
  250.             begin
  251.                 theTrap := band(theTrap, $7ff);
  252.                 if theTrap >= NumToolboxTraps then
  253.                     theTrap := $A89F;{_Unimplemented}
  254.             end;
  255.         TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress($A89F, ToolTrap);{_Unimplemented}
  256.     end;
  257. {End of code from IM6}
  258.  
  259.     procedure OTInitGlobals;
  260.         const
  261. {Trap numbers}
  262.             _WaitNextEvent = $A860;
  263.             _GetCIcon = $AA1E; {E.g. any Color QuickDraw routine}
  264.             k32bQD = $AB1D;
  265.             _SndPlay = $A805;
  266.     begin
  267.         gHasWNE := TrapAvailable(_WaitNextEvent);
  268.         gColorQDFlag := TrapAvailable(k32bQD) and TrapAvailable(_GetCIcon); {???}
  269.         gSoundFlag := TrapAvailable(_SndPlay);
  270. {$IFC UNDEFINED THINK_PASCAL}
  271.         qd.randSeed := TickCount;            {Seed the random number generator - TickCount is good enough.}
  272. {$ELSEC}
  273.         randSeed := TickCount;                {Seed the random number generator - TickCount is good enough.}
  274. {$ENDC}
  275.     end;
  276.  
  277.  
  278.  
  279.  
  280. {Load a cicn to a GWorld. Wastes some memory, but if it isn't too many, the speed increase pays}
  281. {for it.}
  282.  
  283.     function OTGetBoostCicn (cicnId: integer): GrafPtr;
  284.         var
  285.             offscreenGWorld: GrafPtr;
  286.             theCicn: CIconHandle;
  287.             saveGD: GDHandle;
  288.             savePort: GrafPtr;
  289.     begin
  290.         OTGetGWorld(savePort, saveGD);
  291.         theCicn := OTGetCicn(cicnId);
  292.         OTNewGWorld(offscreenGWorld, theCicn^^.iconMask.bounds);
  293.         if offscreenGWorld <> nil then
  294.             begin {OTSetGWorld(offscreenGWorld, nil); Onödigt!}
  295.                 OTPlotCicn(theCicn, offscreenGWorld, theCicn^^.iconMask.bounds);
  296.  
  297. {I use the clipRgn for storing the mask region. This may seem weird, but when we aren't drawing}
  298. {in the GWorld anyway, it won't matter.}
  299.                 if offscreenGWorld = nil then
  300.                     offscreenGWorld^.clipRgn := NewRgn;
  301.                 if gColorQDFlag and TrapAvailable($A8D7) then {a8d7 = BitMapToRegion}
  302.                     begin
  303.                         if noErr <> BitMapToRegion(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
  304.                             offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
  305.                     end
  306.                 else {Trap not available - use the glue routine instead.}
  307.                     begin
  308. {$IFC GENERATINGPOWERPC}
  309. {$ELSEC}
  310.                         if noErr <> BitMapToRegionGlue(offscreenGWorld^.clipRgn, theCicn^^.iconMask) then{}
  311.                             offscreenGWorld^.clipRgn := nil;{or DisposeRgn?}
  312. {$ENDC}
  313.                     end;
  314.                 OTDisposeCicn(theCicn);
  315.             end;
  316.         OTSetGWorld(savePort, saveGD);
  317.         OTGetBoostCicn := offscreenGWorld;
  318.     end;
  319.  
  320.     var
  321.         gTmpRgn: RgnHandle;
  322.  
  323.     procedure OTPlotBoostCicn (theCicn, destPort: GrafPtr; where: Point);
  324.         var
  325.             saveGD: GDHandle;
  326.             savePort: GrafPtr;
  327.             bounds: Rect;
  328.             tmpRgn: RgnHandle;
  329.             saveForeColor, saveBackColor: RGBColor;
  330.     begin
  331.         OTGetGWorld(savePort, saveGD);
  332. {OTSetGWorld(theCicn, nil);}
  333.         bounds := theCicn^.portRect;
  334.         OffsetRect(bounds, where.h - bounds.left, where.v - bounds.top);
  335.  
  336.         if gTmpRgn = nil then
  337.             gTmpRgn := NewRgn; {For top speed, we make this global, and create it only once!}
  338.         CopyRgn(theCicn^.clipRgn, gTmpRgn);
  339.         OffsetRgn(gTmpRgn, where.h, where.v);
  340.         SetPort(destPort); {Device?}
  341.         if gColorQDFlag then
  342.             begin
  343.                 GetForeColor(saveForeColor);
  344.                 GetBackColor(saveBackColor);
  345.             end;
  346.         ForeColor(blackColor);
  347.         BackColor(whiteColor);
  348.         CopyBits(theCicn^.portBits, destPort^.portBits, theCicn^.portRect, bounds, srcCopy, gTmpRgn);
  349. {DisposeRgn(tmpRgn);}
  350.         if gColorQDFlag then
  351.             begin
  352.                 RGBForeColor(saveForeColor);
  353.                 RGBBackColor(saveBackColor);
  354.             end;
  355.         OTSetGWorld(savePort, saveGD);
  356.     end;
  357.  
  358. end.