/* Copyright (C) 2001, 2006 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */ package gov.nasa.worldwind.layers; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.avlist.AVListImpl; import gov.nasa.worldwind.awt.WorldWindowGLCanvas; import gov.nasa.worldwind.geom.Angle; import gov.nasa.worldwind.geom.LatLon; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.geom.Vec4; import gov.nasa.worldwind.globes.Globe; import gov.nasa.worldwind.util.LevelSet; import java.awt.*; import java.awt.image.BufferedImage; /** * Procedural layer example * @author Patrick Murris * @version $Id:$ */ public class ProceduralShadingLayer extends ProceduralTiledImageLayer { public ProceduralShadingLayer() { super(makeLevels()); this.setUseTransparentTextures(true); } private static LevelSet makeLevels() { AVList params = new AVListImpl(); params.setValue(AVKey.TILE_WIDTH, 128); params.setValue(AVKey.TILE_HEIGHT, 128); params.setValue(AVKey.DATA_CACHE_NAME, "Tests/ProceduralShading"); params.setValue(AVKey.SERVICE, "*"); params.setValue(AVKey.DATASET_NAME, "*"); params.setValue(AVKey.FORMAT_SUFFIX, ".png"); params.setValue(AVKey.NUM_LEVELS, 10); params.setValue(AVKey.NUM_EMPTY_LEVELS, 4); params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle.fromDegrees(36d), Angle.fromDegrees(36d))); params.setValue(AVKey.SECTOR, Sector.FULL_SPHERE); return new LevelSet(params); } private WorldWindowGLCanvas wwd; private Vec4 light = new Vec4(1, 1, -1).normalize3(); // Light direction (from South-East) private double ambiant = .3; // Minimum lighting (0 - 1) public void setWwd(WorldWindowGLCanvas wwd) { this.wwd = wwd; } protected BufferedImage createTileImage(TextureTile tile, BufferedImage image) { int width = tile.getLevel().getTileWidth(); int height = tile.getLevel().getTileHeight(); Graphics2D g2 = image.createGraphics(); if (this.wwd != null) { Globe globe = this.wwd.getModel().getGlobe(); double latStep = tile.getSector().getDeltaLatDegrees() / height; double lonStep = tile.getSector().getDeltaLonDegrees() / width; // Compute shading for each pixel for (int x = 0; x < width; x++) { double lon = tile.getSector().getMinLongitude().degrees + lonStep * x + lonStep / 2; for (int y = 0; y < height; y++) { double lat = tile.getSector().getMaxLatitude().degrees - latStep * y - latStep / 2; Vec4 p0 = globe.computePointFromPosition(Angle.fromDegrees(lat), Angle.fromDegrees(lon), 0); Vec4 px = globe.computePointFromPosition(Angle.fromDegrees(lat), Angle.fromDegrees(lon - lonStep / 2), 0); Vec4 py = globe.computePointFromPosition(Angle.fromDegrees(lat + latStep / 2), Angle.fromDegrees(lon), 0); double el0 = globe.getElevation(Angle.fromDegrees(lat), Angle.fromDegrees(lon)); double elx = globe.getElevation(Angle.fromDegrees(lat), Angle.fromDegrees(lon - lonStep / 2)); double ely = globe.getElevation(Angle.fromDegrees(lat + latStep / 2), Angle.fromDegrees(lon)); Vec4 vx = new Vec4(p0.distanceTo3(px), 0, elx - el0).normalize3(); Vec4 vy = new Vec4(0, p0.distanceTo3(py), ely - el0).normalize3(); Vec4 normal = vx.cross3(vy).normalize3(); double shade = 1d - Math.max(-light.dot3(normal), ambiant); image.setRGB(x, y, new Color(0f, 0f, 0f, (float)shade).getRGB()); } } } else { // Draw a red cross on white background g2.setPaint(Color.WHITE); g2.fillRect(0, 0, width, height); g2.setPaint(Color.RED); g2.drawLine(0, 0, width , height); g2.drawLine(0, height, width , 0); } return image; } @Override public String toString() { return "Procedural Shading"; } }