Welcome to MacForumz.com!
FAQFAQ      ProfileProfile    Private MessagesPrivate Messages   Log inLog in

old school offscreen graphics

 
   Macintosh computer (Home) -> Programmer Help RSS
Next:  U-Boat patch, anyone?  
Author Message
Micjuneau

External


Since: Aug 27, 2004
Posts: 13



(Msg. 1) Posted: Fri Aug 27, 2004 11:29 pm
Post subject: old school offscreen graphics
Archived from groups: comp>sys>mac>programmer>help (more info?)

Hello, I've been here some months ago with my questions about System-6
compatible C programming, on various topics.

I'm currently very close to having a very useful function which sets a
BitMap memory space and draws graphics in it, off the screen, so that
it can later be used with copybits. Think of it as a sprite object in
memory, which seems to be what game programming libraries are doing.

Now, I thought it would be extremely straightfoward to:

1) load a PICT resource from a file
2) read the Rect size from the picHandle and deduce the rowBytes for
the receiving bitmap
3) allocate space for the bitmap
4) change the portbits to that very bitmap
5) use drawpicture to draw unto it
6) close the picHandle and the port and return to the regular screen
port, and whatnot
7) use the offscreen bitmap with the fast copybits function.

But somewhere along the step, I'm drawing garbage on that memory
space. Will someone graciously look at my custom function? (I'm trying
to write my own .h file)


NOTE: I've pretty much narrowed it down to something that's happening
in LoadPicResIntoBitMap. I've been able to use offscreen bitmaps
(therefore, CreateOffscreenBitMap is A-OK) that are screen sized
without any problem. I'm only having problem with these custom sized
bitmaps that I'm trying to set up exactly as big at the PICT
resources.

----

Boolean LoadPicResIntoBitMap(BitMap *loadBM,int picID,
ConstStr255Param fileName);
Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds);
void DestroyOffscreenBitMap(GrafPtr oldOffscreen);

Boolean LoadPicResIntoBitMap(BitMap *loadBM,int picID,
ConstStr255Param fileName)
{
PicHandle myPicH;
int resID;
GrafPtr oldG, newG;

if(!(loadBM) || !(picID) || !(fileName)) return FALSE;
GetPort(&oldG); /* saves port before function call, will restore
at end */

myPicH=(PicHandle)NewHandle(sizeof(Picture));
if(myPicH==NULL) ExitToShell();
resID=OpenResFile(fileName);
if(!resID) ExitToShell();
myPicH=GetPicture(picID); /* 5 previous lines handle the PICT
retrieval */

HLock((Handle)myPicH);
loadBM->bounds=(*myPicH)->picFrame;


/* Next line creates a new port with the correct sized Rect read from
the PICT */

if (!CreateOffscreenBitMap(&newG, &(loadBM->bounds))) {
SysBeep(1);
ExitToShell();
}
SetPort(newG);
SetPortBits(loadBM);
EraseRect(&(loadBM->bounds));

/* Once the offscreen BitMap object is set as the port, draw onto it
from the picHandle*/
DrawPicture(myPicH,&(loadBM->bounds));
HUnlock((Handle)myPicH);
DisposeHandle((Handle)myPicH);

/* Last lines take care of the cleanup, hopefully the BitMap is still
usable */
SetPort(oldG);

DestroyOffscreenBitMap(newG);
return TRUE;
}

Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
{
GrafPtr savePort;
GrafPtr newPort;

GetPort(&savePort); /* need this to restore thePort after
OpenPort */

newPort = (GrafPtr) NewPtr(sizeof(GrafPort)); /* allocate
the grafPort */
if (MemError() != noErr)
return FALSE; /* failed to allocate the
off-screen port */
/*
the call to OpenPort does the following . . .
allocates space for visRgn (set to screenBits.bounds)
and
clipRgn (set wide open)
sets portBits to screenBits
sets portRect to screenBits.bounds
(See Inside Mac: Imaging with QuickDraw,
pages 2-38 to 2-39)
side effect: does a SetPort(&offScreen)
*/
OpenPort(newPort);
/* make bitmap the size of the bounds that caller supplied
*/
newPort->portRect = *inBounds;
newPort->portBits.bounds = *inBounds;
RectRgn(newPort->clipRgn, inBounds); /* avoid wide-open
clipRgn, be safe */
RectRgn(newPort->visRgn, inBounds); /* in case newBounds
is screen bounds */

/* rowBytes is size of row, it must be rounded up to an even
number of bytes */
newPort->portBits.rowBytes = ((inBounds->right -
inBounds->left +
15) >> 4) << 1;

/* number of bytes in BitMap is rowBytes * number of rows */
/* see notes at end of Technote about using _NewHandle
rather than _NewPtr*/
newPort->portBits.baseAddr =
NewPtr(newPort->portBits.rowBytes * (long)
(inBounds->bottom
- inBounds->top));
if (newPort->portBits.baseAddr == nil) { /* check to see if
we had
enough room for the bits */
SetPort(savePort);
ClosePort(newPort); /* dump the visRgn and clipRgn
*/
DisposPtr((Ptr)newPort); /* dump the GrafPort */
return false; /* tell caller we failed */
}
/* since the bits are just memory, let's clear them before
we start*/
EraseRect(inBounds); /* OpenPort did a SetPort(newPort)
so we are ok */
*newOffscreen = newPort;
SetPort(savePort);
return TRUE; /* tell caller we succeeded! */
}

void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
{
ClosePort(oldOffscreen); /* dump the visRgn and
clipRgn */
DisposPtr(oldOffscreen->portBits.baseAddr); /* dump the
bits */
DisposPtr((Ptr)oldOffscreen); /* dump the port */
}

 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
David Phillip Oste

External


Since: Apr 25, 2004
Posts: 1083



(Msg. 2) Posted: Sat Aug 28, 2004 3:23 am
Post subject: Re: old school offscreen graphics [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

This code has lots of problems.

In article <b1c9e2ae.0408272129.257b3e1c.RemoveThis@posting.google.com>,
micjuneau.RemoveThis@gmail.com (Micjuneau) wrote:

 > myPicH=(PicHandle)NewHandle(sizeof(Picture));

a picture is a variable size struct, not related to sizeof(Picture)

 > if(myPicH==NULL) ExitToShell();
 > resID=OpenResFile(fileName);
 > if(!resID) ExitToShell();
 > myPicH=GetPicture(picID); /* 5 previous lines handle the PICT

You've just leaked the NewHandle you created in line 1. You're call to
NewHandle was incorrect. It should have been:

myPicH = NULL;

since GetPicture will read it from the resource file. The Resource Map
still owns the return value of GetPicture(). You are incorrect when you
say:
 > DisposeHandle((Handle)myPicH);


 > SetPortBits(loadBM);

this stores loadBM into newG, even though you've carefully allocated an
appropriate bitMap into newG. You just leaked newPort's original bitMap.

 > DestroyOffscreenBitMap(newG);

since newG still references loadBM, you've just disposed the bitmap
you've been drawing on.

Do you know the concept of "ownership"? if A owns B, then only A has the
right to destroy B, and A has the responsibility of destroying B when
the time comes.

You need to go through your code and think about who owns what when.<!-- ~MESSAGE_AFTER~ -->

 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
Micjuneau

External


Since: Aug 27, 2004
Posts: 13



(Msg. 3) Posted: Sat Aug 28, 2004 3:53 am
Post subject: Re: old school offscreen graphics [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Wow, a monumental error on my part.

I forgot to assign a memory block to the bitmap's baseAddr pointer.

I also had the following function in my .h file that I had written in
the beginning, but I lost track of its usefulness in the many
revisions of my file.


(it has to be called right after the PICT's rect is known and loaded
into loadBM->bounds.


----

Boolean InitBitMap(BitMap *loadBM)
{
loadBM->rowBytes = ((loadBM->bounds.right - loadBM->bounds.left
+
15) >> 4) << 1;

/* number of bytes in BitMap is rowBytes * number of rows */

loadBM->baseAddr =
NewPtr(loadBM->rowBytes * (long)
(loadBM->bounds.bottom
- loadBM->bounds.top));
if (loadBM->baseAddr == nil) return FALSE;
return TRUE;
}
 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
Micjuneau

External


Since: Aug 27, 2004
Posts: 13



(Msg. 4) Posted: Sun Aug 29, 2004 12:08 am
Post subject: Re: old school offscreen graphics [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Thanks for your response, David. Bear in mind, maybe by sheer luck,
that with the addition I wrote in my reply, the program works
perfectly. It doesn't do much (just loads up 1 image and displays it
through the loadBM bitmap). It does puzzle me that it works,
especially when I read your comments about the bitmap being destroyed
after I kill the offscreen port. It appears it doesn't disappear. I
still can use that portion of the memory which contains loadBM's
bitmap.


David Phillip Oster <oster.DeleteThis@ieee.org> wrote in message news:<oster-88E3F1.00094528082004.DeleteThis@newssvr21-ext.news.prodigy.com>...
 > You've just leaked the NewHandle you created in line 1. You're call to
 > NewHandle was incorrect. It should have been:
 >
 > myPicH = NULL;
 >
 > since GetPicture will read it from the resource file. The Resource Map
 > still owns the return value of GetPicture(). You are incorrect when you
 > say:
  > > DisposeHandle((Handle)myPicH);
 >

So you're saying:

1) ditch the NewHandle line (when *must* I use NewHandle?)
2) put myPicH = NULL; before loading it up to have a guaranteed false
result if things do not load correctly
3) remove the DisposeHandle line.
4) Assume that the mac's kernel will handle everything about handles
itself through GetPicture? So in a sense, I wasn't taking advantage of
what seems to be a hassle-free, autonomous environment concerning
handles? What if I'm memory constrained, would not caring about the
fate of a certain number of picture handles bar me from having enough
memory?


 >
  > > SetPortBits(loadBM);
 >
 > this stores loadBM into newG, even though you've carefully allocated an
 > appropriate bitMap into newG. You just leaked newPort's original bitMap.

It's true that it's a redundant line. I must have put it when I failed
to understand everything that I was doing/everything that I figured I
needed to do. It's true that CreateOffscreenBitmap does associate
loadBM with newG. Doing it again with that line is overkill. However,
I don't understand how things "can leak" from doing it twice. I don't
master the inner workings of memory enough. Care to elaborate?


 > Do you know the concept of "ownership"? if A owns B, then only A has the
 > right to destroy B, and A has the responsibility of destroying B when
 > the time comes.

It's a bit daunting for me to plan that kind of thing - I knew I would
have some struggles about this. What little I know from C++, is that I
could stop all that intertwined function calling labyrinth with some
classes.

 > You need to go through your code and think about who owns what when.

Ok, here's the kicker:

When I make the above changes that you gave me about the picHandle,
everything still works. Only when I remove the "redundant"
SetPortBits(loadBM), does the graphic become garbled again!! It seems
it's the one line that actually makes it survive the
DestroyOffscreenthingy function. What the who why, now?<!-- ~MESSAGE_AFTER~ -->
 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
David Phillip Oste

External


Since: Apr 25, 2004
Posts: 1083



(Msg. 5) Posted: Sun Aug 29, 2004 4:22 pm
Post subject: Re: old school offscreen graphics [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

In article <b1c9e2ae.0408282208.8fa00a4 DeleteThis @posting.google.com>,
micjuneau DeleteThis @gmail.com (Micjuneau) wrote:

 > So you're saying:
 >
 > 1) ditch the NewHandle line (when *must* I use NewHandle?)

Yes. The resource manager will continue to own the handle.

 > 2) put myPicH = NULL; before loading it up to have a guaranteed false
 > result if things do not load correctly

Yes

 > 3) remove the DisposeHandle line.

Yes

 > 4) Assume that the mac's kernel will handle everything about handles
 > itself through GetPicture? So in a sense, I wasn't taking advantage of
 > what seems to be a hassle-free, autonomous environment concerning
 > handles? What if I'm memory constrained, would not caring about the
 > fate of a certain number of picture handles bar me from having enough
 > memory?

Some handles are resources, owned by the Resource Manager. They aren't
entirely automatic: If they are marked Purgable, the Memory Manager is
allowed to purge them, so correct code would check that they are still
present with NULL != *myPicH, and call LoadResource() if necessary, call
HNoPurge() while it is using them, and call HPurge() when it is done
with them (The advantage over ReleaseResource() is that
ReleaseResource() frees the allocated memory NOW, while HPurge() just
makes it available if the system needs it, so if you re-use a resource,
you might not need to re-read it from disk.

 >
 >
  > >
   > > > SetPortBits(loadBM);
  > >
  > > this stores loadBM into newG, even though you've carefully allocated an
  > > appropriate bitMap into newG. You just leaked newPort's original bitMap.
 >
 > It's true that it's a redundant line. I must have put it when I failed
 > to understand everything that I was doing/everything that I figured I
 > needed to do. It's true that CreateOffscreenBitmap does associate
 > loadBM with newG. Doing it again with that line is overkill. However,
 > I don't understand how things "can leak" from doing it twice. I don't
 > master the inner workings of memory enough. Care to elaborate?

you did a NewPtr() and assigned it to the baseAddr field of the bitMap
field of newG. Then you made qd.thePort point at newG, then you called
SetPortBits(), which stores over the bitMap field of qd.thePort. Now,
nothing points to the NewPtr()ed block, so nothing can ever call
DisposePtr() on it.

  > > Do you know the concept of "ownership"? if A owns B, then only A has the
  > > right to destroy B, and A has the responsibility of destroying B when
  > > the time comes.
 >
 > It's a bit daunting for me to plan that kind of thing - I knew I would
 > have some struggles about this. What little I know from C++, is that I
 > could stop all that intertwined function calling labyrinth with some
 > classes.

C++ gives you tools, destructors that are guaranteed to be called for
each fully contructed object, and like boost::shared_ptr, or
PowerPlant's StDeleter, but it is still up to you to think the issue of
ownership through. Languages like C# and Java have integrated garbage
collectors that preserve correctness of leaky programs, but leaky
programs will still perform worse than ones that build up garbage.

  > > You need to go through your code and think about who owns what when.
 >
 > Ok, here's the kicker:
 >
 > When I make the above changes that you gave me about the picHandle,
 > everything still works. Only when I remove the "redundant"
 > SetPortBits(loadBM), does the graphic become garbled again!! It seems
 > it's the one line that actually makes it survive the
 > DestroyOffscreenthingy function. What the who why, now?

You need the SetPortBits(loadBM) so that the graphic will draw on the
port you think it is drawing on. What you still lack is saving and,
after the drawing, restoring the original BitMap of the port, so that
when you dispose the port, the correct bitmap is destroyed. Also, since
that bitmap exists only so you can destroy it, you don't need to go
through the extra work of NewPtr()ing it to the correct size.

Since you asked this question, it seems that you are still not clear on
what data structures own which other data structures.<!-- ~MESSAGE_AFTER~ -->
 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
Micjuneau

External


Since: Aug 27, 2004
Posts: 13



(Msg. 6) Posted: Mon Aug 30, 2004 12:28 am
Post subject: Re: old school offscreen graphics [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

 > You need the SetPortBits(loadBM) so that the graphic will draw on the
 > port you think it is drawing on. What you still lack is saving and,
 > after the drawing, restoring the original BitMap of the port, so that
 > when you dispose the port, the correct bitmap is destroyed. Also, since
 > that bitmap exists only so you can destroy it, you don't need to go
 > through the extra work of NewPtr()ing it to the correct size.
 >
 > Since you asked this question, it seems that you are still not clear on
 > what data structures own which other data structures.

Ok, I'm seeing much clearer now, or at least I hope.

At the start of LoadPicResIntoBitMap, I declare a
BitMap *oldBM;

which I use right after GetPort:
oldBM=&(oldG->portBits);

in order to save the old port's bitmap, just like you said.

You're telling me to not go through the extra work of NewPtr() the
offscreen bitmap -- I say no: I do need to go through that extra work.
I will both use LoadPicResIntoBitMap and CreateOffscreenBitMap (which
should be renamed as CreateOffscreenPortAndPort but that's getting
clunky) alike. The scenario where I use CreateOffscreenBitMap alone is
going to happen (for double buffering purposes, for example. I'd want
to have a new offscreen canvas that I'm not putting anything inside,
at first), and in that case, I do need to specify the right Rect size
to have a properly set up BitMap associated with it. That function
will not only be used by LoadPicRestIntoBitMap.

Anyway, I've made most of your suggestions of correction, and the
program still stands very well, and now is less leaky. Thanks a lot.<!-- ~MESSAGE_AFTER~ -->
 >> Stay informed about: old school offscreen graphics 
Back to top
Login to vote
Display posts from previous:   
Related Topics:
OffScreen and palette - Hi, first time user of this forum. here my problem: I want to know the exact value of an RGB color of a pixel; first, I read a palette in the resource fork: aPalette = GetNewPalette(noPalette); nbColors = (* aPalette)->pmEntries; for (i = 0; i <...

[cocoa] Is it possible to draw text to an offscreen view t.. - Summary: How can I draw some text to an offscreen view and then print it? Looking for a simple way to do this. Details: I have a bunch of NSTextFields in a window, the contents of which must be printed. There is some other stuff in the window..

Old school (?) drawing philosophy - I finally have a serviceable 2d image drawing engine working under System 1.0 through OS 9.2. I can draw arbitrary sized multi-frames sprites, with (pre-generated) white masks, if needed, and with auto-cleaning (saves background in temp bitmap and draws....

Old school, coming back again. - I started programming for Mac back in the OS 5 days, through OS X 10.1, all the time using the (what is now called) the Carbon API. Now my boss has asked me to write an application for "low end Macs". I'm assuming that "low end" no l...

need help debugging old school BASIC program - this basic program (simple poetry-generating program) keeps giving me errors. I'm using the free Chipmunk Basic on OSX. Any help apprectiated.. 10 rem hanshan 20 gosub 250 : rem initialize 30 rem choose pattern 40 r = int(rnd(1)*3)+1 50 on r gosub..
   Macintosh computer (Home) -> Programmer Help All times are: Pacific Time (US & Canada) (change)
Page 1 of 1

 
You can post new topics in this forum
You can reply to topics in this forum
You can edit your posts in this forum
You can delete your posts in this forum
You can vote in polls in this forum



[ Contact us | Terms of Service/Privacy Policy ]