GLAutoDrawable JavaNULLPointerException

hi all i had a question about the GLAutoDrawable. i have multiple .java files that draw various things through opengl and i just call them from the main program.

when i tried to create a new GL variable, say GL gl = drawable.getGL() where drawable is a global private variable declared in that class i kept getting a JavaNULLPointerException. the only way i got it to work was to pass along the drawable variable from the main program. did i just do it the wrong way or is there something that i was missing. it looks tacky sending drawable in all my function calls that exist in other classes to do the necessary rendering that i need is why i am asking. thanks!!


public class Java1
{
   GLAutoDrawable drawable;
   GL gl;

   public Java1
   {
    gl = drawable.getGL();  //error @ runtime - JavaNULLPointerException

   }
}


#import Java1;

public class MainProgram
{
  
  Java1 test = new Java1();
.....
.....

}



Two things:
In your Java1 constructor, you’ve never initialized your drawable variable, that’s what’s generating the NullPointerException.
Also, you’re not using the JOGL in the safest manner. It is much better to use the GLEventListener interface, and add the listener to your GLCanvas or GLJPanel. When you display the canvas, by using an Animator, or by calling drawable.display() yourself, the event listener’s display(drawable) method is called. From there you will get a valid GL object. GL objects should only be used when the opengl context is current on the thread, which is what the event listener interface guarantees for you.

well i purposely didn’t put my whole code in , but while we are at it you can let me know if this is indeed ok to do, how i have things set up:

//rendering tools
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.GLUT;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

//opengl functionality 
import javax.media.opengl.*;
import javax.media.opengl.glu.*;

//key and mouse events
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.util.Properties;
import java.lang.String;

public class TestGL implements GLEventListener, KeyListener, MouseListener, MouseMotionListener 
{

    private GLCanvas canvas;
    private Frame frame;
    private GLUT myglut;
    private Animator anim;

    private float mouse_start_x;
    private float mouse_start_y;
    private float mouse_current_x;
    private float mouse_current_y;

    boolean is_dragging;


    Grid mygrid; 
    /**this is the main class constructor**/

    public TestGL()
    {
        frame = new Frame("Testing a JOGL Application");
        myglut = new GLUT();
        mygrid = new Grid();

        is_dragging = false;

        canvas = new GLCanvas(); 
        canvas.addGLEventListener(this);
        canvas.addGLEventListener(this);
        canvas.addKeyListener(this);
        canvas.addMouseListener(this);
        canvas.addMouseMotionListener(this);
        
        frame.add(canvas);
        frame.setSize(640, 480);
        anim = new Animator(canvas);
    
        frame.addWindowListener(new WindowAdapter() 
         {

            public void windowClosing(WindowEvent e) 
            {
                new Thread(new Runnable() 
                  {

                     public void run() 
                      {
                         anim.stop();
                         System.exit(0);
                      }
                  }).start();
            
            }
         });

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        anim.start();

    }
    /**initialize some basic opengl states */
    public void init(GLAutoDrawable drawable) 
    {
  
        GL gl = drawable.getGL();
        //System.err.println("INIT GL IS: " + gl.getClass().getName());
        // Enable VSync
        gl.setSwapInterval(1);
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glClearDepth(1.0); 
    }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) 
    {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        if (height <= 0)
           height = 1;
        
        final float h = (float) width / (float) height;
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 1.0, 20.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void keyPressed(KeyEvent e)
    {
    //      System.out.println("key pressed");
    
     switch(e.getKeyCode())
     {
      case KeyEvent.VK_ESCAPE:
          System.out.println("escape was pressed");
          System.exit(0);
      break;
     }

    }

    public void keyReleased(KeyEvent e)
    {}

    public void keyTyped(KeyEvent e)
    {}

    public void mouseExited(MouseEvent e)
    {}

    public void mouseReleased(MouseEvent e)
    {
      is_dragging = false;
    }

    public void mousePressed(MouseEvent e)
    {
      mouse_start_x = e.getX();
      mouse_start_y = e.getY(); 
    }

    public void mouseClicked(MouseEvent e)
    {
      //System.out.println("mouse clicked: " + e.getX() + "," + e.getY());
    
    }

    public void mouseMoved(MouseEvent e)
    {}

    public void mouseEntered(MouseEvent e)
    {}

    public void mouseDragged(MouseEvent e)
    {
      is_dragging = true;
      mouse_current_x = e.getX();
      mouse_current_y = e.getY();      
    
      mygrid.set_mouse_coords(mouse_start_x, mouse_start_y, mouse_current_x, mouse_current_y);
    }

    public void display(GLAutoDrawable drawable) 
    {
        GL gl = drawable.getGL();
        GLUT myglut = new GLUT();

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();

        if(is_dragging)
           mygrid.draw_border(drawable);
        else
        {
           mygrid.draw_border(drawable);
           mygrid.draw_grid(5, 1, drawable);
        }

        gl.glFlush();
    }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) 
    {
    }
    
    
    public static void main(String[] args) 
    {
        new TestGL();
    }
}

//in draw border function in java grid class
public class Grid
{
  private GL gl;
  private GLAutoDrawable drawable;

  //constructor
  public class Grid
  {
    gl  = drawable.getGL(); /** this is where i get the null pointer exception, this is called when TestGL instantiates it(of course)
  }
  
  public void draw_border(GLAutoDrawable drawable)
    {
      GL gl = drawable.getGL();
    
     if(is_border_valid())
      {
        gl.glPushMatrix();

         proj.setOrthoProj(drawable);
          gl.glColor3f(1, 0, 0);
         
          gl.glBegin(gl.GL_LINE_LOOP);

            gl.glVertex2f(mouse.start_x, mouse.current_y);
            gl.glVertex2f(mouse.start_x, mouse.start_y);
            gl.glVertex2f(mouse.current_x, mouse.start_y);
            gl.glVertex2f(mouse.current_x, mouse.current_y);

          gl.glEnd();

         proj.resetPerspProj(drawable);
       
        gl.glPopMatrix();
      }
  }
}

if i didnt send in drawable from main and declared my own variable at the top(as i have between the asterisks) it would crash with the null exception when the class is instantiated. the way i have it now works but i was wondering why i couldnt just make my own local drawable variable. thanks Ihkbob!

//constructor
  public class Grid
  {
    gl  = drawable.getGL(); /** this is where i get the null pointer exception, this is called when TestGL instantiates it(of course)
  }

If this isn’t the exact code that was failing, then you can ignore me. Otherwise, the reason that there was the null pointer exception was that the variable, drawable, was never instanciated. In the Grid object, at the time of construction, it’s set to null since you haven’t set it to anything else. When you call getGL() on it, the null pointer exception occurs. Except for that constructor issue, which it sounds like you’ve taken out anyway, the rest of your code looks fine.

Object variables in java are always references, so you have to assign an object to them before you use them or you have an “empty” reference with a NULL pointer. You can’t implicitely instanciate an object with the variable declaration in java like you can (if I remember correctly) do in C++. Maybe that’s the cause of your confusion.

i understand what you are saying but in the main program, in the basic callbacks for example drawable is never instantiated. its just declared as type GLAutoDrawable in the parameter list…i.e. reshape and init. all i did in Grid was do the same and set it to a private variable. thats why i was confused as to why it wasnt working. where in the main program does drawable get instantiated because i dont see it.

Like you said, the init and reshape methods are callbacks which are called by the JOGL framework internally. JOGL does have an instance and passes it to the methods per reference.

i gotcha. thanks for the info. i will try to instantiate them separately in the classes i guess then.

A Drawable is an interface and cannot be instanciated directly. It’s no good idea to fight the GLEventListener mechanism - you will get in trouble. Just do all your work in the init(), display() and reshape() methods and pass the GL instance (or the drawable) to the methods that needs it. Don’t store the gl instance, because chances are, that it will get invalid or at least cannot be used because of the gl context not being current. If you need to react to something like a keypress, set a flag and do the desired action next time display() is called.

ok thanks for your help with this and tips. i will just pass along the instance of the drawable when i need it.