Hi,
I’m new to JOGL, and I’m looking for some guidance on drawing 2d textures. I’ve built an app to display a background image that shifts as you approach the edges. My code’s working, but the shifting isn’t so smooth; occasionally you see jumps. Am I following the right approach in drawing my image?
The texture rendering:
gl.glEnable(GL.GL_TEXTURE_2D);
backgroundImage.bind();
// replace the quad colours with the texture
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
gl.glBegin(GL.GL_QUADS); {
gl.glTexCoord2f(newLft, newTop);
gl.glVertex2f(verLft, verTop);
gl.glTexCoord2f(newRit, newTop);
gl.glVertex2f(verRit, verTop);
gl.glTexCoord2f(newRit, newBtm);
gl.glVertex2f(verRit, verBtm);
gl.glTexCoord2f(newLft, newBtm);
gl.glVertex2f(verLft, verBtm);
}
gl.glEnd();
gl.glDisable(GL.GL_TEXTURE_2D);
// switch back to modulation of quad colours and texture
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_MODULATE);
And my test application:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.net.*;
import javax.media.opengl.*;
import com.sun.opengl.util.*;
import com.sun.opengl.util.texture.*;
public class JOGLTest {
public static final Dimension BK_SIZE = new Dimension(1459, 1100);
public static final Dimension VIEW_SIZE = new Dimension(300, 300);
public static final Dimension FRAME_SIZE = new Dimension(600, 600);
public static void main(String[] args) {
final Frame f = new Frame();
f.setSize(FRAME_SIZE);
f.setMinimumSize(FRAME_SIZE);
f.setLayout(null);
GLCapabilities glCaps = new GLCapabilities();
glCaps.setDoubleBuffered(true);
glCaps.setHardwareAccelerated(true);
glCaps.setRedBits(8);
glCaps.setBlueBits(8);
glCaps.setGreenBits(8);
glCaps.setAlphaBits(8);
MapCanvas panel = new MapCanvas(glCaps, VIEW_SIZE);
panel.setSize(VIEW_SIZE);
panel.setMinimumSize(VIEW_SIZE);
panel.setMaximumSize(VIEW_SIZE);
panel.setBounds(new Rectangle(new Point(150,150), VIEW_SIZE));
final Animator animator = new Animator(panel);
f.add(panel);
f.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) { }
public void windowClosed(WindowEvent e) {
animator.stop();
f.dispose();
System.exit(0);
}
public void windowClosing(WindowEvent e) {
animator.stop();
f.dispose();
System.exit(0);
}
public void windowDeactivated(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowOpened(WindowEvent e) { }
});
f.setVisible(true);
animator.start();
}
}
class MapCanvas extends GLCanvas {
private Dimension viewSize;
public MapCanvas(final GLCapabilities c, final Dimension s) {
super(c);
viewSize = s;
super.addGLEventListener(new MapCanvasListener(this));
}
public Dimension getViewSize() { return viewSize; }
}
class MapCanvasListener implements GLEventListener {
private MapCanvas canvas;
private float dx;
private float dy;
int backgroundImageWidth = 1200;
int backgroundImageHeight = 824;
private Point2D.Float topLeft;
private GL gl;
private GLDrawable glDrawable;
private static final int EDGE = 64;
private static float scrollSpeed = 0.25f;
private boolean shiftPossible;
private int updates;
int updatesBeforeShift = 10;
private Texture backgroundImage;
public MapCanvasListener(final MapCanvas map) {
canvas = map;
topLeft = new Point2D.Float(0.0f, 0.0f);
}
public final void stopShifting() {
shiftPossible = false;
updates = 0;
}
private void calculateShift() {
dx = 0;
dy = 0;
int bWidth = backgroundImageWidth;
int bHeight = backgroundImageHeight;
int vWidth = JOGLTest.VIEW_SIZE.width;
int vHeight = JOGLTest.VIEW_SIZE.height;
Point mouseLoc = canvas.getMousePosition();
if (mouseLoc == null) {
stopShifting();
} else {
if (mouseLoc.getX() < EDGE) {
if (mouseLoc.getY() < EDGE) {
if (topLeft.x <= 0
&& topLeft.y <= 0) {
stopShifting();
} else {
dx = -scrollSpeed;
dy = -scrollSpeed;
shiftPossible = true;
}
} else if (mouseLoc.getY() > vHeight - EDGE) {
if (topLeft.x <= 0
&& topLeft.y >= bHeight - vHeight) {
stopShifting();
} else {
dx = -scrollSpeed;
dy = scrollSpeed;
shiftPossible = true;
}
} else {
if (topLeft.x <= 0) {
stopShifting();
} else {
dx = -scrollSpeed;
shiftPossible = true;
}
}
} else if (mouseLoc.getX() > vWidth - EDGE) {
if (mouseLoc.getY() < EDGE) {
if (topLeft.x >= bWidth - vWidth
&& topLeft.y <= 0) {
stopShifting();
} else {
dx = scrollSpeed;
dy = -scrollSpeed;
shiftPossible = true;
}
} else if (mouseLoc.getY() > vHeight - EDGE) {
if (topLeft.x >= bWidth - vWidth
&& topLeft.y >= bHeight - vHeight) {
stopShifting();
} else {
dx = scrollSpeed;
dy = scrollSpeed;
shiftPossible = true;
}
} else {
if (topLeft.x >= bWidth - vWidth) {
stopShifting();
} else {
dx = scrollSpeed;
shiftPossible = true;
}
}
} else if (mouseLoc.getY() < EDGE) {
if (topLeft.y <= 0) {
stopShifting();
} else {
dy = -scrollSpeed;
shiftPossible = true;
}
} else if (mouseLoc.getY() > vHeight - EDGE) {
if (topLeft.y >= bHeight - vHeight) {
stopShifting();
} else {
dy = scrollSpeed;
shiftPossible = true;
}
} else {
stopShifting();
}
}
}
public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) { }
public void init(GLAutoDrawable drawable) {
// load background
try {
backgroundImage =
TextureIO.newTexture(new URL("http://media.maps.com/images/downloads/World-Map-1200.gif"),
false,
"gif");
backgroundImage.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER,
GL.GL_NEAREST);
backgroundImage.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER,
GL.GL_NEAREST);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
this.gl = drawable.getGL();
// set the clear color here
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
this.glDrawable = drawable;
drawable.setGL(new DebugGL(drawable.getGL()));
// set anti-aliasing
float[] values = new float[2];
gl.glGetFloatv(GL.GL_LINE_WIDTH_GRANULARITY, values, 0);
gl.glGetFloatv(GL.GL_LINE_WIDTH_RANGE, values, 0);
gl.glEnable(GL.GL_LINE_SMOOTH);
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_DONT_CARE);
gl.glLineWidth(1.5f);
}
private void applyShift() {
if (shiftPossible) {
updates++;
if (updates >= updatesBeforeShift) {
topLeft.x += dx;
if (topLeft.x > backgroundImageWidth - canvas.getViewSize().width) {
topLeft.x = backgroundImageWidth - canvas.getViewSize().width;
}
if (topLeft.x < 0) {
topLeft.x = 0;
}
topLeft.y += dy;
if (topLeft.y > backgroundImageHeight - canvas.getViewSize().height) {
topLeft.y = backgroundImageHeight - canvas.getViewSize().height;
}
if (topLeft.y < 0) {
topLeft.y = 0;
}
}
}
}
public void display(GLAutoDrawable drawable) {
calculateShift();
applyShift();
// clear the screen
gl.glClearDepth(0.0);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
//*******************************
// DRAW THE TEXTURE
//*******************************
// the background covers all 4 corners of the viewing area
float verTop = 1.0f;
float verLft = -1.0f;
float verBtm = -1.0f;
float verRit = 1.0f;
// translate the map coordinates displayed
float texBtm = backgroundImage.getImageTexCoords().bottom();
float texRit = backgroundImage.getImageTexCoords().right();
float verticalScale = (float) backgroundImageHeight / texBtm;
float horizontalScale = (float) backgroundImageWidth / texRit;
float newTop = (0.0f + topLeft.y) / verticalScale;
float newLft = (0.0f + topLeft.x) / horizontalScale;
float newBtm =
((float) JOGLTest.VIEW_SIZE.height + topLeft.y) / verticalScale;
float newRit =
((float) JOGLTest.VIEW_SIZE.width + topLeft.x) / horizontalScale;
// bind to the appropriate texture for this sprite
// enable texturing
gl.glEnable(GL.GL_TEXTURE_2D);
backgroundImage.bind();
// replace the quad colours with the texture
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,
GL.GL_REPLACE);
gl.glBegin(GL.GL_QUADS); {
gl.glTexCoord2f(newLft, newTop);
gl.glVertex2f(verLft, verTop);
gl.glTexCoord2f(newRit, newTop);
gl.glVertex2f(verRit, verTop);
gl.glTexCoord2f(newRit, newBtm);
gl.glVertex2f(verRit, verBtm);
gl.glTexCoord2f(newLft, newBtm);
gl.glVertex2f(verLft, verBtm);
}
gl.glEnd();
gl.glDisable(GL.GL_TEXTURE_2D);
// switch back to modulation of quad colours and texture
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE,
GL.GL_MODULATE);
}
public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) { }
}
Thanks for any help I get.