/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. Copyright 2011 Gephi Consortium. All rights reserved. The contents of this file are subject to the terms of either the GNU General Public License Version 3 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the License at http://gephi.org/about/legal/license-notice/ or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the specific language governing permissions and limitations under the License. When distributing the software, include this License Header Notice in each file and include the License files at /cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the License Header, with the fields enclosed by brackets [] replaced by your own identifying information: "Portions Copyrighted [year] [name of copyright owner]" If you wish your version of this file to be governed by only the CDDL or only the GPL Version 3, indicate your decision by adding "[Contributor] elects to include this software in this distribution under the [CDDL or GPL Version 3] license." If you do not indicate a single choice of license, a recipient has the option to distribute your version of this file under either the CDDL, the GPL Version 3 or to extend the choice of license to its licensees as provided above. However, if you add GPL Version 3 code and therefore, elected the GPL Version 3 license, then the option applies only if the new code is made subject to such option by the copyright holder. Contributor(s): Portions Copyrighted 2011 Gephi Consortium. */ package org.gephi.visualization.swing; import com.jogamp.common.nio.Buffers; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.glu.GLU; import java.awt.Color; import java.awt.Component; import java.awt.Point; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.logging.Level; import java.util.logging.Logger; import org.gephi.lib.gleem.linalg.Vec3f; import org.gephi.visualization.VizArchitecture; import org.gephi.visualization.VizController; import org.gephi.visualization.VizModel; import org.gephi.visualization.apiimpl.GraphDrawable; import org.gephi.visualization.apiimpl.GraphIO; import org.gephi.visualization.apiimpl.Scheduler; import org.gephi.visualization.opengl.AbstractEngine; import org.gephi.visualization.opengl.GraphicalConfiguration; import org.openide.util.Exceptions; /** * * @author Mathieu Bastian */ public abstract class GLAbstractListener implements GLEventListener, VizArchitecture, GraphDrawable { //GLU protected static final GLU GLU = new GLU(); //Architecture protected GLAutoDrawable drawable; protected VizController vizController; protected VizModel vizModel; protected GraphIO graphIO; private long startTime = 0; protected float fps; protected float fpsAvg = 0; protected float fpsCount = 0; private boolean showGLLog = true; private volatile boolean resizing = false; public final float viewField = 30.0f; public final float nearDistance = 1.0f; public final float farDistance = 150000f; private double aspectRatio = 0; protected float globalScale = 1f; protected FloatBuffer projMatrix = Buffers.newDirectFloatBuffer(16); protected FloatBuffer modelMatrix = Buffers.newDirectFloatBuffer(16); protected IntBuffer viewport = Buffers.newDirectIntBuffer(4); protected GraphicalConfiguration graphicalConfiguration; protected GLWindow window; public Component graphComponent; protected AbstractEngine engine; protected Scheduler scheduler; protected float[] cameraLocation; protected float[] cameraTarget; protected double[] draggingMarker = new double[2];//The drag mesure for a moving of 1 to the viewport protected Vec3f cameraVector = new Vec3f(); protected MouseAdapter graphMouseAdapterNewt; protected java.awt.event.MouseAdapter graphMouseAdapterCanvas; protected GraphMouseAdapter graphMouseAdapter; public GLAbstractListener() { this.vizController = VizController.getInstance(); } protected void initDrawable(GLAutoDrawable drawable) { this.drawable = drawable; drawable.addGLEventListener(this); } @Override public void initArchitecture() { this.engine = VizController.getInstance().getEngine(); this.scheduler = VizController.getInstance().getScheduler(); this.graphIO = VizController.getInstance().getGraphIO(); cameraLocation = vizController.getVizConfig().getDefaultCameraPosition(); cameraTarget = vizController.getVizConfig().getDefaultCameraTarget(); //Mouse events if (vizController.getVizConfig().isReduceFpsWhenMouseOut() || vizController.getVizConfig().isPauseLoopWhenMouseOut()) { graphMouseAdapter = new GraphMouseAdapter(); if (window != null) { graphMouseAdapterNewt = new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { graphMouseAdapter.mouseEntered(); } @Override public void mouseExited(MouseEvent e) { graphMouseAdapter.mouseExited(); } }; window.addMouseListener(graphMouseAdapterNewt); } else { graphMouseAdapterCanvas = new java.awt.event.MouseAdapter() { @Override public void mouseEntered(java.awt.event.MouseEvent e) { graphMouseAdapter.mouseEntered(); } @Override public void mouseExited(java.awt.event.MouseEvent e) { graphMouseAdapter.mouseExited(); } }; graphComponent.addMouseListener(graphMouseAdapterCanvas); } } } protected abstract void init(GL2 gl); protected abstract void render3DScene(GL2 gl, GLU glu); protected abstract void reshape3DScene(GL2 gl); protected GLCapabilities getCaps() { GLProfile profile = GLProfile.get(GLProfile.GL2); GLCapabilities caps = new GLCapabilities(profile); try { caps.setAlphaBits(8); //if NOT opaque caps.setDoubleBuffered(true); caps.setHardwareAccelerated(true); //FSAA int antialisaing = vizController.getVizConfig().getAntialiasing(); switch (antialisaing) { case 0: caps.setSampleBuffers(false); break; case 2: caps.setSampleBuffers(true); caps.setNumSamples(2); break; case 4: caps.setSampleBuffers(true); caps.setNumSamples(4); break; case 8: caps.setSampleBuffers(true); caps.setNumSamples(8); break; case 16: caps.setSampleBuffers(true); caps.setNumSamples(16); break; default: } } catch (com.jogamp.opengl.GLException ex) { Exceptions.printStackTrace(ex); } return caps; } @Override public void initConfig(GL2 gl) { //Disable Vertical synchro gl.setSwapInterval(0); //Config gl.glDisable(GL2.GL_DEPTH_TEST); //Z is set by the order of drawing gl.glDisable(GL2.GL_POINT_SMOOTH); gl.glDisable(GL2.GL_LINE_SMOOTH); gl.glClearDepth(1.0f); //Background Color backgroundColor = vizController.getVizModel().getBackgroundColor(); gl.glClearColor(backgroundColor.getRed() / 255f, backgroundColor.getGreen() / 255f, backgroundColor.getBlue() / 255f, 1f); //Blending if (vizController.getVizConfig().isBlending()) { gl.glEnable(GL2.GL_BLEND); gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); //Use alpha values correctly } //Lighting gl.glDisable(GL2.GL_LIGHTING); gl.glShadeModel(GL2.GL_FLAT); //Mesh view if (vizController.getVizConfig().isWireFrame()) { gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); } // Bug: Black faces when enabled // gl.glEnable(GL2.GL_TEXTURE_2D); } @Override public void init(GLAutoDrawable drawable) { GL2 gl = drawable.getGL().getGL2(); graphicalConfiguration = new GraphicalConfiguration(); graphicalConfiguration.checkGeneralCompatibility(gl); //Reinit viewport, to ensure reshape to perform viewport = Buffers.newDirectIntBuffer(4); resizing = false; initConfig(gl); // graphComponent.setCursor(Cursor.getDefaultCursor()); engine.initEngine(gl, GLU); init(gl); } public void refreshDraggingMarker() { //Refresh dragging marker /*DoubleBuffer objPos = BufferUtil.newDoubleBuffer(3); glu.gluProject(0, 0, 0, modelMatrix, projMatrix, viewport, objPos); double dxx = objPos.get(0); double dyy = objPos.get(1); glu.gluProject(1, 1, 0, modelMatrix, projMatrix, viewport, objPos); draggingMarker[0] = dxx - objPos.get(0); draggingMarker[1] = dyy - objPos.get(1); System.out.print(draggingMarker[0]);*/ float[] d = myGluProject(0, 0, 0); float[] d2 = myGluProject(1, 1, 0); draggingMarker[0] = d[0] - d2[0]; draggingMarker[1] = d[1] - d2[1]; } @Override public void setCameraPosition(GL2 gl, GLU glu) { //Refresh rotation angle gl.glLoadIdentity(); glu.gluLookAt(cameraLocation[0], cameraLocation[1], cameraLocation[2], cameraTarget[0], cameraTarget[1], cameraTarget[2], 0, 1, 0); gl.glScalef(globalScale, globalScale, 1f); gl.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, modelMatrix); cameraVector.set(cameraTarget[0] - cameraLocation[0], cameraTarget[1] - cameraLocation[1], cameraTarget[2] - cameraLocation[2]); refreshDraggingMarker(); } @Override public void display(GLAutoDrawable drawable) { //FPS if (startTime == 0) { startTime = System.currentTimeMillis() - 1; } long endTime = System.currentTimeMillis(); long delta = endTime - startTime; startTime = endTime; fps = 1000.0f / delta; if (fps < 100) { fpsAvg = (fpsAvg * fpsCount + fps) / ++fpsCount; } GL2 gl = drawable.getGL().getGL2(); gl.glClear(GL2.GL_COLOR_BUFFER_BIT); render3DScene(gl, GLU); scheduler.display(gl, GLU); // renderTestCube(gl); } @Override public void display() { drawable.display(); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { if (!resizing) { if (viewport.get(2) == width && viewport.get(3) == height) { return; } resizing = true; if (height == 0) { height = 1; } if (width == 0) { width = 1; } int viewportW, viewportH, viewportX, viewportY; aspectRatio = (double) width / (double) height; viewportH = height; viewportW = (int) (height * aspectRatio); if (viewportW > width) { viewportW = width; viewportH = (int) (width * (1 / aspectRatio)); } viewportX = ((width - viewportW) / 2); viewportY = ((height - viewportH) / 2); GL2 gl = drawable.getGL().getGL2(); gl.glViewport(viewportX, viewportY, viewportW, viewportH); gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport);//Update viewport buffer gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(viewField, aspectRatio, nearDistance, farDistance); gl.glGetFloatv(GL2.GL_PROJECTION_MATRIX, projMatrix);//Update projection buffer gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); setCameraPosition(gl, GLU); reshape3DScene(drawable.getGL().getGL2()); if (showGLLog) { showGLLog = false; Logger logger = Logger.getLogger(""); logger.log(Level.INFO, "GL_VENDOR: {0}", gl.glGetString(GL2.GL_VENDOR)); logger.log(Level.INFO, "GL_RENDERER: {0}", gl.glGetString(GL2.GL_RENDERER)); logger.log(Level.INFO, "GL_VERSION: {0}", gl.glGetString(GL2.GL_VERSION)); logger.log(Level.INFO, "GL_SURFACE_SCALE: {0}", globalScale); } resizing = false; } } @Override public void destroy() { if (graphMouseAdapterNewt != null) { window.removeMouseListener(graphMouseAdapterNewt); } else if (graphMouseAdapterCanvas != null) { graphComponent.removeMouseListener(graphMouseAdapterCanvas); } graphMouseAdapter = null; drawable.destroy(); } // TEST CUBE CODE BEGIN private static float rotateFactor = 15f; public void renderTestCube(GL2 gl) { float cubeSize = 1f; gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); GLU.gluLookAt(cameraLocation[0], cameraLocation[1], cameraLocation[2], cameraTarget[0], cameraTarget[1], cameraTarget[2], 0, 1, 0); gl.glColor3f(0f, 0f, 0f); gl.glRotatef(rotateFactor++ % 360f, 0.0f, 1.0f, 0.0f); // Rotate The cube around the Y axis gl.glRotatef(15.0f, 1.0f, 1.0f, 1.0f); gl.glBegin(GL2.GL_QUADS); // Draw The Cube Using quads gl.glColor3f(0.0f, 1.0f, 0.0f); // Color Green gl.glVertex3f(cubeSize, cubeSize, -cubeSize); // Top Right Of The Quad (Top) gl.glVertex3f(-cubeSize, cubeSize, -cubeSize); // Top Left Of The Quad (Top) gl.glVertex3f(-cubeSize, cubeSize, cubeSize); // Bottom Left Of The Quad (Top) gl.glVertex3f(cubeSize, cubeSize, cubeSize); // Bottom Right Of The Quad (Top) gl.glColor3f(1.0f, 0.5f, 0.0f); // Color Orange gl.glVertex3f(cubeSize, -cubeSize, cubeSize); // Top Right Of The Quad (Bottom) gl.glVertex3f(-cubeSize, -cubeSize, cubeSize); // Top Left Of The Quad (Bottom) gl.glVertex3f(-cubeSize, -cubeSize, -cubeSize); // Bottom Left Of The Quad (Bottom) gl.glVertex3f(cubeSize, -cubeSize, -cubeSize); // Bottom Right Of The Quad (Bottom) gl.glColor3f(1.0f, 0.0f, 0.0f); // Color Red gl.glVertex3f(cubeSize, cubeSize, cubeSize); // Top Right Of The Quad (Front) gl.glVertex3f(-cubeSize, cubeSize, cubeSize); // Top Left Of The Quad (Front) gl.glVertex3f(-cubeSize, -cubeSize, cubeSize); // Bottom Left Of The Quad (Front) gl.glVertex3f(cubeSize, -cubeSize, cubeSize); // Bottom Right Of The Quad (Front) gl.glColor3f(1.0f, 1.0f, 0.0f); // Color Yellow gl.glVertex3f(cubeSize, -cubeSize, -cubeSize); // Top Right Of The Quad (Back) gl.glVertex3f(-cubeSize, -cubeSize, -cubeSize); // Top Left Of The Quad (Back) gl.glVertex3f(-cubeSize, cubeSize, -cubeSize); // Bottom Left Of The Quad (Back) gl.glVertex3f(cubeSize, cubeSize, -cubeSize); // Bottom Right Of The Quad (Back) gl.glColor3f(0.0f, 0.0f, 1.0f); // Color Blue gl.glVertex3f(-cubeSize, cubeSize, cubeSize); // Top Right Of The Quad (Left) gl.glVertex3f(-cubeSize, cubeSize, -cubeSize); // Top Left Of The Quad (Left) gl.glVertex3f(-cubeSize, -cubeSize, -cubeSize); // Bottom Left Of The Quad (Left) gl.glVertex3f(-cubeSize, -cubeSize, cubeSize); // Bottom Right Of The Quad (Left) gl.glColor3f(1.0f, 0.0f, 1.0f); // Color Violet gl.glVertex3f(cubeSize, cubeSize, -cubeSize); // Top Right Of The Quad (Right) gl.glVertex3f(cubeSize, cubeSize, cubeSize); // Top Left Of The Quad (Right) gl.glVertex3f(cubeSize, -cubeSize, cubeSize); // Bottom Left Of The Quad (Right) gl.glVertex3f(cubeSize, -cubeSize, -cubeSize); // Bottom Right Of The Quad (Right) gl.glEnd(); // End Drawing The Cube } // TEST CUBE CODE END //Utils @Override public double[] myGluProject(float x, float y) { return myGluProject(x, y); } @Override public float[] myGluProject(float x, float y, float z) { float[] res = new float[2]; float o0 = modelMatrix.get(0) * x + modelMatrix.get(4) * y + modelMatrix.get(8) * z + modelMatrix.get(12) * 1f; float o1 = modelMatrix.get(1) * x + modelMatrix.get(5) * y + modelMatrix.get(9) * z + modelMatrix.get(13) * 1f; float o2 = modelMatrix.get(2) * x + modelMatrix.get(6) * y + modelMatrix.get(10) * z + modelMatrix.get(14) * 1f; float o3 = modelMatrix.get(3) * x + modelMatrix.get(7) * y + modelMatrix.get(11) * z + modelMatrix.get(15) * 1f; float p0 = projMatrix.get(0) * o0 + projMatrix.get(4) * o1 + projMatrix.get(8) * o2 + projMatrix.get(12) * o3; float p1 = projMatrix.get(1) * o0 + projMatrix.get(5) * o1 + projMatrix.get(9) * o2 + projMatrix.get(13) * o3; float p2 = projMatrix.get(2) * o0 + projMatrix.get(6) * o1 + projMatrix.get(10) * o2 + projMatrix.get(14) * o3; float p3 = projMatrix.get(3) * o0 + projMatrix.get(7) * o1 + projMatrix.get(11) * o2 + projMatrix.get(15) * o3; p0 /= p3; p1 /= p3; p2 /= p3; res[0] = viewport.get(0) + (p0 + 1) * viewport.get(2) / 2; res[1] = viewport.get(1) + viewport.get(3) * (p1 + 1) / 2; return res; } private double[] transformVect(double[] in, DoubleBuffer m) { double[] out = new double[4]; out[0] = m.get(0) * in[0] + m.get(4) * in[1] + m.get(8) * in[2] + m.get(12) * in[3]; out[1] = m.get(1) * in[0] + m.get(5) * in[1] + m.get(9) * in[2] + m.get(13) * in[3]; out[2] = m.get(2) * in[0] + m.get(6) * in[1] + m.get(10) * in[2] + m.get(14) * in[3]; out[3] = m.get(3) * in[0] + m.get(7) * in[1] + m.get(11) * in[2] + m.get(15) * in[3]; return out; } public GL2 getGL() { return drawable.getGL().getGL2(); } public void setVizController(VizController vizController) { this.vizController = vizController; } public GLAutoDrawable getGLAutoDrawable() { return drawable; } @Override public GraphicalConfiguration getGraphicalConfiguration() { return graphicalConfiguration; } protected void resetFpsAverage() { fpsAvg = 0; fpsCount = 0; } protected float getFpsAverage() { return fpsAvg; } @Override public float[] getCameraLocation() { return cameraLocation; } @Override public void setCameraLocation(float[] cameraLocation) { this.cameraLocation = cameraLocation; } @Override public float[] getCameraTarget() { return cameraTarget; } @Override public void setCameraTarget(float[] cameraTarget) { this.cameraTarget = cameraTarget; } @Override public Component getGraphComponent() { return graphComponent; } @Override public Vec3f getCameraVector() { return cameraVector; } @Override public int getViewportHeight() { return viewport.get(3); } @Override public int getViewportWidth() { return viewport.get(2); } @Override public double getDraggingMarkerX() { return draggingMarker[0]; } @Override public double getDraggingMarkerY() { return draggingMarker[1]; } @Override public FloatBuffer getProjectionMatrix() { return projMatrix; } public FloatBuffer getModelMatrix() { return modelMatrix; } @Override public IntBuffer getViewport() { return viewport; } @Override public float getGlobalScale() { return globalScale; } @Override public void dispose(GLAutoDrawable glad) { engine.stopDisplay(); VizController.getInstance().getDataBridge().reset(); } @Override public Point getLocationOnScreen() { return graphComponent.getLocationOnScreen(); } private class GraphMouseAdapter { final boolean pause = vizController.getVizConfig().isPauseLoopWhenMouseOut(); final int minVal = vizController.getVizConfig().getReduceFpsWhenMouseOutValue(); final int maxVal = 30; private float lastTarget = 0.1f; private void mouseEntered() { if (pause) { engine.resumeDisplay(); } else { if (!scheduler.isAnimating()) { engine.resumeDisplay(); } scheduler.setFps(maxVal); resetFpsAverage(); } } private void mouseExited() { if (pause) { engine.pauseDisplay(); } else { float fps = getFpsAverage(); float target = (float) (fps / (1. / Math.sqrt(getFpsAverage()) * 10.)); if (fps == 0f) { target = lastTarget; } if (target <= 0.005f) { engine.pauseDisplay(); } else if (target > minVal) { target = minVal; } lastTarget = target; scheduler.setFps(target); } } } }