/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.visualization.opengl;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.gephi.visualization.apiimpl.ModelImpl;
import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;
import org.gephi.graph.api.Model;
import org.gephi.graph.api.Renderable;
import org.gephi.visualization.VizArchitecture;
import org.gephi.visualization.VizController;
import org.gephi.visualization.apiimpl.Engine;
import org.gephi.visualization.apiimpl.GraphIO;
import org.gephi.visualization.apiimpl.VizEventManager;
import org.gephi.visualization.api.objects.ModelClass;
import org.gephi.visualization.api.objects.ModelClassLibrary;
import org.gephi.visualization.apiimpl.Scheduler;
import org.gephi.visualization.apiimpl.VizConfig;
import org.gephi.visualization.api.selection.SelectionArea;
import org.gephi.visualization.bridge.DataBridge;
import org.gephi.visualization.bridge.EventBridge;
import org.gephi.lib.gleem.linalg.Vecf;
import org.gephi.visualization.mode.ModeManager;
import org.gephi.visualization.opengl.octree.Octree;
import org.gephi.visualization.opengl.text.TextManager;
import org.gephi.visualization.swing.GraphDrawableImpl;
/**
* Abstract graphic engine. Real graphic engines inherit from this class and can use the common functionalities.
*
* @author Mathieu Bastian
*/
public abstract class AbstractEngine implements Engine, VizArchitecture {
//Enums
public enum Limits {
MIN_X, MAX_X, MIN_Y, MAX_Y, MIN_Z, MAX_Z
};
public static final int CLASS_NODE = 0;
public static final int CLASS_EDGE = 1;
public static final int CLASS_ARROW = 2;
public static final int CLASS_POTATO = 3;
//Architecture
protected GraphDrawableImpl graphDrawable;
protected GraphIO graphIO;
protected VizEventManager vizEventManager;
protected SelectionArea currentSelectionArea;
protected ModelClassLibrary modelClassLibrary;
protected DataBridge dataBridge;
protected EventBridge eventBridge;
protected VizController vizController;
protected VizConfig vizConfig;
protected ModeManager modeManager;
protected TextManager textManager;
//States
protected boolean rectangleSelection;
protected boolean customSelection;
protected EngineLifeCycle lifeCycle = new EngineLifeCycle();
protected boolean configChanged = false;
protected boolean backgroundChanged = false;
protected boolean reinit = false;
protected float lightenAnimationDelta = 0f;
//Octree
protected Octree octree;
public void initArchitecture() {
this.graphDrawable = VizController.getInstance().getDrawable();
this.graphIO = VizController.getInstance().getGraphIO();
this.modelClassLibrary = VizController.getInstance().getModelClassLibrary();
this.dataBridge = VizController.getInstance().getDataBridge();
this.eventBridge = VizController.getInstance().getEventBridge();
this.vizController = VizController.getInstance();
this.vizConfig = VizController.getInstance().getVizConfig();
this.modeManager = VizController.getInstance().getModeManager();
this.textManager = VizController.getInstance().getTextManager();
initObject3dClass();
initSelection();
//Vizconfig events
vizController.getVizModel().addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
configChanged = true;
if (evt.getPropertyName().equals("backgroundColor")) {
backgroundChanged = true;
} else if (evt.getPropertyName().equals("use3d")) {
reinit = true;
}
getModelClasses()[AbstractEngine.CLASS_EDGE].setEnabled(vizController.getVizModel().isShowEdges());
getModelClasses()[AbstractEngine.CLASS_ARROW].setEnabled(vizController.getVizModel().isShowEdges() && vizConfig.isShowArrows());
getModelClasses()[AbstractEngine.CLASS_POTATO].setEnabled(vizController.getVizModel().isShowHulls());
}
});
}
public abstract void beforeDisplay(GL gl, GLU glu);
public abstract void display(GL gl, GLU glu);
public abstract void afterDisplay(GL gl, GLU glu);
public abstract void initEngine(GL gl, GLU glu);
public abstract void initScreenshot(GL gl, GLU glu);
public abstract void cameraHasBeenMoved(GL gl, GLU glu);
public abstract void mouseMove();
public abstract void mouseDrag();
public abstract void startDrag();
public abstract void stopDrag();
public abstract void mouseClick();
public abstract Scheduler getScheduler();
public abstract void addObject(int classID, ModelImpl obj);
public abstract void removeObject(int classID, ModelImpl obj);
public abstract void worldUpdated(int cacheMarker);
public abstract void updateObjectsPosition();
public abstract boolean updateWorld();
public abstract void refreshGraphLimits();
public abstract void initObject3dClass();
public abstract void initSelection();
public abstract ModelClass[] getModelClasses();
protected abstract void startAnimating();
protected abstract void stopAnimating();
public abstract ModelImpl[] getSelectedObjects(int modelClass);
public abstract void selectObject(Model obj);
public abstract void selectObject(Model[] objs);
public abstract void resetSelection();
/**
* Reset contents of octree for the given class
*/
public abstract void resetObjectClass(ModelClass object3dClass);
public float cameraDistance(ModelImpl object) {
float[] cameraLocation = graphDrawable.getCameraLocation();
double distance = Math.sqrt(Math.pow((double) object.getObj().x() - cameraLocation[0], 2d)
+ Math.pow((double) object.getObj().y() - cameraLocation[1], 2d)
+ Math.pow((double) object.getObj().z() - cameraLocation[2], 2d));
object.setCameraDistance((float) distance);
return (float) distance - object.getObj().getRadius();
}
protected void setViewportPosition(ModelImpl object) {
double[] res = graphDrawable.myGluProject(object.getObj().x(), object.getObj().y(), object.getObj().z());
object.setViewportX((float) res[0]);
object.setViewportY((float) res[1]);
res = graphDrawable.myGluProject(object.getObj().x() + object.getObj().getRadius(), object.getObj().y(), object.getObj().z());
float rad = Math.abs((float) res[0] - object.getViewportX());
object.setViewportRadius(rad);
}
public void reinit() {
reinit = true;
}
protected boolean isUnderMouse(ModelImpl obj) {
if (vizConfig.isEnableAutoSelect() && obj.isAutoSelected()) {
return true;
}
if (obj.onlyAutoSelect()) {
return false;
}
if (!currentSelectionArea.isEnabled()) {
return false;
}
float x1 = graphIO.getMousePosition()[0];
float y1 = graphIO.getMousePosition()[1];
float x2 = obj.getViewportX();
float y2 = obj.getViewportY();
float xDist = Math.abs(x2 - x1);
float yDist = Math.abs(y2 - y1);
float distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
Vecf d = new Vecf(5);
d.set(0, xDist);
d.set(1, yDist);
d.set(2, distance);
return currentSelectionArea.mouseTest(d, obj);
}
public SelectionArea getCurrentSelectionArea() {
return currentSelectionArea;
}
public boolean isRectangleSelection() {
return rectangleSelection;
}
public void setRectangleSelection(boolean rectangleSelection) {
vizConfig.setRectangleSelection(rectangleSelection);
configChanged = true;
lightenAnimationDelta = 0;
vizConfig.setLightenNonSelected(false);
}
public void setConfigChanged(boolean configChanged) {
this.configChanged = configChanged;
}
public void startDisplay() {
lifeCycle.requestStartAnimating();
}
public void stopDisplay() {
lifeCycle.requestStopAnimating();
}
public Octree getOctree() {
return octree;
}
protected class EngineLifeCycle {
private boolean inited;
private boolean requestAnimation;
public void requestStartAnimating() {
if (inited) {
startAnimating();
} else {
requestAnimation = true;
}
}
public void requestStopAnimating() {
if (inited) {
stopAnimating();
}
}
public void initEngine() {
}
public boolean isInited() {
return inited;
}
public void setInited() {
if (!inited) {
inited = true;
if (requestAnimation) {
//graphDrawable.display();
startAnimating();
requestAnimation = false;
}
} else {
dataBridge.reset();
textManager.initArchitecture();
}
}
}
}