// This class will be the interface to Jogl.  It implements GLEventListener, sets up
// the capabilities, provides an interface for other threads to request a display()
// call to a given callback method, and lets the display() allow the AWT thread to
// tell the rendering thread to request a display(), or if the rendering thread is
// current, calls that threads callback.

package JoglTestApp;

import java.awt.*;
import net.java.games.jogl.*;

public class JoglObj implements GLEventListener {
    
    private JoglPanel _parent;
    private GLCanvas _canvas;
    private GL _gl;
    private JoglCallback _joglCallback;
    private Thread _callingThread;

    // This interface allows an object on another thread to request being called
    // back on a display().
    public interface JoglCallback {
        public void joglCallback();
    }
    
    public JoglObj(JoglPanel parent) {
        _parent = parent;
        
        GLCapabilities glC = new GLCapabilities();
        glC.setAccumRedBits(16);
        glC.setAccumGreenBits(16);
        glC.setAccumBlueBits(16);
        _canvas = GLDrawableFactory.getFactory().createGLCanvas(glC);
        
        // Can use DebugGL or TraceGL to debug.
        //_canvas.setGL(new TraceGL(_canvas.getGL(), System.err));
        _canvas.setGL(new DebugGL(_canvas.getGL()));
        _canvas.addGLEventListener(this);
    }

    // Returns the GL interface so an object can make OpenGL calls.   
    public GL getGL() {
        return _gl;
    }
    
    // Returns the GLCanvas as a component (to add it to a parent, for example).
    public Component getCanvas() {
        return _canvas;
    }

    
    //// GLEventListener interface
    
    public void init(GLDrawable drawable) {
        _gl = drawable.getGL();
    }
    
    // The display method will either call its parent's startPicture() method,
    // or, if a callback has been specified, will call that callback.
    public void display(GLDrawable drawable) {
        Thread thread = Thread.currentThread();
        System.err.println("enter display()   thread: " + thread);
        
        GLCanvas canvas = (GLCanvas) drawable;
        
        if (_joglCallback != null && thread == _callingThread) {
            System.err.println("before callback  err " + _gl.glGetError());
            _joglCallback.joglCallback();
            System.err.println("after callback  err " + _gl.glGetError());
        }
        else {
            System.err.println("before startPicture  err " + _gl.glGetError());
            _parent.startPicture();
            System.err.println("after startPicture  err " + _gl.glGetError());
        }

        System.err.println("leave display()   thread: " + thread);
    }
    
    public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {
        // Unimplemented in Jogl
    }
    
    public void reshape(GLDrawable drawable, int x, int y, int width, int height) {
        // The Jogl User's Guide says we don't need to do anything in reshape for GLCanvas.
    }
    
    // Calls display, with the joglCallback() method of the specified object being
    // called instead of the parent's startPicture() method.
    public void renderJogl(JoglCallback joglCallback) {
        Thread thread = Thread.currentThread();
        
        // Try to prevent hangs--threads were locking between GLContext and the rendering thread.
        // However, when I use these (and the opposite lines below) are included, the
        // Feb 4 nightly build fails.
        _canvas.setNoAutoRedrawMode(true);
        _canvas.setRenderingThread(thread);

        _callingThread = thread;
        _joglCallback = joglCallback;
    
        _canvas.display();
        
        _callingThread = null;
        _joglCallback = null;

        // Comment out or include these files with their opposites above.
        _canvas.setRenderingThread(null);
        _canvas.setNoAutoRedrawMode(false);
    }
}
