Problems with user interaction and OpenGL

Apprentice
Posts: 7
Joined: 2008.08
Post: #1
Hey,

I’m teaching myself in Objective C in combination with OpenGL and have some displaying problems.
In my .xib file I defined a custom view, a button and a slider.
The user should be able to create an initial sphere (button) and change the radius (slider).
The action methods and the outlets are called and the values are correct, the sphere is also created, but it is not displayed.
I also called setNeedsDisplay or update after the slider changed the radius, but it doesn’t change anything.
When I initially draw a sphere it is displayed, but I can’t change the radius, again.
Did I miss something?

Thanks
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #2
Um, that's really hard to answer without some code. Maybe you never flush the buffer? Perhaps there is something wrong with your drawing code that makes your changes appear the same?
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #3
- (void)drawRect:(NSRect)rect{


[[self openGLContext] makeCurrentContext];
[[self openGLContext] update];

glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

if([m_sphereList count] !=0){

[self drawSphereList];
}

[[self openGLContext] flushBuffer];


}

-(void)drawSphereList{

int xValue, yValue, zValue;
float sphereRadius;

int i;
for(i = 0; i < [m_sphereList count] ; i++){

xValue = [[m_sphereList objectAtIndex: i] getX ];
yValue = [[m_sphereList objectAtIndex: i] getY ];
zValue = [[m_sphereList objectAtIndex: i] getZ ];
sphereRadius = [[m_sphereList objectAtIndex: i] getRadius];

glLoadIdentity();
glTranslatef(0,0,-40);

glColor3f (1.0, 0.4, 0.8);

GLUquadricObj *glu_obj;
glu_obj = gluNewQuadric();
gluSphere (glu_obj, sphereRadius, 24, 24);
gluDeleteQuadric(glu_obj);

}
}

- (IBAction)drawSphere:(id)sender{

int lengthSphereList;
lengthSphereList = [m_sphereList count];

if(lengthSphereList == 0){

[self initSphereList];

}

[self setActiveSphere:lengthSphereList];

m_tempSphere = [Sphere new];
[m_tempSphere init];

[m_sphereList addObject: m_tempSphere ];

[self setNeedsDisplay:YES];


}


So, here is some code...
The draw sphere action correspondends to the button and adds a sphere (coordinates of the center and radius) to m_sphereList.
drawRect calls drawSphereList, where it should go through all spheres and draw them.
When I initially put a spher in m_sphereList, this sphere will be displayed, but I can't change the radius with the slider.
That means, that it is not possible to actually draw the spheres in drawSphereList, am I right?


Thanks
Quote this message in a reply
Member
Posts: 245
Joined: 2005.11
Post: #4
First, if you use code tags (the # button) and use indenting it makes your code much easier read. Smile
Secondly, have you got a function which takes values from the slider and updates your sphere? If so, do you call the drawing code again afterwords?
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #5
Hey,

sorry for the last post, I'll do my best. =)

I changed drawRect into drawFrame, as you can see above, and it is called with a timer periodically. (With drawRect I hadn't access to m_sphereList when the user added spheres )
But now I'm sure that the draw methods do all have the right values and that the draw method is called after I changed something.
It is just won't draw.

Could it be that the drawFrame method does not know where to draw, after the first drawing?
I haven't got an outlet for the view, but I don't know where to integrate it.

Thanks


Code:
- (void)drawFrame{

    [[self openGLContext] makeCurrentContext];
    [[self openGLContext] update];

    glLoadIdentity();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    
    if([m_sphereList count] != 0){
    
        [self drawSphereList];
    }
    
    [[self openGLContext] flushBuffer];
    
}

-(void)drawSphereList{
    
    int xValue, yValue, zValue;
    float sphereRadius;
    
    int i;
    for(i = 0; i < [m_sphereList count] ; i++){
        
    xValue = [[m_sphereList objectAtIndex: i] getX ];                
    yValue = [[m_sphereList objectAtIndex: i] getY ];            
    zValue = [[m_sphereList objectAtIndex: i] getZ ];
    sphereRadius = [[m_sphereList objectAtIndex: i] getRadius];    

    glLoadIdentity();
    glTranslatef(0,0,-40);

    glColor3f (1.0, 0.4, 0.8);
    
    GLUquadricObj *glu_obj;
    glu_obj = gluNewQuadric();
    gluSphere (glu_obj, sphereRadius, 24, 24);
    gluDeleteQuadric(glu_obj);
    
    }
}

- (IBAction)drawSphere:(id)sender{
    
    if(m_firstSphere){
        
        [self initSphereList];
        m_firstSphere = NO;
    }

    
    int lengthSphereList;
    lengthSphereList = [m_sphereList count];

    [self setActiveSphere:lengthSphereList];
    
    m_tempSphere = [Sphere new];
    [m_tempSphere init];

    [m_sphereList addObject: m_tempSphere ];

}
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #6
That code looks fine to me. From your description of the problem it sounds like the values aren't being retrieved from the slider to update the radius. How do you have that hooked up?

Also, this may be a bit of a nit-pick, but you should probably move the line [self setActiveSphere:lengthSphereList] to the end of the drawSphere method. It may be ok now, but what if the implementation changes so that setActiveSphere needs the new sphere to exist in the list already and doesn't just store the index. Come to think of it, that may be the cause of your problem.
Quote this message in a reply
Member
Posts: 67
Joined: 2006.07
Post: #7
In light of what Blacktiger said, could you post your setActiveSphere method? I have a hunch that's where your problem might be.

Blacktiger Wrote:Also, this may be a bit of a nit-pick, but you should probably move the line [self setActiveSphere:lengthSphereList] to the end of the drawSphere method. It may be ok now, but what if the implementation changes so that setActiveSphere needs the new sphere to exist in the list already and doesn't just store the index. Come to think of it, that may be the cause of your problem.

It may be a minor issue now, but I would recommend not only putting setActiveSphere at the end of the method, but also rewriting the method call you make. Right now, you use the length of the list before the new sphere is added to identify the index of the new active sphere. Technically this is fine, since arrays are zero-based; however, the way it's written is pretty confusing at first glance (I had to think a moment before I realized what you were trying to do).

Personally, I'd write it something like this:

Code:
// ...code

[m_sphereList addObject:m_tempSphere];
[self setActiveSphere:[m_sphereList count] - 1];

This way, it makes it explicitly clear that you're setting the active sphere to the last item in the list. Plus, it might solve your problem, depending on how you wrote your setActiveSphere method.

Once again, this might be nit-picky, but trust me, writing clear code will help you a lot in the long run (and eliminate a lot frustrating, easily-preventable bugs).

Since when was "Fred" a placeholder variable?
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #8
Hello,

yes it may be a bit confusing with m_sphereList. I changed it as you said. =)
Here is my setActiveSphere method. I tested the slider changing method again and all spheres have the right value, but no sphere is displayed.

Thanks

Code:
- (void)setActiveSphere:(unsigned int) sphereIndex{
    
    m_activeSphere = sphereIndex;

    int i;
    for(i = 0; i < [m_sphereList count]; i++)
    {
        if( i != m_activeSphere){    
            
            [[m_sphereList objectAtIndex: i] setActivity:NO];
        }
    }
    
}
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #9
Hello,

here is the whole code, in case I made somewhere else a mistake. =)


Code:
@interface SeedDefinition (privatestuff)

- (void)initGL;

@end


@implementation SeedDefinition

- (id)initWithFrame:(NSRect) frameRect
{
    
    NSOpenGLPixelFormat *nsglFormat;
    NSOpenGLPixelFormatAttribute attr[] =
    {
        NSOpenGLPFAAccelerated,
        NSOpenGLPFANoRecovery,
        NSOpenGLPFADoubleBuffer,
        0    
    };
    
    [self setPostsFrameChangedNotifications: YES];

    nsglFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];

    if(!nsglFormat) { NSLog(@"Invalid format... terminating."); return nil; }
    
    self = [super initWithFrame:frameRect pixelFormat:nsglFormat];
    [nsglFormat release];

    if(!self) { NSLog(@"Self not created... terminating."); return nil; }

    [[self openGLContext] makeCurrentContext];

    [self initGL];
    return self;
}

- (void)initGL
{  

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

    glClearDepth(1.0f);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

}

- (void)awakeFromNib
{

    NSTimer *time;
    
    time = [ [NSTimer scheduledTimerWithTimeInterval: DEFAULT_TIME_INTERVAL
                                              target:self
                                            selector:@selector(drawFrame)    
                                            userInfo:nil
                                             repeats:YES]
            retain
            ];
    [[NSRunLoop currentRunLoop] addTimer: time forMode: NSEventTrackingRunLoopMode];
    [[NSRunLoop currentRunLoop] addTimer: time forMode: NSModalPanelRunLoopMode];
    
    m_sphereHit = NO;
    m_first = YES;
    m_firstSphere = YES;
    
}

- (void) reshape
{

    float aspect;
    NSSize bound = [self frame].size;
    aspect = bound.width / bound.height;
    glViewport(0, 0, bound.width, bound.height);
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)aspect, 0.1f,100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

- (void)drawFrame{

    [[self openGLContext] makeCurrentContext];
    [[self openGLContext] update];

    glLoadIdentity();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    
    if([m_sphereList count] != 0){
    
        [self drawSphereList];
    }

    [[self openGLContext] flushBuffer];
    
}

-(void)drawSphereList{
    
    int xValue, yValue, zValue;
    float sphereRadius;
    
    int i;
    for(i = 0; i < [m_sphereList count] ; i++){
            
        xValue = [[m_sphereList objectAtIndex: i] getX ];                
        yValue = [[m_sphereList objectAtIndex: i] getY ];            
        zValue = [[m_sphereList objectAtIndex: i] getZ ];
        sphereRadius = [[m_sphereList objectAtIndex: i] getRadius];    

        glLoadIdentity();
        glTranslatef(0,0,-40);
        glColor3f (1.0, 0.4, 0.8);
        
        GLUquadricObj *glu_obj;
        glu_obj = gluNewQuadric();
        gluSphere (glu_obj, sphereRadius, 24, 24);
        gluDeleteQuadric(glu_obj);
    
    }
}

- (void)initSphereList{

    m_sphereList= [[NSMutableArray alloc] init];
    
}

- (IBAction)drawSphere:(id)sender{

    if(m_firstSphere){
        
        [self initSphereList];
        m_firstSphere = NO;
    }

    m_tempSphere = [Sphere new];
    [m_tempSphere init];

    [m_sphereList addObject: m_tempSphere ];
    [self setActiveSphere:[m_sphereList count] - 1];
        
}

- (IBAction)proceed:(id)sender {
    
    NSLog( @"TODO:proceed");
}

-(IBAction)setUserRadius:(id)sender{
    
    float userRadius;
    userRadius=[radius floatValue];

    [[m_sphereList objectAtIndex: m_activeSphere] setRadius:userRadius];

}

- (unsigned int)getActiveSphere{
    
    return m_activeSphere;
}

- (void)setActiveSphere:(unsigned int) sphereIndex{
    
    m_activeSphere = sphereIndex;

    int i;
    for(i = 0; i < [m_sphereList count]; i++)
    {
        if( i != m_activeSphere){    
            
            [[m_sphereList objectAtIndex: i] setActivity:NO];
        }
    }
    
}

- (void) dealloc
{
    [m_sphereList release];
    [super dealloc];
}


- (BOOL)acceptsFirstResponder{
    
    return YES;
}
- (BOOL)becomeFirstResponder{
    
    return YES;
}

- (void)keyDown:(NSEvent *)theEvent{
    
    NSLog( @"key down" );
}

- (void)mouseUp:(NSEvent *)theEvent{

    NSLog( @"Mouse L up");    
}


- (void)rightMouseUp:(NSEvent *)theEvent
{
    NSLog( @"Mouse R up");
}

- (void)otherMouseUp:(NSEvent *)theEvent
{
    NSLog( @"Mouse O up");
}




@end
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #10
As far as I can tell, your code should work. Did you make sure that you made a connection from the slider to setUserRadius in Interface Builder? If that is ok, perhaps your sphere class doesn't properly update it's radius?

Why do you use both [Sphere new] and [m_temp_sphere init] in drawSphere? As far as I know, the new method should be equivalent to [[Sphere alloc] init].
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #11
Hey,

I added by the sphere button new spheres to my m_sphereList and changed their radius. I tested all the values and they are right. Also the drawSphereList method has these values.
I think it is not possible to draw to the view anymore. I don't know why.

But thanks.
Quote this message in a reply
Apprentice
Posts: 7
Joined: 2008.08
Post: #12
Hey,

I changed almost everything in the file. For example now I have a drawRect... Now it is working, but thanks for your try. =D
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #13
Haha, no wonder it didn't work. I totally missed that.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Speed problems in MadTak (SDL+openGL in C) Joseph Duchesne 2 2,602 Nov 4, 2004 08:13 AM
Last Post: Joseph Duchesne