Java tutorial
/* * Java Terrain and Stellar System Ports * * Copyright (C) 2006 Martin H. Smith based on work by original * authors. * * Released under the terms of the GNU General Public License * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * Linking TerraJ statically or dynamically with other modules is making a * combined work based on TerraJ. Thus, the terms and conditions of the * GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holders of TerraJ * give you permission to combine this program with free software programs * or libraries that are released under the GNU LGPL and with code included * in the standard release of JOGL, Java Getopt and FreeMarker under the BSD * license (or modified versions of such code, with unchanged license) and with * Apache Commons and Log4J libraries under the Apache license (or modified versions * of such code. You may copy and distribute such a system following the terms * of the GNU GPL for TerraJ and the licenses of the other code concerned, * provided that you include the source code of that other code when and as the * GNU GPL requires distribution of source code. * * Note that people who make modified versions of TerraJ are not obligated to grant * this special exception for their modified versions; it is their choice whether * to do so. The GNU General Public License gives permission to release a modified * version without this exception; this exception also makes it possible to release * a modified version which carries forward this exception. */ /* * TriangleMeshViewerDisplay.java * * Created on December 31, 2005, 10:13 AM * */ package com.alvermont.terraj.fracplanet.render; import com.alvermont.terraj.fracplanet.RenderParameters; import com.alvermont.terraj.fracplanet.colour.ByteRGBA; import com.alvermont.terraj.fracplanet.colour.FloatRGBA; import com.alvermont.terraj.fracplanet.geom.SimpleXYZ; import com.alvermont.terraj.fracplanet.geom.TriangleMesh; import com.alvermont.terraj.fracplanet.geom.Vertex; import com.alvermont.terraj.fracplanet.geom.XYZ; import com.alvermont.terraj.fracplanet.util.ByteBufferUtils; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.nio.Buffer; import java.nio.FloatBuffer; import java.util.List; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GL2ES1; import com.jogamp.opengl.GL2GL3; import com.jogamp.opengl.fixedfunc.*; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.glu.GLU; import javax.swing.JComponent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Class that displays a mesh using JOGL rendering. * * @author martin * @version $Id: TriangleMeshViewerDisplay.java,v 1.16 2006/07/06 15:17:24 martin Exp $ */ public class TriangleMeshViewerDisplay extends JComponent implements GLEventListener { /** Our logging object */ private static Log log = LogFactory.getLog(TriangleMeshViewerDisplay.class); private List<TriangleMesh> meshes; private RenderParameters parameters; private int displayListIndex = 0; private int frame; private int width; private int height; // TODO: frame timings // camera position private XYZ cameraPosition; private XYZ cameraLookAt; private XYZ cameraUp; private XYZ defaultCameraPosition; private XYZ defaultCameraLookAt; private XYZ defaultCameraUp; private XYZ cameraMotion; private XYZ cameraRotation; private float camRotZ = 0.0f; // object parameters private float objectTilt; private float objectRotation; /** Indicates whether we are in flying mode (free camera) */ private boolean flying = false; private GLCanvas canvas; private Camera camera; private CameraPosition savedCameraPosition; private int sizeofFloat = ByteBufferUtils.sizeofFloat(); /** * Creates a new instance of TriangleMeshViewerDisplay * * @param meshes The list of meshes to be displayed * @param param The set of rendering parameters to be used * @param canvas The GL canvas that is to be used for rendering */ public TriangleMeshViewerDisplay(RenderParameters param, List<TriangleMesh> meshes, GLCanvas canvas) { super(); this.canvas = canvas; this.meshes = meshes; this.parameters = param; this.frame = 0; this.width = 0; this.height = 0; // MagicNumber OFF this.defaultCameraPosition = new SimpleXYZ(-3.0f, 0.0f, 0.0f); this.defaultCameraLookAt = new SimpleXYZ(0.0f, 0.0f, 0.0f); this.defaultCameraUp = new SimpleXYZ(0.0f, 0.0f, 1.0f); this.cameraPosition = new SimpleXYZ(-3.0f, 0.0f, 0.0f); this.cameraLookAt = new SimpleXYZ(0.0f, 0.0f, 0.0f); this.cameraUp = new SimpleXYZ(0.0f, 0.0f, 1.0f); this.cameraMotion = new SimpleXYZ(0.0f, 0.0f, 0.0f); this.cameraRotation = new SimpleXYZ(0.0f, 0.0f, 0.0f); this.objectTilt = (float) ((-30f * Math.PI) / 180.0f); this.objectRotation = 0.0f; // MagicNumber ON this.displayListIndex = 0; final CameraPosition campos = new CameraPosition(); campos.setEye(this.defaultCameraPosition); campos.setCentre(this.defaultCameraLookAt); campos.setUp(this.defaultCameraUp); this.savedCameraPosition = new CameraPosition(campos); System.out.println("Canvas GetGL: " + canvas.getGL()); // zzing casted to get rid of error this.camera = new CameraJOGL((GL2) canvas.getGL(), campos); canvas.addGLEventListener(this); } /** * KeyAdapter class used to process keyboard events */ protected class MyKeyAdapter extends KeyAdapter { /** Create an instance of MyKeyAdapter */ public MyKeyAdapter() { } /** Amount of motion per keypress in normal mode */ public static final float CAMERA_MOTION_INCREMENT = 0.01f; /** Amount of rotation per keypress in norma mode */ public static final float CAMERA_ROTATION_INCREMENT = 0.1f; /** Increase in motion/rotation per keypress with shift key held */ public static final float CAMERA_SHIFT_MULTIPLIER = 5.0f; private float cameraMultiplier = 1.0f; // RequireThis OFF: CAMERA_MOTION_INCREMENT // RequireThis OFF: CAMERA_ROTATION_INCREMENT // RequireThis OFF: CAMERA_SHIFT_MULTIPLIER /** * Called when a key has been pressed with the corresponding event * * @param e An event object describing the key press */ public void keyPressed(java.awt.event.KeyEvent e) { if (isFlying()) { switch (e.getKeyCode()) { // shift? case KeyEvent.VK_SHIFT: this.cameraMultiplier = CAMERA_SHIFT_MULTIPLIER; break; // camera reset case KeyEvent.VK_ENTER: case KeyEvent.VK_DELETE: case KeyEvent.VK_BACK_SPACE: cameraMotion.setX(0); cameraMotion.setY(0); cameraMotion.setZ(0); cameraRotation.setX(0); cameraRotation.setY(0); cameraRotation.setZ(0); camRotZ = 0.0f; getCamera().setPosition(savedCameraPosition); break; // camera motion case KeyEvent.VK_W: cameraMotion.setZ(CAMERA_MOTION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_S: cameraMotion.setZ(-CAMERA_MOTION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_A: cameraMotion.setX(CAMERA_MOTION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_D: cameraMotion.setX(-CAMERA_MOTION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_PAGE_UP: cameraMotion.setY(CAMERA_MOTION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_PAGE_DOWN: cameraMotion.setY(-CAMERA_MOTION_INCREMENT * cameraMultiplier); break; // camera rotation case KeyEvent.VK_NUMPAD4: cameraRotation.setX(-CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_NUMPAD6: cameraRotation.setX(CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_NUMPAD8: cameraRotation.setY(-CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_NUMPAD2: cameraRotation.setY(CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_NUMPAD7: cameraRotation.setZ(CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; case KeyEvent.VK_NUMPAD9: cameraRotation.setZ(-CAMERA_ROTATION_INCREMENT * cameraMultiplier); break; default: // do nothing break; } } super.keyPressed(e); } /** * Called when a key has been released with the corresponding event * * @param e An event object describing the key release */ public void keyReleased(java.awt.event.KeyEvent e) { if (isFlying()) { switch (e.getKeyCode()) { case KeyEvent.VK_SHIFT: cameraMultiplier = 1.0f; break; case KeyEvent.VK_W: case KeyEvent.VK_S: cameraMotion.setZ(0); break; case KeyEvent.VK_A: case KeyEvent.VK_D: cameraMotion.setX(0); break; case KeyEvent.VK_PAGE_UP: case KeyEvent.VK_PAGE_DOWN: cameraMotion.setY(0); break; case KeyEvent.VK_NUMPAD4: case KeyEvent.VK_NUMPAD6: cameraRotation.setX(0); break; case KeyEvent.VK_NUMPAD2: case KeyEvent.VK_NUMPAD8: cameraRotation.setY(0); break; case KeyEvent.VK_NUMPAD7: case KeyEvent.VK_NUMPAD9: cameraRotation.setZ(0); break; default: // do nothing break; } } super.keyReleased(e); } } /** * Enter fly mode, giving the user a free camera */ public void beginFly() { // to avoid confusion with coordinate systems etc. objectRotation = 0.0f; objectRotationSpeed = 0.0f; objectTilt = 0.0f; flying = true; } /** * Exit fly mode fixing the camera */ public void endFly() { flying = false; } /** * If there is any cached data e.g. display lists then remove it and * force a redraw */ public void forceRedraw() { if (displayListIndex != 0) { final GL2 gl = (GL2) canvas.getGL(); // NVIDIA driver seems to crash when a list is deleted, don't like // doing this but it looks like the only way for now given the // high speed that the driver can run at with display lists. if (!parameters.isDisableGLDeleteList()) { gl.glDeleteLists(displayListIndex, 1); } displayListIndex = 0; } } /** * Set the mesh that is being rendered by this viewer. * * @param meshes The list of meshes to be displayed */ public void setMeshes(List<TriangleMesh> meshes) { this.meshes = meshes; forceRedraw(); } /** * Draw a frame with the specified camera and object parameters. * * Note this isn't currently being used as I'm using a slightly different * rendering model with JOGL than the original C++ code did. It's left * here for completeness - MS. * * @param p The camera position * @param l The camera lookat point (scene centre) * @param u The camera up vector * @param r The object rotation * @param t The object tilt */ public void drawFrame(XYZ p, XYZ l, XYZ u, float r, float t) { ++frame; cameraPosition = p; cameraLookAt = l; cameraUp = u; objectRotation = r; objectTilt = t; //updateGL(); // ????? canvas.repaint(); } /** * Initialize our use of JOGL. We set up the client state ready to begin * rendering. * * @param gLAutoDrawable The drawable that will be used for output */ public void init(GLAutoDrawable gLAutoDrawable) { final GL2 gl = (GL2) gLAutoDrawable.getGL(); final GLU glu = new GLU(); log.debug("Init GL using: " + gl.getClass().getName()); // zzing do not add to here! as per http://stackoverflow.com/questions/8465401/why-glautodrawable-doesnt-have-the-method-addmouselistener // need to move it else where //gLAutoDrawable.addKeyListener(new MyKeyAdapter()); gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Switch depth-buffering on gl.glEnable(GL.GL_DEPTH_TEST); // Basic lighting stuff (set ambient globally rather than in light) final float[] blackLight = { 0.0f, 0.0f, 0.0f, 1.0f }; gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_AMBIENT, blackLight, 0); gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_SPECULAR, blackLight, 0); gl.glEnable(GLLightingFunc.GL_LIGHT0); gl.glEnable(GLLightingFunc.GL_LIGHTING); // Do smooth shading 'cos colours are specified at vertices gl.glShadeModel(GLLightingFunc.GL_SMOOTH); // Don't waste time on back-facers gl.glFrontFace(GL.GL_CCW); gl.glCullFace(GL.GL_BACK); gl.glEnable(GL.GL_CULL_FACE); // Use arrays of data gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); gl.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); gl.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY); log.debug("Init GL complete."); } // mods private int frames = 0; // end of mods /** * Called to display a frame. This carries out the rendering of the scene * using the drawable object. * * @param gLAutoDrawable The GL drawable object that is to be used for * rendering */ public void display(GLAutoDrawable gLAutoDrawable) { final GL2 gl = (GL2) gLAutoDrawable.getGL(); final GLU glu = new GLU(); if (parameters.isEnableFog()) { // clear to fog background colour final FloatRGBA fogCol = parameters.getFogColour(); final float[] colBuffer = new float[3]; colBuffer[0] = fogCol.getR(); colBuffer[1] = fogCol.getG(); colBuffer[2] = fogCol.getB(); gl.glClearColor(colBuffer[0], colBuffer[1], colBuffer[2], 1.0f); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glEnable(GL2.GL_FOG); gl.glFogi(GL2.GL_FOG_MODE, GL.GL_LINEAR); gl.glFogfv(GL2.GL_FOG_COLOR, colBuffer, 0); gl.glFogf(GL2.GL_FOG_DENSITY, 0.35f); gl.glFogf(GL2.GL_FOG_START, 0.0f); gl.glFogf(GL2.GL_FOG_END, parameters.getFogDistance()); } else { gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glDisable(GL2.GL_FOG); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); } // set up ambient light final float a = parameters.getAmbient(); final float[] globalAmbient = { a, a, a, 1.0f }; gl.glLightModelfv(GL2ES1.GL_LIGHT_MODEL_AMBIENT, globalAmbient, 0); final float[] lightDiffuse = { 1.0f - a, 1.0f - a, 1.0f - a, 1.0f }; gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_DIFFUSE, lightDiffuse, 0); // position and orient the camera getCamera().moveLeft(cameraMotion.getX()); getCamera().moveUp(cameraMotion.getY()); getCamera().moveBackward(cameraMotion.getZ()); camRotZ += cameraRotation.getZ(); getCamera().rotateEye(cameraRotation.getX(), cameraRotation.getY()); getCamera().rotateAxis(camRotZ, 0.0f, 0.0f, 1.0f); //log.debug(camRotZ); getCamera().lookAtScene(); // float lightPosition[] = {-2.0f, -3.0f, 1.0f, 0.0f }; // gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0); // set up sunlight final XYZ sunpos = parameters.getSunPosition(); final float[] lightPosition = new float[4]; lightPosition[0] = sunpos.getX(); lightPosition[1] = sunpos.getY(); lightPosition[2] = sunpos.getZ(); gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_POSITION, lightPosition, 0); final FloatRGBA lightColour = parameters.getSunColour(); lightPosition[0] = lightColour.getR(); lightPosition[1] = lightColour.getG(); lightPosition[2] = lightColour.getB(); lightPosition[0] = 1.0f; gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_DIFFUSE, lightPosition, 0); gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_SPECULAR, lightPosition, 0); objectRotation += objectRotationSpeed; objectRotation %= 360.0f; gl.glRotatef(objectTilt, 0.0f, 1.0f, 0.0f); gl.glRotatef(objectRotation, 0.0f, 0.0f, 1.0f); int drawMode = GL2GL3.GL_FILL; if (parameters.isWireframe()) { drawMode = GL2GL3.GL_LINE; } // end of mods gl.glPolygonMode(gl.GL_FRONT_AND_BACK, drawMode); gl.glEnable(gl.GL_CULL_FACE); gl.glFrontFace(gl.GL_CCW); if (parameters.isDisplayList() && (displayListIndex != 0)) { gl.glCallList(displayListIndex); } else { final boolean buildingList = parameters.isDisplayList() && (displayListIndex == 0); if (buildingList) { displayListIndex = gl.glGenLists(1); gl.glNewList(displayListIndex, GL2.GL_COMPILE); if (log.isDebugEnabled()) { log.debug("Building display list"); } } final float[] defaultMaterialWhite = { 1.0f, 1.0f, 1.0f }; final float[] defaultMaterialBlack = { 0.0f, 0.0f, 0.0f }; gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE, defaultMaterialWhite, 0); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_EMISSION, defaultMaterialBlack, 0); boolean first = true; for (TriangleMesh mesh : meshes) { // Meshes after the first are rendered twice: first the backfacing polys then the front facing. // This solves the problem of either clouds disappearing when we're under them (with backface culling) // or weird stuff around the periphery when culling is on. // It's quite an expensive solution! final int passes = (first ? 1 : 2); for (int pass = 0; pass < passes; pass++) { if (passes == 2 && pass == 0) { gl.glCullFace(gl.GL_FRONT); } else { gl.glCullFace(gl.GL_BACK); } if (mesh.getEmissive() == 0.0) { // Switch blending on for non-emissive meshes after the first if (!first) { gl.glEnable(gl.GL_BLEND); gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA); } else { gl.glDisable(gl.GL_BLEND); } // Use "Color Material" mode 'cos everything is the same // material.... just change the colour gl.glEnable(GLLightingFunc.GL_COLOR_MATERIAL); gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE); // Point GL at arrays of data final FloatBuffer vertBuffer = mesh.getVertices().getPositionBuffer(); vertBuffer.position(0); gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertBuffer); final FloatBuffer normBuffer = mesh.getVertices().getNormalBuffer(); normBuffer.position(0); gl.glNormalPointer(GL.GL_FLOAT, 0, normBuffer); final Buffer colBuffer = mesh.getVertices().getColourBuffer(); colBuffer.position(0); if (first) { gl.glColorPointer(3, GL.GL_BYTE, 8, colBuffer); } else { gl.glColorPointer(4, GL.GL_BYTE, 8, colBuffer); } // Draw the colour-zero triangles final Buffer triBuffer = mesh.getTriangles().getBuffer(); triBuffer.position(0); gl.glDrawElements(GL.GL_TRIANGLES, 3 * mesh.getTriangleColour0Count(), GL.GL_UNSIGNED_INT, triBuffer); // Switch to alternate colour and draw the colour-one triangles colBuffer.position(4); if (first) { gl.glColorPointer(3, GL.GL_BYTE, 8, colBuffer); } else { gl.glColorPointer(4, GL.GL_BYTE, 8, colBuffer); } triBuffer.position(mesh.getTriangleColour0Count() * 3); gl.glDrawElements(GL.GL_TRIANGLES, 3 * mesh.getTriangleColour1Count(), GL.GL_UNSIGNED_INT, triBuffer); gl.glDisable(GLLightingFunc.GL_COLOR_MATERIAL); } else { // We abuse alpha for emission, so no blending gl.glDisable(gl.GL_BLEND); // If there could be emissive vertices, we need to do things the hard way. final float k = 1.0f / 255.0f; final float em = k * (mesh.getEmissive()); final float ad = k * (1.0f - mesh.getEmissive()); gl.glBegin(GL.GL_TRIANGLES); final float[] cAmbDiff = new float[3]; final float[] cEmissive = new float[3]; for (int t = 0; t < mesh.getTriangles().size(); ++t) { int c = 0; if (t >= mesh.getTriangleColour0Count()) { c = 1; } for (int i = 0; i < 3; ++i) { final int vn = mesh.getTriangles().get(t).getVertex(i); final Vertex v = mesh.getVertices().get(vn); final ByteRGBA col = v.getColour(c); if (v.getEmissive(c)) { cAmbDiff[0] = col.getR() * ad; cAmbDiff[1] = col.getG() * ad; cAmbDiff[2] = col.getB() * ad; cEmissive[0] = col.getR() * em; cEmissive[1] = col.getG() * em; cEmissive[2] = col.getB() * em; } else { cAmbDiff[0] = col.getR() * k; cAmbDiff[1] = col.getG() * k; cAmbDiff[2] = col.getB() * k; cEmissive[0] = 0.0f; cEmissive[1] = 0.0f; cEmissive[2] = 0.0f; } gl.glNormal3f(v.getNormal().getX(), v.getNormal().getY(), v.getNormal().getZ()); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE, cAmbDiff, 0); gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION, cEmissive, 0); gl.glVertex3f(v.getPosition().getX(), v.getPosition().getY(), v.getPosition().getZ()); } } gl.glEnd(); } } first = false; } if (buildingList) { gl.glEndList(); if (log.isDebugEnabled()) { log.debug("... built display list"); } } } gl.glFlush(); } /** * Called when the GL drawable has been resized * * @param gLAutoDrawable The drawable being used for rendering * @param x The new x coordinate of the drawable * @param y The new y coordinate of the drawable * @param w The new width of the drawable * @param h The new height of the drawable */ public void reshape(GLAutoDrawable gLAutoDrawable, int x, int y, int w, int h) { final GL2 gl = (GL2) gLAutoDrawable.getGL(); final GLU glu = new GLU(); log.debug("Viewer GL reshape to: " + w + ", " + h); log.debug("OS NAME: " + System.getProperty("os.name")); log.debug("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); log.debug("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); log.debug("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); System.out.println(gl); // allow for bug???? / unimplemented????? glDeleteList() on linux // nvidia driver. if (System.getProperty("os.name").equals("Linux") && gl.glGetString(GL.GL_VENDOR).equals("NVIDIA Corporation")) { parameters.setDisableGLDeleteList(true); log.warn("NVIDIA/Linux: Display lists will not be freed if used."); } width = w; height = h; gl.glViewport(0, 0, w, h); gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); gl.glLoadIdentity(); double vAngle = 45.0; if (width <= height) { vAngle = (45.0 * height) / width; } // View angle is specified in vertical direction, but we need // to exaggerate it if image is taller than wide. final float viewAngleDegrees = (float) Math.min(90.0, vAngle); // Was 0.1 (too far); 0.001 gives artefacts glu.gluPerspective(viewAngleDegrees, (float) width / (float) height, 0.01, 10.0); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); ((CameraJOGL) getCamera()).gl = gl; // zzing hack because camera's context is wrong, can't find // where it was set getCamera().setManagePerspective(false); getCamera().on(); // updateGL(); // ????? canvas.repaint(); log.debug("GL reshape complete"); } /** * Called when the display mode or device associated with our drawable has * changed. * * @param gLAutoDrawable The drawable object we're using * @param b <pre>true</pre> if there has been a display mode change else * <pre>false</pre> * @param b0 <pre>true</pre> If there has been a device change otherwise * <pre>false</pre> */ public void displayChanged(GLAutoDrawable gLAutoDrawable, boolean b, boolean b0) { // not currently implemented by JOGL display(gLAutoDrawable); } /** * Getter for property canvas. * @return Value of property canvas. */ public GLCanvas getCanvas() { return this.canvas; } /** * Sets the tilt angle that the object is drawn at * * @param tilt A new tilt angle in degrees */ public void setObjectTilt(float tilt) { this.objectTilt = tilt; } /** * Sets the rotation angle that the object is drawn at * * @param rotation The new rotation angle in degrees */ public void setObjectRotation(float rotation) { this.objectRotation = rotation; } /** * Holds value of property objectRotationSpeed. */ private float objectRotationSpeed = 0.0f; /** * Getter for property objectRotationSpeed. * @return Value of property objectRotationSpeed. */ public float getObjectRotationSpeed() { return this.objectRotationSpeed; } /** * Setter for property objectRotationSpeed. * @param objectRotationSpeed New value of property objectRotationSpeed. */ public void setObjectRotationSpeed(float objectRotationSpeed) { this.objectRotationSpeed = objectRotationSpeed; } /** * Sets the rendering parameters in use by this viewer * * @param param The new set of rendering parameters to be used */ public void setRenderParameters(RenderParameters param) { this.parameters = param; } /** * Getter for property meshes. * @return Value of property meshes. */ public List<TriangleMesh> getMeshes() { return meshes; } /** * Retrieve the current camera position of the viewer. This is a convenience * method and could be removed as access to the camera object is already * provided * * @return The current camera position object */ public CameraPosition getCameraPosition() { return getCamera().getPosition(); } /** * Set the camera position in the viewer to the specified one * * @param cameraPosition An object describing the new position that the * camera is to be given */ public void setCameraPosition(CameraPosition cameraPosition) { getCamera().setPosition(cameraPosition); } /** * Get the camera for this display * * @return The camera object used by the display. */ public Camera getCamera() { return camera; } /** * Test whether the fly mode is on or off * * @return <pre>true</pre> if the fly mode is on otherwise <pre>false</pre> */ public boolean isFlying() { return flying; } public void dispose(GLAutoDrawable drawable) { } // zzing release all opengl resources }