[SOLVED] How to invoke display() - react on changed value

Hello Together,

this might be a stupid question but due to the fact that I am new to JOGL and 3D I hope you will forgive give me.

Imagine I have a value which is the result of a calculation in a different class.

I want to move my scene to the left every time this value (lets called it moveToLeft) changes. But since moveToLeft is not a user input ( mouse/addMouseListener() or keyboard/addKeyListener() ) I have no idea how to achieve this.

So my question is: How do I invoke the display() method which includes gl.glTranslatef(moveToLeft, 0.0f, 0.0f)?

Is it at least the right way to invoke display() directly or is there a complete different way how to achieve this? Or is there a listener which a have to add which I had overlooked?

I really appreciate any help, code fragment etc.

Thanks
Jaquelin

So all your trying to do is after a function/method call change a variable which moves your “scene” around?

I always thought Display was automaticly called every “frame”…

If your post some of your code I can help you figure out what your problem is, but you shouldn’t have to invoke display() as it’s already being invoked. Much like “paint()” of the graphics class(I think).

Calling display() causes the opengl rendering to happen (by calling any added GLEventListeners). You can use an Animator to automatically call display(), but that’s not really related to the post.

The best way of handling this is to have a main loop that renders the frame over and over. Then within your display(drawable) method, just look-up moveToLeft or other properties and change the drawing as needed. If you didn’t want to render all the time, you could have a boolean needsRender, and after calculating moveToLeft, set it to true. Then the main loop checks needsRender, and then displays everything.

IMPORTANT WARNING: display() is not the same as display(drawable). display() is a method on a GLCanvas or GLJPanel to start the rendering process. display(drawable) is part of the GLEventListener and should never be called directly because the GL object won’t be ready.

Also, it’s not advisable to render from within a mouse or key listener. It’s better to have a property that gets updated by the listener (like mouseX, mouseY, or shiftPressed=true), and then check those values as I described above.

@Cakey + Ihkbob

Thanks for your quick. Yesterday I played around the whole day with your suggestions. Everything works fine.

@ Ihkbob
I even wrote some lines with an animator. To rise my learning curve even a bit more! :smiley: :wink: → See below. Thanks for mention it.

Again, thanks you two. It helped me very much.

Jaquelin

In case someone is interested in the animator solution Ihkbob mentioned see this code. Take a look at moveToLeftAccess() and how the other two classes use this method.

My “Main-Class”


import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLJPanel;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.sun.opengl.util.FPSAnimator;

@SuppressWarnings("serial")
public class TriangleGL extends JFrame {

	//private static int DEFAULT_FPS = 80;

	private static final int JPANEL_WIDTH = 512; // initial size of panel
	private static final int JPANEL_HEIGHT = 512;
 
	private TriangleGLListener triangleGLListener;
	
	private GLJPanel jCanvas;

	private static ValueChanger valueChanger;
	
	private FPSAnimator animator;
	private static int DEFAULT_FPS = 40;
	
	private static float moveToLeft = 0;
	public static final int SET = 1;
	public static final int GET = 2;
	
	public TriangleGL() {
		
		super("Frame for my frist triangle");
		
		Container container = this.getContentPane();
		container.setLayout(new BorderLayout());
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				animator.stop();
				valueChanger.interrupt();
				System.exit(0);
			}
		});
		
		JPanel renderJPanel = makeRenderPanel();
		container.add(renderJPanel, BorderLayout.CENTER);
		
		pack();
		setVisible(true);
		
		animator.start();
		
	}
	
	public static void main(String[] args) {
		
		valueChanger = new ValueChanger();
		valueChanger.start();
		new TriangleGL();
		
	}

	private JPanel makeRenderPanel() {
	
		JPanel renderJPanel = new JPanel();
		renderJPanel.setLayout(new BorderLayout());
		renderJPanel.setPreferredSize(new Dimension(JPANEL_WIDTH, JPANEL_HEIGHT));
		
		GLCapabilities glCapabilities = new GLCapabilities();
		glCapabilities.setAlphaBits(8);
		jCanvas = new GLJPanel(glCapabilities);
		
		triangleGLListener = new TriangleGLListener(this);
		jCanvas.addGLEventListener(triangleGLListener);
		
		animator = new FPSAnimator(jCanvas, DEFAULT_FPS, true);
		
		renderJPanel.add(jCanvas, BorderLayout.CENTER);
		
		return renderJPanel;
		
	}
	
	/**
	 * Thread-save method to read and write moveToLeft
	 * 
	 * @param mode GET or SET value
	 * @param newValue New value.
	 * @return
	 */
	public static synchronized float moveToLeftAccess(int mode, float newValue) {
		
		switch(mode) {
		
		case (SET):
			moveToLeft = newValue;
			break;
		
		case (GET):
			// return value at end of method (see below)
			break;
		}
		
		return moveToLeft;
		
	}
		
}

My GLListener implementation:


import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

public class TriangleGLListener implements GLEventListener {

	private GLU glu;

	public TriangleGLListener(TriangleGL triangle) {

	}

	// ----------------- listener callbacks -----------------------------

	public void display(GLAutoDrawable drawable) {

		// System.out.println("display called");

		GL gl = drawable.getGL();

		// Clear screen and depth buffer
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

		// Reset view (x = 0, y = 0, z = 0)
		gl.glLoadIdentity();

		// Move view - C A L L moveToLeftAccess()!!!
		gl.glTranslatef(TriangleGL.moveToLeftAccess(TriangleGL.GET, 0.0f), 0.0f, -6.0f);

		gl.glBegin(GL.GL_TRIANGLES);
		gl.glVertex3f(0.0f, 1.5f, 0.0f); // Top
		gl.glVertex3f(-1.0f, 0.0f, 0.0f); // Bottom Left
		gl.glVertex3f(1.0f, 0.0f, 0.0f); // Bottom Right
		gl.glEnd();

		gl.glFlush();

	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int width,
			int height) {

		// System.out.println("reshape called");

		GL gl = drawable.getGL();

		// To avoid division by 0 in aspect ration below (gluPerspective()).
		if (height == 0)
			height = 1;

		// Resizes the current viewport
		gl.glViewport(x, y, width, height);

		// Select the projection matrix
		gl.glMatrixMode(GL.GL_PROJECTION);
		// Reset the projection matrix
		gl.glLoadIdentity();

		glu.gluPerspective(45.0f, (float) width / (float) height, 0.1f, 100.0f);

		// Select the ModelView Matrix
		gl.glMatrixMode(GL.GL_MODELVIEW);
		// Reset the ModelView Matrix
		gl.glLoadIdentity();

	}

	public void init(GLAutoDrawable drawable) {

		// System.out.println("init called");

		// don't make this gl a global!
		GL gl = drawable.getGL();

		// this is okay as a global, but only use in callbacks
		glu = new GLU();

		// Enables Smooth Shading
		gl.glShadeModel(GL.GL_SMOOTH);

		gl.glEnable(GL.GL_DEPTH_TEST);

	}

	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
			boolean deviceChanged) {
		// not implemented yet.
	}

}

This class simulates my class which actually calculates some stuff on which changeToLeft depends.


public class ValueChanger extends Thread {

	private float moveToLeftInternal;
	
	public ValueChanger() {
		moveToLeftInternal = 0;
	}
	
	public void run() {
		
		while(true) {
			if(isInterrupted()) {
				break;
			}
			changeMoveToLeft();
		}
		
	}
	
	public void changeMoveToLeft() {
		
		if(moveToLeftInternal > -2.0f) {
			moveToLeftInternal = moveToLeftInternal - 0.1f;
		} else {
			// reset value
			moveToLeftInternal = 0;
		}
		TriangleGL.moveToLeftAccess(TriangleGL.SET, moveToLeftInternal);
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException ie) {
			interrupt();
		}
	}

}

Nicely structured code, also thanks for sharing your solution rather then just saying you figured it out :smiley:

you can also perform active rendering and call display whenever you need