X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fthreedee%2FJava3DWindow.java;h=f5b324390139f6f4af96271e19ce702a87ee52af;hb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465;hp=ba1ed1530c282e5607d24816bc391f72d68d48c7;hpb=326f489e36aa7f235bc19409a57bf4955cd50f24;p=GpsPrune.git diff --git a/tim/prune/threedee/Java3DWindow.java b/tim/prune/threedee/Java3DWindow.java index ba1ed15..f5b3243 100644 --- a/tim/prune/threedee/Java3DWindow.java +++ b/tim/prune/threedee/Java3DWindow.java @@ -13,9 +13,11 @@ import java.awt.geom.GeneralPath; import javax.media.j3d.AmbientLight; import javax.media.j3d.Appearance; +import javax.media.j3d.Billboard; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; import javax.media.j3d.Canvas3D; +import javax.media.j3d.DirectionalLight; import javax.media.j3d.Font3D; import javax.media.j3d.FontExtrusion; import javax.media.j3d.GeometryArray; @@ -27,9 +29,9 @@ import javax.media.j3d.QuadArray; import javax.media.j3d.Shape3D; import javax.media.j3d.Text3D; import javax.media.j3d.Texture; +import javax.media.j3d.TextureAttributes; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; -import javax.media.j3d.TriangleStripArray; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; @@ -40,7 +42,9 @@ import javax.vecmath.Point3d; import javax.vecmath.Point3f; import javax.vecmath.TexCoord2f; import javax.vecmath.Vector3d; +import javax.vecmath.Vector3f; +import tim.prune.DataStatus; import tim.prune.FunctionLibrary; import tim.prune.I18nManager; import tim.prune.data.Track; @@ -53,6 +57,8 @@ import tim.prune.save.MapGrouter; import com.sun.j3d.utils.behaviors.vp.OrbitBehavior; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.geometry.Cylinder; +import com.sun.j3d.utils.geometry.GeometryInfo; +import com.sun.j3d.utils.geometry.NormalGenerator; import com.sun.j3d.utils.geometry.Sphere; import com.sun.j3d.utils.image.TextureLoader; import com.sun.j3d.utils.universe.SimpleUniverse; @@ -72,6 +78,7 @@ public class Java3DWindow implements ThreeDWindow private ImageDefinition _imageDefinition = null; private GroutedImage _baseImage = null; private TerrainDefinition _terrainDefinition = null; + private DataStatus _dataStatus = null; /** only prompt about big track size once */ private static boolean TRACK_SIZE_WARNING_GIVEN = false; @@ -134,6 +141,14 @@ public class Java3DWindow implements ThreeDWindow _terrainDefinition = inDefinition; } + /** + * Set the current data status + */ + public void setDataStatus(DataStatus inStatus) + { + _dataStatus = inStatus; + } + /** * Show the window */ @@ -215,17 +230,6 @@ public class Java3DWindow implements ThreeDWindow } }}); panel.add(povButton); - // Add button for exporting svg - JButton svgButton = new JButton(I18nManager.getText("function.exportsvg")); - svgButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) - { - if (_orbit != null) { - callbackRender(FunctionLibrary.FUNCTION_SVGEXPORT); - } - }}); - panel.add(svgButton); - // Close button JButton closeButton = new JButton(I18nManager.getText("button.close")); closeButton.addActionListener(new ActionListener() @@ -331,24 +335,31 @@ public class Java3DWindow implements ThreeDWindow if (showTerrain) { - // TODO: Is it maybe possible to cache the last terrainTrack? - // (if the dataTrack and the resolution haven't changed) - // Construct the terrain track according to these extents and the grid size TerrainHelper terrainHelper = new TerrainHelper(_terrainDefinition.getGridSize()); - Track terrainTrack = terrainHelper.createGridTrack(_track); - // Get the altitudes from SRTM for all the points in the track - LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM; - srtmLookup.begin(terrainTrack); - while (srtmLookup.isRunning()) + // See if there's a previously saved terrain track we can reuse + Track terrainTrack = TerrainCache.getTerrainTrack(_dataStatus, _terrainDefinition); + if (terrainTrack == null) { - try { - Thread.sleep(750); // just polling in a wait loop isn't ideal but simple + // Construct the terrain track according to these extents and the grid size + terrainTrack = terrainHelper.createGridTrack(_track); + // Get the altitudes from SRTM for all the points in the track + LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM; + srtmLookup.begin(terrainTrack); + while (srtmLookup.isRunning()) + { + try { + Thread.sleep(750); // just polling in a wait loop isn't ideal but simple + } + catch (InterruptedException e) {} } - catch (InterruptedException e) {} - } - // Fix the voids - terrainHelper.fixVoids(terrainTrack); + // Fix the voids + terrainHelper.fixVoids(terrainTrack); + + // Store this back in the cache, maybe we'll need it again + TerrainCache.storeTerrainTrack(terrainTrack, _dataStatus, _terrainDefinition); + } + // else System.out.println("Yay - reusing the cached track!"); // Give the terrain definition to the _model as well _model.setTerrain(terrainTrack); @@ -365,45 +376,61 @@ public class Java3DWindow implements ThreeDWindow // N, S, E, W GeneralPath bevelPath = new GeneralPath(); bevelPath.moveTo(0.0f, 0.0f); - for (int i=0; i<91; i+= 5) { + for (int i=0; i<91; i+= 5) + { bevelPath.lineTo((float) (0.1 - 0.1 * Math.cos(Math.toRadians(i))), (float) (0.1 * Math.sin(Math.toRadians(i)))); } - for (int i=90; i>0; i-=5) { + for (int i=90; i>0; i-=5) + { bevelPath.lineTo((float) (0.3 + 0.1 * Math.cos(Math.toRadians(i))), (float) (0.1 * Math.sin(Math.toRadians(i)))); } Font3D compassFont = new Font3D( new Font(CARDINALS_FONT, Font.PLAIN, 1), new FontExtrusion(bevelPath)); - objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.n"), new Point3f(0f, 0f, -10f), compassFont)); - objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.s"), new Point3f(0f, 0f, 10f), compassFont)); - objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.w"), new Point3f(-11f, 0f, 0f), compassFont)); - objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.e"), new Point3f(10f, 0f, 0f), compassFont)); + objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.n"), new Point3f(0f, 0f, -11.5f), compassFont)); + objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.s"), new Point3f(0f, 0f, 11.5f), compassFont)); + objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.w"), new Point3f(-11.5f, 0f, 0f), compassFont)); + objTrans.addChild(createCompassPoint(I18nManager.getText("cardinal.e"), new Point3f(11.5f, 0f, 0f), compassFont)); // Add points to model objTrans.addChild(createDataPoints(_model)); - // Create lights - BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); + // Create lights - always add ambient light + BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); AmbientLight aLgt = new AmbientLight(new Color3f(1.0f, 1.0f, 1.0f)); aLgt.setInfluencingBounds(bounds); objTrans.addChild(aLgt); - PointLight pLgt = new PointLight(new Color3f(1.0f, 1.0f, 1.0f), - new Point3f(0f, 0f, 2f), new Point3f(0.25f, 0.05f, 0.0f) ); - pLgt.setInfluencingBounds(bounds); - objTrans.addChild(pLgt); - - PointLight pl2 = new PointLight(new Color3f(0.8f, 0.9f, 0.4f), - new Point3f(6f, 1f, 6f), new Point3f(0.2f, 0.1f, 0.05f) ); - pl2.setInfluencingBounds(bounds); - objTrans.addChild(pl2); - - PointLight pl3 = new PointLight(new Color3f(0.7f, 0.7f, 0.7f), - new Point3f(0.0f, 12f, -2f), new Point3f(0.1f, 0.1f, 0.0f) ); - pl3.setInfluencingBounds(bounds); - objTrans.addChild(pl3); + // Additional lights depend on whether there's a terrain or not + if (showTerrain) + { + // If there's a terrain, just have directional light from northwest + DirectionalLight dl = new DirectionalLight(true, + new Color3f(1.0f, 1.0f, 1.0f), + new Vector3f(1.0f, -1.0f, 1.0f)); + dl.setInfluencingBounds(bounds); + objTrans.addChild(dl); + } + else + { + // There is no terrain, so use point lights as before + PointLight pLgt = new PointLight(new Color3f(1.0f, 1.0f, 1.0f), + new Point3f(0f, 0f, 2f), new Point3f(0.25f, 0.05f, 0.0f) ); + pLgt.setInfluencingBounds(bounds); + objTrans.addChild(pLgt); + + PointLight pl2 = new PointLight(new Color3f(0.8f, 0.9f, 0.4f), + new Point3f(6f, 1f, 6f), new Point3f(0.2f, 0.1f, 0.05f) ); + pl2.setInfluencingBounds(bounds); + objTrans.addChild(pl2); + + PointLight pl3 = new PointLight(new Color3f(0.7f, 0.7f, 0.7f), + new Point3f(0.0f, 12f, -2f), new Point3f(0.1f, 0.1f, 0.0f) ); + pl3.setInfluencingBounds(bounds); + objTrans.addChild(pl3); + } // Have Java 3D perform optimizations on this scene graph. objRoot.compile(); @@ -414,12 +441,12 @@ public class Java3DWindow implements ThreeDWindow /** * Create a text object for compass point, N S E or W - * @param text text to display - * @param locn position at which to display - * @param font 3d font to use - * @return Shape3D object + * @param inText text to display + * @param inLocn position at which to display + * @param inFont 3d font to use + * @return compound object */ - private Shape3D createCompassPoint(String inText, Point3f inLocn, Font3D inFont) + private TransformGroup createCompassPoint(String inText, Point3f inLocn, Font3D inFont) { Text3D txt = new Text3D(inFont, inText, inLocn, Text3D.ALIGN_FIRST, Text3D.PATH_RIGHT); Material mat = new Material(new Color3f(0.5f, 0.5f, 0.55f), @@ -429,7 +456,16 @@ public class Java3DWindow implements ThreeDWindow Appearance app = new Appearance(); app.setMaterial(mat); Shape3D shape = new Shape3D(txt, app); - return shape; + + // Make transform group with billboard behaviour + TransformGroup subGroup = new TransformGroup(); + subGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); + subGroup.addChild(shape); + Billboard billboard = new Billboard(subGroup, Billboard.ROTATE_ABOUT_POINT, inLocn); + BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); + billboard.setSchedulingBounds(bounds); + subGroup.addChild(billboard); + return subGroup; } @@ -575,11 +611,8 @@ public class Java3DWindow implements ThreeDWindow { final int numNodes = inHelper.getGridSize(); final int RESULT_SIZE = numNodes * (numNodes * 2 - 2); - final int GEOMETRY_COLOURING_TYPE = (inBaseImage == null ? GeometryArray.COLOR_3 : GeometryArray.TEXTURE_COORDINATE_2); - int[] stripData = inHelper.getStripLengths(); - TriangleStripArray tsa = new TriangleStripArray(RESULT_SIZE, GeometryArray.COORDINATES | GEOMETRY_COLOURING_TYPE, - stripData); + // Get the scaled terrainTrack coordinates (or just heights) from the model final int nSquared = numNodes * numNodes; Point3d[] rawPoints = new Point3d[nSquared]; @@ -590,28 +623,42 @@ public class Java3DWindow implements ThreeDWindow Math.max(height, 0.05), // make sure it's above the box -inModel.getScaledTerrainVertValue(i) * MODEL_SCALE_FACTOR); } - tsa.setCoordinates(0, inHelper.getTerrainCoordinates(rawPoints)); + + GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY); + gi.setCoordinates(inHelper.getTerrainCoordinates(rawPoints)); + gi.setStripCounts(stripData); Appearance tAppearance = new Appearance(); if (inBaseImage != null) { - tsa.setTextureCoordinates(0, 0, inHelper.getTextureCoordinates()); + gi.setTextureCoordinateParams(1, 2); // one coord set of two dimensions + gi.setTextureCoordinates(0, inHelper.getTextureCoordinates()); Texture mapImage = new TextureLoader(inBaseImage.getImage()).getTexture(); tAppearance.setTexture(mapImage); + TextureAttributes texAttr = new TextureAttributes(); + texAttr.setTextureMode(TextureAttributes.MODULATE); + tAppearance.setTextureAttributes(texAttr); } else { Color3f[] colours = new Color3f[RESULT_SIZE]; Color3f terrainColour = new Color3f(0.1f, 0.2f, 0.2f); for (int i=0; i