directional works, positional fails?

This post may be a bit longish, but it’s that way so you can have a complete program to copy/paste if you’d like to try it yourself and see if you can help.

Using SDL under linux. The following program draws coordinate axes, a single triangle in the x-z plane (y is up), with a light circling around the triangle in the x-y plane. I draw a little GL_POINT where the light is.

The problem is, as the program stands below, the little dot is only drawn the first frame. After that it’s not drawn, but everything else works fine.

If I change the last arg in the glLightfv() call (see where the // XXX is) from light_pos to light_dir, the problem goes away. (!?)

I’m using DRI/mesa, and I believe hardware acceleration is working (although, I’m not sure, and that is another post altogether).

// tiny_sdl_gl
//
// main.cpp

#include
#include

#include <gl.h>
#include <glu.h>

#include <SDL.h>
#include <SDL_video.h>

using std::exit;
using std::cout;
using std::endl;

//------------------------------
GLfloat radius = 2.5;
GLfloat light_pos = { 0.0, radius, 0.0, 1.0 }; // positional
GLfloat light_dir = { 0.0, radius, 0.0, 0.0 }; // directional
GLfloat theta = 0; // rotation of light about the z-axis.

//---------------------------------------------------------------------
void processEvents()
{
SDL_Event event;

while( SDL_PollEvent( &event ) )
{
    if ( event.type == SDL_QUIT )
    {
        cout << "quit has been requested via ctrl-c or close window"
             << endl;
        SDL_Quit();
        exit( 0 );
        break;
    }
}

}

//---------------------------------------------------------
void initSDL()
{
if ( SDL_Init( SDL_INIT_VIDEO ) != 0 )
{
cout << "couldn’t initialize SDL: " << SDL_GetError() << endl;
SDL_Quit();
exit(1);
}

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_RED_SIZE,     8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,   8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE,    8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE,   8 );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE,   24 ); // default anyway.

SDL_Surface * surf = SDL_SetVideoMode( 400, 400, 32,
    SDL_DOUBLEBUF | SDL_HWSURFACE | SDL_OPENGL );

if ( surf == NULL )
{
    cout << "unable to set video mode: " << SDL_GetError() << endl;
    SDL_Quit();
    exit(1);
}

SDL_WM_SetCaption( "sdl_ast", "sdl_ast" );

}

//---------------------------------------------------------
void initGL()
{
glPolygonMode( GL_FRONT, GL_FILL );

glShadeModel( GL_SMOOTH );

glCullFace( GL_BACK );
glEnable( GL_CULL_FACE );

glClearColor( 0.0, 0.0, 0.0, 0.0 );
glPointSize( 4.0 );
glLineWidth( 2.0 );

glEnable( GL_DEPTH_TEST );

GLfloat mat_spec[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shin = 50.0;
GLfloat mat_emerald[] = { 0.0, 0.8, 0.1, 1.0 };

GLfloat white_light[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat amb_light[] = { 0.2, 0.2, 0.2, 1.0 };

glMaterialfv( GL_FRONT, GL_SPECULAR, mat_spec );
glMaterialf( GL_FRONT, GL_SHININESS, mat_shin );
glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_emerald );

glLightfv( GL_LIGHT0, GL_AMBIENT, amb_light );
glLightfv( GL_LIGHT0, GL_DIFFUSE, white_light );
glLightfv( GL_LIGHT0, GL_SPECULAR, white_light );

glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );

glViewport( 0, 0, 400, 400 );

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 40.0, 1.0, 4.0, 16.0 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

}

//------------------------------------------------
void draw()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glPushMatrix();
    gluLookAt( 2.0, 4.0, 7.0,
               0.0, 0.0, 0.0,
               0.0, 1.0, 0.0 );

    glPushMatrix();
        glRotated( theta, 0.0, 0.0, 1.0 );
        glLightfv( GL_LIGHT0, GL_POSITION, light_pos ); // XXX

        // And then draw the dot representing the light.
        glDisable( GL_LIGHTING );
        glBegin( GL_POINTS );
            glColor3d( 1.0, 1.0, 1.0 );
            glVertex4fv( light_pos );
        glEnd();
        glEnable( GL_LIGHTING );
    glPopMatrix();

    // Draw the x y z coordinate axes.
    glDisable( GL_LIGHTING );
    glBegin( GL_LINES );
        glColor3d( 1.0, 0.0, 0.0 );
        glVertex3d( 0.0, 0.0, 0.0 );
        glVertex3d( 2.0, 0.0, 0.0 );

        glColor3d( 0.0, 1.0, 0.0 );
        glVertex3d( 0.0, 0.0, 0.0 );
        glVertex3d( 0.0, 2.0, 0.0 );

        glColor3d( 0.0, 0.0, 1.0 );
        glVertex3d( 0.0, 0.0, 0.0 );
        glVertex3d( 0.0, 0.0, 2.0 );
    glEnd();
    glEnable( GL_LIGHTING );

    // Draw a simple triangle facing up near the origin.
    glBegin( GL_TRIANGLES );
        glNormal3d( 0.0, 1.0, 0.0 ); // Normal facing up.

        // The winding is correct so the "front" is facing up,
        // in the same direction as the normal.
        glVertex3d( 0.0, 0.0, 0.0 );
        glVertex3d( 0.5, 0.0, 1.0 );
        glVertex3d( 1.0, 0.0, 0.2 );
    glEnd();
glPopMatrix();
glFinish();

}

//------------------------------------------------
int main( int argc, char * argv )
{
initSDL();
initGL();

while ( true )
{
    SDL_Delay( 500 ); // This is just here to slow things down
                      // enough to see the effect I'm asking about.
    processEvents();
    theta += 5.0;
    if ( theta > 360.0 )
    {
        theta -= 360.0;
    }
    draw();
    SDL_GL_SwapBuffers();
}

SDL_Quit();
return 0;

}

//------------------------------------------------

Does “the Problem goes away” mean that the dot is drawn when you change the argument for glLight* ?

If so, this is really strange. I would understand the error, if you exchanged the values of light_pos and light_dir entirely or used the light_dir for the glVertex call instead of light_pos.
If you don’t, then I have no idea really. I’d simply try to use glVertex3fv to see if that changed anything - you don’t need the w-coordinate I assume, but that’s just clutching at straws…

I can’t easily test it myself since I’m running a on Windows system…
Nick

Nick,

Does “the Problem goes away” mean that the dot is drawn when you change the argument for glLight* ?

Yes.

If so, this is really strange. I would understand the error, if you exchanged the values of light_pos and light_dir entirely

Huh? Not sure what you mean here.

or used the light_dir for the glVertex call instead of light_pos.

In that case, the dot doesn’t show up at all, although the lighting seems to be working as normal. I wouldn’t think it would work anyway though – the 4th coordinate is 0.

I’d simply try to use glVertex3fv to see if that changed anything - you don’t need the w-coordinate I assume, but that’s just clutching at straws…

Since I hadn’t heard back on this thread for a couple days, I posted it in the advanced forum. What you suggested above (“clutching at straws”) is what was suggested to me there – and, to my blinking amazement, it works. Please see that thread for any further discussion on this. I’d sure like to know why it matters…

Hmm very strange - I’d agreed that since the default for w is 1 anyway it doesn’t matter, but there you are…

As long as it works now?

Nick