package au.gov.ga.earthsci.worldwind.common.layers.sphere; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.geom.Matrix; import gov.nasa.worldwind.geom.Vec4; import gov.nasa.worldwind.layers.AbstractLayer; import gov.nasa.worldwind.render.DrawContext; import gov.nasa.worldwind.util.OGLStackHandler; import java.awt.Color; import javax.media.opengl.GL2; import javax.media.opengl.glu.GLU; import javax.media.opengl.glu.GLUquadric; import au.gov.ga.earthsci.worldwind.common.util.AVKeyMore; import au.gov.ga.earthsci.worldwind.common.util.Validate; /** * A simple layer that renders a sphere at the Earth's centre with a specified * radius and colour. * <p/> * Useful for representing Earth core boundaries etc. * <p/> * Uses simple GLU geometry for improved performance. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class SphereLayer extends AbstractLayer { private Vec4 center = Vec4.ZERO; private double radius; private Color color = Color.white; private int slices = 10; private int stacks = 10; /** * Create a new {@link SphereLayer} with the properties in the provided * params list */ public SphereLayer(AVList params) { Validate.notNull(params.getValue(AVKeyMore.SPHERE_RADIUS), "A sphere radius is required."); this.radius = (Double) params.getValue(AVKeyMore.SPHERE_RADIUS); if (params.hasKey(AVKeyMore.COLOR)) { this.color = (Color) params.getValue(AVKeyMore.COLOR); } if (params.hasKey(AVKeyMore.SPHERE_SLICES)) { this.slices = (Integer) params.getValue(AVKeyMore.SPHERE_SLICES); } if (params.hasKey(AVKeyMore.SPHERE_STACKS)) { this.stacks = (Integer) params.getValue(AVKeyMore.SPHERE_STACKS); } this.setValues(params); } /** * Create a new {@link SphereLayer} with the given radius, using defaults * for other properties. * * @param radius * The radius of the sphere, in metres. */ public SphereLayer(double radius) { this.radius = radius; } @Override protected void doRender(DrawContext dc) { GL2 gl = dc.getGL().getGL2(); GLU glu = dc.getGLU(); OGLStackHandler ogsh = new OGLStackHandler(); try { ogsh.pushModelview(gl); ogsh.pushProjection(gl); ogsh.pushAttrib(gl, GL2.GL_TEXTURE_BIT | GL2.GL_ENABLE_BIT | GL2.GL_CURRENT_BIT); setupProjectionMatrix(dc, gl); gl.glDisable(GL2.GL_TEXTURE_2D); gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(), (byte) (getOpacity() * 255)); if (getOpacity() < 1.0) { gl.glEnable(GL2.GL_BLEND); gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA); } gl.glDepthMask(false); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glPushMatrix(); gl.glTranslated(center.x, center.y, center.z); GLUquadric quadric = glu.gluNewQuadric(); glu.gluSphere(quadric, radius, slices, stacks); gl.glPopMatrix(); glu.gluDeleteQuadric(quadric); gl.glDepthMask(true); } finally { ogsh.pop(gl); } } private void setupProjectionMatrix(DrawContext dc, GL2 gl) { // Compute a projection matrix with no far clipping Matrix projection = Matrix.fromPerspective(dc.getView().getFieldOfView(), dc.getView().getViewport().getWidth(), dc .getView().getViewport().getHeight(), 1e3, dc.getGlobe().getDiameter() * 1.5); // Apply the projection matrix to the current OpenGL context. gl.glMatrixMode(GL2.GL_PROJECTION); double[] matrixArray = new double[16]; if (projection != null) { projection.toArray(matrixArray, 0, false); gl.glLoadMatrixd(matrixArray, 0); } } public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public Vec4 getCenter() { return center; } public void setCenter(Vec4 center) { this.center = center; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } public int getSlices() { return slices; } public void setSlices(int slices) { this.slices = slices; } public int getStacks() { return stacks; } public void setStacks(int stacks) { this.stacks = stacks; } }