NSOGL Document Based

Member
Posts: 196
Joined: 2002.04
Post: #1
Hi
I've been really struggling with a Document Based application that has an NSOpenGLView. The thing that's confusing me is the responder and timer stuff. So, does anyone know of a simple tutorial that makes document based files with NSViews?

Thanks,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #2
/Developer/Examples/AppKit/, Sketch or SimpleToolbar show some document features (although not with OpenGL.)

What exactly is the problem? Getting your document methods hooked up to the main nib's First Responder is not entirely obvious... is that it? You have to copy-paste the method names from the document nib into the main nib.

For the timer, are you asking about setting up a continuous animation in your GL view? There are any number of tutorials on this. You just want to create an NSTimer calling your animate method, which does setNeedsDisplay:YES on your view.
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #3
Thanks for the suggestions. I really liked the Simple Toolbar code. I think I may try that toolbar stuff when I get better at Cocoa.

Here's the classes I'm using:

MyDocument--subclass of NSDocument. The only code in here is the stuff from Project Builder's template.

MyOGLView--subclass of NSOpenGLView. Calls everything including makeFirstResponder in the - (void)awakeFromNib.

I've been looking over my code again and I have a few more questions that I think will make more sense. I guess it's the MVC concept that I'm a bit confused on. What is MyDocument? Is it a Model or a Controller?

My application keeps crashing when I close out one of the document windows. I get an error signal 6 (SIGABRT). I'm pretty sure It's because I'm not calling anything in MyDocument. What parts of the NSOpenGLView do I need to set up in MyDocument? I've got the timer, keyboard input, OpenGL context loaded into MyOGLView. I'm almost certain that it's this method in MyDocument I need to do something in:

- (void)windowControllerDidLoadNib:(NSWindowController *) aController;

But what? I'm sorry if this sounds really stupid but I'm totally stumped.

Thanks,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #4
First, have you read the docs? Program Design>Document Based Applications>The Roles of Key Objects, Implementing a Document Based Application, and Frequently Asked Questions are all required reading.

In summary, the MVC pattern goes:

app->document controller->document->window controller->window->views

All of the relations can be one-to-many. The document class is model data. That is, any document state you'll be reading/writing. Your view will probably have its own temporary data (display lists, etc).

For a simple application, you can get away with only subclassing the document and the view, like you're doing. (I do it too, actually, but depending on problems I run into, and the desired functionality, I usually end up also subclassing NSWindow, and NSObject or NSResponder for a generic top level controller.)

For your crash, sounds like you need to trace where your objects are being released.

For setup stuff:
The OpenGL setup should be done within the view. If the document is only the model data, it should know as little as possible about how the view is drawing. You can do your GL setup in initWithFrame, and other view setup in awakeFromNib.

In the document's windowControllerDidLoadNib, you can send your model data to your view. You can also squeeze window related things in here, for example, registering for dragging, or modifying the window title / size.

Your view will be instantiated before the document is sent windowControllerDidLoadNib, so you can send the view messages from the document (e.g. "display this stuff") after it is set up. It might help to instrument all your init... awake... etc functions with a simple NSLog until you understand the order they are called in.
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #5
Thank you so much. I've read through most of the Apple documentation for Document based applications. I even went back through my Big Nerd Ranch book. But, I still couldn't see anything wrong.

Thanks for the NSLog idea too. I tried checking all of the objects but they seem to be in order. My only thought is that it has something to do with the contexts. Especially, since I'm getting a decrease of 20 frames per second when I close out a document window and open a new one. I'm not that good with OpenGL contexts, so I've uploaded a sample application and source code that uses the same context code.

UPDATE: Ok I know what it is now the sample application would not reproduce the real big bug. It has do with bad structure and how I'm allocating the other classes in MyOGLView. Could I e-mail you a link to my actual game source code so you could look over it?

Thanks again,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #6
Well, the code you posted does not crash for me, opening and closing 20 windows. I am using 10.2.6 on a Powerbook with ATI Radeon 7500. What are you using? (iMac SE/Rage 128? Pre 10.2? Guessing from the fact that the project wasn't created with the Dec dev tools.)

Searching cocoa.mamasam.com for "NSTimer NSDocument", the first hit is a very similar question from Mark Levin, who is also hanging around iDevGames. There's no answer to his post, though.

If I had to guess, the crash might be from the NSTimer firing after your view/window have been dealloc'd. I notice that you never invalidate/dealloc the timer in your view. You can do that in -dealloc, or you could set up windowWillClose in your window's delegate (which can be the document subclass.)

I also notice the following problems, but since I don't know your intent I don't know which you might need help with:

1) the window (white) is briefly visible before the context is created and drawn.
2) your context isn't VBL sync'd, so the animation tears.
3) your timer is firing as fast as possible, wasting CPU.
4) windows in the background aren't being flushed.
5) you aren't handling window minimization.
Quote this message in a reply
Feanor
Unregistered
 
Post: #7
I thought I'd add a point about MVC, which is in fact in the docs, just to emphasize. I would amend arekkusu's words a bit and say that the document class is a model controller, not a model class proper -- it does a part of the job of the controller layer, and mediates between proper model classes. Model classes include all classes which directly represent data and processes in the modelled system. In a game, examples include A.I., geometry, and game rules-related classes.

The main issue to keep in mind when creating an MVC program with OpenGL is that you will probably need separate timers and many other things for each document, so naturally the document object or members of the document's own object graph (other controllers which are document specific) will manage that work.

There is an example openGL document-based application on my downloads page, which I put together a couple of months ago -- it is meant to be a skeleton for something else, but I added some drawing code for a lark:

Feanor's sample code. It's the one called "Cavern Quest", for no apparent reason. Grin
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #8
Ok this time I think I got it. Why do you call:
Code:
- (void)drawRect:(NSRect)rect {
    [[[NSDocumentController sharedDocumentController] currentDocument] drawGL];
}
in CQOpenGLView. I tried calling this but it wouldn't update like yours:
Code:
CQDocument *document;

- (id)initWithFrame:(NSRect)frame {
        document = [[CQDocument alloc] init];
     // Draw stuff here
}

- (void)drawRect:(NSRect)rect {
    [document drawGL];
}
Thanks,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #9
If you're trying to fix problem 4) I listed, you need to make the GL context current in your draw function, or any other place (reshape, init) where you send GL commands and there is any possibility of the context not being current.

Do it now, before you go multithreaded, and save yourself a big headache. Smile
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #10
Sorry I missed that post. I've been too busy tearing my hair out with Cocoa I guess. Using Feanor's code is making me go around in circles since I'm totally confused and frustratedWacko.

Quote:Originally posted by arekkusu
(iMac SE/Rage 128? Pre 10.2?

Yes

Quote:Originally posted by arekkusu
2) your context isn't VBL sync'd, so the animation tears.


What is VBL sync? Sounds very good. I've been wondering why the animation is bad.

Also may I please e-mail you a link to the actual project code? It's pretty small and not too messy.

Thanks,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #11
VBL sync: synchronizes the context flush to Vertical BLanking, so the updates are always in sync with your monitor refresh. This also speed limits your frame rate to 60Hz or whatever your monitor is set to; there is no point in drawing any faster than you can see.

It's two lines of code to do this, and ABSOLUTELY REQUIRED, IMHO:

Code:
long sync = 1;
        [[self openGLContext] setValues:&sync  forParameter:NSOpenGLCPSwapInterval];

See http://developer.apple.com/samplecode/Sa...3D/VBL.htm for complete code and http://developer.apple.com/technotes/tn/tn2014.html for discussion.


email: sure, I'll take a look.
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #12
I'll check all that VBL stuff out too. Thanks. I just e-mailed you the link.

Thanks again,
Iceman
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #13
It finally works thank you so much Arek!

>a stupid solution to a stupid problem
Yes, but I still couldn't figure it out. Is there any place I can get more experience with Cocoa in OpenGL? Or is there someone I can e-mail who would like to help me out every once in a while with my code structure and Cocoa? Just so I don't have to have multi threads and stuff. I'll look at the code tomorrow and post any questions.

Thanks,
Iceman
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #14
For others reading the thread, the crash here was because the NSTimer in the view was never being invalidated/released, and the GLView was updating some other text views in the window during its draw.

So, when the window was closed, all the other views were dealloced. But the GLView and the timer were not (because they each retain each other.) So, the timer would continue to fire, and the GLView would try to update a text view which was no longer around. Boom.

Solution: invalidate the timer in windowWillClose so it releases the GLView and everything deallocs properly after that.



Iceman: the dealloc order is a little tricky since there are so many methods flying around. But, to trace this, all I did was look at the stack frame when it crashed and saw that it was failing trying to set the NSTextView. At that point, it's a 99% chance that your pointer to the object is bad, so I looked at where the pointer is being set or dealloced. You can always NSLog(@"obj = %@", object) around any suspicious bits to see if your object is what you expect.

As for future problems, I'd probably just continue posting threads-- there's a good chance that somebody on the board has run into the same problem. There's also the cocoadev mailing list, archived on cocoa.mamasam.com. And the mac-opengl mailing list, although there is no good search interface for that one.
Quote this message in a reply
Member
Posts: 196
Joined: 2002.04
Post: #15
Wow, I almost had it too! I tried calling:
Code:
- (void)windowWillClose:(NSNotification *)aNotification
{
    [time invalidate];
    [time release];
}
In MyOGLView. I noticed that NSLog(); never called it so I thought it must be something else. The text field crash bug was the thing that got me so confused. I also didn't know how to hook up MyDocument to MyOGLView so it could call all the deallocs.

I have a few more questions about document based applications. When I use encode/decode I noticed that the file it outputs has the names of the encoded classes in my project. Could someone use this to hack my game?

Thanks,
Iceman
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Cocoa Document OpenGL App Question CarbonX 2 3,427 Dec 6, 2004 12:37 PM
Last Post: CarbonX