001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.vis; 034 035import java.awt.Dimension; 036import java.util.ArrayList; 037import java.util.List; 038 039import javax.media.opengl.GL; 040import javax.media.opengl.GL2; 041import javax.media.opengl.GL2ES1; 042import javax.media.opengl.GL2GL3; 043import javax.media.opengl.GLAutoDrawable; 044import javax.media.opengl.GLEventListener; 045import javax.media.opengl.fixedfunc.GLLightingFunc; 046import javax.media.opengl.fixedfunc.GLMatrixFunc; 047import javax.media.opengl.glu.gl2.GLUgl2; 048 049import org.openimaj.image.MBFImage; 050import org.openimaj.vis.general.CameraPositionProvider; 051import org.openimaj.vis.general.JOGLWindow; 052 053import com.jogamp.opengl.util.Animator; 054import com.jogamp.opengl.util.gl2.GLUT; 055 056/** 057 * 058 * 059 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 060 * @created 11 Jul 2013 061 * @version $Author$, $Revision$, $Date$ 062 * @param <D> Data type 063 */ 064public abstract class Visualisation3D<D> implements 065 GLEventListener, Visualisation<D>, 066 AnimatedVisualisationProvider 067{ 068 /** The GLU library we'll use */ 069 protected final GLUgl2 glu = new GLUgl2(); 070 071 /** The GLUT library we'll use */ 072 protected final GLUT glut = new GLUT(); 073 074 /** The JOGL Window (NEWT) */ 075 protected JOGLWindow window; 076 077 /** Animation listeners */ 078 private final List<AnimatedVisualisationListener> listeners = 079 new ArrayList<AnimatedVisualisationListener>(); 080 081 /** The animation */ 082 private final Animator animator; 083 084 /** Object that provide the camera position over time */ 085 protected CameraPositionProvider cameraPosition; 086 087 /** The data! */ 088 protected D data; 089 090 /** Whether lighting should be enabled */ 091 private boolean enableLights = false; 092 093 094 /** 095 * Render the visualisation into the drawable 096 * @param drawable The drawable 097 */ 098 protected abstract void renderVis( GLAutoDrawable drawable ); 099 100 101 /** 102 * @param width 103 * @param height 104 */ 105 public Visualisation3D( final int width, final int height ) 106 { 107 this.window = new JOGLWindow( width, height ); 108 109 if( this.window.getDrawableSurface() == null ) 110 throw new RuntimeException( "Unable to get OpenGL surface." ); 111 112 this.window.getDrawableSurface().addGLEventListener( this ); 113 114 this.animator = new Animator( this.window.getDrawableSurface() ); 115 this.animator.add( this.window.getDrawableSurface() ); 116 this.animator.start(); 117 } 118 119 /** 120 * Closes the window and cleans up 121 * 122 * {@inheritDoc} 123 * @see java.lang.Object#finalize() 124 */ 125 @Override 126 protected void finalize() throws Throwable 127 { 128 this.animator.stop(); 129 this.window.close(); 130 }; 131 132 @Override 133 public void addAnimatedVisualisationListener( final AnimatedVisualisationListener avl ) 134 { 135 this.listeners.add( avl ); 136 } 137 138 @Override 139 public void removeAnimatedVisualisationListener( final AnimatedVisualisationListener avl ) 140 { 141 this.listeners.remove( avl ); 142 } 143 144 @Override 145 public void init( final GLAutoDrawable drawable ) 146 { 147 final GL2 gl = drawable.getGL().getGL2(); 148 gl.setSwapInterval( 1 ); 149 gl.glEnable( GL.GL_DEPTH_TEST ); 150 gl.glDepthFunc( GL.GL_LEQUAL ); 151 gl.glShadeModel( GLLightingFunc.GL_SMOOTH ); 152 gl.glHint( GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST ); 153// gl.glEnable( GL.GL_BLEND ); 154// gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA ); 155 gl.glEnable( GL2GL3.GL_POLYGON_SMOOTH ); 156 157 final float w = this.window.getDrawableSurface().getWidth(); 158 final float h = this.window.getDrawableSurface().getHeight(); 159 160 // Set the projection matrix (only done once - just here) 161 gl.glMatrixMode( GLMatrixFunc.GL_PROJECTION ); 162 gl.glLoadIdentity(); 163 this.glu.gluPerspective( 50, (w / h), 0.01, 10 ); 164 165 // Set the initial model matrix 166 gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW ); 167 gl.glLoadIdentity(); 168 gl.glViewport( 0, 0, (int) w, (int) h ); /* viewport size in pixels */ 169 } 170 171 /** 172 * {@inheritDoc} 173 * 174 * @see javax.media.opengl.GLEventListener#display(javax.media.opengl.GLAutoDrawable) 175 */ 176 @Override 177 public void display( final GLAutoDrawable drawable ) 178 { 179 this.updateVis(); 180 181 final GL2 gl = drawable.getGL().getGL2(); 182 gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW ); 183 gl.glLoadIdentity(); 184 185 if( this.cameraPosition != null ) 186 { 187 final float[] pos = this.cameraPosition.getCameraPosition(); 188 this.glu.gluLookAt( pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6], pos[7], pos[8] ); 189 } 190 191 // Prepare light parameters. 192 if( this.enableLights ) 193 { 194 final float SHINE_ALL_DIRECTIONS = 1; 195 final float[] lightPos = {-30, 0, 0, SHINE_ALL_DIRECTIONS}; 196 final float[] lightColorAmbient = {0.2f, 0.2f, 0.2f, 1f}; 197 final float[] lightColorSpecular = {0.5f, 0.5f, 0.5f, 1f}; 198 199 // Set light parameters. 200 gl.glLightfv( GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION, lightPos, 0 ); 201 gl.glLightfv( GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_AMBIENT, lightColorAmbient, 0 ); 202 gl.glLightfv( GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_SPECULAR, lightColorSpecular, 0 ); 203 204 // Enable lighting in GL. 205 gl.glEnable( GLLightingFunc.GL_LIGHT1 ); 206 gl.glEnable( GLLightingFunc.GL_LIGHTING ); 207 } 208 209 gl.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT ); 210 211 this.renderVis( drawable ); 212 } 213 214 /** 215 * {@inheritDoc} 216 * @see javax.media.opengl.GLEventListener#dispose(javax.media.opengl.GLAutoDrawable) 217 */ 218 @Override 219 public void dispose( final GLAutoDrawable drawable ) 220 { 221 drawable.removeGLEventListener( this ); 222 } 223 224 /** 225 * {@inheritDoc} 226 * 227 * @see javax.media.opengl.GLEventListener#reshape(javax.media.opengl.GLAutoDrawable, 228 * int, int, int, int) 229 */ 230 @Override 231 public void reshape( final GLAutoDrawable drawable, final int arg1, final int arg2, final int arg3, final int arg4 ) 232 { 233 final GL2 gl = drawable.getGL().getGL2(); 234 final float w = this.window.getDrawableSurface().getWidth(); 235 final float h = this.window.getDrawableSurface().getHeight(); 236 gl.glMatrixMode( GLMatrixFunc.GL_PROJECTION ); 237 gl.glLoadIdentity(); 238 this.glu.gluPerspective( 50, (w / h), 0.01, 10 ); 239 } 240 241 /** 242 * {@inheritDoc} 243 * @see org.openimaj.vis.VisualisationImageProvider#getVisualisationImage() 244 */ 245 @Override 246 public MBFImage getVisualisationImage() 247 { 248 // TODO: Need to convert the GL buffer to a MBFImage 249 return null; 250 } 251 252 @Override 253 public void setRequiredSize( final Dimension d ) 254 { 255 } 256 257 /** 258 * {@inheritDoc} 259 * @see org.openimaj.vis.Visualisation#setData(java.lang.Object) 260 */ 261 @Override 262 public void setData( final D data ) 263 { 264 this.data = data; 265 } 266 267 268 /** 269 * @return the enableLights 270 */ 271 public boolean isEnableLights() 272 { 273 return this.enableLights; 274 } 275 276 277 /** 278 * @param enableLights the enableLights to set 279 */ 280 public void setEnableLights( final boolean enableLights ) 281 { 282 this.enableLights = enableLights; 283 } 284}