Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

hoschi

macrumors newbie
Original poster
Sep 20, 2005
29
0
I have been using this standard code for single buffered project in Cocoa.

-(void)drawRect:(NSRect)rect
{
glClearColor( 0, 0, 0, 0 ) ;
glClear( GL_COLOR_BUFFER_BIT ) ;
glColor3f( 0.0f, 1.0f, 0.0f ) ;
glBegin( GL_TRIANGLES) ;
{
glVertex3f( ver1x, ver1y, 0.0 ) ;
glVertex3f( ver2x, ver2y, 0.0 ) ;
glVertex3f( ver3x , ver3y, 0.0 ) ;
}
glEnd() ;
glFlush();


-----
My question is how does this get modified in the case of a double buffered opengl program. Also is the call to drawRect ie [self setNeedsDisplay: YES] changed or does it remain the same..

Thanks in Advance,
Vyom
 

gekko513

macrumors 603
Oct 16, 2003
6,301
1
I would expect double buffering using OpenGL in Cocoa works the same as double buffering using OpenGL elsewhere. I'm not exactly sure how it is done, but you should be able to find some tutorials on that if you google for it.

That said, I have done a couple of Cocoa / OpenGL projects and in my case double buffering has been a non-issue since Cocoa (Aqua?) uses double buffering in itself. I think double buffering in OpenGL would make for an effective triple buffering that would degrade performance unless you can turn off the default buffering. I haven't done full screen OpenGL projects, so the situation may be different in that case.

[self setNeedsDisplay:YES] can be a bit slow if you're doing OpenGL animations. I have found that it can be faster to use something like:
[myView lockFocus];
[myView drawRect:dirtyRect];
[myView unlockFocus];
 

hoschi

macrumors newbie
Original poster
Sep 20, 2005
29
0
Fast Looping

In my case I use a "for" loop to reconstruct a triangle and then call [self setNeedsDisplay:YES] to call the drawRect back. The looping is quite fast - like 10000 steps in 10 seconds- but I only see the first and the last states... Even though I have just now modified my program to below, I do not see any intermidiate states...

-(void)drawRect:(NSRect)rect
{
glClearColor( 0, 0, 0, 0 ) ;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glColor3f( 0.0f, 1.0f, 0.0f ) ;
glBegin( GL_TRIANGLES) ;
{
glVertex3f( ver1x, ver1y, 0.0 ) ;
glVertex3f( ver2x, ver2y, 0.0 ) ;
glVertex3f( ver3x , ver3y, 0.0 ) ;
}
glEnd() ;
glFinish();
[[self openGLContext] flushBuffer] ;
}

ANy help would be highly appreciated
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,629
Western US
I think you need to make a custom pixel format in your view's init: method, like this:
Code:
- (id)initWithFrame:(NSRect)aRect {
	NSOpenGLPixelFormatAttribute attr[] = {
        NSOpenGLPFADoubleBuffer,
        0
	};
	
    // create pixel format
    NSOpenGLPixelFormat *nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];

    // create the context...
    if (!(self = [super initWithFrame:aRect pixelFormat:nsglFormat])) {
		return nil;
	}
	
    // make the context current
    [[self openGLContext] makeCurrentContext];

	// enable vertical sychronization to refresh rate
	const long vals = 0x01;
	[[self openGLContext] setValues:&vals forParameter:NSOpenGLCPSwapInterval];

	// rest of your init method ...
}
Then in your drawRect method:
Code:
- (void)drawRect:(NSRect) aRect {
	// OpenGL code here...

	glFlush();
	[[self openGLContext] flushBuffer];
}
But yeah, I haven't really noticed any tearing simply using glFlush() and no custom pixel format recently, so I'm not so sure they haven't changed it in Tiger so that double-buffering happens by default in an OpenGL view (that would kind of make more sense to me, seeing as how everything else is double-buffered by default in Cocoa).
 

gekko513

macrumors 603
Oct 16, 2003
6,301
1
I'm guessing that the problem is with the [self setNeedsDisplay:YES]. [self setNeedsDisplay:YES] just marks the view as needing do be drawn some time soon, it does not actually draw anything. Your program could mark the view as needed to be drawn 10000 times in the loop, then the loop ends and not until then is the drawing actually done.

Try to replace [self setNeedsDisplay:YES] with
[self lockFocus];
[self drawRect:[self frame]];
[self unlockFocus];

If that doesn't help, it could be that Cocoa refuses to switch buffers before the method call ends. That can be fixed by using NSTimer to schedule animation method calls. Here's one solution from developer.apple.com
Code:
- (void) startAnimationTimer
{
    if (animationTimer == nil) {
        animationTimer = [[NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES] retain];
    }
}

- (void) stopAnimationTimer
{
    if (animationTimer != nil) {
        [animationTimer invalidate];
        [animationTimer release];
        animationTimer = nil;
    }
}

- (void) animationTimerFired:(NSTimer *)timer
{
    Scene *scene = [openGLView scene];
    [scene advanceTimeBy:0.017];
    [openGLView setNeedsDisplay:YES];
}
 

hoschi

macrumors newbie
Original poster
Sep 20, 2005
29
0
NSOpenGLContext

I was looking for places which say more about NSOpenGLContext and NSOpenGLPixelFormat, but only found some text with no explained examples. DOes anyone know about tutorials online? NeHe only talks about OpenGL and given the code in Cocoa- however they barely explain what they do in the Cocoa code. Wondering if there is an alternative site.

Thanks
Vyom
 

hoschi

macrumors newbie
Original poster
Sep 20, 2005
29
0
Hi Guys:

This program still doesnt work even though I have kind of tried all the possible above mentioned suggestions. I am posting the implementation file and hope that some of you could be the saviours..

The program esentially takes a triangle and varies the coords of one of the vertices and redraws the whole thing... or should i say it "is supposed to" redraw the whole thing but hasn't been able to ..
 

Attachments

  • Triangle.txt
    2.6 KB · Views: 215

gekko513

macrumors 603
Oct 16, 2003
6,301
1
I see one possible error ...
Code:
for (i = 0; i< 10000; i++){
  ver3x = ver1x+ 0.00005;
  ver3y = ver1y - 0.00005;
  [self lockFocus];
  [self drawRect:[self frame]];
  [self unlockFocus];
  NSLog (@"Drawing in step%d", i);
}
The previous loop doesn't change the coordinates as it goes along. You would need something like the following ...
Code:
for (i = 0; i< 10000; i++){
  ver3x += 0.00005;
  ver3y -= 0.00005;
  [self lockFocus];
  [self drawRect:[self frame]];
  [self unlockFocus];
  NSLog (@"Drawing in step%d", i);
}
 

hoschi

macrumors newbie
Original poster
Sep 20, 2005
29
0
gekko513 said:
I see one possible error ...
Code:
for (i = 0; i< 10000; i++){
  ver3x = ver1x+ 0.00005;
  ver3y = ver1y - 0.00005;
  [self lockFocus];
  [self drawRect:[self frame]];
  [self unlockFocus];
  NSLog (@"Drawing in step%d", i);
}
The previous loop doesn't change the coordinates as it goes along. You would need something like the following ...
Code:
for (i = 0; i< 10000; i++){
  ver3x += 0.00005;
  ver3y -= 0.00005;
  [self lockFocus];
  [self drawRect:[self frame]];
  [self unlockFocus];
  NSLog (@"Drawing in step%d", i);
}

This really works now... thanks.. but I dont understand why a command like ver3x = ver3x - 0.0005 wouldnt work and a command like ver3x += 0.0005 would work...

Never came across such a thing in any book
 

gekko513

macrumors 603
Oct 16, 2003
6,301
1
hoschi said:
This really works now... thanks.. but I dont understand why a command like ver3x = ver3x - 0.0005 wouldnt work and a command like ver3x += 0.0005 would work...

Never came across such a thing in any book
ver3x = ver3x + 0.0005 would work just as well, but you had written ver3x = ver1x + 0.0005, probably by mistake.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.