package org.jzy3d.plot3d.rendering.view;
import java.util.ArrayList;
import java.util.List;
import org.jzy3d.chart.Chart;
import org.jzy3d.chart.factories.IChartComponentFactory;
import org.jzy3d.colors.Color;
import org.jzy3d.events.IViewIsVerticalEventListener;
import org.jzy3d.events.IViewLifecycleEventListener;
import org.jzy3d.events.IViewPointChangedListener;
import org.jzy3d.events.ViewIsVerticalEvent;
import org.jzy3d.events.ViewLifecycleEvent;
import org.jzy3d.events.ViewPointChangedEvent;
import org.jzy3d.maths.BoundingBox3d;
import org.jzy3d.maths.Coord2d;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Rectangle;
import org.jzy3d.plot3d.primitives.axes.AxeBox;
import org.jzy3d.plot3d.primitives.axes.IAxe;
import org.jzy3d.plot3d.rendering.canvas.ICanvas;
import org.jzy3d.plot3d.rendering.canvas.Quality;
import org.jzy3d.plot3d.rendering.compat.GLES2CompatUtils;
import org.jzy3d.plot3d.rendering.lights.LightSet;
import org.jzy3d.plot3d.rendering.scene.Graph;
import org.jzy3d.plot3d.rendering.scene.Scene;
import org.jzy3d.plot3d.rendering.view.modes.CameraMode;
import org.jzy3d.plot3d.rendering.view.modes.ViewBoundMode;
import org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode;
import org.jzy3d.plot3d.transform.Scale;
import org.jzy3d.plot3d.transform.Transform;
import org.jzy3d.plot3d.transform.space.SpaceTransformer;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL2ES1;
import com.jogamp.opengl.GL2GL3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLContext;
import com.jogamp.opengl.fixedfunc.GLLightingFunc;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.opengl.glu.GLU;
/**
* A {@link View} holds a {@link Scene}, a {@link LightSet}, an {@link ICanvas}
* to render into. It is the responsability to layout a set of concrete
* {@link AbstractViewportManager}s such as the {@Camera} rendering the
* scene or an {@link AWTImageViewport} for displaying an image in the same
* window. On can control the {@link Camera} with a {@ViewController
* } and get notifyed by a {@link IViewPointChangedListener}
* that the view point has changed. The control is relative to the center of the
* {@link Scene} and is defined using polar coordinates.
*
* The {@link View} supports post rendering through the addition of
* {@link Renderer2d}s whose implementation can define Java2d calls to render on
* top on OpenGL2.
*
* Last, the {@link View} offers the ability to get an {@link AxeBox} for
* embedding the {@link Scene} and getting values along axes.
*
* @author Martin Pernollet
*/
public class View {
/**
* Create a view attached to a Scene, with its own Camera and Axe. The
* initial view point is set at {@link View.DEFAULT_VIEW}.
*
* The {@link Quality} allows setting the rendering capabilities that are
* set one time by the init() method.
*/
public View(IChartComponentFactory factory, Scene scene, ICanvas canvas, Quality quality) {
BoundingBox3d sceneBounds = getSceneGraphBounds(scene);
this.viewpoint = DEFAULT_VIEW.clone();
this.center = sceneBounds.getCenter();
this.scaling = Coord3d.IDENTITY.clone();
this.viewmode = ViewPositionMode.FREE;
this.boundmode = ViewBoundMode.AUTO_FIT;
this.cameraMode = CameraMode.ORTHOGONAL;
this.axe = factory.newAxe(sceneBounds, this);
this.cam = factory.newCamera(center);
this.scene = scene;
this.canvas = canvas;
this.quality = quality;
this.annotations = factory.newScene(false);
this.viewOnTopListeners = new ArrayList();
this.viewPointChangedListeners = new ArrayList();
this.viewLifecycleListeners = new ArrayList();
this.wasOnTopAtLastRendering = false;
this.glu = new GLU();
this.scene.getGraph().getStrategy().setView(this);
this.spaceTransformer = new SpaceTransformer(); // apply no transform
current = this;
}
public Chart getChart() {
return chart;
}
public void setChart(Chart chart) {
this.chart = chart;
}
public boolean isSlave() {
return slave;
}
public void setSlave(boolean slave) {
this.slave = slave;
}
public void dispose() {
axe.dispose();
cam = null;
viewOnTopListeners.clear();
scene = null;
canvas = null;
quality = null;
}
/**
* Current view selection into the mother Scene, and call to target canvas
* rendering.
*/
public void shoot() {
canvas.forceRepaint();
}
public void project() {
GL gl = getCurrentGL();
scene.getGraph().project(gl, glu, cam);
getCurrentContext().release();
}
public Coord3d projectMouse(int x, int y) {
GL gl = getCurrentGL();
Coord3d p = cam.screenToModel(gl, glu, new Coord3d(x, y, 0));
getCurrentContext().release();
return p;
}
/******************************* GENERAL DISPLAY CONTROLS ***********************************/
public void rotate(final Coord2d move) {
rotate(move, true);
}
public void rotate(final Coord2d move, boolean updateView) {
Coord3d eye = getViewPoint();
eye.x -= move.x;
eye.y += move.y;
setViewPoint(eye, updateView);
// fireControllerEvent(ControllerType.ROTATE, eye);
}
public void shift(final float factor) {
shift(factor, true);
}
public void shift(final float factor, boolean updateView) {
org.jzy3d.maths.Scale current = getScale();
org.jzy3d.maths.Scale newScale = current.add(factor * current.getRange());
setScale(newScale, updateView);
// fireControllerEvent(ControllerType.SHIFT, newScale);
}
public void zoom(final float factor) {
zoom(factor, true);
}
public void zoom(final float factor, boolean updateView) {
org.jzy3d.maths.Scale current = getScale();
double range = current.getMax() - current.getMin();
if (range <= 0)
return;
float center = (current.getMax() + current.getMin()) / 2;
float zmin = center + (current.getMin() - center) * (factor);
float zmax = center + (current.getMax() - center) * (factor);
// set min/max according to bounds
org.jzy3d.maths.Scale scale = null;
if (zmin < zmax)
scale = new org.jzy3d.maths.Scale(zmin, zmax);
else {
if (factor < 1) // forbid to have zmin = zmax if we zoom in
scale = new org.jzy3d.maths.Scale(center, center);
}
if (scale != null) {
setScale(scale, updateView);
// fireControllerEvent(ControllerType.ZOOM, scale);
}
}
public void zoomX(final float factor) {
zoomX(factor, true);
}
public void zoomX(final float factor, boolean updateView) {
double range = getBounds().getXmax() - getBounds().getXmin();
if (range <= 0)
return;
float center = (getBounds().getXmax() + getBounds().getXmin()) / 2;
float min = center + (getBounds().getXmin() - center) * factor;
float max = center + (getBounds().getXmax() - center) * factor;
org.jzy3d.maths.Scale scale = null;
if (min < max)
scale = new org.jzy3d.maths.Scale(min, max);
else {
if (factor < 1) // forbid to have zmin = zmax if we zoom in
scale = new org.jzy3d.maths.Scale(center, center);
}
if (scale != null) {
BoundingBox3d bounds = getBounds();
bounds.setXmin(scale.getMin());
bounds.setXmax(scale.getMax());
setBoundManual(bounds);
if (updateView)
shoot();
// fireControllerEvent(ControllerType.ZOOM, scale);
}
}
public void zoomY(final float factor) {
zoomY(factor, true);
}
public void zoomY(final float factor, boolean updateView) {
double range = getBounds().getYmax() - getBounds().getYmin();
if (range <= 0)
return;
float center = (getBounds().getYmax() + getBounds().getYmin()) / 2;
float min = center + (getBounds().getYmin() - center) * factor;
float max = center + (getBounds().getYmax() - center) * factor;
org.jzy3d.maths.Scale scale = null;
if (min < max)
scale = new org.jzy3d.maths.Scale(min, max);
else {
if (factor < 1) // forbid to have zmin = zmax if we zoom in
scale = new org.jzy3d.maths.Scale(center, center);
}
if (scale != null) {
BoundingBox3d bounds = getBounds();
bounds.setYmin(scale.getMin());
bounds.setYmax(scale.getMax());
setBoundManual(bounds);
if (updateView)
shoot();
// fireControllerEvent(ControllerType.ZOOM, scale);
}
}
public void zoomZ(final float factor) {
zoomZ(factor, true);
}
public void zoomZ(final float factor, boolean updateView) {
double range = getBounds().getZmax() - getBounds().getZmin();
if (range <= 0)
return;
float center = (getBounds().getZmax() + getBounds().getZmin()) / 2;
float min = center + (getBounds().getZmin() - center) * factor;
float max = center + (getBounds().getZmax() - center) * factor;
org.jzy3d.maths.Scale scale = null;
if (min < max)
scale = new org.jzy3d.maths.Scale(min, max);
else {
if (factor < 1) // forbid to have zmin = zmax if we zoom in
scale = new org.jzy3d.maths.Scale(center, center);
}
if (scale != null) {
BoundingBox3d bounds = getBounds();
bounds.setZmin(scale.getMin());
bounds.setZmax(scale.getMax());
setBoundManual(bounds);
if (updateView)
shoot();
// fireControllerEvent(ControllerType.ZOOM, scale);
}
}
/**
* Z scale.
*
* @see setScaleX, setScaleY, setScaleZ
*/
public void setScale(org.jzy3d.maths.Scale scale) {
setScaleZ(scale, true);
}
/**
* Z scale.
*
* @see setScaleX, setScaleY, setScaleZ
*/
public void setScale(org.jzy3d.maths.Scale scale, boolean notify) {
setScaleZ(scale, notify);
}
public void setScaleX(org.jzy3d.maths.Scale scale) {
setScaleX(scale, true);
}
public void setScaleX(org.jzy3d.maths.Scale scale, boolean notify) {
BoundingBox3d bounds = getBounds();
bounds.setXmin(scale.getMin());
bounds.setXmax(scale.getMax());
setBoundManual(bounds);
if (notify)
shoot();
}
public void setScaleY(org.jzy3d.maths.Scale scale) {
setScaleY(scale, true);
}
public void setScaleY(org.jzy3d.maths.Scale scale, boolean notify) {
BoundingBox3d bounds = getBounds();
bounds.setYmin(scale.getMin());
bounds.setYmax(scale.getMax());
setBoundManual(bounds);
if (notify)
shoot();
}
public void setScaleZ(org.jzy3d.maths.Scale scale) {
setScaleZ(scale, true);
}
public void setScaleZ(org.jzy3d.maths.Scale scale, boolean notify) {
BoundingBox3d bounds = getBounds();
bounds.setZmin(scale.getMin());
bounds.setZmax(scale.getMax());
setBoundManual(bounds);
if (notify)
shoot();
}
public org.jzy3d.maths.Scale getScale() {
return new org.jzy3d.maths.Scale(getBounds().getZmin(), getBounds().getZmax());
}
/**
* Set the surrounding AxeBox dimensions and the Camera target, and the
* colorbar range.
*/
public void lookToBox(BoundingBox3d box) {
if (box.isReset())
return;
center = box.getTransformedCenter(spaceTransformer);
axe.setAxe(box);
viewbounds = box;
}
/**
* Return the central point of the view scene, that is the last bounding box
* center set by {@link lookToBox(BoundingBox3d box)}
*/
public Coord3d getCenter() {
return center;
}
/** Get the {@link AxeBox}'s {@link BoundingBox3d} */
public BoundingBox3d getBounds() {
return axe.getBoxBounds();
}
public ViewBoundMode getBoundsMode() {
return boundmode;
}
/** Set the {@link ViewPositionMode} applied to this view. */
public void setViewPositionMode(ViewPositionMode mode) {
this.viewmode = mode;
}
/** Return the {@link ViewPositionMode} applied to this view. */
public ViewPositionMode getViewMode() {
return viewmode;
}
/**
* Set the viewpoint using polar coordinates relative to the target (i.e.
* the center of the scene). Only X and Y dimensions are required, as the
* distance to center will be computed automatically by {@link
* updateCamera()}.
*/
public void setViewPoint(Coord3d polar, boolean updateView) {
viewpoint = polar;
viewpoint.y = viewpoint.y < -PI_div2 ? -PI_div2 : viewpoint.y;
viewpoint.y = viewpoint.y > PI_div2 ? PI_div2 : viewpoint.y;
if (updateView)
shoot();
fireViewPointChangedEvent(new ViewPointChangedEvent(this, polar));
}
/**
* Set the viewpoint and query a view update.
*
* @see {@link setViewPoint(Coord3d polar, boolean updateView)}
*/
public void setViewPoint(Coord3d polar) {
setViewPoint(polar, true);
}
/**
* Get the viewpoint. The Z dimension is the one defined by {@link
* updateCamera()}, which depends on the view scaling.
*
* @see {@link setViewPoint(Coord3d polar, boolean updateView)}
*/
public Coord3d getViewPoint() {
return viewpoint;
}
/**
* Return the last used view scaling that was set according to the {@link
* setSquared(boolean v)} status.
*/
public Coord3d getLastViewScaling() {
return scaling;
}
/* CONTROLS ANNOTATIONS & GENERAL RENDERING */
public void setAxe(IAxe ax) {
axe = ax;
updateBounds();
}
public IAxe getAxe() {
return axe;
}
public boolean getSquared() {
return this.squared;
}
public void setSquared(boolean status) {
this.squared = status;
}
public boolean isAxeBoxDisplayed() {
return axeBoxDisplayed;
}
public void setAxeBoxDisplayed(boolean axeBoxDisplayed) {
this.axeBoxDisplayed = axeBoxDisplayed;
}
public void setBackgroundColor(Color color) {
bgColor = color;
}
public Color getBackgroundColor() {
return bgColor;
}
public Camera getCamera() {
return cam;
}
/**
* Set the projection of this view, either Camera.ORTHOGONAL or
* Camera.PERSPECTIVE.
*/
public void setCameraMode(CameraMode mode) {
this.cameraMode = mode;
}
/**
* Get the projection of this view, either CameraMode.ORTHOGONAL or
* CameraMode.PERSPECTIVE.
*/
public CameraMode getCameraMode() {
return cameraMode;
}
public void setMaximized(boolean status) {
if (status)
this.cam.setViewportMode(ViewportMode.STRETCH_TO_FILL);
else
this.cam.setViewportMode(ViewportMode.RECTANGLE_NO_STRETCH);
}
public Scene getScene() {
return scene;
}
public Rectangle getSceneViewportRectangle() {
return cam.getRectangle();
}
public ICanvas getCanvas() {
return canvas;
}
public Graph getAnnotations() {
return annotations.getGraph();
}
public boolean addViewOnTopEventListener(IViewIsVerticalEventListener listener) {
return viewOnTopListeners.add(listener);
}
public boolean removeViewOnTopEventListener(IViewIsVerticalEventListener listener) {
return viewOnTopListeners.remove(listener);
}
protected void fireViewOnTopEvent(boolean isOnTop) {
ViewIsVerticalEvent e = new ViewIsVerticalEvent(this);
if (isOnTop)
for (IViewIsVerticalEventListener listener : viewOnTopListeners)
listener.viewVerticalReached(e);
else
for (IViewIsVerticalEventListener listener : viewOnTopListeners)
listener.viewVerticalLeft(e);
}
public boolean addViewPointChangedListener(IViewPointChangedListener listener) {
return viewPointChangedListeners.add(listener);
}
public boolean removeViewPointChangedListener(IViewPointChangedListener listener) {
return viewPointChangedListeners.remove(listener);
}
protected void fireViewPointChangedEvent(ViewPointChangedEvent e) {
for (IViewPointChangedListener vp : viewPointChangedListeners)
vp.viewPointChanged(e);
}
public boolean addViewLifecycleChangedListener(IViewLifecycleEventListener listener) {
return viewLifecycleListeners.add(listener);
}
public boolean removeViewLifecycleChangedListener(IViewLifecycleEventListener listener) {
return viewLifecycleListeners.remove(listener);
}
protected void fireViewLifecycleHasInit(ViewLifecycleEvent e) {
for (IViewLifecycleEventListener vp : viewLifecycleListeners)
vp.viewHasInit(e);
}
protected void fireViewLifecycleWillRender(ViewLifecycleEvent e) {
for (IViewLifecycleEventListener vp : viewLifecycleListeners)
vp.viewWillRender(e);
}
/* */
/**
* Select between an automatic bounding (that allows fitting the entire
* scene graph), or a custom bounding.
*/
public void setBoundMode(ViewBoundMode mode) {
boundmode = mode;
updateBounds();
}
/**
* Set the bounds of the view according to the current {@link ViewBoundMode}
* , and orders a {@link Camera.shoot()}.
*/
public void updateBounds() {
if (boundmode == ViewBoundMode.AUTO_FIT)
lookToBox(getSceneGraphBounds()); // set axe and camera
else if (boundmode == ViewBoundMode.MANUAL)
lookToBox(viewbounds); // set axe and camera
else
throw new RuntimeException("Unknown bounds");
shoot();
}
protected BoundingBox3d getSceneGraphBounds() {
return getSceneGraphBounds(scene);
}
protected BoundingBox3d getSceneGraphBounds(Scene scene) {
return scene.getGraph().getBounds();
}
/**
* Update the bounds according to the scene graph whatever is the current
* {@link ViewBoundMode}, and orders a {@link Camera.shoot()}
*/
public void updateBoundsForceUpdate(boolean refresh) {
lookToBox(getSceneGraphBounds());
if (refresh)
shoot();
}
/**
* Set a manual bounding box and switch the bounding mode to
* {ViewBoundMode.MANUAL}, meaning that any call to {@link updateBounds()}
* will update view bounds to the current bounds.
*/
public void setBoundManual(BoundingBox3d bounds) {
// viewbounds = bounds;
boundmode = ViewBoundMode.MANUAL;
lookToBox(bounds);
}
/**
* Return a 3d scaling factor that allows scaling the scene into a square
* box, according to the current ViewBoundMode.
*
* If the scene bounds are Infinite, NaN or zero, for a given dimension, the
* scaler will be set to 1 on the given dimension.
*
* @return a scaling factor for each dimension.
*/
protected Coord3d squarify() {
// Get the view bounds
BoundingBox3d bounds;
if (boundmode == ViewBoundMode.AUTO_FIT)
bounds = scene.getGraph().getBounds();
else if (boundmode == ViewBoundMode.MANUAL)
bounds = viewbounds;
else {
throw new RuntimeException("Unknown bounds mode");
}
// Compute factors
float xLen = 1;
float yLen = 1;
float zLen = 1;
float lmax = 1;
if (bounds != null) {
xLen = spaceTransformer.getX().compute(bounds.getXmax()) - spaceTransformer.getX().compute(bounds.getXmin());
yLen = spaceTransformer.getY().compute(bounds.getYmax()) - spaceTransformer.getY().compute(bounds.getYmin());
zLen = spaceTransformer.getZ().compute(bounds.getZmax()) - spaceTransformer.getZ().compute(bounds.getZmin());
lmax = Math.max(Math.max(xLen, yLen), zLen);
}
if (Float.isInfinite(xLen) || Float.isNaN(xLen) || xLen == 0)
xLen = 1;
if (Float.isInfinite(yLen) || Float.isNaN(yLen) || yLen == 0)
yLen = 1;
if (Float.isInfinite(zLen) || Float.isNaN(zLen) || zLen == 0)
zLen = 1;
if (Float.isInfinite(lmax) || Float.isNaN(lmax) || lmax == 0)
lmax = 1;
// Return a scaler
float xscale = (float) ((double) lmax / (double) xLen);
float yscale = (float) ((double) lmax / (double) yLen);
float zscale = (float) ((double) lmax / (double) zLen);
return new Coord3d(xscale, yscale, zscale);
}
/* GL */
public GL getCurrentGL() {
getCurrentContext().makeCurrent();
return getCanvasAsGLAutoDrawable().getGL().getGL2();
}
public GLContext getCurrentContext() {
GLAutoDrawable c = getCanvasAsGLAutoDrawable();
GLContext context = c.getContext();
return context;
}
protected GLAutoDrawable getCanvasAsGLAutoDrawable() {
if (canvas instanceof GLAutoDrawable) {
// this covers AWT and Swing
return ((GLAutoDrawable) canvas);
} else if (canvas.getDrawable() instanceof GLAutoDrawable) {
// this also covers NEWT and Offscreen
return ((GLAutoDrawable) canvas.getDrawable());
} else
throw new RuntimeException("Unexpected instance type : " + canvas.getClass().toString());
}
/**
* The initialization function:
*
* - specifies general GL settings that impact the rendering quality and
* performance (computation speed).
*
- enable light management
*
- load all required texture resources
*
- fix the current view bounds to the whole scene graph bounds
*
*
* The rendering settings are set by the {@link Quality} given in the
* constructor parameters.
*/
public void init(GL gl) {
initQuality(gl);
initLights(gl);
initResources(gl);
if (viewbounds == null) {
if (initBounds == null)
setBoundManual(getScene().getGraph().getBounds());
else
setBoundManual(initBounds);
// boundmode = ViewBoundMode.AUTO_FIT;
} else {
lookToBox(viewbounds);
}
fireViewLifecycleHasInit(null);
}
public BoundingBox3d getInitBounds() {
return initBounds;
}
public void setInitBounds(BoundingBox3d initBounds) {
this.initBounds = initBounds;
}
public void initQuality(GL gl) {
// Activate Depth buffer
if (quality.isDepthActivated()) {
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
} else
gl.glDisable(GL.GL_DEPTH_TEST);
// Blending
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
// on/off is handled by each viewport (camera or image)
// Activate tranparency
if (quality.isAlphaActivated()) {
gl.glEnable(GL2ES1.GL_ALPHA_TEST);
if (quality.isDisableDepthBufferWhenAlpha())
/* seams better for transparent polygons since they're sorted */
gl.glDisable(GL.GL_DEPTH_TEST); // gl.glDepthFunc(GL2.GL_ALWAYS);
// gl.glAlphaFunc(GL2.GL_EQUAL,1.0f);
} else {
gl.glDisable(GL2ES1.GL_ALPHA_TEST);
}
// Make smooth colors for polygons (interpolate color between points)
if (gl.isGL2()) {
if (quality.isSmoothColor())
gl.getGL2().glShadeModel(GLLightingFunc.GL_SMOOTH);
else
gl.getGL2().glShadeModel(GLLightingFunc.GL_FLAT);
}
// Make smoothing setting
if (quality.isSmoothPolygon()) {
gl.glEnable(GL2GL3.GL_POLYGON_SMOOTH);
gl.glHint(GL2GL3.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST);
} else
gl.glDisable(GL2GL3.GL_POLYGON_SMOOTH);
if (quality.isSmoothLine()) {
gl.glEnable(GL.GL_LINE_SMOOTH);
gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST);
} else
gl.glDisable(GL.GL_LINE_SMOOTH);
if (quality.isSmoothPoint()) {
gl.glEnable(GL2ES1.GL_POINT_SMOOTH);
gl.glHint(GL2ES1.GL_POINT_SMOOTH_HINT, GL.GL_NICEST);
// gl.glDisable(GL2.GL_BLEND);
// gl.glHint(GL2.GL_POINT_SMOOTH_HINT, GL2.GL_NICEST);
} else
gl.glDisable(GL2ES1.GL_POINT_SMOOTH);
}
public void initLights(GL gl) {
// Init light
scene.getLightSet().init(gl);
scene.getLightSet().enableLightIfThereAreLights(gl);
// scene.getLightSet().enable(gl, true);
}
public void initResources(GL gl) {
getScene().getGraph().mountAllGLBindedResources(gl);
}
/** Clear the color and depth buffer. */
public void clear(GL gl) {
clearColorAndDepth(gl);
}
public void clearColorAndDepth(GL gl) {
gl.glClearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a);
gl.glClearDepth(1);
if (slave) {
return;
} else {
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); // or
// use
// GL2
}
}
/* */
public void render(GL gl, GLU glu) {
fireViewLifecycleWillRender(null);
// init(gl);
renderBackground(gl, glu, 0f, 1f);
renderScene(gl, glu);
renderOverlay(gl);
if (dimensionDirty)
dimensionDirty = false;
cam.show(gl, new Transform(new Scale(scaling)), scaling);
}
/**
* To be implemented (see AWTView)
*/
public void renderBackground(GL gl, GLU glu2, float f, float g) {
}
/**
* To be implemented (see AWTView)
*/
public void renderBackground(GL gl, GLU glu2, ViewportConfiguration backgroundViewPort) {
}
public void renderScene(GL gl, GLU glu) {
renderScene(gl, glu, new ViewportConfiguration(canvas.getRendererWidth(), canvas.getRendererHeight()));
}
public void renderScene(GL gl, GLU glu, float left, float right) {
ViewportConfiguration vc = ViewportBuilder.column(canvas.getRendererWidth(), canvas.getRendererHeight(), left, right);
renderScene(gl, glu, vc);
}
public void renderScene(GL gl, GLU glu, ViewportConfiguration viewport) {
updateQuality(gl);
BoundingBox3d scaling = computeScaledViewBounds();
updateCamera(gl, glu, viewport, scaling);
renderAxeBox(gl, glu);
renderSceneGraph(gl, glu);
renderAnnotations(gl, glu);
}
public void updateQuality(GL gl) {
if (quality.isAlphaActivated())
gl.glEnable(GL2.GL_BLEND);
else
gl.glDisable(GL2.GL_BLEND);
}
public BoundingBox3d computeScaledViewBounds() {
scaling = computeSceneScaling();
// -- Compute the bounds for computing cam distance, clipping planes,
if (viewbounds == null)
viewbounds = new BoundingBox3d(0, 1, 0, 1, 0, 1);
BoundingBox3d boundsScaled = new BoundingBox3d();
boundsScaled.add(viewbounds.scale(scaling));
if (MAINTAIN_ALL_OBJECTS_IN_VIEW)
boundsScaled.add(getSceneGraphBounds().scale(scaling));
return boundsScaled;
}
public Coord3d computeSceneScaling() {
if (squared)
return squarify();
else
return Coord3d.IDENTITY.clone();
}
public void updateCamera(GL gl, GLU glu, ViewportConfiguration viewport, BoundingBox3d boundsScaled) {
// before LOG was : (float)bounds.getRadius() * factorViewPointDistance;
float sceneRadius = (float) boundsScaled.getTransformedRadius(spaceTransformer);
updateCamera(gl, glu, viewport, boundsScaled, sceneRadius);
}
public void updateCamera(GL gl, GLU glu, ViewportConfiguration viewport, BoundingBox3d bounds, float sceneRadiusScaled) {
viewpoint.z = sceneRadiusScaled * factorViewPointDistance;
cam.setTarget(computeCameraTarget());
cam.setUp(computeCameraUpAndTriggerEvents());
cam.setEye(computeCameraEye(cam.getTarget()));
computeCameraRenderingSphereRadius(gl, glu, viewport, bounds);
cam.setViewPort(viewport);
cam.shoot(gl, glu, cameraMode);
}
public Coord3d computeCameraTarget() {
return center.mul(scaling);
}
public Coord3d computeCameraEye(Coord3d target) {
Coord3d eye;
if (viewmode == ViewPositionMode.FREE) {
eye = computeCameraEyeFree(viewpoint, target);
} else if (viewmode == ViewPositionMode.TOP) {
eye = computeCameraEyeTop(viewpoint, target);
} else if (viewmode == ViewPositionMode.PROFILE) {
eye = computeCameraEyeProfile(viewpoint, target);
} else
throw new RuntimeException("Unsupported ViewMode: " + viewmode);
return eye;
}
public static Coord3d computeCameraEyeProfile(Coord3d viewpoint, Coord3d target) {
Coord3d eye;
eye = viewpoint;
eye.y = 0;
eye = eye.cartesian().add(target);
return eye;
}
public static Coord3d computeCameraEyeTop(Coord3d viewpoint, Coord3d target) {
Coord3d eye;
eye = viewpoint;
eye.x = -(float) Math.PI / 2; // on x
eye.y = (float) Math.PI / 2; // on top
eye = eye.cartesian().add(target);
return eye;
}
public static Coord3d computeCameraEyeFree(Coord3d viewpoint, Coord3d target) {
Coord3d eye;
eye = viewpoint.cartesian().add(target);
return eye;
}
public Coord3d computeCameraUpAndTriggerEvents() {
Coord3d up;
if (Math.abs(viewpoint.y) == (float) Math.PI / 2) {
up = computeCameraUp();
// handle "on-top" events
if (!wasOnTopAtLastRendering) {
wasOnTopAtLastRendering = true;
fireViewOnTopEvent(true);
}
} else {
// handle up vector
up = new Coord3d(0, 0, 1);
// handle "on-top" events
if (wasOnTopAtLastRendering) {
wasOnTopAtLastRendering = false;
fireViewOnTopEvent(false);
}
}
return up;
}
public Coord3d computeCameraUp() {
Coord2d direction = new Coord2d(viewpoint.x, viewpoint.z).cartesian();
Coord3d up;
if (viewpoint.y > 0) // on top
up = new Coord3d(-direction.x, -direction.y, 0);
else
up = new Coord3d(direction.x, direction.y, 0);
return up;
}
public void computeCameraRenderingSphereRadius(GL gl, GLU glu, ViewportConfiguration viewport, BoundingBox3d bounds) {
if (viewmode == ViewPositionMode.TOP) {
float xdiam = bounds.getXRange().getRange();
float ydiam = bounds.getYRange().getRange();
float radius = Math.max(xdiam, ydiam) / 2;
cam.setRenderingSphereRadius(radius);
correctCameraPositionForIncludingTextLabels(gl, glu, viewport);
} else {
cam.setRenderingSphereRadius((float) bounds.getTransformedRadius(spaceTransformer));
}
}
public void renderAxeBox(GL gl, GLU glu) {
if (axeBoxDisplayed) {
glModelView(gl);
scene.getLightSet().disable(gl);
axe.setScale(scaling);
axe.draw(gl, glu, cam);
scene.getLightSet().enableLightIfThereAreLights(gl);
}
}
public void glModelView(GL gl) {
if (gl.isGL2()) {
gl.getGL2().glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
} else {
GLES2CompatUtils.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
}
}
public void renderSceneGraph(GL gl, GLU glu) {
renderSceneGraph(gl, glu, true);
}
public void renderSceneGraph(GL gl, GLU glu, boolean light) {
if (light) {
scene.getLightSet().apply(gl, scaling);
// gl.glEnable(GL2.GL_LIGHTING);
// gl.glEnable(GL2.GL_LIGHT0);
// gl.glDisable(GL2.GL_LIGHTING);
}
Transform transform = new Transform(new Scale(scaling));
scene.getGraph().setTransform(transform);
scene.getGraph().draw(gl, glu, cam);
}
public void renderOverlay(GL gl) {
renderOverlay(gl, new ViewportConfiguration(canvas));
}
public void renderOverlay(GL gl, ViewportConfiguration viewportConfiguration) {
}
public void renderAnnotations(GL gl, GLU glu) {
Transform transform = new Transform(new Scale(scaling));
annotations.getGraph().setTransform(transform);
annotations.getGraph().draw(gl, glu, null);
}
protected void correctCameraPositionForIncludingTextLabels(GL gl, GLU glu, ViewportConfiguration viewport) {
}
/* */
public static View current() {
return current;
}
/* */
public SpaceTransformer getSpaceTransformer() {
return spaceTransformer;
}
public void setSpaceTransformer(SpaceTransformer transformer) {
this.spaceTransformer = transformer;
}
/* */
/** A view may optionnaly know its parent chart. */
protected Chart chart;
protected GLU glu;
public static float STRETCH_RATIO = 0.25f;
/**
* force to have all object maintained in screen, meaning axebox won't
* always keep the same size.
*/
protected boolean MAINTAIN_ALL_OBJECTS_IN_VIEW = false;
/** display a magenta parallelepiped (debug). */
protected boolean DISPLAY_AXE_WHOLE_BOUNDS = false;
protected boolean axeBoxDisplayed = true;
protected boolean squared = true;
protected Camera cam;
protected IAxe axe;
protected Quality quality;
protected Scene scene;
protected ICanvas canvas;
protected Scene annotations;
protected Coord3d viewpoint;
protected Coord3d center;
protected Coord3d scaling;
protected BoundingBox3d viewbounds;
protected CameraMode cameraMode;
protected ViewPositionMode viewmode;
protected ViewBoundMode boundmode;
// protected BoundingBox3d targetBox;
protected Color bgColor = Color.BLACK;
protected List viewPointChangedListeners;
protected List viewOnTopListeners;
protected List viewLifecycleListeners;
protected boolean wasOnTopAtLastRendering;
protected static final float PI_div2 = (float) Math.PI / 2;
public static final Coord3d DEFAULT_VIEW = new Coord3d(Math.PI / 3, Math.PI / 3, 2000);
protected boolean dimensionDirty = false;
/**
* can be set to true by the Renderer3d so that the View knows it is
* rendering due to a canvas size change
*/
protected boolean viewDirty = false;
protected static View current;
protected BoundingBox3d initBounds;
/**
* Applies a factor to the default camera distance which is set to the
* radius of the scene bounds. Changing this value also change the camera
* clipping planes.
*/
protected float factorViewPointDistance = 2;
/** A slave view won't clear its color and depth buffer before rendering */
protected boolean slave = false;
protected SpaceTransformer spaceTransformer = new SpaceTransformer();
}
Ads help maintain this website.