jwhitnell@cup.portal.com (Jerry D Whitnell) (07/26/90)
Tim writes... |So, I made changes as recommended, including such annoyances as creating |an empty color table. Problem is, after some intensive debugging effort, |peeking at all the fields of the CGrafPort, GDevice, and PixMapHandle |with Lightsbug, and going over my code with a fine-toothed comb, I still |crash during the initial EraseRect. Is there some magic wand I have to |wave to get a 32-bit offscreen pixmap to work? Funny, I could have written this messages a couple of weeks ago. Can you tell me (via email if necessary) what you are doing? A couple of things to check: the pixelType, pixelSize, cmdCount and cmpSize fields in the PixMap. For 32-bit PixMaps, they should be chunky, 32, 3 and 8. Also check the gdType field in the graphics device, it should be direct RGB, not CLUT. If you have a 24-bit color monitor, you might compare a 32-bit color window with your offscreen PixMap, and comfirm the differences. Hope this helps. Jerry Whitnell SuperMac Technology
tim@efi.com (Tim Maroney) (07/28/90)
>Tim writes... >|So, I made changes as recommended, including such annoyances as creating >|an empty color table. Problem is, after some intensive debugging effort, >|peeking at all the fields of the CGrafPort, GDevice, and PixMapHandle >|with Lightsbug, and going over my code with a fine-toothed comb, I still >|crash during the initial EraseRect. Is there some magic wand I have to >|wave to get a 32-bit offscreen pixmap to work? In article <32082@cup.portal.com> jwhitnell@cup.portal.com (Jerry D Whitnell) writes: >A couple of things to check: the pixelType, pixelSize, cmdCount and cmpSize >fields in the PixMap. For 32-bit PixMaps, they should be chunky, 32, 3 and 8. >Also check the gdType field in the graphics device, it should be direct RGB, >not CLUT. Um, I agree with everything here except the pixelType. According to the 32-bit quickdraw manual, page 3, pixelType should be RGBDirect = 16, not chunky = 0. >If you have a 24-bit color monitor, you might compare a 32-bit >color window with your offscreen PixMap, and comfirm the differences. Been there, done that, except not on a 32-bit color system. I'm working on a IIci with built-in video, and working with 32-bit offscreen pixmaps. I compared it to a 32-bit offscreen GWorld built by 32-bit QD on the same system. By popular demand, here's the code. TOffscreen is an abstract base class which underlies TQDOffscreen (which is what I'm having problems with -- roll-your-own offscreen graphics worlds). Because only the inherited IOffscreen method is ever called, this is the only part of TOffscreen I am providing. I am providing all the relevant parts of TQDOffscreen, as well as the utility routine I use to create the TQDOffscreen object. Sorry for the weirdness imposed by the THINK Pascal formatter and the large screen. I have actually had to remove some comments to make the code readable in this format. TQDOffscreen = object(TOffscreen) fBuffer: Ptr; fDevice: GDHandle; fPort: CGrafPtr; procedure TQDOffscreen.IOffscreen (depth: integer; r: Rect; tab: CTabHandle; dev: GDHandle; flags: GWorldFlags); override; { Create and initialize an offscreen drawing environment. } procedure TQDOffscreen.Free; override; { set up and restore drawing world methods } procedure TQDOffscreen.PreDraw; override; { Save the current world and swap in the offscreen world. } procedure TQDOffscreen.PostDraw; override; { Restores the saved port and gDevice. } { rarely used informational methods } function TQDOffscreen.GetPixMap: PixMapHandle; override; { Return the PixMap. } function TQDOffscreen.GetOffPort: CGrafPtr; override; { Return the port } { old-style-pixmap-only reset method } procedure TQDOffscreen.SetPixBase (pixels: Ptr); { Change the baseAddr of the pixel map. } end; { Utility routine for making offscreen pixmaps.} {$S OffScreen} function NewOffWorlder (var aOffScreen: TOffscreen; frame: Rect; depth: integer; useOld: Boolean): Boolean; var fi: FailInfo; offFailed: Boolean; oldMap: TQDOffscreen; newMap: TQD32Offscreen; label 100; procedure AllocFailed (error: OSErr; message: LONGINT); begin offFailed := true; goto 100; end; begin offFailed := false; CatchFailures(fi, AllocFailed); if useOld | not TrapExists(QD32bit) then begin New(oldMap); aOffScreen := oldMap; end else begin New(newMap); aOffScreen := newMap; end; FailNil(aOffScreen); aOffScreen.IOffscreen(depth, frame, nil, nil, []); Success(fi); 100: NewOffWorlder := not offFailed; end; procedure TOffscreen.IOffscreen (depth: integer; r: Rect; tab: CTabHandle; dev: GDHandle; flags: GWorldFlags); { Create and initialize an offscreen drawing environment. } begin if (depth <> 0) & (depth <> 1) & (depth <> 2) & (depth <> 4) & (depth <> 8) & (depth <> 16) & (depth <> 32) then begin Free; Failure(minErr, 0); end; fOldPort := nil; fOldDevice := nil; IObject; end; { Here's the routine which crashes when the EraseRect is called. Note } { that this does not always happen. Sometimes the amount of space } { allocated to INITs has an effect, so that if some INITs are removed, } { (it doesn't matter which ones), a call will work. Other parameters } { always crash wven with all INITs removed. } procedure TQDOffscreen.IOffscreen (depth: integer; r: Rect; tab: CTabHandle; dev: GDHandle; flags: GWorldFlags); { Create and initialize an offscreen drawing environment. } var fi: FailInfo; have32bitQD: Boolean; saveDev: GDHandle; savePort: GrafPtr; docW, docH, pixBytes, theCmpSize, theCmpCount, theType, theRowBytes: integer; procedure DeathOffscreen (error: OSErr; message: longint); begin SetGDevice(saveDev); SetPort(savePort); Free; end; begin have32bitQD := TrapExists(QD32bit); inherited IOffscreen(depth, r, tab, dev, flags); fBuffer := nil; fDevice := nil; fPort := nil; GetPort(savePort); saveDev := GetGDevice; CatchFailures(fi, DeathOffscreen); { Let's set up the size of the rectangle we are using for the document. } docW := r.right - r.left; docH := r.bottom - r.top; { Figure out the color components involved. } case depth of 0: ; { XXX } 1: ; { XXX } 2: ; { XXX } 4: ; { XXX } 8: begin pixBytes := 1; theCmpSize := 8; theCmpCount := 1; theType := clutType; end; 16: begin pixBytes := 2; theCmpSize := 5; theCmpCount := 3; theType := directType; end; 32: begin pixBytes := 4; theCmpSize := 8; theCmpCount := 3; theType := directType; end; end; theRowBytes := docW * pixBytes; if odd(theRowBytes) then theRowBytes := theRowBytes + 1; fBuffer := NewPtr(docH * theRowBytes); FailMemError; { Set up the graphics device. } if dev = nil then begin fDevice := NewGDevice(0, -1); FailNIL(fDevice); HLock(Handle(fDevice)); HLock(Handle(fDevice^^.gdPMap)); with fDevice^^, fDevice^^.gdPMap^^ do begin if (pmVersion < 2) & have32bitQD then pmVersion := 2; gdFlags := $4001; { color, device has no driver } gdType := theType; { color table or direct type } gdRect := r; { the bounding rectangle of device } baseAddr := fBuffer; { The base address of the pixmap } bounds := r; { bounding rectangle of our device } rowBytes := theRowBytes + $8000; { set the color flag in rowBytes } pixelSize := depth; cmpCount := theCmpCount; cmpSize := theCmpSize; if theType = directType then pixelType := RGBDirect else pixelType := 0; { Set up the color table. } DisposCTable(pmTable); { kill the existing color table } pmTable := nil; if tab = nil then begin if theType = clutType then begin pmTable := GetCTable(depth); { install default color table } FailNil(pmTable); end else begin { install stub color table } pmTable := CTabHandle(NewHandle(16)); FailNil(pmTable); pmTable^^.ctSeed := GetCTSeed; pmTable^^.ctSize := 0; pmTable^^.ctFlags := $8000; if have32bitQD then CTabChanged(pmTable); end; end else pmTable := tab; { install caller's color table } { build a new iTable for this device, based on color table } gdResPref := 3; MakeITable(pmTable, gdITable, gdResPref); FailOSErr(QDError); gdId := 0; gdSearchProc := nil; gdCompProc := nil; end; { with } HUnLock(Handle(fDevice^^.gdPMap)); HUnLock(Handle(fDevice)); if have32bitQD then GDeviceChanged(fDevice); end else fDevice := dev; SetGDevice(fDevice); fPort := CGrafPtr(NewPtr(SizeOf(CGrafPort))); FailNil(fPort); OpenCPort(fPort); FailNoReserve; fPort^.portRect := r; RectRgn(fPort^.visRgn, r); if have32bitQD then PortChanged(GrafPtr(fPort)); Success(fi); SetGDevice(saveDev); SetPort(savePort); PreDraw; EraseRect(r); PostDraw; end; procedure TQDOffscreen.Free; override; begin if fBuffer <> nil then DisposPtr(fBuffer); if fPort <> nil then begin CloseCPort(fPort); DisposPtr(Ptr(fPort)); end; if fDevice <> nil then DisposGDevice(fDevice); inherited Free; end; procedure TQDOffscreen.PreDraw; { Save the current world and swap in the offscreen drawing world. } var savePort: GrafPtr; begin {$IFC qDebug} if (fOldDevice <> nil) | (fOldPort <> nil) then ProgramBreak('PreDraw -- fOldDevice or fOldPort is not nil!'); {$ENDC} GetPort(savePort); { save the current graphics port } fOldPort := CGrafPtr(savePort); fOldDevice := GetGDevice; { save the current graphics device } SetGDevice(fDevice); { set up the offscreen graphics device } SetPort(GrafPtr(fPort)); { set up the offscreen graphics port } end; procedure TQDOffscreen.PostDraw; { Reverses the effects of PreDraw by restoring the previously saved port and device. } begin {$IFC qDebug} if (fOldDevice = nil) | (fOldPort = nil) then ProgramBreak('PostDraw -- fOldDevice or fOldPort is nil!'); {$ENDC} SetGDevice(fOldDevice); { restore the saved graphics device } SetPort(GrafPtr(fOldPort)); { restore the saved graphics port } fOldDevice := nil; fOldPort := nil; end; procedure TQDOffscreen.SetPixBase (pixels: Ptr); { Change the baseAddr of the pixel map. } begin if fBuffer <> nil then begin DisposPtr(fBuffer); fBuffer := nil; end; fDevice^^.gdPMap^^.baseAddr := pixels; if TrapExists(QD32bit) then GDeviceChanged(fDevice); fPort^.portPixMap^^.baseAddr := pixels; if TrapExists(QD32bit) then PortChanged(GrafPtr(fPort)); end;