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.general;
034
035import java.awt.Font;
036import java.awt.geom.Rectangle2D;
037
038import javax.media.opengl.GL;
039import javax.media.opengl.GL2;
040import javax.media.opengl.GLAutoDrawable;
041import javax.media.opengl.fixedfunc.GLLightingFunc;
042import javax.media.opengl.fixedfunc.GLMatrixFunc;
043
044import org.openimaj.image.colour.RGBColour;
045import org.openimaj.vis.DataUnitsTransformer;
046
047import com.jogamp.opengl.util.awt.TextRenderer;
048
049
050/**
051 *      A class for drawing rulers in a 3D world.
052 *
053 *      // TODO : This could be made more efficient using DisplayLists.
054 *
055 *      @author David Dupplaw (dpd@ecs.soton.ac.uk)
056 *  @created 8 Jul 2013
057 */
058public class AxisRenderer3D
059        extends AxisRenderer<float[]>
060        implements DataUnitsTransformer<float[], Double, Double>
061{
062        /** The OpenGL surface we're rendering to */
063        private GLAutoDrawable glad;
064
065        /** The length of the axis */
066        private final double axisLength = 1;
067
068        private int gridDirection = 1;
069
070        private final TextRenderer textRenderer;
071
072        /**
073         *      Default constructor sets some default axis values
074         */
075        public AxisRenderer3D()
076        {
077                Float[] c = RGBColour.WHITE;
078                this.config.getRenderingConfig().setColour( new float[]{ c[0], c[1], c[2] } );
079                c = RGBColour.GRAY;
080                this.config.getRenderingConfig().setMajorTickColour( new float[]{ c[0], c[1], c[2] } );
081                this.config.getRenderingConfig().setMajorGridColour( new float[]{ c[0], c[1], c[2] } );
082                this.config.getRenderingConfig().setMinorTickColour( new float[]{ c[0], c[1], c[2] } );
083                c = new Float[] {0.3f,0.3f,0.3f};
084                this.config.getRenderingConfig().setMinorGridColour( new float[]{ c[0], c[1], c[2] } );
085                this.config.getRenderingConfig().setMajorTickLength( 0.04 );
086                this.config.getRenderingConfig().setMinorTickLength( 0.01 );
087                this.config.getRenderingConfig().setMajorTickSpacing( 1 );
088                this.config.getRenderingConfig().setMinorTickSpacing( 0.5 );
089
090                this.config.getRenderingConfig().setThickness( 3 );
091                this.config.getRenderingConfig().setMajorTickThickness( 1 );
092                this.config.getRenderingConfig().setMinorTickThickness( 0.5 );
093
094                this.textRenderer = new TextRenderer( new Font( "SansSerif", Font.BOLD, 36 ) );
095        }
096
097        @Override
098        public void drawAxis( final AxisConfig<float[]> config )
099        {
100                final GL2 gl = this.glad.getGL().getGL2();
101
102                gl.glPushMatrix();
103
104                this.orient( gl );
105
106                final float zero = 0.001f;
107                gl.glBegin( GL.GL_LINE_STRIP );
108                {
109                        gl.glLineWidth( (float)config.getRenderingConfig().getThickness() );
110                        gl.glColor3f( config.getRenderingConfig().getColour()[0],
111                                        config.getRenderingConfig().getColour()[1],
112                                        config.getRenderingConfig().getColour()[2] );
113
114                        final float n1 = this.calculatePosition( config.getMinValue() ).floatValue();
115                        final float n2 = this.calculatePosition( config.getMaxValue() ).floatValue();
116
117                        // We draw in the x axis, so the orientation has to be set appropriately
118                        gl.glVertex3f( n1, zero, zero );
119                        gl.glVertex3f( n2, zero, zero );
120                }
121                gl.glEnd();
122
123                gl.glPopMatrix();
124        }
125
126        @Override
127        public void drawAxisLabel( final AxisConfig<float[]> config )
128        {
129                final GL2 gl = this.glad.getGL().getGL2();
130
131                gl.glPushMatrix();
132//              this.orient( gl );
133
134                final double[] o = this.config.getRenderingConfig().getNameOrientation();
135                if( o != null )
136                {
137                        for( int i = 0; i < o.length; i += 4 )
138                                gl.glRotated( o[i], o[i+1],     o[i+2], o[i+3] );
139                }
140
141                this.textRenderer.begin3DRendering();
142                {
143                        gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW );
144
145                        // TODO: Text colour and size
146                        this.textRenderer.setColor( 1.0f, 0.2f, 0.2f, 0.8f );
147                        final float scale = 0.003f;
148
149                        final Rectangle2D nameBounds = this.textRenderer.getBounds( config.getName() );
150                        this.textRenderer.draw3D( config.getName(), (float)(1-nameBounds.getWidth()*scale),
151                                        (float)(-nameBounds.getHeight()*scale)
152                                        *config.getRenderingConfig().getNameDirection(), 0.1f, scale );
153                }
154                this.textRenderer.end3DRendering();
155                gl.glPopMatrix();
156        }
157
158        @Override
159        public void drawMajorTick( final double location, final AxisConfig<float[]> config )
160        {
161                final GL2 gl = this.glad.getGL().getGL2();
162
163                gl.glPushMatrix();
164
165                this.orient( gl );
166
167                gl.glLineWidth( (float)config.getRenderingConfig().getMajorTickThickness() );
168                gl.glColor3f( config.getRenderingConfig().getMajorTickColour()[0],
169                                config.getRenderingConfig().getMajorTickColour()[1],
170                                config.getRenderingConfig().getMajorTickColour()[2] );
171
172                final float l = (float)config.getRenderingConfig().getMajorTickLength();
173                final float l2 = -l;
174
175                final float ll = this.calculatePosition( location ).floatValue();
176
177                final float zero = 0.001f;
178                gl.glBegin( GL.GL_LINE_STRIP );
179                {
180                        // We draw in the x axis, so the orientation has to be set appropriately
181                        gl.glVertex3f( ll, l, zero );
182                        gl.glVertex3f( ll, l2, zero );
183                }
184                gl.glEnd();
185
186                gl.glBegin( GL.GL_LINE_STRIP );
187                {
188                        // We draw in the x axis, so the orientation has to be set appropriately
189                        gl.glVertex3f( ll, zero, l );
190                        gl.glVertex3f( ll, zero, l2 );
191                }
192                gl.glEnd();
193
194                gl.glPopMatrix();
195        }
196
197        @Override
198        public void drawMajorTickGridline( final double location, final AxisConfig<float[]> config )
199        {
200                final GL2 gl = this.glad.getGL().getGL2();
201
202                gl.glPushMatrix();
203
204                this.orient( gl );
205
206                gl.glLineWidth( (float)config.getRenderingConfig().getMajorGridThickness() );
207                gl.glColor3f( config.getRenderingConfig().getMajorGridColour()[0],
208                                config.getRenderingConfig().getMajorGridColour()[1],
209                                config.getRenderingConfig().getMajorGridColour()[2] );
210
211                final float ll = this.calculatePosition( location ).floatValue();
212
213                final float zero = 0.001f;
214                gl.glBegin( GL.GL_LINE_STRIP );
215                {
216                        // We draw in the x axis, so the orientation has to be set appropriately
217                        gl.glVertex3f( ll, zero, zero );
218                        gl.glVertex3f( ll, 1, zero );
219                }
220                gl.glEnd();
221
222                gl.glBegin( GL.GL_LINE_STRIP );
223                {
224                        // We draw in the x axis, so the orientation has to be set appropriately
225                        gl.glVertex3f( ll, zero, zero );
226                        gl.glVertex3f( ll, zero, 1*this.gridDirection );
227                }
228                gl.glEnd();
229
230                gl.glPopMatrix();
231        }
232
233        @Override
234        public void drawMinorTick( final double location, final AxisConfig<float[]> config )
235        {
236                final GL2 gl = this.glad.getGL().getGL2();
237
238                gl.glPushMatrix();
239
240                this.orient( gl );
241
242                final float zero = 0.001f;
243                gl.glBegin( GL.GL_LINE_STRIP );
244                {
245//                      gl.glEnable( GL2.GL_LINE_STIPPLE );
246//                      gl.glLineStipple( 2, (short) 0x00FF );
247                        gl.glLineWidth( (float)config.getRenderingConfig().getMinorTickThickness() );
248                        gl.glColor3f( config.getRenderingConfig().getMinorTickColour()[0],
249                                        config.getRenderingConfig().getMinorTickColour()[1],
250                                        config.getRenderingConfig().getMinorTickColour()[2] );
251
252                        final float l = (float)config.getRenderingConfig().getMinorTickLength();
253                        final float l2 = -l;
254
255                        final float ll = this.calculatePosition( location ).floatValue();
256
257                        // We draw in the x axis, so the orientation has to be set appropriately
258                        gl.glVertex3f( ll, l, zero );
259                        gl.glVertex3f( ll, l2, zero );
260                }
261                gl.glEnd();
262
263                gl.glPopMatrix();
264        }
265
266        @Override
267        public void drawMinorTickGridline( final double location, final AxisConfig<float[]> config )
268        {
269                final GL2 gl = this.glad.getGL().getGL2();
270
271                gl.glPushMatrix();
272
273                this.orient( gl );
274
275                gl.glLineWidth( (float)config.getRenderingConfig().getMinorGridThickness() );
276                gl.glColor3f( config.getRenderingConfig().getMinorGridColour()[0],
277                                config.getRenderingConfig().getMinorGridColour()[1],
278                                config.getRenderingConfig().getMinorGridColour()[2] );
279        final float[] rgba = { config.getRenderingConfig().getMinorGridColour()[0],
280                                config.getRenderingConfig().getMinorGridColour()[1],
281                                config.getRenderingConfig().getMinorGridColour()[2] };
282        gl.glMaterialfv( GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, rgba, 0);
283        gl.glMaterialfv( GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, rgba, 0);
284        gl.glMaterialf( GL.GL_FRONT, GLLightingFunc.GL_SHININESS, 0f);
285
286                final float ll = this.calculatePosition( location ).floatValue();
287
288                final float zero = 0.001f;
289                gl.glBegin( GL.GL_LINE_STRIP );
290                {
291                        // We draw in the x axis, so the orientation has to be set appropriately
292                        gl.glVertex3f( ll, zero, zero );
293                        gl.glVertex3f( ll, 1, zero );
294                }
295                gl.glEnd();
296
297                gl.glBegin( GL.GL_LINE_STRIP );
298                {
299                        // We draw in the x axis, so the orientation has to be set appropriately
300                        gl.glVertex3f( ll, zero, zero );
301                        gl.glVertex3f( ll, zero, 1*this.gridDirection );
302                }
303                gl.glEnd();
304
305                gl.glPopMatrix();
306        }
307
308        private void orient( final GL2 gl )
309        {
310                if( this.config.getOrientation()[0] != 0 )
311                {
312                        gl.glMatrixMode( GLMatrixFunc.GL_MODELVIEW );
313                        final double[] o = this.config.getOrientation();
314                        for( int i = 0; i < o.length; i+=4 )
315                                gl.glRotated( o[i], o[i+1], o[i+2], o[i+3] );
316                }
317        }
318
319        /**
320         *      @param glad
321         */
322        public void setGLAD( final GLAutoDrawable glad )
323        {
324                this.glad = glad;
325        }
326
327        @Override
328        public Double calculatePosition( final Double units )
329        {
330                return this.axisLength/(this.config.getMaxValue()-this.config.getMinValue()) * units;
331        }
332
333        @Override
334        public Double calculateUnitsAt( final Double position )
335        {
336                return position / (this.axisLength/(this.config.getMaxValue()-this.config.getMinValue()));
337        }
338
339        /**
340         *      @param i
341         */
342        public void setGridDirection( final int i )
343        {
344                this.gridDirection  = i;
345        }
346
347        @Override
348        public Double scaleDimension( final Double dimension )
349        {
350                return dimension * (this.axisLength/(this.config.getMaxValue()-this.config.getMinValue()));
351        }
352}