[SOLVED] Exception implementing VBOs outside init() and triggered by user

Hi guys,

I had my program working with VBOs, but then I had to change the general structure, create additional classes and make everything cleaner, ect…

But when I finished it was not working any more…

Here the basic:

public class Test extends javax.swing.JFrame {

    private Viewer viewer=null;
    ArrayList<Triangle> sectionPointsArray;
    ArrayList<LightBulb> lightBulbs = new ArrayList<LightBulb>();
    ArrayList<Plane> planes = new ArrayList<Plane>();
   
    public Test() {
        initComponents();
        
        DataModelViewer.testclass = this;
        
        this.setSize(800, 800);
        viewer = new Viewer();
        DataModelViewer.viewer = viewer;
      
        this.getContentPane().add(viewer,BorderLayout.CENTER);
       
    }
                    
    private void initComponents() {

        fileChooser = new javax.swing.JFileChooser();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        button_load = new javax.swing.JMenuItem();
        button_calc = new javax.swing.JMenuItem();
        button_exit = new javax.swing.JMenuItem();

        fileChooser.setDialogTitle("Choose a stl file..");
        fileChooser.setFileFilter(new StlFilter());

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jMenu1.setText("Process");

        button_load.setText("Load Model");
        button_load.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_loadActionPerformed(evt);
            }
        });
        jMenu1.add(button_load);

        button_calc.setText("Calculate");
        button_calc.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_calcActionPerformed(evt);
            }
        });
        jMenu1.add(button_calc);

        button_exit.setText("Exit");
        button_exit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                button_exitActionPerformed(evt);
            }
        });
        jMenu1.add(button_exit);

        jMenuBar1.add(jMenu1);

        setJMenuBar(jMenuBar1);

        pack();
    }                    

    private void button_loadActionPerformed(java.awt.event.ActionEvent evt) {                                            
        int returnVal = fileChooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            System.out.println(file.getAbsolutePath());
             System.out.println("Loading model.");
            LoadSTL loadSTL = new LoadSTL(file, DataModelViewer.array);
           System.out.println("Loading model finished.");
            viewer.loadModel(DataModelViewer.gl);
            
        } 
        else {
            System.out.println("File access cancelled by user.");
        }
    }      
}                                     

public class Viewer extends JPanel implements GLEventListener, MouseListener, 
                            MouseMotionListener, MouseWheelListener, KeyListener {

int nbVBO = 1;
    int[] VBO = new int[nbVBO];

public Viewer ()   {
        
        initDisplay();
        initFlags();
    }
    
    private void initDisplay() {
        
        glProfile = GLProfile.get(GLProfile.GL2);
        final GLCapabilities glCapabilities = new GLCapabilities(glProfile);
                
         // Initialize the GL component
        GLCanvas glComponent = new GLCanvas(glCapabilities);
        this.gLCanvas = glComponent;
        
        this.setLayout(new BorderLayout());
        gLCanvas.setPreferredSize(new Dimension(this.getWidth(),this.getHeight()));
        gLCanvas.setBackground(Color.RED);
        this.add(gLCanvas, BorderLayout.CENTER);
        gLCanvas.requestFocus();
           
        gLCanvas.addGLEventListener(this);
        gLCanvas.addMouseListener(this);
        gLCanvas.addMouseMotionListener(this);
        gLCanvas.addMouseWheelListener(this);
        gLCanvas.addKeyListener(this);	
    }

 @Override
    public void init(GLAutoDrawable gLAutoDrawable) {
        System.out.println("Init");

        currentRotation = identity();

        // Create and start the animator
        animator = new Animator(gLCanvas);
        //animator.setRunAsFastAsPossible(true);
        animator.start();

        // Perform the default GL initialization 
        GL2 gl = gLAutoDrawable.getGL().getGL2();
        DataModelViewer.gl = gl;
        
        loadFloorTexture(gl);
        
        
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
        
        gl.glClearColor(0.17f, 0.65f, 0.92f, 0.0f); // light blue 
    }

@Override
    public void display(GLAutoDrawable gLAutoDrawable) {
        
        GL2 gl = gLAutoDrawable.getGL().getGL2();
        
        if ( switchableFlags.get("lighting").getFlag() )
            gl.glEnable(GL2.GL_LIGHTING);
	else 
            gl.glDisable(GL2.GL_LIGHTING);
	
        if ( switchableFlags.get("smoothing").getFlag() ) 
            gl.glShadeModel(GL2.GL_SMOOTH);
	else 
            gl.glShadeModel(GL2.GL_FLAT);	

        if ( switchableFlags.get("color").getFlag() ) 
            gl.glEnable(GL2.GL_COLOR_MATERIAL);
	else 
            gl.glDisable(GL2.GL_COLOR_MATERIAL);
	
        //  set modelview Matrix
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        
        // clear color and depth buffers (faster than doing separately)
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
        
        gl.glLoadIdentity();
        
        gl.glMultMatrixf(currentRotation, 0);
              
        gl.glTranslatef((float)translationX/20.0f, (float)translationY/20.0f, 0);
        gl.glScalef(scale%10.0f, scale%10.0f, scale%10.0f);
       
        gl.glMatrixMode(GL2.GL_PROJECTION);
        
        if(isThereModel)    {
            gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
            
            //  select buffer and specify its format
            gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, VBO[0]);
            gl.glVertexPointer(3, GL2.GL_FLOAT, 0, 0);

            gl.glColor3f(0.0f, 0.0f, 0.0f);

            gl.glDrawArrays(GL2.GL_TRIANGLES, 0, triangleNumber*3);

            gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
        }
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
        
        renderLightSource(gl);
        
        drawFloor(gl);
}

 private void initVertexArray(GL2 gl)    {
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
      
      gl.glGenBuffers(1, VBO, 0);

      gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, VBO[0]);
      
      gl.glBufferData(GL2.GL_ARRAY_BUFFER, triangleNumber*3*3, vertexData, GL2.GL_STATIC_DRAW);
      
      gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
}

And this is still the error I get:

[quote]Exception in thread “AWT-EventQueue-0-AWTAnimator-1” javax.media.opengl.GLException: javax.media.opengl.GLException: array vertex_buffer_object must be enabled to call this method
at jogamp.opengl.awt.AWTThreadingPlugin.invokeOnOpenGLThread(AWTThreadingPlugin.java:98)
at jogamp.opengl.ThreadingImpl.invokeOnOpenGLThread(ThreadingImpl.java:197)
at javax.media.opengl.Threading.invokeOnOpenGLThread(Threading.java:164)
at javax.media.opengl.awt.GLCanvas.maybeDoSingleThreadedWorkaround(GLCanvas.java:830)
at javax.media.opengl.awt.GLCanvas.display(GLCanvas.java:419)
at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:74)
at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:142)
at com.jogamp.opengl.util.Animator$MainLoop.run(Animator.java:176)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.media.opengl.GLException: array vertex_buffer_object must be enabled to call this method
at jogamp.opengl.gl4.GL4bcImpl.checkBufferObject(GL4bcImpl.java:32025)
at jogamp.opengl.gl4.GL4bcImpl.checkArrayVBOEnabled(GL4bcImpl.java:32052)
at jogamp.opengl.gl4.GL4bcImpl.glVertexPointer(GL4bcImpl.java:31004)
at cuda.Viewer.display(Viewer.java:333)
at jogamp.opengl.GLDrawableHelper.displayImpl(GLDrawableHelper.java:182)
at jogamp.opengl.GLDrawableHelper.display(GLDrawableHelper.java:170)
at javax.media.opengl.awt.GLCanvas$DisplayAction.run(GLCanvas.java:939)
at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:398)
at javax.media.opengl.awt.GLCanvas$DisplayOnEventDispatchThreadAction.run(GLCanvas.java:956)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:241)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:705)
at java.awt.EventQueue.access$000(EventQueue.java:101)
at java.awt.EventQueue$3.run(EventQueue.java:666)
at java.awt.EventQueue$3.run(EventQueue.java:664)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:675)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
[/quote]
My specs are: Win7 64bit, 4gb, 560 Ti (285.62)
The code is JOGL in Netbeans. I am using OpenGL 2.0.

Hi

Something disables VBO before you call glVertexPointer. I don’t see anything obvious in your code.

Please find an example here:
http://tuer.svn.sourceforge.net/viewvc/tuer/alpha/drawer/StaticVertexBufferObject.java?revision=387&view=markup

Edit.: I don’t see any call to glGenBuffers in your source code :frowning:

Hi gouessej,

Ok, I added, but I still get the error…

I also tried with glBegin/glEnd and Vertex Array and I didnt encounter any problem…

Is it right to enable GL_Vertex_array only when I need (and disable just after)? or should I keep it always on?

Can I safely declare the gl as public variable instead passing it to each function that needs it?

It is funny, look, I modified the following:

private void initVertexArray()    {
      
      vertexData = GLBuffers.newDirectFloatBuffer(9);
      vertexData.put(new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f});
      vertexData.flip();
      
      gl.glGenBuffers(1, VBO, 0);
      
      gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
            
      gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, VBO[0]);
      
      gl.glBufferData(GL2.GL_ARRAY_BUFFER, 36, vertexData, GL2.GL_STATIC_DRAW);
      
      gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
      
      gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
    }

If I call the initVertexArray from the init(), no problem, the triangle get rendered.

But if I call it when the user performs some action, then I get the exception…

O_o

gl.glEnableClientState(…) is used to tell gl.glDrawArrays(…) or glDrawElements(…) which values it should read from gl****Pointer(…) or from VBOs. It has nothing to do with creating or uploading data to a VBO. Instead you need to use gl.glEnableClientState(…) before your draw command. You can then use gl.glDisableClientState(…) to avoid leaking OpenGL state if you draw other stuff later.

Ah ok, so I can eliminate the 2 calls to enable and disable the GL_Vertex_Array in the creation and data upload…

But for the draw command everything then looks right…

However, how could you explain the fact that calling if I call the initVertexArray from the init() everything works like a charm, but if I do from a triggered event I get an exception? I dont know, but I would say that the code lines about the VBO withing the initVertexArray() have no effect when I dont call it from the init()…

I haven’t looked at your code, but OpenGL commands can only be called from a single thread, the thread owning the context. If your event is being processed on a different thread it would be an illegal command to call any OpenGL functions.

I managed to make it work, I moved the initVertexArray() call in the display():

if(initialize) {
            initVertexArray();
            initialize = false;
        }

In this way the call takes place within the same class

I ended up that the error was because I was calling

public void loadModel() {
        
        System.out.println("BLA1");
        initVertexArray();
        System.out.println("BLA2");
        //initNormalArray();
        
        isThereModel = true;
    }

from another class (but I am pretty sure always within the same thread

No, please never do that. As someone else said, use GL only on the rendering thread and when the context is current, your OpenGL calls have to be done from a JOGL callback, for example in the display() method of your GLEventListener. You should look at the Red Book and the “man” when you don’t know how to use some OpenGL calls. Good luck.

Ok, thanks gouessej (and also theagentd) :wink:

I forgot to explain to you something. The GL instance might become invalid between several passes, that is why storing such an instance is a bad idea. Best regards.

Yep, you are right, indeed I just saw with the gDebugger that during my application up to 8 context are created/destroyed

Actually, GL is not an OpenGL context, several GL instances might be used at runtime with a single real OpenGL context.