Render manually instead of using Animator

Hello,

I want my scene only to be redrawn after modifications.
So I thought of discarding Animator (which is used now) and trigger repaint manually.

Where do I find appropiate information?
Which method do I have to call, when and from which thread?
Which details do I have to take care of or keep in mind? (thread context etc.)

Thx for your help in advance and best regards

Martin

If you are doing your rendering using the GLEventListener mechanism, you can just call display on your GLCanvas or GLJPanel. AFAIK you can call display() from any thread, but I am not sure.

Hello, It is possible to replace Animator, you have to be careful with threads but the only things to do is calling display (the GLJPanel takes care of calling init method first, you don’t have to call it yourself).

I use Executors, very powerful Threads manipulations which lets you create Scheduling capabilities when using ScheduledExecutorService :


ScheduledExecutorService autoDisplayExecutor = Executors.newSingleThreadScheduledExecutor();
autoDisplayExecutor.scheduleWithFixedDelay(displayRunnable, 0, 22, TimeUnit.MILLISECONDS);

This code will call a Runnable in a SingleThread every 22 Milliseconds (approximately 30 fps). If the treatment of displayRunnable is longer, the next call will be differed. This is exactly the same behaviour of the FPSAnimator, it tries to keep a level of FPS.

Here you have the runnable


Runnable displayRunnable = new Runnable() 
{
	public void run()
	{ 
		gljpanel.display();
	}
};

If you want a normal Animator and not a FPSAnimator you could simply use an ExecutorService.

With this scheduleexecutor you can execute other Runnable in the queue like this

autoDisplayExecutor.execute(reinitBufferRunnable);

The Executor will assure the thread safety, it will not execute displayRunnable until reinitBufferRunnable has done.

Replacing the Animator isn’t at all difficult: it’s just a thread where the OpenGL context is current and continuously calls the rendering methods of your app (which if you’ve been using the GLEventListener stuff is the display() method).

Hi,
I see another way to easily do what you want. Just look at the code of the Animator or FPS Animator, you can create your own Animator in which a flag will indicate if a redraw is needed. It seems to me that this is the easiest way if you already rely on the animator.
In fact all the answer you got are quite the same, it’s just a matter of design of your application…

Thanks to you all for your immediate help!

Finally I solved it this way:


public class Displayer 
implements Runnable {
    
    protected GLAutoDrawable drawable;
    protected ArrayBlockingQueue<EventObject> eventQueue;
    protected boolean shouldStop;
    protected Thread thread;
    
    /** Creates a new instance of Displayer */
    public Displayer(GLAutoDrawable drawable) {
        this.drawable = drawable;
        this.eventQueue = new ArrayBlockingQueue<EventObject>(20, true);
        this.shouldStop = false;
    }
    
    public void requestDisplay() {
        eventQueue.offer( new EventObject( this ) );
    }
    
    public void start() {
        thread = new Thread( this );
        thread.start();
    }

    public void run() {
        System.out.println("Displayer running");
        while ( !shouldStop ) {
            try {
                eventQueue.take(); // block here until new event is available
                // System.out.println("Repaint request received");
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            // if event is available, then display our scene
            drawable.display();
        }
    }
}

The display waits as long as no new events are availble. If events are available, it triggers display()

Best regards

Martin

you may try something like that to make active rendering without GLEventListener:

Render class:


import java.awt.*;
import java.awt.event.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;

public final class RenderJOGL 
{	
	private GLContext context;
	private GLCanvas canvas;
	private GL gl;
	private GLU glu;

	public Canvas getCanvas()
	{
		return this.canvas;
	}
	
	public RenderJOGL() throws Throwable
	{
		GLCapabilities glCaps = new GLCapabilities();	
		glCaps.setRedBits(8);
		glCaps.setBlueBits(8);
		glCaps.setGreenBits(8);
		glCaps.setAlphaBits(8);
		glCaps.setDoubleBuffered(true);
		glCaps.setHardwareAccelerated(true);

		this.canvas = new GLCanvas(glCaps);
		this.canvas.setAutoSwapBufferMode(false);
		this.glu=new GLU();

		this.context=this.canvas.getContext();
		this.gl = this.context.getGL();
	}
	
	public void setSize(int viewPixelWidth,int viewPixelHeight)//,int maxAntialias)
	{
		this.canvas.setSize(viewPixelWidth,viewPixelHeight);
	}		
	
	public void render()
	{	
		this.makeContentCurrent();

		this.gl.glDisable(GL.GL_DEPTH_TEST);
		gl.glClearColor(0.0f,0.0f,1.0f,0.0f);	//Background blue
        		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        		gl.glLoadIdentity();	
        		gl.glColor3f(1.0f, 0.0f, 0.0f);	//Color red
        		gl.glBegin(GL.GL_TRIANGLES);
        		gl.glVertex3f(0,0,0.0f);
        		gl.glVertex3f(1,0,0.0f);
        		gl.glVertex3f(0,1,0.0f);        
        		gl.glEnd();	

        		this.context.release();
		this.canvas.swapBuffers();
	}
	
	private void makeContentCurrent()
	{	
		try 
		{
			while (context.makeCurrent() == GLContext.CONTEXT_NOT_CURRENT) 
			{
				System.out.println("Context not yet current...");
				Thread.sleep(100);
			}
		}
		catch (InterruptedException e)
		{
			 e.printStackTrace(); 
		}
	} 			
}

AppletTest class:

 
import java.awt.*;
import java.applet.*;
import java.io.*;
import java.awt.event.*;

public class AppletTest extends Applet implements Runnable
{
	private int nbloop;
	private RenderJOGL render;
    
	private long startTime;
	private Thread process;
	private int nbStart;
	

	public void init() 
	{
		this.nbStart=0;
	}
	
	public void start() 
	{
		//Ensure that start is only called once
		if(this.nbStart!=0)
			return;
		this.nbStart++;
		
		this.render=new RenderJOGL();		
		
		//Add Render canvas to this applet
		this.setLayout(null);
		Canvas canvas=this.render.getCanvas();
		this.add(canvas);
		this.render.setSize(this.getWidth(),this.getHeight());
		
		//Start rendering Thread
		this.process=new Thread(this);
		this.process.start();
	}
	
	public void run()
	{
		try
		{
			while(true)
			{
				this.render.render(); 
				Thread.sleep(10);
			}
		}
		catch(InterruptedException ie)
		{
		}
	}
		
}

EDIT: Maybe you will have some few modifications to make it works properly, as it is a Class comming from 3DzzD API, simplified for a better understanding, so I havn’t tested it…

let me know if it helps!